From bedae51b625f67141dcedfaf5bc95d6cf994bde7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20Eeden?= Date: Tue, 6 Jan 2026 20:53:17 +0100 Subject: [PATCH] expression: Vectorized versions of new UUID functions (#65301) ref pingcap/tidb#61982 --- DEPS.bzl | 12 +- go.mod | 4 +- go.sum | 4 +- pkg/expression/builtin_miscellaneous.go | 8 +- pkg/expression/builtin_miscellaneous_test.go | 112 ++++++++++++++--- pkg/expression/builtin_miscellaneous_vec.go | 117 ++++++++++++++++++ .../builtin_miscellaneous_vec_test.go | 10 +- pkg/expression/util_test.go | 2 +- .../integrationtest/r/expression/uuid.result | 67 ++++++++++ tests/integrationtest/t/expression/uuid.test | 54 ++++++++ 10 files changed, 353 insertions(+), 37 deletions(-) diff --git a/DEPS.bzl b/DEPS.bzl index 16bf7bfb54..71ebd8f492 100644 --- a/DEPS.bzl +++ b/DEPS.bzl @@ -3830,13 +3830,13 @@ def go_deps(): name = "com_github_google_uuid", build_file_proto_mode = "disable_global", importpath = "github.com/google/uuid", - sha256 = "d0f02f377217f42702e259684e06441edbf5140dddcc34ba9bea56038b38a6ed", - strip_prefix = "github.com/google/uuid@v1.6.0", + sha256 = "d955c9e160041902f710b737f6ebd3ac562541c56821c299327f57abff831b10", + strip_prefix = "github.com/google/uuid@v1.6.1-0.20241114170450-2d3c2a9cc518", urls = [ - "http://bazel-cache.pingcap.net:8080/gomod/github.com/google/uuid/com_github_google_uuid-v1.6.0.zip", - "http://ats.apps.svc/gomod/github.com/google/uuid/com_github_google_uuid-v1.6.0.zip", - "https://cache.hawkingrei.com/gomod/github.com/google/uuid/com_github_google_uuid-v1.6.0.zip", - "https://storage.googleapis.com/pingcapmirror/gomod/github.com/google/uuid/com_github_google_uuid-v1.6.0.zip", + "http://bazel-cache.pingcap.net:8080/gomod/github.com/google/uuid/com_github_google_uuid-v1.6.1-0.20241114170450-2d3c2a9cc518.zip", + "http://ats.apps.svc/gomod/github.com/google/uuid/com_github_google_uuid-v1.6.1-0.20241114170450-2d3c2a9cc518.zip", + "https://cache.hawkingrei.com/gomod/github.com/google/uuid/com_github_google_uuid-v1.6.1-0.20241114170450-2d3c2a9cc518.zip", + "https://storage.googleapis.com/pingcapmirror/gomod/github.com/google/uuid/com_github_google_uuid-v1.6.1-0.20241114170450-2d3c2a9cc518.zip", ], ) go_repository( diff --git a/go.mod b/go.mod index 84121f6bf8..6ebad2c527 100644 --- a/go.mod +++ b/go.mod @@ -67,7 +67,7 @@ require ( github.com/google/btree v1.1.2 github.com/google/pprof v0.0.0-20250903194437-c28834ac2320 github.com/google/skylark v0.0.0-20181101142754-a5f7082aabed - github.com/google/uuid v1.6.0 + github.com/google/uuid v1.6.1-0.20241114170450-2d3c2a9cc518 github.com/gordonklaus/ineffassign v0.1.0 github.com/gorilla/mux v1.8.1 github.com/gostaticanalysis/forcetypeassert v0.2.0 @@ -354,7 +354,7 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20250425173222-7b384671a197 // indirect google.golang.org/protobuf v1.36.10 gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apimachinery v0.29.11 // indirect k8s.io/klog/v2 v2.120.1 // indirect diff --git a/go.sum b/go.sum index 9d3a366cd8..70879c630b 100644 --- a/go.sum +++ b/go.sum @@ -481,8 +481,8 @@ github.com/google/skylark v0.0.0-20181101142754-a5f7082aabed h1:rZdD1GeRTHD1aG+V github.com/google/skylark v0.0.0-20181101142754-a5f7082aabed/go.mod h1:CKSX6SxHW1vp20ZNaeGe3TFFBIwCG6vaYrpAiOzX+NA= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.1-0.20241114170450-2d3c2a9cc518 h1:UBg1xk+oAsIVbFuGg6hdfAm7EvCv3EL80vFxJNsslqw= +github.com/google/uuid v1.6.1-0.20241114170450-2d3c2a9cc518/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= diff --git a/pkg/expression/builtin_miscellaneous.go b/pkg/expression/builtin_miscellaneous.go index def439f441..35e6fda660 100644 --- a/pkg/expression/builtin_miscellaneous.go +++ b/pkg/expression/builtin_miscellaneous.go @@ -1656,7 +1656,7 @@ func (b *builtinUUIDVersionSig) evalInt(ctx EvalContext, row chunk.Row) (int64, } u, err := uuid.Parse(val) if err != nil { - return 0, isNull, err + return 0, isNull, errWrongValueForType.GenWithStackByArgs("string", val, "uuid_version") } return int64(u.Version()), false, nil } @@ -1702,13 +1702,11 @@ func (b *builtinUUIDTimestampSig) evalDecimal(ctx EvalContext, row chunk.Row) (* } u, err := uuid.Parse(val) if err != nil { - return new(types.MyDecimal), isNull, err + return new(types.MyDecimal), isNull, errWrongValueForType.GenWithStackByArgs("string", val, "uuid_timestamp") } switch u.Version() { - case 1: - case 6: - case 7: + case 1, 6, 7: default: // No timestamp, return NULL return new(types.MyDecimal), true, nil diff --git a/pkg/expression/builtin_miscellaneous_test.go b/pkg/expression/builtin_miscellaneous_test.go index 59a8abb184..27b4f6e645 100644 --- a/pkg/expression/builtin_miscellaneous_test.go +++ b/pkg/expression/builtin_miscellaneous_test.go @@ -15,11 +15,13 @@ package expression import ( + "fmt" "math" "strings" "testing" "time" + "github.com/google/uuid" "github.com/pingcap/tidb/pkg/parser/ast" "github.com/pingcap/tidb/pkg/parser/mysql" "github.com/pingcap/tidb/pkg/parser/terror" @@ -140,29 +142,99 @@ func TestIsUUID(t *testing.T) { } func TestUUID(t *testing.T) { + uuidGenFuncs := []struct { + funcName string + expectVersion uuid.Version + }{ + {ast.UUID, uuid.Version(1)}, + {ast.UUIDv4, uuid.Version(4)}, + {ast.UUIDv7, uuid.Version(7)}, + } + for _, tf := range uuidGenFuncs { + t.Run(tf.funcName, func(t *testing.T) { + ctx := createContext(t) + f, err := newFunctionForTest(ctx, tf.funcName) + require.NoError(t, err) + d, err := f.Eval(ctx, chunk.Row{}) + require.NoError(t, err) + u, err := uuid.Parse(d.GetString()) + require.NoError(t, err) + require.Equal(t, tf.expectVersion, u.Version(), "Must generate a UUIDv%d", u.Version()) + parts := strings.Split(d.GetString(), "-") + require.Equal(t, 5, len(parts)) + for i, p := range parts { + switch i { + case 0: + require.Equal(t, 8, len(p)) + case 1: + require.Equal(t, 4, len(p)) + case 2: + require.Equal(t, 4, len(p)) + case 3: + require.Equal(t, 4, len(p)) + case 4: + require.Equal(t, 12, len(p)) + } + } + _, err = funcs[tf.funcName].getFunction(ctx, datumsToConstants(nil)) + require.NoError(t, err) + }) + } +} + +func TestUUIDVersion(t *testing.T) { ctx := createContext(t) - f, err := newFunctionForTest(ctx, ast.UUID) - require.NoError(t, err) - d, err := f.Eval(ctx, chunk.Row{}) - require.NoError(t, err) - parts := strings.Split(d.GetString(), "-") - require.Equal(t, 5, len(parts)) - for i, p := range parts { - switch i { - case 0: - require.Equal(t, 8, len(p)) - case 1: - require.Equal(t, 4, len(p)) - case 2: - require.Equal(t, 4, len(p)) - case 3: - require.Equal(t, 4, len(p)) - case 4: - require.Equal(t, 12, len(p)) + tbl := []struct { + arg string + ret int + }{ + {"5f13f854-d74a-11f0-9b7a-0ae0156bd76b", 1}, + {"c6437ef1-5b86-3a4e-a071-c2d4ad414e65", 3}, + {"a3e3b4a1-ea6d-471e-9860-8303a8b261f6", 4}, + {"271a8175-dadd-5df9-b0bd-20a4a0b441e6", 5}, + {"1f0e48c1-7860-69cc-9b3f-35f89c103d4d", 6}, + {"019b1440-87b7-7380-ab00-ce413e795004", 7}, + } + for _, tt := range tbl { + fc := funcs[ast.UUIDVersion] + f, err := fc.getFunction(ctx, datumsToConstants(types.MakeDatums(tt.arg))) + require.NoError(t, err) + r, err := evalBuiltinFunc(f, ctx, chunk.Row{}) + require.NoError(t, err) + testutil.DatumEqual(t, types.NewDatum(tt.ret), r, + fmt.Sprintf("UUID_VERSION('%s') = %d (got %v)", tt.arg, tt.ret, r)) + } +} + +func TestUUIDTimestamp(t *testing.T) { + ctx := createContext(t) + tbl := []struct { + arg string + ret float64 + null bool + }{ + {"5f13f854-d74a-11f0-9b7a-0ae0156bd76b", 1765537487.118139, false}, // v1 + {"c6437ef1-5b86-3a4e-a071-c2d4ad414e65", 0, true}, // v3 + {"a3e3b4a1-ea6d-471e-9860-8303a8b261f6", 0, true}, // v4 + {"271a8175-dadd-5df9-b0bd-20a4a0b441e6", 0, true}, // v5 + {"1f0e48c1-7860-69cc-9b3f-35f89c103d4d", 1766995078.970004, false}, // v6 + {"019b1440-87b7-7380-ab00-ce413e795004", 1765571332.023000, false}, // v7 + {"00000000-0000-0000-0000-000000000000", 0, true}, // Nil UUID + {"ffffffff-ffff-ffff-ffff-ffffffffffff", 0, true}, // Max UUID + } + for _, tt := range tbl { + fc := funcs[ast.UUIDTimestamp] + f, err := fc.getFunction(ctx, datumsToConstants(types.MakeDatums(tt.arg))) + require.NoError(t, err) + r, err := evalBuiltinFunc(f, ctx, chunk.Row{}) + require.NoError(t, err) + if tt.null { + require.True(t, r.IsNull()) + } else { + testutil.DatumEqual(t, types.NewDatum(types.NewDecFromFloatForTest(tt.ret)), r, + fmt.Sprintf("UUID_TIMESTAMP('%s') = %v (got %v)", tt.arg, tt.ret, r)) } } - _, err = funcs[ast.UUID].getFunction(ctx, datumsToConstants(nil)) - require.NoError(t, err) } func TestAnyValue(t *testing.T) { diff --git a/pkg/expression/builtin_miscellaneous_vec.go b/pkg/expression/builtin_miscellaneous_vec.go index bb3b9abfbb..1c1c584049 100644 --- a/pkg/expression/builtin_miscellaneous_vec.go +++ b/pkg/expression/builtin_miscellaneous_vec.go @@ -25,6 +25,7 @@ import ( "github.com/google/uuid" "github.com/pingcap/tidb/pkg/sessionctx/variable" + "github.com/pingcap/tidb/pkg/types" "github.com/pingcap/tidb/pkg/util/chunk" "github.com/pingcap/tidb/pkg/util/vitess" ) @@ -219,6 +220,122 @@ func (b *builtinUUIDSig) vecEvalString(ctx EvalContext, input *chunk.Chunk, resu return nil } +func (b *builtinUUIDv4Sig) vectorized() bool { + return true +} + +func (b *builtinUUIDv4Sig) vecEvalString(ctx EvalContext, input *chunk.Chunk, result *chunk.Column) error { + n := input.NumRows() + result.ReserveString(n) + var id uuid.UUID + var err error + for range n { + id, err = uuid.NewRandom() + if err != nil { + return err + } + result.AppendString(id.String()) + } + return nil +} + +func (b *builtinUUIDv7Sig) vectorized() bool { + return true +} + +func (b *builtinUUIDv7Sig) vecEvalString(ctx EvalContext, input *chunk.Chunk, result *chunk.Column) error { + n := input.NumRows() + result.ReserveString(n) + var id uuid.UUID + var err error + for range n { + id, err = uuid.NewV7() + if err != nil { + return err + } + result.AppendString(id.String()) + } + return nil +} + +func (b *builtinUUIDVersionSig) vectorized() bool { + return true +} + +func (b *builtinUUIDVersionSig) vecEvalInt(ctx EvalContext, input *chunk.Chunk, result *chunk.Column) error { + n := input.NumRows() + buf, err := b.bufAllocator.get() + if err != nil { + return err + } + defer b.bufAllocator.put(buf) + if err := b.args[0].VecEvalString(ctx, input, buf); err != nil { + return err + } + result.ResizeInt64(n, false) + i64s := result.Int64s() + result.MergeNulls(buf) + for i := range n { + if result.IsNull(i) { + continue + } + val := buf.GetString(i) + u, err := uuid.Parse(val) + if err != nil { + return errWrongValueForType.GenWithStackByArgs("string", val, "uuid_version") + } + i64s[i] = int64(u.Version()) + } + return nil +} + +func (b *builtinUUIDTimestampSig) vectorized() bool { + return true +} + +func (b *builtinUUIDTimestampSig) vecEvalDecimal(ctx EvalContext, input *chunk.Chunk, result *chunk.Column) error { + n := input.NumRows() + buf, err := b.bufAllocator.get() + if err != nil { + return err + } + defer b.bufAllocator.put(buf) + if err := b.args[0].VecEvalString(ctx, input, buf); err != nil { + return err + } + result.ResizeDecimal(n, false) + result.MergeNulls(buf) + d := result.Decimals() + for i := range n { + if result.IsNull(i) { + continue + } + val := buf.GetString(i) + u, err := uuid.Parse(val) + if err != nil { + return errWrongValueForType.GenWithStackByArgs("string", val, "uuid_timestamp") + } + switch u.Version() { + case 1, 6, 7: + default: + result.SetNull(i, true) + continue + } + + s, ns := u.Time().UnixTime() + d[i].FromInt((s * 1000000) + (ns / 1000)) + err = d[i].Shift(-6) + if err != nil { + return err + } + err = d[i].Round(&d[i], 6, types.ModeHalfUp) + if err != nil { + return err + } + } + return nil +} + func (b *builtinNameConstDurationSig) vectorized() bool { return true } diff --git a/pkg/expression/builtin_miscellaneous_vec_test.go b/pkg/expression/builtin_miscellaneous_vec_test.go index 6d205b63f3..c0de6a3e1a 100644 --- a/pkg/expression/builtin_miscellaneous_vec_test.go +++ b/pkg/expression/builtin_miscellaneous_vec_test.go @@ -39,7 +39,15 @@ var vecBuiltinMiscellaneousCases = map[string][]vecExprBenchCase{ newSelectRealGener([]float64{0, 0.000001}), }}, }, - ast.UUID: {}, + ast.UUID: {}, + ast.UUIDv4: {}, + ast.UUIDv7: {}, + ast.UUIDTimestamp: { + {retEvalType: types.ETDecimal, childrenTypes: []types.EvalType{types.ETString}, geners: []dataGenerator{&uuidStrGener{newDefaultRandGen()}}}, + }, + ast.UUIDVersion: { + {retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETString}, geners: []dataGenerator{&uuidStrGener{newDefaultRandGen()}}}, + }, ast.Inet6Ntoa: { {retEvalType: types.ETString, childrenTypes: []types.EvalType{types.ETString}, geners: []dataGenerator{ newSelectStringGener( diff --git a/pkg/expression/util_test.go b/pkg/expression/util_test.go index bad584b63c..eef2b2318f 100644 --- a/pkg/expression/util_test.go +++ b/pkg/expression/util_test.go @@ -144,7 +144,7 @@ func TestClone(t *testing.T) { &builtinToSecondsSig{}, &builtinUTCTimeWithArgSig{}, &builtinUTCTimeWithoutArgSig{}, &builtinTimestamp1ArgSig{}, &builtinTimestamp2ArgsSig{}, &builtinTimestampLiteralSig{}, &builtinLastDaySig{}, &builtinStrToDateDateSig{}, &builtinStrToDateDatetimeSig{}, &builtinStrToDateDurationSig{}, &builtinFromUnixTime1ArgSig{}, &builtinFromUnixTime2ArgSig{}, &builtinExtractDatetimeFromStringSig{}, &builtinExtractDatetimeSig{}, &builtinExtractDurationSig{}, &builtinAddSubDateAsStringSig{}, - &builtinAddSubDateDatetimeAnySig{}, &builtinAddSubDateDurationAnySig{}, + &builtinAddSubDateDatetimeAnySig{}, &builtinAddSubDateDurationAnySig{}, &builtinUUIDv4Sig{}, &builtinUUIDv7Sig{}, &builtinUUIDVersionSig{}, &builtinUUIDTimestampSig{}, } for _, f := range builtinFuncs { cf := f.Clone() diff --git a/tests/integrationtest/r/expression/uuid.result b/tests/integrationtest/r/expression/uuid.result index 013965c315..a331c59ba0 100644 --- a/tests/integrationtest/r/expression/uuid.result +++ b/tests/integrationtest/r/expression/uuid.result @@ -28,6 +28,48 @@ NULL SELECT UUID_TIMESTAMP('019b1440-87b7-7380-ab00-ce413e795004'); UUID_TIMESTAMP('019b1440-87b7-7380-ab00-ce413e795004') 1765571332.023000 +SELECT UUID_VERSION('00000000-0000-0000-0000-000000000000'); +UUID_VERSION('00000000-0000-0000-0000-000000000000') +0 +SELECT UUID_VERSION('ffffffff-ffff-ffff-ffff-ffffffffffff'); +UUID_VERSION('ffffffff-ffff-ffff-ffff-ffffffffffff') +15 +SELECT UUID_TIMESTAMP('00000000-0000-0000-0000-000000000000'); +UUID_TIMESTAMP('00000000-0000-0000-0000-000000000000') +NULL +SELECT UUID_TIMESTAMP('ffffffff-ffff-ffff-ffff-ffffffffffff'); +UUID_TIMESTAMP('ffffffff-ffff-ffff-ffff-ffffffffffff') +NULL +SELECT UUID_VERSION('abc'); +Error 1411 (HY000): Incorrect string value: 'abc' for function uuid_version +SELECT UUID_TIMESTAMP('abc'); +Error 1411 (HY000): Incorrect string value: 'abc' for function uuid_timestamp +SELECT UUID_TO_BIN('abc'); +Error 1411 (HY000): Incorrect string value: 'abc' for function uuid_to_bin +SELECT UUID_VERSION('5f13f854-d74a-11f0-9b7a-0ae0156bd76z'); +Error 1411 (HY000): Incorrect string value: '5f13f854-d74a-11f0-9b7a-0ae0156bd76z' for function uuid_version +SELECT UUID_TIMESTAMP('5f13f854-d74a-11f0-9b7a-0ae0156bd76z'); +Error 1411 (HY000): Incorrect string value: '5f13f854-d74a-11f0-9b7a-0ae0156bd76z' for function uuid_timestamp +SELECT HEX(UUID_TO_BIN('5f13f854-d74a-11f0-9b7a-0ae0156bd76z')); +Error 1411 (HY000): Incorrect string value: '5f13f854-d74a-11f0-9b7a-0ae0156bd76z' for function uuid_to_bin +SELECT UUID_VERSION('123e4567-e89b-02d3-a456-426614174000'); +UUID_VERSION('123e4567-e89b-02d3-a456-426614174000') +0 +SELECT UUID_TIMESTAMP('123e4567-e89b-02d3-a456-426614174000'); +UUID_TIMESTAMP('123e4567-e89b-02d3-a456-426614174000') +NULL +SELECT HEX(UUID_TO_BIN('123e4567-e89b-02d3-a456-426614174000')); +HEX(UUID_TO_BIN('123e4567-e89b-02d3-a456-426614174000')) +123E4567E89B02D3A456426614174000 +SELECT UUID_VERSION('123e4567-e89b-12d3-a456-426614174000'); +UUID_VERSION('123e4567-e89b-12d3-a456-426614174000') +1 +SELECT UUID_TIMESTAMP('123e4567-e89b-12d3-a456-426614174000'); +UUID_TIMESTAMP('123e4567-e89b-12d3-a456-426614174000') +8156923288.545008 +SELECT HEX(UUID_TO_BIN('123e4567-e89b-12d3-a456-426614174000')); +HEX(UUID_TO_BIN('123e4567-e89b-12d3-a456-426614174000')) +123E4567E89B12D3A456426614174000 SELECT UUID_SHORT(); Error 1305 (42000): FUNCTION UUID_SHORT does not exist CREATE TABLE t123 (id int PRIMARY KEY, uuid VARCHAR(255) AS (UUID())); @@ -45,3 +87,28 @@ CREATE TABLE t1234 (id int PRIMARY KEY, uuid BINARY(16) DEFAULT (UUID_TO_BIN(UUI CREATE TABLE t12345 (id int PRIMARY KEY, uuid BINARY(16) DEFAULT (UUID_TO_BIN(UUID_V4()))); CREATE TABLE t12346 (id int PRIMARY KEY, uuid BINARY(16) DEFAULT (UUID_TO_BIN(UUID_V7()))); DROP TABLE IF EXISTS t123, t1234, t12345, t12346; +CREATE TABLE u1 ( +uuid BINARY(16) PRIMARY KEY +); +INSERT INTO u1 VALUES +(UUID_TO_BIN("5f13f854-d74a-11f0-9b7a-0ae0156bd76b")), +(UUID_TO_BIN("c6437ef1-5b86-3a4e-a071-c2d4ad414e65")), +(UUID_TO_BIN("a3e3b4a1-ea6d-471e-9860-8303a8b261f6")), +(UUID_TO_BIN("271a8175-dadd-5df9-b0bd-20a4a0b441e6")), +(UUID_TO_BIN("1f0e48c1-7860-69cc-9b3f-35f89c103d4d")), +(UUID_TO_BIN("019b1440-87b7-7380-ab00-ce413e795004")); +SELECT +BIN_TO_UUID(uuid), +UUID_VERSION(BIN_TO_UUID(uuid)), +UUID_TIMESTAMP(BIN_TO_UUID(uuid)), +FROM_UNIXTIME(UUID_TIMESTAMP(BIN_TO_UUID(uuid))) +FROM u1 +ORDER BY uuid; +BIN_TO_UUID(uuid) UUID_VERSION(BIN_TO_UUID(uuid)) UUID_TIMESTAMP(BIN_TO_UUID(uuid)) FROM_UNIXTIME(UUID_TIMESTAMP(BIN_TO_UUID(uuid))) +019b1440-87b7-7380-ab00-ce413e795004 7 1765571332.023000 2025-12-13 04:28:52.023000 +1f0e48c1-7860-69cc-9b3f-35f89c103d4d 6 1766995078.970004 2025-12-29 15:57:58.970004 +271a8175-dadd-5df9-b0bd-20a4a0b441e6 5 NULL NULL +5f13f854-d74a-11f0-9b7a-0ae0156bd76b 1 1765537487.118139 2025-12-12 19:04:47.118139 +a3e3b4a1-ea6d-471e-9860-8303a8b261f6 4 NULL NULL +c6437ef1-5b86-3a4e-a071-c2d4ad414e65 3 NULL NULL +DROP TABLE u1; diff --git a/tests/integrationtest/t/expression/uuid.test b/tests/integrationtest/t/expression/uuid.test index fe30bd8e52..5fb580cd97 100644 --- a/tests/integrationtest/t/expression/uuid.test +++ b/tests/integrationtest/t/expression/uuid.test @@ -16,6 +16,38 @@ SELECT UUID_TIMESTAMP('a3e3b4a1-ea6d-471e-9860-8303a8b261f6'); # UUIDv7 SELECT UUID_TIMESTAMP('019b1440-87b7-7380-ab00-ce413e795004'); +# Null UUID and Max UUID +SELECT UUID_VERSION('00000000-0000-0000-0000-000000000000'); +SELECT UUID_VERSION('ffffffff-ffff-ffff-ffff-ffffffffffff'); +SELECT UUID_TIMESTAMP('00000000-0000-0000-0000-000000000000'); +SELECT UUID_TIMESTAMP('ffffffff-ffff-ffff-ffff-ffffffffffff'); + +# Invalid UUID: short +-- error 1411 +SELECT UUID_VERSION('abc'); +-- error 1411 +SELECT UUID_TIMESTAMP('abc'); +-- error 1411 +SELECT UUID_TO_BIN('abc'); + +# Invalid UUID: z is not hex +-- error 1411 +SELECT UUID_VERSION('5f13f854-d74a-11f0-9b7a-0ae0156bd76z'); +-- error 1411 +SELECT UUID_TIMESTAMP('5f13f854-d74a-11f0-9b7a-0ae0156bd76z'); +-- error 1411 +SELECT HEX(UUID_TO_BIN('5f13f854-d74a-11f0-9b7a-0ae0156bd76z')); + +# Invalid UUID: invalid version +SELECT UUID_VERSION('123e4567-e89b-02d3-a456-426614174000'); +SELECT UUID_TIMESTAMP('123e4567-e89b-02d3-a456-426614174000'); +SELECT HEX(UUID_TO_BIN('123e4567-e89b-02d3-a456-426614174000')); + +# Invalid UUID: invalid variant +SELECT UUID_VERSION('123e4567-e89b-12d3-a456-426614174000'); +SELECT UUID_TIMESTAMP('123e4567-e89b-12d3-a456-426614174000'); +SELECT HEX(UUID_TO_BIN('123e4567-e89b-12d3-a456-426614174000')); + -- error 1305 SELECT UUID_SHORT(); @@ -42,3 +74,25 @@ CREATE TABLE t12345 (id int PRIMARY KEY, uuid BINARY(16) DEFAULT (UUID_TO_BIN(UU CREATE TABLE t12346 (id int PRIMARY KEY, uuid BINARY(16) DEFAULT (UUID_TO_BIN(UUID_V7()))); DROP TABLE IF EXISTS t123, t1234, t12345, t12346; + +CREATE TABLE u1 ( + uuid BINARY(16) PRIMARY KEY +); + +INSERT INTO u1 VALUES + (UUID_TO_BIN("5f13f854-d74a-11f0-9b7a-0ae0156bd76b")), + (UUID_TO_BIN("c6437ef1-5b86-3a4e-a071-c2d4ad414e65")), + (UUID_TO_BIN("a3e3b4a1-ea6d-471e-9860-8303a8b261f6")), + (UUID_TO_BIN("271a8175-dadd-5df9-b0bd-20a4a0b441e6")), + (UUID_TO_BIN("1f0e48c1-7860-69cc-9b3f-35f89c103d4d")), + (UUID_TO_BIN("019b1440-87b7-7380-ab00-ce413e795004")); + +SELECT + BIN_TO_UUID(uuid), + UUID_VERSION(BIN_TO_UUID(uuid)), + UUID_TIMESTAMP(BIN_TO_UUID(uuid)), + FROM_UNIXTIME(UUID_TIMESTAMP(BIN_TO_UUID(uuid))) +FROM u1 +ORDER BY uuid; + +DROP TABLE u1;