[FLINK-40489][table] Add UUID_V4() and UUID_V7() functions - #29154
[FLINK-40489][table] Add UUID_V4() and UUID_V7() functions#29154manner wants to merge 2 commits into
Conversation
| /** Returns a random RFC 9562 version 4 (pseudo randomly generated) {@code UUID} value. */ | ||
| public static ApiExpression uuidV4() { | ||
| return apiCall(BuiltInFunctionDefinitions.UUID_V4); | ||
| } | ||
|
|
||
| /** | ||
| * Returns a time-ordered RFC 9562 version 7 {@code UUID} value, generated from the current | ||
| * timestamp and a random component. | ||
| */ | ||
| public static ApiExpression uuidV7() { | ||
| return apiCall(BuiltInFunctionDefinitions.UUID_V7); | ||
| } | ||
|
|
There was a problem hiding this comment.
Please consider adding the functions into the expression.py too
There was a problem hiding this comment.
Does that work even though there's no UUID type specified in pyflink/table/types.py?
There was a problem hiding this comment.
there are tests in flink-python failing ci without this btw ;)
| public static byte[] generateV4() { | ||
| final byte[] bytes = new byte[UuidType.BYTE_LENGTH]; | ||
| Holder.SECURE_RANDOM.nextBytes(bytes); | ||
|
|
||
| // set the version to 4 | ||
| bytes[6] &= 0x0F; | ||
| bytes[6] |= 0x40; | ||
|
|
||
| // set the variant to IETF | ||
| bytes[8] &= 0x3F; | ||
| bytes[8] |= (byte) 0x80; | ||
|
|
||
| return bytes; | ||
| } | ||
|
|
There was a problem hiding this comment.
The randomUUID method of java.util.UUID does the same:
/**
* Static factory to retrieve a type 4 (pseudo randomly generated) UUID.
*
* The {@code UUID} is generated using a cryptographically strong pseudo
* random number generator.
*
* @return A randomly generated {@code UUID}
*/
public static UUID randomUUID() {
SecureRandom ng = Holder.numberGenerator;
byte[] randomBytes = new byte[16];
ng.nextBytes(randomBytes);
randomBytes[6] &= 0x0f; /* clear version */
randomBytes[6] |= 0x40; /* set to version 4 */
randomBytes[8] &= 0x3f; /* clear variant */
randomBytes[8] |= (byte) 0x80; /* set to IETF variant */
return new UUID(randomBytes);
}There was a problem hiding this comment.
That's right. But randomUUID() builds a UUID from the random bytes, and we'd then have to extract the bytes right back out of it. Generating them directly avoids that copying and the object instantiation.
However, I'm not sure if it's worth it in this case, happy to switch to randomUUID() if you'd rather keep it simple.
There was a problem hiding this comment.
i think it's better to reuse as jdk might apply optimization with version bump which we will get for free in this case
| /** | ||
| * Holder for the {@link SecureRandom} instance, so that seeding it is deferred until a {@code | ||
| * UUID} is actually generated for the first time. | ||
| */ | ||
| private static final class Holder { | ||
| static final SecureRandom SECURE_RANDOM = new SecureRandom(); | ||
| } |
There was a problem hiding this comment.
Why a class and not just a field?
| /** | |
| * Holder for the {@link SecureRandom} instance, so that seeding it is deferred until a {@code | |
| * UUID} is actually generated for the first time. | |
| */ | |
| private static final class Holder { | |
| static final SecureRandom SECURE_RANDOM = new SecureRandom(); | |
| } | |
| /** | |
| * Holder for the {@link SecureRandom} instance, so that seeding it is deferred until a {@code | |
| * UUID} is actually generated for the first time. | |
| */ | |
| private static final SecureRandom SECURE_RANDOM = new SecureRandom(); |
There was a problem hiding this comment.
The idea was to keep the SecureRandom lazily instantiated, so it's only created when actually used (similar to java.util.UUID). But since both/all methods in the class use the RNG, the class is never loaded without needing it, so the holder doesn't help at all.
What is the purpose of the change
This pull request adds two new built-in SQL scalar functions,
UUID_V4()andUUID_V7(), generating RFC 9562 UUID values — a random version 4 UUID and a time-ordered version 7 UUID.Brief change log
BuiltInFunctionDefinitions.UUID_V4/UUID_V7UuidGenerationUtilswithgenerateV4()/generateV7(), producing the 16-byte internal representation of aUUIDvalue directly (no round-trip throughjava.util.UUID)UuidV4Function/UuidV7Functionruntime classesuuidV4()/uuidV7()to the Java and Scala Table API expression DSLsql_functions.yml(English and Chinese)Verifying this change
This change added tests and can be verified as follows:
UuidGenerationUtilsTest, directly asserting on the generated bytes: correct length, version nibble, variant bits, and (for v7) that the embedded timestamp matchesSystem.currentTimeMillis()at call timeUuidFunctionsITCase, covering the SQL and Table API return type (UUID) and the version nibble in the canonical string form, executed end-to-end against a MiniClusterDoes this pull request potentially affect one of the following parts:
@Public(Evolving): yes —Expressions.java(@PublicEvolving) gains two new additive methods,uuidV4()anduuidV7()UUID_V4()/UUID_V7()Documentation
sql_functions.yml) and JavaDocsWas generative AI tooling used to co-author this PR?
Generated-by: Claude Code (Sonnet 5)