summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOleksandr Byelkin <sanja@mariadb.com>2019-02-27 15:53:25 +0100
committerOleksandr Byelkin <sanja@mariadb.com>2019-02-28 18:14:53 +0100
commitcb11b3fbe9d4dde776cb8f2c0d6f83a569655efc (patch)
treec2786c9e12fe67065c887e1a9a027cfaf154fb51
parent0ad598a00b17008b0c0702db40948b14d7eee0d5 (diff)
downloadmariadb-git-cb11b3fbe9d4dde776cb8f2c0d6f83a569655efc.tar.gz
MDEV-17055: Server crashes in find_order_in_list upon 2nd (3rd) execution of SP with UPDATE
1. Always drop merged_for_insert flag on cleanup (there could be errors which prevent TABLE to be assigned) 2. Make more precise cleanup of select parts which was touched
-rw-r--r--mysql-test/r/sp.result33
-rw-r--r--mysql-test/t/sp.test41
-rw-r--r--sql/sql_derived.cc4
-rw-r--r--sql/sql_insert.cc1
-rw-r--r--sql/sql_lex.cc7
-rw-r--r--sql/sql_lex.h7
-rw-r--r--sql/sql_prepare.cc21
-rw-r--r--sql/sql_union.cc5
8 files changed, 104 insertions, 15 deletions
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index 4535056242a..52b52fbbd24 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -8072,4 +8072,37 @@ CALL sp;
c a b a b
DROP PROCEDURE sp;
DROP TABLE t1;
+#
+# MDEV-17055: Server crashes in find_order_in_list upon
+# 2nd (3rd) execution of SP with UPDATE
+#
+CREATE TABLE t1 (a INT);
+CREATE VIEW v1 AS SELECT * FROM t1;
+CREATE TABLE t2 (c INT);
+CREATE PROCEDURE sp() UPDATE v1 SET a = 1 ORDER BY a, b LIMIT 1;
+LOCK TABLE t2 READ;
+CALL sp;
+ERROR HY000: Table 'v1' was not locked with LOCK TABLES
+UNLOCK TABLES;
+CALL sp;
+ERROR 42S22: Unknown column 'b' in 'order clause'
+CALL sp;
+ERROR 42S22: Unknown column 'b' in 'order clause'
+CALL sp;
+ERROR 42S22: Unknown column 'b' in 'order clause'
+DROP PROCEDURE sp;
+CREATE PROCEDURE sp() UPDATE v1 SET a = 1 WHERE a=1 and b=2;
+LOCK TABLE t2 READ;
+CALL sp;
+ERROR HY000: Table 'v1' was not locked with LOCK TABLES
+UNLOCK TABLES;
+CALL sp;
+ERROR 42S22: Unknown column 'b' in 'where clause'
+CALL sp;
+ERROR 42S22: Unknown column 'b' in 'where clause'
+CALL sp;
+ERROR 42S22: Unknown column 'b' in 'where clause'
+DROP PROCEDURE sp;
+DROP VIEW v1;
+DROP TABLE t1, t2;
# End of 5.5 test
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index cb93cd31442..fb9da936fdb 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -9373,5 +9373,46 @@ CALL sp;
DROP PROCEDURE sp;
DROP TABLE t1;
+--echo #
+--echo # MDEV-17055: Server crashes in find_order_in_list upon
+--echo # 2nd (3rd) execution of SP with UPDATE
+--echo #
+
+CREATE TABLE t1 (a INT);
+CREATE VIEW v1 AS SELECT * FROM t1;
+CREATE TABLE t2 (c INT);
+
+CREATE PROCEDURE sp() UPDATE v1 SET a = 1 ORDER BY a, b LIMIT 1;
+LOCK TABLE t2 READ;
+--error ER_TABLE_NOT_LOCKED
+CALL sp;
+UNLOCK TABLES;
+--error ER_BAD_FIELD_ERROR
+CALL sp;
+--error ER_BAD_FIELD_ERROR
+CALL sp;
+--error ER_BAD_FIELD_ERROR
+CALL sp;
+
+# Cleanup
+DROP PROCEDURE sp;
+
+CREATE PROCEDURE sp() UPDATE v1 SET a = 1 WHERE a=1 and b=2;
+LOCK TABLE t2 READ;
+--error ER_TABLE_NOT_LOCKED
+CALL sp;
+UNLOCK TABLES;
+--error ER_BAD_FIELD_ERROR
+CALL sp;
+--error ER_BAD_FIELD_ERROR
+CALL sp;
+--error ER_BAD_FIELD_ERROR
+CALL sp;
+
+# Cleanup
+DROP PROCEDURE sp;
+
+DROP VIEW v1;
+DROP TABLE t1, t2;
--echo # End of 5.5 test
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index e990eba8e54..1709669d8a2 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -90,6 +90,7 @@ mysql_handle_derived(LEX *lex, uint phases)
sl= sl->next_select_in_list())
{
TABLE_LIST *cursor= sl->get_table_list();
+ sl->changed_elements|= TOUCHED_SEL_DERIVED;
/*
DT_MERGE_FOR_INSERT is not needed for views/derived tables inside
subqueries. Views and derived tables of subqueries should be
@@ -1002,8 +1003,7 @@ bool mysql_derived_reinit(THD *thd, LEX *lex, TABLE_LIST *derived)
derived->get_unit()));
st_select_lex_unit *unit= derived->get_unit();
- if (derived->table)
- derived->merged_for_insert= FALSE;
+ derived->merged_for_insert= FALSE;
unit->unclean();
unit->types.empty();
/* for derived tables & PS (which can't be reset by Item_subquery) */
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index ba8134bfaf1..cc040508842 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1510,7 +1510,6 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
DBUG_RETURN(TRUE);
}
select_lex->fix_prepare_information(thd, &fake_conds, &fake_conds);
- select_lex->first_execution= 0;
}
/*
Only call prepare_for_posistion() if we are not performing a DELAYED
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 3c0d3049ae4..7d694f90aa2 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1904,7 +1904,7 @@ void st_select_lex::init_query()
n_child_sum_items= 0;
subquery_in_having= explicit_limit= 0;
is_item_list_lookup= 0;
- first_execution= 1;
+ changed_elements= 0;
first_natural_join_processing= 1;
first_cond_optimization= 1;
parsing_place= NO_MATTER;
@@ -3367,9 +3367,10 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds,
Item **having_conds)
{
DBUG_ENTER("st_select_lex::fix_prepare_information");
- if (!thd->stmt_arena->is_conventional() && first_execution)
+ if (!thd->stmt_arena->is_conventional() &&
+ !(changed_elements & TOUCHED_SEL_COND))
{
- first_execution= 0;
+ changed_elements|= TOUCHED_SEL_COND;
if (group_list.first)
{
if (!group_list_ptrs)
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 8a31560d2bf..5b589714e1a 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -729,6 +729,10 @@ public:
typedef class st_select_lex_unit SELECT_LEX_UNIT;
+
+#define TOUCHED_SEL_COND 1/* WHERE/HAVING/ON should be reinited before use */
+#define TOUCHED_SEL_DERIVED (1<<1)/* derived should be reinited before use */
+
/*
SELECT_LEX - store information of parsed SELECT statment
*/
@@ -876,7 +880,8 @@ public:
subquery. Prepared statements work OK in that regard, as in
case of an error during prepare the PS is not created.
*/
- bool first_execution;
+ uint8 changed_elements; // see TOUCHED_SEL_*
+ /* TODO: add foloowing first_* to bitmap above */
bool first_natural_join_processing;
bool first_cond_optimization;
/* do not wrap view fields with Item_ref */
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 6aa6aacc504..16923ee5a21 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -2496,7 +2496,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
}
for (; sl; sl= sl->next_select_in_list())
{
- if (!sl->first_execution)
+ if (sl->changed_elements & TOUCHED_SEL_COND)
{
/* remove option which was put by mysql_explain_union() */
sl->options&= ~SELECT_DESCRIBE;
@@ -2543,19 +2543,28 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
order->next= sl->group_list_ptrs->at(ix+1);
}
}
+ }
+ { // no harm to do it (item_ptr set on parsing)
+ ORDER *order;
for (order= sl->group_list.first; order; order= order->next)
+ {
order->item= &order->item_ptr;
+ }
/* Fix ORDER list */
for (order= sl->order_list.first; order; order= order->next)
- order->item= &order->item_ptr;
{
+ order->item= &order->item_ptr;
+ }
+ }
+ if (sl->changed_elements & TOUCHED_SEL_DERIVED)
+ {
#ifndef DBUG_OFF
- bool res=
+ bool res=
#endif
- sl->handle_derived(lex, DT_REINIT);
- DBUG_ASSERT(res == 0);
- }
+ sl->handle_derived(lex, DT_REINIT);
+ DBUG_ASSERT(res == 0);
}
+
{
SELECT_LEX_UNIT *unit= sl->master_unit();
unit->unclean();
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index bbb4133417e..e855b64e600 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -215,8 +215,9 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg,
called at the first execution of the statement, while first_execution
shows whether this is called at the first execution of the union that
may form just a subselect.
- */
- if (!fake_select_lex->first_execution && first_execution)
+ */
+ if ((fake_select_lex->changed_elements & TOUCHED_SEL_COND) &&
+ first_execution)
{
for (ORDER *order= global_parameters->order_list.first;
order;