blob: a9bb686b3e31e8bf945d9f315787e3c0cced7088 [file] [log] [blame]
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 &lt;NAME&gt; = VALUE" or "RESET &lt;NAME&gt;", without a leading
* "ALTER &lt;SCOPE&gt;".
*/
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>
)
}