Skip to content

Commit

Permalink
Add a test case verifying matching behaviour for the last_insert_id
Browse files Browse the repository at this point in the history
… behaviour when performing `INSERT ... ON DUPLICATE KEY UPDATE ...` statements.

Signed-off-by: Arthur Schreiber <arthurschreiber@github.com>
  • Loading branch information
arthurschreiber committed Apr 11, 2024
1 parent 0912690 commit 3ccff20
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 2 deletions.
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"
}
]
}
}
}
}

0 comments on commit 3ccff20

Please sign in to comment.