mirror of
https://github.com/MariaDB/server.git
synced 2025-08-09 22:24:09 +03:00
MDEV-10702 Crash in SET STATEMENT FOR EXECUTE
This commit is contained in:
@@ -2542,3 +2542,32 @@ EXECUTE stmt3;
|
|||||||
EXECUTE stmt3;
|
EXECUTE stmt3;
|
||||||
DEALLOCATE PREPARE stmt3;
|
DEALLOCATE PREPARE stmt3;
|
||||||
DROP TEMPORARY TABLES tm, t1;
|
DROP TEMPORARY TABLES tm, t1;
|
||||||
|
#
|
||||||
|
# Start of 10.1 tests
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# MDEV-10702 Crash in SET STATEMENT FOR EXECUTE
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (a INT);
|
||||||
|
PREPARE stmt FROM 'INSERT INTO t1 VALUES (@@max_sort_length)';
|
||||||
|
SET STATEMENT max_sort_length=2048 FOR EXECUTE stmt;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
a
|
||||||
|
2048
|
||||||
|
CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a=NEW.a + 1;
|
||||||
|
SET STATEMENT max_sort_length=2048 FOR EXECUTE stmt;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
a
|
||||||
|
2048
|
||||||
|
1025
|
||||||
|
DROP TRIGGER tr1;
|
||||||
|
SET STATEMENT max_sort_length=2048 FOR EXECUTE stmt;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
a
|
||||||
|
2048
|
||||||
|
1025
|
||||||
|
1024
|
||||||
|
DROP TABLE t1;
|
||||||
|
#
|
||||||
|
# End of 10.1 tests
|
||||||
|
#
|
||||||
|
@@ -2259,3 +2259,27 @@ EXECUTE stmt3;
|
|||||||
EXECUTE stmt3;
|
EXECUTE stmt3;
|
||||||
DEALLOCATE PREPARE stmt3;
|
DEALLOCATE PREPARE stmt3;
|
||||||
DROP TEMPORARY TABLES tm, t1;
|
DROP TEMPORARY TABLES tm, t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Start of 10.1 tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-10702 Crash in SET STATEMENT FOR EXECUTE
|
||||||
|
--echo #
|
||||||
|
CREATE TABLE t1 (a INT);
|
||||||
|
PREPARE stmt FROM 'INSERT INTO t1 VALUES (@@max_sort_length)';
|
||||||
|
SET STATEMENT max_sort_length=2048 FOR EXECUTE stmt;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a=NEW.a + 1;
|
||||||
|
SET STATEMENT max_sort_length=2048 FOR EXECUTE stmt;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
DROP TRIGGER tr1;
|
||||||
|
SET STATEMENT max_sort_length=2048 FOR EXECUTE stmt;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 10.1 tests
|
||||||
|
--echo #
|
||||||
|
@@ -3030,7 +3030,36 @@ void mysql_sql_stmt_execute(THD *thd)
|
|||||||
|
|
||||||
DBUG_PRINT("info",("stmt: 0x%lx", (long) stmt));
|
DBUG_PRINT("info",("stmt: 0x%lx", (long) stmt));
|
||||||
|
|
||||||
|
/*
|
||||||
|
thd->free_list can already have some Items,
|
||||||
|
e.g. for a query like this:
|
||||||
|
PREPARE stmt FROM 'INSERT INTO t1 VALUES (@@max_sort_length)';
|
||||||
|
SET STATEMENT max_sort_length=2048 FOR EXECUTE stmt;
|
||||||
|
thd->free_list contains a pointer to Item_int corresponding to 2048.
|
||||||
|
|
||||||
|
If Prepared_statement::execute() notices that the table metadata for "t1"
|
||||||
|
has changed since PREPARE, it returns an error asking the calling
|
||||||
|
Prepared_statement::execute_loop() to re-prepare the statement.
|
||||||
|
Before returning the error, Prepared_statement::execute()
|
||||||
|
calls Prepared_statement::cleanup_stmt(),
|
||||||
|
which calls thd->cleanup_after_query(),
|
||||||
|
which calls Query_arena::free_items().
|
||||||
|
|
||||||
|
We hide "external" Items, e.g. those created while parsing the
|
||||||
|
"SET STATEMENT" part of the query,
|
||||||
|
so they don't get freed in case of re-prepare.
|
||||||
|
See MDEV-10702 Crash in SET STATEMENT FOR EXECUTE
|
||||||
|
*/
|
||||||
|
Item *free_list_backup= thd->free_list;
|
||||||
|
thd->free_list= NULL; // Hide the external (e.g. "SET STATEMENT") Items
|
||||||
(void) stmt->execute_loop(&expanded_query, FALSE, NULL, NULL);
|
(void) stmt->execute_loop(&expanded_query, FALSE, NULL, NULL);
|
||||||
|
thd->free_items(); // Free items created by execute_loop()
|
||||||
|
/*
|
||||||
|
Now restore the "external" (e.g. "SET STATEMENT") Item list.
|
||||||
|
It will be freed normaly in THD::cleanup_after_query().
|
||||||
|
*/
|
||||||
|
thd->free_list= free_list_backup;
|
||||||
|
|
||||||
stmt->lex->restore_set_statement_var();
|
stmt->lex->restore_set_statement_var();
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
@@ -3853,9 +3882,14 @@ Prepared_statement::execute_loop(String *expanded_query,
|
|||||||
Reprepare_observer reprepare_observer;
|
Reprepare_observer reprepare_observer;
|
||||||
bool error;
|
bool error;
|
||||||
int reprepare_attempt= 0;
|
int reprepare_attempt= 0;
|
||||||
#ifndef DBUG_OFF
|
|
||||||
Item *free_list_state= thd->free_list;
|
/*
|
||||||
#endif
|
- In mysql_sql_stmt_execute() we hide all "external" Items
|
||||||
|
e.g. those created in the "SET STATEMENT" part of the "EXECUTE" query.
|
||||||
|
- In case of mysqld_stmt_execute() there should not be "external" Items.
|
||||||
|
*/
|
||||||
|
DBUG_ASSERT(thd->free_list == NULL);
|
||||||
|
|
||||||
thd->select_number= select_number_after_prepare;
|
thd->select_number= select_number_after_prepare;
|
||||||
/* Check if we got an error when sending long data */
|
/* Check if we got an error when sending long data */
|
||||||
if (state == Query_arena::STMT_ERROR)
|
if (state == Query_arena::STMT_ERROR)
|
||||||
@@ -3877,12 +3911,8 @@ Prepared_statement::execute_loop(String *expanded_query,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
reexecute:
|
reexecute:
|
||||||
/*
|
// Make sure that reprepare() did not create any new Items.
|
||||||
If the free_list is not empty, we'll wrongly free some externally
|
DBUG_ASSERT(thd->free_list == NULL);
|
||||||
allocated items when cleaning up after validation of the prepared
|
|
||||||
statement.
|
|
||||||
*/
|
|
||||||
DBUG_ASSERT(thd->free_list == free_list_state);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Install the metadata observer. If some metadata version is
|
Install the metadata observer. If some metadata version is
|
||||||
|
Reference in New Issue
Block a user