From 46f1fea845642aaf16ffabbf7b2e4ffd886aea34 Mon Sep 17 00:00:00 2001 From: qingxinhome <70939751+qingxinhome@users.noreply.github.com> Date: Mon, 15 Aug 2022 12:48:21 +0800 Subject: [PATCH] Support UUID function#4019 (#4474) Support uuid function Approved by: @aressu1985, @ouyuanning --- pkg/sql/plan/base_binder.go | 5 ++ pkg/sql/plan/function/builtin/multi/uuid.go | 60 ++++++++++++++ .../plan/function/builtin/multi/uuid_test.go | 78 +++++++++++++++++++ pkg/sql/plan/function/builtins.go | 20 +++++ pkg/sql/plan/function/function.go | 12 +++ pkg/sql/plan/function/function_id.go | 2 + test/cases/function/func_string_uuid.test | 5 ++ test/result/function/func_string_uuid.result | 9 +++ 8 files changed, 191 insertions(+) create mode 100644 pkg/sql/plan/function/builtin/multi/uuid.go create mode 100644 pkg/sql/plan/function/builtin/multi/uuid_test.go create mode 100644 test/cases/function/func_string_uuid.test create mode 100644 test/result/function/func_string_uuid.result diff --git a/pkg/sql/plan/base_binder.go b/pkg/sql/plan/base_binder.go index 3d3b2103e..d7b96790f 100644 --- a/pkg/sql/plan/base_binder.go +++ b/pkg/sql/plan/base_binder.go @@ -851,6 +851,11 @@ func bindFuncExprImplByPlanExpr(name string, args []*Expr) (*plan.Expr, error) { } } + if function.GetFunctionAppendHideArgByID(funcID) { + // Append a hidden parameter to the function. The default value is constant null + args = append(args, makePlan2NullConstExprWithType()) + } + // return new expr return &Expr{ Expr: &plan.Expr_F{ diff --git a/pkg/sql/plan/function/builtin/multi/uuid.go b/pkg/sql/plan/function/builtin/multi/uuid.go new file mode 100644 index 000000000..bf7122728 --- /dev/null +++ b/pkg/sql/plan/function/builtin/multi/uuid.go @@ -0,0 +1,60 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package multi + +import ( + "github.com/google/uuid" + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" + "github.com/matrixorigin/matrixone/pkg/vm/process" +) + +const UUID_LENGTH uint32 = 36 + +func UUID(inputVecs []*vector.Vector, proc *process.Process) (*vector.Vector, error) { + if len(inputVecs) != 1 { + return nil, moerr.NewError(moerr.INTERNAL_ERROR, "uuid function requires a hidden parameter") + } + rows := inputVecs[0].Length + resultType := types.T_varchar.ToType() + resultVector := vector.New(resultType) + + results := &types.Bytes{ + Data: make([]byte, int(UUID_LENGTH)*rows), + Offsets: make([]uint32, rows), + Lengths: make([]uint32, rows), + } + var retCursor uint32 = 0 + for i := 0; i < rows; i++ { + id, err := uuid.NewUUID() + if err != nil { + return nil, moerr.NewError(moerr.INTERNAL_ERROR, "generation uuid error") + } + slice := []byte(id.String()) + for _, b := range slice { + results.Data[retCursor] = b + retCursor++ + } + if i != 0 { + results.Offsets[i] = results.Offsets[i-1] + results.Lengths[i-1] + } else { + results.Offsets[i] = uint32(0) + } + results.Lengths[i] = UUID_LENGTH + } + vector.SetCol(resultVector, results) + return resultVector, nil +} diff --git a/pkg/sql/plan/function/builtin/multi/uuid_test.go b/pkg/sql/plan/function/builtin/multi/uuid_test.go new file mode 100644 index 000000000..ae4a049b4 --- /dev/null +++ b/pkg/sql/plan/function/builtin/multi/uuid_test.go @@ -0,0 +1,78 @@ +// Copyright 2021 - 2022 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package multi + +import ( + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" + "github.com/matrixorigin/matrixone/pkg/testutil" + "github.com/stretchr/testify/require" + "testing" +) + +// test return multi line +func TestUUID(t *testing.T) { + //scalar + vec := testutil.MakeScalarNull(5) + proc := testutil.NewProc() + res, err := UUID([]*vector.Vector{vec}, proc) + if err != nil { + t.Fatal(err) + } + + bytes := res.Col.(*types.Bytes) + uuids := make([]string, 5) + + for i := 0; i < 5; i++ { + offset := bytes.Offsets[i] + length := bytes.Lengths[i] + bytes := bytes.Data[offset : offset+length] + uuid := string(bytes) + uuids[i] = uuid + t.Log(uuid) + } + + for i := 0; i < 5; i++ { + for j := 0; j < 5; j++ { + if i == j { + continue + } + require.NotEqual(t, uuids[i], uuids[j]) + } + } +} + +// test retuan one line +func TestUUID2(t *testing.T) { + //scalar + vec := testutil.MakeScalarInt64(1, 1) + proc := testutil.NewProc() + res, err := UUID([]*vector.Vector{vec}, proc) + if err != nil { + t.Fatal(err) + } + + bytes := res.Col.(*types.Bytes) + uuids := make([]string, 1) + + for i := 0; i < 1; i++ { + offset := bytes.Offsets[i] + length := bytes.Lengths[i] + bytes := bytes.Data[offset : offset+length] + uuid := string(bytes) + uuids[i] = uuid + t.Log(uuid) + } +} diff --git a/pkg/sql/plan/function/builtins.go b/pkg/sql/plan/function/builtins.go index 245d24864..8f1552fb8 100644 --- a/pkg/sql/plan/function/builtins.go +++ b/pkg/sql/plan/function/builtins.go @@ -174,6 +174,26 @@ var builtins = map[int]Functions{ }, }, }, + UUID: { + // uuid function contains a hidden placeholder parameter + Id: UUID, + TypeCheckFn: func(_ []Function, inputs []types.T) (overloadIndex int32, ts []types.T) { + if len(inputs) == 0 { + return int32(0), nil + } + return wrongFunctionParameters, nil + }, + Overloads: []Function{ + { + Index: 0, + Flag: plan.Function_STRICT, + Layout: STANDARD_FUNCTION, + Volatile: true, + AppendHideArg: true, + ReturnTyp: types.T_varchar, Fn: multi.UUID, + }, + }, + }, DATE: { Id: DATE, Overloads: []Function{ diff --git a/pkg/sql/plan/function/function.go b/pkg/sql/plan/function/function.go index c69c9b506..80482b2e4 100644 --- a/pkg/sql/plan/function/function.go +++ b/pkg/sql/plan/function/function.go @@ -115,6 +115,9 @@ type Function struct { // Volatile function cannot be fold Volatile bool + // whether the function needs to append a hidden parameter, such as 'uuid' + AppendHideArg bool + Flag plan.Function_FuncFlag // Layout adapt to plan/function.go, used for `explain SQL`. @@ -202,6 +205,15 @@ func GetFunctionIsAggregateByName(name string) bool { return len(fs) > 0 && fs[0].IsAggregate() } +// Check whether the function needs to append a hidden parameter +func GetFunctionAppendHideArgByID(overloadID int64) bool { + function, err := GetFunctionByID(overloadID) + if err != nil { + return false + } + return function.AppendHideArg +} + // GetFunctionByName check a function exist or not according to input function name and arg types, // if matches, // return the encoded overload id and the overload's return type diff --git a/pkg/sql/plan/function/function_id.go b/pkg/sql/plan/function/function_id.go index 286bf94c6..a307d69e6 100644 --- a/pkg/sql/plan/function/function_id.go +++ b/pkg/sql/plan/function/function_id.go @@ -228,6 +228,7 @@ const ( ADD_FAULT_POINT // Add a fault point REMOVE_FAULT_POINT // Remove TRIGGER_FAULT_POINT // Trigger. + UUID // 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. @@ -373,6 +374,7 @@ var functionIdRegister = map[string]int32{ "add_fault_point": ADD_FAULT_POINT, "remove_fault_point": REMOVE_FAULT_POINT, "trigger_fault_point": TRIGGER_FAULT_POINT, + "uuid": UUID, } func GetFunctionIsWinfunByName(name string) bool { diff --git a/test/cases/function/func_string_uuid.test b/test/cases/function/func_string_uuid.test new file mode 100644 index 000000000..4b6b85ff1 --- /dev/null +++ b/test/cases/function/func_string_uuid.test @@ -0,0 +1,5 @@ +create table t1(a INT, b float); +insert into t1 values(12124, -4213.413), (12124, -42413.409); +SELECT length(uuid()) FROM t1; +SELECT uuid(1) FROM t1; +drop table t1; \ No newline at end of file diff --git a/test/result/function/func_string_uuid.result b/test/result/function/func_string_uuid.result new file mode 100644 index 000000000..f972c3044 --- /dev/null +++ b/test/result/function/func_string_uuid.result @@ -0,0 +1,9 @@ +create table t1(a INT, b float); +insert into t1 values(12124, -4213.413), (12124, -42413.409); +SELECT length(uuid()) FROM t1; +length(uuid()) +36 +36 +SELECT uuid(1) FROM t1; +Function 'uuid' with parameters [BIGINT] will be implemented in future version. +drop table t1; -- GitLab