Skip to content

Commit 43a111b

Browse files
authored
allow SPQ cast of null to any type (#6666)
Since removal of typed nulls in #6633, a cast in SPQ of null to any type other than null or a nullable union (i.e., a union containing null) results in an error. Since SQL allows a cast of null to any type, do likewise in SPQ with the result of a cast to a non-null type being a nullable union containing the null value. For example, the result of `null::int64` is `null::(int64|null)`. Note that SUP retains the restriction that null can be cast only to null or a nullable union.
1 parent 722317d commit 43a111b

24 files changed

+58
-45
lines changed

context.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -593,12 +593,12 @@ func (c *Context) WrapError(msg string, val Value) Value {
593593
return NewValue(errType, b.Bytes())
594594
}
595595

596-
func (c *Context) Nullable(typ Type) Type {
596+
func (c *Context) Nullable(typ Type) *TypeUnion {
597597
var types []Type
598598
if union, ok := TypeUnder(typ).(*TypeUnion); ok {
599599
for _, t := range union.Types {
600600
if t == TypeNull {
601-
return typ
601+
return union
602602
}
603603
}
604604
types = slices.Clone(union.Types)

runtime/sam/expr/function/cast.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ func (c *cast) Cast(from super.Value, to super.Type) super.Value {
5050
return from
5151
case fromType.ID() == to.ID():
5252
return super.NewValue(to, from.Bytes())
53+
case fromType == super.TypeNull:
54+
union := c.sctx.Nullable(to)
55+
var b scode.Builder
56+
super.BuildUnion(&b, union.TagOf(super.TypeNull), nil)
57+
return super.NewValue(union, b.Bytes().Body())
5358
}
5459
switch to := to.(type) {
5560
case *super.TypeRecord:

runtime/vam/expr/cast/cast.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,15 @@ func To(sctx *super.Context, vec vector.Any, typ super.Type) vector.Any {
1414
vec = vector.Under(vec)
1515
switch vec.Kind() {
1616
case vector.KindNull:
17-
return errCastFailed(sctx, vec, typ, "")
17+
union := sctx.Nullable(typ)
18+
tag := union.TagOf(super.TypeNull)
19+
tags := make([]uint32, vec.Len())
20+
for i := range vec.Len() {
21+
tags[i] = uint32(tag)
22+
}
23+
vecs := make([]vector.Any, len(union.Types))
24+
vecs[tag] = vector.NewConst(super.Null, vec.Len())
25+
return vector.NewUnion(union, tags, vecs)
1826
case vector.KindError:
1927
return vec
2028
}

runtime/ztests/expr/cast-array.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ input: |
1111
|[1,2]|
1212
1313
output: |
14-
error({message:"cannot cast to [string]",on:null})
15-
[error({message:"cannot cast to string",on:null})]
16-
[error({message:"cannot cast to string",on:null})]
14+
null::(null|[string])
15+
[null]::[string|null]
16+
[null]::[string|null]
1717
["1","2"]
1818
["1","2"]
1919
["1","2"]

runtime/ztests/expr/cast/bool.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ output: |
3838
false
3939
false
4040
error({message:"cannot cast to bool",on:"blah"})
41-
error({message:"cannot cast to bool",on:null})
41+
null::(bool|null)
4242
true
4343
error("bad")
4444
error({message:"cannot cast to bool",on:{x:1}})

runtime/ztests/expr/cast/bytes.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@ output: |
1616
0x666f6f
1717
0x626172
1818
0x
19-
error({message:"cannot cast to bytes",on:null})
19+
null::(bytes|null)
2020
error({message:"cannot cast to bytes",on:{x:"foo"}})
2121
error("bad")

runtime/ztests/expr/cast/duration.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ output: |
2525
-25m
2626
1ns
2727
error({message:"cannot cast to duration",on:1e+19})
28-
error({message:"cannot cast to duration",on:null})
28+
null::(duration|null)
2929
error("bad")
3030
error({message:"cannot cast to duration",on:{x:1}})
3131
error({message:"cannot cast to duration",on:[1,2]})

runtime/ztests/expr/cast/enum.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ output: |
1313
"e2"::enum(e1,e2)
1414
error({message:"no such symbol in enum(e1,e2)",on:"e3"})
1515
error({message:"cannot cast to enum",on:0})
16-
error({message:"cannot cast to enum",on:null})
16+
null::(null|enum(e1,e2))
1717
error("bad")

runtime/ztests/expr/cast/float.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ input: |
1111
2::=named
1212
false
1313
true
14+
null
1415
1516
output: |
1617
1.5::float16
@@ -37,6 +38,9 @@ output: |
3738
1.::float16
3839
1.::float32
3940
1.
41+
null::(float16|null)
42+
null::(float32|null)
43+
null::(float64|null)
4044
4145
---
4246

@@ -45,15 +49,13 @@ spq: cast(this, <float64>)
4549
vector: true
4650

4751
input: |
48-
null
4952
error("bad")
5053
{x:1}
5154
[1,2]
5255
|[1,2]|
5356
|{"x":1}|
5457
5558
output: |
56-
error({message:"cannot cast to float64",on:null})
5759
error("bad")
5860
error({message:"cannot cast to float64",on:{x:1}})
5961
error({message:"cannot cast to float64",on:[1,2]})

runtime/ztests/expr/cast/int.yaml

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ vector: true
66
input: |
77
"-1"
88
"65535"
9-
null
109
1::uint64
1110
10000000000000000000::uint64
1211
-1.
1312
1.5::=named
1413
1e8
1514
false
1615
true
16+
null
1717
1818
output: |
1919
-1::int8
@@ -24,10 +24,6 @@ output: |
2424
error({message:"cannot cast to int16",on:"65535"})
2525
65535::int32
2626
65535
27-
error({message:"cannot cast to int8",on:null})
28-
error({message:"cannot cast to int16",on:null})
29-
error({message:"cannot cast to int32",on:null})
30-
error({message:"cannot cast to int64",on:null})
3127
1::int8
3228
1::int16
3329
1::int32
@@ -56,6 +52,10 @@ output: |
5652
1::int16
5753
1::int32
5854
1
55+
null::(int8|null)
56+
null::(int16|null)
57+
null::(int32|null)
58+
null::(int64|null)
5959
6060
---
6161

@@ -64,15 +64,13 @@ spq: cast(this, <int64>)
6464
vector: true
6565

6666
input: |
67-
null
6867
error("bad")
6968
{x:1}
7069
[1,2]
7170
|[1,2]|
7271
|{"x":1}|
7372
7473
output: |
75-
error({message:"cannot cast to int64",on:null})
7674
error("bad")
7775
error({message:"cannot cast to int64",on:{x:1}})
7876
error({message:"cannot cast to int64",on:[1,2]})

0 commit comments

Comments
 (0)