Skip to content

Feature: last_insert_uuid() function#2362

Merged
fulghum merged 19 commits intomainfrom
fulghum/last_insert_uuid
Mar 6, 2024
Merged

Feature: last_insert_uuid() function#2362
fulghum merged 19 commits intomainfrom
fulghum/last_insert_uuid

Conversation

@fulghum
Copy link
Contributor

@fulghum fulghum commented Mar 1, 2024

UUIDs are often used in place of auto_increment IDs, but MySQL doesn't provide an easy way to get the last generated UUID that was used in an insert. This change introduces a new function, last_insert_uuid() that operates similarly to last_insert_id(). For a column identified as a UUID column, callers can use last_insert_uuid() to retrieve the last generated UUID value that was inserted into that column. In order to be considered a UUID column, a column must be part of the primary key and it must meet one of the following type signatures:

  • VARCHAR(36) or CHAR(36) with a default value expression of UUID()
  • VARBINARY(16) or BINARY(16) with a default value expression of UUID_to_bin(UUID()) (optionally, the swap_flag for UUID_to_bin may also be specified)

Example usage:

create table t (pk binary(16) primary key default (UUID_to_bin(UUID())), c1 varchar(100));
insert into t (c1) values ("one"), ("two");
select last_insert_uuid();
select c1 from t where pk = uuid_to_bin(last_insert_id());

Related to dolthub/dolt#7547

@fulghum fulghum requested a review from zachmu March 1, 2024 23:16
Copy link
Member

@zachmu zachmu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this needs a little work before it's ready to ship, see comments. I might be missing something obvious for why the row solution I proposed isn't workable.

@fulghum fulghum requested a review from max-hoffman March 6, 2024 00:48
Copy link
Contributor

@max-hoffman max-hoffman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly LGTM! Having the plan fixed before execution makes it easier to understand what's happening and why. You also covered a lot of cases I didn't think of, looks very generalizable. One issue I maybe see is the stateful expression behaving unpredictably on re-execution, which is probably an easy fix with sql.Dispose

// read this value too early. We should verify this isn't how MySQL behaves, and then could fix
// by setting a PENDING_LAST_INSERT_UUID value in the session query info, then moving it to
// LAST_INSERT_UUID in the session query info at the end of execution.
ctx.Session.SetLastQueryInfoString(sql.LastInsertUuid, uuidValue)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was expecting most of the state to be handled by the session. For example, if we have a prepared statement INSERT with an autoUuid node (probably common?), would only the first execution update the LastInsertUuid? We get away with stateful nodes and expressions (see Subquery) with the sql.Dispose interface, but that's probably also an anti pattern in the longterm

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh... great catch on the prepared statement case. Thank you! I'll test that and add in the sql.Dispose fix if I can't find another way to address it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added tests for prepared statements in 38b7c52. It looks like they didn't need the sql.Dispose implementation in order to execute correctly – I believe this is because we do a smaller re-analysis and must generate a new plan tree, so the value of foundUuid never leaks into other executions of the prepared statement.

I'm happy to add the sql.Dispose implementation if you think it'd still be safer though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok cool, the latest changes to prepareds might only saved the post-binding plan, resolveInsert is going to be after that step. Might become relevant in the future, but thanks for checking!

fulghum added 2 commits March 6, 2024 11:54
…ptures don't prevent capture in future execution
…atement returns different results through the server engine tests
@fulghum fulghum merged commit e42457f into main Mar 6, 2024
@fulghum fulghum deleted the fulghum/last_insert_uuid branch March 6, 2024 20:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants