mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
improved sql parser. for issue #2079
This commit is contained in:
+19
-3
@@ -21,12 +21,16 @@ import com.alibaba.druid.sql.dialect.db2.ast.DB2Statement;
|
||||
import com.alibaba.druid.sql.dialect.db2.visitor.DB2ASTVisitor;
|
||||
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DB2CreateTableStatement extends SQLCreateTableStatement implements DB2Statement {
|
||||
private boolean dataCaptureNone;
|
||||
private boolean dataCaptureChanges;
|
||||
|
||||
protected SQLName database;
|
||||
protected SQLName validproc;
|
||||
protected SQLName indexIn;
|
||||
|
||||
public boolean isDataCaptureNone() {
|
||||
return dataCaptureNone;
|
||||
@@ -59,11 +63,22 @@ public class DB2CreateTableStatement extends SQLCreateTableStatement implements
|
||||
return validproc;
|
||||
}
|
||||
|
||||
public void setValidproc(SQLName validproc) {
|
||||
public void setValidproc(SQLName x) {
|
||||
if (validproc != null) {
|
||||
validproc.setParent(this);
|
||||
x.setParent(this);
|
||||
}
|
||||
this.validproc = validproc;
|
||||
this.validproc = x;
|
||||
}
|
||||
|
||||
public SQLName getIndexIn() {
|
||||
return indexIn;
|
||||
}
|
||||
|
||||
public void setIndexIn(SQLName x) {
|
||||
if (validproc != null) {
|
||||
x.setParent(this);
|
||||
}
|
||||
this.indexIn = x;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -85,6 +100,7 @@ public class DB2CreateTableStatement extends SQLCreateTableStatement implements
|
||||
this.acceptChild(visitor, select);
|
||||
this.acceptChild(visitor, database);
|
||||
this.acceptChild(visitor, validproc);
|
||||
this.acceptChild(visitor, indexIn);
|
||||
}
|
||||
visitor.endVisit(this);
|
||||
}
|
||||
|
||||
@@ -179,6 +179,12 @@ public class DB2CreateTableParser extends SQLCreateTableParser {
|
||||
lexer.nextToken();
|
||||
}
|
||||
continue;
|
||||
} else if (lexer.token() == Token.INDEX) {
|
||||
lexer.nextToken();
|
||||
accept(Token.IN);
|
||||
SQLName indexIn = this.exprParser.name();
|
||||
createTable.setIndexIn(indexIn);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -101,6 +101,13 @@ public class DB2OutputVisitor extends SQLASTOutputVisitor implements DB2ASTVisit
|
||||
tablespace.accept(this);
|
||||
}
|
||||
|
||||
SQLName indexIn = x.getIndexIn();
|
||||
if (indexIn != null) {
|
||||
println();
|
||||
print("INDEX IN ");
|
||||
indexIn.accept(this);
|
||||
}
|
||||
|
||||
SQLName database = x.getDatabase();
|
||||
if (database != null) {
|
||||
println();
|
||||
|
||||
@@ -89,7 +89,7 @@ public class SQLExprParser extends SQLParser {
|
||||
if (token == Token.COMMA) {
|
||||
return expr;
|
||||
} else if (token == Token.EQ) {
|
||||
expr = equalityRest(expr);
|
||||
expr = equalityRest2(expr);
|
||||
expr = andRest(expr);
|
||||
expr = orRest(expr);
|
||||
return expr;
|
||||
@@ -1668,6 +1668,53 @@ public class SQLExprParser extends SQLParser {
|
||||
return equalityRest(expr);
|
||||
}
|
||||
|
||||
private SQLExpr equalityRest2(SQLExpr expr) {
|
||||
SQLExpr rightExp;
|
||||
lexer.nextToken();
|
||||
try {
|
||||
if (lexer.token == Token.LITERAL_INT) {
|
||||
rightExp = new SQLIntegerExpr(lexer.integerValue());
|
||||
lexer.nextToken();
|
||||
|
||||
if (lexer.token == Token.AND
|
||||
|| lexer.token == Token.RPAREN
|
||||
|| lexer.token == Token.EOF
|
||||
|| lexer.token == Token.OR) {
|
||||
return new SQLBinaryOpExpr(expr, SQLBinaryOperator.Equality, rightExp, dbType);
|
||||
}
|
||||
|
||||
rightExp = primaryRest(rightExp);
|
||||
rightExp = bitXorRest(rightExp);
|
||||
rightExp = multiplicativeRest(rightExp);
|
||||
rightExp = additiveRest(rightExp);
|
||||
rightExp = shiftRest(rightExp);
|
||||
rightExp = bitAndRest(rightExp);
|
||||
rightExp = bitOrRest(rightExp);
|
||||
rightExp = inRest(rightExp);
|
||||
rightExp = relationalRest(rightExp);
|
||||
} else {
|
||||
rightExp = bitOr();
|
||||
}
|
||||
} catch (EOFParserException e) {
|
||||
throw new ParserException("EOF, " + expr + "=", e);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (lexer.token == Token.IS || lexer.token == Token.BETWEEN) {
|
||||
expr = relationalRest(expr);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
|
||||
public SQLExpr equalityRest(SQLExpr expr) {
|
||||
SQLExpr rightExp;
|
||||
|
||||
@@ -1728,7 +1775,18 @@ public class SQLExprParser extends SQLParser {
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
SQLExpr item = this.expr();
|
||||
SQLExpr item;
|
||||
if (lexer.token == Token.LITERAL_INT) {
|
||||
item = new SQLIntegerExpr(lexer.integerValue());
|
||||
lexer.nextToken();
|
||||
if (lexer.token != Token.COMMA && lexer.token != Token.RPAREN) {
|
||||
item = this.primaryRest(item);
|
||||
item = this.exprRest(item);
|
||||
}
|
||||
} else {
|
||||
item = this.expr();
|
||||
}
|
||||
|
||||
item.setParent(inListExpr);
|
||||
targetList.add(item);
|
||||
if (lexer.token == Token.COMMA) {
|
||||
@@ -3049,15 +3107,39 @@ public class SQLExprParser extends SQLParser {
|
||||
|
||||
public SQLLimit parseLimit() {
|
||||
if (lexer.token == Token.LIMIT) {
|
||||
lexer.nextToken();
|
||||
lexer.nextTokenValue();
|
||||
|
||||
SQLLimit limit = new SQLLimit();
|
||||
|
||||
SQLExpr temp = this.expr();
|
||||
SQLExpr temp;
|
||||
if (lexer.token == Token.LITERAL_INT) {
|
||||
temp = new SQLIntegerExpr(lexer.integerValue());
|
||||
lexer.nextTokenComma();
|
||||
if (lexer.token != Token.COMMA && lexer.token != Token.EOF && lexer.token != Token.IDENTIFIER) {
|
||||
temp = this.primaryRest(temp);
|
||||
temp = this.exprRest(temp);
|
||||
}
|
||||
} else {
|
||||
temp = this.expr();
|
||||
}
|
||||
|
||||
if (lexer.token == (Token.COMMA)) {
|
||||
limit.setOffset(temp);
|
||||
lexer.nextToken();
|
||||
limit.setRowCount(this.expr());
|
||||
lexer.nextTokenValue();
|
||||
|
||||
SQLExpr rowCount;
|
||||
if (lexer.token == Token.LITERAL_INT) {
|
||||
rowCount = new SQLIntegerExpr(lexer.integerValue());
|
||||
lexer.nextToken();
|
||||
if (lexer.token != Token.EOF && lexer.token != Token.IDENTIFIER) {
|
||||
rowCount = this.primaryRest(rowCount);
|
||||
rowCount = this.exprRest(rowCount);
|
||||
}
|
||||
} else {
|
||||
rowCount = this.expr();
|
||||
}
|
||||
|
||||
limit.setRowCount(rowCount);
|
||||
} else if (lexer.identifierEquals(FnvHash.Constants.OFFSET)) {
|
||||
limit.setRowCount(temp);
|
||||
lexer.nextToken();
|
||||
|
||||
@@ -585,7 +585,7 @@ public class SQLSelectParser extends SQLParser {
|
||||
}
|
||||
|
||||
protected SQLTableSource parseTableSourceRest(SQLTableSource tableSource) {
|
||||
if ((tableSource.getAlias() == null) || (tableSource.getAlias().length() == 0)) {
|
||||
if (tableSource.getAlias() == null || tableSource.getAlias().length() == 0) {
|
||||
Token token = lexer.token;
|
||||
long hash;
|
||||
if (token != Token.LEFT
|
||||
@@ -599,6 +599,11 @@ public class SQLSelectParser extends SQLParser {
|
||||
String alias = tableAlias();
|
||||
if (alias != null) {
|
||||
tableSource.setAlias(alias);
|
||||
|
||||
if (lexer.token == Token.WHERE) {
|
||||
return tableSource;
|
||||
}
|
||||
|
||||
return parseTableSourceRest(tableSource);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3164,6 +3164,10 @@ public class SQLStatementParser extends SQLParser {
|
||||
expr = new SQLIntegerExpr(lexer.integerValue());
|
||||
}
|
||||
lexer.nextTokenComma();
|
||||
|
||||
if (lexer.token != Token.COMMA && lexer.token != Token.RPAREN) {
|
||||
expr = this.exprParser.exprRest(expr);
|
||||
}
|
||||
} else if (lexer.token() == Token.LITERAL_CHARS) {
|
||||
if (optimizedForParameterized) {
|
||||
expr = new SQLVariantRefExpr("?");
|
||||
@@ -3172,6 +3176,9 @@ public class SQLStatementParser extends SQLParser {
|
||||
expr = new SQLCharExpr(lexer.stringVal());
|
||||
}
|
||||
lexer.nextTokenComma();
|
||||
if (lexer.token != Token.COMMA && lexer.token != Token.RPAREN) {
|
||||
expr = this.exprParser.exprRest(expr);
|
||||
}
|
||||
} else if (lexer.token() == Token.LITERAL_NCHARS) {
|
||||
if (optimizedForParameterized) {
|
||||
expr = new SQLVariantRefExpr("?");
|
||||
@@ -3180,6 +3187,20 @@ public class SQLStatementParser extends SQLParser {
|
||||
expr = new SQLNCharExpr(lexer.stringVal());
|
||||
}
|
||||
lexer.nextTokenComma();
|
||||
if (lexer.token != Token.COMMA && lexer.token != Token.RPAREN) {
|
||||
expr = this.exprParser.exprRest(expr);
|
||||
}
|
||||
} else if (lexer.token == Token.NULL) {
|
||||
if (optimizedForParameterized) {
|
||||
expr = new SQLVariantRefExpr("?");
|
||||
values.incrementReplaceCount();
|
||||
} else {
|
||||
expr = new SQLNullExpr();
|
||||
}
|
||||
lexer.nextTokenComma();
|
||||
if (lexer.token != Token.COMMA && lexer.token != Token.RPAREN) {
|
||||
expr = this.exprParser.exprRest(expr);
|
||||
}
|
||||
} else {
|
||||
expr = exprParser.expr();
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.alibaba.druid.sql.parser;
|
||||
|
||||
import com.alibaba.druid.util.Utils;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
@@ -22,8 +24,19 @@ import java.nio.charset.Charset;
|
||||
*/
|
||||
public class SymbolTable {
|
||||
private static final Charset UTF8 = Charset.forName("UTF-8");
|
||||
private static final boolean JVM_16;
|
||||
|
||||
public static SymbolTable global = new SymbolTable(8192);
|
||||
static {
|
||||
String version = null;
|
||||
try {
|
||||
version = System.getProperty("java.specification.version");
|
||||
} catch (Throwable error) {
|
||||
// skip
|
||||
}
|
||||
JVM_16 = "1.6".equals(version);
|
||||
}
|
||||
|
||||
public static SymbolTable global = new SymbolTable(32768);
|
||||
|
||||
private final Entry[] entries;
|
||||
private final int indexMask;
|
||||
@@ -42,12 +55,16 @@ public class SymbolTable {
|
||||
return entry.value;
|
||||
}
|
||||
|
||||
String str = subString(buffer, offset, len);
|
||||
String str = JVM_16
|
||||
? subString(buffer, offset, len)
|
||||
: buffer.substring(offset, offset + len);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
String str = subString(buffer, offset, len);
|
||||
String str = JVM_16
|
||||
? subString(buffer, offset, len)
|
||||
: buffer.substring(offset, offset + len);
|
||||
entry = new Entry(hash, len, str);
|
||||
entries[bucket] = entry;
|
||||
return str;
|
||||
|
||||
@@ -66,7 +66,8 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
|
||||
|
||||
protected List<Object> parameters;
|
||||
protected List<Object> inputParameters;
|
||||
protected Set<String> tables;
|
||||
protected Set<String> tables;
|
||||
protected String table; // for improved
|
||||
|
||||
protected boolean exportTables = false;
|
||||
|
||||
@@ -149,6 +150,9 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
|
||||
}
|
||||
|
||||
public Set<String> getTables() {
|
||||
if (this.table != null && this.tables == null) {
|
||||
return Collections.singleton(this.table);
|
||||
}
|
||||
return this.tables;
|
||||
}
|
||||
|
||||
@@ -1586,7 +1590,9 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
|
||||
} else {
|
||||
if (owner instanceof SQLIdentifierExpr) {
|
||||
SQLIdentifierExpr ownerIdent = (SQLIdentifierExpr) owner;
|
||||
printName(ownerIdent, ownerIdent.getName());
|
||||
printName(ownerIdent
|
||||
, ownerIdent.getName()
|
||||
, this.shardingSupport && this.parameterized);
|
||||
} else {
|
||||
printExpr(owner);
|
||||
}
|
||||
@@ -1944,7 +1950,13 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
|
||||
|
||||
protected void addTable(String table) {
|
||||
if (tables == null) {
|
||||
tables = new LinkedHashSet<String>();
|
||||
if (this.table == null) {
|
||||
this.table = table;
|
||||
return;
|
||||
} else {
|
||||
tables = new LinkedHashSet<String>();
|
||||
tables.add(this.table);
|
||||
}
|
||||
}
|
||||
this.tables.add(table);
|
||||
}
|
||||
@@ -2842,6 +2854,25 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
|
||||
print0(ucase ? joinType.name : joinType.name_lcase);
|
||||
}
|
||||
|
||||
static String[] variantValuesCache = new String[64];
|
||||
static {
|
||||
for (int len = 0; len < variantValuesCache.length; ++len) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append('(');
|
||||
for (int i = 0; i < len; ++i) {
|
||||
if (i != 0) {
|
||||
if (i % 5 == 0) {
|
||||
buf.append("\n\t\t");
|
||||
}
|
||||
buf.append(", ");
|
||||
}
|
||||
buf.append('?');
|
||||
}
|
||||
buf.append(')');
|
||||
variantValuesCache[len] = buf.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(ValuesClause x) {
|
||||
if ((!this.parameterized)
|
||||
@@ -2851,12 +2882,21 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
|
||||
return false;
|
||||
}
|
||||
|
||||
int xReplaceCount = x.getReplaceCount();
|
||||
final List<SQLExpr> values = x.getValues();
|
||||
|
||||
this.replaceCount += xReplaceCount;
|
||||
|
||||
if (xReplaceCount == values.size() && xReplaceCount < variantValuesCache.length) {
|
||||
String variantValues = variantValuesCache[xReplaceCount];
|
||||
print0(variantValues);
|
||||
return false;
|
||||
}
|
||||
|
||||
print('(');
|
||||
this.indentCount++;
|
||||
|
||||
this.replaceCount += x.getReplaceCount();
|
||||
|
||||
final List<SQLExpr> values = x.getValues();
|
||||
for (int i = 0, size = values.size(); i < size; ++i) {
|
||||
if (i != 0) {
|
||||
if (i % 5 == 0) {
|
||||
|
||||
Reference in New Issue
Block a user