[Commits] fe3246067b4: MDEV-17055: Server crashes in find_order_in_list upon 2nd (3rd) execution of SP with UPDATE
revision-id: fe3246067b4e3dc9fc2b15aedcdcd13b2793cb4f (mariadb-5.5.63-6-gfe3246067b4) parent(s): c9b9d9f5152b2ec16e88c0b235d50420c52b41de author: Oleksandr Byelkin committer: Oleksandr Byelkin timestamp: 2019-02-27 15:53:25 +0100 message: 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. Check very early begining of prepare/execution, they still create need in cleanup. --- mysql-test/r/sp.result | 33 +++++++++++++++++++++++++++++++++ mysql-test/t/sp.test | 41 +++++++++++++++++++++++++++++++++++++++++ sql/sql_delete.cc | 2 ++ sql/sql_derived.cc | 3 +-- sql/sql_insert.cc | 3 ++- sql/sql_lex.cc | 2 +- sql/sql_lex.h | 9 ++++++++- sql/sql_load.cc | 2 ++ sql/sql_prepare.cc | 9 +++++++++ sql/sql_select.cc | 2 ++ sql/sql_update.cc | 2 ++ 11 files changed, 103 insertions(+), 5 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_delete.cc b/sql/sql_delete.cc index cdd7350cb0c..079aa2ee629 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -474,6 +474,8 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) DBUG_ENTER("mysql_prepare_delete"); List<Item> all_fields; + select_lex->first_execution_attempt= FALSE; + thd->lex->allow_sum_func= 0; if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context, &thd->lex->select_lex.top_join_list, diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 2e947ecba16..9734bf60d5b 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -1032,8 +1032,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 809059093c2..dd7cffd243b 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1400,6 +1400,8 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, /* INSERT should have a SELECT or VALUES clause */ DBUG_ASSERT (!select_insert || !values); + select_lex->first_execution_attempt= FALSE; + if (mysql_handle_derived(thd->lex, DT_INIT)) DBUG_RETURN(TRUE); if (table_list->handle_derived(thd->lex, DT_MERGE_FOR_INSERT)) @@ -1510,7 +1512,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 cfbde25314b..247aea6b7d5 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; + first_execution_attempt= first_execution= 1; first_natural_join_processing= 1; first_cond_optimization= 1; parsing_place= NO_MATTER; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 57129cfedc7..63d56fb88ed 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -875,8 +875,15 @@ class st_select_lex: public st_select_lex_node variable to inidicate the optimization/execution state of every subquery. Prepared statements work OK in that regard, as in case of an error during prepare the PS is not created. + + TODO: make a bitmap with execution stages done for nest bool flags + */ + bool first_execution; // where/having saved + /* + False if we have started execution and so there is something to cleanup + in tables/derived tables */ - bool first_execution; + bool first_execution_attempt; bool first_natural_join_processing; bool first_cond_optimization; /* do not wrap view fields with Item_ref */ diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 113cbe1dac0..433bbe190e1 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -202,6 +202,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, bool transactional_table __attribute__((unused)); DBUG_ENTER("mysql_load"); + thd->lex->select_lex.first_execution_attempt= FALSE; + /* Bug #34283 mysqlbinlog leaves tmpfile after termination if binlog contains diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 6aa6aacc504..935ff29f6df 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2533,6 +2533,9 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) else sl->having= NULL; DBUG_ASSERT(sl->join == 0); + } + if (!sl->first_execution_attempt) + { ORDER *order; /* Fix GROUP list */ if (sl->group_list_ptrs && sl->group_list_ptrs->size() > 0) @@ -2544,10 +2547,15 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) } } 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; + } + { #ifndef DBUG_OFF bool res= @@ -2556,6 +2564,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) DBUG_ASSERT(res == 0); } } + { SELECT_LEX_UNIT *unit= sl->master_unit(); unit->unclean(); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 35937f0536f..489851dce46 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -638,6 +638,8 @@ JOIN::prepare(Item ***rref_pointer_array, join_list= &select_lex->top_join_list; union_part= unit_arg->is_union(); + select_lex->first_execution_attempt= FALSE; + // simple check that we got usable conds dbug_print_item(conds); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index fe007d5823d..ef51e2070a3 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1010,6 +1010,8 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, SELECT_LEX *select_lex= &thd->lex->select_lex; DBUG_ENTER("mysql_prepare_update"); + select_lex->first_execution_attempt= FALSE; + #ifndef NO_EMBEDDED_ACCESS_CHECKS table_list->grant.want_privilege= table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege);
participants (1)
-
Oleksandr Byelkin