id = CompoundIdentifier()
+ (
+ { continueIdentity = true; }
+ |
+ { continueIdentity = false; }
+ |
+ { continueIdentity = true; }
+ )
+ {
+ return SqlDdlNodes.truncateTable(s.end(this), id, continueIdentity);
+ }
+}
+
+SqlDrop SqlDropView(Span s, boolean replace) :
+{
+ final boolean ifExists;
+ final SqlIdentifier id;
+}
+{
+ ifExists = IfExistsOpt() id = CompoundIdentifier() {
+ return SqlDdlNodes.dropView(s.end(this), ifExists, id);
+ }
+}
+
+SqlDrop SqlDropMaterializedView(Span s, boolean replace) :
+{
+ final boolean ifExists;
+ final SqlIdentifier id;
+}
+{
+ ifExists = IfExistsOpt() id = CompoundIdentifier() {
+ return SqlDdlNodes.dropMaterializedView(s.end(this), ifExists, id);
+ }
+}
+
+SqlDrop SqlDropFunction(Span s, boolean replace) :
+{
+ final boolean ifExists;
+ final SqlIdentifier id;
+}
+{
+ ifExists = IfExistsOpt()
+ id = CompoundIdentifier() {
+ return SqlDdlNodes.dropFunction(s.end(this), ifExists, id);
+ }
+}
\ No newline at end of file
diff --git a/baremaps-calcite/src/main/codegen/templates/Parser.jj b/baremaps-calcite/src/main/codegen/templates/Parser.jj
new file mode 100644
index 000000000..64cff9bea
--- /dev/null
+++ b/baremaps-calcite/src/main/codegen/templates/Parser.jj
@@ -0,0 +1,9214 @@
+/*
+ * 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.SqlAsofJoin;
+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.
+ *
+ *
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".
+ *
+ *
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 keywords) :
+{}
+{
+ E()
+}
+
+/*
+ * Parses dialect-specific keywords immediately following the INSERT keyword.
+ */
+void SqlInsertKeywords(List 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("");
+
+ // Find all sequences in the error which contain identifier. For
+ // example,
+ // {}
+ // {A}
+ // {B, C}
+ // {D, }
+ // {D, A}
+ // {D, B}
+ //
+ // would yield
+ // {}
+ // {D}
+ final List prefixList = new ArrayList();
+ 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 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 list = new ArrayList();
+ 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