From 72152d91889528e8d78a212acdf880bd124ff319 Mon Sep 17 00:00:00 2001
From: iamlinjunhong <49111204+iamlinjunhong@users.noreply.github.com>
Date: Fri, 19 Aug 2022 13:36:07 +0800
Subject: [PATCH] refact func of oct and support varchar+varchar (#4577)

---
 pkg/sql/plan/base_binder.go                   |   2 +
 pkg/sql/plan/function/aggregate.go            |   6 +
 pkg/sql/plan/function/builtin/unary/oct.go    |  40 ++---
 .../plan/function/builtin/unary/oct_test.go   |  93 +++++------
 pkg/sql/plan/function/builtins.go             |  20 +--
 pkg/sql/plan/function/operator/cast.go        |  10 +-
 pkg/vectorize/oct/oct.go                      |  74 ++++----
 pkg/vectorize/oct/oct_test.go                 | 158 ------------------
 .../cases/function/func_string_concat_ws.test |   2 +-
 test/cases/function/func_string_oct.test      |   2 -
 test/cases/function/func_string_reverse.test  |   2 -
 .../function/func_string_rtrim_ltrim.test     |   2 -
 test/cases/function/func_string_space.test    |   6 -
 .../cases/function/func_string_substring.test |   2 -
 test/result/function/func_string_oct.result   |   6 +-
 .../function/func_string_rtrim_ltrim.result   |   4 +-
 test/result/function/func_string_space.result |  16 +-
 .../function/func_string_substring.result     |   6 +-
 18 files changed, 137 insertions(+), 314 deletions(-)
 delete mode 100644 pkg/vectorize/oct/oct_test.go

diff --git a/pkg/sql/plan/base_binder.go b/pkg/sql/plan/base_binder.go
index 4d007507f..a9590319b 100644
--- a/pkg/sql/plan/base_binder.go
+++ b/pkg/sql/plan/base_binder.go
@@ -773,6 +773,8 @@ func bindFuncExprImplByPlanExpr(name string, args []*Expr) (*plan.Expr, error) {
 		} else if args[0].Typ.Id == int32(types.T_interval) && args[1].Typ.Id == int32(types.T_varchar) {
 			name = "date_add"
 			args, err = resetDateFunctionArgs(args[1], args[0])
+		} else if args[0].Typ.Id == int32(types.T_varchar) && args[1].Typ.Id == int32(types.T_varchar) {
+			name = "concat"
 		}
 		if err != nil {
 			return nil, err
diff --git a/pkg/sql/plan/function/aggregate.go b/pkg/sql/plan/function/aggregate.go
index 71d4f0d08..6e97f5ec7 100644
--- a/pkg/sql/plan/function/aggregate.go
+++ b/pkg/sql/plan/function/aggregate.go
@@ -640,6 +640,9 @@ var aggregates = map[int]Functions{
 				if inputs[0] == types.T_any {
 					return 0, nil
 				}
+				if !operator.IsNumeric(inputs[0]) {
+					return wrongFuncParamForAgg, nil
+				}
 				_, err := aggregate.ReturnType(aggregate.BitOr, types.Type{Oid: inputs[0]})
 				if err == nil {
 					return 0, nil
@@ -664,6 +667,9 @@ var aggregates = map[int]Functions{
 				if inputs[0] == types.T_any {
 					return 0, nil
 				}
+				if !operator.IsNumeric(inputs[0]) {
+					return wrongFuncParamForAgg, nil
+				}
 				_, err := aggregate.ReturnType(aggregate.BitXor, types.Type{Oid: inputs[0]})
 				if err == nil {
 					return 0, nil
diff --git a/pkg/sql/plan/function/builtin/unary/oct.go b/pkg/sql/plan/function/builtin/unary/oct.go
index da7694be0..c57e8994a 100644
--- a/pkg/sql/plan/function/builtin/unary/oct.go
+++ b/pkg/sql/plan/function/builtin/unary/oct.go
@@ -27,7 +27,7 @@ import (
 
 func Oct[T constraints.Unsigned | constraints.Signed](vectors []*vector.Vector, proc *process.Process) (*vector.Vector, error) {
 	inputVector := vectors[0]
-	resultType := types.Type{Oid: types.T_varchar, Size: 24}
+	resultType := types.Type{Oid: types.T_decimal128, Size: 16}
 	resultElementSize := int(resultType.Size)
 	inputValues := vector.MustTCols[T](inputVector)
 	if inputVector.IsScalar() {
@@ -35,32 +35,33 @@ func Oct[T constraints.Unsigned | constraints.Signed](vectors []*vector.Vector,
 			return proc.AllocScalarNullVector(resultType), nil
 		}
 		resultVector := vector.NewConst(resultType, 1)
-		resultValues := &types.Bytes{
-			Data:    []byte{},
-			Offsets: make([]uint32, 1),
-			Lengths: make([]uint32, 1),
+		resultValues := make([]types.Decimal128, 1)
+		col, err := oct.Oct(inputValues, resultValues)
+		if err != nil {
+			return nil, err
 		}
-		vector.SetCol(resultVector, oct.Oct(inputValues, resultValues))
+		vector.SetCol(resultVector, col)
 		return resultVector, nil
 	} else {
 		resultVector, err := proc.AllocVector(resultType, int64(resultElementSize*len(inputValues)))
 		if err != nil {
 			return nil, err
 		}
-		resultValues := &types.Bytes{
-			Data:    []byte{},
-			Offsets: make([]uint32, len(inputValues)),
-			Lengths: make([]uint32, len(inputValues)),
-		}
+		resultValues := types.DecodeDecimal128Slice(resultVector.Data)
+		resultValues = resultValues[:len(inputValues)]
 		nulls.Set(resultVector.Nsp, inputVector.Nsp)
-		vector.SetCol(resultVector, oct.Oct(inputValues, resultValues))
+		col, err := oct.Oct(inputValues, resultValues)
+		if err != nil {
+			return nil, err
+		}
+		vector.SetCol(resultVector, col)
 		return resultVector, nil
 	}
 }
 
 func OctFloat[T constraints.Float](vectors []*vector.Vector, proc *process.Process) (*vector.Vector, error) {
 	inputVector := vectors[0]
-	resultType := types.Type{Oid: types.T_varchar, Size: 24}
+	resultType := types.Type{Oid: types.T_decimal128, Size: 16}
 	resultElementSize := int(resultType.Size)
 	inputValues := vector.MustTCols[T](inputVector)
 	if inputVector.IsScalar() {
@@ -68,11 +69,7 @@ func OctFloat[T constraints.Float](vectors []*vector.Vector, proc *process.Proce
 			return proc.AllocScalarNullVector(resultType), nil
 		}
 		resultVector := vector.NewConst(resultType, 1)
-		resultValues := &types.Bytes{
-			Data:    []byte{},
-			Offsets: make([]uint32, 1),
-			Lengths: make([]uint32, 1),
-		}
+		resultValues := make([]types.Decimal128, 1)
 		col, err := oct.OctFloat(inputValues, resultValues)
 		if err != nil {
 			return nil, fmt.Errorf("the input value is out of integer range")
@@ -84,11 +81,8 @@ func OctFloat[T constraints.Float](vectors []*vector.Vector, proc *process.Proce
 		if err != nil {
 			return nil, err
 		}
-		resultValues := &types.Bytes{
-			Data:    []byte{},
-			Offsets: make([]uint32, len(inputValues)),
-			Lengths: make([]uint32, len(inputValues)),
-		}
+		resultValues := types.DecodeDecimal128Slice(resultVector.Data)
+		resultValues = resultValues[:len(inputValues)]
 		nulls.Set(resultVector.Nsp, inputVector.Nsp)
 		col, err := oct.OctFloat(inputValues, resultValues)
 		if err != nil {
diff --git a/pkg/sql/plan/function/builtin/unary/oct_test.go b/pkg/sql/plan/function/builtin/unary/oct_test.go
index e05b59544..bd5b9fec2 100644
--- a/pkg/sql/plan/function/builtin/unary/oct_test.go
+++ b/pkg/sql/plan/function/builtin/unary/oct_test.go
@@ -27,11 +27,11 @@ func TestOctUint8(t *testing.T) {
 	procs := testutil.NewProc()
 	vecs := make([]*vector.Vector, 1)
 	vecs[0] = testutil.MakeUint8Vector([]uint8{12, 99, 100, 255}, nil)
-	expected := &types.Bytes{
-		Data:    []byte("14143144377"),
-		Lengths: []uint32{2, 3, 3, 3},
-		Offsets: []uint32{0, 2, 5, 8},
-	}
+	e1, _ := types.Decimal128_FromStringWithScale("14", 0)
+	e2, _ := types.Decimal128_FromStringWithScale("143", 0)
+	e3, _ := types.Decimal128_FromStringWithScale("144", 0)
+	e4, _ := types.Decimal128_FromStringWithScale("377", 0)
+	expected := []types.Decimal128{e1, e2, e3, e4}
 
 	t.Run("oct uin8 test", func(t *testing.T) {
 		result, err := Oct[uint8](vecs, procs)
@@ -47,11 +47,14 @@ func TestOctUint16(t *testing.T) {
 	procs := testutil.NewProc()
 	vecs := make([]*vector.Vector, 1)
 	vecs[0] = testutil.MakeUint16Vector([]uint16{12, 99, 100, 255, 1024, 10000, 65535}, nil)
-	expected := &types.Bytes{
-		Data:    []byte("14143144377200023420177777"),
-		Lengths: []uint32{2, 3, 3, 3, 4, 5, 6},
-		Offsets: []uint32{0, 2, 5, 8, 11, 15, 20},
-	}
+	e1, _ := types.Decimal128_FromStringWithScale("14", 0)
+	e2, _ := types.Decimal128_FromStringWithScale("143", 0)
+	e3, _ := types.Decimal128_FromStringWithScale("144", 0)
+	e4, _ := types.Decimal128_FromStringWithScale("377", 0)
+	e5, _ := types.Decimal128_FromStringWithScale("2000", 0)
+	e6, _ := types.Decimal128_FromStringWithScale("23420", 0)
+	e7, _ := types.Decimal128_FromStringWithScale("177777", 0)
+	expected := []types.Decimal128{e1, e2, e3, e4, e5, e6, e7}
 
 	t.Run("oct uin16 test", func(t *testing.T) {
 		result, err := Oct[uint16](vecs, procs)
@@ -65,11 +68,15 @@ func TestOctUint16(t *testing.T) {
 func TestOctUint32(t *testing.T) {
 	procs := testutil.NewProc()
 	vecs := []*vector.Vector{testutil.MakeUint32Vector([]uint32{12, 99, 100, 255, 1024, 10000, 65535, 4294967295}, nil)}
-	expected := &types.Bytes{
-		Data:    []byte("1414314437720002342017777737777777777"),
-		Lengths: []uint32{2, 3, 3, 3, 4, 5, 6, 11},
-		Offsets: []uint32{0, 2, 5, 8, 11, 15, 20, 26},
-	}
+	e1, _ := types.Decimal128_FromStringWithScale("14", 0)
+	e2, _ := types.Decimal128_FromStringWithScale("143", 0)
+	e3, _ := types.Decimal128_FromStringWithScale("144", 0)
+	e4, _ := types.Decimal128_FromStringWithScale("377", 0)
+	e5, _ := types.Decimal128_FromStringWithScale("2000", 0)
+	e6, _ := types.Decimal128_FromStringWithScale("23420", 0)
+	e7, _ := types.Decimal128_FromStringWithScale("177777", 0)
+	e8, _ := types.Decimal128_FromStringWithScale("37777777777", 0)
+	expected := []types.Decimal128{e1, e2, e3, e4, e5, e6, e7, e8}
 
 	t.Run("oct uin32 test", func(t *testing.T) {
 		result, err := Oct[uint32](vecs, procs)
@@ -84,11 +91,16 @@ func TestOctUint32(t *testing.T) {
 func TestOctUint64(t *testing.T) {
 	procs := testutil.NewProc()
 	vecs := []*vector.Vector{testutil.MakeUint64Vector([]uint64{12, 99, 100, 255, 1024, 10000, 65535, 4294967295, 18446744073709551615}, nil)}
-	expected := &types.Bytes{
-		Data:    []byte("14143144377200023420177777377777777771777777777777777777777"),
-		Lengths: []uint32{2, 3, 3, 3, 4, 5, 6, 11, 22},
-		Offsets: []uint32{0, 2, 5, 8, 11, 15, 20, 26, 37},
-	}
+	e1, _ := types.Decimal128_FromStringWithScale("14", 0)
+	e2, _ := types.Decimal128_FromStringWithScale("143", 0)
+	e3, _ := types.Decimal128_FromStringWithScale("144", 0)
+	e4, _ := types.Decimal128_FromStringWithScale("377", 0)
+	e5, _ := types.Decimal128_FromStringWithScale("2000", 0)
+	e6, _ := types.Decimal128_FromStringWithScale("23420", 0)
+	e7, _ := types.Decimal128_FromStringWithScale("177777", 0)
+	e8, _ := types.Decimal128_FromStringWithScale("37777777777", 0)
+	e9, _ := types.Decimal128_FromStringWithScale("1777777777777777777777", 0)
+	expected := []types.Decimal128{e1, e2, e3, e4, e5, e6, e7, e8, e9}
 
 	t.Run("oct uin64 test", func(t *testing.T) {
 		result, err := Oct[uint64](vecs, procs)
@@ -102,11 +114,10 @@ func TestOctUint64(t *testing.T) {
 func TestOctInt8(t *testing.T) {
 	procs := testutil.NewProc()
 	vecs := []*vector.Vector{testutil.MakeInt8Vector([]int8{-128, -1, 127}, nil)}
-	expected := &types.Bytes{
-		Data:    []byte("17777777777777777776001777777777777777777777177"),
-		Lengths: []uint32{22, 22, 3},
-		Offsets: []uint32{0, 22, 44},
-	}
+	e1, _ := types.Decimal128_FromStringWithScale("1777777777777777777600", 0)
+	e2, _ := types.Decimal128_FromStringWithScale("1777777777777777777777", 0)
+	e3, _ := types.Decimal128_FromStringWithScale("177", 0)
+	expected := []types.Decimal128{e1, e2, e3}
 
 	t.Run("oct int8 test", func(t *testing.T) {
 		result, err := Oct[int8](vecs, procs)
@@ -120,11 +131,8 @@ func TestOctInt8(t *testing.T) {
 func TestOctInt16(t *testing.T) {
 	procs := testutil.NewProc()
 	vecs := []*vector.Vector{testutil.MakeInt16Vector([]int16{-32768}, nil)}
-	expected := &types.Bytes{
-		Data:    []byte("1777777777777777700000"),
-		Lengths: []uint32{22},
-		Offsets: []uint32{0},
-	}
+	e1, _ := types.Decimal128_FromStringWithScale("1777777777777777700000", 0)
+	expected := []types.Decimal128{e1}
 
 	t.Run("oct int16 test", func(t *testing.T) {
 		result, err := Oct[int16](vecs, procs)
@@ -138,11 +146,8 @@ func TestOctInt16(t *testing.T) {
 func TestOctInt32(t *testing.T) {
 	procs := testutil.NewProc()
 	vecs := []*vector.Vector{testutil.MakeInt32Vector([]int32{-2147483648}, nil)}
-	expected := &types.Bytes{
-		Data:    []byte("1777777777760000000000"),
-		Lengths: []uint32{22},
-		Offsets: []uint32{0},
-	}
+	e1, _ := types.Decimal128_FromStringWithScale("1777777777760000000000", 0)
+	expected := []types.Decimal128{e1}
 
 	t.Run("oct int32 test", func(t *testing.T) {
 		result, err := Oct[int32](vecs, procs)
@@ -156,11 +161,8 @@ func TestOctInt32(t *testing.T) {
 func TestOctInt64(t *testing.T) {
 	procs := testutil.NewProc()
 	vecs := []*vector.Vector{testutil.MakeInt64Vector([]int64{-9223372036854775808}, nil)}
-	expected := &types.Bytes{
-		Data:    []byte("1000000000000000000000"),
-		Lengths: []uint32{22},
-		Offsets: []uint32{0},
-	}
+	e1, _ := types.Decimal128_FromStringWithScale("1000000000000000000000", 0)
+	expected := []types.Decimal128{e1}
 
 	t.Run("oct int64 test", func(t *testing.T) {
 		result, err := Oct[int64](vecs, procs)
@@ -175,11 +177,8 @@ func TestOctScalar(t *testing.T) {
 	procs := testutil.NewProc()
 	vecs := []*vector.Vector{testutil.MakeInt64Vector([]int64{-9223372036854775808}, nil)}
 	vecs[0].IsConst = true
-	expected := &types.Bytes{
-		Data:    []byte("1000000000000000000000"),
-		Lengths: []uint32{22},
-		Offsets: []uint32{0},
-	}
+	e1, _ := types.Decimal128_FromStringWithScale("1000000000000000000000", 0)
+	expected := []types.Decimal128{e1}
 
 	t.Run("oct scalar test", func(t *testing.T) {
 		result, err := Oct[int64](vecs, procs)
@@ -190,8 +189,8 @@ func TestOctScalar(t *testing.T) {
 	})
 }
 
-func checkOctResult(t *testing.T, result *vector.Vector, expected *types.Bytes, isScalar bool) {
-	col := result.Col.(*types.Bytes)
+func checkOctResult(t *testing.T, result *vector.Vector, expected []types.Decimal128, isScalar bool) {
+	col := result.Col.([]types.Decimal128)
 
 	require.Equal(t, expected, col)
 	require.Equal(t, isScalar, result.IsScalar())
diff --git a/pkg/sql/plan/function/builtins.go b/pkg/sql/plan/function/builtins.go
index 55610eec3..4336fb5d6 100644
--- a/pkg/sql/plan/function/builtins.go
+++ b/pkg/sql/plan/function/builtins.go
@@ -430,7 +430,7 @@ var builtins = map[int]Functions{
 				Flag:      plan.Function_STRICT,
 				Layout:    STANDARD_FUNCTION,
 				Args:      []types.T{types.T_uint8},
-				ReturnTyp: types.T_varchar,
+				ReturnTyp: types.T_decimal128,
 				Fn:        unary.Oct[uint8],
 			},
 			{
@@ -438,7 +438,7 @@ var builtins = map[int]Functions{
 				Flag:      plan.Function_STRICT,
 				Layout:    STANDARD_FUNCTION,
 				Args:      []types.T{types.T_uint16},
-				ReturnTyp: types.T_varchar,
+				ReturnTyp: types.T_decimal128,
 				Fn:        unary.Oct[uint16],
 			},
 			{
@@ -446,7 +446,7 @@ var builtins = map[int]Functions{
 				Flag:      plan.Function_STRICT,
 				Layout:    STANDARD_FUNCTION,
 				Args:      []types.T{types.T_uint32},
-				ReturnTyp: types.T_varchar,
+				ReturnTyp: types.T_decimal128,
 				Fn:        unary.Oct[uint32],
 			},
 			{
@@ -454,7 +454,7 @@ var builtins = map[int]Functions{
 				Flag:      plan.Function_STRICT,
 				Layout:    STANDARD_FUNCTION,
 				Args:      []types.T{types.T_uint64},
-				ReturnTyp: types.T_varchar,
+				ReturnTyp: types.T_decimal128,
 				Fn:        unary.Oct[uint64],
 			},
 			{
@@ -462,7 +462,7 @@ var builtins = map[int]Functions{
 				Flag:      plan.Function_STRICT,
 				Layout:    STANDARD_FUNCTION,
 				Args:      []types.T{types.T_int8},
-				ReturnTyp: types.T_varchar,
+				ReturnTyp: types.T_decimal128,
 				Fn:        unary.Oct[int8],
 			},
 			{
@@ -470,7 +470,7 @@ var builtins = map[int]Functions{
 				Flag:      plan.Function_STRICT,
 				Layout:    STANDARD_FUNCTION,
 				Args:      []types.T{types.T_int16},
-				ReturnTyp: types.T_varchar,
+				ReturnTyp: types.T_decimal128,
 				Fn:        unary.Oct[int16],
 			},
 			{
@@ -478,7 +478,7 @@ var builtins = map[int]Functions{
 				Flag:      plan.Function_STRICT,
 				Layout:    STANDARD_FUNCTION,
 				Args:      []types.T{types.T_int32},
-				ReturnTyp: types.T_varchar,
+				ReturnTyp: types.T_decimal128,
 				Fn:        unary.Oct[int32],
 			},
 			{
@@ -486,7 +486,7 @@ var builtins = map[int]Functions{
 				Flag:      plan.Function_STRICT,
 				Layout:    STANDARD_FUNCTION,
 				Args:      []types.T{types.T_int64},
-				ReturnTyp: types.T_varchar,
+				ReturnTyp: types.T_decimal128,
 				Fn:        unary.Oct[int64],
 			},
 			{
@@ -494,7 +494,7 @@ var builtins = map[int]Functions{
 				Flag:      plan.Function_STRICT,
 				Layout:    STANDARD_FUNCTION,
 				Args:      []types.T{types.T_float32},
-				ReturnTyp: types.T_varchar,
+				ReturnTyp: types.T_decimal128,
 				Fn:        unary.OctFloat[float32],
 			},
 			{
@@ -502,7 +502,7 @@ var builtins = map[int]Functions{
 				Flag:      plan.Function_STRICT,
 				Layout:    STANDARD_FUNCTION,
 				Args:      []types.T{types.T_float64},
-				ReturnTyp: types.T_varchar,
+				ReturnTyp: types.T_decimal128,
 				Fn:        unary.OctFloat[float64],
 			},
 		},
diff --git a/pkg/sql/plan/function/operator/cast.go b/pkg/sql/plan/function/operator/cast.go
index e91bc5866..23ebe10b9 100644
--- a/pkg/sql/plan/function/operator/cast.go
+++ b/pkg/sql/plan/function/operator/cast.go
@@ -369,7 +369,7 @@ func doCast(vs []*vector.Vector, proc *process.Process) (*vector.Vector, error)
 		}
 	}
 
-	if isString(lv.Typ.Oid) && isDecimal(rv.Typ.Oid) {
+	if isString(lv.Typ.Oid) && IsDecimal(rv.Typ.Oid) {
 		switch rv.Typ.Oid {
 		case types.T_decimal64:
 			return CastStringAsDecimal64(lv, rv, proc)
@@ -407,7 +407,7 @@ func doCast(vs []*vector.Vector, proc *process.Process) (*vector.Vector, error)
 			return CastSpecials2Float[float64](lv, rv, proc)
 		}
 	}
-	if isDecimal(lv.Typ.Oid) && isString(rv.Typ.Oid) {
+	if IsDecimal(lv.Typ.Oid) && isString(rv.Typ.Oid) {
 		switch lv.Typ.Oid {
 		case types.T_decimal64:
 			return CastDecimal64ToString(lv, rv, proc)
@@ -559,7 +559,7 @@ func doCast(vs []*vector.Vector, proc *process.Process) (*vector.Vector, error)
 		}
 	}
 
-	if isDecimal(lv.Typ.Oid) && rv.Typ.Oid == types.T_timestamp {
+	if IsDecimal(lv.Typ.Oid) && rv.Typ.Oid == types.T_timestamp {
 		switch lv.Typ.Oid {
 		case types.T_decimal64:
 			return CastDecimal64AsTimestamp(lv, rv, proc)
@@ -2482,8 +2482,8 @@ func isDateSeries(t types.T) bool {
 	return false
 }
 
-// isDecimal: return true if the types.T is decimal64 or decimal128
-func isDecimal(t types.T) bool {
+// IsDecimal: return true if the types.T is decimal64 or decimal128
+func IsDecimal(t types.T) bool {
 	if t == types.T_decimal64 || t == types.T_decimal128 {
 		return true
 	}
diff --git a/pkg/vectorize/oct/oct.go b/pkg/vectorize/oct/oct.go
index 3173dd23c..9bb456d3e 100644
--- a/pkg/vectorize/oct/oct.go
+++ b/pkg/vectorize/oct/oct.go
@@ -16,21 +16,21 @@ package oct
 
 import (
 	"fmt"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
 	"strconv"
 
-	"github.com/matrixorigin/matrixone/pkg/container/types"
 	"golang.org/x/exp/constraints"
 )
 
 var (
-	OctUint8  func([]uint8, *types.Bytes) *types.Bytes
-	OctUint16 func([]uint16, *types.Bytes) *types.Bytes
-	OctUint32 func([]uint32, *types.Bytes) *types.Bytes
-	OctUint64 func([]uint64, *types.Bytes) *types.Bytes
-	OctInt8   func([]int8, *types.Bytes) *types.Bytes
-	OctInt16  func([]int16, *types.Bytes) *types.Bytes
-	OctInt32  func([]int32, *types.Bytes) *types.Bytes
-	OctInt64  func([]int64, *types.Bytes) *types.Bytes
+	OctUint8  func([]uint8, []types.Decimal128) ([]types.Decimal128, error)
+	OctUint16 func([]uint16, []types.Decimal128) ([]types.Decimal128, error)
+	OctUint32 func([]uint32, []types.Decimal128) ([]types.Decimal128, error)
+	OctUint64 func([]uint64, []types.Decimal128) ([]types.Decimal128, error)
+	OctInt8   func([]int8, []types.Decimal128) ([]types.Decimal128, error)
+	OctInt16  func([]int16, []types.Decimal128) ([]types.Decimal128, error)
+	OctInt32  func([]int32, []types.Decimal128) ([]types.Decimal128, error)
+	OctInt64  func([]int64, []types.Decimal128) ([]types.Decimal128, error)
 )
 
 func init() {
@@ -44,62 +44,44 @@ func init() {
 	OctInt64 = Oct[int64]
 }
 
-func Oct[T constraints.Unsigned | constraints.Signed](xs []T, rs *types.Bytes) *types.Bytes {
-	var cursor uint32
-
+func Oct[T constraints.Unsigned | constraints.Signed](xs []T, rs []types.Decimal128) ([]types.Decimal128, error) {
 	for idx := range xs {
-		octbytes := uint64ToOctonary(uint64(xs[idx]))
-		for i := range octbytes {
-			rs.Data = append(rs.Data, octbytes[i])
+		res, err := oct(uint64(xs[idx]))
+		if err != nil {
+			return nil, err
 		}
-		rs.Offsets[idx] = cursor
-		rs.Lengths[idx] = uint32(len(octbytes))
-		cursor += uint32(len(octbytes))
+		rs[idx] = res
 	}
-
-	return rs
+	return rs, nil
 }
 
-func OctFloat[T constraints.Float](xs []T, rs *types.Bytes) (*types.Bytes, error) {
-	var cursor uint32
-
-	var octbytes []byte
+func OctFloat[T constraints.Float](xs []T, rs []types.Decimal128) ([]types.Decimal128, error) {
+	var res types.Decimal128
 	for idx := range xs {
 		if xs[idx] < 0 {
 			val, err := strconv.ParseInt(fmt.Sprintf("%1.0f", xs[idx]), 10, 64)
 			if err != nil {
 				return nil, err
 			}
-			octbytes = uint64ToOctonary(uint64(val))
+			res, err = oct(uint64(val))
+			if err != nil {
+				return nil, err
+			}
 		} else {
 			val, err := strconv.ParseUint(fmt.Sprintf("%1.0f", xs[idx]), 10, 64)
 			if err != nil {
 				return nil, err
 			}
-			octbytes = uint64ToOctonary(val)
-		}
-
-		for i := range octbytes {
-			rs.Data = append(rs.Data, octbytes[i])
+			res, err = oct(val)
+			if err != nil {
+				return nil, err
+			}
 		}
-		rs.Offsets[idx] = cursor
-		rs.Lengths[idx] = uint32(len(octbytes))
-		cursor += uint32(len(octbytes))
+		rs[idx] = res
 	}
 	return rs, nil
 }
 
-func uint64ToOctonary(x uint64) []byte {
-	var a [21 + 1]byte // 64bit value in base 8 [64/3+(64%3!=0)]
-	i := len(a)
-	// Use shifts and masks instead of / and %.
-	for x >= 8 {
-		i--
-		a[i] = byte(x&7 + '0')
-		x >>= 3
-	}
-	// x < 8
-	i--
-	a[i] = byte(x + '0')
-	return a[i:]
+func oct(val uint64) (types.Decimal128, error) {
+	return types.Decimal128_FromStringWithScale(fmt.Sprintf("%o", val), 0)
 }
diff --git a/pkg/vectorize/oct/oct_test.go b/pkg/vectorize/oct/oct_test.go
deleted file mode 100644
index 9798e282a..000000000
--- a/pkg/vectorize/oct/oct_test.go
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright 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 oct
-
-import (
-	"testing"
-
-	"github.com/matrixorigin/matrixone/pkg/container/types"
-	"github.com/stretchr/testify/require"
-)
-
-func TestOctUint8(t *testing.T) {
-	args := []uint8{12, 99, 100, 255}
-	want := &types.Bytes{
-		Data:    []byte("14143144377"),
-		Lengths: []uint32{2, 3, 3, 3},
-		Offsets: []uint32{0, 2, 5, 8},
-	}
-
-	out := &types.Bytes{
-		Data:    []byte{},
-		Lengths: make([]uint32, len(args)),
-		Offsets: make([]uint32, len(args)),
-	}
-	out = OctUint8(args, out)
-	require.Equal(t, want, out)
-}
-
-func TestOctUint16(t *testing.T) {
-	args := []uint16{12, 99, 100, 255, 1024, 10000, 65535}
-	want := &types.Bytes{
-		Data:    []byte("14143144377200023420177777"),
-		Lengths: []uint32{2, 3, 3, 3, 4, 5, 6},
-		Offsets: []uint32{0, 2, 5, 8, 11, 15, 20},
-	}
-
-	out := &types.Bytes{
-		Data:    []byte{},
-		Lengths: make([]uint32, len(args)),
-		Offsets: make([]uint32, len(args)),
-	}
-	out = OctUint16(args, out)
-	require.Equal(t, want, out)
-}
-
-func TestOctUint32(t *testing.T) {
-	args := []uint32{12, 99, 100, 255, 1024, 10000, 65535, 4294967295}
-	want := &types.Bytes{
-		Data:    []byte("1414314437720002342017777737777777777"),
-		Lengths: []uint32{2, 3, 3, 3, 4, 5, 6, 11},
-		Offsets: []uint32{0, 2, 5, 8, 11, 15, 20, 26},
-	}
-
-	out := &types.Bytes{
-		Data:    []byte{},
-		Lengths: make([]uint32, len(args)),
-		Offsets: make([]uint32, len(args)),
-	}
-	out = OctUint32(args, out)
-	require.Equal(t, want, out)
-}
-
-func TestOctUint64(t *testing.T) {
-	args := []uint64{12, 99, 100, 255, 1024, 10000, 65535, 4294967295, 18446744073709551615}
-	want := &types.Bytes{
-		Data:    []byte("14143144377200023420177777377777777771777777777777777777777"),
-		Lengths: []uint32{2, 3, 3, 3, 4, 5, 6, 11, 22},
-		Offsets: []uint32{0, 2, 5, 8, 11, 15, 20, 26, 37},
-	}
-
-	out := &types.Bytes{
-		Data:    []byte{},
-		Lengths: make([]uint32, len(args)),
-		Offsets: make([]uint32, len(args)),
-	}
-	out = OctUint64(args, out)
-	require.Equal(t, want, out)
-}
-
-func TestOctInt8(t *testing.T) {
-	args := []int8{-128, -1, 127}
-	want := &types.Bytes{
-		Data:    []byte("17777777777777777776001777777777777777777777177"),
-		Lengths: []uint32{22, 22, 3},
-		Offsets: []uint32{0, 22, 44},
-	}
-
-	out := &types.Bytes{
-		Data:    []byte{},
-		Lengths: make([]uint32, len(args)),
-		Offsets: make([]uint32, len(args)),
-	}
-	out = OctInt8(args, out)
-	require.Equal(t, want, out)
-}
-
-func TestOctInt16(t *testing.T) {
-	args := []int16{-32768}
-	want := &types.Bytes{
-		Data:    []byte("1777777777777777700000"),
-		Lengths: []uint32{22},
-		Offsets: []uint32{0},
-	}
-
-	out := &types.Bytes{
-		Data:    []byte{},
-		Lengths: make([]uint32, len(args)),
-		Offsets: make([]uint32, len(args)),
-	}
-	out = OctInt16(args, out)
-	require.Equal(t, want, out)
-}
-
-func TestOctInt32(t *testing.T) {
-	args := []int32{-2147483648}
-	want := &types.Bytes{
-		Data:    []byte("1777777777760000000000"),
-		Lengths: []uint32{22},
-		Offsets: []uint32{0},
-	}
-
-	out := &types.Bytes{
-		Data:    []byte{},
-		Lengths: make([]uint32, len(args)),
-		Offsets: make([]uint32, len(args)),
-	}
-	out = OctInt32(args, out)
-	require.Equal(t, want, out)
-}
-
-func TestOctInt64(t *testing.T) {
-	args := []int64{-9223372036854775808}
-	want := &types.Bytes{
-		Data:    []byte("1000000000000000000000"),
-		Lengths: []uint32{22},
-		Offsets: []uint32{0},
-	}
-
-	out := &types.Bytes{
-		Data:    []byte{},
-		Lengths: make([]uint32, len(args)),
-		Offsets: make([]uint32, len(args)),
-	}
-	out = OctInt64(args, out)
-	require.Equal(t, want, out)
-}
diff --git a/test/cases/function/func_string_concat_ws.test b/test/cases/function/func_string_concat_ws.test
index ec623e0d2..bf5aec67b 100644
--- a/test/cases/function/func_string_concat_ws.test
+++ b/test/cases/function/func_string_concat_ws.test
@@ -75,7 +75,7 @@ drop table t1;
 
 #WHERE锛� EXTREME VALUES锛屽祵濂�
 #SET timestamp=UNIX_TIMESTAMP('2011-07-31 10:00:00');
--- @bvt:issue#3716
+-- @bvt:issue#4573
 CREATE TABLE t1 (
 col_datetime_2_not_null_key datetime(2) NOT NULL,
 col_datetime_5 datetime(5) DEFAULT NULL,
diff --git a/test/cases/function/func_string_oct.test b/test/cases/function/func_string_oct.test
index f6a28d2f9..3b108af0a 100644
--- a/test/cases/function/func_string_oct.test
+++ b/test/cases/function/func_string_oct.test
@@ -61,13 +61,11 @@ HAVING oct(a) <>0;
 DROP TABLE t1;
 
 #WHERE, 绠楁湳杩愮畻
--- @bvt:issue#3716
 drop table if exists t1;
 create table t1(a INT,  b int);
 insert into t1 values(1, 2),(2, 3),(3, 4),(4, 5);
 select oct(a)+oct(b) from t1 where oct(a)+oct(b)<>0;
 drop table t1;
--- @bvt:issue
 
 #ON CONDITION
 CREATE TABLE t1 (a int);
diff --git a/test/cases/function/func_string_reverse.test b/test/cases/function/func_string_reverse.test
index def9c7995..f82adce6d 100644
--- a/test/cases/function/func_string_reverse.test
+++ b/test/cases/function/func_string_reverse.test
@@ -98,9 +98,7 @@ drop table t2;
 #EXTREME VALUE
 SELECT REVERSE("@($)@($#)_@(#");
 
--- @bvt:issue#3716
 SELECT REVERSE(space(500)+space(600));
--- @bvt:issue
 
 #DATA TYPES
 SELECT REVERSE(123124);
diff --git a/test/cases/function/func_string_rtrim_ltrim.test b/test/cases/function/func_string_rtrim_ltrim.test
index fe5a8c54e..43838b275 100644
--- a/test/cases/function/func_string_rtrim_ltrim.test
+++ b/test/cases/function/func_string_rtrim_ltrim.test
@@ -166,10 +166,8 @@ drop table t1;
 drop table t2;
 
 #EXTREME VALUE
--- @bvt:issue#3716
 SELECT RTRIM(space(100000000)+"123");
 SELECT LTRIM("123"+space(100000000));
--- @bvt:issue
 SELECT LTRIM("    1241241^&@%#^*^!@#&*(!&");
 SELECT RTRIM("1241241^&@%#^*^!@#&*(!&    ");
 
diff --git a/test/cases/function/func_string_space.test b/test/cases/function/func_string_space.test
index 934ea561d..78a6be5cb 100644
--- a/test/cases/function/func_string_space.test
+++ b/test/cases/function/func_string_space.test
@@ -5,9 +5,7 @@ create table t1 (
 name varchar(10),
 level smallint unsigned);
 insert into t1 values ('string',1);
--- @bvt:issue#3716
 select reverse("123"+space(level)+"456") from t1;
--- @bvt:issue
 select concat_ws("abc", name,space(level)), concat_ws("abc",name, space(level)) from t1;
 drop table t1;
 
@@ -48,12 +46,10 @@ SELECT length(space(9223372036854775809));
 SELECT SPACE(NULL);
 
 #DATE TYPE
--- @bvt:issue#3716
 SELECT SPACE(12)+"123";
 SELECT SPACE(12314.14123)+"123";
 SELECT SPACE("1231")+"123";
 SELECT SPACE("2012-03-12")+"123";
--- @bvt:issue
 
 #EXTREME VALUE, 宓屽
 CREATE TABLE t(i BIGINT UNSIGNED);
@@ -90,6 +86,4 @@ drop table t1;
 drop table t2;
 
 #涓枃
--- @bvt:issue#3716
 SELECT space("浣犲ソ")+"浣犲ソ";
--- @bvt:issue
diff --git a/test/cases/function/func_string_substring.test b/test/cases/function/func_string_substring.test
index d860c8df0..783fb81fb 100644
--- a/test/cases/function/func_string_substring.test
+++ b/test/cases/function/func_string_substring.test
@@ -157,13 +157,11 @@ select * from t1 where substring(b,1,1) = 'a';
 drop table t1;
 
 #HAVING & 閫昏緫杩愮畻
--- @bvt:issue#3716
 drop table if exists t1;
 create table t1(b varchar(5));
 insert into t1 values('ab'), ('abc'), ('abcd'), ('abcde');
 select b from t1 group by b having substring(b,1,1)+'a'='aa';
 drop table t1;
--- @bvt:issue
 
 #ON CONDITION
 drop table if exists t1;
diff --git a/test/result/function/func_string_oct.result b/test/result/function/func_string_oct.result
index 4f89e5e39..bc990a8c1 100644
--- a/test/result/function/func_string_oct.result
+++ b/test/result/function/func_string_oct.result
@@ -70,7 +70,11 @@ drop table if exists t1;
 create table t1(a INT,  b int);
 insert into t1 values(1, 2),(2, 3),(3, 4),(4, 5);
 select oct(a)+oct(b) from t1 where oct(a)+oct(b)<>0;
-Operator '+' with parameters [VARCHAR VARCHAR] will be implemented in future version.
+oct(a) + oct(b)
+3
+5
+7
+9
 drop table t1;
 CREATE TABLE t1 (a int);
 CREATE TABLE t2 (a int);
diff --git a/test/result/function/func_string_rtrim_ltrim.result b/test/result/function/func_string_rtrim_ltrim.result
index a05fbbcf2..7935cefef 100644
--- a/test/result/function/func_string_rtrim_ltrim.result
+++ b/test/result/function/func_string_rtrim_ltrim.result
@@ -249,9 +249,9 @@ a	a
 drop table t1;
 drop table t2;
 SELECT RTRIM(space(100000000)+"123");
-Operator '+' with parameters [VARCHAR VARCHAR] will be implemented in future version.
+the space count exceeds maxallowedCount 8000
 SELECT LTRIM("123"+space(100000000));
-Operator '+' with parameters [VARCHAR VARCHAR] will be implemented in future version.
+the space count exceeds maxallowedCount 8000
 SELECT LTRIM("    1241241^&@%#^*^!@#&*(!&");
 LTRIM("    1241241^&@%#^*^!@#&*(!&")
 1241241^&@%#^*^!@#&*(!&
diff --git a/test/result/function/func_string_space.result b/test/result/function/func_string_space.result
index adfd12ddc..fbe8c457c 100644
--- a/test/result/function/func_string_space.result
+++ b/test/result/function/func_string_space.result
@@ -4,7 +4,8 @@ name varchar(10),
 level smallint unsigned);
 insert into t1 values ('string',1);
 select reverse("123"+space(level)+"456") from t1;
-Operator '+' with parameters [VARCHAR VARCHAR] will be implemented in future version.
+reverse(123 + space(level) + 456)
+654 321
 select concat_ws("abc", name,space(level)), concat_ws("abc",name, space(level)) from t1;
 concat_ws("abc", name,space(level))	concat_ws("abc",name, space(level))
 stringabc 	stringabc
@@ -53,13 +54,16 @@ SELECT SPACE(NULL);
 SPACE(NULL)
 null
 SELECT SPACE(12)+"123";
-Operator '+' with parameters [VARCHAR VARCHAR] will be implemented in future version.
+space(12) + 123
+            123
 SELECT SPACE(12314.14123)+"123";
-Operator '+' with parameters [VARCHAR VARCHAR] will be implemented in future version.
+the space count exceeds maxallowedCount 8000
 SELECT SPACE("1231")+"123";
-Operator '+' with parameters [VARCHAR VARCHAR] will be implemented in future version.
+space(1231) + 123
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               123
+
 SELECT SPACE("2012-03-12")+"123";
-Operator '+' with parameters [VARCHAR VARCHAR] will be implemented in future version.
+Can't cast '2012-03-12' from VARCHAR type to BIGINT type.
 CREATE TABLE t(i BIGINT UNSIGNED);
 INSERT INTO t values(9223372036854775808);
 SELECT space(i) FROM t;
@@ -97,4 +101,4 @@ a	a
 drop table t1;
 drop table t2;
 SELECT space("浣犲ソ")+"浣犲ソ";
-Operator '+' with parameters [VARCHAR VARCHAR] will be implemented in future version.
+Can't cast '浣犲ソ' from VARCHAR type to BIGINT type.
diff --git a/test/result/function/func_string_substring.result b/test/result/function/func_string_substring.result
index 488576b70..e30395014 100644
--- a/test/result/function/func_string_substring.result
+++ b/test/result/function/func_string_substring.result
@@ -251,7 +251,11 @@ drop table if exists t1;
 create table t1(b varchar(5));
 insert into t1 values('ab'), ('abc'), ('abcd'), ('abcde');
 select b from t1 group by b having substring(b,1,1)+'a'='aa';
-Operator '+' with parameters [VARCHAR VARCHAR] will be implemented in future version.
+b
+ab
+abc
+abcd
+abcde
 drop table t1;
 drop table if exists t1;
 drop table if exists t2;
-- 
GitLab