improved sql parser.

This commit is contained in:
wenshao
2017-09-10 03:42:21 +08:00
parent 3330643479
commit 7d54eea716
37 changed files with 848 additions and 243 deletions
@@ -325,6 +325,40 @@ public class Lexer {
nextToken();
}
public final void nextTokenEq() {
if (ch == ' ') {
scanChar();
}
if (ch == '=') {
scanChar();
token = EQ;
return;
}
if (ch == '.') {
scanChar();
token = DOT;
return;
}
if (ch == 'a' || ch == 'A') {
char ch_next = charAt(pos + 1);
if (ch_next == 's' || ch_next == 'S') {
char ch_next_2 = charAt(pos + 2);
if (ch_next_2 == ' ') {
pos += 2;
ch = ' ';
token = Token.AS;
stringVal = "AS";
return;
}
}
}
nextToken();
}
public final void nextTokenLParen() {
if (ch == ' ') {
scanChar();
@@ -362,7 +396,30 @@ public class Lexer {
return;
}
if (isFirstIdentifierChar(ch) && ch != 'N') {
if (ch == 'n' || ch == 'N') {
char c1 = 0, c2, c3, c4;
if (pos + 4 < text.length()
&& ((c1 = text.charAt(pos + 1)) == 'u' || c1 == 'U')
&& ((c2 = text.charAt(pos + 2)) == 'l' || c2 == 'L')
&& ((c3 = text.charAt(pos + 3)) == 'l' || c3 == 'L')
&& (isWhitespace(c4 = text.charAt(pos + 4)) || c4 == ',' || c4 == ')')) {
pos += 4;
ch = c4;
token = Token.NULL;
stringVal = "NULL";
return;
}
if (c1 == '\'') {
++pos;
ch = '\'';
scanString();
token = Token.LITERAL_NCHARS;
return;
}
}
if (isFirstIdentifierChar(ch)) {
scanIdentifier();
return;
}
@@ -608,7 +665,7 @@ public class Lexer {
case '`':
throw new ParserException("TODO. " + info()); // TODO
case '@':
scanVariable();
scanVariable_at();
return;
case '-':
if (charAt(pos +1) == '-') {
@@ -736,6 +793,9 @@ public class Lexer {
if (ch == '=') {
scanChar();
token = Token.EQEQ;
} else if (ch == '>') {
scanChar();
token = Token.EQGT;
} else {
token = Token.EQ;
}
@@ -781,6 +841,9 @@ public class Lexer {
break;
case '!':
scanChar();
while (isWhitespace(ch)) {
scanChar();
}
if (ch == '=') {
scanChar();
token = Token.BANGEQ;
@@ -1145,7 +1208,7 @@ public class Lexer {
}
public void scanVariable() {
if (ch != '@' && ch != ':' && ch != '#' && ch != '$') {
if (ch != ':' && ch != '#' && ch != '$') {
throw new ParserException("illegal variable. " + info());
}
@@ -1154,17 +1217,7 @@ public class Lexer {
char ch;
final char c1 = charAt(pos + 1);
if (c1 == '@') {
if (JdbcConstants.POSTGRESQL.equalsIgnoreCase(dbType)) {
pos += 2;
token = Token.MONKEYS_AT_AT;
this.ch = charAt(++pos);
return;
}
ch = charAt(++pos);
bufPos++;
} else if (c1 == '>' && JdbcConstants.POSTGRESQL.equalsIgnoreCase(dbType)) {
if (c1 == '>' && JdbcConstants.POSTGRESQL.equalsIgnoreCase(dbType)) {
pos += 2;
token = Token.MONKEYS_AT_GT;
this.ch = charAt(++pos);
@@ -1214,6 +1267,38 @@ public class Lexer {
token = Token.VARIANT;
}
protected void scanVariable_at() {
if (ch != '@') {
throw new ParserException("illegal variable. " + info());
}
mark = pos;
bufPos = 1;
char ch;
final char c1 = charAt(pos + 1);
if (c1 == '@') {
++pos;
bufPos++;
}
for (;;) {
ch = charAt(++pos);
if (!isIdentifierChar(ch)) {
break;
}
bufPos++;
continue;
}
this.ch = charAt(pos);
stringVal = addSymbol();
token = Token.VARIANT;
}
public void scanComment() {
if (!allowComment) {
throw new NotAllowCommentException();
@@ -1641,12 +1726,12 @@ public class Lexer {
}
multmin = negative ? MULTMIN_RADIX_TEN : N_MULTMAX_RADIX_TEN;
if (i < max) {
digit = digits[charAt(i++)];
digit = charAt(i++) - '0';
result = -digit;
}
while (i < max) {
// Accumulating negatively avoids surprises near MAX_VALUE
digit = digits[charAt(i++)];
digit = charAt(i++) - '0';
if (result < multmin) {
return new BigInteger(numberString());
}
@@ -44,6 +44,7 @@ import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
import com.alibaba.druid.sql.ast.statement.SQLUnique;
import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem;
import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleArgumentExpr;
import com.alibaba.druid.util.FnvHash;
import com.alibaba.druid.util.JdbcConstants;
@@ -1462,12 +1463,38 @@ public class SQLExprParser extends SQLParser {
accept(Token.RPAREN);
item.setColumn(list);
} else {
item.setColumn(this.primary());
String identName;
long hash;
Token token = lexer.token();
if (token == Token.IDENTIFIER) {
identName = lexer.stringVal();
hash = lexer.hash_lower();
} else if (token == Token.LITERAL_CHARS) {
identName = '\'' + lexer.stringVal() + '\'';
hash = 0;
} else {
identName = lexer.stringVal();
hash = 0;
}
lexer.nextTokenEq();
SQLExpr expr = new SQLIdentifierExpr(identName, hash);
while (lexer.token() == Token.DOT) {
lexer.nextToken();
String propertyName = lexer.stringVal();
lexer.nextTokenEq();
expr = new SQLPropertyExpr(expr, propertyName);
}
item.setColumn(expr);
}
if (lexer.token == Token.COLONEQ) {
lexer.nextToken();
lexer.nextTokenValue();
} else if (lexer.token == Token.EQ) {
lexer.nextTokenValue();
} else {
accept(Token.EQ);
throw new ParserException("syntax error, expect EQ, actual " + lexer.token + " "
+ lexer.info());
}
item.setValue(this.expr());
@@ -1519,28 +1546,28 @@ public class SQLExprParser extends SQLParser {
} catch (EOFParserException e) {
throw new ParserException("EOF, " + expr + "=", e);
}
rightExp = equalityRest(rightExp);
if (lexer.token == Token.COLONEQ) {
lexer.nextToken();
SQLExpr colonExpr = expr();
rightExp = new SQLBinaryOpExpr(rightExp, SQLBinaryOperator.Assignment, colonExpr, dbType);
}
expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Equality, rightExp, dbType);
} else if (token == Token.BANGEQ) {
} else if (lexer.token() == Token.EQGT) {
lexer.nextToken();
rightExp = expr();
String argumentName = ((SQLIdentifierExpr) expr).getName();
return new OracleArgumentExpr(argumentName, rightExp);
} else if (token == Token.BANGEQ || token == Token.CARETEQ) {
lexer.nextToken();
rightExp = bitOr();
rightExp = equalityRest(rightExp);
expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.NotEqual, rightExp, getDbType());
} else if (token == Token.BANG) {
lexer.nextToken();
accept(Token.EQ);
rightExp = bitOr();
rightExp = equalityRest(rightExp);
expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.NotEqual, rightExp, getDbType());
expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.NotEqual, rightExp, dbType);
} else if (token == Token.COLONEQ) {
lexer.nextToken();
rightExp = expr();
expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Assignment, rightExp, getDbType());
expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Assignment, rightExp, dbType);
}
return expr;
@@ -1562,9 +1589,19 @@ public class SQLExprParser extends SQLParser {
return queryExpr;
}
exprList(inListExpr.getTargetList(), inListExpr);
List<SQLExpr> targetList = inListExpr.getTargetList();
for (;;) {
SQLExpr item = this.expr();
item.setParent(inListExpr);
targetList.add(item);
if (lexer.token == Token.COMMA) {
lexer.nextTokenValue();
continue;
}
break;
}
accept(Token.RPAREN);
expr = inListExpr;
} else {
SQLExpr itemExpr = primary();
itemExpr.setParent(inListExpr);
@@ -2632,6 +2669,13 @@ public class SQLExprParser extends SQLParser {
String as = lexer.stringVal();
lexer.nextTokenComma();
if (lexer.token == Token.DOT) {
lexer.nextToken();
as += '.' + lexer.stringVal();
lexer.nextToken();
}
return new SQLSelectItem(expr, as, connectByRoot);
}
@@ -18,8 +18,11 @@ package com.alibaba.druid.sql.parser;
import java.util.List;
import com.alibaba.druid.sql.ast.*;
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOrderingExpr;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
import com.alibaba.druid.util.FnvHash;
import com.alibaba.druid.util.JdbcConstants;
@@ -317,7 +320,7 @@ public class SQLSelectParser extends SQLParser {
}
SQLExpr where = expr();
if (where != null && beforeComments != null) {
if (beforeComments != null) {
where.addBeforeComment(beforeComments);
}
@@ -19,12 +19,10 @@ import java.util.ArrayList;
import java.util.List;
import com.alibaba.druid.sql.ast.*;
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLQueryExpr;
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
import com.alibaba.druid.sql.ast.expr.*;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.ast.statement.SQLCreateTriggerStatement.TriggerType;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
import com.alibaba.druid.sql.dialect.oracle.parser.OracleExprParser;
import com.alibaba.druid.util.FnvHash;
import com.alibaba.druid.util.JdbcConstants;
@@ -77,7 +75,7 @@ public class SQLStatementParser extends SQLParser {
}
public void parseStatementList(List<SQLStatement> statementList) {
parseStatementList(statementList, -1);
parseStatementList(statementList, -1, null);
}
public void parseStatementList(List<SQLStatement> statementList, int max) {
@@ -2430,7 +2428,7 @@ public class SQLStatementParser extends SQLParser {
*/
public SQLStatement parseStatement( final boolean tryBest) {
List<SQLStatement> list = new ArrayList<SQLStatement>();
this.parseStatementList(list, 1);
this.parseStatementList(list, 1, null);
if (tryBest) {
if (lexer.token != Token.EOF) {
throw new ParserException("sql syntax error, no terminated. " + lexer.token);
@@ -317,7 +317,8 @@ public enum Token {
COLON(":"),
COLONCOLON("::"),
COLONEQ(":="),
EQEQ("=="),
EQEQ("=="),
EQGT("=>"),
LTEQ("<="),
LTEQGT("<=>"),
LTGT("<>"),