diff --git a/pkg/sql/plan/function/func_builtin.go b/pkg/sql/plan/function/func_builtin.go index 0ae7984d5d659..7f5c8e33ee79d 100644 --- a/pkg/sql/plan/function/func_builtin.go +++ b/pkg/sql/plan/function/func_builtin.go @@ -1229,6 +1229,239 @@ func builtInUUID(_ []*vector.Vector, result vector.FunctionResultWrapper, proc * return nil } +func builtInIsUUID(parameters []*vector.Vector, result vector.FunctionResultWrapper, _ *process.Process, length int, selectList *FunctionSelectList) error { + p1 := vector.GenerateFunctionStrParameter(parameters[0]) + rs := vector.MustFunctionResult[bool](result) + for i := uint64(0); i < uint64(length); i++ { + v, null := p1.GetStrValue(i) + if null { + if err := rs.Append(false, true); err != nil { + return err + } + continue + } + if err := rs.Append(isUUIDString(functionUtil.QuickBytesToStr(v)), false); err != nil { + return err + } + } + return nil +} + +func builtInUUIDToBin(parameters []*vector.Vector, result vector.FunctionResultWrapper, proc *process.Process, length int, selectList *FunctionSelectList) error { + p1 := vector.GenerateFunctionStrParameter(parameters[0]) + var getSwapFlag func(uint64) (int64, bool) + if len(parameters) == 2 { + getSwapFlag = makeIntegerParamGetter(parameters[1]) + } + rs := vector.MustFunctionResult[types.Varlena](result) + for i := uint64(0); i < uint64(length); i++ { + uuidBytes, null := p1.GetStrValue(i) + if null { + if err := rs.AppendBytes(nil, true); err != nil { + return err + } + continue + } + swapFlag := int64(0) + if getSwapFlag != nil { + var null2 bool + swapFlag, null2 = getSwapFlag(i) + if null2 { + if err := rs.AppendBytes(nil, true); err != nil { + return err + } + continue + } + } + u, err := parseUUIDString(functionUtil.QuickBytesToStr(uuidBytes)) + if err != nil { + return moerr.NewInvalidArg(proc.Ctx, "uuid_to_bin", functionUtil.QuickBytesToStr(uuidBytes)) + } + out := uuidToBin(u, swapFlag != 0) + if err := rs.AppendBytes(out[:], false); err != nil { + return err + } + } + return nil +} + +func builtInBinToUUID(parameters []*vector.Vector, result vector.FunctionResultWrapper, proc *process.Process, length int, selectList *FunctionSelectList) error { + p1 := vector.GenerateFunctionStrParameter(parameters[0]) + var getSwapFlag func(uint64) (int64, bool) + if len(parameters) == 2 { + getSwapFlag = makeIntegerParamGetter(parameters[1]) + } + rs := vector.MustFunctionResult[types.Varlena](result) + for i := uint64(0); i < uint64(length); i++ { + bin, null := p1.GetStrValue(i) + if null { + if err := rs.AppendBytes(nil, true); err != nil { + return err + } + continue + } + swapFlag := int64(0) + if getSwapFlag != nil { + var null2 bool + swapFlag, null2 = getSwapFlag(i) + if null2 { + if err := rs.AppendBytes(nil, true); err != nil { + return err + } + continue + } + } + if len(bin) != 16 { + return moerr.NewInvalidArg(proc.Ctx, "bin_to_uuid", len(bin)) + } + var u types.Uuid + copy(u[:], bin) + if swapFlag != 0 { + u = unswapUUIDTimeParts(u) + } + if err := rs.AppendBytes([]byte(u.String()), false); err != nil { + return err + } + } + return nil +} + +func makeIntegerParamGetter(param *vector.Vector) func(uint64) (int64, bool) { + switch param.GetType().Oid { + case types.T_int8: + p := vector.GenerateFunctionFixedTypeParameter[int8](param) + return func(idx uint64) (int64, bool) { + v, null := p.GetValue(idx) + return int64(v), null + } + case types.T_int16: + p := vector.GenerateFunctionFixedTypeParameter[int16](param) + return func(idx uint64) (int64, bool) { + v, null := p.GetValue(idx) + return int64(v), null + } + case types.T_int32: + p := vector.GenerateFunctionFixedTypeParameter[int32](param) + return func(idx uint64) (int64, bool) { + v, null := p.GetValue(idx) + return int64(v), null + } + case types.T_int64: + p := vector.GenerateFunctionFixedTypeParameter[int64](param) + return func(idx uint64) (int64, bool) { + return p.GetValue(idx) + } + case types.T_uint8: + p := vector.GenerateFunctionFixedTypeParameter[uint8](param) + return func(idx uint64) (int64, bool) { + v, null := p.GetValue(idx) + return int64(v), null + } + case types.T_uint16: + p := vector.GenerateFunctionFixedTypeParameter[uint16](param) + return func(idx uint64) (int64, bool) { + v, null := p.GetValue(idx) + return int64(v), null + } + case types.T_uint32: + p := vector.GenerateFunctionFixedTypeParameter[uint32](param) + return func(idx uint64) (int64, bool) { + v, null := p.GetValue(idx) + return int64(v), null + } + case types.T_uint64: + p := vector.GenerateFunctionFixedTypeParameter[uint64](param) + return func(idx uint64) (int64, bool) { + v, null := p.GetValue(idx) + return int64(v), null + } + default: + p := vector.GenerateFunctionFixedTypeParameter[int64](param) + return func(idx uint64) (int64, bool) { + return p.GetValue(idx) + } + } +} + +func isUUIDString(s string) bool { + _, err := parseUUIDString(s) + return err == nil +} + +func parseUUIDString(s string) (types.Uuid, error) { + if !isMySQLUUIDFormat(s) { + return types.Uuid{}, moerr.NewInvalidInputNoCtx("invalid uuid") + } + if len(s) == 38 { + s = s[1:37] + } + return types.ParseUuid(s) +} + +func isMySQLUUIDFormat(s string) bool { + switch len(s) { + case 32: + return allUUIDHex(s) + case 36: + return isDashedUUIDFormat(s) + case 38: + return s[0] == '{' && s[37] == '}' && isDashedUUIDFormat(s[1:37]) + default: + return false + } +} + +func isDashedUUIDFormat(s string) bool { + if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { + return false + } + return allUUIDHex(s[:8]) && + allUUIDHex(s[9:13]) && + allUUIDHex(s[14:18]) && + allUUIDHex(s[19:23]) && + allUUIDHex(s[24:]) +} + +func allUUIDHex(s string) bool { + for i := 0; i < len(s); i++ { + if !isUUIDHex(s[i]) { + return false + } + } + return true +} + +func isUUIDHex(c byte) bool { + return ('0' <= c && c <= '9') || + ('a' <= c && c <= 'f') || + ('A' <= c && c <= 'F') +} + +func uuidToBin(u types.Uuid, swap bool) [16]byte { + if !swap { + return [16]byte(u) + } + return swapUUIDTimeParts(u) +} + +func swapUUIDTimeParts(u types.Uuid) [16]byte { + return [16]byte{ + u[6], u[7], + u[4], u[5], + u[0], u[1], u[2], u[3], + u[8], u[9], u[10], u[11], u[12], u[13], u[14], u[15], + } +} + +func unswapUUIDTimeParts(u types.Uuid) types.Uuid { + return types.Uuid{ + u[4], u[5], u[6], u[7], + u[2], u[3], + u[0], u[1], + u[8], u[9], u[10], u[11], u[12], u[13], u[14], u[15], + } +} + func builtInUnixTimestamp(parameters []*vector.Vector, result vector.FunctionResultWrapper, _ *process.Process, length int, selectList *FunctionSelectList) error { rs := vector.MustFunctionResult[int64](result) if len(parameters) == 0 { diff --git a/pkg/sql/plan/function/func_builtin_test.go b/pkg/sql/plan/function/func_builtin_test.go index 50e9cffa28f9e..ff5d7693578f9 100644 --- a/pkg/sql/plan/function/func_builtin_test.go +++ b/pkg/sql/plan/function/func_builtin_test.go @@ -1530,3 +1530,199 @@ func TestBuiltInSysdate_ScaleValidation(t *testing.T) { require.Contains(t, err.Error(), "Maximum is 6") }) } + +func TestBuiltInUUIDFunctions(t *testing.T) { + proc := testutil.NewProcess(t) + u := "6ccd780c-baba-1026-9564-5b8c656024db" + noDash := "6ccd780cbaba102695645b8c656024db" + braced := "{6ccd780c-baba-1026-9564-5b8c656024db}" + + { + tc := tcTemp{ + info: "is_uuid accepts documented UUID string forms", + inputs: []FunctionTestInput{ + NewFunctionTestInput(types.T_varchar.ToType(), + []string{u, noDash, braced, "urn:uuid:" + u, "not-a-uuid", "", u}, + []bool{false, false, false, false, false, false, true}), + }, + expect: NewFunctionTestResult(types.T_bool.ToType(), false, + []bool{true, true, true, false, false, false, false}, + []bool{false, false, false, false, false, false, true}), + } + tcc := NewFunctionTestCase(proc, tc.inputs, tc.expect, builtInIsUUID) + succeed, info := tcc.Run() + require.True(t, succeed, tc.info, info) + } + + { + tc := tcTemp{ + info: "uuid_to_bin without swap", + inputs: []FunctionTestInput{ + NewFunctionTestInput(types.T_varchar.ToType(), []string{u, u}, []bool{false, true}), + }, + expect: NewFunctionTestResult(types.T_varbinary.ToType(), false, + []string{string([]byte{ + 0x6c, 0xcd, 0x78, 0x0c, 0xba, 0xba, 0x10, 0x26, + 0x95, 0x64, 0x5b, 0x8c, 0x65, 0x60, 0x24, 0xdb, + }), ""}, + []bool{false, true}), + } + tcc := NewFunctionTestCase(proc, tc.inputs, tc.expect, builtInUUIDToBin) + succeed, info := tcc.Run() + require.True(t, succeed, tc.info, info) + } + + { + tc := tcTemp{ + info: "uuid_to_bin with int64 swap flag", + inputs: []FunctionTestInput{ + NewFunctionTestInput(types.T_varchar.ToType(), []string{u}, []bool{false}), + NewFunctionTestInput(types.T_int64.ToType(), []int64{1}, []bool{false}), + }, + expect: NewFunctionTestResult(types.T_varbinary.ToType(), false, + []string{string([]byte{ + 0x10, 0x26, 0xba, 0xba, 0x6c, 0xcd, 0x78, 0x0c, + 0x95, 0x64, 0x5b, 0x8c, 0x65, 0x60, 0x24, 0xdb, + })}, + []bool{false}), + } + tcc := NewFunctionTestCase(proc, tc.inputs, tc.expect, builtInUUIDToBin) + succeed, info := tcc.Run() + require.True(t, succeed, tc.info, info) + } + + { + tc := tcTemp{ + info: "uuid_to_bin with int32 swap flag", + inputs: []FunctionTestInput{ + NewFunctionTestInput(types.T_varchar.ToType(), []string{u, u}, []bool{false, false}), + NewFunctionTestInput(types.T_int32.ToType(), []int32{0, 1}, []bool{false, false}), + }, + expect: NewFunctionTestResult(types.T_varbinary.ToType(), false, + []string{ + string([]byte{ + 0x6c, 0xcd, 0x78, 0x0c, 0xba, 0xba, 0x10, 0x26, + 0x95, 0x64, 0x5b, 0x8c, 0x65, 0x60, 0x24, 0xdb, + }), + string([]byte{ + 0x10, 0x26, 0xba, 0xba, 0x6c, 0xcd, 0x78, 0x0c, + 0x95, 0x64, 0x5b, 0x8c, 0x65, 0x60, 0x24, 0xdb, + }), + }, + []bool{false, false}), + } + tcc := NewFunctionTestCase(proc, tc.inputs, tc.expect, builtInUUIDToBin) + succeed, info := tcc.Run() + require.True(t, succeed, tc.info, info) + } + + { + bin := string([]byte{ + 0x6c, 0xcd, 0x78, 0x0c, 0xba, 0xba, 0x10, 0x26, + 0x95, 0x64, 0x5b, 0x8c, 0x65, 0x60, 0x24, 0xdb, + }) + swapped := string([]byte{ + 0x10, 0x26, 0xba, 0xba, 0x6c, 0xcd, 0x78, 0x0c, + 0x95, 0x64, 0x5b, 0x8c, 0x65, 0x60, 0x24, 0xdb, + }) + tc := tcTemp{ + info: "bin_to_uuid with and without swap", + inputs: []FunctionTestInput{ + NewFunctionTestInput(types.T_varbinary.ToType(), []string{bin, swapped, ""}, []bool{false, false, true}), + NewFunctionTestInput(types.T_int64.ToType(), []int64{0, 1, 0}, []bool{false, false, false}), + }, + expect: NewFunctionTestResult(types.T_varchar.ToType(), false, + []string{u, u, ""}, + []bool{false, false, true}), + } + tcc := NewFunctionTestCase(proc, tc.inputs, tc.expect, builtInBinToUUID) + succeed, info := tcc.Run() + require.True(t, succeed, tc.info, info) + } + + { + tc := tcTemp{ + info: "uuid_to_bin invalid uuid returns error", + inputs: []FunctionTestInput{ + NewFunctionTestInput(types.T_varchar.ToType(), []string{"not-a-uuid"}, []bool{false}), + }, + expect: NewFunctionTestResult(types.T_varbinary.ToType(), true, []string{""}, []bool{true}), + } + tcc := NewFunctionTestCase(proc, tc.inputs, tc.expect, builtInUUIDToBin) + succeed, info := tcc.Run() + require.True(t, succeed, tc.info, info) + } + + { + tc := tcTemp{ + info: "bin_to_uuid invalid length returns error", + inputs: []FunctionTestInput{ + NewFunctionTestInput(types.T_varbinary.ToType(), []string{"short"}, []bool{false}), + }, + expect: NewFunctionTestResult(types.T_varchar.ToType(), true, []string{""}, []bool{true}), + } + tcc := NewFunctionTestCase(proc, tc.inputs, tc.expect, builtInBinToUUID) + succeed, info := tcc.Run() + require.True(t, succeed, tc.info, info) + } +} + +func TestBuiltInUUIDSwapFlagIntegerTypes(t *testing.T) { + proc := testutil.NewProcess(t) + u := "6ccd780c-baba-1026-9564-5b8c656024db" + bin := string([]byte{ + 0x6c, 0xcd, 0x78, 0x0c, 0xba, 0xba, 0x10, 0x26, + 0x95, 0x64, 0x5b, 0x8c, 0x65, 0x60, 0x24, 0xdb, + }) + swapped := string([]byte{ + 0x10, 0x26, 0xba, 0xba, 0x6c, 0xcd, 0x78, 0x0c, + 0x95, 0x64, 0x5b, 0x8c, 0x65, 0x60, 0x24, 0xdb, + }) + + for _, tc := range []struct { + name string + typ types.Type + values any + }{ + {"int8", types.T_int8.ToType(), []int8{0, 1, 1}}, + {"int16", types.T_int16.ToType(), []int16{0, 1, 1}}, + {"int32", types.T_int32.ToType(), []int32{0, 1, 1}}, + {"int64", types.T_int64.ToType(), []int64{0, 1, 1}}, + {"uint8", types.T_uint8.ToType(), []uint8{0, 1, 1}}, + {"uint16", types.T_uint16.ToType(), []uint16{0, 1, 1}}, + {"uint32", types.T_uint32.ToType(), []uint32{0, 1, 1}}, + {"uint64", types.T_uint64.ToType(), []uint64{0, 1, 1}}, + } { + t.Run(tc.name+"/uuid_to_bin", func(t *testing.T) { + ftc := tcTemp{ + info: "uuid_to_bin with " + tc.name + " swap flag", + inputs: []FunctionTestInput{ + NewFunctionTestInput(types.T_varchar.ToType(), []string{u, u, u}, []bool{false, false, false}), + NewFunctionTestInput(tc.typ, tc.values, []bool{false, false, true}), + }, + expect: NewFunctionTestResult(types.T_varbinary.ToType(), false, + []string{bin, swapped, ""}, + []bool{false, false, true}), + } + tcc := NewFunctionTestCase(proc, ftc.inputs, ftc.expect, builtInUUIDToBin) + succeed, info := tcc.Run() + require.True(t, succeed, ftc.info, info) + }) + + t.Run(tc.name+"/bin_to_uuid", func(t *testing.T) { + ftc := tcTemp{ + info: "bin_to_uuid with " + tc.name + " swap flag", + inputs: []FunctionTestInput{ + NewFunctionTestInput(types.T_varbinary.ToType(), []string{bin, swapped, swapped}, []bool{false, false, false}), + NewFunctionTestInput(tc.typ, tc.values, []bool{false, false, true}), + }, + expect: NewFunctionTestResult(types.T_varchar.ToType(), false, + []string{u, u, ""}, + []bool{false, false, true}), + } + tcc := NewFunctionTestCase(proc, ftc.inputs, ftc.expect, builtInBinToUUID) + succeed, info := tcc.Run() + require.True(t, succeed, ftc.info, info) + }) + } +} diff --git a/pkg/sql/plan/function/function_id.go b/pkg/sql/plan/function/function_id.go index e4100731cde42..bb0736af033af 100644 --- a/pkg/sql/plan/function/function_id.go +++ b/pkg/sql/plan/function/function_id.go @@ -643,11 +643,14 @@ const ( JSON_SCHEMA_VALID = 460 JSON_SCHEMA_VALID_REPORT = 461 JSON_VALUE = 462 + IS_UUID = 463 + UUID_TO_BIN = 464 + BIN_TO_UUID = 465 // FUNCTION_END_NUMBER is not a function, just a flag to record the max number of function. // TODO: every one should put the new function id in front of this one if you want to make a new function. - FUNCTION_END_NUMBER = 463 + FUNCTION_END_NUMBER = 466 ) // functionIdRegister is what function we have registered already. @@ -943,6 +946,9 @@ var functionIdRegister = map[string]int32{ "trigger_fault_point": TRIGGER_FAULT_POINT, "mo_win_truncate": MO_WIN_TRUNCATE, "uuid": UUID, + "is_uuid": IS_UUID, + "uuid_to_bin": UUID_TO_BIN, + "bin_to_uuid": BIN_TO_UUID, "load_file": LOAD_FILE, "save_file": SAVE_FILE, "hex": HEX, diff --git a/pkg/sql/plan/function/function_id_test.go b/pkg/sql/plan/function/function_id_test.go index 99bf03e8fee3b..bcdafc37d5fa5 100644 --- a/pkg/sql/plan/function/function_id_test.go +++ b/pkg/sql/plan/function/function_id_test.go @@ -516,9 +516,12 @@ var predefinedFunids = map[int]int{ JSON_SCHEMA_VALID: 460, JSON_SCHEMA_VALID_REPORT: 461, JSON_VALUE: 462, + IS_UUID: 463, + UUID_TO_BIN: 464, + BIN_TO_UUID: 465, // FUNCTION_END_NUMBER is not a function, just a flag to record the max number of function. // TODO: every one should put the new function id in front of this one if you want to make a new function. - FUNCTION_END_NUMBER: 463, + FUNCTION_END_NUMBER: 466, } func Test_funids(t *testing.T) { diff --git a/pkg/sql/plan/function/list_builtIn.go b/pkg/sql/plan/function/list_builtIn.go index c0ed76b3f3eca..713bc4b84e6e6 100644 --- a/pkg/sql/plan/function/list_builtIn.go +++ b/pkg/sql/plan/function/list_builtIn.go @@ -11551,6 +11551,117 @@ var supportedOthersBuiltIns = []FuncNew{ }, }, + // function `is_uuid` + { + functionId: IS_UUID, + class: plan.Function_STRICT, + layout: STANDARD_FUNCTION, + checkFn: fixedTypeMatch, + + Overloads: []overload{ + { + overloadId: 0, + args: []types.T{types.T_varchar}, + retType: func(parameters []types.Type) types.Type { + return types.T_bool.ToType() + }, + newOp: func() executeLogicOfOverload { + return builtInIsUUID + }, + }, + { + overloadId: 1, + args: []types.T{types.T_text}, + retType: func(parameters []types.Type) types.Type { + return types.T_bool.ToType() + }, + newOp: func() executeLogicOfOverload { + return builtInIsUUID + }, + }, + }, + }, + + // function `uuid_to_bin` + { + functionId: UUID_TO_BIN, + class: plan.Function_STRICT, + layout: STANDARD_FUNCTION, + checkFn: func(overloads []overload, inputs []types.Type) checkResult { + if len(inputs) != 1 && len(inputs) != 2 { + return newCheckResultWithFailure(failedFunctionParametersWrong) + } + castTypes := make([]types.Type, len(inputs)) + copy(castTypes, inputs) + needCast := false + if !inputs[0].Oid.IsMySQLString() { + castTypes[0] = types.T_varchar.ToType() + needCast = true + } + if len(inputs) == 2 && !inputs[1].Oid.IsInteger() { + castTypes[1] = types.T_int64.ToType() + needCast = true + } + if needCast { + return newCheckResultWithCast(0, castTypes) + } + return newCheckResultWithSuccess(0) + }, + + Overloads: []overload{ + { + overloadId: 0, + retType: func(parameters []types.Type) types.Type { + return types.T_varbinary.ToType() + }, + newOp: func() executeLogicOfOverload { + return builtInUUIDToBin + }, + }, + }, + }, + + // function `bin_to_uuid` + { + functionId: BIN_TO_UUID, + class: plan.Function_STRICT, + layout: STANDARD_FUNCTION, + checkFn: func(overloads []overload, inputs []types.Type) checkResult { + if len(inputs) != 1 && len(inputs) != 2 { + return newCheckResultWithFailure(failedFunctionParametersWrong) + } + castTypes := make([]types.Type, len(inputs)) + copy(castTypes, inputs) + needCast := false + switch inputs[0].Oid { + case types.T_binary, types.T_varbinary, types.T_blob: + default: + castTypes[0] = types.T_varbinary.ToType() + needCast = true + } + if len(inputs) == 2 && !inputs[1].Oid.IsInteger() { + castTypes[1] = types.T_int64.ToType() + needCast = true + } + if needCast { + return newCheckResultWithCast(0, castTypes) + } + return newCheckResultWithSuccess(0) + }, + + Overloads: []overload{ + { + overloadId: 0, + retType: func(parameters []types.Type) types.Type { + return types.T_varchar.ToType() + }, + newOp: func() executeLogicOfOverload { + return builtInBinToUUID + }, + }, + }, + }, + // function `values` { functionId: VALUES, diff --git a/test/distributed/cases/function/func_string_uuid2.result b/test/distributed/cases/function/func_string_uuid2.result new file mode 100644 index 0000000000000..037c648f13aeb --- /dev/null +++ b/test/distributed/cases/function/func_string_uuid2.result @@ -0,0 +1,118 @@ +select is_uuid('6ccd780c-baba-1026-9564-5b8c656024db'); +➤ is_uuid(6ccd780c-baba-1026-9564-5b8c656024db)[-7,1,0] 𝄀 +1 +select is_uuid('6ccd780cbaba102695645b8c656024db'); +➤ is_uuid(6ccd780cbaba102695645b8c656024db)[-7,1,0] 𝄀 +1 +select is_uuid('{6ccd780c-baba-1026-9564-5b8c656024db}'); +➤ is_uuid({6ccd780c-baba-1026-9564-5b8c656024db})[-7,1,0] 𝄀 +1 +select is_uuid('6CCD780C-BABA-1026-9564-5B8C656024DB'); +➤ is_uuid(6CCD780C-BABA-1026-9564-5B8C656024DB)[-7,1,0] 𝄀 +1 +select is_uuid('urn:uuid:6ccd780c-baba-1026-9564-5b8c656024db'); +➤ is_uuid(urn:uuid:6ccd780c-baba-1026-9564-5b8c656024db)[-7,1,0] 𝄀 +0 +select is_uuid('6ccd780c-baba-1026-9564-5b8c656024d'); +➤ is_uuid(6ccd780c-baba-1026-9564-5b8c656024d)[-7,1,0] 𝄀 +0 +select is_uuid('6ccd780c-baba-1026-9564-5b8c656024dz'); +➤ is_uuid(6ccd780c-baba-1026-9564-5b8c656024dz)[-7,1,0] 𝄀 +0 +select is_uuid('6ccd780c-baba-1026-95645b8c656024db'); +➤ is_uuid(6ccd780c-baba-1026-95645b8c656024db)[-7,1,0] 𝄀 +0 +select is_uuid('{6ccd780cbaba102695645b8c656024db}'); +➤ is_uuid({6ccd780cbaba102695645b8c656024db})[-7,1,0] 𝄀 +0 +select is_uuid(' 6ccd780c-baba-1026-9564-5b8c656024db '); +➤ is_uuid( 6ccd780c-baba-1026-9564-5b8c656024db )[-7,1,0] 𝄀 +0 +select is_uuid(''); +➤ is_uuid()[-7,1,0] 𝄀 +0 +select is_uuid('not-a-uuid'); +➤ is_uuid(not-a-uuid)[-7,1,0] 𝄀 +0 +select is_uuid(null); +➤ is_uuid(null)[-7,1,0] 𝄀 +null +select hex(uuid_to_bin('6ccd780c-baba-1026-9564-5b8c656024db')); +➤ hex(uuid_to_bin(6ccd780c-baba-1026-9564-5b8c656024db))[12,-1,0] 𝄀 +6CCD780CBABA102695645B8C656024DB +select hex(uuid_to_bin('6ccd780cbaba102695645b8c656024db')); +➤ hex(uuid_to_bin(6ccd780cbaba102695645b8c656024db))[12,-1,0] 𝄀 +6CCD780CBABA102695645B8C656024DB +select hex(uuid_to_bin('{6ccd780c-baba-1026-9564-5b8c656024db}')); +➤ hex(uuid_to_bin({6ccd780c-baba-1026-9564-5b8c656024db}))[12,-1,0] 𝄀 +6CCD780CBABA102695645B8C656024DB +select hex(uuid_to_bin('6CCD780C-BABA-1026-9564-5B8C656024DB')); +➤ hex(uuid_to_bin(6CCD780C-BABA-1026-9564-5B8C656024DB))[12,-1,0] 𝄀 +6CCD780CBABA102695645B8C656024DB +select hex(uuid_to_bin('6ccd780c-baba-1026-9564-5b8c656024db', 1)); +➤ hex(uuid_to_bin(6ccd780c-baba-1026-9564-5b8c656024db, 1))[12,-1,0] 𝄀 +1026BABA6CCD780C95645B8C656024DB +select hex(uuid_to_bin('6ccd780c-baba-1026-9564-5b8c656024db', 0)); +➤ hex(uuid_to_bin(6ccd780c-baba-1026-9564-5b8c656024db, 0))[12,-1,0] 𝄀 +6CCD780CBABA102695645B8C656024DB +select hex(uuid_to_bin(null)); +➤ hex(uuid_to_bin(null))[12,-1,0] 𝄀 +null +select hex(uuid_to_bin('6ccd780c-baba-1026-9564-5b8c656024db', null)); +➤ hex(uuid_to_bin(6ccd780c-baba-1026-9564-5b8c656024db, null))[12,-1,0] 𝄀 +null +select bin_to_uuid(uuid_to_bin('6ccd780c-baba-1026-9564-5b8c656024db')); +➤ bin_to_uuid(uuid_to_bin(6ccd780c-baba-1026-9564-5b8c656024db))[12,-1,0] 𝄀 +6ccd780c-baba-1026-9564-5b8c656024db +select bin_to_uuid(uuid_to_bin('6ccd780c-baba-1026-9564-5b8c656024db', 1), 1); +➤ bin_to_uuid(uuid_to_bin(6ccd780c-baba-1026-9564-5b8c656024db, 1), 1)[12,-1,0] 𝄀 +6ccd780c-baba-1026-9564-5b8c656024db +select bin_to_uuid(uuid_to_bin('6ccd780c-baba-1026-9564-5b8c656024db', 1), 0); +➤ bin_to_uuid(uuid_to_bin(6ccd780c-baba-1026-9564-5b8c656024db, 1), 0)[12,-1,0] 𝄀 +1026baba-6ccd-780c-9564-5b8c656024db +select bin_to_uuid(uuid_to_bin('6ccd780c-baba-1026-9564-5b8c656024db'), null); +➤ bin_to_uuid(uuid_to_bin(6ccd780c-baba-1026-9564-5b8c656024db), null)[12,-1,0] 𝄀 +null +select bin_to_uuid(null); +➤ bin_to_uuid(null)[12,-1,0] 𝄀 +null +select uuid_to_bin('not-a-uuid'); +invalid argument uuid_to_bin, bad value not-a-uuid +select uuid_to_bin('6ccd780c-baba-1026-9564-5b8c656024dz'); +invalid argument uuid_to_bin, bad value 6ccd780c-baba-1026-9564-5b8c656024dz +select bin_to_uuid(cast('short' as varbinary)); +invalid argument bin_to_uuid, bad value 5 +select bin_to_uuid(cast('123456789012345' as varbinary)); +invalid argument bin_to_uuid, bad value 15 +select bin_to_uuid(cast('12345678901234567' as varbinary)); +invalid argument bin_to_uuid, bad value 17 +drop table if exists t_uuid_funcs; +create table t_uuid_funcs(id int, u varchar(50), swap_flag int); +insert into t_uuid_funcs values +(1, '6ccd780c-baba-1026-9564-5b8c656024db', 0), +(2, '6ccd780cbaba102695645b8c656024db', 1), +(3, '{6ccd780c-baba-1026-9564-5b8c656024db}', null), +(4, 'not-a-uuid', 0), +(5, null, 1); +select id, is_uuid(u) from t_uuid_funcs order by id; +➤ id[4,32,0] ¦ is_uuid(u)[-7,1,0] 𝄀 +1 ¦ 1 𝄀 +2 ¦ 1 𝄀 +3 ¦ 1 𝄀 +4 ¦ 0 𝄀 +5 ¦ null +select id, bin_to_uuid(uuid_to_bin(u)) from t_uuid_funcs where is_uuid(u) order by id; +➤ id[4,32,0] ¦ bin_to_uuid(uuid_to_bin(u))[12,-1,0] 𝄀 +1 ¦ 6ccd780c-baba-1026-9564-5b8c656024db 𝄀 +2 ¦ 6ccd780c-baba-1026-9564-5b8c656024db 𝄀 +3 ¦ 6ccd780c-baba-1026-9564-5b8c656024db +select id, hex(uuid_to_bin(u, swap_flag)) from t_uuid_funcs where is_uuid(u) order by id; +➤ id[4,32,0] ¦ hex(uuid_to_bin(u, swap_flag))[12,-1,0] 𝄀 +1 ¦ 6CCD780CBABA102695645B8C656024DB 𝄀 +2 ¦ 1026BABA6CCD780C95645B8C656024DB 𝄀 +3 ¦ null +select id, bin_to_uuid(uuid_to_bin(u, swap_flag), swap_flag) from t_uuid_funcs where is_uuid(u) and swap_flag is not null order by id; +➤ id[4,32,0] ¦ bin_to_uuid(uuid_to_bin(u, swap_flag), swap_flag)[12,-1,0] 𝄀 +1 ¦ 6ccd780c-baba-1026-9564-5b8c656024db 𝄀 +2 ¦ 6ccd780c-baba-1026-9564-5b8c656024db +drop table t_uuid_funcs; diff --git a/test/distributed/cases/function/func_string_uuid2.test b/test/distributed/cases/function/func_string_uuid2.test new file mode 100644 index 0000000000000..63cc65d37d37a --- /dev/null +++ b/test/distributed/cases/function/func_string_uuid2.test @@ -0,0 +1,46 @@ +select is_uuid('6ccd780c-baba-1026-9564-5b8c656024db'); +select is_uuid('6ccd780cbaba102695645b8c656024db'); +select is_uuid('{6ccd780c-baba-1026-9564-5b8c656024db}'); +select is_uuid('6CCD780C-BABA-1026-9564-5B8C656024DB'); +select is_uuid('urn:uuid:6ccd780c-baba-1026-9564-5b8c656024db'); +select is_uuid('6ccd780c-baba-1026-9564-5b8c656024d'); +select is_uuid('6ccd780c-baba-1026-9564-5b8c656024dz'); +select is_uuid('6ccd780c-baba-1026-95645b8c656024db'); +select is_uuid('{6ccd780cbaba102695645b8c656024db}'); +select is_uuid(' 6ccd780c-baba-1026-9564-5b8c656024db '); +select is_uuid(''); +select is_uuid('not-a-uuid'); +select is_uuid(null); + +select hex(uuid_to_bin('6ccd780c-baba-1026-9564-5b8c656024db')); +select hex(uuid_to_bin('6ccd780cbaba102695645b8c656024db')); +select hex(uuid_to_bin('{6ccd780c-baba-1026-9564-5b8c656024db}')); +select hex(uuid_to_bin('6CCD780C-BABA-1026-9564-5B8C656024DB')); +select hex(uuid_to_bin('6ccd780c-baba-1026-9564-5b8c656024db', 1)); +select hex(uuid_to_bin('6ccd780c-baba-1026-9564-5b8c656024db', 0)); +select hex(uuid_to_bin(null)); +select hex(uuid_to_bin('6ccd780c-baba-1026-9564-5b8c656024db', null)); +select bin_to_uuid(uuid_to_bin('6ccd780c-baba-1026-9564-5b8c656024db')); +select bin_to_uuid(uuid_to_bin('6ccd780c-baba-1026-9564-5b8c656024db', 1), 1); +select bin_to_uuid(uuid_to_bin('6ccd780c-baba-1026-9564-5b8c656024db', 1), 0); +select bin_to_uuid(uuid_to_bin('6ccd780c-baba-1026-9564-5b8c656024db'), null); +select bin_to_uuid(null); +select uuid_to_bin('not-a-uuid'); +select uuid_to_bin('6ccd780c-baba-1026-9564-5b8c656024dz'); +select bin_to_uuid(cast('short' as varbinary)); +select bin_to_uuid(cast('123456789012345' as varbinary)); +select bin_to_uuid(cast('12345678901234567' as varbinary)); + +drop table if exists t_uuid_funcs; +create table t_uuid_funcs(id int, u varchar(50), swap_flag int); +insert into t_uuid_funcs values + (1, '6ccd780c-baba-1026-9564-5b8c656024db', 0), + (2, '6ccd780cbaba102695645b8c656024db', 1), + (3, '{6ccd780c-baba-1026-9564-5b8c656024db}', null), + (4, 'not-a-uuid', 0), + (5, null, 1); +select id, is_uuid(u) from t_uuid_funcs order by id; +select id, bin_to_uuid(uuid_to_bin(u)) from t_uuid_funcs where is_uuid(u) order by id; +select id, hex(uuid_to_bin(u, swap_flag)) from t_uuid_funcs where is_uuid(u) order by id; +select id, bin_to_uuid(uuid_to_bin(u, swap_flag), swap_flag) from t_uuid_funcs where is_uuid(u) and swap_flag is not null order by id; +drop table t_uuid_funcs;