Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Match MySQL's LAST_INSERT_ID behaviour #15697

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions go/test/endtoend/vtgate/queries/dml/insert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,70 @@ func TestInsertSelectUnshardedUsingSharded(t *testing.T) {
}
}

// MySQL returns 0 as the `LastInsertId` on `... ON DUPLICATE KEY UPDATE ...` queries
// when no new row is inserted. This test verifies that Vitess behaves the same way.
func TestInsertShardedWithOnDuplicateKeyNoInserts(t *testing.T) {
mcmp, closer := start(t)
defer closer()

mcmp.Exec("insert into last_insert_id_test (id, sharding_key, user_id, reason) values (1, '1:1:1', 1, 'foo'), (2, '2:2:2', 2, 'bar')")

// Bump the sequence value so the sequence accounts for the 2 explicit inserts above.
utils.Exec(t, mcmp.VtConn, "SELECT NEXT 2 VALUES FROM uks.last_insert_id_test_seq")

// First test case, insert a row that already exists, and don't actually change any column at all.
query := "insert into last_insert_id_test (sharding_key, user_id, reason) values ('1:1:1', 1, 'foo') on duplicate key update reason = reason"

mysqlResult := utils.Exec(t, mcmp.MySQLConn, query)
// no new row inserted, so insert id should be 0.
assert.Equal(t, uint64(0), mysqlResult.InsertID)
// no row was modified, so rows affected should be 0.
assert.Equal(t, uint64(0), mysqlResult.RowsAffected)

vitessResult := utils.Exec(t, mcmp.VtConn, query)
assert.Equal(t, mysqlResult.RowsAffected, vitessResult.RowsAffected)
assert.Equal(t, mysqlResult.InsertID, vitessResult.InsertID)

// Second test case, insert a row that already exists, and change a column on the existing row.
query = "insert into last_insert_id_test (sharding_key, user_id, reason) values ('1:1:1', 1, 'bar') on duplicate key update reason = VALUES(reason)"

mysqlResult = utils.Exec(t, mcmp.MySQLConn, query)
// a row was modified, so insert id should match the auto increment column value of the modified row
assert.Equal(t, uint64(1), mysqlResult.InsertID)
// one row was modified, so rows affected should be 2.
assert.Equal(t, uint64(2), mysqlResult.RowsAffected)

vitessResult = utils.Exec(t, mcmp.VtConn, query)
assert.Equal(t, mysqlResult.RowsAffected, vitessResult.RowsAffected)
assert.Equal(t, mysqlResult.InsertID, vitessResult.InsertID)

// Second test case, insert multiple rows, all of which already exist, and change a column on existing rows.
query = "insert into last_insert_id_test (sharding_key, user_id, reason) values ('2:2:2', 2, 'qux'), ('1:1:1', 1, 'baz') on duplicate key update reason = VALUES(reason)"

mysqlResult = utils.Exec(t, mcmp.MySQLConn, query)
// two rows were modified, so insert id will match the auto increment column value of the last modified row
assert.Equal(t, uint64(1), mysqlResult.InsertID)
// two rows were modified, so rows affected should be 2.
assert.Equal(t, uint64(4), mysqlResult.RowsAffected)

vitessResult = utils.Exec(t, mcmp.VtConn, query)
assert.Equal(t, mysqlResult.RowsAffected, vitessResult.RowsAffected)
assert.Equal(t, mysqlResult.InsertID, vitessResult.InsertID)

// Third test case, insert multiple rows, some of which already exist, and change a column on existing rows.
query = "insert into last_insert_id_test (sharding_key, user_id, reason) values ('3:3:3', 3, 'apa'), ('2:2:2', 2, 'bpa'), ('1:1:1', 1, 'cpa') on duplicate key update reason = VALUES(reason)"

mysqlResult = utils.Exec(t, mcmp.MySQLConn, query)
// a new row was inserted, so insert id should match the auto increment column value of the new row
assert.Equal(t, uint64(7), mysqlResult.InsertID)
// one row was inserted, two rows were modified, so rows affected should be 5.
assert.Equal(t, uint64(5), mysqlResult.RowsAffected)

vitessResult = utils.Exec(t, mcmp.VtConn, query)
assert.Equal(t, mysqlResult.RowsAffected, vitessResult.RowsAffected)
assert.Equal(t, mysqlResult.InsertID, vitessResult.InsertID)
}

func TestRedactDupError(t *testing.T) {
mcmp, closer := start(t)
defer closer()
Expand Down
10 changes: 10 additions & 0 deletions go/test/endtoend/vtgate/queries/dml/sharded_schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,13 @@ create table lkp_mixed_idx
keyspace_id varbinary(20),
primary key (lkp_key)
) Engine = InnoDB;

create table last_insert_id_test
(
id bigint NOT NULL AUTO_INCREMENT,
user_id bigint,
reason varchar(20),
sharding_key varchar(20),
primary key (id),
unique (user_id, sharding_key)
)
12 changes: 11 additions & 1 deletion go/test/endtoend/vtgate/queries/dml/unsharded_schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,19 @@ create table u_tbl
primary key (id)
) Engine = InnoDB;

create table last_insert_id_test_seq
(
id int default 0,
next_id bigint default null,
cache bigint default null,
primary key (id)
) comment 'vitess_sequence' Engine = InnoDB;

insert into user_seq(id, next_id, cache)
values (0, 1, 1000);
insert into auto_seq(id, next_id, cache)
values (0, 666, 1000);
insert into mixed_seq(id, next_id, cache)
values (0, 1, 1000);
values (0, 1, 1000);
insert into last_insert_id_test_seq(id, next_id, cache)
values (0, 1, 1000);
17 changes: 16 additions & 1 deletion go/test/endtoend/vtgate/queries/dml/vschema.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
"hash": {
"type": "hash"
},
"xxhash": {
"type": "xxhash"
},
"num_vdx": {
"type": "consistent_lookup_unique",
"params": {
Expand Down Expand Up @@ -188,6 +191,18 @@
"name": "hash"
}
]
},
"last_insert_id_test": {
"auto_increment": {
"column": "id",
"sequence": "uks.last_insert_id_test_seq"
},
"column_vindexes": [
{
"column": "sharding_key",
"name": "xxhash"
}
]
}
}
}
}
Loading