Skip to content

Commit 0d7daa4

Browse files
authored
implement nullif() function (#6448)
1 parent 14c966f commit 0d7daa4

File tree

8 files changed

+127
-1
lines changed

8 files changed

+127
-1
lines changed

runtime/sam/expr/function/function.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ func New(sctx *super.Context, name string, narg int) (expr.Function, error) {
115115
argmax = 0
116116
argmin = 0
117117
f = &Now{}
118+
case "nullif":
119+
argmin, argmax = 2, 2
120+
f = newNullIf()
118121
case "parse_sup":
119122
f = newParseSUP(sctx)
120123
case "parse_uri":
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package function
2+
3+
import (
4+
"github.com/brimdata/super"
5+
"github.com/brimdata/super/order"
6+
"github.com/brimdata/super/runtime/sam/expr"
7+
)
8+
9+
type NullIf struct {
10+
compareFn expr.CompareFn
11+
}
12+
13+
func newNullIf() *NullIf {
14+
return &NullIf{expr.NewValueCompareFn(order.Asc, order.NullsLast)}
15+
}
16+
17+
func (n *NullIf) Call(args []super.Value) super.Value {
18+
val0, val1 := args[0].Under(), args[1].Under()
19+
if val0.IsError() {
20+
return val0
21+
}
22+
if val1.IsError() {
23+
return val1
24+
}
25+
if n.compareFn(val0, val1) == 0 {
26+
return super.NewValue(val0.Type(), nil)
27+
}
28+
return val0
29+
}

runtime/vam/expr/compare.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ func NewCompare(sctx *super.Context, op string, lhs, rhs Evaluator) *Compare {
2323
return &Compare{sctx, vector.CompareOpFromString(op), lhs, rhs}
2424
}
2525

26+
func (c *Compare) Compare(vec0, vec1 vector.Any) vector.Any {
27+
return c.eval(vec0, vec1)
28+
}
29+
2630
func (c *Compare) Eval(val vector.Any) vector.Any {
2731
return vector.Apply(true, c.eval, c.lhs.Eval(val), c.rhs.Eval(val))
2832
}

runtime/vam/expr/function/function.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ func New(sctx *super.Context, name string, narg int) (expr.Function, error) {
8787
case "network_of":
8888
argmax = 2
8989
f = &NetworkOf{sctx}
90+
case "nullif":
91+
argmin, argmax = 2, 2
92+
f = newNullIf(sctx)
9093
case "parse_sup":
9194
f = newParseSUP(sctx)
9295
case "parse_uri":
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package function
2+
3+
import (
4+
"github.com/brimdata/super"
5+
"github.com/brimdata/super/runtime/vam/expr"
6+
"github.com/brimdata/super/vector"
7+
"github.com/brimdata/super/vector/bitvec"
8+
)
9+
10+
type NullIf struct {
11+
compare *expr.Compare
12+
}
13+
14+
func newNullIf(sctx *super.Context) *NullIf {
15+
return &NullIf{expr.NewCompare(sctx, "==", nil, nil)}
16+
}
17+
18+
func (n *NullIf) Call(vecs ...vector.Any) vector.Any {
19+
if vecs[0].Type().Kind() == super.ErrorKind {
20+
return vecs[0]
21+
}
22+
if vecs[1].Type().Kind() == super.ErrorKind {
23+
return vecs[1]
24+
}
25+
result := n.compare.Compare(vecs[0], vecs[1])
26+
if result.Type().Kind() == super.ErrorKind {
27+
return vecs[0]
28+
}
29+
nulls := vector.NullsOf(vecs[0]).Clone()
30+
for i := range result.Len() {
31+
if b, _ := vector.BoolValue(result, i); b {
32+
if nulls.IsZero() {
33+
nulls = bitvec.NewFalse(vecs[0].Len())
34+
}
35+
nulls.Set(i)
36+
}
37+
}
38+
return vector.CopyAndSetNulls(vecs[0], nulls)
39+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
spq: nullif(this[0], this[1])
2+
3+
vector: true
4+
5+
input: |
6+
[1, 1]
7+
[1, 1::int32]
8+
[1::int32, 1]
9+
[1, 2]
10+
[1, "s"]
11+
[1, null]
12+
[1, error(0)]
13+
[null, 1]
14+
[null, null]
15+
[null, error(0)]
16+
[error(0), 1]
17+
[error(0), null]
18+
[error(0), error(1)]
19+
20+
output: |
21+
null::int64
22+
null::int64
23+
null::int32
24+
1
25+
1
26+
1
27+
error(0)
28+
null::int64
29+
null
30+
null::error(int64)
31+
error(0)
32+
error(0)
33+
error(0)

vector/bitvec/bits.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package bitvec
22

33
import (
44
"math/bits"
5+
"slices"
56
"strings"
67
)
78

@@ -28,6 +29,10 @@ func NewTrue(n uint32) Bits {
2829
return b
2930
}
3031

32+
func (b Bits) Clone() Bits {
33+
return Bits{slices.Clone(b.bits), b.length}
34+
}
35+
3136
func (b Bits) IsZero() bool {
3237
return b.length == 0
3338
}

vector/bool.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package vector
22

33
import (
4+
"fmt"
5+
46
"github.com/brimdata/super"
57
"github.com/brimdata/super/scode"
68
"github.com/brimdata/super/vector/bitvec"
@@ -81,7 +83,7 @@ func BoolValue(vec Any, slot uint32) (bool, bool) {
8183
case *View:
8284
return BoolValue(vec.Any, vec.Index[slot])
8385
}
84-
panic(vec)
86+
panic(fmt.Sprintf("%#v", vec))
8587
}
8688

8789
func NullsOf(v Any) bitvec.Bits {
@@ -211,6 +213,14 @@ func CopyAndSetNulls(v Any, nulls bitvec.Bits) Any {
211213
return &copy
212214
case *Union:
213215
return NewUnion(v.Typ, v.Tags, v.Values, nulls)
216+
case *View:
217+
newNulls := bitvec.NewFalse(uint32(len(v.Index)))
218+
for i, idx := range v.Index {
219+
if nulls.IsSet(uint32(i)) {
220+
newNulls.Set(idx)
221+
}
222+
}
223+
return NewView(CopyAndSetNulls(v.Any, newNulls), v.Index)
214224
default:
215225
panic(v)
216226
}

0 commit comments

Comments
 (0)