1
0
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:
Oleg Smirnov
2023-04-03 18:05:44 +07:00
parent 8290a46d50
commit d6c6102cad
7 changed files with 238 additions and 148 deletions

View File

@ -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": { "join_preparation": {
"select_id": 1, "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": [] "steps": []
} }
}, },
{
"join_preparation": {
"select_id": "fake",
"steps": [
{
"expanded_query": "select c AS c from dual"
}
]
}
},
{ {
"join_optimization": { "join_optimization": {
"select_id": "fake", "select_id": "fake",

View File

@ -572,8 +572,8 @@ CREATE TABLE federated.t2 (
a varchar(16) NOT NULL default '' a varchar(16) NOT NULL default ''
) )
DEFAULT CHARSET=latin1; DEFAULT CHARSET=latin1;
INSERT INTO federated.t1 VALUES ('abc'), ('bcd'), ('cde'); INSERT INTO federated.t1 VALUES ('bcd'), ('abc'), ('cde');
INSERT INTO federated.t2 VALUES ('abc'), ('bcd'), ('cde'), ('def'), ('efg'); INSERT INTO federated.t2 VALUES ('cde'), ('efg'), ('abc'), ('bcd'), ('def');
connection master; connection master;
CREATE TABLE federated.t1 ( CREATE TABLE federated.t1 (
a varchar(10) 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; SELECT * from federated.t1 UNION ALL SELECT * from federated.t2;
a a
abc abc
bcd
cde
abc abc
bcd bcd
bcd
cde
cde cde
def def
efg efg
@ -730,10 +730,10 @@ SELECT * FROM
(SELECT * FROM federated.t1 UNION ALL SELECT * FROM federated.t2) q; (SELECT * FROM federated.t1 UNION ALL SELECT * FROM federated.t2) q;
a a
abc abc
bcd
cde
abc abc
bcd bcd
bcd
cde
cde cde
def def
efg efg
@ -861,12 +861,12 @@ SELECT * FROM federated.t1 EXCEPT
SELECT * FROM t4 INTERSECT SELECT * FROM t4 INTERSECT
SELECT * FROM federated.t2; SELECT * FROM federated.t2;
a a
t3_myisam1
t3_myisam2
t3_myisam3
abc abc
bcd bcd
cde cde
t3_myisam1
t3_myisam2
t3_myisam3
EXPLAIN SELECT * FROM t3 UNION ALL EXPLAIN SELECT * FROM t3 UNION ALL
SELECT * FROM federated.t1 EXCEPT SELECT * FROM federated.t1 EXCEPT
SELECT * FROM t4 INTERSECT SELECT * FROM t4 INTERSECT
@ -915,13 +915,13 @@ SELECT * FROM federated.t2) UNION ALL
SELECT * FROM federated.t1; SELECT * FROM federated.t1;
a a
abc abc
abc
bcd bcd
bcd
cde
cde cde
def def
efg efg
abc
bcd
cde
EXPLAIN (SELECT * FROM federated.t1 UNION SELECT * FROM federated.t2) EXPLAIN (SELECT * FROM federated.t1 UNION SELECT * FROM federated.t2)
UNION ALL (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 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); (SELECT * FROM federated.t1 UNION SELECT * FROM federated.t2);
a a
abc abc
bcd
cde
def
efg
abc abc
bcd bcd
bcd
cde
cde cde
def def
def
efg
efg efg
# Union of tables containing different INT data types # Union of tables containing different INT data types
connection slave; connection slave;
@ -955,31 +955,31 @@ CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t12';
# Entire UNION pushdown # Entire UNION pushdown
SELECT a FROM federated.t12 UNION ALL SELECT a FROM federated.t11; SELECT a FROM federated.t12 UNION ALL SELECT a FROM federated.t11;
a a
-1
-32678
0
0 0
1 1
32767 32767
-32678
-1
0
EXPLAIN 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;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL
SELECT a FROM federated.t11 UNION SELECT a FROM federated.t12; SELECT a FROM federated.t11 UNION SELECT a FROM federated.t12;
a a
-32678
-1 -1
-32678
0 0
1 1
32767 32767
# Partial pushdown of SELECTs composing the UNION # Partial pushdown of SELECTs composing the UNION
SELECT a FROM federated.t12 UNION SELECT a FROM federated.t11 UNION SELECT 123; SELECT a FROM federated.t12 UNION SELECT a FROM federated.t11 UNION SELECT 123;
a a
-1
-32678
0 0
1 1
32767
-32678
-1
123 123
32767
EXPLAIN EXPLAIN
SELECT a FROM federated.t12 UNION SELECT a FROM federated.t11 SELECT a FROM federated.t12 UNION SELECT a FROM federated.t11
UNION SELECT 123; UNION SELECT 123;
@ -993,9 +993,9 @@ SELECT 1 UNION ALL
SELECT a FROM federated.t11 EXCEPT SELECT a FROM federated.t11 EXCEPT
SELECT 0; SELECT 0;
a a
-1
-32678 -32678
32767 32767
-1
# Union of tables containing different string data types # Union of tables containing different string data types
connection slave; connection slave;
CREATE TABLE federated.t13 (a CHAR(6)); CREATE TABLE federated.t13 (a CHAR(6));
@ -1011,9 +1011,9 @@ ENGINE="FEDERATED"
CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t14'; CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t14';
SELECT * FROM federated.t13 UNION SELECT * FROM federated.t14; SELECT * FROM federated.t13 UNION SELECT * FROM federated.t14;
a a
common
t13abc t13abc
t13xx t13xx
common
t14abcde t14abcde
t14xyzzz t14xyzzz
EXPLAIN SELECT * FROM federated.t13 UNION SELECT * FROM federated.t14; 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 NULL PUSHED UNION NULL NULL NULL NULL NULL NULL NULL NULL
SELECT * FROM federated.t14 UNION ALL SELECT * FROM federated.t13; SELECT * FROM federated.t14 UNION ALL SELECT * FROM federated.t13;
a a
t14abcde common
t14xyzzz
common common
t13abc t13abc
t13xx t13xx
common t14abcde
t14xyzzz
SELECT * FROM federated.t14 UNION SELECT * FROM federated.t14 UNION
SELECT * FROM federated.t13 UNION SELECT * FROM federated.t13 UNION
SELECT '123456789000'; SELECT '123456789000';
@ -1049,10 +1049,10 @@ SELECT * FROM federated.t13 UNION
SELECT '123456789000' UNION SELECT '123456789000' UNION
SELECT * FROM federated.t14; SELECT * FROM federated.t14;
a a
123456789000
common
t13abc t13abc
t13xx t13xx
common
123456789000
t14abcde t14abcde
t14xyzzz t14xyzzz
# CREATE TABLE .. AS from a pushed UNION # CREATE TABLE .. AS from a pushed UNION
@ -1084,6 +1084,61 @@ a
-1 -1
-32678 -32678
32767 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; connection master;
DROP TABLES federated.t1, federated.t2, t3, t4, t5, t6, federated.t11, DROP TABLES federated.t1, federated.t2, t3, t4, t5, t6, federated.t11,
federated.t12, federated.t13, federated.t14; federated.t12, federated.t13, federated.t14;

View File

@ -398,8 +398,8 @@ CREATE TABLE federated.t2 (
) )
DEFAULT CHARSET=latin1; DEFAULT CHARSET=latin1;
INSERT INTO federated.t1 VALUES ('abc'), ('bcd'), ('cde'); INSERT INTO federated.t1 VALUES ('bcd'), ('abc'), ('cde');
INSERT INTO federated.t2 VALUES ('abc'), ('bcd'), ('cde'), ('def'), ('efg'); INSERT INTO federated.t2 VALUES ('cde'), ('efg'), ('abc'), ('bcd'), ('def');
connection master; 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'); INSERT INTO t4 VALUES ('t4_myisam1'), ('t4_myisam2'), ('t4_myisam3');
--echo # Pushdown of the whole UNION --echo # Pushdown of the whole UNION
--sorted_result
SELECT * from federated.t1 UNION SELECT * from federated.t2; SELECT * from federated.t1 UNION SELECT * from federated.t2;
EXPLAIN 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 --echo # Pushdown of a part of the UNION
--sorted_result
SELECT * from federated.t1 UNION SELECT * from t3; SELECT * from federated.t1 UNION SELECT * from t3;
EXPLAIN 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; SELECT * from federated.t1 UNION ALL SELECT * from federated.t2;
EXPLAIN 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 ANALYZE FORMAT=JSON SELECT * from federated.t1 UNION ALL
SELECT * from federated.t2; SELECT * from federated.t2;
--sorted_result
SELECT * from federated.t1 EXCEPT SELECT * from federated.t2; SELECT * from federated.t1 EXCEPT SELECT * from federated.t2;
EXPLAIN EXTENDED SELECT * from federated.t1 EXCEPT 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 EXPLAIN FORMAT=JSON SELECT * from federated.t1 EXCEPT
SELECT * from federated.t2; SELECT * from federated.t2;
--sorted_result
SELECT * from federated.t1 INTERSECT SELECT * from federated.t2; SELECT * from federated.t1 INTERSECT SELECT * from federated.t2;
EXPLAIN PARTITIONS SELECT * from federated.t1 INTERSECT EXPLAIN PARTITIONS SELECT * from federated.t1 INTERSECT
@ -462,6 +467,7 @@ EXPLAIN FORMAT=JSON SELECT * from federated.t1 INTERSECT
SELECT * from federated.t2; SELECT * from federated.t2;
--echo # More than two SELECTs in a UNIT: --echo # More than two SELECTs in a UNIT:
--sorted_result
SELECT * from federated.t1 INTERSECT SELECT * from federated.t1 INTERSECT
SELECT * from federated.t2 UNION ALL SELECT * from federated.t2 UNION ALL
SELECT * from federated.t2 EXCEPT SELECT * from federated.t2 EXCEPT
@ -486,6 +492,7 @@ ANALYZE
SELECT count(*)+5 from federated.t1; SELECT count(*)+5 from federated.t1;
--echo # UNION inside a derived table: the whole derived table must be pushed --echo # UNION inside a derived table: the whole derived table must be pushed
--sorted_result
SELECT * FROM SELECT * FROM
(SELECT * FROM federated.t1 UNION ALL SELECT * FROM federated.t2) q; (SELECT * FROM federated.t1 UNION ALL SELECT * FROM federated.t2) q;
@ -499,6 +506,7 @@ EXPLAIN
--echo # at the server side --echo # at the server side
--disable_warnings --disable_warnings
--sorted_result
SELECT count(*) FROM federated.t1 UNION SELECT count(*) FROM federated.t1 UNION
SELECT count(*) FROM federated.t1 EXCEPT SELECT count(*) FROM federated.t1 EXCEPT
SELECT count(*)+1 FROM federated.t1 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.t2 EXCEPT
SELECT * from federated.t1"; SELECT * from federated.t1";
--sorted_result
EXECUTE stmt; EXECUTE stmt;
--sorted_result
EXECUTE stmt; EXECUTE stmt;
--sorted_result
EXECUTE stmt; EXECUTE stmt;
PREPARE stmt FROM "EXPLAIN SELECT * from federated.t1 INTERSECT 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.t2 EXCEPT
SELECT * from federated.t1"; SELECT * from federated.t1";
--sorted_result
EXECUTE stmt; EXECUTE stmt;
--sorted_result
EXECUTE stmt; EXECUTE stmt;
--echo # UNIONs of mixed Federated/MyISAM tables, pushing parts of UNIONs --echo # UNIONs of mixed Federated/MyISAM tables, pushing parts of UNIONs
--sorted_result
SELECT * FROM federated.t1 UNION SELECT * FROM t3; SELECT * FROM federated.t1 UNION SELECT * FROM t3;
EXPLAIN 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.t1 UNION ALL
SELECT * FROM t3 EXCEPT SELECT * FROM t3 EXCEPT
SELECT * FROM federated.t2; SELECT * FROM federated.t2;
@ -544,6 +559,7 @@ EXPLAIN SELECT * FROM federated.t1 UNION ALL
SELECT * FROM t3 EXCEPT SELECT * FROM t3 EXCEPT
SELECT * FROM federated.t2; SELECT * FROM federated.t2;
--sorted_result
SELECT * FROM t3 UNION ALL SELECT * FROM t3 UNION ALL
SELECT * FROM federated.t1 EXCEPT SELECT * FROM federated.t1 EXCEPT
SELECT * FROM t4 INTERSECT SELECT * FROM t4 INTERSECT
@ -553,6 +569,7 @@ EXPLAIN SELECT * FROM t3 UNION ALL
SELECT * FROM t4 INTERSECT SELECT * FROM t4 INTERSECT
SELECT * FROM federated.t2; SELECT * FROM federated.t2;
--sorted_result
SELECT * FROM federated.t2 UNION ALL SELECT * FROM federated.t2 UNION ALL
SELECT * FROM t3 EXCEPT SELECT * FROM t3 EXCEPT
SELECT * FROM t4 INTERSECT SELECT * FROM t4 INTERSECT
@ -567,6 +584,7 @@ EXPLAIN (SELECT * FROM federated.t1 UNION
SELECT * FROM federated.t2) UNION ALL SELECT * FROM federated.t2) UNION ALL
SELECT * FROM federated.t1; SELECT * FROM federated.t1;
--sorted_result
(SELECT * FROM federated.t1 UNION (SELECT * FROM federated.t1 UNION
SELECT * FROM federated.t2) UNION ALL SELECT * FROM federated.t2) UNION ALL
SELECT * FROM federated.t1; SELECT * FROM federated.t1;
@ -574,6 +592,7 @@ EXPLAIN (SELECT * FROM federated.t1 UNION
EXPLAIN (SELECT * FROM federated.t1 UNION SELECT * FROM federated.t2) EXPLAIN (SELECT * FROM federated.t1 UNION SELECT * FROM federated.t2)
UNION ALL (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) UNION ALL
(SELECT * FROM federated.t1 UNION SELECT * FROM federated.t2); (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'; CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t12';
--echo # Entire UNION pushdown --echo # Entire UNION pushdown
--sorted_result
SELECT a FROM federated.t12 UNION ALL SELECT a FROM federated.t11; 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; 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; SELECT a FROM federated.t11 UNION SELECT a FROM federated.t12;
--echo # Partial pushdown of SELECTs composing the UNION --echo # Partial pushdown of SELECTs composing the UNION
--sorted_result
SELECT a FROM federated.t12 UNION SELECT a FROM federated.t11 UNION SELECT 123; SELECT a FROM federated.t12 UNION SELECT a FROM federated.t11 UNION SELECT 123;
EXPLAIN EXPLAIN
SELECT a FROM federated.t12 UNION SELECT a FROM federated.t11 SELECT a FROM federated.t12 UNION SELECT a FROM federated.t11
UNION SELECT 123; UNION SELECT 123;
--sorted_result
SELECT a FROM federated.t12 EXCEPT SELECT a FROM federated.t12 EXCEPT
SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT a FROM federated.t11 EXCEPT SELECT a FROM federated.t11 EXCEPT
@ -639,9 +662,11 @@ CREATE TABLE federated.t14 (a VARCHAR(8))
ENGINE="FEDERATED" ENGINE="FEDERATED"
CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t14'; CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t14';
--sorted_result
SELECT * FROM federated.t13 UNION SELECT * FROM federated.t14; SELECT * FROM federated.t13 UNION SELECT * FROM federated.t14;
EXPLAIN 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 ALL SELECT * FROM federated.t13;
SELECT * FROM federated.t14 UNION SELECT * FROM federated.t14 UNION
@ -652,6 +677,7 @@ EXPLAIN SELECT * FROM federated.t14 UNION
SELECT * FROM federated.t13 UNION SELECT * FROM federated.t13 UNION
SELECT '123456789000'; SELECT '123456789000';
--sorted_result
SELECT * FROM federated.t13 UNION SELECT * FROM federated.t13 UNION
SELECT '123456789000' UNION SELECT '123456789000' UNION
SELECT * FROM federated.t14; SELECT * FROM federated.t14;
@ -671,6 +697,41 @@ SHOW CREATE TABLE t6;
--sorted_result --sorted_result
SELECT * FROM t6; 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 # Cleanup
connection master; connection master;
DROP TABLES federated.t1, federated.t2, t3, t4, t5, t6, federated.t11, DROP TABLES federated.t1, federated.t2, t3, t4, t5, t6, federated.t11,

View File

@ -1057,6 +1057,8 @@ private:
bool exec_inner(); bool exec_inner();
bool is_derived_eliminated() const; bool is_derived_eliminated() const;
bool set_direct_union_result(select_result *sel_result); 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; typedef class st_select_lex_unit SELECT_LEX_UNIT;

View File

@ -563,6 +563,7 @@ void JOIN::init(THD *thd_arg, List<Item> &fields_arg,
sjm_scan_tables= 0; sjm_scan_tables= 0;
is_orig_degenerated= false; is_orig_degenerated= false;
with_ties_order_count= 0; 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; unit= unit_arg;
if (prepare_stage2()) if (prepare_stage2())
goto err; goto err;
prepared= true;
DBUG_RETURN(0); // All OK DBUG_RETURN(0); // All OK
@ -5185,7 +5187,8 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds,
} }
else 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))) having, proc_param, select_lex, unit)))
{ {
goto err; goto err;
@ -5211,7 +5214,8 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds,
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
THD_STAGE_INFO(thd, stage_init); THD_STAGE_INFO(thd, stage_init);
thd->lex->used_tables=0; 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))) proc_param, select_lex, unit)))
{ {
goto err; goto err;

View File

@ -1596,6 +1596,8 @@ public:
*/ */
bool impossible_where; bool impossible_where;
bool prepared;
/* /*
All fields used in the query processing. All fields used in the query processing.

View File

@ -1759,24 +1759,6 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
goto err; goto err;
cont: 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 If the query is using select_union_direct, we have postponed
preparation of the underlying select_result until column types preparation of the underlying select_result until column types
@ -1919,37 +1901,6 @@ cont:
if (unlikely(saved_error)) if (unlikely(saved_error))
goto err; 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 else
{ {
@ -1959,23 +1910,45 @@ cont:
*/ */
table->reset_item_list(&item_list, hidden); table->reset_item_list(&item_list, hidden);
} }
if (fake_select_lex != NULL &&
(thd->stmt_arena->is_stmt_prepare() || if (fake_select_lex != NULL)
(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW)))
{ {
if (!fake_select_lex->join && init_prepare_fake_select_lex(thd, TRUE);
!(fake_select_lex->join=
new JOIN(thd, item_list, thd->variables.option_bits, result))) 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(); fake_select_lex->table_list.empty();
DBUG_RETURN(TRUE); 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.elements, // og_num
global_parameters()->order_list.first, // order global_parameters()->order_list.first, // order
false, NULL, NULL, NULL, fake_select_lex, this); 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); 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) bool st_select_lex_unit::set_direct_union_result(select_result *sel_result)
{ {
SELECT_LEX *last= first_select(); SELECT_LEX *last= first_select();
@ -2466,45 +2469,13 @@ bool st_select_lex_unit::exec_inner()
saved_error= true; saved_error= true;
set_limit(global_parameters()); set_limit(global_parameters());
init_prepare_fake_select_lex(thd, first_execution);
JOIN *join= fake_select_lex->join; JOIN *join= fake_select_lex->join;
saved_error= false; saved_error= false;
if (!join) if (!(thd->stmt_arena->is_stmt_prepare() ||
(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW)) &&
first_execution)
{ {
/* save_union_explain_part2(thd->lex->explain);
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);
saved_error= mysql_select(thd, &result_table_list, saved_error= mysql_select(thd, &result_table_list,
item_list, NULL, item_list, NULL,
@ -2527,7 +2498,6 @@ bool st_select_lex_unit::exec_inner()
subquery execution rather than EXPLAIN line production. In order subquery execution rather than EXPLAIN line production. In order
to reset them back, we re-do all of the actions (yes it is ugly): to reset them back, we re-do all of the actions (yes it is ugly):
*/ // psergey-todo: is the above really necessary anymore?? */ // 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, saved_error= mysql_select(thd, &result_table_list, item_list, NULL,
global_parameters()->order_list.elements, global_parameters()->order_list.elements,
global_parameters()->order_list.first, global_parameters()->order_list.first,
@ -2557,7 +2527,6 @@ bool st_select_lex_unit::exec_inner()
} }
} }
thd->lex->current_select= lex_select_save; thd->lex->current_select= lex_select_save;
err:
thd->lex->set_limit_rows_examined(); thd->lex->set_limit_rows_examined();
return saved_error; 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)) if (sl->join->change_result(new_result, old_result))
return true; /* purecov: inspected */ return true; /* purecov: inspected */
} }
/*
If there were a fake_select_lex->join, we would have to change the if (fake_select_lex && fake_select_lex->join)
result of that also, but change_result() is called before such an fake_select_lex->join->change_result(new_result, old_result);
object is created.
*/
DBUG_ASSERT(fake_select_lex == NULL || fake_select_lex->join == NULL);
return false; return false;
} }