Merge 5.3->5.5

This commit is contained in:
Igor Babaev 2013-01-23 15:18:05 -08:00
commit 32151409c1
22 changed files with 382 additions and 86 deletions

View File

@ -6530,16 +6530,16 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref c1 c1 5 const 1 Using index 1 SIMPLE t1 ref c1 c1 5 const 1 Using index
EXPLAIN SELECT * FROM t1 WHERE c1=f1(); EXPLAIN SELECT * FROM t1 WHERE c1=f1();
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref c1 c1 5 const 0 Using where; Using index 1 SIMPLE t1 ref c1 c1 5 const 1 Using where; Using index
EXPLAIN SELECT * FROM v1 WHERE c1=1; EXPLAIN SELECT * FROM v1 WHERE c1=1;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref c1 c1 5 const 1 Using index 1 SIMPLE t1 ref c1 c1 5 const 1 Using index
EXPLAIN SELECT * FROM v1 WHERE c1=f1(); EXPLAIN SELECT * FROM v1 WHERE c1=f1();
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref c1 c1 5 const 0 Using where; Using index 1 SIMPLE t1 ref c1 c1 5 const 1 Using where; Using index
EXPLAIN SELECT * FROM t1 WHERE c1=f2(10); EXPLAIN SELECT * FROM t1 WHERE c1=f2(10);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref c1 c1 5 const 0 Using where; Using index 1 SIMPLE t1 ref c1 c1 5 const 1 Using where; Using index
EXPLAIN SELECT * FROM t1 WHERE c1=f2(c1); EXPLAIN SELECT * FROM t1 WHERE c1=f2(c1);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL c1 5 NULL 5 Using where; Using index 1 SIMPLE t1 index NULL c1 5 NULL 5 Using where; Using index
@ -7852,6 +7852,38 @@ c1 c2 count(c3)
2012-03-01 01:00:00 3 1 2012-03-01 01:00:00 3 1
2012-03-01 02:00:00 3 1 2012-03-01 02:00:00 3 1
DROP PROCEDURE p1; DROP PROCEDURE p1;
MDEV-3900 Optimizer difference between MySQL and MariaDB with stored functions in WHERE clause of UPDATE or DELETE statements
CREATE FUNCTION tdn() RETURNS int(7) DETERMINISTIC RETURN to_days(now());
CREATE TABLE t1 (pk INT NOT NULL AUTO_INCREMENT PRIMARY KEY, daynum INT, a CHAR(1), INDEX(daynum), INDEX(a)) ENGINE=MyISAM;
INSERT INTO t1 (daynum) VALUES (1),(2),(3),(4),(5),(TO_DAYS(NOW())),(7),(8);
INSERT INTO t1 (daynum) SELECT a1.daynum FROM t1 a1, t1 a2, t1 a3, t1 a4, t1 a5;
FLUSH TABLES;
FLUSH STATUS;
SHOW STATUS LIKE '%Handler_read%';
Variable_name Value
Handler_read_first 0
Handler_read_key 0
Handler_read_last 0
Handler_read_next 0
Handler_read_prev 0
Handler_read_rnd 0
Handler_read_rnd_deleted 0
Handler_read_rnd_next 0
UPDATE t1 SET a = '+' WHERE daynum=tdn();
SHOW STATUS LIKE '%Handler_read%';
Variable_name Value
Handler_read_first 0
Handler_read_key 2
Handler_read_last 0
Handler_read_next 4097
Handler_read_prev 0
Handler_read_rnd 0
Handler_read_rnd_deleted 0
Handler_read_rnd_next 0
drop function tdn;
drop table t1;
# #
# lp:1002157 : testing stored function # lp:1002157 : testing stored function
# bug#62125 result for null incorrectly yields 1292 warning. # bug#62125 result for null incorrectly yields 1292 warning.

View File

@ -2274,6 +2274,27 @@ SELECT a3 FROM t3 WHERE b2 = b1 AND b2 <= b1 ORDER BY b3
a1 b1 a1 b1
drop table t1, t2, t3; drop table t1, t2, t3;
# #
# MDEV-4056:Server crashes in Item_func_trig_cond::val_int
# with FROM and NOT IN subqueries, LEFT JOIN, derived_merge+in_to_exists
#
set @optimizer_switch_MDEV4056 = @@optimizer_switch;
SET optimizer_switch = 'derived_merge=on,in_to_exists=on';
CREATE TABLE t1 (a VARCHAR(1)) ENGINE=MyISAM;
INSERT INTO t1 VALUES ('x'),('d');
CREATE TABLE t2 (pk INT PRIMARY KEY, b INT, c VARCHAR(1)) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1,2,'v'),(2,150,'v');
SELECT * FROM t1 LEFT JOIN (
SELECT * FROM t2 WHERE ( pk, pk ) NOT IN (
SELECT MIN(b), SUM(pk) FROM t1
)
) AS alias1 ON (a = c)
WHERE b IS NULL OR a < 'u';
a pk b c
x NULL NULL NULL
d NULL NULL NULL
drop table t1,t2;
set @@optimizer_switch = @optimizer_switch_MDEV4056;
#
# MDEV-3899 Valgrind warnings (blocks are definitely lost) in filesort on IN subquery with SUM and DISTINCT # MDEV-3899 Valgrind warnings (blocks are definitely lost) in filesort on IN subquery with SUM and DISTINCT
# #
CREATE TABLE t1 (a INT) ENGINE=MyISAM; CREATE TABLE t1 (a INT) ENGINE=MyISAM;

View File

@ -391,4 +391,22 @@ select 1 from t1 where 1 like (select 1 from t1 where 1 <=> (select 1 from t1 gr
1 1
1 1
drop table t1; drop table t1;
#
# MDEV-3988 crash in create_tmp_table
#
drop table if exists `t1`,`t2`;
Warnings:
Note 1051 Unknown table 't1'
Note 1051 Unknown table 't2'
create table `t1`(`a` char(1) character set utf8)engine=innodb;
create table `t2`(`b` char(1) character set utf8)engine=memory;
select distinct (select 1 from `t2` where `a`) `d2` from `t1`;
d2
select distinct (select 1 from `t2` where `a`) `d2`, a from `t1`;
d2 a
select distinct a, (select 1 from `t2` where `a`) `d2` from `t1`;
a d2
select distinct (1 + (select 1 from `t2` where `a`)) `d2` from `t1`;
d2
drop table t1,t2;
set optimizer_switch=@subselect_innodb_tmp; set optimizer_switch=@subselect_innodb_tmp;

View File

@ -103,5 +103,20 @@ sm
10323810 10323810
10325070 10325070
10326330 10326330
#
# Bug mdev-4063: SUM(DISTINCT...) with small'max_heap_table_size
# (bug #56927)
#
SET max_heap_table_size=default;
INSERT INTO t1 SELECT id+16384 FROM t1;
DELETE FROM t2;
INSERT INTO t2 SELECT id FROM t1 ORDER BY id*rand();
SELECT SUM(DISTINCT id) sm FROM t2;
sm
536887296
SET max_heap_table_size=16384;
SELECT SUM(DISTINCT id) sm FROM t2;
sm
536887296
DROP TABLE t1; DROP TABLE t1;
DROP TABLE t2; DROP TABLE t2;

View File

@ -389,6 +389,7 @@ select a from t1 where a=(select 2000 from dual where 1);
a a
select a from t1 where a=y2k(); select a from t1 where a=y2k();
a a
00
select a from t1 where a=b; select a from t1 where a=b;
a a
drop table t1; drop table t1;

View File

@ -182,6 +182,17 @@ a b c
2 3 y 2 3 y
0 1 y,n 0 1 y,n
drop table t1,t2; drop table t1,t2;
CREATE TABLE t1 (
ts TIMESTAMP,
tsv TIMESTAMP AS (ADDDATE(ts, INTERVAL 1 DAY)) VIRTUAL
) ENGINE=MyISAM;
INSERT INTO t1 (tsv) VALUES (DEFAULT);
INSERT DELAYED INTO t1 (tsv) VALUES (DEFAULT);
FLUSH TABLES;
SELECT COUNT(*) FROM t1;
COUNT(*)
2
DROP TABLE t1;
create table t1 (a int, b int); create table t1 (a int, b int);
insert into t1 values (3, 30), (4, 20), (1, 20); insert into t1 values (3, 30), (4, 20), (1, 20);
create table t2 (c int, d int, v int as (d+1), index idx(c)); create table t2 (c int, d int, v int as (d+1), index idx(c));

View File

@ -178,6 +178,25 @@ select * from t2;
drop table t1,t2; drop table t1,t2;
#
# Bug mdev-3938: INSERT DELAYED for a table with virtual columns
#
CREATE TABLE t1 (
ts TIMESTAMP,
tsv TIMESTAMP AS (ADDDATE(ts, INTERVAL 1 DAY)) VIRTUAL
) ENGINE=MyISAM;
INSERT INTO t1 (tsv) VALUES (DEFAULT);
INSERT DELAYED INTO t1 (tsv) VALUES (DEFAULT);
FLUSH TABLES;
SELECT COUNT(*) FROM t1;
DROP TABLE t1;
# #
# SELECT that uses a virtual column and executed with BKA # SELECT that uses a virtual column and executed with BKA
# #

View File

@ -9151,6 +9151,26 @@ CALL p1(1);
DROP PROCEDURE p1; DROP PROCEDURE p1;
--echo
--echo MDEV-3900 Optimizer difference between MySQL and MariaDB with stored functions in WHERE clause of UPDATE or DELETE statements
--echo
CREATE FUNCTION tdn() RETURNS int(7) DETERMINISTIC RETURN to_days(now());
CREATE TABLE t1 (pk INT NOT NULL AUTO_INCREMENT PRIMARY KEY, daynum INT, a CHAR(1), INDEX(daynum), INDEX(a)) ENGINE=MyISAM;
INSERT INTO t1 (daynum) VALUES (1),(2),(3),(4),(5),(TO_DAYS(NOW())),(7),(8);
INSERT INTO t1 (daynum) SELECT a1.daynum FROM t1 a1, t1 a2, t1 a3, t1 a4, t1 a5;
FLUSH TABLES;
FLUSH STATUS;
SHOW STATUS LIKE '%Handler_read%';
UPDATE t1 SET a = '+' WHERE daynum=tdn();
SHOW STATUS LIKE '%Handler_read%';
drop function tdn;
drop table t1;
--echo # --echo #
--echo # lp:1002157 : testing stored function --echo # lp:1002157 : testing stored function
--echo # bug#62125 result for null incorrectly yields 1292 warning. --echo # bug#62125 result for null incorrectly yields 1292 warning.

View File

@ -1804,6 +1804,30 @@ SELECT * FROM t1 WHERE a1 IN (
); );
drop table t1, t2, t3; drop table t1, t2, t3;
--echo #
--echo # MDEV-4056:Server crashes in Item_func_trig_cond::val_int
--echo # with FROM and NOT IN subqueries, LEFT JOIN, derived_merge+in_to_exists
--echo #
set @optimizer_switch_MDEV4056 = @@optimizer_switch;
SET optimizer_switch = 'derived_merge=on,in_to_exists=on';
CREATE TABLE t1 (a VARCHAR(1)) ENGINE=MyISAM;
INSERT INTO t1 VALUES ('x'),('d');
CREATE TABLE t2 (pk INT PRIMARY KEY, b INT, c VARCHAR(1)) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1,2,'v'),(2,150,'v');
SELECT * FROM t1 LEFT JOIN (
SELECT * FROM t2 WHERE ( pk, pk ) NOT IN (
SELECT MIN(b), SUM(pk) FROM t1
)
) AS alias1 ON (a = c)
WHERE b IS NULL OR a < 'u';
drop table t1,t2;
set @@optimizer_switch = @optimizer_switch_MDEV4056;
--echo # --echo #
--echo # MDEV-3899 Valgrind warnings (blocks are definitely lost) in filesort on IN subquery with SUM and DISTINCT --echo # MDEV-3899 Valgrind warnings (blocks are definitely lost) in filesort on IN subquery with SUM and DISTINCT
--echo # --echo #

View File

@ -377,4 +377,18 @@ select 1 from t1 where 1 like (select 1 from t1 where 1 <=> (select 1 from t1 gr
drop table t1; drop table t1;
--echo #
--echo # MDEV-3988 crash in create_tmp_table
--echo #
drop table if exists `t1`,`t2`;
create table `t1`(`a` char(1) character set utf8)engine=innodb;
create table `t2`(`b` char(1) character set utf8)engine=memory;
select distinct (select 1 from `t2` where `a`) `d2` from `t1`;
select distinct (select 1 from `t2` where `a`) `d2`, a from `t1`;
select distinct a, (select 1 from `t2` where `a`) `d2` from `t1`;
select distinct (1 + (select 1 from `t2` where `a`)) `d2` from `t1`;
drop table t1,t2;
set optimizer_switch=@subselect_innodb_tmp; set optimizer_switch=@subselect_innodb_tmp;

View File

@ -63,5 +63,22 @@ SELECT SUM(DISTINCT id) sm FROM t1;
SELECT SUM(DISTINCT id) sm FROM t2; SELECT SUM(DISTINCT id) sm FROM t2;
SELECT SUM(DISTINCT id) sm FROM t1 GROUP BY id % 13; SELECT SUM(DISTINCT id) sm FROM t1 GROUP BY id % 13;
--echo #
--echo # Bug mdev-4063: SUM(DISTINCT...) with small'max_heap_table_size
--echo # (bug #56927)
--echo #
SET max_heap_table_size=default;
INSERT INTO t1 SELECT id+16384 FROM t1;
DELETE FROM t2;
INSERT INTO t2 SELECT id FROM t1 ORDER BY id*rand();
SELECT SUM(DISTINCT id) sm FROM t2;
SET max_heap_table_size=16384;
SELECT SUM(DISTINCT id) sm FROM t2;
DROP TABLE t1; DROP TABLE t1;
DROP TABLE t2; DROP TABLE t2;

View File

@ -6524,6 +6524,19 @@ Item_func_sp::init_result_field(THD *thd)
} }
/**
@note
Deterministic stored procedures are considered inexpensive.
Consequently such procedures may be evaluated during optimization,
if they are constant (checked by the optimizer).
*/
bool Item_func_sp::is_expensive()
{
return !(m_sp->m_chistics->detistic);
}
/** /**
@brief Initialize local members with values from the Field interface. @brief Initialize local members with values from the Field interface.

View File

@ -1907,7 +1907,8 @@ private:
bool init_result_field(THD *thd); bool init_result_field(THD *thd);
protected: protected:
bool is_expensive_processor(uchar *arg) { return TRUE; } bool is_expensive_processor(uchar *arg)
{ return is_expensive(); }
public: public:
@ -1986,7 +1987,7 @@ public:
bool fix_fields(THD *thd, Item **ref); bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec(void); void fix_length_and_dec(void);
bool is_expensive() { return 1; } bool is_expensive();
inline Field *get_sp_result_field() inline Field *get_sp_result_field()
{ {

View File

@ -145,11 +145,13 @@ void Item_row::update_used_tables()
{ {
used_tables_cache= 0; used_tables_cache= 0;
const_item_cache= 1; const_item_cache= 1;
maybe_null= 0;
for (uint i= 0; i < arg_count; i++) for (uint i= 0; i < arg_count; i++)
{ {
items[i]->update_used_tables(); items[i]->update_used_tables();
used_tables_cache|= items[i]->used_tables(); used_tables_cache|= items[i]->used_tables();
const_item_cache&= items[i]->const_item(); const_item_cache&= items[i]->const_item();
maybe_null|= items[i]->maybe_null;
} }
} }

View File

@ -1086,7 +1086,7 @@ void Aggregator_distinct::endup()
{ {
/* go over the tree of distinct keys and calculate the aggregate value */ /* go over the tree of distinct keys and calculate the aggregate value */
use_distinct_values= TRUE; use_distinct_values= TRUE;
tree->walk(item_sum_distinct_walk, (void*) this); tree->walk(table, item_sum_distinct_walk, (void*) this);
use_distinct_values= FALSE; use_distinct_values= FALSE;
} }
/* prevent consecutive recalculations */ /* prevent consecutive recalculations */

View File

@ -8939,7 +8939,8 @@ fill_record(THD * thd, List<Item> &fields, List<Item> &values,
ER(ER_WARNING_NON_DEFAULT_VALUE_FOR_VIRTUAL_COLUMN), ER(ER_WARNING_NON_DEFAULT_VALUE_FOR_VIRTUAL_COLUMN),
rfield->field_name, table->s->table_name.str); rfield->field_name, table->s->table_name.str);
} }
if ((value->save_in_field(rfield, 0) < 0) && !ignore_errors) if ((!rfield->vcol_info || rfield->stored_in_db) &&
(value->save_in_field(rfield, 0)) < 0 && !ignore_errors)
{ {
my_message(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR), MYF(0)); my_message(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR), MYF(0));
goto err; goto err;

View File

@ -3856,6 +3856,8 @@ class Unique :public Sql_alloc
uint full_size; uint full_size;
uint min_dupl_count; /* always 0 for unions, > 0 for intersections */ uint min_dupl_count; /* always 0 for unions, > 0 for intersections */
bool merge(TABLE *table, uchar *buff, bool without_last_merge);
public: public:
ulong elements; ulong elements;
Unique(qsort_cmp2 comp_func, void *comp_func_fixed_arg, Unique(qsort_cmp2 comp_func, void *comp_func_fixed_arg,
@ -3896,7 +3898,7 @@ public:
} }
void reset(); void reset();
bool walk(tree_walk_action action, void *walk_action_arg); bool walk(TABLE *table, tree_walk_action action, void *walk_action_arg);
uint get_size() const { return size; } uint get_size() const { return size; }
ulonglong get_max_in_memory_size() const { return max_in_memory_size; } ulonglong get_max_in_memory_size() const { return max_in_memory_size; }

View File

@ -2320,6 +2320,7 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
{ {
my_ptrdiff_t adjust_ptrs; my_ptrdiff_t adjust_ptrs;
Field **field,**org_field, *found_next_number_field; Field **field,**org_field, *found_next_number_field;
Field **vfield;
TABLE *copy; TABLE *copy;
TABLE_SHARE *share; TABLE_SHARE *share;
uchar *bitmap; uchar *bitmap;
@ -2379,6 +2380,13 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
if (!copy_tmp) if (!copy_tmp)
goto error; goto error;
if (share->vfields)
{
vfield= (Field **) client_thd->alloc((share->vfields+1)*sizeof(Field*));
if (!vfield)
goto error;
}
/* Copy the TABLE object. */ /* Copy the TABLE object. */
copy= new (copy_tmp) TABLE; copy= new (copy_tmp) TABLE;
*copy= *table; *copy= *table;
@ -2408,6 +2416,27 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
} }
*field=0; *field=0;
if (share->vfields)
{
copy->vfield= vfield;
for (field= copy->field; *field; field++)
{
if ((*field)->vcol_info)
{
bool error_reported= FALSE;
if (unpack_vcol_info_from_frm(client_thd,
client_thd->mem_root,
copy,
*field,
&(*field)->vcol_info->expr_str,
&error_reported))
goto error;
*vfield++= *field;
}
}
*vfield= 0;
}
/* Adjust timestamp */ /* Adjust timestamp */
if (table->timestamp_field) if (table->timestamp_field)
{ {

View File

@ -14176,10 +14176,20 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
if (group) if (group)
{ {
ORDER **prev= &group;
if (!param->quick_group) if (!param->quick_group)
group=0; // Can't use group key group=0; // Can't use group key
else for (ORDER *tmp=group ; tmp ; tmp=tmp->next) else for (ORDER *tmp=group ; tmp ; tmp=tmp->next)
{ {
/* Exclude found constant from the list */
if ((*tmp->item)->const_item())
{
*prev= tmp->next;
param->group_parts--;
continue;
}
else
prev= &(tmp->next);
/* /*
marker == 4 means two things: marker == 4 means two things:
- store NULLs in the key, and - store NULLs in the key, and

View File

@ -2138,8 +2138,10 @@ end:
@brief @brief
Unpack the definition of a virtual column from its linear representation Unpack the definition of a virtual column from its linear representation
@parm @param
thd The thread object thd The thread object
@param
mem_root The mem_root object where to allocated memory
@param @param
table The table containing the virtual column table The table containing the virtual column
@param @param
@ -2169,6 +2171,7 @@ end:
TRUE Otherwise TRUE Otherwise
*/ */
bool unpack_vcol_info_from_frm(THD *thd, bool unpack_vcol_info_from_frm(THD *thd,
MEM_ROOT *mem_root,
TABLE *table, TABLE *table,
Field *field, Field *field,
LEX_STRING *vcol_expr, LEX_STRING *vcol_expr,
@ -2196,7 +2199,7 @@ bool unpack_vcol_info_from_frm(THD *thd,
"PARSE_VCOL_EXPR (<expr_string_from_frm>)". "PARSE_VCOL_EXPR (<expr_string_from_frm>)".
*/ */
if (!(vcol_expr_str= (char*) alloc_root(&table->mem_root, if (!(vcol_expr_str= (char*) alloc_root(mem_root,
vcol_expr->length + vcol_expr->length +
parse_vcol_keyword.length + 3))) parse_vcol_keyword.length + 3)))
{ {
@ -2230,10 +2233,10 @@ bool unpack_vcol_info_from_frm(THD *thd,
We need to use CONVENTIONAL_EXECUTION here to ensure that We need to use CONVENTIONAL_EXECUTION here to ensure that
any new items created by fix_fields() are not reverted. any new items created by fix_fields() are not reverted.
*/ */
Query_arena expr_arena(&table->mem_root, Query_arena expr_arena(mem_root,
Query_arena::STMT_CONVENTIONAL_EXECUTION); Query_arena::STMT_CONVENTIONAL_EXECUTION);
if (!(vcol_arena= (Query_arena *) alloc_root(&table->mem_root, if (!(vcol_arena= (Query_arena *) alloc_root(mem_root,
sizeof(Query_arena)))) sizeof(Query_arena))))
goto err; goto err;
*vcol_arena= expr_arena; *vcol_arena= expr_arena;
table->expr_arena= vcol_arena; table->expr_arena= vcol_arena;
@ -2491,6 +2494,7 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
if ((*field_ptr)->vcol_info) if ((*field_ptr)->vcol_info)
{ {
if (unpack_vcol_info_from_frm(thd, if (unpack_vcol_info_from_frm(thd,
&outparam->mem_root,
outparam, outparam,
*field_ptr, *field_ptr,
&(*field_ptr)->vcol_info->expr_str, &(*field_ptr)->vcol_info->expr_str,

View File

@ -2373,6 +2373,9 @@ void init_mdl_requests(TABLE_LIST *table_list);
int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias, int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
uint db_stat, uint prgflag, uint ha_open_flags, uint db_stat, uint prgflag, uint ha_open_flags,
TABLE *outparam, bool is_create_table); TABLE *outparam, bool is_create_table);
bool unpack_vcol_info_from_frm(THD *thd, MEM_ROOT *mem_root,
TABLE *table, Field *field,
LEX_STRING *vcol_expr, bool *error_reported);
TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key, TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key,
uint key_length); uint key_length);
void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key, void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key,

View File

@ -584,6 +584,7 @@ end:
SYNOPSIS SYNOPSIS
Unique:walk() Unique:walk()
All params are 'IN': All params are 'IN':
table parameter for the call of the merge method
action function-visitor, typed in include/my_tree.h action function-visitor, typed in include/my_tree.h
function is called for each unique element function is called for each unique element
arg argument for visitor, which is passed to it on each call arg argument for visitor, which is passed to it on each call
@ -592,30 +593,120 @@ end:
<> 0 error <> 0 error
*/ */
bool Unique::walk(tree_walk_action action, void *walk_action_arg) bool Unique::walk(TABLE *table, tree_walk_action action, void *walk_action_arg)
{ {
int res; int res= 0;
uchar *merge_buffer; uchar *merge_buffer;
if (elements == 0) /* the whole tree is in memory */ if (elements == 0) /* the whole tree is in memory */
return tree_walk(&tree, action, walk_action_arg, left_root_right); return tree_walk(&tree, action, walk_action_arg, left_root_right);
table->sort.found_records=elements+tree.elements_in_tree;
/* flush current tree to the file to have some memory for merge buffer */ /* flush current tree to the file to have some memory for merge buffer */
if (flush()) if (flush())
return 1; return 1;
if (flush_io_cache(&file) || reinit_io_cache(&file, READ_CACHE, 0L, 0, 0)) if (flush_io_cache(&file) || reinit_io_cache(&file, READ_CACHE, 0L, 0, 0))
return 1; return 1;
if (!(merge_buffer= (uchar *) my_malloc((ulong) max_in_memory_size, MYF(0)))) ulong buff_sz= (max_in_memory_size / full_size + 1) * full_size;
if (!(merge_buffer= (uchar *) my_malloc((ulong) buff_sz, MYF(0))))
return 1; return 1;
res= merge_walk(merge_buffer, (ulong) max_in_memory_size, size, if (buff_sz < (ulong) (full_size * (file_ptrs.elements + 1)))
(BUFFPEK *) file_ptrs.buffer, res= merge(table, merge_buffer, buff_sz >= full_size * MERGEBUFF2) ;
(BUFFPEK *) file_ptrs.buffer + file_ptrs.elements,
action, walk_action_arg, if (!res)
tree.compare, tree.custom_arg, &file); {
res= merge_walk(merge_buffer, (ulong) max_in_memory_size, full_size,
(BUFFPEK *) file_ptrs.buffer,
(BUFFPEK *) file_ptrs.buffer + file_ptrs.elements,
action, walk_action_arg,
tree.compare, tree.custom_arg, &file);
}
my_free(merge_buffer); my_free(merge_buffer);
return res; return res;
} }
/*
DESCRIPTION
Perform multi-pass sort merge of the elements accessed through table->sort,
using the buffer buff as the merge buffer. The last pass is not performed
if without_last_merge is TRUE.
SYNOPSIS
Unique:merge()
All params are 'IN':
table the parameter to access sort context
buff merge buffer
without_last_merge TRUE <=> do not perform the last merge
RETURN VALUE
0 OK
<> 0 error
*/
bool Unique::merge(TABLE *table, uchar *buff, bool without_last_merge)
{
SORTPARAM sort_param;
IO_CACHE *outfile= table->sort.io_cache;
BUFFPEK *file_ptr= (BUFFPEK*) file_ptrs.buffer;
uint maxbuffer= file_ptrs.elements - 1;
my_off_t save_pos;
bool error= 1;
/* Open cached file if it isn't open */
if (!outfile)
outfile= table->sort.io_cache= (IO_CACHE*) my_malloc(sizeof(IO_CACHE),
MYF(MY_ZEROFILL));
if (!outfile ||
(! my_b_inited(outfile) &&
open_cached_file(outfile,mysql_tmpdir,TEMP_PREFIX,READ_RECORD_BUFFER,
MYF(MY_WME))))
return 1;
reinit_io_cache(outfile,WRITE_CACHE,0L,0,0);
bzero((char*) &sort_param,sizeof(sort_param));
sort_param.max_rows= elements;
sort_param.sort_form= table;
sort_param.rec_length= sort_param.sort_length= sort_param.ref_length=
full_size;
sort_param.min_dupl_count= min_dupl_count;
sort_param.res_length= 0;
sort_param.keys= (uint) (max_in_memory_size / sort_param.sort_length);
sort_param.not_killable= 1;
sort_param.unique_buff= buff + (sort_param.keys * sort_param.sort_length);
sort_param.compare= (qsort2_cmp) buffpek_compare;
sort_param.cmp_context.key_compare= tree.compare;
sort_param.cmp_context.key_compare_arg= tree.custom_arg;
/* Merge the buffers to one file, removing duplicates */
if (merge_many_buff(&sort_param,buff,file_ptr,&maxbuffer,&file))
goto err;
if (flush_io_cache(&file) ||
reinit_io_cache(&file,READ_CACHE,0L,0,0))
goto err;
sort_param.res_length= sort_param.rec_length-
(min_dupl_count ? sizeof(min_dupl_count) : 0);
if (without_last_merge)
{
file_ptrs.elements= maxbuffer+1;
return 0;
}
if (merge_index(&sort_param, buff, file_ptr, maxbuffer, &file, outfile))
goto err;
error= 0;
err:
if (flush_io_cache(outfile))
error= 1;
/* Setup io_cache for reading */
save_pos= outfile->pos_in_file;
if (reinit_io_cache(outfile,READ_CACHE,0L,0,0))
error= 1;
outfile->end_of_file=save_pos;
return error;
}
/* /*
Modify the TABLE element so that when one calls init_records() Modify the TABLE element so that when one calls init_records()
the rows will be read in priority order. the rows will be read in priority order.
@ -623,12 +714,13 @@ bool Unique::walk(tree_walk_action action, void *walk_action_arg)
bool Unique::get(TABLE *table) bool Unique::get(TABLE *table)
{ {
SORTPARAM sort_param; bool rc= 1;
table->sort.found_records=elements+tree.elements_in_tree; uchar *sort_buffer= NULL;
table->sort.found_records= elements+tree.elements_in_tree;
if (my_b_tell(&file) == 0) if (my_b_tell(&file) == 0)
{ {
/* Whole tree is in memory; Don't use disk if you don't need to */ /* Whole tree is in memory; Don't use disk if you don't need to */
DBUG_ASSERT(table->sort.record_pointers == NULL);
if ((record_pointers=table->sort.record_pointers= (uchar*) if ((record_pointers=table->sort.record_pointers= (uchar*)
my_malloc(size * tree.elements_in_tree, MYF(0)))) my_malloc(size * tree.elements_in_tree, MYF(0))))
{ {
@ -645,69 +737,16 @@ bool Unique::get(TABLE *table)
/* Not enough memory; Save the result to file && free memory used by tree */ /* Not enough memory; Save the result to file && free memory used by tree */
if (flush()) if (flush())
return 1; return 1;
IO_CACHE *outfile=table->sort.io_cache; ulong buff_sz= (max_in_memory_size / full_size + 1) * full_size;
BUFFPEK *file_ptr= (BUFFPEK*) file_ptrs.buffer; if (!(sort_buffer= (uchar*) my_malloc(buff_sz, MYF(0))))
uint maxbuffer= file_ptrs.elements - 1;
uchar *sort_buffer;
my_off_t save_pos;
bool error=1;
/* Open cached file if it isn't open */
DBUG_ASSERT(table->sort.io_cache == NULL);
outfile=table->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
MYF(MY_ZEROFILL));
if (!outfile ||
(! my_b_inited(outfile) &&
open_cached_file(outfile,mysql_tmpdir,TEMP_PREFIX,READ_RECORD_BUFFER,
MYF(MY_WME))))
return 1; return 1;
reinit_io_cache(outfile,WRITE_CACHE,0L,0,0);
bzero((char*) &sort_param,sizeof(sort_param)); if (merge(table, sort_buffer, FALSE))
sort_param.max_rows= elements; goto err;
sort_param.sort_form=table; rc= 0;
sort_param.rec_length= sort_param.sort_length= sort_param.ref_length=
full_size;
sort_param.min_dupl_count= min_dupl_count;
sort_param.res_length= 0;
sort_param.keys= (uint) (max_in_memory_size / sort_param.sort_length);
sort_param.not_killable=1;
if (!(sort_buffer=(uchar*) my_malloc((sort_param.keys+1) * err:
sort_param.sort_length, my_free(sort_buffer);
MYF(0)))) return rc;
return 1;
sort_param.unique_buff= sort_buffer+(sort_param.keys*
sort_param.sort_length);
sort_param.compare= (qsort2_cmp) buffpek_compare;
sort_param.cmp_context.key_compare= tree.compare;
sort_param.cmp_context.key_compare_arg= tree.custom_arg;
/* Merge the buffers to one file, removing duplicates */
if (merge_many_buff(&sort_param,sort_buffer,file_ptr,&maxbuffer,&file))
goto err;
if (flush_io_cache(&file) ||
reinit_io_cache(&file,READ_CACHE,0L,0,0))
goto err;
sort_param.res_length= sort_param.rec_length-
(min_dupl_count ? sizeof(min_dupl_count) : 0);
if (merge_index(&sort_param, sort_buffer, file_ptr, maxbuffer, &file, outfile))
goto err;
error=0;
err:
my_free(sort_buffer);
if (flush_io_cache(outfile))
error=1;
/* Setup io_cache for reading */
save_pos=outfile->pos_in_file;
if (reinit_io_cache(outfile,READ_CACHE,0L,0,0))
error=1;
outfile->end_of_file=save_pos;
return error;
} }