Skip to content

Commit 7bcb8e2

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 fb705ac commit 7bcb8e2

8 files changed

+77
-13
lines changed

mysql-test/r/partition_error.result

+29-1
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

+34-1
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

+4-4
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ bool PT_handler_read_base::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::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::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

+1-1
Original file line numberDiff line numberDiff line change
@@ -4089,7 +4089,7 @@ bool PT_subquery::contextualize(Parse_context *pc) {
40894089
if (super::contextualize(pc)) return true;
40904090

40914091
LEX *lex = pc->thd->lex;
4092-
if (!lex->expr_allows_subselect || lex->sql_command == SQLCOM_PURGE) {
4092+
if (!lex->expr_allows_subquery || lex->sql_command == SQLCOM_PURGE) {
40934093
error(pc, pos);
40944094
return true;
40954095
}

sql/parse_tree_partitions.cc

+3
Original file line numberDiff line numberDiff line change
@@ -384,8 +384,11 @@ bool PT_part_type_def::itemize_part_expr(Partition_parse_context *pc,
384384
const POS &pos, Item **item) {
385385
LEX *const lex = pc->thd->lex;
386386
lex->safe_to_cache_query = true;
387+
lex->expr_allows_subquery = false;
387388
if ((*item)->itemize(pc, item)) return true;
388389

390+
lex->expr_allows_subquery = true;
391+
389392
if (!lex->safe_to_cache_query) {
390393
error(pc, pos, ER_THD(pc->thd, ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR));
391394
return true;

sql/sql_lex.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ void LEX::reset() {
450450
m_sql_cmd = nullptr;
451451
query_tables = nullptr;
452452
reset_query_tables_list(false);
453-
expr_allows_subselect = true;
453+
expr_allows_subquery = true;
454454
use_only_table_context = false;
455455
contains_plaintext_password = false;
456456
keep_diagnostics = DA_KEEP_NOTHING;

sql/sql_lex.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -3906,7 +3906,7 @@ struct LEX : public Query_tables_list {
39063906
KILL, HA_READ, CREATE/ALTER EVENT etc. Set this to `false` to get
39073907
syntax error back.
39083908
*/
3909-
bool expr_allows_subselect;
3909+
bool expr_allows_subquery{true};
39103910
/**
39113911
If currently re-parsing a CTE's definition, this is the offset in bytes
39123912
of that definition in the original statement which had the WITH

sql/table.cc

+4-4
Original file line numberDiff line numberDiff line change
@@ -2597,8 +2597,8 @@ bool unpack_value_generator(THD *thd, TABLE *table,
25972597
const CHARSET_INFO *save_character_set_client =
25982598
thd->variables.character_set_client;
25992599
// Subquery is not allowed in generated expression
2600-
const bool save_allow_subselects = thd->lex->expr_allows_subselect;
2601-
thd->lex->expr_allows_subselect = false;
2600+
const bool save_allows_subquery = thd->lex->expr_allows_subquery;
2601+
thd->lex->expr_allows_subquery = false;
26022602
// allow_sum_func is also 0, banning group aggregates and window functions.
26032603
assert(thd->lex->allow_sum_func == 0);
26042604

@@ -2633,7 +2633,7 @@ bool unpack_value_generator(THD *thd, TABLE *table,
26332633
thd->swap_query_arena(save_arena, &val_generator_arena);
26342634
thd->variables.character_set_client = save_character_set_client;
26352635
thd->want_privilege = save_old_privilege;
2636-
thd->lex->expr_allows_subselect = save_allow_subselects;
2636+
thd->lex->expr_allows_subquery = save_allows_subquery;
26372637
};
26382638

26392639
// Properties that need to be restored before leaving the scope if an
@@ -2658,7 +2658,7 @@ bool unpack_value_generator(THD *thd, TABLE *table,
26582658
assert((*val_generator)->expr_item != nullptr &&
26592659
(*val_generator)->expr_str.str == nullptr);
26602660

2661-
thd->lex->expr_allows_subselect = save_allow_subselects;
2661+
thd->lex->expr_allows_subquery = save_allows_subquery;
26622662

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

0 commit comments

Comments
 (0)