Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
The public wrapper for this parser is {@link SqlParser}.
*/
public class HazelcastSqlParser extends SqlAbstractParserImpl
{
private static final Logger LOGGER = CalciteTrace.getParserTracer();
// Can't use quoted literal because of a bug in how JavaCC translates
// backslash-backslash.
private static final char BACKSLASH = 0x5c;
private static final char DOUBLE_QUOTE = 0x22;
private static final String DQ = DOUBLE_QUOTE + "";
private static final String DQDQ = DQ + DQ;
private static final SqlLiteral LITERAL_ZERO =
SqlLiteral.createExactNumeric("0", SqlParserPos.ZERO);
private static final SqlLiteral LITERAL_ONE =
SqlLiteral.createExactNumeric("1", SqlParserPos.ZERO);
private static final SqlLiteral LITERAL_MINUS_ONE =
SqlLiteral.createExactNumeric("-1", SqlParserPos.ZERO);
private static Metadata metadata;
private Casing unquotedCasing;
private Casing quotedCasing;
private int identifierMaxLength;
private SqlConformance conformance;
/**
* {@link SqlParserImplFactory} implementation for creating parser.
*/
public static final SqlParserImplFactory FACTORY = new SqlParserImplFactory() {
public SqlAbstractParserImpl getParser(Reader reader) {
final HazelcastSqlParser parser = new HazelcastSqlParser(reader);
if (reader instanceof SourceStringReader) {
final String sql =
((SourceStringReader) reader).getSourceString();
parser.setOriginalSql(sql);
}
return parser;
}
};
public SqlParseException normalizeException(Throwable ex) {
try {
if (ex instanceof ParseException) {
ex = cleanupParseException((ParseException) ex);
}
return convertException(ex);
} catch (ParseException e) {
throw new AssertionError(e);
}
}
public Metadata getMetadata() {
synchronized (HazelcastSqlParser.class) {
if (metadata == null) {
metadata = new MetadataImpl(
new HazelcastSqlParser(new java.io.StringReader("")));
}
return metadata;
}
}
public void setTabSize(int tabSize) {
jj_input_stream.setTabSize(tabSize);
}
public void switchTo(SqlAbstractParserImpl.LexicalState state) {
final int stateOrdinal =
Arrays.asList(HazelcastSqlParserTokenManager.lexStateNames)
.indexOf(state.name());
token_source.SwitchTo(stateOrdinal);
}
public void setQuotedCasing(Casing quotedCasing) {
this.quotedCasing = quotedCasing;
}
public void setUnquotedCasing(Casing unquotedCasing) {
this.unquotedCasing = unquotedCasing;
}
public void setIdentifierMaxLength(int identifierMaxLength) {
this.identifierMaxLength = identifierMaxLength;
}
public void setConformance(SqlConformance conformance) {
this.conformance = conformance;
}
public SqlNode parseSqlExpressionEof() throws Exception {
return SqlExpressionEof();
}
public SqlNode parseSqlStmtEof() throws Exception {
return SqlStmtEof();
}
public SqlNodeList parseSqlStmtList() throws Exception {
return SqlStmtList();
}
public SqlNode parseArray() throws SqlParseException {
switchTo(LexicalState.BQID);
try {
return ArrayLiteral();
} catch (ParseException ex) {
throw normalizeException(ex);
} catch (TokenMgrError ex) {
throw normalizeException(ex);
}
}
private SqlNode extend(SqlNode table, SqlNodeList extendList) {
return SqlStdOperatorTable.EXTEND.createCall(
Span.of(table, extendList).pos(), table, extendList);
}
/** Adds a warning that a token such as "HOURS" was used,
* whereas the SQL standard only allows "HOUR".
*
*
Currently, we silently add an exception to a list of warnings. In
* future, we may have better compliance checking, for example a strict
* compliance mode that throws if any non-standard features are used. */
private TimeUnit warn(TimeUnit timeUnit) throws ParseException {
final String token = getToken(0).image.toUpperCase(Locale.ROOT);
warnings.add(
SqlUtil.newContextException(getPos(),
RESOURCE.nonStandardFeatureUsed(token)));
return timeUnit;
}
}
PARSER_END(HazelcastSqlParser)
/***************************************
* Utility Codes for Semantic Analysis *
***************************************/
/* For Debug */
JAVACODE
void debug_message1() {
LOGGER.info("{} , {}", getToken(0).image, getToken(1).image);
}
JAVACODE String unquotedIdentifier() {
return SqlParserUtil.toCase(getToken(0).image, unquotedCasing);
}
/**
* Allows parser to be extended with new types of table references. The
* default implementation of this production is empty.
*/
SqlNode ExtendedTableRef() :
{
}
{
UnusedExtension()
{
return null;
}
}
/**
* Allows an OVER clause following a table expression as an extension to
* standard SQL syntax. The default implementation of this production is empty.
*/
SqlNode TableOverOpt() :
{
}
{
{
return null;
}
}
/*
* Parses dialect-specific keywords immediately following the SELECT keyword.
*/
void SqlSelectKeywords(List keywords) :
{}
{
E()
}
/*
* Parses dialect-specific keywords immediately following the INSERT keyword.
*/
void SqlInsertKeywords(List keywords) :
{}
{
E()
}
/*
* Parse Floor/Ceil function parameters
*/
SqlNode FloorCeilOptions(Span s, boolean floorFlag) :
{
SqlNode node;
}
{
node = StandardFloorCeilOptions(s, floorFlag) {
return node;
}
}
/*
// This file contains the heart of a parser for SQL SELECT statements.
// code can be shared between various parsers (for example, a DDL parser and a
// DML parser) but is not a standalone JavaCC file. You need to prepend a
// parser declaration (such as that in Parser.jj).
*/
/* Epsilon */
JAVACODE
void E() {}
/** @Deprecated */
JAVACODE List startList(Object o)
{
List list = new ArrayList();
list.add(o);
return list;
}
/*
* NOTE jvs 6-Feb-2004: The straightforward way to implement the SQL grammar is
* to keep query expressions (SELECT, UNION, etc) separate from row expressions
* (+, LIKE, etc). However, this is not possible with an LL(k) parser, because
* both kinds of expressions allow parenthesization, so no fixed amount of left
* context is ever good enough. A sub-query can be a leaf in a row expression,
* and can include operators like UNION, so it's not even possible to use a
* syntactic lookahead rule like "look past an indefinite number of parentheses
* until you see SELECT, VALUES, or TABLE" (since at that point we still
* don't know whether we're parsing a sub-query like ((select ...) + x)
* vs. (select ... union select ...).
*
* The somewhat messy solution is to unify the two kinds of expression,
* and to enforce syntax rules using parameterized context. This
* is the purpose of the ExprContext parameter. It is passed to
* most expression productions, which check the expressions encountered
* against the context for correctness. When a query
* element like SELECT is encountered, the production calls
* checkQueryExpression, which will throw an exception if
* a row expression was expected instead. When a row expression like
* IN is encountered, the production calls checkNonQueryExpression
* instead. It is very important to understand how this works
* when modifying the grammar.
*
* The commingling of expressions results in some bogus ambiguities which are
* resolved with LOOKAHEAD hints. The worst example is comma. SQL allows both
* (WHERE x IN (1,2)) and (WHERE x IN (select ...)). This means when we parse
* the right-hand-side of an IN, we have to allow any kind of expression inside
* the parentheses. Now consider the expression "WHERE x IN(SELECT a FROM b
* GROUP BY c,d)". When the parser gets to "c,d" it doesn't know whether the
* comma indicates the end of the GROUP BY or the end of one item in an IN
* list. Luckily, we know that select and comma-list are mutually exclusive
* within IN, so we use maximal munch for the GROUP BY comma. However, this
* usage of hints could easily mask unintended ambiguities resulting from
* future changes to the grammar, making it very brittle.
*/
JAVACODE protected SqlParserPos getPos()
{
return new SqlParserPos(
token.beginLine,
token.beginColumn,
token.endLine,
token.endColumn);
}
/** Starts a span at the current position. */
JAVACODE Span span()
{
return Span.of(getPos());
}
JAVACODE void checkQueryExpression(ExprContext exprContext)
{
switch (exprContext) {
case ACCEPT_NON_QUERY:
case ACCEPT_SUB_QUERY:
case ACCEPT_CURSOR:
throw SqlUtil.newContextException(getPos(),
RESOURCE.illegalQueryExpression());
}
}
JAVACODE void checkNonQueryExpression(ExprContext exprContext)
{
switch (exprContext) {
case ACCEPT_QUERY:
throw SqlUtil.newContextException(getPos(),
RESOURCE.illegalNonQueryExpression());
}
}
JAVACODE SqlNode checkNotJoin(SqlNode e)
{
if (e instanceof SqlJoin) {
throw SqlUtil.newContextException(e.getParserPosition(),
RESOURCE.illegalJoinExpression());
}
return e;
}
/**
* Converts a ParseException (local to this particular instantiation
* of the parser) into a SqlParseException (common to all parsers).
*/
JAVACODE SqlParseException convertException(Throwable ex)
{
if (ex instanceof SqlParseException) {
return (SqlParseException) ex;
}
SqlParserPos pos = null;
int[][] expectedTokenSequences = null;
String[] tokenImage = null;
if (ex instanceof ParseException) {
ParseException pex = (ParseException) ex;
expectedTokenSequences = pex.expectedTokenSequences;
tokenImage = pex.tokenImage;
if (pex.currentToken != null) {
final Token token = pex.currentToken.next;
// Checks token.image.equals("1") to avoid recursive call.
// The SqlAbstractParserImpl#MetadataImpl constructor uses constant "1" to
// throw intentionally to collect the expected tokens.
if (!token.image.equals("1")
&& getMetadata().isKeyword(token.image)
&& SqlParserUtil.allowsIdentifier(tokenImage, expectedTokenSequences)) {
// If the next token is a keyword, reformat the error message as:
// Incorrect syntax near the keyword '{keyword}' at line {line_number},
// column {column_number}.
final String expecting = ex.getMessage()
.substring(ex.getMessage().indexOf("Was expecting"));
final String errorMsg = String.format("Incorrect syntax near the keyword '%s' "
+ "at line %d, column %d.\n%s",
token.image,
token.beginLine,
token.beginColumn,
expecting);
// Replace the ParseException with explicit error message.
ex = new ParseException(errorMsg);
}
pos = new SqlParserPos(
token.beginLine,
token.beginColumn,
token.endLine,
token.endColumn);
}
} else if (ex instanceof TokenMgrError) {
expectedTokenSequences = null;
tokenImage = null;
// Example:
// Lexical error at line 3, column 24. Encountered "#" after "a".
final java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(
"(?s)Lexical error at line ([0-9]+), column ([0-9]+).*");
java.util.regex.Matcher matcher = pattern.matcher(ex.getMessage());
if (matcher.matches()) {
int line = Integer.parseInt(matcher.group(1));
int column = Integer.parseInt(matcher.group(2));
pos = new SqlParserPos(line, column, line, column);
}
} else if (ex instanceof CalciteContextException) {
// CalciteContextException is the standard wrapper for exceptions
// produced by the validator, but in the parser, the standard is
// SqlParseException; so, strip it away. In case you were wondering,
// the CalciteContextException appears because the parser
// occasionally calls into validator-style code such as
// SqlSpecialOperator.reduceExpr.
CalciteContextException ece =
(CalciteContextException) ex;
pos = new SqlParserPos(
ece.getPosLine(),
ece.getPosColumn(),
ece.getEndPosLine(),
ece.getEndPosColumn());
ex = ece.getCause();
}
return new SqlParseException(
ex.getMessage(), pos, expectedTokenSequences, tokenImage, ex);
}
/**
* Removes or transforms misleading information from a parse exception.
*
* @param e dirty excn
*
* @return clean excn
*/
JAVACODE ParseException cleanupParseException(ParseException ex)
{
if (ex.expectedTokenSequences == null) {
return ex;
}
int iIdentifier = Arrays.asList(ex.tokenImage).indexOf("");
// Find all sequences in the error which contain identifier. For
// example,
// {}
// {A}
// {B, C}
// {D, }
// {D, A}
// {D, B}
//
// would yield
// {}
// {D}
final List prefixList = new ArrayList();
for (int i = 0; i < ex.expectedTokenSequences.length; ++i) {
int[] seq = ex.expectedTokenSequences[i];
int j = seq.length - 1;
int i1 = seq[j];
if (i1 == iIdentifier) {
int[] prefix = new int[j];
System.arraycopy(seq, 0, prefix, 0, j);
prefixList.add(prefix);
}
}
if (prefixList.isEmpty()) {
return ex;
}
int[][] prefixes = (int[][])
prefixList.toArray(new int[prefixList.size()][]);
// Since was one of the possible productions,
// we know that the parser will also have included all
// of the non-reserved keywords (which are treated as
// identifiers in non-keyword contexts). So, now we need
// to clean those out, since they're totally irrelevant.
final List list = new ArrayList();
Metadata metadata = getMetadata();
for (int i = 0; i < ex.expectedTokenSequences.length; ++i) {
int [] seq = ex.expectedTokenSequences[i];
String tokenImage = ex.tokenImage[seq[seq.length - 1]];
String token = SqlParserUtil.getTokenVal(tokenImage);
if (token == null || !metadata.isNonReservedKeyword(token)) {
list.add(seq);
continue;
}
boolean match = matchesPrefix(seq, prefixes);
if (!match) {
list.add(seq);
}
}
ex.expectedTokenSequences =
(int [][]) list.toArray(new int [list.size()][]);
return ex;
}
JAVACODE boolean matchesPrefix(int[] seq, int[][] prefixes)
{
nextPrefix:
for (int[] prefix : prefixes) {
if (seq.length == prefix.length + 1) {
for (int k = 0; k < prefix.length; k++) {
if (prefix[k] != seq[k]) {
continue nextPrefix;
}
}
return true;
}
}
return false;
}
/*****************************************
* Syntactical Descriptions *
*****************************************/
SqlNode ExprOrJoinOrOrderedQuery(ExprContext exprContext) :
{
SqlNode e;
final List