This is the consolidated patch for mdev-8646:

"Re-factor the code for post-join operations".

The patch mainly contains the code ported from mysql-5.6 and
created for two essential architectural changes:
1. WL#5558: Resolve ORDER BY execution method at the optimization stage
2. WL#6071: Inline tmp tables into the nested loops algorithm

The first task was implemented for mysql-5.6 by Ole John Aske.
It allows to make all decisions on ORDER BY operation at the optimization
stage.

The second task implemented for mysql-5.6 by Evgeny Potemkin adds JOIN_TAB
nodes for post-join operations that require temporary tables. It allows
to execute these operations within the nested loops algorithm that used to
be used before this task only for join queries. Besides these task moves
all planning on the execution of these operations from the execution phase
to the optimization phase.

Some other re-factoring changes of mysql-5.6 were pulled in, mainly because
it was easier to pull them in than roll them back. In particular all
changes concerning Ref_ptr_array were incorporated.

The port required some changes in the MariaDB code that concerned the
functionality of EXPLAIN and ANALYZE. This was done mainly by Sergey
Petrunia.
This commit is contained in:
Igor Babaev 2016-02-09 12:35:59 -08:00
parent 7b50447aa6
commit 2cfc450bf7
53 changed files with 2488 additions and 2088 deletions

View File

@ -488,7 +488,7 @@ ANALYZE
"select_id": 1,
"r_loops": 1,
"volatile parameter": "REPLACED",
"having_condition": "(TOP > a)",
"having_condition": "(TOP > t2.a)",
"filesort": {
"r_loops": 1,
"volatile parameter": "REPLACED",

View File

@ -175,7 +175,7 @@ explain SELECT distinct t3.a FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 4 Using where; Using temporary
1 SIMPLE t3 ref a a 5 test.t1.b 2 Using index
1 SIMPLE t2 index a a 4 NULL 5 Using where; Using index; Distinct; Using join buffer (flat, BNL join)
1 SIMPLE t2 index a a 4 NULL 5 Using where; Using index; Using join buffer (flat, BNL join)
SELECT distinct t3.a FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a;
a
1
@ -302,11 +302,11 @@ WHERE
AND ((t1.id=j_lj_t3.id AND t3_lj.id IS NULL) OR (t1.id=t3.id AND t3.idx=2));
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index id id 4 NULL 2 Using index; Using temporary
1 SIMPLE t2 index id id 8 NULL 1 Using index; Distinct; Using join buffer (flat, BNL join)
1 SIMPLE t3 index id id 8 NULL 1 Using index; Distinct; Using join buffer (flat, BNL join)
1 SIMPLE j_lj_t2 index id id 4 NULL 2 Using where; Using index; Distinct; Using join buffer (flat, BNL join)
1 SIMPLE t2_lj ref id id 4 test.j_lj_t2.id 1 Using where; Using index; Distinct
1 SIMPLE j_lj_t3 index id id 4 NULL 2 Using where; Using index; Distinct; Using join buffer (flat, BNL join)
1 SIMPLE t2 index id id 8 NULL 1 Using index; Using join buffer (flat, BNL join)
1 SIMPLE t3 index id id 8 NULL 1 Using index; Using join buffer (flat, BNL join)
1 SIMPLE j_lj_t2 index id id 4 NULL 2 Using where; Using index; Using join buffer (flat, BNL join)
1 SIMPLE t2_lj ref id id 4 test.j_lj_t2.id 1 Using where; Using index
1 SIMPLE j_lj_t3 index id id 4 NULL 2 Using where; Using index; Using join buffer (flat, BNL join)
1 SIMPLE t3_lj ref id id 4 test.j_lj_t3.id 1 Using where; Using index; Distinct
SELECT DISTINCT
t1.id
@ -518,7 +518,7 @@ id select_type table type possible_keys key key_len ref rows Extra
EXPLAIN SELECT DISTINCT t1_1.a, t1_1.b FROM t1 t1_1, t1 t1_2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1_1 ALL NULL NULL NULL NULL 3 Using temporary
1 SIMPLE t1_2 index NULL PRIMARY 4 NULL 3 Using index; Distinct; Using join buffer (flat, BNL join)
1 SIMPLE t1_2 index NULL PRIMARY 4 NULL 3 Using index; Using join buffer (flat, BNL join)
EXPLAIN SELECT DISTINCT t1_1.a, t1_1.b FROM t1 t1_1, t1 t1_2
WHERE t1_1.a = t1_2.a;
id select_type table type possible_keys key key_len ref rows Extra
@ -916,8 +916,8 @@ SELECT STRAIGHT_JOIN DISTINCT t1.id FROM
t1, v1, t2 WHERE v1.id = t2.i AND t1.i1 = v1.i1 AND t2.i != 3;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 96 100.00 Using where; Using temporary
1 PRIMARY <derived2> ref key0 key0 5 test.t1.i1 9 100.00 Using where; Distinct
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Distinct; Using join buffer (flat, BNL join)
1 PRIMARY <derived2> ref key0 key0 5 test.t1.i1 9 100.00 Using where
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (flat, BNL join)
2 DERIVED t1 ALL NULL NULL NULL NULL 96 100.00
Warnings:
Note 1003 select straight_join distinct `test`.`t1`.`id` AS `id` from `test`.`t1` join `test`.`v1` join `test`.`t2` where ((`test`.`t2`.`i` = `v1`.`id`) and (`v1`.`i1` = `test`.`t1`.`i1`) and (`v1`.`id` <> 3))

View File

@ -1519,7 +1519,7 @@ SELECT MAX(pk) as max, i
FROM t1
ORDER BY max;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using temporary
1 SIMPLE t1 ALL NULL NULL NULL NULL 3
# Only 11 is correct for collumn i in this result
SELECT MAX(pk) as max, i

View File

@ -1346,12 +1346,43 @@ id select_type table type possible_keys key key_len ref rows Extra
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR JOIN (PRIMARY,i2);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 144
#
# For this explain, the query plan is weird: if we are using
# the primary key for reasons other than doing grouping, can't
# GROUP BY code take advantage of this? Well, currently it doesnt:
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR GROUP BY (PRIMARY,i2) GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 144 Using index
1 SIMPLE t1 index NULL PRIMARY 4 NULL 144 Using index; Using filesort
# Here's a proof it is really doing sorting:
flush status;
SELECT a FROM t1 IGNORE INDEX FOR GROUP BY (PRIMARY,i2) GROUP BY a;
show status like 'Sort_%';
Variable_name Value
Sort_merge_passes 0
Sort_priority_queue_sorts 0
Sort_range 0
Sort_rows 144
Sort_scan 1
# Proof ends.
#
# For this explain, the query plan is weird: if we are using
# the primary key for reasons other than doing sorting, can't
# ORDER BY code take advantage of this? Well, currently it doesnt:
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR ORDER BY (PRIMARY,i2) ORDER BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 144 Using index
1 SIMPLE t1 index NULL PRIMARY 4 NULL 144 Using index; Using filesort
# Here's a proof it is really doing sorting:
flush status;
SELECT a FROM t1 IGNORE INDEX FOR ORDER BY (PRIMARY,i2) ORDER BY a;
show status like 'Sort_%';
Variable_name Value
Sort_merge_passes 0
Sort_priority_queue_sorts 0
Sort_range 0
Sort_rows 144
Sort_scan 1
# Proof ends.
#
SELECT a FROM t1 IGNORE INDEX FOR ORDER BY (PRIMARY,i2) ORDER BY a;
a
1

View File

@ -470,10 +470,9 @@ WHERE table2.f1 = 2
GROUP BY table1.f1, table2.f2
HAVING (table2.f2 = 8 AND table1.f1 >= 6);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE table2 const PRIMARY PRIMARY 4 const 1 100.00 Using filesort
1 SIMPLE table1 ALL NULL NULL NULL NULL 4 100.00 Using where
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible HAVING noticed after reading const tables
Warnings:
Note 1003 select `test`.`table1`.`f1` AS `f1`,7 AS `f2` from `test`.`t1` `table1` join `test`.`t1` `table2` where (`test`.`table1`.`f3` = 9) group by `test`.`table1`.`f1`,7 having ((7 = 8) and (`test`.`table1`.`f1` >= 6))
Note 1003 select `test`.`table1`.`f1` AS `f1`,7 AS `f2` from `test`.`t1` `table1` join `test`.`t1` `table2` where (`test`.`table1`.`f3` = 9) group by `test`.`table1`.`f1`,7 having 0
EXPLAIN EXTENDED
SELECT table1.f1, table2.f2
FROM t1 AS table1
@ -482,10 +481,9 @@ WHERE table2.f1 = 2
GROUP BY table1.f1, table2.f2
HAVING (table2.f2 = 8);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE table2 const PRIMARY PRIMARY 4 const 1 100.00 Using filesort
1 SIMPLE table1 ALL NULL NULL NULL NULL 4 100.00 Using where
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible HAVING noticed after reading const tables
Warnings:
Note 1003 select `test`.`table1`.`f1` AS `f1`,7 AS `f2` from `test`.`t1` `table1` join `test`.`t1` `table2` where (`test`.`table1`.`f3` = 9) group by `test`.`table1`.`f1`,7 having (7 = 8)
Note 1003 select `test`.`table1`.`f1` AS `f1`,7 AS `f2` from `test`.`t1` `table1` join `test`.`t1` `table2` where (`test`.`table1`.`f3` = 9) group by `test`.`table1`.`f1`,7 having 0
DROP TABLE t1;
#
# Bug#52336 Segfault / crash in 5.1 copy_fields (param=0x9872980) at sql_select.cc:15355

View File

@ -80,13 +80,13 @@ create table t1 (a int);
insert into t1 values (1),(2),(3),(4),(5),(6),(7);
explain select count(*) c FROM t1 WHERE a > 0 ORDER BY c LIMIT 3;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 7 Using where; Using temporary
1 SIMPLE t1 ALL NULL NULL NULL NULL 7 Using where
select count(*) c FROM t1 WHERE a > 0 ORDER BY c LIMIT 3;
c
7
explain select sum(a) c FROM t1 WHERE a > 0 ORDER BY c LIMIT 3;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 7 Using where; Using temporary
1 SIMPLE t1 ALL NULL NULL NULL NULL 7 Using where
select sum(a) c FROM t1 WHERE a > 0 ORDER BY c LIMIT 3;
c
28

View File

@ -471,9 +471,11 @@ id select_type table type possible_keys key key_len ref rows Extra
select c1, sum(c2) from t3 group by c1 LIMIT ROWS EXAMINED 0;
c1 sum(c2)
Warnings:
Warning 1931 Query execution was interrupted. The query examined at least 2 rows, which exceeds LIMIT ROWS EXAMINED (0). The query result may be incomplete.
Warning 1931 Query execution was interrupted. The query examined at least 1 rows, which exceeds LIMIT ROWS EXAMINED (0). The query result may be incomplete.
select c1, sum(c2) from t3 group by c1 LIMIT ROWS EXAMINED 1;
ERROR HY000: Sort aborted:
c1 sum(c2)
Warnings:
Warning 1931 Query execution was interrupted. The query examined at least 3 rows, which exceeds LIMIT ROWS EXAMINED (1). The query result may be incomplete.
select c1, sum(c2) from t3 group by c1 LIMIT ROWS EXAMINED 20;
c1 sum(c2)
aa 3
@ -496,9 +498,11 @@ id select_type table type possible_keys key key_len ref rows Extra
select c1, sum(c2) from t3i group by c1 LIMIT ROWS EXAMINED 0;
c1 sum(c2)
Warnings:
Warning 1931 Query execution was interrupted. The query examined at least 2 rows, which exceeds LIMIT ROWS EXAMINED (0). The query result may be incomplete.
Warning 1931 Query execution was interrupted. The query examined at least 1 rows, which exceeds LIMIT ROWS EXAMINED (0). The query result may be incomplete.
select c1, sum(c2) from t3i group by c1 LIMIT ROWS EXAMINED 1;
ERROR HY000: Sort aborted:
c1 sum(c2)
Warnings:
Warning 1931 Query execution was interrupted. The query examined at least 3 rows, which exceeds LIMIT ROWS EXAMINED (1). The query result may be incomplete.
select c1, sum(c2) from t3i group by c1 LIMIT ROWS EXAMINED 20;
c1 sum(c2)
aa 3
@ -627,7 +631,7 @@ CREATE TABLE t4 (a int);
INSERT INTO t4 values (1), (2);
INSERT INTO t4 SELECT a + 2 FROM t4 LIMIT ROWS EXAMINED 0;
Warnings:
Warning 1931 Query execution was interrupted. The query examined at least 2 rows, which exceeds LIMIT ROWS EXAMINED (0). The query result may be incomplete.
Warning 1931 Query execution was interrupted. The query examined at least 1 rows, which exceeds LIMIT ROWS EXAMINED (0). The query result may be incomplete.
select * from t4;
a
1
@ -666,7 +670,7 @@ MDEV-115
SET @@optimizer_switch='in_to_exists=on,outer_join_with_cache=on';
CREATE TABLE t1 ( a VARCHAR(3) ) ENGINE=MyISAM;
INSERT INTO t1 VALUES ('USA');
INSERT INTO t1 VALUES ('USA'),('CAN');
CREATE TABLE t2 ( b INT );
INSERT INTO t2 VALUES (3899),(3914),(3888);
CREATE TABLE t3 ( c VARCHAR(33), d INT );
@ -676,8 +680,8 @@ SELECT DISTINCT a AS field1 FROM t1, t2
WHERE EXISTS (SELECT c FROM t3 LEFT JOIN t2 ON b = d)
HAVING field1 > 'aaa' LIMIT ROWS EXAMINED 20;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 system NULL NULL NULL NULL 1 Using temporary
1 PRIMARY t2 ALL NULL NULL NULL NULL 3 Distinct
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using temporary
1 PRIMARY t2 ALL NULL NULL NULL NULL 3 Using join buffer (flat, BNL join)
2 SUBQUERY t3 ALL NULL NULL NULL NULL 3
2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join)
SELECT DISTINCT a AS field1 FROM t1, t2
@ -685,24 +689,27 @@ WHERE EXISTS (SELECT c FROM t3 LEFT JOIN t2 ON b = d)
HAVING field1 > 'aaa' LIMIT ROWS EXAMINED 20;
field1
Warnings:
Warning 1931 Query execution was interrupted. The query examined at least 23 rows, which exceeds LIMIT ROWS EXAMINED (20). The query result may be incomplete.
Warning 1931 Query execution was interrupted. The query examined at least 21 rows, which exceeds LIMIT ROWS EXAMINED (20). The query result may be incomplete.
EXPLAIN
SELECT DISTINCT a FROM t1, t2 HAVING a > ' ' LIMIT ROWS EXAMINED 14;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1 Using temporary
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Distinct
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using temporary
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using join buffer (flat, BNL join)
SELECT DISTINCT a FROM t1, t2 HAVING a > ' ' LIMIT ROWS EXAMINED 14;
a
USA
Warnings:
Warning 1931 Query execution was interrupted. The query examined at least 15 rows, which exceeds LIMIT ROWS EXAMINED (14). The query result may be incomplete.
SELECT DISTINCT a FROM t1, t2 HAVING a > ' ' LIMIT ROWS EXAMINED 15;
a
USA
CAN
Warnings:
Warning 1931 Query execution was interrupted. The query examined at least 16 rows, which exceeds LIMIT ROWS EXAMINED (15). The query result may be incomplete.
SELECT DISTINCT a FROM t1, t2 HAVING a > ' ' LIMIT ROWS EXAMINED 16;
a
USA
CAN
Warnings:
Warning 1931 Query execution was interrupted. The query examined at least 17 rows, which exceeds LIMIT ROWS EXAMINED (16). The query result may be incomplete.
drop table t1,t2,t3;

View File

@ -523,11 +523,11 @@ a
explain select sql_big_result distinct t1.a from t1,t2 order by t2.a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1 Using temporary
1 SIMPLE t2 index NULL PRIMARY 4 NULL 2 Using index; Distinct
1 SIMPLE t2 index NULL PRIMARY 4 NULL 2 Using index
explain select distinct t1.a from t1,t2 order by t2.a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1 Using temporary
1 SIMPLE t2 index NULL PRIMARY 4 NULL 2 Using index; Distinct
1 SIMPLE t2 index NULL PRIMARY 4 NULL 2 Using index
drop table t1,t2;
create table t1 (
c1 varchar(32),

View File

@ -83,20 +83,20 @@ UNIQUE KEY e_n (email,name)
);
EXPLAIN SELECT SQL_CALC_FOUND_ROWS DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL LIMIT 10;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system PRIMARY,kid NULL NULL NULL 0 const row not found
1 SIMPLE t2 index NULL e_n 104 NULL 10
1 SIMPLE t1 system PRIMARY,kid NULL NULL NULL 0 const row not found; Using temporary
1 SIMPLE t2 ALL NULL NULL NULL NULL 200
SELECT SQL_CALC_FOUND_ROWS DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL LIMIT 10;
email
email1
email2
email3
email4
email5
email6
email7
email8
email9
email10
email100
email101
email102
email103
email104
email105
email106
email107
SELECT FOUND_ROWS();
FOUND_ROWS()
200

View File

@ -1044,7 +1044,7 @@ set debug_dbug='+d,show_explain_probe_do_select';
SELECT b AS field1, b AS field2 FROM t1, t2, t3 WHERE d = b ORDER BY field1, field2;
show explain for $thr2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 system NULL NULL NULL NULL 1 Using filesort
1 SIMPLE t2 system NULL NULL NULL NULL 1
1 SIMPLE t1 range b b 6 NULL 107 Using where; Using index
1 SIMPLE t3 ref PRIMARY PRIMARY 5 test.t1.b 1 Using index
Warnings:

View File

@ -19,7 +19,7 @@ SELECT 1 FROM t1
WHERE NOT EXISTS (SELECT 1 FROM t2 WHERE 1 = (SELECT MIN(t2.b) FROM t3))
ORDER BY count(*);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 index NULL a 5 NULL 2 Using where; Using index; Using temporary
1 PRIMARY t1 index NULL a 5 NULL 2 Using where; Using index
2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using where
3 DEPENDENT SUBQUERY t3 system NULL NULL NULL NULL 0 const row not found
# should not crash the next statement

View File

@ -996,8 +996,33 @@ EXPLAIN SELECT a FROM t1 WHERE a < 2 ORDER BY a;
EXPLAIN SELECT a FROM t1 WHERE a < 2 GROUP BY a;
EXPLAIN SELECT a FROM t1 IGNORE INDEX (PRIMARY,i2);
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR JOIN (PRIMARY,i2);
--echo #
--echo # For this explain, the query plan is weird: if we are using
--echo # the primary key for reasons other than doing grouping, can't
--echo # GROUP BY code take advantage of this? Well, currently it doesnt:
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR GROUP BY (PRIMARY,i2) GROUP BY a;
--echo # Here's a proof it is really doing sorting:
flush status;
--disable_result_log
SELECT a FROM t1 IGNORE INDEX FOR GROUP BY (PRIMARY,i2) GROUP BY a;
--enable_result_log
show status like 'Sort_%';
--echo # Proof ends.
--echo #
--echo # For this explain, the query plan is weird: if we are using
--echo # the primary key for reasons other than doing sorting, can't
--echo # ORDER BY code take advantage of this? Well, currently it doesnt:
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR ORDER BY (PRIMARY,i2) ORDER BY a;
--echo # Here's a proof it is really doing sorting:
flush status;
--disable_result_log
SELECT a FROM t1 IGNORE INDEX FOR ORDER BY (PRIMARY,i2) ORDER BY a;
--enable_result_log
show status like 'Sort_%';
--echo # Proof ends.
--echo #
SELECT a FROM t1 IGNORE INDEX FOR ORDER BY (PRIMARY,i2) ORDER BY a;
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR ORDER BY (PRIMARY)
IGNORE INDEX FOR GROUP BY (i2) GROUP BY a;

View File

@ -305,7 +305,6 @@ select c1, sum(c2) from t3 group by c1;
explain
select c1, sum(c2) from t3 group by c1 LIMIT ROWS EXAMINED 0;
select c1, sum(c2) from t3 group by c1 LIMIT ROWS EXAMINED 0;
--error 1028
select c1, sum(c2) from t3 group by c1 LIMIT ROWS EXAMINED 1;
select c1, sum(c2) from t3 group by c1 LIMIT ROWS EXAMINED 20;
select c1, sum(c2) from t3 group by c1 LIMIT ROWS EXAMINED 21;
@ -321,7 +320,6 @@ insert into t3i values
explain
select c1, sum(c2) from t3i group by c1 LIMIT ROWS EXAMINED 0;
select c1, sum(c2) from t3i group by c1 LIMIT ROWS EXAMINED 0;
--error 1028
select c1, sum(c2) from t3i group by c1 LIMIT ROWS EXAMINED 1;
select c1, sum(c2) from t3i group by c1 LIMIT ROWS EXAMINED 20;
select c1, sum(c2) from t3i group by c1 LIMIT ROWS EXAMINED 21;
@ -432,7 +430,7 @@ drop table t1,t2,t1i,t2i;
SET @@optimizer_switch='in_to_exists=on,outer_join_with_cache=on';
CREATE TABLE t1 ( a VARCHAR(3) ) ENGINE=MyISAM;
INSERT INTO t1 VALUES ('USA');
INSERT INTO t1 VALUES ('USA'),('CAN');
CREATE TABLE t2 ( b INT );
INSERT INTO t2 VALUES (3899),(3914),(3888);

View File

@ -120,15 +120,16 @@ void Sort_param::init_for_filesort(uint sortlen, TABLE *table,
@param thd Current thread
@param table Table to sort
@param sortorder How to sort the table
@param s_length Number of elements in sortorder
@param select Condition to apply to the rows
@param max_rows Return only this many rows
@param filesort How to sort the table
@param sort_positions Set to TRUE if we want to force sorting by position
(Needed by UPDATE/INSERT or ALTER TABLE or
when rowids are required by executor)
@param[out] examined_rows Store number of examined rows here
@param[out] found_rows Store the number of found rows here
This is the number of found rows before
applying WHERE condition.
@param[out] found_rows Store the number of found rows here.
This is the number of found rows after
applying WHERE condition.
@note
If we sort by position (like if sort_positions is 1) filesort() will
@ -140,12 +141,9 @@ void Sort_param::init_for_filesort(uint sortlen, TABLE *table,
\# Number of rows
*/
ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
SQL_SELECT *select, ha_rows max_rows,
bool sort_positions,
ha_rows *examined_rows,
ha_rows *found_rows,
Filesort_tracker* tracker)
ha_rows filesort(THD *thd, TABLE *table, Filesort *filesort,
bool sort_positions, ha_rows *examined_rows,
ha_rows *found_rows, Filesort_tracker* tracker)
{
int error;
size_t memory_available= thd->variables.sortbuff_size;
@ -156,9 +154,16 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
Sort_param param;
bool multi_byte_charset;
Bounded_queue<uchar, uchar> pq;
SQL_SELECT *const select= filesort->select;
ha_rows max_rows= filesort->limit;
uint s_length= 0;
DBUG_ENTER("filesort");
DBUG_EXECUTE("info",TEST_filesort(sortorder,s_length););
if (!(s_length= filesort->make_sortorder(thd)))
DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
DBUG_EXECUTE("info",TEST_filesort(filesort->sortorder,s_length););
#ifdef SKIP_DBUG_IN_FILESORT
DBUG_PUSH(""); /* No DBUG here */
#endif
@ -190,7 +195,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
error= 1;
*found_rows= HA_POS_ERROR;
param.init_for_filesort(sortlength(thd, sortorder, s_length,
param.init_for_filesort(sortlength(thd, filesort->sortorder, s_length,
&multi_byte_charset),
table,
thd->variables.max_length_for_sort_data,
@ -292,7 +297,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
goto err;
param.sort_form= table;
param.end=(param.local_sortorder=sortorder)+s_length;
param.end=(param.local_sortorder=filesort->sortorder)+s_length;
num_rows= find_all_keys(thd, &param, select,
&table_sort,
&buffpek_pointers,
@ -470,6 +475,55 @@ void filesort_free_buffers(TABLE *table, bool full)
}
void Filesort::cleanup()
{
if (select && own_select)
{
select->cleanup();
select= NULL;
}
}
uint Filesort::make_sortorder(THD *thd)
{
uint count;
SORT_FIELD *sort,*pos;
ORDER *ord;
DBUG_ENTER("make_sortorder");
count=0;
for (ord = order; ord; ord= ord->next)
count++;
if (!sortorder)
sortorder= (SORT_FIELD*) thd->alloc(sizeof(SORT_FIELD) * (count + 1));
pos= sort= sortorder;
if (!pos)
DBUG_RETURN(0);
for (ord= order; ord; ord= ord->next, pos++)
{
Item *item= ord->item[0]->real_item();
pos->field= 0; pos->item= 0;
if (item->type() == Item::FIELD_ITEM)
pos->field= ((Item_field*) item)->field;
else if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item())
pos->field= ((Item_sum*) item)->get_tmp_table_field();
else if (item->type() == Item::COPY_STR_ITEM)
{ // Blob patch
pos->item= ((Item_copy*) item)->get_item();
}
else
pos->item= *ord->item;
pos->reverse= (ord->direction == ORDER::ORDER_DESC);
DBUG_ASSERT(pos->field != NULL || pos->item != NULL);
}
DBUG_RETURN(count);
}
/** Read 'count' number of buffer pointers into memory. */
static uchar *read_buffpek_from_file(IO_CACHE *buffpek_pointers, uint count,

View File

@ -20,18 +20,58 @@ class SQL_SELECT;
#include "my_global.h" /* uint, uchar */
#include "my_base.h" /* ha_rows */
#include "sql_list.h" /* Sql_alloc */
class SQL_SELECT;
class THD;
struct TABLE;
struct SORT_FIELD;
class Filesort_tracker;
struct SORT_FIELD;
typedef struct st_order ORDER;
ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder,
uint s_length, SQL_SELECT *select,
ha_rows max_rows, bool sort_positions,
ha_rows *examined_rows, ha_rows *found_rows,
Filesort_tracker* tracker);
/**
Sorting related info.
To be extended by another WL to include complete filesort implementation.
*/
class Filesort: public Sql_alloc
{
public:
/** List of expressions to order the table by */
ORDER *order;
/** Number of records to return */
ha_rows limit;
/** ORDER BY list with some precalculated info for filesort */
SORT_FIELD *sortorder;
/** select to use for getting records */
SQL_SELECT *select;
/** TRUE <=> free select on destruction */
bool own_select;
/** true means we are using Priority Queue for order by with limit. */
bool using_pq;
Filesort(ORDER *order_arg, ha_rows limit_arg, SQL_SELECT *select_arg):
order(order_arg),
limit(limit_arg),
sortorder(NULL),
select(select_arg),
own_select(false),
using_pq(false)
{
DBUG_ASSERT(order);
};
~Filesort() { cleanup(); }
/* Prepare ORDER BY list for sorting. */
uint make_sortorder(THD *thd);
private:
void cleanup();
};
ha_rows filesort(THD *thd, TABLE *table, Filesort *filesort,
bool sort_positions, ha_rows *examined_rows,
ha_rows *found_rows, Filesort_tracker* tracker);
void filesort_free_buffers(TABLE *table, bool full);
void change_double_for_sort(double nr,uchar *to);

View File

@ -1733,7 +1733,7 @@ public:
thd->fatal_error() may be called if we are out of memory
*/
void Item::split_sum_func2(THD *thd, Item **ref_pointer_array,
void Item::split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array,
List<Item> &fields, Item **ref,
uint split_flags)
{
@ -1797,7 +1797,7 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array,
if (!(item_ref= (new (thd->mem_root)
Item_aggregate_ref(thd,
&thd->lex->current_select->context,
ref_pointer_array + el, 0, name))))
&ref_pointer_array[el], 0, name))))
return; // fatal_error is set
if (type() == SUM_FUNC_ITEM)
item_ref->depended_from= ((Item_sum *) this)->depended_from();
@ -3738,16 +3738,18 @@ Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it)
str_value.charset());
collation.set(str_value.charset(), DERIVATION_COERCIBLE);
decimals= 0;
item_type= Item::STRING_ITEM;
break;
}
case REAL_RESULT:
set_double(arg->val_real());
item_type= Item::REAL_ITEM;
break;
case INT_RESULT:
set_int(arg->val_int(), arg->max_length);
item_type= Item::INT_ITEM;
break;
case DECIMAL_RESULT:
@ -3759,6 +3761,7 @@ Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it)
return TRUE;
set_decimal(dv);
item_type= Item::DECIMAL_ITEM;
break;
}
@ -3768,11 +3771,11 @@ Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it)
DBUG_ASSERT(TRUE); // Abort in debug mode.
set_null(); // Set to NULL in release mode.
item_type= Item::NULL_ITEM;
return FALSE;
}
set_handler_by_result_type(arg->result_type());
item_type= arg->type();
return FALSE;
}
@ -4472,7 +4475,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
return NULL;
}
DBUG_ASSERT((*select_ref)->fixed);
return (select->ref_pointer_array + counter);
return &select->ref_pointer_array[counter];
}
if (group_by_ref)
return group_by_ref;
@ -6499,15 +6502,14 @@ Item *Item_field::update_value_transformer(THD *thd, uchar *select_arg)
type() != Item::TRIGGER_FIELD_ITEM)
{
List<Item> *all_fields= &select->join->all_fields;
Item **ref_pointer_array= select->ref_pointer_array;
DBUG_ASSERT(all_fields->elements <= select->ref_pointer_array_size);
Ref_ptr_array &ref_pointer_array= select->ref_pointer_array;
int el= all_fields->elements;
Item_ref *ref;
ref_pointer_array[el]= (Item*)this;
all_fields->push_front((Item*)this, thd->mem_root);
ref= new (thd->mem_root)
Item_ref(thd, &select->context, ref_pointer_array + el,
Item_ref(thd, &select->context, &ref_pointer_array[el],
table_name, field_name);
return ref;
}

View File

@ -65,6 +65,8 @@ class RANGE_OPT_PARAM;
class SEL_TREE;
typedef Bounds_checked_array<Item*> Ref_ptr_array;
static inline uint32
char_to_byte_length_safe(uint32 char_length_arg, uint32 mbmaxlen_arg)
{
@ -1182,7 +1184,7 @@ public:
void print_item_w_name(String *, enum_query_type query_type);
void print_value(String *);
virtual void update_used_tables() {}
virtual COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
virtual COND *build_equal_items(THD *thd, COND_EQUAL *inheited,
bool link_item_fields,
COND_EQUAL **cond_equal_ref)
{
@ -1218,10 +1220,11 @@ public:
{
return false;
}
virtual void split_sum_func(THD *thd, Item **ref_pointer_array,
virtual void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array,
List<Item> &fields, uint flags) {}
/* Called for items that really have to be split */
void split_sum_func2(THD *thd, Item **ref_pointer_array, List<Item> &fields,
void split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array,
List<Item> &fields,
Item **ref, uint flags);
virtual bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
bool get_time(MYSQL_TIME *ltime)

View File

@ -4634,7 +4634,7 @@ void Item_cond::traverse_cond(Cond_traverser traverser,
that have or refer (HAVING) to a SUM expression.
*/
void Item_cond::split_sum_func(THD *thd, Item **ref_pointer_array,
void Item_cond::split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array,
List<Item> &fields, uint flags)
{
List_iterator<Item> li(list);

View File

@ -2003,8 +2003,8 @@ public:
SARGABLE_PARAM **sargables);
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
virtual void print(String *str, enum_query_type query_type);
void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields,
uint flags);
void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array,
List<Item> &fields, uint flags);
friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
COND **conds);
void top_level_item() { abort_on_null=1; }
@ -2031,7 +2031,7 @@ template <template<class> class LI, class T> class Item_equal_iterator;
All equality predicates of the form field1=field2 contained in a
conjunction are substituted for a sequence of items of this class.
An item of this class Item_equal(f1,f2,...fk) represents a
multiple equality f1=f2=...=fk.
multiple equality f1=f2=...=fk.l
If a conjunction contains predicates f1=f2 and f2=f3, a new item of
this class is created Item_equal(f1,f2,f3) representing the multiple

View File

@ -431,7 +431,7 @@ void Item_args::propagate_equal_fields(THD *thd,
See comments in Item_cond::split_sum_func()
*/
void Item_func::split_sum_func(THD *thd, Item **ref_pointer_array,
void Item_func::split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array,
List<Item> &fields, uint flags)
{
Item **arg, **arg_end;
@ -4902,9 +4902,16 @@ Item_func_set_user_var::update_hash(void *ptr, uint length,
If we set a variable explicitely to NULL then keep the old
result type of the variable
*/
if ((null_value= args[0]->null_value) && null_item)
if (args[0]->type() == Item::FIELD_ITEM)
{
/* args[0]->null_value may be outdated */
null_value= ((Item_field*)args[0])->field->is_null();
}
else
null_value= args[0]->null_value;
if (null_value && null_item)
res_type= m_var_entry->type; // Don't change type of item
if (::update_hash(m_var_entry, (null_value= args[0]->null_value),
if (::update_hash(m_var_entry, null_value,
ptr, length, res_type, cs, unsigned_arg))
{
null_value= 1;

View File

@ -143,8 +143,8 @@ public:
sync_with_sum_func_and_with_field(list);
list.empty(); // Fields are used
}
void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields,
uint flags);
void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array,
List<Item> &fields, uint flags);
virtual void print(String *str, enum_query_type query_type);
void print_op(String *str, enum_query_type query_type);
void print_args(String *str, uint from, enum_query_type query_type);

View File

@ -100,7 +100,7 @@ void Item_row::cleanup()
}
void Item_row::split_sum_func(THD *thd, Item **ref_pointer_array,
void Item_row::split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array,
List<Item> &fields, uint flags)
{
Item **arg, **arg_end;

View File

@ -76,8 +76,8 @@ public:
bool fix_fields(THD *thd, Item **ref);
void fix_after_pullout(st_select_lex *new_parent, Item **ref);
void cleanup();
void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields,
uint flags);
void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array,
List<Item> &fields, uint flags);
table_map used_tables() const { return used_tables_cache; };
bool const_item() const { return const_item_cache; };
enum Item_result result_type() const { return ROW_RESULT; }

View File

@ -734,7 +734,7 @@ int Item_in_subselect::optimize(double *out_rows, double *cost)
}
/* Now with grouping */
if (join->group_list)
if (join->group_list_for_estimates)
{
DBUG_PRINT("info",("Materialized join has grouping, trying to estimate it"));
double output_rows= get_post_group_estimate(join, *out_rows);
@ -1891,7 +1891,8 @@ bool Item_allany_subselect::transform_into_max_min(JOIN *join)
(ALL && (> || =>)) || (ANY && (< || =<))
for ALL condition is inverted
*/
item= new (thd->mem_root) Item_sum_max(thd, *select_lex->ref_pointer_array);
item= new (thd->mem_root) Item_sum_max(thd,
select_lex->ref_pointer_array[0]);
}
else
{
@ -1899,11 +1900,12 @@ bool Item_allany_subselect::transform_into_max_min(JOIN *join)
(ALL && (< || =<)) || (ANY && (> || =>))
for ALL condition is inverted
*/
item= new (thd->mem_root) Item_sum_min(thd, *select_lex->ref_pointer_array);
item= new (thd->mem_root) Item_sum_min(thd,
select_lex->ref_pointer_array[0]);
}
if (upper_item)
upper_item->set_sum_test(item);
thd->change_item_tree(select_lex->ref_pointer_array, item);
thd->change_item_tree(&select_lex->ref_pointer_array[0], item);
{
List_iterator<Item> it(select_lex->item_list);
it++;
@ -2049,8 +2051,8 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
thd,
&select_lex->context,
this,
select_lex->
ref_pointer_array,
&select_lex->
ref_pointer_array[0],
(char *)"<ref>",
this->full_name()));
if (!abort_on_null && left_expr->maybe_null)
@ -2125,7 +2127,7 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
new (thd->mem_root) Item_ref_null_helper(thd,
&select_lex->context,
this,
select_lex->ref_pointer_array,
&select_lex->ref_pointer_array[0],
(char *)"<no matter>",
(char *)"<result>"));
if (!abort_on_null && left_expr->maybe_null)
@ -2312,7 +2314,7 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
(char *)in_left_expr_name),
new (thd->mem_root)
Item_ref(thd, &select_lex->context,
select_lex->ref_pointer_array + i,
&select_lex->ref_pointer_array[i],
(char *)"<no matter>",
(char *)"<list ref>"));
Item *item_isnull=
@ -2320,7 +2322,7 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
Item_func_isnull(thd,
new (thd->mem_root)
Item_ref(thd, &select_lex->context,
select_lex->ref_pointer_array+i,
&select_lex->ref_pointer_array[i],
(char *)"<no matter>",
(char *)"<list ref>"));
Item *col_item= new (thd->mem_root)
@ -2338,8 +2340,8 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
Item_is_not_null_test(thd, this,
new (thd->mem_root)
Item_ref(thd, &select_lex->context,
select_lex->
ref_pointer_array + i,
&select_lex->
ref_pointer_array[i],
(char *)"<no matter>",
(char *)"<list ref>"));
if (!abort_on_null && left_expr->element_index(i)->maybe_null)
@ -2377,8 +2379,8 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
(char *)in_left_expr_name),
new (thd->mem_root)
Item_direct_ref(thd, &select_lex->context,
select_lex->
ref_pointer_array+i,
&select_lex->
ref_pointer_array[i],
(char *)"<no matter>",
(char *)"<list ref>"));
if (!abort_on_null && select_lex->ref_pointer_array[i]->maybe_null)
@ -2388,7 +2390,7 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
Item_is_not_null_test(thd, this,
new (thd->mem_root)
Item_ref(thd, &select_lex->context,
select_lex->ref_pointer_array + i,
&select_lex->ref_pointer_array[i],
(char *)"<no matter>",
(char *)"<list ref>"));
@ -2397,8 +2399,8 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
Item_func_isnull(thd,
new (thd->mem_root)
Item_direct_ref(thd, &select_lex->context,
select_lex->
ref_pointer_array+i,
&select_lex->
ref_pointer_array[i],
(char *)"<no matter>",
(char *)"<list ref>"));
item= new (thd->mem_root) Item_cond_or(thd, item, item_isnull);
@ -3528,8 +3530,7 @@ int subselect_single_select_engine::prepare()
prepared= 1;
SELECT_LEX *save_select= thd->lex->current_select;
thd->lex->current_select= select_lex;
if (join->prepare(&select_lex->ref_pointer_array,
select_lex->table_list.first,
if (join->prepare(select_lex->table_list.first,
select_lex->with_wild,
select_lex->where,
select_lex->order_list.elements +
@ -3678,14 +3679,6 @@ int subselect_single_select_engine::exec()
*/
select_lex->uncacheable|= UNCACHEABLE_EXPLAIN;
select_lex->master_unit()->uncacheable|= UNCACHEABLE_EXPLAIN;
/*
Force join->join_tmp creation, because this subquery will be replaced
by a simple select from the materialization temp table by optimize()
called by EXPLAIN and we need to preserve the initial query structure
so we can display it.
*/
if (join->need_tmp && join->init_save_join_tab())
DBUG_RETURN(1); /* purecov: inspected */
}
}
if (item->engine_changed(this))
@ -5226,7 +5219,7 @@ double get_post_group_estimate(JOIN* join, double join_op_rows)
table_map tables_in_group_list= table_map(0);
/* Find out which tables are used in GROUP BY list */
for (ORDER *order= join->group_list; order; order= order->next)
for (ORDER *order= join->group_list_for_estimates; order; order= order->next)
{
Item *item= order->item[0];
table_map item_used_tables= item->used_tables();

View File

@ -2898,7 +2898,7 @@ int group_concat_key_cmp_with_order(void* arg, const void* key1,
field->table->s->null_bytes);
int res= field->cmp((uchar*)key1 + offset, (uchar*)key2 + offset);
if (res)
return (*order_item)->asc ? res : -res;
return ((*order_item)->direction == ORDER::ORDER_ASC) ? res : -res;
}
/*
We can't return 0 because in that case the tree class would remove this
@ -3367,8 +3367,8 @@ bool Item_func_group_concat::setup(THD *thd)
if (!ref_pointer_array)
DBUG_RETURN(TRUE);
memcpy(ref_pointer_array, args, arg_count * sizeof(Item*));
if (setup_order(thd, ref_pointer_array, context->table_list, list,
all_fields, *order))
if (setup_order(thd, Ref_ptr_array(ref_pointer_array, n_elems),
context->table_list, list, all_fields, *order))
DBUG_RETURN(TRUE);
}
@ -3494,9 +3494,9 @@ void Item_func_group_concat::print(String *str, enum_query_type query_type)
if (i)
str->append(',');
orig_args[i + arg_count_field]->print(str, query_type);
if (order[i]->asc)
if (order[i]->direction == ORDER::ORDER_ASC)
str->append(STRING_WITH_LEN(" ASC"));
else
else
str->append(STRING_WITH_LEN(" DESC"));
}
}

View File

@ -1531,7 +1531,7 @@ end:
if (!head->no_keyread)
{
doing_key_read= 1;
head->enable_keyread();
head->set_keyread(true);
}
head->prepare_for_position();
@ -10647,7 +10647,7 @@ int read_keys_and_merge_scans(THD *thd,
if (!head->key_read)
{
enabled_keyread= 1;
head->enable_keyread();
head->set_keyread(true);
}
head->prepare_for_position();
@ -10741,14 +10741,14 @@ int read_keys_and_merge_scans(THD *thd,
index merge currently doesn't support "using index" at all
*/
if (enabled_keyread)
head->disable_keyread();
head->set_keyread(false);
if (init_read_record(read_record, thd, head, (SQL_SELECT*) 0, 1 , 1, TRUE))
result= 1;
DBUG_RETURN(result);
err:
if (enabled_keyread)
head->disable_keyread();
head->set_keyread(false);
DBUG_RETURN(1);
}
@ -12074,9 +12074,6 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time)
DBUG_RETURN(NULL); /* Cannot execute with correlated conditions. */
/* Check (SA1,SA4) and store the only MIN/MAX argument - the C attribute.*/
if (join->make_sum_func_list(join->all_fields, join->fields_list, 1))
DBUG_RETURN(NULL);
List_iterator<Item> select_items_it(join->fields_list);
is_agg_distinct = is_indexed_agg_distinct(join, &agg_distinct_flds);
@ -13459,7 +13456,7 @@ QUICK_GROUP_MIN_MAX_SELECT::~QUICK_GROUP_MIN_MAX_SELECT()
{
DBUG_ASSERT(file == head->file);
if (doing_key_read)
head->disable_keyread();
head->set_keyread(false);
/*
There may be a code path when the same table was first accessed by index,
then the index is closed, and the table is scanned (order by + loose scan).
@ -13652,7 +13649,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::reset(void)
if (!head->key_read)
{
doing_key_read= 1;
head->enable_keyread(); /* We need only the key attributes */
head->set_keyread(true); /* We need only the key attributes */
}
if ((result= file->ha_index_init(index,1)))
{

View File

@ -445,7 +445,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred);
static bool convert_subq_to_jtbm(JOIN *parent_join,
Item_in_subselect *subq_pred, bool *remove);
static TABLE_LIST *alloc_join_nest(THD *thd);
static uint get_tmp_table_rec_length(Item **p_list, uint elements);
static uint get_tmp_table_rec_length(Ref_ptr_array p_list, uint elements);
static double get_tmp_table_lookup_cost(THD *thd, double row_count,
uint row_size);
static double get_tmp_table_write_cost(THD *thd, double row_count,
@ -2225,13 +2225,9 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map)
JOIN_TAB *tab= join->best_positions[i].table;
join->map2table[tab->table->tablenr]= tab;
}
//List_iterator<Item> it(right_expr_list);
Item **ref_array= subq_select->ref_pointer_array;
Item **ref_array_end= ref_array + subq_select->item_list.elements;
table_map map= 0;
//while ((item= it++))
for (;ref_array < ref_array_end; ref_array++)
map |= (*ref_array)->used_tables();
for (uint i=0; i < subq_select->item_list.elements; i++)
map|= subq_select->ref_pointer_array[i]->used_tables();
map= map & ~PSEUDO_TABLE_BITS;
Table_map_iterator tm_it(map);
int tableno;
@ -2294,15 +2290,14 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map)
Length of the temptable record, in bytes
*/
static uint get_tmp_table_rec_length(Item **p_items, uint elements)
static uint get_tmp_table_rec_length(Ref_ptr_array p_items, uint elements)
{
uint len= 0;
Item *item;
//List_iterator<Item> it(items);
Item **p_item;
for (p_item= p_items; p_item < p_items + elements ; p_item++)
for (uint i= 0; i < elements ; i++)
{
item = *p_item;
item = p_items[i];
switch (item->result_type()) {
case REAL_RESULT:
len += sizeof(double);
@ -3551,13 +3546,10 @@ bool setup_sj_materialization_part1(JOIN_TAB *sjm_tab)
*/
sjm->sjm_table_param.init();
sjm->sjm_table_param.bit_fields_as_long= TRUE;
//List_iterator<Item> it(item_list);
SELECT_LEX *subq_select= emb_sj_nest->sj_subq_pred->unit->first_select();
Item **p_item= subq_select->ref_pointer_array;
Item **p_end= p_item + subq_select->item_list.elements;
//while((right_expr= it++))
for(;p_item != p_end; p_item++)
sjm->sjm_table_cols.push_back(*p_item, thd->mem_root);
Ref_ptr_array p_items= subq_select->ref_pointer_array;
for (uint i= 0; i < subq_select->item_list.elements; i++)
sjm->sjm_table_cols.push_back(p_items[i], thd->mem_root);
sjm->sjm_table_param.field_count= subq_select->item_list.elements;
sjm->sjm_table_param.force_not_null_cols= TRUE;
@ -3713,13 +3705,13 @@ bool setup_sj_materialization_part2(JOIN_TAB *sjm_tab)
*/
sjm->copy_field= new Copy_field[sjm->sjm_table_cols.elements];
//it.rewind();
Item **p_item= emb_sj_nest->sj_subq_pred->unit->first_select()->ref_pointer_array;
Ref_ptr_array p_items= emb_sj_nest->sj_subq_pred->unit->first_select()->ref_pointer_array;
for (uint i=0; i < sjm->sjm_table_cols.elements; i++)
{
bool dummy;
Item_equal *item_eq;
//Item *item= (it++)->real_item();
Item *item= (*(p_item++))->real_item();
Item *item= p_items[i]->real_item();
DBUG_ASSERT(item->type() == Item::FIELD_ITEM);
Field *copy_to= ((Item_field*)item)->field;
/*
@ -5593,7 +5585,7 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
*/
/* C.1 Compute the cost of the materialization strategy. */
//uint rowlen= get_tmp_table_rec_length(unit->first_select()->item_list);
uint rowlen= get_tmp_table_rec_length(ref_pointer_array,
uint rowlen= get_tmp_table_rec_length(ref_ptrs,
select_lex->item_list.elements);
/* The cost of writing one row into the temporary table. */
double write_cost= get_tmp_table_write_cost(thd, inner_record_count_1,

View File

@ -406,7 +406,7 @@ int opt_sum_query(THD *thd,
if (!error && reckey_in_range(is_max, &ref, item_field->field,
conds, range_fl, prefix_len))
error= HA_ERR_KEY_NOT_FOUND;
table->disable_keyread();
table->set_keyread(false);
table->file->ha_index_end();
if (error)
{
@ -968,7 +968,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
converted (for example to upper case)
*/
if (field->part_of_key.is_set(idx))
table->enable_keyread();
table->set_keyread(true);
DBUG_RETURN(TRUE);
}
}

View File

@ -312,7 +312,7 @@ void end_read_record(READ_RECORD *info)
if (info->table)
{
filesort_free_buffers(info->table,0);
if (info->table->created)
if (info->table->is_created())
(void) info->table->file->extra(HA_EXTRA_NO_CACHE);
if (info->read_record != rr_quick) // otherwise quick_range does it
(void) info->table->file->ha_index_or_rnd_end();

View File

@ -85,6 +85,15 @@ public:
Element_type *array() const { return m_array; }
bool operator==(const Bounds_checked_array<Element_type>&rhs) const
{
return m_array == rhs.m_array && m_size == rhs.m_size;
}
bool operator!=(const Bounds_checked_array<Element_type>&rhs) const
{
return m_array != rhs.m_array || m_size != rhs.m_size;
}
private:
Element_type *m_array;
size_t m_size;

View File

@ -7809,11 +7809,13 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
List<Item> *sum_func_list,
uint wild_num)
{
if (!wild_num)
return(0);
Item *item;
List_iterator<Item> it(fields);
Query_arena *arena, backup;
DBUG_ENTER("setup_wild");
DBUG_ASSERT(wild_num != 0);
/*
Don't use arena if we are not in prepared statements or stored procedures
@ -7892,7 +7894,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
** Check that all given fields exists and fill struct with current data
****************************************************************************/
bool setup_fields(THD *thd, Item **ref_pointer_array,
bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array,
List<Item> &fields, enum_mark_columns mark_used_columns,
List<Item> *sum_func_list, bool allow_sum_func)
{
@ -7924,8 +7926,11 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
TODO: remove it when (if) we made one list for allfields and
ref_pointer_array
*/
if (ref_pointer_array)
bzero(ref_pointer_array, sizeof(Item *) * fields.elements);
if (!ref_pointer_array.is_null())
{
DBUG_ASSERT(ref_pointer_array.size() >= fields.elements);
memset(ref_pointer_array.array(), 0, sizeof(Item *) * fields.elements);
}
/*
We call set_entry() there (before fix_fields() of the whole list of field
@ -7943,7 +7948,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
while ((var= li++))
var->set_entry(thd, FALSE);
Item **ref= ref_pointer_array;
Ref_ptr_array ref= ref_pointer_array;
thd->lex->current_select->cur_pos_in_select_list= 0;
while ((item= it++))
{
@ -7956,12 +7961,16 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
DBUG_RETURN(TRUE); /* purecov: inspected */
}
if (ref)
*(ref++)= item;
if (!ref.is_null())
{
ref[0]= item;
ref.pop_front();
}
if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM &&
sum_func_list)
item->split_sum_func(thd, ref_pointer_array, *sum_func_list,
SPLIT_SUM_SELECT);
thd->lex->current_select->select_list_tables|= item->used_tables();
thd->lex->used_tables|= item->used_tables();
thd->lex->current_select->cur_pos_in_select_list++;
}
@ -8380,7 +8389,10 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
views and natural joins this update is performed inside the loop below.
*/
if (table)
{
thd->lex->used_tables|= table->map;
thd->lex->current_select->select_list_tables|= table->map;
}
/*
Initialize a generic field iterator for the current table reference.
@ -8472,6 +8484,8 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
if (field_table)
{
thd->lex->used_tables|= field_table->map;
thd->lex->current_select->select_list_tables|=
field_table->map;
field_table->covering_keys.intersect(field->part_of_key);
field_table->merge_keys.merge(field->part_of_key);
field_table->used_fields++;

View File

@ -168,7 +168,7 @@ void make_leaves_list(THD *thd, List<TABLE_LIST> &list, TABLE_LIST *tables,
bool full_table_list, TABLE_LIST *boundary);
int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
List<Item> *sum_func_list, uint wild_num);
bool setup_fields(THD *thd, Item** ref_pointer_array,
bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array,
List<Item> &item, enum_mark_columns mark_used_columns,
List<Item> *sum_func_list, bool allow_sum_func);
void unfix_fields(List<Item> &items);
@ -392,7 +392,7 @@ inline TABLE_LIST *find_table_in_local_list(TABLE_LIST *table,
}
inline bool setup_fields_with_no_wrap(THD *thd, Item **ref_pointer_array,
inline bool setup_fields_with_no_wrap(THD *thd, Ref_ptr_array ref_pointer_array,
List<Item> &item,
enum_mark_columns mark_used_columns,
List<Item> *sum_func_list,

View File

@ -4474,16 +4474,9 @@ public:
class TMP_TABLE_PARAM :public Sql_alloc
{
private:
/* Prevent use of these (not safe because of lists and copy_field) */
TMP_TABLE_PARAM(const TMP_TABLE_PARAM &);
void operator=(TMP_TABLE_PARAM &);
public:
List<Item> copy_funcs;
List<Item> save_copy_funcs;
Copy_field *copy_field, *copy_field_end;
Copy_field *save_copy_field, *save_copy_field_end;
uchar *group_buff;
Item **items_to_copy; /* Fields in tmp table */
TMP_ENGINE_COLUMNDEF *recinfo, *start_recinfo;
@ -4518,9 +4511,15 @@ public:
uint hidden_field_count;
uint group_parts,group_length,group_null_parts;
uint quick_group;
bool using_indirect_summary_function;
/* If >0 convert all blob fields to varchar(convert_blob_length) */
uint convert_blob_length;
/**
Enabled when we have atleast one outer_sum_func. Needed when used
along with distinct.
@see create_tmp_table
*/
bool using_outer_summary_function;
CHARSET_INFO *table_charset;
bool schema_table;
/* TRUE if the temp table is created for subquery materialization. */
@ -4550,9 +4549,10 @@ public:
TMP_TABLE_PARAM()
:copy_field(0), group_parts(0),
group_length(0), group_null_parts(0), convert_blob_length(0),
schema_table(0), materialized_subquery(0), force_not_null_cols(0),
precomputed_group_by(0),
force_copy_fields(0), bit_fields_as_long(0), skip_create_table(0)
using_outer_summary_function(0),
schema_table(0), materialized_subquery(0), force_not_null_cols(0),
precomputed_group_by(0),
force_copy_fields(0), bit_fields_as_long(0), skip_create_table(0)
{}
~TMP_TABLE_PARAM()
{
@ -4564,8 +4564,8 @@ public:
if (copy_field) /* Fix for Intel compiler */
{
delete [] copy_field;
save_copy_field= copy_field= NULL;
save_copy_field_end= copy_field_end= NULL;
copy_field= NULL;
copy_field_end= NULL;
}
}
};

View File

@ -259,7 +259,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE");
DBUG_RETURN(TRUE);
}
if (!(table= table_list->table) || !table->created)
if (!(table= table_list->table) || !table->is_created())
{
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
table_list->view_db.str, table_list->view_name.str);
@ -488,10 +488,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
{
ha_rows examined_rows;
ha_rows found_rows;
uint length= 0;
SORT_FIELD *sortorder;
{
Filesort fsort(order, HA_POS_ERROR, select);
DBUG_ASSERT(query_plan.index == MAX_KEY);
table->sort.io_cache= (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL |
@ -499,13 +498,10 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
Filesort_tracker *fs_tracker=
thd->lex->explain->get_upd_del_plan()->filesort_tracker;
if (!(sortorder= make_unireg_sortorder(thd, order, &length, NULL)) ||
(table->sort.found_records= filesort(thd, table, sortorder, length,
select, HA_POS_ERROR,
true,
if ((table->sort.found_records= filesort(thd, table, &fsort, true,
&examined_rows, &found_rows,
fs_tracker))
== HA_POS_ERROR)
== HA_POS_ERROR)
{
delete select;
free_underlaid_joins(thd, &thd->lex->select_lex);
@ -517,7 +513,14 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
so we don't need the where clause
*/
delete select;
free_underlaid_joins(thd, select_lex);
/*
If we are not in DELETE ... RETURNING, we can free subqueries. (in
DELETE ... RETURNING we can't, because the RETURNING part may have
a subquery in it)
*/
if (!with_select)
free_underlaid_joins(thd, select_lex);
select= 0;
}
}
@ -745,7 +748,7 @@ send_nothing_and_leave:
wild_num - number of wildcards used in optional SELECT clause
field_list - list of items in optional SELECT clause
conds - conditions
l
RETURN VALUE
FALSE OK
TRUE error
@ -766,7 +769,8 @@ send_nothing_and_leave:
DELETE_ACL, SELECT_ACL, TRUE))
DBUG_RETURN(TRUE);
if ((wild_num && setup_wild(thd, table_list, field_list, NULL, wild_num)) ||
setup_fields(thd, NULL, field_list, MARK_COLUMNS_READ, NULL, 0) ||
setup_fields(thd, Ref_ptr_array(),
field_list, MARK_COLUMNS_READ, NULL, 0) ||
setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
setup_ftfuncs(select_lex))
DBUG_RETURN(TRUE);

View File

@ -476,7 +476,7 @@ exit_merge:
unconditional_materialization:
derived->change_refs_to_fields();
derived->set_materialized_derived();
if (!derived->table || !derived->table->created)
if (!derived->table || !derived->table->is_created())
res= mysql_derived_create(thd, lex, derived);
if (!res)
res= mysql_derived_fill(thd, lex, derived);
@ -855,7 +855,7 @@ bool mysql_derived_create(THD *thd, LEX *lex, TABLE_LIST *derived)
TABLE *table= derived->table;
SELECT_LEX_UNIT *unit= derived->get_unit();
if (table->created)
if (table->is_created())
DBUG_RETURN(FALSE);
select_union *result= (select_union*)unit->result;
if (table->s->db_type() == TMP_ENGINE_HTON)
@ -908,7 +908,7 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
if (unit->executed && !unit->uncacheable && !unit->describe)
DBUG_RETURN(FALSE);
/*check that table creation passed without problems. */
DBUG_ASSERT(derived->table && derived->table->created);
DBUG_ASSERT(derived->table && derived->table->is_created());
SELECT_LEX *first_select= unit->first_select();
select_union *derived_result= derived->derived_result;
SELECT_LEX *save_current_select= lex->current_select;
@ -924,7 +924,7 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
first_select->options&= ~OPTION_FOUND_ROWS;
lex->current_select= first_select;
res= mysql_select(thd, &first_select->ref_pointer_array,
res= mysql_select(thd,
first_select->table_list.first,
first_select->with_wild,
first_select->item_list, first_select->where,

View File

@ -29,7 +29,7 @@ bool mysql_do(THD *thd, List<Item> &values)
List_iterator<Item> li(values);
Item *value;
DBUG_ENTER("mysql_do");
if (setup_fields(thd, 0, values, MARK_COLUMNS_NONE, 0, 0))
if (setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_NONE, 0, 0))
DBUG_RETURN(TRUE);
while ((value = li++))
(void) value->is_null();

View File

@ -697,12 +697,13 @@ bool Explain_node::print_explain_json_cache(Json_writer *writer,
}
#if 0
void Explain_select::replace_table(uint idx, Explain_table_access *new_tab)
{
delete join_tabs[idx];
join_tabs[idx]= new_tab;
}
#endif
Explain_basic_join::~Explain_basic_join()
{

View File

@ -215,11 +215,13 @@ public:
ops_tracker(is_analyze)
{}
#if 0
/*
This is used to save the results of "late" test_if_skip_sort_order() calls
that are made from JOIN::exec
*/
void replace_table(uint idx, Explain_table_access *new_tab);
#endif
public:
const char *select_type;

View File

@ -258,7 +258,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
if (table_list->is_view())
unfix_fields(fields);
res= setup_fields(thd, 0, fields, MARK_COLUMNS_WRITE, 0, 0);
res= setup_fields(thd, Ref_ptr_array(), fields, MARK_COLUMNS_WRITE, 0, 0);
/* Restore the current context. */
ctx_state.restore_state(context, table_list);
@ -346,7 +346,8 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
}
/* Check the fields we are going to modify */
if (setup_fields(thd, 0, update_fields, MARK_COLUMNS_WRITE, 0, 0))
if (setup_fields(thd, Ref_ptr_array(),
update_fields, MARK_COLUMNS_WRITE, 0, 0))
return -1;
if (insert_table_list->is_view() &&
@ -771,7 +772,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
goto abort;
}
if (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0))
if (setup_fields(thd, Ref_ptr_array(), *values, MARK_COLUMNS_READ, 0, 0))
goto abort;
switch_to_nullable_trigger_fields(*values, table);
}
@ -1466,7 +1467,8 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
table_list->next_local= 0;
context->resolve_in_table_list_only(table_list);
res= (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0) ||
res= (setup_fields(thd, Ref_ptr_array(),
*values, MARK_COLUMNS_READ, 0, 0) ||
check_insert_fields(thd, context->table_list, fields, *values,
!insert_into_view, 0, &map));
@ -1482,7 +1484,8 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
}
if (!res)
res= setup_fields(thd, 0, update_values, MARK_COLUMNS_READ, 0, 0);
res= setup_fields(thd, Ref_ptr_array(),
update_values, MARK_COLUMNS_READ, 0, 0);
if (!res && duplic == DUP_UPDATE)
{
@ -3436,7 +3439,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
*/
lex->current_select= &lex->select_lex;
res= (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0) ||
res= (setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_READ, 0, 0) ||
check_insert_fields(thd, table_list, *fields, values,
!insert_into_view, 1, &map));
@ -3489,7 +3492,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
table_list->next_name_resolution_table=
ctx_state.get_first_name_resolution_table();
res= res || setup_fields(thd, 0, *info.update_values,
res= res || setup_fields(thd, Ref_ptr_array(), *info.update_values,
MARK_COLUMNS_READ, 0, 0);
if (!res)
{
@ -3618,7 +3621,7 @@ void select_insert::cleanup()
select_insert::~select_insert()
{
DBUG_ENTER("~select_insert");
if (table && table->created)
if (table && table->is_created())
{
table->next_number_field=0;
table->auto_increment_field_not_null= FALSE;

View File

@ -1905,8 +1905,7 @@ void st_select_lex::init_query()
parent_lex->push_context(&context, parent_lex->thd->mem_root);
cond_count= between_count= with_wild= 0;
max_equal_elems= 0;
ref_pointer_array= 0;
ref_pointer_array_size= 0;
ref_pointer_array.reset();
select_n_where_fields= 0;
select_n_reserved= 0;
select_n_having_items= 0;
@ -1924,6 +1923,7 @@ void st_select_lex::init_query()
prep_leaf_list_state= UNINIT;
have_merged_subqueries= FALSE;
bzero((char*) expr_cache_may_be_used, sizeof(expr_cache_may_be_used));
select_list_tables= 0;
m_non_agg_field_used= false;
m_agg_func_used= false;
}
@ -2421,7 +2421,7 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
select_n_having_items +
select_n_where_fields +
order_group_num) * 5;
if (ref_pointer_array != NULL)
if (!ref_pointer_array.is_null())
{
/*
We need to take 'n_sum_items' into account when allocating the array,
@ -2430,17 +2430,24 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
In the usual case we can reuse the array from the prepare phase.
If we need a bigger array, we must allocate a new one.
*/
if (ref_pointer_array_size >= n_elems)
{
DBUG_PRINT("info", ("reusing old ref_array"));
if (ref_pointer_array.size() == n_elems)
return false;
}
}
ref_pointer_array= static_cast<Item**>(arena->alloc(sizeof(Item*) * n_elems));
if (ref_pointer_array != NULL)
ref_pointer_array_size= n_elems;
return ref_pointer_array == NULL;
/*
We need to take 'n_sum_items' into account when allocating the array,
and this may actually increase during the optimization phase due to
MIN/MAX rewrite in Item_in_subselect::single_value_transformer.
In the usual case we can reuse the array from the prepare phase.
If we need a bigger array, we must allocate a new one.
*/
if (ref_pointer_array.size() == n_elems)
return false;
}
Item **array= static_cast<Item**>(arena->alloc(sizeof(Item*) * n_elems));
if (array != NULL)
ref_pointer_array= Ref_ptr_array(array, n_elems);
return array == NULL;
}
@ -2511,8 +2518,8 @@ void st_select_lex::print_order(String *str,
}
else
(*order->item)->print(str, query_type);
if (!order->asc)
str->append(STRING_WITH_LEN(" desc"));
if (order->direction == ORDER::ORDER_DESC)
str->append(STRING_WITH_LEN(" desc"));
if (order->next)
str->append(',');
}
@ -3941,9 +3948,11 @@ void SELECT_LEX::update_used_tables()
Item *item;
List_iterator_fast<Item> it(join->fields_list);
select_list_tables= 0;
while ((item= it++))
{
item->update_used_tables();
select_list_tables|= item->used_tables();
}
Item_outer_ref *ref;
List_iterator_fast<Item_outer_ref> ref_it(inner_refs_list);
@ -3993,6 +4002,8 @@ void st_select_lex::update_correlated_cache()
if (join->conds)
is_correlated|= MY_TEST(join->conds->used_tables() & OUTER_REF_TABLE_BIT);
is_correlated|= join->having_is_correlated;
if (join->having)
is_correlated|= MY_TEST(join->having->used_tables() & OUTER_REF_TABLE_BIT);

View File

@ -709,6 +709,7 @@ public:
};
typedef class st_select_lex_unit SELECT_LEX_UNIT;
typedef Bounds_checked_array<Item*> Ref_ptr_array;
/*
SELECT_LEX - store information of parsed SELECT statment
@ -787,9 +788,9 @@ public:
SQL_I_List<ORDER> order_list; /* ORDER clause */
SQL_I_List<ORDER> gorder_list;
Item *select_limit, *offset_limit; /* LIMIT clause parameters */
// Arrays of pointers to top elements of all_fields list
Item **ref_pointer_array;
size_t ref_pointer_array_size; // Number of elements in array.
/// Array of pointers to top elements of all_fields list
Ref_ptr_array ref_pointer_array;
/*
number of items in select_list and HAVING clause used to get number
@ -886,6 +887,12 @@ public:
*/
List<String> *prev_join_using;
/**
The set of those tables whose fields are referenced in the select list of
this select level.
*/
table_map select_list_tables;
/* namp of nesting SELECT visibility (for aggregate functions check) */
nesting_map name_visibility_map;

View File

@ -277,22 +277,25 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
Let us also prepare SET clause, altough it is probably empty
in this case.
*/
if (setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0))
if (setup_fields(thd, Ref_ptr_array(),
set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
setup_fields(thd, Ref_ptr_array(), set_values, MARK_COLUMNS_READ, 0, 0))
DBUG_RETURN(TRUE);
}
else
{ // Part field list
/* TODO: use this conds for 'WITH CHECK OPTIONS' */
if (setup_fields(thd, 0, fields_vars, MARK_COLUMNS_WRITE, 0, 0) ||
setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
if (setup_fields(thd, Ref_ptr_array(),
fields_vars, MARK_COLUMNS_WRITE, 0, 0) ||
setup_fields(thd, Ref_ptr_array(),
set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
check_that_all_fields_are_given_values(thd, table, table_list))
DBUG_RETURN(TRUE);
/* Add all fields with default functions to table->write_set. */
if (table->default_field)
table->mark_default_fields_for_write();
/* Fix the expressions in SET clause */
if (setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0))
if (setup_fields(thd, Ref_ptr_array(), set_values, MARK_COLUMNS_READ, 0, 0))
DBUG_RETURN(TRUE);
}
switch_to_nullable_trigger_fields(fields_vars, table);

View File

@ -4143,7 +4143,7 @@ end_with_restore_list:
lex->table_count);
if (result)
{
res= mysql_select(thd, &select_lex->ref_pointer_array,
res= mysql_select(thd,
select_lex->get_table_list(),
select_lex->with_wild,
select_lex->item_list,
@ -7382,7 +7382,6 @@ add_proc_to_list(THD* thd, Item *item)
item_ptr = (Item**) (order+1);
*item_ptr= item;
order->item=item_ptr;
order->free_me=0;
thd->lex->proc_list.link_in_list(order, &order->next);
return 0;
}
@ -7400,8 +7399,7 @@ bool add_to_list(THD *thd, SQL_I_List<ORDER> &list, Item *item,bool asc)
DBUG_RETURN(1);
order->item_ptr= item;
order->item= &order->item_ptr;
order->asc = asc;
order->free_me=0;
order->direction= (asc ? ORDER::ORDER_ASC : ORDER::ORDER_DESC);
order->used=0;
order->counter_used= 0;
order->fast_field_copier_setup= 0;

View File

@ -1306,7 +1306,7 @@ static bool mysql_test_insert(Prepared_statement *stmt,
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
goto error;
}
if (setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, 0))
if (setup_fields(thd, Ref_ptr_array(), *values, MARK_COLUMNS_NONE, 0, 0))
goto error;
}
}
@ -1396,7 +1396,8 @@ static int mysql_test_update(Prepared_statement *stmt,
table_list->register_want_access(want_privilege);
#endif
thd->lex->select_lex.no_wrap_view_item= TRUE;
res= setup_fields(thd, 0, select->item_list, MARK_COLUMNS_READ, 0, 0);
res= setup_fields(thd, Ref_ptr_array(),
select->item_list, MARK_COLUMNS_READ, 0, 0);
thd->lex->select_lex.no_wrap_view_item= FALSE;
if (res)
goto error;
@ -1407,7 +1408,8 @@ static int mysql_test_update(Prepared_statement *stmt,
(SELECT_ACL & ~table_list->table->grant.privilege);
table_list->register_want_access(SELECT_ACL);
#endif
if (setup_fields(thd, 0, stmt->lex->value_list, MARK_COLUMNS_NONE, 0, 0) ||
if (setup_fields(thd, Ref_ptr_array(),
stmt->lex->value_list, MARK_COLUMNS_NONE, 0, 0) ||
check_unique_table(thd, table_list))
goto error;
/* TODO: here we should send types of placeholders to the client. */
@ -1453,7 +1455,7 @@ static bool mysql_test_delete(Prepared_statement *stmt,
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE");
goto error;
}
if (!table_list->table || !table_list->table->created)
if (!table_list->table || !table_list->table->is_created())
{
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
table_list->view_db.str, table_list->view_name.str);
@ -1577,7 +1579,8 @@ static bool mysql_test_do_fields(Prepared_statement *stmt,
if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL,
DT_PREPARE | DT_CREATE))
DBUG_RETURN(TRUE);
DBUG_RETURN(setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, 0));
DBUG_RETURN(setup_fields(thd, Ref_ptr_array(),
*values, MARK_COLUMNS_NONE, 0, 0));
}

File diff suppressed because it is too large Load Diff

View File

@ -32,7 +32,9 @@
#include "sql_array.h" /* Array */
#include "records.h" /* READ_RECORD */
#include "opt_range.h" /* SQL_SELECT, QUICK_SELECT_I */
#include "filesort.h"
typedef struct st_join_table JOIN_TAB;
/* Values in optimize */
#define KEY_OPTIMIZE_EXISTS 1
@ -184,7 +186,7 @@ enum sj_strategy_enum
typedef enum_nested_loop_state
(*Next_select_func)(JOIN *, struct st_join_table *, bool);
Next_select_func setup_end_select_func(JOIN *join);
Next_select_func setup_end_select_func(JOIN *join, JOIN_TAB *tab);
int rr_sequential(READ_RECORD *info);
int rr_sequential_and_unpack(READ_RECORD *info);
@ -198,9 +200,11 @@ int rr_sequential_and_unpack(READ_RECORD *info);
class JOIN_CACHE;
class SJ_TMP_TABLE;
class JOIN_TAB_RANGE;
class AGGR_OP;
class Filesort;
typedef struct st_join_table {
st_join_table() {} /* Remove gcc warning */
st_join_table() {}
TABLE *table;
KEYUSE *keyuse; /**< pointer to first used key */
KEY *hj_key; /**< descriptor of the used best hash join key
@ -260,6 +264,7 @@ typedef struct st_join_table {
*/
uint packed_info;
// READ_RECORD::Setup_func materialize_table;
READ_RECORD::Setup_func read_first_record;
Next_select_func next_select;
READ_RECORD read_record;
@ -346,6 +351,7 @@ typedef struct st_join_table {
*/
Item *cache_idx_cond;
SQL_SELECT *cache_select;
AGGR_OP *aggr;
JOIN *join;
/*
Embedding SJ-nest (may be not the direct parent), or NULL if none.
@ -412,6 +418,39 @@ typedef struct st_join_table {
/* NestedOuterJoins: Bitmap of nested joins this table is part of */
nested_join_map embedding_map;
/* Tmp table info */
TMP_TABLE_PARAM *tmp_table_param;
/* Sorting related info */
Filesort *filesort;
/**
List of topmost expressions in the select list. The *next* JOIN TAB
in the plan should use it to obtain correct values. Same applicable to
all_fields. These lists are needed because after tmp tables functions
will be turned to fields. These variables are pointing to
tmp_fields_list[123]. Valid only for tmp tables and the last non-tmp
table in the query plan.
@see JOIN::make_tmp_tables_info()
*/
List<Item> *fields;
/** List of all expressions in the select list */
List<Item> *all_fields;
/*
Pointer to the ref array slice which to switch to before sending
records. Valid only for tmp tables.
*/
Ref_ptr_array *ref_array;
/** Number of records saved in tmp table */
ha_rows send_records;
/** HAVING condition for checking prior saving a record into tmp table*/
Item *having;
/** TRUE <=> remove duplicates on this table. */
bool distinct;
/*
Semi-join strategy to be used for this join table. This is a copy of
POSITION::sj_strategy field. This field is set up by the
@ -426,9 +465,9 @@ typedef struct st_join_table {
void cleanup();
inline bool is_using_loose_index_scan()
{
return (select && select->quick &&
(select->quick->get_type() ==
QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX));
const SQL_SELECT *sel= filesort ? filesort->select : select;
return (sel && sel->quick &&
(sel->quick->get_type() == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX));
}
bool is_using_agg_loose_index_scan ()
{
@ -563,16 +602,22 @@ typedef struct st_join_table {
void save_explain_data(Explain_table_access *eta, table_map prefix_tables,
bool distinct, struct st_join_table *first_top_tab);
void update_explain_data(uint idx);
bool use_order() const; ///< Use ordering provided by chosen index?
bool sort_table();
bool remove_duplicates();
} JOIN_TAB;
#include "sql_join_cache.h"
enum_nested_loop_state sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool
end_of_records);
enum_nested_loop_state sub_select(JOIN *join,JOIN_TAB *join_tab, bool
end_of_records);
enum_nested_loop_state
sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
enum_nested_loop_state
sub_select(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
enum_nested_loop_state
sub_select_postjoin_aggr(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
enum_nested_loop_state
end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
bool end_of_records);
@ -867,12 +912,14 @@ typedef struct st_position
Sj_materialization_picker sjmat_picker;
} POSITION;
typedef Bounds_checked_array<Item_null_result*> Item_null_array;
typedef struct st_rollup
{
enum State { STATE_NONE, STATE_INITED, STATE_READY };
State state;
Item_null_result **null_items;
Item ***ref_pointer_arrays;
Item_null_array null_items;
Ref_ptr_array *ref_pointer_arrays;
List<Item> *fields;
} ROLLUP;
@ -886,6 +933,56 @@ public:
class Pushdown_query;
/**
@brief
Class to perform postjoin aggregation operations
@details
The result records are obtained on the put_record() call.
The aggrgation process is determined by the write_func, it could be:
end_write Simply store all records in tmp table.
end_write_group Perform grouping using join->group_fields,
records are expected to be sorted.
end_update Perform grouping using the key generated on tmp
table. Input records aren't expected to be sorted.
Tmp table uses the heap engine
end_update_unique Same as above, but the engine is myisam.
Lazy table initialization is used - the table will be instantiated and
rnd/index scan started on the first put_record() call.
*/
class AGGR_OP :public Sql_alloc
{
public:
JOIN_TAB *join_tab;
AGGR_OP(JOIN_TAB *tab) : join_tab(tab), write_func(NULL)
{};
enum_nested_loop_state put_record() { return put_record(false); };
/*
Send the result of operation further (to a next operation/client)
This function is called after all records were put into tmp table.
@return return one of enum_nested_loop_state values.
*/
enum_nested_loop_state end_send();
/** write_func setter */
void set_write_func(Next_select_func new_write_func)
{
write_func= new_write_func;
}
private:
/** Write function that would be used for saving records in tmp table. */
Next_select_func write_func;
enum_nested_loop_state put_record(bool end_of_records);
bool prepare_tmp_table();
};
class JOIN :public Sql_alloc
{
private:
@ -954,14 +1051,6 @@ protected:
public:
JOIN_TAB *join_tab, **best_ref;
/*
Saved join_tab for pre_sorting. create_sort_index() will save here..
*/
JOIN_TAB *pre_sort_join_tab;
uint pre_sort_index;
Item *pre_sort_idx_pushed_cond;
void clean_pre_sort_join_tab();
/* List of fields that aren't under an aggregate function */
List<Item_field> non_agg_fields;
@ -979,8 +1068,6 @@ public:
uint top_table_access_tabs_count;
JOIN_TAB **map2table; ///< mapping between table indexes and JOIN_TABs
JOIN_TAB *join_tab_save; ///< saved join_tab for subquery reexecution
List<JOIN_TAB_RANGE> join_tab_ranges;
/*
@ -1011,6 +1098,7 @@ public:
We keep it here so that it is saved/restored with JOIN::restore_tmp.
*/
uint top_join_tab_count;
uint aggr_tables; ///< Number of post-join tmp tables
uint send_group_parts;
/*
This counts how many times do_select() was invoked for this JOIN.
@ -1123,6 +1211,7 @@ public:
*/
table_map complex_firstmatch_tables;
Next_select_func first_select;
/*
The cost of best complete join plan found so far during optimization,
after optimization phase - cost of picked join order (not taking into
@ -1138,9 +1227,6 @@ public:
double join_record_count;
List<Item> *fields;
List<Cached_item> group_fields, group_fields_cache;
TABLE *tmp_table;
/// used to store 2 possible tmp table of SELECT
TABLE *exec_tmp_table1, *exec_tmp_table2;
THD *thd;
Item_sum **sum_funcs, ***sum_funcs_end;
/** second copy of sumfuncs (for queries with 2 temporary tables */
@ -1149,6 +1235,8 @@ public:
Item *having;
Item *tmp_having; ///< To store having when processed temporary table
Item *having_history; ///< Store having for explain
ORDER *group_list_for_estimates;
bool having_is_correlated;
ulonglong select_options;
/*
Bitmap of allowed types of the join caches that
@ -1187,26 +1275,6 @@ public:
*/
bool filesort_found_rows;
/**
Copy of this JOIN to be used with temporary tables.
tmp_join is used when the JOIN needs to be "reusable" (e.g. in a
subquery that gets re-executed several times) and we know will use
temporary tables for materialization. The materialization to a
temporary table overwrites the JOIN structure to point to the
temporary table after the materialization is done. This is where
tmp_join is used : it's a copy of the JOIN before the
materialization and is used in restoring before re-execution by
overwriting the current JOIN structure with the saved copy.
Because of this we should pay extra care of not freeing up helper
structures that are referenced by the original contents of the
JOIN. We can check for this by making sure the "current" join is
not the temporary copy, e.g. !tmp_join || tmp_join != join
We should free these sub-structures at JOIN::destroy() if the
"current" join has a copy is not that copy.
*/
JOIN *tmp_join;
ROLLUP rollup; ///< Used with rollup
bool mixed_implicit_grouping;
@ -1228,6 +1296,19 @@ public:
GROUP/ORDER BY.
*/
bool simple_order, simple_group;
/*
ordered_index_usage is set if an ordered index access
should be used instead of a filesort when computing
ORDER/GROUP BY.
*/
enum
{
ordered_index_void, // No ordered index avail.
ordered_index_group_by, // Use index for GROUP BY
ordered_index_order_by // Use index for ORDER BY
} ordered_index_usage;
/**
Is set only in case if we have a GROUP BY clause
and no ORDER BY after constant elimination of 'order'.
@ -1280,10 +1361,19 @@ public:
List<Item> exec_const_order_group_cond;
SQL_SELECT *select; ///<created in optimisation phase
JOIN_TAB *return_tab; ///<used only for outer joins
Item **ref_pointer_array; ///<used pointer reference for this select
// Copy of above to be used with different lists
Item **items0, **items1, **items2, **items3, **current_ref_pointer_array;
uint ref_pointer_array_size; ///< size of above in bytes
/*
Used pointer reference for this select.
select_lex->ref_pointer_array contains five "slices" of the same length:
|========|========|========|========|========|
ref_ptrs items0 items1 items2 items3
*/
Ref_ptr_array ref_ptrs;
// Copy of the initial slice above, to be used with different lists
Ref_ptr_array items0, items1, items2, items3;
// Used by rollup, to restore ref_ptrs after overwriting it.
Ref_ptr_array current_ref_ptrs;
const char *zero_result_cause; ///< not 0 if exec must return zero result
bool union_part; ///< this subselect is part of union
@ -1310,20 +1400,12 @@ public:
/* SJM nests that are executed with SJ-Materialization strategy */
List<SJ_MATERIALIZATION_INFO> sjm_info_list;
/*
storage for caching buffers allocated during query execution.
These buffers allocations need to be cached as the thread memory pool is
cleared only at the end of the execution of the whole query and not caching
allocations that occur in repetition at execution time will result in
excessive memory usage.
Note: make_simple_join always creates an execution plan that accesses
a single table, thus it is sufficient to have a one-element array for
table_reexec.
*/
SORT_FIELD *sortorder; // make_unireg_sortorder()
TABLE *table_reexec[1]; // make_simple_join()
JOIN_TAB *join_tab_reexec; // make_simple_join()
/* end of allocation caching storage */
/** TRUE <=> ref_pointer_array is set to items3. */
bool set_group_rpa;
/** Exec time only: TRUE <=> current group has been sent */
bool group_sent;
JOIN_TAB *sort_and_group_aggr_tab;
JOIN(THD *thd_arg, List<Item> &fields_arg, ulonglong select_options_arg,
select_result *result_arg)
@ -1335,12 +1417,13 @@ public:
void init(THD *thd_arg, List<Item> &fields_arg, ulonglong select_options_arg,
select_result *result_arg)
{
join_tab= join_tab_save= 0;
join_tab= 0;
table= 0;
table_count= 0;
top_join_tab_count= 0;
const_tables= 0;
const_table_map= 0;
aggr_tables= 0;
eliminated_tables= 0;
join_list= 0;
implicit_grouping= FALSE;
@ -1350,25 +1433,21 @@ public:
send_records= 0;
found_records= 0;
fetch_limit= HA_POS_ERROR;
join_examined_rows= 0;
exec_tmp_table1= 0;
exec_tmp_table2= 0;
sortorder= 0;
table_reexec[0]= 0;
join_tab_reexec= 0;
thd= thd_arg;
sum_funcs= sum_funcs2= 0;
procedure= 0;
having= tmp_having= having_history= 0;
having_is_correlated= false;
group_list_for_estimates= 0;
select_options= select_options_arg;
result= result_arg;
lock= thd_arg->lock;
select_lex= 0; //for safety
tmp_join= 0;
select_distinct= MY_TEST(select_options & SELECT_DISTINCT);
no_order= 0;
simple_order= 0;
simple_group= 0;
ordered_index_usage= ordered_index_void;
need_distinct= 0;
skip_sort_order= 0;
need_tmp= 0;
@ -1376,8 +1455,11 @@ public:
error= 0;
select= 0;
return_tab= 0;
ref_pointer_array= items0= items1= items2= items3= 0;
ref_pointer_array_size= 0;
ref_ptrs.reset();
items0.reset();
items1.reset();
items2.reset();
items3.reset();
zero_result_cause= 0;
optimized= 0;
have_query_plan= QEP_NOT_PRESENT_YET;
@ -1405,10 +1487,13 @@ public:
rollup.state= ROLLUP::STATE_NONE;
no_const_tables= FALSE;
first_select= sub_select;
set_group_rpa= false;
group_sent= 0;
outer_ref_cond= pseudo_bits_cond= NULL;
in_to_exists_where= NULL;
in_to_exists_having= NULL;
pre_sort_join_tab= NULL;
emb_sjm_nest= NULL;
sjm_lookup_tables= 0;
@ -1420,7 +1505,10 @@ public:
table_access_tabs= NULL;
}
int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num,
/* True if the plan guarantees that it will be returned zero or one row */
bool only_const_tables() { return const_tables == table_count; }
int prepare(TABLE_LIST *tables, uint wind_num,
COND *conds, uint og_num, ORDER *order, bool skip_order_by,
ORDER *group, Item *having, ORDER *proc_param, SELECT_LEX *select,
SELECT_LEX_UNIT *unit);
@ -1431,6 +1519,7 @@ public:
int init_execution();
void exec();
void exec_inner();
bool prepare_result(List<Item> **columns_list);
int destroy();
void restore_tmp();
bool alloc_func_list();
@ -1440,16 +1529,42 @@ public:
bool make_sum_func_list(List<Item> &all_fields, List<Item> &send_fields,
bool before_group_by, bool recompute= FALSE);
inline void set_items_ref_array(Item **ptr)
/// Initialzes a slice, see comments for ref_ptrs above.
Ref_ptr_array ref_ptr_array_slice(size_t slice_num)
{
memcpy((char*) ref_pointer_array, (char*) ptr, ref_pointer_array_size);
current_ref_pointer_array= ptr;
size_t slice_sz= select_lex->ref_pointer_array.size() / 5U;
DBUG_ASSERT(select_lex->ref_pointer_array.size() % 5 == 0);
DBUG_ASSERT(slice_num < 5U);
return Ref_ptr_array(&select_lex->ref_pointer_array[slice_num * slice_sz],
slice_sz);
}
inline void init_items_ref_array()
/**
Overwrites one slice with the contents of another slice.
In the normal case, dst and src have the same size().
However: the rollup slices may have smaller size than slice_sz.
*/
void copy_ref_ptr_array(Ref_ptr_array dst_arr, Ref_ptr_array src_arr)
{
items0= ref_pointer_array + all_fields.elements;
memcpy(items0, ref_pointer_array, ref_pointer_array_size);
current_ref_pointer_array= items0;
DBUG_ASSERT(dst_arr.size() >= src_arr.size());
void *dest= dst_arr.array();
const void *src= src_arr.array();
memcpy(dest, src, src_arr.size() * src_arr.element_size());
}
/// Overwrites 'ref_ptrs' and remembers the the source as 'current'.
void set_items_ref_array(Ref_ptr_array src_arr)
{
copy_ref_ptr_array(ref_ptrs, src_arr);
current_ref_ptrs= src_arr;
}
/// Initializes 'items0' and remembers that it is 'current'.
void init_items_ref_array()
{
items0= ref_ptr_array_slice(1);
copy_ref_ptr_array(items0, ref_ptrs);
current_ref_ptrs= items0;
}
bool rollup_init();
@ -1458,18 +1573,10 @@ public:
Item_sum ***func);
int rollup_send_data(uint idx);
int rollup_write_data(uint idx, TABLE *table);
/**
Release memory and, if possible, the open tables held by this execution
plan (and nested plans). It's used to release some tables before
the end of execution in order to increase concurrency and reduce
memory consumption.
*/
void join_free();
/** Cleanup this JOIN, possibly for reuse */
void cleanup(bool full);
void clear();
bool save_join_tab();
bool init_save_join_tab();
bool send_row_on_empty_set()
{
return (do_send_rows && implicit_grouping && !group_optimized_away &&
@ -1488,6 +1595,8 @@ public:
return (table_map(1) << table_count) - 1;
}
void drop_unused_derived_keys();
bool get_best_combination();
bool add_sorting_to_table(JOIN_TAB *tab, ORDER *order);
inline void eval_select_list_used_tables();
/*
Return the table for which an index scan can be used to satisfy
@ -1552,13 +1661,42 @@ public:
JOIN_TAB *first_breadth_first_optimization_tab() { return table_access_tabs; }
JOIN_TAB *first_breadth_first_execution_tab() { return join_tab; }
private:
/**
Create a temporary table to be used for processing DISTINCT/ORDER
BY/GROUP BY.
@note Will modify JOIN object wrt sort/group attributes
@param tab the JOIN_TAB object to attach created table to
@param tmp_table_fields List of items that will be used to define
column types of the table.
@param tmp_table_group Group key to use for temporary table, NULL if none.
@param save_sum_fields If true, do not replace Item_sum items in
@c tmp_fields list with Item_field items referring
to fields in temporary table.
@returns false on success, true on failure
*/
bool create_postjoin_aggr_table(JOIN_TAB *tab, List<Item> *tmp_table_fields,
ORDER *tmp_table_group,
bool save_sum_fields,
bool distinct,
bool keep_row_ordermake);
/**
Optimize distinct when used on a subset of the tables.
E.g.,: SELECT DISTINCT t1.a FROM t1,t2 WHERE t1.b=t2.b
In this case we can stop scanning t2 when we have found one t1.a
*/
void optimize_distinct();
/**
TRUE if the query contains an aggregate function but has no GROUP
BY clause.
*/
bool implicit_grouping;
bool make_simple_join(JOIN *join, TABLE *tmp_table);
void cleanup_item_list(List<Item> &items) const;
bool make_aggr_tables_info();
};
enum enum_with_bush_roots { WITH_BUSH_ROOTS, WITHOUT_BUSH_ROOTS};
@ -1583,7 +1721,7 @@ extern const char *join_type_str[];
void count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param,
List<Item> &fields, bool reset_with_sum_func);
bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
Item **ref_pointer_array,
Ref_ptr_array ref_pointer_array,
List<Item> &new_list1, List<Item> &new_list2,
uint elements, List<Item> &fields);
void copy_fields(TMP_TABLE_PARAM *param);
@ -1824,19 +1962,19 @@ int safe_index_read(JOIN_TAB *tab);
int get_quick_record(SQL_SELECT *select);
SORT_FIELD * make_unireg_sortorder(THD *thd, ORDER *order, uint *length,
SORT_FIELD *sortorder);
int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, List <Item> &all_fields, ORDER *order);
int setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
int setup_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, List<Item> &all_fields, ORDER *order,
bool *hidden_group_fields);
bool fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
Item **ref_pointer_array);
Ref_ptr_array ref_pointer_array);
int join_read_key2(THD *thd, struct st_join_table *tab, TABLE *table,
struct st_table_ref *table_ref);
bool handle_select(THD *thd, LEX *lex, select_result *result,
ulong setup_tables_done_option);
bool mysql_select(THD *thd, Item ***rref_pointer_array,
bool mysql_select(THD *thd,
TABLE_LIST *tables, uint wild_num, List<Item> &list,
COND *conds, uint og_num, ORDER *order, ORDER *group,
Item *having, ORDER *proc_param, ulonglong select_type,

View File

@ -9301,8 +9301,6 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
int error= 1;
Copy_field *copy= NULL, *copy_end;
ha_rows found_count= 0, delete_count= 0;
uint length= 0;
SORT_FIELD *sortorder;
READ_RECORD info;
TABLE_LIST tables;
List<Item> fields;
@ -9404,10 +9402,10 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
Filesort_tracker dummy_tracker(false);
if (thd->lex->select_lex.setup_ref_array(thd, order_num) ||
setup_order(thd, thd->lex->select_lex.ref_pointer_array,
&tables, fields, all_fields, order) ||
!(sortorder= make_unireg_sortorder(thd, order, &length, NULL)) ||
(from->sort.found_records= filesort(thd, from, sortorder, length,
NULL, HA_POS_ERROR,
&tables, fields, all_fields, order))
goto err;
Filesort fsort(order, HA_POS_ERROR, NULL);
if ((from->sort.found_records= filesort(thd, from, &fsort,
true,
&examined_rows, &found_rows,
&dummy_tracker)) ==

View File

@ -437,8 +437,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
can_skip_order_by= is_union_select && !(sl->braces && sl->explicit_limit);
saved_error= join->prepare(&sl->ref_pointer_array,
sl->table_list.first,
saved_error= join->prepare(sl->table_list.first,
sl->with_wild,
sl->where,
(can_skip_order_by ? 0 :
@ -647,8 +646,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
fake_select_lex->n_child_sum_items+= global_parameters()->n_sum_items;
saved_error= fake_select_lex->join->
prepare(&fake_select_lex->ref_pointer_array,
fake_select_lex->table_list.first,
prepare(fake_select_lex->table_list.first,
0, 0,
global_parameters()->order_list.elements, // og_num
global_parameters()->order_list.first, // order
@ -703,7 +701,7 @@ bool st_select_lex_unit::optimize()
{
item->assigned(0); // We will reinit & rexecute unit
item->reset();
if (table->created)
if (table->is_created())
{
table->file->ha_delete_all_rows();
table->file->info(HA_STATUS_VARIABLE);
@ -947,13 +945,13 @@ bool st_select_lex_unit::exec()
Don't add more sum_items if we have already done JOIN::prepare
for this (with a different join object)
*/
if (!fake_select_lex->ref_pointer_array)
if (fake_select_lex->ref_pointer_array.is_null())
fake_select_lex->n_child_sum_items+= global_parameters()->n_sum_items;
if (!was_executed)
save_union_explain_part2(thd->lex->explain);
saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array,
saved_error= mysql_select(thd,
&result_table_list,
0, item_list, NULL,
global_parameters()->order_list.elements,
@ -976,7 +974,7 @@ bool st_select_lex_unit::exec()
to reset them back, we re-do all of the actions (yes it is ugly):
*/ // psergey-todo: is the above really necessary anymore??
join->init(thd, item_list, fake_select_lex->options, result);
saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array,
saved_error= mysql_select(thd,
&result_table_list,
0, item_list, NULL,
global_parameters()->order_list.elements,
@ -1023,27 +1021,11 @@ bool st_select_lex_unit::cleanup()
}
cleaned= 1;
if (union_result)
{
delete union_result;
union_result=0; // Safety
if (table)
free_tmp_table(thd, table);
table= 0; // Safety
}
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
error|= sl->cleanup();
if (fake_select_lex)
{
JOIN *join;
if ((join= fake_select_lex->join))
{
join->tables_list= 0;
join->table_count= 0;
join->top_join_tab_count= 0;
}
error|= fake_select_lex->cleanup();
/*
There are two cases when we should clean order items:
@ -1065,6 +1047,15 @@ bool st_select_lex_unit::cleanup()
}
}
if (union_result)
{
delete union_result;
union_result=0; // Safety
if (table)
free_tmp_table(thd, table);
table= 0; // Safety
}
DBUG_RETURN(error);
}

View File

@ -340,7 +340,8 @@ int mysql_update(THD *thd,
if (table_list->is_view())
unfix_fields(fields);
if (setup_fields_with_no_wrap(thd, 0, fields, MARK_COLUMNS_WRITE, 0, 0))
if (setup_fields_with_no_wrap(thd, Ref_ptr_array(),
fields, MARK_COLUMNS_WRITE, 0, 0))
DBUG_RETURN(1); /* purecov: inspected */
if (table_list->view && check_fields(thd, fields))
{
@ -359,7 +360,7 @@ int mysql_update(THD *thd,
table_list->grant.want_privilege= table->grant.want_privilege=
(SELECT_ACL & ~table->grant.privilege);
#endif
if (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0))
if (setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_READ, 0, 0))
{
free_underlaid_joins(thd, select_lex);
DBUG_RETURN(1); /* purecov: inspected */
@ -555,10 +556,9 @@ int mysql_update(THD *thd,
to update
NOTE: filesort will call table->prepare_for_position()
*/
uint length= 0;
SORT_FIELD *sortorder;
ha_rows examined_rows;
ha_rows found_rows;
Filesort fsort(order, limit, select);
table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL |
@ -566,13 +566,10 @@ int mysql_update(THD *thd,
Filesort_tracker *fs_tracker=
thd->lex->explain->get_upd_del_plan()->filesort_tracker;
if (!(sortorder=make_unireg_sortorder(thd, order, &length, NULL)) ||
(table->sort.found_records= filesort(thd, table, sortorder, length,
select, limit,
true,
if ((table->sort.found_records= filesort(thd, table, &fsort, true,
&examined_rows, &found_rows,
fs_tracker))
== HA_POS_ERROR)
== HA_POS_ERROR)
{
goto err;
}
@ -701,7 +698,7 @@ int mysql_update(THD *thd,
if (error >= 0)
goto err;
}
table->disable_keyread();
table->set_keyread(false);
table->column_bitmaps_set(save_read_set, save_write_set);
}
@ -1053,7 +1050,7 @@ int mysql_update(THD *thd,
err:
delete select;
free_underlaid_joins(thd, select_lex);
table->disable_keyread();
table->set_keyread(false);
thd->abort_on_warning= 0;
DBUG_RETURN(1);
@ -1427,7 +1424,8 @@ int mysql_multi_update_prepare(THD *thd)
if (lex->select_lex.handle_derived(thd->lex, DT_MERGE))
DBUG_RETURN(TRUE);
if (setup_fields_with_no_wrap(thd, 0, *fields, MARK_COLUMNS_WRITE, 0, 0))
if (setup_fields_with_no_wrap(thd, Ref_ptr_array(),
*fields, MARK_COLUMNS_WRITE, 0, 0))
DBUG_RETURN(TRUE);
for (tl= table_list; tl ; tl= tl->next_local)
@ -1614,7 +1612,7 @@ bool mysql_multi_update(THD *thd,
thd->abort_on_warning= thd->is_strict_mode();
List<Item> total_list;
res= mysql_select(thd, &select_lex->ref_pointer_array,
res= mysql_select(thd,
table_list, select_lex->with_wild,
total_list,
conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL,
@ -1710,7 +1708,8 @@ int multi_update::prepare(List<Item> &not_used_values,
reference tables
*/
int error= setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0);
int error= setup_fields(thd, Ref_ptr_array(),
*values, MARK_COLUMNS_READ, 0, 0);
ti.rewind();
while ((table_ref= ti++))
@ -2037,7 +2036,7 @@ loop_end:
/* Make an unique key over the first field to avoid duplicated updates */
bzero((char*) &group, sizeof(group));
group.asc= 1;
group.direction= ORDER::ORDER_ASC;
group.item= (Item**) temp_fields.head_ref();
tmp_param->quick_group=1;

View File

@ -5732,7 +5732,7 @@ void TABLE::mark_columns_used_by_index(uint index)
MY_BITMAP *bitmap= &tmp_set;
DBUG_ENTER("TABLE::mark_columns_used_by_index");
enable_keyread();
set_keyread(true);
bitmap_clear_all(bitmap);
mark_columns_used_by_index_no_reset(index, bitmap);
column_bitmaps_set(bitmap, bitmap);
@ -5753,7 +5753,7 @@ void TABLE::add_read_columns_used_by_index(uint index)
MY_BITMAP *bitmap= &tmp_set;
DBUG_ENTER("TABLE::add_read_columns_used_by_index");
enable_keyread();
set_keyread(true);
bitmap_copy(bitmap, read_set);
mark_columns_used_by_index_no_reset(index, bitmap);
column_bitmaps_set(bitmap, write_set);
@ -5776,7 +5776,7 @@ void TABLE::restore_column_maps_after_mark_index()
{
DBUG_ENTER("TABLE::restore_column_maps_after_mark_index");
disable_keyread();
set_keyread(false);
default_column_bitmaps();
file->column_bitmaps_signal();
DBUG_VOID_RETURN;

View File

@ -212,8 +212,13 @@ typedef struct st_order {
Field *fast_field_copier_setup;
int counter; /* position in SELECT list, correct
only if counter_used is true*/
bool asc; /* true if ascending */
bool free_me; /* true if item isn't shared */
enum enum_order {
ORDER_NOT_RELEVANT,
ORDER_ASC,
ORDER_DESC
};
enum_order direction; /* Requested direction of ordering */
bool in_field_list; /* true if in select field list */
bool counter_used; /* parameter was counter of columns */
Field *field; /* If tmp-table group */
@ -337,6 +342,7 @@ public:
uchar *record_pointers; /* If sorted in memory */
ha_rows found_records; /* How many records in sort */
Filesort_info(): record_pointers(0) {};
/** Sort filesort_buffer */
void sort_buffer(Sort_param *param, uint count)
{ filesort_buffer.sort_buffer(param, count); }
@ -1239,7 +1245,9 @@ public:
bool alias_name_used; /* true if table_name is alias */
bool get_fields_in_item_tree; /* Signal to fix_field */
bool m_needs_reopen;
private:
bool created; /* For tmp tables. TRUE <=> tmp table was actually created.*/
public:
#ifdef HAVE_REPLICATION
/* used in RBR Triggers */
bool master_had_triggers;
@ -1346,30 +1354,46 @@ public:
map= map_arg;
tablenr= tablenr_arg;
}
inline void enable_keyread()
void set_keyread(bool flag)
{
DBUG_ENTER("enable_keyread");
DBUG_ASSERT(key_read == 0);
key_read= 1;
file->extra(HA_EXTRA_KEYREAD);
DBUG_VOID_RETURN;
DBUG_ASSERT(file);
if (flag && !key_read)
{
key_read= 1;
if (is_created())
file->extra(HA_EXTRA_KEYREAD);
}
else if (!flag && key_read)
{
key_read= 0;
if (is_created())
file->extra(HA_EXTRA_NO_KEYREAD);
}
}
/// Return true if table is instantiated, and false otherwise.
bool is_created() const { return created; }
/**
Set the table as "created", and enable flags in storage engine
that could not be enabled without an instantiated table.
*/
void set_created()
{
if (created)
return;
if (key_read)
file->extra(HA_EXTRA_KEYREAD);
created= true;
}
/*
Returns TRUE if the table is filled at execution phase (and so, the
optimizer must not do anything that depends on the contents of the table,
like range analysis or constant table detection)
*/
bool is_filled_at_execution();
inline void disable_keyread()
{
DBUG_ENTER("disable_keyread");
if (key_read)
{
key_read= 0;
file->extra(HA_EXTRA_NO_KEYREAD);
}
DBUG_VOID_RETURN;
}
bool update_const_key_parts(COND *conds);
@ -2056,6 +2080,11 @@ struct TABLE_LIST
/* TRUE <=> this table is a const one and was optimized away. */
bool optimized_away;
/**
TRUE <=> already materialized. Valid only for materialized derived
tables/views.
*/
bool materialized;
/* I_S: Flags to open_table (e.g. OPEN_TABLE_ONLY or OPEN_VIEW_ONLY) */
uint i_s_requested_object;

View File

@ -143,7 +143,7 @@ static mysql_mutex_t *mrn_LOCK_open;
# define MRN_NEED_M_LOCK_TYPE_CHECK_FOR_WRAPPER_EXTERNAL_LOCK
#endif
#if MYSQL_VERSION_ID >= 50603 && !defined(MRN_MARIADB_P)
#if MYSQL_VERSION_ID >= 50603 || defined(MRN_MARIADB_P)
# define MRN_ORDER_IS_ASC(order) ((order)->direction == ORDER::ORDER_ASC)
#else
# define MRN_ORDER_IS_ASC(order) ((order)->asc)

View File

@ -8134,7 +8134,7 @@ int spider_mysql_handler::append_key_order_for_direct_order_limit_with_alias(
DBUG_PRINT("info",("spider error=%d", error_num));
DBUG_RETURN(error_num);
}
if (order->asc)
if (order->direction == ORDER::ORDER_ASC)
{
if (str->reserve(SPIDER_SQL_COMMA_LEN))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);