Skip to content

Commit 410278f

Browse files
committed
chore(embedded/sql): add COALESCE function
Signed-off-by: Stefano Scafiti <[email protected]>
1 parent 519cbc7 commit 410278f

File tree

2 files changed

+78
-0
lines changed

2 files changed

+78
-0
lines changed

embedded/sql/engine_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9513,6 +9513,51 @@ func TestFunctions(t *testing.T) {
95139513
)
95149514
require.NoError(t, err)
95159515

9516+
t.Run("coalesce", func(t *testing.T) {
9517+
type testCase struct {
9518+
query string
9519+
expectedValues string
9520+
err error
9521+
}
9522+
9523+
cases := []testCase{
9524+
{
9525+
query: "SELECT COALESCE (NULL)",
9526+
expectedValues: "NULL",
9527+
},
9528+
{
9529+
query: "SELECT COALESCE (NULL, NULL)",
9530+
expectedValues: "NULL",
9531+
},
9532+
{
9533+
query: "SELECT COALESCE(NULL, 1, 1.5, 3)",
9534+
expectedValues: "1",
9535+
},
9536+
{
9537+
query: "SELECT COALESCE('one', 'two', 'three')",
9538+
expectedValues: "'one'",
9539+
},
9540+
{
9541+
query: "SELECT COALESCE(1, 'test')",
9542+
err: ErrInvalidTypes,
9543+
},
9544+
}
9545+
9546+
for _, tc := range cases {
9547+
if tc.err != nil {
9548+
_, err := engine.queryAll(context.Background(), nil, tc.query, nil)
9549+
require.ErrorIs(t, err, tc.err)
9550+
continue
9551+
}
9552+
9553+
assertQueryShouldProduceResults(
9554+
t,
9555+
engine,
9556+
tc.query,
9557+
fmt.Sprintf("SELECT * FROM (VALUES (%s))", tc.expectedValues))
9558+
}
9559+
})
9560+
95169561
t.Run("timestamp functions", func(t *testing.T) {
95179562
_, err := engine.queryAll(context.Background(), nil, "SELECT NOW(1) FROM mytable", nil)
95189563
require.ErrorIs(t, err, ErrIllegalArguments)

embedded/sql/functions.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
)
2626

2727
const (
28+
CoalesceFnCall string = "COALESCE"
2829
LengthFnCall string = "LENGTH"
2930
SubstringFnCall string = "SUBSTRING"
3031
ConcatFnCall string = "CONCAT"
@@ -47,6 +48,7 @@ const (
4748
)
4849

4950
var builtinFunctions = map[string]Function{
51+
CoalesceFnCall: &CoalesceFn{},
5052
LengthFnCall: &LengthFn{},
5153
SubstringFnCall: &SubstringFn{},
5254
ConcatFnCall: &ConcatFn{},
@@ -67,6 +69,37 @@ type Function interface {
6769
Apply(tx *SQLTx, params []TypedValue) (TypedValue, error)
6870
}
6971

72+
type CoalesceFn struct{}
73+
74+
func (f *CoalesceFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
75+
return AnyType, nil
76+
}
77+
78+
func (f *CoalesceFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
79+
return nil
80+
}
81+
82+
func (f *CoalesceFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
83+
t := AnyType
84+
85+
for _, p := range params {
86+
if !p.IsNull() {
87+
if t == AnyType {
88+
t = p.Type()
89+
} else if p.Type() != t && !(IsNumericType(t) && IsNumericType(p.Type())) {
90+
return nil, fmt.Errorf("coalesce: %w", ErrInvalidTypes)
91+
}
92+
}
93+
}
94+
95+
for _, p := range params {
96+
if !p.IsNull() {
97+
return p, nil
98+
}
99+
}
100+
return NewNull(t), nil
101+
}
102+
70103
// -------------------------------------
71104
// String Functions
72105
// -------------------------------------

0 commit comments

Comments
 (0)