Skip to content

Commit aed590b

Browse files
committed
Bug#33754993: crash in Item_ref::check_cols after function execution
There is a failure in second execution of a stored function with a CREATE TABLE statement that has an error that is revealed during preparation. In the first execution, a preparation is performed and the error is noticed. Thus, the statement does not reach the "prepared" state and the statement is also attempted prepared in the subsequent execution. However, the statement is not cleaned up after the first prepare attempt, and we reach some inconsistent data structures and the failure occurs. Notice that we never expected a second preparation. The expectation is to delete all remains of a failed preparation and retry it from a fresh data structure. This situation may also never occur with a prepared statement, because a prepared statement that fails preparation is simply not created. The solution here is to delete the AST of a stored function statement if preparation fails and recreate it on the next execution. We do this by marking the statement as "invalid" if an error has occurred and the execution never started, assuming that this means preparation never completed. There is already code to pick up the "invalid" state on the next execution, and thus the existing AST is deleted and recreated from the statement text. Notice that we would have better control if we had fully separate preparation and execution of all statements, meaning that we could call the preparation function on first execution and could have a simple test for whether preparation was successful or not. This patch also fixes bug#33079896, and a test case for this has been added. Change-Id: I0a1757ebbd1abf856f97f7aa7ca39e9e4ac5631a
1 parent a802a45 commit aed590b

File tree

1 file changed

+9
-2
lines changed

1 file changed

+9
-2
lines changed

sql/sp_instr.cc

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -741,9 +741,16 @@ bool sp_lex_instr::validate_lex_and_execute_core(THD *thd, uint *nextp,
741741
raise it to the user;
742742
*/
743743
if (stmt_reprepare_observer == nullptr || thd->is_fatal_error() ||
744-
thd->killed || thd->get_stmt_da()->mysql_errno() != ER_NEED_REPREPARE)
744+
thd->killed || thd->get_stmt_da()->mysql_errno() != ER_NEED_REPREPARE) {
745+
/*
746+
If an error occurred before execution, make sure next execution is
747+
started with a clean statement:
748+
*/
749+
if (m_lex->is_metadata_used() && !m_lex->is_exec_started()) {
750+
invalidate();
751+
}
745752
return true;
746-
753+
}
747754
/*
748755
Reprepare_observer ensures that the statement is retried a maximum number
749756
of times, to avoid an endless loop.

0 commit comments

Comments
 (0)