From 10eac46a520351d47ffbe74aeb14fdd7c6fecd87 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Apr 2006 18:55:04 +0400 Subject: [PATCH] Bug#15728: LAST_INSERT_ID function inside a stored function returns 0 Do not reset value of LAST_INSERT_ID() in sub-statement. mysql-test/r/rpl_insert_id.result: Add result for bug#15728. mysql-test/r/sp.result: Add result for bug#15728. mysql-test/t/rpl_insert_id.test: Add test case for bug#15728. mysql-test/t/sp.test: Add test case for bug#15728. sql/sql_class.cc: Do not reset value of LAST_INSERT_ID() in sub-statement. --- mysql-test/r/rpl_insert_id.result | 58 +++++++++++++++++++++++++ mysql-test/r/sp.result | 17 ++++++++ mysql-test/t/rpl_insert_id.test | 70 +++++++++++++++++++++++++++++++ mysql-test/t/sp.test | 25 +++++++++++ sql/sql_class.cc | 5 ++- 5 files changed, 173 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/rpl_insert_id.result b/mysql-test/r/rpl_insert_id.result index d7b6946f7e5..b11f1b92020 100644 --- a/mysql-test/r/rpl_insert_id.result +++ b/mysql-test/r/rpl_insert_id.result @@ -74,3 +74,61 @@ SET FOREIGN_KEY_CHECKS=0; INSERT INTO t1 VALUES (1),(1); ERROR 23000: Duplicate entry '1' for key 1 drop table t1; +drop function if exists bug15728; +drop function if exists bug15728_insert; +drop table if exists t1, t2; +create table t1 ( +id int not null auto_increment, +last_id int, +primary key (id) +); +create function bug15728() returns int(11) +return last_insert_id(); +insert into t1 (last_id) values (0); +insert into t1 (last_id) values (last_insert_id()); +insert into t1 (last_id) values (bug15728()); +create table t2 ( +id int not null auto_increment, +last_id int, +primary key (id) +); +create function bug15728_insert() returns int(11) modifies sql data +begin +insert into t2 (last_id) values (bug15728()); +return bug15728(); +end| +create trigger t1_bi before insert on t1 for each row +begin +declare res int; +select bug15728_insert() into res; +set NEW.last_id = res; +end| +insert into t1 (last_id) values (0); +drop trigger t1_bi; +select last_insert_id(); +last_insert_id() +4 +select bug15728_insert(); +bug15728_insert() +2 +select last_insert_id(); +last_insert_id() +4 +insert into t1 (last_id) values (bug15728()); +select last_insert_id(); +last_insert_id() +5 +select * from t1; +id last_id +1 0 +2 1 +3 2 +4 1 +5 4 +select * from t2; +id last_id +1 3 +2 4 +drop function bug15728; +drop function bug15728_insert; +drop table t1, t2; diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 2787f0d5991..59ce1d13d2b 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -4848,6 +4848,23 @@ c 2 b 3 a 1 delete from t1| +drop function if exists bug15728| +drop table if exists t3| +create table t3 ( +id int not null auto_increment, +primary key (id) +)| +create function bug15728() returns int(11) +return last_insert_id()| +insert into t3 values (0)| +select last_insert_id()| +last_insert_id() +1 +select bug15728()| +bug15728() +1 +drop function bug15728| +drop table t3| drop procedure if exists bug18787| create procedure bug18787() begin diff --git a/mysql-test/t/rpl_insert_id.test b/mysql-test/t/rpl_insert_id.test index f025ae9e587..ccd80dce388 100644 --- a/mysql-test/t/rpl_insert_id.test +++ b/mysql-test/t/rpl_insert_id.test @@ -78,3 +78,73 @@ connection master; drop table t1; sync_slave_with_master; # End of 4.1 tests + + +# +# BUG#15728: LAST_INSERT_ID function inside a stored function returns 0 +# +# The solution is not to reset last_insert_id on enter to sub-statement. +# +connection master; +--disable_warnings +drop function if exists bug15728; +drop function if exists bug15728_insert; +drop table if exists t1, t2; +--enable_warnings + +create table t1 ( + id int not null auto_increment, + last_id int, + primary key (id) +); +create function bug15728() returns int(11) + return last_insert_id(); + +insert into t1 (last_id) values (0); +insert into t1 (last_id) values (last_insert_id()); +insert into t1 (last_id) values (bug15728()); + +# Check that nested call replicates too. +create table t2 ( + id int not null auto_increment, + last_id int, + primary key (id) +); +delimiter |; +create function bug15728_insert() returns int(11) modifies sql data +begin + insert into t2 (last_id) values (bug15728()); + return bug15728(); +end| +create trigger t1_bi before insert on t1 for each row +begin + declare res int; + select bug15728_insert() into res; + set NEW.last_id = res; +end| +delimiter ;| + +insert into t1 (last_id) values (0); + +drop trigger t1_bi; + +# Check that nested call doesn't affect outer context. +select last_insert_id(); +select bug15728_insert(); +select last_insert_id(); +insert into t1 (last_id) values (bug15728()); +# This should be exactly one greater than in the previous call. +select last_insert_id(); + +save_master_pos; +connection slave; +sync_with_master; +select * from t1; +select * from t2; +connection master; + +drop function bug15728; +drop function bug15728_insert; +drop table t1, t2; + +# End of 5.0 tests diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 77c1982a7a8..22500bbd280 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -5698,6 +5698,31 @@ select * from t1 order by @x| delete from t1| +# +# BUG#15728: LAST_INSERT_ID function inside a stored function returns 0 +# +# The solution is not to reset last_insert_id on enter to sub-statement. +# +--disable_warnings +drop function if exists bug15728| +drop table if exists t3| +--enable_warnings + +create table t3 ( + id int not null auto_increment, + primary key (id) +)| +create function bug15728() returns int(11) + return last_insert_id()| + +insert into t3 values (0)| +select last_insert_id()| +select bug15728()| + +drop function bug15728| +drop table t3| + + # # BUG#18787: Server crashed when calling a stored procedure containing # a misnamed function diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d56f10a7a30..026c3e0d515 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2025,7 +2025,7 @@ void THD::restore_backup_open_tables_state(Open_tables_state *backup) The following things is done - Disable binary logging for the duration of the statement - Disable multi-result-sets for the duration of the statement - - Value of last_insert_id() is reset and restored + - Value of last_insert_id() is saved and restored - Value set by 'SET INSERT_ID=#' is reset and restored - Value for found_rows() is reset and restored - examined_row_count is added to the total @@ -2037,6 +2037,8 @@ void THD::restore_backup_open_tables_state(Open_tables_state *backup) We reset examined_row_count and cuted_fields and add these to the result to ensure that if we have a bug that would reset these within a function, we are not loosing any rows from the main statement. + + We do not reset value of last_insert_id(). ****************************************************************************/ void THD::reset_sub_statement_state(Sub_statement_state *backup, @@ -2062,7 +2064,6 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, /* Disable result sets */ client_capabilities &= ~CLIENT_MULTI_RESULTS; in_sub_stmt|= new_state; - last_insert_id= 0; next_insert_id= 0; insert_id_used= 0; examined_row_count= 0;