diff --git a/pkg/sql/plan2/function/builtin/multi/substr_test.go b/pkg/sql/plan2/function/builtin/multi/substr_test.go new file mode 100644 index 0000000000000000000000000000000000000000..bd8997923b98eec7be54e18f69f26427da6bea81 --- /dev/null +++ b/pkg/sql/plan2/function/builtin/multi/substr_test.go @@ -0,0 +1,278 @@ +// 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 multi + +import ( + "github.com/matrixorigin/matrixone/pkg/container/nulls" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" + "github.com/matrixorigin/matrixone/pkg/vm/mheap" + "github.com/matrixorigin/matrixone/pkg/vm/mmu/guest" + "github.com/matrixorigin/matrixone/pkg/vm/mmu/host" + "github.com/matrixorigin/matrixone/pkg/vm/process" + "github.com/stretchr/testify/require" + "testing" +) + +func TestSubStr(t *testing.T) { + procs := makeProcess() + cases := []struct { + name string + vecs []*vector.Vector + proc *process.Process + wantBytes []byte + wantScalar bool + }{ + { + name: "TEST01", + vecs: makeSubStrVectors("abcdefghijklmn", 5, 0, false), + proc: procs, + wantBytes: []byte("efghijklmn"), + wantScalar: true, + }, + { + name: "TEST02", + vecs: makeSubStrVectors("abcdefghijklmn", 7, 0, false), + proc: procs, + wantBytes: []byte("ghijklmn"), + wantScalar: true, + }, + { + name: "TEST03", + vecs: makeSubStrVectors("abcdefghijklmn", 11, 0, false), + proc: procs, + wantBytes: []byte("klmn"), + wantScalar: true, + }, + { + name: "TEST04", + vecs: makeSubStrVectors("abcdefghijklmn", 16, 0, false), + proc: procs, + wantBytes: []byte(""), + wantScalar: true, + }, + { + name: "TEST05", + vecs: makeSubStrVectors("abcdefghijklmn", 5, 6, true), + proc: procs, + wantBytes: []byte("efghij"), + wantScalar: true, + }, + { + name: "TEST06", + vecs: makeSubStrVectors("abcdefghijklmn", 5, 10, true), + proc: procs, + wantBytes: []byte("efghijklmn"), + wantScalar: true, + }, + { + name: "TEST07", + vecs: makeSubStrVectors("abcdefghijklmn", 5, 0, true), + proc: procs, + wantBytes: []byte(""), + wantScalar: true, + }, + { + name: "TEST08", + vecs: makeSubStrVectors("abcdefghijklmn", 6, -8, true), + proc: procs, + wantBytes: []byte("f"), + wantScalar: true, + }, + { + name: "TEST09", + vecs: makeSubStrVectors("abcdefghijklmn", 6, -9, true), + proc: procs, + wantBytes: []byte(""), + wantScalar: true, + }, + { + name: "TEST09", + vecs: makeSubStrVectors("abcdefghijklmn", 6, -4, true), + proc: procs, + wantBytes: []byte("fghij"), + wantScalar: true, + }, + { + name: "TEST10", + vecs: makeSubStrVectors("abcdefghijklmn", 6, -1, true), + proc: procs, + wantBytes: []byte("fghijklm"), + wantScalar: true, + }, + { + name: "Test11", + vecs: makeSubStrVectors("abcdefghijklmn", -4, 0, false), + proc: procs, + wantBytes: []byte("klmn"), + wantScalar: true, + }, + { + name: "Test12", + vecs: makeSubStrVectors("abcdefghijklmn", -14, 0, false), + proc: procs, + wantBytes: []byte("abcdefghijklmn"), + wantScalar: true, + }, + { + name: "Test13", + vecs: makeSubStrVectors("abcdefghijklmn", -16, 0, false), + proc: procs, + wantBytes: []byte("abcdefghijklmn"), + wantScalar: true, + }, + { + name: "Test14", + vecs: makeSubStrVectors("abcdefghijklmn", -4, 3, true), + proc: procs, + wantBytes: []byte("klm"), + wantScalar: true, + }, + { + name: "Test15", + vecs: makeSubStrVectors("abcdefghijklmn", -14, 10, true), + proc: procs, + wantBytes: []byte("abcdefghij"), + wantScalar: true, + }, + { + name: "Test16", + vecs: makeSubStrVectors("abcdefghijklmn", -14, 15, true), + proc: procs, + wantBytes: []byte("abcdefghijklmn"), + wantScalar: true, + }, + { + name: "Test17", + vecs: makeSubStrVectors("abcdefghijklmn", -16, 10, true), + proc: procs, + wantBytes: []byte("abcdefgh"), + wantScalar: true, + }, + { + name: "Test18", + vecs: makeSubStrVectors("abcdefghijklmn", -16, 20, true), + proc: procs, + wantBytes: []byte("abcdefghijklmn"), + wantScalar: true, + }, + { + name: "Test19", + vecs: makeSubStrVectors("abcdefghijklmn", -16, 2, true), + proc: procs, + wantBytes: []byte(""), + wantScalar: true, + }, + { + name: "Test20", + vecs: makeSubStrVectors("abcdefghijklmn", -12, 2, true), + proc: procs, + wantBytes: []byte("cd"), + wantScalar: true, + }, + { + name: "Test21", + vecs: makeSubStrVectors("abcdefghijklmn", -12, 14, true), + proc: procs, + wantBytes: []byte("cdefghijklmn"), + wantScalar: true, + }, + { + name: "Test22", + vecs: makeSubStrVectors("abcdefghijklmn", -12, 0, true), + proc: procs, + wantBytes: []byte(""), + wantScalar: true, + }, + { + name: "Test23", + vecs: makeSubStrVectors("abcdefghijklmn", -6, -5, true), + proc: procs, + wantBytes: []byte("ijk"), + wantScalar: true, + }, + { + name: "Test24", + vecs: makeSubStrVectors("abcdefghijklmn", -6, -10, true), + proc: procs, + wantBytes: []byte(""), + wantScalar: true, + }, + { + name: "Test25", + vecs: makeSubStrVectors("abcdefghijklmn", -6, -1, true), + proc: procs, + wantBytes: []byte("ijklmn"), + wantScalar: true, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + substr, err := Substring(c.vecs, c.proc) + if err != nil { + t.Fatal(err) + } + col := substr.Col.(*types.Bytes) + offset := col.Offsets[0] + length := col.Lengths[0] + resBytes := col.Data[offset:length] + require.Equal(t, c.wantBytes, resBytes) + require.Equal(t, c.wantScalar, substr.IsScalar()) + }) + } +} + +func makeProcess() *process.Process { + hm := host.New(1 << 40) + gm := guest.New(1<<40, hm) + return process.New(mheap.New(gm)) +} + +// Construct vector parameter of substring function +func makeSubStrVectors(src string, start int64, length int64, withLength bool) []*vector.Vector { + vec := make([]*vector.Vector, 2) + srcBytes := &types.Bytes{ + Data: []byte(src), + Offsets: []uint32{0}, + Lengths: []uint32{uint32(len(src))}, + } + + vec[0] = &vector.Vector{ + Col: srcBytes, + Nsp: &nulls.Nulls{}, + Typ: types.Type{Oid: types.T_varchar, Size: 24}, + IsConst: true, + Length: 10, + } + + vec[1] = &vector.Vector{ + Col: []int64{start}, + Nsp: &nulls.Nulls{}, + Typ: types.Type{Oid: types.T_int64}, + IsConst: true, + Length: 10, + } + if withLength { + vec = append(vec, &vector.Vector{ + Col: []int64{length}, + Nsp: &nulls.Nulls{}, + Typ: types.Type{Oid: types.T_int64}, + IsConst: true, + Length: 10, + }) + } + return vec +} diff --git a/pkg/sql/plan2/function/operator/div.go b/pkg/sql/plan2/function/operator/div.go index 05e7cfe5244498804c1bff230c9c4c8ca8567fef..1fea53547b3d0b23129818abe32acf91e1dfdf67 100644 --- a/pkg/sql/plan2/function/operator/div.go +++ b/pkg/sql/plan2/function/operator/div.go @@ -181,7 +181,7 @@ func DivDecimal64(vectors []*vector.Vector, proc *process.Process) (*vector.Vect case lv.IsScalar() && !rv.IsScalar(): if !nulls.Any(rv.Nsp) { for _, v := range rvs { - if int64(v) != 0 { + if int64(v) == 0 { return nil, ErrDivByZero } } diff --git a/pkg/sql/plan2/function/operator/div_test.go b/pkg/sql/plan2/function/operator/div_test.go new file mode 100644 index 0000000000000000000000000000000000000000..f81f52be97b7f69a8237d8673589eab84f1bcf2c --- /dev/null +++ b/pkg/sql/plan2/function/operator/div_test.go @@ -0,0 +1,231 @@ +// 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 operator + +import ( + "github.com/matrixorigin/matrixone/pkg/container/nulls" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" + "github.com/matrixorigin/matrixone/pkg/vm/process" + "github.com/stretchr/testify/require" + "golang.org/x/exp/constraints" + "testing" +) + +func TestDiv(t *testing.T) { + divFloat[float32](t, types.T_float32, 235, 7.5, 31.333334) + divFloat[float64](t, types.T_float64, 235, 7.5, 31.333333333333332) + + leftType1 := types.Type{Oid: types.T_decimal64, Size: 8, Width: 10, Scale: 5} + rightType1 := types.Type{Oid: types.T_decimal64, Size: 8, Width: 10, Scale: 5} + resType1 := types.Type{Oid: types.T_decimal128, Size: 16, Width: 38, Scale: 5} + divDecimal64(t, 33333300, leftType1, -123450000, rightType1, types.Decimal128{Lo: -27001, Hi: -1}, resType1) + + leftType2 := types.Type{Oid: types.T_decimal128, Size: 16, Width: 20, Scale: 5} + rightType2 := types.Type{Oid: types.T_decimal128, Size: 16, Width: 20, Scale: 5} + resType2 := types.Type{Oid: types.T_decimal128, Size: 16, Width: 38, Scale: 5} + divDecimal128(t, types.Decimal128{Lo: 33333300, Hi: 0}, leftType2, types.Decimal128{Lo: -123450000, Hi: -1}, rightType2, + types.Decimal128{Lo: -27001, Hi: -1}, resType2) +} + +// Unit test input of int and float parameters of div operator +func divFloat[T constraints.Float](t *testing.T, typ types.T, left T, right T, res T) { + procs := makeProcess() + cases := []struct { + name string + vecs []*vector.Vector + proc *process.Process + wantBytes interface{} + wantScalar bool + }{ + { + name: "TEST01", + vecs: makeDivVectors[T](left, true, right, true, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: true, + }, + { + name: "TEST02", + vecs: makeDivVectors[T](left, false, right, true, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: false, + }, + { + name: "TEST03", + vecs: makeDivVectors[T](left, true, right, false, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: false, + }, + { + name: "TEST04", + vecs: makeDivVectors[T](left, false, right, false, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: false, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + plus, err := Div[T](c.vecs, c.proc) + if err != nil { + t.Fatal(err) + } + require.Equal(t, c.wantBytes, plus.Col, 0.000001) + require.Equal(t, c.wantScalar, plus.IsScalar()) + }) + } +} + +// Construct vector parameters of div operator +func makeDivVectors[T constraints.Float](left T, leftScalar bool, right T, rightScalar bool, t types.T) []*vector.Vector { + vectors := make([]*vector.Vector, 2) + vectors[0] = &vector.Vector{ + Col: []T{left}, + Nsp: &nulls.Nulls{}, + Typ: types.Type{Oid: t}, + IsConst: leftScalar, + Length: 1, + } + vectors[1] = &vector.Vector{ + Col: []T{right}, + Nsp: &nulls.Nulls{}, + Typ: types.Type{Oid: t}, + IsConst: rightScalar, + Length: 1, + } + return vectors +} + +// Decimal64 parameter unit test input of div operator +func divDecimal64(t *testing.T, left types.Decimal64, leftType types.Type, right types.Decimal64, rightType types.Type, + res types.Decimal128, restType types.Type) { + procs := makeProcess() + cases := []struct { + name string + vecs []*vector.Vector + proc *process.Process + wantBytes interface{} + wantType types.Type + wantScalar bool + }{ + { + name: "TEST01", + vecs: makeDecimal64Vectors(left, leftType, true, right, rightType, true), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: restType, + wantScalar: true, + }, + { + name: "TEST02", + vecs: makeDecimal64Vectors(left, leftType, false, right, rightType, true), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: restType, + wantScalar: false, + }, + { + name: "TEST03", + vecs: makeDecimal64Vectors(left, leftType, true, right, rightType, false), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: restType, + wantScalar: false, + }, + { + name: "TEST04", + vecs: makeDecimal64Vectors(left, leftType, false, right, rightType, false), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: restType, + wantScalar: false, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + decimalres, err := DivDecimal64(c.vecs, c.proc) + if err != nil { + t.Fatal(err) + } + require.Equal(t, c.wantBytes, decimalres.Col) + require.Equal(t, c.wantType, decimalres.Typ) + require.Equal(t, c.wantScalar, decimalres.IsScalar()) + }) + } +} + +// Decimal128 parameter unit test input of div operator +func divDecimal128(t *testing.T, left types.Decimal128, leftType types.Type, right types.Decimal128, rightType types.Type, + res types.Decimal128, restType types.Type) { + procs := makeProcess() + cases := []struct { + name string + vecs []*vector.Vector + proc *process.Process + wantBytes interface{} + wantType types.Type + wantScalar bool + }{ + { + name: "TEST01", + vecs: makeDecimal128Vectors(left, leftType, true, right, rightType, true), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: restType, + wantScalar: true, + }, + { + name: "TEST02", + vecs: makeDecimal128Vectors(left, leftType, false, right, rightType, true), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: restType, + wantScalar: false, + }, + { + name: "TEST03", + vecs: makeDecimal128Vectors(left, leftType, true, right, rightType, false), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: restType, + wantScalar: false, + }, + { + name: "TEST04", + vecs: makeDecimal128Vectors(left, leftType, false, right, rightType, false), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: restType, + wantScalar: false, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + decimalres, err := DivDecimal128(c.vecs, c.proc) + if err != nil { + t.Fatal(err) + } + require.Equal(t, c.wantBytes, decimalres.Col) + require.Equal(t, c.wantType, decimalres.Typ) + require.Equal(t, c.wantScalar, decimalres.IsScalar()) + }) + } +} diff --git a/pkg/sql/plan2/function/operator/integerdiv_test.go b/pkg/sql/plan2/function/operator/integerdiv_test.go new file mode 100644 index 0000000000000000000000000000000000000000..7d608a893d073e4b3d83d6654fa38127c959aea1 --- /dev/null +++ b/pkg/sql/plan2/function/operator/integerdiv_test.go @@ -0,0 +1,102 @@ +// 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 operator + +import ( + "github.com/matrixorigin/matrixone/pkg/container/nulls" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" + "github.com/matrixorigin/matrixone/pkg/vm/process" + "github.com/stretchr/testify/require" + "golang.org/x/exp/constraints" + "testing" +) + +func TestIntegerDiv(t *testing.T) { + integerDivFloat[float32](t, types.T_float32, 235, 7.5, 31) + integerDivFloat[float64](t, types.T_float64, 21.45, 40.55, 0) +} + +// Unit test input of float type parameter of integerdiv operator +func integerDivFloat[T constraints.Float](t *testing.T, typ types.T, left T, right T, res int64) { + procs := makeProcess() + cases := []struct { + name string + vecs []*vector.Vector + proc *process.Process + wantBytes interface{} + wantScalar bool + }{ + { + name: "TEST01", + vecs: makeIntegerDivVectors[T](left, true, right, true, typ), + proc: procs, + wantBytes: []int64{res}, + wantScalar: true, + }, + { + name: "TEST02", + vecs: makeIntegerDivVectors[T](left, false, right, true, typ), + proc: procs, + wantBytes: []int64{res}, + wantScalar: false, + }, + { + name: "TEST03", + vecs: makeIntegerDivVectors[T](left, true, right, false, typ), + proc: procs, + wantBytes: []int64{res}, + wantScalar: false, + }, + { + name: "TEST04", + vecs: makeIntegerDivVectors[T](left, false, right, false, typ), + proc: procs, + wantBytes: []int64{res}, + wantScalar: false, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + plus, err := IntegerDiv[T](c.vecs, c.proc) + if err != nil { + t.Fatal(err) + } + require.Equal(t, c.wantBytes, plus.Col) + require.Equal(t, c.wantScalar, plus.IsScalar()) + }) + } +} + +// Construct the vector parameters of the integerdiv operator +func makeIntegerDivVectors[T constraints.Float](left T, leftScalar bool, right T, rightScalar bool, t types.T) []*vector.Vector { + vectors := make([]*vector.Vector, 2) + vectors[0] = &vector.Vector{ + Col: []T{left}, + Nsp: &nulls.Nulls{}, + Typ: types.Type{Oid: t}, + IsConst: leftScalar, + Length: 1, + } + vectors[1] = &vector.Vector{ + Col: []T{right}, + Nsp: &nulls.Nulls{}, + Typ: types.Type{Oid: t}, + IsConst: rightScalar, + Length: 1, + } + return vectors +} diff --git a/pkg/sql/plan2/function/operator/minus.go b/pkg/sql/plan2/function/operator/minus.go index d9e7eeb4c2624858d8d83e638d771b637d74bbf2..a86e3f87d3c4edfdfb20ce0bce251f601f65ada7 100644 --- a/pkg/sql/plan2/function/operator/minus.go +++ b/pkg/sql/plan2/function/operator/minus.go @@ -55,7 +55,7 @@ func Minus[T constraints.Integer | constraints.Float](vectors []*vector.Vector, } resultValues := encoding.DecodeFixedSlice[T](resultVector.Data, resultElementSize) nulls.Or(lv.Nsp, rv.Nsp, resultVector.Nsp) - vector.SetCol(resultVector, sub.NumericScalar(rvs[0], lvs, resultValues)) + vector.SetCol(resultVector, sub.NumericByScalar(rvs[0], lvs, resultValues)) return resultVector, nil default: resultVector, err := proc.AllocVector(lv.Typ, int64(resultElementSize*len(lvs))) @@ -109,7 +109,7 @@ func MinusDecimal64(vectors []*vector.Vector, proc *process.Process) (*vector.Ve resultValues = resultValues[:len(lvs)] nulls.Set(resultVector.Nsp, lv.Nsp) nulls.Or(lv.Nsp, rv.Nsp, resultVector.Nsp) - vector.SetCol(resultVector, sub.Decimal64SubScalar(rvs[0], lvs, rvScale, lvScale, resultValues)) + vector.SetCol(resultVector, sub.Decimal64SubByScalar(rvs[0], lvs, rvScale, lvScale, resultValues)) return resultVector, nil default: resultVector, err := proc.AllocVector(lv.Typ, int64(resultTyp.Size)*int64(len(lvs))) @@ -163,7 +163,7 @@ func MinusDecimal128(vectors []*vector.Vector, proc *process.Process) (*vector.V rs := encoding.DecodeDecimal128Slice(vec.Data) rs = rs[:len(lvs)] nulls.Or(lv.Nsp, rv.Nsp, vec.Nsp) - vector.SetCol(vec, sub.Decimal128SubScalar(rvs[0], lvs, rvScale, lvScale, rs)) + vector.SetCol(vec, sub.Decimal128SubByScalar(rvs[0], lvs, rvScale, lvScale, rs)) return vec, nil default: vec, err := proc.AllocVector(resultTyp, int64(resultTyp.Size)*int64(len(lvs))) diff --git a/pkg/sql/plan2/function/operator/minus_test.go b/pkg/sql/plan2/function/operator/minus_test.go new file mode 100644 index 0000000000000000000000000000000000000000..357ced50237f5a933b6eac3aadcc8d6e02a125e1 --- /dev/null +++ b/pkg/sql/plan2/function/operator/minus_test.go @@ -0,0 +1,242 @@ +// 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 operator + +import ( + "github.com/matrixorigin/matrixone/pkg/container/nulls" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" + "github.com/matrixorigin/matrixone/pkg/vm/process" + "github.com/stretchr/testify/require" + "golang.org/x/exp/constraints" + "testing" +) + +func TestMinus(t *testing.T) { + minusIntAndFloat[int8](t, types.T_int8, 26, 47, -21) + minusIntAndFloat[int16](t, types.T_int16, 26, 47, -21) + minusIntAndFloat[int32](t, types.T_int32, 26, 47, -21) + minusIntAndFloat[int64](t, types.T_int64, 26, 47, -21) + + minusIntAndFloat[uint8](t, types.T_uint8, 100, 47, 53) + minusIntAndFloat[uint16](t, types.T_uint16, 100, 47, 53) + minusIntAndFloat[uint32](t, types.T_uint32, 100, 47, 53) + minusIntAndFloat[uint64](t, types.T_uint64, 100, 47, 53) + + minusIntAndFloat[float32](t, types.T_float32, 95.46, 20, 75.46) + minusIntAndFloat[float64](t, types.T_float64, 95.46, 20, 75.46) + + leftType1 := types.Type{Oid: types.T_decimal64, Size: 8, Width: 10, Scale: 5} + rightType1 := types.Type{Oid: types.T_decimal64, Size: 8, Width: 10, Scale: 5} + resType1 := types.Type{Oid: types.T_decimal64, Size: 8, Width: 18, Scale: 5} + minusDecimal64(t, 33333300, leftType1, -123450000, rightType1, 156783300, resType1) + + leftType2 := types.Type{Oid: types.T_decimal128, Size: 16, Width: 20, Scale: 5} + rightType2 := types.Type{Oid: types.T_decimal128, Size: 16, Width: 20, Scale: 5} + resType2 := types.Type{Oid: types.T_decimal128, Size: 16, Width: 38, Scale: 5} + minusDecimal128(t, types.Decimal128{Lo: 33333300, Hi: 0}, leftType2, types.Decimal128{Lo: -123450000, Hi: -1}, rightType2, types.Decimal128{Lo: 156783300, Hi: 0}, resType2) + +} + +// Unit test input for int and float type parameters of the minus operator +func minusIntAndFloat[T constraints.Integer | constraints.Float](t *testing.T, typ types.T, left T, right T, res T) { + procs := makeProcess() + cases := []struct { + name string + vecs []*vector.Vector + proc *process.Process + wantBytes interface{} + wantScalar bool + }{ + { + name: "TEST01", + vecs: makeMinusVectors[T](left, true, right, true, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: true, + }, + { + name: "TEST02", + vecs: makeMinusVectors[T](left, false, right, true, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: false, + }, + { + name: "TEST03", + vecs: makeMinusVectors[T](left, true, right, false, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: false, + }, + { + name: "TEST04", + vecs: makeMinusVectors[T](left, false, right, false, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: false, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + plus, err := Minus[T](c.vecs, c.proc) + if err != nil { + t.Fatal(err) + } + + require.Equal(t, c.wantBytes, plus.Col) + require.Equal(t, c.wantScalar, plus.IsScalar()) + }) + } +} + +// Construct the vector parameters of the minus operator +func makeMinusVectors[T constraints.Integer | constraints.Float](left T, leftScalar bool, right T, rightScalar bool, t types.T) []*vector.Vector { + vectors := make([]*vector.Vector, 2) + vectors[0] = &vector.Vector{ + Col: []T{left}, + Nsp: &nulls.Nulls{}, + Typ: types.Type{Oid: t}, + IsConst: leftScalar, + Length: 1, + } + vectors[1] = &vector.Vector{ + Col: []T{right}, + Nsp: &nulls.Nulls{}, + Typ: types.Type{Oid: t}, + IsConst: rightScalar, + Length: 1, + } + return vectors +} + +// Unit test input of decimal64 parameter of minus operator +func minusDecimal64(t *testing.T, left types.Decimal64, leftType types.Type, right types.Decimal64, rightType types.Type, + res types.Decimal64, restType types.Type) { + procs := makeProcess() + cases := []struct { + name string + vecs []*vector.Vector + proc *process.Process + wantBytes interface{} + wantType types.Type + wantScalar bool + }{ + { + name: "TEST01", + vecs: makeDecimal64Vectors(left, leftType, true, right, rightType, true), + proc: procs, + wantBytes: []types.Decimal64{res}, + wantType: restType, + wantScalar: true, + }, + { + name: "TEST02", + vecs: makeDecimal64Vectors(left, leftType, false, right, rightType, true), + proc: procs, + wantBytes: []types.Decimal64{res}, + wantType: restType, + wantScalar: false, + }, + { + name: "TEST03", + vecs: makeDecimal64Vectors(left, leftType, true, right, rightType, false), + proc: procs, + wantBytes: []types.Decimal64{res}, + wantType: restType, + wantScalar: false, + }, + { + name: "TEST04", + vecs: makeDecimal64Vectors(left, leftType, false, right, rightType, false), + proc: procs, + wantBytes: []types.Decimal64{res}, + wantType: leftType, + wantScalar: false, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + decimalres, err := MinusDecimal64(c.vecs, c.proc) + if err != nil { + t.Fatal(err) + } + require.Equal(t, c.wantBytes, decimalres.Col) + require.Equal(t, c.wantType, decimalres.Typ) + require.Equal(t, c.wantScalar, decimalres.IsScalar()) + }) + } +} + +// Unit test input of decimal128 parameter of minus operator +func minusDecimal128(t *testing.T, left types.Decimal128, leftType types.Type, right types.Decimal128, rightType types.Type, + res types.Decimal128, resType types.Type) { + procs := makeProcess() + cases := []struct { + name string + vecs []*vector.Vector + proc *process.Process + wantBytes interface{} + wantType types.Type + wantScalar bool + }{ + { + name: "TEST01", + vecs: makeDecimal128Vectors(left, leftType, true, right, rightType, true), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: resType, + wantScalar: true, + }, + { + name: "TEST02", + vecs: makeDecimal128Vectors(left, leftType, false, right, rightType, true), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: resType, + wantScalar: false, + }, + { + name: "TEST03", + vecs: makeDecimal128Vectors(left, leftType, true, right, rightType, false), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: resType, + wantScalar: false, + }, + { + name: "TEST04", + vecs: makeDecimal128Vectors(left, leftType, false, right, rightType, false), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: resType, + wantScalar: false, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + decimalres, err := MinusDecimal128(c.vecs, c.proc) + if err != nil { + t.Fatal(err) + } + require.Equal(t, c.wantBytes, decimalres.Col) + require.Equal(t, c.wantType, decimalres.Typ) + require.Equal(t, c.wantScalar, decimalres.IsScalar()) + }) + } +} diff --git a/pkg/sql/plan2/function/operator/mod.go b/pkg/sql/plan2/function/operator/mod.go index c68441d2a74ed96b0c9b2002b7ab00d06c6b8618..7f41eaaf2ad60367bc3e544f89118beff80626b6 100644 --- a/pkg/sql/plan2/function/operator/mod.go +++ b/pkg/sql/plan2/function/operator/mod.go @@ -104,7 +104,7 @@ func ModInt[T constraints.Integer](vectors []*vector.Vector, proc *process.Proce } rs := encoding.DecodeFixedSlice[T](vec.Data, rtl) nulls.Set(vec.Nsp, lv.Nsp) - mod.IntModByScalar(rvs[0], lvs, rs) + vector.SetCol(vec, mod.IntModByScalar(rvs[0], lvs, rs)) return vec, nil } vec, err := proc.AllocVector(lv.Typ, int64(rtl)*int64(len(lvs))) @@ -218,7 +218,7 @@ func ModFloat[T constraints.Float](vectors []*vector.Vector, proc *process.Proce } rs := encoding.DecodeFixedSlice[T](vec.Data, rtl) nulls.Set(vec.Nsp, lv.Nsp) - mod.FloatModByScalar(rvs[0], lvs, rs) + vector.SetCol(vec, mod.FloatModByScalar(rvs[0], lvs, rs)) return vec, nil } vec, err := proc.AllocVector(lv.Typ, int64(rtl)*int64(len(lvs))) diff --git a/pkg/sql/plan2/function/operator/mod_test.go b/pkg/sql/plan2/function/operator/mod_test.go new file mode 100644 index 0000000000000000000000000000000000000000..5f19de5fa4f6434d9034a57eb06a9aa0e8a74347 --- /dev/null +++ b/pkg/sql/plan2/function/operator/mod_test.go @@ -0,0 +1,164 @@ +// 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 operator + +import ( + "github.com/matrixorigin/matrixone/pkg/container/nulls" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" + "github.com/matrixorigin/matrixone/pkg/vm/process" + "github.com/stretchr/testify/require" + "golang.org/x/exp/constraints" + "testing" +) + +func TestMod(t *testing.T) { + modInteger[int8](t, types.T_int8, 28, -5, 3) + modInteger[int16](t, types.T_int16, 28, -5, 3) + modInteger[int32](t, types.T_int32, 28, -5, 3) + modInteger[int64](t, types.T_int64, 28, -5, 3) + + modInteger[uint8](t, types.T_uint8, 28, 5, 3) + modInteger[uint16](t, types.T_uint16, 28, 5, 3) + modInteger[uint32](t, types.T_uint32, 28, 5, 3) + modInteger[uint64](t, types.T_uint64, 28, 5, 3) + + modFloater[float32](t, types.T_float32, 24.45, 12.4, 0) + modFloater[float64](t, types.T_float64, 24.45, 12.4, 0) +} + +// Integer unit test entry for mod operator +func modInteger[T constraints.Integer](t *testing.T, typ types.T, left T, right T, res T) { + procs := makeProcess() + cases := []struct { + name string + vecs []*vector.Vector + proc *process.Process + wantBytes interface{} + wantScalar bool + }{ + { + name: "TEST01", + vecs: makeModVectors[T](left, true, right, true, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: true, + }, + { + name: "TEST02", + vecs: makeModVectors[T](left, false, right, true, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: false, + }, + { + name: "TEST03", + vecs: makeModVectors[T](left, true, right, false, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: false, + }, + { + name: "TEST04", + vecs: makeModVectors[T](left, false, right, false, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: false, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + plus, err := ModInt[T](c.vecs, c.proc) + if err != nil { + t.Fatal(err) + } + require.Equal(t, c.wantBytes, plus.Col) + require.Equal(t, c.wantScalar, plus.IsScalar()) + }) + } +} + +// Float unit test entry for mod operator +func modFloater[T constraints.Float](t *testing.T, typ types.T, left T, right T, res T) { + procs := makeProcess() + cases := []struct { + name string + vecs []*vector.Vector + proc *process.Process + wantBytes interface{} + wantScalar bool + }{ + { + name: "TEST01", + vecs: makeModVectors[T](left, true, right, true, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: true, + }, + { + name: "TEST02", + vecs: makeModVectors[T](left, false, right, true, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: false, + }, + { + name: "TEST03", + vecs: makeModVectors[T](left, true, right, false, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: false, + }, + { + name: "TEST04", + vecs: makeModVectors[T](left, false, right, false, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: false, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + plus, err := ModFloat[T](c.vecs, c.proc) + if err != nil { + t.Fatal(err) + } + require.Equal(t, c.wantBytes, plus.Col) + require.Equal(t, c.wantScalar, plus.IsScalar()) + }) + } +} + +// Construct vector parameters of mod operator +func makeModVectors[T constraints.Integer | constraints.Float](left T, leftScalar bool, right T, rightScalar bool, t types.T) []*vector.Vector { + vectors := make([]*vector.Vector, 2) + vectors[0] = &vector.Vector{ + Col: []T{left}, + Nsp: &nulls.Nulls{}, + Typ: types.Type{Oid: t}, + IsConst: leftScalar, + Length: 1, + } + vectors[1] = &vector.Vector{ + Col: []T{right}, + Nsp: &nulls.Nulls{}, + Typ: types.Type{Oid: t}, + IsConst: rightScalar, + Length: 1, + } + return vectors +} diff --git a/pkg/sql/plan2/function/operator/mult_test.go b/pkg/sql/plan2/function/operator/mult_test.go new file mode 100644 index 0000000000000000000000000000000000000000..f229abf6fe43e754288060ada76037dc33ab9a1b --- /dev/null +++ b/pkg/sql/plan2/function/operator/mult_test.go @@ -0,0 +1,281 @@ +// 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 operator + +import ( + "github.com/matrixorigin/matrixone/pkg/container/nulls" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" + "github.com/matrixorigin/matrixone/pkg/vm/process" + "github.com/stretchr/testify/require" + "golang.org/x/exp/constraints" + "testing" +) + +func TestMult(t *testing.T) { + multIntAndFloat[int8](t, types.T_int8, 10, -5, -50) + multIntAndFloat[int16](t, types.T_int16, 10, -5, -50) + multIntAndFloat[int32](t, types.T_int32, 10, -5, -50) + multIntAndFloat[int64](t, types.T_int64, 10, -5, -50) + + multIntAndFloat[uint8](t, types.T_uint8, 10, 5, 50) + multIntAndFloat[uint16](t, types.T_uint16, 10, 5, 50) + multIntAndFloat[uint32](t, types.T_uint32, 10, 5, 50) + multIntAndFloat[uint64](t, types.T_uint64, 10, 5, 50) + + multIntAndFloat[float32](t, types.T_float32, 20.85, 12.5, 260.625) + multIntAndFloat[float64](t, types.T_float64, 20.85, 12.5, 260.625) + + leftType1 := types.Type{Oid: types.T_decimal64, Size: 8, Width: 10, Scale: 5} + rightType1 := types.Type{Oid: types.T_decimal64, Size: 8, Width: 10, Scale: 5} + resType1 := types.Type{Oid: types.T_decimal128, Size: 16, Width: 38, Scale: 10} + multDecimal64(t, 33333300, leftType1, -123450000, rightType1, types.Decimal128{Lo: -4114995885000000, Hi: -1}, resType1) + + leftType2 := types.Type{Oid: types.T_decimal128, Size: 16, Width: 20, Scale: 5} + rightType2 := types.Type{Oid: types.T_decimal128, Size: 16, Width: 20, Scale: 5} + resType2 := types.Type{Oid: types.T_decimal128, Size: 16, Width: 38, Scale: 10} + multDecimal128(t, types.Decimal128{Lo: 33333300, Hi: 0}, leftType2, types.Decimal128{Lo: -123450000, Hi: -1}, rightType2, + types.Decimal128{Lo: -4114995885000000, Hi: -1}, resType2) +} + +// Unit test input of int and float parameters of mult operator +func multIntAndFloat[T constraints.Integer | constraints.Float](t *testing.T, typ types.T, left T, right T, res T) { + procs := makeProcess() + cases := []struct { + name string + vecs []*vector.Vector + proc *process.Process + wantBytes interface{} + wantScalar bool + }{ + { + name: "TEST01", + vecs: makeMultVectors[T](left, true, right, true, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: true, + }, + { + name: "TEST02", + vecs: makeMultVectors[T](left, false, right, true, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: false, + }, + { + name: "TEST03", + vecs: makeMultVectors[T](left, true, right, false, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: false, + }, + { + name: "TEST04", + vecs: makeMultVectors[T](left, false, right, false, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: false, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + plus, err := Mult[T](c.vecs, c.proc) + if err != nil { + t.Fatal(err) + } + require.Equal(t, c.wantBytes, plus.Col) + require.Equal(t, c.wantScalar, plus.IsScalar()) + }) + } +} + +// Construct vector parameter of mult operator +func makeMultVectors[T constraints.Integer | constraints.Float](left T, leftScalar bool, right T, rightScalar bool, t types.T) []*vector.Vector { + vectors := make([]*vector.Vector, 2) + vectors[0] = &vector.Vector{ + Col: []T{left}, + Nsp: &nulls.Nulls{}, + Typ: types.Type{Oid: t}, + IsConst: leftScalar, + Length: 1, + } + vectors[1] = &vector.Vector{ + Col: []T{right}, + Nsp: &nulls.Nulls{}, + Typ: types.Type{Oid: t}, + IsConst: rightScalar, + Length: 1, + } + return vectors +} + +// Unit test input of decimal64 parameter of mult operator +func multDecimal64(t *testing.T, left types.Decimal64, leftType types.Type, right types.Decimal64, rightType types.Type, + res types.Decimal128, restType types.Type) { + procs := makeProcess() + cases := []struct { + name string + vecs []*vector.Vector + proc *process.Process + wantBytes interface{} + wantType types.Type + wantScalar bool + }{ + { + name: "TEST01", + vecs: makeDecimal64Vectors(left, leftType, true, right, rightType, true), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: restType, + wantScalar: true, + }, + { + name: "TEST02", + vecs: makeDecimal64Vectors(left, leftType, false, right, rightType, true), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: restType, + wantScalar: false, + }, + { + name: "TEST03", + vecs: makeDecimal64Vectors(left, leftType, true, right, rightType, false), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: restType, + wantScalar: false, + }, + { + name: "TEST04", + vecs: makeDecimal64Vectors(left, leftType, false, right, rightType, false), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: restType, + wantScalar: false, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + decimalres, err := MultDecimal64(c.vecs, c.proc) + if err != nil { + t.Fatal(err) + } + require.Equal(t, c.wantBytes, decimalres.Col) + require.Equal(t, c.wantType, decimalres.Typ) + require.Equal(t, c.wantScalar, decimalres.IsScalar()) + }) + } +} + +// Unit test input of decimal128 parameter of mult operator +func multDecimal128(t *testing.T, left types.Decimal128, leftType types.Type, right types.Decimal128, rightType types.Type, + res types.Decimal128, restType types.Type) { + procs := makeProcess() + cases := []struct { + name string + vecs []*vector.Vector + proc *process.Process + wantBytes interface{} + wantType types.Type + wantScalar bool + }{ + { + name: "TEST01", + vecs: makeDecimal128Vectors(left, leftType, true, right, rightType, true), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: restType, + wantScalar: true, + }, + { + name: "TEST02", + vecs: makeDecimal128Vectors(left, leftType, false, right, rightType, true), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: restType, + wantScalar: false, + }, + { + name: "TEST03", + vecs: makeDecimal128Vectors(left, leftType, true, right, rightType, false), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: restType, + wantScalar: false, + }, + { + name: "TEST04", + vecs: makeDecimal128Vectors(left, leftType, false, right, rightType, false), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: restType, + wantScalar: false, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + decimalres, err := MultDecimal128(c.vecs, c.proc) + if err != nil { + t.Fatal(err) + } + require.Equal(t, c.wantBytes, decimalres.Col) + require.Equal(t, c.wantType, decimalres.Typ) + require.Equal(t, c.wantScalar, decimalres.IsScalar()) + }) + } +} + +// Building a vector slice with two decimal64 type elements +func makeDecimal64Vectors(left types.Decimal64, leftType types.Type, leftScalar bool, right types.Decimal64, rightType types.Type, rightScalar bool) []*vector.Vector { + vectors := make([]*vector.Vector, 2) + vectors[0] = &vector.Vector{ + Col: []types.Decimal64{left}, + Nsp: &nulls.Nulls{}, + Typ: leftType, + IsConst: leftScalar, + Length: 1, + } + vectors[1] = &vector.Vector{ + Col: []types.Decimal64{right}, + Nsp: &nulls.Nulls{}, + Typ: rightType, + IsConst: rightScalar, + Length: 1, + } + return vectors +} + +// Building a vector slice with two decimal128 type elements +func makeDecimal128Vectors(left types.Decimal128, leftType types.Type, leftScalar bool, right types.Decimal128, rightType types.Type, rightScalar bool) []*vector.Vector { + vectors := make([]*vector.Vector, 2) + vectors[0] = &vector.Vector{ + Col: []types.Decimal128{left}, + Nsp: &nulls.Nulls{}, + Typ: leftType, + IsConst: leftScalar, + Length: 1, + } + vectors[1] = &vector.Vector{ + Col: []types.Decimal128{right}, + Nsp: &nulls.Nulls{}, + Typ: rightType, + IsConst: rightScalar, + Length: 1, + } + return vectors +} diff --git a/pkg/sql/plan2/function/operator/plus_test.go b/pkg/sql/plan2/function/operator/plus_test.go new file mode 100644 index 0000000000000000000000000000000000000000..eef54901a96d487d1cd7089f1c7aa776ab4b4623 --- /dev/null +++ b/pkg/sql/plan2/function/operator/plus_test.go @@ -0,0 +1,243 @@ +// 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 operator + +import ( + "github.com/matrixorigin/matrixone/pkg/container/nulls" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" + "github.com/matrixorigin/matrixone/pkg/vm/process" + "github.com/stretchr/testify/require" + "golang.org/x/exp/constraints" + "testing" +) + +func TestPlus(t *testing.T) { + plusIntAndFloat[int8](t, types.T_int8, 21, -41, -20) + plusIntAndFloat[int16](t, types.T_int16, 21, -41, -20) + plusIntAndFloat[int32](t, types.T_int32, 21, -41, -20) + plusIntAndFloat[int64](t, types.T_int64, 21, -41, -20) + + plusIntAndFloat[uint8](t, types.T_uint8, 21, 47, 68) + plusIntAndFloat[uint16](t, types.T_uint16, 21, 47, 68) + plusIntAndFloat[uint32](t, types.T_uint32, 21, 47, 68) + plusIntAndFloat[uint64](t, types.T_uint64, 21, 47, 68) + + plusIntAndFloat[float32](t, types.T_float32, 21.45, 40.55, 62) + plusIntAndFloat[float64](t, types.T_float64, 21.45, 40.55, 62) + + leftType1 := types.Type{Oid: types.T_decimal64, Size: 8, Width: 10, Scale: 5} + rightType1 := types.Type{Oid: types.T_decimal64, Size: 8, Width: 10, Scale: 5} + resType1 := types.Type{Oid: types.T_decimal64, Size: 8, Width: 18, Scale: 5} + plusDecimal64(t, 33333300, leftType1, -123450000, rightType1, -90116700, resType1) + + leftType2 := types.Type{Oid: types.T_decimal128, Size: 16, Width: 20, Scale: 5} + rightType2 := types.Type{Oid: types.T_decimal128, Size: 16, Width: 20, Scale: 5} + resType2 := types.Type{Oid: types.T_decimal128, Size: 16, Width: 38, Scale: 5} + plusDecimal128(t, types.Decimal128{Lo: 33333300, Hi: 0}, leftType2, types.Decimal128{Lo: -123450000, Hi: -1}, rightType2, types.Decimal128{Lo: -90116700, Hi: -1}, resType2) +} + +// Unit test input for int and float type parameters of the plus operator +func plusIntAndFloat[T constraints.Integer | constraints.Float](t *testing.T, typ types.T, left T, right T, res T) { + procs := makeProcess() + cases := []struct { + name string + vecs []*vector.Vector + proc *process.Process + wantBytes interface{} + wantScalar bool + }{ + { + name: "TEST01", + vecs: makePlusVectors[T](left, true, right, true, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: true, + }, + { + name: "TEST02", + vecs: makePlusVectors[T](left, false, right, true, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: false, + }, + { + name: "TEST03", + vecs: makePlusVectors[T](left, true, right, false, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: false, + }, + { + name: "TEST04", + vecs: makePlusVectors[T](left, false, right, false, typ), + proc: procs, + wantBytes: []T{res}, + wantScalar: false, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + plus, err := Plus[T](c.vecs, c.proc) + if err != nil { + t.Fatal(err) + } + require.Equal(t, c.wantBytes, plus.Col) + require.Equal(t, c.wantScalar, plus.IsScalar()) + }) + } +} + +// Construct the vector parameter of the plus operator +func makePlusVectors[T constraints.Integer | constraints.Float](left T, leftScalar bool, right T, rightScalar bool, t types.T) []*vector.Vector { + vectors := make([]*vector.Vector, 2) + vectors[0] = &vector.Vector{ + Col: []T{left}, + Nsp: &nulls.Nulls{}, + Typ: types.Type{Oid: t}, + IsConst: leftScalar, + Length: 1, + } + vectors[1] = &vector.Vector{ + Col: []T{right}, + Nsp: &nulls.Nulls{}, + Typ: types.Type{Oid: t}, + IsConst: rightScalar, + Length: 1, + } + return vectors +} + +// Unit test input of decimal64 parameters of plus operator +func plusDecimal64(t *testing.T, left types.Decimal64, leftType types.Type, right types.Decimal64, rightType types.Type, + res types.Decimal64, restType types.Type) { + procs := makeProcess() + cases := []struct { + name string + vecs []*vector.Vector + proc *process.Process + wantBytes interface{} + wantType types.Type + wantScalar bool + }{ + { + name: "TEST01", + vecs: makeDecimal64Vectors(left, leftType, true, right, rightType, true), + proc: procs, + wantBytes: []types.Decimal64{res}, + wantType: restType, + wantScalar: true, + }, + { + name: "TEST02", + vecs: makeDecimal64Vectors(left, leftType, false, right, rightType, true), + proc: procs, + wantBytes: []types.Decimal64{res}, + wantType: restType, + wantScalar: false, + }, + { + name: "TEST03", + vecs: makeDecimal64Vectors(left, leftType, true, right, rightType, false), + proc: procs, + wantBytes: []types.Decimal64{res}, + wantType: restType, + wantScalar: false, + }, + { + name: "TEST04", + vecs: makeDecimal64Vectors(left, leftType, false, right, rightType, false), + proc: procs, + wantBytes: []types.Decimal64{res}, + wantType: leftType, + wantScalar: false, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + decimalres, err := PlusDecimal64(c.vecs, c.proc) + if err != nil { + t.Fatal(err) + } + require.Equal(t, c.wantBytes, decimalres.Col) + require.Equal(t, c.wantType, decimalres.Typ) + require.Equal(t, c.wantScalar, decimalres.IsScalar()) + }) + } +} + +// Unit test input of decimal128 parameter of plus operator +func plusDecimal128(t *testing.T, left types.Decimal128, leftType types.Type, right types.Decimal128, rightType types.Type, + res types.Decimal128, resType types.Type) { + //leftType := types.Type{Oid: types.T_decimal128, Size: 16, Width: 20, Scale: 5} + //rightType := types.Type{Oid: types.T_decimal128, Size: 16, Width: 20, Scale: 5} + + procs := makeProcess() + cases := []struct { + name string + vecs []*vector.Vector + proc *process.Process + wantBytes interface{} + wantType types.Type + wantScalar bool + }{ + { + name: "TEST01", + vecs: makeDecimal128Vectors(left, leftType, true, right, rightType, true), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: resType, + wantScalar: true, + }, + { + name: "TEST02", + vecs: makeDecimal128Vectors(left, leftType, false, right, rightType, true), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: resType, + wantScalar: false, + }, + { + name: "TEST03", + vecs: makeDecimal128Vectors(left, leftType, true, right, rightType, false), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: resType, + wantScalar: false, + }, + { + name: "TEST04", + vecs: makeDecimal128Vectors(left, leftType, false, right, rightType, false), + proc: procs, + wantBytes: []types.Decimal128{res}, + wantType: leftType, + wantScalar: false, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + decimalres, err := PlusDecimal128(c.vecs, c.proc) + if err != nil { + t.Fatal(err) + } + require.Equal(t, c.wantBytes, decimalres.Col) + require.Equal(t, c.wantType, decimalres.Typ) + require.Equal(t, c.wantScalar, decimalres.IsScalar()) + }) + } +} diff --git a/pkg/sql/plan2/function/operators.go b/pkg/sql/plan2/function/operators.go index e625289895fb644cfbcc9756168ee9158173f9c2..2f7cb5792ee27147352ff1a778fed48dbc415943 100644 --- a/pkg/sql/plan2/function/operators.go +++ b/pkg/sql/plan2/function/operators.go @@ -1604,7 +1604,7 @@ var operators = map[int][]Function{ Index: 8, Flag: plan.Function_STRICT, Layout: BINARY_ARITHMETIC_OPERATOR, - Args: []types.T{types.T_float32, types.T_float64}, + Args: []types.T{types.T_float32, types.T_float32}, ReturnTyp: types.T_float32, TypeCheckFn: strictTypeCheck, Fn: operator.Plus[float32], @@ -1723,7 +1723,7 @@ var operators = map[int][]Function{ Index: 8, Flag: plan.Function_STRICT, Layout: BINARY_ARITHMETIC_OPERATOR, - Args: []types.T{types.T_float32, types.T_float64}, + Args: []types.T{types.T_float32, types.T_float32}, ReturnTyp: types.T_float32, TypeCheckFn: strictTypeCheck, Fn: operator.Minus[float32], @@ -1842,7 +1842,7 @@ var operators = map[int][]Function{ Index: 8, Flag: plan.Function_STRICT, Layout: BINARY_ARITHMETIC_OPERATOR, - Args: []types.T{types.T_float32, types.T_float64}, + Args: []types.T{types.T_float32, types.T_float32}, ReturnTyp: types.T_float32, TypeCheckFn: strictTypeCheck, Fn: operator.Mult[float32], @@ -2010,7 +2010,7 @@ var operators = map[int][]Function{ Index: 8, Flag: plan.Function_STRICT, Layout: BINARY_ARITHMETIC_OPERATOR, - Args: []types.T{types.T_float32, types.T_float64}, + Args: []types.T{types.T_float32, types.T_float32}, ReturnTyp: types.T_float32, TypeCheckFn: strictTypeCheck, Fn: operator.ModFloat[float32],