Bug #116939 | LAST_INSERT_ID(0) not visible in OK packet | ||
---|---|---|---|
Submitted: | 11 Dec 2024 9:38 | Modified: | 11 Dec 2024 15:59 |
Reporter: | Andres Taylor | Email Updates: | |
Status: | Not a Bug | Impact on me: | |
Category: | MySQL Server: Connection Handling | Severity: | S3 (Non-critical) |
Version: | 8.4.2 | OS: | MacOS |
Assigned to: | CPU Architecture: | ARM |
[11 Dec 2024 9:38]
Andres Taylor
[11 Dec 2024 9:39]
Andres Taylor
Wireshark capture showing the issue
Attachment: last_insert_id.pcap (application/octet-stream, text), 6.21 KiB.
[11 Dec 2024 11:28]
Daniël van Eeden
Hi. Looking at the pcap I think this might be an issue with Wireshark and not an issue with MySQL. There is one byte between the 'Affected Rows' value and the 'Server Status' value. I think this 00 should have been the last insert ID. Please report an issue for this at https://gitlab.com/wireshark/wireshark/-/issues/new and I'll try to debug and fix this. However, you likely may have looked into this because of issues with an application or otherwise. Maybe that application, connector, etc. has a similar issue. In that case it *could* be a MySQL related issue.
[11 Dec 2024 11:29]
Daniël van Eeden
https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_ok_packet.html has the details of the OK packet
[11 Dec 2024 14:26]
Daniël van Eeden
https://gitlab.com/wireshark/wireshark/-/issues/20285
[11 Dec 2024 14:56]
MySQL Verification Team
Thank you, Daniel, This proves that this report is not a bug. Hence, the status is changed.
[11 Dec 2024 15:59]
Andres Taylor
Hi Daniël, thanks for the quick response. We encountered this while working on Vitess to replicate MySQL behavior: https://github.com/vitessio/vitess/issues/17298 From what we’ve seen, a value of 0 is returned in cases where the last_insert_id is not explicitly changed. For example, running: UPDATE test.t SET id = 12; produces an OK packet with last_insert_id=0, even though no last_insert_id was set by this query. 0000 45 00 00 68 00 00 40 00 40 06 00 00 7f 00 00 01 0010 7f 00 00 01 0c ea d1 92 48 3a d5 b6 a1 60 78 4f 0020 80 18 18 e7 fe 5c 00 00 01 01 08 0a fc 4b ea db 0030 48 66 21 34 30 00 00 01 00 01 ->00<- 22 00 00 00 28 0040 52 6f 77 73 20 6d 61 74 63 68 65 64 3a 20 31 20 0050 20 43 68 61 6e 67 65 64 3a 20 31 20 20 57 61 72 0060 6e 69 6e 67 73 3a 20 30 This creates ambiguity: 0 can mean either “no change to the session value” or “the session value was explicitly set to zero.” In Vitess, we’re working around this by ignoring the zero result unless the query clearly includes a last_insert_id(x) call. Without that context, clients cannot reliably distinguish between the two scenarios. As it stands, this ambiguity seems tied to the current protocol. Unless the protocol is adjusted to differentiate these cases, clients will continue having to rely on the query itself to interpret the returned zero value.
[11 Dec 2024 16:05]
MySQL Verification Team
Hi Mr. Taylor, Thank you for your latest comment. We understand from your comment that a change in the protocol packets would be required. That is VERY difficult to do and it would necessitate many, many changes. It would all start with a change in the protocol version, so that olde Connectors and API's should have no problem in logging in with the new design of the packet, while also accommodating new Connectors and new API's ....... This would also makes huge problems with replication, since you could have two different protocol packet versions communicating in the same cluster. Hence, it would be very , very hard to accommodate this change .....
[12 Dec 2024 7:59]
Daniël van Eeden
I think the "Not a Bug" status is correct. This just seems to be a protocol limitation. This behavior probably stems from the link between LAST_INSERT_ID() and AUTO_INCREMENT, where 0 means next-id. mysql-9.1.0> CREATE TABLE t1(id int AUTO_INCREMENT PRIMARY KEY, c1 int); Query OK, 0 rows affected (0.02 sec) mysql-9.1.0> INSERT INTO t1(c1) values (10); Query OK, 1 row affected (0.01 sec) mysql-9.1.0> INSERT INTO t1(c1) values (20); Query OK, 1 row affected (0.01 sec) mysql-9.1.0> INSERT INTO t1 values (9, 30); Query OK, 1 row affected (0.01 sec) mysql-9.1.0> INSERT INTO t1 values (0, 40); Query OK, 1 row affected (0.01 sec) mysql-9.1.0> SELECT LAST_INSERT_ID(); +------------------+ | LAST_INSERT_ID() | +------------------+ | 10 | +------------------+ 1 row in set (0.00 sec) mysql-9.1.0> TABLE t1; +----+------+ | id | c1 | +----+------+ | 1 | 10 | | 2 | 20 | | 9 | 30 | | 10 | 40 | +----+------+ 4 rows in set (0.00 sec) Note that LAST_INSERT_ID() doesn't work for things that are server generated, but are not using AUTO_INCREMENT mysql-9.1.0> create table t1 (id bigint as (123) stored primary key, c1 int); Query OK, 0 rows affected (0.02 sec) mysql-9.1.0> insert into t1(c1) values (10); Query OK, 1 row affected (0.01 sec) mysql-9.1.0> select last_insert_id(); +------------------+ | last_insert_id() | +------------------+ | 0 | +------------------+ 1 row in set (0.00 sec) mysql-9.1.0> table t1; +-----+------+ | id | c1 | +-----+------+ | 123 | 10 | +-----+------+ 1 row in set (0.00 sec) I think the way forward is to: - Stop using last_insert_id (the function and the field in the OK packet) - Support the RETURNING keyword, e.g. `insert into t1(c1) values (10) returning id,c2`. Note that this doesn't need a protocol modification as it is just a normal resultset. This would also make it easier to return other columns that might be generated server side based on column defaults and definitions for generated columns.
[12 Dec 2024 11:06]
MySQL Verification Team
Thank you, Daniel .....