diff --git a/BitKeeper/etc/collapsed b/BitKeeper/etc/collapsed index a4f24702b58..0eb8a32482d 100644 --- a/BitKeeper/etc/collapsed +++ b/BitKeeper/etc/collapsed @@ -5,3 +5,5 @@ 4513d8e4Af4dQWuk13sArwofRgFDQw 4519a6c5BVUxEHTf5iJnjZkixMBs8g 451ab499rgdjXyOnUDqHu-wBDoS-OQ +45214442pBGT9KuZEGixBH71jTzbOA +45214a07hVsIGwvwa-WrO-jpeaSwVw diff --git a/mysql-test/r/ps_11bugs.result b/mysql-test/r/ps_11bugs.result index c849c25d646..ebe161f46b3 100644 --- a/mysql-test/r/ps_11bugs.result +++ b/mysql-test/r/ps_11bugs.result @@ -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. diff --git a/mysql-test/t/ps_11bugs.test b/mysql-test/t/ps_11bugs.test index ff1c87f3bd8..515bcc03c1a 100644 --- a/mysql-test/t/ps_11bugs.test +++ b/mysql-test/t/ps_11bugs.test @@ -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. diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 63a129918d0..fa33cafdab1 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2287,6 +2287,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)) @@ -2349,6 +2357,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; @@ -2827,12 +2842,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); @@ -2930,7 +2945,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(),