From 61aae86612a7bcd27b0173f1686e756ce1629813 Mon Sep 17 00:00:00 2001 From: Noah Treuhaft Date: Wed, 18 Mar 2026 12:30:38 -0400 Subject: [PATCH] vam: implement complex value comparisons This implements the same semantics as sam. It's inefficient but works for now. --- compiler/ztests/sql/having-this.yaml | 2 + compiler/ztests/this.yaml | 2 + runtime/vam/expr/compare.go | 32 ++++++- runtime/ztests/expr/compare.yaml | 127 +++++++++++++++++++++++++++ 4 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 runtime/ztests/expr/compare.yaml diff --git a/compiler/ztests/sql/having-this.yaml b/compiler/ztests/sql/having-this.yaml index f31b0b1362..37a9b2e98f 100644 --- a/compiler/ztests/sql/having-this.yaml +++ b/compiler/ztests/sql/having-this.yaml @@ -1,4 +1,6 @@ spq: select count() from (values 1,2) having this={count:2} +vector: true + output: | {count:2} diff --git a/compiler/ztests/this.yaml b/compiler/ztests/this.yaml index b57f9aa800..d22c95e003 100644 --- a/compiler/ztests/this.yaml +++ b/compiler/ztests/this.yaml @@ -1,5 +1,7 @@ spq: 'values {yodawg:this,b:this==this}' +vector: true + input: | {a:1} diff --git a/runtime/vam/expr/compare.go b/runtime/vam/expr/compare.go index 9f5310defe..c6d2820fc2 100644 --- a/runtime/vam/expr/compare.go +++ b/runtime/vam/expr/compare.go @@ -8,6 +8,7 @@ import ( "github.com/brimdata/super" "github.com/brimdata/super/runtime/sam/expr/coerce" + "github.com/brimdata/super/scode" "github.com/brimdata/super/vector" ) @@ -38,8 +39,8 @@ func (c *Compare) eval(vecs ...vector.Any) vector.Any { rhs := vector.Under(vecs[1]) lhs, rhs, errVal := coerceVals(c.sctx, lhs, rhs) if errVal != nil { - // if incompatible types return false - return vector.NewConstBool(false, vecs[0].Len()) + // Incompatible types so return true for != and false otherwise. + return vector.NewConstBool(c.opCode == vector.CompNE, errVal.Len()) } //XXX need to handle overflow (see sam) kind := lhs.Kind() @@ -53,6 +54,12 @@ func (c *Compare) eval(vecs ...vector.Any) vector.Any { return c.compareNets(lhs, rhs) case vector.KindType: return c.compareTypeVals(lhs, rhs) + case vector.KindRecord, + vector.KindArray, + vector.KindSet, + vector.KindMap, + vector.KindEnum: + return c.compareComplex(lhs, rhs) } lform, ok := vector.FormOf(lhs) if !ok { @@ -138,6 +145,27 @@ func (c *Compare) compareTypeVals(lhs, rhs vector.Any) vector.Any { return out } +func (c *Compare) compareComplex(lhs, rhs vector.Any) vector.Any { + if c.opCode == vector.CompLT || c.opCode == vector.CompGT || + lhs.Type().ID() != rhs.Type().ID() { + return vector.NewConstBool(false, lhs.Len()) + } + var lb, rb scode.Builder + out := vector.NewFalse(lhs.Len()) + for i := range lhs.Len() { + l := vector.ValueAt(&lb, lhs, i).Bytes() + r := vector.ValueAt(&rb, rhs, i).Bytes() + v := string(l) == string(r) + if c.opCode == vector.CompNE { + v = !v + } + if v { + out.Set(i) + } + } + return out +} + type isNull struct { expr Evaluator } diff --git a/runtime/ztests/expr/compare.yaml b/runtime/ztests/expr/compare.yaml new file mode 100644 index 0000000000..3dc7e6508f --- /dev/null +++ b/runtime/ztests/expr/compare.yaml @@ -0,0 +1,127 @@ +spq: values [a==b, a!=b, a=b, a>b] + +vector: true + +input: | + {a:{aa:1},b:{aa:1}} + {a:{aa:1},b:{aa:2}} + {a:{aa:1},b:{aa:"1"}} + {a:{aa:1},b:{aa:null}} + {a:{aa:1},b:{aa:error(0)}} + {a:{aa:1},b:{bb:1}} + {a:{aa:1},b:1} + {a:{aa:1},b:null} + {a:{aa:1},b:error(0)} + +output: | + [true,false,false,true,true,false] + [false,true,false,false,false,false] + [false,true,false,false,false,false] + [false,true,false,false,false,false] + [false,true,false,false,false,false] + [false,true,false,false,false,false] + [false,true,false,false,false,false] + [null,null,null,null,null,null] + [error(0),error(0),error(0),error(0),error(0),error(0)] + +--- + +spq: values [a==b, a!=b, a=b, a>b] + +vector: true + +input: | + {a:[1],b:[1]} + {a:[1],b:[2]} + {a:[1],b:["2"]} + {a:[1],b:[null]} + {a:[1],b:[error(0)]} + {a:[1],b:1} + {a:[1],b:null} + {a:[1],b:error(0)} + +output: | + [true,false,false,true,true,false] + [false,true,false,false,false,false] + [false,true,false,false,false,false] + [false,true,false,false,false,false] + [false,true,false,false,false,false] + [false,true,false,false,false,false] + [null,null,null,null,null,null] + [error(0),error(0),error(0),error(0),error(0),error(0)] + +--- + +spq: values [a==b, a!=b, a=b, a>b] + +vector: true + +input: | + {a:|[1]|,b:|[1]|} + {a:|[1]|,b:|[2]|} + {a:|[1]|,b:|["2"]|} + {a:|[1]|,b:|[null]|} + {a:|[1]|,b:|[error(0)]|} + {a:[1],b:1} + {a:|[1]|,b:null} + {a:|[1]|,b:error(0)} + +output: | + [true,false,false,true,true,false] + [false,true,false,false,false,false] + [false,true,false,false,false,false] + [false,true,false,false,false,false] + [false,true,false,false,false,false] + [false,true,false,false,false,false] + [null,null,null,null,null,null] + [error(0),error(0),error(0),error(0),error(0),error(0)] + +--- + +spq: values [a==b, a!=b, a=b, a>b] + +vector: true + +input: | + {a:|{"aa":1}|,b:|{"aa":1}|} + {a:|{"aa":1}|,b:|{"aa":2}|} + {a:|{"aa":1}|,b:|{"aa":"2"}|} + {a:|{"aa":1}|,b:|{"aa":null}|} + {a:|{"aa":1}|,b:|{"aa":error(0)}|} + {a:|{"aa":1}|,b:|{"bb":1}|} + {a:|{"aa":1}|,b:1} + {a:|{"aa":1}|,b:null} + {a:|{"aa":1}|,b:error(0)} + +output: | + [true,false,false,true,true,false] + [false,true,false,false,false,false] + [false,true,false,false,false,false] + [false,true,false,false,false,false] + [false,true,false,false,false,false] + [false,true,false,false,false,false] + [false,true,false,false,false,false] + [null,null,null,null,null,null] + [error(0),error(0),error(0),error(0),error(0),error(0)] + +--- + +spq: values [a==b, a!=b, a=b, a>b] + +vector: true + +input: | + {a:"aa"::enum(aa,bb),b:"aa"::enum(aa,bb)} + {a:"aa"::enum(aa,bb),b:"bb"::enum(aa,bb)} + {a:"aa"::enum(aa,bb),b:"aa"::enum(aa,zz)} + {a:"aa"::enum(aa,bb),b:"aa"} + {a:"aa"::enum(aa,bb),b:null} + {a:"aa"::enum(aa,bb),b:error(0)} + +output: | + [true,false,false,true,true,false] + [false,true,false,false,false,false] + [false,true,false,false,false,false] + [false,true,false,false,false,false] + [null,null,null,null,null,null] + [error(0),error(0),error(0),error(0),error(0),error(0)]