summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2021-03-03 22:48:39 -0800
committerIgor Babaev <igor@askmonty.org>2021-03-03 22:49:29 -0800
commit08d8bce583227a25b4f646fa9a836f7893badd9a (patch)
tree9cc6227d699b7ae4e267085663f30bd4b6d4e318 /sql
parent5bd994b0d56d11bf62717a84172c49ca9ed37de4 (diff)
downloadmariadb-git-08d8bce583227a25b4f646fa9a836f7893badd9a.tar.gz
MDEV-22786 Crashes with nested table value constructors
The bug caused crashes of the server when processing queries with nested table value constructors (TVC) . It happened because the grammar rules to parse TVC used the same global lists for both nested TVC and nesting TVC. As a result invalid select trees were constructed for queries with nested TVC and this led to crashes at the prepare stage. This patch provides its own lists structures for each TVC nest level. Besides the patch fixes a bug in the function wrap_tvc() that missed inheritance of the SELECT_LEX::exclude_from_table_unique_test for selects that wrapped TVCs. This inheritance is critical for specifications of derived tables that employ nested TVCs. Approved by dmitry.shulga@mariadb.com
Diffstat (limited to 'sql')
-rw-r--r--sql/sql_lex.cc45
-rw-r--r--sql/sql_lex.h12
-rw-r--r--sql/sql_tvc.cc2
-rw-r--r--sql/sql_yacc.yy3
-rw-r--r--sql/sql_yacc_ora.yy3
5 files changed, 52 insertions, 13 deletions
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 70d795c145d..c2bc8386404 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -2421,6 +2421,8 @@ void st_select_lex::init_select()
with_dep= 0;
join= 0;
lock_type= TL_READ_DEFAULT;
+ save_many_values.empty();
+ save_insert_list= 0;
tvc= 0;
in_funcs.empty();
curr_tvc_name= 0;
@@ -8302,16 +8304,52 @@ bool LEX::last_field_generated_always_as_row_end()
}
+void LEX::save_values_list_state()
+{
+ current_select->save_many_values= many_values;
+ current_select->save_insert_list= insert_list;
+}
+
+
+void LEX::restore_values_list_state()
+{
+ many_values= current_select->save_many_values;
+ insert_list= current_select->save_insert_list;
+}
+
+
+void LEX::tvc_start()
+{
+ if (current_select == &select_lex)
+ mysql_init_select(this);
+ else
+ save_values_list_state();
+ many_values.empty();
+ insert_list= 0;
+}
+
+
+bool LEX::tvc_start_derived()
+{
+ if (current_select->linkage == GLOBAL_OPTIONS_TYPE ||
+ unlikely(mysql_new_select(this, 1, NULL)))
+ return true;
+ save_values_list_state();
+ many_values.empty();
+ insert_list= 0;
+ return false;
+}
+
+
bool LEX::tvc_finalize()
{
- mysql_init_select(this);
if (unlikely(!(current_select->tvc=
new (thd->mem_root)
table_value_constr(many_values,
current_select,
current_select->options))))
return true;
- many_values.empty();
+ restore_values_list_state();
if (!current_select->master_unit()->fake_select_lex)
current_select->master_unit()->add_fake_select_lex(thd);
return false;
@@ -8326,9 +8364,6 @@ bool LEX::tvc_finalize_derived()
thd->parse_error();
return true;
}
- if (current_select->linkage == GLOBAL_OPTIONS_TYPE ||
- unlikely(mysql_new_select(this, 1, NULL)))
- return true;
current_select->linkage= DERIVED_TABLE_TYPE;
return tvc_finalize();
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 979e212c1f6..474f3174ac9 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1176,6 +1176,8 @@ public:
/* it is for correct printing SELECT options */
thr_lock_type lock_type;
+ List<List_item> save_many_values;
+ List<Item> *save_insert_list;
table_value_constr *tvc;
bool in_tvc;
@@ -4046,12 +4048,10 @@ public:
return false;
}
- void tvc_start()
- {
- field_list.empty();
- many_values.empty();
- insert_list= 0;
- }
+ void save_values_list_state();
+ void restore_values_list_state();
+ void tvc_start();
+ bool tvc_start_derived();
bool tvc_finalize();
bool tvc_finalize_derived();
diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc
index cb056b0e15f..96c5223ee6a 100644
--- a/sql/sql_tvc.cc
+++ b/sql/sql_tvc.cc
@@ -673,6 +673,8 @@ st_select_lex *wrap_tvc(THD *thd, st_select_lex *tvc_sl,
wrapper_sl->nest_level= tvc_sl->nest_level;
wrapper_sl->parsing_place= tvc_sl->parsing_place;
wrapper_sl->linkage= tvc_sl->linkage;
+ wrapper_sl->exclude_from_table_unique_test=
+ tvc_sl->exclude_from_table_unique_test;
lex->current_select= wrapper_sl;
item= new (thd->mem_root) Item_field(thd, &wrapper_sl->context,
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 88f12e97bfa..b26e2ddbf1b 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -12334,7 +12334,8 @@ derived_query_specification:
derived_table_value_constructor:
VALUES
{
- Lex->tvc_start();
+ if (Lex->tvc_start_derived())
+ MYSQL_YYABORT;
}
values_list
{
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index eaeaf2e5e7e..4af034db921 100644
--- a/sql/sql_yacc_ora.yy
+++ b/sql/sql_yacc_ora.yy
@@ -12272,7 +12272,8 @@ derived_query_specification:
derived_table_value_constructor:
VALUES
{
- Lex->tvc_start();
+ if (Lex->tvc_start_derived())
+ MYSQL_YYABORT;
}
values_list
{