summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/main/insert_returning.result64
-rw-r--r--mysql-test/main/insert_returning.test70
-rw-r--r--sql/sql_base.cc12
-rw-r--r--sql/sql_class.h7
-rw-r--r--sql/sql_lex.cc6
-rw-r--r--sql/sql_priv.h1
-rw-r--r--sql/sql_yacc.yy44
7 files changed, 181 insertions, 23 deletions
diff --git a/mysql-test/main/insert_returning.result b/mysql-test/main/insert_returning.result
index a3cde7b1270..1976c1ca02e 100644
--- a/mysql-test/main/insert_returning.result
+++ b/mysql-test/main/insert_returning.result
@@ -400,10 +400,10 @@ f(id2)
14
EXPLAIN INSERT INTO t2 SELECT * FROM t1 WHERE id1=8 RETURNING id2;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 const PRIMARY PRIMARY 4 const 1
+1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1
EXPLAIN EXTENDED INSERT INTO t1 SELECT * FROM t1 WHERE id1=9 RETURNING val1;
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
EXPLAIN FORMAT="json" INSERT INTO t1 SELECT * FROM t1 WHERE id1=10 RETURNING val1;
EXPLAIN
{
@@ -433,7 +433,7 @@ Warning 1062 Duplicate entry '7' for key 'PRIMARY'
Warning 1062 Duplicate entry '8' for key 'PRIMARY'
ANALYZE INSERT INTO t2 SELECT * FROM t1 WHERE id1=11 RETURNING *;
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL no matching row in const table
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL no matching row in const table
SELECT * FROM t2;
id2 val2
1 a
@@ -615,3 +615,61 @@ DROP TABLE ins_duplicate;
DROP VIEW v1;
DROP VIEW v2;
DROP FUNCTION f;
+#
+# MDEV-25028: ASAN use-after-poison in base_list_iterator::next or
+# Assertion `sl->join == 0' upon INSERT .. RETURNING via PS
+#
+CREATE TABLE t1 (a INT);
+CREATE TABLE t2 (b INT);
+PREPARE stmt1 FROM "INSERT INTO t1 SELECT * FROM t1 WHERE a IN (SELECT b FROM t2) RETURNING a";
+EXECUTE stmt1;
+a
+PREPARE stmt2 FROM "INSERT INTO t1 SELECT * FROM t1 WHERE a IN (SELECT b FROM t2) RETURNING (SELECT b FROM t2)";
+EXECUTE stmt2;
+(SELECT b FROM t2)
+DROP TABLE t1, t2;
+#
+# MDEV-25187: Assertion `inited == NONE || table->open_by_handler'
+# failed or Direct leak in init_dynamic_array2 upon INSERT .. RETURNING
+# and memory leak in init_dynamic_array2
+#
+CREATE TABLE t (a INT, KEY (a));
+CREATE TABLE t1 (f INT);
+INSERT INTO t VALUES (1),(2);
+INSERT INTO t1 SELECT a FROM t WHERE 1 NOT IN (SELECT a FROM t) RETURNING f;
+f
+DROP TABLE t, t1;
+#
+# MDEV-28740: crash in INSERT RETURNING subquery in prepared statements
+#
+CREATE TABLE t1 (
+id INTEGER NOT NULL,
+data VARCHAR(30),
+PRIMARY KEY (id)
+)ENGINE=MyISAM;
+EXECUTE IMMEDIATE 'INSERT INTO t1 (id, data) VALUES ((SELECT CAST(1 AS SIGNED INTEGER) AS anon_1), ?) RETURNING t1.id' using 'hi';
+id
+1
+DROP TABLE t1;
+#
+# MDEV-27165: crash in base_list_iterator::next
+#
+CREATE TABLE t1 ( id int, a int);
+CREATE TABLE t2 ( id int);
+INSERT INTO t1 VALUES (( SELECT 1 from t2),999999999999) RETURNING id;
+ERROR 22003: Out of range value for column 'a' at row 1
+EXECUTE immediate "INSERT INTO t1 VALUES (( SELECT 1 from t2),999999999999) RETURNING id ";
+ERROR 22003: Out of range value for column 'a' at row 1
+EXECUTE immediate "INSERT INTO t1 VALUES (( SELECT 1 from t2),9) RETURNING id ";
+id
+NULL
+DROP TABLE t1, t2;
+#
+# MDEV-29686: Assertion `slave == 0' failed in
+# st_select_lex_node::attach_single
+#
+CREATE TABLE t (a INT);
+INSERT t WITH cte AS (SELECT 1) SELECT * FROM cte RETURNING *;
+a
+1
+DROP TABLE t;
diff --git a/mysql-test/main/insert_returning.test b/mysql-test/main/insert_returning.test
index 6c8e71a4617..837d61d2c16 100644
--- a/mysql-test/main/insert_returning.test
+++ b/mysql-test/main/insert_returning.test
@@ -326,3 +326,73 @@ DROP TABLE ins_duplicate;
DROP VIEW v1;
DROP VIEW v2;
DROP FUNCTION f;
+
+--echo #
+--echo # MDEV-25028: ASAN use-after-poison in base_list_iterator::next or
+--echo # Assertion `sl->join == 0' upon INSERT .. RETURNING via PS
+--echo #
+CREATE TABLE t1 (a INT);
+CREATE TABLE t2 (b INT);
+
+PREPARE stmt1 FROM "INSERT INTO t1 SELECT * FROM t1 WHERE a IN (SELECT b FROM t2) RETURNING a";
+EXECUTE stmt1;
+
+PREPARE stmt2 FROM "INSERT INTO t1 SELECT * FROM t1 WHERE a IN (SELECT b FROM t2) RETURNING (SELECT b FROM t2)";
+EXECUTE stmt2;
+
+DROP TABLE t1, t2;
+
+--echo #
+--echo # MDEV-25187: Assertion `inited == NONE || table->open_by_handler'
+--echo # failed or Direct leak in init_dynamic_array2 upon INSERT .. RETURNING
+--echo # and memory leak in init_dynamic_array2
+--echo #
+CREATE TABLE t (a INT, KEY (a));
+CREATE TABLE t1 (f INT);
+
+INSERT INTO t VALUES (1),(2);
+
+INSERT INTO t1 SELECT a FROM t WHERE 1 NOT IN (SELECT a FROM t) RETURNING f;
+
+# Cleanup
+DROP TABLE t, t1;
+
+--echo #
+--echo # MDEV-28740: crash in INSERT RETURNING subquery in prepared statements
+--echo #
+
+CREATE TABLE t1 (
+ id INTEGER NOT NULL,
+ data VARCHAR(30),
+ PRIMARY KEY (id)
+ )ENGINE=MyISAM;
+
+EXECUTE IMMEDIATE 'INSERT INTO t1 (id, data) VALUES ((SELECT CAST(1 AS SIGNED INTEGER) AS anon_1), ?) RETURNING t1.id' using 'hi';
+
+DROP TABLE t1;
+
+--echo #
+--echo # MDEV-27165: crash in base_list_iterator::next
+--echo #
+
+CREATE TABLE t1 ( id int, a int);
+CREATE TABLE t2 ( id int);
+
+--error ER_WARN_DATA_OUT_OF_RANGE
+INSERT INTO t1 VALUES (( SELECT 1 from t2),999999999999) RETURNING id;
+--error ER_WARN_DATA_OUT_OF_RANGE
+EXECUTE immediate "INSERT INTO t1 VALUES (( SELECT 1 from t2),999999999999) RETURNING id ";
+
+EXECUTE immediate "INSERT INTO t1 VALUES (( SELECT 1 from t2),9) RETURNING id ";
+
+DROP TABLE t1, t2;
+
+--echo #
+--echo # MDEV-29686: Assertion `slave == 0' failed in
+--echo # st_select_lex_node::attach_single
+--echo #
+
+CREATE TABLE t (a INT);
+INSERT t WITH cte AS (SELECT 1) SELECT * FROM cte RETURNING *;
+
+DROP TABLE t;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index b10f09d67a5..607d03d3450 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -7484,10 +7484,12 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
Item *item;
List_iterator<Item> it(fields);
Query_arena *arena, backup;
+ uint *with_wild= returning_field ? &(thd->lex->returning()->with_wild) :
+ &(select_lex->with_wild);
DBUG_ENTER("setup_wild");
- if (!select_lex->with_wild)
- DBUG_RETURN(0);
+ if (!(*with_wild))
+ DBUG_RETURN(0);
/*
Don't use arena if we are not in prepared statements or stored procedures
@@ -7496,7 +7498,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
arena= thd->activate_stmt_arena_if_needed(&backup);
thd->lex->current_select->cur_pos_in_select_list= 0;
- while (select_lex->with_wild && (item= it++))
+ while (*with_wild && (item= it++))
{
if (item->type() == Item::FIELD_ITEM &&
((Item_field*) item)->field_name.str == star_clex_str.str &&
@@ -7534,12 +7536,12 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
*/
sum_func_list->elements+= fields.elements - elem;
}
- select_lex->with_wild--;
+ (*with_wild)--;
}
else
thd->lex->current_select->cur_pos_in_select_list++;
}
- DBUG_ASSERT(!select_lex->with_wild);
+ DBUG_ASSERT(!(*with_wild));
thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS;
if (arena)
thd->restore_active_arena(arena, &backup);
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 880a3bc1d09..51c1bc984da 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -7039,7 +7039,12 @@ public:
inline bool add_item_to_list(THD *thd, Item *item)
{
- bool res= thd->lex->current_select->add_item_to_list(thd, item);
+ bool res;
+ LEX *lex= thd->lex;
+ if (lex->current_select->parsing_place == IN_RETURNING)
+ res= lex->returning()->add_item_to_list(thd, item);
+ else
+ res= lex->current_select->add_item_to_list(thd, item);
return res;
}
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 4fe097a4067..35ed1af7bc1 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -9522,7 +9522,8 @@ Item *LEX::create_item_qualified_asterisk(THD *thd,
null_clex_str, *name,
star_clex_str)))
return NULL;
- current_select->with_wild++;
+ current_select->parsing_place == IN_RETURNING ?
+ thd->lex->returning()->with_wild++ : current_select->with_wild++;
return item;
}
@@ -9537,7 +9538,8 @@ Item *LEX::create_item_qualified_asterisk(THD *thd,
if (!(item= new (thd->mem_root) Item_field(thd, current_context(),
schema, *b, star_clex_str)))
return NULL;
- current_select->with_wild++;
+ current_select->parsing_place == IN_RETURNING ?
+ thd->lex->returning()->with_wild++ : current_select->with_wild++;
return item;
}
diff --git a/sql/sql_priv.h b/sql/sql_priv.h
index b18a80ba1f2..a304cd39df7 100644
--- a/sql/sql_priv.h
+++ b/sql/sql_priv.h
@@ -374,6 +374,7 @@ enum enum_parsing_place
BEFORE_OPT_LIST,
AFTER_LIST,
FOR_LOOP_BOUND,
+ IN_RETURNING,
PARSING_PLACE_SIZE /* always should be the last */
};
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index cab60b2c266..9e172646af9 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -9175,14 +9175,20 @@ select_item_list:
| select_item
| '*'
{
+ bool is_parsing_returning=
+ thd->lex->current_select->parsing_place ==
+ IN_RETURNING;
+ SELECT_LEX *correct_select= is_parsing_returning ?
+ thd->lex->returning() :
+ thd->lex->current_select;
Item *item= new (thd->mem_root)
- Item_field(thd, &thd->lex->current_select->context,
+ Item_field(thd, &correct_select->context,
star_clex_str);
if (unlikely(item == NULL))
MYSQL_YYABORT;
if (unlikely(add_item_to_list(thd, item)))
MYSQL_YYABORT;
- (thd->lex->current_select->with_wild)++;
+ correct_select->with_wild++;
}
;
@@ -13360,19 +13366,33 @@ opt_returning:
| RETURNING_SYM
{
DBUG_ASSERT(!Lex->has_returning());
- if (($<num>$= (Select != Lex->returning())))
- {
- SELECT_LEX *sl= Lex->returning();
- sl->set_master_unit(0);
- Select->attach_single(Lex->create_unit(sl));
- sl->include_global((st_select_lex_node**)&Lex->all_selects_list);
- Lex->push_select(sl);
- }
+ /*
+ When parsing_place is IN_RETURNING, we push select items to
+ item_list of builtin_select instead of current_select.
+ But set parsing_place of current_select to true.
+
+ Because parsing_place for builtin_select will be IN_RETURNING,
+ regardless there is SELECT in RETURNING. Example, if
+ there is RETURNING (SELECT...), then when we parse
+ SELECT inside RETURNING, builtin_select->parsing_place
+ will still be true. So the select items of SELECT inside
+ RETURNING will be added to item_list of builtin_select which
+ is incorrect. We want to prevent this from happening.
+ Since for every new select, a new SELECT_LEX
+ object is created and pushed to select stack, current_select
+ will point to SELECT inside RETURNING, and also has
+ parsing_place not set to IN_RETURNING by default.
+ So items are correctly added to item_list of SELECT inside
+ RETURNING instead of builtin_select.
+ */
+
+ thd->lex->current_select->parsing_place= IN_RETURNING;
+ thd->lex->push_context(&thd->lex->returning()->context);
}
select_item_list
{
- if ($<num>2)
- Lex->pop_select();
+ thd->lex->pop_context();
+ thd->lex->current_select->parsing_place= NO_MATTER;
}
;