From 15beea86b0c5ad92779a780b410551057988d835 Mon Sep 17 00:00:00 2001 From: Alan Cai Date: Mon, 2 May 2022 21:34:48 -0700 Subject: [PATCH 1/2] Add more parse tests from partiql-lang-kotlin; add omitted tests list --- partiql-lang-kotlin-omitted-tests.md | 70 +++++++ .../primitives/aggregate-function-call.ion | 127 +++++++++++++ .../fail/parser/primitives/call.ion | 174 ++++++++++++++++++ .../fail/parser/primitives/case.ion | 31 ++++ .../fail/parser/primitives/cast.ion | 23 +++ .../primitives/container-constructors.ion | 7 + .../fail/parser/primitives/expressions.ion | 31 ++++ .../primitives/operators/at-operator.ion | 31 ++++ .../primitives/operators/between-operator.ion | 7 + .../primitives/operators/is-operator.ion | 31 ++++ .../primitives/operators/like-operator.ion | 47 +++++ .../parser/primitives/path-expression.ion | 15 ++ partiql-test-data/fail/parser/query/pivot.ion | 7 + .../fail/parser/query/select/joins.ion | 152 +++++++++++++++ .../fail/parser/query/select/limit-offset.ion | 31 ++++ .../fail/parser/query/select/order-by.ion | 127 +++++++++++++ .../fail/parser/query/select/select.ion | 63 +++++++ .../fail/parser/select/select-from-where.ion | 7 - .../primitives/aggregate-function-call.ion | 124 ++++++++++++- .../operators/arithmetic-operators.ion | 59 ++++++ .../operators/comparison-operators.ion | 79 ++++++++ .../operators/logical-operators.ion | 39 ++++ .../primitives/operators/string-operators.ion | 19 ++ .../primitives/operators/unary-operators.ion | 10 - .../pass/parser/query/select/joins.ion | 38 ++++ 25 files changed, 1330 insertions(+), 19 deletions(-) create mode 100644 partiql-lang-kotlin-omitted-tests.md create mode 100644 partiql-test-data/fail/parser/primitives/aggregate-function-call.ion create mode 100644 partiql-test-data/fail/parser/primitives/call.ion create mode 100644 partiql-test-data/fail/parser/primitives/case.ion create mode 100644 partiql-test-data/fail/parser/primitives/cast.ion create mode 100644 partiql-test-data/fail/parser/primitives/container-constructors.ion create mode 100644 partiql-test-data/fail/parser/primitives/expressions.ion create mode 100644 partiql-test-data/fail/parser/primitives/operators/at-operator.ion create mode 100644 partiql-test-data/fail/parser/primitives/operators/between-operator.ion create mode 100644 partiql-test-data/fail/parser/primitives/operators/is-operator.ion create mode 100644 partiql-test-data/fail/parser/primitives/operators/like-operator.ion create mode 100644 partiql-test-data/fail/parser/primitives/path-expression.ion create mode 100644 partiql-test-data/fail/parser/query/pivot.ion create mode 100644 partiql-test-data/fail/parser/query/select/joins.ion create mode 100644 partiql-test-data/fail/parser/query/select/limit-offset.ion create mode 100644 partiql-test-data/fail/parser/query/select/order-by.ion create mode 100644 partiql-test-data/fail/parser/query/select/select.ion delete mode 100644 partiql-test-data/fail/parser/select/select-from-where.ion create mode 100644 partiql-test-data/pass/parser/primitives/operators/arithmetic-operators.ion create mode 100644 partiql-test-data/pass/parser/primitives/operators/comparison-operators.ion create mode 100644 partiql-test-data/pass/parser/primitives/operators/logical-operators.ion create mode 100644 partiql-test-data/pass/parser/primitives/operators/string-operators.ion diff --git a/partiql-lang-kotlin-omitted-tests.md b/partiql-lang-kotlin-omitted-tests.md new file mode 100644 index 0000000..e7b6af9 --- /dev/null +++ b/partiql-lang-kotlin-omitted-tests.md @@ -0,0 +1,70 @@ +The following lists out the tests from `partiql-lang-kotlin`'s parse tests that are not part of `partiql-tests`: + +Tests excluded: +- Custom type cast + - https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/syntax/SqlParserTest.kt#L631-L644 + - [SqlParserCastTests.kt](https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/syntax/SqlParserCastTests.kt) + - [SqlParserCustomTypeCatalogTests.kt](https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/syntax/SqlParserCustomTypeCatalogTests.kt) +- ORDER BY tests testing defaults for sort spec and null spec + - https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/syntax/SqlParserTest.kt#L1793-L1888 + - dependent on when parsed ast checking is added +- Many nested NOT regression test + - https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/syntax/SqlParserTest.kt#L4239-L4271 + - performance test shouldn't be included in parse tests +- `expectedSelectMissingFrom` -- not part of the PartiQL spec +https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L403-L415 +- LET clause parsing (not part of spec formally yet) + - https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/syntax/SqlParserTest.kt#L4066-L4128 + - `expectedAsForLet` https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L431-L443 + - `expectedIdentForAliasLet` https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L473-L485 +- `idIsNotStringLiteral` -- logic tested elsewhere +https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L768-L780 +- DML, DDL tests (DML, DDL not defined in spec yet) + - https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/syntax/SqlParserTest.kt#L2129-L3855 + - https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/syntax/SqlParserTest.kt#L3857-L3939 + - `unexpectedKeywordUpdateInSelectList` - https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L132-L142 + - https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L1291-L1457 + - https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L1980-L2662 +- Stored procedure calls (EXEC) not in spec yet + - https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L2760-L2846 + - https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/syntax/SqlParserTest.kt#L4179-L4237 +- semicolon semantic tests + - https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L1860-L1886 + - https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/syntax/SqlParserTest.kt#L4025-L4064 + +Unsure if should be included: +- `expectedCastAsIntArity`, `expectedCastAsRealArity` -- type supplied with parameter; not sure is parse error +https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L172-L204 +- `expectedUnsupportedLiteralsGroupBy` -- not part of the PartiQL spec; SQL92 says group by must use a column name +https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L417-L429 + - also for `groupByOrdinal`, `groupByOutOfBoundsOrdinal`, `groupByBadOrdinal`, `groupByStringConstantOrdinal` https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L953-L1007 +- `idIsNotGroupMissing` -- type surrounded by parens +https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L782-L794 +- `castToVarCharToTooBigLength`, `castToDecimalToTooBigLength_1`, `castToDecimalToTooBigLength_2`, `castToNumericToTooBigLength_1`, `castToNumericToTooBigLength_2` -- not quite a parse error; more so a semantic error +https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L220-L288 + - Similarly for `castNegativeArg` + https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L883-L895 +- `offsetBeforeLimit` -- not part of spec; postgresql allows; kotlin impl+mysql+sqlite don't allow; included as test for now +https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L1221-L1233 +- date_add/date_diff tests - date_add and date_diff aren't part of specs + - https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/syntax/SqlParserTest.kt#L957-L1036 + - https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L1743-L1858 +- `countExpressionStar` +https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L1966-L1978 +- `*` and path `*` with other select list items +https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L1903-L1936 + +Repeated tests (tests repeated at some other place): +- `expectedExpectedTypeName` +https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L78-L90 +- `likeWrongOrderOfArgs`, `likeMissingEscapeValue`, `likeMissingPattern` +https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L1487-L1527 +- `nullIsNullIonLiteral`, `idIsStringLiteral` +https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L1585-L1611 +- `selectWithFromAtAndAs` +https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L1627-L1639 + +To be included: +- DATE and TIME tests from [SqlParserDateTimeTests.kt](https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/syntax/SqlParserDateTimeTests.kt) +and [ParserErrorsTest.kt](https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L2848-L3099) +- Operator precedence tests from [SqlParserPrecedenceTest.kt](https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/syntax/SqlParserPrecedenceTest.kt) \ No newline at end of file diff --git a/partiql-test-data/fail/parser/primitives/aggregate-function-call.ion b/partiql-test-data/fail/parser/primitives/aggregate-function-call.ion new file mode 100644 index 0000000..fae7cd6 --- /dev/null +++ b/partiql-test-data/fail/parser/primitives/aggregate-function-call.ion @@ -0,0 +1,127 @@ +parse::{ + name: "AVG no args", + statement: "AVG()", + assert: { + result: ParseError + }, +} + +parse::{ + name: "AVG too many args", + statement: "AVG(a, b)", + assert: { + result: ParseError + }, +} + +parse::{ + name: "AVG with star", + statement: "AVG(*)", + assert: { + result: ParseError + }, +} + +parse::{ + name: "MAX no args", + statement: "MAX()", + assert: { + result: ParseError + }, +} + +parse::{ + name: "MAX too many args", + statement: "MAX(a, b)", + assert: { + result: ParseError + }, +} + +parse::{ + name: "MAX with star", + statement: "MAX(*)", + assert: { + result: ParseError + }, +} + +parse::{ + name: "MIN no args", + statement: "MIN()", + assert: { + result: ParseError + }, +} + +parse::{ + name: "MIN too many args", + statement: "MIN(a, b)", + assert: { + result: ParseError + }, +} + +parse::{ + name: "MIN with star", + statement: "MIN(*)", + assert: { + result: ParseError + }, +} + +parse::{ + name: "SUM no args", + statement: "SUM()", + assert: { + result: ParseError + }, +} + +parse::{ + name: "SUM too many args", + statement: "SUM(a, b)", + assert: { + result: ParseError + }, +} + +parse::{ + name: "SUM with star", + statement: "SUM(*)", + assert: { + result: ParseError + }, +} + +parse::{ + name: "COUNT no args", + statement: "COUNT()", + assert: { + result: ParseError + }, +} + +parse::{ + name: "COUNT too many args", + statement: "COUNT(a, b)", + assert: { + result: ParseError + }, +} + +parse::{ + name: "COUNT DISTINCT star", + statement: "COUNT(DISTINCT *)", + assert: { + result: ParseError + }, +} + +parse::{ + name: "COUNT ALL star", + statement: "COUNT(ALL *)", + assert: { + result: ParseError + }, +} diff --git a/partiql-test-data/fail/parser/primitives/call.ion b/partiql-test-data/fail/parser/primitives/call.ion new file mode 100644 index 0000000..f061b95 --- /dev/null +++ b/partiql-test-data/fail/parser/primitives/call.ion @@ -0,0 +1,174 @@ +substring::[ + sql92::[ + parse::{ + name: "SUBSTRING sql92 syntax missing left paren", + statement: "SELECT SUBSTRING FROM 'asdf' FOR 1) FROM foo", + assert: { + result: ParseError + }, + }, + parse::{ + name: "SUBSTRING sql92 syntax missing FROM or comma", + statement: "SELECT SUBSTRING('str' 1) FROM foo", + assert: { + result: ParseError + }, + }, + parse::{ + name: "SUBSTRING sql92 syntax without length and missing right paren", + statement: "SELECT SUBSTRING('str' FROM 1 FROM foo", + assert: { + result: ParseError + }, + }, + parse::{ + name: "SUBSTRING sql92 syntax with length missing right paren", + statement: "SELECT SUBSTRING('str' FROM 1 FOR 1 FROM foo", + assert: { + result: ParseError + }, + } + ], + partiql::[ + parse::{ + name: "SUBSTRING without length missing right paren", + statement: "SELECT SUBSTRING('str', 1 FROM foo", + assert: { + result: ParseError + }, + }, + parse::{ + name: "SUBSTRING missing right paren", + statement: "SELECT SUBSTRING('str', 1, 1 FROM foo", + assert: { + result: ParseError + }, + } + ] +] + +trim::[ + parse::{ + name: "TRIM no left paren", + statement: "TRIM ' ')", + assert: { + result: ParseError + }, + }, + parse::{ + name: "TRIM too many arguments", + statement: "TRIM(BOTH ' ' FROM 'test' 2)", + assert: { + result: ParseError + }, + }, + parse::{ + name: "TRIM with BOTH missing FROM", + statement: "TRIM(BOTH 'test')", + assert: { + result: ParseError + }, + }, + parse::{ + name: "TRIM and remove without FROM", + statement: "trim(both '' 'test')", + assert: { + result: ParseError + }, + }, + parse::{ + name: "TRIM without string", + statement: "TRIM(FROM)", + assert: { + result: ParseError + }, + }, + parse::{ + name: "TRIM no args", + statement: "TRIM()", + assert: { + result: ParseError + }, + }, + parse::{ + name: "TRIM with TRAILING missing FROM", + statement: "TRIM(trailing '')", + assert: { + result: ParseError + }, + }, + parse::{ + name: "TRIM all args but string", + statement: "TRIM(TRAILING '' FROM)", + assert: { + result: ParseError + }, + }, + parse::{ + name: "TRIM two args no FROM", + statement: "TRIM(' ' ' 1 ')", + assert: { + result: ParseError + }, + }, + parse::{ + name: "TRIM spec and FROM no string", + statement: "TRIM(TRAILING FROM)", + assert: { + result: ParseError + }, + }, +] + +extract::[ + parse::{ + name: "EXTRACT missing FROM", + statement: "EXTRACT(YEAR b)", + assert: { + result: ParseError + }, + }, + parse::{ + name: "EXTRACT missing FROM with comma", + statement: "EXTRACT(YEAR, b)", + assert: { + result: ParseError + }, + }, + parse::{ + name: "EXTRACT missing second argument", + statement: "EXTRACT(YEAR from)", + assert: { + result: ParseError + }, + }, + parse::{ + name: "EXTRACT missing date time part", + statement: "EXTRACT(FROM b)", + assert: { + result: ParseError + }, + }, + parse::{ + name: "EXTRACT with only second argument", + statement: "EXTRACT(b)", + assert: { + result: ParseError + }, + }, + parse::{ + name: "EXTRACT with only date time part", + statement: "EXTRACT(YEAR)", + assert: { + result: ParseError + }, + }, +] + +parse::{ + name: "function call not COUNT with star", + statement: "F(*)", + assert: { + result: ParseError + }, +} diff --git a/partiql-test-data/fail/parser/primitives/case.ion b/partiql-test-data/fail/parser/primitives/case.ion new file mode 100644 index 0000000..b5bf88d --- /dev/null +++ b/partiql-test-data/fail/parser/primitives/case.ion @@ -0,0 +1,31 @@ +parse::{ + name: "CASE expected WHEN clause", + statement: "CASE name ELSE 1 END", + assert: { + result: ParseError + }, +} + +parse::{ + name: "CASE only with END", + statement: "CASE END", + assert: { + result: ParseError + }, +} + +parse::{ + name: "searched CASE no when with ELSE", + statement: "CASE ELSE 1 END", + assert: { + result: ParseError + }, +} + +parse::{ + name: "simple CASE no when with ELSE", + statement: "CASE name ELSE 1 END", + assert: { + result: ParseError + }, +} diff --git a/partiql-test-data/fail/parser/primitives/cast.ion b/partiql-test-data/fail/parser/primitives/cast.ion new file mode 100644 index 0000000..914c56c --- /dev/null +++ b/partiql-test-data/fail/parser/primitives/cast.ion @@ -0,0 +1,23 @@ +parse::{ + name: "invalid cast type parameter", + statement: "CAST(5 AS VARCHAR(a))", + assert: { + result: ParseError + }, +} + +parse::{ + name: "CAST expected left paren", + statement: "CAST 5 as integer", + assert: { + result: ParseError + }, +} + +parse::{ + name: "CAST given keyword as type arg", + statement: "CAST(5 AS SELECT)", + assert: { + result: ParseError + }, +} diff --git a/partiql-test-data/fail/parser/primitives/container-constructors.ion b/partiql-test-data/fail/parser/primitives/container-constructors.ion new file mode 100644 index 0000000..ec7aef6 --- /dev/null +++ b/partiql-test-data/fail/parser/primitives/container-constructors.ion @@ -0,0 +1,7 @@ +parse::{ + name: "VALUES constructor expect left paren", + statement: "VALUES 1,2)", + assert: { + result: ParseError + }, +} diff --git a/partiql-test-data/fail/parser/primitives/expressions.ion b/partiql-test-data/fail/parser/primitives/expressions.ion new file mode 100644 index 0000000..4e96541 --- /dev/null +++ b/partiql-test-data/fail/parser/primitives/expressions.ion @@ -0,0 +1,31 @@ +parse::{ + name: "missing right paren", + statement: "(1 + 2", + assert: { + result: ParseError + }, +} + +parse::{ + name: "missing operation between literals", + statement: "5 5", + assert: { + result: ParseError + }, +} + +parse::{ + name: "semicolon inside expression", + statement: "(1;)", + assert: { + result: ParseError + }, +} + +parse::{ + name: "VALUE as top-level expression", + statement: "VALUE 1", + assert: { + result: ParseError + }, +} diff --git a/partiql-test-data/fail/parser/primitives/operators/at-operator.ion b/partiql-test-data/fail/parser/primitives/operators/at-operator.ion new file mode 100644 index 0000000..1c51717 --- /dev/null +++ b/partiql-test-data/fail/parser/primitives/operators/at-operator.ion @@ -0,0 +1,31 @@ +parse::{ + name: "at operator without identifier", + statement: "@", + assert: { + result: ParseError + }, +} + +parse::{ + name: "at operator on non identifier", + statement: "@(a)", + assert: { + result: ParseError + }, +} + +parse::{ + name: "double at operator on identifier", + statement: "@ @a", + assert: { + result: ParseError + }, +} + +parse::{ + name: "double at operator on identifier", + statement: "@ @a", + assert: { + result: ParseError + }, +} diff --git a/partiql-test-data/fail/parser/primitives/operators/between-operator.ion b/partiql-test-data/fail/parser/primitives/operators/between-operator.ion new file mode 100644 index 0000000..c03522a --- /dev/null +++ b/partiql-test-data/fail/parser/primitives/operators/between-operator.ion @@ -0,0 +1,7 @@ +parse::{ + name: "BETWEEN operator missing AND", + statement: "5 BETWEEN 1 10", + assert: { + result: ParseError + }, +} diff --git a/partiql-test-data/fail/parser/primitives/operators/is-operator.ion b/partiql-test-data/fail/parser/primitives/operators/is-operator.ion new file mode 100644 index 0000000..adbe32d --- /dev/null +++ b/partiql-test-data/fail/parser/primitives/operators/is-operator.ion @@ -0,0 +1,31 @@ +parse::{ + name: "IS operator expects type name", + statement: "NULL IS `null`", + assert: { + result: ParseError + }, +} + +parse::{ + name: "IS NOT operator expects type name", + statement: "NULL IS NOT `null`", + assert: { + result: ParseError + }, +} + +parse::{ + name: "IS operator parens around type name", + statement: "a IS (MISSING)", + assert: { + result: ParseError + }, +} + +parse::{ + name: "IS operator parens around type name", + statement: "a IS (MISSING)", + assert: { + result: ParseError + }, +} diff --git a/partiql-test-data/fail/parser/primitives/operators/like-operator.ion b/partiql-test-data/fail/parser/primitives/operators/like-operator.ion new file mode 100644 index 0000000..909dbb8 --- /dev/null +++ b/partiql-test-data/fail/parser/primitives/operators/like-operator.ion @@ -0,0 +1,47 @@ +parse::{ + name: "LIKE wrong order of args", + statement: "SELECT a, b FROM data WHERE LIKE a b", + assert: { + result: ParseError + }, +} + +parse::{ + name: "LIKE expected expression following ESCAPE", + statement: "SELECT a, b FROM data WHERE a LIKE b ESCAPE", + assert: { + result: ParseError + }, +} + +parse::{ + name: "LIKE missing rhs argument", + statement: "SELECT a, b FROM data WHERE a LIKE", + assert: { + result: ParseError + }, +} + +parse::{ + name: "LIKE col name LIKE col name ESCAPE typo", + statement: "SELECT a, b FROM data WHERE a LIKE b ECSAPE '\\'", + assert: { + result: ParseError + }, +} + +parse::{ + name: "LIKE ESCAPE before LIKE", + statement: "SELECT a, b FROM data WHERE ESCAPE '\\' a LIKE b", + assert: { + result: ParseError + }, +} + +parse::{ + name: "LIKE ESCAPE as second argument", + statement: "SELECT a, b FROM data WHERE a LIKE ESCAPE '\\' b", + assert: { + result: ParseError + }, +} diff --git a/partiql-test-data/fail/parser/primitives/path-expression.ion b/partiql-test-data/fail/parser/primitives/path-expression.ion new file mode 100644 index 0000000..a212cd5 --- /dev/null +++ b/partiql-test-data/fail/parser/primitives/path-expression.ion @@ -0,0 +1,15 @@ +parse::{ + name: "invalid path component too many dots", + statement: "x...a", + assert: { + result: ParseError + }, +} + +parse::{ + name: "invalid path componenet keyword in path", + statement: '''SELECT foo.id, foo.table FROM `[{id: 1, table: "foos"}]` AS foo''', + assert: { + result: ParseError + }, +} diff --git a/partiql-test-data/fail/parser/query/pivot.ion b/partiql-test-data/fail/parser/query/pivot.ion new file mode 100644 index 0000000..dc549d9 --- /dev/null +++ b/partiql-test-data/fail/parser/query/pivot.ion @@ -0,0 +1,7 @@ +parse::{ + name: "PIVOT no AT", + statement: "PIVOT v FROM data", + assert: { + result: ParseError + }, +} diff --git a/partiql-test-data/fail/parser/query/select/joins.ion b/partiql-test-data/fail/parser/query/select/joins.ion new file mode 100644 index 0000000..a9cdce2 --- /dev/null +++ b/partiql-test-data/fail/parser/query/select/joins.ion @@ -0,0 +1,152 @@ +parse::{ + name: "INNER CROSS JOIN with ON condition", + statement: "SELECT * FROM foo INNER CROSS JOIN bar ON true", + assert: { + result: ParseError + }, +} + +parse::{ + name: "LEFT CROSS JOIN with ON condition", + statement: "SELECT * FROM foo LEFT CROSS JOIN bar ON true", + assert: { + result: ParseError + }, +} + +parse::{ + name: "RIGHT CROSS JOIN with ON condition", + statement: "SELECT * FROM foo RIGHT CROSS JOIN bar ON true", + assert: { + result: ParseError + }, +} + +// From pg 181 of sql92 spec, must be specified for qualified joins +parse::{ + name: "INNER JOIN without ON condition", + statement: "SELECT * FROM foo INNER JOIN bar", + assert: { + result: ParseError + }, +} + +parse::{ + name: "LEFT JOIN without ON condition", + statement: "SELECT * FROM foo LEFT JOIN bar", + assert: { + result: ParseError + }, +} + +parse::{ + name: "RIGHT JOIN without ON condition", + statement: "SELECT * FROM foo RIGHT JOIN bar", + assert: { + result: ParseError + }, +} + +parse::{ + name: "JOIN without ON condition", + statement: "SELECT * FROM foo JOIN bar", + assert: { + result: ParseError + }, +} + +parse::{ + name: "paren INNER JOIN without ON clause", + statement: "SELECT * FROM foo INNER JOIN (bar INNER JOIN baz ON true)", + assert: { + result: ParseError + }, +} + +parse::{ + name: "SELECT with RIGHT CROSS JOIN", + statement: "SELECT x FROM stuff s RIGHT CROSS JOIN foo f", + assert: { + result: ParseError + }, +} + +parse::{ + name: "SELECT with FULL OUTER JOIN and ON condition", + statement: "SELECT x FROM stuff s FULL OUTER JOIN foo f ON s = f", + assert: { + result: ParseError + }, +} + +parse::{ + name: "SELECT single join parens test", + statement: "SELECT x FROM (A INNER JOIN B ON A = B)", + assert: { + result: ParseError + }, +} + +parse::{ + name: "SELECT single join multi parens", + statement: "SELECT x FROM (((A INNER JOIN B ON A = B)))", + assert: { + result: ParseError + }, +} + +parse::{ + name: "SELECT two joins natural order parens", + statement: "SELECT x FROM (A INNER JOIN B ON A = B) INNER JOIN C ON B = C", + assert: { + result: ParseError + }, +} + +parse::{ + name: "SELECT two joins specified order parens", + statement: "SELECT x FROM A INNER JOIN (B INNER JOIN C ON B = C) ON A = B", + assert: { + result: ParseError + }, +} + +parse::{ + name: "SELECT three joins specified order parens", + statement: "SELECT x FROM A INNER JOIN (B INNER JOIN (C INNER JOIN D ON C = D) ON B = C) ON A = B", + assert: { + result: ParseError + }, +} + +parse::{ + name: "SELECT literal wrapped in parens", + statement: "SELECT x FROM A INNER JOIN (1) ON true", + assert: { + result: ParseError + }, +} + +parse::{ + name: "SELECT subquery wrapped in parens", + statement: "SELECT x FROM A INNER JOIN (SELECT x FROM 1) ON true", + assert: { + result: ParseError + }, +} + +parse::{ + name: "SELECT with multiple JOINS and implicit CROSS JOIN", + statement: "SELECT x FROM a, b CROSS JOIN c LEFT JOIN d ON e RIGHT OUTER CROSS JOIN f OUTER JOIN g ON h", + assert: { + result: ParseError + }, +} + +parse::{ + name: "SELECT with multiple JOINS and explicit CROSS JOIN", + statement: "SELECT x FROM a INNER CROSS JOIN b CROSS JOIN c LEFT JOIN d ON e RIGHT OUTER CROSS JOIN f OUTER JOIN g ON h", + assert: { + result: ParseError + }, +} diff --git a/partiql-test-data/fail/parser/query/select/limit-offset.ion b/partiql-test-data/fail/parser/query/select/limit-offset.ion new file mode 100644 index 0000000..0b87bfd --- /dev/null +++ b/partiql-test-data/fail/parser/query/select/limit-offset.ion @@ -0,0 +1,31 @@ +parse::{ + name: "LIMIT OFFSET before ORDER BY", + statement: "SELECT a FROM tb LIMIT 10 OFFSET 5 ORDER BY b ASC", + assert: { + result: ParseError + }, +} + +parse::{ + name: "LIMIT OFFSET before ORDER BY with NULLS spec", + statement: "SELECT a FROM tb LIMIT 10 OFFSET 5 ORDER BY b ASC NULLS FIRST", + assert: { + result: ParseError + }, +} + +parse::{ + name: "OFFSET missing argument", + statement: "SELECT a FROM tb OFFSET", + assert: { + result: ParseError + }, +} + +parse::{ + name: "OFFSET unexpected keyword as attribute", + statement: "SELECT a FROM tb OFFSET SELECT", + assert: { + result: ParseError + }, +} diff --git a/partiql-test-data/fail/parser/query/select/order-by.ion b/partiql-test-data/fail/parser/query/select/order-by.ion new file mode 100644 index 0000000..a2f07dd --- /dev/null +++ b/partiql-test-data/fail/parser/query/select/order-by.ion @@ -0,0 +1,127 @@ +parse::{ + name: "ORDER BY missing BY and sort spec", + statement: "SELECT a FROM tb ORDER", + assert: { + result: ParseError + }, +} + +parse::{ + name: "ORDER BY missing BY", + statement: "SELECT a FROM tb ORDER foo", + assert: { + result: ParseError + }, +} + +parse::{ + name: "ORDER BY missing sort spec", + statement: "SELECT a FROM tb ORDER BY", + assert: { + result: ParseError + }, +} + +parse::{ + name: "ORDER BY multiple attributes in sort spec missing comma", + statement: "SELECT a FROM tb ORDER BY foo bar", + assert: { + result: ParseError + }, +} + +parse::{ + name: "ORDER BY multiple empty parsed comma list", + statement: "SELECT a FROM tb ORDER BY foo, ,", + assert: { + result: ParseError + }, +} + +parse::{ + name: "ORDER BY missing attribute name", + statement: "SELECT a FROM tb ORDER BY ASC, bar", + assert: { + result: ParseError + }, +} + +parse::{ + name: "ORDER BY invalid punctuation", + statement: "SELECT a FROM tb ORDER BY ASC; bar", + assert: { + result: ParseError + }, +} + +parse::{ + name: "ORDER BY multiple order spec", + statement: "SELECT a FROM tb ORDER BY foo ASC DESC", + assert: { + result: ParseError + }, +} + +parse::{ + name: "ORDER BY unexpected keyword as attribute", + statement: "SELECT a FROM tb ORDER BY SELECT", + assert: { + result: ParseError + }, +} + +parse::{ + name: "ORDER BY missing NULLS type", + statement: "SELECT a FROM tb ORDER BY a ASC NULLS", + assert: { + result: ParseError + }, +} + +parse::{ + name: "ORDER BY missing NULLS keyword with FIRST", + statement: "SELECT a FROM tb ORDER BY a ASC FIRST", + assert: { + result: ParseError + }, +} + +parse::{ + name: "ORDER BY missing NULLS keyword with LAST", + statement: "SELECT a FROM tb ORDER BY a ASC LAST", + assert: { + result: ParseError + }, +} + +parse::{ + name: "ORDER BY NULLS spec before ORDER BY", + statement: "SELECT a FROM tb NULLS LAST ORDER BY a ASC", + assert: { + result: ParseError + }, +} + +parse::{ + name: "ORDER BY unexpected NULLS keyword attribute", + statement: "SELECT a FROM tb ORDER BY a NULLS SELECT", + assert: { + result: ParseError + }, +} + +parse::{ + name: "ORDER BY unexpected keyword", + statement: "SELECT a FROM tb ORDER BY a NULLS FIRST SELECT", + assert: { + result: ParseError + }, +} + +parse::{ + name: "OFFSET before LIMIT", + statement: "SELECT a FROM tb OFFSET 5 LIMIT 10", + assert: { + result: ParseError + }, +} diff --git a/partiql-test-data/fail/parser/query/select/select.ion b/partiql-test-data/fail/parser/query/select/select.ion new file mode 100644 index 0000000..c2573af --- /dev/null +++ b/partiql-test-data/fail/parser/query/select/select.ion @@ -0,0 +1,63 @@ +parse::{ + name: "SFW without WHERE expression", + statement: "SELECT * FROM foo WHERE", + assert: { + result: ParseError + }, +} + +parse::{ + name: "SELECT without comma between projection items", + statement: "SELECT a data", + assert: { + result: ParseError + }, +} + +parse::{ + name: "AT before AS alias", + statement: "SELECT ord, val FROM table1 AT ord AS val", + assert: { + result: ParseError + }, +} + +parse::{ + name: "SELECT missing projection", + statement: "SELECT FROM table1", + assert: { + result: ParseError + }, +} + +parse::{ + name: "SELECT list with extra comma", + statement: "SELECT a, FROM {'a' : 1}", + assert: { + result: ParseError + }, +} + +parse::{ + name: "SELECT projection with empty parens", + statement: "SELECT () FROM data", + assert: { + result: ParseError + }, +} + +parse::{ + name: "expected identifier for AS alias", + statement: "SELECT a AS true FROM data", + assert: { + result: ParseError + }, +} + +parse::{ + name: "expected identifier for AT alias", + statement: "SELECT a FROM data AT true", + assert: { + result: ParseError + }, +} diff --git a/partiql-test-data/fail/parser/select/select-from-where.ion b/partiql-test-data/fail/parser/select/select-from-where.ion deleted file mode 100644 index 20a3d2e..0000000 --- a/partiql-test-data/fail/parser/select/select-from-where.ion +++ /dev/null @@ -1,7 +0,0 @@ -parse::{ - name: "SFW without WHERE expression", - statement: "SELECT * FROM foo WHERE", - assert: { - result: ParseError - }, -} diff --git a/partiql-test-data/pass/parser/primitives/aggregate-function-call.ion b/partiql-test-data/pass/parser/primitives/aggregate-function-call.ion index 7e95c3c..d327a04 100644 --- a/partiql-test-data/pass/parser/primitives/aggregate-function-call.ion +++ b/partiql-test-data/pass/parser/primitives/aggregate-function-call.ion @@ -1,6 +1,6 @@ parse::{ - name: "COUNT aggregate function call", - statement: "COUNT(a)", + name: "SUM aggregate function call", + statement: "SUM(a)", assert: [ { result: ParseOk @@ -18,6 +18,26 @@ parse::{ ] } +parse::{ + name: "SUM ALL aggregate function call", + statement: "SUM(ALL a)", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "COUNT aggregate function call", + statement: "COUNT(a)", + assert: [ + { + result: ParseOk + }, + ] +} + parse::{ name: "COUNT star aggregate function call", statement: "COUNT(*)", @@ -28,6 +48,16 @@ parse::{ ] } +parse::{ + name: "COUNT ALL aggregate function call", + statement: "COUNT(ALL a)", + assert: [ + { + result: ParseOk + }, + ] +} + parse::{ name: "COUNT DISTINCT aggregate function call", statement: "COUNT(DISTINCT a)", @@ -37,3 +67,93 @@ parse::{ }, ] } + +parse::{ + name: "AVG aggregate function call", + statement: "AVG(a)", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "AVG DISTINCT aggregate function call", + statement: "AVG(DISTINCT a)", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "AVG ALL aggregate function call", + statement: "AVG(ALL a)", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "MAX DISTINCT aggregate function call", + statement: "MAX(a)", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "MAX DISTINCT aggregate function call", + statement: "MAX(DISTINCT a)", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "MAX ALL aggregate function call", + statement: "MAX(ALL a)", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "MIN DISTINCT aggregate function call", + statement: "MIN(a)", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "MIN DISTINCT aggregate function call", + statement: "MIN(DISTINCT a)", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "MIN ALL aggregate function call", + statement: "MIN(ALL a)", + assert: [ + { + result: ParseOk + }, + ] +} diff --git a/partiql-test-data/pass/parser/primitives/operators/arithmetic-operators.ion b/partiql-test-data/pass/parser/primitives/operators/arithmetic-operators.ion new file mode 100644 index 0000000..c025920 --- /dev/null +++ b/partiql-test-data/pass/parser/primitives/operators/arithmetic-operators.ion @@ -0,0 +1,59 @@ +parse::{ + name: "plus operator", + statement: "a + b", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "minus operator", + statement: "a - b", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "times operator", + statement: "a * b", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "divide operator", + statement: "a / b", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "modulo operator", + statement: "a % b", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "arithmetic operators chained together", + statement: "a + b - c * d / e % f", + assert: [ + { + result: ParseOk + }, + ] +} \ No newline at end of file diff --git a/partiql-test-data/pass/parser/primitives/operators/comparison-operators.ion b/partiql-test-data/pass/parser/primitives/operators/comparison-operators.ion new file mode 100644 index 0000000..d017d83 --- /dev/null +++ b/partiql-test-data/pass/parser/primitives/operators/comparison-operators.ion @@ -0,0 +1,79 @@ +parse::{ + name: "eq operator", + statement: "a = b", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "neq operator", + statement: "a != b", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "neq operator other form", + statement: "a <> b", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "gt operator", + statement: "a > b", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "lt operator", + statement: "a < b", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "gte operator", + statement: "a >= b", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "lte operator", + statement: "a <= b", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "comparison ops with logical ops", + statement: "a = b AND NOT c != d OR e <> f AND g > h OR NOT NOT i < j AND k >= l OR m <= n", + assert: [ + { + result: ParseOk + }, + ] +} diff --git a/partiql-test-data/pass/parser/primitives/operators/logical-operators.ion b/partiql-test-data/pass/parser/primitives/operators/logical-operators.ion new file mode 100644 index 0000000..6cddb74 --- /dev/null +++ b/partiql-test-data/pass/parser/primitives/operators/logical-operators.ion @@ -0,0 +1,39 @@ +parse::{ + name: "unary NOT literal", + statement: "not 1", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "chained logical AND", + statement: "a AND b AND c", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "chained logical OR", + statement: "a OR b OR c", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "chained logical ops", + statement: "NOT NOT a AND b OR c OR NOT d AND NOT NOT NOT e", + assert: [ + { + result: ParseOk + }, + ] +} diff --git a/partiql-test-data/pass/parser/primitives/operators/string-operators.ion b/partiql-test-data/pass/parser/primitives/operators/string-operators.ion new file mode 100644 index 0000000..8d2b77d --- /dev/null +++ b/partiql-test-data/pass/parser/primitives/operators/string-operators.ion @@ -0,0 +1,19 @@ +parse::{ + name: "concat operator", + statement: "a || b", + assert: [ + { + result: ParseOk + }, + ] +} + +parse::{ + name: "chained concat operator", + statement: "a || b || c || d || e", + assert: [ + { + result: ParseOk + }, + ] +} diff --git a/partiql-test-data/pass/parser/primitives/operators/unary-operators.ion b/partiql-test-data/pass/parser/primitives/operators/unary-operators.ion index 4cb256b..5c41d15 100644 --- a/partiql-test-data/pass/parser/primitives/operators/unary-operators.ion +++ b/partiql-test-data/pass/parser/primitives/operators/unary-operators.ion @@ -57,13 +57,3 @@ parse::{ }, ] } - -parse::{ - name: "unary NOT literal", - statement: "not 1", - assert: [ - { - result: ParseOk - }, - ] -} diff --git a/partiql-test-data/pass/parser/query/select/joins.ion b/partiql-test-data/pass/parser/query/select/joins.ion index d76a8bf..9e1c010 100644 --- a/partiql-test-data/pass/parser/query/select/joins.ion +++ b/partiql-test-data/pass/parser/query/select/joins.ion @@ -29,3 +29,41 @@ parse::{ result: ParseOk } } + +'correlated-joins'::[ + parse::{ + name: "SELECT correlated JOIN", + statement: "SELECT a, b FROM stuff s, @s WHERE f(s)", + assert: { + result: ParseOk + } + }, + parse::{ + name: "SELECT correlated with explicit CROSS JOIN", + statement: "SELECT a, b FROM stuff s CROSS JOIN @s WHERE f(s)", + assert: { + result: ParseOk + } + }, + parse::{ + name: "SELECT correlated with explicit LEFT CROSS JOIN", + statement: "SELECT a, b FROM stuff s LEFT CROSS JOIN @s WHERE f(s)", + assert: { + result: ParseOk + } + }, + parse::{ + name: "SELECT correlated with explicit LEFT OUTER JOIN and ON", + statement: "SELECT a, b FROM stuff s LEFT JOIN @s ON f(s)", + assert: { + result: ParseOk + } + }, + parse::{ + name: "SELECT correlated JOIN with explicit INNER JOIN", + statement: "SELECT a, b FROM stuff s INNER CROSS JOIN @s WHERE f(s)", + assert: { + result: ParseOk + } + }, +] From 26a5720d8eba843e9f4d8421d5c25f511eefb449 Mon Sep 17 00:00:00 2001 From: Alan Cai Date: Sun, 8 May 2022 22:09:12 -0700 Subject: [PATCH 2/2] Add semantic/ fail tests directory; move some JOIN tests to pass directory --- README.md | 1 + partiql-lang-kotlin-omitted-tests.md | 9 +- .../fail/parser/primitives/call.ion | 116 ------------------ .../fail/parser/primitives/cast.ion | 8 -- .../primitives/operators/at-operator.ion | 8 -- .../primitives/operators/is-operator.ion | 12 +- .../parser/primitives/path-expression.ion | 2 +- .../fail/parser/query/select/joins.ion | 104 ++-------------- .../fail/parser/query/select/select.ion | 8 ++ partiql-test-data/fail/semantic/README.md | 4 + .../primitives/aggregate-function-call.ion | 64 +++++----- .../fail/semantic/primitives/call.ion | 111 +++++++++++++++++ .../fail/semantic/primitives/cast.ion | 7 ++ .../primitives/operator/is-operator.ion | 7 ++ .../pass/parser/query/select/joins.ion | 88 +++++++++++++ partiql-tests-schema-proposal.md | 20 +++ 16 files changed, 294 insertions(+), 275 deletions(-) create mode 100644 partiql-test-data/fail/semantic/README.md rename partiql-test-data/fail/{parser => semantic}/primitives/aggregate-function-call.ion (65%) create mode 100644 partiql-test-data/fail/semantic/primitives/call.ion create mode 100644 partiql-test-data/fail/semantic/primitives/cast.ion create mode 100644 partiql-test-data/fail/semantic/primitives/operator/is-operator.ion diff --git a/README.md b/README.md index 53f5a5a..5ce0fe4 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ The test data is partitioned into the following directories: Subdirectories: - `pass/parser` - statements that can parse without error - `fail/parser` - statements that give an error when parsed +- `fail/semantic` - statements that give an error at some stage between parsing and evaluation - `pass/eval` - statements that can be evaluated successfully and return the same result as the expected result - `fail/eval` - statements that throw an error during evaluation diff --git a/partiql-lang-kotlin-omitted-tests.md b/partiql-lang-kotlin-omitted-tests.md index e7b6af9..af9a1ff 100644 --- a/partiql-lang-kotlin-omitted-tests.md +++ b/partiql-lang-kotlin-omitted-tests.md @@ -7,12 +7,11 @@ Tests excluded: - [SqlParserCustomTypeCatalogTests.kt](https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/syntax/SqlParserCustomTypeCatalogTests.kt) - ORDER BY tests testing defaults for sort spec and null spec - https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/syntax/SqlParserTest.kt#L1793-L1888 - - dependent on when parsed ast checking is added + - dependent on when parsed ast checking is added or up to the implementation to test via correspondence (see comment here https://github.com/partiql/partiql-tests/pull/11/files#r865515909) + - alternatively, this may be better tested in the evaluator - Many nested NOT regression test - https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/syntax/SqlParserTest.kt#L4239-L4271 - performance test shouldn't be included in parse tests -- `expectedSelectMissingFrom` -- not part of the PartiQL spec -https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L403-L415 - LET clause parsing (not part of spec formally yet) - https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/syntax/SqlParserTest.kt#L4066-L4128 - `expectedAsForLet` https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L431-L443 @@ -53,7 +52,9 @@ https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L1966-L1978 - `*` and path `*` with other select list items https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L1903-L1936 - +- `callTrimSpecificationMissingFrom` -- PostgreSQL supports; unsure of utility of creating this fail test + - https://github.com/~~partiql~~/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L683-L696 + - More details provided by Josh in this comment on the ambiguity https://github.com/partiql/partiql-tests/pull/11/files#r865505304 Repeated tests (tests repeated at some other place): - `expectedExpectedTypeName` https://github.com/partiql/partiql-lang-kotlin/blob/34625c68dbcbaf7b8ae60df7a4cf65c60b2a3b79/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt#L78-L90 diff --git a/partiql-test-data/fail/parser/primitives/call.ion b/partiql-test-data/fail/parser/primitives/call.ion index f061b95..d224ba1 100644 --- a/partiql-test-data/fail/parser/primitives/call.ion +++ b/partiql-test-data/fail/parser/primitives/call.ion @@ -55,120 +55,4 @@ trim::[ result: ParseError }, }, - parse::{ - name: "TRIM too many arguments", - statement: "TRIM(BOTH ' ' FROM 'test' 2)", - assert: { - result: ParseError - }, - }, - parse::{ - name: "TRIM with BOTH missing FROM", - statement: "TRIM(BOTH 'test')", - assert: { - result: ParseError - }, - }, - parse::{ - name: "TRIM and remove without FROM", - statement: "trim(both '' 'test')", - assert: { - result: ParseError - }, - }, - parse::{ - name: "TRIM without string", - statement: "TRIM(FROM)", - assert: { - result: ParseError - }, - }, - parse::{ - name: "TRIM no args", - statement: "TRIM()", - assert: { - result: ParseError - }, - }, - parse::{ - name: "TRIM with TRAILING missing FROM", - statement: "TRIM(trailing '')", - assert: { - result: ParseError - }, - }, - parse::{ - name: "TRIM all args but string", - statement: "TRIM(TRAILING '' FROM)", - assert: { - result: ParseError - }, - }, - parse::{ - name: "TRIM two args no FROM", - statement: "TRIM(' ' ' 1 ')", - assert: { - result: ParseError - }, - }, - parse::{ - name: "TRIM spec and FROM no string", - statement: "TRIM(TRAILING FROM)", - assert: { - result: ParseError - }, - }, ] - -extract::[ - parse::{ - name: "EXTRACT missing FROM", - statement: "EXTRACT(YEAR b)", - assert: { - result: ParseError - }, - }, - parse::{ - name: "EXTRACT missing FROM with comma", - statement: "EXTRACT(YEAR, b)", - assert: { - result: ParseError - }, - }, - parse::{ - name: "EXTRACT missing second argument", - statement: "EXTRACT(YEAR from)", - assert: { - result: ParseError - }, - }, - parse::{ - name: "EXTRACT missing date time part", - statement: "EXTRACT(FROM b)", - assert: { - result: ParseError - }, - }, - parse::{ - name: "EXTRACT with only second argument", - statement: "EXTRACT(b)", - assert: { - result: ParseError - }, - }, - parse::{ - name: "EXTRACT with only date time part", - statement: "EXTRACT(YEAR)", - assert: { - result: ParseError - }, - }, -] - -parse::{ - name: "function call not COUNT with star", - statement: "F(*)", - assert: { - result: ParseError - }, -} diff --git a/partiql-test-data/fail/parser/primitives/cast.ion b/partiql-test-data/fail/parser/primitives/cast.ion index 914c56c..58dd9ef 100644 --- a/partiql-test-data/fail/parser/primitives/cast.ion +++ b/partiql-test-data/fail/parser/primitives/cast.ion @@ -1,11 +1,3 @@ -parse::{ - name: "invalid cast type parameter", - statement: "CAST(5 AS VARCHAR(a))", - assert: { - result: ParseError - }, -} - parse::{ name: "CAST expected left paren", statement: "CAST 5 as integer", diff --git a/partiql-test-data/fail/parser/primitives/operators/at-operator.ion b/partiql-test-data/fail/parser/primitives/operators/at-operator.ion index 1c51717..2975054 100644 --- a/partiql-test-data/fail/parser/primitives/operators/at-operator.ion +++ b/partiql-test-data/fail/parser/primitives/operators/at-operator.ion @@ -21,11 +21,3 @@ parse::{ result: ParseError }, } - -parse::{ - name: "double at operator on identifier", - statement: "@ @a", - assert: { - result: ParseError - }, -} diff --git a/partiql-test-data/fail/parser/primitives/operators/is-operator.ion b/partiql-test-data/fail/parser/primitives/operators/is-operator.ion index adbe32d..8b891a0 100644 --- a/partiql-test-data/fail/parser/primitives/operators/is-operator.ion +++ b/partiql-test-data/fail/parser/primitives/operators/is-operator.ion @@ -1,11 +1,3 @@ -parse::{ - name: "IS operator expects type name", - statement: "NULL IS `null`", - assert: { - result: ParseError - }, -} - parse::{ name: "IS NOT operator expects type name", statement: "NULL IS NOT `null`", @@ -23,8 +15,8 @@ parse::{ } parse::{ - name: "IS operator parens around type name", - statement: "a IS (MISSING)", + name: "IS NOT operator parens around type name", + statement: "a IS NOT (MISSING)", assert: { result: ParseError }, diff --git a/partiql-test-data/fail/parser/primitives/path-expression.ion b/partiql-test-data/fail/parser/primitives/path-expression.ion index a212cd5..23c702c 100644 --- a/partiql-test-data/fail/parser/primitives/path-expression.ion +++ b/partiql-test-data/fail/parser/primitives/path-expression.ion @@ -7,7 +7,7 @@ parse::{ } parse::{ - name: "invalid path componenet keyword in path", + name: "invalid path component keyword in path", statement: '''SELECT foo.id, foo.table FROM `[{id: 1, table: "foos"}]` AS foo''', assert: { result: ParseError diff --git a/partiql-test-data/fail/parser/query/select/joins.ion b/partiql-test-data/fail/parser/query/select/joins.ion index a9cdce2..50cb978 100644 --- a/partiql-test-data/fail/parser/query/select/joins.ion +++ b/partiql-test-data/fail/parser/query/select/joins.ion @@ -1,5 +1,5 @@ parse::{ - name: "INNER CROSS JOIN with ON condition", + name: "INNER CROSS JOIN with extraneous ON condition", statement: "SELECT * FROM foo INNER CROSS JOIN bar ON true", assert: { result: ParseError @@ -7,7 +7,7 @@ parse::{ } parse::{ - name: "LEFT CROSS JOIN with ON condition", + name: "LEFT CROSS JOIN with extraneous ON condition", statement: "SELECT * FROM foo LEFT CROSS JOIN bar ON true", assert: { result: ParseError @@ -15,7 +15,7 @@ parse::{ } parse::{ - name: "RIGHT CROSS JOIN with ON condition", + name: "RIGHT CROSS JOIN with extraneous ON condition", statement: "SELECT * FROM foo RIGHT CROSS JOIN bar ON true", assert: { result: ParseError @@ -24,7 +24,7 @@ parse::{ // From pg 181 of sql92 spec, must be specified for qualified joins parse::{ - name: "INNER JOIN without ON condition", + name: "INNER JOIN missing required ON condition", statement: "SELECT * FROM foo INNER JOIN bar", assert: { result: ParseError @@ -32,7 +32,7 @@ parse::{ } parse::{ - name: "LEFT JOIN without ON condition", + name: "LEFT JOIN missing required ON condition", statement: "SELECT * FROM foo LEFT JOIN bar", assert: { result: ParseError @@ -40,7 +40,7 @@ parse::{ } parse::{ - name: "RIGHT JOIN without ON condition", + name: "RIGHT JOIN missing required ON condition", statement: "SELECT * FROM foo RIGHT JOIN bar", assert: { result: ParseError @@ -48,7 +48,7 @@ parse::{ } parse::{ - name: "JOIN without ON condition", + name: "JOIN missing required ON condition", statement: "SELECT * FROM foo JOIN bar", assert: { result: ParseError @@ -56,97 +56,9 @@ parse::{ } parse::{ - name: "paren INNER JOIN without ON clause", + name: "paren INNER JOIN missing required ON clause", statement: "SELECT * FROM foo INNER JOIN (bar INNER JOIN baz ON true)", assert: { result: ParseError }, } - -parse::{ - name: "SELECT with RIGHT CROSS JOIN", - statement: "SELECT x FROM stuff s RIGHT CROSS JOIN foo f", - assert: { - result: ParseError - }, -} - -parse::{ - name: "SELECT with FULL OUTER JOIN and ON condition", - statement: "SELECT x FROM stuff s FULL OUTER JOIN foo f ON s = f", - assert: { - result: ParseError - }, -} - -parse::{ - name: "SELECT single join parens test", - statement: "SELECT x FROM (A INNER JOIN B ON A = B)", - assert: { - result: ParseError - }, -} - -parse::{ - name: "SELECT single join multi parens", - statement: "SELECT x FROM (((A INNER JOIN B ON A = B)))", - assert: { - result: ParseError - }, -} - -parse::{ - name: "SELECT two joins natural order parens", - statement: "SELECT x FROM (A INNER JOIN B ON A = B) INNER JOIN C ON B = C", - assert: { - result: ParseError - }, -} - -parse::{ - name: "SELECT two joins specified order parens", - statement: "SELECT x FROM A INNER JOIN (B INNER JOIN C ON B = C) ON A = B", - assert: { - result: ParseError - }, -} - -parse::{ - name: "SELECT three joins specified order parens", - statement: "SELECT x FROM A INNER JOIN (B INNER JOIN (C INNER JOIN D ON C = D) ON B = C) ON A = B", - assert: { - result: ParseError - }, -} - -parse::{ - name: "SELECT literal wrapped in parens", - statement: "SELECT x FROM A INNER JOIN (1) ON true", - assert: { - result: ParseError - }, -} - -parse::{ - name: "SELECT subquery wrapped in parens", - statement: "SELECT x FROM A INNER JOIN (SELECT x FROM 1) ON true", - assert: { - result: ParseError - }, -} - -parse::{ - name: "SELECT with multiple JOINS and implicit CROSS JOIN", - statement: "SELECT x FROM a, b CROSS JOIN c LEFT JOIN d ON e RIGHT OUTER CROSS JOIN f OUTER JOIN g ON h", - assert: { - result: ParseError - }, -} - -parse::{ - name: "SELECT with multiple JOINS and explicit CROSS JOIN", - statement: "SELECT x FROM a INNER CROSS JOIN b CROSS JOIN c LEFT JOIN d ON e RIGHT OUTER CROSS JOIN f OUTER JOIN g ON h", - assert: { - result: ParseError - }, -} diff --git a/partiql-test-data/fail/parser/query/select/select.ion b/partiql-test-data/fail/parser/query/select/select.ion index c2573af..632eb5c 100644 --- a/partiql-test-data/fail/parser/query/select/select.ion +++ b/partiql-test-data/fail/parser/query/select/select.ion @@ -61,3 +61,11 @@ parse::{ result: ParseError }, } + +parse::{ + name: "SELECT query missing FROM", + statement: "SELECT a DATA", + assert: { + result: ParseError + }, +} diff --git a/partiql-test-data/fail/semantic/README.md b/partiql-test-data/fail/semantic/README.md new file mode 100644 index 0000000..62ba3a4 --- /dev/null +++ b/partiql-test-data/fail/semantic/README.md @@ -0,0 +1,4 @@ +Tests in this directory should have statements that error at some stage of semantic passes or type-checking. That is, +at some stage between parsing and evaluation. It's up to the PartiQL implementation to decide at what stage tests in +this directory will give an error. For some implementations, these tests may fail in the parse stage if they strictly +implement SQL standard's EBNF, but some implementations may fail at a different stage. \ No newline at end of file diff --git a/partiql-test-data/fail/parser/primitives/aggregate-function-call.ion b/partiql-test-data/fail/semantic/primitives/aggregate-function-call.ion similarity index 65% rename from partiql-test-data/fail/parser/primitives/aggregate-function-call.ion rename to partiql-test-data/fail/semantic/primitives/aggregate-function-call.ion index fae7cd6..c31fd70 100644 --- a/partiql-test-data/fail/parser/primitives/aggregate-function-call.ion +++ b/partiql-test-data/fail/semantic/primitives/aggregate-function-call.ion @@ -1,127 +1,127 @@ -parse::{ +semantic::{ name: "AVG no args", statement: "AVG()", assert: { - result: ParseError + result: SemanticError }, } -parse::{ +semantic::{ name: "AVG too many args", statement: "AVG(a, b)", assert: { - result: ParseError + result: SemanticError }, } -parse::{ +semantic::{ name: "AVG with star", statement: "AVG(*)", assert: { - result: ParseError + result: SemanticError }, } -parse::{ +semantic::{ name: "MAX no args", statement: "MAX()", assert: { - result: ParseError + result: SemanticError }, } -parse::{ +semantic::{ name: "MAX too many args", statement: "MAX(a, b)", assert: { - result: ParseError + result: SemanticError }, } -parse::{ +semantic::{ name: "MAX with star", statement: "MAX(*)", assert: { - result: ParseError + result: SemanticError }, } -parse::{ +semantic::{ name: "MIN no args", statement: "MIN()", assert: { - result: ParseError + result: SemanticError }, } -parse::{ +semantic::{ name: "MIN too many args", statement: "MIN(a, b)", assert: { - result: ParseError + result: SemanticError }, } -parse::{ +semantic::{ name: "MIN with star", statement: "MIN(*)", assert: { - result: ParseError + result: SemanticError }, } -parse::{ +semantic::{ name: "SUM no args", statement: "SUM()", assert: { - result: ParseError + result: SemanticError }, } -parse::{ +semantic::{ name: "SUM too many args", statement: "SUM(a, b)", assert: { - result: ParseError + result: SemanticError }, } -parse::{ +semantic::{ name: "SUM with star", statement: "SUM(*)", assert: { - result: ParseError + result: SemanticError }, } -parse::{ +semantic::{ name: "COUNT no args", statement: "COUNT()", assert: { - result: ParseError + result: SemanticError }, } -parse::{ +semantic::{ name: "COUNT too many args", statement: "COUNT(a, b)", assert: { - result: ParseError + result: SemanticError }, } -parse::{ +semantic::{ name: "COUNT DISTINCT star", statement: "COUNT(DISTINCT *)", assert: { - result: ParseError + result: SemanticError }, } -parse::{ +semantic::{ name: "COUNT ALL star", statement: "COUNT(ALL *)", assert: { - result: ParseError + result: SemanticError }, } diff --git a/partiql-test-data/fail/semantic/primitives/call.ion b/partiql-test-data/fail/semantic/primitives/call.ion new file mode 100644 index 0000000..6062ac0 --- /dev/null +++ b/partiql-test-data/fail/semantic/primitives/call.ion @@ -0,0 +1,111 @@ +trim::[ + semantic::{ + name: "TRIM too many arguments", + statement: "TRIM(BOTH ' ' FROM 'test' 2)", + assert: { + result: SemanticError + }, + }, + semantic::{ + name: "TRIM with BOTH missing FROM", + statement: "TRIM(BOTH 'test')", + assert: { + result: SemanticError + }, + }, + semantic::{ + name: "TRIM and remove without FROM", + statement: "trim(both '' 'test')", + assert: { + result: SemanticError + }, + }, + semantic::{ + name: "TRIM without string", + statement: "TRIM(FROM)", + assert: { + result: SemanticError + }, + }, + semantic::{ + name: "TRIM no args", + statement: "TRIM()", + assert: { + result: SemanticError + }, + }, + semantic::{ + name: "TRIM all args but string", + statement: "TRIM(TRAILING '' FROM)", + assert: { + result: SemanticError + }, + }, + semantic::{ + name: "TRIM two args no FROM", + statement: "TRIM(' ' ' 1 ')", + assert: { + result: SemanticError + }, + }, + semantic::{ + name: "TRIM spec and FROM no string", + statement: "TRIM(TRAILING FROM)", + assert: { + result: SemanticError + }, + }, +] + +extract::[ + semantic::{ + name: "EXTRACT missing FROM", + statement: "EXTRACT(YEAR b)", + assert: { + result: SemanticError + }, + }, + semantic::{ + name: "EXTRACT missing FROM with comma", + statement: "EXTRACT(YEAR, b)", + assert: { + result: SemanticError + }, + }, + semantic::{ + name: "EXTRACT missing second argument", + statement: "EXTRACT(YEAR from)", + assert: { + result: SemanticError + }, + }, + semantic::{ + name: "EXTRACT missing date time part", + statement: "EXTRACT(FROM b)", + assert: { + result: SemanticError + }, + }, + semantic::{ + name: "EXTRACT with only second argument", + statement: "EXTRACT(b)", + assert: { + result: SemanticError + }, + }, + semantic::{ + name: "EXTRACT with only date time part", + statement: "EXTRACT(YEAR)", + assert: { + result: SemanticError + }, + }, +] + +semantic::{ + name: "function call not COUNT with star", + statement: "F(*)", + assert: { + result: SemanticError + }, +} diff --git a/partiql-test-data/fail/semantic/primitives/cast.ion b/partiql-test-data/fail/semantic/primitives/cast.ion new file mode 100644 index 0000000..88d36f8 --- /dev/null +++ b/partiql-test-data/fail/semantic/primitives/cast.ion @@ -0,0 +1,7 @@ +semantic::{ + name: "invalid cast type parameter", + statement: "CAST(5 AS VARCHAR(a))", + assert: { + result: SemanticError + }, +} diff --git a/partiql-test-data/fail/semantic/primitives/operator/is-operator.ion b/partiql-test-data/fail/semantic/primitives/operator/is-operator.ion new file mode 100644 index 0000000..a7a47af --- /dev/null +++ b/partiql-test-data/fail/semantic/primitives/operator/is-operator.ion @@ -0,0 +1,7 @@ +semantic::{ + name: "IS operator expects type name", + statement: "NULL IS `null`", + assert: { + result: SemanticError + }, +} diff --git a/partiql-test-data/pass/parser/query/select/joins.ion b/partiql-test-data/pass/parser/query/select/joins.ion index 9e1c010..d2549ca 100644 --- a/partiql-test-data/pass/parser/query/select/joins.ion +++ b/partiql-test-data/pass/parser/query/select/joins.ion @@ -30,6 +30,94 @@ parse::{ } } +parse::{ + name: "SELECT with RIGHT CROSS JOIN", + statement: "SELECT x FROM stuff s RIGHT CROSS JOIN foo f", + assert: { + result: ParseOk + }, +} + +parse::{ + name: "SELECT with FULL OUTER JOIN and ON condition", + statement: "SELECT x FROM stuff s FULL OUTER JOIN foo f ON s = f", + assert: { + result: ParseOk + }, +} + +parse::{ + name: "SELECT single join parens test", + statement: "SELECT x FROM (A INNER JOIN B ON A = B)", + assert: { + result: ParseOk + }, +} + +parse::{ + name: "SELECT single join multi parens", + statement: "SELECT x FROM (((A INNER JOIN B ON A = B)))", + assert: { + result: ParseOk + }, +} + +parse::{ + name: "SELECT two joins natural order parens", + statement: "SELECT x FROM (A INNER JOIN B ON A = B) INNER JOIN C ON B = C", + assert: { + result: ParseOk + }, +} + +parse::{ + name: "SELECT two joins specified order parens", + statement: "SELECT x FROM A INNER JOIN (B INNER JOIN C ON B = C) ON A = B", + assert: { + result: ParseOk + }, +} + +parse::{ + name: "SELECT three joins specified order parens", + statement: "SELECT x FROM A INNER JOIN (B INNER JOIN (C INNER JOIN D ON C = D) ON B = C) ON A = B", + assert: { + result: ParseOk + }, +} + +parse::{ + name: "SELECT literal wrapped in parens", + statement: "SELECT x FROM A INNER JOIN (1) ON true", + assert: { + result: ParseOk + }, +} + +parse::{ + name: "SELECT subquery wrapped in parens", + statement: "SELECT x FROM A INNER JOIN (SELECT x FROM 1) ON true", + assert: { + result: ParseOk + }, +} + +parse::{ + name: "SELECT with multiple JOINS and implicit CROSS JOIN", + statement: "SELECT x FROM a, b CROSS JOIN c LEFT JOIN d ON e RIGHT OUTER CROSS JOIN f OUTER JOIN g ON h", + assert: { + result: ParseOk + }, +} + +parse::{ + name: "SELECT with multiple JOINS and explicit CROSS JOIN", + statement: "SELECT x FROM a INNER CROSS JOIN b CROSS JOIN c LEFT JOIN d ON e RIGHT OUTER CROSS JOIN f OUTER JOIN g ON h", + assert: { + result: ParseOk + }, +} + 'correlated-joins'::[ parse::{ name: "SELECT correlated JOIN", diff --git a/partiql-tests-schema-proposal.md b/partiql-tests-schema-proposal.md index da05124..db03dab 100644 --- a/partiql-tests-schema-proposal.md +++ b/partiql-tests-schema-proposal.md @@ -96,6 +96,26 @@ parse::{ --- +### Semantic Tests + +Currently have a set of `fail` tests that error on the provided statement. These tests should error at some stage +between parsing and evaluation. It's up to the implementation to decide at what stage these statements should error. + +For now, composed of the same properties as the `parse` `fail` tests. The only differences are the outer test annotation +(i.e. `semantic`) and the `assert`'s error (i.e. `SemanticError`). + +``` +semantic::{ + name: , + statement: , + assert: { + result: SemanticError + }, +} +``` + +--- + ### Evaluation Tests Tests whether a given PartiQL statement evaluates to the expected result. For now, composed of these properties: