diff --git a/CHANGELOG.md b/CHANGELOG.md index 46b7c31647..3a13971730 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,11 @@ unconstrained which is not SQL-conformant and is causing issues in integrating w INTEGER an alias for INT4 which is the internal type name. In a later release, we will make INTEGER the default 32-bit integer with INT/INT4/INTEGER4 being aliases per other systems. This change only applies to org.partiql.parser.PartiQLParser, not the org.partiql.lang.syntax.PartiQLParser. +- **Breaking change**: partiql-plan: adds a set quantifier field to SQL set operators `UNION`, `INTERSECT`, and `EXCEPT` +- partiql-plan: adds a dedicated Rex node for PartiQL bag operators `UNION`, `INTERSECT`, and `EXCEPT` +- partiql-planner: Adds typing support for set operators +- partiql-parser: parses non-SFW expressions to be PartiQL `OUTER` bag operators +- partiql-ast: fixes missing parens from `bag_op` when printing using `SqlDialect` ### Deprecated @@ -1082,7 +1087,9 @@ breaking changes if migrating from v0.9.2. The breaking changes accidentally int ### Added Initial alpha release of PartiQL. -[Unreleased]: https://github.com/partiql/partiql-lang-kotlin/compare/v0.14.4...HEAD +[Unreleased]: https://github.com/partiql/partiql-lang-kotlin/compare/v0.14.6...HEAD +[0.14.6]: https://github.com/partiql/partiql-lang-kotlin/compare/v0.14.5...v0.14.6 +[0.14.5]: https://github.com/partiql/partiql-lang-kotlin/compare/v0.14.4...v0.14.5 [0.14.4]: https://github.com/partiql/partiql-lang-kotlin/compare/v0.14.3...v0.14.4 [0.14.3]: https://github.com/partiql/partiql-lang-kotlin/compare/v0.14.2...v0.14.3 [0.14.2]: https://github.com/partiql/partiql-lang-kotlin/compare/v0.14.1...v0.14.2 diff --git a/README.md b/README.md index 6818fc481a..26eccb7741 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ This project is published to [Maven Central](https://search.maven.org/artifact/o | Group ID | Artifact ID | Recommended Version | |---------------|-----------------------|---------------------| -| `org.partiql` | `partiql-lang-kotlin` | `0.14.5` | +| `org.partiql` | `partiql-lang-kotlin` | `0.14.6` | For Maven builds, add the following to your `pom.xml`: diff --git a/gradle.properties b/gradle.properties index e6bdc6d7bd..9c0c032835 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ group=org.partiql -version=0.14.6-SNAPSHOT +version=0.14.6 ossrhUsername=EMPTY ossrhPassword=EMPTY diff --git a/partiql-ast/src/main/kotlin/org/partiql/ast/sql/SqlDialect.kt b/partiql-ast/src/main/kotlin/org/partiql/ast/sql/SqlDialect.kt index 6a589a0556..c4ad9217fc 100644 --- a/partiql-ast/src/main/kotlin/org/partiql/ast/sql/SqlDialect.kt +++ b/partiql-ast/src/main/kotlin/org/partiql/ast/sql/SqlDialect.kt @@ -64,6 +64,13 @@ public abstract class SqlDialect : AstBaseVisitor() { h = h concat ")" h } + is Expr.BagOp -> { + var h = head + h = h concat "(" + h = visitExprBagOp(node, h) + h = h concat ")" + h + } else -> visitExpr(node, head) } diff --git a/partiql-ast/src/main/kotlin/org/partiql/ast/sql/internal/InternalSqlDialect.kt b/partiql-ast/src/main/kotlin/org/partiql/ast/sql/internal/InternalSqlDialect.kt index 4ecfb9d569..4612feefeb 100644 --- a/partiql-ast/src/main/kotlin/org/partiql/ast/sql/internal/InternalSqlDialect.kt +++ b/partiql-ast/src/main/kotlin/org/partiql/ast/sql/internal/InternalSqlDialect.kt @@ -82,6 +82,13 @@ internal abstract class InternalSqlDialect : AstBaseVisitor { + var t = tail + t = t concat "(" + t = visitExprBagOp(node, t) + t = t concat ")" + t + } else -> visitExpr(node, tail) } diff --git a/partiql-ast/src/main/resources/partiql_ast.ion b/partiql-ast/src/main/resources/partiql_ast.ion index 67c48663c8..37d833d96d 100644 --- a/partiql-ast/src/main/resources/partiql_ast.ion +++ b/partiql-ast/src/main/resources/partiql_ast.ion @@ -500,7 +500,7 @@ expr::[ where: optional::expr, group_by: optional::group_by, having: optional::expr, - set_op: optional::{ + set_op: optional::{ // TODO modeling of `set_op` needs updated to support left-associative set ops https://github.com/partiql/partiql-lang-kotlin/issues/1507 type: '.set_op', operand: '.expr.s_f_w', }, diff --git a/partiql-ast/src/test/kotlin/org/partiql/ast/sql/SqlDialectTest.kt b/partiql-ast/src/test/kotlin/org/partiql/ast/sql/SqlDialectTest.kt index 6276adb43d..9520d83519 100644 --- a/partiql-ast/src/test/kotlin/org/partiql/ast/sql/SqlDialectTest.kt +++ b/partiql-ast/src/test/kotlin/org/partiql/ast/sql/SqlDialectTest.kt @@ -986,6 +986,120 @@ class SqlDialectTest { rhs = v("y") } }, + expect("(x UNION y) UNION z") { + exprBagOp { + type = setOp { + type = SetOp.Type.UNION + setq = null + } + outer = false + lhs = exprBagOp { + type = setOp { + type = SetOp.Type.UNION + setq = null + } + outer = false + lhs = v("x") + rhs = v("y") + } + rhs = v("z") + } + }, + expect("x UNION (y UNION z)") { + exprBagOp { + type = setOp { + type = SetOp.Type.UNION + setq = null + } + outer = false + lhs = v("x") + rhs = exprBagOp { + type = setOp { + type = SetOp.Type.UNION + setq = null + } + outer = false + lhs = v("y") + rhs = v("z") + } + } + }, + expect("(x EXCEPT y) EXCEPT z") { + exprBagOp { + type = setOp { + type = SetOp.Type.EXCEPT + setq = null + } + outer = false + lhs = exprBagOp { + type = setOp { + type = SetOp.Type.EXCEPT + setq = null + } + outer = false + lhs = v("x") + rhs = v("y") + } + rhs = v("z") + } + }, + expect("x EXCEPT (y EXCEPT z)") { + exprBagOp { + type = setOp { + type = SetOp.Type.EXCEPT + setq = null + } + outer = false + lhs = v("x") + rhs = exprBagOp { + type = setOp { + type = SetOp.Type.EXCEPT + setq = null + } + outer = false + lhs = v("y") + rhs = v("z") + } + } + }, + expect("(x INTERSECT y) INTERSECT z") { + exprBagOp { + type = setOp { + type = SetOp.Type.INTERSECT + setq = null + } + outer = false + lhs = exprBagOp { + type = setOp { + type = SetOp.Type.INTERSECT + setq = null + } + outer = false + lhs = v("x") + rhs = v("y") + } + rhs = v("z") + } + }, + expect("x INTERSECT (y INTERSECT z)") { + exprBagOp { + type = setOp { + type = SetOp.Type.INTERSECT + setq = null + } + outer = false + lhs = v("x") + rhs = exprBagOp { + type = setOp { + type = SetOp.Type.INTERSECT + setq = null + } + outer = false + lhs = v("y") + rhs = v("z") + } + } + }, ) @JvmStatic diff --git a/partiql-lang/src/main/kotlin/org/partiql/lang/prettyprint/QueryPrettyPrinter.kt b/partiql-lang/src/main/kotlin/org/partiql/lang/prettyprint/QueryPrettyPrinter.kt index ce4d31f479..4e40444a47 100644 --- a/partiql-lang/src/main/kotlin/org/partiql/lang/prettyprint/QueryPrettyPrinter.kt +++ b/partiql-lang/src/main/kotlin/org/partiql/lang/prettyprint/QueryPrettyPrinter.kt @@ -320,7 +320,14 @@ class QueryPrettyPrinter { is PartiqlAst.Expr.Or -> writeNAryOperator("OR", node.operands, sb, level) is PartiqlAst.Expr.InCollection -> writeNAryOperator("IN", node.operands, sb, level) is PartiqlAst.Expr.BagOp -> { - var name = node.op.javaClass.simpleName.toUpperCase().replace("_", " ") + var name = when (node.op) { + is PartiqlAst.BagOpType.Except -> "EXCEPT" + is PartiqlAst.BagOpType.Intersect -> "INTERSECT" + is PartiqlAst.BagOpType.Union -> "UNION" + is PartiqlAst.BagOpType.OuterExcept -> "OUTER EXCEPT" + is PartiqlAst.BagOpType.OuterIntersect -> "OUTER INTERSECT" + is PartiqlAst.BagOpType.OuterUnion -> "OUTER UNION" + } if (node.quantifier is PartiqlAst.SetQuantifier.All) { name += " ALL" } diff --git a/partiql-lang/src/main/kotlin/org/partiql/lang/syntax/impl/PartiQLPigVisitor.kt b/partiql-lang/src/main/kotlin/org/partiql/lang/syntax/impl/PartiQLPigVisitor.kt index a74ef956d4..07eb7ea0b4 100644 --- a/partiql-lang/src/main/kotlin/org/partiql/lang/syntax/impl/PartiQLPigVisitor.kt +++ b/partiql-lang/src/main/kotlin/org/partiql/lang/syntax/impl/PartiQLPigVisitor.kt @@ -752,12 +752,33 @@ internal class PartiQLPigVisitor( * */ + /** + * Verifies if all of the [args] are + * 1. [PartiqlAst.Expr.Select] or + * 2. [PartiqlAst.Expr.BagOp] and is a SQL Set op (i.e. not an `OUTER` bag op) + */ + private fun argsAreSFW(args: List): Boolean { + return args.all { arg -> + arg is PartiqlAst.Expr.Select || (arg is PartiqlAst.Expr.BagOp && isOuter(arg.op)) + } + } + + private fun isOuter(op: PartiqlAst.BagOpType): Boolean { + return op is PartiqlAst.BagOpType.OuterUnion || op is PartiqlAst.BagOpType.OuterExcept || op is PartiqlAst.BagOpType.OuterIntersect + } + override fun visitIntersect(ctx: PartiQLParser.IntersectContext) = PartiqlAst.build { val lhs = visit(ctx.lhs) as PartiqlAst.Expr val rhs = visit(ctx.rhs) as PartiqlAst.Expr val quantifier = if (ctx.ALL() != null) all() else distinct() val (intersect, metas) = when (ctx.OUTER()) { - null -> intersect() to ctx.INTERSECT().getSourceMetaContainer() + null -> { + if (argsAreSFW(listOf(lhs, rhs))) { + intersect() to ctx.INTERSECT().getSourceMetaContainer() + } else { + outerIntersect() to ctx.OUTER().getSourceMetaContainer() + } + } else -> outerIntersect() to ctx.OUTER().getSourceMetaContainer() } bagOp(intersect, quantifier, listOf(lhs, rhs), metas) @@ -768,7 +789,13 @@ internal class PartiQLPigVisitor( val rhs = visit(ctx.rhs) as PartiqlAst.Expr val quantifier = if (ctx.ALL() != null) all() else distinct() val (except, metas) = when (ctx.OUTER()) { - null -> except() to ctx.EXCEPT().getSourceMetaContainer() + null -> { + if (argsAreSFW(listOf(lhs, rhs))) { + except() to ctx.EXCEPT().getSourceMetaContainer() + } else { + outerExcept() to ctx.OUTER().getSourceMetaContainer() + } + } else -> outerExcept() to ctx.OUTER().getSourceMetaContainer() } bagOp(except, quantifier, listOf(lhs, rhs), metas) @@ -779,7 +806,13 @@ internal class PartiQLPigVisitor( val rhs = visit(ctx.rhs) as PartiqlAst.Expr val quantifier = if (ctx.ALL() != null) all() else distinct() val (union, metas) = when (ctx.OUTER()) { - null -> union() to ctx.UNION().getSourceMetaContainer() + null -> { + if (argsAreSFW(listOf(lhs, rhs))) { + union() to ctx.UNION().getSourceMetaContainer() + } else { + outerUnion() to ctx.OUTER().getSourceMetaContainer() + } + } else -> outerUnion() to ctx.OUTER().getSourceMetaContainer() } bagOp(union, quantifier, listOf(lhs, rhs), metas) diff --git a/partiql-lang/src/test/kotlin/org/partiql/lang/prettyprint/ASTPrettyPrinterTest.kt b/partiql-lang/src/test/kotlin/org/partiql/lang/prettyprint/ASTPrettyPrinterTest.kt index e49fa8500a..fdd7c18012 100644 --- a/partiql-lang/src/test/kotlin/org/partiql/lang/prettyprint/ASTPrettyPrinterTest.kt +++ b/partiql-lang/src/test/kotlin/org/partiql/lang/prettyprint/ASTPrettyPrinterTest.kt @@ -539,7 +539,7 @@ class ASTPrettyPrinterTest { checkPrettyPrintAst( "a UNION b", """ - Union + OuterUnion Id a (case_insensitive) (unqualified) Id b (case_insensitive) (unqualified) """.trimIndent() @@ -551,7 +551,7 @@ class ASTPrettyPrinterTest { checkPrettyPrintAst( "a EXCEPT b", """ - Except + OuterExcept Id a (case_insensitive) (unqualified) Id b (case_insensitive) (unqualified) """.trimIndent() @@ -563,7 +563,7 @@ class ASTPrettyPrinterTest { checkPrettyPrintAst( "a INTERSECT b", """ - Intersect + OuterIntersect Id a (case_insensitive) (unqualified) Id b (case_insensitive) (unqualified) """.trimIndent() diff --git a/partiql-lang/src/test/kotlin/org/partiql/lang/prettyprint/QueryPrettyPrinterTest.kt b/partiql-lang/src/test/kotlin/org/partiql/lang/prettyprint/QueryPrettyPrinterTest.kt index 828d49ef36..29e73d7241 100644 --- a/partiql-lang/src/test/kotlin/org/partiql/lang/prettyprint/QueryPrettyPrinterTest.kt +++ b/partiql-lang/src/test/kotlin/org/partiql/lang/prettyprint/QueryPrettyPrinterTest.kt @@ -465,22 +465,22 @@ class QueryPrettyPrinterTest { @Test fun union1() { - checkPrettyPrintQuery("a UNION b", "a UNION b") + checkPrettyPrintQuery("a UNION b", "a OUTER UNION b") } @Test fun union2() { - checkPrettyPrintQuery("a UNION ALL b", "a UNION ALL b") + checkPrettyPrintQuery("a UNION ALL b", "a OUTER UNION ALL b") } @Test fun except() { - checkPrettyPrintQuery("a EXCEPT b", "a EXCEPT b") + checkPrettyPrintQuery("a EXCEPT b", "a OUTER EXCEPT b") } @Test fun intersect() { - checkPrettyPrintQuery("a INTERSECT b", "a INTERSECT b") + checkPrettyPrintQuery("a INTERSECT b", "a OUTER INTERSECT b") } @Test @@ -822,7 +822,7 @@ class QueryPrettyPrinterTest { checkPrettyPrintQuery( "(SELECT a FROM b) UNION (SELECT c FROM d) UNION (SELECT e FROM f)", """ - ((SELECT a FROM b) UNION (SELECT c FROM d)) UNION (SELECT e FROM f) + ((SELECT a FROM b) UNION (SELECT c FROM d)) OUTER UNION (SELECT e FROM f) """.trimIndent() ) } @@ -832,7 +832,7 @@ class QueryPrettyPrinterTest { checkPrettyPrintQuery( "(SELECT a FROM b) UNION c", """ - (SELECT a FROM b) UNION c + (SELECT a FROM b) OUTER UNION c """.trimIndent() ) } @@ -873,7 +873,7 @@ class QueryPrettyPrinterTest { "CASE (SELECT name FROM t) WHEN (SELECT a FROM b) UNION c THEN 1 WHEN (SELECT c FROM d) THEN 2 ELSE (SELECT e FROM f) END", """ CASE (SELECT name FROM t) - WHEN (SELECT a FROM b) UNION c THEN 1 + WHEN (SELECT a FROM b) OUTER UNION c THEN 1 WHEN (SELECT c FROM d) THEN 2 ELSE (SELECT e FROM f) END diff --git a/partiql-lang/src/test/kotlin/org/partiql/lang/syntax/PartiQLParserMatchTest.kt b/partiql-lang/src/test/kotlin/org/partiql/lang/syntax/PartiQLParserMatchTest.kt index d45c4a4fb1..16b2bb4db5 100644 --- a/partiql-lang/src/test/kotlin/org/partiql/lang/syntax/PartiQLParserMatchTest.kt +++ b/partiql-lang/src/test/kotlin/org/partiql/lang/syntax/PartiQLParserMatchTest.kt @@ -109,7 +109,7 @@ class PartiQLParserMatchTest : PartiQLParserTestBase() { "(MyGraph MATCH (x)) UNION SELECT * FROM tbl1" ) { bagOp( - op = union(), + op = outerUnion(), // TODO decide if graph match set op maps to PartiQL or SQL quantifier = distinct(), operands = listOf( astMygraphMatchAllNodes, @@ -142,7 +142,7 @@ class PartiQLParserMatchTest : PartiQLParserTestBase() { "SELECT * FROM tbl1 UNION (MyGraph MATCH (x))" ) { bagOp( - op = union(), + op = outerUnion(), // TODO decide if graph match set op maps to PartiQL or SQL quantifier = distinct(), operands = listOf( astSelectStarFromTbl1, diff --git a/partiql-lang/src/test/kotlin/org/partiql/lang/syntax/PartiQLParserPrecedenceTest.kt b/partiql-lang/src/test/kotlin/org/partiql/lang/syntax/PartiQLParserPrecedenceTest.kt index 48b5d05022..815e833196 100644 --- a/partiql-lang/src/test/kotlin/org/partiql/lang/syntax/PartiQLParserPrecedenceTest.kt +++ b/partiql-lang/src/test/kotlin/org/partiql/lang/syntax/PartiQLParserPrecedenceTest.kt @@ -30,33 +30,33 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { fun intersectPrecedence(pair: Pair) = runTest(pair) fun parametersForIntersectPrecedence(): List> = listOf( // two by two binary operators - /* (intersect, intersect_all) */ "a intersect b intersect all c" to "(bag_op (intersect) (all) (bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (intersect, except) */ "a intersect b except c" to "(bag_op (except) (distinct) (bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (intersect, except_all) */ "a intersect b except all c" to "(bag_op (except) (all) (bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (intersect, union) */ "a intersect b union c" to "(bag_op (union) (distinct) (bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (intersect, union_all) */ "a intersect b union all c" to "(bag_op (union) (all) (bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (intersect, and) */ "a intersect b and c" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (and (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect, or) */ "a intersect b or c" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (or (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect, =) */ "a intersect b = c" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (eq (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect, <>) */ "a intersect b <> c" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (ne (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect, in) */ "a intersect b in c" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect, not_in) */ "a intersect b not in c" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (not (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", - /* (intersect, <) */ "a intersect b < c" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (lt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect, <=) */ "a intersect b <= c" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (lte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect, >) */ "a intersect b > c" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (gt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect, >=) */ "a intersect b >= c" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (gte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect, between) */ "a intersect b between w and c" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (between (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect, not_between) */ "a intersect b not between y and c" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (not (between (id b (case_insensitive) (unqualified)) (id y (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", - /* (intersect, like) */ "a intersect b like c" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null))", - /* (intersect, not_like) */ "a intersect b not like c" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (not (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null)))", - /* (intersect, +) */ "a intersect b + c" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (plus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect, -) */ "a intersect b - c" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (minus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect, ||) */ "a intersect b || c" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (concat (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect, *) */ "a intersect b * c" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (times (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect, /) */ "a intersect b / c" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (divide (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect, %) */ "a intersect b % c" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (modulo (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect, is) */ "a intersect b is boolean" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (is_type (id b (case_insensitive) (unqualified)) (boolean_type)))", - /* (intersect, is_not) */ "a intersect b is not boolean" to "(bag_op (intersect) (distinct) (id a (case_insensitive) (unqualified)) (not (is_type (id b (case_insensitive) (unqualified)) (boolean_type))))" + /* (intersect, intersect_all) */ "a intersect b intersect all c" to "(bag_op (outer_intersect) (all) (bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (intersect, except) */ "a intersect b except c" to "(bag_op (outer_except) (distinct) (bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (intersect, except_all) */ "a intersect b except all c" to "(bag_op (outer_except) (all) (bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (intersect, union) */ "a intersect b union c" to "(bag_op (outer_union) (distinct) (bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (intersect, union_all) */ "a intersect b union all c" to "(bag_op (outer_union) (all) (bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (intersect, and) */ "a intersect b and c" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (and (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect, or) */ "a intersect b or c" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (or (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect, =) */ "a intersect b = c" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (eq (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect, <>) */ "a intersect b <> c" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (ne (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect, in) */ "a intersect b in c" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect, not_in) */ "a intersect b not in c" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (not (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", + /* (intersect, <) */ "a intersect b < c" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (lt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect, <=) */ "a intersect b <= c" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (lte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect, >) */ "a intersect b > c" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (gt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect, >=) */ "a intersect b >= c" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (gte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect, between) */ "a intersect b between w and c" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (between (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect, not_between) */ "a intersect b not between y and c" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (not (between (id b (case_insensitive) (unqualified)) (id y (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", + /* (intersect, like) */ "a intersect b like c" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null))", + /* (intersect, not_like) */ "a intersect b not like c" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (not (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null)))", + /* (intersect, +) */ "a intersect b + c" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (plus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect, -) */ "a intersect b - c" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (minus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect, ||) */ "a intersect b || c" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (concat (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect, *) */ "a intersect b * c" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (times (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect, /) */ "a intersect b / c" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (divide (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect, %) */ "a intersect b % c" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (modulo (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect, is) */ "a intersect b is boolean" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (is_type (id b (case_insensitive) (unqualified)) (boolean_type)))", + /* (intersect, is_not) */ "a intersect b is not boolean" to "(bag_op (outer_intersect) (distinct) (id a (case_insensitive) (unqualified)) (not (is_type (id b (case_insensitive) (unqualified)) (boolean_type))))" ) @Test @@ -64,33 +64,33 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun intersectAllPrecedence(pair: Pair) = runTest(pair) fun parametersForIntersectAllPrecedence() = listOf( - /* (intersect_all, intersect) */ "a intersect all b intersect c" to "(bag_op (intersect) (distinct) (bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (intersect_all, except) */ "a intersect all b except c" to "(bag_op (except) (distinct) (bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (intersect_all, except_all) */ "a intersect all b except all c" to "(bag_op (except) (all) (bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (intersect_all, union) */ "a intersect all b union c" to "(bag_op (union) (distinct) (bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (intersect_all, union_all) */ "a intersect all b union all c" to "(bag_op (union) (all) (bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (intersect_all, and) */ "a intersect all b and c" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (and (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect_all, or) */ "a intersect all b or c" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (or (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect_all, =) */ "a intersect all b = c" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (eq (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect_all, <>) */ "a intersect all b <> c" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (ne (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect_all, in) */ "a intersect all b in c" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect_all, not_in) */ "a intersect all b not in c" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (not (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", - /* (intersect_all, <) */ "a intersect all b < c" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (lt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect_all, <=) */ "a intersect all b <= c" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (lte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect_all, >) */ "a intersect all b > c" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (gt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect_all, >=) */ "a intersect all b >= c" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (gte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect_all, between) */ "a intersect all b between w and c" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (between (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect_all, not_between) */ "a intersect all b not between y and c" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (not (between (id b (case_insensitive) (unqualified)) (id y (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", - /* (intersect_all, like) */ "a intersect all b like c" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null))", - /* (intersect_all, not_like) */ "a intersect all b not like c" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (not (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null)))", - /* (intersect_all, +) */ "a intersect all b + c" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (plus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect_all, -) */ "a intersect all b - c" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (minus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect_all, ||) */ "a intersect all b || c" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (concat (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect_all, *) */ "a intersect all b * c" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (times (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect_all, /) */ "a intersect all b / c" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (divide (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect_all, %) */ "a intersect all b % c" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (modulo (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (intersect_all, is) */ "a intersect all b is boolean" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (is_type (id b (case_insensitive) (unqualified)) (boolean_type)))", - /* (intersect_all, is_not) */ "a intersect all b is not boolean" to "(bag_op (intersect) (all) (id a (case_insensitive) (unqualified)) (not (is_type (id b (case_insensitive) (unqualified)) (boolean_type))))" + /* (intersect_all, intersect) */ "a intersect all b intersect c" to "(bag_op (outer_intersect) (distinct) (bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (intersect_all, except) */ "a intersect all b except c" to "(bag_op (outer_except) (distinct) (bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (intersect_all, except_all) */ "a intersect all b except all c" to "(bag_op (outer_except) (all) (bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (intersect_all, union) */ "a intersect all b union c" to "(bag_op (outer_union) (distinct) (bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (intersect_all, union_all) */ "a intersect all b union all c" to "(bag_op (outer_union) (all) (bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (intersect_all, and) */ "a intersect all b and c" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (and (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect_all, or) */ "a intersect all b or c" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (or (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect_all, =) */ "a intersect all b = c" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (eq (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect_all, <>) */ "a intersect all b <> c" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (ne (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect_all, in) */ "a intersect all b in c" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect_all, not_in) */ "a intersect all b not in c" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (not (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", + /* (intersect_all, <) */ "a intersect all b < c" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (lt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect_all, <=) */ "a intersect all b <= c" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (lte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect_all, >) */ "a intersect all b > c" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (gt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect_all, >=) */ "a intersect all b >= c" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (gte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect_all, between) */ "a intersect all b between w and c" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (between (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect_all, not_between) */ "a intersect all b not between y and c" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (not (between (id b (case_insensitive) (unqualified)) (id y (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", + /* (intersect_all, like) */ "a intersect all b like c" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null))", + /* (intersect_all, not_like) */ "a intersect all b not like c" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (not (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null)))", + /* (intersect_all, +) */ "a intersect all b + c" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (plus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect_all, -) */ "a intersect all b - c" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (minus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect_all, ||) */ "a intersect all b || c" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (concat (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect_all, *) */ "a intersect all b * c" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (times (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect_all, /) */ "a intersect all b / c" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (divide (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect_all, %) */ "a intersect all b % c" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (modulo (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (intersect_all, is) */ "a intersect all b is boolean" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (is_type (id b (case_insensitive) (unqualified)) (boolean_type)))", + /* (intersect_all, is_not) */ "a intersect all b is not boolean" to "(bag_op (outer_intersect) (all) (id a (case_insensitive) (unqualified)) (not (is_type (id b (case_insensitive) (unqualified)) (boolean_type))))" ) @Test @@ -98,33 +98,33 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun exceptPrecedence(pair: Pair) = runTest(pair) fun parametersForExceptPrecedence() = listOf( - /* (except, intersect) */ "a except b intersect c" to "(bag_op (intersect) (distinct) (bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (except, intersect_all) */ "a except b intersect all c" to "(bag_op (intersect) (all) (bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (except, except_all) */ "a except b except all c" to "(bag_op (except) (all) (bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (except, union) */ "a except b union c" to "(bag_op (union) (distinct) (bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (except, union_all) */ "a except b union all c" to "(bag_op (union) (all) (bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (except, and) */ "a except b and c" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (and (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except, or) */ "a except b or c" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (or (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except, =) */ "a except b = c" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (eq (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except, <>) */ "a except b <> c" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (ne (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except, in) */ "a except b in c" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except, not_in) */ "a except b not in c" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (not (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", - /* (except, <) */ "a except b < c" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (lt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except, <=) */ "a except b <= c" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (lte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except, >) */ "a except b > c" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (gt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except, >=) */ "a except b >= c" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (gte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except, between) */ "a except b between w and c" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (between (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except, not_between) */ "a except b not between y and c" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (not (between (id b (case_insensitive) (unqualified)) (id y (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", - /* (except, like) */ "a except b like c" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null))", - /* (except, not_like) */ "a except b not like c" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (not (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null)))", - /* (except, +) */ "a except b + c" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (plus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except, -) */ "a except b - c" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (minus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except, ||) */ "a except b || c" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (concat (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except, *) */ "a except b * c" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (times (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except, /) */ "a except b / c" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (divide (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except, %) */ "a except b % c" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (modulo (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except, is) */ "a except b is boolean" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (is_type (id b (case_insensitive) (unqualified)) (boolean_type)))", - /* (except, is_not) */ "a except b is not boolean" to "(bag_op (except) (distinct) (id a (case_insensitive) (unqualified)) (not (is_type (id b (case_insensitive) (unqualified)) (boolean_type))))" + /* (except, intersect) */ "a except b intersect c" to "(bag_op (outer_intersect) (distinct) (bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (except, intersect_all) */ "a except b intersect all c" to "(bag_op (outer_intersect) (all) (bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (except, except_all) */ "a except b except all c" to "(bag_op (outer_except) (all) (bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (except, union) */ "a except b union c" to "(bag_op (outer_union) (distinct) (bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (except, union_all) */ "a except b union all c" to "(bag_op (outer_union) (all) (bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (except, and) */ "a except b and c" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (and (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except, or) */ "a except b or c" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (or (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except, =) */ "a except b = c" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (eq (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except, <>) */ "a except b <> c" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (ne (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except, in) */ "a except b in c" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except, not_in) */ "a except b not in c" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (not (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", + /* (except, <) */ "a except b < c" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (lt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except, <=) */ "a except b <= c" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (lte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except, >) */ "a except b > c" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (gt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except, >=) */ "a except b >= c" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (gte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except, between) */ "a except b between w and c" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (between (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except, not_between) */ "a except b not between y and c" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (not (between (id b (case_insensitive) (unqualified)) (id y (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", + /* (except, like) */ "a except b like c" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null))", + /* (except, not_like) */ "a except b not like c" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (not (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null)))", + /* (except, +) */ "a except b + c" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (plus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except, -) */ "a except b - c" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (minus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except, ||) */ "a except b || c" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (concat (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except, *) */ "a except b * c" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (times (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except, /) */ "a except b / c" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (divide (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except, %) */ "a except b % c" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (modulo (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except, is) */ "a except b is boolean" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (is_type (id b (case_insensitive) (unqualified)) (boolean_type)))", + /* (except, is_not) */ "a except b is not boolean" to "(bag_op (outer_except) (distinct) (id a (case_insensitive) (unqualified)) (not (is_type (id b (case_insensitive) (unqualified)) (boolean_type))))" ) @Test @@ -132,33 +132,33 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun exceptAllPrecedence(pair: Pair) = runTest(pair) fun parametersForExceptAllPrecedence() = listOf( - /* (except_all, intersect) */ "a except all b intersect c" to "(bag_op (intersect) (distinct) (bag_op (except) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (except_all, intersect_all) */ "a except all b intersect all c" to "(bag_op (intersect) (all) (bag_op (except) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (except_all, except) */ "a except all b except c" to "(bag_op (except) (distinct) (bag_op (except) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (except_all, union) */ "a except all b union c" to "(bag_op (union) (distinct) (bag_op (except) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (except_all, union_all) */ "a except all b union all c" to "(bag_op (union) (all) (bag_op (except) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (except_all, and) */ "a except all b and c" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (and (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except_all, or) */ "a except all b or c" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (or (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except_all, =) */ "a except all b = c" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (eq (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except_all, <>) */ "a except all b <> c" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (ne (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except_all, in) */ "a except all b in c" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except_all, not_in) */ "a except all b not in c" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (not (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", - /* (except_all, <) */ "a except all b < c" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (lt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except_all, <=) */ "a except all b <= c" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (lte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except_all, >) */ "a except all b > c" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (gt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except_all, >=) */ "a except all b >= c" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (gte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except_all, between) */ "a except all b between w and c" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (between (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except_all, not_between) */ "a except all b not between y and c" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (not (between (id b (case_insensitive) (unqualified)) (id y (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", - /* (except_all, like) */ "a except all b like c" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null))", - /* (except_all, not_like) */ "a except all b not like c" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (not (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null)))", - /* (except_all, +) */ "a except all b + c" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (plus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except_all, -) */ "a except all b - c" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (minus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except_all, ||) */ "a except all b || c" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (concat (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except_all, *) */ "a except all b * c" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (times (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except_all, /) */ "a except all b / c" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (divide (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except_all, %) */ "a except all b % c" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (modulo (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (except_all, is) */ "a except all b is boolean" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (is_type (id b (case_insensitive) (unqualified)) (boolean_type)))", - /* (except_all, is_not) */ "a except all b is not boolean" to "(bag_op (except) (all) (id a (case_insensitive) (unqualified)) (not (is_type (id b (case_insensitive) (unqualified)) (boolean_type))))" + /* (except_all, intersect) */ "a except all b intersect c" to "(bag_op (outer_intersect) (distinct) (bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (except_all, intersect_all) */ "a except all b intersect all c" to "(bag_op (outer_intersect) (all) (bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (except_all, except) */ "a except all b except c" to "(bag_op (outer_except) (distinct) (bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (except_all, union) */ "a except all b union c" to "(bag_op (outer_union) (distinct) (bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (except_all, union_all) */ "a except all b union all c" to "(bag_op (outer_union) (all) (bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (except_all, and) */ "a except all b and c" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (and (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except_all, or) */ "a except all b or c" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (or (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except_all, =) */ "a except all b = c" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (eq (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except_all, <>) */ "a except all b <> c" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (ne (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except_all, in) */ "a except all b in c" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except_all, not_in) */ "a except all b not in c" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (not (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", + /* (except_all, <) */ "a except all b < c" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (lt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except_all, <=) */ "a except all b <= c" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (lte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except_all, >) */ "a except all b > c" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (gt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except_all, >=) */ "a except all b >= c" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (gte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except_all, between) */ "a except all b between w and c" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (between (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except_all, not_between) */ "a except all b not between y and c" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (not (between (id b (case_insensitive) (unqualified)) (id y (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", + /* (except_all, like) */ "a except all b like c" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null))", + /* (except_all, not_like) */ "a except all b not like c" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (not (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null)))", + /* (except_all, +) */ "a except all b + c" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (plus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except_all, -) */ "a except all b - c" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (minus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except_all, ||) */ "a except all b || c" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (concat (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except_all, *) */ "a except all b * c" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (times (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except_all, /) */ "a except all b / c" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (divide (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except_all, %) */ "a except all b % c" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (modulo (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (except_all, is) */ "a except all b is boolean" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (is_type (id b (case_insensitive) (unqualified)) (boolean_type)))", + /* (except_all, is_not) */ "a except all b is not boolean" to "(bag_op (outer_except) (all) (id a (case_insensitive) (unqualified)) (not (is_type (id b (case_insensitive) (unqualified)) (boolean_type))))" ) @Test @@ -166,33 +166,33 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun unionPrecedence(pair: Pair) = runTest(pair) fun parametersForUnionPrecedence() = listOf( - /* (union, intersect) */ "a union b intersect c" to "(bag_op (intersect) (distinct) (bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (union, intersect_all) */ "a union b intersect all c" to "(bag_op (intersect) (all) (bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (union, except) */ "a union b except c" to "(bag_op (except) (distinct) (bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (union, except_all) */ "a union b except all c" to "(bag_op (except) (all) (bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (union, union_all) */ "a union b union all c" to "(bag_op (union) (all) (bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (union, and) */ "a union b and c" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (and (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union, or) */ "a union b or c" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (or (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union, =) */ "a union b = c" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (eq (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union, <>) */ "a union b <> c" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (ne (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union, in) */ "a union b in c" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union, not_in) */ "a union b not in c" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (not (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", - /* (union, <) */ "a union b < c" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (lt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union, <=) */ "a union b <= c" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (lte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union, >) */ "a union b > c" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (gt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union, >=) */ "a union b >= c" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (gte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union, between) */ "a union b between w and c" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (between (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union, not_between) */ "a union b not between y and c" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (not (between (id b (case_insensitive) (unqualified)) (id y (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", - /* (union, like) */ "a union b like c" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null))", - /* (union, not_like) */ "a union b not like c" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (not (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null)))", - /* (union, +) */ "a union b + c" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (plus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union, -) */ "a union b - c" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (minus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union, ||) */ "a union b || c" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (concat (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union, *) */ "a union b * c" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (times (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union, /) */ "a union b / c" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (divide (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union, %) */ "a union b % c" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (modulo (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union, is) */ "a union b is boolean" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (is_type (id b (case_insensitive) (unqualified)) (boolean_type)))", - /* (union, is_not) */ "a union b is not boolean" to "(bag_op (union) (distinct) (id a (case_insensitive) (unqualified)) (not (is_type (id b (case_insensitive) (unqualified)) (boolean_type))))" + /* (union, intersect) */ "a union b intersect c" to "(bag_op (outer_intersect) (distinct) (bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (union, intersect_all) */ "a union b intersect all c" to "(bag_op (outer_intersect) (all) (bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (union, except) */ "a union b except c" to "(bag_op (outer_except) (distinct) (bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (union, except_all) */ "a union b except all c" to "(bag_op (outer_except) (all) (bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (union, union_all) */ "a union b union all c" to "(bag_op (outer_union) (all) (bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (union, and) */ "a union b and c" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (and (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union, or) */ "a union b or c" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (or (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union, =) */ "a union b = c" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (eq (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union, <>) */ "a union b <> c" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (ne (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union, in) */ "a union b in c" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union, not_in) */ "a union b not in c" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (not (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", + /* (union, <) */ "a union b < c" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (lt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union, <=) */ "a union b <= c" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (lte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union, >) */ "a union b > c" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (gt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union, >=) */ "a union b >= c" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (gte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union, between) */ "a union b between w and c" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (between (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union, not_between) */ "a union b not between y and c" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (not (between (id b (case_insensitive) (unqualified)) (id y (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", + /* (union, like) */ "a union b like c" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null))", + /* (union, not_like) */ "a union b not like c" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (not (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null)))", + /* (union, +) */ "a union b + c" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (plus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union, -) */ "a union b - c" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (minus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union, ||) */ "a union b || c" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (concat (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union, *) */ "a union b * c" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (times (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union, /) */ "a union b / c" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (divide (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union, %) */ "a union b % c" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (modulo (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union, is) */ "a union b is boolean" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (is_type (id b (case_insensitive) (unqualified)) (boolean_type)))", + /* (union, is_not) */ "a union b is not boolean" to "(bag_op (outer_union) (distinct) (id a (case_insensitive) (unqualified)) (not (is_type (id b (case_insensitive) (unqualified)) (boolean_type))))" ) @Test @@ -200,33 +200,33 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun unionAllPrecedence(pair: Pair) = runTest(pair) fun parametersForUnionAllPrecedence() = listOf( - /* (union_all, intersect) */ "a union all b intersect c" to "(bag_op (intersect) (distinct) (bag_op (union) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (union_all, intersect_all) */ "a union all b intersect all c" to "(bag_op (intersect) (all) (bag_op (union) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (union_all, except) */ "a union all b except c" to "(bag_op (except) (distinct) (bag_op (union) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (union_all, except_all) */ "a union all b except all c" to "(bag_op (except) (all) (bag_op (union) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (union_all, union) */ "a union all b union c" to "(bag_op (union) (distinct) (bag_op (union) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (union_all, and) */ "a union all b and c" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (and (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union_all, or) */ "a union all b or c" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (or (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union_all, =) */ "a union all b = c" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (eq (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union_all, <>) */ "a union all b <> c" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (ne (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union_all, in) */ "a union all b in c" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union_all, not_in) */ "a union all b not in c" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (not (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", - /* (union_all, <) */ "a union all b < c" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (lt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union_all, <=) */ "a union all b <= c" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (lte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union_all, >) */ "a union all b > c" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (gt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union_all, >=) */ "a union all b >= c" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (gte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union_all, between) */ "a union all b between w and c" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (between (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union_all, not_between) */ "a union all b not between y and c" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (not (between (id b (case_insensitive) (unqualified)) (id y (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", - /* (union_all, like) */ "a union all b like c" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null))", - /* (union_all, not_like) */ "a union all b not like c" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (not (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null)))", - /* (union_all, +) */ "a union all b + c" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (plus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union_all, -) */ "a union all b - c" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (minus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union_all, ||) */ "a union all b || c" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (concat (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union_all, *) */ "a union all b * c" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (times (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union_all, /) */ "a union all b / c" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (divide (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union_all, %) */ "a union all b % c" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (modulo (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", - /* (union_all, is) */ "a union all b is boolean" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (is_type (id b (case_insensitive) (unqualified)) (boolean_type)))", - /* (union_all, is_not) */ "a union all b is not boolean" to "(bag_op (union) (all) (id a (case_insensitive) (unqualified)) (not (is_type (id b (case_insensitive) (unqualified)) (boolean_type))))" + /* (union_all, intersect) */ "a union all b intersect c" to "(bag_op (outer_intersect) (distinct) (bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (union_all, intersect_all) */ "a union all b intersect all c" to "(bag_op (outer_intersect) (all) (bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (union_all, except) */ "a union all b except c" to "(bag_op (outer_except) (distinct) (bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (union_all, except_all) */ "a union all b except all c" to "(bag_op (outer_except) (all) (bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (union_all, union) */ "a union all b union c" to "(bag_op (outer_union) (distinct) (bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (union_all, and) */ "a union all b and c" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (and (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union_all, or) */ "a union all b or c" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (or (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union_all, =) */ "a union all b = c" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (eq (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union_all, <>) */ "a union all b <> c" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (ne (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union_all, in) */ "a union all b in c" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union_all, not_in) */ "a union all b not in c" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (not (in_collection (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", + /* (union_all, <) */ "a union all b < c" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (lt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union_all, <=) */ "a union all b <= c" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (lte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union_all, >) */ "a union all b > c" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (gt (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union_all, >=) */ "a union all b >= c" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (gte (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union_all, between) */ "a union all b between w and c" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (between (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union_all, not_between) */ "a union all b not between y and c" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (not (between (id b (case_insensitive) (unqualified)) (id y (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)))))", + /* (union_all, like) */ "a union all b like c" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null))", + /* (union_all, not_like) */ "a union all b not like c" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (not (like (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified)) null)))", + /* (union_all, +) */ "a union all b + c" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (plus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union_all, -) */ "a union all b - c" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (minus (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union_all, ||) */ "a union all b || c" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (concat (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union_all, *) */ "a union all b * c" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (times (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union_all, /) */ "a union all b / c" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (divide (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union_all, %) */ "a union all b % c" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (modulo (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", + /* (union_all, is) */ "a union all b is boolean" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (is_type (id b (case_insensitive) (unqualified)) (boolean_type)))", + /* (union_all, is_not) */ "a union all b is not boolean" to "(bag_op (outer_union) (all) (id a (case_insensitive) (unqualified)) (not (is_type (id b (case_insensitive) (unqualified)) (boolean_type))))" ) @Test @@ -234,12 +234,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun andPrecedence(pair: Pair) = runTest(pair) fun parametersForAndPrecedence() = listOf( - /* (and, intersect) */ "a and b intersect c" to "(bag_op (intersect) (distinct) (and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (and, intersect_all) */ "a and b intersect all c" to "(bag_op (intersect) (all) (and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (and, except) */ "a and b except c" to "(bag_op (except) (distinct) (and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (and, except_all) */ "a and b except all c" to "(bag_op (except) (all) (and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (and, union) */ "a and b union c" to "(bag_op (union) (distinct) (and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (and, union_all) */ "a and b union all c" to "(bag_op (union) (all) (and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (and, intersect) */ "a and b intersect c" to "(bag_op (outer_intersect) (distinct) (and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (and, intersect_all) */ "a and b intersect all c" to "(bag_op (outer_intersect) (all) (and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (and, except) */ "a and b except c" to "(bag_op (outer_except) (distinct) (and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (and, except_all) */ "a and b except all c" to "(bag_op (outer_except) (all) (and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (and, union) */ "a and b union c" to "(bag_op (outer_union) (distinct) (and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (and, union_all) */ "a and b union all c" to "(bag_op (outer_union) (all) (and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (and, or) */ "a and b or c" to "(or (and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (and, =) */ "a and b = c" to "(and (id a (case_insensitive) (unqualified)) (eq (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", /* (and, <>) */ "a and b <> c" to "(and (id a (case_insensitive) (unqualified)) (ne (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", @@ -268,12 +268,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun orPrecedence(pair: Pair) = runTest(pair) fun parametersForOrPrecedence() = listOf( - /* (or, intersect) */ "a or b intersect c" to "(bag_op (intersect) (distinct) (or (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (or, intersect_all) */ "a or b intersect all c " to "(bag_op (intersect) (all) (or (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (or, except) */ "a or b except c" to "(bag_op (except) (distinct) (or (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (or, except_all) */ "a or b except all c " to "(bag_op (except) (all) (or (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (or, union) */ "a or b union c" to "(bag_op (union) (distinct) (or (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (or, union_all) */ "a or b union all c " to "(bag_op (union) (all) (or (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (or, intersect) */ "a or b intersect c" to "(bag_op (outer_intersect) (distinct) (or (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (or, intersect_all) */ "a or b intersect all c " to "(bag_op (outer_intersect) (all) (or (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (or, except) */ "a or b except c" to "(bag_op (outer_except) (distinct) (or (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (or, except_all) */ "a or b except all c " to "(bag_op (outer_except) (all) (or (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (or, union) */ "a or b union c" to "(bag_op (outer_union) (distinct) (or (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (or, union_all) */ "a or b union all c " to "(bag_op (outer_union) (all) (or (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (or, and) */ "a or b and c" to "(or (id a (case_insensitive) (unqualified)) (and (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", /* (or, =) */ "a or b = c" to "(or (id a (case_insensitive) (unqualified)) (eq (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", /* (or, <>) */ "a or b <> c" to "(or (id a (case_insensitive) (unqualified)) (ne (id b (case_insensitive) (unqualified)) (id c (case_insensitive) (unqualified))))", @@ -302,12 +302,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun equalsPrecedence(pair: Pair) = runTest(pair) fun parametersForEqualsPrecedence() = listOf( - /* (=, intersect) */ "a = b intersect c" to "(bag_op (intersect) (distinct) (eq (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (=, intersect_all) */ "a = b intersect all c " to "(bag_op (intersect) (all) (eq (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (=, except) */ "a = b except c" to "(bag_op (except) (distinct) (eq (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (=, except_all) */ "a = b except all c " to "(bag_op (except) (all) (eq (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (=, union) */ "a = b union c" to "(bag_op (union) (distinct) (eq (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (=, union_all) */ "a = b union all c " to "(bag_op (union) (all) (eq (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (=, intersect) */ "a = b intersect c" to "(bag_op (outer_intersect) (distinct) (eq (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (=, intersect_all) */ "a = b intersect all c " to "(bag_op (outer_intersect) (all) (eq (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (=, except) */ "a = b except c" to "(bag_op (outer_except) (distinct) (eq (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (=, except_all) */ "a = b except all c " to "(bag_op (outer_except) (all) (eq (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (=, union) */ "a = b union c" to "(bag_op (outer_union) (distinct) (eq (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (=, union_all) */ "a = b union all c " to "(bag_op (outer_union) (all) (eq (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (=, or) */ "a = b or c" to "(or (eq (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (=, and) */ "a = b and c" to "(and (eq (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (=, <>) */ "a = b <> c" to "(ne (eq (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", @@ -328,12 +328,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun notEqualPrecedence(pair: Pair) = runTest(pair) fun parametersForNotEqualPrecedence() = listOf( - /* (<>, intersect) */ "a <> b intersect c" to "(bag_op (intersect) (distinct) (ne (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (<>, intersect_all) */ "a <> b intersect all c" to "(bag_op (intersect) (all) (ne (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (<>, except) */ "a <> b except c" to "(bag_op (except) (distinct) (ne (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (<>, except_all) */ "a <> b except all c" to "(bag_op (except) (all) (ne (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (<>, union) */ "a <> b union c" to "(bag_op (union) (distinct) (ne (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (<>, union_all) */ "a <> b union all c" to "(bag_op (union) (all) (ne (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (<>, intersect) */ "a <> b intersect c" to "(bag_op (outer_intersect) (distinct) (ne (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (<>, intersect_all) */ "a <> b intersect all c" to "(bag_op (outer_intersect) (all) (ne (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (<>, except) */ "a <> b except c" to "(bag_op (outer_except) (distinct) (ne (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (<>, except_all) */ "a <> b except all c" to "(bag_op (outer_except) (all) (ne (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (<>, union) */ "a <> b union c" to "(bag_op (outer_union) (distinct) (ne (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (<>, union_all) */ "a <> b union all c" to "(bag_op (outer_union) (all) (ne (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (<>, or) */ "a <> b or c" to "(or (ne (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (<>, and) */ "a <> b and c" to "(and (ne (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (<>, =) */ "a <> b = c" to "(eq (ne (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", @@ -354,12 +354,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun isPrecedence(pair: Pair) = runTest(pair) fun parametersForIsPrecedence() = listOf( - /* (is, intersect) */ "a is boolean intersect c" to "(bag_op (intersect) (distinct) (is_type (id a (case_insensitive) (unqualified)) (boolean_type)) (id c (case_insensitive) (unqualified)))", - /* (is, intersect_all) */ "a is boolean intersect all c" to "(bag_op (intersect) (all) (is_type (id a (case_insensitive) (unqualified)) (boolean_type)) (id c (case_insensitive) (unqualified)))", - /* (is, except) */ "a is boolean except c" to "(bag_op (except) (distinct) (is_type (id a (case_insensitive) (unqualified)) (boolean_type)) (id c (case_insensitive) (unqualified)))", - /* (is, except_all) */ "a is boolean except all c" to "(bag_op (except) (all) (is_type (id a (case_insensitive) (unqualified)) (boolean_type)) (id c (case_insensitive) (unqualified)))", - /* (is, union) */ "a is boolean union c" to "(bag_op (union) (distinct) (is_type (id a (case_insensitive) (unqualified)) (boolean_type)) (id c (case_insensitive) (unqualified)))", - /* (is, union_all) */ "a is boolean union all c" to "(bag_op (union) (all) (is_type (id a (case_insensitive) (unqualified)) (boolean_type)) (id c (case_insensitive) (unqualified)))", + /* (is, intersect) */ "a is boolean intersect c" to "(bag_op (outer_intersect) (distinct) (is_type (id a (case_insensitive) (unqualified)) (boolean_type)) (id c (case_insensitive) (unqualified)))", + /* (is, intersect_all) */ "a is boolean intersect all c" to "(bag_op (outer_intersect) (all) (is_type (id a (case_insensitive) (unqualified)) (boolean_type)) (id c (case_insensitive) (unqualified)))", + /* (is, except) */ "a is boolean except c" to "(bag_op (outer_except) (distinct) (is_type (id a (case_insensitive) (unqualified)) (boolean_type)) (id c (case_insensitive) (unqualified)))", + /* (is, except_all) */ "a is boolean except all c" to "(bag_op (outer_except) (all) (is_type (id a (case_insensitive) (unqualified)) (boolean_type)) (id c (case_insensitive) (unqualified)))", + /* (is, union) */ "a is boolean union c" to "(bag_op (outer_union) (distinct) (is_type (id a (case_insensitive) (unqualified)) (boolean_type)) (id c (case_insensitive) (unqualified)))", + /* (is, union_all) */ "a is boolean union all c" to "(bag_op (outer_union) (all) (is_type (id a (case_insensitive) (unqualified)) (boolean_type)) (id c (case_insensitive) (unqualified)))", /* (is, or) */ "a is boolean or c" to "(or (is_type (id a (case_insensitive) (unqualified)) (boolean_type)) (id c (case_insensitive) (unqualified)))", /* (is, and) */ "a is boolean and c" to "(and (is_type (id a (case_insensitive) (unqualified)) (boolean_type)) (id c (case_insensitive) (unqualified)))", /* (is, =) */ "a is boolean = c" to "(eq (is_type (id a (case_insensitive) (unqualified)) (boolean_type)) (id c (case_insensitive) (unqualified)))", @@ -381,11 +381,11 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun isNotPrecedence(pair: Pair) = runTest(pair) fun parametersForIsNotPrecedence() = listOf( - /* (not (is, intersect) */ "a is not boolean intersect c" to "(bag_op (intersect) (distinct) (not (is_type (id a (case_insensitive) (unqualified)) (boolean_type))) (id c (case_insensitive) (unqualified)))", - /* (not (is, intersect_all) */ "a is not boolean intersect all c" to "(bag_op (intersect) (all) (not (is_type (id a (case_insensitive) (unqualified)) (boolean_type))) (id c (case_insensitive) (unqualified)))", - /* (not (is, except) */ "a is not boolean except c" to "(bag_op (except) (distinct) (not (is_type (id a (case_insensitive) (unqualified)) (boolean_type))) (id c (case_insensitive) (unqualified)))", - /* (not (is, union) */ "a is not boolean union c" to "(bag_op (union) (distinct) (not (is_type (id a (case_insensitive) (unqualified)) (boolean_type))) (id c (case_insensitive) (unqualified)))", - /* (not (is, union_all) */ "a is not boolean union all c" to "(bag_op (union) (all) (not (is_type (id a (case_insensitive) (unqualified)) (boolean_type))) (id c (case_insensitive) (unqualified)))", + /* (not (is, intersect) */ "a is not boolean intersect c" to "(bag_op (outer_intersect) (distinct) (not (is_type (id a (case_insensitive) (unqualified)) (boolean_type))) (id c (case_insensitive) (unqualified)))", + /* (not (is, intersect_all) */ "a is not boolean intersect all c" to "(bag_op (outer_intersect) (all) (not (is_type (id a (case_insensitive) (unqualified)) (boolean_type))) (id c (case_insensitive) (unqualified)))", + /* (not (is, except) */ "a is not boolean except c" to "(bag_op (outer_except) (distinct) (not (is_type (id a (case_insensitive) (unqualified)) (boolean_type))) (id c (case_insensitive) (unqualified)))", + /* (not (is, union) */ "a is not boolean union c" to "(bag_op (outer_union) (distinct) (not (is_type (id a (case_insensitive) (unqualified)) (boolean_type))) (id c (case_insensitive) (unqualified)))", + /* (not (is, union_all) */ "a is not boolean union all c" to "(bag_op (outer_union) (all) (not (is_type (id a (case_insensitive) (unqualified)) (boolean_type))) (id c (case_insensitive) (unqualified)))", /* (not (is, or) */ "a is not boolean or c" to "(or (not (is_type (id a (case_insensitive) (unqualified)) (boolean_type))) (id c (case_insensitive) (unqualified)))", /* (not (is, and) */ "a is not boolean and c" to "(and (not (is_type (id a (case_insensitive) (unqualified)) (boolean_type))) (id c (case_insensitive) (unqualified)))", /* (not (is, =) */ "a is not boolean = c" to "(eq (not (is_type (id a (case_insensitive) (unqualified)) (boolean_type))) (id c (case_insensitive) (unqualified)))", @@ -408,12 +408,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun inPrecedence(pair: Pair) = runTest(pair) fun parametersForInPrecedence() = listOf( - /* (in, intersect) */ "a in b intersect c" to "(bag_op (intersect) (distinct) (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (in, intersect_all) */ "a in b intersect all c" to "(bag_op (intersect) (all) (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (in, except) */ "a in b except c" to "(bag_op (except) (distinct) (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (in, except_all) */ "a in b except all c" to "(bag_op (except) (all) (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (in, union) */ "a in b union c" to "(bag_op (union) (distinct) (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (in, union_all) */ "a in b union all c" to "(bag_op (union) (all) (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (in, intersect) */ "a in b intersect c" to "(bag_op (outer_intersect) (distinct) (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (in, intersect_all) */ "a in b intersect all c" to "(bag_op (outer_intersect) (all) (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (in, except) */ "a in b except c" to "(bag_op (outer_except) (distinct) (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (in, except_all) */ "a in b except all c" to "(bag_op (outer_except) (all) (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (in, union) */ "a in b union c" to "(bag_op (outer_union) (distinct) (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (in, union_all) */ "a in b union all c" to "(bag_op (outer_union) (all) (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (in, or) */ "a in b or c" to "(or (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (in, and) */ "a in b and c" to "(and (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (in, =) */ "a in b = c" to "(eq (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", @@ -434,12 +434,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun notInPrecedence(pair: Pair) = runTest(pair) fun parametersForNotInPrecedence() = listOf( - /* (not (in, intersect) */ "a not in b intersect c" to "(bag_op (intersect) (distinct) (not (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", - /* (not (in, intersect_all) */ "a not in b intersect all c" to "(bag_op (intersect) (all) (not (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", - /* (not (in, except) */ "a not in b except c" to "(bag_op (except) (distinct) (not (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", - /* (not (in, except_all) */ "a not in b except all c" to "(bag_op (except) (all) (not (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", - /* (not (in, union) */ "a not in b union c" to "(bag_op (union) (distinct) (not (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", - /* (not (in, union_all) */ "a not in b union all c" to "(bag_op (union) (all) (not (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", + /* (not (in, intersect) */ "a not in b intersect c" to "(bag_op (outer_intersect) (distinct) (not (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", + /* (not (in, intersect_all) */ "a not in b intersect all c" to "(bag_op (outer_intersect) (all) (not (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", + /* (not (in, except) */ "a not in b except c" to "(bag_op (outer_except) (distinct) (not (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", + /* (not (in, except_all) */ "a not in b except all c" to "(bag_op (outer_except) (all) (not (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", + /* (not (in, union) */ "a not in b union c" to "(bag_op (outer_union) (distinct) (not (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", + /* (not (in, union_all) */ "a not in b union all c" to "(bag_op (outer_union) (all) (not (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", /* (not (in, or) */ "a not in b or c" to "(or (not (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", /* (not (in, and) */ "a not in b and c" to "(and (not (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", /* (not (in, =) */ "a not in b = c" to "(eq (not (in_collection (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", @@ -460,12 +460,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun ltPrecedence(pair: Pair) = runTest(pair) fun parametersForLtPrecedence() = listOf( - /* (<, intersect) */ "a < b intersect c" to "(bag_op (intersect) (distinct) (lt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (<, intersect_all) */ "a < b intersect all c" to "(bag_op (intersect) (all) (lt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (<, except) */ "a < b except c" to "(bag_op (except) (distinct) (lt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (<, except_all) */ "a < b except all c" to "(bag_op (except) (all) (lt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (<, union) */ "a < b union c" to "(bag_op (union) (distinct) (lt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (<, union_all) */ "a < b union all c" to "(bag_op (union) (all) (lt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (<, intersect) */ "a < b intersect c" to "(bag_op (outer_intersect) (distinct) (lt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (<, intersect_all) */ "a < b intersect all c" to "(bag_op (outer_intersect) (all) (lt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (<, except) */ "a < b except c" to "(bag_op (outer_except) (distinct) (lt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (<, except_all) */ "a < b except all c" to "(bag_op (outer_except) (all) (lt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (<, union) */ "a < b union c" to "(bag_op (outer_union) (distinct) (lt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (<, union_all) */ "a < b union all c" to "(bag_op (outer_union) (all) (lt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (<, or) */ "a < b or c" to "(or (lt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (<, and) */ "a < b and c" to "(and (lt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (<, =) */ "a < b = c" to "(eq (lt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", @@ -494,12 +494,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun ltePrecedence(pair: Pair) = runTest(pair) fun parametersForLtePrecedence() = listOf( - /* (<=, intersect) */ "a <= b intersect c" to "(bag_op (intersect) (distinct) (lte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (<=, intersect_all) */ "a <= b intersect all c" to "(bag_op (intersect) (all) (lte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (<=, except) */ "a <= b except c" to "(bag_op (except) (distinct) (lte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (<=, except_all) */ "a <= b except all c" to "(bag_op (except) (all) (lte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (<=, union) */ "a <= b union c" to "(bag_op (union) (distinct) (lte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (<=, union_all) */ "a <= b union all c" to "(bag_op (union) (all) (lte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (<=, intersect) */ "a <= b intersect c" to "(bag_op (outer_intersect) (distinct) (lte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (<=, intersect_all) */ "a <= b intersect all c" to "(bag_op (outer_intersect) (all) (lte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (<=, except) */ "a <= b except c" to "(bag_op (outer_except) (distinct) (lte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (<=, except_all) */ "a <= b except all c" to "(bag_op (outer_except) (all) (lte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (<=, union) */ "a <= b union c" to "(bag_op (outer_union) (distinct) (lte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (<=, union_all) */ "a <= b union all c" to "(bag_op (outer_union) (all) (lte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (<=, or) */ "a <= b or c" to "(or (lte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (<=, and) */ "a <= b and c" to "(and (lte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (<=, =) */ "a <= b = c" to "(eq (lte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", @@ -528,12 +528,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun gtPrecedence(pair: Pair) = runTest(pair) fun parametersForGtPrecedence() = listOf( - /* (>, intersect) */ "a > b intersect c" to "(bag_op (intersect) (distinct) (gt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (>, intersect_all) */ "a > b intersect all c" to "(bag_op (intersect) (all) (gt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (>, except) */ "a > b except c" to "(bag_op (except) (distinct) (gt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (>, except_all) */ "a > b except all c" to "(bag_op (except) (all) (gt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (>, union) */ "a > b union c" to "(bag_op (union) (distinct) (gt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (>, union_all) */ "a > b union all c" to "(bag_op (union) (all) (gt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (>, intersect) */ "a > b intersect c" to "(bag_op (outer_intersect) (distinct) (gt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (>, intersect_all) */ "a > b intersect all c" to "(bag_op (outer_intersect) (all) (gt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (>, except) */ "a > b except c" to "(bag_op (outer_except) (distinct) (gt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (>, except_all) */ "a > b except all c" to "(bag_op (outer_except) (all) (gt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (>, union) */ "a > b union c" to "(bag_op (outer_union) (distinct) (gt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (>, union_all) */ "a > b union all c" to "(bag_op (outer_union) (all) (gt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (>, or) */ "a > b or c" to "(or (gt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (>, and) */ "a > b and c" to "(and (gt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (>, =) */ "a > b = c" to "(eq (gt (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", @@ -562,12 +562,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun gtePrecedence(pair: Pair) = runTest(pair) fun parametersForGtePrecedence() = listOf( - /* (>=, intersect) */ "a >= b intersect c" to "(bag_op (intersect) (distinct) (gte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (>=, intersect_all) */ "a >= b intersect all c" to "(bag_op (intersect) (all) (gte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (>=, except) */ "a >= b except c" to "(bag_op (except) (distinct) (gte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (>=, except_all) */ "a >= b except all c" to "(bag_op (except) (all) (gte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (>=, union) */ "a >= b union c" to "(bag_op (union) (distinct) (gte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (>=, union_all) */ "a >= b union all c" to "(bag_op (union) (all) (gte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (>=, intersect) */ "a >= b intersect c" to "(bag_op (outer_intersect) (distinct) (gte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (>=, intersect_all) */ "a >= b intersect all c" to "(bag_op (outer_intersect) (all) (gte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (>=, except) */ "a >= b except c" to "(bag_op (outer_except) (distinct) (gte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (>=, except_all) */ "a >= b except all c" to "(bag_op (outer_except) (all) (gte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (>=, union) */ "a >= b union c" to "(bag_op (outer_union) (distinct) (gte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (>=, union_all) */ "a >= b union all c" to "(bag_op (outer_union) (all) (gte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (>=, or) */ "a >= b or c" to "(or (gte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (>=, and) */ "a >= b and c" to "(and (gte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (>=, =) */ "a >= b = c" to "(eq (gte (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", @@ -596,12 +596,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun betweenPrecedence(pair: Pair) = runTest(pair) fun parametersForBetweenPrecedence() = listOf( - /* (between, intersect) */ "a between b and w intersect c" to "(bag_op (intersect) (distinct) (between (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (between, intersect_all) */ "a between b and w intersect all c" to "(bag_op (intersect) (all) (between (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (between, except) */ "a between b and w except c" to "(bag_op (except) (distinct) (between (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (between, except_all) */ "a between b and w except all c" to "(bag_op (except) (all) (between (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (between, union) */ "a between b and w union c" to "(bag_op (union) (distinct) (between (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (between, union_all) */ "a between b and w union all c" to "(bag_op (union) (all) (between (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (between, intersect) */ "a between b and w intersect c" to "(bag_op (outer_intersect) (distinct) (between (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (between, intersect_all) */ "a between b and w intersect all c" to "(bag_op (outer_intersect) (all) (between (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (between, except) */ "a between b and w except c" to "(bag_op (outer_except) (distinct) (between (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (between, except_all) */ "a between b and w except all c" to "(bag_op (outer_except) (all) (between (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (between, union) */ "a between b and w union c" to "(bag_op (outer_union) (distinct) (between (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (between, union_all) */ "a between b and w union all c" to "(bag_op (outer_union) (all) (between (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (between, or) */ "a between w and b or c" to "(or (between (id a (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (between, and) */ "a between w and b and c" to "(and (between (id a (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (between, =) */ "a between w and b = c" to "(eq (between (id a (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", @@ -630,12 +630,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun notBetweenPrecedence(pair: Pair) = runTest(pair) fun parametersForNotBetweenPrecedence() = listOf( - /* (not (between, intersect) */ "a not between w and b intersect c" to "(bag_op (intersect) (distinct) (not (between (id a (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", - /* (not (between, intersect_all) */ "a not between w and b intersect all c" to "(bag_op (intersect) (all) (not (between (id a (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", - /* (not (between, except) */ "a not between w and b except c" to "(bag_op (except) (distinct) (not (between (id a (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", - /* (not (between, except_all) */ "a not between w and b except all c" to "(bag_op (except) (all) (not (between (id a (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", - /* (not (between, union) */ "a not between w and b union c" to "(bag_op (union) (distinct) (not (between (id a (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", - /* (not (between, union_all) */ "a not between w and b union all c" to "(bag_op (union) (all) (not (between (id a (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", + /* (not (between, intersect) */ "a not between w and b intersect c" to "(bag_op (outer_intersect) (distinct) (not (between (id a (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", + /* (not (between, intersect_all) */ "a not between w and b intersect all c" to "(bag_op (outer_intersect) (all) (not (between (id a (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", + /* (not (between, except) */ "a not between w and b except c" to "(bag_op (outer_except) (distinct) (not (between (id a (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", + /* (not (between, except_all) */ "a not between w and b except all c" to "(bag_op (outer_except) (all) (not (between (id a (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", + /* (not (between, union) */ "a not between w and b union c" to "(bag_op (outer_union) (distinct) (not (between (id a (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", + /* (not (between, union_all) */ "a not between w and b union all c" to "(bag_op (outer_union) (all) (not (between (id a (case_insensitive) (unqualified)) (id w (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", /* (not (between, or) */ "a not between y and b or c" to "(or (not (between (id a (case_insensitive) (unqualified)) (id y (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", /* (not (between, and) */ "a not between y and b and c" to "(and (not (between (id a (case_insensitive) (unqualified)) (id y (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", /* (not (between, =) */ "a not between y and b = c" to "(eq (not (between (id a (case_insensitive) (unqualified)) (id y (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)))) (id c (case_insensitive) (unqualified)))", @@ -664,12 +664,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun likePrecedence(pair: Pair) = runTest(pair) fun parametersForLikePrecedence() = listOf( - /* (like, intersect) */ "a like b intersect c" to "(bag_op (intersect) (distinct) (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null) (id c (case_insensitive) (unqualified)))", - /* (like, intersect_all) */ "a like b intersect all c" to "(bag_op (intersect) (all) (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null) (id c (case_insensitive) (unqualified)))", - /* (like, except) */ "a like b except c" to "(bag_op (except) (distinct) (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null) (id c (case_insensitive) (unqualified)))", - /* (like, except_all) */ "a like b except all c" to "(bag_op (except) (all) (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null) (id c (case_insensitive) (unqualified)))", - /* (like, union) */ "a like b union c" to "(bag_op (union) (distinct) (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null) (id c (case_insensitive) (unqualified)))", - /* (like, union_all) */ "a like b union all c" to "(bag_op (union) (all) (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null) (id c (case_insensitive) (unqualified)))", + /* (like, intersect) */ "a like b intersect c" to "(bag_op (outer_intersect) (distinct) (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null) (id c (case_insensitive) (unqualified)))", + /* (like, intersect_all) */ "a like b intersect all c" to "(bag_op (outer_intersect) (all) (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null) (id c (case_insensitive) (unqualified)))", + /* (like, except) */ "a like b except c" to "(bag_op (outer_except) (distinct) (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null) (id c (case_insensitive) (unqualified)))", + /* (like, except_all) */ "a like b except all c" to "(bag_op (outer_except) (all) (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null) (id c (case_insensitive) (unqualified)))", + /* (like, union) */ "a like b union c" to "(bag_op (outer_union) (distinct) (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null) (id c (case_insensitive) (unqualified)))", + /* (like, union_all) */ "a like b union all c" to "(bag_op (outer_union) (all) (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null) (id c (case_insensitive) (unqualified)))", /* (like, or) */ "a like b or c" to "(or (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null) (id c (case_insensitive) (unqualified)))", /* (like, and) */ "a like b and c" to "(and (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null) (id c (case_insensitive) (unqualified)))", /* (like, =) */ "a like b = c" to "(eq (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null) (id c (case_insensitive) (unqualified)))", @@ -698,12 +698,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun notLikePrecedence(pair: Pair) = runTest(pair) fun parametersForNotLikePrecedence() = listOf( - /* (not (like, intersect) */ "a not like b intersect c" to "(bag_op (intersect) (distinct) (not (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null)) (id c (case_insensitive) (unqualified)))", - /* (not (like, intersect_all) */ "a not like b intersect all c" to "(bag_op (intersect) (all) (not (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null)) (id c (case_insensitive) (unqualified)))", - /* (not (like, except) */ "a not like b except c" to "(bag_op (except) (distinct) (not (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null)) (id c (case_insensitive) (unqualified)))", - /* (not (like, except_all) */ "a not like b except all c" to "(bag_op (except) (all) (not (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null)) (id c (case_insensitive) (unqualified)))", - /* (not (like, union) */ "a not like b union c" to "(bag_op (union) (distinct) (not (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null)) (id c (case_insensitive) (unqualified)))", - /* (not (like, union_all) */ "a not like b union all c" to "(bag_op (union) (all) (not (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null)) (id c (case_insensitive) (unqualified)))", + /* (not (like, intersect) */ "a not like b intersect c" to "(bag_op (outer_intersect) (distinct) (not (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null)) (id c (case_insensitive) (unqualified)))", + /* (not (like, intersect_all) */ "a not like b intersect all c" to "(bag_op (outer_intersect) (all) (not (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null)) (id c (case_insensitive) (unqualified)))", + /* (not (like, except) */ "a not like b except c" to "(bag_op (outer_except) (distinct) (not (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null)) (id c (case_insensitive) (unqualified)))", + /* (not (like, except_all) */ "a not like b except all c" to "(bag_op (outer_except) (all) (not (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null)) (id c (case_insensitive) (unqualified)))", + /* (not (like, union) */ "a not like b union c" to "(bag_op (outer_union) (distinct) (not (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null)) (id c (case_insensitive) (unqualified)))", + /* (not (like, union_all) */ "a not like b union all c" to "(bag_op (outer_union) (all) (not (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null)) (id c (case_insensitive) (unqualified)))", /* (not (like, or) */ "a not like b or c" to "(or (not (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null)) (id c (case_insensitive) (unqualified)))", /* (not (like, and) */ "a not like b and c" to "(and (not (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null)) (id c (case_insensitive) (unqualified)))", /* (not (like, =) */ "a not like b = c" to "(eq (not (like (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified)) null)) (id c (case_insensitive) (unqualified)))", @@ -732,12 +732,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun subtractPrecedence(pair: Pair) = runTest(pair) fun parametersForSubtractPrecedence() = listOf( - /* (+, intersect) */ "a + b intersect c" to "(bag_op (intersect) (distinct) (plus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (+, intersect_all) */ "a + b intersect all c" to "(bag_op (intersect) (all) (plus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (+, except) */ "a + b except c" to "(bag_op (except) (distinct) (plus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (+, except_all) */ "a + b except all c" to "(bag_op (except) (all) (plus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (+, union) */ "a + b union c" to "(bag_op (union) (distinct) (plus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (+, union_all) */ "a + b union all c" to "(bag_op (union) (all) (plus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (+, intersect) */ "a + b intersect c" to "(bag_op (outer_intersect) (distinct) (plus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (+, intersect_all) */ "a + b intersect all c" to "(bag_op (outer_intersect) (all) (plus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (+, except) */ "a + b except c" to "(bag_op (outer_except) (distinct) (plus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (+, except_all) */ "a + b except all c" to "(bag_op (outer_except) (all) (plus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (+, union) */ "a + b union c" to "(bag_op (outer_union) (distinct) (plus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (+, union_all) */ "a + b union all c" to "(bag_op (outer_union) (all) (plus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (+, or) */ "a + b or c" to "(or (plus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (+, and) */ "a + b and c" to "(and (plus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (+, =) */ "a + b = c" to "(eq (plus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", @@ -766,12 +766,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun minusPrecedence(pair: Pair) = runTest(pair) fun parametersForMinusPrecedence() = listOf( - /* (-, intersect) */ "a - b intersect c" to "(bag_op (intersect) (distinct) (minus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (-, intersect_all) */ "a - b intersect all c" to "(bag_op (intersect) (all) (minus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (-, except) */ "a - b except c" to "(bag_op (except) (distinct) (minus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (-, except_all) */ "a - b except all c" to "(bag_op (except) (all) (minus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (-, union) */ "a - b union c" to "(bag_op (union) (distinct) (minus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (-, union_all) */ "a - b union all c" to "(bag_op (union) (all) (minus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (-, intersect) */ "a - b intersect c" to "(bag_op (outer_intersect) (distinct) (minus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (-, intersect_all) */ "a - b intersect all c" to "(bag_op (outer_intersect) (all) (minus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (-, except) */ "a - b except c" to "(bag_op (outer_except) (distinct) (minus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (-, except_all) */ "a - b except all c" to "(bag_op (outer_except) (all) (minus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (-, union) */ "a - b union c" to "(bag_op (outer_union) (distinct) (minus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (-, union_all) */ "a - b union all c" to "(bag_op (outer_union) (all) (minus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (-, or) */ "a - b or c" to "(or (minus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (-, and) */ "a - b and c" to "(and (minus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (-, =) */ "a - b = c" to "(eq (minus (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", @@ -800,12 +800,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun concatPrecedence(pair: Pair) = runTest(pair) fun parametersForConcatPrecedence() = listOf( - /* (||, intersect) */ "a || b intersect c" to "(bag_op (intersect) (distinct) (concat (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (||, intersect_all) */ "a || b intersect all c" to "(bag_op (intersect) (all) (concat (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (||, except) */ "a || b except c" to "(bag_op (except) (distinct) (concat (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (||, except_all) */ "a || b except all c" to "(bag_op (except) (all) (concat (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (||, union) */ "a || b union c" to "(bag_op (union) (distinct) (concat (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (||, union_all) */ "a || b union all c" to "(bag_op (union) (all) (concat (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (||, intersect) */ "a || b intersect c" to "(bag_op (outer_intersect) (distinct) (concat (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (||, intersect_all) */ "a || b intersect all c" to "(bag_op (outer_intersect) (all) (concat (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (||, except) */ "a || b except c" to "(bag_op (outer_except) (distinct) (concat (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (||, except_all) */ "a || b except all c" to "(bag_op (outer_except) (all) (concat (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (||, union) */ "a || b union c" to "(bag_op (outer_union) (distinct) (concat (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (||, union_all) */ "a || b union all c" to "(bag_op (outer_union) (all) (concat (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (||, or) */ "a || b or c" to "(or (concat (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (||, and) */ "a || b and c" to "(and (concat (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (||, =) */ "a || b = c" to "(eq (concat (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", @@ -832,12 +832,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun mulPrecedence(pair: Pair) = runTest(pair) fun parametersForMulPrecedence() = listOf( - /* (*, intersect) */ "a * b intersect c" to "(bag_op (intersect) (distinct) (times (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (*, intersect_all) */ "a * b intersect all c" to "(bag_op (intersect) (all) (times (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (*, except) */ "a * b except c" to "(bag_op (except) (distinct) (times (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (*, except_all) */ "a * b except all c" to "(bag_op (except) (all) (times (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (*, union) */ "a * b union c" to "(bag_op (union) (distinct) (times (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (*, union_all) */ "a * b union all c" to "(bag_op (union) (all) (times (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (*, intersect) */ "a * b intersect c" to "(bag_op (outer_intersect) (distinct) (times (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (*, intersect_all) */ "a * b intersect all c" to "(bag_op (outer_intersect) (all) (times (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (*, except) */ "a * b except c" to "(bag_op (outer_except) (distinct) (times (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (*, except_all) */ "a * b except all c" to "(bag_op (outer_except) (all) (times (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (*, union) */ "a * b union c" to "(bag_op (outer_union) (distinct) (times (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (*, union_all) */ "a * b union all c" to "(bag_op (outer_union) (all) (times (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (*, or) */ "a * b or c" to "(or (times (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (*, and) */ "a * b and c" to "(and (times (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (*, =) */ "a * b = c" to "(eq (times (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", @@ -866,12 +866,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun divPrecedence(pair: Pair) = runTest(pair) fun parametersForDivPrecedence() = listOf( - /* (/, intersect) */ "a / b intersect c" to "(bag_op (intersect) (distinct) (divide (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (/, intersect_all) */ "a / b intersect all c" to "(bag_op (intersect) (all) (divide (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (/, except) */ "a / b except c" to "(bag_op (except) (distinct) (divide (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (/, except_all) */ "a / b except all c" to "(bag_op (except) (all) (divide (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (/, union) */ "a / b union c" to "(bag_op (union) (distinct) (divide (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (/, union_all) */ "a / b union all c" to "(bag_op (union) (all) (divide (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (/, intersect) */ "a / b intersect c" to "(bag_op (outer_intersect) (distinct) (divide (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (/, intersect_all) */ "a / b intersect all c" to "(bag_op (outer_intersect) (all) (divide (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (/, except) */ "a / b except c" to "(bag_op (outer_except) (distinct) (divide (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (/, except_all) */ "a / b except all c" to "(bag_op (outer_except) (all) (divide (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (/, union) */ "a / b union c" to "(bag_op (outer_union) (distinct) (divide (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (/, union_all) */ "a / b union all c" to "(bag_op (outer_union) (all) (divide (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (/, or) */ "a / b or c" to "(or (divide (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (/, and) */ "a / b and c" to "(and (divide (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (/, =) */ "a / b = c" to "(eq (divide (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", @@ -900,12 +900,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun modPrecedence(pair: Pair) = runTest(pair) fun parametersForModPrecedence() = listOf( - /* (%, intersect) */ "a % b intersect c" to "(bag_op (intersect) (distinct) (modulo (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (%, intersect_all) */ "a % b intersect all c" to "(bag_op (intersect) (all) (modulo (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (%, except) */ "a % b except c" to "(bag_op (except) (distinct) (modulo (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (%, except_all) */ "a % b except all c" to "(bag_op (except) (all) (modulo (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (%, union) */ "a % b union c" to "(bag_op (union) (distinct) (modulo (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (%, union_all) */ "a % b union all c" to "(bag_op (union) (all) (modulo (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (%, intersect) */ "a % b intersect c" to "(bag_op (outer_intersect) (distinct) (modulo (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (%, intersect_all) */ "a % b intersect all c" to "(bag_op (outer_intersect) (all) (modulo (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (%, except) */ "a % b except c" to "(bag_op (outer_except) (distinct) (modulo (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (%, except_all) */ "a % b except all c" to "(bag_op (outer_except) (all) (modulo (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (%, union) */ "a % b union c" to "(bag_op (outer_union) (distinct) (modulo (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (%, union_all) */ "a % b union all c" to "(bag_op (outer_union) (all) (modulo (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (%, or) */ "a % b or c" to "(or (modulo (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (%, and) */ "a % b and c" to "(and (modulo (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (%, =) */ "a % b = c" to "(eq (modulo (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", @@ -934,12 +934,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun bitwiseAndPrecedence(pair: Pair) = runTest(pair) fun parametersForBitwiseAndPrecedence() = listOf( - /* (&, intersect) */ "a & b intersect c" to "(bag_op (intersect) (distinct) (bitwise_and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (&, intersect_all) */ "a & b intersect all c" to "(bag_op (intersect) (all) (bitwise_and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (&, except) */ "a & b except c" to "(bag_op (except) (distinct) (bitwise_and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (&, except_all) */ "a & b except all c" to "(bag_op (except) (all) (bitwise_and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (&, union) */ "a & b union c" to "(bag_op (union) (distinct) (bitwise_and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", - /* (&, union_all) */ "a & b union all c" to "(bag_op (union) (all) (bitwise_and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (&, intersect) */ "a & b intersect c" to "(bag_op (outer_intersect) (distinct) (bitwise_and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (&, intersect_all) */ "a & b intersect all c" to "(bag_op (outer_intersect) (all) (bitwise_and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (&, except) */ "a & b except c" to "(bag_op (outer_except) (distinct) (bitwise_and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (&, except_all) */ "a & b except all c" to "(bag_op (outer_except) (all) (bitwise_and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (&, union) */ "a & b union c" to "(bag_op (outer_union) (distinct) (bitwise_and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", + /* (&, union_all) */ "a & b union all c" to "(bag_op (outer_union) (all) (bitwise_and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (&, or) */ "a & b or c" to "(or (bitwise_and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (&, and) */ "a & b and c" to "(and (bitwise_and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", /* (&, =) */ "a & b = c" to "(eq (bitwise_and (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))) (id c (case_insensitive) (unqualified)))", @@ -990,12 +990,12 @@ class PartiQLParserPrecedenceTest : PartiQLParserTestBase() { @TestCaseName("{0}") fun notUnaryPrecedence(pair: Pair) = runTest(pair) fun parametersForNotUnaryPrecedence() = listOf( - /* (not, intersect) */ "not a intersect b" to "(bag_op (intersect) (distinct) (not (id a (case_insensitive) (unqualified))) (id b (case_insensitive) (unqualified)))", - /* (not, intersect_all) */ "not a intersect all b" to "(bag_op (intersect) (all) (not (id a (case_insensitive) (unqualified))) (id b (case_insensitive) (unqualified)))", - /* (not, except) */ "not a except b" to "(bag_op (except) (distinct) (not (id a (case_insensitive) (unqualified))) (id b (case_insensitive) (unqualified)))", - /* (not, except_all) */ "not a except all b" to "(bag_op (except) (all) (not (id a (case_insensitive) (unqualified))) (id b (case_insensitive) (unqualified)))", - /* (not, union) */ "not a union b" to "(bag_op (union) (distinct) (not (id a (case_insensitive) (unqualified))) (id b (case_insensitive) (unqualified)))", - /* (not, union_all) */ "not a union all b" to "(bag_op (union) (all) (not (id a (case_insensitive) (unqualified))) (id b (case_insensitive) (unqualified)))", + /* (not, intersect) */ "not a intersect b" to "(bag_op (outer_intersect) (distinct) (not (id a (case_insensitive) (unqualified))) (id b (case_insensitive) (unqualified)))", + /* (not, intersect_all) */ "not a intersect all b" to "(bag_op (outer_intersect) (all) (not (id a (case_insensitive) (unqualified))) (id b (case_insensitive) (unqualified)))", + /* (not, except) */ "not a except b" to "(bag_op (outer_except) (distinct) (not (id a (case_insensitive) (unqualified))) (id b (case_insensitive) (unqualified)))", + /* (not, except_all) */ "not a except all b" to "(bag_op (outer_except) (all) (not (id a (case_insensitive) (unqualified))) (id b (case_insensitive) (unqualified)))", + /* (not, union) */ "not a union b" to "(bag_op (outer_union) (distinct) (not (id a (case_insensitive) (unqualified))) (id b (case_insensitive) (unqualified)))", + /* (not, union_all) */ "not a union all b" to "(bag_op (outer_union) (all) (not (id a (case_insensitive) (unqualified))) (id b (case_insensitive) (unqualified)))", /* (not, or) */ "not a or b" to "(or (not (id a (case_insensitive) (unqualified))) (id b (case_insensitive) (unqualified)))", /* (not, and) */ "not a and b" to "(and (not (id a (case_insensitive) (unqualified))) (id b (case_insensitive) (unqualified)))", /* (not, =) */ "not a = b" to "(not (eq (id a (case_insensitive) (unqualified)) (id b (case_insensitive) (unqualified))))", diff --git a/partiql-lang/src/test/kotlin/org/partiql/lang/syntax/PartiQLParserTest.kt b/partiql-lang/src/test/kotlin/org/partiql/lang/syntax/PartiQLParserTest.kt index a72fefa81f..78482f90d2 100644 --- a/partiql-lang/src/test/kotlin/org/partiql/lang/syntax/PartiQLParserTest.kt +++ b/partiql-lang/src/test/kotlin/org/partiql/lang/syntax/PartiQLParserTest.kt @@ -4102,7 +4102,7 @@ class PartiQLParserTest : PartiQLParserTestBase() { "a UNION b" ) { bagOp( - op = PartiqlAst.BagOpType.Union(), + op = PartiqlAst.BagOpType.OuterUnion(), quantifier = PartiqlAst.SetQuantifier.Distinct(), operands = listOf( id("a"), @@ -4116,7 +4116,7 @@ class PartiQLParserTest : PartiQLParserTestBase() { "a UNION DISTINCT b" ) { bagOp( - op = PartiqlAst.BagOpType.Union(), + op = PartiqlAst.BagOpType.OuterUnion(), quantifier = PartiqlAst.SetQuantifier.Distinct(), operands = listOf( id("a"), @@ -4130,7 +4130,7 @@ class PartiQLParserTest : PartiQLParserTestBase() { "a UNION ALL b" ) { bagOp( - op = PartiqlAst.BagOpType.Union(), + op = PartiqlAst.BagOpType.OuterUnion(), quantifier = PartiqlAst.SetQuantifier.All(), operands = listOf( id("a"), @@ -4144,7 +4144,7 @@ class PartiQLParserTest : PartiQLParserTestBase() { "a INTERSECT b" ) { bagOp( - op = PartiqlAst.BagOpType.Intersect(), + op = PartiqlAst.BagOpType.OuterIntersect(), quantifier = PartiqlAst.SetQuantifier.Distinct(), operands = listOf( id("a"), @@ -4158,7 +4158,7 @@ class PartiQLParserTest : PartiQLParserTestBase() { "a INTERSECT DISTINCT b" ) { bagOp( - op = PartiqlAst.BagOpType.Intersect(), + op = PartiqlAst.BagOpType.OuterIntersect(), quantifier = PartiqlAst.SetQuantifier.Distinct(), operands = listOf( id("a"), @@ -4172,7 +4172,7 @@ class PartiQLParserTest : PartiQLParserTestBase() { "a INTERSECT ALL b" ) { bagOp( - op = PartiqlAst.BagOpType.Intersect(), + op = PartiqlAst.BagOpType.OuterIntersect(), quantifier = PartiqlAst.SetQuantifier.All(), operands = listOf( id("a"), @@ -4186,7 +4186,7 @@ class PartiQLParserTest : PartiQLParserTestBase() { "a EXCEPT b" ) { bagOp( - op = PartiqlAst.BagOpType.Except(), + op = PartiqlAst.BagOpType.OuterExcept(), quantifier = PartiqlAst.SetQuantifier.Distinct(), operands = listOf( id("a"), @@ -4200,7 +4200,7 @@ class PartiQLParserTest : PartiQLParserTestBase() { "a EXCEPT DISTINCT b" ) { bagOp( - op = PartiqlAst.BagOpType.Except(), + op = PartiqlAst.BagOpType.OuterExcept(), quantifier = PartiqlAst.SetQuantifier.Distinct(), operands = listOf( id("a"), @@ -4214,7 +4214,7 @@ class PartiQLParserTest : PartiQLParserTestBase() { "a EXCEPT ALL b" ) { bagOp( - op = PartiqlAst.BagOpType.Except(), + op = PartiqlAst.BagOpType.OuterExcept(), quantifier = PartiqlAst.SetQuantifier.All(), operands = listOf( id("a"), diff --git a/partiql-parser/src/main/kotlin/org/partiql/parser/internal/PartiQLParserDefault.kt b/partiql-parser/src/main/kotlin/org/partiql/parser/internal/PartiQLParserDefault.kt index ac30689f17..d5c02c4710 100644 --- a/partiql-parser/src/main/kotlin/org/partiql/parser/internal/PartiQLParserDefault.kt +++ b/partiql-parser/src/main/kotlin/org/partiql/parser/internal/PartiQLParserDefault.kt @@ -1113,6 +1113,17 @@ internal class PartiQLParserDefault : PartiQLParser { * */ + /** + * Verifies if all of the [args] are + * 1. [Expr.SFW] or + * 2. [Expr.BagOp] and is a SQL Set op (i.e. [Expr.BagOp.outer] != true) + */ + private fun argsAreSFW(args: List): Boolean { + return args.all { arg -> + arg is Expr.SFW || (arg is Expr.BagOp && arg.outer != true) + } + } + override fun visitIntersect(ctx: GeneratedParser.IntersectContext) = translate(ctx) { val setq = when { ctx.ALL() != null -> SetQuantifier.ALL @@ -1123,7 +1134,7 @@ internal class PartiQLParserDefault : PartiQLParser { val lhs = visitAs(ctx.lhs) val rhs = visitAs(ctx.rhs) val outer = ctx.OUTER() != null - exprBagOp(op, lhs, rhs, outer) + exprBagOp(op, lhs, rhs, outer || !argsAreSFW(listOf(lhs, rhs))) } override fun visitExcept(ctx: GeneratedParser.ExceptContext) = translate(ctx) { @@ -1136,7 +1147,7 @@ internal class PartiQLParserDefault : PartiQLParser { val lhs = visitAs(ctx.lhs) val rhs = visitAs(ctx.rhs) val outer = ctx.OUTER() != null - exprBagOp(op, lhs, rhs, outer) + exprBagOp(op, lhs, rhs, outer || !argsAreSFW(listOf(lhs, rhs))) } override fun visitUnion(ctx: GeneratedParser.UnionContext) = translate(ctx) { @@ -1149,7 +1160,7 @@ internal class PartiQLParserDefault : PartiQLParser { val lhs = visitAs(ctx.lhs) val rhs = visitAs(ctx.rhs) val outer = ctx.OUTER() != null - exprBagOp(op, lhs, rhs, outer) + exprBagOp(op, lhs, rhs, outer || !argsAreSFW(listOf(lhs, rhs))) } /** diff --git a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserBagOpTests.kt b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserBagOpTests.kt new file mode 100644 index 0000000000..8a556e6c89 --- /dev/null +++ b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserBagOpTests.kt @@ -0,0 +1,483 @@ +package org.partiql.parser.internal + +import org.junit.jupiter.api.Test +import org.partiql.ast.AstNode +import org.partiql.ast.Expr +import org.partiql.ast.From +import org.partiql.ast.SetOp +import org.partiql.ast.SetQuantifier +import org.partiql.ast.builder.AstBuilder +import org.partiql.ast.builder.ast +import org.partiql.value.PartiQLValueExperimental +import org.partiql.value.int32Value +import org.partiql.value.stringValue +import kotlin.test.assertEquals + +class PartiQLParserBagOpTests { + + private val parser = PartiQLParserDefault() + + private fun query(block: AstBuilder.() -> Expr) = ast { statementQuery { expr = block() } } + + @OptIn(PartiQLValueExperimental::class) + private fun createSFW(i: Int): Expr.SFW = + ast { + exprSFW { + select = selectStar() + from = fromValue { + expr = exprCollection { + type = Expr.Collection.Type.BAG + values = mutableListOf( + exprStruct { + fields = mutableListOf( + exprStructField { + name = exprLit { value = stringValue("a") } + value = exprLit { value = int32Value(i) } + } + ) + } + ) + } + type = From.Value.Type.SCAN + } + } + } + + @OptIn(PartiQLValueExperimental::class) + private fun createLit(i: Int) = ast { exprLit { value = int32Value(i) } } + + // SQL Union + @Test + fun sqlUnion() = assertExpression( + "SELECT * FROM <<{'a': 1}>> UNION SELECT * FROM <<{'a': 2}>>", + query { + exprBagOp { + type = setOp { + type = SetOp.Type.UNION + } + lhs = createSFW(1) + rhs = createSFW(2) + outer = false + } + } + ) + + @Test + fun sqlUnionMultiple() = assertExpression( + "SELECT * FROM <<{'a': 1}>> UNION ALL SELECT * FROM <<{'a': 2}>> UNION DISTINCT SELECT * FROM <<{'a': 3}>>", + query { + exprBagOp { + type = setOp { + type = SetOp.Type.UNION + setq = SetQuantifier.DISTINCT + } + lhs = exprBagOp { + type = setOp { + type = SetOp.Type.UNION + setq = SetQuantifier.ALL + } + lhs = createSFW(1) + rhs = createSFW(2) + outer = false + } + rhs = createSFW(3) + outer = false + } + } + ) + + @Test + fun sqlUnionMultipleRight() = assertExpression( + "SELECT * FROM <<{'a': 1}>> UNION ALL (SELECT * FROM <<{'a': 2}>> UNION DISTINCT SELECT * FROM <<{'a': 3}>>)", + query { + exprBagOp { + type = setOp { + type = SetOp.Type.UNION + setq = SetQuantifier.ALL + } + lhs = createSFW(1) + rhs = exprBagOp { + type = setOp { + type = SetOp.Type.UNION + setq = SetQuantifier.DISTINCT + } + lhs = createSFW(2) + rhs = createSFW(3) + outer = false + } + outer = false + } + } + ) + + // Outer Union + @Test + fun outerUnion() = assertExpression( + "SELECT * FROM <<{'a': 1}>> OUTER UNION SELECT * FROM <<{'a': 2}>>", + query { + exprBagOp { + type = setOp { + type = SetOp.Type.UNION + } + lhs = createSFW(1) + rhs = createSFW(2) + outer = true + } + } + ) + + @Test + fun outerUnionNonSpecified() = assertExpression( + "SELECT * FROM <<{'a': 1}>> UNION 2", + query { + exprBagOp { + type = setOp { + type = SetOp.Type.UNION + } + lhs = createSFW(1) + rhs = createLit(2) + outer = true + } + } + ) + + @Test + fun sqlUnionAndOuterUnion() = assertExpression( + "SELECT * FROM <<{'a': 1}>> UNION ALL SELECT * FROM <<{'a': 2}>> UNION DISTINCT 3", + query { + exprBagOp { + type = setOp { + type = SetOp.Type.UNION + setq = SetQuantifier.DISTINCT + } + lhs = exprBagOp { + type = setOp { + type = SetOp.Type.UNION + setq = SetQuantifier.ALL + } + lhs = createSFW(1) + rhs = createSFW(2) + outer = false + } + rhs = createLit(3) + outer = true // outer + } + } + ) + + @Test + fun outerUnionAndSQLUnion() = assertExpression( + "1 UNION ALL SELECT * FROM <<{'a': 2}>> UNION DISTINCT SELECT * FROM <<{'a': 3}>>", + query { + exprBagOp { + type = setOp { + type = SetOp.Type.UNION + setq = SetQuantifier.DISTINCT + } + lhs = exprBagOp { + type = setOp { + type = SetOp.Type.UNION + setq = SetQuantifier.ALL + } + lhs = createLit(1) + rhs = createSFW(2) + outer = true // outer + } + rhs = createSFW(3) + outer = true // also outer + } + } + ) + + // SQL Except + @Test + fun sqlExcept() = assertExpression( + "SELECT * FROM <<{'a': 1}>> EXCEPT SELECT * FROM <<{'a': 2}>>", + query { + exprBagOp { + type = setOp { + type = SetOp.Type.EXCEPT + } + lhs = createSFW(1) + rhs = createSFW(2) + outer = false + } + } + ) + + @Test + fun sqlExceptMultiple() = assertExpression( + "SELECT * FROM <<{'a': 1}>> EXCEPT ALL SELECT * FROM <<{'a': 2}>> EXCEPT DISTINCT SELECT * FROM <<{'a': 3}>>", + query { + exprBagOp { + type = setOp { + type = SetOp.Type.EXCEPT + setq = SetQuantifier.DISTINCT + } + lhs = exprBagOp { + type = setOp { + type = SetOp.Type.EXCEPT + setq = SetQuantifier.ALL + } + lhs = createSFW(1) + rhs = createSFW(2) + outer = false + } + rhs = createSFW(3) + outer = false + } + } + ) + + @Test + fun sqlExceptMultipleRight() = assertExpression( + "SELECT * FROM <<{'a': 1}>> EXCEPT ALL (SELECT * FROM <<{'a': 2}>> EXCEPT DISTINCT SELECT * FROM <<{'a': 3}>>)", + query { + exprBagOp { + type = setOp { + type = SetOp.Type.EXCEPT + setq = SetQuantifier.ALL + } + lhs = createSFW(1) + rhs = exprBagOp { + type = setOp { + type = SetOp.Type.EXCEPT + setq = SetQuantifier.DISTINCT + } + lhs = createSFW(2) + rhs = createSFW(3) + outer = false + } + outer = false + } + } + ) + + // Outer Except + @Test + fun outerExcept() = assertExpression( + "SELECT * FROM <<{'a': 1}>> OUTER EXCEPT SELECT * FROM <<{'a': 2}>>", + query { + exprBagOp { + type = setOp { + type = SetOp.Type.EXCEPT + } + lhs = createSFW(1) + rhs = createSFW(2) + outer = true + } + } + ) + + @Test + fun outerExceptNonSpecified() = assertExpression( + "SELECT * FROM <<{'a': 1}>> EXCEPT 2", + query { + exprBagOp { + type = setOp { + type = SetOp.Type.EXCEPT + } + lhs = createSFW(1) + rhs = createLit(2) + outer = true + } + } + ) + + @Test + fun sqlExceptAndOuterExcept() = assertExpression( + "SELECT * FROM <<{'a': 1}>> EXCEPT ALL SELECT * FROM <<{'a': 2}>> EXCEPT DISTINCT 3", + query { + exprBagOp { + type = setOp { + type = SetOp.Type.EXCEPT + setq = SetQuantifier.DISTINCT + } + lhs = exprBagOp { + type = setOp { + type = SetOp.Type.EXCEPT + setq = SetQuantifier.ALL + } + lhs = createSFW(1) + rhs = createSFW(2) + outer = false + } + rhs = createLit(3) + outer = true // outer + } + } + ) + + @Test + fun outerExceptAndSQLExcept() = assertExpression( + "1 EXCEPT ALL SELECT * FROM <<{'a': 2}>> EXCEPT DISTINCT SELECT * FROM <<{'a': 3}>>", + query { + exprBagOp { + type = setOp { + type = SetOp.Type.EXCEPT + setq = SetQuantifier.DISTINCT + } + lhs = exprBagOp { + type = setOp { + type = SetOp.Type.EXCEPT + setq = SetQuantifier.ALL + } + lhs = createLit(1) + rhs = createSFW(2) + outer = true // outer + } + rhs = createSFW(3) + outer = true // also outer + } + } + ) + + // SQL Intersect + @Test + fun sqlIntersect() = assertExpression( + "SELECT * FROM <<{'a': 1}>> INTERSECT SELECT * FROM <<{'a': 2}>>", + query { + exprBagOp { + type = setOp { + type = SetOp.Type.INTERSECT + } + lhs = createSFW(1) + rhs = createSFW(2) + outer = false + } + } + ) + + @Test + fun sqlIntersectMultiple() = assertExpression( + "SELECT * FROM <<{'a': 1}>> INTERSECT ALL SELECT * FROM <<{'a': 2}>> INTERSECT DISTINCT SELECT * FROM <<{'a': 3}>>", + query { + exprBagOp { + type = setOp { + type = SetOp.Type.INTERSECT + setq = SetQuantifier.DISTINCT + } + lhs = exprBagOp { + type = setOp { + type = SetOp.Type.INTERSECT + setq = SetQuantifier.ALL + } + lhs = createSFW(1) + rhs = createSFW(2) + outer = false + } + rhs = createSFW(3) + outer = false + } + } + ) + + @Test + fun sqlIntersectMultipleRight() = assertExpression( + "SELECT * FROM <<{'a': 1}>> INTERSECT ALL (SELECT * FROM <<{'a': 2}>> INTERSECT DISTINCT SELECT * FROM <<{'a': 3}>>)", + query { + exprBagOp { + type = setOp { + type = SetOp.Type.INTERSECT + setq = SetQuantifier.ALL + } + lhs = createSFW(1) + rhs = exprBagOp { + type = setOp { + type = SetOp.Type.INTERSECT + setq = SetQuantifier.DISTINCT + } + lhs = createSFW(2) + rhs = createSFW(3) + outer = false + } + outer = false + } + } + ) + + // Outer Intersect + @Test + fun outerIntersect() = assertExpression( + "SELECT * FROM <<{'a': 1}>> OUTER INTERSECT SELECT * FROM <<{'a': 2}>>", + query { + exprBagOp { + type = setOp { + type = SetOp.Type.INTERSECT + } + lhs = createSFW(1) + rhs = createSFW(2) + outer = true + } + } + ) + + @Test + fun outerIntersectNonSpecified() = assertExpression( + "SELECT * FROM <<{'a': 1}>> INTERSECT 2", + query { + exprBagOp { + type = setOp { + type = SetOp.Type.INTERSECT + } + lhs = createSFW(1) + rhs = createLit(2) + outer = true + } + } + ) + + @Test + fun sqlIntersectAndOuterIntersect() = assertExpression( + "SELECT * FROM <<{'a': 1}>> INTERSECT ALL SELECT * FROM <<{'a': 2}>> INTERSECT DISTINCT 3", + query { + exprBagOp { + type = setOp { + type = SetOp.Type.INTERSECT + setq = SetQuantifier.DISTINCT + } + lhs = exprBagOp { + type = setOp { + type = SetOp.Type.INTERSECT + setq = SetQuantifier.ALL + } + lhs = createSFW(1) + rhs = createSFW(2) + outer = false + } + rhs = createLit(3) + outer = true // outer + } + } + ) + + @Test + fun outerIntersectAndSQLIntersect() = assertExpression( + "1 INTERSECT ALL SELECT * FROM <<{'a': 2}>> INTERSECT DISTINCT SELECT * FROM <<{'a': 3}>>", + query { + exprBagOp { + type = setOp { + type = SetOp.Type.INTERSECT + setq = SetQuantifier.DISTINCT + } + lhs = exprBagOp { + type = setOp { + type = SetOp.Type.INTERSECT + setq = SetQuantifier.ALL + } + lhs = createLit(1) + rhs = createSFW(2) + outer = true // outer + } + rhs = createSFW(3) + outer = true // also outer + } + } + ) + + private fun assertExpression(input: String, expected: AstNode) { + val result = parser.parse(input) + val actual = result.root + assertEquals(expected, actual) + } +} diff --git a/partiql-plan/src/main/resources/partiql_plan.ion b/partiql-plan/src/main/resources/partiql_plan.ion index 78ab9f5ab2..29804e2b6b 100644 --- a/partiql-plan/src/main/resources/partiql_plan.ion +++ b/partiql-plan/src/main/resources/partiql_plan.ion @@ -73,6 +73,12 @@ identifier::[ ], ] +// [ ALL | DISTINCT ] +set_quantifier::[ + ALL, + DISTINCT, +] + // Rex rex::{ type: static_type, @@ -187,6 +193,25 @@ rex::{ args: list::[rex], }, + // PartiQL bag ops + union::{ + setq: set_quantifier, + lhs: rex, + rhs: rex, + }, + + intersect::{ + setq: set_quantifier, + lhs: rex, + rhs: rex, + }, + + except::{ + setq: set_quantifier, + lhs: rex, + rhs: rex, + }, + err::{ message: string, }, @@ -240,17 +265,21 @@ rel::{ ], }, + // SQL set ops union::{ + setq: set_quantifier, lhs: rel, rhs: rel, }, intersect::{ + setq: set_quantifier, lhs: rel, rhs: rel, }, except::{ + setq: set_quantifier, lhs: rel, rhs: rel, }, diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/ir/Nodes.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/ir/Nodes.kt index db65156fa8..b99411608c 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/ir/Nodes.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/ir/Nodes.kt @@ -54,7 +54,9 @@ import org.partiql.planner.internal.ir.builder.RexOpCaseBuilder import org.partiql.planner.internal.ir.builder.RexOpCoalesceBuilder import org.partiql.planner.internal.ir.builder.RexOpCollectionBuilder import org.partiql.planner.internal.ir.builder.RexOpErrBuilder +import org.partiql.planner.internal.ir.builder.RexOpExceptBuilder import org.partiql.planner.internal.ir.builder.RexOpGlobalBuilder +import org.partiql.planner.internal.ir.builder.RexOpIntersectBuilder import org.partiql.planner.internal.ir.builder.RexOpLitBuilder import org.partiql.planner.internal.ir.builder.RexOpNullifBuilder import org.partiql.planner.internal.ir.builder.RexOpPathIndexBuilder @@ -66,6 +68,7 @@ import org.partiql.planner.internal.ir.builder.RexOpStructBuilder import org.partiql.planner.internal.ir.builder.RexOpStructFieldBuilder import org.partiql.planner.internal.ir.builder.RexOpSubqueryBuilder import org.partiql.planner.internal.ir.builder.RexOpTupleUnionBuilder +import org.partiql.planner.internal.ir.builder.RexOpUnionBuilder import org.partiql.planner.internal.ir.builder.RexOpVarResolvedBuilder import org.partiql.planner.internal.ir.builder.RexOpVarUnresolvedBuilder import org.partiql.planner.internal.ir.builder.StatementQueryBuilder @@ -322,6 +325,9 @@ internal data class Rex( is Subquery -> visitor.visitRexOpSubquery(this, ctx) is Select -> visitor.visitRexOpSelect(this, ctx) is TupleUnion -> visitor.visitRexOpTupleUnion(this, ctx) + is Union -> visitor.visitRexOpUnion(this, ctx) + is Intersect -> visitor.visitRexOpIntersect(this, ctx) + is Except -> visitor.visitRexOpExcept(this, ctx) is Err -> visitor.visitRexOpErr(this, ctx) } @@ -744,6 +750,81 @@ internal data class Rex( internal fun builder(): RexOpTupleUnionBuilder = RexOpTupleUnionBuilder() } } + + internal data class Union( + @JvmField + internal val setq: SetQuantifier, + @JvmField + internal val lhs: Rex, + @JvmField + internal val rhs: Rex, + ) : Op() { + internal override val children: List by lazy { + val kids = mutableListOf() + kids.add(lhs) + kids.add(rhs) + kids.filterNotNull() + } + + + internal override fun accept(visitor: PlanVisitor, ctx: C): R = + visitor.visitRexOpUnion(this, ctx) + + internal companion object { + @JvmStatic + internal fun builder(): RexOpUnionBuilder = RexOpUnionBuilder() + } + } + + internal data class Intersect( + @JvmField + internal val setq: SetQuantifier, + @JvmField + internal val lhs: Rex, + @JvmField + internal val rhs: Rex, + ) : Op() { + internal override val children: List by lazy { + val kids = mutableListOf() + kids.add(lhs) + kids.add(rhs) + kids.filterNotNull() + } + + + internal override fun accept(visitor: PlanVisitor, ctx: C): R = + visitor.visitRexOpIntersect(this, ctx) + + internal companion object { + @JvmStatic + internal fun builder(): RexOpIntersectBuilder = RexOpIntersectBuilder() + } + } + + internal data class Except( + @JvmField + internal val setq: SetQuantifier, + @JvmField + internal val lhs: Rex, + @JvmField + internal val rhs: Rex, + ) : Op() { + internal override val children: List by lazy { + val kids = mutableListOf() + kids.add(lhs) + kids.add(rhs) + kids.filterNotNull() + } + + + internal override fun accept(visitor: PlanVisitor, ctx: C): R = + visitor.visitRexOpExcept(this, ctx) + + internal companion object { + @JvmStatic + internal fun builder(): RexOpExceptBuilder = RexOpExceptBuilder() + } + } internal data class Err( @JvmField internal val message: String, @@ -952,60 +1033,78 @@ internal data class Rel( } internal data class Union( - @JvmField internal val lhs: Rel, - @JvmField internal val rhs: Rel, + @JvmField + internal val setq: SetQuantifier, + @JvmField + internal val lhs: Rel, + @JvmField + internal val rhs: Rel, ) : Op() { - override val children: List by lazy { - val kids = mutableListOf() - kids.add(lhs) - kids.add(rhs) - kids.filterNotNull() - } - - override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRelOpUnion(this, ctx) - - internal companion object { - @JvmStatic - internal fun builder(): RelOpUnionBuilder = RelOpUnionBuilder() - } + internal override val children: List by lazy { + val kids = mutableListOf() + kids.add(lhs) + kids.add(rhs) + kids.filterNotNull() + } + + + internal override fun accept(visitor: PlanVisitor, ctx: C): R = + visitor.visitRelOpUnion(this, ctx) + + internal companion object { + @JvmStatic + internal fun builder(): RelOpUnionBuilder = RelOpUnionBuilder() + } } - + internal data class Intersect( - @JvmField internal val lhs: Rel, - @JvmField internal val rhs: Rel, + @JvmField + internal val setq: SetQuantifier, + @JvmField + internal val lhs: Rel, + @JvmField + internal val rhs: Rel, ) : Op() { - override val children: List by lazy { - val kids = mutableListOf() - kids.add(lhs) - kids.add(rhs) - kids.filterNotNull() - } - - override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRelOpIntersect(this, ctx) - - internal companion object { - @JvmStatic - internal fun builder(): RelOpIntersectBuilder = RelOpIntersectBuilder() - } + internal override val children: List by lazy { + val kids = mutableListOf() + kids.add(lhs) + kids.add(rhs) + kids.filterNotNull() + } + + + internal override fun accept(visitor: PlanVisitor, ctx: C): R = + visitor.visitRelOpIntersect(this, ctx) + + internal companion object { + @JvmStatic + internal fun builder(): RelOpIntersectBuilder = RelOpIntersectBuilder() + } } - + internal data class Except( - @JvmField internal val lhs: Rel, - @JvmField internal val rhs: Rel, + @JvmField + internal val setq: SetQuantifier, + @JvmField + internal val lhs: Rel, + @JvmField + internal val rhs: Rel, ) : Op() { - override val children: List by lazy { - val kids = mutableListOf() - kids.add(lhs) - kids.add(rhs) - kids.filterNotNull() - } - - override fun accept(visitor: PlanVisitor, ctx: C): R = visitor.visitRelOpExcept(this, ctx) - - internal companion object { - @JvmStatic - internal fun builder(): RelOpExceptBuilder = RelOpExceptBuilder() - } + internal override val children: List by lazy { + val kids = mutableListOf() + kids.add(lhs) + kids.add(rhs) + kids.filterNotNull() + } + + + internal override fun accept(visitor: PlanVisitor, ctx: C): R = + visitor.visitRelOpExcept(this, ctx) + + internal companion object { + @JvmStatic + internal fun builder(): RelOpExceptBuilder = RelOpExceptBuilder() + } } internal data class Limit( @@ -1281,3 +1380,8 @@ internal data class Rel( internal fun builder(): RelBuilder = RelBuilder() } } + +internal enum class SetQuantifier { + ALL, + DISTINCT, +} diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/PlanTransform.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/PlanTransform.kt index a814cc7a35..01940d40c4 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/PlanTransform.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/PlanTransform.kt @@ -13,6 +13,7 @@ import org.partiql.planner.internal.ir.Identifier import org.partiql.planner.internal.ir.PartiQLPlan import org.partiql.planner.internal.ir.Rel import org.partiql.planner.internal.ir.Rex +import org.partiql.planner.internal.ir.SetQuantifier import org.partiql.planner.internal.ir.Statement import org.partiql.planner.internal.ir.visitor.PlanBaseVisitor import org.partiql.planner.internal.utils.PlanUtils @@ -236,6 +237,24 @@ internal object PlanTransform : PlanBaseVisitor() { override fun visitRexOpTupleUnion(node: Rex.Op.TupleUnion, ctx: ProblemCallback) = org.partiql.plan.Rex.Op.TupleUnion(args = node.args.map { visitRex(it, ctx) }) + override fun visitRexOpExcept(node: Rex.Op.Except, ctx: ProblemCallback) = org.partiql.plan.Rex.Op.Except( + lhs = visitRex(node.lhs, ctx), + rhs = visitRex(node.rhs, ctx), + setq = visitSetQuantifier(node.setq) + ) + + override fun visitRexOpIntersect(node: Rex.Op.Intersect, ctx: ProblemCallback) = org.partiql.plan.Rex.Op.Intersect( + lhs = visitRex(node.lhs, ctx), + rhs = visitRex(node.rhs, ctx), + setq = visitSetQuantifier(node.setq) + ) + + override fun visitRexOpUnion(node: Rex.Op.Union, ctx: ProblemCallback) = org.partiql.plan.Rex.Op.Union( + lhs = visitRex(node.lhs, ctx), + rhs = visitRex(node.rhs, ctx), + setq = visitSetQuantifier(node.setq) + ) + override fun visitRexOpErr(node: Rex.Op.Err, ctx: ProblemCallback) = org.partiql.plan.Rex.Op.Err(node.message) // RELATION OPERATORS @@ -296,21 +315,29 @@ internal object PlanTransform : PlanBaseVisitor() { } ) - override fun visitRelOpUnion(node: Rel.Op.Union, ctx: ProblemCallback) = org.partiql.plan.Rel.Op.Union( + override fun visitRelOpExcept(node: Rel.Op.Except, ctx: ProblemCallback) = org.partiql.plan.Rel.Op.Except( lhs = visitRel(node.lhs, ctx), rhs = visitRel(node.rhs, ctx), + setq = visitSetQuantifier(node.setq) ) override fun visitRelOpIntersect(node: Rel.Op.Intersect, ctx: ProblemCallback) = org.partiql.plan.Rel.Op.Intersect( lhs = visitRel(node.lhs, ctx), rhs = visitRel(node.rhs, ctx), + setq = visitSetQuantifier(node.setq) ) - override fun visitRelOpExcept(node: Rel.Op.Except, ctx: ProblemCallback) = org.partiql.plan.Rel.Op.Except( + override fun visitRelOpUnion(node: Rel.Op.Union, ctx: ProblemCallback) = org.partiql.plan.Rel.Op.Union( lhs = visitRel(node.lhs, ctx), rhs = visitRel(node.rhs, ctx), + setq = visitSetQuantifier(node.setq) ) + private fun visitSetQuantifier(node: SetQuantifier) = when (node) { + SetQuantifier.ALL -> org.partiql.plan.SetQuantifier.ALL + SetQuantifier.DISTINCT -> org.partiql.plan.SetQuantifier.DISTINCT + } + override fun visitRelOpLimit(node: Rel.Op.Limit, ctx: ProblemCallback) = org.partiql.plan.Rel.Op.Limit( input = visitRel(node.input, ctx), limit = visitRex(node.limit, ctx), diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RelConverter.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RelConverter.kt index 73cba006fc..9d6fe42a22 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RelConverter.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RelConverter.kt @@ -40,7 +40,6 @@ import org.partiql.planner.internal.ir.relOpAggregate import org.partiql.planner.internal.ir.relOpAggregateCall import org.partiql.planner.internal.ir.relOpDistinct import org.partiql.planner.internal.ir.relOpErr -import org.partiql.planner.internal.ir.relOpExcept import org.partiql.planner.internal.ir.relOpExclude import org.partiql.planner.internal.ir.relOpExcludeItem import org.partiql.planner.internal.ir.relOpExcludeStepCollIndex @@ -48,7 +47,6 @@ import org.partiql.planner.internal.ir.relOpExcludeStepCollWildcard import org.partiql.planner.internal.ir.relOpExcludeStepStructField import org.partiql.planner.internal.ir.relOpExcludeStepStructWildcard import org.partiql.planner.internal.ir.relOpFilter -import org.partiql.planner.internal.ir.relOpIntersect import org.partiql.planner.internal.ir.relOpJoin import org.partiql.planner.internal.ir.relOpLimit import org.partiql.planner.internal.ir.relOpOffset @@ -57,7 +55,6 @@ import org.partiql.planner.internal.ir.relOpScan import org.partiql.planner.internal.ir.relOpScanIndexed import org.partiql.planner.internal.ir.relOpSort import org.partiql.planner.internal.ir.relOpSortSpec -import org.partiql.planner.internal.ir.relOpUnion import org.partiql.planner.internal.ir.relOpUnpivot import org.partiql.planner.internal.ir.relType import org.partiql.planner.internal.ir.rex @@ -75,7 +72,7 @@ import org.partiql.value.boolValue internal object RelConverter { // IGNORE — so we don't have to non-null assert on operator inputs - private val nil = rel(relType(emptyList(), emptySet()), relOpErr("nil")) + internal val nil = rel(relType(emptyList(), emptySet()), relOpErr("nil")) /** * Here we convert an SFW to composed [Rel]s, then apply the appropriate relation-value projection to get a [Rex]. @@ -123,7 +120,7 @@ internal object RelConverter { private fun Expr.toRex(env: Env): Rex = RexConverter.apply(this, env) @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE", "LocalVariableName") - private class ToRel(private val env: Env) : AstBaseVisitor() { + internal class ToRel(private val env: Env) : AstBaseVisitor() { override fun defaultReturn(node: AstNode, input: Rel): Rel = throw IllegalArgumentException("unsupported rel $node") @@ -163,6 +160,35 @@ internal object RelConverter { return rel } + // Create a SQL set op + override fun visitExprBagOp(node: Expr.BagOp, ctx: Rel): Rel { + // Assumes parser correctly only allows Expr.SFW or other Expr.BagOps with Expr.SFW arguments when + // converting to the SQL set op + assert(node.lhs is Expr.SFW || node.lhs is Expr.BagOp) { + "Expect LHS of bag op to be a Expr.SFW or a Expr.BagOp. " + + "However, it is ${node.lhs}." + } + assert(node.rhs is Expr.SFW || node.rhs is Expr.BagOp) { + "Expect RHS of bag op to be a Expr.SFW or a Expr.BagOp. " + + "However, it is ${node.lhs}." + } + val setq = when (node.type.setq) { + SetQuantifier.ALL -> org.partiql.planner.internal.ir.SetQuantifier.ALL + null, SetQuantifier.DISTINCT -> org.partiql.planner.internal.ir.SetQuantifier.DISTINCT + } + val lhsRel = visitExpr(node.lhs, ctx) + val rhsRel = visitExpr(node.rhs, ctx) + val op = when (node.type.type) { + SetOp.Type.UNION -> Rel.Op.Union(setq, lhsRel, rhsRel) + SetOp.Type.EXCEPT -> Rel.Op.Except(setq, lhsRel, rhsRel) + SetOp.Type.INTERSECT -> Rel.Op.Intersect(setq, lhsRel, rhsRel) + } + return Rel( + type = nil.type, + op = op + ) + } + /** * Given a non-null [setQuantifier], this will return a [Rel] of [Rel.Op.Distinct] wrapping the [input]. * If [setQuantifier] is null or ALL, this will return the [input]. @@ -407,9 +433,6 @@ internal object RelConverter { /** * Append SQL set operator if present - * - * TODO combine/compare schemas - * TODO set quantifier */ private fun convertSetOp(input: Rel, setOp: Expr.SFW.SetOp?): Rel { if (setOp == null) { @@ -418,10 +441,14 @@ internal object RelConverter { val type = input.type.copy(props = emptySet()) val lhs = input val rhs = visitExprSFW(setOp.operand, nil) + val quantifier = when (setOp.type.setq) { + SetQuantifier.ALL -> org.partiql.planner.internal.ir.SetQuantifier.ALL + null, SetQuantifier.DISTINCT -> org.partiql.planner.internal.ir.SetQuantifier.DISTINCT + } val op = when (setOp.type.type) { - SetOp.Type.UNION -> relOpUnion(lhs, rhs) - SetOp.Type.INTERSECT -> relOpIntersect(lhs, rhs) - SetOp.Type.EXCEPT -> relOpExcept(lhs, rhs) + SetOp.Type.UNION -> Rel.Op.Union(quantifier, lhs, rhs) + SetOp.Type.EXCEPT -> Rel.Op.Except(quantifier, lhs, rhs) + SetOp.Type.INTERSECT -> Rel.Op.Intersect(quantifier, lhs, rhs) } return rel(type, op) } diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RexConverter.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RexConverter.kt index f7501d2768..3f054a518a 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RexConverter.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RexConverter.kt @@ -19,6 +19,8 @@ package org.partiql.planner.internal.transforms import org.partiql.ast.AstNode import org.partiql.ast.DatetimeField import org.partiql.ast.Expr +import org.partiql.ast.SetOp +import org.partiql.ast.SetQuantifier import org.partiql.ast.Type import org.partiql.ast.visitor.AstBaseVisitor import org.partiql.planner.internal.Env @@ -41,7 +43,9 @@ import org.partiql.planner.internal.ir.rexOpStruct import org.partiql.planner.internal.ir.rexOpStructField import org.partiql.planner.internal.ir.rexOpSubquery import org.partiql.planner.internal.ir.rexOpTupleUnion +import org.partiql.planner.internal.ir.rexOpVarResolved import org.partiql.planner.internal.ir.rexOpVarUnresolved +import org.partiql.planner.internal.transforms.RelConverter.nil import org.partiql.planner.internal.typer.toNonNullStaticType import org.partiql.planner.internal.typer.toStaticType import org.partiql.types.StaticType @@ -631,6 +635,40 @@ internal object RexConverter { override fun visitExprSFW(node: Expr.SFW, context: Env): Rex = RelConverter.apply(node, context) + override fun visitExprBagOp(node: Expr.BagOp, ctx: Env): Rex { + if (node.outer == true) { + // PartiQL bag op; create bag op rex + val lhs = visitExpr(node.lhs, ctx) + val rhs = visitExpr(node.rhs, ctx) + val setq = when (node.type.setq) { + SetQuantifier.ALL -> org.partiql.planner.internal.ir.SetQuantifier.ALL + null, SetQuantifier.DISTINCT -> org.partiql.planner.internal.ir.SetQuantifier.DISTINCT + } + val op = when (node.type.type) { + SetOp.Type.UNION -> Rex.Op.Union(setq, lhs, rhs) + SetOp.Type.EXCEPT -> Rex.Op.Except(setq, lhs, rhs) + SetOp.Type.INTERSECT -> Rex.Op.Intersect(setq, lhs, rhs) + } + return Rex( + type = StaticType.ANY, + op = op + ) + } else { + // SQL set op; create set op rel + val rel = node.accept(RelConverter.ToRel(ctx), nil) + return Rex( + type = StaticType.ANY, + op = Rex.Op.Select( + constructor = Rex( + StaticType.ANY, + rexOpVarResolved(0) + ), + rel = rel + ) + ) + } + } + // Helpers private fun bool(v: Boolean): Rex { diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/typer/PlanTyper.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/typer/PlanTyper.kt index 199caf2027..55c023e6b4 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/typer/PlanTyper.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/typer/PlanTyper.kt @@ -103,6 +103,7 @@ import org.partiql.value.TextValue import org.partiql.value.boolValue import org.partiql.value.missingValue import org.partiql.value.stringValue +import kotlin.math.max /** * Rewrites an untyped algebraic translation of the query to be both typed and have resolved variables. @@ -241,16 +242,88 @@ internal class PlanTyper( return rel(type, op) } - override fun visitRelOpUnion(node: Rel.Op.Union, ctx: Rel.Type?): Rel { - TODO("Type RelOp Union") + override fun visitRelOpExcept(node: Rel.Op.Except, ctx: Rel.Type?): Rel { + val lhs = visitRel(node.lhs, node.lhs.type) + val rhs = visitRel(node.rhs, node.rhs.type) + // Check for Compatibility + if (!setOpSchemaSizesMatch(lhs, rhs)) { + return createRelErrForSetOpMismatchSizes() + } + if (!setOpSchemaTypesMatch(lhs, rhs)) { + return createRelErrForSetOpMismatchTypes() + } + // Compute Schema + val type = Rel.Type(lhs.type.schema, props = emptySet()) + return Rel(type, node.copy(lhs = lhs, rhs = rhs)) } override fun visitRelOpIntersect(node: Rel.Op.Intersect, ctx: Rel.Type?): Rel { - TODO("Type RelOp Intersect") + val lhs = visitRel(node.lhs, node.lhs.type) + val rhs = visitRel(node.rhs, node.rhs.type) + // Check for Compatibility + if (!setOpSchemaSizesMatch(lhs, rhs)) { + return createRelErrForSetOpMismatchSizes() + } + if (!setOpSchemaTypesMatch(lhs, rhs)) { + return createRelErrForSetOpMismatchTypes() + } + // Compute Schema + val type = Rel.Type(lhs.type.schema, props = emptySet()) + return Rel(type, node.copy(lhs = lhs, rhs = rhs)) } - override fun visitRelOpExcept(node: Rel.Op.Except, ctx: Rel.Type?): Rel { - TODO("Type RelOp Except") + override fun visitRelOpUnion(node: Rel.Op.Union, ctx: Rel.Type?): Rel { + val lhs = visitRel(node.lhs, node.lhs.type) + val rhs = visitRel(node.rhs, node.rhs.type) + // Check for Compatibility + if (!setOpSchemaSizesMatch(lhs, rhs)) { + return createRelErrForSetOpMismatchSizes() + } + if (!setOpSchemaTypesMatch(lhs, rhs)) { + return createRelErrForSetOpMismatchTypes() + } + // Compute Schema + val size = max(lhs.type.schema.size, rhs.type.schema.size) + val schema = List(size) { + val lhsBinding = lhs.type.schema.getOrNull(it) ?: Rel.Binding("_$it", MISSING) + val rhsBinding = rhs.type.schema.getOrNull(it) ?: Rel.Binding("_$it", MISSING) + val bindingName = when (lhsBinding.name == rhsBinding.name) { + true -> lhsBinding.name + false -> "_$it" + } + Rel.Binding(bindingName, unionOf(lhsBinding.type, rhsBinding.type).flatten()) + } + val type = Rel.Type(schema, props = emptySet()) + return Rel(type, node.copy(lhs = lhs, rhs = rhs)) + } + + /** + * @return whether each type of the [lhs] is comparable to its counterpart on the [rhs] + * @param lhs should be typed already + * @param rhs should be typed already + */ + private fun setOpSchemaTypesMatch(lhs: Rel, rhs: Rel): Boolean { + // TODO: [RFC-0007](https://github.com/partiql/partiql-lang/blob/main/RFCs/0007-rfc-bag-operators.md) + // states that the types must be "comparable". For now, we will always return true. In the future, we need + // to add support for checking comparable types. + return true + } + + /** + * @return whether the [lhs] and [rhs] schemas are of equal size + * @param lhs should be typed already + * @param rhs should be typed already + */ + private fun setOpSchemaSizesMatch(lhs: Rel, rhs: Rel): Boolean { + return lhs.type.schema.size == rhs.type.schema.size + } + + private fun createRelErrForSetOpMismatchSizes(): Rel { + return Rel(Rel.Type(emptyList(), emptySet()), Rel.Op.Err("LHS and RHS of SET OP do not have the same number of bindings.")) + } + + private fun createRelErrForSetOpMismatchTypes(): Rel { + return Rel(Rel.Type(emptyList(), emptySet()), Rel.Op.Err("LHS and RHS of SET OP do not have the same type.")) } override fun visitRelOpLimit(node: Rel.Op.Limit, ctx: Rel.Type?): Rel { @@ -435,6 +508,30 @@ internal class PlanTyper( override fun visitRex(node: Rex, ctx: StaticType?): Rex = visitRexOp(node.op, node.type) as Rex + override fun visitRexOpUnion(node: Rex.Op.Union, ctx: StaticType?): Rex { + val lhs = visitRex(node.lhs, node.lhs.type) + val rhs = visitRex(node.rhs, node.rhs.type) + // Compute Schema + val type = unionOf(lhs.type, rhs.type).flatten() + return Rex(type, node.copy(lhs = lhs, rhs = rhs)) + } + + override fun visitRexOpExcept(node: Rex.Op.Except, ctx: StaticType?): Rex { + val lhs = visitRex(node.lhs, node.lhs.type) + val rhs = visitRex(node.rhs, node.rhs.type) + // Compute Schema + val type = unionOf(lhs.type, rhs.type).flatten() + return Rex(type, node.copy(lhs = lhs, rhs = rhs)) + } + + override fun visitRexOpIntersect(node: Rex.Op.Intersect, ctx: StaticType?): Rex { + val lhs = visitRex(node.lhs, node.lhs.type) + val rhs = visitRex(node.rhs, node.rhs.type) + // Compute Schema + val type = unionOf(lhs.type, rhs.type).flatten() + return Rex(type, node.copy(lhs = lhs, rhs = rhs)) + } + override fun visitRexOpLit(node: Rex.Op.Lit, ctx: StaticType?): Rex { // type comes from RexConverter return rex(ctx!!, node) diff --git a/partiql-planner/src/main/resources/partiql_plan_internal.ion b/partiql-planner/src/main/resources/partiql_plan_internal.ion index 667922ed6a..75779e5a3f 100644 --- a/partiql-planner/src/main/resources/partiql_plan_internal.ion +++ b/partiql-planner/src/main/resources/partiql_plan_internal.ion @@ -84,6 +84,12 @@ identifier::[ ], ] +// [ ALL | DISTINCT ] +set_quantifier::[ + ALL, + DISTINCT, +] + // Rex rex::{ type: static_type, @@ -210,6 +216,25 @@ rex::{ args: list::[rex], }, + // PartiQL bag ops + union::{ + setq: set_quantifier, + lhs: rex, + rhs: rex, + }, + + intersect::{ + setq: set_quantifier, + lhs: rex, + rhs: rex, + }, + + except::{ + setq: set_quantifier, + lhs: rex, + rhs: rex, + }, + err::{ message: string, }, @@ -263,17 +288,21 @@ rel::{ ], }, + // SQL set ops union::{ + setq: set_quantifier, lhs: rel, rhs: rel, }, intersect::{ + setq: set_quantifier, lhs: rel, rhs: rel, }, except::{ + setq: set_quantifier, lhs: rel, rhs: rel, },