Skip to content

Commit 3337405

Browse files
authored
expression, parser: add built-in func is_uuid (#30318)
1 parent bc08b50 commit 3337405

File tree

9 files changed

+118
-4
lines changed

9 files changed

+118
-4
lines changed

executor/show_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1394,7 +1394,7 @@ func (s *testSuite5) TestShowBuiltin(c *C) {
13941394
res := tk.MustQuery("show builtins;")
13951395
c.Assert(res, NotNil)
13961396
rows := res.Rows()
1397-
const builtinFuncNum = 273
1397+
const builtinFuncNum = 274
13981398
c.Assert(builtinFuncNum, Equals, len(rows))
13991399
c.Assert("abs", Equals, rows[0][0].(string))
14001400
c.Assert("yearweek", Equals, rows[builtinFuncNum-1][0].(string))

expression/builtin.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,7 @@ var funcs = map[string]functionClass{
772772
ast.IsIPv4Mapped: &isIPv4MappedFunctionClass{baseFunctionClass{ast.IsIPv4Mapped, 1, 1}},
773773
ast.IsIPv6: &isIPv6FunctionClass{baseFunctionClass{ast.IsIPv6, 1, 1}},
774774
ast.IsUsedLock: &isUsedLockFunctionClass{baseFunctionClass{ast.IsUsedLock, 1, 1}},
775+
ast.IsUUID: &isUUIDFunctionClass{baseFunctionClass{ast.IsUUID, 1, 1}},
775776
ast.MasterPosWait: &masterPosWaitFunctionClass{baseFunctionClass{ast.MasterPosWait, 2, 4}},
776777
ast.NameConst: &nameConstFunctionClass{baseFunctionClass{ast.NameConst, 2, 2}},
777778
ast.ReleaseAllLocks: &releaseAllLocksFunctionClass{baseFunctionClass{ast.ReleaseAllLocks, 0, 0}},

expression/builtin_miscellaneous.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ var (
5757
_ functionClass = &vitessHashFunctionClass{}
5858
_ functionClass = &uuidToBinFunctionClass{}
5959
_ functionClass = &binToUUIDFunctionClass{}
60+
_ functionClass = &isUUIDFunctionClass{}
6061
)
6162

6263
var (
@@ -78,6 +79,7 @@ var (
7879
_ builtinFunc = &builtinIsIPv4CompatSig{}
7980
_ builtinFunc = &builtinIsIPv4MappedSig{}
8081
_ builtinFunc = &builtinIsIPv6Sig{}
82+
_ builtinFunc = &builtinIsUUIDSig{}
8183
_ builtinFunc = &builtinUUIDSig{}
8284
_ builtinFunc = &builtinVitessHashSig{}
8385
_ builtinFunc = &builtinUUIDToBinSig{}
@@ -862,6 +864,47 @@ func (c *isUsedLockFunctionClass) getFunction(ctx sessionctx.Context, args []Exp
862864
return nil, errFunctionNotExists.GenWithStackByArgs("FUNCTION", "IS_USED_LOCK")
863865
}
864866

867+
type isUUIDFunctionClass struct {
868+
baseFunctionClass
869+
}
870+
871+
func (c *isUUIDFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
872+
if err := c.verifyArgs(args); err != nil {
873+
return nil, err
874+
}
875+
bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETInt, types.ETString)
876+
if err != nil {
877+
return nil, err
878+
}
879+
bf.tp.Flen = 1
880+
sig := &builtinIsUUIDSig{bf}
881+
sig.setPbCode(tipb.ScalarFuncSig_IsUUID)
882+
return sig, nil
883+
}
884+
885+
type builtinIsUUIDSig struct {
886+
baseBuiltinFunc
887+
}
888+
889+
func (b *builtinIsUUIDSig) Clone() builtinFunc {
890+
newSig := &builtinIsUUIDSig{}
891+
newSig.cloneFrom(&b.baseBuiltinFunc)
892+
return newSig
893+
}
894+
895+
// evalInt evals a builtinIsUUIDSig.
896+
// See https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_is-uuid
897+
func (b *builtinIsUUIDSig) evalInt(row chunk.Row) (int64, bool, error) {
898+
val, isNull, err := b.args[0].EvalString(b.ctx, row)
899+
if err != nil || isNull {
900+
return 0, isNull, err
901+
}
902+
if _, err = uuid.Parse(val); err != nil {
903+
return 0, false, nil
904+
}
905+
return 1, false, nil
906+
}
907+
865908
type masterPosWaitFunctionClass struct {
866909
baseFunctionClass
867910
}

expression/builtin_miscellaneous_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,42 @@ func TestIsIPv4(t *testing.T) {
9797
trequire.DatumEqual(t, types.NewDatum(0), r)
9898
}
9999

100+
func TestIsUUID(t *testing.T) {
101+
t.Parallel()
102+
ctx := createContext(t)
103+
tests := []struct {
104+
uuid string
105+
expect interface{}
106+
}{
107+
{"6ccd780c-baba-1026-9564-5b8c656024db", 1},
108+
{"6CCD780C-BABA-1026-9564-5B8C656024DB", 1},
109+
{"6ccd780cbaba102695645b8c656024db", 1},
110+
{"{6ccd780c-baba-1026-9564-5b8c656024db}", 1},
111+
{"6ccd780c-baba-1026-9564-5b8c6560", 0},
112+
{"6CCD780C-BABA-1026-9564-5B8C656024DQ", 0},
113+
// This is a bug in google/uuid#60
114+
{"{99a9ad03-5298-11ec-8f5c-00ff90147ac3*", 1},
115+
// This is a format google/uuid support, while mysql doesn't
116+
{"urn:uuid:99a9ad03-5298-11ec-8f5c-00ff90147ac3", 1},
117+
}
118+
119+
fc := funcs[ast.IsUUID]
120+
for _, test := range tests {
121+
uuid := types.NewStringDatum(test.uuid)
122+
f, err := fc.getFunction(ctx, datumsToConstants([]types.Datum{uuid}))
123+
require.NoError(t, err)
124+
result, err := evalBuiltinFunc(f, chunk.Row{})
125+
require.NoError(t, err)
126+
trequire.DatumEqual(t, types.NewDatum(test.expect), result)
127+
}
128+
129+
var argNull types.Datum
130+
f, _ := fc.getFunction(ctx, datumsToConstants([]types.Datum{argNull}))
131+
r, err := evalBuiltinFunc(f, chunk.Row{})
132+
require.NoError(t, err)
133+
require.True(t, r.IsNull())
134+
}
135+
100136
func TestUUID(t *testing.T) {
101137
t.Parallel()
102138
ctx := createContext(t)

expression/builtin_miscellaneous_vec.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,36 @@ func (b *builtinIsIPv6Sig) vecEvalInt(input *chunk.Chunk, result *chunk.Column)
154154
return nil
155155
}
156156

157+
func (b *builtinIsUUIDSig) vectorized() bool {
158+
return true
159+
}
160+
161+
func (b *builtinIsUUIDSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {
162+
n := input.NumRows()
163+
buf, err := b.bufAllocator.get()
164+
if err != nil {
165+
return err
166+
}
167+
defer b.bufAllocator.put(buf)
168+
if err := b.args[0].VecEvalString(b.ctx, input, buf); err != nil {
169+
return err
170+
}
171+
result.ResizeInt64(n, false)
172+
i64s := result.Int64s()
173+
result.MergeNulls(buf)
174+
for i := 0; i < n; i++ {
175+
if result.IsNull(i) {
176+
continue
177+
}
178+
if _, err = uuid.Parse(buf.GetString(i)); err != nil {
179+
i64s[i] = 0
180+
} else {
181+
i64s[i] = 1
182+
}
183+
}
184+
return nil
185+
}
186+
157187
func (b *builtinNameConstStringSig) vectorized() bool {
158188
return true
159189
}

expression/builtin_miscellaneous_vec_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ var vecBuiltinMiscellaneousCases = map[string][]vecExprBenchCase{
108108
{retEvalType: types.ETString, childrenTypes: []types.EvalType{types.ETString}, geners: []dataGenerator{&uuidBinGener{newDefaultRandGen()}}},
109109
{retEvalType: types.ETString, childrenTypes: []types.EvalType{types.ETString, types.ETInt}, geners: []dataGenerator{&uuidBinGener{newDefaultRandGen()}}},
110110
},
111+
ast.IsUUID: {
112+
{retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETString}, geners: []dataGenerator{&uuidStrGener{newDefaultRandGen()}}},
113+
},
111114
}
112115

113116
func TestVectorizedBuiltinMiscellaneousEvalOneVec(t *testing.T) {

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ require (
5353
github.com/pingcap/sysutil v0.0.0-20210730114356-fcd8a63f68c5
5454
github.com/pingcap/tidb-tools v5.2.2-0.20211019062242-37a8bef2fa17+incompatible
5555
github.com/pingcap/tidb/parser v0.0.0-20211011031125-9b13dc409c5e
56-
github.com/pingcap/tipb v0.0.0-20211116093845-e9b045a0bdf8
56+
github.com/pingcap/tipb v0.0.0-20211201080053-bd104bb270ba
5757
github.com/prometheus/client_golang v1.5.1
5858
github.com/prometheus/client_model v0.2.0
5959
github.com/prometheus/common v0.9.1

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -597,8 +597,8 @@ github.com/pingcap/tidb-dashboard v0.0.0-20211008050453-a25c25809529/go.mod h1:O
597597
github.com/pingcap/tidb-dashboard v0.0.0-20211107164327-80363dfbe884/go.mod h1:OCXbZTBTIMRcIt0jFsuCakZP+goYRv6IjawKbwLS2TQ=
598598
github.com/pingcap/tidb-tools v5.2.2-0.20211019062242-37a8bef2fa17+incompatible h1:c7+izmker91NkjkZ6FgTlmD4k1A5FLOAq+li6Ki2/GY=
599599
github.com/pingcap/tidb-tools v5.2.2-0.20211019062242-37a8bef2fa17+incompatible/go.mod h1:XGdcy9+yqlDSEMTpOXnwf3hiTeqrV6MN/u1se9N8yIM=
600-
github.com/pingcap/tipb v0.0.0-20211116093845-e9b045a0bdf8 h1:Vu/6oq8EFNWgyXRHiclNzTKIu+YKHPCSI/Ba5oVrLtM=
601-
github.com/pingcap/tipb v0.0.0-20211116093845-e9b045a0bdf8/go.mod h1:A7mrd7WHBl1o63LE2bIBGEJMTNWXqhgmYiOvMLxozfs=
600+
github.com/pingcap/tipb v0.0.0-20211201080053-bd104bb270ba h1:Tt5W/maVBUbG+wxg2nfc88Cqj/HiWYb0TJQ2Rfi0UOQ=
601+
github.com/pingcap/tipb v0.0.0-20211201080053-bd104bb270ba/go.mod h1:A7mrd7WHBl1o63LE2bIBGEJMTNWXqhgmYiOvMLxozfs=
602602
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
603603
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
604604
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

parser/ast/functions.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ const (
279279
IsIPv4Mapped = "is_ipv4_mapped"
280280
IsIPv6 = "is_ipv6"
281281
IsUsedLock = "is_used_lock"
282+
IsUUID = "is_uuid"
282283
MasterPosWait = "master_pos_wait"
283284
NameConst = "name_const"
284285
ReleaseAllLocks = "release_all_locks"

0 commit comments

Comments
 (0)