mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
MDEV-30828 Prevent pushing down unions with incorrect ORDER BY
Fake_select_lex->join was prepared at the unit execution stage so the validation of fake_select_lex before the unit pushdown was incomplete. That caused pushing down of statements having an incorrect ORDER BY clause. This commit moves preparation of the fake_select_lex->join to the unit prepare() method, before initializing of the pushdown handler, so incorrect clauses error out before being pushed down
This commit is contained in:
@ -11720,6 +11720,16 @@ UPDATE t, v SET t.b = t.a, t.a = v.c WHERE v.c < t.a {
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"join_preparation": {
|
||||
"select_id": "fake",
|
||||
"steps": [
|
||||
{
|
||||
"expanded_query": "select c AS c from dual"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"join_preparation": {
|
||||
"select_id": 1,
|
||||
@ -11967,16 +11977,6 @@ UPDATE t, v SET t.b = t.a, t.a = v.c WHERE v.c < t.a {
|
||||
"steps": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"join_preparation": {
|
||||
"select_id": "fake",
|
||||
"steps": [
|
||||
{
|
||||
"expanded_query": "select c AS c from dual"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"join_optimization": {
|
||||
"select_id": "fake",
|
||||
|
@ -572,8 +572,8 @@ CREATE TABLE federated.t2 (
|
||||
a varchar(16) NOT NULL default ''
|
||||
)
|
||||
DEFAULT CHARSET=latin1;
|
||||
INSERT INTO federated.t1 VALUES ('abc'), ('bcd'), ('cde');
|
||||
INSERT INTO federated.t2 VALUES ('abc'), ('bcd'), ('cde'), ('def'), ('efg');
|
||||
INSERT INTO federated.t1 VALUES ('bcd'), ('abc'), ('cde');
|
||||
INSERT INTO federated.t2 VALUES ('cde'), ('efg'), ('abc'), ('bcd'), ('def');
|
||||
connection master;
|
||||
CREATE TABLE federated.t1 (
|
||||
a varchar(10)
|
||||
@ -617,10 +617,10 @@ NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL
|
||||
SELECT * from federated.t1 UNION ALL SELECT * from federated.t2;
|
||||
a
|
||||
abc
|
||||
bcd
|
||||
cde
|
||||
abc
|
||||
bcd
|
||||
bcd
|
||||
cde
|
||||
cde
|
||||
def
|
||||
efg
|
||||
@ -730,10 +730,10 @@ SELECT * FROM
|
||||
(SELECT * FROM federated.t1 UNION ALL SELECT * FROM federated.t2) q;
|
||||
a
|
||||
abc
|
||||
bcd
|
||||
cde
|
||||
abc
|
||||
bcd
|
||||
bcd
|
||||
cde
|
||||
cde
|
||||
def
|
||||
efg
|
||||
@ -861,12 +861,12 @@ SELECT * FROM federated.t1 EXCEPT
|
||||
SELECT * FROM t4 INTERSECT
|
||||
SELECT * FROM federated.t2;
|
||||
a
|
||||
t3_myisam1
|
||||
t3_myisam2
|
||||
t3_myisam3
|
||||
abc
|
||||
bcd
|
||||
cde
|
||||
t3_myisam1
|
||||
t3_myisam2
|
||||
t3_myisam3
|
||||
EXPLAIN SELECT * FROM t3 UNION ALL
|
||||
SELECT * FROM federated.t1 EXCEPT
|
||||
SELECT * FROM t4 INTERSECT
|
||||
@ -915,13 +915,13 @@ SELECT * FROM federated.t2) UNION ALL
|
||||
SELECT * FROM federated.t1;
|
||||
a
|
||||
abc
|
||||
abc
|
||||
bcd
|
||||
bcd
|
||||
cde
|
||||
cde
|
||||
def
|
||||
efg
|
||||
abc
|
||||
bcd
|
||||
cde
|
||||
EXPLAIN (SELECT * FROM federated.t1 UNION SELECT * FROM federated.t2)
|
||||
UNION ALL (SELECT * FROM federated.t1 UNION SELECT * FROM federated.t2);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
@ -930,14 +930,14 @@ NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL
|
||||
(SELECT * FROM federated.t1 UNION SELECT * FROM federated.t2);
|
||||
a
|
||||
abc
|
||||
bcd
|
||||
cde
|
||||
def
|
||||
efg
|
||||
abc
|
||||
bcd
|
||||
bcd
|
||||
cde
|
||||
cde
|
||||
def
|
||||
def
|
||||
efg
|
||||
efg
|
||||
# Union of tables containing different INT data types
|
||||
connection slave;
|
||||
@ -955,31 +955,31 @@ CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t12';
|
||||
# Entire UNION pushdown
|
||||
SELECT a FROM federated.t12 UNION ALL SELECT a FROM federated.t11;
|
||||
a
|
||||
-1
|
||||
-32678
|
||||
0
|
||||
0
|
||||
1
|
||||
32767
|
||||
-32678
|
||||
-1
|
||||
0
|
||||
EXPLAIN SELECT a FROM federated.t12 UNION ALL SELECT a FROM federated.t11;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL
|
||||
SELECT a FROM federated.t11 UNION SELECT a FROM federated.t12;
|
||||
a
|
||||
-32678
|
||||
-1
|
||||
-32678
|
||||
0
|
||||
1
|
||||
32767
|
||||
# Partial pushdown of SELECTs composing the UNION
|
||||
SELECT a FROM federated.t12 UNION SELECT a FROM federated.t11 UNION SELECT 123;
|
||||
a
|
||||
-1
|
||||
-32678
|
||||
0
|
||||
1
|
||||
32767
|
||||
-32678
|
||||
-1
|
||||
123
|
||||
32767
|
||||
EXPLAIN
|
||||
SELECT a FROM federated.t12 UNION SELECT a FROM federated.t11
|
||||
UNION SELECT 123;
|
||||
@ -993,9 +993,9 @@ SELECT 1 UNION ALL
|
||||
SELECT a FROM federated.t11 EXCEPT
|
||||
SELECT 0;
|
||||
a
|
||||
-1
|
||||
-32678
|
||||
32767
|
||||
-1
|
||||
# Union of tables containing different string data types
|
||||
connection slave;
|
||||
CREATE TABLE federated.t13 (a CHAR(6));
|
||||
@ -1011,9 +1011,9 @@ ENGINE="FEDERATED"
|
||||
CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t14';
|
||||
SELECT * FROM federated.t13 UNION SELECT * FROM federated.t14;
|
||||
a
|
||||
common
|
||||
t13abc
|
||||
t13xx
|
||||
common
|
||||
t14abcde
|
||||
t14xyzzz
|
||||
EXPLAIN SELECT * FROM federated.t13 UNION SELECT * FROM federated.t14;
|
||||
@ -1021,12 +1021,12 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL
|
||||
SELECT * FROM federated.t14 UNION ALL SELECT * FROM federated.t13;
|
||||
a
|
||||
t14abcde
|
||||
t14xyzzz
|
||||
common
|
||||
common
|
||||
t13abc
|
||||
t13xx
|
||||
common
|
||||
t14abcde
|
||||
t14xyzzz
|
||||
SELECT * FROM federated.t14 UNION
|
||||
SELECT * FROM federated.t13 UNION
|
||||
SELECT '123456789000';
|
||||
@ -1049,10 +1049,10 @@ SELECT * FROM federated.t13 UNION
|
||||
SELECT '123456789000' UNION
|
||||
SELECT * FROM federated.t14;
|
||||
a
|
||||
123456789000
|
||||
common
|
||||
t13abc
|
||||
t13xx
|
||||
common
|
||||
123456789000
|
||||
t14abcde
|
||||
t14xyzzz
|
||||
# CREATE TABLE .. AS from a pushed UNION
|
||||
@ -1084,6 +1084,61 @@ a
|
||||
-1
|
||||
-32678
|
||||
32767
|
||||
#
|
||||
# MDEV-30828 ORDER BY clause using an integer (positional argument)
|
||||
#
|
||||
SELECT a FROM federated.t1 UNION SELECT a FROM federated.t2 ORDER BY 1;
|
||||
a
|
||||
abc
|
||||
bcd
|
||||
cde
|
||||
def
|
||||
efg
|
||||
SELECT a FROM federated.t1 UNION ALL SELECT a FROM federated.t2 ORDER BY a DESC;
|
||||
a
|
||||
efg
|
||||
def
|
||||
cde
|
||||
cde
|
||||
bcd
|
||||
bcd
|
||||
abc
|
||||
abc
|
||||
# Check handling of incorrect ORDER BY clause
|
||||
SELECT a FROM federated.t1 UNION SELECT a FROM federated.t2 ORDER BY 2;
|
||||
ERROR 42S22: Unknown column '2' in 'order clause'
|
||||
PREPARE stmt FROM
|
||||
"SELECT a FROM federated.t1 UNION ALL SELECT a FROM federated.t2 ORDER BY 2";
|
||||
ERROR 42S22: Unknown column '2' in 'order clause'
|
||||
SELECT a FROM federated.t1 UNION ALL SELECT a FROM federated.t2 ORDER BY 2,1,3;
|
||||
ERROR 42S22: Unknown column '2' in 'order clause'
|
||||
SELECT a FROM federated.t1 UNION ALL SELECT a FROM federated.t2 ORDER BY t1.a;
|
||||
ERROR 42000: Table 't1' from one of the SELECTs cannot be used in ORDER clause
|
||||
SELECT * from federated.t1 INTERSECT
|
||||
SELECT * from federated.t2 UNION ALL
|
||||
SELECT * from federated.t2 EXCEPT
|
||||
SELECT * from federated.t1
|
||||
ORDER BY 1;
|
||||
a
|
||||
def
|
||||
efg
|
||||
SELECT * from federated.t1 INTERSECT
|
||||
SELECT * from federated.t2 UNION ALL
|
||||
SELECT * from federated.t2 EXCEPT
|
||||
SELECT * from federated.t1
|
||||
ORDER BY 3;
|
||||
ERROR 42S22: Unknown column '3' in 'order clause'
|
||||
# UNION of mixed Federated/MyISAM tables, pushing parts of UNIONs
|
||||
SELECT * FROM federated.t1 UNION SELECT * FROM t3 ORDER BY a;
|
||||
a
|
||||
abc
|
||||
bcd
|
||||
cde
|
||||
t3_myisam1
|
||||
t3_myisam2
|
||||
t3_myisam3
|
||||
SELECT * FROM federated.t1 UNION SELECT * FROM t3 ORDER BY 2;
|
||||
ERROR 42S22: Unknown column '2' in 'order clause'
|
||||
connection master;
|
||||
DROP TABLES federated.t1, federated.t2, t3, t4, t5, t6, federated.t11,
|
||||
federated.t12, federated.t13, federated.t14;
|
||||
|
@ -398,8 +398,8 @@ CREATE TABLE federated.t2 (
|
||||
)
|
||||
DEFAULT CHARSET=latin1;
|
||||
|
||||
INSERT INTO federated.t1 VALUES ('abc'), ('bcd'), ('cde');
|
||||
INSERT INTO federated.t2 VALUES ('abc'), ('bcd'), ('cde'), ('def'), ('efg');
|
||||
INSERT INTO federated.t1 VALUES ('bcd'), ('abc'), ('cde');
|
||||
INSERT INTO federated.t2 VALUES ('cde'), ('efg'), ('abc'), ('bcd'), ('def');
|
||||
|
||||
connection master;
|
||||
|
||||
@ -426,13 +426,16 @@ INSERT INTO t3 VALUES ('t3_myisam1'), ('t3_myisam2'), ('t3_myisam3');
|
||||
INSERT INTO t4 VALUES ('t4_myisam1'), ('t4_myisam2'), ('t4_myisam3');
|
||||
|
||||
--echo # Pushdown of the whole UNION
|
||||
--sorted_result
|
||||
SELECT * from federated.t1 UNION SELECT * from federated.t2;
|
||||
EXPLAIN SELECT * from federated.t1 UNION SELECT * from federated.t2;
|
||||
|
||||
--echo # Pushdown of a part of the UNION
|
||||
--sorted_result
|
||||
SELECT * from federated.t1 UNION SELECT * from t3;
|
||||
EXPLAIN SELECT * from federated.t1 UNION SELECT * from t3;
|
||||
|
||||
--sorted_result
|
||||
SELECT * from federated.t1 UNION ALL SELECT * from federated.t2;
|
||||
EXPLAIN SELECT * from federated.t1 UNION ALL SELECT * from federated.t2;
|
||||
|
||||
@ -445,6 +448,7 @@ ANALYZE SELECT * from federated.t1 UNION ALL SELECT * from federated.t2;
|
||||
ANALYZE FORMAT=JSON SELECT * from federated.t1 UNION ALL
|
||||
SELECT * from federated.t2;
|
||||
|
||||
--sorted_result
|
||||
SELECT * from federated.t1 EXCEPT SELECT * from federated.t2;
|
||||
|
||||
EXPLAIN EXTENDED SELECT * from federated.t1 EXCEPT
|
||||
@ -453,6 +457,7 @@ EXPLAIN EXTENDED SELECT * from federated.t1 EXCEPT
|
||||
EXPLAIN FORMAT=JSON SELECT * from federated.t1 EXCEPT
|
||||
SELECT * from federated.t2;
|
||||
|
||||
--sorted_result
|
||||
SELECT * from federated.t1 INTERSECT SELECT * from federated.t2;
|
||||
|
||||
EXPLAIN PARTITIONS SELECT * from federated.t1 INTERSECT
|
||||
@ -462,6 +467,7 @@ EXPLAIN FORMAT=JSON SELECT * from federated.t1 INTERSECT
|
||||
SELECT * from federated.t2;
|
||||
|
||||
--echo # More than two SELECTs in a UNIT:
|
||||
--sorted_result
|
||||
SELECT * from federated.t1 INTERSECT
|
||||
SELECT * from federated.t2 UNION ALL
|
||||
SELECT * from federated.t2 EXCEPT
|
||||
@ -486,6 +492,7 @@ ANALYZE
|
||||
SELECT count(*)+5 from federated.t1;
|
||||
|
||||
--echo # UNION inside a derived table: the whole derived table must be pushed
|
||||
--sorted_result
|
||||
SELECT * FROM
|
||||
(SELECT * FROM federated.t1 UNION ALL SELECT * FROM federated.t2) q;
|
||||
|
||||
@ -499,6 +506,7 @@ EXPLAIN
|
||||
--echo # at the server side
|
||||
|
||||
--disable_warnings
|
||||
--sorted_result
|
||||
SELECT count(*) FROM federated.t1 UNION
|
||||
SELECT count(*) FROM federated.t1 EXCEPT
|
||||
SELECT count(*)+1 FROM federated.t1
|
||||
@ -521,8 +529,11 @@ PREPARE stmt FROM "SELECT * from federated.t1 INTERSECT
|
||||
SELECT * from federated.t2 EXCEPT
|
||||
SELECT * from federated.t1";
|
||||
|
||||
--sorted_result
|
||||
EXECUTE stmt;
|
||||
--sorted_result
|
||||
EXECUTE stmt;
|
||||
--sorted_result
|
||||
EXECUTE stmt;
|
||||
|
||||
PREPARE stmt FROM "EXPLAIN SELECT * from federated.t1 INTERSECT
|
||||
@ -530,13 +541,17 @@ PREPARE stmt FROM "EXPLAIN SELECT * from federated.t1 INTERSECT
|
||||
SELECT * from federated.t2 EXCEPT
|
||||
SELECT * from federated.t1";
|
||||
|
||||
--sorted_result
|
||||
EXECUTE stmt;
|
||||
--sorted_result
|
||||
EXECUTE stmt;
|
||||
|
||||
--echo # UNIONs of mixed Federated/MyISAM tables, pushing parts of UNIONs
|
||||
--sorted_result
|
||||
SELECT * FROM federated.t1 UNION SELECT * FROM t3;
|
||||
EXPLAIN SELECT * FROM federated.t1 UNION SELECT * FROM t3;
|
||||
|
||||
--sorted_result
|
||||
SELECT * FROM federated.t1 UNION ALL
|
||||
SELECT * FROM t3 EXCEPT
|
||||
SELECT * FROM federated.t2;
|
||||
@ -544,6 +559,7 @@ EXPLAIN SELECT * FROM federated.t1 UNION ALL
|
||||
SELECT * FROM t3 EXCEPT
|
||||
SELECT * FROM federated.t2;
|
||||
|
||||
--sorted_result
|
||||
SELECT * FROM t3 UNION ALL
|
||||
SELECT * FROM federated.t1 EXCEPT
|
||||
SELECT * FROM t4 INTERSECT
|
||||
@ -553,6 +569,7 @@ EXPLAIN SELECT * FROM t3 UNION ALL
|
||||
SELECT * FROM t4 INTERSECT
|
||||
SELECT * FROM federated.t2;
|
||||
|
||||
--sorted_result
|
||||
SELECT * FROM federated.t2 UNION ALL
|
||||
SELECT * FROM t3 EXCEPT
|
||||
SELECT * FROM t4 INTERSECT
|
||||
@ -567,6 +584,7 @@ EXPLAIN (SELECT * FROM federated.t1 UNION
|
||||
SELECT * FROM federated.t2) UNION ALL
|
||||
SELECT * FROM federated.t1;
|
||||
|
||||
--sorted_result
|
||||
(SELECT * FROM federated.t1 UNION
|
||||
SELECT * FROM federated.t2) UNION ALL
|
||||
SELECT * FROM federated.t1;
|
||||
@ -574,6 +592,7 @@ EXPLAIN (SELECT * FROM federated.t1 UNION
|
||||
EXPLAIN (SELECT * FROM federated.t1 UNION SELECT * FROM federated.t2)
|
||||
UNION ALL (SELECT * FROM federated.t1 UNION SELECT * FROM federated.t2);
|
||||
|
||||
--sorted_result
|
||||
(SELECT * FROM federated.t1 UNION SELECT * FROM federated.t2) UNION ALL
|
||||
(SELECT * FROM federated.t1 UNION SELECT * FROM federated.t2);
|
||||
|
||||
@ -601,17 +620,21 @@ ENGINE="FEDERATED"
|
||||
CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t12';
|
||||
|
||||
--echo # Entire UNION pushdown
|
||||
--sorted_result
|
||||
SELECT a FROM federated.t12 UNION ALL SELECT a FROM federated.t11;
|
||||
EXPLAIN SELECT a FROM federated.t12 UNION ALL SELECT a FROM federated.t11;
|
||||
|
||||
--sorted_result
|
||||
SELECT a FROM federated.t11 UNION SELECT a FROM federated.t12;
|
||||
|
||||
--echo # Partial pushdown of SELECTs composing the UNION
|
||||
--sorted_result
|
||||
SELECT a FROM federated.t12 UNION SELECT a FROM federated.t11 UNION SELECT 123;
|
||||
EXPLAIN
|
||||
SELECT a FROM federated.t12 UNION SELECT a FROM federated.t11
|
||||
UNION SELECT 123;
|
||||
|
||||
--sorted_result
|
||||
SELECT a FROM federated.t12 EXCEPT
|
||||
SELECT 1 UNION ALL
|
||||
SELECT a FROM federated.t11 EXCEPT
|
||||
@ -639,9 +662,11 @@ CREATE TABLE federated.t14 (a VARCHAR(8))
|
||||
ENGINE="FEDERATED"
|
||||
CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t14';
|
||||
|
||||
--sorted_result
|
||||
SELECT * FROM federated.t13 UNION SELECT * FROM federated.t14;
|
||||
EXPLAIN SELECT * FROM federated.t13 UNION SELECT * FROM federated.t14;
|
||||
|
||||
--sorted_result
|
||||
SELECT * FROM federated.t14 UNION ALL SELECT * FROM federated.t13;
|
||||
|
||||
SELECT * FROM federated.t14 UNION
|
||||
@ -652,6 +677,7 @@ EXPLAIN SELECT * FROM federated.t14 UNION
|
||||
SELECT * FROM federated.t13 UNION
|
||||
SELECT '123456789000';
|
||||
|
||||
--sorted_result
|
||||
SELECT * FROM federated.t13 UNION
|
||||
SELECT '123456789000' UNION
|
||||
SELECT * FROM federated.t14;
|
||||
@ -671,6 +697,41 @@ SHOW CREATE TABLE t6;
|
||||
--sorted_result
|
||||
SELECT * FROM t6;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-30828 ORDER BY clause using an integer (positional argument)
|
||||
--echo #
|
||||
SELECT a FROM federated.t1 UNION SELECT a FROM federated.t2 ORDER BY 1;
|
||||
|
||||
SELECT a FROM federated.t1 UNION ALL SELECT a FROM federated.t2 ORDER BY a DESC;
|
||||
|
||||
--echo # Check handling of incorrect ORDER BY clause
|
||||
--error ER_BAD_FIELD_ERROR
|
||||
SELECT a FROM federated.t1 UNION SELECT a FROM federated.t2 ORDER BY 2;
|
||||
--error ER_BAD_FIELD_ERROR
|
||||
PREPARE stmt FROM
|
||||
"SELECT a FROM federated.t1 UNION ALL SELECT a FROM federated.t2 ORDER BY 2";
|
||||
|
||||
--error ER_BAD_FIELD_ERROR
|
||||
SELECT a FROM federated.t1 UNION ALL SELECT a FROM federated.t2 ORDER BY 2,1,3;
|
||||
--error ER_TABLENAME_NOT_ALLOWED_HERE
|
||||
SELECT a FROM federated.t1 UNION ALL SELECT a FROM federated.t2 ORDER BY t1.a;
|
||||
SELECT * from federated.t1 INTERSECT
|
||||
SELECT * from federated.t2 UNION ALL
|
||||
SELECT * from federated.t2 EXCEPT
|
||||
SELECT * from federated.t1
|
||||
ORDER BY 1;
|
||||
--error ER_BAD_FIELD_ERROR
|
||||
SELECT * from federated.t1 INTERSECT
|
||||
SELECT * from federated.t2 UNION ALL
|
||||
SELECT * from federated.t2 EXCEPT
|
||||
SELECT * from federated.t1
|
||||
ORDER BY 3;
|
||||
--echo # UNION of mixed Federated/MyISAM tables, pushing parts of UNIONs
|
||||
SELECT * FROM federated.t1 UNION SELECT * FROM t3 ORDER BY a;
|
||||
--error ER_BAD_FIELD_ERROR
|
||||
SELECT * FROM federated.t1 UNION SELECT * FROM t3 ORDER BY 2;
|
||||
|
||||
|
||||
# Cleanup
|
||||
connection master;
|
||||
DROP TABLES federated.t1, federated.t2, t3, t4, t5, t6, federated.t11,
|
||||
|
@ -1057,6 +1057,8 @@ private:
|
||||
bool exec_inner();
|
||||
bool is_derived_eliminated() const;
|
||||
bool set_direct_union_result(select_result *sel_result);
|
||||
bool prepare_pushdown(bool use_direct_union_result,
|
||||
select_result *sel_result);
|
||||
};
|
||||
|
||||
typedef class st_select_lex_unit SELECT_LEX_UNIT;
|
||||
|
@ -563,6 +563,7 @@ void JOIN::init(THD *thd_arg, List<Item> &fields_arg,
|
||||
sjm_scan_tables= 0;
|
||||
is_orig_degenerated= false;
|
||||
with_ties_order_count= 0;
|
||||
prepared= false;
|
||||
};
|
||||
|
||||
|
||||
@ -1816,6 +1817,7 @@ JOIN::prepare(TABLE_LIST *tables_init, COND *conds_init, uint og_num,
|
||||
unit= unit_arg;
|
||||
if (prepare_stage2())
|
||||
goto err;
|
||||
prepared= true;
|
||||
|
||||
DBUG_RETURN(0); // All OK
|
||||
|
||||
@ -5185,7 +5187,8 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds,
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((err= join->prepare(tables, conds, og_num, order, false, group,
|
||||
if (!join->prepared &&
|
||||
(err= join->prepare(tables, conds, og_num, order, false, group,
|
||||
having, proc_param, select_lex, unit)))
|
||||
{
|
||||
goto err;
|
||||
@ -5211,7 +5214,8 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds,
|
||||
DBUG_RETURN(TRUE);
|
||||
THD_STAGE_INFO(thd, stage_init);
|
||||
thd->lex->used_tables=0;
|
||||
if ((err= join->prepare(tables, conds, og_num, order, false, group, having,
|
||||
if (!join->prepared &&
|
||||
(err= join->prepare(tables, conds, og_num, order, false, group, having,
|
||||
proc_param, select_lex, unit)))
|
||||
{
|
||||
goto err;
|
||||
|
@ -1596,6 +1596,8 @@ public:
|
||||
*/
|
||||
bool impossible_where;
|
||||
|
||||
bool prepared;
|
||||
|
||||
/*
|
||||
All fields used in the query processing.
|
||||
|
||||
|
174
sql/sql_union.cc
174
sql/sql_union.cc
@ -1759,24 +1759,6 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
|
||||
goto err;
|
||||
|
||||
cont:
|
||||
pushdown_unit= find_unit_handler(thd, this);
|
||||
if (pushdown_unit)
|
||||
{
|
||||
if (unlikely(pushdown_unit->prepare()))
|
||||
goto err;
|
||||
/*
|
||||
Always use select_union_direct result for pushed down units, overwrite
|
||||
the previous union_result unless select_union_direct is already used
|
||||
*/
|
||||
if (!use_direct_union_result)
|
||||
{
|
||||
if (unlikely(set_direct_union_result(sel_result)))
|
||||
goto err;
|
||||
fake_select_lex= NULL;
|
||||
instantiate_tmp_table= false;
|
||||
use_direct_union_result= true;
|
||||
}
|
||||
}
|
||||
/*
|
||||
If the query is using select_union_direct, we have postponed
|
||||
preparation of the underlying select_result until column types
|
||||
@ -1919,37 +1901,6 @@ cont:
|
||||
|
||||
if (unlikely(saved_error))
|
||||
goto err;
|
||||
|
||||
if (fake_select_lex != NULL &&
|
||||
(thd->stmt_arena->is_stmt_prepare() ||
|
||||
(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW)))
|
||||
{
|
||||
/* Validate the global parameters of this union */
|
||||
|
||||
init_prepare_fake_select_lex(thd, TRUE);
|
||||
/* Should be done only once (the only item_list per statement) */
|
||||
DBUG_ASSERT(fake_select_lex->join == 0);
|
||||
if (!(fake_select_lex->join= new JOIN(thd, item_list, thd->variables.option_bits,
|
||||
result)))
|
||||
{
|
||||
fake_select_lex->table_list.empty();
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
Fake st_select_lex should have item list for correct ref_array
|
||||
allocation.
|
||||
*/
|
||||
fake_select_lex->item_list= item_list;
|
||||
|
||||
thd->lex->current_select= fake_select_lex;
|
||||
|
||||
/*
|
||||
We need to add up n_sum_items in order to make the correct
|
||||
allocation in setup_ref_array().
|
||||
*/
|
||||
fake_select_lex->n_child_sum_items+= global_parameters()->n_sum_items;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1959,23 +1910,45 @@ cont:
|
||||
*/
|
||||
table->reset_item_list(&item_list, hidden);
|
||||
}
|
||||
if (fake_select_lex != NULL &&
|
||||
(thd->stmt_arena->is_stmt_prepare() ||
|
||||
(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW)))
|
||||
|
||||
if (fake_select_lex != NULL)
|
||||
{
|
||||
if (!fake_select_lex->join &&
|
||||
!(fake_select_lex->join=
|
||||
new JOIN(thd, item_list, thd->variables.option_bits, result)))
|
||||
init_prepare_fake_select_lex(thd, TRUE);
|
||||
|
||||
DBUG_ASSERT(fake_select_lex->join == 0);
|
||||
if (!(fake_select_lex->join= new JOIN(thd, item_list, options, result)))
|
||||
{
|
||||
fake_select_lex->table_list.empty();
|
||||
DBUG_RETURN(TRUE);
|
||||
fake_select_lex->table_list.empty();
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
saved_error= fake_select_lex->join->
|
||||
prepare(fake_select_lex->table_list.first, 0,
|
||||
|
||||
/*
|
||||
Fake st_select_lex should have item list for correct ref_array
|
||||
allocation.
|
||||
*/
|
||||
fake_select_lex->item_list= item_list;
|
||||
|
||||
thd->lex->current_select= fake_select_lex;
|
||||
|
||||
/*
|
||||
We need to add up n_sum_items in order to make the correct
|
||||
allocation in setup_ref_array().
|
||||
*/
|
||||
fake_select_lex->n_child_sum_items+= global_parameters()->n_sum_items;
|
||||
fake_select_lex->join->no_const_tables= TRUE;
|
||||
saved_error= fake_select_lex->join->prepare(
|
||||
fake_select_lex->table_list.first, 0,
|
||||
global_parameters()->order_list.elements, // og_num
|
||||
global_parameters()->order_list.first, // order
|
||||
false, NULL, NULL, NULL, fake_select_lex, this);
|
||||
fake_select_lex->table_list.empty();
|
||||
}
|
||||
|
||||
if (!thd->lex->is_view_context_analysis())
|
||||
pushdown_unit= find_unit_handler(thd, this);
|
||||
if (pushdown_unit)
|
||||
{
|
||||
if (prepare_pushdown(use_direct_union_result, sel_result))
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1989,6 +1962,36 @@ err:
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief
|
||||
Prepare st_select_lex_unit for the pushdown handler processing
|
||||
@details
|
||||
Creates and initializes data structures required for processing of the
|
||||
pushdown handler. Validates fake_select_lex then discards it and sets
|
||||
direct union result which is necessary for pushed down statements
|
||||
@return
|
||||
false - success
|
||||
true - failure
|
||||
*/
|
||||
bool st_select_lex_unit::prepare_pushdown(bool use_direct_union_result,
|
||||
select_result *sel_result)
|
||||
{
|
||||
if (unlikely(pushdown_unit->prepare()))
|
||||
return true;
|
||||
|
||||
if(!use_direct_union_result)
|
||||
{
|
||||
/*
|
||||
Always use select_union_direct result for pushed down units, overwrite
|
||||
the previous union_result unless select_union_direct is already used
|
||||
*/
|
||||
if (unlikely(set_direct_union_result(sel_result)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool st_select_lex_unit::set_direct_union_result(select_result *sel_result)
|
||||
{
|
||||
SELECT_LEX *last= first_select();
|
||||
@ -2466,45 +2469,13 @@ bool st_select_lex_unit::exec_inner()
|
||||
saved_error= true;
|
||||
|
||||
set_limit(global_parameters());
|
||||
init_prepare_fake_select_lex(thd, first_execution);
|
||||
JOIN *join= fake_select_lex->join;
|
||||
saved_error= false;
|
||||
if (!join)
|
||||
if (!(thd->stmt_arena->is_stmt_prepare() ||
|
||||
(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW)) &&
|
||||
first_execution)
|
||||
{
|
||||
/*
|
||||
allocate JOIN for fake select only once (prevent
|
||||
mysql_select automatic allocation)
|
||||
TODO: The above is nonsense. mysql_select() will not allocate the
|
||||
join if one already exists. There must be some other reason why we
|
||||
don't let it allocate the join. Perhaps this is because we need
|
||||
some special parameter values passed to join constructor?
|
||||
*/
|
||||
if (unlikely(!(fake_select_lex->join=
|
||||
new JOIN(thd, item_list, fake_select_lex->options,
|
||||
result))))
|
||||
{
|
||||
fake_select_lex->table_list.empty();
|
||||
goto err;
|
||||
}
|
||||
fake_select_lex->join->no_const_tables= TRUE;
|
||||
|
||||
/*
|
||||
Fake st_select_lex should have item list for correct ref_array
|
||||
allocation.
|
||||
*/
|
||||
fake_select_lex->item_list= item_list;
|
||||
|
||||
/*
|
||||
We need to add up n_sum_items in order to make the correct
|
||||
allocation in setup_ref_array().
|
||||
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.is_null())
|
||||
fake_select_lex->n_child_sum_items+= global_parameters()->n_sum_items;
|
||||
|
||||
if (!was_executed)
|
||||
save_union_explain_part2(thd->lex->explain);
|
||||
save_union_explain_part2(thd->lex->explain);
|
||||
|
||||
saved_error= mysql_select(thd, &result_table_list,
|
||||
item_list, NULL,
|
||||
@ -2527,7 +2498,6 @@ bool st_select_lex_unit::exec_inner()
|
||||
subquery execution rather than EXPLAIN line production. In order
|
||||
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, &result_table_list, item_list, NULL,
|
||||
global_parameters()->order_list.elements,
|
||||
global_parameters()->order_list.first,
|
||||
@ -2557,7 +2527,6 @@ bool st_select_lex_unit::exec_inner()
|
||||
}
|
||||
}
|
||||
thd->lex->current_select= lex_select_save;
|
||||
err:
|
||||
thd->lex->set_limit_rows_examined();
|
||||
return saved_error;
|
||||
}
|
||||
@ -2822,12 +2791,9 @@ bool st_select_lex_unit::change_result(select_result_interceptor *new_result,
|
||||
if (sl->join->change_result(new_result, old_result))
|
||||
return true; /* purecov: inspected */
|
||||
}
|
||||
/*
|
||||
If there were a fake_select_lex->join, we would have to change the
|
||||
result of that also, but change_result() is called before such an
|
||||
object is created.
|
||||
*/
|
||||
DBUG_ASSERT(fake_select_lex == NULL || fake_select_lex->join == NULL);
|
||||
|
||||
if (fake_select_lex && fake_select_lex->join)
|
||||
fake_select_lex->join->change_result(new_result, old_result);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user