From ba9d4d04281a15cb5e12ea22c623a2e2338cb6d1 Mon Sep 17 00:00:00 2001 From: Alan Cai Date: Fri, 9 Aug 2024 14:04:55 -0700 Subject: [PATCH 1/3] Fix some more SQL set op + PartiQL bag op tests --- .../primitives/operators/bag-operators.ion | 204 +++++++++++++++--- partiql-tests-data/eval/rfc/0007.ion | 24 ++- .../primitives/union-except-intersect.ion | 136 ++++++++++-- 3 files changed, 314 insertions(+), 50 deletions(-) diff --git a/partiql-tests-data/eval/primitives/operators/bag-operators.ion b/partiql-tests-data/eval/primitives/operators/bag-operators.ion index 29fad6c..8bdc517 100644 --- a/partiql-tests-data/eval/primitives/operators/bag-operators.ion +++ b/partiql-tests-data/eval/primitives/operators/bag-operators.ion @@ -143,56 +143,204 @@ bagOperators::[ ] } }, + // outer union coercion { name:"outerUnionCoerceScalar", statement:"1 OUTER UNION 2", - assert:{ - evalMode:[EvalModeCoerce, EvalModeError], - result:EvaluationSuccess, - output:$bag::[ - 1, - 2 - ] - } + assert:[ + { + evalMode:EvalModeCoerce, + result:EvaluationSuccess, + output:$bag::[ + 1, + 2 + ] + }, + { + evalMode:EvalModeError, + result:EvaluationFail + }, + ] }, { name:"outerUnionCoerceStruct", statement:"{'a': 1} OUTER UNION {'b': 2}", + assert:[ + { + evalMode:EvalModeCoerce, + result:EvaluationSuccess, + output:$bag::[ + { + a:1 + }, + { + b:2 + } + ] + }, + { + evalMode:EvalModeError, + result:EvaluationFail + }, + ] + }, + { + name:"outerUnionCoerceNullMissing", + statement:"NULL OUTER UNION MISSING", + assert:[ + { + evalMode:EvalModeCoerce, + result:EvaluationSuccess, + output:$bag::[ + ] + }, + { + evalMode: EvalModeError, + result:EvaluationFail + }, + ] + }, + { + name:"outerUnionCoerceList", + statement:"[ 1, 1, 1 ] OUTER UNION ALL [ 1, 2 ]", assert:{ evalMode:[EvalModeCoerce, EvalModeError], result:EvaluationSuccess, output:$bag::[ - { - a:1 - }, - { - b:2 - } + 1, + 1, + 1, + 1, + 2 ] } }, + // outer intersect coercion { - name:"outerUnionCoerceNullMissing", - statement:"NULL OUTER UNION MISSING", + name:"outerIntersectCoerceScalar", + statement:"1 OUTER INTERSECT 1", + assert:[ + { + evalMode:EvalModeCoerce, + result:EvaluationSuccess, + output:$bag::[ + 1 + ] + }, + { + evalMode:EvalModeError, + result:EvaluationFail + }, + ] + }, + { + name:"outerIntersectCoerceStruct", + statement:"{'a': 1} OUTER INTERSECT {'a': 1}", + assert:[ + { + evalMode:EvalModeCoerce, + result:EvaluationSuccess, + output:$bag::[ + { + a:1 + } + ] + }, + { + evalMode:EvalModeError, + result:EvaluationFail + }, + ] + }, + { + name:"outerIntersectCoerceNullMissing", + statement:"NULL OUTER INTERSECT MISSING", + assert:[ + { + evalMode:EvalModeCoerce, + result:EvaluationSuccess, + output:$bag::[ + ] + }, + { + evalMode: EvalModeError, + result:EvaluationFail + }, + ] + }, + { + name:"outerIntersectCoerceList", + statement:"[ 1, 1, 1 ] OUTER INTERSECT ALL [ 1, 2 ]", assert:{ evalMode:[EvalModeCoerce, EvalModeError], result:EvaluationSuccess, output:$bag::[ + 1 ] } }, + // outer except coercion { - name:"outerUnionCoerceList", - statement:"[ 1, 1, 1 ] OUTER UNION ALL [ 1, 2 ]", + name:"outerExceptCoerceScalar", + statement:"1 OUTER EXCEPT 2", + assert:[ + { + evalMode:EvalModeCoerce, + result:EvaluationSuccess, + output:$bag::[ + 1 + ] + }, + { + evalMode:EvalModeError, + result:EvaluationFail + }, + ] + }, + { + name:"outerExceptCoerceStruct", + statement:"{'a': 1} OUTER EXCEPT {'b': 2}", + assert:[ + { + evalMode:EvalModeCoerce, + result:EvaluationSuccess, + output:$bag::[ + { + a:1 + } + ] + }, + { + evalMode:EvalModeError, + result:EvaluationFail + }, + ] + }, + { + name:"outerExceptCoerceNullMissing", + statement:"NULL OUTER EXCEPT MISSING", + assert:[ + { + evalMode:EvalModeCoerce, + result:EvaluationSuccess, + output:$bag::[ + ] + }, + { + evalMode: EvalModeError, + result:EvaluationFail + }, + ] + }, + { + name:"outerExceptCoerceList", + statement:"[ 1, 1, 1 ] OUTER EXCEPT ALL [ 1, 2 ]", assert:{ evalMode:[EvalModeCoerce, EvalModeError], result:EvaluationSuccess, output:$bag::[ 1, - 1, - 1, - 1, - 2 + 1 ] } }, @@ -244,8 +392,8 @@ bagOperators::[ } }, { - name:"OUTER UNION with ORDER BY LIMIT on children and bag op", - statement:"(SELECT a, tbl FROM t1 ORDER BY a LIMIT 2) OUTER UNION ALL (SELECT a, tbl FROM t2 ORDER BY a LIMIT 2) ORDER BY a LIMIT 2", + name:"SQL UNION with ORDER BY LIMIT on children and bag op", + statement:"(SELECT a, tbl FROM t1 ORDER BY a LIMIT 2) UNION ALL (SELECT a, tbl FROM t2 ORDER BY a LIMIT 2) ORDER BY a LIMIT 2", assert:{ evalMode:[EvalModeCoerce, EvalModeError], result:EvaluationSuccess, @@ -262,8 +410,8 @@ bagOperators::[ } }, { - name:"OUTER INTERSECT with ORDER BY LIMIT on children and bag op", - statement:"(SELECT a FROM t1 ORDER BY a LIMIT 4) OUTER INTERSECT ALL (SELECT a FROM t2 ORDER BY a LIMIT 4) ORDER BY a LIMIT 2", + name:"SQL INTERSECT with ORDER BY LIMIT on children and bag op", + statement:"(SELECT a FROM t1 ORDER BY a LIMIT 4) INTERSECT ALL (SELECT a FROM t2 ORDER BY a LIMIT 4) ORDER BY a LIMIT 2", assert:{ evalMode:[EvalModeCoerce, EvalModeError], result:EvaluationSuccess, @@ -278,8 +426,8 @@ bagOperators::[ } }, { - name:"OUTER EXCEPT with ORDER BY LIMIT on children and bag op", - statement:"(SELECT a FROM t1 ORDER BY a LIMIT 2) OUTER EXCEPT ALL (SELECT a FROM t2 ORDER BY a LIMIT 2) ORDER BY a LIMIT 2", + name:"SQL EXCEPT with ORDER BY LIMIT on children and bag op", + statement:"(SELECT a FROM t1 ORDER BY a LIMIT 2) EXCEPT ALL (SELECT a FROM t2 ORDER BY a LIMIT 2) ORDER BY a LIMIT 2", assert:{ evalMode:[EvalModeCoerce, EvalModeError], result:EvaluationSuccess, diff --git a/partiql-tests-data/eval/rfc/0007.ion b/partiql-tests-data/eval/rfc/0007.ion index e708b7f..09243ff 100644 --- a/partiql-tests-data/eval/rfc/0007.ion +++ b/partiql-tests-data/eval/rfc/0007.ion @@ -174,14 +174,22 @@ bag::[ { name: "Example 6 — Value Coercion; Coercion of single value", statement: '''SELECT * FROM << 1 >> OUTER UNION 'A' ''', - assert: { - evalMode: [EvalModeCoerce, EvalModeError], - result: EvaluationSuccess, - output: $bag::[ - { "_1": 1 }, - "A", - ] - } + assert: [ + { + evalMode: EvalModeCoerce, + result: EvaluationSuccess, + output: $bag::[ + { + "_1": 1 + }, + "A", + ] + }, + { + evalMode: EvalModeError, + result: EvaluationFail, + }, + ] }, { name: "Example 6 — Value Coercion", diff --git a/partiql-tests-data/success/syntax/primitives/union-except-intersect.ion b/partiql-tests-data/success/syntax/primitives/union-except-intersect.ion index 985102d..77f0b30 100644 --- a/partiql-tests-data/success/syntax/primitives/union-except-intersect.ion +++ b/partiql-tests-data/success/syntax/primitives/union-except-intersect.ion @@ -158,7 +158,7 @@ 'order-by-limit-offset-bag-ops'::[ { - name: "UNION SFW children with ORDER BY LIMIT OFFSET", + name: "SQL UNION SFW children with ORDER BY LIMIT OFFSET", statement: ''' (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) UNION @@ -169,7 +169,7 @@ } }, { - name: "INTERSECT SFW children with ORDER BY LIMIT OFFSET", + name: "SQL INTERSECT SFW children with ORDER BY LIMIT OFFSET", statement: ''' (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) INTERSECT @@ -180,7 +180,7 @@ } }, { - name: "EXCEPT SFW children with ORDER BY LIMIT OFFSET", + name: "SQL EXCEPT SFW children with ORDER BY LIMIT OFFSET", statement: ''' (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) EXCEPT @@ -191,14 +191,14 @@ } }, { - name: "nested bag op with ORDER BY LIMIT OFFSET", + name: "nested SQL set op with ORDER BY LIMIT OFFSET", statement: ''' ( (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) UNION DISTINCT (SELECT a2 FROM b2 ORDER BY c2 LIMIT d2 OFFSET e2) ) - OUTER UNION ALL + UNION ALL (SELECT a3 FROM b3 ORDER BY c3 LIMIT d3 OFFSET e3) ORDER BY c4 LIMIT d4 OFFSET e4''', assert: { @@ -206,18 +206,126 @@ } }, { - name: "deep nested bag ops with ORDER BY LIMIT OFFSET", + name: "bag ops with ORDER BY LIMIT OFFSET in children", statement: ''' - (a UNION b) - INTERSECT - ( - c EXCEPT - d UNION ALL (e INTERSECT f ORDER BY g LIMIT h OFFSET i) - ) - EXCEPT j - ORDER BY k LIMIT l OFFSET m''', + (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) + OUTER UNION + (SELECT a2 FROM b2 ORDER BY c2 LIMIT d2 OFFSET e2) + OUTER INTERSECT ALL + (SELECT a3 FROM b3 ORDER BY c3 LIMIT d3 OFFSET e3) + OUTER EXCEPT DISTINCT + (SELECT a4 FROM b4 ORDER BY c4 LIMIT d4 OFFSET e4) + ''', assert: { result: SyntaxSuccess } }, + { + name: "disallow outer union with ORDER BY", + statement: ''' + (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) + OUTER UNION + (SELECT a2 FROM b2 ORDER BY c2 LIMIT d2 OFFSET e2) + ORDER BY c3 + ''', + assert: { + result: SyntaxFail + } + }, + { + name: "disallow outer union with LIMIT", + statement: ''' + (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) + OUTER UNION + (SELECT a2 FROM b2 ORDER BY c2 LIMIT d2 OFFSET e2) + LIMIT d3 + ''', + assert: { + result: SyntaxFail + } + }, + { + name: "disallow outer union with OFFSET", + statement: ''' + (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) + OUTER UNION + (SELECT a2 FROM b2 ORDER BY c2 LIMIT d2 OFFSET e2) + OFFSET e3 + ''', + assert: { + result: SyntaxFail + } + }, + { + name: "disallow outer intersect with ORDER BY", + statement: ''' + (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) + OUTER INTERSECT + (SELECT a2 FROM b2 ORDER BY c2 LIMIT d2 OFFSET e2) + ORDER BY c3 + ''', + assert: { + result: SyntaxFail + } + }, + { + name: "disallow outer intersect with LIMIT", + statement: ''' + (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) + OUTER INTERSECT + (SELECT a2 FROM b2 ORDER BY c2 LIMIT d2 OFFSET e2) + LIMIT d3 + ''', + assert: { + result: SyntaxFail + } + }, + { + name: "disallow outer intersect with OFFSET", + statement: ''' + (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) + OUTER INTERSECT + (SELECT a2 FROM b2 ORDER BY c2 LIMIT d2 OFFSET e2) + OFFSET e3 + ''', + assert: { + result: SyntaxFail + } + }, + { + name: "disallow outer except with ORDER BY", + statement: ''' + (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) + OUTER EXCEPT + (SELECT a2 FROM b2 ORDER BY c2 LIMIT d2 OFFSET e2) + ORDER BY c3 + ''', + assert: { + result: SyntaxFail + } + }, + { + name: "disallow outer except with LIMIT", + statement: ''' + (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) + OUTER EXCEPT + (SELECT a2 FROM b2 ORDER BY c2 LIMIT d2 OFFSET e2) + LIMIT d3 + ''', + assert: { + result: SyntaxFail + } + }, + { + name: "disallow outer except with OFFSET", + statement: ''' + (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) + OUTER EXCEPT + (SELECT a2 FROM b2 ORDER BY c2 LIMIT d2 OFFSET e2) + OFFSET e3 + ''', + assert: { + result: SyntaxFail + } + }, ] From 3183bb0073523bf295d3f6afb2b5e93c6f0ab6e7 Mon Sep 17 00:00:00 2001 From: Alan Cai Date: Thu, 15 Aug 2024 16:28:26 -0700 Subject: [PATCH 2/3] Fix set op behavior --- .../primitives/operators/bag-operators.ion | 5 ++- .../primitives/union-except-intersect.ion | 36 +++++++++---------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/partiql-tests-data/eval/primitives/operators/bag-operators.ion b/partiql-tests-data/eval/primitives/operators/bag-operators.ion index 8bdc517..0b5535c 100644 --- a/partiql-tests-data/eval/primitives/operators/bag-operators.ion +++ b/partiql-tests-data/eval/primitives/operators/bag-operators.ion @@ -192,6 +192,8 @@ bagOperators::[ evalMode:EvalModeCoerce, result:EvaluationSuccess, output:$bag::[ + null, + $missing::null ] }, { @@ -259,7 +261,7 @@ bagOperators::[ { evalMode:EvalModeCoerce, result:EvaluationSuccess, - output:$bag::[ + output:$bag::[ // still empty bag since both sides coerce to bag of absent value ] }, { @@ -324,6 +326,7 @@ bagOperators::[ evalMode:EvalModeCoerce, result:EvaluationSuccess, output:$bag::[ + null ] }, { diff --git a/partiql-tests-data/success/syntax/primitives/union-except-intersect.ion b/partiql-tests-data/success/syntax/primitives/union-except-intersect.ion index 77f0b30..ed789cd 100644 --- a/partiql-tests-data/success/syntax/primitives/union-except-intersect.ion +++ b/partiql-tests-data/success/syntax/primitives/union-except-intersect.ion @@ -221,7 +221,7 @@ } }, { - name: "disallow outer union with ORDER BY", + name: "allow outer union with ORDER BY", statement: ''' (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) OUTER UNION @@ -229,11 +229,11 @@ ORDER BY c3 ''', assert: { - result: SyntaxFail + result: SyntaxSuccess } }, { - name: "disallow outer union with LIMIT", + name: "allow outer union with LIMIT", statement: ''' (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) OUTER UNION @@ -241,11 +241,11 @@ LIMIT d3 ''', assert: { - result: SyntaxFail + result: SyntaxSuccess } }, { - name: "disallow outer union with OFFSET", + name: "allow outer union with OFFSET", statement: ''' (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) OUTER UNION @@ -253,11 +253,11 @@ OFFSET e3 ''', assert: { - result: SyntaxFail + result: SyntaxSuccess } }, { - name: "disallow outer intersect with ORDER BY", + name: "allow outer intersect with ORDER BY", statement: ''' (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) OUTER INTERSECT @@ -265,11 +265,11 @@ ORDER BY c3 ''', assert: { - result: SyntaxFail + result: SyntaxSuccess } }, { - name: "disallow outer intersect with LIMIT", + name: "allow outer intersect with LIMIT", statement: ''' (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) OUTER INTERSECT @@ -277,11 +277,11 @@ LIMIT d3 ''', assert: { - result: SyntaxFail + result: SyntaxSuccess } }, { - name: "disallow outer intersect with OFFSET", + name: "allow outer intersect with OFFSET", statement: ''' (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) OUTER INTERSECT @@ -289,11 +289,11 @@ OFFSET e3 ''', assert: { - result: SyntaxFail + result: SyntaxSuccess } }, { - name: "disallow outer except with ORDER BY", + name: "allow outer except with ORDER BY", statement: ''' (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) OUTER EXCEPT @@ -301,11 +301,11 @@ ORDER BY c3 ''', assert: { - result: SyntaxFail + result: SyntaxSuccess } }, { - name: "disallow outer except with LIMIT", + name: "allow outer except with LIMIT", statement: ''' (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) OUTER EXCEPT @@ -313,11 +313,11 @@ LIMIT d3 ''', assert: { - result: SyntaxFail + result: SyntaxSuccess } }, { - name: "disallow outer except with OFFSET", + name: "allow outer except with OFFSET", statement: ''' (SELECT a1 FROM b1 ORDER BY c1 LIMIT d1 OFFSET e1) OUTER EXCEPT @@ -325,7 +325,7 @@ OFFSET e3 ''', assert: { - result: SyntaxFail + result: SyntaxSuccess } }, ] From 8c398834a04e3f6600f44076a7354d70983f815d Mon Sep 17 00:00:00 2001 From: Alan Cai Date: Wed, 21 Aug 2024 12:02:03 -0700 Subject: [PATCH 3/3] Fix null/missing set op coerce tests --- .../primitives/operators/bag-operators.ion | 62 ++++++++++++++++--- 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/partiql-tests-data/eval/primitives/operators/bag-operators.ion b/partiql-tests-data/eval/primitives/operators/bag-operators.ion index 0b5535c..56bc0e9 100644 --- a/partiql-tests-data/eval/primitives/operators/bag-operators.ion +++ b/partiql-tests-data/eval/primitives/operators/bag-operators.ion @@ -193,7 +193,6 @@ bagOperators::[ result:EvaluationSuccess, output:$bag::[ null, - $missing::null ] }, { @@ -261,7 +260,8 @@ bagOperators::[ { evalMode:EvalModeCoerce, result:EvaluationSuccess, - output:$bag::[ // still empty bag since both sides coerce to bag of absent value + output:$bag::[ + null ] }, { @@ -325,9 +325,7 @@ bagOperators::[ { evalMode:EvalModeCoerce, result:EvaluationSuccess, - output:$bag::[ - null - ] + output:$bag::[] }, { evalMode: EvalModeError, @@ -395,7 +393,7 @@ bagOperators::[ } }, { - name:"SQL UNION with ORDER BY LIMIT on children and bag op", + name:"SQL UNION with ORDER BY LIMIT on children and set op", statement:"(SELECT a, tbl FROM t1 ORDER BY a LIMIT 2) UNION ALL (SELECT a, tbl FROM t2 ORDER BY a LIMIT 2) ORDER BY a LIMIT 2", assert:{ evalMode:[EvalModeCoerce, EvalModeError], @@ -413,7 +411,7 @@ bagOperators::[ } }, { - name:"SQL INTERSECT with ORDER BY LIMIT on children and bag op", + name:"SQL INTERSECT with ORDER BY LIMIT on children and set op", statement:"(SELECT a FROM t1 ORDER BY a LIMIT 4) INTERSECT ALL (SELECT a FROM t2 ORDER BY a LIMIT 4) ORDER BY a LIMIT 2", assert:{ evalMode:[EvalModeCoerce, EvalModeError], @@ -429,7 +427,7 @@ bagOperators::[ } }, { - name:"SQL EXCEPT with ORDER BY LIMIT on children and bag op", + name:"SQL EXCEPT with ORDER BY LIMIT on children and set op", statement:"(SELECT a FROM t1 ORDER BY a LIMIT 2) EXCEPT ALL (SELECT a FROM t2 ORDER BY a LIMIT 2) ORDER BY a LIMIT 2", assert:{ evalMode:[EvalModeCoerce, EvalModeError], @@ -441,4 +439,52 @@ bagOperators::[ ] } }, + // following tests are equivalent to above but use the PartiQL outer bag op + { + name:"PartiQL OUTER UNION with ORDER BY LIMIT on children and bag op", + statement:"(SELECT a, tbl FROM t1 ORDER BY a LIMIT 2) OUTER UNION ALL (SELECT a, tbl FROM t2 ORDER BY a LIMIT 2) ORDER BY a LIMIT 2", + assert:{ + evalMode:[EvalModeCoerce, EvalModeError], + result:EvaluationSuccess, + output:[ + { + a: 1, + tbl: 1, + }, + { + a: 2, + tbl: 1 + } + ] + } + }, + { + name:"PartiQL OUTER INTERSECT with ORDER BY LIMIT on children and bag op", + statement:"(SELECT a FROM t1 ORDER BY a LIMIT 4) OUTER INTERSECT ALL (SELECT a FROM t2 ORDER BY a LIMIT 4) ORDER BY a LIMIT 2", + assert:{ + evalMode:[EvalModeCoerce, EvalModeError], + result:EvaluationSuccess, + output:[ + { + a: 2, + }, + { + a: 3, + } + ] + } + }, + { + name:"PartiQL OUTER EXCEPT with ORDER BY LIMIT on children and bag op", + statement:"(SELECT a FROM t1 ORDER BY a LIMIT 2) OUTER EXCEPT ALL (SELECT a FROM t2 ORDER BY a LIMIT 2) ORDER BY a LIMIT 2", + assert:{ + evalMode:[EvalModeCoerce, EvalModeError], + result:EvaluationSuccess, + output:[ + { + a: 1, + }, + ] + } + }, ]