diff options
author | Oleksandr Byelkin <sanja@mariadb.com> | 2019-02-27 15:53:25 +0100 |
---|---|---|
committer | Oleksandr Byelkin <sanja@mariadb.com> | 2019-02-28 18:14:53 +0100 |
commit | cb11b3fbe9d4dde776cb8f2c0d6f83a569655efc (patch) | |
tree | c2786c9e12fe67065c887e1a9a027cfaf154fb51 | |
parent | 0ad598a00b17008b0c0702db40948b14d7eee0d5 (diff) | |
download | mariadb-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.result | 33 | ||||
-rw-r--r-- | mysql-test/t/sp.test | 41 | ||||
-rw-r--r-- | sql/sql_derived.cc | 4 | ||||
-rw-r--r-- | sql/sql_insert.cc | 1 | ||||
-rw-r--r-- | sql/sql_lex.cc | 7 | ||||
-rw-r--r-- | sql/sql_lex.h | 7 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 21 | ||||
-rw-r--r-- | sql/sql_union.cc | 5 |
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; |