Skip to content

Commit d3f19a1

Browse files
committed
Bug#35476172: MySQL server fails when executing query
The problem here is when a partition clause in a CREATE TABLE statement contains a subquery. This is not valid syntax, however our problem here is that the subquery is attached to the main query expression of the SQL command. If this CREATE TABLE statement also contains a source query expression for initial population of the table, this query expression will be resolved before the table is created. But the mentioned subquery is an incomplete structure and the resolving may thus fail. The fix for the problem is to disallow subqueries in partition expressions by clearing the member LEX::expr_allows_subselect while contextualizing the partition expression. This means that such invalid expressions will cause a syntax error. Also renamed the expr_allows_subselect member to the more standard looking expr_allows_subquery. Change-Id: I40796351e37561404d372a10cd8e960c18535512
1 parent 6670ed9 commit d3f19a1

8 files changed

+77
-13
lines changed

mysql-test/r/partition_error.result

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1476,7 +1476,8 @@ ERROR HY000: This partition function is not allowed
14761476
create table t1 (a int)
14771477
partition by range (a + (select count(*) from t1))
14781478
(partition p1 values less than (1));
1479-
ERROR HY000: This partition function is not allowed
1479+
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(select count(*) from t1))
1480+
(partition p1 values less than (1))' at line 2
14801481
create table t1 (a char(10))
14811482
partition by hash (extractvalue(a,'a'));
14821483
ERROR HY000: This partition function is not allowed
@@ -1938,3 +1939,30 @@ Warning 4095 Delimiter ':' in position 2 in datetime value '00:00:00' at row 1 i
19381939
Warning 1441 Datetime function: from_days field overflow
19391940
DROP TABLE t1;
19401941
SET sql_mode=default;
1942+
# Bug#35476172: MySQL server fails when executing query
1943+
CREATE TABLE t0(c1 INTEGER);
1944+
CREATE TABLE t1(c3 INTEGER)
1945+
PARTITION BY HASH ((SELECT c1 FROM t0));
1946+
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(SELECT c1 FROM t0))' at line 2
1947+
CREATE TABLE t1(c3 INTEGER)
1948+
PARTITION BY HASH ((SELECT c1 FROM t0))
1949+
AS TABLE t0;
1950+
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(SELECT c1 FROM t0))
1951+
AS TABLE t0' at line 2
1952+
CREATE TABLE t1(c3 INTEGER)
1953+
PARTITION BY RANGE ((SELECT c1 FROM t0)) (PARTITION a1 VALUES LESS THAN (1));
1954+
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(SELECT c1 FROM t0)) (PARTITION a1 VALUES LESS THAN (1))' at line 2
1955+
CREATE TABLE t1(c3 INTEGER)
1956+
PARTITION BY RANGE ((SELECT c1 FROM t0)) (PARTITION a1 VALUES LESS THAN (1))
1957+
AS TABLE t0;
1958+
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(SELECT c1 FROM t0)) (PARTITION a1 VALUES LESS THAN (1))
1959+
AS TABLE t0' at line 2
1960+
CREATE TABLE t1(c3 INTEGER)
1961+
PARTITION BY LIST ((SELECT c1 FROM t0)) (PARTITION p0 VALUES IN (0));
1962+
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(SELECT c1 FROM t0)) (PARTITION p0 VALUES IN (0))' at line 2
1963+
CREATE TABLE t1(c3 INTEGER)
1964+
PARTITION BY LIST ((SELECT c1 FROM t0)) (PARTITION p0 VALUES IN (0))
1965+
AS TABLE t0;
1966+
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(SELECT c1 FROM t0)) (PARTITION p0 VALUES IN (0))
1967+
AS TABLE t0' at line 2
1968+
DROP TABLE t0;

mysql-test/t/partition_error.test

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1648,7 +1648,7 @@ partition by hash (NOW()+a);
16481648
-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
16491649
create table t1 (a int)
16501650
partition by hash (extract(hour from convert_tz(a, '+00:00', '+00:00')));
1651-
-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
1651+
-- error ER_PARSE_ERROR
16521652
create table t1 (a int)
16531653
partition by range (a + (select count(*) from t1))
16541654
(partition p1 values less than (1));
@@ -2132,3 +2132,36 @@ SELECT FROM_DAYS(4294967660), FROM_DAYS(4294967661), FROM_DAYS(4294967663);
21322132
INSERT t1 VALUES(ADDTIME(0,0)), (FROM_DAYS(3652499));
21332133
DROP TABLE t1;
21342134
SET sql_mode=default;
2135+
2136+
--echo # Bug#35476172: MySQL server fails when executing query
2137+
2138+
CREATE TABLE t0(c1 INTEGER);
2139+
2140+
--error ER_PARSE_ERROR
2141+
CREATE TABLE t1(c3 INTEGER)
2142+
PARTITION BY HASH ((SELECT c1 FROM t0));
2143+
2144+
--error ER_PARSE_ERROR
2145+
CREATE TABLE t1(c3 INTEGER)
2146+
PARTITION BY HASH ((SELECT c1 FROM t0))
2147+
AS TABLE t0;
2148+
2149+
--error ER_PARSE_ERROR
2150+
CREATE TABLE t1(c3 INTEGER)
2151+
PARTITION BY RANGE ((SELECT c1 FROM t0)) (PARTITION a1 VALUES LESS THAN (1));
2152+
2153+
--error ER_PARSE_ERROR
2154+
CREATE TABLE t1(c3 INTEGER)
2155+
PARTITION BY RANGE ((SELECT c1 FROM t0)) (PARTITION a1 VALUES LESS THAN (1))
2156+
AS TABLE t0;
2157+
2158+
--error ER_PARSE_ERROR
2159+
CREATE TABLE t1(c3 INTEGER)
2160+
PARTITION BY LIST ((SELECT c1 FROM t0)) (PARTITION p0 VALUES IN (0));
2161+
2162+
--error ER_PARSE_ERROR
2163+
CREATE TABLE t1(c3 INTEGER)
2164+
PARTITION BY LIST ((SELECT c1 FROM t0)) (PARTITION p0 VALUES IN (0))
2165+
AS TABLE t0;
2166+
2167+
DROP TABLE t0;

sql/parse_tree_handler.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ bool PT_handler_read_base::do_contextualize(Parse_context *pc) {
8585
}
8686

8787
// ban subqueries in WHERE and LIMIT clauses
88-
lex->expr_allows_subselect = false;
88+
lex->expr_allows_subquery = false;
8989

9090
Item *one = new (thd->mem_root) Item_int(1);
9191
if (one == nullptr) return true; // OOM
@@ -107,7 +107,7 @@ bool PT_handler_read_base::do_contextualize(Parse_context *pc) {
107107
if (m_opt_limit_clause != nullptr && m_opt_limit_clause->contextualize(pc))
108108
return true;
109109

110-
lex->expr_allows_subselect = true;
110+
lex->expr_allows_subquery = true;
111111

112112
/* Stored functions are not supported for HANDLER READ. */
113113
if (lex->uses_stored_routines()) {
@@ -142,11 +142,11 @@ Sql_cmd *PT_handler_index_scan::make_cmd(THD *thd) {
142142
Sql_cmd *PT_handler_index_range_scan::make_cmd(THD *thd) {
143143
thd->lex->sql_command = SQLCOM_HA_READ;
144144

145-
thd->lex->expr_allows_subselect = false;
145+
thd->lex->expr_allows_subquery = false;
146146
Parse_context pc(thd, thd->lex->current_query_block());
147147
if (m_keypart_values->contextualize(&pc) || super::do_contextualize(&pc))
148148
return nullptr;
149-
thd->lex->expr_allows_subselect = true;
149+
thd->lex->expr_allows_subquery = true;
150150

151151
return new (thd->mem_root)
152152
Sql_cmd_handler_read(enum_ha_read_modes::RKEY, m_index,

sql/parse_tree_nodes.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4373,7 +4373,7 @@ bool PT_subquery::do_contextualize(Parse_context *pc) {
43734373
if (super::do_contextualize(pc)) return true;
43744374

43754375
LEX *lex = pc->thd->lex;
4376-
if (!lex->expr_allows_subselect || lex->sql_command == SQLCOM_PURGE) {
4376+
if (!lex->expr_allows_subquery || lex->sql_command == SQLCOM_PURGE) {
43774377
error(pc, m_pos);
43784378
return true;
43794379
}

sql/parse_tree_partitions.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,8 +387,11 @@ bool PT_part_type_def::itemize_part_expr(Partition_parse_context *pc,
387387
const POS &pos, Item **item) {
388388
LEX *const lex = pc->thd->lex;
389389
lex->safe_to_cache_query = true;
390+
lex->expr_allows_subquery = false;
390391
if ((*item)->itemize(pc, item)) return true;
391392

393+
lex->expr_allows_subquery = true;
394+
392395
if (!lex->safe_to_cache_query) {
393396
error(pc, pos, ER_THD(pc->thd, ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR));
394397
return true;

sql/sql_lex.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ void LEX::reset() {
442442
m_sql_cmd = nullptr;
443443
query_tables = nullptr;
444444
reset_query_tables_list(false);
445-
expr_allows_subselect = true;
445+
expr_allows_subquery = true;
446446
use_only_table_context = false;
447447
contains_plaintext_password = false;
448448
keep_diagnostics = DA_KEEP_NOTHING;

sql/sql_lex.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4057,7 +4057,7 @@ struct LEX : public Query_tables_list {
40574057
KILL, HA_READ, CREATE/ALTER EVENT etc. Set this to `false` to get
40584058
syntax error back.
40594059
*/
4060-
bool expr_allows_subselect;
4060+
bool expr_allows_subquery{true};
40614061
/**
40624062
If currently re-parsing a CTE's definition, this is the offset in bytes
40634063
of that definition in the original statement which had the WITH

sql/table.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2614,8 +2614,8 @@ bool unpack_value_generator(THD *thd, TABLE *table,
26142614
const CHARSET_INFO *save_character_set_client =
26152615
thd->variables.character_set_client;
26162616
// Subquery is not allowed in generated expression
2617-
const bool save_allow_subselects = thd->lex->expr_allows_subselect;
2618-
thd->lex->expr_allows_subselect = false;
2617+
const bool save_allows_subquery = thd->lex->expr_allows_subquery;
2618+
thd->lex->expr_allows_subquery = false;
26192619
// allow_sum_func is also 0, banning group aggregates and window functions.
26202620
assert(thd->lex->allow_sum_func == 0);
26212621

@@ -2650,7 +2650,7 @@ bool unpack_value_generator(THD *thd, TABLE *table,
26502650
thd->swap_query_arena(save_arena, &val_generator_arena);
26512651
thd->variables.character_set_client = save_character_set_client;
26522652
thd->want_privilege = save_old_privilege;
2653-
thd->lex->expr_allows_subselect = save_allow_subselects;
2653+
thd->lex->expr_allows_subquery = save_allows_subquery;
26542654
};
26552655

26562656
// Properties that need to be restored before leaving the scope if an
@@ -2675,7 +2675,7 @@ bool unpack_value_generator(THD *thd, TABLE *table,
26752675
assert((*val_generator)->expr_item != nullptr &&
26762676
(*val_generator)->expr_str.str == nullptr);
26772677

2678-
thd->lex->expr_allows_subselect = save_allow_subselects;
2678+
thd->lex->expr_allows_subquery = save_allows_subquery;
26792679

26802680
// Set the stored_in_db attribute of the column it depends on (if any)
26812681
if (field != nullptr) (*val_generator)->set_field_stored(field->stored_in_db);

0 commit comments

Comments
 (0)