Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions pkg/sql/colexec/evalExpression_zonemap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"context"
"testing"

"github.com/matrixorigin/matrixone/pkg/container/batch"
"github.com/matrixorigin/matrixone/pkg/container/types"
"github.com/matrixorigin/matrixone/pkg/container/vector"
"github.com/matrixorigin/matrixone/pkg/objectio"
Expand All @@ -27,6 +28,7 @@ import (
"github.com/matrixorigin/matrixone/pkg/sql/plan/function"
"github.com/matrixorigin/matrixone/pkg/testutil"
"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/index"
"github.com/matrixorigin/matrixone/pkg/vm/process"
"github.com/stretchr/testify/require"
)

Expand All @@ -42,6 +44,46 @@ func TestEvaluateFilterByZoneMapNullableInListIsConservative(t *testing.T) {
require.True(t, selected, plan2.FormatExpr(expr, plan2.FormatOption{}))
}

func TestEvaluateFilterByZoneMapNullableInVecIsConservative(t *testing.T) {
proc := testutil.NewProcess(t)
ctx := proc.Ctx

expr := makeVarcharInVecExpr(t, ctx, proc, "keep", true)
meta := makeVarcharBlockMeta("key", "keep")
zms, vecs := makeZoneMapEvalScratch(expr)

selected := colexec.EvaluateFilterByZoneMap(ctx, proc, expr, meta, map[int]int{0: 0}, zms, vecs)
require.True(t, selected, plan2.FormatExpr(expr, plan2.FormatOption{}))
}

func TestFoldedNullableInExprKeepsMatchAndNullsMiss(t *testing.T) {
proc := testutil.NewProcess(t)
ctx := proc.Ctx

expr := makeVarcharInExpr(t, ctx, "keep", true)
folded, err := plan2.ConstantFold(batch.EmptyForConstFoldBatch, plan2.DeepCopyExpr(expr), proc, true, true)
require.NoError(t, err)

result := evalVarcharPredicate(t, proc, folded, "keep", "key", "")
requireBoolValue(t, result, 0, true, false)
requireBoolValue(t, result, 1, false, true)
requireBoolValue(t, result, 2, false, true)
}

func TestFoldedNullableNotInExprNullsMiss(t *testing.T) {
proc := testutil.NewProcess(t)
ctx := proc.Ctx

expr := makeVarcharNotInExpr(t, ctx, "keep", true)
folded, err := plan2.ConstantFold(batch.EmptyForConstFoldBatch, plan2.DeepCopyExpr(expr), proc, true, true)
require.NoError(t, err)

result := evalVarcharPredicate(t, proc, folded, "keep", "key", "")
requireBoolValue(t, result, 0, false, false)
requireBoolValue(t, result, 1, false, true)
requireBoolValue(t, result, 2, false, true)
}

func TestEvaluateFilterByZoneMapStillPrunesFalseEquality(t *testing.T) {
proc := testutil.NewProcess(t)
ctx := proc.Ctx
Expand Down Expand Up @@ -286,6 +328,32 @@ func makeVarcharInExpr(t *testing.T, ctx context.Context, value string, withNull
return expr
}

func makeVarcharInVecExpr(t *testing.T, ctx context.Context, proc *process.Process, value string, withNull bool) *plan.Expr {
t.Helper()

vec := vector.NewVec(types.T_varchar.ToType())
require.NoError(t, vector.AppendBytes(vec, []byte(value), false, proc.Mp()))
if withNull {
require.NoError(t, vector.AppendBytes(vec, nil, true, proc.Mp()))
}
data, err := vec.MarshalBinary()
require.NoError(t, err)
vec.Free(proc.Mp())

vecLen := int32(1)
if withNull {
vecLen = 2
}
vecExpr := &plan.Expr{
Typ: makeVarcharColExpr().Typ,
Expr: &plan.Expr_Vec{Vec: &plan.LiteralVec{Len: vecLen, Data: data}},
}
return makeNativeVarcharInExpr(t, ctx, []*plan.Expr{
makeVarcharColExpr(),
vecExpr,
})
}

func makeNativeVarcharInExpr(t *testing.T, ctx context.Context, args []*plan.Expr) *plan.Expr {
t.Helper()

Expand Down Expand Up @@ -335,6 +403,43 @@ func makeVarcharNotInExpr(t *testing.T, ctx context.Context, value string, withN
return expr
}

func evalVarcharPredicate(t *testing.T, proc *process.Process, expr *plan.Expr, values ...string) *vector.Vector {
t.Helper()

input := batch.NewWithSize(1)
defer input.Clean(proc.Mp())
vec := vector.NewVec(types.T_varchar.ToType())
input.Vecs[0] = vec
for _, value := range values {
require.NoError(t, vector.AppendBytes(vec, []byte(value), value == "", proc.Mp()))
}
input.SetRowCount(len(values))

executor, err := colexec.NewExpressionExecutor(proc, expr)
require.NoError(t, err)
defer executor.Free()

result, err := executor.Eval(proc, []*batch.Batch{input}, nil)
require.NoError(t, err)
dup, err := result.Dup(proc.Mp())
require.NoError(t, err)
t.Cleanup(func() {
dup.Free(proc.Mp())
})
return dup
}

func requireBoolValue(t *testing.T, vec *vector.Vector, row uint64, expected bool, expectedNull bool) {
t.Helper()

param := vector.GenerateFunctionFixedTypeParameter[bool](vec)
actual, isNull := param.GetValue(row)
require.Equal(t, expectedNull, isNull)
if !expectedNull {
require.Equal(t, expected, actual)
}
}

func makeVarcharColExpr() *plan.Expr {
return makeVarcharColExprAt(0)
}
Expand Down
64 changes: 54 additions & 10 deletions pkg/sql/plan/function/operator_in.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ type TGenericOfIn interface {
}

type opOperatorFixedIn[T TGenericOfIn] struct {
ready bool
mp map[T]bool
ready bool
hasNull bool
mp map[T]bool
}

type opOperatorStrIn struct {
ready bool
mp map[string]bool
ready bool
hasNull bool
mp map[string]bool
}

func newOpOperatorFixedIn[T TGenericOfIn]() *opOperatorFixedIn[T] {
Expand All @@ -50,15 +52,22 @@ func newOpOperatorStrIn() *opOperatorStrIn {

func (op *opOperatorFixedIn[T]) init(tuple *vector.Vector) {
op.ready = true
op.hasNull = false

if tuple.IsConstNull() {
op.hasNull = true
op.mp = make(map[T]bool)
return
}
p := vector.GenerateFunctionFixedTypeParameter[T](tuple)

if tuple.IsConst() {
v, _ := p.GetValue(0)
v, null := p.GetValue(0)
if null {
op.hasNull = true
op.mp = make(map[T]bool)
return
}
op.mp = make(map[T]bool, 1)
op.mp[v] = true
return
Expand All @@ -67,23 +76,32 @@ func (op *opOperatorFixedIn[T]) init(tuple *vector.Vector) {
op.mp = make(map[T]bool, tuple.Length())
for i := uint64(0); i < uint64(tuple.Length()); i++ {
v, null := p.GetValue(i)
if !null {
op.mp[v] = true
if null {
op.hasNull = true
continue
}
op.mp[v] = true
}
}

func (op *opOperatorStrIn) init(tuple *vector.Vector) {
op.ready = true
op.hasNull = false

if tuple.IsConstNull() {
op.hasNull = true
op.mp = make(map[string]bool)
return
}
p := vector.GenerateFunctionStrParameter(tuple)

if tuple.IsConst() {
v, _ := p.GetStrValue(0)
v, null := p.GetStrValue(0)
if null {
op.hasNull = true
op.mp = make(map[string]bool)
return
}
op.mp = make(map[string]bool, 1)
op.mp[string(v)] = true
return
Expand All @@ -92,9 +110,11 @@ func (op *opOperatorStrIn) init(tuple *vector.Vector) {
op.mp = make(map[string]bool)
for i := uint64(0); i < uint64(tuple.Length()); i++ {
v, null := p.GetStrValue(i)
if !null {
op.mp[string(v)] = true
if null {
op.hasNull = true
continue
}
op.mp[string(v)] = true
}
}

Expand All @@ -113,6 +133,12 @@ func (op *opOperatorFixedIn[T]) operatorIn(parameters []*vector.Vector, result v
}
} else {
_, ok := op.mp[v]
if !ok && op.hasNull {
if err := rs.Append(false, true); err != nil {
return err
}
continue
}
if err := rs.Append(ok, false); err != nil {
return err
}
Expand All @@ -136,6 +162,12 @@ func (op *opOperatorFixedIn[T]) operatorNotIn(parameters []*vector.Vector, resul
}
} else {
_, ok := op.mp[v]
if !ok && op.hasNull {
if err := rs.Append(false, true); err != nil {
return err
}
continue
}
if err := rs.Append(!ok, false); err != nil {
return err
}
Expand All @@ -159,6 +191,12 @@ func (op *opOperatorStrIn) operatorIn(parameters []*vector.Vector, result vector
}
} else {
_, ok := op.mp[string(v)]
if !ok && op.hasNull {
if err := rs.Append(false, true); err != nil {
return err
}
continue
}
if err := rs.Append(ok, false); err != nil {
return err
}
Expand All @@ -182,6 +220,12 @@ func (op *opOperatorStrIn) operatorNotIn(parameters []*vector.Vector, result vec
}
} else {
_, ok := op.mp[string(v)]
if !ok && op.hasNull {
if err := rs.Append(false, true); err != nil {
return err
}
continue
}
if err := rs.Append(!ok, false); err != nil {
return err
}
Expand Down
Loading
Loading