diff options
author | Igor Babaev <igor@askmonty.org> | 2022-04-25 18:08:57 -0700 |
---|---|---|
committer | Igor Babaev <igor@askmonty.org> | 2022-04-27 08:23:01 -0700 |
commit | 39feab3cd31b5414aa9b428eaba915c251ac34a2 (patch) | |
tree | d30244a324d73d724ce0c50b1d72a46467a2d3d5 | |
parent | fccca49997320bafe1282c758a5143f88b6e0e0f (diff) | |
download | mariadb-git-39feab3cd31b5414aa9b428eaba915c251ac34a2.tar.gz |
MDEV-26412 Server crash in Item_field::fix_outer_field for INSERT SELECT
IF an INSERT/REPLACE SELECT statement contained an ON expression in the top
level select and this expression used a subquery with a column reference
that could not be resolved then an attempt to resolve this reference as
an outer reference caused a crash of the server. This happened because the
outer context field in the Name_resolution_context structure was not set
to NULL for such references. Rather it pointed to the first element in
the select_stack.
Note that starting from 10.4 we cannot use the SELECT_LEX::outer_select()
method when parsing a SELECT construct.
Approved by Oleksandr Byelkin <sanja@mariadb.com>
-rw-r--r-- | mysql-test/main/insert.result | 16 | ||||
-rw-r--r-- | mysql-test/main/insert.test | 22 | ||||
-rw-r--r-- | sql/sql_lex.cc | 1 | ||||
-rw-r--r-- | sql/sql_lex.h | 17 | ||||
-rw-r--r-- | sql/sql_parse.cc | 4 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 2 |
6 files changed, 59 insertions, 3 deletions
diff --git a/mysql-test/main/insert.result b/mysql-test/main/insert.result index 4aea81262d2..1062ddd6a94 100644 --- a/mysql-test/main/insert.result +++ b/mysql-test/main/insert.result @@ -751,3 +751,19 @@ REPLACE INTO v1 SET f = NULL; ERROR 22007: Truncated incorrect DOUBLE value: 'foo' DROP VIEW v1; DROP TABLE t1; +# End of 10.0 tests +# +# MDEV-26412: INSERT CREATE with subquery in ON expression +# +create table t1 (a int); +create table t2 (b int); +create table t3 (c int); +create table t4 (d1 int, d2 int); +insert into t4 +select * from t1 left join t2 on (select t1.i from t3); +ERROR 42S22: Unknown column 't1.i' in 'field list' +replace t4 +select * from t1 left join t2 on (select t1.i from t3); +ERROR 42S22: Unknown column 't1.i' in 'field list' +drop table t1,t2,t3,t4; +# End of 10.4 tests diff --git a/mysql-test/main/insert.test b/mysql-test/main/insert.test index e00c9cd7a0d..9fd0933cc7c 100644 --- a/mysql-test/main/insert.test +++ b/mysql-test/main/insert.test @@ -612,3 +612,25 @@ CREATE VIEW v1 AS SELECT * FROM t1 WHERE f <=> 'foo' WITH CHECK OPTION; REPLACE INTO v1 SET f = NULL; DROP VIEW v1; DROP TABLE t1; + +--echo # End of 10.0 tests + +--echo # +--echo # MDEV-26412: INSERT CREATE with subquery in ON expression +--echo # + +create table t1 (a int); +create table t2 (b int); +create table t3 (c int); +create table t4 (d1 int, d2 int); + +--error ER_BAD_FIELD_ERROR +insert into t4 + select * from t1 left join t2 on (select t1.i from t3); +--error ER_BAD_FIELD_ERROR +replace t4 + select * from t1 left join t2 on (select t1.i from t3); + +drop table t1,t2,t3,t4; + +--echo # End of 10.4 tests diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index c769e6f0972..e622d5fb863 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -701,6 +701,7 @@ void LEX::start(THD *thd_arg) context_stack.empty(); //empty select_stack select_stack_top= 0; + select_stack_outer_barrier= 0; unit.init_query(); current_select_number= 0; curr_with_clause= 0; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 044eb425f71..3e35d16d355 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3246,6 +3246,12 @@ public: List<Name_resolution_context> context_stack; SELECT_LEX *select_stack[MAX_SELECT_NESTING + 1]; uint select_stack_top; + /* + Usually this is set to 0, but for INSERT/REPLACE SELECT it is set to 1. + When parsing such statements the pointer to the most outer select is placed + into the second element of select_stack rather than into the first. + */ + uint select_stack_outer_barrier; SQL_I_List<ORDER> proc_list; SQL_I_List<TABLE_LIST> auxiliary_table_list, save_list; @@ -3686,6 +3692,17 @@ public: bool copy_db_to(LEX_CSTRING *to); + void inc_select_stack_outer_barrier() + { + select_stack_outer_barrier++; + } + + SELECT_LEX *parser_current_outer_select() + { + return select_stack_top - 1 == select_stack_outer_barrier ? + 0 : select_stack[select_stack_top - 1]; + } + Name_resolution_context *current_context() { return context_stack.head(); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 5471861c092..6a1b849b912 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -9015,9 +9015,7 @@ push_new_name_resolution_context(THD *thd, right_op->last_leaf_for_name_resolution(); LEX *lex= thd->lex; on_context->select_lex = lex->current_select; - st_select_lex *curr_select= lex->pop_select(); - st_select_lex *outer_sel= lex->select_stack_head(); - lex->push_select(curr_select); + st_select_lex *outer_sel= lex->parser_current_outer_select(); on_context->outer_context = outer_sel ? &outer_sel->context : 0; return lex->push_context(on_context); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 1559118a211..cb0d8fff50a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -13608,6 +13608,7 @@ insert: if (Lex->main_select_push()) MYSQL_YYABORT; mysql_init_select(lex); + lex->inc_select_stack_outer_barrier(); lex->current_select->parsing_place= BEFORE_OPT_LIST; } insert_lock_option @@ -13634,6 +13635,7 @@ replace: if (Lex->main_select_push()) MYSQL_YYABORT; mysql_init_select(lex); + lex->inc_select_stack_outer_barrier(); lex->current_select->parsing_place= BEFORE_OPT_LIST; } replace_lock_option insert2 |