| /* | 
 |  * Licensed to the Apache Software Foundation (ASF) under one or more | 
 |  * contributor license agreements.  See the NOTICE file distributed with | 
 |  * this work for additional information regarding copyright ownership. | 
 |  * The ASF licenses this file to you under the Apache License, Version 2.0 | 
 |  * (the "License"); you may not use this file except in compliance with | 
 |  * the License.  You may obtain a copy of the License at | 
 |  * | 
 |  * http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License 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. | 
 |  */ | 
 | <@pp.dropOutputFile /> | 
 |  | 
 | <@pp.changeOutputFile name="javacc/Parser.jj" /> | 
 |  | 
 | options { | 
 |     STATIC = false; | 
 |     IGNORE_CASE = true; | 
 |     UNICODE_INPUT = true; | 
 | } | 
 |  | 
 |  | 
 | PARSER_BEGIN(${parser.class}) | 
 |  | 
 | package ${parser.package}; | 
 |  | 
 | <#list (parser.imports!default.parser.imports) as importStr> | 
 | import ${importStr}; | 
 | </#list> | 
 |  | 
 | import org.apache.calcite.avatica.util.Casing; | 
 | import org.apache.calcite.avatica.util.TimeUnit; | 
 | import org.apache.calcite.rel.type.RelDataType; | 
 | import org.apache.calcite.runtime.CalciteContextException; | 
 | import org.apache.calcite.sql.JoinConditionType; | 
 | import org.apache.calcite.sql.JoinType; | 
 | import org.apache.calcite.sql.SqlAlter; | 
 | import org.apache.calcite.sql.SqlBasicTypeNameSpec; | 
 | import org.apache.calcite.sql.SqlBinaryOperator; | 
 | import org.apache.calcite.sql.SqlCall; | 
 | import org.apache.calcite.sql.SqlCharStringLiteral; | 
 | import org.apache.calcite.sql.SqlCollation; | 
 | import org.apache.calcite.sql.SqlCollectionTypeNameSpec; | 
 | import org.apache.calcite.sql.SqlDataTypeSpec; | 
 | import org.apache.calcite.sql.SqlDelete; | 
 | import org.apache.calcite.sql.SqlDescribeSchema; | 
 | import org.apache.calcite.sql.SqlDescribeTable; | 
 | import org.apache.calcite.sql.SqlDynamicParam; | 
 | import org.apache.calcite.sql.SqlExplain; | 
 | import org.apache.calcite.sql.SqlExplainFormat; | 
 | import org.apache.calcite.sql.SqlExplainLevel; | 
 | import org.apache.calcite.sql.SqlFunction; | 
 | import org.apache.calcite.sql.SqlFunctionCategory; | 
 | import org.apache.calcite.sql.SqlHint; | 
 | import org.apache.calcite.sql.SqlIdentifier; | 
 | import org.apache.calcite.sql.SqlInsert; | 
 | import org.apache.calcite.sql.SqlInsertKeyword; | 
 | import org.apache.calcite.sql.SqlIntervalQualifier; | 
 | import org.apache.calcite.sql.SqlJdbcDataTypeName; | 
 | import org.apache.calcite.sql.SqlJdbcFunctionCall; | 
 | import org.apache.calcite.sql.SqlJoin; | 
 | import org.apache.calcite.sql.SqlJsonConstructorNullClause; | 
 | import org.apache.calcite.sql.SqlJsonEncoding; | 
 | import org.apache.calcite.sql.SqlJsonExistsErrorBehavior; | 
 | import org.apache.calcite.sql.SqlJsonEmptyOrError; | 
 | import org.apache.calcite.sql.SqlJsonQueryEmptyOrErrorBehavior; | 
 | import org.apache.calcite.sql.SqlJsonQueryWrapperBehavior; | 
 | import org.apache.calcite.sql.SqlJsonValueEmptyOrErrorBehavior; | 
 | import org.apache.calcite.sql.SqlJsonValueReturning; | 
 | import org.apache.calcite.sql.SqlKind; | 
 | import org.apache.calcite.sql.SqlLambda; | 
 | import org.apache.calcite.sql.SqlLiteral; | 
 | import org.apache.calcite.sql.SqlMatchRecognize; | 
 | import org.apache.calcite.sql.SqlMerge; | 
 | import org.apache.calcite.sql.SqlMapTypeNameSpec; | 
 | import org.apache.calcite.sql.SqlNode; | 
 | import org.apache.calcite.sql.SqlNodeList; | 
 | import org.apache.calcite.sql.SqlNumericLiteral; | 
 | import org.apache.calcite.sql.SqlOperator; | 
 | import org.apache.calcite.sql.SqlOrderBy; | 
 | import org.apache.calcite.sql.SqlPivot; | 
 | import org.apache.calcite.sql.SqlPostfixOperator; | 
 | import org.apache.calcite.sql.SqlPrefixOperator; | 
 | import org.apache.calcite.sql.SqlRowTypeNameSpec; | 
 | import org.apache.calcite.sql.SqlSampleSpec; | 
 | import org.apache.calcite.sql.SqlSelect; | 
 | import org.apache.calcite.sql.SqlSelectKeyword; | 
 | import org.apache.calcite.sql.SqlSetOption; | 
 | import org.apache.calcite.sql.SqlSnapshot; | 
 | import org.apache.calcite.sql.SqlTableRef; | 
 | import org.apache.calcite.sql.SqlTypeNameSpec; | 
 | import org.apache.calcite.sql.SqlUnnestOperator; | 
 | import org.apache.calcite.sql.SqlUnpivot; | 
 | import org.apache.calcite.sql.SqlUpdate; | 
 | import org.apache.calcite.sql.SqlUserDefinedTypeNameSpec; | 
 | import org.apache.calcite.sql.SqlUtil; | 
 | import org.apache.calcite.sql.SqlWindow; | 
 | import org.apache.calcite.sql.SqlWith; | 
 | import org.apache.calcite.sql.SqlWithItem; | 
 | import org.apache.calcite.sql.fun.SqlCase; | 
 | import org.apache.calcite.sql.fun.SqlInternalOperators; | 
 | import org.apache.calcite.sql.fun.SqlLibraryOperators; | 
 | import org.apache.calcite.sql.fun.SqlStdOperatorTable; | 
 | import org.apache.calcite.sql.fun.SqlTrimFunction; | 
 | import org.apache.calcite.sql.parser.Span; | 
 | import org.apache.calcite.sql.parser.SqlAbstractParserImpl; | 
 | import org.apache.calcite.sql.parser.SqlParseException; | 
 | import org.apache.calcite.sql.parser.SqlParser; | 
 | import org.apache.calcite.sql.parser.SqlParserImplFactory; | 
 | import org.apache.calcite.sql.parser.SqlParserPos; | 
 | import org.apache.calcite.sql.parser.SqlParserUtil; | 
 | import org.apache.calcite.sql.type.SqlTypeName; | 
 | import org.apache.calcite.sql.validate.SqlConformance; | 
 | import org.apache.calcite.sql.validate.SqlConformanceEnum; | 
 | import org.apache.calcite.util.Glossary; | 
 | import org.apache.calcite.util.Pair; | 
 | import org.apache.calcite.util.SourceStringReader; | 
 | import org.apache.calcite.util.Util; | 
 | import org.apache.calcite.util.trace.CalciteTrace; | 
 |  | 
 | import com.google.common.collect.ImmutableList; | 
 | import com.google.common.collect.ImmutableMap; | 
 | import org.slf4j.Logger; | 
 |  | 
 | import java.io.Reader; | 
 | import java.math.BigDecimal; | 
 | import java.util.ArrayList; | 
 | import java.util.Arrays; | 
 | import java.util.Collections; | 
 | import java.util.List; | 
 | import java.util.Locale; | 
 | import java.util.Map; | 
 |  | 
 | import static org.apache.calcite.util.Static.RESOURCE; | 
 |  | 
 | /** | 
 |  * SQL parser, generated from Parser.jj by JavaCC. | 
 |  * | 
 |  * <p>The public wrapper for this parser is {@link SqlParser}. | 
 |  */ | 
 | public class ${parser.class} extends SqlAbstractParserImpl | 
 | { | 
 |     private static final Logger LOGGER = CalciteTrace.getParserTracer(); | 
 |  | 
 |     // Can't use quoted literal because of a bug in how JavaCC translates | 
 |     // backslash-backslash. | 
 |     private static final char BACKSLASH = 0x5c; | 
 |     private static final char DOUBLE_QUOTE = 0x22; | 
 |     private static final String DQ = DOUBLE_QUOTE + ""; | 
 |     private static final String DQDQ = DQ + DQ; | 
 |     private static final SqlLiteral LITERAL_ZERO = | 
 |         SqlLiteral.createExactNumeric("0", SqlParserPos.ZERO); | 
 |     private static final SqlLiteral LITERAL_ONE = | 
 |         SqlLiteral.createExactNumeric("1", SqlParserPos.ZERO); | 
 |     private static final SqlLiteral LITERAL_MINUS_ONE = | 
 |         SqlLiteral.createExactNumeric("-1", SqlParserPos.ZERO); | 
 |     private static final BigDecimal ONE_HUNDRED = BigDecimal.valueOf(100L); | 
 |  | 
 |     private static Metadata metadata; | 
 |  | 
 |     private Casing unquotedCasing; | 
 |     private Casing quotedCasing; | 
 |     private int identifierMaxLength; | 
 |     private SqlConformance conformance; | 
 |  | 
 |     /** | 
 |      * {@link SqlParserImplFactory} implementation for creating parser. | 
 |      */ | 
 |     public static final SqlParserImplFactory FACTORY = new SqlParserImplFactory() { | 
 |         public SqlAbstractParserImpl getParser(Reader reader) { | 
 |             final ${parser.class} parser = new ${parser.class}(reader); | 
 |             if (reader instanceof SourceStringReader) { | 
 |                 final String sql = | 
 |                     ((SourceStringReader) reader).getSourceString(); | 
 |                 parser.setOriginalSql(sql); | 
 |             } | 
 |           return parser; | 
 |         } | 
 |     }; | 
 |  | 
 |     public SqlParseException normalizeException(Throwable ex) { | 
 |         try { | 
 |             if (ex instanceof ParseException) { | 
 |                 ex = cleanupParseException((ParseException) ex); | 
 |             } | 
 |             return convertException(ex); | 
 |         } catch (ParseException e) { | 
 |             throw new AssertionError(e); | 
 |         } | 
 |     } | 
 |  | 
 |     public Metadata getMetadata() { | 
 |         synchronized (${parser.class}.class) { | 
 |             if (metadata == null) { | 
 |                 metadata = new MetadataImpl( | 
 |                     new ${parser.class}(new java.io.StringReader(""))); | 
 |             } | 
 |             return metadata; | 
 |         } | 
 |     } | 
 |  | 
 |     public void setTabSize(int tabSize) { | 
 |         jj_input_stream.setTabSize(tabSize); | 
 |     } | 
 |  | 
 |     public void switchTo(SqlAbstractParserImpl.LexicalState state) { | 
 |         final int stateOrdinal = | 
 |             Arrays.asList(${parser.class}TokenManager.lexStateNames) | 
 |                 .indexOf(state.name()); | 
 |         token_source.SwitchTo(stateOrdinal); | 
 |     } | 
 |  | 
 |     public void setQuotedCasing(Casing quotedCasing) { | 
 |         this.quotedCasing = quotedCasing; | 
 |     } | 
 |  | 
 |     public void setUnquotedCasing(Casing unquotedCasing) { | 
 |         this.unquotedCasing = unquotedCasing; | 
 |     } | 
 |  | 
 |     public void setIdentifierMaxLength(int identifierMaxLength) { | 
 |         this.identifierMaxLength = identifierMaxLength; | 
 |     } | 
 |  | 
 |     public void setConformance(SqlConformance conformance) { | 
 |         this.conformance = conformance; | 
 |     } | 
 |  | 
 |     public SqlNode parseSqlExpressionEof() throws Exception { | 
 |         return SqlExpressionEof(); | 
 |     } | 
 |  | 
 |     public SqlNode parseSqlStmtEof() throws Exception { | 
 |         return SqlStmtEof(); | 
 |     } | 
 |  | 
 |     public SqlNodeList parseSqlStmtList() throws Exception { | 
 |         return SqlStmtList(); | 
 |     } | 
 |  | 
 |     public SqlNode parseArray() throws SqlParseException { | 
 |         switchTo(LexicalState.BQID); | 
 |         try { | 
 |           return ArrayLiteral(); | 
 |         } catch (ParseException ex) { | 
 |           throw normalizeException(ex); | 
 |         } catch (TokenMgrError ex) { | 
 |           throw normalizeException(ex); | 
 |         } | 
 |     } | 
 |  | 
 |     private SqlNode extend(SqlNode table, SqlNodeList extendList) { | 
 |         return SqlStdOperatorTable.EXTEND.createCall( | 
 |             Span.of(table, extendList).pos(), table, extendList); | 
 |     } | 
 |  | 
 |     /** Adds a warning that a token such as "HOURS" was used, | 
 |     * whereas the SQL standard only allows "HOUR". | 
 |     * | 
 |     * <p>Currently, we silently add an exception to a list of warnings. In | 
 |     * future, we may have better compliance checking, for example a strict | 
 |     * compliance mode that throws if any non-standard features are used. */ | 
 |     private TimeUnit warn(TimeUnit timeUnit) throws ParseException { | 
 |         final String token = getToken(0).image.toUpperCase(Locale.ROOT); | 
 |         warnings.add( | 
 |             SqlUtil.newContextException(getPos(), | 
 |                 RESOURCE.nonStandardFeatureUsed(token))); | 
 |         return timeUnit; | 
 |     } | 
 | } | 
 |  | 
 | PARSER_END(${parser.class}) | 
 |  | 
 |  | 
 | /*************************************** | 
 |  * Utility Codes for Semantic Analysis * | 
 |  ***************************************/ | 
 |  | 
 | /* For Debug */ | 
 | JAVACODE | 
 | void debug_message1() { | 
 |     LOGGER.info("{} , {}", getToken(0).image, getToken(1).image); | 
 | } | 
 |  | 
 | JAVACODE String unquotedIdentifier() { | 
 |     return SqlParserUtil.toCase(getToken(0).image, unquotedCasing); | 
 | } | 
 |  | 
 | /** | 
 |  * Allows parser to be extended with new types of table references.  The | 
 |  * default implementation of this production is empty. | 
 |  */ | 
 | SqlNode ExtendedTableRef() : | 
 | { | 
 | } | 
 | { | 
 |     UnusedExtension() | 
 |     { | 
 |         return null; | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Allows an OVER clause following a table expression as an extension to | 
 |  * standard SQL syntax. The default implementation of this production is empty. | 
 |  */ | 
 | SqlNode TableOverOpt() : | 
 | { | 
 | } | 
 | { | 
 |     { | 
 |         return null; | 
 |     } | 
 | } | 
 |  | 
 | /* | 
 |  * Parses dialect-specific keywords immediately following the SELECT keyword. | 
 |  */ | 
 | void SqlSelectKeywords(List<SqlLiteral> keywords) : | 
 | {} | 
 | { | 
 |     E() | 
 | } | 
 |  | 
 | /* | 
 |  * Parses dialect-specific keywords immediately following the INSERT keyword. | 
 |  */ | 
 | void SqlInsertKeywords(List<SqlLiteral> keywords) : | 
 | {} | 
 | { | 
 |     E() | 
 | } | 
 |  | 
 | /* | 
 | * Parse Floor/Ceil function parameters | 
 | */ | 
 | SqlNode FloorCeilOptions(Span s, boolean floorFlag) : | 
 | { | 
 |     SqlNode node; | 
 | } | 
 | { | 
 |     node = StandardFloorCeilOptions(s, floorFlag) { | 
 |         return node; | 
 |     } | 
 | } | 
 |  | 
 | /* | 
 | // This file contains the heart of a parser for SQL SELECT statements. | 
 | // code can be shared between various parsers (for example, a DDL parser and a | 
 | // DML parser) but is not a standalone JavaCC file. You need to prepend a | 
 | // parser declaration (such as that in Parser.jj). | 
 | */ | 
 |  | 
 | /* Epsilon */ | 
 | JAVACODE | 
 | void E() {} | 
 |  | 
 | /** @Deprecated */ | 
 | JAVACODE List startList(Object o) | 
 | { | 
 |     List list = new ArrayList(); | 
 |     list.add(o); | 
 |     return list; | 
 | } | 
 |  | 
 | /* | 
 |  * NOTE jvs 6-Feb-2004: The straightforward way to implement the SQL grammar is | 
 |  * to keep query expressions (SELECT, UNION, etc) separate from row expressions | 
 |  * (+, LIKE, etc).  However, this is not possible with an LL(k) parser, because | 
 |  * both kinds of expressions allow parenthesization, so no fixed amount of left | 
 |  * context is ever good enough.  A sub-query can be a leaf in a row expression, | 
 |  * and can include operators like UNION, so it's not even possible to use a | 
 |  * syntactic lookahead rule like "look past an indefinite number of parentheses | 
 |  * until you see SELECT, VALUES, or TABLE" (since at that point we still | 
 |  * don't know whether we're parsing a sub-query like ((select ...) + x) | 
 |  * vs. (select ... union select ...). | 
 |  * | 
 |  * The somewhat messy solution is to unify the two kinds of expression, | 
 |  * and to enforce syntax rules using parameterized context.  This | 
 |  * is the purpose of the ExprContext parameter.  It is passed to | 
 |  * most expression productions, which check the expressions encountered | 
 |  * against the context for correctness.  When a query | 
 |  * element like SELECT is encountered, the production calls | 
 |  * checkQueryExpression, which will throw an exception if | 
 |  * a row expression was expected instead.  When a row expression like | 
 |  * IN is encountered, the production calls checkNonQueryExpression | 
 |  * instead.  It is very important to understand how this works | 
 |  * when modifying the grammar. | 
 |  * | 
 |  * The commingling of expressions results in some bogus ambiguities which are | 
 |  * resolved with LOOKAHEAD hints.  The worst example is comma.  SQL allows both | 
 |  * (WHERE x IN (1,2)) and (WHERE x IN (select ...)).  This means when we parse | 
 |  * the right-hand-side of an IN, we have to allow any kind of expression inside | 
 |  * the parentheses.  Now consider the expression "WHERE x IN(SELECT a FROM b | 
 |  * GROUP BY c,d)".  When the parser gets to "c,d" it doesn't know whether the | 
 |  * comma indicates the end of the GROUP BY or the end of one item in an IN | 
 |  * list.  Luckily, we know that select and comma-list are mutually exclusive | 
 |  * within IN, so we use maximal munch for the GROUP BY comma.  However, this | 
 |  * usage of hints could easily mask unintended ambiguities resulting from | 
 |  * future changes to the grammar, making it very brittle. | 
 |  */ | 
 |  | 
 | JAVACODE protected SqlParserPos getPos() | 
 | { | 
 |     return new SqlParserPos( | 
 |         token.beginLine, | 
 |         token.beginColumn, | 
 |         token.endLine, | 
 |         token.endColumn); | 
 | } | 
 |  | 
 | /** Starts a span at the current position. */ | 
 | JAVACODE Span span() | 
 | { | 
 |     return Span.of(getPos()); | 
 | } | 
 |  | 
 | JAVACODE void checkQueryExpression(ExprContext exprContext) | 
 | { | 
 |     switch (exprContext) { | 
 |     case ACCEPT_NON_QUERY: | 
 |     case ACCEPT_SUB_QUERY: | 
 |     case ACCEPT_CURSOR: | 
 |         throw SqlUtil.newContextException(getPos(), | 
 |             RESOURCE.illegalQueryExpression()); | 
 |     } | 
 | } | 
 |  | 
 | JAVACODE void checkNonQueryExpression(ExprContext exprContext) | 
 | { | 
 |     switch (exprContext) { | 
 |     case ACCEPT_QUERY: | 
 |         throw SqlUtil.newContextException(getPos(), | 
 |             RESOURCE.illegalNonQueryExpression()); | 
 |     } | 
 | } | 
 |  | 
 | JAVACODE SqlNode checkNotJoin(SqlNode e) | 
 | { | 
 |     if (e instanceof SqlJoin) { | 
 |         throw SqlUtil.newContextException(e.getParserPosition(), | 
 |             RESOURCE.illegalJoinExpression()); | 
 |     } | 
 |     return e; | 
 | } | 
 |  | 
 | /** | 
 |  * Converts a ParseException (local to this particular instantiation | 
 |  * of the parser) into a SqlParseException (common to all parsers). | 
 |  */ | 
 | JAVACODE SqlParseException convertException(Throwable ex) | 
 | { | 
 |     if (ex instanceof SqlParseException) { | 
 |         return (SqlParseException) ex; | 
 |     } | 
 |     SqlParserPos pos = null; | 
 |     int[][] expectedTokenSequences = null; | 
 |     String[] tokenImage = null; | 
 |     if (ex instanceof ParseException) { | 
 |         ParseException pex = (ParseException) ex; | 
 |         expectedTokenSequences = pex.expectedTokenSequences; | 
 |         tokenImage = pex.tokenImage; | 
 |         if (pex.currentToken != null) { | 
 |             final Token token = pex.currentToken.next; | 
 |             // Checks token.image.equals("1") to avoid recursive call. | 
 |             // The SqlAbstractParserImpl#MetadataImpl constructor uses constant "1" to | 
 |             // throw intentionally to collect the expected tokens. | 
 |             if (!token.image.equals("1") | 
 |                 && getMetadata().isKeyword(token.image) | 
 |                 && SqlParserUtil.allowsIdentifier(tokenImage, expectedTokenSequences)) { | 
 |                 // If the next token is a keyword, reformat the error message as: | 
 |  | 
 |                 // Incorrect syntax near the keyword '{keyword}' at line {line_number}, | 
 |                 // column {column_number}. | 
 |                 final String expecting = ex.getMessage() | 
 |                     .substring(ex.getMessage().indexOf("Was expecting")); | 
 |                 final String errorMsg = String.format("Incorrect syntax near the keyword '%s' " | 
 |                         + "at line %d, column %d.\n%s", | 
 |                     token.image, | 
 |                     token.beginLine, | 
 |                     token.beginColumn, | 
 |                     expecting); | 
 |                 // Replace the ParseException with explicit error message. | 
 |                 ex = new ParseException(errorMsg); | 
 |             } | 
 |             pos = new SqlParserPos( | 
 |                 token.beginLine, | 
 |                 token.beginColumn, | 
 |                 token.endLine, | 
 |                 token.endColumn); | 
 |         } | 
 |     } else if (ex instanceof TokenMgrError) { | 
 |         expectedTokenSequences = null; | 
 |         tokenImage = null; | 
 |         // Example: | 
 |         //    Lexical error at line 3, column 24.  Encountered "#" after "a". | 
 |         final java.util.regex.Pattern pattern = java.util.regex.Pattern.compile( | 
 |             "(?s)Lexical error at line ([0-9]+), column ([0-9]+).*"); | 
 |         java.util.regex.Matcher matcher = pattern.matcher(ex.getMessage()); | 
 |         if (matcher.matches()) { | 
 |             int line = Integer.parseInt(matcher.group(1)); | 
 |             int column = Integer.parseInt(matcher.group(2)); | 
 |             pos = new SqlParserPos(line, column, line, column); | 
 |         } | 
 |     } else if (ex instanceof CalciteContextException) { | 
 |         // CalciteContextException is the standard wrapper for exceptions | 
 |         // produced by the validator, but in the parser, the standard is | 
 |         // SqlParseException; so, strip it away. In case you were wondering, | 
 |         // the CalciteContextException appears because the parser | 
 |         // occasionally calls into validator-style code such as | 
 |         // SqlSpecialOperator.reduceExpr. | 
 |         CalciteContextException ece = | 
 |             (CalciteContextException) ex; | 
 |         pos = new SqlParserPos( | 
 |             ece.getPosLine(), | 
 |             ece.getPosColumn(), | 
 |             ece.getEndPosLine(), | 
 |             ece.getEndPosColumn()); | 
 |         ex = ece.getCause(); | 
 |     } | 
 |  | 
 |     return new SqlParseException( | 
 |         ex.getMessage(), pos, expectedTokenSequences, tokenImage, ex); | 
 | } | 
 |  | 
 | /** | 
 |  * Removes or transforms misleading information from a parse exception. | 
 |  * | 
 |  * @param e dirty excn | 
 |  * | 
 |  * @return clean excn | 
 |  */ | 
 | JAVACODE ParseException cleanupParseException(ParseException ex) | 
 | { | 
 |     if (ex.expectedTokenSequences == null) { | 
 |         return ex; | 
 |     } | 
 |     int iIdentifier = Arrays.asList(ex.tokenImage).indexOf("<IDENTIFIER>"); | 
 |  | 
 |     // Find all sequences in the error which contain identifier. For | 
 |     // example, | 
 |     //       {<IDENTIFIER>} | 
 |     //       {A} | 
 |     //       {B, C} | 
 |     //       {D, <IDENTIFIER>} | 
 |     //       {D, A} | 
 |     //       {D, B} | 
 |     // | 
 |     // would yield | 
 |     //       {} | 
 |     //       {D} | 
 |     final List<int[]> prefixList = new ArrayList<int[]>(); | 
 |     for (int i = 0; i < ex.expectedTokenSequences.length; ++i) { | 
 |         int[] seq = ex.expectedTokenSequences[i]; | 
 |         int j = seq.length - 1; | 
 |         int i1 = seq[j]; | 
 |         if (i1 == iIdentifier) { | 
 |             int[] prefix = new int[j]; | 
 |             System.arraycopy(seq, 0, prefix, 0, j); | 
 |             prefixList.add(prefix); | 
 |         } | 
 |     } | 
 |  | 
 |     if (prefixList.isEmpty()) { | 
 |         return ex; | 
 |     } | 
 |  | 
 |     int[][] prefixes = (int[][]) | 
 |         prefixList.toArray(new int[prefixList.size()][]); | 
 |  | 
 |     // Since <IDENTIFIER> was one of the possible productions, | 
 |     // we know that the parser will also have included all | 
 |     // of the non-reserved keywords (which are treated as | 
 |     // identifiers in non-keyword contexts).  So, now we need | 
 |     // to clean those out, since they're totally irrelevant. | 
 |  | 
 |     final List<int[]> list = new ArrayList<int[]>(); | 
 |     Metadata metadata = getMetadata(); | 
 |     for (int i = 0; i < ex.expectedTokenSequences.length; ++i) { | 
 |         int [] seq = ex.expectedTokenSequences[i]; | 
 |         String tokenImage = ex.tokenImage[seq[seq.length - 1]]; | 
 |         String token = SqlParserUtil.getTokenVal(tokenImage); | 
 |         if (token == null  || !metadata.isNonReservedKeyword(token)) { | 
 |             list.add(seq); | 
 |             continue; | 
 |         } | 
 |         boolean match = matchesPrefix(seq, prefixes); | 
 |         if (!match) { | 
 |             list.add(seq); | 
 |         } | 
 |     } | 
 |  | 
 |     ex.expectedTokenSequences = | 
 |         (int [][]) list.toArray(new int [list.size()][]); | 
 |     return ex; | 
 | } | 
 |  | 
 | JAVACODE boolean matchesPrefix(int[] seq, int[][] prefixes) | 
 | { | 
 |     nextPrefix: | 
 |     for (int[] prefix : prefixes) { | 
 |         if (seq.length == prefix.length + 1) { | 
 |             for (int k = 0; k < prefix.length; k++) { | 
 |                 if (prefix[k] != seq[k]) { | 
 |                     continue nextPrefix; | 
 |                 } | 
 |             } | 
 |             return true; | 
 |         } | 
 |     } | 
 |     return false; | 
 | } | 
 |  | 
 | /***************************************** | 
 |  * Syntactical Descriptions              * | 
 |  *****************************************/ | 
 |  | 
 | SqlNode ExprOrJoinOrOrderedQuery(ExprContext exprContext) : | 
 | { | 
 |     SqlNode e; | 
 |     final List<Object> list = new ArrayList<Object>(); | 
 | } | 
 | { | 
 |     // Lookhead to distinguish between "TABLE emp" (which will be | 
 |     // matched by ExplicitTable() via Query()) | 
 |     // and "TABLE fun(args)" (which will be matched by TableRef()) | 
 |     ( | 
 |         LOOKAHEAD(2) | 
 |         e = Query(exprContext) | 
 |         e = OrderByLimitOpt(e) | 
 |         { return e; } | 
 |     | | 
 |         e = TableRef1(ExprContext.ACCEPT_QUERY_OR_JOIN) | 
 |         ( e = JoinTable(e) )* | 
 |         { list.add(e); } | 
 |         ( AddSetOpQuery(list, exprContext) )* | 
 |         { return SqlParserUtil.toTree(list); } | 
 |     ) | 
 | } | 
 |  | 
 | /** | 
 |  * Parses either a row expression or a query expression with an optional | 
 |  * ORDER BY. | 
 |  * | 
 |  * <p>Postgres syntax for limit: | 
 |  * | 
 |  * <blockquote><pre> | 
 |  *    [ LIMIT { count | ALL } ] | 
 |  *    [ OFFSET start ]</pre> | 
 |  * </blockquote> | 
 |  * | 
 |  * <p>Trino syntax for limit: | 
 |  * | 
 |  * <blockquote><pre> | 
 |  *    [ OFFSET start ] | 
 |  *    [ LIMIT { count | ALL } ]</pre> | 
 |  * </blockquote> | 
 |  * | 
 |  * <p>MySQL syntax for limit: | 
 |  * | 
 |  * <blockquote><pre> | 
 |  *    [ LIMIT { count | start, count } ]</pre> | 
 |  * </blockquote> | 
 |  * | 
 |  * <p>SQL:2008 syntax for limit: | 
 |  * | 
 |  * <blockquote><pre> | 
 |  *    [ OFFSET start { ROW | ROWS } ] | 
 |  *    [ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY ]</pre> | 
 |  * </blockquote> | 
 |  */ | 
 | SqlNode OrderedQueryOrExpr(ExprContext exprContext) : | 
 | { | 
 |     SqlNode e; | 
 | } | 
 | { | 
 |     e = QueryOrExpr(exprContext) | 
 |     e = OrderByLimitOpt(e) | 
 |     { return e; } | 
 | } | 
 |  | 
 | /** Reads optional "ORDER BY", "LIMIT", "OFFSET", "FETCH" following a query, | 
 |  * {@code e}. If any of them are present, adds them to the query; | 
 |  * otherwise returns the query unchanged. | 
 |  * Throws if they are present and {@code e} is not a query. */ | 
 | SqlNode OrderByLimitOpt(SqlNode e) : | 
 | { | 
 |     final SqlNodeList orderBy; | 
 |     final Span s = Span.of(); | 
 |     SqlNode[] offsetFetch = {null, null}; | 
 | } | 
 | { | 
 |     ( | 
 |         // use the syntactic type of the expression we just parsed | 
 |         // to decide whether ORDER BY makes sense | 
 |         orderBy = OrderBy(e.isA(SqlKind.QUERY)) | 
 |     |   { orderBy = null; } | 
 |     ) | 
 |     [ | 
 |         LimitClause(s, offsetFetch) | 
 |         [ OffsetClause(s, offsetFetch) ] | 
 |     | | 
 |         OffsetClause(s, offsetFetch) | 
 |         [ | 
 |             LimitClause(s, offsetFetch) { | 
 |                 if (!this.conformance.isOffsetLimitAllowed()) { | 
 |                     throw SqlUtil.newContextException(s.end(this), | 
 |                         RESOURCE.offsetLimitNotAllowed()); | 
 |                 } | 
 |             } | 
 |         | | 
 |             FetchClause(offsetFetch) | 
 |         ] | 
 |     | | 
 |         FetchClause(offsetFetch) | 
 |     ] | 
 |     { | 
 |         if (orderBy != null || offsetFetch[0] != null || offsetFetch[1] != null) { | 
 |             return new SqlOrderBy(getPos(), e, | 
 |                 Util.first(orderBy, SqlNodeList.EMPTY), | 
 |                 offsetFetch[0], offsetFetch[1]); | 
 |         } | 
 |         return e; | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses an OFFSET clause in an ORDER BY expression. | 
 |  */ | 
 | void OffsetClause(Span s, SqlNode[] offsetFetch) : | 
 | { | 
 | } | 
 | { | 
 |     // ROW or ROWS is required in SQL:2008 but we make it optional | 
 |     // because it is not present in Postgres-style syntax. | 
 |     <OFFSET> { s.add(this); } | 
 |     offsetFetch[0] = UnsignedNumericLiteralOrParam() | 
 |     [ <ROW> | <ROWS> ] | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a FETCH clause in an ORDER BY expression. | 
 |  */ | 
 | void FetchClause(SqlNode[] offsetFetch) : | 
 | { | 
 | } | 
 | { | 
 |     // SQL:2008-style syntax. "OFFSET ... FETCH ...". | 
 |     // If you specify both LIMIT and FETCH, FETCH wins. | 
 |     <FETCH> ( <FIRST> | <NEXT> ) offsetFetch[1] = UnsignedNumericLiteralOrParam() | 
 |     ( <ROW> | <ROWS> ) <ONLY> | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a LIMIT clause in an ORDER BY expression. | 
 |  */ | 
 | void LimitClause(Span s, SqlNode[] offsetFetch) : | 
 | { | 
 |     final String error; | 
 | } | 
 | { | 
 |     // Postgres-style syntax. "LIMIT ... OFFSET ..." | 
 |     <LIMIT> { s.add(this); } | 
 |     ( | 
 |         // MySQL-style syntax. "LIMIT start, count" or "LIMIT start, ALL" | 
 |         LOOKAHEAD(2) | 
 |         offsetFetch[0] = UnsignedNumericLiteralOrParam() | 
 |         <COMMA> | 
 |         ( | 
 |             offsetFetch[1] = UnsignedNumericLiteralOrParam() { | 
 |                 error = "count"; | 
 |             } | 
 |         | | 
 |             <ALL> { | 
 |                 error = "ALL"; | 
 |             } | 
 |         ) { | 
 |             if (!this.conformance.isLimitStartCountAllowed()) { | 
 |                 throw SqlUtil.newContextException(s.end(this), | 
 |                     RESOURCE.limitStartCountOrAllNotAllowed(error)); | 
 |             } | 
 |         } | 
 |     | | 
 |         offsetFetch[1] = UnsignedNumericLiteralOrParam() | 
 |     | | 
 |         <ALL> | 
 |     ) | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a leaf in a query expression (SELECT, VALUES or TABLE). | 
 |  */ | 
 | SqlNode LeafQuery(ExprContext exprContext) : | 
 | { | 
 |     SqlNode e; | 
 | } | 
 | { | 
 |     { | 
 |         // ensure a query is legal in this context | 
 |         checkQueryExpression(exprContext); | 
 |     } | 
 |     e = SqlSelect() { return e; } | 
 | | | 
 |     e = TableConstructor() { return e; } | 
 | | | 
 |     e = ExplicitTable(getPos()) { return e; } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a parenthesized query or single row expression. | 
 |  * Depending on {@code exprContext}, may also accept a join. | 
 |  */ | 
 | SqlNode ParenthesizedExpression(ExprContext exprContext) : | 
 | { | 
 |     SqlNode e; | 
 | } | 
 | { | 
 |     <LPAREN> | 
 |     { | 
 |         // we've now seen left paren, so queries inside should | 
 |         // be allowed as sub-queries | 
 |         switch (exprContext) { | 
 |         case ACCEPT_SUB_QUERY: | 
 |             exprContext = ExprContext.ACCEPT_NONCURSOR; | 
 |             break; | 
 |         case ACCEPT_CURSOR: | 
 |             exprContext = ExprContext.ACCEPT_ALL; | 
 |             break; | 
 |         } | 
 |     } | 
 |     e = ExprOrJoinOrOrderedQuery(exprContext) | 
 |     <RPAREN> | 
 |     { | 
 |         exprContext.throwIfNotCompatible(e); | 
 |         return e; | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a parenthesized query or comma-list of row expressions. | 
 |  * | 
 |  * <p>REVIEW jvs 8-Feb-2004: There's a small hole in this production.  It can be | 
 |  * used to construct something like | 
 |  * | 
 |  * <blockquote><pre> | 
 |  * WHERE x IN (select count(*) from t where c=d,5)</pre> | 
 |  * </blockquote> | 
 |  * | 
 |  * <p>which should be illegal.  The above is interpreted as equivalent to | 
 |  * | 
 |  * <blockquote><pre> | 
 |  * WHERE x IN ((select count(*) from t where c=d),5)</pre> | 
 |  * </blockquote> | 
 |  * | 
 |  * <p>which is a legal use of a sub-query.  The only way to fix the hole is to | 
 |  * be able to remember whether a subexpression was parenthesized or not, which | 
 |  * means preserving parentheses in the SqlNode tree.  This is probably | 
 |  * desirable anyway for use in purely syntactic parsing applications (e.g. SQL | 
 |  * pretty-printer).  However, if this is done, it's important to also make | 
 |  * isA() on the paren node call down to its operand so that we can | 
 |  * always correctly discriminate a query from a row expression. | 
 |  */ | 
 | SqlNodeList ParenthesizedQueryOrCommaList( | 
 |     ExprContext exprContext) : | 
 | { | 
 |     SqlNode e; | 
 |     final List<SqlNode> list = new ArrayList<SqlNode>(); | 
 |     ExprContext firstExprContext = exprContext; | 
 |     final Span s; | 
 | } | 
 | { | 
 |     <LPAREN> | 
 |     { | 
 |         // we've now seen left paren, so a query by itself should | 
 |         // be interpreted as a sub-query | 
 |         s = span(); | 
 |         switch (exprContext) { | 
 |         case ACCEPT_SUB_QUERY: | 
 |             firstExprContext = ExprContext.ACCEPT_NONCURSOR; | 
 |             break; | 
 |         case ACCEPT_CURSOR: | 
 |             firstExprContext = ExprContext.ACCEPT_ALL; | 
 |             break; | 
 |         } | 
 |     } | 
 |     e = OrderedQueryOrExpr(firstExprContext) { list.add(e); } | 
 |     ( | 
 |         <COMMA> | 
 |         { | 
 |             // a comma-list can't appear where only a query is expected | 
 |             checkNonQueryExpression(exprContext); | 
 |         } | 
 |         AddExpression(list, exprContext) | 
 |     )* | 
 |     <RPAREN> | 
 |     { | 
 |         return new SqlNodeList(list, s.end(this)); | 
 |     } | 
 | } | 
 |  | 
 | /** As ParenthesizedQueryOrCommaList, but allows DEFAULT | 
 |  * in place of any of the expressions. For example, | 
 |  * {@code (x, DEFAULT, null, DEFAULT)}. */ | 
 | SqlNodeList ParenthesizedQueryOrCommaListWithDefault( | 
 |     ExprContext exprContext) : | 
 | { | 
 |     SqlNode e; | 
 |     final List<SqlNode> list = new ArrayList<SqlNode>(); | 
 |     ExprContext firstExprContext = exprContext; | 
 |     final Span s; | 
 | } | 
 | { | 
 |     <LPAREN> | 
 |     { | 
 |         // we've now seen left paren, so a query by itself should | 
 |         // be interpreted as a sub-query | 
 |         s = span(); | 
 |         switch (exprContext) { | 
 |         case ACCEPT_SUB_QUERY: | 
 |             firstExprContext = ExprContext.ACCEPT_NONCURSOR; | 
 |             break; | 
 |         case ACCEPT_CURSOR: | 
 |             firstExprContext = ExprContext.ACCEPT_ALL; | 
 |             break; | 
 |         } | 
 |     } | 
 |     ( | 
 |         e = OrderedQueryOrExpr(firstExprContext) { list.add(e); } | 
 |     | | 
 |         e = Default() { list.add(e); } | 
 |     ) | 
 |     ( | 
 |         <COMMA> | 
 |         { | 
 |             // a comma-list can't appear where only a query is expected | 
 |             checkNonQueryExpression(exprContext); | 
 |         } | 
 |         ( | 
 |             e = Expression(exprContext) { list.add(e); } | 
 |         | | 
 |             e = Default() { list.add(e); } | 
 |         ) | 
 |     )* | 
 |     <RPAREN> | 
 |     { | 
 |         return new SqlNodeList(list, s.end(this)); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses function parameter lists. | 
 |  * If the list starts with DISTINCT or ALL, it is discarded. | 
 |  */ | 
 | List<SqlNode> UnquantifiedFunctionParameterList(ExprContext exprContext) : | 
 | { | 
 |     final List<SqlNode> args; | 
 | } | 
 | { | 
 |     args = FunctionParameterList(exprContext) { | 
 |         args.remove(0); // remove DISTINCT or ALL, if present | 
 |         return args; | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses function parameter lists including DISTINCT keyword recognition, | 
 |  * DEFAULT, and named argument assignment. | 
 |  */ | 
 | List<SqlNode> FunctionParameterList(ExprContext exprContext) : | 
 | { | 
 |     final SqlLiteral qualifier; | 
 |     final List<SqlNode> list = new ArrayList<SqlNode>(); | 
 | } | 
 | { | 
 |     <LPAREN> | 
 |     ( | 
 |         qualifier = AllOrDistinct() { list.add(qualifier); } | 
 |     | | 
 |         { list.add(null); } | 
 |     ) | 
 |     AddArg0(list, exprContext) | 
 |     ( | 
 |         <COMMA> { | 
 |             // a comma-list can't appear where only a query is expected | 
 |             checkNonQueryExpression(exprContext); | 
 |         } | 
 |         AddArg(list, exprContext) | 
 |     )* | 
 |     <RPAREN> | 
 |     { | 
 |         return list; | 
 |     } | 
 | } | 
 |  | 
 | SqlLiteral AllOrDistinct() : | 
 | { | 
 | } | 
 | { | 
 |     <DISTINCT> { return SqlSelectKeyword.DISTINCT.symbol(getPos()); } | 
 | | | 
 |     <ALL> { return SqlSelectKeyword.ALL.symbol(getPos()); } | 
 | } | 
 |  | 
 | void AddArg0(List<SqlNode> list, ExprContext exprContext) : | 
 | { | 
 |     final SqlIdentifier name; | 
 |     SqlNode e; | 
 |     final ExprContext firstExprContext; | 
 |     { | 
 |         // we've now seen left paren, so queries inside should | 
 |         // be allowed as sub-queries | 
 |         switch (exprContext) { | 
 |         case ACCEPT_SUB_QUERY: | 
 |             firstExprContext = ExprContext.ACCEPT_NONCURSOR; | 
 |             break; | 
 |         case ACCEPT_CURSOR: | 
 |             firstExprContext = ExprContext.ACCEPT_ALL; | 
 |             break; | 
 |         default: | 
 |             firstExprContext = exprContext; | 
 |             break; | 
 |         } | 
 |     } | 
 | } | 
 | { | 
 |     ( | 
 |         LOOKAHEAD(2) name = SimpleIdentifier() <NAMED_ARGUMENT_ASSIGNMENT> | 
 |     |   { name = null; } | 
 |     ) | 
 |     ( | 
 |         e = Default() | 
 |     | | 
 |         LOOKAHEAD((SimpleIdentifierOrList() | <LPAREN> <RPAREN>) <LAMBDA>) | 
 |         e = LambdaExpression() | 
 |     | | 
 |         LOOKAHEAD(3) | 
 |         e = TableParam() | 
 |     | | 
 |         e = PartitionedQueryOrQueryOrExpr(firstExprContext) | 
 |     ) | 
 |     { | 
 |         if (name != null) { | 
 |             e = SqlStdOperatorTable.ARGUMENT_ASSIGNMENT.createCall( | 
 |                 Span.of(name, e).pos(), e, name); | 
 |         } | 
 |         list.add(e); | 
 |     } | 
 | } | 
 |  | 
 | void AddArg(List<SqlNode> list, ExprContext exprContext) : | 
 | { | 
 |     final SqlIdentifier name; | 
 |     SqlNode e; | 
 | } | 
 | { | 
 |     ( | 
 |         LOOKAHEAD(2) name = SimpleIdentifier() <NAMED_ARGUMENT_ASSIGNMENT> | 
 |     |   { name = null; } | 
 |     ) | 
 |     ( | 
 |         e = Default() | 
 |     | | 
 |         LOOKAHEAD((SimpleIdentifierOrList() | <LPAREN> <RPAREN>) <LAMBDA>) | 
 |         e = LambdaExpression() | 
 |     | | 
 |         e = Expression(exprContext) | 
 |     | | 
 |         e = TableParam() | 
 |     ) | 
 |     { | 
 |         if (name != null) { | 
 |             e = SqlStdOperatorTable.ARGUMENT_ASSIGNMENT.createCall( | 
 |                 Span.of(name, e).pos(), e, name); | 
 |         } | 
 |         list.add(e); | 
 |     } | 
 | } | 
 |  | 
 | SqlNode Default() : {} | 
 | { | 
 |     <DEFAULT_> { | 
 |         return SqlStdOperatorTable.DEFAULT.createCall(getPos()); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a query (SELECT, UNION, INTERSECT, EXCEPT, VALUES, TABLE) followed by | 
 |  * the end-of-file symbol. | 
 |  */ | 
 | SqlNode SqlQueryEof() : | 
 | { | 
 |     SqlNode query; | 
 | } | 
 | { | 
 |     query = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY) | 
 |     <EOF> | 
 |     { return query; } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a list of SQL statements separated by semicolon. | 
 |  * The semicolon is required between statements, but is | 
 |  * optional at the end. | 
 |  */ | 
 | SqlNodeList SqlStmtList() : | 
 | { | 
 |     final List<SqlNode> stmtList = new ArrayList<SqlNode>(); | 
 |     SqlNode stmt; | 
 | } | 
 | { | 
 |     stmt = SqlStmt() { | 
 |         stmtList.add(stmt); | 
 |     } | 
 |     ( | 
 |         <SEMICOLON> | 
 |         [ | 
 |             stmt = SqlStmt() { | 
 |                 stmtList.add(stmt); | 
 |             } | 
 |         ] | 
 |     )* | 
 |     <EOF> | 
 |     { | 
 |         return new SqlNodeList(stmtList, Span.of(stmtList).pos()); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses an SQL statement. | 
 |  */ | 
 | SqlNode SqlStmt() : | 
 | { | 
 |     SqlNode stmt; | 
 | } | 
 | { | 
 |     ( | 
 | <#-- Add methods to parse additional statements here --> | 
 | <#list (parser.statementParserMethods!default.parser.statementParserMethods) as method> | 
 |         LOOKAHEAD(2) stmt = ${method} | 
 |     | | 
 | </#list> | 
 |         stmt = SqlSetOption(Span.of(), null) | 
 |     | | 
 |         stmt = SqlAlter() | 
 |     | | 
 | <#if (parser.createStatementParserMethods!default.parser.createStatementParserMethods)?size != 0> | 
 |         stmt = SqlCreate() | 
 |     | | 
 | </#if> | 
 | <#if (parser.dropStatementParserMethods!default.parser.dropStatementParserMethods)?size != 0> | 
 |         stmt = SqlDrop() | 
 |     | | 
 | </#if> | 
 | <#if (parser.truncateStatementParserMethods!default.parser.truncateStatementParserMethods)?size != 0> | 
 |         LOOKAHEAD(2) | 
 |         stmt = SqlTruncate() | 
 |     | | 
 | </#if> | 
 |         stmt = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY) | 
 |     | | 
 |         stmt = SqlExplain() | 
 |     | | 
 |         stmt = SqlDescribe() | 
 |     | | 
 |         stmt = SqlInsert() | 
 |     | | 
 |         stmt = SqlDelete() | 
 |     | | 
 |         stmt = SqlUpdate() | 
 |     | | 
 |         stmt = SqlMerge() | 
 |     | | 
 |         stmt = SqlProcedureCall() | 
 |     ) | 
 |     { | 
 |         return stmt; | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses an SQL statement followed by the end-of-file symbol. | 
 |  */ | 
 | SqlNode SqlStmtEof() : | 
 | { | 
 |     SqlNode stmt; | 
 | } | 
 | { | 
 |     stmt = SqlStmt() <EOF> | 
 |     { | 
 |         return stmt; | 
 |     } | 
 | } | 
 |  | 
 | <#-- Add implementations of additional parser statement calls here --> | 
 | <#list (parser.implementationFiles!default.parser.implementationFiles) as file> | 
 |     <#include "/@includes/"+file /> | 
 | </#list> | 
 |  | 
 | SqlNodeList ParenthesizedKeyValueOptionCommaList() : | 
 | { | 
 |     final Span s; | 
 |     final List<SqlNode> list = new ArrayList<SqlNode>(); | 
 | } | 
 | { | 
 |     { s = span(); } | 
 |     <LPAREN> | 
 |     AddKeyValueOption(list) | 
 |     ( | 
 |         <COMMA> | 
 |         AddKeyValueOption(list) | 
 |     )* | 
 |     <RPAREN> { | 
 |         return new SqlNodeList(list, s.end(this)); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 | * Parses an option with format key=val whose key is a simple identifier or string literal | 
 | * and value is a string literal. | 
 | */ | 
 | void AddKeyValueOption(List<SqlNode> list) : | 
 | { | 
 |     final SqlNode key; | 
 |     final SqlNode value; | 
 | } | 
 | { | 
 |     ( | 
 |         key = SimpleIdentifier() | 
 |     | | 
 |         key = StringLiteral() | 
 |     ) | 
 |     <EQ> | 
 |     value = StringLiteral() { | 
 |         list.add(key); | 
 |         list.add(value); | 
 |     } | 
 | } | 
 |  | 
 | /** Parses an option value (either a string or a numeric) and adds to a list. */ | 
 | void AddOptionValue(List<SqlNode> list) : | 
 | { | 
 |     final SqlNode value; | 
 | } | 
 | { | 
 |     ( | 
 |         value = NumericLiteral() { list.add(value); } | 
 |     | | 
 |         value = StringLiteral() { list.add(value); } | 
 |     ) | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a literal list separated by comma. The literal is either a string or a numeric. | 
 |  */ | 
 | SqlNodeList ParenthesizedLiteralOptionCommaList() : | 
 | { | 
 |     final Span s; | 
 |     final List<SqlNode> list = new ArrayList<SqlNode>(); | 
 | } | 
 | { | 
 |     { s = span(); } | 
 |     <LPAREN> | 
 |     AddOptionValue(list) ( <COMMA> AddOptionValue(list) )* | 
 |     <RPAREN> { | 
 |         return new SqlNodeList(list, s.end(this)); | 
 |     } | 
 | } | 
 |  | 
 | void AddHint(List<SqlNode> hints) : | 
 | { | 
 |     final SqlIdentifier hintName; | 
 |     final SqlNodeList hintOptions; | 
 |     final SqlHint.HintOptionFormat optionFormat; | 
 | } | 
 | { | 
 |     hintName = SimpleIdentifier() | 
 |     ( | 
 |        LOOKAHEAD(5) | 
 |         hintOptions = ParenthesizedKeyValueOptionCommaList() { | 
 |             optionFormat = SqlHint.HintOptionFormat.KV_LIST; | 
 |         } | 
 |     | | 
 |         LOOKAHEAD(3) | 
 |         hintOptions = ParenthesizedSimpleIdentifierList() { | 
 |             optionFormat = SqlHint.HintOptionFormat.ID_LIST; | 
 |         } | 
 |     | | 
 |         LOOKAHEAD(3) | 
 |         hintOptions = ParenthesizedLiteralOptionCommaList() { | 
 |             optionFormat = SqlHint.HintOptionFormat.LITERAL_LIST; | 
 |         } | 
 |     | | 
 |         LOOKAHEAD(2) | 
 |         [<LPAREN> <RPAREN>] | 
 |         { | 
 |             hintOptions = SqlNodeList.EMPTY; | 
 |             optionFormat = SqlHint.HintOptionFormat.EMPTY; | 
 |         } | 
 |     ) | 
 |     { | 
 |         hints.add( | 
 |            new SqlHint(Span.of(hintOptions).end(this), hintName, hintOptions, | 
 |                optionFormat)); | 
 |     } | 
 | } | 
 |  | 
 | /** Parses hints following a table reference, | 
 |  * and returns the wrapped table reference. */ | 
 | SqlNode TableHints(SqlIdentifier tableName) : | 
 | { | 
 |     final List<SqlNode> hints = new ArrayList<SqlNode>(); | 
 | } | 
 | { | 
 |     <HINT_BEG> AddHint(hints) ( <COMMA> AddHint(hints) )* <COMMENT_END> { | 
 |         final SqlParserPos pos = Span.of(tableName).addAll(hints).end(this); | 
 |         final SqlNodeList hintList = new SqlNodeList(hints, pos); | 
 |         return new SqlTableRef(pos, tableName, hintList); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a leaf SELECT expression without ORDER BY. | 
 |  */ | 
 | SqlSelect SqlSelect() : | 
 | { | 
 |     final List<SqlLiteral> keywords = new ArrayList<SqlLiteral>(); | 
 |     final SqlLiteral keyword; | 
 |     final SqlNodeList keywordList; | 
 |     final List<SqlNode> selectList = new ArrayList<SqlNode>(); | 
 |     final SqlNode fromClause; | 
 |     final SqlNode where; | 
 |     final SqlNodeList groupBy; | 
 |     final SqlNode having; | 
 |     final SqlNodeList windowDecls; | 
 |     final SqlNode qualify; | 
 |     final List<SqlNode> hints = new ArrayList<SqlNode>(); | 
 |     final Span s; | 
 | } | 
 | { | 
 |     <SELECT> { s = span(); } | 
 |     [ <HINT_BEG> AddHint(hints) ( <COMMA> AddHint(hints) )* <COMMENT_END> ] | 
 |     SqlSelectKeywords(keywords) | 
 |     ( | 
 |         <STREAM> { | 
 |             keywords.add(SqlSelectKeyword.STREAM.symbol(getPos())); | 
 |         } | 
 |     )? | 
 |     ( | 
 |         keyword = AllOrDistinct() { keywords.add(keyword); } | 
 |     )? | 
 |     { | 
 |         keywordList = new SqlNodeList(keywords, s.addAll(keywords).pos()); | 
 |     } | 
 |     AddSelectItem(selectList) | 
 |     ( <COMMA> AddSelectItem(selectList) )* | 
 |     ( | 
 |         <FROM> fromClause = FromClause() | 
 |         ( where = Where() | { where = null; } ) | 
 |         ( groupBy = GroupBy() | { groupBy = null; } ) | 
 |         ( having = Having() | { having = null; } ) | 
 |         ( windowDecls = Window() | { windowDecls = null; } ) | 
 |         ( qualify = Qualify() | { qualify = null; } ) | 
 |     | | 
 |         E() { | 
 |             fromClause = null; | 
 |             where = null; | 
 |             groupBy = null; | 
 |             having = null; | 
 |             windowDecls = null; | 
 |             qualify = null; | 
 |         } | 
 |     ) | 
 |     { | 
 |         return new SqlSelect(s.end(this), keywordList, | 
 |             new SqlNodeList(selectList, Span.of(selectList).pos()), | 
 |             fromClause, where, groupBy, having, windowDecls, qualify, | 
 |             null, null, null, new SqlNodeList(hints, getPos())); | 
 |     } | 
 | } | 
 |  | 
 | /* | 
 |  * Abstract production: | 
 |  * | 
 |  *    void SqlSelectKeywords(List keywords) | 
 |  * | 
 |  * Parses dialect-specific keywords immediately following the SELECT keyword. | 
 |  */ | 
 |  | 
 | /** | 
 |  * Parses an EXPLAIN PLAN statement. | 
 |  */ | 
 | SqlNode SqlExplain() : | 
 | { | 
 |     SqlNode stmt; | 
 |     SqlExplainLevel detailLevel = SqlExplainLevel.EXPPLAN_ATTRIBUTES; | 
 |     SqlExplain.Depth depth; | 
 |     final SqlExplainFormat format; | 
 | } | 
 | { | 
 |     <EXPLAIN> <PLAN> | 
 |     [ detailLevel = ExplainDetailLevel() ] | 
 |     depth = ExplainDepth() | 
 |     ( | 
 |         LOOKAHEAD(2) | 
 |         <AS> <XML> { format = SqlExplainFormat.XML; } | 
 |     | | 
 |         LOOKAHEAD(2) | 
 |         <AS> <JSON> { format = SqlExplainFormat.JSON; } | 
 |     | | 
 |         <AS> <DOT_FORMAT> { format = SqlExplainFormat.DOT; } | 
 |     | | 
 |         { format = SqlExplainFormat.TEXT; } | 
 |     ) | 
 |     <FOR> stmt = SqlQueryOrDml() { | 
 |         return new SqlExplain(getPos(), | 
 |             stmt, | 
 |             detailLevel.symbol(SqlParserPos.ZERO), | 
 |             depth.symbol(SqlParserPos.ZERO), | 
 |             format.symbol(SqlParserPos.ZERO), | 
 |             nDynamicParams); | 
 |     } | 
 | } | 
 |  | 
 | /** Parses a query (SELECT or VALUES) | 
 |  * or DML statement (INSERT, UPDATE, DELETE, MERGE). */ | 
 | SqlNode SqlQueryOrDml() : | 
 | { | 
 |     SqlNode stmt; | 
 | } | 
 | { | 
 |     ( | 
 |         stmt = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY) | 
 |     | | 
 |         stmt = SqlInsert() | 
 |     | | 
 |         stmt = SqlDelete() | 
 |     | | 
 |         stmt = SqlUpdate() | 
 |     | | 
 |         stmt = SqlMerge() | 
 |     ) { return stmt; } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses WITH TYPE | WITH IMPLEMENTATION | WITHOUT IMPLEMENTATION modifier for | 
 |  * EXPLAIN PLAN. | 
 |  */ | 
 | SqlExplain.Depth ExplainDepth() : | 
 | { | 
 | } | 
 | { | 
 |     ( | 
 |         LOOKAHEAD(2) | 
 |         <WITH> <TYPE> | 
 |         { | 
 |             return SqlExplain.Depth.TYPE; | 
 |         } | 
 |         | | 
 |         <WITH> <IMPLEMENTATION> | 
 |         { | 
 |             return SqlExplain.Depth.PHYSICAL; | 
 |         } | 
 |         | | 
 |         <WITHOUT> <IMPLEMENTATION> | 
 |         { | 
 |             return SqlExplain.Depth.LOGICAL; | 
 |         } | 
 |         | | 
 |         { | 
 |             return SqlExplain.Depth.PHYSICAL; | 
 |         } | 
 |  | 
 |     ) | 
 | } | 
 |  | 
 | /** | 
 |  * Parses INCLUDING ALL ATTRIBUTES modifier for EXPLAIN PLAN. | 
 |  */ | 
 | SqlExplainLevel ExplainDetailLevel() : | 
 | { | 
 |     SqlExplainLevel level = SqlExplainLevel.EXPPLAN_ATTRIBUTES; | 
 | } | 
 | { | 
 |     ( | 
 |         <EXCLUDING> <ATTRIBUTES> | 
 |         { | 
 |             level = SqlExplainLevel.NO_ATTRIBUTES; | 
 |         } | 
 |         | | 
 |         <INCLUDING> | 
 |         [ <ALL> { level = SqlExplainLevel.ALL_ATTRIBUTES; } ] | 
 |         <ATTRIBUTES> | 
 |         { | 
 |         } | 
 |     ) | 
 |     { | 
 |         return level; | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a DESCRIBE statement. | 
 |  */ | 
 | SqlNode SqlDescribe() : | 
 | { | 
 |    final Span s; | 
 |    final SqlIdentifier table; | 
 |    final SqlIdentifier column; | 
 |    final SqlIdentifier id; | 
 |    final SqlNode stmt; | 
 | } | 
 | { | 
 |     <DESCRIBE> { s = span(); } | 
 |     ( | 
 |         LOOKAHEAD(2) (<DATABASE> | <CATALOG> | <SCHEMA>) | 
 |         id = CompoundIdentifier() { | 
 |             // DESCRIBE DATABASE and DESCRIBE CATALOG currently do the same as | 
 |             // DESCRIBE SCHEMA but should be different. See | 
 |             //   [CALCITE-1221] Implement DESCRIBE DATABASE, CATALOG, STATEMENT | 
 |             return new SqlDescribeSchema(s.end(id), id); | 
 |         } | 
 |     | | 
 |         // Use syntactic lookahead to determine whether a table name is coming. | 
 |         // We do not allow SimpleIdentifier() because that includes <STATEMENT>. | 
 |         LOOKAHEAD( <TABLE> | 
 |            | <IDENTIFIER> | 
 |            | <HYPHENATED_IDENTIFIER> | 
 |            | <QUOTED_IDENTIFIER> | 
 |            | <BACK_QUOTED_IDENTIFIER> | 
 |            | <BIG_QUERY_BACK_QUOTED_IDENTIFIER> | 
 |            | <BRACKET_QUOTED_IDENTIFIER> ) | 
 |         (<TABLE>)? | 
 |         table = CompoundIdentifier() | 
 |         ( column = SimpleIdentifier() | { column = null; } ) | 
 |         { | 
 |             return new SqlDescribeTable(s.add(table).addIf(column).pos(), | 
 |                 table, column); | 
 |         } | 
 |     | | 
 |         (LOOKAHEAD(1) <STATEMENT>)? | 
 |         stmt = SqlQueryOrDml() { | 
 |             // DESCRIBE STATEMENT currently does the same as EXPLAIN. See | 
 |             //   [CALCITE-1221] Implement DESCRIBE DATABASE, CATALOG, STATEMENT | 
 |             final SqlExplainLevel detailLevel = SqlExplainLevel.EXPPLAN_ATTRIBUTES; | 
 |             final SqlExplain.Depth depth = SqlExplain.Depth.PHYSICAL; | 
 |             final SqlExplainFormat format = SqlExplainFormat.TEXT; | 
 |             return new SqlExplain(s.end(stmt), | 
 |                 stmt, | 
 |                 detailLevel.symbol(SqlParserPos.ZERO), | 
 |                 depth.symbol(SqlParserPos.ZERO), | 
 |                 format.symbol(SqlParserPos.ZERO), | 
 |                 nDynamicParams); | 
 |         } | 
 |     ) | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a CALL statement. | 
 |  */ | 
 | SqlNode SqlProcedureCall() : | 
 | { | 
 |     final Span s; | 
 |     SqlNode routineCall; | 
 | } | 
 | { | 
 |     <CALL> { | 
 |         s = span(); | 
 |     } | 
 |     routineCall = NamedRoutineCall( | 
 |         SqlFunctionCategory.USER_DEFINED_PROCEDURE, | 
 |         ExprContext.ACCEPT_SUB_QUERY) | 
 |     { | 
 |         return SqlStdOperatorTable.PROCEDURE_CALL.createCall( | 
 |             s.end(routineCall), routineCall); | 
 |     } | 
 | } | 
 |  | 
 | SqlNode NamedRoutineCall( | 
 |     SqlFunctionCategory routineType, | 
 |     ExprContext exprContext) : | 
 | { | 
 |     final SqlIdentifier name; | 
 |     final List<SqlNode> list = new ArrayList<SqlNode>(); | 
 |     final Span s; | 
 | } | 
 | { | 
 |     name = CompoundIdentifier() { | 
 |         s = span(); | 
 |     } | 
 |     <LPAREN> | 
 |     [ | 
 |         AddArg0(list, exprContext) | 
 |         ( | 
 |             <COMMA> { | 
 |                 // a comma-list can't appear where only a query is expected | 
 |                 checkNonQueryExpression(exprContext); | 
 |             } | 
 |             AddArg(list, exprContext) | 
 |         )* | 
 |     ] | 
 |     <RPAREN> | 
 |     { | 
 |         return createCall(name, s.end(this), routineType, null, list); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Table parameter of a table function. | 
 |  * The input table with set semantics may be partitioned/ordered on one or more columns. | 
 |  */ | 
 | SqlNode TableParam() : | 
 | { | 
 |     final Span s; | 
 |     final SqlNodeList partitionList; | 
 |     final SqlNodeList orderList; | 
 |     SqlNode tableRef; | 
 | } | 
 | { | 
 |     { s = span(); } | 
 |     tableRef = ExplicitTable(getPos()) | 
 |     ( | 
 |         <PARTITION> <BY> | 
 |         partitionList = SimpleIdentifierOrList() | 
 |     |   { partitionList = SqlNodeList.EMPTY; } | 
 |     ) | 
 |     ( | 
 |         orderList = OrderByOfSetSemanticsTable() | 
 |      |  { orderList = SqlNodeList.EMPTY; } | 
 |     ) | 
 |     { return CreateSetSemanticsTableIfNeeded(s, tableRef, partitionList, orderList); } | 
 | } | 
 |  | 
 | SqlNode PartitionedQueryOrQueryOrExpr(ExprContext exprContext) : | 
 | { | 
 |     SqlNode e; | 
 | } | 
 | { | 
 |     e = OrderedQueryOrExpr(exprContext) | 
 |     e = PartitionedByAndOrderBy(e) | 
 |  | 
 |     { return e; } | 
 | } | 
 |  | 
 | SqlNode PartitionedByAndOrderBy(SqlNode e) : | 
 | { | 
 |     final Span s; | 
 |     final SqlNodeList partitionList; | 
 |     final SqlNodeList orderList; | 
 | } | 
 | { | 
 |     { s = span(); } | 
 |     ( | 
 |         <PARTITION> <BY> | 
 |         partitionList = SimpleIdentifierOrList() | 
 |     |   { partitionList = SqlNodeList.EMPTY; } | 
 |     ) | 
 |     ( | 
 |         orderList = OrderByOfSetSemanticsTable() | 
 |      |  { orderList = SqlNodeList.EMPTY; } | 
 |     ) | 
 |     { return CreateSetSemanticsTableIfNeeded(s, e, partitionList, orderList); } | 
 | } | 
 |  | 
 | SqlNodeList OrderByOfSetSemanticsTable() : | 
 | { | 
 |     final List<SqlNode> list = new ArrayList<SqlNode>(); | 
 |     final Span s; | 
 | } | 
 | { | 
 |   <ORDER> | 
 |   { s = span(); } | 
 |   <BY> | 
 |   ( | 
 |       LOOKAHEAD(2) | 
 |       <LPAREN> AddOrderItem(list) | 
 |       ( | 
 |         // NOTE jvs 6-Feb-2004:  See comments at top of file for why | 
 |         // hint is necessary here. | 
 |         LOOKAHEAD(2) <COMMA> AddOrderItem(list) | 
 |       )* | 
 |       <RPAREN> { | 
 |           return new SqlNodeList(list, s.addAll(list).pos()); | 
 |       } | 
 |   | | 
 |       AddOrderItem(list) | 
 |       { | 
 |           return new SqlNodeList(list, s.addAll(list).pos()); | 
 |       } | 
 |   ) | 
 | } | 
 |  | 
 | SqlNode CreateSetSemanticsTableIfNeeded( | 
 |     final Span s, | 
 |     final SqlNode e, | 
 |     final SqlNodeList partitionList, | 
 |     final SqlNodeList orderList) : | 
 | { | 
 |  | 
 | } | 
 | { | 
 |  | 
 |     { | 
 |         if (partitionList.isEmpty() && orderList.isEmpty()) { | 
 |             return e; | 
 |         } else { | 
 |             return SqlStdOperatorTable.SET_SEMANTICS_TABLE.createCall( | 
 |                 s.pos(), e, partitionList, orderList); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses an INSERT statement. | 
 |  */ | 
 | SqlNode SqlInsert() : | 
 | { | 
 |     final List<SqlLiteral> keywords = new ArrayList<SqlLiteral>(); | 
 |     final SqlNodeList keywordList; | 
 |     final SqlIdentifier tableName; | 
 |     SqlNode tableRef; | 
 |     SqlNode source; | 
 |     final SqlNodeList columnList; | 
 |     final Span s; | 
 |     final Pair<SqlNodeList, SqlNodeList> p; | 
 | } | 
 | { | 
 |     ( | 
 |         <INSERT> | 
 |     | | 
 |         <UPSERT> { keywords.add(SqlInsertKeyword.UPSERT.symbol(getPos())); } | 
 |     ) | 
 |     { s = span(); } | 
 |     SqlInsertKeywords(keywords) { | 
 |         keywordList = new SqlNodeList(keywords, s.addAll(keywords).pos()); | 
 |     } | 
 |     <INTO> tableName = CompoundTableIdentifier() | 
 |     ( tableRef = TableHints(tableName) | { tableRef = tableName; } ) | 
 |     [ LOOKAHEAD(5) tableRef = ExtendTable(tableRef) ] | 
 |     ( | 
 |         LOOKAHEAD(2) | 
 |         p = ParenthesizedCompoundIdentifierList() { | 
 |             if (p.right.size() > 0) { | 
 |                 tableRef = extend(tableRef, p.right); | 
 |             } | 
 |             if (p.left.size() > 0) { | 
 |                 columnList = p.left; | 
 |             } else { | 
 |                 columnList = null; | 
 |             } | 
 |         } | 
 |     |   { columnList = null; } | 
 |     ) | 
 |     source = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY) { | 
 |         return new SqlInsert(s.end(source), keywordList, tableRef, source, | 
 |             columnList); | 
 |     } | 
 | } | 
 |  | 
 | /* | 
 |  * Abstract production: | 
 |  * | 
 |  *    void SqlInsertKeywords(List keywords) | 
 |  * | 
 |  * Parses dialect-specific keywords immediately following the INSERT keyword. | 
 |  */ | 
 |  | 
 | /** | 
 |  * Parses a DELETE statement. | 
 |  */ | 
 | SqlNode SqlDelete() : | 
 | { | 
 |     final SqlIdentifier tableName; | 
 |     SqlNode tableRef; | 
 |     final SqlIdentifier alias; | 
 |     final SqlNode where; | 
 |     final Span s; | 
 | } | 
 | { | 
 |     <DELETE> { | 
 |         s = span(); | 
 |     } | 
 |     <FROM> tableName = CompoundTableIdentifier() | 
 |     ( tableRef = TableHints(tableName) | { tableRef = tableName; } ) | 
 |     [ tableRef = ExtendTable(tableRef) ] | 
 |     ( [ <AS> ] alias = SimpleIdentifier() | { alias = null; } ) | 
 |     ( where = Where() | { where = null; } ) | 
 |     { | 
 |         return new SqlDelete(s.add(tableRef).addIf(alias).addIf(where).pos(), | 
 |             tableRef, where, null, alias); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses an UPDATE statement. | 
 |  */ | 
 | SqlNode SqlUpdate() : | 
 | { | 
 |     final SqlIdentifier tableName; | 
 |     SqlNode tableRef; | 
 |     final SqlIdentifier alias; | 
 |     final SqlNode where; | 
 |     final SqlNodeList sourceExpressionList; | 
 |     final SqlNodeList targetColumnList; | 
 |     SqlIdentifier id; | 
 |     final Span s; | 
 | } | 
 | { | 
 |     <UPDATE> { | 
 |         s = span(); | 
 |         targetColumnList = new SqlNodeList(s.pos()); | 
 |         sourceExpressionList = new SqlNodeList(s.pos()); | 
 |     } | 
 |     tableName = CompoundTableIdentifier() | 
 |     ( tableRef = TableHints(tableName) | { tableRef = tableName; } ) | 
 |     [ tableRef = ExtendTable(tableRef) ] | 
 |     ( [ <AS> ] alias = SimpleIdentifier() | { alias = null; } ) | 
 |     <SET> id = SimpleIdentifier() { | 
 |         targetColumnList.add(id); | 
 |     } | 
 |     // TODO:  support DEFAULT also | 
 |     <EQ> AddExpression(sourceExpressionList, ExprContext.ACCEPT_SUB_QUERY) | 
 |     ( | 
 |         <COMMA> | 
 |         id = SimpleIdentifier() { targetColumnList.add(id); } | 
 |         <EQ> AddExpression(sourceExpressionList, ExprContext.ACCEPT_SUB_QUERY) | 
 |     )* | 
 |     ( where = Where() | { where = null; } ) | 
 |     { | 
 |         final SqlParserPos pos = s.addAll(targetColumnList) | 
 |             .addAll(sourceExpressionList).addIf(where).pos(); | 
 |         return new SqlUpdate(pos, tableRef, targetColumnList, | 
 |             sourceExpressionList, where, null, alias); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a MERGE statement. | 
 |  */ | 
 | SqlNode SqlMerge() : | 
 | { | 
 |     final SqlIdentifier tableName; | 
 |     SqlNode tableRef; | 
 |     final SqlIdentifier alias; | 
 |     final SqlNode sourceTableRef; | 
 |     final SqlNode condition; | 
 |     final SqlUpdate updateCall; | 
 |     final SqlInsert insertCall; | 
 |     final Span s; | 
 | } | 
 | { | 
 |     <MERGE> { s = span(); } <INTO> tableName = CompoundTableIdentifier() | 
 |     ( tableRef = TableHints(tableName) | { tableRef = tableName; } ) | 
 |     [ tableRef = ExtendTable(tableRef) ] | 
 |     ( [ <AS> ] alias = SimpleIdentifier() | { alias = null; } ) | 
 |     <USING> sourceTableRef = TableRef() | 
 |     <ON> condition = Expression(ExprContext.ACCEPT_SUB_QUERY) | 
 |     ( | 
 |         LOOKAHEAD(2) | 
 |         updateCall = WhenMatchedClause(tableRef, alias) | 
 |         ( insertCall = WhenNotMatchedClause(tableRef) | { insertCall = null; } ) | 
 |     | | 
 |         { updateCall = null; } | 
 |         insertCall = WhenNotMatchedClause(tableRef) | 
 |     ) | 
 |     { | 
 |         final SqlParserPos pos = s.addIf(updateCall).addIf(insertCall).pos(); | 
 |         return new SqlMerge(pos, tableRef, condition, sourceTableRef, | 
 |             updateCall, insertCall, null, alias); | 
 |     } | 
 | } | 
 |  | 
 | SqlUpdate WhenMatchedClause(SqlNode table, SqlIdentifier alias) : | 
 | { | 
 |     SqlIdentifier id; | 
 |     final Span s; | 
 |     final SqlNodeList updateColumnList = new SqlNodeList(SqlParserPos.ZERO); | 
 |     final SqlNodeList updateExprList = new SqlNodeList(SqlParserPos.ZERO); | 
 | } | 
 | { | 
 |     <WHEN> { s = span(); } <MATCHED> <THEN> | 
 |     <UPDATE> <SET> id = CompoundIdentifier() { | 
 |         updateColumnList.add(id); | 
 |     } | 
 |     <EQ> AddExpression(updateExprList, ExprContext.ACCEPT_SUB_QUERY) | 
 |     ( | 
 |         <COMMA> | 
 |         id = CompoundIdentifier() { | 
 |             updateColumnList.add(id); | 
 |         } | 
 |         <EQ> AddExpression(updateExprList, ExprContext.ACCEPT_SUB_QUERY) | 
 |     )* | 
 |     { | 
 |         return new SqlUpdate(s.addAll(updateExprList).pos(), table, | 
 |             updateColumnList, updateExprList, null, null, alias); | 
 |     } | 
 | } | 
 |  | 
 | SqlInsert WhenNotMatchedClause(SqlNode table) : | 
 | { | 
 |     final Span insertSpan, valuesSpan; | 
 |     final List<SqlLiteral> keywords = new ArrayList<SqlLiteral>(); | 
 |     final SqlNodeList keywordList; | 
 |     final SqlNodeList insertColumnList; | 
 |     SqlNode rowConstructor; | 
 |     SqlNode insertValues; | 
 | } | 
 | { | 
 |     <WHEN> <NOT> <MATCHED> <THEN> <INSERT> { | 
 |         insertSpan = span(); | 
 |     } | 
 |     SqlInsertKeywords(keywords) { | 
 |         keywordList = new SqlNodeList(keywords, insertSpan.end(this)); | 
 |     } | 
 |     ( | 
 |         LOOKAHEAD(2) | 
 |         insertColumnList = ParenthesizedSimpleIdentifierList() | 
 |     |   { insertColumnList = null; } | 
 |     ) | 
 |     ( | 
 |         <LPAREN> | 
 |         <VALUES> { valuesSpan = span(); } rowConstructor = RowConstructor() | 
 |         <RPAREN> | 
 |     | | 
 |         <VALUES> { valuesSpan = span(); } rowConstructor = RowConstructor() | 
 |     ) | 
 |     { | 
 |         // TODO zfong 5/26/06: note that extra parentheses are accepted above | 
 |         // around the VALUES clause as a hack for unparse, but this is | 
 |         // actually invalid SQL; should fix unparse | 
 |         insertValues = SqlStdOperatorTable.VALUES.createCall( | 
 |             valuesSpan.end(this), rowConstructor); | 
 |         return new SqlInsert(insertSpan.end(this), keywordList, | 
 |             table, insertValues, insertColumnList); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses one item in a select list. | 
 |  */ | 
 | void AddSelectItem(List<SqlNode> list) : | 
 | { | 
 |     final SqlNode e; | 
 |     final SqlIdentifier id; | 
 | } | 
 | { | 
 |     e = SelectExpression() | 
 |     ( | 
 |         [ <AS> ] | 
 |         ( | 
 |             id = SimpleIdentifier() | 
 |         | | 
 |             // Mute the warning about ambiguity between alias and continued | 
 |             // string literal. | 
 |             LOOKAHEAD(1) | 
 |             id = SimpleIdentifierFromStringLiteral() | 
 |         ) | 
 |         { list.add(SqlStdOperatorTable.AS.createCall(span().end(e), e, id)); } | 
 |     |   { list.add(e); } | 
 |     ) | 
 | } | 
 |  | 
 | /** | 
 |  * Parses one unaliased expression in a select list. | 
 |  */ | 
 | SqlNode SelectExpression() : | 
 | { | 
 |     SqlNode e; | 
 | } | 
 | { | 
 |     <STAR> { | 
 |         return SqlIdentifier.star(getPos()); | 
 |     } | 
 | | | 
 |     e = Expression(ExprContext.ACCEPT_SUB_QUERY) { | 
 |         return e; | 
 |     } | 
 | } | 
 |  | 
 | SqlLiteral Natural() : | 
 | { | 
 | } | 
 | { | 
 |     <NATURAL> { return SqlLiteral.createBoolean(true, getPos()); } | 
 | | | 
 |     { return SqlLiteral.createBoolean(false, getPos()); } | 
 | } | 
 |  | 
 | SqlLiteral JoinType() : | 
 | { | 
 |     JoinType joinType; | 
 | } | 
 | { | 
 |     ( | 
 | <#list (parser.joinTypes!default.parser.joinTypes) as method> | 
 |         LOOKAHEAD(3) // required for "LEFT SEMI JOIN" and "LEFT ANTI JOIN" in Babel | 
 |         joinType = ${method}() | 
 |     | | 
 | </#list> | 
 |         <JOIN> { joinType = JoinType.INNER; } | 
 |     | | 
 |         <INNER> <JOIN> { joinType = JoinType.INNER; } | 
 |     | | 
 |         <LEFT> [ <OUTER> ] <JOIN> { joinType = JoinType.LEFT; } | 
 |     | | 
 |         <RIGHT> [ <OUTER> ] <JOIN> { joinType = JoinType.RIGHT; } | 
 |     | | 
 |         <FULL> [ <OUTER> ] <JOIN> { joinType = JoinType.FULL; } | 
 |     | | 
 |         <CROSS> <JOIN> { joinType = JoinType.CROSS; } | 
 |     ) | 
 |     { | 
 |         return joinType.symbol(getPos()); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses the FROM clause for a SELECT. | 
 |  * | 
 |  * <p>FROM is mandatory in standard SQL, optional in dialects such as MySQL, | 
 |  * PostgreSQL. The parser allows SELECT without FROM, but the validator fails | 
 |  * if conformance is, say, STRICT_2003. | 
 |  */ | 
 | SqlNode FromClause() : | 
 | { | 
 |     SqlNode e, e2; | 
 |     SqlLiteral joinType; | 
 | } | 
 | { | 
 |     e = Join() | 
 |     ( | 
 |         // Comma joins should only occur at top-level in the FROM clause. | 
 |         // Valid: | 
 |         //  * FROM a, b | 
 |         //  * FROM (a CROSS JOIN b), c | 
 |         // Not valid: | 
 |         //  * FROM a CROSS JOIN (b, c) | 
 |         LOOKAHEAD(1) | 
 |         <COMMA> { joinType = JoinType.COMMA.symbol(getPos()); } | 
 |         e2 = Join() { | 
 |             e = new SqlJoin(joinType.getParserPosition(), | 
 |                 e, | 
 |                 SqlLiteral.createBoolean(false, joinType.getParserPosition()), | 
 |                 joinType, | 
 |                 e2, | 
 |                 JoinConditionType.NONE.symbol(SqlParserPos.ZERO), | 
 |                 null); | 
 |         } | 
 |     )* | 
 |     { return e; } | 
 | } | 
 |  | 
 | SqlNode Join() : | 
 | { | 
 |     SqlNode e; | 
 | } | 
 | { | 
 |     e = TableRef1(ExprContext.ACCEPT_QUERY_OR_JOIN) | 
 |     ( | 
 |         LOOKAHEAD(2) | 
 |         e = JoinTable(e) | 
 |     )* | 
 |     { | 
 |         return e; | 
 |     } | 
 | } | 
 |  | 
 | /** Matches "LEFT JOIN t ON ...", "RIGHT JOIN t USING ...", "JOIN t". */ | 
 | SqlNode JoinTable(SqlNode e) : | 
 | { | 
 |     SqlNode e2, condition; | 
 |     final SqlLiteral natural, joinType, on, using; | 
 |     SqlNodeList list; | 
 | } | 
 | { | 
 |     // LOOKAHEAD(3) is needed here rather than a LOOKAHEAD(2) because JavaCC | 
 |     // calculates minimum lookahead count incorrectly for choice that contains | 
 |     // zero size child. For instance, with the generated code, | 
 |     // "LOOKAHEAD(2, Natural(), JoinType())" | 
 |     // returns true immediately if it sees a single "<CROSS>" token. Where we | 
 |     // expect the lookahead succeeds after "<CROSS> <APPLY>". | 
 |     // | 
 |     // For more information about the issue, | 
 |     // see https://github.com/javacc/javacc/issues/86 | 
 |     // | 
 |     // We allow CROSS JOIN (joinType = CROSS_JOIN) to have a join condition, | 
 |     // even though that is not valid SQL; the validator will catch it. | 
 |     LOOKAHEAD(3) | 
 |     natural = Natural() | 
 |     joinType = JoinType() | 
 |     e2 = TableRef1(ExprContext.ACCEPT_QUERY_OR_JOIN) | 
 |     ( | 
 |         <ON> { on = JoinConditionType.ON.symbol(getPos()); } | 
 |         condition = Expression(ExprContext.ACCEPT_SUB_QUERY) { | 
 |             return new SqlJoin(joinType.getParserPosition(), | 
 |                 e, | 
 |                 natural, | 
 |                 joinType, | 
 |                 e2, | 
 |                 on, | 
 |                 condition); | 
 |         } | 
 |     | | 
 |         <USING> { using = JoinConditionType.USING.symbol(getPos()); } | 
 |         list = ParenthesizedSimpleIdentifierList() { | 
 |             return new SqlJoin(joinType.getParserPosition(), | 
 |                 e, | 
 |                 natural, | 
 |                 joinType, | 
 |                 e2, | 
 |                 using, | 
 |                 new SqlNodeList(list, Span.of(using).end(this))); | 
 |         } | 
 |     | | 
 |         { | 
 |             return new SqlJoin(joinType.getParserPosition(), | 
 |                 e, | 
 |                 natural, | 
 |                 joinType, | 
 |                 e2, | 
 |                 JoinConditionType.NONE.symbol(joinType.getParserPosition()), | 
 |                 null); | 
 |         } | 
 |     ) | 
 | | | 
 |     <CROSS> { joinType = JoinType.CROSS.symbol(getPos()); } <APPLY> | 
 |     e2 = TableRef2(true) { | 
 |         if (!this.conformance.isApplyAllowed()) { | 
 |             throw SqlUtil.newContextException(getPos(), RESOURCE.applyNotAllowed()); | 
 |         } | 
 |         return new SqlJoin(joinType.getParserPosition(), | 
 |             e, | 
 |             SqlLiteral.createBoolean(false, joinType.getParserPosition()), | 
 |             joinType, | 
 |             e2, | 
 |             JoinConditionType.NONE.symbol(SqlParserPos.ZERO), | 
 |             null); | 
 |     } | 
 | | | 
 |     <OUTER> { joinType = JoinType.LEFT.symbol(getPos()); } <APPLY> | 
 |     e2 = TableRef2(true) { | 
 |         if (!this.conformance.isApplyAllowed()) { | 
 |             throw SqlUtil.newContextException(getPos(), RESOURCE.applyNotAllowed()); | 
 |         } | 
 |         return new SqlJoin(joinType.getParserPosition(), | 
 |             e, | 
 |             SqlLiteral.createBoolean(false, joinType.getParserPosition()), | 
 |             joinType, | 
 |             e2, | 
 |             JoinConditionType.ON.symbol(SqlParserPos.ZERO), | 
 |             SqlLiteral.createBoolean(true, joinType.getParserPosition())); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a table reference in a FROM clause, not lateral unless LATERAL | 
 |  * is explicitly specified. | 
 |  */ | 
 | SqlNode TableRef() : | 
 | { | 
 |     final SqlNode e; | 
 | } | 
 | { | 
 |     e = TableRef3(ExprContext.ACCEPT_QUERY, false) { return e; } | 
 | } | 
 |  | 
 | SqlNode TableRef1(ExprContext exprContext) : | 
 | { | 
 |     final SqlNode e; | 
 | } | 
 | { | 
 |     e = TableRef3(exprContext, false) { return e; } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a table reference in a FROM clause. | 
 |  */ | 
 | SqlNode TableRef2(boolean lateral) : | 
 | { | 
 |     final SqlNode e; | 
 | } | 
 | { | 
 |     e = TableRef3(ExprContext.ACCEPT_QUERY, lateral) { return e; } | 
 | } | 
 |  | 
 | SqlNode TableRef3(ExprContext exprContext, boolean lateral) : | 
 | { | 
 |     final SqlIdentifier tableName; | 
 |     SqlNode tableRef; | 
 |     final SqlIdentifier alias; | 
 |     final Span s; | 
 |     SqlNodeList args; | 
 |     final SqlNodeList columnAliasList; | 
 |     SqlUnnestOperator unnestOp = SqlStdOperatorTable.UNNEST; | 
 | } | 
 | { | 
 |     ( | 
 |         LOOKAHEAD(2) | 
 |         tableName = CompoundTableIdentifier() { s = span(); } | 
 |         ( | 
 |             // Table call syntax like FROM a.b() instead of FROM TABLE(a.b()) | 
 |             // Three tokens needed to disambiguate EXTEND syntax from CALCITE-493. | 
 |             // Example: "FROM EventLog(lastGCTime TIME)". | 
 |             LOOKAHEAD(3) | 
 |             tableRef = ImplicitTableFunctionCallArgs(tableName) | 
 |         | | 
 |             ( tableRef = TableHints(tableName) | { tableRef = tableName; } ) | 
 |             [ tableRef = ExtendTable(tableRef) ] | 
 |             tableRef = Over(tableRef) | 
 |             [ tableRef = Snapshot(tableRef) ] | 
 |             [ tableRef = MatchRecognize(tableRef) ] | 
 |         ) | 
 |     | | 
 |         LOOKAHEAD(2) | 
 |         [ <LATERAL> { lateral = true; } ] | 
 |         tableRef = ParenthesizedExpression(exprContext) | 
 |         tableRef = Over(tableRef) | 
 |         tableRef = addLateral(tableRef, lateral) | 
 |         [ tableRef = MatchRecognize(tableRef) ] | 
 |     | | 
 |         <UNNEST> { s = span(); } | 
 |         args = ParenthesizedQueryOrCommaList(ExprContext.ACCEPT_SUB_QUERY) | 
 |         [ | 
 |             <WITH> <ORDINALITY> { | 
 |                 unnestOp = SqlStdOperatorTable.UNNEST_WITH_ORDINALITY; | 
 |             } | 
 |         ] | 
 |         { | 
 |             tableRef = unnestOp.createCall(s.end(this), (List<SqlNode>) args); | 
 |         } | 
 |     | | 
 |         [ <LATERAL> { lateral = true; } ] | 
 |         tableRef = TableFunctionCall() | 
 |         tableRef = addLateral(tableRef, lateral) | 
 |     | | 
 |         tableRef = ExtendedTableRef() | 
 |     ) | 
 |     [ | 
 |         LOOKAHEAD(2) | 
 |         tableRef = Pivot(tableRef) | 
 |     ] | 
 |     [ | 
 |         LOOKAHEAD(2) | 
 |         tableRef = Unpivot(tableRef) | 
 |     ] | 
 |     [ | 
 |         [ <AS> ] alias = SimpleIdentifier() | 
 |         ( | 
 |             columnAliasList = ParenthesizedSimpleIdentifierList() | 
 |         |   { columnAliasList = null; } | 
 |         ) | 
 |         { | 
 |             // Standard SQL (and Postgres) allow applying "AS alias" to a JOIN, | 
 |             // e.g. "FROM (a CROSS JOIN b) AS c". The new alias obscures the | 
 |             // internal aliases, and columns cannot be referenced if they are | 
 |             // not unique. TODO: Support this behavior; see | 
 |             // [CALCITE-5168] Allow AS after parenthesized JOIN | 
 |             checkNotJoin(tableRef); | 
 |             if (columnAliasList == null) { | 
 |                 tableRef = SqlStdOperatorTable.AS.createCall( | 
 |                     Span.of(tableRef).end(this), tableRef, alias); | 
 |             } else { | 
 |                 List<SqlNode> idList = new ArrayList<SqlNode>(); | 
 |                 idList.add(tableRef); | 
 |                 idList.add(alias); | 
 |                 idList.addAll(columnAliasList.getList()); | 
 |                 tableRef = SqlStdOperatorTable.AS.createCall( | 
 |                     Span.of(tableRef).end(this), idList); | 
 |             } | 
 |         } | 
 |     ] | 
 |     [ tableRef = Tablesample(tableRef) ] | 
 |     { return tableRef; } | 
 | } | 
 |  | 
 | SqlNode Tablesample(SqlNode tableRef) : | 
 | { | 
 |     final Span s; | 
 |     final SqlNode sample; | 
 |     final boolean isBernoulli; | 
 |     final SqlNumericLiteral samplePercentage; | 
 |     boolean isRepeatable = false; | 
 |     int repeatableSeed = 0; | 
 | } | 
 | { | 
 |     <TABLESAMPLE> { s = span(); checkNotJoin(tableRef); } | 
 |     ( | 
 |         <SUBSTITUTE> <LPAREN> sample = StringLiteral() <RPAREN> | 
 |         { | 
 |             String sampleName = | 
 |                 SqlLiteral.unchain(sample).getValueAs(String.class); | 
 |             SqlSampleSpec sampleSpec = SqlSampleSpec.createNamed(sampleName); | 
 |             final SqlLiteral sampleLiteral = | 
 |                 SqlLiteral.createSample(sampleSpec, s.end(this)); | 
 |             return SqlStdOperatorTable.TABLESAMPLE.createCall( | 
 |                 s.add(tableRef).end(this), tableRef, sampleLiteral); | 
 |         } | 
 |     | | 
 |         ( | 
 |             <BERNOULLI> { isBernoulli = true; } | 
 |         | | 
 |             <SYSTEM> { isBernoulli = false; } | 
 |         ) | 
 |         <LPAREN> samplePercentage = UnsignedNumericLiteral() <RPAREN> | 
 |         [ | 
 |             <REPEATABLE> <LPAREN> repeatableSeed = IntLiteral() <RPAREN> | 
 |             { | 
 |                 isRepeatable = true; | 
 |             } | 
 |         ] | 
 |         { | 
 |             BigDecimal rate = | 
 |                 samplePercentage.bigDecimalValue().divide(ONE_HUNDRED); | 
 |             SqlSampleSpec tableSampleSpec = | 
 |                 isRepeatable | 
 |                     ? SqlSampleSpec.createTableSample(isBernoulli, rate, | 
 |                         repeatableSeed) | 
 |                     : SqlSampleSpec.createTableSample(isBernoulli, rate); | 
 |             SqlLiteral tableSampleLiteral = | 
 |                 SqlLiteral.createSample(tableSampleSpec, s.end(this)); | 
 |             return SqlStdOperatorTable.TABLESAMPLE.createCall( | 
 |                 s.end(this), tableRef, tableSampleLiteral); | 
 |         } | 
 |     ) | 
 | } | 
 |  | 
 | /** Wraps a table reference in a call to EXTEND if an optional "EXTEND" clause | 
 |  * is present. */ | 
 | SqlNode ExtendTable(SqlNode tableRef) : | 
 | { | 
 |     final SqlNodeList extendList; | 
 | } | 
 | { | 
 |     [ <EXTEND> ] | 
 |     extendList = ExtendList() { | 
 |         return extend(tableRef, extendList); | 
 |     } | 
 | } | 
 |  | 
 | SqlNodeList ExtendList() : | 
 | { | 
 |     final Span s; | 
 |     List<SqlNode> list = new ArrayList<SqlNode>(); | 
 | } | 
 | { | 
 |     <LPAREN> { s = span(); } | 
 |     AddColumnType(list) | 
 |     ( | 
 |         <COMMA> AddColumnType(list) | 
 |     )* | 
 |     <RPAREN> { | 
 |         return new SqlNodeList(list, s.end(this)); | 
 |     } | 
 | } | 
 |  | 
 | void AddColumnType(List<SqlNode> list) : | 
 | { | 
 |     final SqlIdentifier name; | 
 |     final SqlDataTypeSpec type; | 
 |     final boolean nullable; | 
 | } | 
 | { | 
 |     name = CompoundIdentifier() | 
 |     type = DataType() | 
 |     nullable = NotNullOpt() | 
 |     { | 
 |         list.add(name); | 
 |         list.add(type.withNullable(nullable, getPos())); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a compound identifier with optional type. | 
 |  */ | 
 | void AddCompoundIdentifierType(List<SqlNode> list, List<SqlNode> extendList) : | 
 | { | 
 |     final SqlIdentifier name; | 
 |     final SqlDataTypeSpec type; | 
 |     final boolean nullable; | 
 | } | 
 | { | 
 |     name = CompoundIdentifier() | 
 |     ( | 
 |         type = DataType() | 
 |         nullable = NotNullOpt() | 
 |     | | 
 |         { type = null; nullable = true; } | 
 |     ) | 
 |     { | 
 |         if (type != null) { | 
 |             if (!this.conformance.allowExtend()) { | 
 |                 throw SqlUtil.newContextException(type.getParserPosition(), | 
 |                     RESOURCE.extendNotAllowed()); | 
 |             } | 
 |             extendList.add(name); | 
 |             extendList.add(type.withNullable(nullable, getPos())); | 
 |         } | 
 |         list.add(name); | 
 |     } | 
 | } | 
 |  | 
 | SqlNode ImplicitTableFunctionCallArgs(SqlIdentifier name) : | 
 | { | 
 |     final List<SqlNode> tableFuncArgs = new ArrayList<SqlNode>(); | 
 |     final SqlNode call; | 
 |     final Span s; | 
 | } | 
 | { | 
 |     // Table call syntax like FROM a.b() instead of FROM TABLE(a.b()) | 
 |     // We've already parsed the name, so we don't use NamedRoutineCall. | 
 |     { s = span(); } | 
 |     <LPAREN> | 
 |     [ | 
 |         AddArg0(tableFuncArgs, ExprContext.ACCEPT_CURSOR) | 
 |         ( | 
 |             <COMMA> { | 
 |                 // a comma-list can't appear where only a query is expected | 
 |                 checkNonQueryExpression(ExprContext.ACCEPT_CURSOR); | 
 |             } | 
 |             AddArg(tableFuncArgs, ExprContext.ACCEPT_CURSOR) | 
 |         )* | 
 |     ] | 
 |     <RPAREN> | 
 |     { | 
 |         final SqlParserPos pos = s.end(this); | 
 |         call = createCall(name, pos, | 
 |             SqlFunctionCategory.USER_DEFINED_TABLE_FUNCTION, null, | 
 |             tableFuncArgs); | 
 |         return SqlStdOperatorTable.COLLECTION_TABLE.createCall(pos, | 
 |             call); | 
 |     } | 
 | } | 
 |  | 
 | SqlNode TableFunctionCall() : | 
 | { | 
 |     final Span s; | 
 |     final SqlNode call; | 
 |     SqlFunctionCategory funcType = SqlFunctionCategory.USER_DEFINED_TABLE_FUNCTION; | 
 | } | 
 | { | 
 |     <TABLE> { s = span(); } <LPAREN> | 
 |     [ | 
 |         <SPECIFIC> | 
 |         { | 
 |             funcType = SqlFunctionCategory.USER_DEFINED_TABLE_SPECIFIC_FUNCTION; | 
 |         } | 
 |     ] | 
 |     call = NamedRoutineCall(funcType, ExprContext.ACCEPT_CURSOR) | 
 |     <RPAREN> | 
 |     { | 
 |         return SqlStdOperatorTable.COLLECTION_TABLE.createCall(s.end(this), call); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Abstract production: | 
 |  *    SqlNode ExtendedTableRef() | 
 |  * | 
 |  * <p>Allows parser to be extended with new types of table references.  The | 
 |  * default implementation of this production is empty. | 
 |  */ | 
 |  | 
 | /* | 
 |  * Abstract production: | 
 |  * | 
 |  *    SqlNode TableOverOpt() | 
 |  * | 
 |  * Allows an OVER clause following a table expression as an extension to | 
 |  * standard SQL syntax. The default implementation of this production is empty. | 
 |  */ | 
 |  | 
 | /** | 
 |  * Parses an explicit TABLE t reference. | 
 |  */ | 
 | SqlNode ExplicitTable(SqlParserPos pos) : | 
 | { | 
 |     SqlNode tableRef; | 
 | } | 
 | { | 
 |     <TABLE> tableRef = CompoundIdentifier() | 
 |     { | 
 |         return SqlStdOperatorTable.EXPLICIT_TABLE.createCall(pos, tableRef); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a VALUES leaf query expression. | 
 |  */ | 
 | SqlNode TableConstructor() : | 
 | { | 
 |     final List<SqlNode> list = new ArrayList<SqlNode>(); | 
 |     final Span s; | 
 | } | 
 | { | 
 |     ( | 
 |         <VALUES> { s = span(); } | 
 |     | | 
 |         <VALUE> | 
 |         { | 
 |             s = span(); | 
 |             if (!this.conformance.isValueAllowed()) { | 
 |                 throw SqlUtil.newContextException(getPos(), RESOURCE.valueNotAllowed()); | 
 |             } | 
 |         } | 
 |     ) | 
 |     AddRowConstructor(list) | 
 |     ( | 
 |         LOOKAHEAD(2) | 
 |         <COMMA> AddRowConstructor(list) | 
 |     )* | 
 |     { | 
 |         return SqlStdOperatorTable.VALUES.createCall(s.end(this), list); | 
 |     } | 
 | } | 
 |  | 
 | /** Parses a row constructor and adds it to a list. */ | 
 | void AddRowConstructor(List<SqlNode> list) : | 
 | { | 
 |     SqlNode e; | 
 | } | 
 | { | 
 |     e = RowConstructor() { list.add(e); } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a row constructor in the context of a VALUES expression. | 
 |  */ | 
 | SqlNode RowConstructor() : | 
 | { | 
 |     final SqlNodeList valueList; | 
 |     final SqlNode value; | 
 |     final Span s; | 
 | } | 
 | { | 
 |     // hints are necessary here due to common LPAREN prefixes | 
 |     ( | 
 |         // TODO jvs 8-Feb-2004: extra parentheses are accepted here as a hack | 
 |         // for unparse, but this is actually invalid SQL; should | 
 |         // fix unparse | 
 |         LOOKAHEAD(3) | 
 |         <LPAREN> { s = span(); } | 
 |         <ROW> | 
 |         valueList = ParenthesizedQueryOrCommaListWithDefault(ExprContext.ACCEPT_NONCURSOR) | 
 |         <RPAREN> { s.add(this); } | 
 |     | | 
 |         LOOKAHEAD(3) | 
 |         ( | 
 |             <ROW> { s = span(); } | 
 |         | | 
 |             { s = Span.of(); } | 
 |         ) | 
 |         valueList = ParenthesizedQueryOrCommaListWithDefault(ExprContext.ACCEPT_NONCURSOR) | 
 |     | | 
 |         value = Expression(ExprContext.ACCEPT_NONCURSOR) | 
 |         { | 
 |             // NOTE: A bare value here is standard SQL syntax, believe it or | 
 |             // not.  Taken together with multi-row table constructors, it leads | 
 |             // to very easy mistakes if you forget the parentheses on a | 
 |             // single-row constructor.  This is also the reason for the | 
 |             // LOOKAHEAD in TableConstructor().  It would be so much more | 
 |             // reasonable to require parentheses.  Sigh. | 
 |             s = Span.of(value); | 
 |             valueList = new SqlNodeList(ImmutableList.of(value), | 
 |                 value.getParserPosition()); | 
 |         } | 
 |     ) | 
 |     { | 
 |         // REVIEW jvs 8-Feb-2004: Should we discriminate between scalar | 
 |         // sub-queries inside of ROW and row sub-queries?  The standard does, | 
 |         // but the distinction seems to be purely syntactic. | 
 |         return SqlStdOperatorTable.ROW.createCall(s.end(valueList), | 
 |             (List<SqlNode>) valueList); | 
 |     } | 
 | } | 
 |  | 
 | /** Parses a WHERE clause for SELECT, DELETE, and UPDATE. */ | 
 | SqlNode Where() : | 
 | { | 
 |     SqlNode condition; | 
 | } | 
 | { | 
 |     <WHERE> condition = Expression(ExprContext.ACCEPT_SUB_QUERY) { | 
 |         return condition; | 
 |     } | 
 | } | 
 |  | 
 | /** Parses a GROUP BY clause for SELECT. */ | 
 | SqlNodeList GroupBy() : | 
 | { | 
 |     final List<SqlNode> list; | 
 |     final boolean distinct; | 
 |     final Span s; | 
 | } | 
 | { | 
 |     <GROUP> { s = span(); } | 
 |     <BY> | 
 |     ( | 
 |         <DISTINCT> { distinct = true; } | 
 |     |   <ALL> { distinct = false; } | 
 |     |   { distinct = false; } | 
 |     ) | 
 |     list = GroupingElementList() { | 
 |         final SqlParserPos pos = s.end(this); | 
 |         final List<SqlNode> list2 = distinct | 
 |             ? ImmutableList.of( | 
 |                 SqlInternalOperators.GROUP_BY_DISTINCT.createCall(pos, list)) | 
 |             : list; | 
 |         return new SqlNodeList(list2, pos); | 
 |     } | 
 | } | 
 |  | 
 | List<SqlNode> GroupingElementList() : | 
 | { | 
 |     final List<SqlNode> list = new ArrayList<SqlNode>(); | 
 | } | 
 | { | 
 |     AddGroupingElement(list) | 
 |     ( LOOKAHEAD(2) <COMMA> AddGroupingElement(list) )* | 
 |     { return list; } | 
 | } | 
 |  | 
 | void AddGroupingElement(List<SqlNode> list) : | 
 | { | 
 |     final List<SqlNode> subList; | 
 |     final SqlNodeList nodes; | 
 |     final Span s; | 
 | } | 
 | { | 
 |     LOOKAHEAD(2) | 
 |     <GROUPING> { s = span(); } | 
 |     <SETS> <LPAREN> subList = GroupingElementList() <RPAREN> { | 
 |         list.add( | 
 |             SqlStdOperatorTable.GROUPING_SETS.createCall(s.end(this), subList)); | 
 |     } | 
 | |   <ROLLUP> { s = span(); } | 
 |     <LPAREN> nodes = ExpressionCommaList(s, ExprContext.ACCEPT_SUB_QUERY) | 
 |     <RPAREN> { | 
 |         list.add( | 
 |             SqlStdOperatorTable.ROLLUP.createCall(s.end(this), nodes.getList())); | 
 |     } | 
 | |   <CUBE> { s = span(); } | 
 |     <LPAREN> nodes = ExpressionCommaList(s, ExprContext.ACCEPT_SUB_QUERY) | 
 |     <RPAREN> { | 
 |         list.add( | 
 |             SqlStdOperatorTable.CUBE.createCall(s.end(this), nodes.getList())); | 
 |     } | 
 | |   LOOKAHEAD(3) | 
 |     <LPAREN> { s = span(); } <RPAREN> { | 
 |         list.add(new SqlNodeList(s.end(this))); | 
 |     } | 
 | |   AddExpression(list, ExprContext.ACCEPT_SUB_QUERY) | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a list of expressions separated by commas. | 
 |  */ | 
 | SqlNodeList ExpressionCommaList( | 
 |     final Span s, | 
 |     ExprContext exprContext) : | 
 | { | 
 |     final List<SqlNode> list = new ArrayList<SqlNode>(); | 
 | } | 
 | { | 
 |     AddExpressions(list, exprContext) { | 
 |         return new SqlNodeList(list, s.addAll(list).pos()); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a list of expressions separated by commas, | 
 |  * appending expressions to a given list. | 
 |  */ | 
 | void AddExpressions(List<SqlNode> list, ExprContext exprContext) : | 
 | { | 
 | } | 
 | { | 
 |     AddExpression(list, exprContext) | 
 |     ( | 
 |         // NOTE jvs 6-Feb-2004:  See comments at top of file for why | 
 |         // hint is necessary here. | 
 |         LOOKAHEAD(2) | 
 |         <COMMA> AddExpression(list, ExprContext.ACCEPT_SUB_QUERY) | 
 |     )* | 
 | } | 
 |  | 
 | /** Parses a HAVING clause for SELECT. */ | 
 | SqlNode Having() : | 
 | { | 
 |     SqlNode e; | 
 | } | 
 | { | 
 |     <HAVING> e = Expression(ExprContext.ACCEPT_SUB_QUERY) { return e; } | 
 | } | 
 |  | 
 | /** Parses a WINDOW clause for SELECT. */ | 
 | SqlNodeList Window() : | 
 | { | 
 |     final List<SqlNode> list = new ArrayList<SqlNode>(); | 
 |     final Span s; | 
 | } | 
 | { | 
 |     <WINDOW> { s = span(); } | 
 |     AddWindowSpec(list) | 
 |     ( | 
 |         LOOKAHEAD(2) | 
 |         <COMMA> AddWindowSpec(list) | 
 |     )* | 
 |     { | 
 |         return new SqlNodeList(list, s.addAll(list).pos()); | 
 |     } | 
 | } | 
 |  | 
 | void AddWindowSpec(List<SqlNode> list) : | 
 | { | 
 |     final SqlIdentifier id; | 
 |     final SqlWindow e; | 
 | } | 
 | { | 
 |     id = SimpleIdentifier() <AS> e = WindowSpecification() { | 
 |         e.setDeclName(id); | 
 |         list.add(e); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a window specification. | 
 |  */ | 
 | SqlWindow WindowSpecification() : | 
 | { | 
 |     final SqlIdentifier id; | 
 |     final SqlNodeList partitionList; | 
 |     final SqlNodeList orderList; | 
 |     final SqlLiteral isRows; | 
 |     final SqlNode lowerBound, upperBound; | 
 |     final Span s, s1, s2; | 
 |     final SqlLiteral allowPartial; | 
 | } | 
 | { | 
 |     <LPAREN> { s = span(); } | 
 |     ( | 
 |         id = SimpleIdentifier() | 
 |     |   { id = null; } | 
 |     ) | 
 |     ( | 
 |         <PARTITION> { s1 = span(); } | 
 |         <BY> | 
 |         partitionList = ExpressionCommaList(s1, ExprContext.ACCEPT_NON_QUERY) | 
 |     |   { partitionList = SqlNodeList.EMPTY; } | 
 |     ) | 
 |     ( | 
 |         orderList = OrderBy(true) | 
 |     |   { orderList = SqlNodeList.EMPTY; } | 
 |     ) | 
 |     ( | 
 |         ( | 
 |             <ROWS> { isRows = SqlLiteral.createBoolean(true, getPos()); } | 
 |         | | 
 |             <RANGE> { isRows = SqlLiteral.createBoolean(false, getPos()); } | 
 |         ) | 
 |         ( | 
 |             <BETWEEN> lowerBound = WindowRange() | 
 |             <AND> upperBound = WindowRange() | 
 |         | | 
 |             lowerBound = WindowRange() | 
 |             { upperBound = null; } | 
 |         ) | 
 |     | | 
 |         { | 
 |             isRows = SqlLiteral.createBoolean(false, SqlParserPos.ZERO); | 
 |             lowerBound = upperBound = null; | 
 |         } | 
 |     ) | 
 |     ( | 
 |         <ALLOW> { s2 = span(); } <PARTIAL> { | 
 |             allowPartial = SqlLiteral.createBoolean(true, s2.end(this)); | 
 |         } | 
 |     | | 
 |         <DISALLOW> { s2 = span(); } <PARTIAL> { | 
 |             allowPartial = SqlLiteral.createBoolean(false, s2.end(this)); | 
 |         } | 
 |     |   { allowPartial = null; } | 
 |     ) | 
 |     <RPAREN> | 
 |     { | 
 |         return SqlWindow.create(null, id, partitionList, orderList, | 
 |             isRows, lowerBound, upperBound, allowPartial, s.end(this)); | 
 |     } | 
 | } | 
 |  | 
 | SqlNode WindowRange() : | 
 | { | 
 |     final SqlNode e; | 
 |     final Span s; | 
 | } | 
 | { | 
 |     LOOKAHEAD(2) | 
 |     <CURRENT> { s = span(); } <ROW> { | 
 |         return SqlWindow.createCurrentRow(s.end(this)); | 
 |     } | 
 | | | 
 |     LOOKAHEAD(2) | 
 |     <UNBOUNDED> { s = span(); } | 
 |     ( | 
 |         <PRECEDING> { | 
 |             return SqlWindow.createUnboundedPreceding(s.end(this)); | 
 |         } | 
 |     | | 
 |         <FOLLOWING> { | 
 |             return SqlWindow.createUnboundedFollowing(s.end(this)); | 
 |         } | 
 |     ) | 
 | | | 
 |     e = Expression(ExprContext.ACCEPT_NON_QUERY) | 
 |     ( | 
 |         <PRECEDING> { | 
 |             return SqlWindow.createPreceding(e, getPos()); | 
 |         } | 
 |     | | 
 |         <FOLLOWING> { | 
 |             return SqlWindow.createFollowing(e, getPos()); | 
 |         } | 
 |     ) | 
 | } | 
 |  | 
 | /** Parses a QUALIFY clause for SELECT. */ | 
 | SqlNode Qualify() : | 
 | { | 
 |     SqlNode e; | 
 | } | 
 | { | 
 |     <QUALIFY> e = Expression(ExprContext.ACCEPT_SUB_QUERY) { return e; } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses an ORDER BY clause. | 
 |  */ | 
 | SqlNodeList OrderBy(boolean accept) : | 
 | { | 
 |     final List<SqlNode> list = new ArrayList<SqlNode>(); | 
 |     final Span s; | 
 | } | 
 | { | 
 |     <ORDER> { | 
 |         s = span(); | 
 |         if (!accept) { | 
 |             // Someone told us ORDER BY wasn't allowed here.  So why | 
 |             // did they bother calling us?  To get the correct | 
 |             // parser position for error reporting. | 
 |             throw SqlUtil.newContextException(s.pos(), RESOURCE.illegalOrderBy()); | 
 |         } | 
 |     } | 
 |     <BY> AddOrderItem(list) | 
 |     ( | 
 |         // NOTE jvs 6-Feb-2004:  See comments at top of file for why | 
 |         // hint is necessary here. | 
 |         LOOKAHEAD(2) <COMMA> AddOrderItem(list) | 
 |     )* | 
 |     { | 
 |         return new SqlNodeList(list, s.addAll(list).pos()); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses one item in an ORDER BY clause, and adds it to a list. | 
 |  */ | 
 | void AddOrderItem(List<SqlNode> list) : | 
 | { | 
 |     SqlNode e; | 
 | } | 
 | { | 
 |     e = Expression(ExprContext.ACCEPT_SUB_QUERY) | 
 |     ( | 
 |         <ASC> | 
 |     |   <DESC> { | 
 |             e = SqlStdOperatorTable.DESC.createCall(getPos(), e); | 
 |         } | 
 |     )? | 
 |     ( | 
 |         LOOKAHEAD(2) | 
 |         <NULLS> <FIRST> { | 
 |             e = SqlStdOperatorTable.NULLS_FIRST.createCall(getPos(), e); | 
 |         } | 
 |     | | 
 |         <NULLS> <LAST> { | 
 |             e = SqlStdOperatorTable.NULLS_LAST.createCall(getPos(), e); | 
 |         } | 
 |     )? | 
 |     { | 
 |         list.add(e); | 
 |     } | 
 | } | 
 |  | 
 | /** Wraps a table reference in a call to OVER if an optional "OVER" clause | 
 |  * is present (if the dialect supports OVER for table expressions). */ | 
 | SqlNode Over(SqlNode tableRef) : | 
 | { | 
 |     final SqlNode over; | 
 | } | 
 | { | 
 |     over = TableOverOpt() { | 
 |         if (over != null) { | 
 |             return SqlStdOperatorTable.OVER.createCall( | 
 |                 getPos(), checkNotJoin(tableRef), over); | 
 |         } else { | 
 |             return tableRef; | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | /** Wraps a table reference in a call to LATERAL if {@code lateral} is true. */ | 
 | JAVACODE SqlNode addLateral(SqlNode tableRef, boolean lateral) { | 
 |     return lateral | 
 |         ? SqlStdOperatorTable.LATERAL.createCall(getPos(), | 
 |             checkNotJoin(tableRef)) | 
 |         : tableRef; | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a FOR SYSTEM_TIME clause following a table expression. | 
 |  */ | 
 | SqlSnapshot Snapshot(SqlNode tableRef) : | 
 | { | 
 |     final Span s; | 
 |     final SqlNode e; | 
 | } | 
 | { | 
 |     { s = span(); } <FOR> <SYSTEM_TIME> <AS> <OF> | 
 |     // Syntax for temporal table in | 
 |     // standard SQL 2011 IWD 9075-2:201?(E) 7.6 <table reference> | 
 |     // supports grammar as following: | 
 |     // 1. datetime literal | 
 |     // 2. datetime value function, i.e. CURRENT_TIMESTAMP | 
 |     // 3. datetime term in 1 or 2 +(or -) interval term | 
 |  | 
 |     // We extend to support column reference, use Expression | 
 |     // to simplify the parsing code. | 
 |     e = Expression(ExprContext.ACCEPT_NON_QUERY) { | 
 |         return new SqlSnapshot(s.end(this), tableRef, e); | 
 |     } | 
 | } | 
 |  | 
 | /** Parses a PIVOT clause following a table expression. */ | 
 | SqlNode Pivot(SqlNode tableRef) : | 
 | { | 
 |     final Span s; | 
 |     final Span s2; | 
 |     final List<SqlNode> aggList = new ArrayList<SqlNode>(); | 
 |     final List<SqlNode> valueList = new ArrayList<SqlNode>(); | 
 |     final SqlNodeList axisList; | 
 |     final SqlNodeList inList; | 
 | } | 
 | { | 
 |     <PIVOT> { s = span(); checkNotJoin(tableRef); } | 
 |     <LPAREN> | 
 |     AddPivotAgg(aggList) ( <COMMA> AddPivotAgg(aggList) )* | 
 |     <FOR> axisList = SimpleIdentifierOrList() | 
 |     <IN> <LPAREN> { s2 = span(); } | 
 |     [ AddPivotValue(valueList) ( <COMMA> AddPivotValue(valueList) )* ] | 
 |     <RPAREN> { | 
 |         inList = new SqlNodeList(valueList, s2.end(this)); | 
 |     } | 
 |     <RPAREN> | 
 |     { | 
 |         return new SqlPivot(s.end(this), tableRef, | 
 |             new SqlNodeList(aggList, SqlParserPos.sum(aggList)), | 
 |             axisList, inList); | 
 |     } | 
 | } | 
 |  | 
 | void AddPivotAgg(List<SqlNode> list) : | 
 | { | 
 |     final SqlNode e; | 
 |     final SqlIdentifier alias; | 
 | } | 
 | { | 
 |     e = NamedFunctionCall() | 
 |     ( | 
 |         // Because babel put FOR into non-reserved keyword set. | 
 |         LOOKAHEAD({getToken(1).kind != COMMA && getToken(1).kind != FOR}) | 
 |         [ <AS> ] alias = SimpleIdentifier() { | 
 |             list.add( | 
 |                 SqlStdOperatorTable.AS.createCall(Span.of(e).end(this), e, | 
 |                     alias)); | 
 |         } | 
 |     | | 
 |         { list.add(e); } | 
 |     ) | 
 | } | 
 |  | 
 | void AddPivotValue(List<SqlNode> list) : | 
 | { | 
 |     final SqlNode e; | 
 |     final SqlNodeList tuple; | 
 |     final SqlIdentifier alias; | 
 | } | 
 | { | 
 |     e = RowConstructor() { tuple = SqlParserUtil.stripRow(e); } | 
 |     ( | 
 |         [ <AS> ] alias = SimpleIdentifier() { | 
 |             list.add( | 
 |                 SqlStdOperatorTable.AS.createCall(Span.of(tuple).end(this), | 
 |                     tuple, alias)); | 
 |         } | 
 |     | | 
 |         { list.add(tuple); } | 
 |     ) | 
 | } | 
 |  | 
 | /** Parses an UNPIVOT clause following a table expression. */ | 
 | SqlNode Unpivot(SqlNode tableRef) : | 
 | { | 
 |     final Span s; | 
 |     final boolean includeNulls; | 
 |     final SqlNodeList measureList; | 
 |     final SqlNodeList axisList; | 
 |     final Span s2; | 
 |     final List<SqlNode> values = new ArrayList<SqlNode>(); | 
 |     final SqlNodeList inList; | 
 | } | 
 | { | 
 |     <UNPIVOT> { s = span(); checkNotJoin(tableRef); } | 
 |     ( | 
 |         <INCLUDE> <NULLS> { includeNulls = true; } | 
 |     |   <EXCLUDE> <NULLS> { includeNulls = false; } | 
 |     |   { includeNulls = false; } | 
 |     ) | 
 |     <LPAREN> | 
 |     measureList = SimpleIdentifierOrList() | 
 |     <FOR> axisList = SimpleIdentifierOrList() | 
 |     <IN> | 
 |     <LPAREN> { s2 = span(); } | 
 |     AddUnpivotValue(values) ( <COMMA> AddUnpivotValue(values) )* | 
 |     <RPAREN> | 
 |     { inList = new SqlNodeList(values, s2.end(this)); } | 
 |     <RPAREN> { | 
 |         return new SqlUnpivot(s.end(this), tableRef, includeNulls, measureList, | 
 |             axisList, inList); | 
 |     } | 
 | } | 
 |  | 
 | void AddUnpivotValue(List<SqlNode> list) : | 
 | { | 
 |     final SqlNodeList columnList; | 
 |     final SqlNode values; | 
 | } | 
 | { | 
 |     columnList = SimpleIdentifierOrList() | 
 |     ( | 
 |         <AS> values = RowConstructor() { | 
 |             final SqlNodeList valueList = SqlParserUtil.stripRow(values); | 
 |             list.add( | 
 |                 SqlStdOperatorTable.AS.createCall(Span.of(columnList).end(this), | 
 |                     columnList, valueList)); | 
 |         } | 
 |     | | 
 |         { list.add(columnList); } | 
 |     ) | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a MATCH_RECOGNIZE clause following a table expression. | 
 |  */ | 
 | SqlMatchRecognize MatchRecognize(SqlNode tableRef) : | 
 | { | 
 |     final Span s, s0, s1, s2; | 
 |     final SqlNodeList measureList; | 
 |     final SqlNodeList partitionList; | 
 |     final SqlNodeList orderList; | 
 |     final SqlNode pattern; | 
 |     final SqlLiteral interval; | 
 |     final SqlNodeList patternDefList; | 
 |     final SqlNode after; | 
 |     final SqlNode var; | 
 |     final SqlLiteral rowsPerMatch; | 
 |     final SqlNodeList subsetList; | 
 |     final SqlLiteral isStrictStarts; | 
 |     final SqlLiteral isStrictEnds; | 
 | } | 
 | { | 
 |     <MATCH_RECOGNIZE> { s = span(); checkNotJoin(tableRef); } <LPAREN> | 
 |     ( | 
 |         <PARTITION> { s2 = span(); } <BY> | 
 |         partitionList = ExpressionCommaList(s2, ExprContext.ACCEPT_NON_QUERY) | 
 |     | | 
 |         { partitionList = SqlNodeList.EMPTY; } | 
 |     ) | 
 |     ( | 
 |         orderList = OrderBy(true) | 
 |     | | 
 |         { orderList = SqlNodeList.EMPTY; } | 
 |     ) | 
 |     ( | 
 |         <MEASURES> | 
 |         measureList = MeasureColumnCommaList(span()) | 
 |     | | 
 |         { measureList = SqlNodeList.EMPTY; } | 
 |     ) | 
 |     ( | 
 |         <ONE> { s0 = span(); } <ROW> <PER> <MATCH> { | 
 |             rowsPerMatch = SqlMatchRecognize.RowsPerMatchOption.ONE_ROW.symbol(s0.end(this)); | 
 |         } | 
 |     | | 
 |         <ALL> { s0 = span(); } <ROWS> <PER> <MATCH> { | 
 |             rowsPerMatch = SqlMatchRecognize.RowsPerMatchOption.ALL_ROWS.symbol(s0.end(this)); | 
 |         } | 
 |     |   { rowsPerMatch = null; } | 
 |     ) | 
 |     ( | 
 |         <AFTER> { s1 = span(); } <MATCH> <SKIP_> | 
 |         ( | 
 |             <TO> | 
 |             ( | 
 |                 LOOKAHEAD(2) | 
 |                 <NEXT> <ROW> { | 
 |                     after = SqlMatchRecognize.AfterOption.SKIP_TO_NEXT_ROW | 
 |                         .symbol(s1.end(this)); | 
 |                 } | 
 |             | | 
 |                 LOOKAHEAD(2) | 
 |                 <FIRST> var = SimpleIdentifier() { | 
 |                     after = SqlMatchRecognize.SKIP_TO_FIRST.createCall( | 
 |                         s1.end(var), var); | 
 |                 } | 
 |             | | 
 |                 // This "LOOKAHEAD({true})" is a workaround for Babel. | 
 |                 // Because of babel parser uses option "LOOKAHEAD=2" globally, | 
 |                 // JavaCC generates something like "LOOKAHEAD(2, [<LAST>] SimpleIdentifier())" | 
 |                 // here. But the correct LOOKAHEAD should be | 
 |                 // "LOOKAHEAD(2, [ LOOKAHEAD(2, <LAST> SimpleIdentifier()) <LAST> ] | 
 |                 // SimpleIdentifier())" which have the syntactic lookahead for <LAST> considered. | 
 |                 // | 
 |                 // Overall LOOKAHEAD({true}) is even better as this is the last branch in the | 
 |                 // choice. | 
 |                 LOOKAHEAD({true}) | 
 |                 [ LOOKAHEAD(2, <LAST> SimpleIdentifier()) <LAST> ] var = SimpleIdentifier() { | 
 |                     after = SqlMatchRecognize.SKIP_TO_LAST.createCall( | 
 |                         s1.end(var), var); | 
 |                 } | 
 |             ) | 
 |         | | 
 |             <PAST> <LAST> <ROW> { | 
 |                  after = SqlMatchRecognize.AfterOption.SKIP_PAST_LAST_ROW | 
 |                      .symbol(s1.end(this)); | 
 |             } | 
 |         ) | 
 |     |   { after = null; } | 
 |     ) | 
 |     <PATTERN> | 
 |     <LPAREN> | 
 |     ( | 
 |         <CARET> { isStrictStarts = SqlLiteral.createBoolean(true, getPos()); } | 
 |     |   { isStrictStarts = SqlLiteral.createBoolean(false, getPos()); } | 
 |     ) | 
 |     pattern = PatternExpression() | 
 |     ( | 
 |         <DOLLAR> { isStrictEnds = SqlLiteral.createBoolean(true, getPos()); } | 
 |     |   { isStrictEnds = SqlLiteral.createBoolean(false, getPos()); } | 
 |     ) | 
 |     <RPAREN> | 
 |     ( | 
 |         <WITHIN> interval = IntervalLiteral() | 
 |     |   { interval = null; } | 
 |     ) | 
 |     ( | 
 |         <SUBSET> subsetList = SubsetDefinitionCommaList(span()) | 
 |     |   { subsetList = SqlNodeList.EMPTY; } | 
 |     ) | 
 |     <DEFINE> | 
 |     patternDefList = PatternDefinitionCommaList(span()) | 
 |     <RPAREN> { | 
 |         return new SqlMatchRecognize(s.end(this), tableRef, | 
 |             pattern, isStrictStarts, isStrictEnds, patternDefList, measureList, | 
 |             after, subsetList, rowsPerMatch, partitionList, orderList, interval); | 
 |     } | 
 | } | 
 |  | 
 | SqlNodeList MeasureColumnCommaList(Span s) : | 
 | { | 
 |     final List<SqlNode> list = new ArrayList<SqlNode>(); | 
 | } | 
 | { | 
 |     AddMeasureColumn(list) | 
 |     ( <COMMA> AddMeasureColumn(list) )* | 
 |     { return new SqlNodeList(list, s.addAll(list).pos()); } | 
 | } | 
 |  | 
 | void AddMeasureColumn(List<SqlNode> list) : | 
 | { | 
 |     final SqlNode e; | 
 |     final SqlIdentifier alias; | 
 | } | 
 | { | 
 |     e = Expression(ExprContext.ACCEPT_NON_QUERY) | 
 |     <AS> | 
 |     alias = SimpleIdentifier() { | 
 |         list.add(SqlStdOperatorTable.AS.createCall(Span.of(e).end(this), e, alias)); | 
 |     } | 
 | } | 
 |  | 
 | SqlNode PatternExpression() : | 
 | { | 
 |     SqlNode left; | 
 |     SqlNode right; | 
 | } | 
 | { | 
 |     left = PatternTerm() | 
 |     ( | 
 |         <VERTICAL_BAR> | 
 |         right = PatternTerm() { | 
 |             left = SqlStdOperatorTable.PATTERN_ALTER.createCall( | 
 |                 Span.of(left).end(right), left, right); | 
 |         } | 
 |     )* | 
 |     { | 
 |         return left; | 
 |     } | 
 | } | 
 |  | 
 | SqlNode PatternTerm() : | 
 | { | 
 |     SqlNode left; | 
 |     SqlNode right; | 
 | } | 
 | { | 
 |     left = PatternFactor() | 
 |     ( | 
 |         right = PatternFactor() { | 
 |             left = SqlStdOperatorTable.PATTERN_CONCAT.createCall( | 
 |                 Span.of(left).end(right), left, right); | 
 |         } | 
 |     )* | 
 |     { | 
 |         return left; | 
 |     } | 
 | } | 
 |  | 
 | SqlNode PatternFactor() : | 
 | { | 
 |     final SqlNode e; | 
 |     final SqlNode extra; | 
 |     final SqlLiteral startNum; | 
 |     final SqlLiteral endNum; | 
 |     final SqlLiteral reluctant; | 
 | } | 
 | { | 
 |     e = PatternPrimary() | 
 |     ( | 
 |         LOOKAHEAD(1) | 
 |         ( | 
 |             <STAR> { | 
 |                 startNum = LITERAL_ZERO; | 
 |                 endNum = LITERAL_MINUS_ONE; | 
 |             } | 
 |         | | 
 |             <PLUS> { | 
 |                 startNum = LITERAL_ONE; | 
 |                 endNum = LITERAL_MINUS_ONE; | 
 |             } | 
 |         | | 
 |             <HOOK> { | 
 |                 startNum = LITERAL_ZERO; | 
 |                 endNum = LITERAL_ONE; | 
 |             } | 
 |         | | 
 |             <LBRACE> | 
 |             ( | 
 |                 startNum = UnsignedNumericLiteral() | 
 |                 ( | 
 |                     <COMMA> | 
 |                     ( | 
 |                         endNum = UnsignedNumericLiteral() | 
 |                     | | 
 |                         { endNum = LITERAL_MINUS_ONE; } | 
 |                     ) | 
 |                 | | 
 |                      { endNum = startNum; } | 
 |                 ) | 
 |                 <RBRACE> | 
 |             | | 
 |                 <COMMA> | 
 |                 endNum = UnsignedNumericLiteral() | 
 |                 <RBRACE> | 
 |                 { startNum = LITERAL_MINUS_ONE; } | 
 |             | | 
 |                 <MINUS> extra = PatternExpression() <MINUS> <RBRACE> { | 
 |                     return SqlStdOperatorTable.PATTERN_CONCAT.createCall( | 
 |                         Span.of(e).end(this), e, | 
 |                         SqlStdOperatorTable.PATTERN_EXCLUDE.createCall( | 
 |                             Span.of(extra).end(this), extra)); | 
 |                 } | 
 |             ) | 
 |         ) | 
 |         ( | 
 |             <HOOK> { | 
 |                 reluctant = SqlLiteral.createBoolean( | 
 |                     startNum.intValue(true) != endNum.intValue(true), | 
 |                     SqlParserPos.ZERO); | 
 |             } | 
 |         | | 
 |             { reluctant = SqlLiteral.createBoolean(false, SqlParserPos.ZERO); } | 
 |         ) | 
 |     | | 
 |         { return e; } | 
 |     ) | 
 |     { | 
 |         return SqlStdOperatorTable.PATTERN_QUANTIFIER.createCall( | 
 |             span().end(e), e, startNum, endNum, reluctant); | 
 |     } | 
 | } | 
 |  | 
 | SqlNode PatternPrimary() : | 
 | { | 
 |     final Span s; | 
 |     SqlNode e; | 
 |     final List<SqlNode> list; | 
 | } | 
 | { | 
 |     e = SimpleIdentifier() { return e; } | 
 | | | 
 |     <LPAREN> e = PatternExpression() <RPAREN> { return e; } | 
 | | | 
 |     <LBRACE> { s = span(); } | 
 |     <MINUS> e = PatternExpression() | 
 |     <MINUS> <RBRACE> { | 
 |         return SqlStdOperatorTable.PATTERN_EXCLUDE.createCall(s.end(this), e); | 
 |     } | 
 | | | 
 |     ( | 
 |         <PERMUTE> { s = span(); list = new ArrayList<SqlNode>(); } | 
 |         <LPAREN> | 
 |         e = PatternExpression() { list.add(e); } | 
 |         ( <COMMA> e = PatternExpression() { list.add(e); } )* | 
 |         <RPAREN> { | 
 |             return SqlStdOperatorTable.PATTERN_PERMUTE.createCall( | 
 |                 s.end(this), list); | 
 |         } | 
 |     ) | 
 | } | 
 |  | 
 | SqlNodeList SubsetDefinitionCommaList(Span s) : | 
 | { | 
 |     final List<SqlNode> list = new ArrayList<SqlNode>(); | 
 | } | 
 | { | 
 |     AddSubsetDefinition(list) | 
 |     ( <COMMA> AddSubsetDefinition(list) )* | 
 |     { return new SqlNodeList(list, s.addAll(list).pos()); } | 
 | } | 
 |  | 
 | void AddSubsetDefinition(List<SqlNode> list) : | 
 | { | 
 |     final SqlNode var; | 
 |     final SqlNodeList varList; | 
 | } | 
 | { | 
 |     var = SimpleIdentifier() | 
 |     <EQ> | 
 |     <LPAREN> | 
 |     varList = ExpressionCommaList(span(), ExprContext.ACCEPT_NON_QUERY) | 
 |     <RPAREN> { | 
 |         list.add( | 
 |             SqlStdOperatorTable.EQUALS.createCall(span().end(var), var, | 
 |                 varList)); | 
 |     } | 
 | } | 
 |  | 
 | SqlNodeList PatternDefinitionCommaList(Span s) : | 
 | { | 
 |     SqlNode e; | 
 |     final List<SqlNode> eList = new ArrayList<SqlNode>(); | 
 | } | 
 | { | 
 |     e = PatternDefinition() { | 
 |         eList.add(e); | 
 |     } | 
 |     ( | 
 |         <COMMA> | 
 |         e = PatternDefinition() { | 
 |             eList.add(e); | 
 |         } | 
 |     )* | 
 |     { | 
 |         return new SqlNodeList(eList, s.addAll(eList).pos()); | 
 |     } | 
 | } | 
 |  | 
 | SqlNode PatternDefinition() : | 
 | { | 
 |     final SqlNode var; | 
 |     final SqlNode e; | 
 | } | 
 | { | 
 |     var = SimpleIdentifier() | 
 |     <AS> | 
 |     e = Expression(ExprContext.ACCEPT_SUB_QUERY) { | 
 |         return SqlStdOperatorTable.AS.createCall(Span.of(var, e).pos(), e, var); | 
 |     } | 
 | } | 
 |  | 
 | // ---------------------------------------------------------------------------- | 
 | // Expressions | 
 |  | 
 | /** | 
 |  * Parses a SQL expression (such as might occur in a WHERE clause) followed by | 
 |  * the end-of-file symbol. | 
 |  */ | 
 | SqlNode SqlExpressionEof() : | 
 | { | 
 |     SqlNode e; | 
 | } | 
 | { | 
 |     e = Expression(ExprContext.ACCEPT_SUB_QUERY) (<EOF>) | 
 |     { | 
 |         return e; | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses either a row expression or a query expression without ORDER BY. | 
 |  * | 
 |  * <p>Examples of valid queries: | 
 |  * <ul> | 
 |  * <li>{@code SELECT c FROM t} | 
 |  * <li>{@code SELECT c} (valid in some dialects) | 
 |  * <li>{@code SELECT c FROM t UNION SELECT c2 FROM t2} | 
 |  * <li>{@code WITH q AS (SELECT 1) SELECT * FROM q} | 
 |  * <li>{@code VALUES (1, 2)} | 
 |  * <li>{@code TABLE t} | 
 |  * </ul> | 
 |  * | 
 |  * <p>Non-examples: | 
 |  * <ul> | 
 |  * <li>{@code emp CROSS JOIN dept} | 
 |  * <li>{@code SELECT c FROM t ORDER BY c} | 
 |  * <li>{@code (SELECT c FROM t)} | 
 |  * </ul> | 
 |  */ | 
 | SqlNode QueryOrExpr(ExprContext exprContext) : | 
 | { | 
 |     SqlNodeList withList = null; | 
 |     final SqlNode e; | 
 |     final List<Object> list = new ArrayList<Object>(); | 
 | } | 
 | { | 
 |     [ withList = WithList() ] | 
 |     e = LeafQueryOrExpr(exprContext) { list.add(e); } | 
 |     ( AddSetOpQuery(list, exprContext) )* | 
 |     { return addWith(withList, SqlParserUtil.toTree(list)); } | 
 | } | 
 |  | 
 | SqlNode Query(ExprContext exprContext) : | 
 | { | 
 |     SqlNodeList withList = null; | 
 |     final SqlNode e; | 
 |     final List<Object> list = new ArrayList<Object>(); | 
 | } | 
 | { | 
 |     [ withList = WithList() ] | 
 |     e = LeafQuery(exprContext) { list.add(e); } | 
 |     ( AddSetOpQuery(list, exprContext) )* | 
 |     { return addWith(withList, SqlParserUtil.toTree(list)); } | 
 | } | 
 |  | 
 | JAVACODE SqlNode addWith(SqlNodeList withList, SqlNode e) { | 
 |     return withList == null | 
 |         ? e | 
 |         : new SqlWith(withList.getParserPosition(), withList, e); | 
 | } | 
 |  | 
 | /** Parses a set operator (e.g. UNION or INTERSECT) | 
 |  * followed by a query or expression, | 
 |  * and adds both to {@code list}. */ | 
 | void AddSetOpQueryOrExpr(List<Object> list, ExprContext exprContext) : | 
 | { | 
 |     final SqlOperator op; | 
 |     final SqlParserPos pos; | 
 |     final SqlNode e; | 
 | } | 
 | { | 
 |     { | 
 |         if (list.size() == 1 && !((SqlNode) list.get(0)).isA(SqlKind.QUERY)) { | 
 |             // whoops, expression we just parsed wasn't a query, | 
 |             // but we're about to see something like UNION, so | 
 |             // force an exception retroactively | 
 |             checkNonQueryExpression(ExprContext.ACCEPT_QUERY); | 
 |         } | 
 |     } | 
 |     op = BinaryQueryOperator() { | 
 |         // ensure a query is legal in this context | 
 |         pos = getPos(); | 
 |         checkQueryExpression(exprContext); | 
 |     } | 
 |     e = LeafQueryOrExpr(ExprContext.ACCEPT_QUERY) { | 
 |         list.add(new SqlParserUtil.ToTreeListItem(op, pos)); | 
 |         list.add(e); | 
 |     } | 
 | } | 
 |  | 
 | /** Parses a set operator (e.g. UNION or INTERSECT) | 
 |  * followed by a query, | 
 |  * and adds both to {@code list}. */ | 
 | void AddSetOpQuery(List<Object> list, ExprContext exprContext) : | 
 | { | 
 |     final SqlOperator op; | 
 |     final SqlParserPos pos; | 
 |     final SqlNode e; | 
 | } | 
 | { | 
 |     { | 
 |         if (list.size() == 1 && !((SqlNode) list.get(0)).isA(SqlKind.QUERY)) { | 
 |             // whoops, expression we just parsed wasn't a query, | 
 |             // but we're about to see something like UNION, so | 
 |             // force an exception retroactively | 
 |             checkNonQueryExpression(ExprContext.ACCEPT_QUERY); | 
 |         } | 
 |     } | 
 |     op = BinaryQueryOperator() { | 
 |         // ensure a query is legal in this context | 
 |         pos = getPos(); | 
 |         checkQueryExpression(exprContext); | 
 |     } | 
 |     e = LeafQueryOrExpr(ExprContext.ACCEPT_QUERY) { | 
 |         list.add(new SqlParserUtil.ToTreeListItem(op, pos)); | 
 |         list.add(e); | 
 |     } | 
 | } | 
 |  | 
 | SqlNodeList WithList() : | 
 | { | 
 |     final Span s; | 
 |     final List<SqlWithItem> list = new ArrayList<SqlWithItem>(); | 
 |     boolean recursive = false; | 
 | } | 
 | { | 
 |     <WITH> [ <RECURSIVE> { recursive = true; } ]{ s = span(); } | 
 |     AddWithItem(list, SqlLiteral.createBoolean(recursive, getPos())) | 
 |     ( <COMMA> AddWithItem(list, SqlLiteral.createBoolean(recursive, getPos())) )* | 
 |     { return new SqlNodeList(list, s.end(this)); } | 
 | } | 
 |  | 
 | void AddWithItem(List<SqlWithItem> list, SqlLiteral recursive) : | 
 | { | 
 |     final SqlIdentifier id; | 
 |     final SqlNodeList columnList; | 
 |     final SqlNode definition; | 
 | } | 
 | { | 
 |     id = SimpleIdentifier() | 
 |     ( columnList = ParenthesizedSimpleIdentifierList() | { columnList = null; } ) | 
 |     <AS> | 
 |     definition = ParenthesizedExpression(ExprContext.ACCEPT_QUERY) | 
 |     { list.add(new SqlWithItem(id.getParserPosition(), id, columnList, definition, recursive)); } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses either a row expression, a leaf query expression, or | 
 |  * a parenthesized expression of any kind. | 
 |  */ | 
 | SqlNode LeafQueryOrExpr(ExprContext exprContext) : | 
 | { | 
 |     SqlNode e; | 
 | } | 
 | { | 
 |     e = LeafQuery(exprContext) { return e; } | 
 | | | 
 |     e = Expression(exprContext) { return e; } | 
 | } | 
 |  | 
 | /** As {@link #Expression} but appends to a list. */ | 
 | void AddExpression(List<SqlNode> list, ExprContext exprContext) : | 
 | { | 
 |     final SqlNode e; | 
 | } | 
 | { | 
 |     e = Expression(exprContext) { list.add(e); } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a row expression or a parenthesized expression of any kind. | 
 |  */ | 
 | SqlNode Expression(ExprContext exprContext) : | 
 | { | 
 |     final List<Object> list; | 
 | } | 
 | { | 
 |     list = Expression2(exprContext) { return SqlParserUtil.toTree(list); } | 
 | } | 
 |  | 
 | void AddExpression2b(List<Object> list, ExprContext exprContext) : | 
 | { | 
 |     SqlNode e; | 
 |     SqlOperator op; | 
 |     SqlNode ext; | 
 | } | 
 | { | 
 |     ( | 
 |         LOOKAHEAD(1) | 
 |         op = PrefixRowOperator() { | 
 |             checkNonQueryExpression(exprContext); | 
 |             list.add(new SqlParserUtil.ToTreeListItem(op, getPos())); | 
 |         } | 
 |     )* | 
 |     e = Expression3(exprContext) { | 
 |         list.add(e); | 
 |     } | 
 |     ( | 
 |         LOOKAHEAD(2) <DOT> | 
 |         ext = RowExpressionExtension() { | 
 |             list.add( | 
 |                 new SqlParserUtil.ToTreeListItem( | 
 |                     SqlStdOperatorTable.DOT, getPos())); | 
 |             list.add(ext); | 
 |         } | 
 |     )* | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a binary row expression, or a parenthesized expression of any | 
 |  * kind. | 
 |  * | 
 |  * <p>The result is as a flat list of operators and operands. The top-level | 
 |  * call to get an expression should call {@link #Expression}, but lower-level | 
 |  * calls should call this, to give the parser the opportunity to associate | 
 |  * operator calls. | 
 |  * | 
 |  * <p>For example 'a = b like c = d' should come out '((a = b) like c) = d' | 
 |  * because LIKE and '=' have the same precedence, but tends to come out as '(a | 
 |  * = b) like (c = d)' because (a = b) and (c = d) are parsed as separate | 
 |  * expressions. | 
 |  */ | 
 | List<Object> Expression2(ExprContext exprContext) : | 
 | { | 
 |     final List<Object> list = new ArrayList(); | 
 |     List<Object> list2; | 
 |     final List<Object> list3 = new ArrayList(); | 
 |     SqlNodeList nodeList; | 
 |     SqlNode e; | 
 |     SqlOperator itemOp; | 
 |     SqlOperator op; | 
 |     SqlIdentifier p; | 
 |     final Span s = span(); | 
 | } | 
 | { | 
 |     AddExpression2b(list, exprContext) | 
 |     ( | 
 |         LOOKAHEAD(2) | 
 |         ( | 
 |             LOOKAHEAD(2) | 
 |             ( | 
 |                 // Special case for "IN", because RHS of "IN" is the only place | 
 |                 // that an expression-list is allowed ("exp IN (exp1, exp2)"). | 
 |                 LOOKAHEAD(2) { | 
 |                     checkNonQueryExpression(exprContext); | 
 |                 } | 
 |                 ( | 
 |                     <NOT> <IN> { op = SqlStdOperatorTable.NOT_IN; } | 
 |                 | | 
 |                     <IN> { op = SqlStdOperatorTable.IN; } | 
 |                 | | 
 |                     { final SqlKind k; } | 
 |                     k = comp() | 
 |                     ( | 
 |                         <SOME> { op = SqlStdOperatorTable.some(k); } | 
 |                     | | 
 |                         <ANY> { op = SqlStdOperatorTable.some(k); } | 
 |                     | | 
 |                         <ALL> { op = SqlStdOperatorTable.all(k); } | 
 |                     ) | 
 |                 ) | 
 |                 { s.clear().add(this); } | 
 |                 nodeList = ParenthesizedQueryOrCommaList(ExprContext.ACCEPT_NONCURSOR) | 
 |                 { | 
 |                     list.add(new SqlParserUtil.ToTreeListItem(op, s.pos())); | 
 |                     s.add(nodeList); | 
 |                     // special case for stuff like IN (s1 UNION s2) | 
 |                     if (nodeList.size() == 1) { | 
 |                         SqlNode item = nodeList.get(0); | 
 |                         if (item.isA(SqlKind.QUERY)) { | 
 |                             list.add(item); | 
 |                         } else { | 
 |                             list.add(nodeList); | 
 |                         } | 
 |                     } else { | 
 |                         list.add(nodeList); | 
 |                     } | 
 |                 } | 
 |             | | 
 |                 LOOKAHEAD(2) { | 
 |                     checkNonQueryExpression(exprContext); | 
 |                 } | 
 |                 ( | 
 |                     <NOT> <BETWEEN> { | 
 |                         op = SqlStdOperatorTable.NOT_BETWEEN; | 
 |                         s.clear().add(this); | 
 |                     } | 
 |                     [ | 
 |                         <SYMMETRIC> { op = SqlStdOperatorTable.SYMMETRIC_NOT_BETWEEN; } | 
 |                     | | 
 |                         <ASYMMETRIC> | 
 |                     ] | 
 |                 | | 
 |                     <BETWEEN> | 
 |                     { | 
 |                         op = SqlStdOperatorTable.BETWEEN; | 
 |                         s.clear().add(this); | 
 |                     } | 
 |                     [ | 
 |                         <SYMMETRIC> { op = SqlStdOperatorTable.SYMMETRIC_BETWEEN; } | 
 |                     | | 
 |                         <ASYMMETRIC> | 
 |                     ] | 
 |                 ) | 
 |                 AddExpression2b(list3, ExprContext.ACCEPT_SUB_QUERY) { | 
 |                     list.add(new SqlParserUtil.ToTreeListItem(op, s.pos())); | 
 |                     list.addAll(list3); | 
 |                     list3.clear(); | 
 |                 } | 
 |             | | 
 |                 LOOKAHEAD(2) { | 
 |                     checkNonQueryExpression(exprContext); | 
 |                     s.clear().add(this); | 
 |                 } | 
 |                 ( | 
 |                     ( | 
 |                         <NOT> | 
 |                         ( | 
 |                             <LIKE> { op = SqlStdOperatorTable.NOT_LIKE; } | 
 |                         | | 
 |                             <ILIKE> { op = SqlLibraryOperators.NOT_ILIKE; } | 
 |                         | | 
 |                             <RLIKE> { op = SqlLibraryOperators.NOT_RLIKE; } | 
 |                         | | 
 |                             <SIMILAR> <TO> { op = SqlStdOperatorTable.NOT_SIMILAR_TO; } | 
 |                         ) | 
 |                     | | 
 |                         <LIKE> { op = SqlStdOperatorTable.LIKE; } | 
 |                     | | 
 |                         <ILIKE> { op = SqlLibraryOperators.ILIKE; } | 
 |                     | | 
 |                         <RLIKE> { op = SqlLibraryOperators.RLIKE; } | 
 |                     | | 
 |                         <SIMILAR> <TO> { op = SqlStdOperatorTable.SIMILAR_TO; } | 
 |                     ) | 
 |                 <#if (parser.includePosixOperators!default.parser.includePosixOperators)> | 
 |                 | | 
 |                     <NEGATE> <TILDE> { op = SqlStdOperatorTable.NEGATED_POSIX_REGEX_CASE_SENSITIVE; } | 
 |                     [ <STAR> { op = SqlStdOperatorTable.NEGATED_POSIX_REGEX_CASE_INSENSITIVE; } ] | 
 |                 | | 
 |                     <TILDE> { op = SqlStdOperatorTable.POSIX_REGEX_CASE_SENSITIVE; } | 
 |                     [ <STAR> { op = SqlStdOperatorTable.POSIX_REGEX_CASE_INSENSITIVE; } ] | 
 |                 </#if> | 
 |                 ) | 
 |                 list2 = Expression2(ExprContext.ACCEPT_SUB_QUERY) { | 
 |                     list.add(new SqlParserUtil.ToTreeListItem(op, s.pos())); | 
 |                     list.addAll(list2); | 
 |                 } | 
 |                 [ | 
 |                     LOOKAHEAD(2) | 
 |                     <ESCAPE> e = Expression3(ExprContext.ACCEPT_SUB_QUERY) { | 
 |                         s.clear().add(this); | 
 |                         list.add( | 
 |                             new SqlParserUtil.ToTreeListItem( | 
 |                                 SqlStdOperatorTable.ESCAPE, s.pos())); | 
 |                         list.add(e); | 
 |                     } | 
 |                 ] | 
 |             | | 
 |             <#list (parser.extraBinaryExpressions!default.parser.extraBinaryExpressions) as extra > | 
 |                 ${extra}(list, exprContext, s) | 
 |             | | 
 |             </#list> | 
 |                 LOOKAHEAD(3) op = BinaryRowOperator() { | 
 |                     checkNonQueryExpression(exprContext); | 
 |                     list.add(new SqlParserUtil.ToTreeListItem(op, getPos())); | 
 |                 } | 
 |                 AddExpression2b(list, ExprContext.ACCEPT_SUB_QUERY) | 
 |             | | 
 |                 <LBRACKET> | 
 |                 itemOp = getItemOp() | 
 |                 e = Expression(ExprContext.ACCEPT_SUB_QUERY) | 
 |                 <RBRACKET> { | 
 |                     list.add( | 
 |                         new SqlParserUtil.ToTreeListItem( | 
 |                             itemOp, getPos())); | 
 |                     list.add(e); | 
 |                 } | 
 |                 ( | 
 |                     LOOKAHEAD(2) <DOT> | 
 |                     p = SimpleIdentifier() { | 
 |                         list.add( | 
 |                             new SqlParserUtil.ToTreeListItem( | 
 |                                 SqlStdOperatorTable.DOT, getPos())); | 
 |                         list.add(p); | 
 |                     } | 
 |                 )* | 
 |             | | 
 |                 { | 
 |                     checkNonQueryExpression(exprContext); | 
 |                 } | 
 |                 op = PostfixRowOperator() { | 
 |                     list.add(new SqlParserUtil.ToTreeListItem(op, getPos())); | 
 |                 } | 
 |             ) | 
 |         )+ | 
 |         { | 
 |             return list; | 
 |         } | 
 |     | | 
 |         { | 
 |             return list; | 
 |         } | 
 |     ) | 
 | } | 
 |  | 
 | /** Returns the appropriate ITEM operator for indexing arrays. */ | 
 | SqlOperator getItemOp() : | 
 | { | 
 | } | 
 | { | 
 |     <OFFSET> { return SqlLibraryOperators.OFFSET; } | 
 | | | 
 |     <ORDINAL> { return SqlLibraryOperators.ORDINAL; } | 
 | | | 
 |     <SAFE_OFFSET> { return SqlLibraryOperators.SAFE_OFFSET; } | 
 | | | 
 |     <SAFE_ORDINAL> { return SqlLibraryOperators.SAFE_ORDINAL; } | 
 | | | 
 |     { return SqlStdOperatorTable.ITEM; } | 
 | } | 
 |  | 
 | /** Parses a comparison operator inside a SOME / ALL predicate. */ | 
 | SqlKind comp() : | 
 | { | 
 | } | 
 | { | 
 |     <LT> { return SqlKind.LESS_THAN; } | 
 | | | 
 |     <LE> { return SqlKind.LESS_THAN_OR_EQUAL; } | 
 | | | 
 |     <GT> { return SqlKind.GREATER_THAN; } | 
 | | | 
 |     <GE> { return SqlKind.GREATER_THAN_OR_EQUAL; } | 
 | | | 
 |     <EQ> { return SqlKind.EQUALS; } | 
 | | | 
 |     <NE> { return SqlKind.NOT_EQUALS; } | 
 | | | 
 |     <NE2> { | 
 |         if (!this.conformance.isBangEqualAllowed()) { | 
 |             throw SqlUtil.newContextException(getPos(), RESOURCE.bangEqualNotAllowed()); | 
 |         } | 
 |         return SqlKind.NOT_EQUALS; | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a unary row expression, or a parenthesized expression of any | 
 |  * kind. | 
 |  */ | 
 | SqlNode Expression3(ExprContext exprContext) : | 
 | { | 
 |     final SqlNode e; | 
 |     final SqlNodeList list; | 
 |     final SqlNodeList list1; | 
 |     final Span s; | 
 |     final Span rowSpan; | 
 | } | 
 | { | 
 |     LOOKAHEAD(2) | 
 |     e = AtomicRowExpression() | 
 |     { | 
 |         checkNonQueryExpression(exprContext); | 
 |         return e; | 
 |     } | 
 | | | 
 |     e = CursorExpression(exprContext) { return e; } | 
 | | | 
 |     LOOKAHEAD(3) | 
 |     <ROW> { | 
 |         s = span(); | 
 |     } | 
 |     list = ParenthesizedQueryOrCommaList(exprContext) { | 
 |         if (exprContext != ExprContext.ACCEPT_ALL | 
 |             && exprContext != ExprContext.ACCEPT_CURSOR | 
 |             && !this.conformance.allowExplicitRowValueConstructor()) | 
 |         { | 
 |             throw SqlUtil.newContextException(s.end(list), | 
 |                 RESOURCE.illegalRowExpression()); | 
 |         } | 
 |         return SqlStdOperatorTable.ROW.createCall(list); | 
 |     } | 
 | | | 
 |     ( | 
 |         <ROW> { rowSpan = span(); } | 
 |     |   { rowSpan = null; } | 
 |     ) | 
 |     list1 = ParenthesizedQueryOrCommaList(exprContext) { | 
 |         if (rowSpan != null) { | 
 |             // interpret as row constructor | 
 |             return SqlStdOperatorTable.ROW.createCall(rowSpan.end(list1), | 
 |                 (List<SqlNode>) list1); | 
 |         } | 
 |     } | 
 |     [ | 
 |         LOOKAHEAD(2) | 
 |         /* TODO: | 
 |         ( | 
 |             op = periodOperator() | 
 |             list2 = ParenthesizedQueryOrCommaList(exprContext) | 
 |             { | 
 |                 if (list1.size() != 2 || list2.size() != 2) { | 
 |                     throw SqlUtil.newContextException( | 
 |                         list1.getParserPosition().plus( | 
 |                             list2.getParserPosition()), | 
 |                         RESOURCE.illegalOverlaps()); | 
 |                 } | 
 |                 for (SqlNode node : list2) { | 
 |                     list1.add(node); | 
 |                 } | 
 |                 return op.createCall( | 
 |                     list1.getParserPosition().plus(list2.getParserPosition()), | 
 |                     list1.toArray()); | 
 |             } | 
 |         ) | 
 |     | | 
 |         */ | 
 |         ( | 
 |             e = IntervalQualifier() | 
 |             { | 
 |                 if ((list1.size() == 1) | 
 |                     && list1.get(0) instanceof SqlCall) | 
 |                 { | 
 |                     final SqlCall call = (SqlCall) list1.get(0); | 
 |                     if (call.getKind() == SqlKind.MINUS | 
 |                             && call.operandCount() == 2) { | 
 |                         return SqlStdOperatorTable.MINUS_DATE.createCall( | 
 |                             Span.of(list1).end(this), call.operand(0), | 
 |                             call.operand(1), e); | 
 |                      } | 
 |                 } | 
 |                 throw SqlUtil.newContextException(span().end(list1), | 
 |                     RESOURCE.illegalMinusDate()); | 
 |             } | 
 |         ) | 
 |     ] | 
 |     { | 
 |         if (list1.size() == 1) { | 
 |             // interpret as single value or query | 
 |             return list1.get(0); | 
 |         } else { | 
 |             // interpret as row constructor | 
 |             return SqlStdOperatorTable.ROW.createCall(span().end(list1), | 
 |                 (List<SqlNode>) list1); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a lambda expression. | 
 |  */ | 
 | SqlNode LambdaExpression() : | 
 | { | 
 |     final SqlNodeList parameters; | 
 |     final SqlNode expression; | 
 |     final Span s; | 
 | } | 
 | { | 
 |     parameters = SimpleIdentifierOrListOrEmpty() | 
 |     <LAMBDA> { s = span(); } | 
 |     expression = Expression(ExprContext.ACCEPT_NON_QUERY) | 
 |     { | 
 |         return new SqlLambda(s.end(this), parameters, expression); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * List of simple identifiers in parentheses or empty parentheses or one simple identifier. | 
 |  * <ul>Examples: | 
 |  * <li>{@code ()} | 
 |  * <li>{@code DEPTNO} | 
 |  * <li>{@code (EMPNO, DEPTNO)} | 
 |  * </ul> | 
 |  */ | 
 | SqlNodeList SimpleIdentifierOrListOrEmpty() : | 
 | { | 
 |     SqlNodeList list; | 
 | } | 
 | { | 
 |     LOOKAHEAD(2) | 
 |     <LPAREN> <RPAREN> { return SqlNodeList.EMPTY; } | 
 | | | 
 |     list = SimpleIdentifierOrList() { return list; } | 
 | } | 
 |  | 
 | SqlOperator periodOperator() : | 
 | { | 
 | } | 
 | { | 
 |      <OVERLAPS> { return SqlStdOperatorTable.OVERLAPS; } | 
 | | | 
 |      LOOKAHEAD(2) | 
 |      <IMMEDIATELY> <PRECEDES> { return SqlStdOperatorTable.IMMEDIATELY_PRECEDES; } | 
 | | | 
 |      <PRECEDES> { return SqlStdOperatorTable.PRECEDES; } | 
 | | | 
 |      <IMMEDIATELY> <SUCCEEDS> { return SqlStdOperatorTable.IMMEDIATELY_SUCCEEDS; } | 
 | | | 
 |      <SUCCEEDS> { return SqlStdOperatorTable.SUCCEEDS; } | 
 | | | 
 |      <EQUALS> { return SqlStdOperatorTable.PERIOD_EQUALS; } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a COLLATE clause | 
 |  */ | 
 | SqlCollation CollateClause() : | 
 | { | 
 | } | 
 | { | 
 |     <COLLATE> <COLLATION_ID> | 
 |     { | 
 |         return new SqlCollation( | 
 |             getToken(0).image, SqlCollation.Coercibility.EXPLICIT); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Numeric literal or parameter; used in LIMIT, OFFSET and FETCH clauses. | 
 |  */ | 
 | SqlNode UnsignedNumericLiteralOrParam() : | 
 | { | 
 |     final SqlNode e; | 
 | } | 
 | { | 
 |     ( | 
 |         e = UnsignedNumericLiteral() | 
 |     | | 
 |         e = DynamicParam() | 
 |     ) | 
 |     { return e; } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a row expression extension, it can be either an identifier, | 
 |  * or a call to a named function. | 
 |  */ | 
 | SqlNode RowExpressionExtension() : | 
 | { | 
 |     final SqlFunctionCategory funcType = SqlFunctionCategory.USER_DEFINED_FUNCTION; | 
 |     final SqlIdentifier p; | 
 |     final Span s; | 
 |     final List<SqlNode> args; | 
 |     final SqlLiteral quantifier; | 
 | } | 
 | { | 
 |     p = SimpleIdentifier() | 
 |     ( | 
 |         LOOKAHEAD( <LPAREN> ) { s = span(); } | 
 |         ( | 
 |             LOOKAHEAD(2) <LPAREN> <STAR> { | 
 |                 quantifier = null; | 
 |                 args = ImmutableList.of(SqlIdentifier.star(getPos())); | 
 |             } | 
 |             <RPAREN> | 
 |         | | 
 |             LOOKAHEAD(2) <LPAREN> <RPAREN> { | 
 |                 quantifier = null; | 
 |                 args = ImmutableList.of(); | 
 |             } | 
 |         | | 
 |             args = FunctionParameterList(ExprContext.ACCEPT_SUB_QUERY) { | 
 |                 quantifier = (SqlLiteral) args.get(0); | 
 |                 args.remove(0); | 
 |             } | 
 |         ) | 
 |         { return createCall(p, s.end(this), funcType, quantifier, args); } | 
 |     | | 
 |         { return p; } | 
 |     ) | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a call to the STRING_AGG aggregate function (or to an aggregate | 
 |  * function with similar syntax: ARRAY_AGG, ARRAY_CONCAT_AGG, GROUP_CONCAT). | 
 |  */ | 
 | SqlCall StringAggFunctionCall() : | 
 | { | 
 |     final Span s, s2; | 
 |     final SqlOperator op; | 
 |     final List<SqlNode> args = new ArrayList<SqlNode>(); | 
 |     final SqlLiteral qualifier; | 
 |     final SqlNodeList orderBy; | 
 |     final Pair<SqlParserPos, SqlOperator> nullTreatment; | 
 |     final SqlNode separator; | 
 | } | 
 | { | 
 |     ( | 
 |         <ARRAY_AGG> { s = span(); op = SqlLibraryOperators.ARRAY_AGG; } | 
 |     |   <ARRAY_CONCAT_AGG> { s = span(); op = SqlLibraryOperators.ARRAY_CONCAT_AGG; } | 
 |     |   <GROUP_CONCAT> { s = span(); op = SqlLibraryOperators.GROUP_CONCAT; } | 
 |     |   <STRING_AGG> { s = span(); op = SqlLibraryOperators.STRING_AGG; } | 
 |     ) | 
 |     <LPAREN> | 
 |     ( | 
 |         qualifier = AllOrDistinct() | 
 |     |   { qualifier = null; } | 
 |     ) | 
 |     AddArg(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     ( | 
 |         <COMMA> { | 
 |             // a comma-list can't appear where only a query is expected | 
 |             // TODO: the following line is a no-op; remove it? | 
 |             checkNonQueryExpression(ExprContext.ACCEPT_SUB_QUERY); | 
 |         } | 
 |         AddArg(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     )* | 
 |     ( | 
 |         nullTreatment = NullTreatment() | 
 |     |   { nullTreatment = null; } | 
 |     ) | 
 |     [ | 
 |         orderBy = OrderBy(true) { | 
 |             args.add(orderBy); | 
 |         } | 
 |     ] | 
 |     [ | 
 |         <SEPARATOR> { s2 = span(); } separator = StringLiteral() { | 
 |             args.add(SqlInternalOperators.SEPARATOR.createCall(s2.end(this), separator)); | 
 |         } | 
 |     ] | 
 |     <RPAREN> | 
 |     { | 
 |         SqlCall call = op.createCall(qualifier, s.end(this), args); | 
 |         if (nullTreatment != null) { | 
 |             // Wrap in RESPECT_NULLS or IGNORE_NULLS. | 
 |             call = nullTreatment.right.createCall(nullTreatment.left, call); | 
 |         } | 
 |         return call; | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses both the standard and the BigQuery PERCENTILE_CONT/PERCENTILE_DISC | 
 |  * functions. | 
 |  * | 
 |  * <p>The standard is of the form "PERCENTILE_CONT(fraction)" while BigQuery is | 
 |  * of the form "PERCENTILE_CONT(value, fraction [ {RESPECT | IGNORE} NULLS ] )". | 
 |  * Handles the parsing of the operator and its operands but not the WITHIN GROUP | 
 |  * (for the standard) or OVER (for BigQuery) clauses. | 
 |  */ | 
 | SqlCall PercentileFunctionCall() : | 
 | { | 
 |    final Span s; | 
 |    SqlOperator op; | 
 |    final SqlNode e; | 
 |    final List<SqlNode> args = new ArrayList<SqlNode>(); | 
 |    final Pair<SqlParserPos, SqlOperator> nullTreatment; | 
 | } | 
 | { | 
 |    ( | 
 |        <PERCENTILE_CONT> { op = SqlStdOperatorTable.PERCENTILE_CONT; } | 
 |    |   <PERCENTILE_DISC> { op = SqlStdOperatorTable.PERCENTILE_DISC; } | 
 |    ) | 
 |    { s = span(); } | 
 |    <LPAREN> | 
 |    AddArg(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |    ( | 
 |        <RPAREN> { | 
 |            return op.createCall(s.end(this), args); | 
 |        } | 
 |    | | 
 |        <COMMA> | 
 |        e = NumericLiteral() { args.add(e); } | 
 |        ( | 
 |            nullTreatment = NullTreatment() | 
 |        |   { nullTreatment = null; } | 
 |        ) | 
 |        <RPAREN> | 
 |        { | 
 |            op = | 
 |                op == SqlStdOperatorTable.PERCENTILE_CONT | 
 |                    ? SqlLibraryOperators.PERCENTILE_CONT2 | 
 |                    : SqlLibraryOperators.PERCENTILE_DISC2; | 
 |            SqlCall call = op.createCall(s.end(this), args); | 
 |            if (nullTreatment != null) { | 
 |                // Wrap in RESPECT_NULLS or IGNORE_NULLS. | 
 |                call = nullTreatment.right.createCall(nullTreatment.left, call); | 
 |            } | 
 |            return call; | 
 |        } | 
 |    ) | 
 | } | 
 |  | 
 |  | 
 | /** | 
 |  * Parses an atomic row expression. | 
 |  */ | 
 | SqlNode AtomicRowExpression() : | 
 | { | 
 |     final SqlNode e; | 
 | } | 
 | { | 
 |     ( | 
 |         LOOKAHEAD(2) | 
 |         e = LiteralOrIntervalExpression() | 
 |     | | 
 |         e = DynamicParam() | 
 |     | | 
 |         LOOKAHEAD(2) | 
 |         e = BuiltinFunctionCall() | 
 |     | | 
 |         e = JdbcFunctionCall() | 
 |     | | 
 |         e = MultisetConstructor() | 
 |     | | 
 |         e = ArrayConstructor() | 
 |     | | 
 |         LOOKAHEAD(3) | 
 |         e = MapConstructor() | 
 |     | | 
 |         e = PeriodConstructor() | 
 |     | | 
 |         // NOTE jvs 18-Jan-2005:  use syntactic lookahead to discriminate | 
 |         // compound identifiers from function calls in which the function | 
 |         // name is a compound identifier | 
 |         LOOKAHEAD( [<SPECIFIC>] FunctionName() <LPAREN>) | 
 |         e = NamedFunctionCall() | 
 |     | | 
 |         e = ContextVariable() | 
 |     | | 
 |         e = CompoundIdentifier() | 
 |     | | 
 |         e = NewSpecification() | 
 |     | | 
 |         e = CaseExpression() | 
 |     | | 
 |         e = SequenceExpression() | 
 |     ) | 
 |     { return e; } | 
 | } | 
 |  | 
 | SqlNode CaseExpression() : | 
 | { | 
 |     final Span whenSpan = Span.of(); | 
 |     final Span thenSpan = Span.of(); | 
 |     final Span s; | 
 |     SqlNode e; | 
 |     final SqlNode caseIdentifier; | 
 |     final SqlNode elseClause; | 
 |     final List<SqlNode> whenList = new ArrayList<SqlNode>(); | 
 |     final List<SqlNode> thenList = new ArrayList<SqlNode>(); | 
 | } | 
 | { | 
 |     <CASE> { s = span(); } | 
 |     ( | 
 |         caseIdentifier = Expression(ExprContext.ACCEPT_SUB_QUERY) | 
 |     |   { caseIdentifier = null; } | 
 |     ) | 
 |     ( | 
 |         <WHEN> { whenSpan.add(this); } | 
 |         e = ExpressionCommaList(s, ExprContext.ACCEPT_SUB_QUERY) { | 
 |             if (((SqlNodeList) e).size() == 1) { | 
 |                 e = ((SqlNodeList) e).get(0); | 
 |             } | 
 |             whenList.add(e); | 
 |         } | 
 |         <THEN> { thenSpan.add(this); } | 
 |         e = Expression(ExprContext.ACCEPT_SUB_QUERY) { | 
 |             thenList.add(e); | 
 |         } | 
 |     )+ | 
 |     ( | 
 |         <ELSE> elseClause = Expression(ExprContext.ACCEPT_SUB_QUERY) | 
 |     |   { elseClause = null; } | 
 |     ) | 
 |     <END> { | 
 |         return SqlCase.createSwitched(s.end(this), caseIdentifier, | 
 |             new SqlNodeList(whenList, whenSpan.addAll(whenList).pos()), | 
 |             new SqlNodeList(thenList, thenSpan.addAll(thenList).pos()), | 
 |             elseClause); | 
 |     } | 
 | } | 
 |  | 
 | SqlCall SequenceExpression() : | 
 | { | 
 |     final Span s; | 
 |     final SqlOperator f; | 
 |     final SqlNode sequenceRef; | 
 | } | 
 | { | 
 |     ( | 
 |         <NEXT> { f = SqlStdOperatorTable.NEXT_VALUE; s = span(); } | 
 |     | | 
 |         LOOKAHEAD(3) | 
 |         <CURRENT> { f = SqlStdOperatorTable.CURRENT_VALUE; s = span(); } | 
 |     ) | 
 |     <VALUE> <FOR> sequenceRef = CompoundIdentifier() { | 
 |         return f.createCall(s.end(sequenceRef), sequenceRef); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses "SET <NAME> = VALUE" or "RESET <NAME>", without a leading | 
 |  * "ALTER <SCOPE>". | 
 |  */ | 
 | SqlSetOption SqlSetOption(Span s, String scope) : | 
 | { | 
 |     SqlIdentifier name; | 
 |     final SqlNode val; | 
 | } | 
 | { | 
 |     ( | 
 |         <SET> { | 
 |             s.add(this); | 
 |         } | 
 |         name = CompoundIdentifier() | 
 |         <EQ> | 
 |         ( | 
 |             val = Literal() | 
 |         | | 
 |             val = SimpleIdentifier() | 
 |         | | 
 |             <ON> { | 
 |                 // OFF is handled by SimpleIdentifier, ON handled here. | 
 |                 val = new SqlIdentifier(token.image.toUpperCase(Locale.ROOT), | 
 |                     getPos()); | 
 |             } | 
 |         ) | 
 |         { | 
 |             return new SqlSetOption(s.end(val), scope, name, val); | 
 |         } | 
 |     | | 
 |         <RESET> { | 
 |             s.add(this); | 
 |         } | 
 |         ( | 
 |             name = CompoundIdentifier() | 
 |         | | 
 |             <ALL> { | 
 |                 name = new SqlIdentifier(token.image.toUpperCase(Locale.ROOT), | 
 |                     getPos()); | 
 |             } | 
 |         ) | 
 |         { | 
 |             return new SqlSetOption(s.end(name), scope, name, null); | 
 |         } | 
 |     ) | 
 | } | 
 |  | 
 | /** | 
 |  * Parses an expression for setting or resetting an option in SQL, such as QUOTED_IDENTIFIERS, | 
 |  * or explain plan level (physical/logical). | 
 |  */ | 
 | SqlAlter SqlAlter() : | 
 | { | 
 |     final Span s; | 
 |     final String scope; | 
 |     final SqlAlter alterNode; | 
 | } | 
 | { | 
 |     <ALTER> { s = span(); } | 
 |     scope = Scope() | 
 |     ( | 
 | <#-- additional literal parser methods are included here --> | 
 | <#list (parser.alterStatementParserMethods!default.parser.alterStatementParserMethods) as method> | 
 |         alterNode = ${method}(s, scope) | 
 |     | | 
 | </#list> | 
 |  | 
 |         alterNode = SqlSetOption(s, scope) | 
 |     ) | 
 |     { | 
 |         return alterNode; | 
 |     } | 
 | } | 
 |  | 
 | String Scope() : | 
 | { | 
 | } | 
 | { | 
 |     ( <SYSTEM> | <SESSION> ) { return token.image.toUpperCase(Locale.ROOT); } | 
 | } | 
 |  | 
 | <#if (parser.createStatementParserMethods!default.parser.createStatementParserMethods)?size != 0> | 
 | /** | 
 |  * Parses a CREATE statement. | 
 |  */ | 
 | SqlCreate SqlCreate() : | 
 | { | 
 |     final Span s; | 
 |     boolean replace = false; | 
 |     final SqlCreate create; | 
 | } | 
 | { | 
 |     <CREATE> { s = span(); } | 
 |     [ | 
 |         <OR> <REPLACE> { | 
 |             replace = true; | 
 |         } | 
 |     ] | 
 |     ( | 
 | <#-- additional literal parser methods are included here --> | 
 | <#list (parser.createStatementParserMethods!default.parser.createStatementParserMethods) as method> | 
 |         create = ${method}(s, replace) | 
 |         <#sep>| LOOKAHEAD(2) </#sep> | 
 | </#list> | 
 |     ) | 
 |     { | 
 |         return create; | 
 |     } | 
 | } | 
 | </#if> | 
 |  | 
 | <#if (parser.dropStatementParserMethods!default.parser.dropStatementParserMethods)?size != 0> | 
 | /** | 
 |  * Parses a DROP statement. | 
 |  */ | 
 | SqlDrop SqlDrop() : | 
 | { | 
 |     final Span s; | 
 |     boolean replace = false; | 
 |     final SqlDrop drop; | 
 | } | 
 | { | 
 |     <DROP> { s = span(); } | 
 |     ( | 
 | <#-- additional literal parser methods are included here --> | 
 | <#list (parser.dropStatementParserMethods!default.parser.dropStatementParserMethods) as method> | 
 |         drop = ${method}(s, replace) | 
 |         <#sep>|</#sep> | 
 | </#list> | 
 |     ) | 
 |     { | 
 |         return drop; | 
 |     } | 
 | } | 
 | </#if> | 
 |  | 
 | <#if (parser.truncateStatementParserMethods!default.parser.truncateStatementParserMethods)?size != 0> | 
 | /** | 
 |  * Parses a TRUNCATE statement. | 
 |  */ | 
 | SqlTruncate SqlTruncate() : | 
 | { | 
 |     final Span s; | 
 |     final SqlTruncate truncate; | 
 | } | 
 | { | 
 |     <TRUNCATE> { s = span(); } | 
 |     ( | 
 | <#-- additional literal parser methods are included here --> | 
 | <#list (parser.truncateStatementParserMethods!default.parser.truncateStatementParserMethods) as method> | 
 |         truncate = ${method}(s) | 
 |         <#sep>|</#sep> | 
 | </#list> | 
 |     ) | 
 |     { | 
 |         return truncate; | 
 |     } | 
 | } | 
 | </#if> | 
 |  | 
 | /** | 
 |  * Parses a literal expression, allowing continued string literals. | 
 |  * Usually returns an SqlLiteral, but a continued string literal | 
 |  * is an SqlCall expression, which concatenates 2 or more string | 
 |  * literals; the validator reduces this. | 
 |  * | 
 |  * <p>If the context allows both literals and expressions, | 
 |  * use {@link #LiteralOrIntervalExpression}, which requires less | 
 |  * lookahead. | 
 |  */ | 
 | SqlNode Literal() : | 
 | { | 
 |     SqlNode e; | 
 | } | 
 | { | 
 |     ( | 
 |         e = NonIntervalLiteral() | 
 |     | | 
 |         e = IntervalLiteral() | 
 |     ) | 
 |     { return e; } | 
 | } | 
 |  | 
 | /** Parses a literal that is not an interval literal. */ | 
 | SqlNode NonIntervalLiteral() : | 
 | { | 
 |     final SqlNode e; | 
 | } | 
 | { | 
 |     ( | 
 |         e = NumericLiteral() | 
 |     | | 
 |         e = StringLiteral() | 
 |     | | 
 |         e = SpecialLiteral() | 
 |     | | 
 |         e = DateTimeLiteral() | 
 | <#-- additional literal parser methods are included here --> | 
 | <#list (parser.literalParserMethods!default.parser.literalParserMethods) as method> | 
 |     | | 
 |         e = ${method} | 
 | </#list> | 
 |     ) | 
 |     { | 
 |         return e; | 
 |     } | 
 | } | 
 |  | 
 | /** Parses a literal or an interval expression. | 
 |  * | 
 |  * <p>We include them in the same production because it is difficult to | 
 |  * distinguish interval literals from interval expression (both of which | 
 |  * start with the {@code INTERVAL} keyword); this way, we can use less | 
 |  * LOOKAHEAD. */ | 
 | SqlNode LiteralOrIntervalExpression() : | 
 | { | 
 |     final SqlNode e; | 
 | } | 
 | { | 
 |     ( | 
 |         e = IntervalLiteralOrExpression() | 
 |     | | 
 |         e = NonIntervalLiteral() | 
 |     ) | 
 |     { return e; } | 
 | } | 
 |  | 
 | /** Parses a unsigned numeric literal */ | 
 | SqlNumericLiteral UnsignedNumericLiteral() : | 
 | { | 
 | final String p; | 
 | } | 
 | { | 
 |     <UNSIGNED_INTEGER_LITERAL> { | 
 |         return SqlLiteral.createExactNumeric(token.image, getPos()); | 
 |     } | 
 | | | 
 |     <DECIMAL_NUMERIC_LITERAL> { | 
 |         return SqlLiteral.createExactNumeric(token.image, getPos()); | 
 |     } | 
 | | | 
 |     <DECIMAL> | 
 |     p = SimpleStringLiteral() { | 
 |         return SqlParserUtil.parseDecimalLiteral(SqlParserUtil.trim(p, " "), getPos()); | 
 |     } | 
 | | | 
 |     <APPROX_NUMERIC_LITERAL> { | 
 |         return SqlLiteral.createApproxNumeric(token.image, getPos()); | 
 |     } | 
 | } | 
 |  | 
 | /** Parses a numeric literal (can be signed) */ | 
 | SqlLiteral NumericLiteral() : | 
 | { | 
 |     final SqlNumericLiteral num; | 
 |     final Span s; | 
 | } | 
 | { | 
 |     <PLUS> num = UnsignedNumericLiteral() { | 
 |         return num; | 
 |     } | 
 | | | 
 |     <MINUS> { s = span(); } num = UnsignedNumericLiteral() { | 
 |         return SqlLiteral.createNegative(num, s.end(this)); | 
 |     } | 
 | | | 
 |     num = UnsignedNumericLiteral() { | 
 |         return num; | 
 |     } | 
 | } | 
 |  | 
 | /** Parse a special literal keyword */ | 
 | SqlLiteral SpecialLiteral() : | 
 | { | 
 | } | 
 | { | 
 |     <TRUE> { return SqlLiteral.createBoolean(true, getPos()); } | 
 | | | 
 |     <FALSE> { return SqlLiteral.createBoolean(false, getPos()); } | 
 | | | 
 |     <UNKNOWN> { return SqlLiteral.createUnknown(getPos()); } | 
 | | | 
 |     <NULL> { return SqlLiteral.createNull(getPos()); } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a string literal. The literal may be continued onto several | 
 |  * lines.  For a simple literal, the result is an SqlLiteral.  For a continued | 
 |  * literal, the result is an SqlCall expression, which concatenates 2 or more | 
 |  * string literals; the validator reduces this. | 
 |  * | 
 |  * @see SqlLiteral#unchain(SqlNode) | 
 |  * @see SqlLiteral#stringValue(SqlNode) | 
 |  * | 
 |  * @return a literal expression | 
 |  */ | 
 | SqlNode StringLiteral() : | 
 | { | 
 |     String p; | 
 |     final List<SqlLiteral> frags; | 
 |     char unicodeEscapeChar = 0; | 
 |     String charSet = null; | 
 |     SqlCharStringLiteral literal; | 
 | } | 
 | { | 
 |     // A continued string literal consists of a head fragment and one or more | 
 |     // tail fragments. Since comments may occur between the fragments, and | 
 |     // comments are special tokens, each fragment is a token. But since spaces | 
 |     // or comments may not occur between the prefix and the first quote, the | 
 |     // head fragment, with any prefix, is one token. | 
 |  | 
 |     <BINARY_STRING_LITERAL> | 
 |     { | 
 |         frags = new ArrayList<SqlLiteral>(); | 
 |         try { | 
 |             p = SqlParserUtil.trim(token.image, "xX'"); | 
 |             frags.add(SqlLiteral.createBinaryString(p, getPos())); | 
 |         } catch (NumberFormatException ex) { | 
 |             throw SqlUtil.newContextException(getPos(), | 
 |                 RESOURCE.illegalBinaryString(token.image)); | 
 |         } | 
 |     } | 
 |     ( | 
 |         // The grammar is ambiguous when a continued literals and a character | 
 |         // string alias are both possible. For example, in | 
 |         //   SELECT x'01'\n'ab' | 
 |         // we prefer that 'ab' continues the literal, and is not an alias. | 
 |         // The following LOOKAHEAD mutes the warning about ambiguity. | 
 |         LOOKAHEAD(1) | 
 |         <QUOTED_STRING> | 
 |         { | 
 |             try { | 
 |                 p = SqlParserUtil.trim(token.image, "'"); // no embedded quotes | 
 |                 frags.add(SqlLiteral.createBinaryString(p, getPos())); | 
 |             } catch (NumberFormatException ex) { | 
 |                 throw SqlUtil.newContextException(getPos(), | 
 |                     RESOURCE.illegalBinaryString(token.image)); | 
 |             } | 
 |         } | 
 |     )* | 
 |     { | 
 |         assert !frags.isEmpty(); | 
 |         if (frags.size() == 1) { | 
 |             return frags.get(0); // just the head fragment | 
 |         } else { | 
 |             SqlParserPos pos2 = SqlParserPos.sum(frags); | 
 |             return SqlStdOperatorTable.LITERAL_CHAIN.createCall(pos2, frags); | 
 |         } | 
 |     } | 
 | | | 
 |     ( | 
 |         <PREFIXED_STRING_LITERAL> | 
 |         { charSet = SqlParserUtil.getCharacterSet(token.image); } | 
 |     |   <QUOTED_STRING> | 
 |     |   <UNICODE_STRING_LITERAL> { | 
 |             // TODO jvs 2-Feb-2009:  support the explicit specification of | 
 |             // a character set for Unicode string literals, per SQL:2003 | 
 |             unicodeEscapeChar = BACKSLASH; | 
 |             charSet = "UTF16"; | 
 |         } | 
 |     ) | 
 |     { | 
 |         frags = new ArrayList<SqlLiteral>(); | 
 |         p = SqlParserUtil.parseString(token.image); | 
 |         try { | 
 |             literal = SqlLiteral.createCharString(p, charSet, getPos()); | 
 |             frags.add(literal); | 
 |         } catch (java.nio.charset.UnsupportedCharsetException e) { | 
 |             throw SqlUtil.newContextException(getPos(), | 
 |                 RESOURCE.unknownCharacterSet(charSet)); | 
 |         } | 
 |     } | 
 |     ( | 
 |         // The grammar is ambiguous when a continued literals and a character | 
 |         // string alias are both possible. For example, in | 
 |         //   SELECT 'taxi'\n'cab' | 
 |         // we prefer that 'cab' continues the literal, and is not an alias. | 
 |         // The following LOOKAHEAD mutes the warning about ambiguity. | 
 |         LOOKAHEAD(1) | 
 |         <QUOTED_STRING> | 
 |         { | 
 |             p = SqlParserUtil.parseString(token.image); | 
 |             try { | 
 |                 literal = SqlLiteral.createCharString(p, charSet, getPos()); | 
 |                 frags.add(literal); | 
 |             } catch (java.nio.charset.UnsupportedCharsetException e) { | 
 |                 throw SqlUtil.newContextException(getPos(), | 
 |                     RESOURCE.unknownCharacterSet(charSet)); | 
 |             } | 
 |         } | 
 |     )* | 
 |     [ | 
 |         <UESCAPE> <QUOTED_STRING> | 
 |         { | 
 |             if (unicodeEscapeChar == 0) { | 
 |                 throw SqlUtil.newContextException(getPos(), | 
 |                     RESOURCE.unicodeEscapeUnexpected()); | 
 |             } | 
 |             String s = SqlParserUtil.parseString(token.image); | 
 |             unicodeEscapeChar = SqlParserUtil.checkUnicodeEscapeChar(s); | 
 |         } | 
 |     ] | 
 |     { | 
 |         assert !frags.isEmpty(); | 
 |         if (frags.size() == 1) { | 
 |             // just the head fragment | 
 |             SqlLiteral lit = (SqlLiteral) frags.get(0); | 
 |             return lit.unescapeUnicode(unicodeEscapeChar); | 
 |         } else { | 
 |             SqlNode[] rands = (SqlNode[]) frags.toArray(new SqlNode[0]); | 
 |             for (int i = 0; i < rands.length; ++i) { | 
 |                 rands[i] = ((SqlLiteral) rands[i]).unescapeUnicode( | 
 |                     unicodeEscapeChar); | 
 |             } | 
 |             SqlParserPos pos2 = SqlParserPos.sum(rands); | 
 |             return SqlStdOperatorTable.LITERAL_CHAIN.createCall(pos2, rands); | 
 |         } | 
 |     } | 
 | | | 
 |     <C_STYLE_ESCAPED_STRING_LITERAL> | 
 |     { | 
 |         try { | 
 |             p = SqlParserUtil.parseCString(getToken(0).image); | 
 |         } catch (SqlParserUtil.MalformedUnicodeEscape e) { | 
 |             throw SqlUtil.newContextException(getPos(), | 
 |                 RESOURCE.unicodeEscapeMalformed(e.i)); | 
 |        } | 
 |        return SqlLiteral.createCharString(p, "UTF16", getPos()); | 
 |     } | 
 | | | 
 |     <BIG_QUERY_DOUBLE_QUOTED_STRING> | 
 |     { | 
 |         p = SqlParserUtil.stripQuotes(getToken(0).image, DQ, DQ, "\\\"", | 
 |             Casing.UNCHANGED); | 
 |         try { | 
 |             return SqlLiteral.createCharString(p, charSet, getPos()); | 
 |         } catch (java.nio.charset.UnsupportedCharsetException e) { | 
 |             throw SqlUtil.newContextException(getPos(), | 
 |                 RESOURCE.unknownCharacterSet(charSet)); | 
 |         } | 
 |     } | 
 | | | 
 |     <BIG_QUERY_QUOTED_STRING> | 
 |     { | 
 |         p = SqlParserUtil.stripQuotes(getToken(0).image, "'", "'", "\\'", | 
 |             Casing.UNCHANGED); | 
 |         try { | 
 |             return SqlLiteral.createCharString(p, charSet, getPos()); | 
 |         } catch (java.nio.charset.UnsupportedCharsetException e) { | 
 |             throw SqlUtil.newContextException(getPos(), | 
 |                 RESOURCE.unknownCharacterSet(charSet)); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | /** Parses a character literal. | 
 |  * Matches a single-quoted string, such as 'foo'; | 
 |  * on BigQuery also matches a double-quoted string, such as "foo". | 
 |  * Returns the value of the string with quotes removed. */ | 
 | String SimpleStringLiteral() : | 
 | { | 
 | } | 
 | { | 
 |     <QUOTED_STRING> { | 
 |         return SqlParserUtil.parseString(token.image); | 
 |     } | 
 | | | 
 |     <BIG_QUERY_QUOTED_STRING> { | 
 |         return SqlParserUtil.stripQuotes(token.image, "'", "'", "\\'", Casing.UNCHANGED); | 
 |     } | 
 | | | 
 |     <BIG_QUERY_DOUBLE_QUOTED_STRING> { | 
 |         return SqlParserUtil.stripQuotes(token.image, DQ, DQ, "\\\"", Casing.UNCHANGED); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a date/time literal. | 
 |  */ | 
 | SqlLiteral DateTimeLiteral() : | 
 | { | 
 |     final String p; | 
 |     final Span s; | 
 |     boolean local = false; | 
 | } | 
 | { | 
 |     <LBRACE_D> <QUOTED_STRING> { | 
 |         p = SqlParserUtil.parseString(token.image); | 
 |     } | 
 |     <RBRACE> { | 
 |         return SqlParserUtil.parseDateLiteral(p, getPos()); | 
 |     } | 
 | | | 
 |     <LBRACE_T> <QUOTED_STRING> { | 
 |         p = SqlParserUtil.parseString(token.image); | 
 |     } | 
 |     <RBRACE> { | 
 |         return SqlParserUtil.parseTimeLiteral(p, getPos()); | 
 |     } | 
 | | | 
 |     <LBRACE_TS> { s = span(); } <QUOTED_STRING> { | 
 |         p = SqlParserUtil.parseString(token.image); | 
 |     } | 
 |     <RBRACE> { | 
 |         return SqlParserUtil.parseTimestampLiteral(p, s.end(this)); | 
 |     } | 
 | | | 
 |     <DATE> { s = span(); } p = SimpleStringLiteral() { | 
 |       return SqlLiteral.createUnknown("DATE", p, s.end(this)); | 
 |     } | 
 | | | 
 |     <DATETIME> { s = span(); } p = SimpleStringLiteral() { | 
 |         return SqlLiteral.createUnknown("DATETIME", p, s.end(this)); | 
 |     } | 
 | | | 
 |     LOOKAHEAD(2) | 
 |     <TIME> { s = span(); } p = SimpleStringLiteral() { | 
 |       return SqlLiteral.createUnknown("TIME", p, s.end(this)); | 
 |     } | 
 | | | 
 |     LOOKAHEAD(2) | 
 |     <TIMESTAMP> { s = span(); } p = SimpleStringLiteral() { | 
 |         return SqlLiteral.createUnknown("TIMESTAMP", p, s.end(this)); | 
 |     } | 
 | | | 
 |     LOOKAHEAD(2) | 
 |     <TIME> { s = span(); } <WITH> ( <LOCAL> { local = true; } )? <TIME> <ZONE> p = SimpleStringLiteral() { | 
 |         return SqlLiteral.createUnknown("TIME WITH " + (local ? "LOCAL " : "") + "TIME ZONE", p, s.end(this)); | 
 |     } | 
 | | | 
 |     LOOKAHEAD(2) | 
 |     <TIMESTAMP> { s = span(); } <WITH> ( <LOCAL> { local = true; } )? <TIME> <ZONE> p = SimpleStringLiteral() { | 
 |         return SqlLiteral.createUnknown("TIMESTAMP WITH " + (local ? "LOCAL " : "") + "TIME ZONE", p, s.end(this)); | 
 |     } | 
 | } | 
 |  | 
 | /** Parses a Date/Time constructor function, for example "DATE(1969, 7, 21)" | 
 |  * or "DATETIME(d, t)". Enabled in some libraries (e.g. BigQuery). */ | 
 | SqlNode DateTimeConstructorCall() : | 
 | { | 
 |     final SqlFunctionCategory funcType = SqlFunctionCategory.TIMEDATE; | 
 |     final SqlIdentifier qualifiedName; | 
 |     final Span s; | 
 |     final SqlLiteral quantifier; | 
 |     final List<? extends SqlNode> args; | 
 | } | 
 | { | 
 |     (<DATE> | <TIME> | <DATETIME> | <TIMESTAMP>) { | 
 |         s = span(); | 
 |         qualifiedName = new SqlIdentifier(unquotedIdentifier(), getPos()); | 
 |     } | 
 |     args = FunctionParameterList(ExprContext.ACCEPT_SUB_QUERY) { | 
 |         quantifier = (SqlLiteral) args.get(0); | 
 |         args.remove(0); | 
 |         return createCall(qualifiedName, s.end(this), funcType, quantifier, args); | 
 |     } | 
 | } | 
 |  | 
 | /** Parses a MULTISET constructor */ | 
 | SqlNode MultisetConstructor() : | 
 | { | 
 |     final List<SqlNode> args = new ArrayList<SqlNode>(); | 
 |     SqlNode e; | 
 |     final Span s; | 
 | } | 
 | { | 
 |     <MULTISET> { s = span(); } | 
 |     ( | 
 |         LOOKAHEAD(2) | 
 |         <LPAREN> | 
 |         // by sub query "MULTISET(SELECT * FROM T)" | 
 |         e = LeafQueryOrExpr(ExprContext.ACCEPT_QUERY) | 
 |         <RPAREN> { | 
 |             return SqlStdOperatorTable.MULTISET_QUERY.createCall( | 
 |                 s.end(this), e); | 
 |         } | 
 |     | | 
 |         // by enumeration "MULTISET[e0, e1, ..., eN]" | 
 |         <LBRACKET> // TODO: do trigraph as well ??( ??) | 
 |         AddExpression(args, ExprContext.ACCEPT_NON_QUERY) | 
 |         ( <COMMA> AddExpression(args, ExprContext.ACCEPT_NON_QUERY) )* | 
 |         <RBRACKET> | 
 |         { | 
 |             return SqlStdOperatorTable.MULTISET_VALUE.createCall( | 
 |                 s.end(this), args); | 
 |         } | 
 |     ) | 
 | } | 
 |  | 
 | /** Parses an ARRAY constructor */ | 
 | SqlNode ArrayConstructor() : | 
 | { | 
 |     final SqlNodeList args; | 
 |     SqlNode e; | 
 |     final Span s; | 
 |     final String p; | 
 | } | 
 | { | 
 |     <ARRAY> { s = span(); } | 
 |     ( | 
 |         ( | 
 |             // nullary array function call: "array()" (Apache Spark) | 
 |             LOOKAHEAD(2) | 
 |             <LPAREN> <RPAREN> { args = SqlNodeList.EMPTY; } | 
 |         | | 
 |             args = ParenthesizedQueryOrCommaList(ExprContext.ACCEPT_ALL) | 
 |         ) | 
 |         { | 
 |             if (args.size() == 1 && args.get(0).isA(SqlKind.QUERY)) { | 
 |                 // Array query constructor, 'ARRAY (SELECT * FROM t)' | 
 |                 return SqlStdOperatorTable.ARRAY_QUERY.createCall(s.end(this), args.get(0)); | 
 |             } else { | 
 |                 // Spark ARRAY function, 'ARRAY(1, 2)', | 
 |                 // equivalent to standard 'ARRAY [1, 2]' | 
 |                 return SqlLibraryOperators.ARRAY.createCall(s.end(this), args.getList()); | 
 |             } | 
 |         } | 
 |     | | 
 |         // by enumeration "ARRAY[e0, e1, ..., eN]" | 
 |         <LBRACKET> // TODO: do trigraph as well ??( ??) | 
 |         ( | 
 |             args = ExpressionCommaList(s, ExprContext.ACCEPT_NON_QUERY) | 
 |         | | 
 |             { args = SqlNodeList.EMPTY; } | 
 |         ) | 
 |         <RBRACKET> | 
 |         { | 
 |             return SqlStdOperatorTable.ARRAY_VALUE_CONSTRUCTOR.createCall( | 
 |                 s.end(this), args.getList()); | 
 |         } | 
 | <#if (parser.includeParsingStringLiteralAsArrayLiteral!default.parser.includeParsingStringLiteralAsArrayLiteral) > | 
 |     | | 
 |         p = SimpleStringLiteral() { | 
 |             try { | 
 |                 return SqlParserUtil.parseArrayLiteral(p); | 
 |             } catch (SqlParseException ex) { | 
 |                 throw SqlUtil.newContextException(getPos(), | 
 |                     RESOURCE.illegalArrayExpression(p)); | 
 |             } | 
 |         } | 
 | </#if> | 
 |     ) | 
 | } | 
 |  | 
 | SqlCall ArrayLiteral() : | 
 | { | 
 |     final List<SqlNode> list; | 
 |     SqlNode e; | 
 |     final Span s; | 
 | } | 
 | { | 
 |     <LBRACE> { s = span(); } | 
 |     ( | 
 |         e = Literal() { list = startList(e); } | 
 |         ( <COMMA> e = Literal() { list.add(e); } )* | 
 |     | | 
 |         e = ArrayLiteral() { list = startList(e); } | 
 |         ( <COMMA> e = ArrayLiteral() { list.add(e); } )* | 
 |     | | 
 |         { list = Collections.emptyList(); } | 
 |     ) | 
 |     <RBRACE> { | 
 |        return SqlStdOperatorTable.ARRAY_VALUE_CONSTRUCTOR.createCall(s.end(this), list); | 
 |     } | 
 | } | 
 |  | 
 | /** Parses a MAP constructor */ | 
 | SqlNode MapConstructor() : | 
 | { | 
 |     SqlNodeList args; | 
 |     final Span s; | 
 | } | 
 | { | 
 |     <MAP> { s = span(); } | 
 |     ( | 
 |         ( | 
 |             // empty map function call: "map()" | 
 |             LOOKAHEAD(2) | 
 |             <LPAREN> <RPAREN> { args = SqlNodeList.EMPTY; } | 
 |         | | 
 |             args = ParenthesizedQueryOrCommaList(ExprContext.ACCEPT_ALL) | 
 |         ) | 
 |         { | 
 |             if (args.size() == 1 && args.get(0).isA(SqlKind.QUERY)) { | 
 |                 // MAP query constructor e.g. "MAP (SELECT empno, deptno FROM emps)" | 
 |                 return SqlStdOperatorTable.MAP_QUERY.createCall(s.end(this), args.get(0)); | 
 |             } else { | 
 |                 // MAP function e.g. "MAP(1, 2)" equivalent to standard "MAP[1, 2]" | 
 |                 return SqlLibraryOperators.MAP.createCall(s.end(this), args.getList()); | 
 |             } | 
 |         } | 
 |     | | 
 |         // by enumeration "MAP[k0, v0, ..., kN, vN]" | 
 |         <LBRACKET> // TODO: do trigraph as well ??( ??) | 
 |         ( | 
 |             args = ExpressionCommaList(s, ExprContext.ACCEPT_NON_QUERY) | 
 |         | | 
 |             { args = SqlNodeList.EMPTY; } | 
 |         ) | 
 |         <RBRACKET> | 
 |         { | 
 |             return SqlStdOperatorTable.MAP_VALUE_CONSTRUCTOR.createCall( | 
 |                 s.end(this), args.getList()); | 
 |         } | 
 |     ) | 
 | } | 
 |  | 
 | /** Parses a PERIOD constructor */ | 
 | SqlNode PeriodConstructor() : | 
 | { | 
 |     final List<SqlNode> args = new ArrayList<SqlNode>(); | 
 |     final Span s; | 
 | } | 
 | { | 
 |     <PERIOD> { s = span(); } | 
 |     <LPAREN> | 
 |     AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     <COMMA> | 
 |     AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     <RPAREN> { | 
 |         return SqlStdOperatorTable.ROW.createCall(s.end(this), args); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses an interval literal. | 
 |  */ | 
 | SqlLiteral IntervalLiteral() : | 
 | { | 
 |     final String p; | 
 |     final SqlIntervalQualifier intervalQualifier; | 
 |     int sign = 1; | 
 |     final Span s; | 
 | } | 
 | { | 
 |     <INTERVAL> { s = span(); } | 
 |     [ | 
 |         <MINUS> { sign = -1; } | 
 |     | | 
 |         <PLUS> { sign = 1; } | 
 |     ] | 
 |     p = SimpleStringLiteral() | 
 |     intervalQualifier = IntervalQualifier() { | 
 |         return SqlParserUtil.parseIntervalLiteral(s.end(intervalQualifier), | 
 |             sign, p, intervalQualifier); | 
 |     } | 
 | } | 
 |  | 
 | /** Parses an interval literal (e.g. {@code INTERVAL '2:3' HOUR TO MINUTE}) | 
 |  * or an interval expression (e.g. {@code INTERVAL emp.empno MINUTE} | 
 |  * or {@code INTERVAL 3 MONTHS}). */ | 
 | SqlNode IntervalLiteralOrExpression() : | 
 | { | 
 |     final String p; | 
 |     final SqlIntervalQualifier intervalQualifier; | 
 |     int sign = 1; | 
 |     final Span s; | 
 |     SqlNode e; | 
 | } | 
 | { | 
 |     <INTERVAL> { s = span(); } | 
 |     [ | 
 |         <MINUS> { sign = -1; } | 
 |     | | 
 |         <PLUS> { sign = 1; } | 
 |     ] | 
 |     ( | 
 |         // literal (with quoted string) | 
 |         p = SimpleStringLiteral() | 
 |         intervalQualifier = IntervalQualifier() { | 
 |             return SqlParserUtil.parseIntervalLiteral(s.end(intervalQualifier), | 
 |                 sign, p, intervalQualifier); | 
 |         } | 
 |     | | 
 |         // To keep parsing simple, any expressions besides numeric literal and | 
 |         // identifiers must be enclosed in parentheses. | 
 |         ( | 
 |             <LPAREN> | 
 |             e = Expression(ExprContext.ACCEPT_SUB_QUERY) | 
 |             <RPAREN> | 
 |         | | 
 |             e = UnsignedNumericLiteral() | 
 |         | | 
 |             e = CompoundIdentifier() | 
 |         ) | 
 |         intervalQualifier = IntervalQualifierStart() { | 
 |             if (sign == -1) { | 
 |                 e = SqlStdOperatorTable.UNARY_MINUS.createCall(e.getParserPosition(), e); | 
 |             } | 
 |             return SqlStdOperatorTable.INTERVAL.createCall(s.end(this), e, | 
 |                 intervalQualifier); | 
 |         } | 
 |     ) | 
 | } | 
 |  | 
 | TimeUnit Year() : | 
 | { | 
 | } | 
 | { | 
 |     <YEAR> { return TimeUnit.YEAR; } | 
 | | | 
 |     <YEARS> { return warn(TimeUnit.YEAR); } | 
 | } | 
 |  | 
 | TimeUnit Quarter() : | 
 | { | 
 | } | 
 | { | 
 |     <QUARTER> { return TimeUnit.QUARTER; } | 
 | | | 
 |     <QUARTERS> { return warn(TimeUnit.QUARTER); } | 
 | } | 
 |  | 
 | TimeUnit Month() : | 
 | { | 
 | } | 
 | { | 
 |     <MONTH> { return TimeUnit.MONTH; } | 
 | | | 
 |     <MONTHS> { return warn(TimeUnit.MONTH); } | 
 | } | 
 |  | 
 | TimeUnit Week() : | 
 | { | 
 | } | 
 | { | 
 |     <WEEK> { return TimeUnit.WEEK; } | 
 | | | 
 |     <WEEKS> { return warn(TimeUnit.WEEK); } | 
 | } | 
 |  | 
 | TimeUnit Day() : | 
 | { | 
 | } | 
 | { | 
 |     <DAY> { return TimeUnit.DAY; } | 
 | | | 
 |     <DAYS> { return warn(TimeUnit.DAY); } | 
 | } | 
 |  | 
 | TimeUnit Hour() : | 
 | { | 
 | } | 
 | { | 
 |     <HOUR> { return TimeUnit.HOUR; } | 
 | | | 
 |     <HOURS> { return warn(TimeUnit.HOUR); } | 
 | } | 
 |  | 
 | TimeUnit Minute() : | 
 | { | 
 | } | 
 | { | 
 |     <MINUTE> { return TimeUnit.MINUTE; } | 
 | | | 
 |     <MINUTES> { return warn(TimeUnit.MINUTE); } | 
 | } | 
 |  | 
 | TimeUnit Second() : | 
 | { | 
 | } | 
 | { | 
 |     <SECOND> { return TimeUnit.SECOND; } | 
 | | | 
 |     <SECONDS> { return warn(TimeUnit.SECOND); } | 
 | } | 
 |  | 
 | SqlIntervalQualifier IntervalQualifier() : | 
 | { | 
 |     final Span s; | 
 |     final TimeUnit start; | 
 |     final TimeUnit end; | 
 |     final int startPrec; | 
 |     int secondFracPrec = RelDataType.PRECISION_NOT_SPECIFIED; | 
 | } | 
 | { | 
 |     ( | 
 |         start = Year() { s = span(); } startPrec = PrecisionOpt() | 
 |         ( | 
 |             LOOKAHEAD(2) <TO> end = Month() | 
 |         |   { end = null; } | 
 |         ) | 
 |     | | 
 |         start = Quarter() { s = span(); } startPrec = PrecisionOpt() | 
 |         { end = null; } | 
 |     | | 
 |         start = Month() { s = span(); } startPrec = PrecisionOpt() | 
 |         { end = null; } | 
 |     | | 
 |         start = Week() { s = span(); } startPrec = PrecisionOpt() | 
 |         { end = null; } | 
 |     | | 
 |         start = Day() { s = span(); } startPrec = PrecisionOpt() | 
 |         ( | 
 |             LOOKAHEAD(2) <TO> | 
 |             ( | 
 |                 end = Hour() | 
 |             | | 
 |                 end = Minute() | 
 |             | | 
 |                 end = Second() secondFracPrec = PrecisionOpt() | 
 |             ) | 
 |         |   { end = null; } | 
 |         ) | 
 |     | | 
 |         start = Hour() { s = span(); } startPrec = PrecisionOpt() | 
 |         ( | 
 |             LOOKAHEAD(2) <TO> | 
 |             ( | 
 |                 end = Minute() | 
 |             | | 
 |                 end = Second() | 
 |                 [ <LPAREN> secondFracPrec = UnsignedIntLiteral() <RPAREN> ] | 
 |             ) | 
 |         |   { end = null; } | 
 |         ) | 
 |     | | 
 |         start = Minute() { s = span(); } startPrec = PrecisionOpt() | 
 |         ( | 
 |             LOOKAHEAD(2) <TO> | 
 |             end = Second() | 
 |             [ <LPAREN> secondFracPrec = UnsignedIntLiteral() <RPAREN> ] | 
 |         |   { end = null; } | 
 |         ) | 
 |     | | 
 |         start = Second() { s = span(); } | 
 |         ( | 
 |             <LPAREN> startPrec = UnsignedIntLiteral() | 
 |             [ <COMMA> secondFracPrec = UnsignedIntLiteral() ] | 
 |             <RPAREN> | 
 |         |   { startPrec = -1; } | 
 |         ) | 
 |         { end = null; } | 
 |     ) | 
 |     { | 
 |         return new SqlIntervalQualifier(start, startPrec, end, secondFracPrec, | 
 |             s.end(this)); | 
 |     } | 
 | } | 
 |  | 
 | /** Interval qualifier without 'TO unit'. */ | 
 | SqlIntervalQualifier IntervalQualifierStart() : | 
 | { | 
 |     final Span s; | 
 |     final TimeUnit start; | 
 |     int startPrec = RelDataType.PRECISION_NOT_SPECIFIED; | 
 |     int secondFracPrec = RelDataType.PRECISION_NOT_SPECIFIED; | 
 | } | 
 | { | 
 |     ( | 
 |         ( | 
 |             start = Year() | 
 |         |   start = Quarter() | 
 |         |   start = Month() | 
 |         |   start = Week() | 
 |         |   start = Day() | 
 |         |   start = Hour() | 
 |         |   start = Minute() | 
 |         ) | 
 |         { s = span(); } | 
 |         startPrec = PrecisionOpt() | 
 |     | | 
 |         start = Second() { s = span(); } | 
 |         [   <LPAREN> startPrec = UnsignedIntLiteral() | 
 |             [ <COMMA> secondFracPrec = UnsignedIntLiteral() ] | 
 |             <RPAREN> | 
 |         ] | 
 |     ) | 
 |     { | 
 |         return new SqlIntervalQualifier(start, startPrec, null, secondFracPrec, | 
 |             s.end(this)); | 
 |     } | 
 | } | 
 |  | 
 | /** Parses a built-in time unit (e.g. "YEAR") | 
 |  * or user-defined time frame (e.g. "MINUTE15") | 
 |  * and in each case returns a {@link SqlIntervalQualifier}. | 
 |  * | 
 |  * <p>The units are used in several functions, incuding CEIL, FLOOR, EXTRACT. | 
 |  * Includes NANOSECOND, MILLISECOND, which were previously allowed in EXTRACT | 
 |  * but not CEIL, FLOOR. | 
 |  * | 
 |  * <p>Includes {@code WEEK} and {@code WEEK(SUNDAY)} through | 
 |   {@code WEEK(SATURDAY)}. | 
 |  * | 
 |  * <p>Does not include SQL_TSI_DAY, SQL_TSI_FRAC_SECOND etc. These will be | 
 |  * parsed as identifiers and can be resolved in the validator if they are | 
 |  * registered as abbreviations in your time frame set. | 
 |  */ | 
 | SqlIntervalQualifier TimeUnitOrName() : { | 
 |     final SqlIdentifier unitName; | 
 |     final SqlIntervalQualifier intervalQualifier; | 
 | } | 
 | { | 
 |     // When we see a time unit that is also a non-reserved keyword, such as | 
 |     // NANOSECOND, there is a choice between using the TimeUnit enum | 
 |     // (TimeUnit.NANOSECOND) or the name. The following LOOKAHEAD directive | 
 |     // tells the parser that we prefer the former. | 
 |     // | 
 |     // Reserved keywords, such as SECOND, cannot be identifiers, and are | 
 |     // therefore not ambiguous. | 
 |     LOOKAHEAD(2) | 
 |     intervalQualifier = TimeUnit() { | 
 |         return intervalQualifier; | 
 |     } | 
 | |   unitName = SimpleIdentifier() { | 
 |         return new SqlIntervalQualifier(unitName.getSimple(), | 
 |             unitName.getParserPosition()); | 
 |     } | 
 | } | 
 |  | 
 | /** Parses a built-in time unit (e.g. "YEAR") | 
 |  * and returns a {@link SqlIntervalQualifier}. | 
 |  * | 
 |  * <p>Includes {@code WEEK} and {@code WEEK(SUNDAY)} through | 
 |   {@code WEEK(SATURDAY)}. | 
 |  * | 
 |  * <p>Does not include SQL_TSI_DAY, SQL_TSI_FRAC_SECOND etc. These will be | 
 |  * parsed as identifiers and can be resolved in the validator if they are | 
 |  * registered as abbreviations in your time frame set. | 
 |  */ | 
 | SqlIntervalQualifier TimeUnit() : { | 
 |     final Span span; | 
 |     final String w; | 
 | } | 
 | { | 
 |     <NANOSECOND> { return new SqlIntervalQualifier(TimeUnit.NANOSECOND, null, getPos()); } | 
 | |   <MICROSECOND> { return new SqlIntervalQualifier(TimeUnit.MICROSECOND, null, getPos()); } | 
 | |   <MILLISECOND> { return new SqlIntervalQualifier(TimeUnit.MILLISECOND, null, getPos()); } | 
 | |   <SECOND> { return new SqlIntervalQualifier(TimeUnit.SECOND, null, getPos()); } | 
 | |   <MINUTE> { return new SqlIntervalQualifier(TimeUnit.MINUTE, null, getPos()); } | 
 | |   <HOUR> { return new SqlIntervalQualifier(TimeUnit.HOUR, null, getPos()); } | 
 | |   <DAY> { return new SqlIntervalQualifier(TimeUnit.DAY, null, getPos()); } | 
 | |   <DAYOFWEEK> { return new SqlIntervalQualifier(TimeUnit.DOW, null, getPos()); } | 
 | |   <DAYOFYEAR> { return new SqlIntervalQualifier(TimeUnit.DOY, null, getPos()); } | 
 | |   <DOW> { return new SqlIntervalQualifier(TimeUnit.DOW, null, getPos()); } | 
 | |   <DOY> { return new SqlIntervalQualifier(TimeUnit.DOY, null, getPos()); } | 
 | |   <ISODOW> { return new SqlIntervalQualifier(TimeUnit.ISODOW, null, getPos()); } | 
 | |   <ISOYEAR> { return new SqlIntervalQualifier(TimeUnit.ISOYEAR, null, getPos()); } | 
 | |   <WEEK> { span = span(); } | 
 |     ( | 
 |         // There is a choice between "WEEK(weekday)" and "WEEK". We prefer | 
 |         // the former, and the parser will look ahead for '('. | 
 |         LOOKAHEAD(2) | 
 |         <LPAREN> w = weekdayName() <RPAREN> { | 
 |             return new SqlIntervalQualifier(w, span.end(this)); | 
 |         } | 
 |     | | 
 |         { return new SqlIntervalQualifier(TimeUnit.WEEK, null, getPos()); } | 
 |     ) | 
 | |   <MONTH> { return new SqlIntervalQualifier(TimeUnit.MONTH, null, getPos()); } | 
 | |   <QUARTER> { return new SqlIntervalQualifier(TimeUnit.QUARTER, null, getPos()); } | 
 | |   <YEAR> { return new SqlIntervalQualifier(TimeUnit.YEAR, null, getPos()); } | 
 | |   <EPOCH> { return new SqlIntervalQualifier(TimeUnit.EPOCH, null, getPos()); } | 
 | |   <DECADE> { return new SqlIntervalQualifier(TimeUnit.DECADE, null, getPos()); } | 
 | |   <CENTURY> { return new SqlIntervalQualifier(TimeUnit.CENTURY, null, getPos()); } | 
 | |   <MILLENNIUM> { return new SqlIntervalQualifier(TimeUnit.MILLENNIUM, null, getPos()); } | 
 | } | 
 |  | 
 | String weekdayName() : | 
 | { | 
 | } | 
 | { | 
 |     <SUNDAY> { return "WEEK_SUNDAY"; } | 
 | |   <MONDAY> { return "WEEK_MONDAY"; } | 
 | |   <TUESDAY> { return "WEEK_TUESDAY"; } | 
 | |   <WEDNESDAY> { return "WEEK_WEDNESDAY"; } | 
 | |   <THURSDAY> { return "WEEK_THURSDAY"; } | 
 | |   <FRIDAY> { return "WEEK_FRIDAY"; } | 
 | |   <SATURDAY> { return "WEEK_SATURDAY"; } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a dynamic parameter marker. | 
 |  */ | 
 | SqlDynamicParam DynamicParam() : | 
 | { | 
 | } | 
 | { | 
 |     <HOOK> { | 
 |         return new SqlDynamicParam(nDynamicParams++, getPos()); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses one segment of an identifier that may be composite. | 
 |  * | 
 |  * <p>Each time it reads an identifier it writes one element to each list; | 
 |  * the entry in {@code positions} records its position and whether the | 
 |  * segment was quoted. | 
 |  */ | 
 | void AddIdentifierSegment(List<String> names, List<SqlParserPos> positions) : | 
 | { | 
 |     final String id; | 
 |     char unicodeEscapeChar = BACKSLASH; | 
 |     final SqlParserPos pos; | 
 |     final Span span; | 
 | } | 
 | { | 
 |     ( | 
 |         <IDENTIFIER> { | 
 |             id = unquotedIdentifier(); | 
 |             pos = getPos(); | 
 |         } | 
 |     | | 
 |         <HYPHENATED_IDENTIFIER> { | 
 |             id = unquotedIdentifier(); | 
 |             pos = getPos(); | 
 |         } | 
 |     | | 
 |         <QUOTED_IDENTIFIER> { | 
 |             id = SqlParserUtil.stripQuotes(getToken(0).image, DQ, DQ, DQDQ, | 
 |                 quotedCasing); | 
 |             pos = getPos().withQuoting(true); | 
 |         } | 
 |     | | 
 |         <BACK_QUOTED_IDENTIFIER> { | 
 |             id = SqlParserUtil.stripQuotes(getToken(0).image, "`", "`", "``", | 
 |                 quotedCasing); | 
 |             pos = getPos().withQuoting(true); | 
 |         } | 
 |     | | 
 |         <BIG_QUERY_BACK_QUOTED_IDENTIFIER> { | 
 |             id = SqlParserUtil.stripQuotes(getToken(0).image, "`", "`", "\\`", | 
 |                 quotedCasing); | 
 |             pos = getPos().withQuoting(true); | 
 |         } | 
 |     | | 
 |         <BRACKET_QUOTED_IDENTIFIER> { | 
 |             id = SqlParserUtil.stripQuotes(getToken(0).image, "[", "]", "]]", | 
 |                 quotedCasing); | 
 |             pos = getPos().withQuoting(true); | 
 |         } | 
 |     | | 
 |         <UNICODE_QUOTED_IDENTIFIER> { | 
 |             span = span(); | 
 |             String image = getToken(0).image; | 
 |             image = image.substring(image.indexOf('"')); | 
 |             image = SqlParserUtil.stripQuotes(image, DQ, DQ, DQDQ, quotedCasing); | 
 |         } | 
 |         [ | 
 |             <UESCAPE> <QUOTED_STRING> { | 
 |                 String s = SqlParserUtil.parseString(token.image); | 
 |                 unicodeEscapeChar = SqlParserUtil.checkUnicodeEscapeChar(s); | 
 |             } | 
 |         ] | 
 |         { | 
 |             pos = span.end(this).withQuoting(true); | 
 |             SqlLiteral lit = SqlLiteral.createCharString(image, "UTF16", pos); | 
 |             lit = lit.unescapeUnicode(unicodeEscapeChar); | 
 |             id = lit.toValue(); | 
 |         } | 
 |     | | 
 |         id = NonReservedKeyWord() { | 
 |             pos = getPos(); | 
 |         } | 
 |     ) | 
 |     { | 
 |         if (id.length() > this.identifierMaxLength) { | 
 |             throw SqlUtil.newContextException(pos, | 
 |                 RESOURCE.identifierTooLong(id, this.identifierMaxLength)); | 
 |         } | 
 |         names.add(id); | 
 |         if (positions != null) { | 
 |             positions.add(pos); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | /** As {@link #AddIdentifierSegment} but part of a table name (for example, | 
 |  * following {@code FROM}, {@code INSERT} or {@code UPDATE}). | 
 |  * | 
 |  * <p>In some dialects the lexical rules for table names are different from | 
 |  * for other identifiers. For example, in BigQuery, table names may contain | 
 |  * hyphens. */ | 
 | void AddTableIdentifierSegment(List<String> names, List<SqlParserPos> positions) : | 
 | { | 
 | } | 
 | { | 
 |     AddIdentifierSegment(names, positions) { | 
 |         final int n = names.size(); | 
 |         if (n > 0 | 
 |                 && positions.size() == n | 
 |                 && names.get(n - 1).contains(".") | 
 |                 && positions.get(n - 1).isQuoted() | 
 |                 && this.conformance.splitQuotedTableName()) { | 
 |             final String name = names.remove(n - 1); | 
 |             final SqlParserPos pos = positions.remove(n - 1); | 
 |             final String[] splitNames = name.split("\\."); | 
 |             for (String splitName : splitNames) { | 
 |                 names.add(splitName); | 
 |                 positions.add(pos); | 
 |             } | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a simple identifier as a String. | 
 |  */ | 
 | String Identifier() : | 
 | { | 
 |     final List<String> names = new ArrayList<String>(); | 
 | } | 
 | { | 
 |     AddIdentifierSegment(names, null) { | 
 |         return names.get(0); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a simple identifier as an SqlIdentifier. | 
 |  */ | 
 | SqlIdentifier SimpleIdentifier() : | 
 | { | 
 |     final List<String> names = new ArrayList<String>(); | 
 |     final List<SqlParserPos> positions = new ArrayList<SqlParserPos>(); | 
 | } | 
 | { | 
 |     AddIdentifierSegment(names, positions) { | 
 |         return new SqlIdentifier(names.get(0), positions.get(0)); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a character literal as an SqlIdentifier. | 
 |  * Only valid for column aliases in certain dialects. | 
 |  */ | 
 | SqlIdentifier SimpleIdentifierFromStringLiteral() : | 
 | { | 
 | } | 
 | { | 
 |     <QUOTED_STRING> { | 
 |         if (!this.conformance.allowCharLiteralAlias()) { | 
 |             throw SqlUtil.newContextException(getPos(), RESOURCE.charLiteralAliasNotValid()); | 
 |         } | 
 |         final String s = SqlParserUtil.parseString(token.image); | 
 |         return new SqlIdentifier(s, getPos()); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a comma-separated list of simple identifiers. | 
 |  */ | 
 | void AddSimpleIdentifiers(List<SqlNode> list) : | 
 | { | 
 |     SqlIdentifier id; | 
 | } | 
 | { | 
 |     id = SimpleIdentifier() {list.add(id);} | 
 |     ( | 
 |         <COMMA> id = SimpleIdentifier() { | 
 |             list.add(id); | 
 |         } | 
 |     )* | 
 | } | 
 |  | 
 | /** | 
 |   * List of simple identifiers in parentheses. The position extends from the | 
 |   * open parenthesis to the close parenthesis. | 
 |   */ | 
 | SqlNodeList ParenthesizedSimpleIdentifierList() : | 
 | { | 
 |     final Span s; | 
 |     final List<SqlNode> list = new ArrayList<SqlNode>(); | 
 | } | 
 | { | 
 |     <LPAREN> { s = span(); } | 
 |     AddSimpleIdentifiers(list) | 
 |     <RPAREN> { | 
 |         return new SqlNodeList(list, s.end(this)); | 
 |     } | 
 | } | 
 |  | 
 | /** List of simple identifiers in parentheses or one simple identifier. | 
 |  * | 
 |  * <ul>Examples: | 
 |  * <li>{@code DEPTNO} | 
 |  * <li>{@code (EMPNO, DEPTNO)} | 
 |  * </ul> | 
 |  */ | 
 | SqlNodeList SimpleIdentifierOrList() : | 
 | { | 
 |     SqlIdentifier id; | 
 |     SqlNodeList list; | 
 | } | 
 | { | 
 |     id = SimpleIdentifier() { | 
 |         return new SqlNodeList(Collections.singletonList(id), id.getParserPosition()); | 
 |     } | 
 | | | 
 |     list = ParenthesizedSimpleIdentifierList() { | 
 |         return list; | 
 |     } | 
 | } | 
 |  | 
 | <#if (parser.includeCompoundIdentifier!default.parser.includeCompoundIdentifier) > | 
 | /** | 
 |  * Parses a compound identifier. | 
 |  */ | 
 | SqlIdentifier CompoundIdentifier() : | 
 | { | 
 |     final List<String> nameList = new ArrayList<String>(); | 
 |     final List<SqlParserPos> posList = new ArrayList<SqlParserPos>(); | 
 |     boolean star = false; | 
 | } | 
 | { | 
 |     AddIdentifierSegment(nameList, posList) | 
 |     ( | 
 |         LOOKAHEAD(2) | 
 |         <DOT> | 
 |         AddIdentifierSegment(nameList, posList) | 
 |     )* | 
 |     ( | 
 |         LOOKAHEAD(2) | 
 |         <DOT> | 
 |         <STAR> { | 
 |             star = true; | 
 |             nameList.add(""); | 
 |             posList.add(getPos()); | 
 |         } | 
 |     )? | 
 |     { | 
 |         SqlParserPos pos = SqlParserPos.sum(posList); | 
 |         if (star) { | 
 |             return SqlIdentifier.star(nameList, pos, posList); | 
 |         } | 
 |         return new SqlIdentifier(nameList, null, pos, posList); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a compound identifier in the FROM clause. | 
 |  */ | 
 | SqlIdentifier CompoundTableIdentifier() : | 
 | { | 
 |     final List<String> nameList = new ArrayList<String>(); | 
 |     final List<SqlParserPos> posList = new ArrayList<SqlParserPos>(); | 
 | } | 
 | { | 
 |     AddTableIdentifierSegment(nameList, posList) | 
 |     ( | 
 |         LOOKAHEAD(2) | 
 |         <DOT> | 
 |         AddTableIdentifierSegment(nameList, posList) | 
 |     )* | 
 |     { | 
 |         SqlParserPos pos = SqlParserPos.sum(posList); | 
 |         return new SqlIdentifier(nameList, null, pos, posList); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a comma-separated list of compound identifiers. | 
 |  */ | 
 | void AddCompoundIdentifierTypes(List<SqlNode> list, List<SqlNode> extendList) : | 
 | { | 
 | } | 
 | { | 
 |     AddCompoundIdentifierType(list, extendList) | 
 |     (<COMMA> AddCompoundIdentifierType(list, extendList))* | 
 | } | 
 |  | 
 | /** | 
 |  * List of compound identifiers in parentheses. The position extends from the | 
 |  * open parenthesis to the close parenthesis. | 
 |  */ | 
 | Pair<SqlNodeList, SqlNodeList> ParenthesizedCompoundIdentifierList() : | 
 | { | 
 |     final Span s; | 
 |     final List<SqlNode> list = new ArrayList<SqlNode>(); | 
 |     final List<SqlNode> extendList = new ArrayList<SqlNode>(); | 
 | } | 
 | { | 
 |     <LPAREN> { s = span(); } | 
 |     AddCompoundIdentifierTypes(list, extendList) | 
 |     <RPAREN> { | 
 |         return Pair.of(new SqlNodeList(list, s.end(this)), new SqlNodeList(extendList, s.end(this))); | 
 |     } | 
 | } | 
 | <#else> | 
 |   <#include "/@includes/compoundIdentifier.ftl" /> | 
 | </#if> | 
 |  | 
 | /** | 
 |  * Parses a NEW UDT(...) expression. | 
 |  */ | 
 | SqlNode NewSpecification() : | 
 | { | 
 |     final Span s; | 
 |     final SqlNode routineCall; | 
 | } | 
 | { | 
 |     <NEW> { s = span(); } | 
 |     routineCall = | 
 |         NamedRoutineCall(SqlFunctionCategory.USER_DEFINED_CONSTRUCTOR, | 
 |             ExprContext.ACCEPT_SUB_QUERY) { | 
 |         return SqlStdOperatorTable.NEW.createCall(s.end(routineCall), routineCall); | 
 |     } | 
 | } | 
 |  | 
 | //TODO: real parse errors. | 
 | int UnsignedIntLiteral() : | 
 | { | 
 |     Token t; | 
 | } | 
 | { | 
 |     t = <UNSIGNED_INTEGER_LITERAL> | 
 |     { | 
 |         try { | 
 |             return Integer.parseInt(t.image); | 
 |         } catch (NumberFormatException ex) { | 
 |             throw SqlUtil.newContextException(getPos(), | 
 |                 RESOURCE.invalidLiteral(t.image, Integer.class.getCanonicalName())); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | int IntLiteral() : | 
 | { | 
 |     Token t; | 
 | } | 
 | { | 
 |     ( | 
 |         t = <UNSIGNED_INTEGER_LITERAL> | 
 |     | | 
 |         <PLUS> t = <UNSIGNED_INTEGER_LITERAL> | 
 |     ) | 
 |     { | 
 |         try { | 
 |             return Integer.parseInt(t.image); | 
 |         } catch (NumberFormatException ex) { | 
 |             throw SqlUtil.newContextException(getPos(), | 
 |                 RESOURCE.invalidLiteral(t.image, Integer.class.getCanonicalName())); | 
 |         } | 
 |     } | 
 | | | 
 |     <MINUS> t = <UNSIGNED_INTEGER_LITERAL> { | 
 |         try { | 
 |             return -Integer.parseInt(t.image); | 
 |         } catch (NumberFormatException ex) { | 
 |             throw SqlUtil.newContextException(getPos(), | 
 |                 RESOURCE.invalidLiteral(t.image, Integer.class.getCanonicalName())); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | // Type name with optional scale and precision. | 
 | SqlDataTypeSpec DataType() : | 
 | { | 
 |     SqlTypeNameSpec typeName; | 
 |     final Span s; | 
 | } | 
 | { | 
 |     typeName = TypeName() { | 
 |         s = Span.of(typeName.getParserPos()); | 
 |     } | 
 |     ( | 
 |         typeName = CollectionsTypeName(typeName) | 
 |     )* | 
 |     { | 
 |         return new SqlDataTypeSpec(typeName, s.add(typeName.getParserPos()).pos()); | 
 |     } | 
 | } | 
 |  | 
 | // Some SQL type names need special handling due to the fact that they have | 
 | // spaces in them but are not quoted. | 
 | SqlTypeNameSpec TypeName() : | 
 | { | 
 |     final SqlTypeNameSpec typeNameSpec; | 
 |     final SqlIdentifier typeName; | 
 |     final Span s = Span.of(); | 
 | } | 
 | { | 
 |     ( | 
 | <#-- additional types are included here --> | 
 | <#-- put custom data types in front of Calcite core data types --> | 
 | <#list (parser.dataTypeParserMethods!default.parser.dataTypeParserMethods) as method> | 
 |         LOOKAHEAD(2) | 
 |         typeNameSpec = ${method} | 
 |     | | 
 | </#list> | 
 |         LOOKAHEAD(2) | 
 |         typeNameSpec = SqlTypeName(s) | 
 |     | | 
 |         typeNameSpec = RowTypeName() | 
 |     | | 
 |         LOOKAHEAD(2) | 
 |         typeNameSpec = MapTypeName() | 
 |     | | 
 |         typeName = CompoundIdentifier() { | 
 |             typeNameSpec = new SqlUserDefinedTypeNameSpec(typeName, s.end(this)); | 
 |         } | 
 |     ) | 
 |     { | 
 |         return typeNameSpec; | 
 |     } | 
 | } | 
 |  | 
 | // Types used for JDBC and ODBC scalar conversion function | 
 | SqlTypeNameSpec SqlTypeName(Span s) : | 
 | { | 
 |     final SqlTypeNameSpec sqlTypeNameSpec; | 
 | } | 
 | { | 
 |     ( | 
 |         sqlTypeNameSpec = SqlTypeName1(s) | 
 |     | | 
 |         sqlTypeNameSpec = SqlTypeName2(s) | 
 |     | | 
 |         sqlTypeNameSpec = SqlTypeName3(s) | 
 |     | | 
 |         sqlTypeNameSpec = CharacterTypeName(s) | 
 |     | | 
 |         sqlTypeNameSpec = DateTimeTypeName() | 
 |     ) | 
 |     { | 
 |         return sqlTypeNameSpec; | 
 |     } | 
 | } | 
 |  | 
 | // Parse sql type name that don't allow any extra specifications except the type name. | 
 | // For extra specification, we mean precision, scale, charSet, etc. | 
 | SqlTypeNameSpec SqlTypeName1(Span s) : | 
 | { | 
 |     final SqlTypeName sqlTypeName; | 
 | } | 
 | { | 
 |     ( | 
 |         <GEOMETRY> { | 
 |             if (!this.conformance.allowGeometry()) { | 
 |                 throw SqlUtil.newContextException(getPos(), RESOURCE.geometryDisabled()); | 
 |             } | 
 |             s.add(this); | 
 |             sqlTypeName = SqlTypeName.GEOMETRY; | 
 |         } | 
 |     | | 
 |         <BOOLEAN> { s.add(this); sqlTypeName = SqlTypeName.BOOLEAN; } | 
 |     | | 
 |         ( <INTEGER> | <INT> ) { s.add(this); sqlTypeName = SqlTypeName.INTEGER; } | 
 |     | | 
 |         <TINYINT> { s.add(this); sqlTypeName = SqlTypeName.TINYINT; } | 
 |     | | 
 |         <SMALLINT> { s.add(this); sqlTypeName = SqlTypeName.SMALLINT; } | 
 |     | | 
 |         <BIGINT> { s.add(this); sqlTypeName = SqlTypeName.BIGINT; } | 
 |     | | 
 |         <REAL> { s.add(this); sqlTypeName = SqlTypeName.REAL; } | 
 |     | | 
 |         <DOUBLE> { s.add(this); } | 
 |         [ <PRECISION> ] { sqlTypeName = SqlTypeName.DOUBLE; } | 
 |     | | 
 |         <FLOAT> { s.add(this); sqlTypeName = SqlTypeName.FLOAT; } | 
 |     ) | 
 |     { | 
 |         return new SqlBasicTypeNameSpec(sqlTypeName, s.end(this)); | 
 |     } | 
 | } | 
 |  | 
 | // Parse sql type name that allows precision specification. | 
 | SqlTypeNameSpec SqlTypeName2(Span s) : | 
 | { | 
 |     final SqlTypeName sqlTypeName; | 
 |     int precision = -1; | 
 | } | 
 | { | 
 |     ( | 
 |         <BINARY> { s.add(this); } | 
 |         ( | 
 |             <VARYING> { sqlTypeName = SqlTypeName.VARBINARY; } | 
 |         | | 
 |             { sqlTypeName = SqlTypeName.BINARY; } | 
 |         ) | 
 |     | | 
 |         <VARBINARY> { s.add(this); sqlTypeName = SqlTypeName.VARBINARY; } | 
 |     ) | 
 |     precision = PrecisionOpt() | 
 |     { | 
 |         return new SqlBasicTypeNameSpec(sqlTypeName, precision, s.end(this)); | 
 |     } | 
 | } | 
 |  | 
 | // Parse sql type name that allows precision and scale specifications. | 
 | SqlTypeNameSpec SqlTypeName3(Span s) : | 
 | { | 
 |     final SqlTypeName sqlTypeName; | 
 |     int precision = -1; | 
 |     int scale = -1; | 
 | } | 
 | { | 
 |     ( | 
 |         (<DECIMAL> | <DEC> | <NUMERIC>) { s.add(this); sqlTypeName = SqlTypeName.DECIMAL; } | 
 |     | | 
 |         <ANY> { s.add(this); sqlTypeName = SqlTypeName.ANY; } | 
 |     ) | 
 |     [ | 
 |         <LPAREN> | 
 |         precision = UnsignedIntLiteral() | 
 |         [ | 
 |             <COMMA> | 
 |             scale = UnsignedIntLiteral() | 
 |         ] | 
 |         <RPAREN> | 
 |     ] | 
 |     { | 
 |         return new SqlBasicTypeNameSpec(sqlTypeName, precision, scale, s.end(this)); | 
 |     } | 
 | } | 
 |  | 
 | // Types used for for JDBC and ODBC scalar conversion function | 
 | SqlJdbcDataTypeName JdbcOdbcDataTypeName() : | 
 | { | 
 | } | 
 | { | 
 |     (<SQL_CHAR> | <CHAR>) { return SqlJdbcDataTypeName.SQL_CHAR; } | 
 | |   (<SQL_VARCHAR> | <VARCHAR>) { return SqlJdbcDataTypeName.SQL_VARCHAR; } | 
 | |   (<SQL_DATE> | <DATE>) { return SqlJdbcDataTypeName.SQL_DATE; } | 
 | |   (<SQL_TIME> | <TIME>) { return SqlJdbcDataTypeName.SQL_TIME; } | 
 | |   (<SQL_TIMESTAMP> | <TIMESTAMP>) { return SqlJdbcDataTypeName.SQL_TIMESTAMP; } | 
 | |   (<SQL_DECIMAL> | <DECIMAL>) { return SqlJdbcDataTypeName.SQL_DECIMAL; } | 
 | |   (<SQL_NUMERIC> | <NUMERIC>) { return SqlJdbcDataTypeName.SQL_NUMERIC; } | 
 | |   (<SQL_BOOLEAN> | <BOOLEAN>) { return SqlJdbcDataTypeName.SQL_BOOLEAN; } | 
 | |   (<SQL_INTEGER> | <INTEGER>) { return SqlJdbcDataTypeName.SQL_INTEGER; } | 
 | |   (<SQL_BINARY> | <BINARY>) { return SqlJdbcDataTypeName.SQL_BINARY; } | 
 | |   (<SQL_VARBINARY> | <VARBINARY>) { return SqlJdbcDataTypeName.SQL_VARBINARY; } | 
 | |   (<SQL_TINYINT> | <TINYINT>) { return SqlJdbcDataTypeName.SQL_TINYINT; } | 
 | |   (<SQL_SMALLINT> | <SMALLINT>) { return SqlJdbcDataTypeName.SQL_SMALLINT; } | 
 | |   (<SQL_BIGINT> | <BIGINT>) { return SqlJdbcDataTypeName.SQL_BIGINT; } | 
 | |   (<SQL_REAL>| <REAL>) { return SqlJdbcDataTypeName.SQL_REAL; } | 
 | |   (<SQL_DOUBLE> | <DOUBLE>) { return SqlJdbcDataTypeName.SQL_DOUBLE; } | 
 | |   (<SQL_FLOAT> | <FLOAT>) { return SqlJdbcDataTypeName.SQL_FLOAT; } | 
 | |   <SQL_INTERVAL_YEAR> { return SqlJdbcDataTypeName.SQL_INTERVAL_YEAR; } | 
 | |   <SQL_INTERVAL_YEAR_TO_MONTH> { return SqlJdbcDataTypeName.SQL_INTERVAL_YEAR_TO_MONTH; } | 
 | |   <SQL_INTERVAL_MONTH> { return SqlJdbcDataTypeName.SQL_INTERVAL_MONTH; } | 
 | |   <SQL_INTERVAL_DAY> { return SqlJdbcDataTypeName.SQL_INTERVAL_DAY; } | 
 | |   <SQL_INTERVAL_DAY_TO_HOUR> { return SqlJdbcDataTypeName.SQL_INTERVAL_DAY_TO_HOUR; } | 
 | |   <SQL_INTERVAL_DAY_TO_MINUTE> { return SqlJdbcDataTypeName.SQL_INTERVAL_DAY_TO_MINUTE; } | 
 | |   <SQL_INTERVAL_DAY_TO_SECOND> { return SqlJdbcDataTypeName.SQL_INTERVAL_DAY_TO_SECOND; } | 
 | |   <SQL_INTERVAL_HOUR> { return SqlJdbcDataTypeName.SQL_INTERVAL_HOUR; } | 
 | |   <SQL_INTERVAL_HOUR_TO_MINUTE> { return SqlJdbcDataTypeName.SQL_INTERVAL_HOUR_TO_MINUTE; } | 
 | |   <SQL_INTERVAL_HOUR_TO_SECOND> { return SqlJdbcDataTypeName.SQL_INTERVAL_HOUR_TO_SECOND; } | 
 | |   <SQL_INTERVAL_MINUTE> { return SqlJdbcDataTypeName.SQL_INTERVAL_MINUTE; } | 
 | |   <SQL_INTERVAL_MINUTE_TO_SECOND> { return SqlJdbcDataTypeName.SQL_INTERVAL_MINUTE_TO_SECOND; } | 
 | |   <SQL_INTERVAL_SECOND> { return SqlJdbcDataTypeName.SQL_INTERVAL_SECOND; } | 
 | } | 
 |  | 
 | SqlLiteral JdbcOdbcDataType() : | 
 | { | 
 |     SqlJdbcDataTypeName typeName; | 
 | } | 
 | { | 
 |     typeName = JdbcOdbcDataTypeName() { | 
 |         return typeName.symbol(getPos()); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 | * Parse a collection type name, the input element type name may | 
 | * also be a collection type. | 
 | */ | 
 | SqlTypeNameSpec CollectionsTypeName(SqlTypeNameSpec elementTypeName) : | 
 | { | 
 |     final SqlTypeName collectionTypeName; | 
 | } | 
 | { | 
 |     ( | 
 |         <MULTISET> { collectionTypeName = SqlTypeName.MULTISET; } | 
 |     | | 
 |         <ARRAY> { collectionTypeName = SqlTypeName.ARRAY; } | 
 |     ) | 
 |     { | 
 |         return new SqlCollectionTypeNameSpec(elementTypeName, | 
 |                 collectionTypeName, getPos()); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 | * Parse a nullable option, default is true. | 
 | */ | 
 | boolean NullableOptDefaultTrue() : | 
 | { | 
 | } | 
 | { | 
 |     <NULL> { return true; } | 
 | | | 
 |     <NOT> <NULL> { return false; } | 
 | | | 
 |     { return true; } | 
 | } | 
 |  | 
 | /** | 
 | * Parse a nullable option, default is false. | 
 | */ | 
 | boolean NullableOptDefaultFalse() : | 
 | { | 
 | } | 
 | { | 
 |     <NULL> { return true; } | 
 | | | 
 |     <NOT> <NULL> { return false; } | 
 | | | 
 |     { return false; } | 
 | } | 
 |  | 
 | /** Parses NOT NULL and returns false, or parses nothing and returns true. */ | 
 | boolean NotNullOpt() : | 
 | { | 
 | } | 
 | { | 
 |     <NOT> <NULL> { return false; } | 
 | | | 
 |     { return true; } | 
 | } | 
 |  | 
 | /** | 
 | * Parse a "name1 type1 [NULL | NOT NULL], name2 type2 [NULL | NOT NULL] ..." list, | 
 | * the field type default is not nullable. | 
 | */ | 
 | void AddFieldNameTypes(List<SqlIdentifier> fieldNames, | 
 |     List<SqlDataTypeSpec> fieldTypes) : | 
 | { | 
 | } | 
 | { | 
 |     AddFieldNameType(fieldNames, fieldTypes) | 
 |     ( <COMMA> AddFieldNameType(fieldNames, fieldTypes) )* | 
 | } | 
 |  | 
 | void AddFieldNameType(List<SqlIdentifier> fieldNames, | 
 |     List<SqlDataTypeSpec> fieldTypes) : | 
 | { | 
 |     final SqlIdentifier fName; | 
 |     final SqlDataTypeSpec fType; | 
 |     final boolean nullable; | 
 | } | 
 | { | 
 |     fName = SimpleIdentifier() | 
 |     fType = DataType() | 
 |     nullable = NullableOptDefaultFalse() | 
 |     { | 
 |         fieldNames.add(fName); | 
 |         fieldTypes.add(fType.withNullable(nullable, getPos())); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 | * Parse Row type with format: Row(name1 type1, name2 type2). | 
 | * Every field type can have suffix of `NULL` or `NOT NULL` to indicate if this type is nullable. | 
 | * i.e. Row(f0 int not null, f1 varchar null). | 
 | */ | 
 | SqlTypeNameSpec RowTypeName() : | 
 | { | 
 |     List<SqlIdentifier> fieldNames = new ArrayList<SqlIdentifier>(); | 
 |     List<SqlDataTypeSpec> fieldTypes = new ArrayList<SqlDataTypeSpec>(); | 
 | } | 
 | { | 
 |     <ROW> | 
 |     <LPAREN> AddFieldNameTypes(fieldNames, fieldTypes) <RPAREN> | 
 |     { | 
 |         return new SqlRowTypeNameSpec(getPos(), fieldNames, fieldTypes); | 
 |     } | 
 | } | 
 |  | 
 | SqlTypeNameSpec MapTypeName() : | 
 | { | 
 |     SqlDataTypeSpec keyType = null; | 
 |     SqlDataTypeSpec valType = null; | 
 | } | 
 | { | 
 |     <MAP> | 
 |     <LT> | 
 |     keyType = DataType() | 
 |     <COMMA> | 
 |     valType = DataType() | 
 |     <GT> | 
 |     { | 
 |         return new SqlMapTypeNameSpec(keyType, valType, getPos()); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 | * Parse character types: char, varchar. | 
 | */ | 
 | SqlTypeNameSpec CharacterTypeName(Span s) : | 
 | { | 
 |     int precision = -1; | 
 |     final SqlTypeName sqlTypeName; | 
 |     String charSetName = null; | 
 | } | 
 | { | 
 |     ( | 
 |         (<CHARACTER> | <CHAR>) { s.add(this); } | 
 |         ( | 
 |             <VARYING> { sqlTypeName = SqlTypeName.VARCHAR; } | 
 |         | | 
 |             { sqlTypeName = SqlTypeName.CHAR; } | 
 |         ) | 
 |     | | 
 |         <VARCHAR> { s.add(this); sqlTypeName = SqlTypeName.VARCHAR; } | 
 |     ) | 
 |     precision = PrecisionOpt() | 
 |     [ | 
 |         <CHARACTER> <SET> | 
 |         charSetName = Identifier() | 
 |     ] | 
 |     { | 
 |         return new SqlBasicTypeNameSpec(sqlTypeName, precision, charSetName, s.end(this)); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 | * Parse datetime types: date, time, timestamp. | 
 | */ | 
 | SqlTypeNameSpec DateTimeTypeName() : | 
 | { | 
 |     int precision = -1; | 
 |     SqlTypeName typeName; | 
 |     final Span s; | 
 | } | 
 | { | 
 |     <DATE> { | 
 |         typeName = SqlTypeName.DATE; | 
 |         return new SqlBasicTypeNameSpec(typeName, getPos()); | 
 |     } | 
 | | | 
 |     LOOKAHEAD(2) | 
 |     <TIME> { s = span(); } | 
 |     precision = PrecisionOpt() | 
 |     typeName = TimeZoneOpt(true) | 
 |     { | 
 |         return new SqlBasicTypeNameSpec(typeName, precision, s.end(this)); | 
 |     } | 
 | | | 
 |     <TIMESTAMP> { s = span(); } | 
 |     precision = PrecisionOpt() | 
 |     typeName = TimeZoneOpt(false) | 
 |     { | 
 |         return new SqlBasicTypeNameSpec(typeName, precision, s.end(this)); | 
 |     } | 
 | } | 
 |  | 
 | // Parse an optional data type precision, default is -1. | 
 | int PrecisionOpt() : | 
 | { | 
 |     int precision = -1; | 
 | } | 
 | { | 
 |     <LPAREN> | 
 |     precision = UnsignedIntLiteral() | 
 |     <RPAREN> | 
 |     { return precision; } | 
 | | | 
 |     { return -1; } | 
 | } | 
 |  | 
 | /** | 
 | * Parse a time zone suffix for DateTime types. According to SQL-2011, | 
 | * "with time zone" and "without time zone" belong to standard SQL. | 
 | * We also support "with local time zone". | 
 | */ | 
 | SqlTypeName TimeZoneOpt(boolean timeType) : | 
 | { | 
 |     boolean local = false; | 
 | } | 
 | { | 
 |     LOOKAHEAD(3) | 
 |     <WITHOUT> <TIME> <ZONE> { return timeType ? SqlTypeName.TIME : SqlTypeName.TIMESTAMP;  } | 
 | | | 
 |     <WITH> ( <LOCAL> { local = true; } )? <TIME> <ZONE> { | 
 |         return timeType ? (local ? SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE : SqlTypeName.TIME_TZ) | 
 |                         : (local ? SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE : SqlTypeName.TIMESTAMP_TZ); } | 
 | | | 
 |     { return timeType ? SqlTypeName.TIME : SqlTypeName.TIMESTAMP; } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a CURSOR(query) expression.  The parser allows these | 
 |  * anywhere, but the validator restricts them to appear only as | 
 |  * arguments to table functions. | 
 |  */ | 
 | SqlNode CursorExpression(ExprContext exprContext) : | 
 | { | 
 |     final SqlNode e; | 
 |     final Span s; | 
 | } | 
 | { | 
 |     <CURSOR> { | 
 |         s = span(); | 
 |         if (exprContext != ExprContext.ACCEPT_ALL | 
 |                 && exprContext != ExprContext.ACCEPT_CURSOR) { | 
 |             throw SqlUtil.newContextException(s.end(this), | 
 |                 RESOURCE.illegalCursorExpression()); | 
 |         } | 
 |     } | 
 |     e = Expression(ExprContext.ACCEPT_QUERY) { | 
 |         return SqlStdOperatorTable.CURSOR.createCall(s.end(e), e); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a call to a builtin function with special syntax. | 
 |  */ | 
 | SqlNode BuiltinFunctionCall() : | 
 | { | 
 |     final SqlIdentifier name; | 
 |     final List<SqlNode> args = new ArrayList<SqlNode>(); | 
 |     SqlNode e; | 
 |     final Span s; | 
 |     SqlDataTypeSpec dt; | 
 |     final SqlIntervalQualifier unit; | 
 |     final SqlNode node; | 
 |     final SqlLiteral style; // mssql convert 'style' operand | 
 |     final SqlFunction f; | 
 |     final SqlNode format; | 
 | } | 
 | { | 
 |     //~ FUNCTIONS WITH SPECIAL SYNTAX --------------------------------------- | 
 |     ( | 
 |         (  <CAST> { f = SqlStdOperatorTable.CAST; } | 
 |         | <SAFE_CAST> { f = SqlLibraryOperators.SAFE_CAST; } | 
 |         | <TRY_CAST> { f = SqlLibraryOperators.TRY_CAST; } | 
 |         ) | 
 |         { s = span(); } | 
 |         <LPAREN> AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |         <AS> | 
 |         ( | 
 |             dt = DataType() { args.add(dt); } | 
 |         | | 
 |             <INTERVAL> e = IntervalQualifier() { args.add(e); } | 
 |         ) | 
 |         [ <FORMAT> format = StringLiteral() { args.add(format); } ] | 
 |         <RPAREN> { | 
 |             return f.createCall(s.end(this), args); | 
 |         } | 
 |     | | 
 |         <EXTRACT> { s = span(); } | 
 |         <LPAREN> unit = TimeUnitOrName() { | 
 |             args.add(unit); | 
 |         } | 
 |         <FROM> | 
 |         AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |         <RPAREN> { | 
 |             return SqlStdOperatorTable.EXTRACT.createCall(s.end(this), args); | 
 |         } | 
 |     | | 
 |         <POSITION> { s = span(); } | 
 |         <LPAREN> | 
 |         // FIXME jvs 31-Aug-2006:  FRG-192:  This should be | 
 |         // Expression(ExprContext.ACCEPT_SUB_QUERY), but that doesn't work | 
 |         // because it matches the other kind of IN. | 
 |         e = AtomicRowExpression() { args.add(e); } | 
 |         <IN> | 
 |         AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |         [ <FROM> AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) ] | 
 |         <RPAREN> { | 
 |             return SqlStdOperatorTable.POSITION.createCall(s.end(this), args); | 
 |         } | 
 |     | | 
 |         <CONVERT> { s = span(); } | 
 |         <LPAREN> | 
 |         ( | 
 |             // CONVERT in the form of CONVERT(x USING y) | 
 |  | 
 |             // "AddExpression" matches INTERVAL, | 
 |             // which can also be 1st token in args of MSSQL CONVERT | 
 |             // So lookahead another token (to match <USING> vs. <COMMA>) | 
 |             LOOKAHEAD(2) | 
 |             AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |             ( | 
 |                 <USING> name = SimpleIdentifier() { args.add(name); } | 
 |                 <RPAREN> { | 
 |                     return SqlStdOperatorTable.TRANSLATE.createCall(s.end(this), args); | 
 |                 } | 
 |             | | 
 |                 <COMMA> e = SimpleIdentifier() { args.add(e); } | 
 |                 <COMMA> e = SimpleIdentifier() { args.add(e); } | 
 |                 <RPAREN> { | 
 |                     return SqlStdOperatorTable.CONVERT.createCall(s.end(this), args); | 
 |                 } | 
 |             ) | 
 |         | | 
 |             // MSSql CONVERT(type, val [,style]) | 
 |             ( | 
 |                 dt = DataType() { args.add(dt); } | 
 |             | | 
 |                 <INTERVAL> e = IntervalQualifier() { args.add(e); } | 
 |             ) | 
 |             <COMMA> | 
 |             AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |             [ | 
 |                 <COMMA> | 
 |                 ( | 
 |                     style = UnsignedNumericLiteral() { args.add(style); } | 
 |                 | | 
 |                     <NULL> { args.add(SqlLiteral.createNull(getPos())); } | 
 |                 ) | 
 |             ] | 
 |             <RPAREN> { | 
 |                 return SqlLibraryOperators.MSSQL_CONVERT.createCall(s.end(this), args); | 
 |             } | 
 |         ) | 
 |     | | 
 |         <TRANSLATE> { s = span(); } | 
 |         <LPAREN> | 
 |         AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |         ( | 
 |             <USING> name = SimpleIdentifier() { args.add(name); } | 
 |             <RPAREN> { | 
 |                 return SqlStdOperatorTable.TRANSLATE.createCall(s.end(this), | 
 |                     args); | 
 |             } | 
 |         | | 
 |             ( <COMMA> AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) )* | 
 |             <RPAREN> { | 
 |                 return SqlLibraryOperators.TRANSLATE3.createCall(s.end(this), | 
 |                     args); | 
 |             } | 
 |         ) | 
 |     | | 
 |         <OVERLAY> { s = span(); } | 
 |         <LPAREN> AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |         <PLACING> AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |         <FROM> AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |         [ <FOR> AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) ] | 
 |         <RPAREN> { | 
 |             return SqlStdOperatorTable.OVERLAY.createCall(s.end(this), args); | 
 |         } | 
 |     | | 
 |         <FLOOR> { s = span(); } | 
 |         e = FloorCeilOptions(s, true) { | 
 |             return e; | 
 |         } | 
 |     | | 
 |         ( <CEIL> | <CEILING>) { s = span(); } | 
 |         e = FloorCeilOptions(s, false) { | 
 |             return e; | 
 |         } | 
 |     | | 
 |         <SUBSTRING> { s = span(); } | 
 |         <LPAREN> | 
 |         AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |         ( <FROM> | <COMMA>) | 
 |         AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |         [ | 
 |             (<FOR> | <COMMA>) | 
 |             AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |         ] | 
 |         <RPAREN> { | 
 |             return SqlStdOperatorTable.SUBSTRING.createCall( | 
 |                 s.end(this), args); | 
 |         } | 
 |     | | 
 |         <TRIM> { | 
 |             SqlLiteral flag = null; | 
 |             SqlNode trimChars = null; | 
 |             s = span(); | 
 |         } | 
 |         <LPAREN> | 
 |         [ | 
 |             LOOKAHEAD(2) | 
 |             [ | 
 |                 <BOTH> { | 
 |                     s.add(this); | 
 |                     flag = SqlTrimFunction.Flag.BOTH.symbol(getPos()); | 
 |                 } | 
 |             | | 
 |                 <TRAILING> { | 
 |                     s.add(this); | 
 |                     flag = SqlTrimFunction.Flag.TRAILING.symbol(getPos()); | 
 |                 } | 
 |             | | 
 |                 <LEADING> { | 
 |                     s.add(this); | 
 |                     flag = SqlTrimFunction.Flag.LEADING.symbol(getPos()); | 
 |                 } | 
 |             ] | 
 |             [ trimChars = Expression(ExprContext.ACCEPT_SUB_QUERY) ] | 
 |             ( | 
 |                 <FROM> { | 
 |                     if (null == flag && null == trimChars) { | 
 |                         throw SqlUtil.newContextException(getPos(), | 
 |                             RESOURCE.illegalFromEmpty()); | 
 |                     } | 
 |                 } | 
 |             | | 
 |                 <RPAREN> { | 
 |                     // This is to handle the case of TRIM(x) | 
 |                     // (FRG-191). | 
 |                     if (flag == null) { | 
 |                         flag = SqlTrimFunction.Flag.BOTH.symbol(SqlParserPos.ZERO); | 
 |                     } | 
 |                     args.add(flag); | 
 |                     args.add(null); // no trim chars | 
 |                     args.add(trimChars); // reinterpret trimChars as source | 
 |                     return SqlStdOperatorTable.TRIM.createCall(s.end(this), | 
 |                         args); | 
 |                 } | 
 |             ) | 
 |         ] | 
 |         e = Expression(ExprContext.ACCEPT_SUB_QUERY) { | 
 |             if (flag == null) { | 
 |                 flag = SqlTrimFunction.Flag.BOTH.symbol(SqlParserPos.ZERO); | 
 |             } | 
 |             args.add(flag); | 
 |             args.add(trimChars); | 
 |             args.add(e); | 
 |         } | 
 |         <RPAREN> { | 
 |             return SqlStdOperatorTable.TRIM.createCall(s.end(this), args); | 
 |         } | 
 |     | | 
 |         node = ContainsSubstrFunctionCall() { return node; } | 
 |     | | 
 |         node = DateTimeConstructorCall() { return node; } | 
 |     | | 
 |         node = DateDiffFunctionCall() { return node; } | 
 |     | | 
 |         node = DateTruncFunctionCall() { return node; } | 
 |     | | 
 |         node = DatetimeTruncFunctionCall() { return node; } | 
 |     | | 
 |         node = TimestampAddFunctionCall() { return node; } | 
 |     | | 
 |         node = DatetimeDiffFunctionCall() { return node; } | 
 |     | | 
 |         node = TimestampDiffFunctionCall() { return node; } | 
 |     | | 
 |         node = TimestampDiff3FunctionCall() { return node; } | 
 |     | | 
 |         node = TimestampTruncFunctionCall() { return node; } | 
 |     | | 
 |         node = TimeDiffFunctionCall() { return node; } | 
 |     | | 
 |         node = TimeTruncFunctionCall() { return node; } | 
 |     | | 
 | <#list (parser.builtinFunctionCallMethods!default.parser.builtinFunctionCallMethods) as method> | 
 |         node = ${method} { return node; } | 
 |     | | 
 | </#list> | 
 |         node = MatchRecognizeFunctionCall() { return node; } | 
 |     | | 
 |         node = JsonExistsFunctionCall() { return node; } | 
 |     | | 
 |         node = JsonValueFunctionCall() { return node; } | 
 |     | | 
 |         node = JsonQueryFunctionCall() { return node; } | 
 |     | | 
 |         node = JsonObjectFunctionCall() { return node; } | 
 |     | | 
 |         node = JsonObjectAggFunctionCall() { return node; } | 
 |     | | 
 |         node = JsonArrayFunctionCall() { return node; } | 
 |     | | 
 |         node = JsonArrayAggFunctionCall() { return node; } | 
 |     | | 
 |         node = GroupByWindowingCall() { return node; } | 
 |     ) | 
 | } | 
 |  | 
 | SqlJsonEncoding JsonRepresentation() : | 
 | { | 
 | } | 
 | { | 
 |     <JSON> | 
 |     [ | 
 |         // Encoding is currently ignored. | 
 |         LOOKAHEAD(2) <ENCODING> | 
 |         ( | 
 |             <UTF8> { return SqlJsonEncoding.UTF8; } | 
 |         | | 
 |             <UTF16> { return SqlJsonEncoding.UTF16; } | 
 |         | | 
 |             <UTF32> { return SqlJsonEncoding.UTF32; } | 
 |         ) | 
 |     ] | 
 |     { | 
 |         return SqlJsonEncoding.UTF8; | 
 |     } | 
 | } | 
 |  | 
 | void JsonInputClause() : | 
 | { | 
 | } | 
 | { | 
 |     <FORMAT> JsonRepresentation() | 
 | } | 
 |  | 
 | SqlDataTypeSpec JsonReturningClause() : | 
 | { | 
 |     SqlDataTypeSpec dt; | 
 | } | 
 | { | 
 |     <RETURNING> dt = DataType() { return dt; } | 
 | } | 
 |  | 
 | SqlDataTypeSpec JsonOutputClause() : | 
 | { | 
 |     SqlDataTypeSpec dataType; | 
 | } | 
 | { | 
 |     dataType = JsonReturningClause() | 
 |     [ | 
 |         <FORMAT> JsonRepresentation() | 
 |     ] | 
 |     { | 
 |         return dataType; | 
 |     } | 
 | } | 
 |  | 
 | SqlNode JsonPathSpec() : | 
 | { | 
 |     SqlNode e; | 
 | } | 
 | { | 
 |     e = StringLiteral() { | 
 |         return e; | 
 |     } | 
 | } | 
 |  | 
 | List<SqlNode> JsonApiCommonSyntax() : | 
 | { | 
 |     SqlNode e; | 
 |     final List<SqlNode> args = new ArrayList<SqlNode>(); | 
 | } | 
 | { | 
 |     AddExpression(args, ExprContext.ACCEPT_NON_QUERY) | 
 |     <COMMA> | 
 |     AddExpression(args, ExprContext.ACCEPT_NON_QUERY) | 
 |     [ | 
 |         // We currently don't support JSON passing clause, leave the java code blocks no-op | 
 |         <PASSING> e = Expression(ExprContext.ACCEPT_NON_QUERY) { | 
 |             // no-op | 
 |         } | 
 |         <AS> e = SimpleIdentifier() { | 
 |             // no-op | 
 |         } | 
 |         ( | 
 |             <COMMA> | 
 |             e = Expression(ExprContext.ACCEPT_NON_QUERY) { | 
 |                 // no-op | 
 |             } | 
 |             <AS> e = SimpleIdentifier() { | 
 |                 // no-op | 
 |             } | 
 |         )* | 
 |     ] | 
 |     { | 
 |         return args; | 
 |     } | 
 | } | 
 |  | 
 | SqlJsonExistsErrorBehavior JsonExistsErrorBehavior() : | 
 | { | 
 |  | 
 | } | 
 | { | 
 |     <TRUE> { return SqlJsonExistsErrorBehavior.TRUE; } | 
 |     | | 
 |     <FALSE> { return SqlJsonExistsErrorBehavior.FALSE; } | 
 |     | | 
 |     <UNKNOWN> { return SqlJsonExistsErrorBehavior.UNKNOWN; } | 
 |     | | 
 |     <ERROR> { return SqlJsonExistsErrorBehavior.ERROR; } | 
 | } | 
 |  | 
 | SqlCall JsonExistsFunctionCall() : | 
 | { | 
 |     List<SqlNode> args = new ArrayList<SqlNode>(); | 
 |     List<SqlNode> commonSyntax; | 
 |     final Span span; | 
 |     SqlJsonExistsErrorBehavior errorBehavior; | 
 | } | 
 | { | 
 |     <JSON_EXISTS> { span = span(); } | 
 |     <LPAREN> commonSyntax = JsonApiCommonSyntax() { | 
 |         args.addAll(commonSyntax); | 
 |     } | 
 |     [ | 
 |         errorBehavior = JsonExistsErrorBehavior() { args.add(errorBehavior.symbol(getPos())); } | 
 |         <ON> <ERROR> | 
 |     ] | 
 |     <RPAREN> { | 
 |         return SqlStdOperatorTable.JSON_EXISTS.createCall(span.end(this), args); | 
 |     } | 
 | } | 
 |  | 
 | List<SqlNode> JsonValueEmptyOrErrorBehavior() : | 
 | { | 
 |     final List<SqlNode> list = new ArrayList<SqlNode>(); | 
 | } | 
 | { | 
 |     ( | 
 |         <ERROR> { | 
 |             list.add(SqlJsonValueEmptyOrErrorBehavior.ERROR.symbol(getPos())); | 
 |         } | 
 |     | | 
 |         <NULL> { | 
 |             list.add(SqlJsonValueEmptyOrErrorBehavior.NULL.symbol(getPos())); | 
 |         } | 
 |     | | 
 |         <DEFAULT_> { | 
 |             list.add(SqlJsonValueEmptyOrErrorBehavior.DEFAULT.symbol(getPos())); | 
 |         } | 
 |         AddExpression(list, ExprContext.ACCEPT_NON_QUERY) | 
 |     ) | 
 |     <ON> | 
 |     ( | 
 |         <EMPTY> { | 
 |             list.add(SqlJsonEmptyOrError.EMPTY.symbol(getPos())); | 
 |         } | 
 |     | | 
 |         <ERROR> { | 
 |             list.add(SqlJsonEmptyOrError.ERROR.symbol(getPos())); | 
 |         } | 
 |     ) | 
 |     { return list; } | 
 | } | 
 |  | 
 | SqlCall JsonValueFunctionCall() : | 
 | { | 
 |     final List<SqlNode> args = new ArrayList<SqlNode>(7); | 
 |     SqlNode e; | 
 |     List<SqlNode> commonSyntax; | 
 |     final Span span; | 
 |     List<SqlNode> behavior; | 
 | } | 
 | { | 
 |     <JSON_VALUE> { span = span(); } | 
 |     <LPAREN> commonSyntax = JsonApiCommonSyntax() { | 
 |         args.addAll(commonSyntax); | 
 |     } | 
 |     [ | 
 |         e = JsonReturningClause() { | 
 |             args.add(SqlJsonValueReturning.RETURNING.symbol(getPos())); | 
 |             args.add(e); | 
 |         } | 
 |     ] | 
 |     ( | 
 |         behavior = JsonValueEmptyOrErrorBehavior() { | 
 |             args.addAll(behavior); | 
 |         } | 
 |     )* | 
 |     <RPAREN> { | 
 |         return SqlStdOperatorTable.JSON_VALUE.createCall(span.end(this), args); | 
 |     } | 
 | } | 
 |  | 
 | List<SqlNode> JsonQueryEmptyOrErrorBehavior() : | 
 | { | 
 |     final List<SqlNode> list = new ArrayList<SqlNode>(); | 
 | } | 
 | { | 
 |     ( | 
 |         <ERROR> { | 
 |             list.add(SqlLiteral.createSymbol(SqlJsonQueryEmptyOrErrorBehavior.ERROR, getPos())); | 
 |         } | 
 |     | | 
 |         <NULL> { | 
 |             list.add(SqlLiteral.createSymbol(SqlJsonQueryEmptyOrErrorBehavior.NULL, getPos())); | 
 |         } | 
 |     | | 
 |         LOOKAHEAD(2) | 
 |         <EMPTY> <ARRAY> { | 
 |             list.add(SqlLiteral.createSymbol(SqlJsonQueryEmptyOrErrorBehavior.EMPTY_ARRAY, getPos())); | 
 |         } | 
 |     | | 
 |         <EMPTY> <OBJECT> { | 
 |             list.add(SqlLiteral.createSymbol(SqlJsonQueryEmptyOrErrorBehavior.EMPTY_OBJECT, getPos())); | 
 |         } | 
 |     ) | 
 |     <ON> | 
 |     ( | 
 |         <EMPTY> { | 
 |             list.add(SqlLiteral.createSymbol(SqlJsonEmptyOrError.EMPTY, getPos())); | 
 |         } | 
 |     | | 
 |         <ERROR> { | 
 |             list.add(SqlLiteral.createSymbol(SqlJsonEmptyOrError.ERROR, getPos())); | 
 |         } | 
 |     ) | 
 |     { return list; } | 
 | } | 
 |  | 
 | SqlNode JsonQueryWrapperBehavior() : | 
 | { | 
 | } | 
 | { | 
 |     <WITHOUT> [<ARRAY>] { | 
 |         return SqlLiteral.createSymbol(SqlJsonQueryWrapperBehavior.WITHOUT_ARRAY, getPos()); | 
 |     } | 
 | | | 
 |     LOOKAHEAD(2) | 
 |     <WITH> <CONDITIONAL> [<ARRAY>] { | 
 |         return SqlLiteral.createSymbol(SqlJsonQueryWrapperBehavior.WITH_CONDITIONAL_ARRAY, getPos()); | 
 |     } | 
 | | | 
 |     <WITH> [<UNCONDITIONAL>] [<ARRAY>] { | 
 |         return SqlLiteral.createSymbol(SqlJsonQueryWrapperBehavior.WITH_UNCONDITIONAL_ARRAY, getPos()); | 
 |     } | 
 | } | 
 |  | 
 | SqlCall JsonQueryFunctionCall() : | 
 | { | 
 |     final SqlNode[] args = new SqlNode[6]; | 
 |     SqlNode e; | 
 |     List<SqlNode> commonSyntax; | 
 |     final Span span; | 
 |     List<SqlNode> behavior; | 
 | } | 
 | { | 
 |     <JSON_QUERY> { span = span(); } | 
 |     <LPAREN> commonSyntax = JsonApiCommonSyntax() { | 
 |         args[0] = commonSyntax.get(0); | 
 |         args[1] = commonSyntax.get(1); | 
 |     } | 
 |     [ | 
 |         e = JsonReturningClause() { | 
 |             args[5] = e; | 
 |         } | 
 |     ] | 
 |     [ | 
 |         e = JsonQueryWrapperBehavior() <WRAPPER> { | 
 |             args[2] = e; | 
 |         } | 
 |     ] | 
 |     ( | 
 |         behavior = JsonQueryEmptyOrErrorBehavior() { | 
 |             final SqlJsonEmptyOrError symbol = | 
 |                 ((SqlLiteral) behavior.get(1)).getValueAs(SqlJsonEmptyOrError.class); | 
 |             switch (symbol) { | 
 |             case EMPTY: | 
 |                 args[3] = behavior.get(0); | 
 |                 break; | 
 |             case ERROR: | 
 |                 args[4] = behavior.get(0); | 
 |                 break; | 
 |             } | 
 |         } | 
 |     )* | 
 |     <RPAREN> { | 
 |         return SqlStdOperatorTable.JSON_QUERY.createCall(span.end(this), args); | 
 |     } | 
 | } | 
 |  | 
 | SqlNode JsonName() : | 
 | { | 
 |     final SqlNode e; | 
 | } | 
 | { | 
 |      e = Expression(ExprContext.ACCEPT_NON_QUERY) { | 
 |         return e; | 
 |      } | 
 | } | 
 |  | 
 | List<SqlNode> JsonNameAndValue() : | 
 | { | 
 |     final List<SqlNode> list = new ArrayList<SqlNode>(); | 
 |     final SqlNode e; | 
 |     boolean kvMode = false; | 
 | } | 
 | { | 
 |     [ | 
 |         LOOKAHEAD(2, <KEY> JsonName()) | 
 |         <KEY> { kvMode = true; } | 
 |     ] | 
 |     e = JsonName() { | 
 |         list.add(e); | 
 |     } | 
 |     ( | 
 |         <VALUE> | 
 |     | | 
 |         <COMMA> { | 
 |             if (kvMode) { | 
 |                 throw SqlUtil.newContextException(getPos(), RESOURCE.illegalComma()); | 
 |             } | 
 |         } | 
 |     | | 
 |         <COLON> { | 
 |             if (kvMode) { | 
 |                 throw SqlUtil.newContextException(getPos(), RESOURCE.illegalColon()); | 
 |             } | 
 |         } | 
 |     ) | 
 |     AddExpression(list, ExprContext.ACCEPT_NON_QUERY) | 
 |     { | 
 |         return list; | 
 |     } | 
 | } | 
 |  | 
 | SqlNode JsonConstructorNullClause() : | 
 | { | 
 | } | 
 | { | 
 |     <NULL> <ON> <NULL> { | 
 |         return SqlLiteral.createSymbol(SqlJsonConstructorNullClause.NULL_ON_NULL, getPos()); | 
 |     } | 
 | | | 
 |     <ABSENT> <ON> <NULL> { | 
 |         return SqlLiteral.createSymbol(SqlJsonConstructorNullClause.ABSENT_ON_NULL, getPos()); | 
 |     } | 
 | } | 
 |  | 
 | SqlCall JsonObjectFunctionCall() : | 
 | { | 
 |     final List<SqlNode> nvArgs = new ArrayList<SqlNode>(); | 
 |     final SqlNode[] otherArgs = new SqlNode[1]; | 
 |     SqlNode e; | 
 |     List<SqlNode> list; | 
 |     final Span span; | 
 | } | 
 | { | 
 |     <JSON_OBJECT> { span = span(); } | 
 |     <LPAREN> [ | 
 |         LOOKAHEAD(2) | 
 |         list = JsonNameAndValue() { | 
 |             nvArgs.addAll(list); | 
 |         } | 
 |         ( | 
 |             <COMMA> | 
 |             list = JsonNameAndValue() { | 
 |                 nvArgs.addAll(list); | 
 |             } | 
 |         )* | 
 |     ] | 
 |     [ | 
 |         e = JsonConstructorNullClause() { | 
 |             otherArgs[0] = e; | 
 |         } | 
 |     ] | 
 |     <RPAREN> { | 
 |         final List<SqlNode> args = new ArrayList(); | 
 |         args.addAll(Arrays.asList(otherArgs)); | 
 |         args.addAll(nvArgs); | 
 |         return SqlStdOperatorTable.JSON_OBJECT.createCall(span.end(this), args); | 
 |     } | 
 | } | 
 |  | 
 | SqlCall JsonObjectAggFunctionCall() : | 
 | { | 
 |     final SqlNode[] args = new SqlNode[2]; | 
 |     List<SqlNode> list; | 
 |     final Span span; | 
 |     SqlJsonConstructorNullClause nullClause = | 
 |         SqlJsonConstructorNullClause.NULL_ON_NULL; | 
 |     final SqlNode e; | 
 | } | 
 | { | 
 |     <JSON_OBJECTAGG> { span = span(); } | 
 |     <LPAREN> list = JsonNameAndValue() { | 
 |         args[0] = list.get(0); | 
 |         args[1] = list.get(1); | 
 |     } | 
 |     [ | 
 |         e = JsonConstructorNullClause() { | 
 |             nullClause = (SqlJsonConstructorNullClause) ((SqlLiteral) e).getValue(); | 
 |         } | 
 |     ] | 
 |     <RPAREN> { | 
 |         return SqlStdOperatorTable.JSON_OBJECTAGG.with(nullClause) | 
 |             .createCall(span.end(this), args); | 
 |     } | 
 | } | 
 |  | 
 | SqlCall JsonArrayFunctionCall() : | 
 | { | 
 |     final List<SqlNode> elements = new ArrayList<SqlNode>(); | 
 |     final SqlNode[] otherArgs = new SqlNode[1]; | 
 |     SqlNode e; | 
 |     final Span span; | 
 | } | 
 | { | 
 |     <JSON_ARRAY> { span = span(); } | 
 |     <LPAREN> [ | 
 |         LOOKAHEAD(2) | 
 |         AddExpression(elements, ExprContext.ACCEPT_NON_QUERY) | 
 |         ( <COMMA> AddExpression(elements, ExprContext.ACCEPT_NON_QUERY) )* | 
 |     ] | 
 |     [ | 
 |         e = JsonConstructorNullClause() { | 
 |             otherArgs[0] = e; | 
 |         } | 
 |     ] | 
 |     <RPAREN> { | 
 |         final List<SqlNode> args = new ArrayList(); | 
 |         args.addAll(Arrays.asList(otherArgs)); | 
 |         args.addAll(elements); | 
 |         return SqlStdOperatorTable.JSON_ARRAY.createCall(span.end(this), args); | 
 |     } | 
 | } | 
 |  | 
 | SqlNodeList JsonArrayAggOrderByClause() : | 
 | { | 
 |     final SqlNodeList orderList; | 
 | } | 
 | { | 
 |     orderList = OrderBy(true) | 
 |     { return orderList; } | 
 | } | 
 |  | 
 | SqlCall JsonArrayAggFunctionCall() : | 
 | { | 
 |     final SqlNode valueExpr; | 
 |     final SqlNodeList orderList; | 
 |     final Span span; | 
 |     final SqlJsonConstructorNullClause nullClause; | 
 |     SqlNode e; | 
 |     final SqlNode aggCall; | 
 | } | 
 | { | 
 |     <JSON_ARRAYAGG> { span = span(); } | 
 |     <LPAREN> e = Expression(ExprContext.ACCEPT_NON_QUERY) { | 
 |         valueExpr = e; | 
 |     } | 
 |     ( orderList = JsonArrayAggOrderByClause() | { orderList = null; } ) | 
 |     ( | 
 |         e = JsonConstructorNullClause() { | 
 |             nullClause = (SqlJsonConstructorNullClause) ((SqlLiteral) e).getValue(); | 
 |         } | 
 |     |   { nullClause = SqlJsonConstructorNullClause.ABSENT_ON_NULL; } | 
 |     ) | 
 |     <RPAREN> | 
 |     { | 
 |         aggCall = SqlStdOperatorTable.JSON_ARRAYAGG.with(nullClause) | 
 |             .createCall(span.end(this), valueExpr, orderList); | 
 |     } | 
 |     [ | 
 |         e = withinGroup(aggCall) { | 
 |             if (orderList != null) { | 
 |                 throw SqlUtil.newContextException(span.pos().plus(e.getParserPosition()), | 
 |                     RESOURCE.ambiguousSortOrderInJsonArrayAggFunc()); | 
 |             } | 
 |             return (SqlCall) e; | 
 |         } | 
 |     ] | 
 |     { | 
 |         if (orderList == null) { | 
 |             return SqlStdOperatorTable.JSON_ARRAYAGG.with(nullClause) | 
 |                 .createCall(span.end(this), valueExpr); | 
 |         } | 
 |         return SqlStdOperatorTable.JSON_ARRAYAGG.with(nullClause) | 
 |             .createCall(span.end(this), valueExpr, orderList); | 
 |     } | 
 | } | 
 |  | 
 |  /** | 
 |  * Parses the CONTAINS_SUBSTR function, which has a unique optional third argument "JSON_SCOPE" | 
 |  * that specifies what scope to search if the first argument is a JSON string. | 
 |  */ | 
 |  SqlCall ContainsSubstrFunctionCall() : | 
 |  { | 
 |     final List<SqlNode> args = new ArrayList<SqlNode>(); | 
 |     final Span s; | 
 |     SqlNode e; | 
 |  } | 
 |  { | 
 |      <CONTAINS_SUBSTR> { s = span(); } | 
 |      <LPAREN> | 
 |      AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |      <COMMA> | 
 |      AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |      ( | 
 |         <RPAREN> | 
 |      | | 
 |         <COMMA> | 
 |         <JSON_SCOPE> | 
 |         <NAMED_ARGUMENT_ASSIGNMENT> e = Expression(ExprContext.ACCEPT_SUB_QUERY)  { args.add(e); } | 
 |         <RPAREN> | 
 |      ) { return SqlLibraryOperators.CONTAINS_SUBSTR.createCall(s.end(this), args); } | 
 |  } | 
 |  | 
 | /** | 
 |  * Parses a call to BigQuery's DATE_DIFF. | 
 |  */ | 
 | SqlCall DateDiffFunctionCall() : | 
 | { | 
 |     final List<SqlNode> args = new ArrayList<SqlNode>(); | 
 |     final Span s; | 
 |     final SqlIntervalQualifier unit; | 
 | } | 
 | { | 
 |     <DATE_DIFF> { s = span(); } | 
 |     <LPAREN> | 
 |     AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     <COMMA> | 
 |     AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     <COMMA> | 
 |     unit = TimeUnitOrName() { args.add(unit); } | 
 |     <RPAREN> { | 
 |         return SqlLibraryOperators.DATE_DIFF.createCall(s.end(this), args); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a call to TIMESTAMPADD. | 
 |  */ | 
 | SqlCall TimestampAddFunctionCall() : | 
 | { | 
 |     final List<SqlNode> args = new ArrayList<SqlNode>(); | 
 |     final Span s; | 
 |     final SqlIntervalQualifier unit; | 
 | } | 
 | { | 
 |     <TIMESTAMPADD> { s = span(); } | 
 |     <LPAREN> | 
 |     unit = TimeUnitOrName() { args.add(unit); } | 
 |     <COMMA> | 
 |     AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     <COMMA> | 
 |     AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     <RPAREN> { | 
 |         return SqlStdOperatorTable.TIMESTAMP_ADD.createCall( | 
 |             s.end(this), args); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a call to TIMESTAMPDIFF. | 
 |  */ | 
 | SqlCall TimestampDiffFunctionCall() : | 
 | { | 
 |     final List<SqlNode> args = new ArrayList<SqlNode>(); | 
 |     final Span s; | 
 |     final SqlIntervalQualifier unit; | 
 | } | 
 | { | 
 |     <TIMESTAMPDIFF> { s = span(); } | 
 |     <LPAREN> | 
 |     unit = TimeUnitOrName() { args.add(unit); } | 
 |     <COMMA> | 
 |     AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     <COMMA> | 
 |     AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     <RPAREN> { | 
 |         return SqlStdOperatorTable.TIMESTAMP_DIFF.createCall( | 
 |             s.end(this), args); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a call to BigQuery's TIMESTAMP_DIFF. | 
 |  * | 
 |  * <p>The difference between TIMESTAMPDIFF and TIMESTAMP_DIFF is the ordering of | 
 |  * the parameters and the arrangement of the subtraction. | 
 |  * TIMESTAMPDIFF uses (unit, timestamp1, timestamp2) with (t2 - t1), while | 
 |  * TIMESTAMP_DIFF uses (timestamp1, timestamp2, unit) with (t1 - t2). | 
 |  */ | 
 | SqlCall TimestampDiff3FunctionCall() : | 
 | { | 
 |     final List<SqlNode> args = new ArrayList<SqlNode>(); | 
 |     final Span s; | 
 |     final SqlIntervalQualifier unit; | 
 | } | 
 | { | 
 |     <TIMESTAMP_DIFF> { s = span(); } | 
 |     <LPAREN> | 
 |     AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     <COMMA> | 
 |     AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     <COMMA> | 
 |     unit = TimeUnitOrName() { args.add(unit); } | 
 |     <RPAREN> { | 
 |         return SqlLibraryOperators.TIMESTAMP_DIFF3.createCall(s.end(this), args); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses BigQuery's built-in DATETIME_DIFF() function. | 
 |  */ | 
 | SqlCall DatetimeDiffFunctionCall() : | 
 | { | 
 |     final List<SqlNode> args = new ArrayList<SqlNode>(); | 
 |     final Span s; | 
 |     final SqlIntervalQualifier unit; | 
 | } | 
 | { | 
 |     <DATETIME_DIFF> { s = span(); } | 
 |     <LPAREN> | 
 |     AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     <COMMA> | 
 |     AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     <COMMA> | 
 |     unit = TimeUnitOrName() { args.add(unit); } | 
 |     <RPAREN> { | 
 |         return SqlLibraryOperators.DATETIME_DIFF.createCall(s.end(this), args); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a call to DATE_TRUNC. | 
 |  */ | 
 | SqlCall DateTruncFunctionCall() : | 
 | { | 
 |     final List<SqlNode> args = new ArrayList<SqlNode>(); | 
 |     final Span s; | 
 |     final SqlIntervalQualifier unit; | 
 | } | 
 | { | 
 |     <DATE_TRUNC> { s = span(); } | 
 |     <LPAREN> | 
 |     AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     <COMMA> | 
 |     // A choice of arguments allows us to support both | 
 |     // the BigQuery variant, e.g. "DATE_TRUNC(d, YEAR)", | 
 |     // and the Redshift variant, e.g. "DATE_TRUNC('year', DATE '2008-09-08')". | 
 |     ( | 
 |         LOOKAHEAD(2) | 
 |         unit = TimeUnit() { args.add(unit); } | 
 |     | | 
 |         AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     ) | 
 |     <RPAREN> { | 
 |         return SqlLibraryOperators.DATE_TRUNC.createCall(s.end(this), args); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a call to TIMESTAMP_TRUNC. | 
 |  */ | 
 | SqlCall TimestampTruncFunctionCall() : | 
 | { | 
 |     final List<SqlNode> args = new ArrayList<SqlNode>(); | 
 |     final Span s; | 
 |     final SqlIntervalQualifier unit; | 
 | } | 
 | { | 
 |     <TIMESTAMP_TRUNC> { s = span(); } | 
 |     <LPAREN> | 
 |     AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     <COMMA> | 
 |     unit = TimeUnitOrName() { args.add(unit); } | 
 |     <RPAREN> { | 
 |         return SqlLibraryOperators.TIMESTAMP_TRUNC.createCall(s.end(this), args); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a call to BigQuery's TIME_DIFF. | 
 |  */ | 
 | SqlCall TimeDiffFunctionCall() : | 
 | { | 
 |     final List<SqlNode> args = new ArrayList<SqlNode>(); | 
 |     final Span s; | 
 |     final SqlIntervalQualifier unit; | 
 | } | 
 | { | 
 |     <TIME_DIFF> { s = span(); } | 
 |     <LPAREN> | 
 |     AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     <COMMA> | 
 |     AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     <COMMA> | 
 |     unit = TimeUnitOrName() { args.add(unit); } | 
 |     <RPAREN> { | 
 |         return SqlLibraryOperators.TIME_DIFF.createCall(s.end(this), args); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a call to DATETIME_TRUNC. | 
 |  */ | 
 | SqlNode DatetimeTruncFunctionCall() : | 
 | { | 
 |     final List<SqlNode> args = new ArrayList<SqlNode>(); | 
 |     final Span s; | 
 |     final SqlIntervalQualifier unit; | 
 |     final SqlNode literal; | 
 | } | 
 | { | 
 |     <DATETIME_TRUNC> { s = span(); } | 
 |     <LPAREN> | 
 |     AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     <COMMA> | 
 |     unit = TimeUnitOrName() { args.add(unit); } | 
 |     <RPAREN> { | 
 |         return SqlLibraryOperators.DATETIME_TRUNC.createCall(s.end(this), args); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a call to TIME_TRUNC. | 
 |  */ | 
 | SqlCall TimeTruncFunctionCall() : | 
 | { | 
 |     final List<SqlNode> args = new ArrayList<SqlNode>(); | 
 |     final Span s; | 
 |     final SqlIntervalQualifier unit; | 
 | } | 
 | { | 
 |     <TIME_TRUNC> { s = span(); } | 
 |     <LPAREN> | 
 |     AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     <COMMA> | 
 |     unit = TimeUnitOrName() { args.add(unit); } | 
 |     <RPAREN> { | 
 |         return SqlLibraryOperators.TIME_TRUNC.createCall(s.end(this), args); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a call to a grouping function inside the GROUP BY clause, | 
 |  * for example {@code TUMBLE(rowtime, INTERVAL '1' MINUTE)}. | 
 |  */ | 
 | SqlCall GroupByWindowingCall() : | 
 | { | 
 |     final Span s; | 
 |     final List<SqlNode> args; | 
 |     final SqlOperator op; | 
 | } | 
 | { | 
 |     ( | 
 |         <TUMBLE> { op = SqlStdOperatorTable.TUMBLE_OLD; } | 
 |     | | 
 |         <HOP> { op = SqlStdOperatorTable.HOP_OLD; } | 
 |     | | 
 |         <SESSION> { op = SqlStdOperatorTable.SESSION_OLD; } | 
 |     ) | 
 |     { s = span(); } | 
 |     args = UnquantifiedFunctionParameterList(ExprContext.ACCEPT_SUB_QUERY) { | 
 |         return op.createCall(s.end(this), args); | 
 |     } | 
 | } | 
 |  | 
 | SqlCall MatchRecognizeFunctionCall() : | 
 | { | 
 |     final SqlCall func; | 
 |     final Span s; | 
 | } | 
 | { | 
 |     ( | 
 |         <CLASSIFIER> { s = span(); } <LPAREN> <RPAREN> { | 
 |             func = SqlStdOperatorTable.CLASSIFIER.createCall(s.end(this)); | 
 |         } | 
 |     | | 
 |         <MATCH_NUMBER> { s = span(); } <LPAREN> <RPAREN> { | 
 |             func = SqlStdOperatorTable.MATCH_NUMBER.createCall(s.end(this)); | 
 |         } | 
 |     | | 
 |         LOOKAHEAD(3) | 
 |         func = MatchRecognizeNavigationLogical() | 
 |     | | 
 |         LOOKAHEAD(2) | 
 |         func = MatchRecognizeNavigationPhysical() | 
 |     | | 
 |         func = MatchRecognizeCallWithModifier() | 
 |     ) | 
 |     { return func; } | 
 | } | 
 |  | 
 | SqlCall MatchRecognizeCallWithModifier() : | 
 | { | 
 |     final Span s; | 
 |     final SqlOperator runningOp; | 
 |     final SqlNode func; | 
 | } | 
 | { | 
 |     ( | 
 |         <RUNNING> { runningOp = SqlStdOperatorTable.RUNNING; } | 
 |     | | 
 |         <FINAL> { runningOp = SqlStdOperatorTable.FINAL; } | 
 |     ) | 
 |     { s = span(); } | 
 |     func = NamedFunctionCall() { | 
 |         return runningOp.createCall(s.end(func), func); | 
 |     } | 
 | } | 
 |  | 
 | SqlCall MatchRecognizeNavigationLogical() : | 
 | { | 
 |     final Span s = Span.of(); | 
 |     SqlCall func; | 
 |     final SqlOperator funcOp; | 
 |     final SqlOperator runningOp; | 
 |     final List<SqlNode> args = new ArrayList<SqlNode>(); | 
 |     SqlNode e; | 
 | } | 
 | { | 
 |     ( | 
 |         <RUNNING> { runningOp = SqlStdOperatorTable.RUNNING; s.add(this); } | 
 |     | | 
 |         <FINAL> { runningOp = SqlStdOperatorTable.FINAL; s.add(this); } | 
 |     |   { runningOp = null; } | 
 |     ) | 
 |     ( | 
 |         <FIRST> { funcOp = SqlStdOperatorTable.FIRST; } | 
 |     | | 
 |         <LAST> { funcOp = SqlStdOperatorTable.LAST; } | 
 |     ) | 
 |     { s.add(this); } | 
 |     <LPAREN> | 
 |     AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     ( | 
 |         <COMMA> e = NumericLiteral() { args.add(e); } | 
 |     | | 
 |         { args.add(LITERAL_ZERO); } | 
 |     ) | 
 |     <RPAREN> { | 
 |         func = funcOp.createCall(s.end(this), args); | 
 |         if (runningOp != null) { | 
 |             return runningOp.createCall(s.end(this), func); | 
 |         } else { | 
 |             return func; | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | SqlCall MatchRecognizeNavigationPhysical() : | 
 | { | 
 |     final Span s; | 
 |     final SqlOperator funcOp; | 
 |     final List<SqlNode> args = new ArrayList<SqlNode>(); | 
 |     SqlNode e; | 
 | } | 
 | { | 
 |     ( | 
 |         <PREV> { funcOp = SqlStdOperatorTable.PREV; } | 
 |     | | 
 |         <NEXT> { funcOp = SqlStdOperatorTable.NEXT; } | 
 |     ) | 
 |     { s = span(); } | 
 |     <LPAREN> | 
 |     AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     ( | 
 |         <COMMA> e = NumericLiteral() { args.add(e); } | 
 |     | | 
 |         { args.add(LITERAL_ONE); } | 
 |     ) | 
 |     <RPAREN> { | 
 |         return funcOp.createCall(s.end(this), args); | 
 |     } | 
 | } | 
 |  | 
 | SqlCall withinDistinct(SqlNode arg) : | 
 | { | 
 |     final Span s; | 
 |     final SqlNodeList distinctList; | 
 | } | 
 | { | 
 |     <WITHIN> { s = span(); } | 
 |     <DISTINCT> | 
 |     <LPAREN> | 
 |     distinctList = ExpressionCommaList(s, ExprContext.ACCEPT_SUB_QUERY) | 
 |     <RPAREN> { | 
 |         return SqlStdOperatorTable.WITHIN_DISTINCT.createCall( | 
 |             s.end(this), arg, distinctList); | 
 |     } | 
 | } | 
 |  | 
 | SqlCall withinGroup(SqlNode arg) : | 
 | { | 
 |     final Span s; | 
 |     final SqlNodeList orderList; | 
 | } | 
 | { | 
 |     <WITHIN> { s = span(); } | 
 |     <GROUP> | 
 |     <LPAREN> | 
 |     orderList = OrderBy(true) | 
 |     <RPAREN> { | 
 |         return SqlStdOperatorTable.WITHIN_GROUP.createCall( | 
 |             s.end(this), arg, orderList); | 
 |     } | 
 | } | 
 |  | 
 | Pair<SqlParserPos, SqlOperator> NullTreatment() : | 
 | { | 
 |     final Span span; | 
 | } | 
 | { | 
 |     <IGNORE> { span = span(); } <NULLS> { | 
 |         return Pair.of(span.end(this), SqlStdOperatorTable.IGNORE_NULLS); | 
 |     } | 
 | | | 
 |     <RESPECT> { span = span(); } <NULLS> { | 
 |         return Pair.of(span.end(this), SqlStdOperatorTable.RESPECT_NULLS); | 
 |     } | 
 | } | 
 |  | 
 | SqlCall nullTreatment(SqlCall arg) : | 
 | { | 
 |     final Pair<SqlParserPos, SqlOperator> pair; | 
 | } | 
 | { | 
 |     pair = NullTreatment() { return pair.right.createCall(pair.left, arg); } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a call to a named function (could be a builtin with regular | 
 |  * syntax, or else a UDF). | 
 |  * | 
 |  * <p>NOTE: every UDF has two names: an <em>invocation name</em> and a | 
 |  * <em>specific name</em>.  Normally, function calls are resolved via overload | 
 |  * resolution and invocation names.  The SPECIFIC prefix allows overload | 
 |  * resolution to be bypassed.  Note that usage of the SPECIFIC prefix in | 
 |  * queries is non-standard; it is used internally by Farrago, e.g. in stored | 
 |  * view definitions to permanently bind references to a particular function | 
 |  * after the overload resolution performed by view creation. | 
 |  * | 
 |  * <p>TODO jvs 25-Mar-2005:  Once we have SQL-Flagger support, flag SPECIFIC | 
 |  * as non-standard. | 
 |  */ | 
 | SqlNode NamedFunctionCall() : | 
 | { | 
 |     SqlCall call; | 
 |     final Span filterSpan; | 
 |     final SqlNode filter; | 
 |     final Span overSpan; | 
 |     final SqlNode over; | 
 | } | 
 | { | 
 |     ( | 
 |         LOOKAHEAD(2) | 
 |         call = StringAggFunctionCall() | 
 |     | | 
 |         LOOKAHEAD(1) | 
 |         call = PercentileFunctionCall() | 
 |     | | 
 |         call = NamedCall() | 
 |     ) | 
 |     [ | 
 |         LOOKAHEAD(2) call = nullTreatment(call) | 
 |     ] | 
 |     [ | 
 |         LOOKAHEAD(2) // decide between WITHIN DISTINCT and WITHIN GROUP | 
 |         call = withinDistinct(call) | 
 |     ] | 
 |     [ | 
 |         call = withinGroup(call) | 
 |     ] | 
 |     [ | 
 |         <FILTER> { filterSpan = span(); } | 
 |         <LPAREN> | 
 |         <WHERE> | 
 |         filter = Expression(ExprContext.ACCEPT_SUB_QUERY) | 
 |         <RPAREN> { | 
 |             call = SqlStdOperatorTable.FILTER.createCall( | 
 |                 filterSpan.end(this), call, filter); | 
 |         } | 
 |     ] | 
 |     [ | 
 |         <OVER> { overSpan = span(); } | 
 |         ( | 
 |             over = SimpleIdentifier() | 
 |         | | 
 |             over = WindowSpecification() | 
 |         ) | 
 |         { | 
 |             call = SqlStdOperatorTable.OVER.createCall(overSpan.end(over), call, over); | 
 |         } | 
 |     ] | 
 |     { | 
 |         return call; | 
 |     } | 
 | } | 
 |  | 
 | SqlCall NamedCall() : | 
 | { | 
 |     final SqlFunctionCategory funcType; | 
 |     final SqlIdentifier qualifiedName; | 
 |     final Span s; | 
 |     final List<SqlNode> args; | 
 |     SqlLiteral quantifier = null; | 
 | } | 
 | { | 
 |     ( | 
 |         <SPECIFIC> { | 
 |             funcType = SqlFunctionCategory.USER_DEFINED_SPECIFIC_FUNCTION; | 
 |         } | 
 |     | | 
 |         { funcType = SqlFunctionCategory.USER_DEFINED_FUNCTION; } | 
 |     ) | 
 |     qualifiedName = FunctionName() { | 
 |         s = span(); | 
 |     } | 
 |     ( | 
 |         LOOKAHEAD(2) <LPAREN> <STAR> { | 
 |             args = ImmutableList.of(SqlIdentifier.star(getPos())); | 
 |         } | 
 |         <RPAREN> | 
 |     | | 
 |         LOOKAHEAD(2) <LPAREN> <RPAREN> { | 
 |             args = ImmutableList.of(); | 
 |         } | 
 |     | | 
 |         args = FunctionParameterList(ExprContext.ACCEPT_SUB_QUERY) { | 
 |             quantifier = (SqlLiteral) args.get(0); | 
 |             args.remove(0); | 
 |         } | 
 |     ) | 
 |     { | 
 |         return createCall(qualifiedName, s.end(this), funcType, quantifier, args); | 
 |     } | 
 | } | 
 |  | 
 | /* | 
 | * Parse Floor/Ceil function parameters | 
 | */ | 
 | SqlNode StandardFloorCeilOptions(Span s, boolean floorFlag) : | 
 | { | 
 |     SqlNode e; | 
 |     final List<SqlNode> args = new ArrayList<SqlNode>(); | 
 |     final SqlIntervalQualifier unit; | 
 |     SqlCall function; | 
 |     final Span s1; | 
 | } | 
 | { | 
 |     <LPAREN> AddExpression(args, ExprContext.ACCEPT_SUB_QUERY) | 
 |     ( | 
 |         <TO> unit = TimeUnitOrName() { | 
 |             args.add(unit); | 
 |         } | 
 |     )? | 
 |     <RPAREN> { | 
 |         SqlOperator op = SqlStdOperatorTable.floorCeil(floorFlag, this.conformance); | 
 |         function =  op.createCall(s.end(this), args); | 
 |     } | 
 |     ( | 
 |         <OVER> { s1 = span(); } | 
 |         ( | 
 |             e = SimpleIdentifier() | 
 |         | | 
 |             e = WindowSpecification() | 
 |         ) | 
 |         { | 
 |             return SqlStdOperatorTable.OVER.createCall(s1.end(this), function, e); | 
 |         } | 
 |     | | 
 |         { return function; } | 
 |     ) | 
 | } | 
 |  | 
 | /** | 
 |  * Parses the name of a JDBC function that is a token but is not reserved. | 
 |  */ | 
 | String NonReservedJdbcFunctionName() : | 
 | { | 
 | } | 
 | { | 
 |     ( | 
 |         <SUBSTRING> | 
 |     ) | 
 |     { | 
 |         return unquotedIdentifier(); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses the name of a function (either a compound identifier or | 
 |  * a reserved word which can be used as a function name). | 
 |  */ | 
 | SqlIdentifier FunctionName() : | 
 | { | 
 |     SqlIdentifier qualifiedName; | 
 | } | 
 | { | 
 |     ( | 
 |         qualifiedName = CompoundIdentifier() | 
 |     | | 
 |         qualifiedName = ReservedFunctionName() | 
 |     ) | 
 |     { | 
 |         return qualifiedName; | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a reserved word which is used as the name of a function. | 
 |  */ | 
 | SqlIdentifier ReservedFunctionName() : | 
 | { | 
 | } | 
 | { | 
 |     ( | 
 |         <ABS> | 
 |     |   <AVG> | 
 |     |   <CARDINALITY> | 
 |     |   <CEILING> | 
 |     |   <CHAR> | 
 |     |   <CHAR_LENGTH> | 
 |     |   <CHARACTER_LENGTH> | 
 |     |   <COALESCE> | 
 |     |   <COLLECT> | 
 |     |   <COVAR_POP> | 
 |     |   <COVAR_SAMP> | 
 |     |   <CUME_DIST> | 
 |     |   <COUNT> | 
 |     |   <CURRENT_DATE> | 
 |     |   <CURRENT_TIME> | 
 |     |   <CURRENT_TIMESTAMP> | 
 |     |   <DENSE_RANK> | 
 |     |   <ELEMENT> | 
 |     |   <EVERY> | 
 |     |   <EXP> | 
 |     |   <FIRST_VALUE> | 
 |     |   <FLOOR> | 
 |     |   <FUSION> | 
 |     |   <INTERSECTION> | 
 |     |   <GROUPING> | 
 |     |   <HOUR> | 
 |     |   <LAG> | 
 |     |   <LEAD> | 
 |     |   <LEFT> | 
 |     |   <LAST_VALUE> | 
 |     |   <LN> | 
 |     |   <LOCALTIME> | 
 |     |   <LOCALTIMESTAMP> | 
 |     |   <LOWER> | 
 |     |   <MAX> | 
 |     |   <MIN> | 
 |     |   <MINUTE> | 
 |     |   <MOD> | 
 |     |   <MONTH> | 
 |     |   <NTH_VALUE> | 
 |     |   <NTILE> | 
 |     |   <NULLIF> | 
 |     |   <OCTET_LENGTH> | 
 |     |   <PERCENTILE_CONT> | 
 |     |   <PERCENTILE_DISC> | 
 |     |   <PERCENT_RANK> | 
 |     |   <POWER> | 
 |     |   <RANK> | 
 |     |   <REGR_COUNT> | 
 |     |   <REGR_SXX> | 
 |     |   <REGR_SYY> | 
 |     |   <RIGHT> | 
 |     |   <ROW_NUMBER> | 
 |     |   <SECOND> | 
 |     |   <SOME> | 
 |     |   <SQRT> | 
 |     |   <STDDEV_POP> | 
 |     |   <STDDEV_SAMP> | 
 |     |   <SUM> | 
 |     |   <UPPER> | 
 |     |   <TRUNCATE> | 
 |     |   <USER> | 
 |     |   <VAR_POP> | 
 |     |   <VAR_SAMP> | 
 |     |   <YEAR> | 
 |     ) | 
 |     { | 
 |         return new SqlIdentifier(unquotedIdentifier(), getPos()); | 
 |     } | 
 | } | 
 |  | 
 | SqlIdentifier ContextVariable() : | 
 | { | 
 | } | 
 | { | 
 |     ( | 
 |         <CURRENT_CATALOG> | 
 |     |   <CURRENT_DATE> | 
 |     |   <CURRENT_DEFAULT_TRANSFORM_GROUP> | 
 |     |   <CURRENT_PATH> | 
 |     |   <CURRENT_ROLE> | 
 |     |   <CURRENT_SCHEMA> | 
 |     |   <CURRENT_TIME> | 
 |     |   <CURRENT_TIMESTAMP> | 
 |     |   <CURRENT_USER> | 
 |     |   <LOCALTIME> | 
 |     |   <LOCALTIMESTAMP> | 
 |     |   <SESSION_USER> | 
 |     |   <SYSTEM_USER> | 
 |     |   <USER> | 
 |     ) | 
 |     { | 
 |         return new SqlIdentifier(unquotedIdentifier(), getPos()); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a function call expression with JDBC syntax. | 
 |  */ | 
 | SqlNode JdbcFunctionCall() : | 
 | { | 
 |     String name; | 
 |     SqlIdentifier id; | 
 |     SqlNode e; | 
 |     SqlLiteral tl; | 
 |     SqlNodeList args; | 
 |     SqlCall call; | 
 |     final Span s, s1; | 
 | } | 
 | { | 
 |     <LBRACE_FN> { | 
 |         s = span(); | 
 |     } | 
 |     ( | 
 |         LOOKAHEAD(1) | 
 |         call = ContainsSubstrFunctionCall() { | 
 |             name = call.getOperator().getName(); | 
 |             args = new SqlNodeList(call.getOperandList(), getPos()); | 
 |         } | 
 |     | | 
 |         LOOKAHEAD(1) | 
 |         call = DateDiffFunctionCall() { | 
 |             name = call.getOperator().getName(); | 
 |             args = new SqlNodeList(call.getOperandList(), getPos()); | 
 |         } | 
 |     | | 
 |         LOOKAHEAD(1) | 
 |         call = DatetimeDiffFunctionCall() { | 
 |             name = call.getOperator().getName(); | 
 |             args = new SqlNodeList(call.getOperandList(), getPos()); | 
 |         } | 
 |     | | 
 |         LOOKAHEAD(1) | 
 |         call = TimestampAddFunctionCall() { | 
 |             name = call.getOperator().getName(); | 
 |             args = new SqlNodeList(call.getOperandList(), getPos()); | 
 |         } | 
 |     | | 
 |         LOOKAHEAD(1) | 
 |         call = DateTruncFunctionCall() { | 
 |             name = call.getOperator().getName(); | 
 |             args = new SqlNodeList(call.getOperandList(), getPos()); | 
 |         } | 
 |     | | 
 |         LOOKAHEAD(1) | 
 |         call = TimestampTruncFunctionCall() { | 
 |             name = call.getOperator().getName(); | 
 |             args = new SqlNodeList(call.getOperandList(), getPos()); | 
 |         } | 
 |     | | 
 |         LOOKAHEAD(1) | 
 |         call = TimeTruncFunctionCall() { | 
 |             name = call.getOperator().getName(); | 
 |             args = new SqlNodeList(call.getOperandList(), getPos()); | 
 |         } | 
 |     | | 
 |         LOOKAHEAD(1) | 
 |         call = TimestampDiff3FunctionCall() { | 
 |             name = call.getOperator().getName(); | 
 |             args = new SqlNodeList(call.getOperandList(), getPos()); | 
 |         } | 
 |     | | 
 |         LOOKAHEAD(1) | 
 |         call = TimeDiffFunctionCall() { | 
 |             name = call.getOperator().getName(); | 
 |             args = new SqlNodeList(call.getOperandList(), getPos()); | 
 |         } | 
 |     | | 
 |         LOOKAHEAD(3) | 
 |         call = TimestampDiffFunctionCall() { | 
 |             name = call.getOperator().getName(); | 
 |             args = new SqlNodeList(call.getOperandList(), getPos()); | 
 |         } | 
 |     | | 
 |         <CONVERT> { name = unquotedIdentifier(); } | 
 |         <LPAREN> | 
 |         e = Expression(ExprContext.ACCEPT_SUB_QUERY) { | 
 |             args = new SqlNodeList(getPos()); | 
 |             args.add(e); | 
 |         } | 
 |         <COMMA> | 
 |         tl = JdbcOdbcDataType() { args.add(tl); } | 
 |         <RPAREN> | 
 |     | | 
 |         ( | 
 |             // INSERT is a reserved word, but we need to handle {fn insert} | 
 |             // Similarly LEFT, RIGHT, TRUNCATE | 
 |             LOOKAHEAD(1) | 
 |             ( <INSERT> | <LEFT> | <RIGHT> | <TRUNCATE> ) { name = unquotedIdentifier(); } | 
 |         | | 
 |             // For cases like {fn power(1,2)} and {fn lower('a')} | 
 |             id = ReservedFunctionName() { name = id.getSimple(); } | 
 |         | | 
 |             // For cases like {fn substring('foo', 1,2)} | 
 |             name = NonReservedJdbcFunctionName() | 
 |         | | 
 |             name = Identifier() | 
 |         ) | 
 |         ( | 
 |             LOOKAHEAD(2) <LPAREN> <STAR> { s1 = span(); } <RPAREN> | 
 |             { | 
 |                 args = new SqlNodeList(s1.pos()); | 
 |                 args.add(SqlIdentifier.star(s1.pos())); | 
 |             } | 
 |         | | 
 |             LOOKAHEAD(2) <LPAREN> <RPAREN> { args = SqlNodeList.EMPTY; } | 
 |         | | 
 |             args = ParenthesizedQueryOrCommaList(ExprContext.ACCEPT_SUB_QUERY) | 
 |         ) | 
 |     ) | 
 |     <RBRACE> { | 
 |         return new SqlJdbcFunctionCall(name).createCall(s.end(this), | 
 |             args.getList()); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a binary query operator like UNION. | 
 |  */ | 
 | SqlBinaryOperator BinaryQueryOperator() : | 
 | { | 
 | } | 
 | { | 
 |     // If both the ALL or DISTINCT keywords are missing, DISTINCT is implicit. | 
 |     ( | 
 |         <UNION> | 
 |         ( | 
 |             <ALL> { return SqlStdOperatorTable.UNION_ALL; } | 
 |         |   <DISTINCT> { return SqlStdOperatorTable.UNION; } | 
 |         |   { return SqlStdOperatorTable.UNION; } | 
 |         ) | 
 |     | | 
 |         <INTERSECT> | 
 |         ( | 
 |             <ALL> { return SqlStdOperatorTable.INTERSECT_ALL; } | 
 |         |   <DISTINCT> { return SqlStdOperatorTable.INTERSECT; } | 
 |         |   { return SqlStdOperatorTable.INTERSECT; } | 
 |         ) | 
 |     | | 
 |         ( | 
 |             <EXCEPT> | 
 |         | | 
 |             <SET_MINUS> { | 
 |                 if (!this.conformance.isMinusAllowed()) { | 
 |                     throw SqlUtil.newContextException(getPos(), RESOURCE.minusNotAllowed()); | 
 |                 } | 
 |             } | 
 |         ) | 
 |         ( | 
 |             <ALL> { return SqlStdOperatorTable.EXCEPT_ALL; } | 
 |         |   <DISTINCT> { return SqlStdOperatorTable.EXCEPT; } | 
 |         |   { return SqlStdOperatorTable.EXCEPT; } | 
 |         ) | 
 |     ) | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a binary multiset operator. | 
 |  */ | 
 | SqlBinaryOperator BinaryMultisetOperator() : | 
 | { | 
 | } | 
 | { | 
 |     // If both the ALL or DISTINCT keywords are missing, DISTINCT is implicit | 
 |     <MULTISET> | 
 |     ( | 
 |         <UNION> | 
 |         [ | 
 |             <ALL> | 
 |         |   <DISTINCT> { return SqlStdOperatorTable.MULTISET_UNION_DISTINCT; } | 
 |         ] | 
 |         { return SqlStdOperatorTable.MULTISET_UNION; } | 
 |     | | 
 |         <INTERSECT> | 
 |         [ | 
 |             <ALL> | 
 |         |   <DISTINCT> { return SqlStdOperatorTable.MULTISET_INTERSECT_DISTINCT; } | 
 |         ] | 
 |         { return SqlStdOperatorTable.MULTISET_INTERSECT; } | 
 |     | | 
 |         <EXCEPT> | 
 |         [ | 
 |             <ALL> | 
 |         |   <DISTINCT> { return SqlStdOperatorTable.MULTISET_EXCEPT_DISTINCT; } | 
 |         ] | 
 |         { return SqlStdOperatorTable.MULTISET_EXCEPT; } | 
 |     ) | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a binary row operator like AND. | 
 |  */ | 
 | SqlBinaryOperator BinaryRowOperator() : | 
 | { | 
 |     SqlBinaryOperator op; | 
 | } | 
 | { | 
 |     // <IN> is handled as a special case | 
 |     <EQ> { return SqlStdOperatorTable.EQUALS; } | 
 | |   <GT> { return SqlStdOperatorTable.GREATER_THAN; } | 
 | |   <LT> { return SqlStdOperatorTable.LESS_THAN; } | 
 | |   <LE> { return SqlStdOperatorTable.LESS_THAN_OR_EQUAL; } | 
 | |   <GE> { return SqlStdOperatorTable.GREATER_THAN_OR_EQUAL; } | 
 | |   <NE> { return SqlStdOperatorTable.NOT_EQUALS; } | 
 | |   <NE2> { | 
 |         if (!this.conformance.isBangEqualAllowed()) { | 
 |             throw SqlUtil.newContextException(getPos(), RESOURCE.bangEqualNotAllowed()); | 
 |         } | 
 |         return SqlStdOperatorTable.NOT_EQUALS; | 
 |     } | 
 | |   <PLUS> { return SqlStdOperatorTable.PLUS; } | 
 | |   <MINUS> { return SqlStdOperatorTable.MINUS; } | 
 | |   <STAR> { return SqlStdOperatorTable.MULTIPLY; } | 
 | |   <SLASH> { return SqlStdOperatorTable.DIVIDE; } | 
 | |   <PERCENT_REMAINDER> { | 
 |         if (!this.conformance.isPercentRemainderAllowed()) { | 
 |             throw SqlUtil.newContextException(getPos(), RESOURCE.percentRemainderNotAllowed()); | 
 |         } | 
 |         return SqlStdOperatorTable.PERCENT_REMAINDER; | 
 |     } | 
 | |   <CONCAT> { return SqlStdOperatorTable.CONCAT; } | 
 | |   <AND> { return SqlStdOperatorTable.AND; } | 
 | |   <OR> { return SqlStdOperatorTable.OR; } | 
 | |   LOOKAHEAD(2) <IS> <DISTINCT> <FROM> { return SqlStdOperatorTable.IS_DISTINCT_FROM; } | 
 | |   <IS> <NOT> <DISTINCT> <FROM> { return SqlStdOperatorTable.IS_NOT_DISTINCT_FROM; } | 
 | |   <MEMBER> <OF> { return SqlStdOperatorTable.MEMBER_OF; } | 
 | |   LOOKAHEAD(2) <SUBMULTISET> <OF> { return SqlStdOperatorTable.SUBMULTISET_OF; } | 
 | |   <NOT> <SUBMULTISET> <OF> { return SqlStdOperatorTable.NOT_SUBMULTISET_OF; } | 
 | |   <CONTAINS> { return SqlStdOperatorTable.CONTAINS; } | 
 | |   <OVERLAPS> { return SqlStdOperatorTable.OVERLAPS; } | 
 | |   <EQUALS> { return SqlStdOperatorTable.PERIOD_EQUALS; } | 
 | |   <PRECEDES> { return SqlStdOperatorTable.PRECEDES; } | 
 | |   <SUCCEEDS> { return SqlStdOperatorTable.SUCCEEDS; } | 
 | |   LOOKAHEAD(2) <IMMEDIATELY> <PRECEDES> { return SqlStdOperatorTable.IMMEDIATELY_PRECEDES; } | 
 | |   <IMMEDIATELY> <SUCCEEDS> { return SqlStdOperatorTable.IMMEDIATELY_SUCCEEDS; } | 
 | |   op = BinaryMultisetOperator() { return op; } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a prefix row operator like NOT. | 
 |  */ | 
 | SqlPrefixOperator PrefixRowOperator() : | 
 | {} | 
 | { | 
 |     <PLUS> { return SqlStdOperatorTable.UNARY_PLUS; } | 
 | |   <MINUS> { return SqlStdOperatorTable.UNARY_MINUS; } | 
 | |   <NOT> { return SqlStdOperatorTable.NOT; } | 
 | |   <EXISTS> { return SqlStdOperatorTable.EXISTS; } | 
 | |   <UNIQUE> { return SqlStdOperatorTable.UNIQUE; } | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a postfix row operator like IS NOT NULL. | 
 |  */ | 
 | SqlPostfixOperator PostfixRowOperator() : | 
 | {} | 
 | { | 
 |     <IS> | 
 |     ( | 
 |         <A> <SET> { return SqlStdOperatorTable.IS_A_SET; } | 
 |     | | 
 |         <NOT> | 
 |         ( | 
 |             <NULL> { return SqlStdOperatorTable.IS_NOT_NULL; } | 
 |         |   <TRUE> { return SqlStdOperatorTable.IS_NOT_TRUE; } | 
 |         |   <FALSE> { return SqlStdOperatorTable.IS_NOT_FALSE; } | 
 |         |   <UNKNOWN> { return SqlStdOperatorTable.IS_NOT_UNKNOWN; } | 
 |         |   <A> <SET> { return SqlStdOperatorTable.IS_NOT_A_SET; } | 
 |         |   <EMPTY> { return SqlStdOperatorTable.IS_NOT_EMPTY; } | 
 |         |   LOOKAHEAD(2) <JSON> <VALUE> { return SqlStdOperatorTable.IS_NOT_JSON_VALUE; } | 
 |         |   LOOKAHEAD(2) <JSON> <OBJECT> { return SqlStdOperatorTable.IS_NOT_JSON_OBJECT; } | 
 |         |   LOOKAHEAD(2) <JSON> <ARRAY> { return SqlStdOperatorTable.IS_NOT_JSON_ARRAY; } | 
 |         |   LOOKAHEAD(2) <JSON> <SCALAR> { return SqlStdOperatorTable.IS_NOT_JSON_SCALAR; } | 
 |         |   <JSON> { return SqlStdOperatorTable.IS_NOT_JSON_VALUE; } | 
 |         ) | 
 |     | | 
 |         ( | 
 |             <NULL> { return SqlStdOperatorTable.IS_NULL; } | 
 |         |   <TRUE> { return SqlStdOperatorTable.IS_TRUE; } | 
 |         |   <FALSE> { return SqlStdOperatorTable.IS_FALSE; } | 
 |         |   <UNKNOWN> { return SqlStdOperatorTable.IS_UNKNOWN; } | 
 |         |   <EMPTY> { return SqlStdOperatorTable.IS_EMPTY; } | 
 |         |   LOOKAHEAD(2) <JSON> <VALUE> { return SqlStdOperatorTable.IS_JSON_VALUE; } | 
 |         |   LOOKAHEAD(2) <JSON> <OBJECT> { return SqlStdOperatorTable.IS_JSON_OBJECT; } | 
 |         |   LOOKAHEAD(2) <JSON> <ARRAY> { return SqlStdOperatorTable.IS_JSON_ARRAY; } | 
 |         |   LOOKAHEAD(2) <JSON> <SCALAR> { return SqlStdOperatorTable.IS_JSON_SCALAR; } | 
 |         |   <JSON> { return SqlStdOperatorTable.IS_JSON_VALUE; } | 
 |         ) | 
 |     ) | 
 | | | 
 |     <FORMAT> | 
 |     ( | 
 |         JsonRepresentation() { | 
 |             return SqlStdOperatorTable.JSON_VALUE_EXPRESSION; | 
 |         } | 
 |     ) | 
 | } | 
 |  | 
 |  | 
 | /* KEYWORDS:  anything in this list is a reserved word unless it appears | 
 |    in the NonReservedKeyWord() production. */ | 
 |  | 
 | <DEFAULT, DQID, BTID, BQID, BQHID> TOKEN : | 
 | { | 
 |     < A: "A" > | 
 | |   < ABS: "ABS" > | 
 | |   < ABSENT: "ABSENT" > | 
 | |   < ABSOLUTE: "ABSOLUTE" > | 
 | |   < ACTION: "ACTION" > | 
 | |   < ADA: "ADA" > | 
 | |   < ADD: "ADD" > | 
 | |   < ADMIN: "ADMIN" > | 
 | |   < AFTER: "AFTER" > | 
 | |   < ALL: "ALL" > | 
 | |   < ALLOCATE: "ALLOCATE" > | 
 | |   < ALLOW: "ALLOW" > | 
 | |   < ALTER: "ALTER" > | 
 | |   < ALWAYS: "ALWAYS" > | 
 | |   < AND: "AND" > | 
 | |   < ANY: "ANY" > | 
 | |   < APPLY: "APPLY" > | 
 | |   < ARE: "ARE" > | 
 | |   < ARRAY: "ARRAY" > | 
 | |   < ARRAY_AGG: "ARRAY_AGG" > | 
 | |   < ARRAY_CONCAT_AGG: "ARRAY_CONCAT_AGG" > | 
 | |   < ARRAY_MAX_CARDINALITY: "ARRAY_MAX_CARDINALITY" > | 
 | |   < AS: "AS" > | 
 | |   < ASC: "ASC" > | 
 | |   < ASENSITIVE: "ASENSITIVE" > | 
 | |   < ASSERTION: "ASSERTION" > | 
 | |   < ASSIGNMENT: "ASSIGNMENT" > | 
 | |   < ASYMMETRIC: "ASYMMETRIC" > | 
 | |   < AT: "AT" > | 
 | |   < ATOMIC: "ATOMIC" > | 
 | |   < ATTRIBUTE: "ATTRIBUTE" > | 
 | |   < ATTRIBUTES: "ATTRIBUTES" > | 
 | |   < AUTHORIZATION: "AUTHORIZATION" > | 
 | |   < AVG: "AVG" > | 
 | |   < BEFORE: "BEFORE" > | 
 | |   < BEGIN: "BEGIN" > | 
 | |   < BEGIN_FRAME: "BEGIN_FRAME" > | 
 | |   < BEGIN_PARTITION: "BEGIN_PARTITION" > | 
 | |   < BERNOULLI: "BERNOULLI" > | 
 | |   < BETWEEN: "BETWEEN" > | 
 | |   < BIGINT: "BIGINT" > | 
 | |   < BINARY: "BINARY" > | 
 | |   < BIT: "BIT" > | 
 | |   < BLOB: "BLOB" > | 
 | |   < BOOLEAN: "BOOLEAN" > | 
 | |   < BOTH: "BOTH" > | 
 | |   < BREADTH: "BREADTH" > | 
 | |   < BY: "BY" > | 
 | |   < C: "C" > | 
 | |   < CALL: "CALL" > | 
 | |   < CALLED: "CALLED" > | 
 | |   < CARDINALITY: "CARDINALITY" > | 
 | |   < CASCADE: "CASCADE" > | 
 | |   < CASCADED: "CASCADED" > | 
 | |   < CASE: "CASE" > | 
 | |   < CAST: "CAST" > | 
 | |   < CATALOG: "CATALOG" > | 
 | |   < CATALOG_NAME: "CATALOG_NAME" > | 
 | |   < CEIL: "CEIL" > | 
 | |   < CEILING: "CEILING" > | 
 | |   < CENTURY: "CENTURY" > | 
 | |   < CHAIN: "CHAIN" > | 
 | |   < CHAR: "CHAR" > | 
 | |   < CHAR_LENGTH: "CHAR_LENGTH" > | 
 | |   < CHARACTER: "CHARACTER" > | 
 | |   < CHARACTER_LENGTH: "CHARACTER_LENGTH" > | 
 | |   < CHARACTER_SET_CATALOG: "CHARACTER_SET_CATALOG" > | 
 | |   < CHARACTER_SET_NAME: "CHARACTER_SET_NAME" > | 
 | |   < CHARACTER_SET_SCHEMA: "CHARACTER_SET_SCHEMA" > | 
 | |   < CHARACTERISTICS: "CHARACTERISTICS" > | 
 | |   < CHARACTERS: "CHARACTERS" > | 
 | |   < CHECK: "CHECK" > | 
 | |   < CLASSIFIER: "CLASSIFIER" > | 
 | |   < CLASS_ORIGIN: "CLASS_ORIGIN" > | 
 | |   < CLOB: "CLOB" > | 
 | |   < CLOSE: "CLOSE" > | 
 | |   < COALESCE: "COALESCE" > | 
 | |   < COBOL: "COBOL" > | 
 | |   < COLLATE: "COLLATE" > | 
 | |   < COLLATION: "COLLATION" > | 
 | |   < COLLATION_CATALOG: "COLLATION_CATALOG" > | 
 | |   < COLLATION_NAME: "COLLATION_NAME" > | 
 | |   < COLLATION_SCHEMA: "COLLATION_SCHEMA" > | 
 | |   < COLLECT: "COLLECT" > | 
 | |   < COLUMN: "COLUMN" > | 
 | |   < COLUMN_NAME: "COLUMN_NAME" > | 
 | |   < COMMAND_FUNCTION: "COMMAND_FUNCTION" > | 
 | |   < COMMAND_FUNCTION_CODE: "COMMAND_FUNCTION_CODE" > | 
 | |   < COMMIT: "COMMIT" > | 
 | |   < COMMITTED: "COMMITTED" > | 
 | |   < CONDITION: "CONDITION" > | 
 | |   < CONDITIONAL: "CONDITIONAL" > | 
 | |   < CONDITION_NUMBER: "CONDITION_NUMBER" > | 
 | |   < CONNECT: "CONNECT" > | 
 | |   < CONNECTION: "CONNECTION" > | 
 | |   < CONNECTION_NAME: "CONNECTION_NAME" > | 
 | |   < CONSTRAINT: "CONSTRAINT" > | 
 | |   < CONSTRAINT_CATALOG: "CONSTRAINT_CATALOG" > | 
 | |   < CONSTRAINT_NAME: "CONSTRAINT_NAME" > | 
 | |   < CONSTRAINT_SCHEMA: "CONSTRAINT_SCHEMA" > | 
 | |   < CONSTRAINTS: "CONSTRAINTS" > | 
 | |   < CONSTRUCTOR: "CONSTRUCTOR" > | 
 | |   < CONTAINS: "CONTAINS" > | 
 | |   < CONTAINS_SUBSTR: "CONTAINS_SUBSTR" > | 
 | |   < CONTINUE: "CONTINUE" > | 
 | |   < CONVERT: "CONVERT" > | 
 | |   < CORR: "CORR" > | 
 | |   < CORRESPONDING: "CORRESPONDING" > | 
 | |   < COUNT: "COUNT" > | 
 | |   < COVAR_POP: "COVAR_POP" > | 
 | |   < COVAR_SAMP: "COVAR_SAMP" > | 
 | |   < CREATE: "CREATE" > | 
 | |   < CROSS: "CROSS" > | 
 | |   < CUBE: "CUBE" > | 
 | |   < CUME_DIST: "CUME_DIST" > | 
 | |   < CURRENT: "CURRENT" > | 
 | |   < CURRENT_CATALOG: "CURRENT_CATALOG" > | 
 | |   < CURRENT_DATE: "CURRENT_DATE" > | 
 | |   < CURRENT_DEFAULT_TRANSFORM_GROUP: "CURRENT_DEFAULT_TRANSFORM_GROUP" > | 
 | |   < CURRENT_PATH: "CURRENT_PATH" > | 
 | |   < CURRENT_ROLE: "CURRENT_ROLE" > | 
 | |   < CURRENT_ROW: "CURRENT_ROW" > | 
 | |   < CURRENT_SCHEMA: "CURRENT_SCHEMA" > | 
 | |   < CURRENT_TIME: "CURRENT_TIME" > | 
 | |   < CURRENT_TIMESTAMP: "CURRENT_TIMESTAMP" > | 
 | |   < CURRENT_TRANSFORM_GROUP_FOR_TYPE: "CURRENT_TRANSFORM_GROUP_FOR_TYPE" > | 
 | |   < CURRENT_USER: "CURRENT_USER" > | 
 | |   < CURSOR: "CURSOR" > | 
 | |   < CURSOR_NAME: "CURSOR_NAME" > | 
 | |   < CYCLE: "CYCLE" > | 
 | |   < DATA: "DATA" > | 
 | |   < DATABASE: "DATABASE" > | 
 | |   < DATE: "DATE" > | 
 | |   < DATE_DIFF: "DATE_DIFF" > | 
 | |   < DATE_TRUNC: "DATE_TRUNC" > | 
 | |   < DATETIME: "DATETIME" > | 
 | |   < DATETIME_DIFF: "DATETIME_DIFF" > | 
 | |   < DATETIME_INTERVAL_CODE: "DATETIME_INTERVAL_CODE" > | 
 | |   < DATETIME_INTERVAL_PRECISION: "DATETIME_INTERVAL_PRECISION" > | 
 | |   < DATETIME_TRUNC: "DATETIME_TRUNC" > | 
 | |   < DAY: "DAY" > | 
 | |   < DAYOFWEEK: "DAYOFWEEK" > | 
 | |   < DAYOFYEAR: "DAYOFYEAR" > | 
 | |   < DAYS: "DAYS" > | 
 | |   < DEALLOCATE: "DEALLOCATE" > | 
 | |   < DEC: "DEC" > | 
 | |   < DECADE: "DECADE" > | 
 | |   < DECIMAL: "DECIMAL" > | 
 | |   < DECLARE: "DECLARE" > | 
 | |   < DEFAULT_: "DEFAULT" > | 
 | |   < DEFAULTS: "DEFAULTS" > | 
 | |   < DEFERRABLE: "DEFERRABLE" > | 
 | |   < DEFERRED: "DEFERRED" > | 
 | |   < DEFINE: "DEFINE" > | 
 | |   < DEFINED: "DEFINED" > | 
 | |   < DEFINER: "DEFINER" > | 
 | |   < DEGREE: "DEGREE" > | 
 | |   < DELETE: "DELETE" > { beforeTableName(); } | 
 | |   < DENSE_RANK: "DENSE_RANK" > | 
 | |   < DEPTH: "DEPTH" > | 
 | |   < DEREF: "DEREF" > | 
 | |   < DERIVED: "DERIVED" > | 
 | |   < DESC: "DESC" > | 
 | |   < DESCRIBE: "DESCRIBE" > { beforeTableName(); } | 
 | |   < DESCRIPTION: "DESCRIPTION" > | 
 | |   < DESCRIPTOR: "DESCRIPTOR" > | 
 | |   < DETERMINISTIC: "DETERMINISTIC" > | 
 | |   < DIAGNOSTICS: "DIAGNOSTICS" > | 
 | |   < DISALLOW: "DISALLOW" > | 
 | |   < DISCONNECT: "DISCONNECT" > | 
 | |   < DISPATCH: "DISPATCH" > | 
 | |   < DISTINCT: "DISTINCT" > | 
 | |   < DOMAIN: "DOMAIN" > | 
 | |   < DOT_FORMAT: "DOT" > | 
 | |   < DOUBLE: "DOUBLE" > | 
 | |   < DOW: "DOW" > | 
 | |   < DOY: "DOY" > | 
 | |   < DROP: "DROP" > | 
 | |   < DYNAMIC: "DYNAMIC" > | 
 | |   < DYNAMIC_FUNCTION: "DYNAMIC_FUNCTION" > | 
 | |   < DYNAMIC_FUNCTION_CODE: "DYNAMIC_FUNCTION_CODE" > | 
 | |   < EACH: "EACH" > | 
 | |   < ELEMENT: "ELEMENT" > | 
 | |   < ELSE: "ELSE" > | 
 | |   < EMPTY: "EMPTY" > | 
 | |   < ENCODING: "ENCODING"> | 
 | |   < END: "END" > | 
 | |   < END_EXEC: "END-EXEC" > | 
 | |   < END_FRAME: "END_FRAME" > | 
 | |   < END_PARTITION: "END_PARTITION" > | 
 | |   < EPOCH: "EPOCH" > | 
 | |   < EQUALS: "EQUALS" > | 
 | |   < ERROR: "ERROR" > | 
 | |   < ESCAPE: "ESCAPE" > | 
 | |   < EVERY: "EVERY" > | 
 | |   < EXCEPT: "EXCEPT" > | 
 | |   < EXCEPTION: "EXCEPTION" > | 
 | |   < EXCLUDE: "EXCLUDE" > | 
 | |   < EXCLUDING: "EXCLUDING" > | 
 | |   < EXEC: "EXEC" > | 
 | |   < EXECUTE: "EXECUTE" > | 
 | |   < EXISTS: "EXISTS" > | 
 | |   < EXP: "EXP" > | 
 | |   < EXPLAIN: "EXPLAIN" > | 
 | |   < EXTEND: "EXTEND" > | 
 | |   < EXTERNAL: "EXTERNAL" > | 
 | |   < EXTRACT: "EXTRACT" > | 
 | |   < FALSE: "FALSE" > | 
 | |   < FETCH: "FETCH" > | 
 | |   < FILTER: "FILTER" > | 
 | |   < FINAL: "FINAL" > | 
 | |   < FIRST: "FIRST" > | 
 | |   < FIRST_VALUE: "FIRST_VALUE"> | 
 | |   < FLOAT: "FLOAT" > | 
 | |   < FLOOR: "FLOOR" > | 
 | |   < FOLLOWING: "FOLLOWING" > | 
 | |   < FOR: "FOR" > | 
 | |   < FORMAT: "FORMAT" > | 
 | |   < FOREIGN: "FOREIGN" > | 
 | |   < FORTRAN: "FORTRAN" > | 
 | |   < FOUND: "FOUND" > | 
 | |   < FRAC_SECOND: "FRAC_SECOND" > | 
 | |   < FRAME_ROW: "FRAME_ROW" > | 
 | |   < FREE: "FREE" > | 
 | |   < FRIDAY: "FRIDAY" > | 
 | |   < FROM: "FROM" > { beforeTableName(); } | 
 | |   < FULL: "FULL" > | 
 | |   < FUNCTION: "FUNCTION" > | 
 | |   < FUSION: "FUSION" > | 
 | |   < G: "G" > | 
 | |   < GENERAL: "GENERAL" > | 
 | |   < GENERATED: "GENERATED" > | 
 | |   < GEOMETRY: "GEOMETRY" > | 
 | |   < GET: "GET" > | 
 | |   < GLOBAL: "GLOBAL" > | 
 | |   < GO: "GO" > | 
 | |   < GOTO: "GOTO" > | 
 | |   < GRANT: "GRANT" > | 
 | |   < GRANTED: "GRANTED" > | 
 | |   < GROUP: "GROUP" > | 
 | |   < GROUP_CONCAT: "GROUP_CONCAT" > | 
 | |   < GROUPING: "GROUPING" > | 
 | |   < GROUPS: "GROUPS" > | 
 | |   < HAVING: "HAVING" > | 
 | |   < HIERARCHY: "HIERARCHY" > | 
 | |   < HOLD: "HOLD" > | 
 | |   < HOP: "HOP" > | 
 | |   < HOUR: "HOUR" > | 
 | |   < HOURS: "HOURS" > | 
 | |   < IDENTITY: "IDENTITY" > | 
 | |   < IGNORE: "IGNORE" > | 
 | |   < ILIKE: "ILIKE" > | 
 | |   < IMMEDIATE: "IMMEDIATE" > | 
 | |   < IMMEDIATELY: "IMMEDIATELY" > | 
 | |   < IMPLEMENTATION: "IMPLEMENTATION" > | 
 | |   < IMPORT: "IMPORT" > | 
 | |   < IN: "IN" > | 
 | |   < INCLUDE: "INCLUDE" > | 
 | |   < INCLUDING: "INCLUDING" > | 
 | |   < INCREMENT: "INCREMENT" > | 
 | |   < INDICATOR: "INDICATOR" > | 
 | |   < INITIAL: "INITIAL" > | 
 | |   < INITIALLY: "INITIALLY" > | 
 | |   < INNER: "INNER" > | 
 | |   < INOUT: "INOUT" > | 
 | |   < INPUT: "INPUT" > | 
 | |   < INSENSITIVE: "INSENSITIVE" > | 
 | |   < INSERT: "INSERT" > { beforeTableName(); } | 
 | |   < INSTANCE: "INSTANCE" > | 
 | |   < INSTANTIABLE: "INSTANTIABLE" > | 
 | |   < INT: "INT" > | 
 | |   < INTEGER: "INTEGER" > | 
 | |   < INTERSECT: "INTERSECT" > | 
 | |   < INTERSECTION: "INTERSECTION" > | 
 | |   < INTERVAL: "INTERVAL" > | 
 | |   < INTO: "INTO" > | 
 | |   < INVOKER: "INVOKER" > | 
 | |   < IS: "IS" > | 
 | |   < ISODOW: "ISODOW" > | 
 | |   < ISOYEAR: "ISOYEAR" > | 
 | |   < ISOLATION: "ISOLATION" > | 
 | |   < JAVA: "JAVA" > | 
 | |   < JOIN: "JOIN" > { beforeTableName(); } | 
 | |   < JSON: "JSON" > | 
 | |   < JSON_ARRAY: "JSON_ARRAY"> | 
 | |   < JSON_ARRAYAGG: "JSON_ARRAYAGG"> | 
 | |   < JSON_EXISTS: "JSON_EXISTS" > | 
 | |   < JSON_OBJECT: "JSON_OBJECT"> | 
 | |   < JSON_OBJECTAGG: "JSON_OBJECTAGG"> | 
 | |   < JSON_QUERY: "JSON_QUERY" > | 
 | |   < JSON_SCOPE: "JSON_SCOPE" > | 
 | |   < JSON_VALUE: "JSON_VALUE" > | 
 | |   < K: "K" > | 
 | |   < KEY: "KEY" > | 
 | |   < KEY_MEMBER: "KEY_MEMBER" > | 
 | |   < KEY_TYPE: "KEY_TYPE" > | 
 | |   < LABEL: "LABEL" > | 
 | |   < LAG: "LAG" > | 
 | |   < LANGUAGE: "LANGUAGE" > | 
 | |   < LARGE: "LARGE" > | 
 | |   < LAST: "LAST" > | 
 | |   < LAST_VALUE: "LAST_VALUE" > | 
 | |   < LATERAL: "LATERAL" > | 
 | |   < LEAD: "LEAD" > | 
 | |   < LEADING: "LEADING" > | 
 | |   < LEFT: "LEFT" > | 
 | |   < LENGTH: "LENGTH" > | 
 | |   < LEVEL: "LEVEL" > | 
 | |   < LIBRARY: "LIBRARY" > | 
 | |   < LIKE: "LIKE" > | 
 | |   < LIKE_REGEX: "LIKE_REGEX" > | 
 | |   < LIMIT: "LIMIT" > | 
 | |   < LN: "LN" > | 
 | |   < LOCAL: "LOCAL" > | 
 | |   < LOCALTIME: "LOCALTIME" > | 
 | |   < LOCALTIMESTAMP: "LOCALTIMESTAMP" > | 
 | |   < LOCATOR: "LOCATOR" > | 
 | |   < LOWER: "LOWER" > | 
 | |   < M: "M" > | 
 | |   < MAP: "MAP" > | 
 | |   < MATCH: "MATCH" > | 
 | |   < MATCHED: "MATCHED" > | 
 | |   < MATCHES: "MATCHES" > | 
 | |   < MATCH_NUMBER: "MATCH_NUMBER"> | 
 | |   < MATCH_RECOGNIZE: "MATCH_RECOGNIZE"> | 
 | |   < MAX: "MAX" > | 
 | |   < MAXVALUE: "MAXVALUE" > | 
 | |   < MEASURES: "MEASURES" > | 
 | |   < MEMBER: "MEMBER" > | 
 | |   < MERGE: "MERGE" > { beforeTableName(); } | 
 | |   < MESSAGE_LENGTH: "MESSAGE_LENGTH" > | 
 | |   < MESSAGE_OCTET_LENGTH: "MESSAGE_OCTET_LENGTH" > | 
 | |   < MESSAGE_TEXT: "MESSAGE_TEXT" > | 
 | |   < METHOD: "METHOD" > | 
 | |   < MICROSECOND: "MICROSECOND" > | 
 | |   < MILLISECOND: "MILLISECOND" > | 
 | |   < MILLENNIUM: "MILLENNIUM" > | 
 | |   < MIN: "MIN" > | 
 | |   < MINUTE: "MINUTE" > | 
 | |   < MINUTES: "MINUTES" > | 
 | |   < MINVALUE: "MINVALUE" > | 
 | |   < MOD: "MOD" > | 
 | |   < MODIFIES: "MODIFIES" > | 
 | |   < MODULE: "MODULE" > | 
 | |   < MONDAY: "MONDAY" > | 
 | |   < MONTH: "MONTH" > | 
 | |   < MONTHS: "MONTHS" > | 
 | |   < MORE_: "MORE" > | 
 | |   < MULTISET: "MULTISET" > | 
 | |   < MUMPS: "MUMPS" > | 
 | |   < NAME: "NAME" > | 
 | |   < NAMES: "NAMES" > | 
 | |   < NANOSECOND: "NANOSECOND" > | 
 | |   < NATIONAL: "NATIONAL" > | 
 | |   < NATURAL: "NATURAL" > | 
 | |   < NCHAR: "NCHAR" > | 
 | |   < NCLOB: "NCLOB" > | 
 | |   < NESTING: "NESTING" > | 
 | |   < NEW: "NEW" > | 
 | |   < NEXT: "NEXT" > | 
 | |   < NO: "NO" > | 
 | |   < NONE: "NONE" > | 
 | |   < NORMALIZE: "NORMALIZE" > | 
 | |   < NORMALIZED: "NORMALIZED" > | 
 | |   < NOT: "NOT" > | 
 | |   < NTH_VALUE: "NTH_VALUE" > | 
 | |   < NTILE: "NTILE" > | 
 | |   < NULL: "NULL" > | 
 | |   < NULLABLE: "NULLABLE" > | 
 | |   < NULLIF: "NULLIF" > | 
 | |   < NULLS: "NULLS" > | 
 | |   < NUMBER: "NUMBER" > | 
 | |   < NUMERIC: "NUMERIC" > | 
 | |   < OBJECT: "OBJECT" > | 
 | |   < OCCURRENCES_REGEX: "OCCURRENCES_REGEX" > | 
 | |   < OCTET_LENGTH: "OCTET_LENGTH" > | 
 | |   < OCTETS: "OCTETS" > | 
 | |   < OF: "OF" > | 
 | |   < OFFSET: "OFFSET" > | 
 | |   < OLD: "OLD" > | 
 | |   < OMIT: "OMIT" > | 
 | |   < ON: "ON" > | 
 | |   < ONE: "ONE" > | 
 | |   < ONLY: "ONLY" > | 
 | |   < OPEN: "OPEN" > | 
 | |   < OPTION: "OPTION" > | 
 | |   < OPTIONS: "OPTIONS" > | 
 | |   < OR: "OR" > | 
 | |   < ORDER: "ORDER" > | 
 | |   < ORDERING: "ORDERING" > | 
 | |   < ORDINAL: "ORDINAL" > | 
 | |   < ORDINALITY: "ORDINALITY" > | 
 | |   < OTHERS: "OTHERS" > | 
 | |   < OUT: "OUT" > | 
 | |   < OUTER: "OUTER" > | 
 | |   < OUTPUT: "OUTPUT" > | 
 | |   < OVER: "OVER" > | 
 | |   < OVERLAPS: "OVERLAPS" > | 
 | |   < OVERLAY: "OVERLAY" > | 
 | |   < OVERRIDING: "OVERRIDING" > | 
 | |   < PAD: "PAD" > | 
 | |   < PARAMETER: "PARAMETER" > | 
 | |   < PARAMETER_MODE: "PARAMETER_MODE" > | 
 | |   < PARAMETER_NAME: "PARAMETER_NAME" > | 
 | |   < PARAMETER_ORDINAL_POSITION: "PARAMETER_ORDINAL_POSITION" > | 
 | |   < PARAMETER_SPECIFIC_CATALOG: "PARAMETER_SPECIFIC_CATALOG" > | 
 | |   < PARAMETER_SPECIFIC_NAME: "PARAMETER_SPECIFIC_NAME" > | 
 | |   < PARAMETER_SPECIFIC_SCHEMA: "PARAMETER_SPECIFIC_SCHEMA" > | 
 | |   < PARTIAL: "PARTIAL" > | 
 | |   < PARTITION: "PARTITION" > | 
 | |   < PASCAL: "PASCAL" > | 
 | |   < PASSING: "PASSING" > | 
 | |   < PASSTHROUGH: "PASSTHROUGH" > | 
 | |   < PAST: "PAST" > | 
 | |   < PATH: "PATH" > | 
 | |   < PATTERN: "PATTERN" > | 
 | |   < PER: "PER" > | 
 | |   < PERCENT: "PERCENT" > | 
 | |   < PERCENTILE_CONT: "PERCENTILE_CONT" > | 
 | |   < PERCENTILE_DISC: "PERCENTILE_DISC" > | 
 | |   < PERCENT_RANK: "PERCENT_RANK" > | 
 | |   < PERIOD: "PERIOD" > | 
 | |   < PERMUTE: "PERMUTE" > | 
 | |   < PIVOT: "PIVOT" > | 
 | |   < PLACING: "PLACING" > | 
 | |   < PLAN: "PLAN" > | 
 | |   < PLI: "PLI" > | 
 | |   < PORTION: "PORTION" > | 
 | |   < POSITION: "POSITION" > | 
 | |   < POSITION_REGEX: "POSITION_REGEX" > | 
 | |   < POWER: "POWER" > | 
 | |   < PRECEDES: "PRECEDES" > | 
 | |   < PRECEDING: "PRECEDING" > | 
 | |   < PRECISION: "PRECISION" > | 
 | |   < PREPARE: "PREPARE" > | 
 | |   < PRESERVE: "PRESERVE" > | 
 | |   < PREV: "PREV" > | 
 | |   < PRIMARY: "PRIMARY" > | 
 | |   < PRIOR: "PRIOR" > | 
 | |   < PRIVILEGES: "PRIVILEGES" > | 
 | |   < PROCEDURE: "PROCEDURE" > | 
 | |   < PUBLIC: "PUBLIC" > | 
 | |   < QUALIFY: "QUALIFY" > | 
 | |   < QUARTER: "QUARTER" > | 
 | |   < QUARTERS: "QUARTERS" > | 
 | |   < RANGE: "RANGE" > | 
 | |   < RANK: "RANK" > | 
 | |   < READ: "READ" > | 
 | |   < READS: "READS" > | 
 | |   < REAL: "REAL" > | 
 | |   < RECURSIVE: "RECURSIVE" > | 
 | |   < REF: "REF" > | 
 | |   < REFERENCES: "REFERENCES" > | 
 | |   < REFERENCING: "REFERENCING" > | 
 | |   < REGR_AVGX: "REGR_AVGX" > | 
 | |   < REGR_AVGY: "REGR_AVGY" > | 
 | |   < REGR_COUNT: "REGR_COUNT" > | 
 | |   < REGR_INTERCEPT: "REGR_INTERCEPT" > | 
 | |   < REGR_R2: "REGR_R2" > | 
 | |   < REGR_SLOPE: "REGR_SLOPE" > | 
 | |   < REGR_SXX: "REGR_SXX" > | 
 | |   < REGR_SXY: "REGR_SXY" > | 
 | |   < REGR_SYY: "REGR_SYY" > | 
 | |   < RELATIVE: "RELATIVE" > | 
 | |   < RELEASE: "RELEASE" > | 
 | |   < REPEATABLE: "REPEATABLE" > | 
 | |   < REPLACE: "REPLACE" > | 
 | |   < RESET: "RESET" > | 
 | |   < RESPECT: "RESPECT" > | 
 | |   < RESTART: "RESTART" > | 
 | |   < RESTRICT: "RESTRICT" > | 
 | |   < RESULT: "RESULT" > | 
 | |   < RETURN: "RETURN" > | 
 | |   < RETURNED_CARDINALITY: "RETURNED_CARDINALITY" > | 
 | |   < RETURNED_LENGTH: "RETURNED_LENGTH" > | 
 | |   < RETURNED_OCTET_LENGTH: "RETURNED_OCTET_LENGTH" > | 
 | |   < RETURNED_SQLSTATE: "RETURNED_SQLSTATE" > | 
 | |   < RETURNING: "RETURNING" > | 
 | |   < RETURNS: "RETURNS" > | 
 | |   < REVOKE: "REVOKE" > | 
 | |   < RIGHT: "RIGHT" > | 
 | |   < RLIKE: "RLIKE" > | 
 | |   < ROLE: "ROLE" > | 
 | |   < ROLLBACK: "ROLLBACK" > | 
 | |   < ROLLUP: "ROLLUP" > | 
 | |   < ROUTINE: "ROUTINE" > | 
 | |   < ROUTINE_CATALOG: "ROUTINE_CATALOG" > | 
 | |   < ROUTINE_NAME: "ROUTINE_NAME" > | 
 | |   < ROUTINE_SCHEMA: "ROUTINE_SCHEMA" > | 
 | |   < ROW: "ROW" > | 
 | |   < ROW_COUNT: "ROW_COUNT" > | 
 | |   < ROW_NUMBER: "ROW_NUMBER" > | 
 | |   < ROWS: "ROWS" > | 
 | |   < RUNNING: "RUNNING" > | 
 | |   < SAFE_CAST: "SAFE_CAST" > | 
 | |   < SAFE_OFFSET: "SAFE_OFFSET" > | 
 | |   < SAFE_ORDINAL: "SAFE_ORDINAL" > | 
 | |   < SATURDAY: "SATURDAY" > | 
 | |   < SAVEPOINT: "SAVEPOINT" > | 
 | |   < SCALAR: "SCALAR" > | 
 | |   < SCALE: "SCALE" > | 
 | |   < SCHEMA: "SCHEMA" > | 
 | |   < SCHEMA_NAME: "SCHEMA_NAME" > | 
 | |   < SCOPE: "SCOPE" > | 
 | |   < SCOPE_CATALOGS: "SCOPE_CATALOGS" > | 
 | |   < SCOPE_NAME: "SCOPE_NAME" > | 
 | |   < SCOPE_SCHEMA: "SCOPE_SCHEMA" > | 
 | |   < SCROLL: "SCROLL" > | 
 | |   < SEARCH: "SEARCH" > | 
 | |   < SECOND: "SECOND" > | 
 | |   < SECONDS: "SECONDS" > | 
 | |   < SECTION: "SECTION" > | 
 | |   < SECURITY: "SECURITY" > | 
 | |   < SEEK: "SEEK" > | 
 | |   < SELECT: "SELECT" > { afterTableName(); } | 
 | |   < SELF: "SELF" > | 
 | |   < SENSITIVE: "SENSITIVE" > | 
 | |   < SEPARATOR: "SEPARATOR" > | 
 | |   < SEQUENCE: "SEQUENCE" > | 
 | |   < SERIALIZABLE: "SERIALIZABLE" > | 
 | |   < SERVER: "SERVER" > | 
 | |   < SERVER_NAME: "SERVER_NAME" > | 
 | |   < SESSION: "SESSION" > | 
 | |   < SESSION_USER: "SESSION_USER" > | 
 | |   < SET: "SET" > { afterTableName(); } | 
 | |   < SETS: "SETS" > | 
 | |   < SET_MINUS: "MINUS"> | 
 | |   < SHOW: "SHOW" > | 
 | |   < SIMILAR: "SIMILAR" > | 
 | |   < SIMPLE: "SIMPLE" > | 
 | |   < SIZE: "SIZE" > | 
 | |   < SKIP_: "SKIP" > | 
 | |   < SMALLINT: "SMALLINT" > | 
 | |   < SOME: "SOME" > | 
 | |   < SOURCE: "SOURCE" > | 
 | |   < SPACE: "SPACE" > | 
 | |   < SPECIFIC: "SPECIFIC" > | 
 | |   < SPECIFIC_NAME: "SPECIFIC_NAME" > | 
 | |   < SPECIFICTYPE: "SPECIFICTYPE" > | 
 | |   < SQL: "SQL" > | 
 | |   < SQLEXCEPTION: "SQLEXCEPTION" > | 
 | |   < SQLSTATE: "SQLSTATE" > | 
 | |   < SQLWARNING: "SQLWARNING" > | 
 | |   < SQL_BIGINT: "SQL_BIGINT" > | 
 | |   < SQL_BINARY: "SQL_BINARY" > | 
 | |   < SQL_BIT: "SQL_BIT" > | 
 | |   < SQL_BLOB: "SQL_BLOB" > | 
 | |   < SQL_BOOLEAN: "SQL_BOOLEAN" > | 
 | |   < SQL_CHAR: "SQL_CHAR" > | 
 | |   < SQL_CLOB: "SQL_CLOB" > | 
 | |   < SQL_DATE: "SQL_DATE" > | 
 | |   < SQL_DECIMAL: "SQL_DECIMAL" > | 
 | |   < SQL_DOUBLE: "SQL_DOUBLE" > | 
 | |   < SQL_FLOAT: "SQL_FLOAT" > | 
 | |   < SQL_INTEGER: "SQL_INTEGER" > | 
 | |   < SQL_INTERVAL_DAY: "SQL_INTERVAL_DAY" > | 
 | |   < SQL_INTERVAL_DAY_TO_HOUR: "SQL_INTERVAL_DAY_TO_HOUR" > | 
 | |   < SQL_INTERVAL_DAY_TO_MINUTE: "SQL_INTERVAL_DAY_TO_MINUTE" > | 
 | |   < SQL_INTERVAL_DAY_TO_SECOND: "SQL_INTERVAL_DAY_TO_SECOND" > | 
 | |   < SQL_INTERVAL_HOUR: "SQL_INTERVAL_HOUR" > | 
 | |   < SQL_INTERVAL_HOUR_TO_MINUTE: "SQL_INTERVAL_HOUR_TO_MINUTE" > | 
 | |   < SQL_INTERVAL_HOUR_TO_SECOND: "SQL_INTERVAL_HOUR_TO_SECOND" > | 
 | |   < SQL_INTERVAL_MINUTE: "SQL_INTERVAL_MINUTE" > | 
 | |   < SQL_INTERVAL_MINUTE_TO_SECOND: "SQL_INTERVAL_MINUTE_TO_SECOND" > | 
 | |   < SQL_INTERVAL_MONTH: "SQL_INTERVAL_MONTH" > | 
 | |   < SQL_INTERVAL_SECOND: "SQL_INTERVAL_SECOND" > | 
 | |   < SQL_INTERVAL_YEAR: "SQL_INTERVAL_YEAR" > | 
 | |   < SQL_INTERVAL_YEAR_TO_MONTH: "SQL_INTERVAL_YEAR_TO_MONTH" > | 
 | |   < SQL_LONGVARBINARY: "SQL_LONGVARBINARY" > | 
 | |   < SQL_LONGVARCHAR: "SQL_LONGVARCHAR" > | 
 | |   < SQL_LONGVARNCHAR: "SQL_LONGVARNCHAR" > | 
 | |   < SQL_NCHAR: "SQL_NCHAR" > | 
 | |   < SQL_NCLOB: "SQL_NCLOB" > | 
 | |   < SQL_NUMERIC: "SQL_NUMERIC" > | 
 | |   < SQL_NVARCHAR: "SQL_NVARCHAR" > | 
 | |   < SQL_REAL: "SQL_REAL" > | 
 | |   < SQL_SMALLINT: "SQL_SMALLINT" > | 
 | |   < SQL_TIME: "SQL_TIME" > | 
 | |   < SQL_TIMESTAMP: "SQL_TIMESTAMP" > | 
 | |   < SQL_TINYINT: "SQL_TINYINT" > | 
 | |   < SQL_TSI_DAY: "SQL_TSI_DAY" > | 
 | |   < SQL_TSI_FRAC_SECOND: "SQL_TSI_FRAC_SECOND" > | 
 | |   < SQL_TSI_HOUR: "SQL_TSI_HOUR" > | 
 | |   < SQL_TSI_MICROSECOND: "SQL_TSI_MICROSECOND" > | 
 | |   < SQL_TSI_MINUTE: "SQL_TSI_MINUTE" > | 
 | |   < SQL_TSI_MONTH: "SQL_TSI_MONTH" > | 
 | |   < SQL_TSI_QUARTER: "SQL_TSI_QUARTER" > | 
 | |   < SQL_TSI_SECOND: "SQL_TSI_SECOND" > | 
 | |   < SQL_TSI_WEEK: "SQL_TSI_WEEK" > | 
 | |   < SQL_TSI_YEAR: "SQL_TSI_YEAR" > | 
 | |   < SQL_VARBINARY: "SQL_VARBINARY" > | 
 | |   < SQL_VARCHAR: "SQL_VARCHAR" > | 
 | |   < SQRT: "SQRT" > | 
 | |   < START: "START" > | 
 | |   < STATE: "STATE" > | 
 | |   < STATEMENT: "STATEMENT" > | 
 | |   < STATIC: "STATIC" > | 
 | |   < STDDEV_POP: "STDDEV_POP" > | 
 | |   < STDDEV_SAMP: "STDDEV_SAMP" > | 
 | |   < STREAM: "STREAM" > | 
 | |   < STRING_AGG: "STRING_AGG" > | 
 | |   < STRUCTURE: "STRUCTURE" > | 
 | |   < STYLE: "STYLE" > | 
 | |   < SUBCLASS_ORIGIN: "SUBCLASS_ORIGIN" > | 
 | |   < SUBMULTISET: "SUBMULTISET" > | 
 | |   < SUBSET: "SUBSET" > | 
 | |   < SUBSTITUTE: "SUBSTITUTE" > | 
 | |   < SUBSTRING: "SUBSTRING" > | 
 | |   < SUBSTRING_REGEX: "SUBSTRING_REGEX" > | 
 | |   < SUCCEEDS: "SUCCEEDS" > | 
 | |   < SUM: "SUM" > | 
 | |   < SUNDAY: "SUNDAY" > | 
 | |   < SYMMETRIC: "SYMMETRIC" > | 
 | |   < SYSTEM: "SYSTEM" > | 
 | |   < SYSTEM_TIME: "SYSTEM_TIME" > | 
 | |   < SYSTEM_USER: "SYSTEM_USER" > | 
 | |   < TABLE: "TABLE" > { beforeTableName(); } | 
 | |   < TABLE_NAME: "TABLE_NAME" > | 
 | |   < TABLESAMPLE: "TABLESAMPLE" > | 
 | |   < TEMPORARY: "TEMPORARY" > | 
 | |   < THEN: "THEN" > | 
 | |   < THURSDAY: "THURSDAY" > | 
 | |   < TIES: "TIES" > | 
 | |   < TIME: "TIME" > | 
 | |   < TIME_DIFF: "TIME_DIFF" > | 
 | |   < TIME_TRUNC: "TIME_TRUNC" > | 
 | |   < TIMESTAMP: "TIMESTAMP" > | 
 | |   < TIMESTAMPADD: "TIMESTAMPADD" > | 
 | |   < TIMESTAMPDIFF: "TIMESTAMPDIFF" > | 
 | |   < TIMESTAMP_DIFF: "TIMESTAMP_DIFF" > | 
 | |   < TIMESTAMP_TRUNC: "TIMESTAMP_TRUNC" > | 
 | |   < TIMEZONE_HOUR: "TIMEZONE_HOUR" > | 
 | |   < TIMEZONE_MINUTE: "TIMEZONE_MINUTE" > | 
 | |   < TINYINT: "TINYINT" > | 
 | |   < TO: "TO" > | 
 | |   < TOP_LEVEL_COUNT: "TOP_LEVEL_COUNT" > | 
 | |   < TRAILING: "TRAILING" > | 
 | |   < TRANSACTION: "TRANSACTION" > | 
 | |   < TRANSACTIONS_ACTIVE: "TRANSACTIONS_ACTIVE" > | 
 | |   < TRANSACTIONS_COMMITTED: "TRANSACTIONS_COMMITTED" > | 
 | |   < TRANSACTIONS_ROLLED_BACK: "TRANSACTIONS_ROLLED_BACK" > | 
 | |   < TRANSFORM: "TRANSFORM" > | 
 | |   < TRANSFORMS: "TRANSFORMS" > | 
 | |   < TRANSLATE: "TRANSLATE" > | 
 | |   < TRANSLATE_REGEX: "TRANSLATE_REGEX" > | 
 | |   < TRANSLATION: "TRANSLATION" > | 
 | |   < TREAT: "TREAT" > | 
 | |   < TRIGGER: "TRIGGER" > | 
 | |   < TRIGGER_CATALOG: "TRIGGER_CATALOG" > | 
 | |   < TRIGGER_NAME: "TRIGGER_NAME" > | 
 | |   < TRIGGER_SCHEMA: "TRIGGER_SCHEMA" > | 
 | |   < TRIM: "TRIM" > | 
 | |   < TRIM_ARRAY: "TRIM_ARRAY" > | 
 | |   < TRUE: "TRUE" > | 
 | |   < TRUNCATE: "TRUNCATE" > | 
 | |   < TRY_CAST: "TRY_CAST" > | 
 | |   < TUESDAY: "TUESDAY" > | 
 | |   < TUMBLE: "TUMBLE" > | 
 | |   < TYPE: "TYPE" > | 
 | |   < UESCAPE: "UESCAPE" > | 
 | |   < UNBOUNDED: "UNBOUNDED" > | 
 | |   < UNCOMMITTED: "UNCOMMITTED" > | 
 | |   < UNCONDITIONAL: "UNCONDITIONAL" > | 
 | |   < UNDER: "UNDER" > | 
 | |   < UNION: "UNION" > | 
 | |   < UNIQUE: "UNIQUE" > | 
 | |   < UNKNOWN: "UNKNOWN" > | 
 | |   < UNPIVOT: "UNPIVOT" > | 
 | |   < UNNAMED: "UNNAMED" > | 
 | |   < UNNEST: "UNNEST" > | 
 | |   < UPDATE: "UPDATE" > { beforeTableName(); } | 
 | |   < UPPER: "UPPER" > | 
 | |   < UPSERT: "UPSERT" > | 
 | |   < USAGE: "USAGE" > | 
 | |   < USER: "USER" > | 
 | |   < USER_DEFINED_TYPE_CATALOG: "USER_DEFINED_TYPE_CATALOG" > | 
 | |   < USER_DEFINED_TYPE_CODE: "USER_DEFINED_TYPE_CODE" > | 
 | |   < USER_DEFINED_TYPE_NAME: "USER_DEFINED_TYPE_NAME" > | 
 | |   < USER_DEFINED_TYPE_SCHEMA: "USER_DEFINED_TYPE_SCHEMA" > | 
 | |   < USING: "USING" > | 
 | |   < UTF8: "UTF8" > | 
 | |   < UTF16: "UTF16" > | 
 | |   < UTF32: "UTF32" > | 
 | |   < VALUE: "VALUE" > | 
 | |   < VALUES: "VALUES" > { afterTableName(); } | 
 | |   < VALUE_OF: "VALUE_OF" > | 
 | |   < VAR_POP: "VAR_POP" > | 
 | |   < VAR_SAMP: "VAR_SAMP" > | 
 | |   < VARBINARY: "VARBINARY" > | 
 | |   < VARCHAR: "VARCHAR" > | 
 | |   < VARYING: "VARYING" > | 
 | |   < VERSION: "VERSION" > | 
 | |   < VERSIONING: "VERSIONING" > | 
 | |   < VIEW: "VIEW" > | 
 | |   < WEDNESDAY: "WEDNESDAY" > | 
 | |   < WEEK: "WEEK" > | 
 | |   < WEEKS: "WEEKS" > | 
 | |   < WHEN: "WHEN" > | 
 | |   < WHENEVER: "WHENEVER" > | 
 | |   < WHERE: "WHERE" > | 
 | |   < WIDTH_BUCKET: "WIDTH_BUCKET" > | 
 | |   < WINDOW: "WINDOW" > | 
 | |   < WITH: "WITH" > | 
 | |   < WITHIN: "WITHIN" > | 
 | |   < WITHOUT: "WITHOUT" > | 
 | |   < WORK: "WORK" > | 
 | |   < WRAPPER: "WRAPPER" > | 
 | |   < WRITE: "WRITE" > | 
 | |   < XML: "XML" > | 
 | |   < YEAR: "YEAR" > | 
 | |   < YEARS: "YEARS" > | 
 | |   < ZONE: "ZONE" > | 
 | <#-- additional parser keywords are included here --> | 
 | <#list (parser.keywords!default.parser.keywords) as keyword> | 
 | |   < ${keyword}: "${keyword}" > | 
 | </#list> | 
 | } | 
 |  | 
 | /** | 
 |  * Parses a non-reserved keyword for use as an identifier. | 
 |  * | 
 |  * <p>The method is broken up into several sub-methods; without this | 
 |  * decomposition, parsers such as Babel with more than ~1,000 non-reserved | 
 |  * keywords would generate such deeply nested 'if' statements that javac would | 
 |  * fail with a {@link StackOverflowError}. | 
 |  * | 
 |  * <p>The list is generated from the FMPP config data. To add or remove | 
 |  * keywords, modify config.fmpp. For parsers except Babel, make sure that | 
 |  * keywords are not reserved by the SQL standard. | 
 |  * | 
 |  * @see Glossary#SQL2003 SQL:2003 Part 2 Section 5.2 | 
 |  */ | 
 | String NonReservedKeyWord() : | 
 | { | 
 | } | 
 | { | 
 |     ( | 
 |         NonReservedKeyWord0of3() | 
 |     |   NonReservedKeyWord1of3() | 
 |     |   NonReservedKeyWord2of3() | 
 |     ) | 
 |     { | 
 |         return unquotedIdentifier(); | 
 |     } | 
 | } | 
 |  | 
 | /** @see #NonReservedKeyWord */ | 
 | void NonReservedKeyWord0of3() : | 
 | { | 
 | } | 
 | { | 
 |     ( | 
 | <#list (parser.nonReservedKeywords!default.parser.nonReservedKeywords) + (parser.nonReservedKeywordsToAdd!default.parser.nonReservedKeywordsToAdd) as keyword> | 
 | <#if keyword?index == 0> | 
 |         <${keyword}> | 
 | <#elseif keyword?index % 3 == 0> | 
 |     |   <${keyword}> | 
 | </#if> | 
 | </#list> | 
 |     ) | 
 | } | 
 |  | 
 | /** @see #NonReservedKeyWord */ | 
 | void NonReservedKeyWord1of3() : | 
 | { | 
 | } | 
 | { | 
 |     ( | 
 | <#list (parser.nonReservedKeywords!default.parser.nonReservedKeywords) + (parser.nonReservedKeywordsToAdd!default.parser.nonReservedKeywordsToAdd) as keyword> | 
 | <#if keyword?index == 1> | 
 |         <${keyword}> | 
 | <#elseif keyword?index % 3 == 1> | 
 |     |   <${keyword}> | 
 | </#if> | 
 | </#list> | 
 |     ) | 
 | } | 
 |  | 
 | /** @see #NonReservedKeyWord */ | 
 | void NonReservedKeyWord2of3() : | 
 | { | 
 | } | 
 | { | 
 |     ( | 
 | <#list (parser.nonReservedKeywords!default.parser.nonReservedKeywords) + (parser.nonReservedKeywordsToAdd!default.parser.nonReservedKeywordsToAdd) as keyword> | 
 | <#if keyword?index == 2> | 
 |         <${keyword}> | 
 | <#elseif keyword?index % 3 == 2> | 
 |     |   <${keyword}> | 
 | </#if> | 
 | </#list> | 
 |     ) | 
 | } | 
 |  | 
 | /* LITERALS */ | 
 |  | 
 | <DEFAULT, DQID, BTID, BQID, BQHID> TOKEN : | 
 | { | 
 |     < UNSIGNED_INTEGER_LITERAL: (["0"-"9"])+ > | 
 | | | 
 |     < APPROX_NUMERIC_LITERAL: | 
 |     (<UNSIGNED_INTEGER_LITERAL> | <DECIMAL_NUMERIC_LITERAL>) <EXPONENT> > | 
 | | | 
 |     < DECIMAL_NUMERIC_LITERAL: | 
 |     (["0"-"9"])+(".")?(["0"-"9"])* | 
 |     | "."(["0"-"9"])+ | 
 |     > | 
 | | | 
 |     < #EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ > | 
 | | | 
 |     < #HEXDIGIT: ["0"-"9","a"-"f","A"-"F"] > | 
 | | | 
 |     < #WHITESPACE: | 
 |     [ " ","\t","\n","\r","\f" ] | 
 |     > | 
 | | | 
 |     /* To improve error reporting, we allow all kinds of characters, | 
 |      * not just hexits, in a binary string literal. */ | 
 |     < BINARY_STRING_LITERAL: ["x","X"] <QUOTE> ( (~["'"]) | ("''"))* <QUOTE> > | 
 | } | 
 |  | 
 | // All databases except BigQuery support standard single-quoted literals, | 
 | // which use single-quote as the escape character. | 
 | <DEFAULT, DQID, BTID> TOKEN : | 
 | { | 
 |     < QUOTED_STRING: <QUOTE> ( (~["'"]) | ("''"))* <QUOTE> > | 
 | | | 
 |     < PREFIXED_STRING_LITERAL: ("_" <CHARSETNAME> | "N") <QUOTED_STRING> > | 
 | | | 
 |     < UNICODE_STRING_LITERAL: "U" "&" <QUOTED_STRING> > | 
 | | | 
 |     < C_STYLE_ESCAPED_STRING_LITERAL: "E" <QUOTE> ( (~["'", "\\"]) | ("\\" ~[]) | "''")* <QUOTE> > | 
 | | | 
 |     < #CHARSETNAME: (["a"-"z","A"-"Z","0"-"9"]) | 
 |     (["a"-"z","A"-"Z","0"-"9",":",".","-","_"])* | 
 |     > | 
 | } | 
 |  | 
 | // BigQuery supports single- and double-quoted literals with back-slash | 
 | // as the escape character. | 
 | <BQID, BQHID> TOKEN : | 
 | { | 
 |     // BigQuery-style double-quoted string, escaped using backslash | 
 |     < BIG_QUERY_DOUBLE_QUOTED_STRING: | 
 |       <DOUBLE_QUOTE> ( (~["\\", "\""]) | ("\\" ~[]) )* <DOUBLE_QUOTE> | 
 |     > | 
 | | | 
 |     // BigQuery-style single-quoted string, escaped using backslash | 
 |     < BIG_QUERY_QUOTED_STRING: | 
 |       <QUOTE> ( (~["\\", "'"]) | ("\\" ~[]) )* <QUOTE> | 
 |     > | 
 | } | 
 |  | 
 | <DEFAULT, DQID, BTID, BQID, BQHID> TOKEN : | 
 | { | 
 |     < UNICODE_QUOTED_ESCAPE_CHAR: | 
 |     <QUOTE> | 
 |     (~["0"-"9","a"-"f","A"-"F","+","\""," ","\t","\n","\r","\f"]) | 
 |     <QUOTE> | 
 |     > | 
 | } | 
 |  | 
 | /* SEPARATORS */ | 
 |  | 
 | <DEFAULT, DQID, BTID, BQID, BQHID> TOKEN : | 
 | { | 
 |     < LPAREN: "("> | 
 | |   < RPAREN: ")"> | 
 | <#if (parser.includeBraces!default.parser.includeBraces) > | 
 | |   < LBRACE_D: "{" (" ")* ["d","D"] > | 
 | |   < LBRACE_T: "{" (" ")* ["t","T"] > | 
 | |   < LBRACE_TS: "{" (" ")* ["t","T"] ["s","S"] > | 
 | |   < LBRACE_FN: "{" (" ")* ["f","F"] ["n","N"] > | 
 | |   < LBRACE: "{" > | 
 | |   < RBRACE: "}" > | 
 | <#else> | 
 | <#include "/@includes/braces.ftl" /> | 
 | </#if> | 
 | |   < LBRACKET: "[" > | 
 | |   < RBRACKET: "]" > | 
 | |   < SEMICOLON: ";" > | 
 | |   < DOT: "." > | 
 | |   < COMMA: "," > | 
 | } | 
 |  | 
 | /* OPERATORS */ | 
 |  | 
 | <DEFAULT, DQID, BTID, BQID, BQHID> TOKEN : | 
 | { | 
 |     < EQ: "=" > | 
 | |   < GT: ">" > | 
 | |   < LT: "<" > | 
 | |   < HOOK: "?" > | 
 | |   < COLON: ":" > | 
 | |   < LE: "<=" > | 
 | |   < GE: ">=" > | 
 | |   < NE: "<>" > | 
 | |   < NE2: "!=" > | 
 | |   < PLUS: "+" > | 
 | |   < MINUS: "-" > | 
 | |   < LAMBDA: "->" > | 
 | |   < STAR: "*" > | 
 | |   < SLASH: "/" > | 
 | |   < PERCENT_REMAINDER: "%" > | 
 | |   < CONCAT: "||" > | 
 | |   < NAMED_ARGUMENT_ASSIGNMENT: "=>" > | 
 | |   < DOUBLE_PERIOD: ".." > | 
 | |   < QUOTE: "'" > | 
 | |   < DOUBLE_QUOTE: "\"" > | 
 | |   < VERTICAL_BAR: "|" > | 
 | |   < CARET: "^" > | 
 | |   < DOLLAR: "$" > | 
 | <#list (parser.binaryOperatorsTokens!default.parser.binaryOperatorsTokens) as operator> | 
 | |   ${operator} | 
 | </#list> | 
 | } | 
 |  | 
 |  | 
 | /***************************************** | 
 |  * Lexical Descriptions                  * | 
 |  *****************************************/ | 
 |  | 
 | TOKEN_MGR_DECLS : { | 
 |     final List<Integer> lexicalStateStack = new ArrayList<Integer>(); | 
 |  | 
 |     void pushState() { | 
 |       lexicalStateStack.add(curLexState); | 
 |     } | 
 |  | 
 |     void popState() { | 
 |       SwitchTo(lexicalStateStack.remove(lexicalStateStack.size() - 1)); | 
 |     } | 
 |  | 
 |     void beforeTableName() { | 
 |       if (curLexState == BQID) { | 
 |         pushState(); | 
 |         SwitchTo(BQHID); | 
 |       } | 
 |     } | 
 |  | 
 |     void afterTableName() { | 
 |       if (curLexState == BQHID) { | 
 |         popState(); | 
 |       } | 
 |     } | 
 |  | 
 | <#if (parser.includeAdditionalDeclarations!default.parser.includeAdditionalDeclarations)> | 
 |   <#include "/@includes/tokenManagerDeclarations.ftl" /> | 
 | </#if> | 
 | } | 
 |  | 
 | /* | 
 | Lexical states: | 
 |  | 
 | DEFAULT: Identifiers are quoted in brackets, e.g. [My Identifier] | 
 | DQID:    Identifiers are double-quoted, e.g. "My Identifier" | 
 | BTID:    Identifiers are enclosed in back-ticks, escaped using back-ticks, | 
 |          e.g. `My ``Quoted`` Identifier` | 
 | BQID:    Identifiers are enclosed in back-ticks, escaped using backslash, | 
 |          e.g. `My \`Quoted\` Identifier`, | 
 |          and with the potential to shift into BQHID in contexts where table | 
 |          names are expected, and thus allow hyphen-separated identifiers as | 
 |          part of table names | 
 | BQHID:   Identifiers are enclosed in back-ticks, escaped using backslash, | 
 |          e.g. `My \`Quoted\` Identifier` | 
 |          and unquoted identifiers may contain hyphens, e.g. foo-bar | 
 | IN_SINGLE_LINE_COMMENT: | 
 | IN_FORMAL_COMMENT: | 
 | IN_MULTI_LINE_COMMENT: | 
 |  | 
 | DEFAULT, DQID, BTID, BQID are the 4 'normal states'. Behavior is identical | 
 | except for how quoted identifiers are recognized. | 
 |  | 
 | The BQHID state exists only at the start of a table name (e.g. immediately after | 
 | FROM or INSERT INTO). As soon as an identifier is seen, the state shifts back | 
 | to BTID. | 
 |  | 
 | After a comment has completed, the lexer returns to the previous state, one | 
 | of the 'normal states'. | 
 | */ | 
 |  | 
 | /* WHITE SPACE */ | 
 |  | 
 | <DEFAULT, DQID, BTID, BQID, BQHID> SKIP : | 
 | { | 
 |     " " | 
 | |   "\t" | 
 | |   "\n" | 
 | |   "\r" | 
 | |   "\f" | 
 | } | 
 |  | 
 | /* COMMENTS */ | 
 |  | 
 | <DEFAULT, DQID, BTID, BQID, BQHID> TOKEN : | 
 | { | 
 |     < HINT_BEG: "/*+"> | 
 | |   < COMMENT_END: "*/" > | 
 | } | 
 |  | 
 | <DEFAULT, DQID, BTID, BQID, BQHID> MORE : | 
 | { | 
 |     <"/**" ~["/"]> { pushState(); } : IN_FORMAL_COMMENT | 
 | } | 
 |  | 
 | <DEFAULT, DQID, BTID, BQID, BQHID> MORE : | 
 | { | 
 |     "/*" { pushState(); } : IN_MULTI_LINE_COMMENT | 
 | } | 
 |  | 
 | <DEFAULT, DQID, BTID, BQID, BQHID> SKIP : | 
 | { | 
 |     <SINGLE_LINE_COMMENT: ("//"|"--")(~["\n","\r"])* ("\n"|"\r"|"\r\n")? > | 
 | } | 
 |  | 
 | <IN_FORMAL_COMMENT> | 
 | SPECIAL_TOKEN : | 
 | { | 
 |     <FORMAL_COMMENT: <COMMENT_END> > { popState(); } | 
 | } | 
 |  | 
 | <IN_MULTI_LINE_COMMENT> | 
 | SPECIAL_TOKEN : | 
 | { | 
 |     <MULTI_LINE_COMMENT: <COMMENT_END> > { popState(); } | 
 | } | 
 |  | 
 | <IN_FORMAL_COMMENT,IN_MULTI_LINE_COMMENT> | 
 | MORE : | 
 | { | 
 |     < ~[] > | 
 | } | 
 |  | 
 |  | 
 | /* IDENTIFIERS */ | 
 |  | 
 | <DEFAULT> TOKEN : | 
 | { | 
 |     < BRACKET_QUOTED_IDENTIFIER: | 
 |     "[" | 
 |     ( | 
 |         (~["]","\n","\r"]) | 
 |     | | 
 |         ("]]") | 
 |     )+ | 
 |     "]" | 
 |     > | 
 | } | 
 |  | 
 | <DQID> TOKEN : | 
 | { | 
 |     < QUOTED_IDENTIFIER: | 
 |     "\"" | 
 |     ( | 
 |         (~["\"","\n","\r"]) | 
 |     | | 
 |         ("\"\"") | 
 |     )+ | 
 |     "\"" | 
 |     > | 
 | } | 
 |  | 
 | <BTID> TOKEN : | 
 | { | 
 |     < BACK_QUOTED_IDENTIFIER: | 
 |     "`" | 
 |     ( | 
 |         (~["`","\n","\r"]) | 
 |     | | 
 |         ("``") | 
 |     )+ | 
 |     "`" | 
 |     > | 
 | } | 
 |  | 
 | <BQID, BQHID> TOKEN : | 
 | { | 
 |     // BigQuery-style backtick-quoted identifier, escaped using backslash | 
 |     < BIG_QUERY_BACK_QUOTED_IDENTIFIER: | 
 |     "`" | 
 |     ( | 
 |         (~["\\", "`"]) | 
 |     | | 
 |         ("\\" ~[]) | 
 |     )* | 
 |     "`" | 
 |     > | 
 | } | 
 |  | 
 | <BQHID> TOKEN : | 
 | { | 
 |     // Per BigQuery: "Project IDs must contain 6-63 lowercase letters, digits, | 
 |     // or dashes. IDs must start with a letter and may not end with a dash." | 
 |     // We do not restrict length, or prevent identifiers from ending in a dash. | 
 |     < HYPHENATED_IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>|"-")* > { popState(); } | 
 | } | 
 |  | 
 | <DEFAULT, DQID, BTID, BQID> TOKEN : | 
 | { | 
 |     <#if parser.customIdentifierToken?has_content> | 
 |         ${parser.customIdentifierToken} | 
 |     <#else> | 
 |         < IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>)* > | 
 |     </#if> | 
 | } | 
 |  | 
 | <DEFAULT, DQID, BTID, BQID, BQHID> TOKEN : | 
 | { | 
 |     < COLLATION_ID: | 
 |     (<LETTER>|<DIGIT>)+ (<LETTER>|<DIGIT>|":"|"."|"-"|"_")* | 
 |     "$" | 
 |     (<LETTER>|"_")+ | 
 |     ("$" (<LETTER>|<DIGIT>|"_")+)? | 
 |     > | 
 | | | 
 |     < UNICODE_QUOTED_IDENTIFIER: "U" "&" <QUOTED_IDENTIFIER> > | 
 | | | 
 |     < #LETTER: | 
 |     [ | 
 |         "\u0024", | 
 |         "\u0041"-"\u005a", | 
 |         "\u005f", | 
 |         "\u0061"-"\u007a", | 
 |         "\u00c0"-"\u00d6", | 
 |         "\u00d8"-"\u00f6", | 
 |         "\u00f8"-"\u00ff", | 
 |         "\u0100"-"\u1fff", | 
 |         "\u3040"-"\u318f", | 
 |         "\u3300"-"\u337f", | 
 |         "\u3400"-"\u3d2d", | 
 |         "\u4e00"-"\u9fff", | 
 |         "\uf900"-"\ufaff" | 
 |     ] | 
 |     > | 
 | | | 
 |     < #DIGIT: | 
 |     [ | 
 |         "\u0030"-"\u0039", | 
 |         "\u0660"-"\u0669", | 
 |         "\u06f0"-"\u06f9", | 
 |         "\u0966"-"\u096f", | 
 |         "\u09e6"-"\u09ef", | 
 |         "\u0a66"-"\u0a6f", | 
 |         "\u0ae6"-"\u0aef", | 
 |         "\u0b66"-"\u0b6f", | 
 |         "\u0be7"-"\u0bef", | 
 |         "\u0c66"-"\u0c6f", | 
 |         "\u0ce6"-"\u0cef", | 
 |         "\u0d66"-"\u0d6f", | 
 |         "\u0e50"-"\u0e59", | 
 |         "\u0ed0"-"\u0ed9", | 
 |         "\u1040"-"\u1049" | 
 |     ] | 
 |     > | 
 | } | 
 |  | 
 | /* Special token to throw a wrench in the works. It is never valid in SQL, | 
 |    and so when it occurs, it causes the parser to print which tokens would | 
 |    have been valid at that point. Used by SqlAdvisor. */ | 
 | <DEFAULT, DQID, BTID, BQID, BQHID> TOKEN : | 
 | { | 
 |     < BEL: | 
 |     [ | 
 |         "\u0007" | 
 |     ] | 
 |     > | 
 | } | 
 |  | 
 | /** | 
 |  * Defines a production which can never be accepted by the parser. | 
 |  * In effect, it tells the parser, "If you got here, you've gone too far." | 
 |  * It is used as the default production for parser extension points; | 
 |  * derived parsers replace it with a real production when they want to | 
 |  * implement a particular extension point. | 
 |  */ | 
 | void UnusedExtension() : | 
 | { | 
 | } | 
 | { | 
 |     ( | 
 |         LOOKAHEAD({false}) <ZONE> | 
 |     ) | 
 | } |