1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-23 08:45:18 +03:00

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
This commit is contained in:
Oleksandr Byelkin
2019-02-27 15:53:25 +01:00
parent 0ad598a00b
commit cb11b3fbe9
8 changed files with 105 additions and 16 deletions

View File

@ -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

View File

@ -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

View File

@ -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)
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) */

View File

@ -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

View File

@ -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,
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)

View File

@ -729,6 +729,10 @@ public:
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 @@ public:
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 */

View File

@ -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)
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;
{ {
#ifndef DBUG_OFF order->item= &order->item_ptr;
bool res=
#endif
sl->handle_derived(lex, DT_REINIT);
DBUG_ASSERT(res == 0);
} }
} }
if (sl->changed_elements & TOUCHED_SEL_DERIVED)
{
#ifndef DBUG_OFF
bool res=
#endif
sl->handle_derived(lex, DT_REINIT);
DBUG_ASSERT(res == 0);
}
{ {
SELECT_LEX_UNIT *unit= sl->master_unit(); SELECT_LEX_UNIT *unit= sl->master_unit();
unit->unclean(); unit->unclean();

View File

@ -216,7 +216,8 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg,
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;