expression, parser: add built-in func is_uuid (#30318)
This commit is contained in:
@ -772,6 +772,7 @@ var funcs = map[string]functionClass{
|
||||
ast.IsIPv4Mapped: &isIPv4MappedFunctionClass{baseFunctionClass{ast.IsIPv4Mapped, 1, 1}},
|
||||
ast.IsIPv6: &isIPv6FunctionClass{baseFunctionClass{ast.IsIPv6, 1, 1}},
|
||||
ast.IsUsedLock: &isUsedLockFunctionClass{baseFunctionClass{ast.IsUsedLock, 1, 1}},
|
||||
ast.IsUUID: &isUUIDFunctionClass{baseFunctionClass{ast.IsUUID, 1, 1}},
|
||||
ast.MasterPosWait: &masterPosWaitFunctionClass{baseFunctionClass{ast.MasterPosWait, 2, 4}},
|
||||
ast.NameConst: &nameConstFunctionClass{baseFunctionClass{ast.NameConst, 2, 2}},
|
||||
ast.ReleaseAllLocks: &releaseAllLocksFunctionClass{baseFunctionClass{ast.ReleaseAllLocks, 0, 0}},
|
||||
|
||||
@ -57,6 +57,7 @@ var (
|
||||
_ functionClass = &vitessHashFunctionClass{}
|
||||
_ functionClass = &uuidToBinFunctionClass{}
|
||||
_ functionClass = &binToUUIDFunctionClass{}
|
||||
_ functionClass = &isUUIDFunctionClass{}
|
||||
)
|
||||
|
||||
var (
|
||||
@ -78,6 +79,7 @@ var (
|
||||
_ builtinFunc = &builtinIsIPv4CompatSig{}
|
||||
_ builtinFunc = &builtinIsIPv4MappedSig{}
|
||||
_ builtinFunc = &builtinIsIPv6Sig{}
|
||||
_ builtinFunc = &builtinIsUUIDSig{}
|
||||
_ builtinFunc = &builtinUUIDSig{}
|
||||
_ builtinFunc = &builtinVitessHashSig{}
|
||||
_ builtinFunc = &builtinUUIDToBinSig{}
|
||||
@ -862,6 +864,47 @@ func (c *isUsedLockFunctionClass) getFunction(ctx sessionctx.Context, args []Exp
|
||||
return nil, errFunctionNotExists.GenWithStackByArgs("FUNCTION", "IS_USED_LOCK")
|
||||
}
|
||||
|
||||
type isUUIDFunctionClass struct {
|
||||
baseFunctionClass
|
||||
}
|
||||
|
||||
func (c *isUUIDFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
|
||||
if err := c.verifyArgs(args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETInt, types.ETString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bf.tp.Flen = 1
|
||||
sig := &builtinIsUUIDSig{bf}
|
||||
sig.setPbCode(tipb.ScalarFuncSig_IsUUID)
|
||||
return sig, nil
|
||||
}
|
||||
|
||||
type builtinIsUUIDSig struct {
|
||||
baseBuiltinFunc
|
||||
}
|
||||
|
||||
func (b *builtinIsUUIDSig) Clone() builtinFunc {
|
||||
newSig := &builtinIsUUIDSig{}
|
||||
newSig.cloneFrom(&b.baseBuiltinFunc)
|
||||
return newSig
|
||||
}
|
||||
|
||||
// evalInt evals a builtinIsUUIDSig.
|
||||
// See https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_is-uuid
|
||||
func (b *builtinIsUUIDSig) evalInt(row chunk.Row) (int64, bool, error) {
|
||||
val, isNull, err := b.args[0].EvalString(b.ctx, row)
|
||||
if err != nil || isNull {
|
||||
return 0, isNull, err
|
||||
}
|
||||
if _, err = uuid.Parse(val); err != nil {
|
||||
return 0, false, nil
|
||||
}
|
||||
return 1, false, nil
|
||||
}
|
||||
|
||||
type masterPosWaitFunctionClass struct {
|
||||
baseFunctionClass
|
||||
}
|
||||
|
||||
@ -97,6 +97,42 @@ func TestIsIPv4(t *testing.T) {
|
||||
trequire.DatumEqual(t, types.NewDatum(0), r)
|
||||
}
|
||||
|
||||
func TestIsUUID(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := createContext(t)
|
||||
tests := []struct {
|
||||
uuid string
|
||||
expect interface{}
|
||||
}{
|
||||
{"6ccd780c-baba-1026-9564-5b8c656024db", 1},
|
||||
{"6CCD780C-BABA-1026-9564-5B8C656024DB", 1},
|
||||
{"6ccd780cbaba102695645b8c656024db", 1},
|
||||
{"{6ccd780c-baba-1026-9564-5b8c656024db}", 1},
|
||||
{"6ccd780c-baba-1026-9564-5b8c6560", 0},
|
||||
{"6CCD780C-BABA-1026-9564-5B8C656024DQ", 0},
|
||||
// This is a bug in google/uuid#60
|
||||
{"{99a9ad03-5298-11ec-8f5c-00ff90147ac3*", 1},
|
||||
// This is a format google/uuid support, while mysql doesn't
|
||||
{"urn:uuid:99a9ad03-5298-11ec-8f5c-00ff90147ac3", 1},
|
||||
}
|
||||
|
||||
fc := funcs[ast.IsUUID]
|
||||
for _, test := range tests {
|
||||
uuid := types.NewStringDatum(test.uuid)
|
||||
f, err := fc.getFunction(ctx, datumsToConstants([]types.Datum{uuid}))
|
||||
require.NoError(t, err)
|
||||
result, err := evalBuiltinFunc(f, chunk.Row{})
|
||||
require.NoError(t, err)
|
||||
trequire.DatumEqual(t, types.NewDatum(test.expect), result)
|
||||
}
|
||||
|
||||
var argNull types.Datum
|
||||
f, _ := fc.getFunction(ctx, datumsToConstants([]types.Datum{argNull}))
|
||||
r, err := evalBuiltinFunc(f, chunk.Row{})
|
||||
require.NoError(t, err)
|
||||
require.True(t, r.IsNull())
|
||||
}
|
||||
|
||||
func TestUUID(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := createContext(t)
|
||||
|
||||
@ -154,6 +154,36 @@ func (b *builtinIsIPv6Sig) vecEvalInt(input *chunk.Chunk, result *chunk.Column)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *builtinIsUUIDSig) vectorized() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (b *builtinIsUUIDSig) vecEvalInt(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(b.ctx, input, buf); err != nil {
|
||||
return err
|
||||
}
|
||||
result.ResizeInt64(n, false)
|
||||
i64s := result.Int64s()
|
||||
result.MergeNulls(buf)
|
||||
for i := 0; i < n; i++ {
|
||||
if result.IsNull(i) {
|
||||
continue
|
||||
}
|
||||
if _, err = uuid.Parse(buf.GetString(i)); err != nil {
|
||||
i64s[i] = 0
|
||||
} else {
|
||||
i64s[i] = 1
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *builtinNameConstStringSig) vectorized() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@ -108,6 +108,9 @@ var vecBuiltinMiscellaneousCases = map[string][]vecExprBenchCase{
|
||||
{retEvalType: types.ETString, childrenTypes: []types.EvalType{types.ETString}, geners: []dataGenerator{&uuidBinGener{newDefaultRandGen()}}},
|
||||
{retEvalType: types.ETString, childrenTypes: []types.EvalType{types.ETString, types.ETInt}, geners: []dataGenerator{&uuidBinGener{newDefaultRandGen()}}},
|
||||
},
|
||||
ast.IsUUID: {
|
||||
{retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETString}, geners: []dataGenerator{&uuidStrGener{newDefaultRandGen()}}},
|
||||
},
|
||||
}
|
||||
|
||||
func TestVectorizedBuiltinMiscellaneousEvalOneVec(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user