Skip to content

Commit d7b37d4

Browse files
author
Sreeharsha Ramanavarapu
committed
Bug #25053286: USE VIEW WITH CONDITION IN PROCEDURE CAUSES
INCORRECT BEHAVIOR Issue: ------ This problem occurs when a stored procedure contains a query with a view. While resolving the columns in the WHERE condition, find_field_in_view insists on creating a Item_direct_view_ref object every time an execution happens. This object is not destroyed at the end of the execution. In the next execution, a new object is created and will be appended to the free_list. Hence the size of the free_list is growing and the cleanup phase at the end of each execute takes increasingly longer time. Solution: --------- This is a regression due to the fix for BUG#19897405. Ideally the Item_direct_view_ref object (which is related to the view's column in WHERE clause) should be created at the beginning of every execution and destroyed at the end. This doesn't happen because the check related to the status (STMT_INITIALIZED_FOR_SP / STMT_EXECUTED) had been removed. This check has been re-introduced. Scenario 1 in BUG#19897405: -------------------------- a) SP is executed--> The view fields are resolved/fixed. b) FLUSH TABLE <table-name>. c) SP is executed--> Triggers re-prepare--> Query arena state is not reset and remains as 'STMT_EXECUTED'. Previously created Item_direct_view_ref object is destroyed. The view fields are resolved/fixed using the execution mem_root. It creates a new Item_direct_view_ref object, this is destroyed at the end of the execution. d) SP is executed--> Server crashes while trying to access the resolved view columns allocated on the execution mem_root which was freed after execution(c). Solution to Scenario 1 in BUG#19897405: --------------------------------------- The root cause of the problem mentioned in BUG#19897405 is that when a re-prepare error is raised due to a FLUSH TABLE / DROP TABLE, the state of statement arena should be switched to STMT_INITIALIZED_FOR_SP. Without this, the statement is unaware that previously created Item_direct_view_ref have been destroyed after the table re-open. While it creates a new Item_direct_view_ref object, this is destroyed at the end of the execution. Hence the execution that follows will not have any Item_direct_view_ref to use. The fix here is to set the state to STMT_INITIALIZED_FOR_SP after the re-prepare error is raised. Problem 2 in BUG#19897405: -------------------------- a) SP is executed--> The view fields are resolved/fixed. b) SP is executed--> Gets re-prepare error. Destroys Item_direct_view_ref object. At the end "TABLE EXISTS" error is raised and state is set to EXECUTED c) DROP TABLE <table-created-in-sp> d) SP is executed--> Creates new item_direct_view_ref object. Destroys the object at the end of the statement. d) DROP TABLE <table-created-in-sp> e) SP is executed--> Server crashes while trying to access the resolved view columns allocated on the execution mem_root which was freed after execution. Solution to Scenario 2 in BUG#19897405: --------------------------------------- CREATE TABLE ... SELECT statement in an SP requires some special handling. The state is always set to STMT_INITIALIZED_FOR_SP in such a case.
1 parent dbe0ae4 commit d7b37d4

File tree

3 files changed

+62
-11
lines changed

3 files changed

+62
-11
lines changed

sql/sp_instr.cc

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -422,14 +422,49 @@ bool sp_lex_instr::reset_lex_and_exec_core(THD *thd,
422422
thd->rollback_item_tree_changes();
423423

424424
/*
425-
Update the state of the active arena if no errors on
426-
open_tables stage.
425+
Change state of current arena according to outcome of execution.
426+
427+
When entering this function, state is STMT_INITIALIZED_FOR_SP if this is
428+
the first execution, otherwise it is STMT_EXECUTED.
429+
430+
When an error occurs during opening tables, no execution takes place and
431+
no state change will take place.
432+
433+
When a re-prepare error is raised, the next execution will re-prepare the
434+
statement. To make sure that items are created in the statement mem_root,
435+
change state to STMT_INITIALIZED_FOR_SP.
436+
437+
In other cases, the state should become (or remain) STMT_EXECUTED.
438+
See Query_arena->state definition for explanation.
439+
440+
Some special handling of CREATE TABLE .... SELECT in an SP is required. The
441+
state is always set to STMT_INITIALIZED_FOR_SP in such a case.
442+
443+
Why is this necessary? A useful pointer would be to note how
444+
PREPARE/EXECUTE uses functions like select_like_stmt_test to implement
445+
CREATE TABLE .... SELECT. The SELECT part of the DDL is resolved first.
446+
Then there is an attempt to create the table. So in the execution phase,
447+
if "table exists" error occurs or flush table preceeds the execute, the
448+
item tree of the select is re-created and followed by an attempt to create
449+
the table.
450+
451+
But SP uses mysql_execute_command (which is used by the conventional
452+
execute) after doing a parse. This creates a problem for SP since it
453+
tries to preserve the item tree from the previous execution.
427454
*/
428455

429-
if (!rc || !thd->is_error() ||
430-
(thd->get_stmt_da()->sql_errno() != ER_CANT_REOPEN_TABLE &&
431-
thd->get_stmt_da()->sql_errno() != ER_NO_SUCH_TABLE &&
432-
thd->get_stmt_da()->sql_errno() != ER_UPDATE_TABLE_USED))
456+
bool reprepare_error=
457+
rc && thd->get_stmt_da()->sql_errno() == ER_NEED_REPREPARE;
458+
bool is_create_table_select=
459+
thd->lex && thd->lex->sql_command == SQLCOM_CREATE_TABLE &&
460+
thd->lex->select_lex.item_list.elements > 0;
461+
462+
if (reprepare_error || is_create_table_select)
463+
thd->stmt_arena->state= Query_arena::STMT_INITIALIZED_FOR_SP;
464+
else if (!rc || !thd->is_error() ||
465+
(thd->get_stmt_da()->sql_errno() != ER_CANT_REOPEN_TABLE &&
466+
thd->get_stmt_da()->sql_errno() != ER_NO_SUCH_TABLE &&
467+
thd->get_stmt_da()->sql_errno() != ER_UPDATE_TABLE_USED))
433468
thd->stmt_arena->state= Query_arena::STMT_EXECUTED;
434469

435470
/*
@@ -493,7 +528,7 @@ LEX *sp_lex_instr::parse_expr(THD *thd, sp_head *sp)
493528
initiated. Also set the statement query arena to the lex mem_root.
494529
*/
495530
MEM_ROOT *execution_mem_root= thd->mem_root;
496-
Query_arena parse_arena(&m_lex_mem_root, STMT_INITIALIZED_FOR_SP);
531+
Query_arena parse_arena(&m_lex_mem_root, thd->stmt_arena->state);
497532

498533
thd->mem_root= &m_lex_mem_root;
499534
thd->stmt_arena->set_query_arena(&parse_arena);

sql/sql_base.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -6574,7 +6574,10 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list,
65746574
Use own arena for Prepared Statements or data will be freed after
65756575
PREPARE.
65766576
*/
6577-
Prepared_stmt_arena_holder ps_arena_holder(thd, register_tree_change);
6577+
Prepared_stmt_arena_holder ps_arena_holder(
6578+
thd,
6579+
register_tree_change &&
6580+
thd->stmt_arena->is_stmt_prepare_or_first_stmt_execute());
65786581

65796582
/*
65806583
create_item() may, or may not create a new Item, depending on

sql/sql_class.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights
1+
/* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights
22
reserved.
33
44
This program is free software; you can redistribute it and/or modify
@@ -727,6 +727,19 @@ class Query_arena
727727
STMT_CONVENTIONAL_EXECUTION= 3, STMT_EXECUTED= 4, STMT_ERROR= -1
728728
};
729729

730+
/*
731+
State and state changes in SP:
732+
1) When state is STMT_INITIALIZED_FOR_SP, objects in the item tree are
733+
created on the statement memroot. This is enforced through
734+
ps_arena_holder checking the state.
735+
2) After the first execute (call p1()), this state should change to
736+
STMT_EXECUTED. Objects will be created on the execution memroot and will
737+
be destroyed at the end of each execution.
738+
3) In case an ER_NEED_REPREPARE error occurs, state should be changed to
739+
STMT_INITIALIZED_FOR_SP and objects will again be created on the
740+
statement memroot. At the end of this execution, state should change to
741+
STMT_EXECUTED.
742+
*/
730743
enum_state state;
731744

732745
/* We build without RTTI, so dynamic_cast can't be used. */

0 commit comments

Comments
 (0)