| |
| 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> |
| ) |
| } |