generated parser files using javacc
diff --git a/WORKSPACE b/WORKSPACE
index 22c75f8..871d713 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -495,6 +495,15 @@
)
# end Pulsar Client
+# java cc
+new_http_archive(
+ name = "javacc",
+ url = "https://javacc.org/downloads/javacc-5.0.tar.gz",
+ strip_prefix = "javacc-5.0",
+ build_file = "third_party/java/javacc/javacc.BUILD",
+)
+# end java cc
+
# Kubernetes java client
kubernetes_client_version = "1.0.0-beta1"
squareup_okhttp_version = "2.7.5"
@@ -891,4 +900,4 @@
)
load("@io_bazel_rules_scala//scala:scala.bzl", "scala_repositories")
-scala_repositories()
\ No newline at end of file
+scala_repositories()
diff --git a/heron/sql/src/java/BUILD b/heron/sql/src/java/BUILD
new file mode 100644
index 0000000..2c9ea2e
--- /dev/null
+++ b/heron/sql/src/java/BUILD
@@ -0,0 +1,26 @@
+licenses(["notice"])
+
+package(default_visibility = ["//visibility:public"])
+
+generated_files = [
+ "ParseException.java",
+ "Token.java",
+ "TokenMgrError.java",
+ "SimpleCharStream.java",
+ "HeronSqlParserImpl.java",
+ "HeronSqlParserImplConstants.java",
+ "HeronSqlParserImplTokenManager.java",
+]
+
+genrule(
+ name = "parser-srcs",
+ srcs = ["com/twitter/heron/sql/parser/impl/Parser.jj"],
+ outs = generated_files,
+ tools = [
+ "//third_party/java:javacc",
+ ],
+ cmd = "\n".join([
+ 'export INSTALL_DIR=$$(pwd)/$(@D)',
+ '$(location //third_party/java:javacc) -OUTPUT_DIRECTORY=$$INSTALL_DIR $<',
+ ]),
+)
diff --git a/heron/sql/src/java/com/twitter/heron/sql/parser/impl/Parser.jj b/heron/sql/src/java/com/twitter/heron/sql/parser/impl/Parser.jj
new file mode 100644
index 0000000..a9bb686
--- /dev/null
+++ b/heron/sql/src/java/com/twitter/heron/sql/parser/impl/Parser.jj
@@ -0,0 +1,6240 @@
+
+options {
+ STATIC = false;
+ IGNORE_CASE = true;
+ UNICODE_INPUT = true;
+}
+
+
+PARSER_BEGIN(HeronSqlParserImpl)
+
+package com.twitter.heron.sql.parser.impl;
+
+import org.apache.calcite.sql.validate.*;
+import org.apache.calcite.util.*;
+import com.twitter.heron.sql.parser.*;
+import java.util.*;
+
+
+import org.apache.calcite.avatica.util.Casing;
+import org.apache.calcite.avatica.util.DateTimeUtils;
+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.SqlBinaryOperator;
+import org.apache.calcite.sql.SqlCall;
+import org.apache.calcite.sql.SqlCharStringLiteral;
+import org.apache.calcite.sql.SqlCollation;
+import org.apache.calcite.sql.SqlDataTypeSpec;
+import org.apache.calcite.sql.SqlDateLiteral;
+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.SqlIdentifier;
+import org.apache.calcite.sql.SqlInsert;
+import org.apache.calcite.sql.SqlInsertKeyword;
+import org.apache.calcite.sql.SqlIntervalLiteral;
+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.SqlKind;
+import org.apache.calcite.sql.SqlLiteral;
+import org.apache.calcite.sql.SqlMerge;
+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.SqlPostfixOperator;
+import org.apache.calcite.sql.SqlPrefixOperator;
+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.SqlTimeLiteral;
+import org.apache.calcite.sql.SqlTimestampLiteral;
+import org.apache.calcite.sql.SqlUnnestOperator;
+import org.apache.calcite.sql.SqlUpdate;
+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.OracleSqlOperatorTable;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.fun.SqlTrimFunction;
+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.util.Util;
+import org.apache.calcite.util.trace.CalciteTrace;
+
+import com.google.common.collect.Lists;
+
+import org.slf4j.Logger;
+
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.List;
+
+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 HeronSqlParserImpl 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 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 stream) {
+ return new HeronSqlParserImpl(stream);
+ }
+ };
+
+ 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 (HeronSqlParserImpl.class) {
+ if (metadata == null) {
+ metadata = new MetadataImpl(
+ new HeronSqlParserImpl(new java.io.StringReader("")));
+ }
+ return metadata;
+ }
+ }
+
+ public void setTabSize(int tabSize)
+ {
+ jj_input_stream.setTabSize(tabSize);
+ }
+
+ public void switchTo(String stateName)
+ {
+ int state = Arrays.asList(HeronSqlParserImpl.lexStateNames)
+ .indexOf(stateName);
+ token_source.SwitchTo(state);
+ }
+
+ 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();
+ }
+
+ private SqlNode extend(SqlNode table, SqlNodeList extendList) {
+ return SqlStdOperatorTable.EXTEND.createCall(
+ table.getParserPosition().plus(extendList.getParserPosition()),
+ table, extendList);
+ }
+}
+
+PARSER_END(HeronSqlParserImpl)
+
+
+/*****************************************
+ * Utility Codes for Semantical Analysis *
+ *****************************************/
+
+/* For Debug */
+JAVACODE
+void debug_message1() {
+ LOGGER.info("{} , {}", getToken(0).image, getToken(1).image);
+}
+
+JAVACODE String unquotedIdentifier() {
+ return SqlParserUtil.strip(getToken(0).image, null, null, null,
+ unquotedCasing);
+}
+
+String NonReservedKeyWord() :
+{
+ String kw;
+}
+{
+ kw = CommonNonReservedKeyWord()
+ {
+ return kw;
+ }
+}
+
+/**
+ * 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()
+}
+
+SqlNode ExtendedBuiltinFunctionCall() :
+{
+}
+{
+ UnusedExtension()
+ {
+ return null;
+ }
+}
+
+/*
+* Parse Floor/Ceil function parameters
+*/
+SqlNode FloorCeilOptions(SqlParserPos pos, boolean floorFlag) :
+{
+ SqlNode node;
+}
+{
+ node = StandardFloorCeilOptions(pos, floorFlag)
+ {
+ return node;
+ }
+}
+
+
+
+// End Parser.jj
+
+/*
+// 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() {}
+
+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 SqlParserPos getPos()
+{
+ return new SqlParserPos(
+ token.beginLine,
+ token.beginColumn,
+ token.endLine,
+ token.endColumn);
+}
+
+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());
+ }
+}
+
+// The date/time parse utilities have to live here, instead of in the
+// SqlParserUtil class because ParseException is ambiguous, and
+// CommonParser has to live in multiple packages.
+
+JAVACODE SqlDateLiteral parseDateLiteral(String s, SqlParserPos pos) {
+ String dateStr = SqlParserUtil.parseString(s);
+ Calendar cal = DateTimeUtils.parseDateFormat(
+ dateStr, DateTimeUtils.DATE_FORMAT_STRING, DateTimeUtils.GMT_ZONE);
+ if (null == cal) {
+ throw SqlUtil.newContextException(pos,
+ RESOURCE.illegalLiteral("DATE", s,
+ RESOURCE.badFormat(DateTimeUtils.DATE_FORMAT_STRING).str()));
+ }
+ return SqlLiteral.createDate(cal, pos);
+}
+
+JAVACODE SqlTimeLiteral parseTimeLiteral(String s, SqlParserPos pos) {
+ String dateStr = SqlParserUtil.parseString(s);
+ DateTimeUtils.PrecisionTime pt =
+ DateTimeUtils.parsePrecisionDateTimeLiteral(
+ dateStr, DateTimeUtils.TIME_FORMAT_STRING, DateTimeUtils.GMT_ZONE);
+ if (null == pt) {
+ throw SqlUtil.newContextException(pos,
+ RESOURCE.illegalLiteral("TIME", s,
+ RESOURCE.badFormat(DateTimeUtils.TIME_FORMAT_STRING).str()));
+ }
+ return SqlLiteral.createTime(pt.getCalendar(), pt.getPrecision(), pos);
+}
+
+JAVACODE SqlTimestampLiteral parseTimestampLiteral(String s, SqlParserPos pos) {
+ String dateStr = SqlParserUtil.parseString(s);
+ DateTimeUtils.PrecisionTime pt =
+ DateTimeUtils.parsePrecisionDateTimeLiteral(
+ dateStr, DateTimeUtils.TIMESTAMP_FORMAT_STRING, DateTimeUtils.GMT_ZONE);
+ if (null == pt) {
+ throw SqlUtil.newContextException(pos,
+ RESOURCE.illegalLiteral("TIMESTAMP", s,
+ RESOURCE.badFormat(DateTimeUtils.TIMESTAMP_FORMAT_STRING).str()));
+ }
+ return SqlLiteral.createTimestamp(pt.getCalendar(), pt.getPrecision(), pos);
+}
+
+JAVACODE SqlIntervalLiteral parseIntervalLiteral(
+ SqlParserPos pos,
+ int sign,
+ String s,
+ SqlIntervalQualifier intervalQualifier) throws ParseException
+{
+ String intervalStr = SqlParserUtil.parseString(s);
+ if ("".equals(intervalStr)) {
+ throw new ParseException(
+ RESOURCE.illegalIntervalLiteral(s + " "
+ + intervalQualifier.toString(), pos.toString()).str());
+ }
+ return SqlLiteral.createInterval(sign, intervalStr, intervalQualifier, pos);
+}
+
+/**
+ * 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;
+ pos = new SqlParserPos(
+ token.beginLine,
+ token.beginColumn,
+ token.endLine,
+ token.endColumn);
+ }
+ } else if (ex instanceof TokenMgrError) {
+ TokenMgrError tme = (TokenMgrError) ex;
+ 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 = java.util.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}
+ boolean id = false;
+ 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 *
+ *****************************************/
+
+/**
+ * Parses either a row expression or a query expression with an optional
+ * ORDER BY.
+ *
+ * <p>Postgres syntax for limit:
+ *
+ * [ LIMIT { count | ALL } ]
+ * [ OFFSET start ]
+ *
+ * <p>SQL:2008 syntax for limit:
+ *
+ * [ OFFSET start { ROW | ROWS } ]
+ * [ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY ]
+ */
+SqlNode OrderedQueryOrExpr(ExprContext exprContext) :
+{
+ SqlNode e;
+ SqlNodeList orderBy = null;
+ SqlNode start = null;
+ SqlNode count = null;
+ SqlParserPos pos = null;
+}
+{
+ (
+ e = QueryOrExpr(exprContext)
+ )
+ [
+ // use the syntactic type of the expression we just parsed
+ // to decide whether ORDER BY makes sense
+ orderBy = OrderBy(e.isA(SqlKind.QUERY))
+ ]
+ [
+ // Postgres-style syntax. "LIMIT ... OFFSET ..."
+ <LIMIT> ( count = UnsignedNumericLiteral() | <ALL> )
+ ]
+ [
+ // ROW or ROWS is required in SQL:2008 but we make it optional
+ // because it is not present in Postgres-style syntax.
+ <OFFSET> start = UnsignedNumericLiteral() [ <ROW> | <ROWS> ]
+ ]
+ [
+ // SQL:2008-style syntax. "OFFSET ... FETCH ...".
+ // If you specify both LIMIT and FETCH, FETCH wins.
+ <FETCH> ( <FIRST> | <NEXT> ) count = UnsignedNumericLiteral() ( <ROW> | <ROWS> ) <ONLY>
+ ]
+ {
+ if (orderBy != null || start != null || count != null) {
+ pos = getPos();
+ if (orderBy == null) {
+ orderBy = SqlNodeList.EMPTY;
+ }
+ e = new SqlOrderBy(pos, e, orderBy, start, count);
+
+ }
+ return e;
+ }
+}
+
+/**
+ * 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.
+ */
+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 = OrderedQueryOrExpr(exprContext)
+ <RPAREN>
+ {
+ 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
+ *
+ * <code>WHERE x IN (select count(*) from t where c=d,5)</code>,
+ *
+ * which should be illegal. The above is interpreted as equivalent to
+ *
+ * <code>WHERE x IN ((select count(*) from t where c=d),5)</code>,
+ *
+ * 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;
+ List<SqlNode> list;
+ ExprContext firstExprContext = exprContext;
+ SqlParserPos pos;
+}
+{
+ <LPAREN>
+ {
+ // we've now seen left paren, so a query by itself should
+ // be interpreted as a sub-query
+ pos = getPos();
+ switch (exprContext) {
+ case ACCEPT_SUB_QUERY:
+ firstExprContext = ExprContext.ACCEPT_NONCURSOR;
+ break;
+ case ACCEPT_CURSOR:
+ firstExprContext = ExprContext.ACCEPT_ALL;
+ break;
+ }
+ }
+ e = OrderedQueryOrExpr(firstExprContext)
+ {
+ list = startList(e);
+ }
+ (
+ <COMMA>
+ {
+ // a comma-list can't appear where only a query is expected
+ checkNonQueryExpression(exprContext);
+ }
+ e = Expression(exprContext)
+ {
+ list.add(e);
+ }
+ ) *
+ <RPAREN>
+ {
+ return new SqlNodeList(list, pos.plus(getPos()));
+ }
+}
+
+/**
+ * Parses function parameter lists including DISTINCT keyword recognition,
+ * DEFAULT, and named argument assignment.
+ */
+List FunctionParameterList(
+ ExprContext exprContext) :
+{
+ SqlNode e = null;
+ List list = new ArrayList();
+}
+{
+ <LPAREN>
+ [
+ <DISTINCT> {
+ e = SqlSelectKeyword.DISTINCT.symbol(getPos());
+ }
+ |
+ <ALL> {
+ e = SqlSelectKeyword.ALL.symbol(getPos());
+ }
+ ]
+ {
+ list.add(e);
+ }
+ Arg0(list, exprContext)
+ (
+ <COMMA> {
+ // a comma-list can't appear where only a query is expected
+ checkNonQueryExpression(exprContext);
+ }
+ Arg(list, exprContext)
+ )*
+ <RPAREN>
+ {
+ return list;
+ }
+}
+
+void Arg0(List list, ExprContext exprContext) :
+{
+ SqlIdentifier name = null;
+ SqlNode e = null;
+ 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;
+ }
+ }
+}
+{
+ [
+ name = SimpleIdentifier() <NAMED_ARGUMENT_ASSIGNMENT>
+ ]
+ (
+ <DEFAULT_KW> {
+ e = SqlStdOperatorTable.DEFAULT.createCall(getPos());
+ }
+ |
+ e = OrderedQueryOrExpr(firstExprContext)
+ )
+ {
+ if (e != null) {
+ if (name != null) {
+ e = SqlStdOperatorTable.ARGUMENT_ASSIGNMENT.createCall(
+ name.getParserPosition().plus(e.getParserPosition()),
+ e, name);
+ }
+ list.add(e);
+ }
+ }
+}
+
+void Arg(List list, ExprContext exprContext) :
+{
+ SqlIdentifier name = null;
+ SqlNode e = null;
+}
+{
+ [
+ name = SimpleIdentifier() <NAMED_ARGUMENT_ASSIGNMENT>
+ ]
+ (
+ <DEFAULT_KW> {
+ e = SqlStdOperatorTable.DEFAULT.createCall(getPos());
+ }
+ |
+ e = Expression(exprContext)
+ )
+ {
+ if (e != null) {
+ if (name != null) {
+ e = SqlStdOperatorTable.ARGUMENT_ASSIGNMENT.createCall(
+ name.getParserPosition().plus(e.getParserPosition()),
+ e, name);
+ }
+ list.add(e);
+ }
+ }
+}
+
+/**
+ * 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 an SQL statement.
+ */
+SqlNode SqlStmt() :
+{
+ SqlNode stmt;
+}
+{
+ (
+ stmt = SqlSetOption(null, null)
+ |
+ stmt = SqlAlter()
+ |
+ stmt = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY)
+ |
+ stmt = SqlExplain()
+ |
+ stmt = SqlDescribe()
+ |
+ stmt = SqlInsert()
+ |
+ stmt = SqlDelete()
+ |
+ stmt = SqlUpdate()
+ |
+ stmt = SqlMerge()
+ |
+ stmt = SqlProcedureCall()
+
+ |
+ stmt = SqlCreateTable()
+ |
+ stmt = SqlCreateFunction()
+ )
+ {
+ return stmt;
+ }
+}
+
+/**
+ * Parses an SQL statement followed by the end-of-file symbol.
+ */
+SqlNode SqlStmtEof() :
+{
+ SqlNode stmt;
+}
+{
+ stmt = SqlStmt() <EOF>
+ {
+ return stmt;
+ }
+}
+
+
+
+private void ColumnDef(List<ColumnDefinition> list) :
+{
+ SqlParserPos pos;
+ SqlIdentifier name;
+ SqlDataTypeSpec type;
+ ColumnConstraint constraint = null;
+ SqlMonotonicity monotonicity = SqlMonotonicity.NOT_MONOTONIC;
+}
+{
+ name = SimpleIdentifier() { pos = getPos(); }
+ type = DataType()
+ [
+ <PRIMARY> <KEY>
+ [ <ASC> { monotonicity = SqlMonotonicity.INCREASING; }
+ | <DESC> { monotonicity = SqlMonotonicity.DECREASING; }
+ ]
+ { constraint = new ColumnConstraint.PrimaryKey(monotonicity, getPos()); }
+ ]
+ {
+ list.add(new ColumnDefinition(name, type, constraint, pos));
+ }
+}
+
+SqlNodeList ColumnDefinitionList() :
+{
+ SqlParserPos pos;
+ List<ColumnDefinition> list = Lists.newArrayList();
+}
+{
+ <LPAREN> { pos = getPos(); }
+ ColumnDef(list)
+ ( <COMMA> ColumnDef(list) )*
+ <RPAREN> {
+ return new SqlNodeList(list, pos.plus(getPos()));
+ }
+}
+
+/**
+ * CREATE EXTERNAL TABLE ( IF NOT EXISTS )?
+ * ( database_name '.' )? table_name ( '(' column_def ( ',' column_def )* ')'
+ * ( STORED AS INPUTFORMAT input_format_classname OUTPUTFORMAT output_format_classname )?
+ * LOCATION location_uri
+ * ( TBLPROPERTIES tbl_properties )?
+ * ( AS select_stmt )
+ */
+SqlNode SqlCreateTable() :
+{
+ SqlParserPos pos;
+ SqlIdentifier tblName;
+ SqlNodeList fieldList;
+ SqlNode location;
+ SqlNode parallelism = null;
+ SqlNode input_format_class_name = null, output_format_class_name = null;
+ SqlNode tbl_properties = null;
+ SqlNode select = null;
+}
+{
+ <CREATE> { pos = getPos(); }
+ <EXTERNAL> <TABLE>
+ tblName = CompoundIdentifier()
+ fieldList = ColumnDefinitionList()
+ [
+ <STORED> <AS>
+ <INPUTFORMAT> input_format_class_name = StringLiteral()
+ <OUTPUTFORMAT> output_format_class_name = StringLiteral()
+ ]
+ <LOCATION>
+ location = StringLiteral()
+ [ <PARALLELISM> parallelism = UnsignedNumericLiteral() ]
+ [ <TBLPROPERTIES> tbl_properties = StringLiteral() ]
+ [ <AS> select = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY) ] {
+ return new SqlCreateTable(pos, tblName, fieldList,
+ input_format_class_name, output_format_class_name, location,
+ parallelism, tbl_properties, select);
+ }
+}
+
+/**
+ * CREATE FUNCTION functionname AS 'classname'
+ */
+SqlNode SqlCreateFunction() :
+{
+ SqlParserPos pos;
+ SqlIdentifier functionName;
+ SqlNode className;
+ SqlNode jarName = null;
+}
+{
+ <CREATE> { pos = getPos(); }
+ <FUNCTION>
+ functionName = CompoundIdentifier()
+ <AS>
+ className = StringLiteral()
+ [
+ <USING> <JAR>
+ jarName = StringLiteral()
+ ]
+ {
+ return new SqlCreateFunction(pos, functionName, className, jarName);
+ }
+}
+/**
+ * Parses a leaf SELECT expression without ORDER BY.
+ */
+SqlSelect SqlSelect() :
+{
+ final List<SqlLiteral> keywords = Lists.newArrayList();
+ List<SqlNode> selectList;
+ final SqlNode fromClause;
+ final SqlNode where;
+ final SqlNodeList groupBy;
+ final SqlNode having;
+ final SqlNodeList windowDecls;
+ SqlParserPos pos;
+}
+{
+ <SELECT>
+ {
+ pos = getPos();
+ }
+ SqlSelectKeywords(keywords)
+ (
+ <STREAM> {
+ keywords.add(SqlSelectKeyword.STREAM.symbol(getPos()));
+ }
+ )?
+ (
+ <DISTINCT> {
+ keywords.add(SqlSelectKeyword.DISTINCT.symbol(getPos()));
+ }
+ | <ALL> {
+ keywords.add(SqlSelectKeyword.ALL.symbol(getPos()));
+ }
+ )?
+ selectList = SelectList()
+ (
+ <FROM> fromClause = FromClause()
+ where = WhereOpt()
+ groupBy = GroupByOpt()
+ having = HavingOpt()
+ windowDecls = WindowOpt()
+ |
+ E() {
+ fromClause = null;
+ where = null;
+ groupBy = null;
+ having = null;
+ windowDecls = null;
+ }
+ )
+ {
+ final SqlNode selectItem = (SqlNode)selectList.get(0);
+ final SqlParserPos selectListPos = selectItem.getParserPosition();
+ return new SqlSelect(pos.plus(getPos()),
+ new SqlNodeList(keywords, pos),
+ new SqlNodeList(selectList, selectListPos.plusAll(selectList)),
+ fromClause, where, groupBy, having, windowDecls, null, null, null);
+ }
+}
+
+/*
+ * 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;
+ SqlParserPos pos;
+ final SqlExplainFormat format;
+}
+{
+ <EXPLAIN> <PLAN>
+ [ detailLevel = ExplainDetailLevel() ]
+ depth = ExplainDepth()
+ (
+ <AS> <XML> { format = SqlExplainFormat.XML; }
+ |
+ <AS> <JSON> { format = SqlExplainFormat.JSON; }
+ |
+ { format = SqlExplainFormat.TEXT; }
+ )
+ <FOR> stmt = SqlQueryOrDml() {
+ pos = getPos();
+ return new SqlExplain(pos,
+ 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 SqlParserPos pos;
+ final SqlIdentifier table;
+ final SqlIdentifier column;
+ final SqlNode stmt;
+}
+{
+ <DESCRIBE> { pos = getPos(); }
+ (
+ (<DATABASE> | <CATALOG> | <SCHEMA>) {
+ // 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(pos, CompoundIdentifier());
+ }
+ |
+ // Use syntactic lookahead to determine whether a table name is coming.
+ // We do not allow SimpleIdentifier() because that includes <STATEMENT>.
+ LOOKAHEAD( <TABLE> | <IDENTIFIER> | <QUOTED_IDENTIFIER>
+ | <BACK_QUOTED_IDENTIFIER> | <BRACKET_QUOTED_IDENTIFIER> )
+ (<TABLE>)?
+ table = CompoundIdentifier()
+ (
+ column = SimpleIdentifier()
+ |
+ E() { column = null; }
+ ) {
+ return new SqlDescribeTable(pos, table, column);
+ }
+ |
+ (<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(pos,
+ stmt,
+ detailLevel.symbol(SqlParserPos.ZERO),
+ depth.symbol(SqlParserPos.ZERO),
+ format.symbol(SqlParserPos.ZERO),
+ nDynamicParams);
+ }
+ )
+}
+
+/**
+ * Parses a CALL statement.
+ */
+SqlNode SqlProcedureCall() :
+{
+ SqlParserPos callPos;
+ SqlNode routineCall;
+}
+{
+ <CALL>
+ {
+ callPos = getPos();
+ }
+ routineCall = NamedRoutineCall(
+ SqlFunctionCategory.USER_DEFINED_PROCEDURE,
+ ExprContext.ACCEPT_SUB_QUERY)
+ {
+ return SqlStdOperatorTable.PROCEDURE_CALL.createCall(
+ callPos, routineCall);
+ }
+}
+
+SqlNode NamedRoutineCall(
+ SqlFunctionCategory routineType,
+ ExprContext exprContext) :
+{
+ SqlIdentifier name;
+ final List<SqlNode> list = Lists.newArrayList();
+ final SqlParserPos pos;
+}
+{
+ name = CompoundIdentifier() {
+ pos = getPos();
+ }
+ <LPAREN>
+ [
+ Arg0(list, exprContext)
+ (
+ <COMMA> {
+ // a comma-list can't appear where only a query is expected
+ checkNonQueryExpression(exprContext);
+ }
+ Arg(list, exprContext)
+ )*
+ ]
+ <RPAREN>
+ {
+ SqlNode function = createCall(
+ name, pos.plus(getPos()), routineType, null, SqlParserUtil.toNodeArray(list));
+ return function;
+ }
+}
+
+/**
+ * Parses an INSERT statement.
+ */
+SqlNode SqlInsert() :
+{
+ final List<SqlLiteral> keywords = Lists.newArrayList();
+ SqlIdentifier table;
+ SqlNode source;
+ SqlNodeList columnList = null;
+ SqlParserPos pos;
+}
+{
+ (
+ <INSERT>
+ |
+ <UPSERT> { keywords.add(SqlInsertKeyword.UPSERT.symbol(getPos())); }
+ )
+ SqlInsertKeywords(keywords)
+ <INTO> table = CompoundIdentifier()
+ {
+ pos = getPos();
+ }
+ [
+ LOOKAHEAD(2)
+ columnList = ParenthesizedCompoundIdentifierList()
+ ]
+ source = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY)
+ {
+ return new SqlInsert(pos, new SqlNodeList(keywords, pos), table, source,
+ columnList);
+ }
+}
+
+/*
+ * Abstract production:
+ *
+ * void SqlInsertKeywords(List keywords)
+ *
+ * Parses dialect-specific keywords immediately following the INSERT keyword.
+ */
+
+/**
+ * Parses a DELETE statement.
+ */
+SqlNode SqlDelete() :
+{
+ SqlNode table;
+ SqlNodeList extendList = null;
+ SqlIdentifier alias = null;
+ SqlNode condition;
+ SqlParserPos pos;
+}
+{
+ <DELETE>
+ {
+ pos = getPos();
+ }
+ <FROM> table = CompoundIdentifier()
+ {
+
+ }
+ [
+ [ <EXTEND> ]
+ extendList = ExtendList() {
+ table = extend(table, extendList);
+ }
+ ]
+ [ [ <AS> ] alias = SimpleIdentifier() ]
+ condition = WhereOpt()
+ {
+ return new SqlDelete(pos, table, condition, null, alias);
+ }
+}
+
+/**
+ * Parses an UPDATE statement.
+ */
+SqlNode SqlUpdate() :
+{
+ SqlNode table;
+ SqlNodeList extendList = null;
+ SqlIdentifier alias = null;
+ SqlNode condition;
+ SqlNodeList sourceExpressionList;
+ SqlNodeList targetColumnList;
+ SqlIdentifier id;
+ SqlNode exp;
+ SqlParserPos pos;
+}
+{
+ <UPDATE> table = CompoundIdentifier()
+ {
+ pos = getPos();
+ targetColumnList = new SqlNodeList(pos);
+ sourceExpressionList = new SqlNodeList(pos);
+ }
+ [
+ [ <EXTEND> ]
+ extendList = ExtendList() {
+ table = extend(table, extendList);
+ }
+ ]
+ [ [ <AS> ] alias = SimpleIdentifier() ]
+ <SET> id = SimpleIdentifier()
+ {
+ targetColumnList.add(id);
+ }
+ <EQ> exp = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ {
+ // TODO: support DEFAULT also
+ sourceExpressionList.add(exp);
+ }
+ (
+ <COMMA>
+ id = SimpleIdentifier()
+ {
+ targetColumnList.add(id);
+ }
+ <EQ> exp = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ {
+ sourceExpressionList.add(exp);
+ }
+ ) *
+ condition = WhereOpt()
+ {
+ return new SqlUpdate(pos, table, targetColumnList, sourceExpressionList,
+ condition, null, alias);
+ }
+}
+
+/**
+ * Parses a MERGE statement.
+ */
+SqlNode SqlMerge() :
+{
+ SqlNode table;
+ SqlNodeList extendList = null;
+ SqlIdentifier alias = null;
+ SqlNode sourceTableRef;
+ SqlNode condition;
+ SqlUpdate updateCall = null;
+ SqlInsert insertCall = null;
+ SqlParserPos mergePos;
+}
+{
+ <MERGE> <INTO> table = CompoundIdentifier()
+ {
+ mergePos = getPos();
+ }
+ [
+ [ <EXTEND> ]
+ extendList = ExtendList() {
+ table = extend(table, extendList);
+ }
+ ]
+ [ [ <AS> ] alias = SimpleIdentifier() ]
+
+ <USING> sourceTableRef = TableRef()
+
+ <ON> condition = Expression(ExprContext.ACCEPT_SUB_QUERY)
+
+ (
+ LOOKAHEAD(2)
+ updateCall = WhenMatchedClause(table, alias)
+ [ insertCall = WhenNotMatchedClause(table) ]
+ |
+ insertCall = WhenNotMatchedClause(table)
+ )
+ {
+ return new SqlMerge(mergePos, table, condition, sourceTableRef,
+ updateCall, insertCall, null, alias);
+ }
+}
+
+SqlUpdate WhenMatchedClause(SqlNode table, SqlIdentifier alias) :
+{
+ SqlIdentifier id;
+ SqlParserPos pos;
+ SqlNodeList updateColumnList;
+ SqlNode exp;
+ SqlNodeList updateExprList;
+}
+{
+ <WHEN> <MATCHED> <THEN>
+ <UPDATE> <SET> id = SimpleIdentifier()
+ {
+ pos = getPos();
+ updateColumnList = new SqlNodeList(pos);
+ updateExprList = new SqlNodeList(pos);
+ updateColumnList.add(id);
+ }
+ <EQ> exp = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ {
+ updateExprList.add(exp);
+ }
+ (
+ <COMMA>
+ id = SimpleIdentifier()
+ {
+ updateColumnList.add(id);
+ }
+ <EQ> exp = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ {
+ updateExprList.add(exp);
+ }
+ ) *
+ {
+ return new SqlUpdate(pos, table, updateColumnList, updateExprList, null,
+ null, alias);
+ }
+}
+
+SqlInsert WhenNotMatchedClause(SqlNode table) :
+{
+ SqlParserPos pos, insertPos;
+ List<SqlLiteral> keywords = Lists.newArrayList();
+ SqlNodeList insertColumnList = null;
+ SqlNode rowConstructor;
+ SqlNode insertValues;
+}
+{
+ <WHEN> <NOT> <MATCHED> <THEN>
+ <INSERT>
+ {
+ insertPos = getPos();
+ }
+ SqlInsertKeywords(keywords)
+ [
+ LOOKAHEAD(2)
+ insertColumnList = ParenthesizedSimpleIdentifierList()
+ ]
+ [ <LPAREN> ]
+ <VALUES> { pos = getPos(); }
+ rowConstructor = RowConstructor()
+ [ <RPAREN> ]
+ {
+ // 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(
+ pos.plus(rowConstructor.getParserPosition()),
+ rowConstructor);
+ return new SqlInsert(insertPos, new SqlNodeList(keywords, insertPos),
+ table, insertValues, insertColumnList);
+ }
+}
+
+/**
+ * Parses the select list of a SELECT statement.
+ */
+List<SqlNode> SelectList() :
+{
+ List<SqlNode> list = new ArrayList<SqlNode>();
+ SqlNode item;
+}
+{
+ item = SelectItem() {list.add(item);}
+ ( <COMMA> item = SelectItem() {list.add(item);} ) *
+ {
+ return list;
+ }
+}
+
+/**
+ * Parses one item in a select list.
+ */
+SqlNode SelectItem() :
+{
+ SqlNode e;
+ SqlIdentifier id;
+ SqlParserPos pos;
+}
+{
+ e = SelectExpression()
+ [
+ [ <AS> ]
+ id = SimpleIdentifier()
+ {
+ pos = e.getParserPosition().plus(getPos());
+ e = SqlStdOperatorTable.AS.createCall(pos, e, id);
+ }
+ ]
+ {
+ return 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;
+}
+{
+ (
+ <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());
+ }
+}
+
+/** Matches "LEFT JOIN t ON ...", "RIGHT JOIN t USING ...", "JOIN t". */
+SqlNode JoinTable(SqlNode e) :
+{
+ SqlNode e2, condition;
+ SqlLiteral natural, joinType;
+ SqlNodeList list;
+ SqlParserPos pos;
+}
+{
+ natural = Natural()
+ joinType = JoinType()
+ e2 = TableRef()
+ (
+ <ON> { pos = getPos(); }
+ condition = Expression(ExprContext.ACCEPT_SUB_QUERY) {
+ SqlParserPos onPos = pos.plus(getPos());
+ return new SqlJoin(joinType.getParserPosition(),
+ e,
+ natural,
+ joinType,
+ e2,
+ JoinConditionType.ON.symbol(onPos),
+ condition);
+ }
+ |
+ <USING> { pos = getPos(); }
+ list = ParenthesizedSimpleIdentifierList() {
+ SqlParserPos usingPos = pos.plus(getPos());
+ return new SqlJoin(joinType.getParserPosition(),
+ e,
+ natural,
+ joinType,
+ e2,
+ JoinConditionType.USING.symbol(usingPos),
+ new SqlNodeList(list.getList(), usingPos));
+ }
+ |
+ {
+ return new SqlJoin(joinType.getParserPosition(),
+ e,
+ natural,
+ joinType,
+ e2,
+ JoinConditionType.NONE.symbol(joinType.getParserPosition()),
+ null);
+ }
+ )
+}
+
+// TODO jvs 15-Nov-2003: SQL standard allows parentheses in the FROM list for
+// building up non-linear join trees (e.g. OUTER JOIN two tables, and then INNER
+// JOIN the result). Also note that aliases on parenthesized FROM expressions
+// "hide" all table names inside the parentheses (without aliases, they're
+// visible).
+//
+// We allow CROSS JOIN to have a join condition, even though that is not valid
+// SQL; the validator will catch it.
+/**
+ * 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, condition;
+ SqlLiteral natural, joinType;
+ SqlNodeList list;
+ SqlParserPos pos;
+}
+{
+ e = TableRef()
+ (
+ // Decide whether to read a JOIN clause or a comma, or to quit having
+ // seen a single entry FROM clause like 'FROM emps'. See comments
+ // elsewhere regarding <COMMA> lookahead.
+ LOOKAHEAD(2)
+ natural = Natural()
+ joinType = JoinType()
+ e2 = TableRef()
+ (
+ <ON> { pos = getPos(); }
+ condition = Expression(ExprContext.ACCEPT_SUB_QUERY) {
+ SqlParserPos onPos = pos.plus(getPos());
+ e = new SqlJoin(joinType.getParserPosition(),
+ e,
+ natural,
+ joinType,
+ e2,
+ JoinConditionType.ON.symbol(onPos),
+ condition);
+ }
+ |
+ <USING> { pos = getPos(); }
+ list = ParenthesizedSimpleIdentifierList() {
+ SqlParserPos usingPos = pos.plus(getPos());
+ e = new SqlJoin(joinType.getParserPosition(),
+ e,
+ natural,
+ joinType,
+ e2,
+ JoinConditionType.USING.symbol(usingPos),
+ new SqlNodeList(list.getList(), usingPos));
+ }
+ |
+ {
+ e = new SqlJoin(joinType.getParserPosition(),
+ e,
+ natural,
+ joinType,
+ e2,
+ JoinConditionType.NONE.symbol(joinType.getParserPosition()),
+ null);
+ }
+ )
+ |
+ // NOTE jvs 6-Feb-2004: See comments at top of file for why
+ // hint is necessary here. I had to use this special semantic
+ // lookahead form to get JavaCC to shut up, which makes
+ // me even more uneasy.
+ //LOOKAHEAD({true})
+ <COMMA> { pos = getPos(); }
+ e2 = TableRef() {
+ e = new SqlJoin(pos,
+ e,
+ SqlLiteral.createBoolean(false, pos),
+ JoinType.COMMA.symbol(SqlParserPos.ZERO),
+ e2,
+ JoinConditionType.NONE.symbol(SqlParserPos.ZERO),
+ null);
+ }
+ |
+ <CROSS> { pos = getPos(); } <APPLY>
+ e2 = TableRef2(true) {
+ if (!this.conformance.isApplyAllowed()) {
+ throw new ParseException(RESOURCE.applyNotAllowed().str());
+ }
+ e = new SqlJoin(pos,
+ e,
+ SqlLiteral.createBoolean(false, pos),
+ JoinType.CROSS.symbol(SqlParserPos.ZERO),
+ e2,
+ JoinConditionType.NONE.symbol(SqlParserPos.ZERO),
+ null);
+ }
+ |
+ <OUTER> { pos = getPos(); } <APPLY>
+ e2 = TableRef2(true) {
+ if (!this.conformance.isApplyAllowed()) {
+ throw new ParseException(RESOURCE.applyNotAllowed().str());
+ }
+ e = new SqlJoin(pos,
+ e,
+ SqlLiteral.createBoolean(false, pos),
+ JoinType.LEFT.symbol(SqlParserPos.ZERO),
+ e2,
+ JoinConditionType.ON.symbol(SqlParserPos.ZERO),
+ SqlLiteral.createBoolean(true, pos));
+ }
+ ) *
+ {
+ return e;
+ }
+}
+
+// TODO jvs 15-Nov-2003: SQL standard allows column aliases on table
+// references, e.g. DEPTS AS D1(DEPTNO1,DNAME1); I guess this is syntactic
+// sugar to make it easier for query writers to conform to the column name
+// uniqueness rules without requiring them to write a nested SELECT, but it
+// seems pretty useless for non-trivial tables, since you have to supply names
+// for ALL columns at once.
+/**
+ * Parses a table reference in a FROM clause, not lateral unless LATERAL
+ * is explicitly specified.
+ */
+SqlNode TableRef() :
+{
+ final SqlNode e;
+}
+{
+ e = TableRef2(false) { return e; }
+}
+
+/**
+ * Parses a table reference in a FROM clause.
+ */
+SqlNode TableRef2(boolean lateral) :
+{
+ SqlNode tableRef;
+ SqlNode over;
+ SqlNodeList extendList = null;
+ String alias;
+ SqlParserPos pos;
+ SqlNodeList args;
+ SqlNode sample;
+ boolean isBernoulli;
+ SqlNumericLiteral samplePercentage;
+ boolean isRepeatable = false;
+ int repeatableSeed = 0;
+ SqlNodeList columnAliasList = null;
+ SqlUnnestOperator unnestOp = SqlStdOperatorTable.UNNEST;
+}
+{
+ (
+ LOOKAHEAD(2)
+ tableRef = CompoundIdentifier()
+ [
+ [ <EXTEND> ]
+ extendList = ExtendList() {
+ tableRef = extend(tableRef, extendList);
+ }
+ ]
+ over = TableOverOpt()
+ {
+ if (over != null) {
+ pos = getPos();
+ tableRef = SqlStdOperatorTable.OVER.createCall(
+ pos, tableRef, over);
+ }
+ }
+ |
+ [ <LATERAL> { lateral = true; } ]
+ tableRef = ParenthesizedExpression(ExprContext.ACCEPT_QUERY)
+ over = TableOverOpt()
+ {
+ if (over != null) {
+ pos = getPos();
+ tableRef = SqlStdOperatorTable.OVER.createCall(
+ pos, tableRef, over);
+ }
+ if (lateral) {
+ tableRef = SqlStdOperatorTable.LATERAL.createCall(
+ getPos(), tableRef);
+ }
+ }
+ |
+ <UNNEST> { pos = getPos(); }
+ args = ParenthesizedQueryOrCommaList(ExprContext.ACCEPT_SUB_QUERY)
+ [
+ <WITH> <ORDINALITY> {
+ unnestOp = SqlStdOperatorTable.UNNEST_WITH_ORDINALITY;
+ }
+ ]
+ {
+ tableRef = unnestOp.createCall(pos.plus(getPos()), args.toArray());
+ }
+ |
+ [ <LATERAL> { lateral = true; } ]
+ <TABLE> { pos = getPos(); } <LPAREN>
+ tableRef = TableFunctionCall(pos)
+ <RPAREN>
+ {
+ if (lateral) {
+ tableRef = SqlStdOperatorTable.LATERAL.createCall(
+ getPos(), tableRef);
+ }
+ }
+ |
+ tableRef = ExtendedTableRef()
+ )
+ [
+ [ <AS> ] alias = Identifier()
+ [ columnAliasList = ParenthesizedSimpleIdentifierList() ]
+ {
+ pos = getPos();
+ if (columnAliasList == null) {
+ tableRef = SqlStdOperatorTable.AS.createCall(
+ pos, tableRef, new SqlIdentifier(alias, pos));
+ } else {
+ List<SqlNode> idList = new ArrayList<SqlNode>();
+ idList.add(tableRef);
+ idList.add(new SqlIdentifier(alias, pos));
+ idList.addAll(columnAliasList.getList());
+ tableRef = SqlStdOperatorTable.AS.createCall(pos, idList);
+ }
+ }
+ ]
+ [
+ <TABLESAMPLE> { pos = getPos(); }
+ (
+ <SUBSTITUTE> <LPAREN> sample = StringLiteral() <RPAREN>
+ {
+ String sampleName = SqlLiteral.stringValue(sample);
+ SqlSampleSpec sampleSpec = SqlSampleSpec.createNamed(sampleName);
+ SqlLiteral sampleLiteral = SqlLiteral.createSample(sampleSpec, pos);
+ tableRef = SqlStdOperatorTable.TABLESAMPLE.createCall(
+ pos.plus(getPos()), tableRef, sampleLiteral);
+ }
+ |
+ (
+ <BERNOULLI>
+ {
+ isBernoulli = true;
+ }
+ |
+ <SYSTEM>
+ {
+ isBernoulli = false;
+ }
+ )
+ <LPAREN> samplePercentage = UnsignedNumericLiteral() <RPAREN>
+ [
+ <REPEATABLE> <LPAREN> repeatableSeed = IntLiteral() <RPAREN>
+ {
+ isRepeatable = true;
+ }
+ ]
+ {
+ final BigDecimal ONE_HUNDRED = BigDecimal.valueOf(100L);
+ BigDecimal rate = samplePercentage.bigDecimalValue();
+ if (rate.compareTo(BigDecimal.ZERO) < 0
+ || rate.compareTo(ONE_HUNDRED) > 0)
+ {
+ throw new ParseException(RESOURCE.invalidSampleSize().str());
+ }
+
+ // Treat TABLESAMPLE(0) and TABLESAMPLE(100) as no table
+ // sampling at all. Not strictly correct: TABLESAMPLE(0)
+ // should produce no output, but it simplifies implementation
+ // to know that some amount of sampling will occur.
+ // In practice values less than ~1E-43% are treated as 0.0 and
+ // values greater than ~99.999997% are treated as 1.0
+ float fRate = rate.divide(ONE_HUNDRED).floatValue();
+ if (fRate > 0.0f && fRate < 1.0f) {
+ SqlSampleSpec tableSampleSpec =
+ isRepeatable
+ ? SqlSampleSpec.createTableSample(
+ isBernoulli, fRate, repeatableSeed)
+ : SqlSampleSpec.createTableSample(isBernoulli, fRate);
+
+ SqlLiteral tableSampleLiteral =
+ SqlLiteral.createSample(tableSampleSpec, pos);
+ tableRef = SqlStdOperatorTable.TABLESAMPLE.createCall(
+ pos.plus(getPos()), tableRef, tableSampleLiteral);
+ }
+ }
+ )
+ ]
+ {
+ return tableRef;
+ }
+}
+
+SqlNodeList ExtendList() :
+{
+ SqlParserPos pos;
+ List<SqlNode> list = Lists.newArrayList();
+}
+{
+ <LPAREN> { pos = getPos(); }
+ ColumnType(list)
+ (
+ <COMMA> ColumnType(list)
+ )*
+ <RPAREN> {
+ return new SqlNodeList(list, pos.plus(getPos()));
+ }
+}
+
+void ColumnType(List<SqlNode> list) :
+{
+ SqlIdentifier name;
+ SqlDataTypeSpec type;
+}
+{
+ name = SimpleIdentifier()
+ type = DataType()
+ [ <NOT> <NULL> { type = type.withNullable(false); } ]
+ {
+ list.add(name);
+ list.add(type);
+ }
+}
+
+SqlNode TableFunctionCall(SqlParserPos pos) :
+{
+ SqlNode call;
+ SqlFunctionCategory funcType = SqlFunctionCategory.USER_DEFINED_TABLE_FUNCTION;
+}
+{
+ [
+ <SPECIFIC>
+ {
+ funcType = SqlFunctionCategory.USER_DEFINED_TABLE_SPECIFIC_FUNCTION;
+ }
+ ]
+ {
+ }
+ call = NamedRoutineCall(funcType, ExprContext.ACCEPT_CURSOR)
+ {
+ return SqlStdOperatorTable.COLLECTION_TABLE.createCall(pos, call);
+ }
+}
+
+/**
+ * Abstract production:
+ * SqlNode ExtendedTableRef()
+ *
+ * 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() :
+{
+ SqlNodeList rowConstructorList;
+ SqlParserPos pos;
+}
+{
+ <VALUES>
+ {
+ pos = getPos();
+ }
+ rowConstructorList = RowConstructorList(pos)
+ {
+ return SqlStdOperatorTable.VALUES.createCall(
+ pos.plus(getPos()), rowConstructorList.toArray());
+ }
+}
+
+/**
+ * Parses one or more rows in a VALUES expression.
+ */
+SqlNodeList RowConstructorList(SqlParserPos pos) :
+{
+ List<SqlNode> list = new ArrayList<SqlNode>();
+ SqlNode rowConstructor;
+}
+{
+ rowConstructor = RowConstructor() { list.add(rowConstructor); }
+ (
+ LOOKAHEAD(2)
+ <COMMA> rowConstructor = RowConstructor() { list.add(rowConstructor); }
+ ) *
+ {
+ return new SqlNodeList(list, pos.plus(getPos()));
+ }
+}
+
+/**
+ * Parses a row constructor in the context of a VALUES expression.
+ */
+SqlNode RowConstructor() :
+{
+ SqlNodeList valueList;
+ SqlNode value;
+ SqlParserPos pos;
+}
+{
+ // 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> { pos = getPos(); }
+ <ROW>
+ valueList = ParenthesizedQueryOrCommaList(ExprContext.ACCEPT_NONCURSOR)
+ <RPAREN> { pos = pos.plus(getPos()); }
+ |
+ LOOKAHEAD(3)
+ { pos = getPos(); }
+ [
+ <ROW>
+ ]
+ valueList = ParenthesizedQueryOrCommaList(ExprContext.ACCEPT_NONCURSOR)
+ { pos = pos.plus(getPos()); }
+ |
+ 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 RowConstructorList(). It would be so much more
+ // reasonable to require parentheses. Sigh.
+ pos = value.getParserPosition();
+ valueList = new SqlNodeList(Collections.singletonList(value), pos);
+ }
+ )
+ {
+ // 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(pos, valueList.toArray());
+ }
+}
+
+/**
+ * Parses the optional WHERE clause for SELECT, DELETE, and UPDATE.
+ */
+SqlNode WhereOpt() :
+{
+ SqlNode condition;
+}
+{
+ <WHERE> condition = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ {
+ return condition;
+ }
+ |
+ {
+ return null;
+ }
+}
+
+/**
+ * Parses the optional GROUP BY clause for SELECT.
+ */
+SqlNodeList GroupByOpt() :
+{
+ List<SqlNode> list = Lists.newArrayList();
+ SqlNode e;
+ SqlParserPos pos;
+}
+{
+ <GROUP> { pos = getPos(); }
+ <BY> list = GroupingElementList() {
+ return new SqlNodeList(list, pos.plusAll(list));
+ }
+|
+ {
+ return null;
+ }
+}
+
+List<SqlNode> GroupingElementList() :
+{
+ List<SqlNode> list = Lists.newArrayList();
+ SqlNode e;
+}
+{
+ e = GroupingElement() { list.add(e); }
+ (
+ <COMMA>
+ e = GroupingElement() { list.add(e); }
+ )*
+ { return list; }
+}
+
+SqlNode GroupingElement() :
+{
+ List<SqlNode> list;
+ SqlNodeList nlist;
+ SqlNode e;
+ SqlParserPos pos;
+}
+{
+ <GROUPING> { pos = getPos(); }
+ <SETS> <LPAREN> list = GroupingElementList() <RPAREN> {
+ return SqlStdOperatorTable.GROUPING_SETS.createCall(pos, list);
+ }
+| <ROLLUP> { pos = getPos(); }
+ <LPAREN> nlist = ExpressionCommaList(pos, ExprContext.ACCEPT_SUB_QUERY)
+ <RPAREN> {
+ return SqlStdOperatorTable.ROLLUP.createCall(nlist);
+ }
+| <CUBE> { pos = getPos(); }
+ <LPAREN> nlist = ExpressionCommaList(pos, ExprContext.ACCEPT_SUB_QUERY)
+ <RPAREN> {
+ return SqlStdOperatorTable.CUBE.createCall(nlist);
+ }
+| LOOKAHEAD(3)
+ <LPAREN> <RPAREN> {
+ return new SqlNodeList(getPos());
+ }
+| e = Expression(ExprContext.ACCEPT_SUB_QUERY) {
+ return e;
+ }
+}
+
+/**
+ * Parses a list of expressions separated by commas.
+ */
+SqlNodeList ExpressionCommaList(
+ SqlParserPos pos,
+ ExprContext exprContext) :
+{
+ List<SqlNode> list;
+ SqlNode e;
+}
+{
+ e = Expression(exprContext)
+ {
+ if (pos == null) {
+ pos = getPos();
+ }
+ pos = pos.plus(getPos());
+ list = startList(e);
+ }
+ (
+ // NOTE jvs 6-Feb-2004: See comments at top of file for why
+ // hint is necessary here.
+ LOOKAHEAD(2)
+ <COMMA> e = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ {
+ list.add(e);
+ pos = pos.plus(getPos());
+ }
+ ) *
+ {
+ return new SqlNodeList(list, pos);
+ }
+}
+
+/**
+ * Parses the optional HAVING clause for SELECT.
+ */
+SqlNode HavingOpt() :
+{
+ SqlNode e;
+}
+{
+ <HAVING> e = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ {
+ return e;
+ }
+ |
+ {
+ return null;
+ }
+}
+
+/**
+ * Parses the optional WINDOW clause for SELECT
+ */
+SqlNodeList WindowOpt() :
+{
+ SqlIdentifier id;
+ SqlWindow e;
+ List<SqlNode> list;
+ SqlParserPos pos;
+}
+{
+ <WINDOW> id = SimpleIdentifier() <AS> e = WindowSpecification()
+ {
+ pos = getPos();
+ e.setDeclName(id);
+ list = startList(e);
+ }
+ (
+ // NOTE jhyde 22-Oct-2004: See comments at top of file for why
+ // hint is necessary here.
+ LOOKAHEAD(2)
+ <COMMA> id = SimpleIdentifier() <AS> e = WindowSpecification()
+ {
+ e.setDeclName(id);
+ list.add(e);
+ }
+ ) *
+ {
+ return new SqlNodeList(list, pos);
+ }
+ |
+ {
+ return null;
+ }
+}
+
+/**
+ * Parses a window specification.
+ */
+SqlWindow WindowSpecification() :
+{
+ SqlIdentifier id;
+ List list;
+ SqlNodeList partitionList;
+ SqlNodeList orderList;
+ SqlLiteral isRows = SqlLiteral.createBoolean(false, SqlParserPos.ZERO);
+ SqlNode lowerBound = null, upperBound = null;
+ SqlParserPos startPos;
+ SqlParserPos endPos;
+ SqlParserPos pos;
+ SqlLiteral allowPartial = null;
+}
+{
+ <LPAREN> { startPos = pos = getPos(); }
+ (
+ id = SimpleIdentifier()
+ |
+ { id = null; }
+ )
+ (
+ <PARTITION>
+ { pos = getPos(); }
+ <BY>
+ partitionList = ExpressionCommaList(pos, 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()
+ )
+ ]
+ [
+ <ALLOW> { pos = getPos(); } <PARTIAL> {
+ allowPartial = SqlLiteral.createBoolean(true, pos.plus(getPos()));
+ }
+ |
+ <DISALLOW> { pos = getPos(); } <PARTIAL> {
+ allowPartial = SqlLiteral.createBoolean(false, pos.plus(getPos()));
+ }
+ ]
+ <RPAREN>
+ {
+ endPos = getPos();
+ return SqlWindow.create(
+ null, id, partitionList, orderList,
+ isRows, lowerBound, upperBound, allowPartial,
+ startPos.plus(endPos));
+ }
+}
+
+SqlNode WindowRange() :
+{
+ SqlNode e;
+ SqlParserPos pos = null;
+ SqlParserPos endPos;
+}
+{
+ <CURRENT> {pos = getPos();} <ROW>
+ {
+ endPos = getPos();
+ return SqlWindow.createCurrentRow(pos.plus(endPos));
+ }
+ |
+ <UNBOUNDED>
+ { pos = getPos();}
+ (
+ <PRECEDING>
+ {
+ endPos = getPos();
+ return SqlWindow.createUnboundedPreceding(pos.plus(endPos));
+ }
+ |
+ <FOLLOWING>
+ {
+ endPos = getPos();
+ return SqlWindow.createUnboundedFollowing(pos.plus(endPos));
+ }
+ )
+ |
+ e = Expression(ExprContext.ACCEPT_NON_QUERY)
+ (
+ <PRECEDING>
+ {
+ return SqlWindow.createPreceding(
+ e, getPos());
+ }
+ |
+ <FOLLOWING>
+ {
+ return SqlWindow.createFollowing(
+ e, getPos());
+ }
+ )
+}
+
+/**
+ * Parses an ORDER BY clause.
+ */
+SqlNodeList OrderBy(boolean accept) :
+{
+ List<SqlNode> list;
+ SqlNode e;
+ SqlParserPos pos;
+}
+{
+ <ORDER> {
+ pos = getPos();
+ 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(pos, RESOURCE.illegalOrderBy());
+ }
+ }
+ <BY> e = OrderItem() {
+ list = startList(e);
+ }
+ (
+ // NOTE jvs 6-Feb-2004: See comments at top of file for why
+ // hint is necessary here.
+ LOOKAHEAD(2) <COMMA> e = OrderItem() { list.add(e); }
+ ) *
+ {
+ return new SqlNodeList(list, pos.plusAll(list));
+ }
+}
+
+/**
+ * Parses one list item in an ORDER BY clause.
+ */
+SqlNode OrderItem() :
+{
+ SqlNode e;
+}
+{
+ e = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ (
+ <ASC>
+ | <DESC> {
+ e = SqlStdOperatorTable.DESC.createCall(getPos(), e);
+ }
+ )?
+ (
+ <NULLS> <FIRST> {
+ e = SqlStdOperatorTable.NULLS_FIRST.createCall(getPos(), e);
+ }
+ |
+ <NULLS> <LAST> {
+ e = SqlStdOperatorTable.NULLS_LAST.createCall(getPos(), e);
+ }
+ )?
+ {
+ return e;
+ }
+}
+
+// ----------------------------------------------------------------------------
+// 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.
+ */
+SqlNode QueryOrExpr(ExprContext exprContext) :
+{
+ SqlNodeList withList = null;
+ SqlNode e;
+ SqlOperator op;
+ SqlParserPos pos;
+ SqlParserPos withPos;
+ List<Object> list;
+}
+{
+ [
+ withList = WithList()
+ ]
+ (
+ e = LeafQueryOrExpr(exprContext)
+ )
+ {
+ list = startList(e);
+ }
+ (
+ {
+ if (!e.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);
+ }
+ ) *
+ {
+ e = SqlParserUtil.toTree(list);
+ if (withList != null) {
+ e = new SqlWith(withList.getParserPosition(), withList, e);
+ }
+ return e;
+ }
+}
+
+SqlNodeList WithList() :
+{
+ SqlWithItem withItem;
+ SqlParserPos pos;
+ SqlNodeList list;
+}
+{
+ <WITH> { list = new SqlNodeList(getPos()); }
+ withItem = WithItem() {list.add(withItem);}
+ (
+ <COMMA> withItem = WithItem() {list.add(withItem);}
+ )*
+ { return list; }
+}
+
+SqlWithItem WithItem() :
+{
+ SqlIdentifier id;
+ SqlNodeList columnList = null;
+ SqlNode definition;
+}
+{
+ id = SimpleIdentifier()
+ [
+ LOOKAHEAD(2)
+ columnList = ParenthesizedSimpleIdentifierList()
+ ]
+ <AS>
+ definition = ParenthesizedExpression(ExprContext.ACCEPT_QUERY)
+ {
+ return new SqlWithItem(id.getParserPosition(), id, columnList,
+ definition);
+ }
+}
+
+/**
+ * Parses either a row expression, a leaf query expression, or
+ * a parenthesized expression of any kind.
+ */
+SqlNode LeafQueryOrExpr(ExprContext exprContext) :
+{
+ SqlNode e;
+}
+{
+ e = Expression(exprContext)
+ {
+ return e;
+ }
+ | e = LeafQuery(exprContext)
+ {
+ return e;
+ }
+}
+
+/**
+ * Parses a row expression or a parenthesized expression of any kind.
+ */
+SqlNode Expression(ExprContext exprContext) :
+{
+ List<Object> list;
+ SqlNode e;
+}
+{
+ list = Expression2(exprContext)
+ {
+ e = SqlParserUtil.toTree(list);
+ return e;
+ }
+}
+
+// TODO jvs 15-Nov-2003: ANY/ALL
+
+void Expression2b(ExprContext exprContext, List<Object> list) :
+{
+ SqlNode e;
+ SqlOperator op;
+}
+{
+ (
+ op = PrefixRowOperator() {
+ checkNonQueryExpression(exprContext);
+ list.add(new SqlParserUtil.ToTreeListItem(op, getPos()));
+ }
+ )*
+ e = Expression3(exprContext) {
+ list.add(e);
+ }
+}
+
+/**
+ * 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;
+ SqlNodeList nodeList;
+ SqlNode e;
+ SqlOperator op;
+ SqlParserPos pos = getPos();
+}
+{
+ Expression2b(exprContext, list)
+ (
+ (
+ 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;
+ pos = getPos();
+ }
+ |
+ <IN>
+ {
+ op = SqlStdOperatorTable.IN;
+ pos = getPos();
+ }
+ )
+ nodeList = ParenthesizedQueryOrCommaList(ExprContext.ACCEPT_NONCURSOR)
+ {
+ list.add(new SqlParserUtil.ToTreeListItem(op, pos));
+ pos = pos.plus(getPos());
+ // 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;
+ pos = getPos();
+ }
+ [
+ <SYMMETRIC> { op = SqlStdOperatorTable.SYMMETRIC_NOT_BETWEEN; }
+ |
+ <ASYMMETRIC>
+ ]
+ |
+ <BETWEEN>
+ {
+ op = SqlStdOperatorTable.BETWEEN;
+ pos = getPos();
+ }
+ [
+ <SYMMETRIC> { op = SqlStdOperatorTable.SYMMETRIC_BETWEEN; }
+ |
+ <ASYMMETRIC>
+ ]
+ )
+ e = Expression3(ExprContext.ACCEPT_SUB_QUERY)
+ {
+ list.add(new SqlParserUtil.ToTreeListItem(op, pos));
+ list.add(e);
+ }
+ |
+ {
+ checkNonQueryExpression(exprContext);
+ pos = getPos();
+ }
+ (
+ <NOT>
+ (
+ <LIKE> { op = SqlStdOperatorTable.NOT_LIKE; }
+ |
+ <SIMILAR> <TO> { op = SqlStdOperatorTable.NOT_SIMILAR_TO; }
+ )
+ |
+ <LIKE> { op = SqlStdOperatorTable.LIKE; }
+ |
+ <SIMILAR> <TO> { op = SqlStdOperatorTable.SIMILAR_TO; }
+ )
+ list2 = Expression2(ExprContext.ACCEPT_SUB_QUERY)
+ {
+ list.add(new SqlParserUtil.ToTreeListItem(op, pos));
+ list.addAll(list2);
+ }
+ [
+ LOOKAHEAD(2)
+ <ESCAPE> e = Expression3(ExprContext.ACCEPT_SUB_QUERY)
+ {
+ pos = getPos();
+ list.add(
+ new SqlParserUtil.ToTreeListItem(
+ SqlStdOperatorTable.ESCAPE, pos));
+ list.add(e);
+ }
+ ]
+ |
+ LOOKAHEAD(3) op = BinaryRowOperator()
+ {
+ checkNonQueryExpression(exprContext);
+ list.add(new SqlParserUtil.ToTreeListItem(op, getPos()));
+ }
+ Expression2b(ExprContext.ACCEPT_SUB_QUERY, list)
+ |
+ <LBRACKET>
+ e = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ <RBRACKET>
+ {
+ list.add(
+ new SqlParserUtil.ToTreeListItem(
+ SqlStdOperatorTable.ITEM, getPos()));
+ list.add(e);
+ }
+ |
+ {
+ checkNonQueryExpression(exprContext);
+ }
+ op = PostfixRowOperator()
+ {
+ list.add(new SqlParserUtil.ToTreeListItem(op, getPos()));
+ }
+ )
+ ) +
+ {
+ return list;
+ }
+ |
+ {
+ return list;
+ }
+ )
+}
+
+/**
+ * Parses a unary row expression, or a parenthesized expression of any
+ * kind.
+ */
+SqlNode Expression3(ExprContext exprContext) :
+{
+ SqlNode e;
+ SqlNodeList list;
+ SqlNodeList list1;
+ SqlNodeList list2;
+ SqlPrefixOperator op;
+ boolean rowSeen = false;
+ SqlParserPos pos;
+ SqlParserPos prefixRowOpPos;
+}
+{
+ LOOKAHEAD(2)
+ e = AtomicRowExpression()
+ {
+ checkNonQueryExpression(exprContext);
+ return e;
+ }
+ |
+ e = CursorExpression(exprContext) { return e; }
+ |
+ LOOKAHEAD(3)
+ <ROW> list = ParenthesizedSimpleIdentifierList()
+ {
+ pos = getPos();
+ if (exprContext != ExprContext.ACCEPT_ALL
+ && exprContext != ExprContext.ACCEPT_CURSOR)
+ {
+ throw SqlUtil.newContextException(pos,
+ RESOURCE.illegalRowExpression());
+ }
+ return SqlStdOperatorTable.ROW.createCall(list);
+ }
+ |
+ {
+ pos = getPos();
+ }
+ [
+ <ROW>
+ {
+ pos = getPos(); rowSeen = true;
+ }
+ ]
+ list1 = ParenthesizedQueryOrCommaList(exprContext) {
+ if (rowSeen) {
+ // interpret as row constructor
+ return SqlStdOperatorTable.ROW.createCall(pos, list1.toArray());
+
+ }
+ }
+ [
+ (
+ <OVERLAPS>
+ 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 SqlStdOperatorTable.OVERLAPS.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) {
+ List<SqlNode> list3 = startList(call.operand(0));
+ list3.add(call.operand(1));
+ list3.add(e);
+ return SqlStdOperatorTable.MINUS_DATE.createCall(
+ list1.getParserPosition().plus(getPos()),
+ SqlParserUtil.toNodeArray(list3));
+ }
+ }
+ throw SqlUtil.newContextException(
+ list1.getParserPosition().plus(getPos()),
+ 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(pos, list1.toArray());
+ }
+ }
+}
+
+/**
+ * Parses a COLLATE clause
+ */
+SqlCollation CollateClause() :
+{
+}
+{
+ <COLLATE> <COLLATION_ID>
+ {
+ return new SqlCollation(
+ getToken(0).image, SqlCollation.Coercibility.EXPLICIT);
+ }
+}
+
+/**
+ * Parses an atomic row expression.
+ */
+SqlNode AtomicRowExpression() :
+{
+ SqlNode e;
+ SqlParserPos pos;
+}
+{
+ LOOKAHEAD(1)
+ e = Literal() { return e; }
+ |
+ e = DynamicParam() { return e; }
+ |
+ e = BuiltinFunctionCall() { return e; }
+ |
+ e = JdbcFunctionCall() { return e; }
+ |
+ e = MultisetConstructor() { return e; }
+ |
+ e = ArrayConstructor() { return e; }
+ |
+ e = MapConstructor() { return e; }
+ |
+ // 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() { return e; }
+ |
+ e = ContextVariable() { return e; }
+ |
+ e = CompoundIdentifier() { return e; }
+ |
+ e = NewSpecification() { return e; }
+ |
+ e = CaseExpression() { return e; }
+ |
+ e = SequenceExpression() { return e; }
+}
+
+SqlNode CaseExpression() :
+{
+ SqlParserPos whenPos;
+ SqlParserPos thenPos;
+ SqlParserPos pos;
+ SqlNode e;
+ SqlNode caseIdentifier = null;
+ SqlNode elseClause = null;
+ List<SqlNode> whenList = new ArrayList<SqlNode>();
+ List<SqlNode> thenList = new ArrayList<SqlNode>();
+}
+{
+ <CASE>
+ {
+ pos = getPos();
+ }
+ [
+ caseIdentifier = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ ]
+ (
+ <WHEN>
+ { whenPos = getPos(); }
+ e = ExpressionCommaList(pos, ExprContext.ACCEPT_SUB_QUERY)
+ {
+ if (((SqlNodeList) e).size() == 1) {
+ e = ((SqlNodeList) e).get(0);
+ }
+ whenList.add(e);
+ }
+ <THEN> e = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ { thenPos = getPos(); thenList.add(e); }
+ ) +
+ [
+ <ELSE> elseClause = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ ]
+ <END>
+ {
+ pos = pos.plus(getPos());
+ return SqlCase.createSwitched(pos, caseIdentifier,
+ new SqlNodeList(whenList, whenPos),
+ new SqlNodeList(thenList, thenPos),
+ elseClause);
+ }
+}
+
+SqlCall SequenceExpression() :
+{
+ final SqlParserPos pos;
+ final SqlOperator f;
+ final SqlNode sequenceRef;
+}
+{
+ (
+ <NEXT> { f = SqlStdOperatorTable.NEXT_VALUE; pos = getPos(); }
+ |
+ <CURRENT> { f = SqlStdOperatorTable.CURRENT_VALUE; pos = getPos(); }
+ )
+ <VALUE> <FOR> sequenceRef = CompoundIdentifier() {
+ return f.createCall(pos, sequenceRef);
+ }
+}
+
+/**
+ * Parses "SET <NAME> = VALUE" or "RESET <NAME>", without a leading
+ * "ALTER <SCOPE>".
+ */
+SqlSetOption SqlSetOption(SqlParserPos pos, String scope) :
+{
+ SqlIdentifier name;
+ final SqlNode val;
+}
+{
+ (
+ <SET> {
+ pos = pos == null ? getPos() : pos;
+ }
+ name = CompoundIdentifier()
+ <EQ>
+ (
+ val = Literal()
+ |
+ val = SimpleIdentifier()
+ |
+ <ON> {
+ // OFF is handled by SimpleIdentifier, ON handled here.
+ val = new SqlIdentifier(token.image.toUpperCase(), getPos());
+ }
+ )
+ {
+ return new SqlSetOption(pos.plus(getPos()), scope, name, val);
+ }
+ |
+ <RESET> {
+ pos = pos == null ? getPos() : pos;
+ }
+ (
+ name = CompoundIdentifier()
+ |
+ <ALL> {
+ name = new SqlIdentifier(token.image.toUpperCase(), getPos());
+ }
+ )
+ {
+ return new SqlSetOption(pos.plus(getPos()), 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 SqlParserPos pos;
+ final String scope;
+ final SqlAlter alterNode;
+}
+{
+ (
+ <ALTER> { pos = getPos(); }
+ scope = Scope()
+ )
+ (
+ alterNode = SqlSetOption(pos, scope)
+
+ )
+ {
+ return alterNode;
+ }
+}
+
+String Scope() :
+{
+}
+{
+ ( <SYSTEM> | <SESSION> ) { return token.image.toUpperCase(); }
+}
+
+
+
+/**
+ * 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.
+ */
+SqlNode Literal() :
+{
+ SqlNode e;
+}
+{
+ (
+ e = NumericLiteral()
+ |
+ e = StringLiteral()
+ |
+ e = SpecialLiteral()
+ |
+ e = DateTimeLiteral()
+ |
+ e = IntervalLiteral()
+ )
+ {
+ return e;
+ }
+
+
+}
+
+/** Parses a unsigned numeric literal */
+SqlNumericLiteral UnsignedNumericLiteral() :
+{
+}
+{
+ <UNSIGNED_INTEGER_LITERAL>
+ {
+ return SqlLiteral.createExactNumeric(token.image, getPos());
+ }
+ |
+ <DECIMAL_NUMERIC_LITERAL>
+ {
+ return SqlLiteral.createExactNumeric(token.image, getPos());
+ }
+ |
+ <APPROX_NUMERIC_LITERAL>
+ {
+ return SqlLiteral.createApproxNumeric(token.image, getPos());
+ }
+}
+
+/** Parses a numeric literal (can be signed) */
+SqlLiteral NumericLiteral() :
+{
+ SqlNumericLiteral num;
+ SqlParserPos pos;
+}
+{
+ <PLUS> num = UnsignedNumericLiteral()
+ {
+ return num;
+ }
+ |
+ <MINUS> { pos = getPos(); } num = UnsignedNumericLiteral()
+ {
+ return SqlLiteral.createNegative(num, pos.plus(getPos()));
+ }
+ |
+ 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;
+ int nfrags = 0;
+ List<SqlLiteral> frags = null;
+ char unicodeEscapeChar = 0;
+}
+{
+ // 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>
+ {
+ try {
+ p = SqlParserUtil.trim(token.image, "xX'");
+ frags = startList(SqlLiteral.createBinaryString(p, getPos()));
+ nfrags++;
+ } catch (NumberFormatException ex) {
+ throw SqlUtil.newContextException(getPos(),
+ RESOURCE.illegalBinaryString(token.image));
+ }
+ }
+ (
+ <QUOTED_STRING>
+ {
+ try {
+ p = SqlParserUtil.trim(token.image, "'"); // no embedded quotes
+ frags.add(SqlLiteral.createBinaryString(p, getPos()));
+ nfrags++;
+ } catch (NumberFormatException ex) {
+ throw SqlUtil.newContextException(getPos(),
+ RESOURCE.illegalBinaryString(token.image));
+ }
+ }
+ ) *
+ {
+ assert (nfrags > 0);
+ if (nfrags == 1) {
+ return frags.get(0); // just the head fragment
+ } else {
+ SqlParserPos pos2 = SqlParserPos.sum(frags);
+ return SqlStdOperatorTable.LITERAL_CHAIN.createCall(pos2, frags);
+ }
+ }
+ |
+ {
+ String charSet = null;
+ }
+ (
+ <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";
+ }
+ )
+ {
+ p = SqlParserUtil.parseString(token.image);
+ SqlCharStringLiteral literal;
+ try {
+ literal = SqlLiteral.createCharString(p, charSet, getPos());
+ } catch (java.nio.charset.UnsupportedCharsetException e) {
+ throw SqlUtil.newContextException(getPos(),
+ RESOURCE.unknownCharacterSet(charSet));
+ }
+ frags = startList(literal);
+ nfrags++;
+ }
+ (
+ <QUOTED_STRING>
+ {
+ p = SqlParserUtil.parseString(token.image);
+ try {
+ literal = SqlLiteral.createCharString(p, charSet, getPos());
+ } catch (java.nio.charset.UnsupportedCharsetException e) {
+ throw SqlUtil.newContextException(getPos(),
+ RESOURCE.unknownCharacterSet(charSet));
+ }
+ frags.add(literal);
+ nfrags++;
+ }
+ ) *
+ {
+ }
+ [
+ <UESCAPE> <QUOTED_STRING>
+ {
+ if (unicodeEscapeChar == 0) {
+ throw SqlUtil.newContextException(getPos(),
+ RESOURCE.unicodeEscapeUnexpected());
+ }
+ String s = SqlParserUtil.parseString(token.image);
+ unicodeEscapeChar = SqlParserUtil.checkUnicodeEscapeChar(s);
+ }
+ ]
+ {
+ }
+ {
+ assert nfrags > 0;
+ if (nfrags == 1) {
+ // just the head fragment
+ SqlLiteral lit = (SqlLiteral) frags.get(0);
+ return lit.unescapeUnicode(unicodeEscapeChar);
+ } else {
+ SqlNode[] rands = (SqlNode[]) frags.toArray(new SqlNode[nfrags]);
+ 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);
+ }
+ }
+}
+
+
+/**
+ * Parses a date/time literal.
+ */
+SqlLiteral DateTimeLiteral() :
+{
+ String p;
+ SqlParserPos pos;
+}
+{
+ <LBRACE_D> <QUOTED_STRING>
+ {
+ p = token.image;
+ }
+ <RBRACE>
+ {
+ return parseDateLiteral(p, getPos());
+ }
+ |
+ <LBRACE_T> <QUOTED_STRING>
+ {
+ p = token.image;
+ }
+ <RBRACE>
+ {
+ return parseTimeLiteral(p, getPos());
+ }
+ |
+ <LBRACE_TS> <QUOTED_STRING>
+ {
+ p = token.image;
+ }
+ <RBRACE>
+ {
+ return parseTimestampLiteral(p, getPos());
+ }
+ |
+ <DATE> { pos = getPos(); } <QUOTED_STRING>
+ {
+ return parseDateLiteral(token.image, pos.plus(getPos()));
+ }
+ |
+ <TIME> { pos = getPos(); } <QUOTED_STRING>
+ {
+ return parseTimeLiteral(token.image, pos.plus(getPos()));
+ }
+ |
+ <TIMESTAMP> { pos = getPos(); } <QUOTED_STRING>
+ {
+ return parseTimestampLiteral(token.image, pos.plus(getPos()));
+ }
+}
+
+/** Parses a MULTISET constructor */
+SqlNode MultisetConstructor() :
+{
+ List<SqlNode> args;
+ SqlNode e;
+ SqlParserPos pos;
+}
+{
+ <MULTISET> { pos = getPos(); }
+ (
+ LOOKAHEAD(1)
+ <LPAREN>
+ // by sub query "MULTISET(SELECT * FROM T)"
+ e = LeafQueryOrExpr(ExprContext.ACCEPT_QUERY)
+ <RPAREN>
+ {
+ return SqlStdOperatorTable.MULTISET_QUERY.createCall(
+ pos.plus(getPos()), e);
+ }
+ |
+ // by enumeration "MULTISET[e0, e1, ..., eN]"
+ <LBRACKET> // TODO: do trigraph as well ??( ??)
+ e = Expression(ExprContext.ACCEPT_NON_QUERY) { args = startList(e); }
+ (
+ <COMMA> e = Expression(ExprContext.ACCEPT_NON_QUERY) { args.add(e); }
+ ) *
+ <RBRACKET>
+ {
+ return SqlStdOperatorTable.MULTISET_VALUE.createCall(
+ pos.plus(getPos()), SqlParserUtil.toNodeArray(args));
+ }
+ )
+}
+
+/** Parses an ARRAY constructor */
+SqlNode ArrayConstructor() :
+{
+ SqlNodeList args;
+ SqlNode e;
+ SqlParserPos pos;
+}
+{
+ <ARRAY> { pos = getPos(); }
+ (
+ LOOKAHEAD(1)
+ <LPAREN>
+ // by sub query "MULTISET(SELECT * FROM T)"
+ e = LeafQueryOrExpr(ExprContext.ACCEPT_QUERY)
+ <RPAREN>
+ {
+ return SqlStdOperatorTable.ARRAY_QUERY.createCall(
+ pos.plus(getPos()), e);
+ }
+ |
+ // by enumeration "ARRAY[e0, e1, ..., eN]"
+ <LBRACKET> // TODO: do trigraph as well ??( ??)
+ (
+ args = ExpressionCommaList(pos, ExprContext.ACCEPT_NON_QUERY)
+ |
+ { args = new SqlNodeList(getPos()); }
+ )
+ <RBRACKET>
+ {
+ return SqlStdOperatorTable.ARRAY_VALUE_CONSTRUCTOR.createCall(
+ pos.plus(getPos()), SqlParserUtil.toNodeArray(args));
+ }
+ )
+}
+
+/** Parses an MAP constructor */
+SqlNode MapConstructor() :
+{
+ SqlNodeList args;
+ SqlNode e;
+ SqlParserPos pos;
+}
+{
+ <MAP> { pos = getPos(); }
+ (
+ LOOKAHEAD(1)
+ <LPAREN>
+ // by sub query "MAP (SELECT empno, deptno FROM emp)"
+ e = LeafQueryOrExpr(ExprContext.ACCEPT_QUERY)
+ <RPAREN>
+ {
+ return SqlStdOperatorTable.MAP_QUERY.createCall(
+ pos.plus(getPos()), e);
+ }
+ |
+ // by enumeration "MAP[k0, v0, ..., kN, vN]"
+ <LBRACKET> // TODO: do trigraph as well ??( ??)
+ (
+ args = ExpressionCommaList(pos, ExprContext.ACCEPT_NON_QUERY)
+ |
+ { args = new SqlNodeList(getPos()); }
+ )
+ <RBRACKET>
+ {
+ return SqlStdOperatorTable.MAP_VALUE_CONSTRUCTOR.createCall(
+ pos.plus(getPos()), SqlParserUtil.toNodeArray(args));
+ }
+ )
+}
+
+/**
+ * Parses an interval literal.
+ */
+SqlLiteral IntervalLiteral() :
+{
+ String p;
+ SqlIntervalQualifier intervalQualifier;
+ int sign = 1;
+ SqlParserPos pos;
+}
+{
+ <INTERVAL> { pos = getPos(); }
+ [
+ <MINUS> { sign = -1; }
+ |
+ <PLUS> { sign = 1; }
+ ]
+ <QUOTED_STRING> { p = token.image; }
+ intervalQualifier = IntervalQualifier()
+ {
+ return parseIntervalLiteral(pos.plus(getPos()), sign, p, intervalQualifier);
+ }
+}
+
+SqlIntervalQualifier IntervalQualifier() :
+{
+ TimeUnit start;
+ TimeUnit end = null;
+ int startPrec = RelDataType.PRECISION_NOT_SPECIFIED;
+ int secondFracPrec = RelDataType.PRECISION_NOT_SPECIFIED;
+}
+{
+ (
+ <YEAR> [ <LPAREN> startPrec = UnsignedIntLiteral() <RPAREN> ]
+ [
+ LOOKAHEAD(2) <TO> <MONTH>
+ {
+ end = TimeUnit.MONTH;
+ }
+ ]
+ { start = TimeUnit.YEAR; }
+ |
+ <MONTH> [ <LPAREN> startPrec = UnsignedIntLiteral() <RPAREN> ]
+ { start = TimeUnit.MONTH; }
+ |
+ <DAY> [ <LPAREN> startPrec = UnsignedIntLiteral() <RPAREN> ]
+ [ LOOKAHEAD(2) <TO>
+ (
+ <HOUR> { end = TimeUnit.HOUR; }
+ | <MINUTE> { end = TimeUnit.MINUTE; }
+ | <SECOND> { end = TimeUnit.SECOND; }
+ [ <LPAREN> secondFracPrec = UnsignedIntLiteral() <RPAREN> ]
+ )
+ ]
+ { start = TimeUnit.DAY; }
+ |
+ <HOUR> [ <LPAREN> startPrec = UnsignedIntLiteral() <RPAREN> ]
+ [ LOOKAHEAD(2) <TO>
+ (
+ <MINUTE> { end = TimeUnit.MINUTE; }
+ | <SECOND> { end = TimeUnit.SECOND; }
+ [ <LPAREN> secondFracPrec = UnsignedIntLiteral() <RPAREN> ]
+ )
+ ]
+ { start = TimeUnit.HOUR; }
+ |
+ <MINUTE> [ <LPAREN> startPrec = UnsignedIntLiteral() <RPAREN> ]
+ [ LOOKAHEAD(2) <TO>
+ (
+ <SECOND> { end = TimeUnit.SECOND; }
+ [ <LPAREN> secondFracPrec = UnsignedIntLiteral() <RPAREN> ]
+ )
+ ]
+ { start = TimeUnit.MINUTE; }
+ |
+ <SECOND>
+ [ <LPAREN> startPrec = UnsignedIntLiteral()
+ [ <COMMA> secondFracPrec = UnsignedIntLiteral() ]
+ <RPAREN>
+ ]
+ { start = TimeUnit.SECOND; }
+ )
+ {
+ return new SqlIntervalQualifier(start,
+ startPrec,
+ end,
+ secondFracPrec,
+ getPos());
+ }
+}
+
+/**
+ * Parses time unit for EXTRACT, CEIL and FLOOR functions.
+ */
+TimeUnit TimeUnit() :
+{}
+{
+ <SECOND> { return TimeUnit.SECOND; }
+| <MINUTE> { return TimeUnit.MINUTE; }
+| <HOUR> { return TimeUnit.HOUR; }
+| <DAY> { return TimeUnit.DAY; }
+| <DOW> { return TimeUnit.DOW; }
+| <DOY> { return TimeUnit.DOY; }
+| <WEEK> { return TimeUnit.WEEK; }
+| <MONTH> { return TimeUnit.MONTH; }
+| <QUARTER> { return TimeUnit.QUARTER; }
+| <YEAR> { return TimeUnit.YEAR; }
+| <EPOCH> { return TimeUnit.EPOCH; }
+| <DECADE> { return TimeUnit.DECADE; }
+| <CENTURY> { return TimeUnit.CENTURY; }
+| <MILLENNIUM> { return TimeUnit.MILLENNIUM; }
+}
+
+TimeUnit TimestampInterval() :
+{}
+{
+ <FRAC_SECOND> { return TimeUnit.MICROSECOND; }
+| <MICROSECOND> { return TimeUnit.MICROSECOND; }
+| <SQL_TSI_FRAC_SECOND> { return TimeUnit.MICROSECOND; }
+| <SQL_TSI_MICROSECOND> { return TimeUnit.MICROSECOND; }
+| <SECOND> { return TimeUnit.SECOND; }
+| <SQL_TSI_SECOND> { return TimeUnit.SECOND; }
+| <MINUTE> { return TimeUnit.MINUTE; }
+| <SQL_TSI_MINUTE> { return TimeUnit.MINUTE; }
+| <HOUR> { return TimeUnit.HOUR; }
+| <SQL_TSI_HOUR> { return TimeUnit.HOUR; }
+| <DAY> { return TimeUnit.DAY; }
+| <SQL_TSI_DAY> { return TimeUnit.DAY; }
+| <WEEK> { return TimeUnit.WEEK; }
+| <SQL_TSI_WEEK> { return TimeUnit.WEEK; }
+| <MONTH> { return TimeUnit.MONTH; }
+| <SQL_TSI_MONTH> { return TimeUnit.MONTH; }
+| <QUARTER> { return TimeUnit.QUARTER; }
+| <SQL_TSI_QUARTER> { return TimeUnit.QUARTER; }
+| <YEAR> { return TimeUnit.YEAR; }
+| <SQL_TSI_YEAR> { return TimeUnit.YEAR; }
+}
+
+
+
+/**
+ * Parses a dynamic parameter marker.
+ */
+SqlDynamicParam DynamicParam() :
+{
+ SqlParserPos pos;
+}
+{
+ <HOOK>
+ {
+ pos = getPos();
+ return new SqlDynamicParam(nDynamicParams++, pos);
+ }
+}
+
+
+/**
+ * Parses a simple identifier as a string.
+ */
+String Identifier() :
+{
+ String id;
+ char unicodeEscapeChar = BACKSLASH;
+}
+{
+ (
+ <IDENTIFIER>
+ {
+ id = unquotedIdentifier();
+ }
+ | <QUOTED_IDENTIFIER>
+ {
+ id = SqlParserUtil.strip(getToken(0).image, DQ, DQ, DQDQ,
+ quotedCasing);
+ }
+ | <BACK_QUOTED_IDENTIFIER>
+ {
+ id = SqlParserUtil.strip(getToken(0).image, "`", "`", "``",
+ quotedCasing);
+ }
+ | <BRACKET_QUOTED_IDENTIFIER>
+ {
+ id = SqlParserUtil.strip(getToken(0).image, "[", "]", "]]",
+ quotedCasing);
+ }
+ | <UNICODE_QUOTED_IDENTIFIER>
+ {
+ id = getToken(0).image;
+ id = id.substring(id.indexOf('"'));
+ id = SqlParserUtil.strip(id, DQ, DQ, DQDQ, quotedCasing);
+ }
+ [ <UESCAPE> <QUOTED_STRING>
+ {
+ String s = SqlParserUtil.parseString(token.image);
+ unicodeEscapeChar = SqlParserUtil.checkUnicodeEscapeChar(s);
+ }
+ ]
+ {
+ }
+ {
+ SqlLiteral lit = SqlLiteral.createCharString(id, "UTF16", getPos());
+ lit = lit.unescapeUnicode(unicodeEscapeChar);
+ return lit.toValue();
+ }
+ | id = NonReservedKeyWord()
+ )
+ {
+ if (id.length() > this.identifierMaxLength) {
+ throw SqlUtil.newContextException(getPos(),
+ RESOURCE.identifierTooLong(id, this.identifierMaxLength));
+ }
+ return id;
+ }
+}
+
+/**
+ * Parses a simple identifier as an SqlIdentifier.
+ */
+SqlIdentifier SimpleIdentifier() :
+{
+ String p;
+ SqlParserPos pos;
+}
+{
+ p = Identifier(){pos = getPos();}
+ {
+ return new SqlIdentifier(p,pos);
+ }
+}
+
+/**
+ * Parses a comma-separated list of simple identifiers.
+ */
+void SimpleIdentifierCommaList(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() :
+{
+ SqlParserPos pos;
+ List<SqlNode> list = new ArrayList<SqlNode>();
+}
+{
+ <LPAREN> { pos = getPos(); }
+ SimpleIdentifierCommaList(list)
+ <RPAREN>
+ {
+ return new SqlNodeList(list, pos.plus(getPos()));
+ }
+}
+
+/**
+ * Parses a compound identifier.
+ */
+SqlIdentifier CompoundIdentifier() :
+{
+ List<String> list = new ArrayList<String>();
+ List<SqlParserPos> posList = new ArrayList<SqlParserPos>();
+ String p;
+ boolean star = false;
+}
+{
+ p = Identifier()
+ {
+ posList.add(getPos());
+ list.add(p);
+ }
+ (
+ <DOT>
+ p = Identifier() {
+ list.add(p);
+ posList.add(getPos());
+ }
+ ) *
+ (
+ <DOT>
+ <STAR> {
+ star = true;
+ list.add("");
+ posList.add(getPos());
+ }
+ )?
+ {
+ SqlParserPos pos = SqlParserPos.sum(posList);
+ if (star) {
+ return SqlIdentifier.star(list, pos, posList);
+ }
+ return new SqlIdentifier(list, null, pos, posList);
+ }
+}
+
+/**
+ * Parses a comma-separated list of compound identifiers.
+ */
+void CompoundIdentifierCommaList(List<SqlNode> list) :
+{
+ SqlIdentifier id;
+}
+{
+ id = CompoundIdentifier() {list.add(id);}
+ (<COMMA> id = CompoundIdentifier() {list.add(id);}) *
+}
+
+/**
+ * List of compound identifiers in parentheses. The position extends from the
+ * open parenthesis to the close parenthesis.
+ */
+SqlNodeList ParenthesizedCompoundIdentifierList() :
+{
+ SqlParserPos pos;
+ List<SqlNode> list = new ArrayList<SqlNode>();
+}
+{
+ <LPAREN> { pos = getPos(); }
+ CompoundIdentifierCommaList(list)
+ <RPAREN>
+ {
+ return new SqlNodeList(list, pos.plus(getPos()));
+ }
+}
+
+/**
+ * Parses a NEW UDT(...) expression.
+ */
+SqlNode NewSpecification() :
+{
+ SqlParserPos callPos;
+ SqlNode routineCall;
+}
+{
+ <NEW>
+ {
+ callPos = getPos();
+ }
+ routineCall =
+ NamedRoutineCall(
+ SqlFunctionCategory.USER_DEFINED_CONSTRUCTOR,
+ ExprContext.ACCEPT_SUB_QUERY)
+ {
+ return SqlStdOperatorTable.NEW.createCall(callPos, routineCall);
+ }
+}
+
+//TODO: real parse errors.
+int UnsignedIntLiteral() :
+{
+ Token t;
+}
+{
+ t = <UNSIGNED_INTEGER_LITERAL>
+ {
+ try {
+ return Integer.parseInt(t.image);
+ } catch (NumberFormatException ex) {
+ throw generateParseException();
+ }
+ }
+}
+
+int IntLiteral() :
+{
+ Token t;
+}
+{
+ ( t = <UNSIGNED_INTEGER_LITERAL> | <PLUS> t = <UNSIGNED_INTEGER_LITERAL> )
+ {
+ try {
+ return Integer.parseInt(t.image);
+ } catch (NumberFormatException ex) {
+ throw generateParseException();
+ }
+ }
+ |
+ <MINUS> t = <UNSIGNED_INTEGER_LITERAL>
+ {
+ try {
+ return -Integer.parseInt(t.image);
+ } catch (NumberFormatException ex) {
+ throw generateParseException();
+ }
+ }
+}
+
+// Type name with optional scale and precision
+SqlDataTypeSpec DataType() :
+{
+ SqlIdentifier typeName;
+ SqlIdentifier collectionTypeName = null;
+ int scale = -1;
+ int precision = -1;
+ String charSetName = null;
+ SqlParserPos pos;
+}
+{
+ (
+ typeName = TypeName()
+ {
+ pos = getPos();
+ }
+ [
+ <LPAREN>
+ precision = UnsignedIntLiteral()
+ [
+ <COMMA>
+ scale = UnsignedIntLiteral()
+ ]
+ <RPAREN>
+ ]
+ [
+ <CHARACTER> <SET>
+ charSetName = Identifier()
+ ]
+ [
+ collectionTypeName = CollectionsTypeName()
+ ]
+ )
+ {
+ if (null != collectionTypeName) {
+ return new SqlDataTypeSpec(
+ collectionTypeName,
+ typeName,
+ precision,
+ scale,
+ charSetName,
+ pos);
+ }
+ return new SqlDataTypeSpec(
+ typeName,
+ precision,
+ scale,
+ charSetName,
+ null,
+ pos);
+ }
+}
+
+// Some SQL type names need special handling due to the fact that they have
+// spaces in them but are not quoted.
+SqlIdentifier TypeName() :
+{
+ SqlIdentifier typeName = null;
+ SqlParserPos pos = getPos();
+}
+{
+ (
+ (<CHARACTER> | <CHAR>)
+ {
+ typeName = new SqlIdentifier(
+ SqlTypeName.CHAR.name(), pos);
+ }
+ [
+ <VARYING>
+ {
+ typeName = new SqlIdentifier(
+ SqlTypeName.VARCHAR.name(), pos);
+ }
+ ]
+ | <VARCHAR>
+ {
+ typeName = new SqlIdentifier(
+ SqlTypeName.VARCHAR.name(), pos);
+ }
+ | <DATE>
+ {
+ typeName = new SqlIdentifier(
+ SqlTypeName.DATE.name(),pos);
+ }
+ | <TIME>
+ {
+ typeName = new SqlIdentifier(
+ SqlTypeName.TIME.name(),pos);
+ }
+ | <TIMESTAMP>
+ {
+ typeName = new SqlIdentifier(
+ SqlTypeName.TIMESTAMP.name(),pos);
+ }
+ | (<DECIMAL> | <DEC> | <NUMERIC>)
+ {
+ typeName = new SqlIdentifier(
+ SqlTypeName.DECIMAL.name(),pos);
+ }
+ | <BOOLEAN>
+ {
+ typeName = new SqlIdentifier(
+ SqlTypeName.BOOLEAN.name(),pos);
+ }
+ | <INTEGER>
+ {
+ typeName = new SqlIdentifier(
+ SqlTypeName.INTEGER.name(),pos);
+ }
+ | <INT>
+ {
+ typeName = new SqlIdentifier(
+ SqlTypeName.INTEGER.name(),pos);
+ }
+ |
+ (
+ <BINARY>
+ {
+ typeName = new SqlIdentifier(
+ SqlTypeName.BINARY.name(),pos);
+ }
+ )
+ [
+ <VARYING>
+ {
+ typeName = new SqlIdentifier(
+ SqlTypeName.VARBINARY.name(), pos);
+ }
+ ]
+ | <VARBINARY>
+ {
+ typeName = new SqlIdentifier(
+ SqlTypeName.VARBINARY.name(),pos);
+ }
+ | <TINYINT>
+ {
+ typeName = new SqlIdentifier(
+ SqlTypeName.TINYINT.name(),pos);
+ }
+ | <SMALLINT>
+ {
+ typeName = new SqlIdentifier(
+ SqlTypeName.SMALLINT.name(),pos);
+ }
+ | <BIGINT>
+ {
+ typeName = new SqlIdentifier(
+ SqlTypeName.BIGINT.name(),pos);
+ }
+ | <REAL>
+ {
+ typeName = new SqlIdentifier(
+ SqlTypeName.REAL.name(),pos);
+ }
+ | <DOUBLE> [ <PRECISION> ]
+ {
+ typeName = new SqlIdentifier(
+ SqlTypeName.DOUBLE.name(),pos);
+ }
+ | <FLOAT>
+ {
+ typeName = new SqlIdentifier(
+ SqlTypeName.FLOAT.name(),pos);
+ }
+ | <ANY>
+ {
+ typeName = new SqlIdentifier(
+ SqlTypeName.ANY.name(),pos);
+ }
+ | typeName = CollectionsTypeName()
+ | typeName = CompoundIdentifier()
+ )
+ {
+ return typeName;
+ }
+}
+
+// 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());
+ }
+}
+
+SqlIdentifier CollectionsTypeName() :
+{
+ SqlIdentifier typeName = null;
+ SqlParserPos pos = getPos();
+}
+{
+ <MULTISET>
+ {
+ typeName = new SqlIdentifier(
+ SqlTypeName.MULTISET.name(),pos);
+ return typeName;
+ }
+}
+
+/**
+ * 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) :
+{
+ SqlNode e;
+ SqlParserPos pos;
+}
+{
+ <CURSOR>
+ {
+ pos = getPos();
+ if (exprContext != ExprContext.ACCEPT_ALL
+ && exprContext != ExprContext.ACCEPT_CURSOR)
+ {
+ throw SqlUtil.newContextException(pos,
+ RESOURCE.illegalCursorExpression());
+ }
+ }
+ e = Expression(ExprContext.ACCEPT_QUERY)
+ {
+ return SqlStdOperatorTable.CURSOR.createCall(pos, e);
+ }
+}
+
+/**
+ * Parses a call to a builtin function with special syntax.
+ */
+SqlNode BuiltinFunctionCall() :
+{
+ String name;
+ List<SqlNode> args = null;
+ SqlNode e = null;
+ SqlParserPos pos;
+ SqlParserPos starPos;
+ SqlParserPos namePos;
+ SqlDataTypeSpec dt;
+ TimeUnit interval;
+ SqlNode node;
+}
+{
+ //~ FUNCTIONS WITH SPECIAL SYNTAX ---------------------------------------
+ (
+ <CAST>
+ {
+ pos = getPos();
+ }
+ <LPAREN> e = Expression(ExprContext.ACCEPT_SUB_QUERY) { args = startList(e); }
+ <AS>
+ (
+ dt = DataType() { args.add(dt); }
+ | <INTERVAL> e = IntervalQualifier() { args.add(e); }
+ )
+ <RPAREN>
+ {
+ return SqlStdOperatorTable.CAST.createCall(
+ pos.plus(getPos()), SqlParserUtil.toNodeArray(args));
+ }
+ )
+ |
+ (
+ <EXTRACT>
+ {
+ pos = getPos();
+ TimeUnit unit;
+ }
+ <LPAREN>
+ unit = TimeUnit()
+ { args = startList(new SqlIntervalQualifier(unit, null, getPos())); }
+ <FROM>
+ e = Expression(ExprContext.ACCEPT_SUB_QUERY) { args.add(e); }
+ <RPAREN>
+ {
+ return SqlStdOperatorTable.EXTRACT.createCall(
+ pos.plus(getPos()), SqlParserUtil.toNodeArray(args));
+ }
+ )
+ |
+ (
+ <POSITION>
+ {
+ pos = getPos();
+ }
+ <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 = startList(e); }
+ <IN>
+ e = Expression(ExprContext.ACCEPT_SUB_QUERY) { args.add(e);}
+ [
+ <FROM>
+ e = Expression(ExprContext.ACCEPT_SUB_QUERY) { args.add(e); }
+ ]
+ <RPAREN>
+ {
+ return SqlStdOperatorTable.POSITION.createCall(
+ pos.plus(getPos()), SqlParserUtil.toNodeArray(args));
+ }
+ )
+ |
+ (
+ <CONVERT>
+ {
+ pos = getPos();
+ }
+ <LPAREN>
+ e = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ {
+ args = startList(e);
+ }
+ <USING> name = Identifier()
+ {
+ namePos = getPos();
+ args.add(new SqlIdentifier(name, namePos));
+ }
+ <RPAREN>
+ {
+ return SqlStdOperatorTable.CONVERT.createCall(
+ pos, SqlParserUtil.toNodeArray(args));
+ }
+ )
+ |
+ (
+ <TRANSLATE>
+ {
+ pos = getPos();
+ }
+ <LPAREN>
+ e = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ {
+ args = startList(e);
+ }
+ (
+ <USING> name = Identifier() {
+ namePos = getPos();
+ args.add(new SqlIdentifier(name, namePos));
+ }
+ <RPAREN> {
+ return SqlStdOperatorTable.TRANSLATE.createCall(
+ pos, SqlParserUtil.toNodeArray(args));
+ }
+ |
+ (
+ <COMMA> e = Expression(ExprContext.ACCEPT_SUB_QUERY) {
+ args.add(e);
+ }
+ )*
+ <RPAREN> {
+ return OracleSqlOperatorTable.TRANSLATE3.createCall(
+ pos.plus(getPos()), SqlParserUtil.toNodeArray(args));
+ }
+ )
+ )
+ |
+ (
+ <OVERLAY>
+ {
+ pos = getPos();
+ }
+ <LPAREN>
+ e = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ {
+ args = startList(e);
+ }
+ <PLACING>
+ e = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ {
+ args.add(e);
+ }
+ <FROM>
+ e = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ {
+ args.add(e);
+ }
+ [
+ <FOR>
+ e = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ {
+ args.add(e);
+ }
+ ]
+ <RPAREN>
+ {
+ return SqlStdOperatorTable.OVERLAY.createCall(
+ pos.plus(getPos()), SqlParserUtil.toNodeArray(args));
+ }
+ )
+ |
+ (
+ <FLOOR>
+ e = FloorCeilOptions(getPos(), true)
+ { return e; }
+ )
+ |
+ (
+ ( <CEIL> | <CEILING>)
+ e = FloorCeilOptions(getPos(), false)
+ { return e; }
+ )
+ |
+ (
+ <SUBSTRING>
+ {
+ pos = getPos();
+ }
+ <LPAREN>
+ e = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ { args = startList(e); }
+ ( <FROM> | <COMMA>)
+ e = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ { args.add(e); }
+ [
+ (<FOR> | <COMMA>)
+ e = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ { args.add(e); }
+ ]
+ <RPAREN>
+ {
+ return SqlStdOperatorTable.SUBSTRING.createCall(
+ pos.plus(getPos()), SqlParserUtil.toNodeArray(args));
+ }
+ )
+ |
+ (
+ <TRIM>
+ {
+ SqlLiteral flag = null;
+ SqlNode trimChars = null;
+ pos = getPos();
+ }
+ <LPAREN>
+ [
+ LOOKAHEAD(2)
+ [
+ <BOTH>
+ {
+ pos = getPos();
+ flag = SqlTrimFunction.Flag.BOTH.symbol(pos);
+ }
+ |
+ <TRAILING>
+ {
+ pos = getPos();
+ flag = SqlTrimFunction.Flag.TRAILING.symbol(pos);
+ }
+ |
+ <LEADING>
+ {
+ pos = getPos();
+ flag = SqlTrimFunction.Flag.LEADING.symbol(pos);
+ }
+ ]
+ [ 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 = startList(flag);
+ args.add(null); // no trim chars
+ args.add(trimChars); // reinterpret trimChars as source
+ return SqlStdOperatorTable.TRIM.createCall(
+ pos, SqlParserUtil.toNodeArray(args));
+ }
+ )
+ ]
+ e = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ {
+ if (flag == null) {
+ flag = SqlTrimFunction.Flag.BOTH.symbol(SqlParserPos.ZERO);
+ }
+ args = startList(flag);
+ args.add(trimChars);
+ args.add(e);
+ }
+ <RPAREN>
+ {
+ return SqlStdOperatorTable.TRIM.createCall(
+ pos.plus(getPos()), SqlParserUtil.toNodeArray(args));
+ }
+ )
+ |
+ node = TimestampAddFunctionCall() { return node; }
+ |
+ node = TimestampDiffFunctionCall() { return node; }
+ |
+ node = ExtendedBuiltinFunctionCall() { return node; }
+}
+
+/**
+ * Parses a call to TIMESTAMPADD.
+ */
+SqlCall TimestampAddFunctionCall() :
+{
+ List<SqlNode> args;
+ SqlNode e;
+ SqlParserPos pos;
+ TimeUnit interval;
+ SqlNode node;
+}
+{
+ <TIMESTAMPADD> {
+ pos = getPos();
+ }
+ <LPAREN>
+ interval = TimestampInterval() {
+ args = startList(SqlLiteral.createSymbol(interval, getPos()));
+ }
+ <COMMA>
+ e = Expression(ExprContext.ACCEPT_SUB_QUERY) { args.add(e); }
+ <COMMA>
+ e = Expression(ExprContext.ACCEPT_SUB_QUERY) { args.add(e); }
+ <RPAREN> {
+ return SqlStdOperatorTable.TIMESTAMP_ADD.createCall(
+ pos.plus(getPos()), SqlParserUtil.toNodeArray(args));
+ }
+}
+
+/**
+ * Parses a call to TIMESTAMPDIFF.
+ */
+SqlCall TimestampDiffFunctionCall() :
+{
+ List<SqlNode> args;
+ SqlNode e;
+ SqlParserPos pos;
+ TimeUnit interval;
+ SqlNode node;
+}
+{
+ <TIMESTAMPDIFF> {
+ pos = getPos();
+ }
+ <LPAREN>
+ interval = TimestampInterval() {
+ args = startList(SqlLiteral.createSymbol(interval, getPos()));
+ }
+ <COMMA>
+ e = Expression(ExprContext.ACCEPT_SUB_QUERY) { args.add(e); }
+ <COMMA>
+ e = Expression(ExprContext.ACCEPT_SUB_QUERY) { args.add(e); }
+ <RPAREN> {
+ return SqlStdOperatorTable.TIMESTAMP_DIFF.createCall(
+ pos.plus(getPos()), SqlParserUtil.toNodeArray(args));
+ }
+}
+
+/**
+ * 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() :
+{
+ SqlIdentifier qualifiedName;
+ SqlIdentifier id = null;
+ List<SqlNode> args;
+ SqlParserPos pos;
+ SqlParserPos starPos;
+ SqlParserPos filterPos = null;
+ SqlNode filter = null;
+ SqlFunctionCategory funcType = SqlFunctionCategory.USER_DEFINED_FUNCTION;
+ SqlNode e = null;
+ SqlLiteral quantifier = null;
+}
+{
+ [
+ <SPECIFIC>
+ {
+ funcType = SqlFunctionCategory.USER_DEFINED_SPECIFIC_FUNCTION;
+ }
+ ]
+ (
+ qualifiedName = FunctionName()
+ {
+ pos = getPos();
+ }
+ (
+ LOOKAHEAD(2) <LPAREN> <STAR> { starPos = getPos(); } <RPAREN>
+ {
+ args = startList(SqlIdentifier.star(starPos));
+ pos = pos.plus(getPos());
+ }
+ | LOOKAHEAD(2) <LPAREN> <RPAREN>
+ {
+ args = Collections.emptyList();
+ pos = pos.plus(getPos());
+ }
+ | args = FunctionParameterList(ExprContext.ACCEPT_SUB_QUERY)
+ {
+ pos = pos.plus(getPos());
+ quantifier = (SqlLiteral) args.get(0);
+ args.remove(0);
+ }
+ )
+ [
+ <FILTER> { filterPos = getPos(); }
+ <LPAREN>
+ <WHERE>
+ filter = Expression(ExprContext.ACCEPT_SUB_QUERY)
+ <RPAREN> { filterPos = filterPos.plus(getPos()); }
+ ]
+ [
+ <OVER>
+ (
+ id = SimpleIdentifier()
+ | e = WindowSpecification()
+ )
+ {
+ pos = pos.plus(getPos());
+ }
+ ]
+ {
+ SqlCall function = createCall(
+ qualifiedName, pos, funcType, quantifier,
+ SqlParserUtil.toNodeArray(args));
+
+ if (filter != null) {
+ function = SqlStdOperatorTable.FILTER.createCall(filterPos,
+ function, filter);
+ }
+ if (id != null) {
+ return SqlStdOperatorTable.OVER.createCall(pos, function, id);
+ }
+ if (e != null) {
+ return SqlStdOperatorTable.OVER.createCall(pos, function, e);
+ }
+ return function;
+ }
+ )
+}
+
+
+/*
+* Parse Floor/Ceil function parameters
+*/
+SqlNode StandardFloorCeilOptions(SqlParserPos pos, boolean floorFlag) :
+{
+ SqlIdentifier name;
+ SqlParserPos overPos = null;
+ SqlIdentifier id = null;
+ SqlNode e;
+ List<SqlNode> args;
+ TimeUnit unit;
+ boolean over = false;
+}
+{
+ <LPAREN> e = Expression(ExprContext.ACCEPT_SUB_QUERY) {
+ args = startList(e);
+ }
+ (
+ <TO>
+ unit = TimeUnit() {
+ args.add(new SqlIntervalQualifier(unit, null, getPos()));
+ }
+ )?
+ <RPAREN>
+ [
+ <OVER>
+ {
+ overPos = getPos();
+ over = true;
+ }
+ (
+ id = SimpleIdentifier()
+ | e = WindowSpecification()
+ )
+ ]
+ {
+ SqlOperator op = floorFlag
+ ? SqlStdOperatorTable.FLOOR
+ : SqlStdOperatorTable.CEIL;
+ final SqlCall function = op.createCall(pos.plus(getPos()), args);
+ if (over) {
+ return SqlStdOperatorTable.OVER.createCall(overPos, function,
+ Util.first(id, e));
+ } else {
+ 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>
+ | <CHAR_LENGTH>
+ | <CHARACTER_LENGTH>
+ | <COALESCE>
+ | <COLLECT>
+ | <COVAR_POP>
+ | <COVAR_SAMP>
+ | <CUME_DIST>
+ | <COUNT>
+ | <CURRENT_DATE>
+ | <CURRENT_TIME>
+ | <CURRENT_TIMESTAMP>
+ | <DENSE_RANK>
+ | <ELEMENT>
+ | <EXP>
+ | <FIRST_VALUE>
+ | <FUSION>
+ | <GROUPING>
+ | <LAST_VALUE>
+ | <LN>
+ | <LOCALTIME>
+ | <LOCALTIMESTAMP>
+ | <LOWER>
+ | <MAX>
+ | <MIN>
+ | <MOD>
+ | <NULLIF>
+ | <OCTET_LENGTH>
+ | <PERCENT_RANK>
+ | <POWER>
+ | <RANK>
+ | <REGR_SXX>
+ | <REGR_SYY>
+ | <ROW_NUMBER>
+ | <SQRT>
+ | <STDDEV_POP>
+ | <STDDEV_SAMP>
+ | <SUM>
+ | <UPPER>
+ | <VAR_POP>
+ | <VAR_SAMP>
+ )
+ {
+ 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;
+ SqlParserPos pos;
+ SqlParserPos starPos;
+}
+{
+ <LBRACE_FN>
+ {
+ pos = getPos();
+ }
+ (
+ LOOKAHEAD(1)
+ call = TimestampAddFunctionCall() {
+ name = call.getOperator().getName();
+ args = new SqlNodeList(call.getOperandList(), getPos());
+ }
+ |
+ 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}
+ <INSERT> { 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> {starPos = getPos();} <RPAREN>
+ {
+ args = new SqlNodeList(starPos);
+ args.add(SqlIdentifier.star(starPos));
+ }
+ |
+ LOOKAHEAD(2) <LPAREN> <RPAREN> { args = new SqlNodeList(pos); }
+ |
+ args = ParenthesizedQueryOrCommaList(ExprContext.ACCEPT_SUB_QUERY)
+ )
+ )
+ <RBRACE> {
+ return new SqlJdbcFunctionCall(name).createCall(
+ pos.plus(getPos()), SqlParserUtil.toNodeArray(args));
+ }
+}
+
+/**
+ * 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 new ParseException(RESOURCE.minusNotAllowed().str());
+ }
+ }
+ )
+ (
+ <ALL> { return SqlStdOperatorTable.EXCEPT_ALL; }
+ | <DISTINCT> { return SqlStdOperatorTable.EXCEPT; }
+ | { return SqlStdOperatorTable.EXCEPT; }
+ )
+ )
+}
+
+/**
+ * Parses a binary multiset operator.
+ */
+SqlBinaryOperator BinaryMultisetOperator() :
+{
+ SqlBinaryOperator op;
+}
+{
+ /* If both the ALL or DISTINCT keywords are missing, DISTINCT is implicit */
+ (
+ <MULTISET>
+ (
+ <UNION> { op = SqlStdOperatorTable.MULTISET_UNION; }
+ [
+ <ALL> { op = SqlStdOperatorTable.MULTISET_UNION_ALL; }
+ | <DISTINCT> { op = SqlStdOperatorTable.MULTISET_UNION; }
+ ]
+ |
+ <INTERSECT> { op = SqlStdOperatorTable.MULTISET_INTERSECT; }
+ [
+ <ALL> { op = SqlStdOperatorTable.MULTISET_INTERSECT_ALL; }
+ | <DISTINCT> { op = SqlStdOperatorTable.MULTISET_INTERSECT; }
+ ]
+ |
+ <EXCEPT> { op = SqlStdOperatorTable.MULTISET_EXCEPT; }
+ [
+ <ALL> { op = SqlStdOperatorTable.MULTISET_EXCEPT_ALL; }
+ | <DISTINCT> { op = SqlStdOperatorTable.MULTISET_EXCEPT; }
+ ]
+ )
+ )
+ { return op; }
+}
+
+/**
+ * Parses a binary row operator like AND.
+ */
+SqlBinaryOperator BinaryRowOperator() :
+{
+ SqlBinaryOperator op;
+}
+{
+ <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 new ParseException(RESOURCE.bangEqualNotAllowed().str());
+ }
+ return SqlStdOperatorTable.NOT_EQUALS;
+ }
+ | <PLUS>
+ { return SqlStdOperatorTable.PLUS; }
+ | <MINUS>
+ { return SqlStdOperatorTable.MINUS; }
+ | <STAR>
+ { return SqlStdOperatorTable.MULTIPLY; }
+ | <SLASH>
+ { return SqlStdOperatorTable.DIVIDE; }
+ | <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; }
+ // <IN> is handled as a special case
+ | <MEMBER> <OF>
+ { return SqlStdOperatorTable.MEMBER_OF; }
+ | <SUBMULTISET> <OF>
+ { return SqlStdOperatorTable.SUBMULTISET_OF; }
+ | 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; }
+}
+
+/**
+ * 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; }
+ )
+ |
+ (
+ <NULL> { return SqlStdOperatorTable.IS_NULL; }
+ | <TRUE> { return SqlStdOperatorTable.IS_TRUE; }
+ | <FALSE> { return SqlStdOperatorTable.IS_FALSE; }
+ | <UNKNOWN> { return SqlStdOperatorTable.IS_UNKNOWN; }
+ )
+ )
+}
+
+
+/* KEYWORDS: anything in this list is a reserved word unless it appears
+ in the NonReservedKeyWord() production. */
+
+<DEFAULT, DQID, BTID> TOKEN :
+{
+ < A: "A" >
+ | < ABS: "ABS" >
+ | < ABSOLUTE: "ABSOLUTE" >
+ | < ACTION: "ACTION" >
+ | < ADA: "ADA" >
+ | < ADD: "ADD" >
+ | < ADMIN: "ADMIN" >
+ | < AFTER: "AFTER" >
+ | < ALL: "ALL" >
+ | < ALLOCATE: "ALLOCATE" >
+ | < ALLOW: "ALLOW" >
+ | < ALWAYS: "ALWAYS" >
+ | < ALTER: "ALTER" >
+ | < AND: "AND" >
+ | < ANY: "ANY" >
+ | < ARE: "ARE" >
+ | < ARRAY: "ARRAY" >
+ | < 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" >
+ | < 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" >
+ | < 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" >
+ | < 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" >
+ | < CONVERT: "CONVERT" >
+ | < CONTINUE: "CONTINUE" >
+ | < 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_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" >
+ | < DATETIME_INTERVAL_CODE: "DATETIME_INTERVAL_CODE" >
+ | < DATETIME_INTERVAL_PRECISION: "DATETIME_INTERVAL_PRECISION" >
+ | < DAY: "DAY" >
+ | < DEALLOCATE: "DEALLOCATE" >
+ | < DEC: "DEC" >
+ | < DECADE: "DECADE" >
+ | < DECIMAL: "DECIMAL" >
+ | < DECLARE: "DECLARE" >
+ | < DEFAULT_KW: "DEFAULT" >
+ | < DEFAULTS: "DEFAULTS" >
+ | < DEFERRABLE: "DEFERRABLE" >
+ | < DEFERRED: "DEFERRED" >
+ | < DEFINED: "DEFINED" >
+ | < DEFINER: "DEFINER" >
+ | < DEGREE: "DEGREE" >
+ | < DELETE: "DELETE" >
+ | < DENSE_RANK: "DENSE_RANK" >
+ | < DEPTH: "DEPTH" >
+ | < DEREF: "DEREF" >
+ | < DERIVED: "DERIVED" >
+ | < DESCRIBE: "DESCRIBE" >
+ | < DESC: "DESC" >
+ | < DESCRIPTION: "DESCRIPTION" >
+ | < DESCRIPTOR: "DESCRIPTOR" >
+ | < DETERMINISTIC: "DETERMINISTIC" >
+ | < DIAGNOSTICS: "DIAGNOSTICS" >
+ | < DISALLOW: "DISALLOW" >
+ | < DISCONNECT: "DISCONNECT" >
+ | < DISPATCH: "DISPATCH" >
+ | < DISTINCT: "DISTINCT" >
+ | < DOMAIN: "DOMAIN" >
+ | < 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" >
+ | < END: "END" >
+ | < END_EXEC: "END-EXEC" >
+ | < EPOCH: "EPOCH" >
+ | < EQUALS: "EQUALS" >
+ | < ESCAPE: "ESCAPE" >
+ | < EVERY: "EVERY" >
+ | < EXCEPT: "EXCEPT" >
+ | < EXCEPTION: "EXCEPTION" >
+ | < EXCLUDE: "EXCLUDE" >
+ | < EXCLUDING: "EXCLUDING" >
+ | < EXEC: "EXEC" >
+ | < EXECUTE: "EXECUTE" >
+ | < EXISTS: "EXISTS" >
+ | < EXP: "EXP" >
+ | < EXPLAIN: "EXPLAIN" >
+ | < EXTERNAL: "EXTERNAL" >
+ | < EXTEND: "EXTEND" >
+ | < EXTRACT: "EXTRACT" >
+ | < FALSE: "FALSE" >
+ | < FETCH: "FETCH" >
+ | < FILTER: "FILTER" >
+ | < FINAL: "FINAL" >
+ | < FIRST: "FIRST" >
+ | < FIRST_VALUE: "FIRST_VALUE">
+ | < FLOAT: "FLOAT" >
+ | < FLOOR: "FLOOR" >
+ | < FOLLOWING: "FOLLOWING" >
+ | < FOR: "FOR" >
+ | < FOREIGN: "FOREIGN" >
+ | < FORTRAN: "FORTRAN" >
+ | < FOUND: "FOUND" >
+ | < FRAC_SECOND: "FRAC_SECOND" >
+ | < FREE: "FREE" >
+ | < FROM: "FROM" >
+ | < FULL: "FULL" >
+ | < FUNCTION: "FUNCTION" >
+ | < FUSION: "FUSION" >
+ | < G: "G" >
+ | < GENERAL: "GENERAL" >
+ | < GENERATED: "GENERATED" >
+ | < GET: "GET" >
+ | < GLOBAL: "GLOBAL" >
+ | < GO: "GO" >
+ | < GOTO: "GOTO" >
+ | < GRANT: "GRANT" >
+ | < GRANTED: "GRANTED" >
+ | < GROUP: "GROUP" >
+ | < GROUPING: "GROUPING" >
+ | < HAVING: "HAVING" >
+ | < HIERARCHY: "HIERARCHY" >
+ | < HOLD: "HOLD" >
+ | < HOUR: "HOUR" >
+ | < IDENTITY: "IDENTITY" >
+ | < IMMEDIATE: "IMMEDIATE" >
+ | < IMPLEMENTATION: "IMPLEMENTATION" >
+ | < IMPORT: "IMPORT" >
+ | < IN: "IN" >
+ | < INDICATOR: "INDICATOR" >
+ | < INCLUDING: "INCLUDING" >
+ | < INCREMENT: "INCREMENT" >
+ | < INITIALLY: "INITIALLY" >
+ | < INNER: "INNER" >
+ | < INOUT: "INOUT" >
+ | < INPUT: "INPUT" >
+ | < INSENSITIVE: "INSENSITIVE" >
+ | < INSERT: "INSERT" >
+ | < INSTANCE: "INSTANCE" >
+ | < INSTANTIABLE: "INSTANTIABLE" >
+ | < INT: "INT" >
+ | < INTEGER: "INTEGER" >
+ | < INTERSECT: "INTERSECT" >
+ | < INTERSECTION: "INTERSECTION" >
+ | < INTERVAL: "INTERVAL" >
+ | < INTO: "INTO" >
+ | < INVOKER: "INVOKER" >
+ | < IS: "IS" >
+ | < ISOLATION: "ISOLATION" >
+ | < JAVA: "JAVA" >
+ | < JOIN: "JOIN" >
+ | < JSON: "JSON" >
+ | < K: "K" >
+ | < KEY: "KEY" >
+ | < KEY_MEMBER: "KEY_MEMBER" >
+ | < KEY_TYPE: "KEY_TYPE" >
+ | < LABEL: "LABEL" >
+ | < LANGUAGE: "LANGUAGE" >
+ | < LARGE: "LARGE" >
+ | < LAST: "LAST" >
+ | < LAST_VALUE: "LAST_VALUE" >
+ | < LATERAL: "LATERAL" >
+ | < LEADING: "LEADING" >
+ | < LEFT: "LEFT" >
+ | < LENGTH: "LENGTH" >
+ | < LEVEL: "LEVEL" >
+ | < LIBRARY: "LIBRARY" >
+ | < LIKE: "LIKE" >
+ | < LIMIT: "LIMIT" >
+ | < LN: "LN" >
+ | < LOCAL: "LOCAL" >
+ | < LOCALTIME: "LOCALTIME" >
+ | < LOCALTIMESTAMP: "LOCALTIMESTAMP" >
+ | < LOCATOR: "LOCATOR" >
+ | < LOWER: "LOWER" >
+ | < M: "M" >
+ | < MAP: "MAP" >
+ | < MATCH: "MATCH" >
+ | < MATCHED: "MATCHED" >
+ | < MAX: "MAX" >
+ | < MAXVALUE: "MAXVALUE" >
+ | < MEMBER: "MEMBER" >
+ | < MERGE: "MERGE" >
+ | < MESSAGE_LENGTH: "MESSAGE_LENGTH" >
+ | < MESSAGE_OCTET_LENGTH: "MESSAGE_OCTET_LENGTH" >
+ | < MESSAGE_TEXT: "MESSAGE_TEXT" >
+ | < METHOD: "METHOD" >
+ | < MICROSECOND: "MICROSECOND" >
+ | < MILLENNIUM: "MILLENNIUM" >
+ | < MIN: "MIN" >
+ | < MINUTE: "MINUTE" >
+ | < MINVALUE: "MINVALUE" >
+ | < MOD: "MOD" >
+ | < MODIFIES: "MODIFIES" >
+ | < MODULE: "MODULE" >
+ | < MONTH: "MONTH" >
+ | < MORE_KW: "MORE" >
+ | < MULTISET: "MULTISET" >
+ | < MUMPS: "MUMPS" >
+ | < NAME: "NAME" >
+ | < NAMES: "NAMES" >
+ | < NATIONAL: "NATIONAL" >
+ | < NATURAL: "NATURAL" >
+ | < NCHAR: "NCHAR" >
+ | < NCLOB: "NCLOB" >
+ | < NESTING: "NESTING" >
+ | < NEW: "NEW" >
+ | < NEXT: "NEXT" >
+ | < NO: "NO" >
+ | < NONE: "NONE" >
+ | < NORMALIZE: "NORMALIZE" >
+ | < NORMALIZED: "NORMALIZED" >
+ | < NOT: "NOT" >
+ | < NULL: "NULL" >
+ | < NULLABLE: "NULLABLE" >
+ | < NULLIF: "NULLIF" >
+ | < NULLS: "NULLS" >
+ | < NUMBER: "NUMBER" >
+ | < NUMERIC: "NUMERIC" >
+ | < OBJECT: "OBJECT" >
+ | < OCTET_LENGTH: "OCTET_LENGTH" >
+ | < OCTETS: "OCTETS" >
+ | < OF: "OF" >
+ | < OFFSET: "OFFSET" >
+ | < OLD: "OLD" >
+ | < ON: "ON" >
+ | < ONLY: "ONLY" >
+ | < OPEN: "OPEN" >
+ | < OPTION: "OPTION" >
+ | < OPTIONS: "OPTIONS" >
+ | < OR: "OR" >
+ | < ORDER: "ORDER" >
+ | < ORDERING: "ORDERING" >
+ | < 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" >
+ | < PASSTHROUGH: "PASSTHROUGH" >
+ | < PATH: "PATH" >
+ | < PERCENT_RANK: "PERCENT_RANK" >
+ | < PERCENTILE_CONT: "PERCENTILE_CONT" >
+ | < PERCENTILE_DISC: "PERCENTILE_DISC" >
+ | < PLACING: "PLACING" >
+ | < PLAN: "PLAN" >
+ | < PLI: "PLI" >
+ | < POSITION: "POSITION" >
+ | < POWER: "POWER" >
+ | < PRECEDING: "PRECEDING" >
+ | < PRECISION: "PRECISION" >
+ | < PREPARE: "PREPARE" >
+ | < PRESERVE: "PRESERVE" >
+ | < PRIMARY: "PRIMARY" >
+ | < PRIOR: "PRIOR" >
+ | < PRIVILEGES: "PRIVILEGES" >
+ | < PROCEDURE: "PROCEDURE" >
+ | < PUBLIC: "PUBLIC" >
+ | < QUARTER: "QUARTER" >
+ | < 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" >
+ | < 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" >
+ | < RETURNS: "RETURNS" >
+ | < REVOKE: "REVOKE" >
+ | < RIGHT: "RIGHT" >
+ | < 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" >
+ | < SAVEPOINT: "SAVEPOINT" >
+ | < 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" >
+ | < SECTION: "SECTION" >
+ | < SECURITY: "SECURITY" >
+ | < SELECT: "SELECT" >
+ | < SELF: "SELF" >
+ | < SENSITIVE: "SENSITIVE" >
+ | < SEQUENCE: "SEQUENCE" >
+ | < SERIALIZABLE: "SERIALIZABLE" >
+ | < SERVER: "SERVER" >
+ | < SERVER_NAME: "SERVER_NAME" >
+ | < SESSION: "SESSION" >
+ | < SESSION_USER: "SESSION_USER" >
+ | < SET: "SET" >
+ | < SETS: "SETS" >
+ | < SET_MINUS: "MINUS">
+ | < SIMILAR: "SIMILAR" >
+ | < SIMPLE: "SIMPLE" >
+ | < SIZE: "SIZE" >
+ | < 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" >
+ | < STRUCTURE: "STRUCTURE" >
+ | < STYLE: "STYLE" >
+ | < SUBCLASS_ORIGIN: "SUBCLASS_ORIGIN" >
+ | < SUBMULTISET: "SUBMULTISET" >
+ | < SUBSTRING: "SUBSTRING" >
+ | < SUBSTITUTE: "SUBSTITUTE" >
+ | < SUM: "SUM" >
+ | < SYMMETRIC: "SYMMETRIC" >
+ | < SYSTEM: "SYSTEM" >
+ | < SYSTEM_USER: "SYSTEM_USER" >
+ | < TABLE: "TABLE" >
+ | < TABLE_NAME: "TABLE_NAME" >
+ | < TABLESAMPLE: "TABLESAMPLE" >
+ | < TEMPORARY: "TEMPORARY" >
+ | < THEN: "THEN" >
+ | < TIES: "TIES" >
+ | < TIME: "TIME" >
+ | < TIMESTAMP: "TIMESTAMP" >
+ | < TIMESTAMPADD: "TIMESTAMPADD" >
+ | < TIMESTAMPDIFF: "TIMESTAMPDIFF" >
+ | < 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" >
+ | < TRANSLATION: "TRANSLATION" >
+ | < TREAT: "TREAT" >
+ | < TRIGGER: "TRIGGER" >
+ | < TRIGGER_CATALOG: "TRIGGER_CATALOG" >
+ | < TRIGGER_NAME: "TRIGGER_NAME" >
+ | < TRIGGER_SCHEMA: "TRIGGER_SCHEMA" >
+ | < TRIM: "TRIM" >
+ | < TRUE: "TRUE" >
+ | < TYPE: "TYPE" >
+ | < UESCAPE: "UESCAPE" >
+ | < UNBOUNDED: "UNBOUNDED" >
+ | < UNCOMMITTED: "UNCOMMITTED" >
+ | < UNDER: "UNDER" >
+ | < UNION: "UNION" >
+ | < UNIQUE: "UNIQUE" >
+ | < UNKNOWN: "UNKNOWN" >
+ | < UNNAMED: "UNNAMED" >
+ | < UNNEST: "UNNEST" >
+ | < UPDATE: "UPDATE" >
+ | < 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" >
+ | < VALUE: "VALUE" >
+ | < VALUES: "VALUES" >
+ | < VAR_POP: "VAR_POP" >
+ | < VAR_SAMP: "VAR_SAMP" >
+ | < VARCHAR: "VARCHAR" >
+ | < VARBINARY: "VARBINARY" >
+ | < VARYING: "VARYING" >
+ | < VERSION: "VERSION" >
+ | < VIEW: "VIEW" >
+ | < WEEK: "WEEK" >
+ | < 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" >
+ | < ZONE: "ZONE" >
+ | < APPLY: "APPLY" >
+ | < LOCATION: "LOCATION" >
+ | < INPUTFORMAT: "INPUTFORMAT" >
+ | < OUTPUTFORMAT: "OUTPUTFORMAT" >
+ | < PARALLELISM: "PARALLELISM" >
+ | < STORED: "STORED" >
+ | < TBLPROPERTIES: "TBLPROPERTIES" >
+ | < JAR: "JAR" >
+}
+
+/*
+ * Abstract production:
+ *
+ * String NonReservedKeyWord()
+ *
+ * Parses non-reserved keywords (e.g. keywords that may be used as
+ * identifiers). Should use CommonNonReservedKeyWord as a base, but
+ * may add other key words.
+ */
+
+/**
+ * Parses a non-reserved keyword for use as an identifier. Specializations
+ * of this parser can use this as a base for implementing the
+ * NonReservedKeyWord() production.
+ *
+ * <p>When adding keywords to this list, be sure that they are not reserved
+ * by the SQL:2003 standard (see productions for "non-reserved word"
+ * and "reserved word" in reference below).
+ *
+ * @sql.2003 Part 2 Section 5.2
+ */
+String CommonNonReservedKeyWord() :
+{
+}
+{
+ (
+ <A>
+ | <ABSOLUTE>
+ | <ACTION>
+ | <ADA>
+ | <ADD>
+ | <ADMIN>
+ | <AFTER>
+ | <ALWAYS>
+ | <APPLY>
+ | <ASC>
+ | <ASSERTION>
+ | <ASSIGNMENT>
+ | <ATTRIBUTE>
+ | <ATTRIBUTES>
+ | <BEFORE>
+ | <BERNOULLI>
+ | <BREADTH>
+ | <C>
+ | <CASCADE>
+ | <CATALOG>
+ | <CATALOG_NAME>
+ | <CENTURY>
+ | <CHAIN>
+ | <CHARACTER_SET_CATALOG>
+ | <CHARACTER_SET_NAME>
+ | <CHARACTER_SET_SCHEMA>
+ | <CHARACTERISTICS>
+ | <CHARACTERS>
+ | <CLASS_ORIGIN>
+ | <COBOL>
+ | <COLLATION>
+ | <COLLATION_CATALOG>
+ | <COLLATION_NAME>
+ | <COLLATION_SCHEMA>
+ | <COLUMN_NAME>
+ | <COMMAND_FUNCTION>
+ | <COMMAND_FUNCTION_CODE>
+ | <COMMITTED>
+ | <CONDITION_NUMBER>
+ | <CONNECTION>
+ | <CONNECTION_NAME>
+ | <CONSTRAINT_CATALOG>
+ | <CONSTRAINT_NAME>
+ | <CONSTRAINT_SCHEMA>
+ | <CONSTRAINTS>
+ | <CONSTRUCTOR>
+ | <CONTAINS>
+ | <CONTINUE>
+ | <CURSOR_NAME>
+ | <DATA>
+ | <DATABASE>
+ | <DATETIME_INTERVAL_CODE>
+ | <DATETIME_INTERVAL_PRECISION>
+ | <DECADE>
+ | <DEFAULTS>
+ | <DEFERRABLE>
+ | <DEFERRED>
+ | <DEFINED>
+ | <DEFINER>
+ | <DEGREE>
+ | <DEPTH>
+ | <DERIVED>
+ | <DESC>
+ | <DESCRIPTION>
+ | <DESCRIPTOR>
+ | <DIAGNOSTICS>
+ | <DISPATCH>
+ | <DOMAIN>
+ | <DOW>
+ | <DOY>
+ | <DYNAMIC_FUNCTION>
+ | <DYNAMIC_FUNCTION_CODE>
+ | <EPOCH>
+ | <EQUALS>
+ | <EXCEPTION>
+ | <EXCLUDE>
+ | <EXCLUDING>
+ | <FINAL>
+ | <FIRST>
+ | <FOLLOWING>
+ | <FORTRAN>
+ | <FOUND>
+ | <FRAC_SECOND>
+ | <G>
+ | <GENERAL>
+ | <GENERATED>
+ | <GO>
+ | <GOTO>
+ | <GRANTED>
+ | <HIERARCHY>
+ | <IMMEDIATE>
+ | <IMPLEMENTATION>
+ | <INCLUDING>
+ | <INCREMENT>
+ | <INITIALLY>
+ | <INPUT>
+ | <INSTANCE>
+ | <INSTANTIABLE>
+ | <INVOKER>
+ | <ISOLATION>
+ | <JAVA>
+ | <JSON>
+ | <K>
+ | <KEY>
+ | <KEY_MEMBER>
+ | <KEY_TYPE>
+ | <LABEL>
+ | <LAST>
+ | <LENGTH>
+ | <LEVEL>
+ | <LIBRARY>
+ | <LOCATOR>
+ | <M>
+ | <MAP>
+ | <MATCHED>
+ | <MAXVALUE>
+ | <MICROSECOND>
+ | <MESSAGE_LENGTH>
+ | <MESSAGE_OCTET_LENGTH>
+ | <MESSAGE_TEXT>
+ | <MILLENNIUM>
+ | <MINVALUE>
+ | <MORE_KW>
+ | <MUMPS>
+ | <NAME>
+ | <NAMES>
+ | <NESTING>
+ | <NORMALIZED>
+ | <NULLABLE>
+ | <NULLS>
+ | <NUMBER>
+ | <OBJECT>
+ | <OCTETS>
+ | <OPTION>
+ | <OPTIONS>
+ | <ORDERING>
+ | <ORDINALITY>
+ | <OTHERS>
+ | <OUTPUT>
+ | <OVERRIDING>
+ | <PAD>
+ | <PARAMETER_MODE>
+ | <PARAMETER_NAME>
+ | <PARAMETER_ORDINAL_POSITION>
+ | <PARAMETER_SPECIFIC_CATALOG>
+ | <PARAMETER_SPECIFIC_NAME>
+ | <PARAMETER_SPECIFIC_SCHEMA>
+ | <PARTIAL>
+ | <PASCAL>
+ | <PASSTHROUGH>
+ | <PATH>
+ | <PLACING>
+ | <PLAN>
+ | <PLI>
+ | <PRECEDING>
+ | <PRESERVE>
+ | <PRIOR>
+ | <PRIVILEGES>
+ | <PUBLIC>
+ | <QUARTER>
+ | <READ>
+ | <RELATIVE>
+ | <REPEATABLE>
+ | <REPLACE>
+ | <RESTART>
+ | <RESTRICT>
+ | <RETURNED_CARDINALITY>
+ | <RETURNED_LENGTH>
+ | <RETURNED_OCTET_LENGTH>
+ | <RETURNED_SQLSTATE>
+ | <ROLE>
+ | <ROUTINE>
+ | <ROUTINE_CATALOG>
+ | <ROUTINE_NAME>
+ | <ROUTINE_SCHEMA>
+ | <ROW_COUNT>
+ | <SCALE>
+ | <SCHEMA>
+ | <SCHEMA_NAME>
+ | <SCOPE_CATALOGS>
+ | <SCOPE_NAME>
+ | <SCOPE_SCHEMA>
+ | <SECTION>
+ | <SECURITY>
+ | <SELF>
+ | <SEQUENCE>
+ | <SERIALIZABLE>
+ | <SERVER>
+ | <SERVER_NAME>
+ | <SESSION>
+ | <SETS>
+ | <SIMPLE>
+ | <SIZE>
+ | <SOURCE>
+ | <SPACE>
+ | <SPECIFIC_NAME>
+ | <SQL_BIGINT>
+ | <SQL_BINARY>
+ | <SQL_BIT>
+ | <SQL_BLOB>
+ | <SQL_BOOLEAN>
+ | <SQL_CHAR>
+ | <SQL_CLOB>
+ | <SQL_DATE>
+ | <SQL_DECIMAL>
+ | <SQL_DOUBLE>
+ | <SQL_FLOAT>
+ | <SQL_INTEGER>
+ | <SQL_INTERVAL_DAY>
+ | <SQL_INTERVAL_DAY_TO_HOUR>
+ | <SQL_INTERVAL_DAY_TO_MINUTE>
+ | <SQL_INTERVAL_DAY_TO_SECOND>
+ | <SQL_INTERVAL_HOUR>
+ | <SQL_INTERVAL_HOUR_TO_MINUTE>
+ | <SQL_INTERVAL_HOUR_TO_SECOND>
+ | <SQL_INTERVAL_MINUTE>
+ | <SQL_INTERVAL_MINUTE_TO_SECOND>
+ | <SQL_INTERVAL_MONTH>
+ | <SQL_INTERVAL_SECOND>
+ | <SQL_INTERVAL_YEAR>
+ | <SQL_INTERVAL_YEAR_TO_MONTH>
+ | <SQL_LONGVARBINARY>
+ | <SQL_LONGVARNCHAR>
+ | <SQL_LONGVARCHAR>
+ | <SQL_NCHAR>
+ | <SQL_NCLOB>
+ | <SQL_NUMERIC>
+ | <SQL_NVARCHAR>
+ | <SQL_REAL>
+ | <SQL_SMALLINT>
+ | <SQL_TIME>
+ | <SQL_TIMESTAMP>
+ | <SQL_TINYINT>
+ | <SQL_TSI_DAY>
+ | <SQL_TSI_FRAC_SECOND>
+ | <SQL_TSI_HOUR>
+ | <SQL_TSI_MICROSECOND>
+ | <SQL_TSI_MINUTE>
+ | <SQL_TSI_MONTH>
+ | <SQL_TSI_QUARTER>
+ | <SQL_TSI_SECOND>
+ | <SQL_TSI_WEEK>
+ | <SQL_TSI_YEAR>
+ | <SQL_VARBINARY>
+ | <SQL_VARCHAR>
+ | <STATE>
+ | <STATEMENT>
+ | <STRUCTURE>
+ | <STYLE>
+ | <SUBCLASS_ORIGIN>
+ | <SUBSTITUTE>
+ | <TABLE_NAME>
+ | <TEMPORARY>
+ | <TIES>
+ | <TIMESTAMPADD>
+ | <TIMESTAMPDIFF>
+ | <TOP_LEVEL_COUNT>
+ | <TRANSACTION>
+ | <TRANSACTIONS_ACTIVE>
+ | <TRANSACTIONS_COMMITTED>
+ | <TRANSACTIONS_ROLLED_BACK>
+ | <TRANSFORM>
+ | <TRANSFORMS>
+ | <TRIGGER_CATALOG>
+ | <TRIGGER_NAME>
+ | <TRIGGER_SCHEMA>
+ | <TYPE>
+ | <UNBOUNDED>
+ | <UNCOMMITTED>
+ | <UNDER>
+ | <UNNAMED>
+ | <USAGE>
+ | <USER_DEFINED_TYPE_CATALOG>
+ | <USER_DEFINED_TYPE_CODE>
+ | <USER_DEFINED_TYPE_NAME>
+ | <USER_DEFINED_TYPE_SCHEMA>
+ | <VERSION>
+ | <VIEW>
+ | <WEEK>
+ | <WRAPPER>
+ | <WORK>
+ | <WRITE>
+ | <XML>
+ | <ZONE>
+ )
+ {
+ return unquotedIdentifier();
+ }
+}
+
+/* LITERALS */
+
+<DEFAULT, DQID, BTID> 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> >
+ |
+ < QUOTED_STRING: <QUOTE> ( (~["'"]) | ("''"))* <QUOTE> >
+ |
+ < PREFIXED_STRING_LITERAL: ("_" <CHARSETNAME> | "N") <QUOTED_STRING> >
+ |
+ < UNICODE_STRING_LITERAL: "U" "&" <QUOTED_STRING> >
+ |
+ < #CHARSETNAME: (["a"-"z","A"-"Z","0"-"9"])
+ (["a"-"z","A"-"Z","0"-"9",":",".","-","_"])*
+ >
+}
+
+<DEFAULT, DQID, BTID> TOKEN :
+{
+ < UNICODE_QUOTED_ESCAPE_CHAR:
+ <QUOTE>
+ (~["0"-"9","a"-"f","A"-"F","+","\""," ","\t","\n","\r","\f"])
+ <QUOTE>
+ >
+}
+
+/* SEPARATORS */
+
+<DEFAULT, DQID, BTID> TOKEN :
+{
+ < LPAREN: "(">
+ | < RPAREN: ")">
+ | < LBRACE_D: "{" (" ")* ["d","D"] >
+ | < LBRACE_T: "{" (" ")* ["t","T"] >
+ | < LBRACE_TS: "{" (" ")* ["t","T"] ["s","S"] >
+ | < LBRACE_FN: "{" (" ")* ["f","F"] ["n","N"] >
+ | < LBRACE: "{" >
+ | < RBRACE: "}" >
+ | < LBRACKET: "[" >
+ | < RBRACKET: "]" >
+ | < SEMICOLON: ";" >
+ | < DOT: "." >
+ | < COMMA: "," >
+}
+
+/* OPERATORS */
+
+<DEFAULT, DQID, BTID> TOKEN :
+{
+ < EQ: "=" >
+ | < GT: ">" >
+ | < LT: "<" >
+ | < HOOK: "?" >
+ | < COLON: ":" >
+ | < LE: "<=" >
+ | < GE: ">=" >
+ | < NE: "<>" >
+ | < NE2: "!=" >
+ | < PLUS: "+" >
+ | < MINUS: "-" >
+ | < STAR: "*" >
+ | < SLASH: "/" >
+ | < CONCAT: "||" >
+ | < NAMED_ARGUMENT_ASSIGNMENT: "=>" >
+ | < DOUBLE_PERIOD: ".." >
+ | < QUOTE: "'" >
+ | < DOUBLE_QUOTE: "\"" >
+}
+
+
+/*****************************************
+ * Lexical Descriptions *
+ *****************************************/
+
+TOKEN_MGR_DECLS : {
+ List<Integer> lexicalStateStack = new ArrayList<Integer>();
+
+ void pushState() {
+ lexicalStateStack.add(curLexState);
+ }
+
+ void popState() {
+ SwitchTo(lexicalStateStack.remove(lexicalStateStack.size() - 1));
+ }
+
+}
+
+/*
+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, e.g. `My Identifier`
+IN_SINGLE_LINE_COMMENT:
+IN_FORMAL_COMMENT:
+IN_MULTI_LINE_COMMENT:
+
+DEFAULT, DQID, BTID are the 3 'normal states'. Behavior is identical except
+for how quoted identifiers are recognized.
+
+After a comment has completed, the lexer returns to the previous state, one
+of the 'normal states'.
+*/
+
+/* WHITE SPACE */
+
+<DEFAULT, DQID, BTID> SKIP :
+{
+ " "
+ | "\t"
+ | "\n"
+ | "\r"
+ | "\f"
+}
+
+/* COMMENTS */
+
+<DEFAULT, DQID, BTID> MORE :
+{
+ <"/**" ~["/"]> { pushState(); } : IN_FORMAL_COMMENT
+}
+
+<DEFAULT, DQID, BTID> MORE :
+{
+ "/*" { pushState(); } : IN_MULTI_LINE_COMMENT
+}
+
+<DEFAULT, DQID, BTID> SKIP :
+{
+ <SINGLE_LINE_COMMENT: ("//"|"--")(~["\n","\r"])* ("\n"|"\r"|"\r\n")? >
+}
+
+<IN_FORMAL_COMMENT>
+SPECIAL_TOKEN :
+{
+ <FORMAL_COMMENT: "*/" > { popState(); }
+}
+
+<IN_MULTI_LINE_COMMENT>
+SPECIAL_TOKEN :
+{
+ <MULTI_LINE_COMMENT: "*/" > { 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"])
+ | ("``")
+ )+
+ "`"
+ >
+}
+
+<DEFAULT, DQID, BTID> TOKEN :
+{
+ < COLLATION_ID:
+ (<LETTER>|<DIGIT>)+ (<LETTER>|<DIGIT>|":"|"."|"-"|"_")*
+ "$"
+ (<LETTER>|"_")+
+ ("$" (<LETTER>|<DIGIT>|"_")+)?
+ >
+ |
+ < IDENTIFIER: <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> 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>
+ )
+}
diff --git a/third_party/java/BUILD b/third_party/java/BUILD
index ba59451..1471844 100644
--- a/third_party/java/BUILD
+++ b/third_party/java/BUILD
@@ -2,6 +2,11 @@
package(default_visibility = ["//visibility:public"])
+filegroup(
+ name = "javacc",
+ srcs = ["@javacc//:javacc"],
+)
+
java_library(
name = "aws-java-sdk",
srcs = [ "Empty.java" ],
diff --git a/third_party/java/javacc/javacc.BUILD b/third_party/java/javacc/javacc.BUILD
new file mode 100644
index 0000000..036aad7
--- /dev/null
+++ b/third_party/java/javacc/javacc.BUILD
@@ -0,0 +1,10 @@
+licenses(["notice"])
+
+package(default_visibility = ["//visibility:public"])
+
+filegroup(
+ name = "javacc",
+ srcs = [
+ "bin/javacc",
+ ],
+)