From 7f05b895f177ad61e4a9abc454017e42784bdcac Mon Sep 17 00:00:00 2001 From: John Ed Quinn Date: Mon, 12 Sep 2022 17:47:51 -0700 Subject: [PATCH 1/2] Initializes non-reserved PartiQL keywords --- docs/_Sidebar.md | 1 + docs/documentation/Keywords.md | 325 ++++++++++++++++++ .../partiql/lang/visitors/PartiQLVisitor.kt | 57 +-- .../partiql/lang/errors/ParserErrorsTest.kt | 10 +- .../org/partiql/lang/syntax/KeywordsTest.kt | 153 +++++++++ .../main/antlr/org/partiql/grammar/PartiQL.g4 | 24 +- .../org/partiql/grammar/PartiQLTokens.g4 | 6 + 7 files changed, 522 insertions(+), 54 deletions(-) create mode 100644 docs/documentation/Keywords.md create mode 100644 lang/test/org/partiql/lang/syntax/KeywordsTest.kt diff --git a/docs/_Sidebar.md b/docs/_Sidebar.md index 40311978db..aff4641228 100644 --- a/docs/_Sidebar.md +++ b/docs/_Sidebar.md @@ -8,6 +8,7 @@ * [Architecture Design](https://github.com/partiql/partiql-lang-kotlin/wiki/Architecture-Design) * [Code Style Guidelines](https://github.com/partiql/partiql-lang-kotlin/wiki/CODE-STYLE) * Documentation + * [PartiQL Keywords](https://github.com/partiql/partiql-lang-kotlin/wiki/Keywords) * [Exceptions](https://github.com/partiql/partiql-lang-kotlin/wiki/Exceptions) * [Functions](https://github.com/partiql/partiql-lang-kotlin/wiki/Functions) * [Numeric Data Type & Arithmetic Operations](https://github.com/partiql/partiql-lang-kotlin/wiki/Numeric-Data-Type-&-Arithmetic-Operations) diff --git a/docs/documentation/Keywords.md b/docs/documentation/Keywords.md new file mode 100644 index 0000000000..fe6e40bb31 --- /dev/null +++ b/docs/documentation/Keywords.md @@ -0,0 +1,325 @@ +# Overview + +PartiQL's list of keywords can be broken down into **reserved** and **non-reserved** keywords. PartiQL's keywords are subject to +move between reserved and non-reserved keywords at any time, and, therefore, we recommend wrapping the use of **all** +keywords with double quotes. + +It is **recommended** that you wrap *all* keywords with double quotes to avoid parser issues -- now or in the future. As +an example, the keyword `ACYCLIC` is currently considered non-reserved, but it may become reserved in the future. Therefore, +while PartiQL currently allows + +```sql +SELECT acyclic FROM a MATCH [ACYCLIC (b) -> (c)]; +``` + +it is best to wrap the use of `ACYCLIC` when using it as an identifier (column name, table name, variable, etc). + +```sql +SELECT "acyclic" FROM a MATCH [ACYCLIC (b) -> (c)]; +``` + +# Reserved vs Non-Reserved Keywords + +Reserved keywords are keywords that may **not** be used as identifiers (column names, table names, etc) unless +double-quotes are used as well. + +Non-reserved keywords are keywords that you may use as identifiers without the use of double-quotes -- however, we +**recommend** the use of double-quotes, as some non-reserved keywords may eventually become reserved in the future. + +# Reserved Keywords + +Below is the list of currently reserved keywords. You can also find the most up-to-date list in the `partiql-lang-kotlin` +sub-project, `partiql-grammar`. + +| ALL KEYWORDS | RESERVED (Y/N) | +|-------------------|----------------| +| ABSOLUTE | Y | +| ACTION | Y | +| ACYCLIC | N | +| ADD | Y | +| ALL | Y | +| ALLOCATE | Y | +| ALTER | Y | +| AND | Y | +| ANY | Y | +| ARE | Y | +| AS | Y | +| ASC | Y | +| ASSERTION | Y | +| AT | Y | +| AUTHORIZATION | Y | +| AVG | Y | +| BAG | Y | +| BEGIN | Y | +| BETWEEN | Y | +| BIGINT | Y | +| BIT | Y | +| BIT_LENGTH | Y | +| BLOB | Y | +| BOOL | Y | +| BOOLEAN | Y | +| BOTH | N | +| BY | Y | +| CAN_CAST | Y | +| CAN_LOSSLESS_CAST | Y | +| CASCADE | Y | +| CASCADED | Y | +| CASE | Y | +| CAST | Y | +| CATALOG | Y | +| CHAR | Y | +| CHARACTER | Y | +| CHARACTER_LENGTH | Y | +| CHAR_LENGTH | Y | +| CHECK | Y | +| CLOB | Y | +| CLOSE | Y | +| COALESCE | Y | +| COLLATE | Y | +| COLLATION | Y | +| COLUMN | Y | +| CONFLICT | Y | +| COMMIT | Y | +| CONNECT | Y | +| CONNECTION | Y | +| CONSTRAINT | Y | +| CONSTRAINTS | Y | +| CONTINUE | Y | +| CONVERT | Y | +| CORRESPONDING | Y | +| COUNT | Y | +| CREATE | Y | +| CROSS | Y | +| CURRENT | Y | +| CURRENT_DATE | Y | +| CURRENT_TIME | Y | +| CURRENT_TIMESTAMP | Y | +| CURRENT_USER | Y | +| CURSOR | Y | +| DATE | Y | +| DEALLOCATE | Y | +| DEC | Y | +| DECIMAL | Y | +| DECLARE | Y | +| DEFAULT | Y | +| DEFERRABLE | Y | +| DEFERRED | Y | +| DELETE | Y | +| DESC | Y | +| DESCRIBE | Y | +| DESCRIPTOR | Y | +| DIAGNOSTICS | Y | +| DISCONNECT | Y | +| DISTINCT | Y | +| DO | Y | +| DOMAIN | N | +| DOUBLE | Y | +| DROP | Y | +| ELSE | Y | +| END | Y | +| END-EXEC | Y | +| ESCAPE | Y | +| EXCEPT | Y | +| EXCEPTION | Y | +| EXEC | Y | +| EXECUTE | Y | +| EXISTS | Y | +| EXTERNAL | Y | +| EXTRACT | Y | +| DATE_ADD | Y | +| DATE_DIFF | Y | +| FALSE | Y | +| FETCH | Y | +| FIRST | Y | +| FLOAT | Y | +| FOR | Y | +| FOREIGN | Y | +| FOUND | Y | +| FROM | Y | +| FULL | Y | +| GET | Y | +| GLOBAL | Y | +| GO | Y | +| GOTO | Y | +| GRANT | Y | +| GROUP | Y | +| HAVING | Y | +| IDENTITY | Y | +| IMMEDIATE | Y | +| IN | Y | +| INDEX | Y | +| INDICATOR | Y | +| INITIALLY | Y | +| INNER | Y | +| INPUT | Y | +| INSENSITIVE | Y | +| INSERT | Y | +| INT | Y | +| INT2 | Y | +| INT4 | Y | +| INT8 | Y | +| INTEGER | Y | +| INTEGER2 | Y | +| INTEGER4 | Y | +| INTEGER8 | Y | +| INTERSECT | Y | +| INTERVAL | Y | +| INTO | Y | +| IS | Y | +| ISOLATION | Y | +| JOIN | Y | +| KEY | Y | +| LANGUAGE | Y | +| LAST | Y | +| LATERAL | Y | +| LEADING | N | +| LEFT | Y | +| LET | Y | +| LEVEL | Y | +| LIKE | Y | +| LIMIT | Y | +| LIST | Y | +| LOCAL | Y | +| LOWER | Y | +| MATCH | Y | +| MAX | Y | +| MIN | Y | +| MISSING | Y | +| MODIFIED | Y | +| MODULE | Y | +| NAMES | Y | +| NATIONAL | Y | +| NATURAL | Y | +| NCHAR | Y | +| NEW | Y | +| NEXT | Y | +| NO | Y | +| NOT | Y | +| NOTHING | Y | +| NULL | Y | +| NULLS | Y | +| NULLIF | Y | +| NUMERIC | Y | +| OCTET_LENGTH | Y | +| OF | Y | +| OFFSET | Y | +| OLD | Y | +| ON | Y | +| ONLY | Y | +| OPEN | Y | +| OPTION | Y | +| OR | Y | +| ORDER | Y | +| OUTER | Y | +| OUTPUT | Y | +| OVERLAPS | Y | +| PAD | Y | +| PARTIAL | Y | +| POSITION | Y | +| PRECISION | Y | +| PREPARE | Y | +| PRESERVE | Y | +| PRIMARY | Y | +| PRIOR | Y | +| PRIVILEGES | Y | +| PROCEDURE | Y | +| PUBLIC | N | +| READ | Y | +| REAL | Y | +| REFERENCES | Y | +| RELATIVE | Y | +| RESTRICT | Y | +| REVOKE | Y | +| RIGHT | Y | +| ROLLBACK | Y | +| ROWS | Y | +| SCHEMA | Y | +| SCROLL | Y | +| SECTION | Y | +| SELECT | Y | +| SESSION | Y | +| SESSION_USER | Y | +| SET | Y | +| SHORTEST | Y | +| SIMPLE | Y | +| SIZE | Y | +| SMALLINT | Y | +| SOME | Y | +| SPACE | Y | +| SQL | Y | +| SQLCODE | Y | +| SQLERROR | Y | +| SQLSTATE | Y | +| STRING | Y | +| STRUCT | Y | +| SUBSTRING | Y | +| SUM | Y | +| SYMBOL | Y | +| SYSTEM_USER | Y | +| TABLE | Y | +| TEMPORARY | Y | +| THEN | Y | +| TIME | Y | +| TIMESTAMP | Y | +| TO | Y | +| TRANSACTION | Y | +| TRANSLATE | Y | +| TRANSLATION | Y | +| TRIM | Y | +| TRUE | Y | +| TUPLE | Y | +| UNION | Y | +| UNIQUE | Y | +| UNKNOWN | Y | +| UNPIVOT | Y | +| UPDATE | Y | +| UPPER | Y | +| USAGE | Y | +| USER | Y | +| USING | Y | +| PIVOT | Y | +| REMOVE | Y | +| RETURNING | Y | +| SEXP | Y | +| SIMPLE | N | +| TRAIL | N | +| TRAILING | N | +| USER | N | +| VALUE | Y | +| VALUES | Y | +| VARCHAR | Y | +| VARYING | Y | +| VIEW | Y | +| WHEN | Y | +| WHENEVER | Y | +| WHERE | Y | +| WITH | Y | +| WORK | Y | +| WRITE | Y | +| ZONE | Y | + +# Other Examples + +While the non-reserved keywords above do not **require** the use of double-quotes, it may be of use to use them for specific +scenarios. Take, for instance, the `TRIM` function. `TRIM`, as its first optional argument, takes keywords `LEADING`, `BOTH`, +or `TRAILING`. + +```sql +SELECT leading FROM t WHERE TRIM(leading FROM t.someString) = 'otherString'; +``` + +The above query removes the *leading* whitespace of `t.someString`, compares it with the literal `'otherString'`, and +selects the column `leading` from table `t`. + +If, however, you wanted to trim whatever `leading` refers to as a column reference from both sides of `t.someString`, you +would want to re-write your query as: + +```sql +SELECT leading FROM t WHERE TRIM("leading" FROM t.someString) = 'otherString'; +``` + +Or, if you wanted to be extremely explicit (**recommended**), you could write the query as: + +```sql +SELECT "leading" FROM t WHERE TRIM(BOTH "leading" FROM t.someString) = 'otherString'; +``` diff --git a/lang/src/org/partiql/lang/visitors/PartiQLVisitor.kt b/lang/src/org/partiql/lang/visitors/PartiQLVisitor.kt index 3a9d9d4ca5..0685eabafd 100644 --- a/lang/src/org/partiql/lang/visitors/PartiQLVisitor.kt +++ b/lang/src/org/partiql/lang/visitors/PartiQLVisitor.kt @@ -55,7 +55,6 @@ import org.partiql.lang.eval.EvaluationException import org.partiql.lang.eval.time.MAX_PRECISION_FOR_TIME import org.partiql.lang.syntax.DATE_TIME_PART_KEYWORDS import org.partiql.lang.syntax.ParserException -import org.partiql.lang.syntax.TRIM_SPECIFICATION_KEYWORDS import org.partiql.lang.types.CustomType import org.partiql.lang.util.DATE_PATTERN_REGEX import org.partiql.lang.util.bigDecimalOf @@ -115,6 +114,7 @@ internal class PartiQLVisitor(val ion: IonSystem, val customTypes: List id(ctx.IDENTIFIER_QUOTED().getStringValue(), caseSensitive(), unqualified(), metas) PartiQLParser.IDENTIFIER -> id(ctx.IDENTIFIER().getStringValue(), caseInsensitive(), unqualified(), metas) @@ -122,6 +122,11 @@ internal class PartiQLVisitor(val ion: IonSystem, val customTypes: List restrictorTrail(metas) - "acyclic" -> restrictorAcyclic(metas) - "simple" -> restrictorSimple(metas) + when (ctx.restrictor.type) { + PartiQLParser.TRAIL -> restrictorTrail(metas) + PartiQLParser.ACYCLIC -> restrictorAcyclic(metas) + PartiQLParser.SIMPLE -> restrictorSimple(metas) else -> throw ParserException("Unrecognized pattern restrictor", ErrorCode.PARSE_INVALID_QUERY) } } @@ -847,10 +852,9 @@ internal class PartiQLVisitor(val ion: IonSystem, val customTypes: List FROM ) needs to be parsed as below. The needs to be - * an identifier (according to SqlParser), but if the identifier is NOT a trim specification, and the is - * null, we need to make the substring equal to the (and make null). - */ override fun visitTrimFunction(ctx: PartiQLParser.TrimFunctionContext) = PartiqlAst.build { - val possibleModText = if (ctx.mod != null) ctx.mod.text.toLowerCase() else null - val isTrimSpec = TRIM_SPECIFICATION_KEYWORDS.contains(possibleModText) - val (modifier, substring) = when { - // if is not null and is null - // then there are two possible cases trim(( BOTH | LEADING | TRAILING ) FROM ) - // or trim( FROM target), i.e., we treat what is recognized by parser as the modifier as - ctx.mod != null && ctx.sub == null -> { - if (isTrimSpec) ctx.mod.toSymbol() to null - else null to id(possibleModText!!, caseInsensitive(), unqualified(), ctx.mod.getSourceMetaContainer()) - } - ctx.mod == null && ctx.sub != null -> { - null to visitExpr(ctx.sub) - } - ctx.mod != null && ctx.sub != null -> { - if (isTrimSpec) ctx.mod.toSymbol() to visitExpr(ctx.sub) - // todo we need to decide if it should be an evaluator error or a parser error - else { - val errorContext = PropertyValueMap() - errorContext[Property.TOKEN_STRING] = ctx.mod.text - throw ctx.mod.err( - "'${ctx.mod.text}' is an unknown trim specification, valid values: $TRIM_SPECIFICATION_KEYWORDS", - ErrorCode.PARSE_INVALID_TRIM_SPEC, - errorContext - ) - } - } - else -> null to null - } - + val modifier = if (ctx.mod != null) lit(ionSymbol(ctx.mod.text.toLowerCase())) else null + val substring = visitOrNull(ctx.sub, PartiqlAst.Expr::class) val target = visitExpr(ctx.target) val args = listOfNotNull(modifier, substring, target) val metas = ctx.func.getSourceMetaContainer() diff --git a/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt b/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt index 0f01e6bb2c..d59582c6e6 100644 --- a/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt +++ b/lang/test/org/partiql/lang/errors/ParserErrorsTest.kt @@ -1302,16 +1302,14 @@ class ParserErrorsTest : SqlParserTestBase() { ), targetParsers = setOf(ParserTypes.SQL_PARSER) ) - // for sql parser, the logic is, if the first token is not one of { NONE | BOTH | LEADING | TRAILING} - // throw out a parser error checkInputThrowingParserException( "trim(something ' ' from ' string ')", - ErrorCode.PARSE_INVALID_TRIM_SPEC, + ErrorCode.PARSE_UNEXPECTED_TOKEN, mapOf( Property.LINE_NUMBER to 1L, - Property.COLUMN_NUMBER to 6L, - Property.TOKEN_TYPE to TokenType.IDENTIFIER, - Property.TOKEN_VALUE to ion.newSymbol("something") + Property.COLUMN_NUMBER to 16L, + Property.TOKEN_TYPE to TokenType.LITERAL, + Property.TOKEN_VALUE to ion.newString(" ") ), targetParsers = setOf(ParserTypes.PARTIQL_PARSER) ) diff --git a/lang/test/org/partiql/lang/syntax/KeywordsTest.kt b/lang/test/org/partiql/lang/syntax/KeywordsTest.kt new file mode 100644 index 0000000000..83ae5b37d5 --- /dev/null +++ b/lang/test/org/partiql/lang/syntax/KeywordsTest.kt @@ -0,0 +1,153 @@ +/* + * Copyright 2022 Amazon.com, Inc. or its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at: + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + */ + +package org.partiql.lang.syntax + +import com.amazon.ionelement.api.ionString +import com.amazon.ionelement.api.ionSymbol +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ArgumentsSource +import org.partiql.lang.domains.PartiqlAst +import org.partiql.lang.util.ArgumentsProviderBase + +/** + * Tests that non-reserved keywords parse correctly. + */ +class KeywordsTest : SqlParserTestBase() { + + private class TrimModifiers() : ArgumentsProviderBase() { + override fun getParameters(): List = listOf("both", "leading", "trailing") + } + + private class OtherKeywordsTestParams() : ArgumentsProviderBase() { + override fun getParameters(): List = listOf("public", "user", "domain") + } + + private class GraphMatchRestrictorRefs() : ArgumentsProviderBase() { + override fun getParameters(): List = listOf>( + "acyclic" to PartiqlAst.GraphMatchRestrictor.RestrictorAcyclic(), + "simple" to PartiqlAst.GraphMatchRestrictor.RestrictorSimple(), + "trail" to PartiqlAst.GraphMatchRestrictor.RestrictorTrail() + ) + } + + @ParameterizedTest + @ArgumentsSource(TrimModifiers::class) + fun testTrimModifierAndSubstring(modifier: String) { + assertExpression( + source = "SELECT $modifier FROM <<{ '$modifier': 'h' }>> WHERE trim($modifier $modifier from ' h') = $modifier", + expectedPigBuilder = { + trimLeadingExpectedModifier( + modifier, + call( + "trim", + lit(ionSymbol(modifier)), + id(modifier, caseInsensitive(), unqualified()), + lit(ionString(" h")) + ), + ) + } + ) + } + + @ParameterizedTest + @ArgumentsSource(TrimModifiers::class) + fun testTrimExplicitIdentifier(modifier: String) { + assertExpression( + source = "SELECT $modifier FROM <<{ '$modifier': 'h' }>> WHERE trim(\"$modifier\" from ' h') = $modifier", + expectedPigBuilder = { + trimLeadingExpectedModifier( + modifier, + call("trim", id(modifier, caseSensitive(), unqualified()), lit(ionString(" h"))), + ) + } + ) + } + + @ParameterizedTest + @ArgumentsSource(TrimModifiers::class) + fun testTrimModifierOnly(modifier: String) { + assertExpression( + source = "SELECT $modifier FROM <<{ '$modifier': 'h' }>> WHERE trim($modifier from ' h') = $modifier", + expectedPigBuilder = { + trimLeadingExpectedModifier( + modifier, + call("trim", lit(ionSymbol(modifier)), lit(ionString(" h"))), + ) + } + ) + } + + private fun PartiqlAst.Builder.trimLeadingExpectedModifier( + modifier: String, + expected: PartiqlAst.Expr + ): PartiqlAst.Expr.Select = + select( + project = projectList(projectExpr(id(modifier, caseInsensitive(), unqualified()))), + from = scan( + bag( + struct( + exprPair( + lit(ionString(modifier)), lit(ionString("h")) + ) + ) + ) + ), + where = eq(expected, id(modifier, caseInsensitive(), unqualified())) + ) + + @ParameterizedTest + @ArgumentsSource(GraphMatchRestrictorRefs::class) + fun testAcyclicKeyword(input: Pair) { + val (restrictor, restrictorAst) = input + assertExpressionNoRoundTrip( + source = "SELECT $restrictor FROM $restrictor MATCH [$restrictor $restrictor= ($restrictor)]", + targetParsers = setOf(ParserTypes.PARTIQL_PARSER), + expectedPigBuilder = { + select( + project = projectList(projectExpr(id(restrictor, caseInsensitive(), unqualified()))), + from = graphMatch( + id(restrictor, caseInsensitive(), unqualified()), + graphMatchExpr( + patterns0 = graphMatchPattern( + parts0 = pattern( + graphMatchPattern( + restrictorAst, + variable = restrictor, + parts0 = node(variable = restrictor) + ) + ) + ) + ) + ) + ) + } + ) + } + + @ParameterizedTest + @ArgumentsSource(OtherKeywordsTestParams::class) + fun testOtherKeywords(keyword: String) { + assertExpression( + source = "SELECT $keyword FROM \"$keyword\"", + targetParsers = setOf(ParserTypes.PARTIQL_PARSER), + expectedPigBuilder = { + select( + project = projectList(projectExpr(id(keyword, caseInsensitive(), unqualified()))), + from = scan(id(keyword, caseSensitive(), unqualified())) + ) + } + ) + } +} diff --git a/partiql-grammar/src/main/antlr/org/partiql/grammar/PartiQL.g4 b/partiql-grammar/src/main/antlr/org/partiql/grammar/PartiQL.g4 index f84ce39387..f2fd032427 100644 --- a/partiql-grammar/src/main/antlr/org/partiql/grammar/PartiQL.g4 +++ b/partiql-grammar/src/main/antlr/org/partiql/grammar/PartiQL.g4 @@ -35,7 +35,21 @@ byIdent : BY symbolPrimitive; symbolPrimitive - : ident=( IDENTIFIER | IDENTIFIER_QUOTED ) + : ident=(IDENTIFIER | IDENTIFIER_QUOTED) + | key=nonreservedKeyword + ; + +nonreservedKeyword + : key=( ACYCLIC + | BOTH + | DOMAIN + | LEADING + | PUBLIC + | SIMPLE + | TRAIL + | TRAILING + | USER + ) ; /** @@ -269,8 +283,8 @@ matchSelector patternPathVariable : symbolPrimitive EQ; -patternRestrictor // Should be TRAIL / ACYCLIC / SIMPLE - : restrictor=IDENTIFIER; +patternRestrictor + : restrictor=( TRAIL | ACYCLIC | SIMPLE ); node : PAREN_LEFT symbolPrimitive? patternPartLabel? whereClause? PAREN_RIGHT; @@ -539,7 +553,7 @@ extract : EXTRACT PAREN_LEFT IDENTIFIER FROM rhs=expr PAREN_RIGHT; trimFunction - : func=TRIM PAREN_LEFT ( mod=IDENTIFIER? sub=expr? FROM )? target=expr PAREN_RIGHT; + : func=TRIM PAREN_LEFT ( mod=(BOTH|LEADING|TRAILING)? sub=expr? FROM )? target=expr PAREN_RIGHT; dateFunction : func=(DATE_ADD|DATE_DIFF) PAREN_LEFT dt=IDENTIFIER COMMA expr COMMA expr PAREN_RIGHT; @@ -562,7 +576,7 @@ parameter : QUESTION_MARK; varRefExpr - : qualifier=AT_SIGN? ident=(IDENTIFIER|IDENTIFIER_QUOTED); + : qualifier=AT_SIGN? ident=symbolPrimitive; /** * diff --git a/partiql-grammar/src/main/antlr/org/partiql/grammar/PartiQLTokens.g4 b/partiql-grammar/src/main/antlr/org/partiql/grammar/PartiQLTokens.g4 index 7b7f524abc..913a38fa13 100644 --- a/partiql-grammar/src/main/antlr/org/partiql/grammar/PartiQLTokens.g4 +++ b/partiql-grammar/src/main/antlr/org/partiql/grammar/PartiQLTokens.g4 @@ -26,6 +26,7 @@ options { ABSOLUTE: 'ABSOLUTE'; ACTION: 'ACTION'; +ACYCLIC: 'ACYCLIC'; ADD: 'ADD'; ALL: 'ALL'; ALLOCATE: 'ALLOCATE'; @@ -43,6 +44,7 @@ BEGIN: 'BEGIN'; BETWEEN: 'BETWEEN'; BIT: 'BIT'; BIT_LENGTH: 'BIT_LENGTH'; +BOTH: 'BOTH'; BY: 'BY'; CASCADE: 'CASCADE'; CASCADED: 'CASCADED'; @@ -144,6 +146,7 @@ KEY: 'KEY'; LANGUAGE: 'LANGUAGE'; LAST: 'LAST'; LATERAL: 'LATERAL'; +LEADING: 'LEADING'; LEFT: 'LEFT'; LEVEL: 'LEVEL'; LIKE: 'LIKE'; @@ -203,6 +206,7 @@ SESSION: 'SESSION'; SESSION_USER: 'SESSION_USER'; SET: 'SET'; SHORTEST: 'SHORTEST'; +SIMPLE: 'SIMPLE'; SIZE: 'SIZE'; SMALLINT: 'SMALLINT'; SOME: 'SOME'; @@ -220,6 +224,8 @@ THEN: 'THEN'; TIME: 'TIME'; TIMESTAMP: 'TIMESTAMP'; TO: 'TO'; +TRAIL: 'TRAIL'; +TRAILING: 'TRAILING'; TRANSACTION: 'TRANSACTION'; TRANSLATE: 'TRANSLATE'; TRANSLATION: 'TRANSLATION'; From da349cc76d090d04c4c1fefa64768473b5b8cdaf Mon Sep 17 00:00:00 2001 From: John Ed Quinn Date: Wed, 14 Sep 2022 12:22:17 -0700 Subject: [PATCH 2/2] Updates changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0288f3d1d9..a463d3663a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - See GitHub Issues [#709](https://github.com/partiql/partiql-lang-kotlin/issues/709), [#708](https://github.com/partiql/partiql-lang-kotlin/issues/708), [#707](https://github.com/partiql/partiql-lang-kotlin/issues/707), [#683](https://github.com/partiql/partiql-lang-kotlin/issues/683), and [#730](https://github.com/partiql/partiql-lang-kotlin/issues/730) +- Specifies and adds support for a limited set of PartiQL non-reserved keywords (ACYCLIC, BOTH, DOMAIN, LEADING, PUBLIC, + SIMPLE, TRAIL, TRAILING, and USER) #### Experimental Planner Additions