Bug #21726 Incorrect result with multiple invocations of LAST_INSERT_ID
| Submitted: | 18 Aug 2006 19:57 | Modified: | 13 Nov 2006 18:28 |
|---|---|---|---|
| Reporter: | Dean Ellis | Email Updates: | |
| Status: | Closed | Impact on me: | |
| Category: | MySQL Server: Stored Routines | Severity: | S1 (Critical) |
| Version: | 5.0.25-bk,4.1 | OS: | |
| Assigned to: | Tomash Brechko | CPU Architecture: | Any |
[18 Aug 2006 19:57]
Dean Ellis
[31 Aug 2006 5:32]
Valeriy Kravchuk
Bug #21808 was marked as a duplicate of this one. 5.0.24, Windows.
[31 Aug 2006 8:01]
Guilhem Bichot
It will be interesting to check if this bug also exists in 5.1: I changed some things in LAST_INSERT_ID() in 5.1 in July.
[5 Sep 2006 19:48]
Vance Rodriguez
This bug may have/be a duplicate at Bug #21616.
[14 Sep 2006 19:44]
Sveta Smirnova
There is duplicate bug #22327
[22 Sep 2006 12:34]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/12394 ChangeSet@1.2264, 2006-09-22 16:33:20+04:00, kroki@moonlight.intranet +10 -0 BUG#21726: Incorrect result with multiple invocations of LAST_INSERT_ID Non-upper-level INSERTs (the ones in the body of stored procedure, stored function, or trigger) into a table that have AUTO_INCREMENT column didn't affected the result of LAST_INSERT_ID() on this level. The problem was introduced with the fix of bug 6880, where current insert_id value that was remembered on the first call to LAST_INSERT_ID() was returned from that function until it was reset before the next _upper-level_ statement. The very procedure of remembering current insert_id had another defects that made the fix for bug 6880 only a partial solution. The fix for bug#21726 employs the following protocol: - remember insert_id value after the statement execution (which is at that point equals to the first insert_id value generated by the statement or the result of its explicit setting). - on statements "LAST_INSERT_ID(expr)", "SET LAST_INSERT_ID= expr", and on binary log command "LAST_INSERT_ID= constant" update remembered insert_id value. Thus, the value returned by LAST_INSERT_ID() is not affected by values generated by current statement, but affected by its explicit update. This fix is for 5.0 only, as in 5.1 WL 3146 solves the same problems in a more generic way. This patch tries to produce the same results as 5.1.
[27 Sep 2006 16:14]
Konstantin Osipov
I'm the second reviewer here, after Rafal. Setting a ETA.
[28 Sep 2006 19:05]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/12762 ChangeSet@1.2289, 2006-09-28 23:04:11+04:00, kroki@moonlight.intranet +13 -0 BUG#21726: Incorrect result with multiple invocations of LAST_INSERT_ID Non-upper-level INSERTs (the ones in the body of stored procedure, stored function, or trigger) into a table that have AUTO_INCREMENT column didn't affected the result of LAST_INSERT_ID() on this level. The problem was introduced with the fix of bug 6880, which in turn was introduced with the fix of bug 3117, where current insert_id value was remembered on the first call to LAST_INSERT_ID() (bug 3117) and was returned from that function until it was reset before the next _upper-level_ statement (bug 6880). The fix for bug#21726 brings back the behaviour of version 4.0, and implements the following: remember insert_id value in Item_func_last_insert_id::fix_fields() (which at that point equals to the first insert_id value generated by the previous statement), and return that remembered value from THD::insert_id(). Thus, the value returned by LAST_INSERT_ID() is not affected by values generated by current statement, nor by LAST_INSERT_ID(expr) calls in this statement. Version 5.1 does not have this bug (it was fixed by WL 3146).
[2 Oct 2006 10:29]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/12930 ChangeSet@1.2293, 2006-10-02 14:28:23+04:00, kroki@moonlight.intranet +14 -0 BUG#21726: Incorrect result with multiple invocations of LAST_INSERT_ID Non-upper-level INSERTs (the ones in the body of stored procedure, stored function, or trigger) into a table that have AUTO_INCREMENT column didn't affected the result of LAST_INSERT_ID() on this level. The problem was introduced with the fix of bug 6880, which in turn was introduced with the fix of bug 3117, where current insert_id value was remembered on the first call to LAST_INSERT_ID() (bug 3117) and was returned from that function until it was reset before the next _upper-level_ statement (bug 6880). The fix for bug#21726 brings back the behaviour of version 4.0, and implements the following: remember insert_id value at the beginning of the statement or expression (which at that point equals to the first insert_id value generated by the previous statement), and return that remembered value from LAST_INSERT_ID() or @@LAST_INSERT_ID. Thus, the value returned by LAST_INSERT_ID() is not affected by values generated by current statement, nor by LAST_INSERT_ID(expr) calls in this statement. Version 5.1 does not have this bug (it was fixed by WL 3146).
[2 Oct 2006 13:45]
Tomash Brechko
Pushed to 5.0.
[2 Oct 2006 13:50]
Tomash Brechko
Pushed to 5.0.26, that is.
[2 Oct 2006 15:04]
Konstantin Osipov
For the record: the patch was approved over email, phone, irc. Me, Rafal and Guilhem all looked at the final patch.
[3 Oct 2006 9:39]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/12990 ChangeSet@1.2294, 2006-10-03 13:38:16+04:00, kroki@moonlight.intranet +9 -0 Fix for the patch for bug#21726: Incorrect result with multiple invocations of LAST_INSERT_ID. Reding of LAST_INSERT_ID inside stored function wasn't noted by caller, and no LAST_INSERT_ID_EVENT was issued for binary log. The solution is to add THD::last_insert_id_used_bin_log, which is much like THD::last_insert_id_used, but is reset only for upper-level statements. This new variable is used to issue LAST_INSERT_ID_EVENT.
[3 Oct 2006 20:12]
Russ Brown
Is there a workaround that I can use to get around this problem while I wait for an official release which contains the fix? The only one I can think of is to wrap the inserts into individual functions, but that seems really messy and over the top... Thanks.
[4 Oct 2006 19:12]
Paul DuBois
Noted in 5.0.26. The value of LAST_INSERT_ID() was not always updated correctly within stored routines.
[5 Oct 2006 9:54]
Tomash Brechko
Setting back to 'In progress' for 4.1.
[6 Oct 2006 9:35]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/13222 ChangeSet@1.2554, 2006-10-06 13:34:07+04:00, kroki@moonlight.intranet +13 -0 BUG#21726: Incorrect result with multiple invocations of LAST_INSERT_ID. Note: bug#21726 does not directly apply to 4.1, as it doesn't have stored procedures. However, 4.1 had some bugs that were fixed in 5.0 by the patch for bug#21726, and this patch is a backport of those fixes. Namely, in 4.1 it fixes: - LAST_INSERT_ID(expr) didn't return value of expr (4.1 specific). - LAST_INSERT_ID() could return the value generated by current statement if the call happens after the generation, like in CREATE TABLE t1 (i INT AUTO_INCREMENT PRIMARY KEY, j INT); INSERT INTO t1 VALUES (NULL, 0), (NULL, LAST_INSERT_ID()); - Redundant binary log LAST_INSERT_ID_EVENTs could be generated.
[11 Oct 2006 12:20]
Paul van Rossem
Bug still present in 5.0.26.
[11 Oct 2006 12:28]
Tomash Brechko
Paul, could you please provide an example the reveals this bug in 5.0.26?
[12 Oct 2006 15:46]
Peter Andrews
This bug is stil present in 5.1.11 beta windows. Here is a sample that returns increasing values for last_insert_id() despite the table remaining with only one row: DROP TABLE IF EXISTS `d`; CREATE TABLE `d` ( `k` int(11) NOT NULL auto_increment, `a` int(11) default NULL, `c` int(11) default NULL, PRIMARY KEY (`k`), UNIQUE KEY `idx_1` (`a`) ) ENGINE=InnoDB; insert into d values(null,4,2); insert into d values(null,5,2),(null,4,2); select last_insert_id(); select * from d; insert into d values(null,5,2),(null,4,2); select last_insert_id(); select * from d; insert into d values(null,5,2),(null,4,2); select last_insert_id(); select * from d; insert into d values(null,5,2),(null,4,2); select last_insert_id(); select * from d; insert into d values(null,5,2),(null,4,2); select last_insert_id(); select * from d;
[13 Oct 2006 7:22]
Paul van Rossem
Example where this still fails in 5.0.26:
CREATE TABLE T3
(T3ID INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE T1
(T1ID INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
T3Ref INTEGER,
FOREIGN KEY (T3Ref) REFERENCES T3(T3ID) ON DELETE RESTRICT ON UPDATE CASCADE
);
CREATE TABLE T2
(T2ID INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
T1Ref INTEGER NOT NULL,
FOREIGN KEY (T1Ref) REFERENCES T1(T1ID) ON DELETE CASCADE ON UPDATE CASCADE
);
INSERT INTO T3(T3ID) VALUES (123);
INSERT INTO T1(T1ID, T3Ref) VALUES (33, 123);
INSERT INTO T2(T2ID, T1Ref) VALUES (222, 33);
CREATE PROCEDURE T1_COPY (srcT1 INTEGER)
BEGIN
DECLARE dstT1 INTEGER
DECLARE srcT3 INTEGER; DECLARE dstT3 INTEGER;
DECLARE srcT2 INTEGER; DECLARE dstT2 INTEGER;
DECLARE done SMALLINT DEFAULT 0;
DECLARE t2Cursor CURSOR FOR SELECT T2ID FROM T2 WHERE T1Ref = srcT1;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
SELECT T3Ref INTO srcT3 FROM T1 WHERE T1ID = srcT1;
CALL T3_COPY(srcT3, dstT3);
INSERT INTO T1(T3Ref) VALUES (dstT3);
SET dstT1 = LAST_INSERT_ID(); /* this sets the value of the last T3 insert,
not of the T1 insert! */
OPEN t2Cursor;
REPEAT
FETCH t2Cursor INTO srcT2;
IF NOT done THEN
CALL T2_COPY(srcT2, dstT1, dstT2); /* fails because of invalid dstT1 */
END IF;
UNTIL done END REPEAT;
END $
CREATE PROCEDURE T2_COPY (srcT2 INTEGER, dstT1 INTEGER, OUT newT2 INTEGER)
BEGIN
DECLARE srcT1 INTEGER;
SELECT T1Ref INTO srcT1 FROM T2 WHERE T2ID = srcT2;
INSERT INTO T2(T1Ref) VALUES (dstT1);
SET newT2 = LAST_INSERT_ID();
END $
CREATE PROCEDURE T3_COPY (srcT3 INTEGER, OUT newT3 INTEGER)
BEGIN
INSERT INTO T3() VALUES ();
SET newT3 = LAST_INSERT_ID();
END $
CALL T1_COPY(33, result); /* fails for resons mentioned above */
[13 Oct 2006 7:59]
Tomash Brechko
Paul, after running your test case I get the following correct results: SELECT * FROM T1; #+------+-------+ #| T1ID | T3Ref | #+------+-------+ #| 33 | 123 | #| 34 | 124 | <= '34' was generated by INSERT INTO T1(T3Ref) VALUES (dstT3); #+------+-------+ and it was assigned to dstT1. SELECT * FROM T2; #+------+-------+ #| T2ID | T1Ref | #+------+-------+ #| 222 | 33 | #| 223 | 34 | <= '34' was inserted by INSERT INTO T2(T1Ref) VALUES (dstT1); #+------+-------+ which is correct. SELECT * FROM T3; #+------+ #| T3ID | #+------+ #| 123 | #| 124 | #+------+ If you results differ from the above, please paste them, and also the output of "SELECT VERSION();". If you have the same results, then I guess everything is correct.
[13 Oct 2006 9:08]
Tomash Brechko
Peter, I have opened a new bug#23249 based on your input, thanks.
[13 Oct 2006 11:24]
Paul van Rossem
Tomash, I re-downloaded and re-installed windows server 5.0.26, and now I get the correct results. So the problem must have been with my server installation. Owe you an apology. The problem appears solved with 5.0.26. Regards, Paul.
[13 Oct 2006 11:32]
Tomash Brechko
Paul, that's great. Thanks for letting us know.
[16 Oct 2006 16:47]
Konstantin Osipov
Approved the version for 4.1
[17 Oct 2006 10:01]
Tomash Brechko
4.1 version queued to 4.1-runtime and null-merged to 5.0-runtime and 5.1-runtime.
[3 Nov 2006 10:54]
Tomash Brechko
Bug#23932 relates to this bug.
[11 Nov 2006 3:27]
Paul DuBois
Noted in 4.1.22 changelog. The value of LAST_INSERT_ID() was not always updated correctly within stored routines.
[13 Nov 2006 18:28]
Paul DuBois
Corrected the 4.1.21 changelog entry: Redundant binary log LAST_INSERT_ID events could be generated; LAST_INSERT_ID(expr) didn't return value of expr; LAST_INSERT_ID() could return the value generated by the current statement if the call happens after value generation, as in: CREATE TABLE t1 (i INT AUTO_INCREMENT PRIMARY KEY, j INT); INSERT INTO t1 VALUES (NULL, 0), (NULL, LAST_INSERT_ID());
Portions of this website are copyright © 2001, 2002 The PHP Group
Page generated in 0.066 sec. using MySQL 8.4.7-u6-cloud
Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the
respective copyright holders.
It is not reviewed in advance
by Oracle and does not necessarily represent the opinion of
Oracle or any other party.