Skip to content
Snippets Groups Projects
Unverified Commit 6fc3312d authored by qingxinhome's avatar qingxinhome Committed by GitHub
Browse files

Migate like operator and test (#2768)

parent 8fed89a9
No related branches found
No related tags found
No related merge requests found
// 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 (
"errors"
"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/encoding"
"github.com/matrixorigin/matrixone/pkg/vectorize/like"
"github.com/matrixorigin/matrixone/pkg/vm/process"
)
var (
errUnexpected = errors.New("unexpected case for LIKE operator")
)
func Like(vectors []*vector.Vector, proc *process.Process) (*vector.Vector, error) {
lv, rv := vectors[0], vectors[1]
lvs, rvs := lv.Col.(*types.Bytes), rv.Col.(*types.Bytes)
rtl := 8
if lv.IsScalarNull() || rv.IsScalarNull() {
return proc.AllocScalarNullVector(types.Type{Oid: types.T_bool}), nil
}
switch {
case !lv.IsScalar() && rv.IsScalar():
vec, err := proc.AllocVector(types.Type{Oid: types.T_bool}, int64(len(lvs.Offsets)*rtl))
if err != nil {
return nil, err
}
rs := encoding.DecodeInt64Slice(vec.Data)
rs = rs[:len(lvs.Lengths)]
if nulls.Any(lv.Nsp) {
rs, err = like.BtSliceNullAndConst(lvs, rvs.Get(0), lv.Nsp.Np, rs)
if err != nil {
return nil, err
}
vec.Nsp = lv.Nsp
} else {
rs, err = like.BtSliceAndConst(lvs, rvs.Get(0), rs)
if err != nil {
return nil, err
}
}
col := make([]bool, len(lvs.Offsets))
rsi := 0
for i := 0; i < len(col); i++ {
if rsi >= len(rs) {
break
}
if int64(i) == rs[rsi] {
col[i] = true
rsi++
} else {
col[i] = false
}
}
vector.SetCol(vec, col)
return vec, nil
case lv.IsScalar() && rv.IsScalar(): // in our design, this case should deal while pruning extends.
vec := proc.AllocScalarVector(types.Type{Oid: types.T_bool})
rs := make([]int64, 1)
rs, err := like.BtConstAndConst(lvs.Get(0), rvs.Get(0), rs)
if err != nil {
return nil, err
}
col := make([]bool, 1)
if rs == nil {
col[0] = false
} else {
col[0] = rs[0] == int64(0)
}
vector.SetCol(vec, col)
return vec, nil
case lv.IsScalar() && !rv.IsScalar():
vec, err := proc.AllocVector(types.Type{Oid: types.T_bool}, int64(len(rvs.Offsets)*rtl))
if err != nil {
return nil, err
}
rs := encoding.DecodeInt64Slice(vec.Data)
rs = rs[:len(rvs.Lengths)]
if nulls.Any(rv.Nsp) {
rs, err = like.BtConstAndSliceNull(lvs.Get(0), rvs, rv.Nsp.Np, rs)
if err != nil {
return nil, err
}
vec.Nsp = rv.Nsp
} else {
rs, err = like.BtConstAndSlice(lvs.Get(0), rvs, rs)
if err != nil {
return nil, err
}
}
col := make([]bool, len(rvs.Offsets))
rsi := 0
for i := 0; i < len(col); i++ {
if rsi >= len(rs) {
break
}
if int64(i) == rs[rsi] {
col[i] = true
rsi++
} else {
col[i] = false
}
}
vector.SetCol(vec, col)
return vec, nil
case !lv.IsScalar() && !rv.IsScalar():
vec, err := proc.AllocVector(types.Type{Oid: types.T_bool}, int64(len(lvs.Offsets)*rtl))
if err != nil {
return nil, err
}
rs := encoding.DecodeInt64Slice(vec.Data)
rs = rs[:len(rvs.Lengths)]
if nulls.Any(rv.Nsp) && nulls.Any(lv.Nsp) {
nsp := lv.Nsp.Or(rv.Nsp)
rs, err = like.BtSliceNullAndSliceNull(lvs, rvs, nsp.Np, rs)
if err != nil {
return nil, err
}
vec.Nsp = nsp
} else if nulls.Any(rv.Nsp) && !nulls.Any(lv.Nsp) {
rs, err = like.BtSliceNullAndSliceNull(lvs, rvs, rv.Nsp.Np, rs)
if err != nil {
return nil, err
}
vec.Nsp = rv.Nsp
} else if !nulls.Any(rv.Nsp) && nulls.Any(lv.Nsp) {
rs, err = like.BtSliceNullAndSliceNull(lvs, rvs, lv.Nsp.Np, rs)
if err != nil {
return nil, err
}
//vector.SetCol(vec, rs)
vec.Nsp = lv.Nsp
} else {
rs, err = like.BtSliceAndSlice(lvs, rvs, rs)
if err != nil {
return nil, err
}
}
col := make([]bool, len(lvs.Offsets))
rsi := 0
for i := 0; i < len(col); i++ {
if rsi >= len(rs) {
break
}
if int64(i) == rs[rsi] {
col[i] = true
rsi++
} else {
col[i] = false
}
}
vector.SetCol(vec, col)
return vec, nil
}
return nil, errUnexpected
}
// 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/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 TestLpadVarchar(t *testing.T) {
cases := []struct {
name string
vecs []*vector.Vector
proc *process.Process
wantBytes []bool
}{
{
name: "TEST01",
vecs: makeLikeVectors("RUNOOB.COM", "%COM", true, true),
proc: process.New(mheap.New(nil)),
wantBytes: []bool{true},
},
{
name: "TEST02",
vecs: makeLikeVectors("aaa", "aaa", true, true),
proc: process.New(mheap.New(nil)),
wantBytes: []bool{true},
},
{
name: "TEST03",
vecs: makeLikeVectors("123", "1%", true, true),
proc: process.New(mheap.New(nil)),
wantBytes: []bool{true},
},
{
name: "TEST04",
vecs: makeLikeVectors("SALESMAN", "%SAL%", true, true),
proc: process.New(mheap.New(nil)),
wantBytes: []bool{true},
},
{
name: "TEST05",
vecs: makeLikeVectors("MANAGER@@@", "MAN_", true, true),
proc: process.New(mheap.New(nil)),
wantBytes: []bool{false},
},
{
name: "TEST06",
vecs: makeLikeVectors("MANAGER@@@", "_", true, true),
proc: process.New(mheap.New(nil)),
wantBytes: []bool{false},
},
{
name: "TEST07",
vecs: makeLikeVectors("hello@world", "hello_world", true, true),
proc: process.New(mheap.New(nil)),
wantBytes: []bool{true},
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
likeRes, err := Like(c.vecs, c.proc)
if err != nil {
t.Fatal(err)
}
require.Equal(t, c.wantBytes, likeRes.Col.([]bool))
})
}
}
func TestLpadVarchar2(t *testing.T) {
procs := makeProcess()
cases := []struct {
name string
vecs []*vector.Vector
proc *process.Process
wantBytes []bool
wantScalar bool
}{
{
name: "TEST01",
vecs: makeLikeVectors("RUNOOB.COM", "%COM", false, true),
proc: procs,
wantBytes: []bool{true},
wantScalar: false,
},
{
name: "TEST02",
vecs: makeLikeVectors("aaa", "aaa", false, true),
proc: procs,
wantBytes: []bool{true},
wantScalar: false,
},
{
name: "TEST03",
vecs: makeLikeVectors("123", "1%", false, true),
proc: procs,
wantBytes: []bool{true},
wantScalar: false,
},
{
name: "TEST04",
vecs: makeLikeVectors("SALESMAN", "%SAL%", false, true),
proc: procs,
wantBytes: []bool{true},
wantScalar: false,
},
{
name: "TEST05",
vecs: makeLikeVectors("MANAGER@@@", "MAN_", false, true),
proc: procs,
wantBytes: []bool{false},
wantScalar: false,
},
{
name: "TEST06",
vecs: makeLikeVectors("MANAGER@@@", "_", false, true),
proc: procs,
wantBytes: []bool{false},
wantScalar: false,
},
{
name: "TEST07",
vecs: makeLikeVectors("hello@world", "hello_world", false, true),
proc: procs,
wantBytes: []bool{true},
wantScalar: false,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
likeRes, err := Like(c.vecs, c.proc)
if err != nil {
t.Fatal(err)
}
require.Equal(t, c.wantBytes, likeRes.Col.([]bool))
require.Equal(t, c.wantScalar, likeRes.IsScalar())
})
}
}
func makeProcess() *process.Process {
hm := host.New(1 << 40)
gm := guest.New(1<<40, hm)
return process.New(mheap.New(gm))
}
func makeLikeVectors(src string, patten string, isSrcConst bool, isPattenConst bool) []*vector.Vector {
resVectors := make([]*vector.Vector, 2)
srcBytes := &types.Bytes{
Data: []byte(src),
Offsets: []uint32{0},
Lengths: []uint32{uint32(len(src))},
}
pattenBytes := &types.Bytes{
Data: []byte(patten),
Offsets: []uint32{0},
Lengths: []uint32{uint32(len(patten))},
}
resVectors[0] = &vector.Vector{
Col: srcBytes,
Nsp: &nulls.Nulls{},
Typ: types.Type{Oid: types.T_varchar, Size: 24},
IsConst: isSrcConst,
Length: 10,
}
resVectors[1] = &vector.Vector{
Col: pattenBytes,
Nsp: &nulls.Nulls{},
Typ: types.Type{Oid: types.T_varchar, Size: 24},
IsConst: isPattenConst,
Length: 10,
}
return resVectors
}
......@@ -1282,10 +1282,7 @@ var operators = map[int][]Function{
Layout: BINARY_LOGICAL_OPERATOR,
Args: nil,
ReturnTyp: types.T_bool,
Fn: func(vs []*vector.Vector, proc *process.Process) (*vector.Vector, error) {
_, _ = vs[0].Col.(*types.Bytes), vs[1].Col.(*types.Bytes)
return nil, nil
},
Fn: operator.Like,
TypeCheckFn: func(inputTypes []types.T, _ []types.T) (match bool) {
if len(inputTypes) != 2 {
return false
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment