Commit cb11b3fb authored by Oleksandr Byelkin's avatar Oleksandr Byelkin

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
parent 0ad598a0
...@@ -8072,4 +8072,37 @@ CALL sp; ...@@ -8072,4 +8072,37 @@ CALL sp;
c a b a b c a b a b
DROP PROCEDURE sp; DROP PROCEDURE sp;
DROP TABLE t1; 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 # End of 5.5 test
...@@ -9373,5 +9373,46 @@ CALL sp; ...@@ -9373,5 +9373,46 @@ CALL sp;
DROP PROCEDURE sp; DROP PROCEDURE sp;
DROP TABLE t1; 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 --echo # End of 5.5 test
...@@ -90,6 +90,7 @@ mysql_handle_derived(LEX *lex, uint phases) ...@@ -90,6 +90,7 @@ mysql_handle_derived(LEX *lex, uint phases)
sl= sl->next_select_in_list()) sl= sl->next_select_in_list())
{ {
TABLE_LIST *cursor= sl->get_table_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 DT_MERGE_FOR_INSERT is not needed for views/derived tables inside
subqueries. Views and derived tables of subqueries should be subqueries. Views and derived tables of subqueries should be
...@@ -1002,8 +1003,7 @@ bool mysql_derived_reinit(THD *thd, LEX *lex, TABLE_LIST *derived) ...@@ -1002,8 +1003,7 @@ bool mysql_derived_reinit(THD *thd, LEX *lex, TABLE_LIST *derived)
derived->get_unit())); derived->get_unit()));
st_select_lex_unit *unit= 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->unclean();
unit->types.empty(); unit->types.empty();
/* for derived tables & PS (which can't be reset by Item_subquery) */ /* for derived tables & PS (which can't be reset by Item_subquery) */
......
...@@ -1510,7 +1510,6 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, ...@@ -1510,7 +1510,6 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
select_lex->fix_prepare_information(thd, &fake_conds, &fake_conds); 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 Only call prepare_for_posistion() if we are not performing a DELAYED
......
...@@ -1904,7 +1904,7 @@ void st_select_lex::init_query() ...@@ -1904,7 +1904,7 @@ void st_select_lex::init_query()
n_child_sum_items= 0; n_child_sum_items= 0;
subquery_in_having= explicit_limit= 0; subquery_in_having= explicit_limit= 0;
is_item_list_lookup= 0; is_item_list_lookup= 0;
first_execution= 1; changed_elements= 0;
first_natural_join_processing= 1; first_natural_join_processing= 1;
first_cond_optimization= 1; first_cond_optimization= 1;
parsing_place= NO_MATTER; parsing_place= NO_MATTER;
...@@ -3367,9 +3367,10 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds, ...@@ -3367,9 +3367,10 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds,
Item **having_conds) Item **having_conds)
{ {
DBUG_ENTER("st_select_lex::fix_prepare_information"); 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.first)
{ {
if (!group_list_ptrs) if (!group_list_ptrs)
......
...@@ -729,6 +729,10 @@ class st_select_lex_unit: public st_select_lex_node { ...@@ -729,6 +729,10 @@ class st_select_lex_unit: public st_select_lex_node {
typedef class st_select_lex_unit SELECT_LEX_UNIT; 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 SELECT_LEX - store information of parsed SELECT statment
*/ */
...@@ -876,7 +880,8 @@ class st_select_lex: public st_select_lex_node ...@@ -876,7 +880,8 @@ class st_select_lex: public st_select_lex_node
subquery. Prepared statements work OK in that regard, as in subquery. Prepared statements work OK in that regard, as in
case of an error during prepare the PS is not created. 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_natural_join_processing;
bool first_cond_optimization; bool first_cond_optimization;
/* do not wrap view fields with Item_ref */ /* do not wrap view fields with Item_ref */
......
...@@ -2496,7 +2496,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) ...@@ -2496,7 +2496,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
} }
for (; sl; sl= sl->next_select_in_list()) 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() */ /* remove option which was put by mysql_explain_union() */
sl->options&= ~SELECT_DESCRIBE; sl->options&= ~SELECT_DESCRIBE;
...@@ -2543,19 +2543,28 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) ...@@ -2543,19 +2543,28 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
order->next= sl->group_list_ptrs->at(ix+1); 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) for (order= sl->group_list.first; order; order= order->next)
{
order->item= &order->item_ptr; order->item= &order->item_ptr;
}
/* Fix ORDER list */ /* Fix ORDER list */
for (order= sl->order_list.first; order; order= order->next) 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 #ifndef DBUG_OFF
bool res= bool res=
#endif #endif
sl->handle_derived(lex, DT_REINIT); sl->handle_derived(lex, DT_REINIT);
DBUG_ASSERT(res == 0); DBUG_ASSERT(res == 0);
}
} }
{ {
SELECT_LEX_UNIT *unit= sl->master_unit(); SELECT_LEX_UNIT *unit= sl->master_unit();
unit->unclean(); unit->unclean();
......
...@@ -215,8 +215,9 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg, ...@@ -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 called at the first execution of the statement, while first_execution
shows whether this is called at the first execution of the union that shows whether this is called at the first execution of the union that
may form just a subselect. 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; for (ORDER *order= global_parameters->order_list.first;
order; order;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment