summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2022-04-25 18:08:57 -0700
committerIgor Babaev <igor@askmonty.org>2022-04-27 08:23:01 -0700
commit39feab3cd31b5414aa9b428eaba915c251ac34a2 (patch)
treed30244a324d73d724ce0c50b1d72a46467a2d3d5
parentfccca49997320bafe1282c758a5143f88b6e0e0f (diff)
downloadmariadb-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.result16
-rw-r--r--mysql-test/main/insert.test22
-rw-r--r--sql/sql_lex.cc1
-rw-r--r--sql/sql_lex.h17
-rw-r--r--sql/sql_parse.cc4
-rw-r--r--sql/sql_yacc.yy2
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