You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by el...@apache.org on 2017/04/01 20:36:04 UTC
[12/51] [partial] calcite-avatica git commit: [CALCITE-1717] Remove
Calcite code and lift avatica
http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/core/src/main/codegen/templates/Parser.jj
----------------------------------------------------------------------
diff --git a/core/src/main/codegen/templates/Parser.jj b/core/src/main/codegen/templates/Parser.jj
deleted file mode 100644
index c30794d..0000000
--- a/core/src/main/codegen/templates/Parser.jj
+++ /dev/null
@@ -1,6623 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-<@pp.dropOutputFile />
-
-<@pp.changeOutputFile name="javacc/Parser.jj" />
-
-options {
- STATIC = false;
- IGNORE_CASE = true;
- UNICODE_INPUT = true;
-}
-
-
-PARSER_BEGIN(${parser.class})
-
-package ${parser.package};
-
-<#list parser.imports as importStr>
-import ${importStr};
-</#list>
-
-
-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.SqlMatchRecognize;
-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.Glossary;
-import org.apache.calcite.util.NlsString;
-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 java.util.Locale;
-
-import static org.apache.calcite.util.Static.RESOURCE;
-
-/**
- * SQL parser, generated from Parser.jj by JavaCC.
- *
- * <p>The public wrapper for this parser is {@link SqlParser}.
- */
-public class ${parser.class} extends SqlAbstractParserImpl
-{
- private static final Logger LOGGER = CalciteTrace.getParserTracer();
-
- // Can't use quoted literal because of a bug in how JavaCC translates
- // backslash-backslash.
- private static final char BACKSLASH = 0x5c;
- private static final char DOUBLE_QUOTE = 0x22;
- private static final String DQ = DOUBLE_QUOTE + "";
- private static final String DQDQ = DQ + DQ;
-
- private static 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 ${parser.class}(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 (${parser.class}.class) {
- if (metadata == null) {
- metadata = new MetadataImpl(
- new ${parser.class}(new java.io.StringReader("")));
- }
- return metadata;
- }
- }
-
- public void setTabSize(int tabSize)
- {
- jj_input_stream.setTabSize(tabSize);
- }
-
- public void switchTo(String stateName)
- {
- int state = Arrays.asList(${parser.class}TokenManager.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(${parser.class})
-
-
-/***************************************
- * Utility Codes for Semantic Analysis *
- ***************************************/
-
-/* For Debug */
-JAVACODE
-void debug_message1() {
- LOGGER.info("{} , {}", getToken(0).image, getToken(1).image);
-}
-
-JAVACODE String unquotedIdentifier() {
- return SqlParserUtil.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;
- }
-}
-
-/*
-// 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()
- |
-<#if parser.createStatementParserMethods?size != 0>
- stmt = SqlCreate()
- |
-</#if>
- stmt = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY)
- |
- stmt = SqlExplain()
- |
- stmt = SqlDescribe()
- |
- stmt = SqlInsert()
- |
- stmt = SqlDelete()
- |
- stmt = SqlUpdate()
- |
- stmt = SqlMerge()
- |
- stmt = SqlProcedureCall()
-
- <#-- Add methods to parse additional statements here -->
- <#list parser.statementParserMethods as method>
- |
- stmt = ${method}
- </#list>
- )
- {
- return stmt;
- }
-}
-
-/**
- * Parses an SQL statement followed by the end-of-file symbol.
- */
-SqlNode SqlStmtEof() :
-{
- SqlNode stmt;
-}
-{
- stmt = SqlStmt() <EOF>
- {
- return stmt;
- }
-}
-
-<#-- Add implementations of additional parser statement calls here -->
-<#list parser.implementationFiles as file>
- <#include "/@includes/"+file />
-</#list>
-
-/**
- * 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();
- SqlNode table;
- SqlNodeList extendList = null;
- SqlNode source;
- SqlNodeList columnList = null;
- SqlParserPos pos;
-}
-{
- (
- <INSERT>
- |
- <UPSERT> { keywords.add(SqlInsertKeyword.UPSERT.symbol(getPos())); }
- )
- SqlInsertKeywords(keywords)
- <INTO> table = CompoundIdentifier()
- [
- LOOKAHEAD(3)
- [ <EXTEND> ]
- extendList = ExtendList() {
- table = extend(table, extendList);
- }
- ]
- {
- 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);
- }
- }
- [
- over = MatchRecognizeOpt(tableRef)
- {
- if (over != null) {
- 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);
- }
- }
- (
- [ over = MatchRecognizeOpt(tableRef) ]
- {
- if (over != null) {
- tableRef = over;
- }
- }
- )
- |
- <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 =
- ((NlsString) SqlLiteral.value(sample)).getValue();
- 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;
- boolean nullable = true;
-}
-{
- name = SimpleIdentifier()
- type = DataType()
- [
- <NOT> <NULL> {
- nullable = false;
- }
- ]
- {
- list.add(name);
- list.add(type.withNullable(nullable));
- }
-}
-
-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;
- }
-}
-
-/**
- * Parses a MATCH_RECOGNIZE clause following a table expression.
- */
-SqlMatchRecognize MatchRecognizeOpt(SqlNode tableRef) :
-{
- final SqlParserPos startPos;
- SqlParserPos pos;
- SqlNode pattern;
- SqlNodeList patternDefList;
- SqlLiteral isStrictStarts = SqlLiteral.createBoolean(false, getPos());
- SqlLiteral isStrictEnds = SqlLiteral.createBoolean(false, getPos());
-}
-{
- <MATCH_RECOGNIZE> { startPos = getPos(); } <LPAREN>
- <PATTERN>
- <LPAREN>
- (
- <CARET> { isStrictStarts = SqlLiteral.createBoolean(true, getPos()); }
- |
- { isStrictStarts = SqlLiteral.createBoolean(false, getPos()); }
- )
- pattern = PatternExpression()
- (
- <DOLLAR> { isStrictEnds = SqlLiteral.createBoolean(true, getPos()); }
- |
- { isStrictEnds = SqlLiteral.createBoolean(false, getPos()); }
- )
- <RPAREN>
- <DEFINE> { pos = getPos(); }
- patternDefList = PatternDefinitionCommaList(pos)
- <RPAREN> {
- return new SqlMatchRecognize(startPos.plus(getPos()), tableRef,
- pattern, isStrictStarts, isStrictEnds, patternDefList);
- }
-}
-
-SqlNode PatternExpression() :
-{
- SqlNode left;
- SqlNode right;
-}
-{
- left = PatternTerm()
- (
- <VERTICAL_BAR>
- right = PatternTerm() {
- left = SqlStdOperatorTable.PATTERN_ALTER.createCall(
- left.getParserPosition().plus(getPos()), left, right);
- }
- )*
- {
- return left;
- }
-}
-
-SqlNode PatternTerm() :
-{
- SqlNode left;
- SqlNode right;
-}
-{
- left = PatternFactor()
- (
- right = PatternFactor() {
- left = SqlStdOperatorTable.PATTERN_CONCAT.createCall(
- left.getParserPosition().plus(getPos()), left, right);
- }
- )*
- {
- return left;
- }
-}
-
-SqlNode PatternFactor() :
-{
- SqlNode e;
- SqlNode extra;
- SqlLiteral startNum = null;
- SqlLiteral endNum = null;
- SqlLiteral reluctant = SqlLiteral.createBoolean(false, SqlParserPos.ZERO);
-}
-{
- e = PatternPrimary()
- [
- (
- <STAR> {
- startNum = SqlLiteral.createExactNumeric("0", SqlParserPos.ZERO);
- endNum = SqlLiteral.createExactNumeric("-1", SqlParserPos.ZERO);
- }
- |
- <PLUS> {
- startNum = SqlLiteral.createExactNumeric("1", SqlParserPos.ZERO);
- endNum = SqlLiteral.createExactNumeric("-1", SqlParserPos.ZERO);
- }
- |
- <HOOK> {
- startNum = SqlLiteral.createExactNumeric("0", SqlParserPos.ZERO);
- endNum = SqlLiteral.createExactNumeric("1", SqlParserPos.ZERO);
- }
- |
- <LBRACE>
- (
- startNum = UnsignedNumericLiteral() { endNum = startNum; }
- [
- <COMMA> {
- endNum = SqlLiteral.createExactNumeric("-1", SqlParserPos.ZERO);
- }
- [
- endNum = UnsignedNumericLiteral()
- ]
- ]
- <RBRACE>
- |
- {
- startNum = SqlLiteral.createExactNumeric("-1", SqlParserPos.ZERO);
- }
- <COMMA>
- endNum = UnsignedNumericLiteral()
- <RBRACE>
- |
- <MINUS> extra = PatternExpression() <MINUS> <RBRACE> {
- extra = SqlStdOperatorTable.PATTERN_EXCLUDE.createCall(
- extra.getParserPosition().plus(getPos()), extra);
- e = SqlStdOperatorTable.PATTERN_CONCAT.createCall(
- e.getParserPosition().plus(getPos()), e, extra);
- return e;
- }
- )
- )
- [
- <HOOK>
- {
- if (startNum.intValue(true) != endNum.intValue(true)) {
- reluctant = SqlLiteral.createBoolean(true, SqlParserPos.ZERO);
- }
- }
- ]
- ]
- {
- if (startNum == null) {
- return e;
- } else {
- return SqlStdOperatorTable.PATTERN_QUANTIFIER.createCall(
- e.getParserPosition().plus(getPos()),
- e, startNum, endNum, reluctant);
- }
- }
-}
-
-SqlNode PatternPrimary() :
-{
- SqlParserPos pos;
- SqlNode e;
- List<SqlNode> eList;
-}
-{
- (
- e = SimpleIdentifier()
- |
- <LPAREN> e = PatternExpression() <RPAREN>
- |
- <LBRACE> { pos = getPos(); }
- <MINUS> e = PatternExpression()
- <MINUS> <RBRACE> {
- e = SqlStdOperatorTable.PATTERN_EXCLUDE.createCall(
- pos.plus(getPos()), e);
- }
- |
- (
- <PERMUTE> { pos = getPos(); }
- <LPAREN>
- e = PatternExpression() {
- eList = new ArrayList<SqlNode>();
- eList.add(e);
- }
- (
- <COMMA>
- e = PatternExpression()
- {
- eList.add(e);
- }
- )*
- <RPAREN> {
- e = SqlStdOperatorTable.PATTERN_PERMUTE.createCall(
- pos.plus(getPos()), eList);
- }
- )
- )
- {
- return e;
- }
-}
-
-SqlNodeList PatternDefinitionCommaList(SqlParserPos pos) :
-{
- SqlNode e;
- final List<SqlNode> eList = new ArrayList<SqlNode>();
-}
-{
- e = PatternDefinition() {
- if (pos == null) {
- pos = e.getParserPosition();
- }
- eList.add(e);
- }
- (
- <COMMA>
- e = PatternDefinition() {
- eList.add(e);
- }
- )*
- {
- return new SqlNodeList(eList, pos.plus(getPos()));
- }
-}
-
-SqlNode PatternDefinition() :
-{
- SqlNode var;
- SqlNode e;
-}
-{
- var = SimpleIdentifier()
- <AS>
- e = Expression(ExprContext.ACCEPT_SUB_QUERY) {
- return SqlStdOperatorTable.AS.createCall(
- var.getParserPosition().plus(getPos()), e, var);
- }
-}
-
-// ----------------------------------------------------------------------------
-// Expressions
-
-/**
- * Parses a SQL expression (such as might occur in a WHERE clause) followed by
- * the end-of-file symbol.
- */
-SqlNode SqlExpressionEof() :
-{
- SqlNode e;
-}
-{
- e = Expression(ExprContext.ACCEPT_SUB_QUERY) (<EOF>)
- {
- return e;
- }
-}
-
-/**
- * Parses either a row expression or a query expression without ORDER BY.
- */
-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(
<TRUNCATED>