mirror of
https://github.com/MariaDB/server.git
synced 2026-04-20 23:35:32 +02:00
Bug#19356: Assert on undefined @uservar in prepared statement execute
The executing code had a safety assertion so that it refused to free Items
that it didn't create. However, there is a case, undefined user variables,
which would put Items into the list to be freed.
Instead, do something that is more risky in expectation that the code will
be refactored soon, as Kostja wants to do: Remove the assertions from
prepare() and execute(). Put one assertion at a higher level, before
stmt->set_params_from_vars(), which may then create new to-be-freed Items .
mysql-test/r/ps_11bugs.result:
Create tests to prove that undefined variables work, as keys and not, and
that variables explicitly assigned to Null work.
mysql-test/t/ps_11bugs.test:
Create tests to prove that undefined variables work, as keys and not, and
that variables explicitly assigned to Null work.
sql/sql_prepare.cc:
Move a safety assertion up one level and higher, because there is
legitimately a case where thd->free_list is not NULL going into
Prepared_statement::{prepare,execute} methods.
Kostja plans to refactor this code so that it is both safe and works.
(Now it works, but isn't very safe.)
This commit is contained in:
parent
00820e2b0a
commit
f60ea28841
4 changed files with 96 additions and 6 deletions
|
|
@ -2,3 +2,5 @@
|
|||
44ec850ac2k4y2Omgr92GiWPBAVKGQ
|
||||
44edb86b1iE5knJ97MbliK_3lCiAXA
|
||||
44f33f3aj5KW5qweQeekY1LU0E9ZCg
|
||||
45214442pBGT9KuZEGixBH71jTzbOA
|
||||
45214a07hVsIGwvwa-WrO-jpeaSwVw
|
||||
|
|
|
|||
|
|
@ -130,3 +130,36 @@ prepare st_18492 from 'select * from t1 where 3 in (select (1+1) union select 1)
|
|||
execute st_18492;
|
||||
a
|
||||
drop table t1;
|
||||
create table t1 (a int, b varchar(4));
|
||||
create table t2 (a int, b varchar(4), primary key(a));
|
||||
prepare stmt1 from 'insert into t1 (a, b) values (?, ?)';
|
||||
prepare stmt2 from 'insert into t2 (a, b) values (?, ?)';
|
||||
set @intarg= 11;
|
||||
set @varchararg= '2222';
|
||||
execute stmt1 using @intarg, @varchararg;
|
||||
execute stmt2 using @intarg, @varchararg;
|
||||
set @intarg= 12;
|
||||
execute stmt1 using @intarg, @UNDEFINED;
|
||||
execute stmt2 using @intarg, @UNDEFINED;
|
||||
set @intarg= 13;
|
||||
execute stmt1 using @UNDEFINED, @varchararg;
|
||||
execute stmt2 using @UNDEFINED, @varchararg;
|
||||
ERROR 23000: Column 'a' cannot be null
|
||||
set @intarg= 14;
|
||||
set @nullarg= Null;
|
||||
execute stmt1 using @UNDEFINED, @nullarg;
|
||||
execute stmt2 using @nullarg, @varchararg;
|
||||
ERROR 23000: Column 'a' cannot be null
|
||||
select * from t1;
|
||||
a b
|
||||
11 2222
|
||||
12 NULL
|
||||
NULL 2222
|
||||
NULL NULL
|
||||
select * from t2;
|
||||
a b
|
||||
11 2222
|
||||
12 NULL
|
||||
drop table t1;
|
||||
drop table t2;
|
||||
End of 5.0 tests.
|
||||
|
|
|
|||
|
|
@ -144,3 +144,37 @@ prepare st_18492 from 'select * from t1 where 3 in (select (1+1) union select 1)
|
|||
execute st_18492;
|
||||
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# Bug#19356: Assertion failure with undefined @uservar in prepared statement execution
|
||||
#
|
||||
create table t1 (a int, b varchar(4));
|
||||
create table t2 (a int, b varchar(4), primary key(a));
|
||||
|
||||
prepare stmt1 from 'insert into t1 (a, b) values (?, ?)';
|
||||
prepare stmt2 from 'insert into t2 (a, b) values (?, ?)';
|
||||
|
||||
set @intarg= 11;
|
||||
set @varchararg= '2222';
|
||||
execute stmt1 using @intarg, @varchararg;
|
||||
execute stmt2 using @intarg, @varchararg;
|
||||
set @intarg= 12;
|
||||
execute stmt1 using @intarg, @UNDEFINED;
|
||||
execute stmt2 using @intarg, @UNDEFINED;
|
||||
set @intarg= 13;
|
||||
execute stmt1 using @UNDEFINED, @varchararg;
|
||||
--error 1048
|
||||
execute stmt2 using @UNDEFINED, @varchararg;
|
||||
set @intarg= 14;
|
||||
set @nullarg= Null;
|
||||
execute stmt1 using @UNDEFINED, @nullarg;
|
||||
--error 1048
|
||||
execute stmt2 using @nullarg, @varchararg;
|
||||
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
|
||||
drop table t1;
|
||||
drop table t2;
|
||||
|
||||
--echo End of 5.0 tests.
|
||||
|
|
|
|||
|
|
@ -2248,6 +2248,14 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
|
|||
#endif
|
||||
if (!(specialflag & SPECIAL_NO_PRIOR))
|
||||
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
|
||||
|
||||
/*
|
||||
If the free_list is not empty, we'll wrongly free some externally
|
||||
allocated items when cleaning up after validation of the prepared
|
||||
statement.
|
||||
*/
|
||||
DBUG_ASSERT(thd->free_list == NULL);
|
||||
|
||||
error= stmt->execute(&expanded_query,
|
||||
test(flags & (ulong) CURSOR_TYPE_READ_ONLY));
|
||||
if (!(specialflag & SPECIAL_NO_PRIOR))
|
||||
|
|
@ -2310,6 +2318,13 @@ void mysql_sql_stmt_execute(THD *thd)
|
|||
|
||||
DBUG_PRINT("info",("stmt: %p", stmt));
|
||||
|
||||
/*
|
||||
If the free_list is not empty, we'll wrongly free some externally
|
||||
allocated items when cleaning up after validation of the prepared
|
||||
statement.
|
||||
*/
|
||||
DBUG_ASSERT(thd->free_list == NULL);
|
||||
|
||||
if (stmt->set_params_from_vars(stmt, lex->prepared_stmt_params,
|
||||
&expanded_query))
|
||||
goto set_params_data_err;
|
||||
|
|
@ -2788,12 +2803,12 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
|
|||
external changes when cleaning up after validation.
|
||||
*/
|
||||
DBUG_ASSERT(thd->change_list.is_empty());
|
||||
/*
|
||||
If the free_list is not empty, we'll wrongly free some externally
|
||||
allocated items when cleaning up after validation of the prepared
|
||||
statement.
|
||||
|
||||
/*
|
||||
The only case where we should have items in the thd->free_list is
|
||||
after stmt->set_params_from_vars(), which may in some cases create
|
||||
Item_null objects.
|
||||
*/
|
||||
DBUG_ASSERT(thd->free_list == NULL);
|
||||
|
||||
if (error == 0)
|
||||
error= check_prepared_statement(this, name.str != 0);
|
||||
|
|
@ -2891,7 +2906,13 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
|
|||
allocated items when cleaning up after execution of this statement.
|
||||
*/
|
||||
DBUG_ASSERT(thd->change_list.is_empty());
|
||||
DBUG_ASSERT(thd->free_list == NULL);
|
||||
|
||||
/*
|
||||
The only case where we should have items in the thd->free_list is
|
||||
after stmt->set_params_from_vars(), which may in some cases create
|
||||
Item_null objects.
|
||||
*/
|
||||
|
||||
thd->set_n_backup_statement(this, &stmt_backup);
|
||||
if (expanded_query->length() &&
|
||||
alloc_query(thd, (char*) expanded_query->ptr(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue