mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
improved sql parser.
This commit is contained in:
@@ -27,6 +27,7 @@ import java.util.Properties;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import com.alibaba.druid.VERSION;
|
||||
import com.alibaba.druid.filter.Filter;
|
||||
import com.alibaba.druid.filter.FilterChain;
|
||||
import com.alibaba.druid.filter.FilterEventAdapter;
|
||||
@@ -145,7 +146,7 @@ public class StatFilter extends FilterEventAdapter implements StatFilterMBean {
|
||||
try {
|
||||
sql = ParameterizedOutputVisitorUtils.parameterize(sql, dbType);
|
||||
} catch (Exception e) {
|
||||
LOG.error("merge sql error, dbType " + dbType + ", sql : " + sql, e);
|
||||
LOG.error("merge sql error, dbType " + dbType + ", druid-" + VERSION.getVersionNumber() + ", sql : " + sql, e);
|
||||
}
|
||||
|
||||
return sql;
|
||||
|
||||
@@ -168,7 +168,7 @@ public class SQLTransformUtils {
|
||||
dataType = new SQLDataTypeImpl("smallint");
|
||||
} else if (precision < 9) {
|
||||
dataType = new SQLDataTypeImpl("int");
|
||||
} else if (precision < 19) {
|
||||
} else if (precision <= 20) {
|
||||
dataType = new SQLDataTypeImpl("bigint");
|
||||
} else {
|
||||
dataType = new SQLDataTypeImpl("decimal", precision);
|
||||
@@ -468,7 +468,7 @@ public class SQLTransformUtils {
|
||||
dataType = new SQLDataTypeImpl("smallint");
|
||||
} else if (precision < 9) {
|
||||
dataType = new SQLDataTypeImpl("int");
|
||||
} else if (precision < 19) {
|
||||
} else if (precision <= 20) {
|
||||
dataType = new SQLDataTypeImpl("bigint");
|
||||
} else {
|
||||
dataType = new SQLDataTypeImpl("decimal", precision);
|
||||
|
||||
@@ -234,7 +234,9 @@ public class SQLUtils {
|
||||
|
||||
public static String format(String sql, String dbType, List<Object> parameters, FormatOption option) {
|
||||
try {
|
||||
SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, dbType, true);
|
||||
SQLParserFeature[] features = {SQLParserFeature.KeepComments, SQLParserFeature.EnableSQLBinaryOpExprGroup};
|
||||
|
||||
SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, dbType, features);
|
||||
parser.setKeepComments(true);
|
||||
|
||||
List<SQLStatement> statementList = parser.parseStatementList();
|
||||
|
||||
@@ -33,4 +33,7 @@ public interface SQLDataType extends SQLObject {
|
||||
boolean isWithLocalTimeZone();
|
||||
|
||||
SQLDataType clone();
|
||||
|
||||
void setDbType(String dbType);
|
||||
String getDbType();
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.alibaba.druid.sql.ast;
|
||||
|
||||
import com.alibaba.druid.sql.SQLUtils;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
|
||||
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
|
||||
import com.alibaba.druid.util.FnvHash;
|
||||
@@ -24,11 +25,12 @@ import java.util.List;
|
||||
|
||||
public class SQLDataTypeImpl extends SQLObjectImpl implements SQLDataType {
|
||||
|
||||
private String name;
|
||||
private long nameHashCode64;
|
||||
private String name;
|
||||
private long nameHashCode64;
|
||||
protected final List<SQLExpr> arguments = new ArrayList<SQLExpr>();
|
||||
private Boolean withTimeZone;
|
||||
private boolean withLocalTimeZone = false;
|
||||
private Boolean withTimeZone;
|
||||
private boolean withLocalTimeZone = false;
|
||||
private String dbType;
|
||||
|
||||
public SQLDataTypeImpl(){
|
||||
|
||||
@@ -122,6 +124,14 @@ public class SQLDataTypeImpl extends SQLObjectImpl implements SQLDataType {
|
||||
this.withLocalTimeZone = withLocalTimeZone;
|
||||
}
|
||||
|
||||
public String getDbType() {
|
||||
return dbType;
|
||||
}
|
||||
|
||||
public void setDbType(String dbType) {
|
||||
this.dbType = dbType;
|
||||
}
|
||||
|
||||
public SQLDataTypeImpl clone() {
|
||||
SQLDataTypeImpl x = new SQLDataTypeImpl();
|
||||
|
||||
@@ -131,6 +141,7 @@ public class SQLDataTypeImpl extends SQLObjectImpl implements SQLDataType {
|
||||
}
|
||||
|
||||
public void cloneTo(SQLDataTypeImpl x) {
|
||||
x.dbType = dbType;
|
||||
x.name = name;
|
||||
|
||||
for (SQLExpr arg : arguments) {
|
||||
@@ -140,4 +151,8 @@ public class SQLDataTypeImpl extends SQLObjectImpl implements SQLDataType {
|
||||
x.withTimeZone = withTimeZone;
|
||||
x.withLocalTimeZone = withLocalTimeZone;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return SQLUtils.toSQLString(this, dbType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,14 @@ public class SQLIdentifierExpr extends SQLExprImpl implements SQLName {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getLowerName() {
|
||||
if (name == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return name.toLowerCase();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@@ -36,9 +36,6 @@ public class SQLPropertyExpr extends SQLExprImpl implements SQLName {
|
||||
}
|
||||
|
||||
public SQLPropertyExpr(SQLExpr owner, String name){
|
||||
if (name == null) {
|
||||
throw new IllegalArgumentException("name is null.");
|
||||
}
|
||||
setOwner(owner);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ public interface SQLForeignKeyConstraint extends SQLConstraint, SQLTableElement,
|
||||
|
||||
List<SQLName> getReferencingColumns();
|
||||
|
||||
SQLExprTableSource getReferencedTable();
|
||||
SQLName getReferencedTableName();
|
||||
|
||||
void setReferencedTableName(SQLName value);
|
||||
|
||||
@@ -22,12 +22,11 @@ import com.alibaba.druid.sql.ast.SQLName;
|
||||
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
|
||||
|
||||
public class SQLForeignKeyImpl extends SQLConstraintImpl implements SQLForeignKeyConstraint {
|
||||
|
||||
private SQLName referencedTableName;
|
||||
private List<SQLName> referencingColumns = new ArrayList<SQLName>();
|
||||
private List<SQLName> referencedColumns = new ArrayList<SQLName>();
|
||||
private boolean onDeleteCascade = false;
|
||||
private boolean onDeleteSetNull = false;
|
||||
private SQLExprTableSource referencedTable;
|
||||
private List<SQLName> referencingColumns = new ArrayList<SQLName>();
|
||||
private List<SQLName> referencedColumns = new ArrayList<SQLName>();
|
||||
private boolean onDeleteCascade = false;
|
||||
private boolean onDeleteSetNull = false;
|
||||
|
||||
public SQLForeignKeyImpl(){
|
||||
|
||||
@@ -38,14 +37,33 @@ public class SQLForeignKeyImpl extends SQLConstraintImpl implements SQLForeignKe
|
||||
return referencingColumns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLExprTableSource getReferencedTable() {
|
||||
return referencedTable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLName getReferencedTableName() {
|
||||
return referencedTableName;
|
||||
if (referencedTable == null) {
|
||||
return null;
|
||||
}
|
||||
return referencedTable.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReferencedTableName(SQLName value) {
|
||||
this.referencedTableName = value;
|
||||
if (value == null) {
|
||||
this.referencedTable = null;
|
||||
return;
|
||||
}
|
||||
this.setReferencedTable(new SQLExprTableSource(value));
|
||||
}
|
||||
|
||||
public void setReferencedTable(SQLExprTableSource x) {
|
||||
if (x != null) {
|
||||
x.setParent(this);
|
||||
}
|
||||
this.referencedTable = x;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -83,8 +101,8 @@ public class SQLForeignKeyImpl extends SQLConstraintImpl implements SQLForeignKe
|
||||
public void cloneTo(SQLForeignKeyImpl x) {
|
||||
super.cloneTo(x);
|
||||
|
||||
if (referencedTableName != null) {
|
||||
x.setReferencedTableName(referencedTableName.clone());
|
||||
if (referencedTable != null) {
|
||||
x.setReferencedTable(referencedTable.clone());
|
||||
}
|
||||
|
||||
for (SQLName column : referencingColumns) {
|
||||
|
||||
@@ -102,21 +102,21 @@ public class DB2ExprParser extends SQLExprParser {
|
||||
}
|
||||
|
||||
protected SQLExpr dotRest(SQLExpr expr) {
|
||||
if (lexer.identifierEquals("NEXTVAL")) {
|
||||
if (lexer.identifierEquals(FnvHash.Constants.NEXTVAL)) {
|
||||
if (expr instanceof SQLIdentifierExpr) {
|
||||
SQLIdentifierExpr identExpr = (SQLIdentifierExpr) expr;
|
||||
SQLSequenceExpr seqExpr = new SQLSequenceExpr(identExpr, SQLSequenceExpr.Function.NextVal);
|
||||
lexer.nextToken();
|
||||
return seqExpr;
|
||||
}
|
||||
} else if (lexer.identifierEquals("PREVVAL")) {
|
||||
} else if (lexer.identifierEquals(FnvHash.Constants.PREVVAL)) {
|
||||
if (expr instanceof SQLIdentifierExpr) {
|
||||
SQLIdentifierExpr identExpr = (SQLIdentifierExpr) expr;
|
||||
SQLSequenceExpr seqExpr = new SQLSequenceExpr(identExpr, SQLSequenceExpr.Function.PrevVal);
|
||||
lexer.nextToken();
|
||||
return seqExpr;
|
||||
}
|
||||
} else if (lexer.identifierEquals("CURRVAL")) {
|
||||
} else if (lexer.identifierEquals(FnvHash.Constants.CURRVAL)) {
|
||||
if (expr instanceof SQLIdentifierExpr) {
|
||||
SQLIdentifierExpr identExpr = (SQLIdentifierExpr) expr;
|
||||
SQLSequenceExpr seqExpr = new SQLSequenceExpr(identExpr, SQLSequenceExpr.Function.CurrVal);
|
||||
|
||||
+4
-3
@@ -63,15 +63,15 @@ public class MySqlCreateTableParser extends SQLCreateTableParser {
|
||||
super(exprParser);
|
||||
}
|
||||
|
||||
public SQLCreateTableStatement parseCrateTable() {
|
||||
return parseCrateTable(true);
|
||||
public SQLCreateTableStatement parseCreateTable() {
|
||||
return parseCreateTable(true);
|
||||
}
|
||||
|
||||
public MySqlExprParser getExprParser() {
|
||||
return (MySqlExprParser) exprParser;
|
||||
}
|
||||
|
||||
public MySqlCreateTableStatement parseCrateTable(boolean acceptCreate) {
|
||||
public MySqlCreateTableStatement parseCreateTable(boolean acceptCreate) {
|
||||
MySqlCreateTableStatement stmt = new MySqlCreateTableStatement();
|
||||
if (acceptCreate) {
|
||||
if (lexer.hasComment() && lexer.isKeepComments()) {
|
||||
@@ -120,6 +120,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser {
|
||||
|| lexer.token() == Token.PRIMARY //
|
||||
|| lexer.token() == Token.UNIQUE) {
|
||||
SQLTableConstraint constraint = this.parseConstraint();
|
||||
constraint.setParent(stmt);
|
||||
stmt.getTableElementList().add(constraint);
|
||||
} else if (lexer.token() == (Token.INDEX)) {
|
||||
lexer.nextToken();
|
||||
|
||||
@@ -712,7 +712,7 @@ public class MySqlExprParser extends SQLExprParser {
|
||||
}
|
||||
|
||||
accept(Token.LPAREN);
|
||||
this.names(fk.getReferencingColumns());
|
||||
this.names(fk.getReferencingColumns(), fk);
|
||||
accept(Token.RPAREN);
|
||||
|
||||
accept(Token.REFERENCES);
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.alibaba.druid.sql.parser.*;
|
||||
import com.alibaba.druid.util.FnvHash;
|
||||
|
||||
public class MySqlLexer extends Lexer {
|
||||
public static SymbolTable quoteTable = new SymbolTable(8192);
|
||||
@@ -226,7 +227,8 @@ public class MySqlLexer extends Lexer {
|
||||
|
||||
final char first = ch;
|
||||
|
||||
if (ch == 'b' && charAt(pos + 1) == '\'') {
|
||||
if (ch == 'b'
|
||||
&& charAt(pos + 1) == '\'') {
|
||||
int i = 2;
|
||||
int mark = pos + 2;
|
||||
for (;;++i) {
|
||||
@@ -336,6 +338,7 @@ public class MySqlLexer extends Lexer {
|
||||
token = Token.IDENTIFIER;
|
||||
stringVal = SymbolTable.global.addSymbol(text, mark, bufPos, hash);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,7 +398,9 @@ public class MySqlLexer extends Lexer {
|
||||
stringVal = this.subString(mark + startHintSp, starIndex - startHintSp - mark);
|
||||
token = Token.HINT;
|
||||
} else {
|
||||
stringVal = this.subString(mark, starIndex + 2 - mark);
|
||||
if (!optimizedForParameterized) {
|
||||
stringVal = this.subString(mark, starIndex + 2 - mark);
|
||||
}
|
||||
token = Token.MULTI_LINE_COMMENT;
|
||||
commentCount++;
|
||||
if (keepComments) {
|
||||
|
||||
@@ -114,7 +114,7 @@ public class MySqlStatementParser extends SQLStatementParser {
|
||||
|
||||
public SQLCreateTableStatement parseCreateTable() {
|
||||
MySqlCreateTableParser parser = new MySqlCreateTableParser(this.exprParser);
|
||||
return parser.parseCrateTable();
|
||||
return parser.parseCreateTable();
|
||||
}
|
||||
|
||||
public SQLStatement parseSelect() {
|
||||
@@ -230,7 +230,7 @@ public class MySqlStatementParser extends SQLStatementParser {
|
||||
lexer.reset(markBp, markChar, Token.CREATE);
|
||||
}
|
||||
MySqlCreateTableParser parser = new MySqlCreateTableParser(this.exprParser);
|
||||
MySqlCreateTableStatement stmt = parser.parseCrateTable(false);
|
||||
MySqlCreateTableStatement stmt = parser.parseCreateTable(false);
|
||||
stmt.setHints(hints);
|
||||
|
||||
if (comments != null) {
|
||||
|
||||
@@ -200,13 +200,13 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV
|
||||
SQLOrderBy orderBy = x.getOrderBy();
|
||||
if (orderBy != null) {
|
||||
println();
|
||||
orderBy.accept(this);
|
||||
visit(orderBy);
|
||||
}
|
||||
|
||||
SQLLimit limit = x.getLimit();
|
||||
if (limit != null) {
|
||||
println();
|
||||
limit.accept(this);
|
||||
visit(limit);
|
||||
}
|
||||
|
||||
SQLName procedureName = x.getProcedureName();
|
||||
|
||||
+1
-3
@@ -1057,7 +1057,7 @@ public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements MySqlAS
|
||||
|
||||
@Override
|
||||
public boolean visit(MysqlForeignKey x) {
|
||||
return super.visit(x);
|
||||
return super.visit((SQLForeignKeyImpl) x);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1310,6 +1310,4 @@ public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements MySqlAS
|
||||
public void endVisit(MySqlFlushStatement x) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -118,6 +118,7 @@ public class FromSubqueryResolver extends OracleASTVisitorAdapter {
|
||||
String entryName = entry.getAlias();
|
||||
|
||||
SQLCreateViewStatement entryStmt = new SQLCreateViewStatement();
|
||||
entryStmt.setOrReplace(true);
|
||||
entryStmt.setDbType(stmt.getDbType());
|
||||
|
||||
String entryViewName = visitor.generateSubViewName();
|
||||
@@ -136,6 +137,7 @@ public class FromSubqueryResolver extends OracleASTVisitorAdapter {
|
||||
String dbType = stmt.getDbType();
|
||||
for (int i = 0; i < targetList.size() - 1; ++i) {
|
||||
SQLCreateViewStatement targetStmt = (SQLCreateViewStatement) targetList.get(i);
|
||||
targetStmt.setOrReplace(true);
|
||||
targetStmt.setDbType(dbType);
|
||||
targetStmt.setAfterSemi(true);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public class OdpsCreateTableParser extends SQLCreateTableParser {
|
||||
super(exprParser);
|
||||
}
|
||||
|
||||
public SQLCreateTableStatement parseCrateTable(boolean acceptCreate) {
|
||||
public SQLCreateTableStatement parseCreateTable(boolean acceptCreate) {
|
||||
OdpsCreateTableStatement stmt = new OdpsCreateTableStatement();
|
||||
|
||||
if (acceptCreate) {
|
||||
|
||||
@@ -72,7 +72,7 @@ public class OdpsStatementParser extends SQLStatementParser {
|
||||
|
||||
public SQLCreateTableStatement parseCreateTable() {
|
||||
SQLCreateTableParser parser = new OdpsCreateTableParser(this.exprParser);
|
||||
return parser.parseCrateTable();
|
||||
return parser.parseCreateTable();
|
||||
}
|
||||
|
||||
public SQLCreateTableParser getSQLCreateTableParser() {
|
||||
|
||||
+2
-9
@@ -15,19 +15,12 @@
|
||||
*/
|
||||
package com.alibaba.druid.sql.dialect.oracle.parser;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.SQLName;
|
||||
import com.alibaba.druid.sql.ast.SQLPartition;
|
||||
import com.alibaba.druid.sql.ast.SQLPartitionBy;
|
||||
import com.alibaba.druid.sql.ast.SQLPartitionByHash;
|
||||
import com.alibaba.druid.sql.ast.SQLPartitionByList;
|
||||
import com.alibaba.druid.sql.ast.SQLPartitionByRange;
|
||||
import com.alibaba.druid.sql.ast.SQLSubPartition;
|
||||
import com.alibaba.druid.sql.ast.SQLSubPartitionBy;
|
||||
import com.alibaba.druid.sql.ast.SQLSubPartitionByHash;
|
||||
import com.alibaba.druid.sql.ast.SQLSubPartitionByList;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLNumericLiteralExpr;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelect;
|
||||
@@ -53,8 +46,8 @@ public class OracleCreateTableParser extends SQLCreateTableParser {
|
||||
return new OracleCreateTableStatement();
|
||||
}
|
||||
|
||||
public OracleCreateTableStatement parseCrateTable(boolean acceptCreate) {
|
||||
OracleCreateTableStatement stmt = (OracleCreateTableStatement) super.parseCrateTable(acceptCreate);
|
||||
public OracleCreateTableStatement parseCreateTable(boolean acceptCreate) {
|
||||
OracleCreateTableStatement stmt = (OracleCreateTableStatement) super.parseCreateTable(acceptCreate);
|
||||
|
||||
if (lexer.token() == Token.OF) {
|
||||
lexer.nextToken();
|
||||
|
||||
@@ -216,6 +216,7 @@ public class OracleExprParser extends SQLExprParser {
|
||||
|
||||
if ("TIMESTAMP".equalsIgnoreCase(typeName)) {
|
||||
SQLDataTypeImpl timestamp = new SQLDataTypeImpl(typeName);
|
||||
timestamp.setDbType(dbType);
|
||||
|
||||
if (lexer.token() == Token.LPAREN) {
|
||||
lexer.nextToken();
|
||||
@@ -280,7 +281,8 @@ public class OracleExprParser extends SQLExprParser {
|
||||
}
|
||||
|
||||
|
||||
SQLDataType dataType = new SQLDataTypeImpl(typeName);
|
||||
SQLDataTypeImpl dataType = new SQLDataTypeImpl(typeName);
|
||||
dataType.setDbType(dbType);
|
||||
return parseDataTypeRest(dataType);
|
||||
}
|
||||
|
||||
@@ -700,14 +702,14 @@ public class OracleExprParser extends SQLExprParser {
|
||||
return expr;
|
||||
}
|
||||
|
||||
if (lexer.identifierEquals("NEXTVAL")) {
|
||||
if (lexer.identifierEquals(FnvHash.Constants.NEXTVAL)) {
|
||||
if (expr instanceof SQLIdentifierExpr) {
|
||||
SQLIdentifierExpr identExpr = (SQLIdentifierExpr) expr;
|
||||
SQLSequenceExpr seqExpr = new SQLSequenceExpr(identExpr, SQLSequenceExpr.Function.NextVal);
|
||||
lexer.nextToken();
|
||||
return seqExpr;
|
||||
}
|
||||
} else if (lexer.identifierEquals("CURRVAL")) {
|
||||
} else if (lexer.identifierEquals(FnvHash.Constants.CURRVAL)) {
|
||||
if (expr instanceof SQLIdentifierExpr) {
|
||||
SQLIdentifierExpr identExpr = (SQLIdentifierExpr) expr;
|
||||
SQLSequenceExpr seqExpr = new SQLSequenceExpr(identExpr, SQLSequenceExpr.Function.CurrVal);
|
||||
@@ -1404,12 +1406,12 @@ public class OracleExprParser extends SQLExprParser {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lexer.identifierEquals("VALIDATE")) {
|
||||
if (lexer.identifierEquals(FnvHash.Constants.VALIDATE)) {
|
||||
lexer.nextToken();
|
||||
constraint.setValidate(Boolean.TRUE);
|
||||
continue;
|
||||
}
|
||||
if (lexer.identifierEquals("NOVALIDATE")) {
|
||||
if (lexer.identifierEquals(FnvHash.Constants.NOVALIDATE)) {
|
||||
lexer.nextToken();
|
||||
constraint.setValidate(Boolean.FALSE);
|
||||
continue;
|
||||
@@ -1431,7 +1433,7 @@ public class OracleExprParser extends SQLExprParser {
|
||||
|
||||
if (lexer.token() == Token.NOT) {
|
||||
lexer.nextToken();
|
||||
if (lexer.identifierEquals("DEFERRABLE")) {
|
||||
if (lexer.identifierEquals(FnvHash.Constants.DEFERRABLE)) {
|
||||
lexer.nextToken();
|
||||
constraint.setDeferrable(false);
|
||||
continue;
|
||||
@@ -1439,11 +1441,16 @@ public class OracleExprParser extends SQLExprParser {
|
||||
throw new ParserException("TODO " + lexer.info());
|
||||
}
|
||||
|
||||
if (lexer.identifierEquals("DEFERRABLE")) {
|
||||
if (lexer.identifierEquals(FnvHash.Constants.DEFERRABLE)) {
|
||||
lexer.nextToken();
|
||||
constraint.setDeferrable(true);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lexer.token() == Token.USING) {
|
||||
OracleUsingIndexClause using = parseUsingIndex();
|
||||
constraint.setUsing(using);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -247,7 +247,7 @@ public class OracleSelectParser extends SQLSelectParser {
|
||||
}
|
||||
|
||||
public SQLSelectQuery query() {
|
||||
if (lexer.token() == (Token.LPAREN)) {
|
||||
if (lexer.token() == Token.LPAREN) {
|
||||
lexer.nextToken();
|
||||
|
||||
SQLSelectQuery select = query();
|
||||
@@ -270,13 +270,13 @@ public class OracleSelectParser extends SQLSelectParser {
|
||||
|
||||
parseHints(queryBlock);
|
||||
|
||||
if (lexer.token() == (Token.DISTINCT)) {
|
||||
if (lexer.token() == Token.DISTINCT) {
|
||||
queryBlock.setDistionOption(SQLSetQuantifier.DISTINCT);
|
||||
lexer.nextToken();
|
||||
} else if (lexer.token() == (Token.UNIQUE)) {
|
||||
} else if (lexer.token() == Token.UNIQUE) {
|
||||
queryBlock.setDistionOption(SQLSetQuantifier.UNIQUE);
|
||||
lexer.nextToken();
|
||||
} else if (lexer.token() == (Token.ALL)) {
|
||||
} else if (lexer.token() == Token.ALL) {
|
||||
queryBlock.setDistionOption(SQLSetQuantifier.ALL);
|
||||
lexer.nextToken();
|
||||
}
|
||||
@@ -304,16 +304,16 @@ public class OracleSelectParser extends SQLSelectParser {
|
||||
}
|
||||
|
||||
public SQLSelectQuery queryRest(SQLSelectQuery selectQuery) {
|
||||
if (lexer.token() == (Token.UNION)) {
|
||||
if (lexer.token() == Token.UNION) {
|
||||
SQLUnionQuery union = new SQLUnionQuery();
|
||||
union.setLeft(selectQuery);
|
||||
|
||||
lexer.nextToken();
|
||||
|
||||
if (lexer.token() == (Token.ALL)) {
|
||||
if (lexer.token() == Token.ALL) {
|
||||
union.setOperator(SQLUnionOperator.UNION_ALL);
|
||||
lexer.nextToken();
|
||||
} else if (lexer.token() == (Token.DISTINCT)) {
|
||||
} else if (lexer.token() == Token.DISTINCT) {
|
||||
union.setOperator(SQLUnionOperator.DISTINCT);
|
||||
lexer.nextToken();
|
||||
}
|
||||
@@ -582,10 +582,6 @@ public class OracleSelectParser extends SQLSelectParser {
|
||||
}
|
||||
}
|
||||
|
||||
protected String as() {
|
||||
return super.as();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLTableSource parseTableSource() {
|
||||
SQLTableSource tableSource = parseTableSourcePrimary();
|
||||
@@ -601,11 +597,11 @@ public class OracleSelectParser extends SQLSelectParser {
|
||||
if (lexer.token() == (Token.LPAREN)) {
|
||||
lexer.nextToken();
|
||||
|
||||
OracleSelectSubqueryTableSource tableSource;
|
||||
OracleSelectTableSource tableSource;
|
||||
if (lexer.token() == Token.SELECT || lexer.token() == Token.WITH) {
|
||||
tableSource = new OracleSelectSubqueryTableSource(select());
|
||||
} else if (lexer.token() == (Token.LPAREN)) {
|
||||
tableSource = new OracleSelectSubqueryTableSource(select());
|
||||
} else if (lexer.token() == Token.LPAREN) {
|
||||
tableSource = (OracleSelectTableSource) parseTableSource();
|
||||
} else if (lexer.token() == Token.IDENTIFIER) {
|
||||
SQLTableSource identTable = parseTableSource();
|
||||
accept(Token.RPAREN);
|
||||
@@ -613,9 +609,17 @@ public class OracleSelectParser extends SQLSelectParser {
|
||||
} else {
|
||||
throw new ParserException("TODO :" + lexer.info());
|
||||
}
|
||||
|
||||
accept(Token.RPAREN);
|
||||
|
||||
parsePivot((OracleSelectTableSource) tableSource);
|
||||
if (lexer.token() == Token.UNION && tableSource instanceof OracleSelectSubqueryTableSource) {
|
||||
OracleSelectSubqueryTableSource selectSubqueryTableSource = (OracleSelectSubqueryTableSource) tableSource;
|
||||
SQLSelect select = selectSubqueryTableSource.getSelect();
|
||||
SQLSelectQuery selectQuery = this.queryRest(select.getQuery());
|
||||
select.setQuery(selectQuery);
|
||||
}
|
||||
|
||||
parsePivot(tableSource);
|
||||
|
||||
return tableSource;
|
||||
}
|
||||
|
||||
@@ -1606,6 +1606,7 @@ public class OracleStatementParser extends SQLStatementParser {
|
||||
accept(Token.CURSOR);
|
||||
|
||||
dataType = new SQLDataTypeImpl("REF CURSOR");
|
||||
dataType.setDbType(dbType);
|
||||
} else if (lexer.token() == Token.TABLE) {
|
||||
lexer.nextToken();
|
||||
accept(Token.OF);
|
||||
@@ -1619,6 +1620,7 @@ public class OracleStatementParser extends SQLStatementParser {
|
||||
|
||||
String typeName = "TABLE OF " + name.toString() + "%TYPE";
|
||||
dataType = new SQLDataTypeImpl(typeName);
|
||||
dataType.setDbType(dbType);
|
||||
} else if (lexer.identifierEquals("VARRAY")) {
|
||||
lexer.nextToken();
|
||||
accept(Token.LPAREN);
|
||||
@@ -1630,6 +1632,7 @@ public class OracleStatementParser extends SQLStatementParser {
|
||||
lexer.nextToken();
|
||||
String typeName = "VARRAY(" + len + ") OF NUMBER";
|
||||
dataType = new SQLDataTypeImpl(typeName);
|
||||
dataType.setDbType(dbType);
|
||||
} else {
|
||||
throw new ParserException("TODO : " + lexer.info());
|
||||
}
|
||||
|
||||
+9
-4
@@ -139,10 +139,15 @@ public class SQLServerObjectReferenceExpr extends SQLServerObjectImpl implements
|
||||
@Override
|
||||
public long hashCode64() {
|
||||
if (hashCode64 == 0) {
|
||||
hashCode64 = new SQLPropertyExpr(
|
||||
new SQLPropertyExpr(server, database)
|
||||
, schema)
|
||||
.hashCode64();
|
||||
if (server == null) {
|
||||
hashCode64 = new SQLPropertyExpr(
|
||||
new SQLPropertyExpr(server, database)
|
||||
, schema)
|
||||
.hashCode64();
|
||||
} else {
|
||||
hashCode64 = new SQLPropertyExpr(database, schema)
|
||||
.hashCode64();
|
||||
}
|
||||
}
|
||||
return hashCode64;
|
||||
}
|
||||
|
||||
@@ -19,19 +19,9 @@ import static com.alibaba.druid.sql.parser.CharTypes.isFirstIdentifierChar;
|
||||
import static com.alibaba.druid.sql.parser.CharTypes.isIdentifierChar;
|
||||
import static com.alibaba.druid.sql.parser.CharTypes.isWhitespace;
|
||||
import static com.alibaba.druid.sql.parser.LayoutCharacters.EOI;
|
||||
import static com.alibaba.druid.sql.parser.Token.COLONCOLON;
|
||||
import static com.alibaba.druid.sql.parser.Token.COLONEQ;
|
||||
import static com.alibaba.druid.sql.parser.Token.COMMA;
|
||||
import static com.alibaba.druid.sql.parser.Token.EOF;
|
||||
import static com.alibaba.druid.sql.parser.Token.ERROR;
|
||||
import static com.alibaba.druid.sql.parser.Token.LBRACE;
|
||||
import static com.alibaba.druid.sql.parser.Token.LBRACKET;
|
||||
import static com.alibaba.druid.sql.parser.Token.LITERAL_ALIAS;
|
||||
import static com.alibaba.druid.sql.parser.Token.LITERAL_CHARS;
|
||||
import static com.alibaba.druid.sql.parser.Token.LPAREN;
|
||||
import static com.alibaba.druid.sql.parser.Token.RBRACE;
|
||||
import static com.alibaba.druid.sql.parser.Token.RBRACKET;
|
||||
import static com.alibaba.druid.sql.parser.Token.RPAREN;
|
||||
import static com.alibaba.druid.sql.parser.SQLParserFeature.KeepComments;
|
||||
import static com.alibaba.druid.sql.parser.SQLParserFeature.OptimizedForParameterized;
|
||||
import static com.alibaba.druid.sql.parser.Token.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
@@ -49,6 +39,7 @@ import com.alibaba.druid.util.StringUtils;
|
||||
* @author wenshao [szujobs@hotmail.com]
|
||||
*/
|
||||
public class Lexer {
|
||||
protected static SymbolTable symbols_l2 = new SymbolTable(512);
|
||||
|
||||
protected int features = 0; //SQLParserFeature.of(SQLParserFeature.EnableSQLBinaryOpExprGroup);
|
||||
protected final String text;
|
||||
@@ -69,29 +60,24 @@ public class Lexer {
|
||||
protected long hash;
|
||||
|
||||
protected int commentCount = 0;
|
||||
|
||||
protected List<String> comments = new ArrayList<String>(2);
|
||||
|
||||
protected boolean skipComment = true;
|
||||
|
||||
private SavePoint savePoint = null;
|
||||
|
||||
/*
|
||||
* anti sql injection
|
||||
*/
|
||||
private boolean allowComment = true;
|
||||
|
||||
private int varIndex = -1;
|
||||
|
||||
protected CommentHandler commentHandler;
|
||||
protected boolean endOfComment = false;
|
||||
protected boolean keepComments = false;
|
||||
|
||||
protected int line = 0;
|
||||
protected int lines = 0;
|
||||
|
||||
protected String dbType;
|
||||
|
||||
protected boolean optimizedForParameterized = false;
|
||||
|
||||
private int startPos;
|
||||
private int posLine;
|
||||
private int posColumn;
|
||||
@@ -316,6 +302,12 @@ public class Lexer {
|
||||
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') {
|
||||
@@ -837,6 +829,7 @@ public class Lexer {
|
||||
protected void scanString() {
|
||||
mark = pos;
|
||||
boolean hasSpecial = false;
|
||||
Token preToken = this.token;
|
||||
|
||||
for (;;) {
|
||||
if (isEOF()) {
|
||||
@@ -875,7 +868,11 @@ public class Lexer {
|
||||
}
|
||||
|
||||
if (!hasSpecial) {
|
||||
stringVal = subString(mark + 1, bufPos);
|
||||
if (preToken == Token.AS) {
|
||||
stringVal = subString(mark, bufPos + 2);
|
||||
} else {
|
||||
stringVal = subString(mark + 1, bufPos);
|
||||
}
|
||||
} else {
|
||||
stringVal = new String(buf, 0, bufPos);
|
||||
}
|
||||
@@ -902,7 +899,12 @@ public class Lexer {
|
||||
throw new ParserException("unclosed str. " + info());
|
||||
}
|
||||
|
||||
String stringVal = subString(startIndex, endIndex - startIndex);
|
||||
String stringVal;
|
||||
if (token == Token.AS) {
|
||||
stringVal = subString(pos, endIndex + 1 - pos);
|
||||
} else {
|
||||
stringVal = subString(startIndex, endIndex - startIndex);
|
||||
}
|
||||
// hasSpecial = stringVal.indexOf('\\') != -1;
|
||||
|
||||
if (!hasSpecial) {
|
||||
@@ -1537,6 +1539,15 @@ public class Lexer {
|
||||
return stringVal;
|
||||
}
|
||||
|
||||
private final void stringVal(StringBuffer out) {
|
||||
if (stringVal != null) {
|
||||
out.append(stringVal);
|
||||
return;
|
||||
}
|
||||
|
||||
out.append(text, mark, mark + bufPos);
|
||||
}
|
||||
|
||||
public final boolean identifierEquals(String text) {
|
||||
if (token != Token.IDENTIFIER) {
|
||||
return false;
|
||||
@@ -1799,9 +1810,69 @@ public class Lexer {
|
||||
|
||||
public void config(SQLParserFeature feature, boolean state) {
|
||||
features = SQLParserFeature.config(features, feature, state);
|
||||
|
||||
if (feature == OptimizedForParameterized) {
|
||||
optimizedForParameterized = state;
|
||||
} else if (feature == KeepComments) {
|
||||
this.keepComments = state;
|
||||
}
|
||||
}
|
||||
|
||||
public final boolean isEnabled(SQLParserFeature feature) {
|
||||
return SQLParserFeature.isEnabled(this.features, feature);
|
||||
}
|
||||
|
||||
public static String parameterize(String sql, String dbType) {
|
||||
Lexer lexer = SQLParserUtils.createLexer(sql, dbType);
|
||||
lexer.optimizedForParameterized = true; // optimized
|
||||
|
||||
lexer.nextToken();
|
||||
|
||||
StringBuffer buf = new StringBuffer();
|
||||
|
||||
for_:
|
||||
for (;;) {
|
||||
Token token = lexer.token;
|
||||
switch (token) {
|
||||
case LITERAL_ALIAS:
|
||||
case LITERAL_FLOAT:
|
||||
case LITERAL_CHARS:
|
||||
case LITERAL_INT:
|
||||
case LITERAL_NCHARS:
|
||||
case LITERAL_HEX:
|
||||
case VARIANT:
|
||||
if (buf.length() != 0) {
|
||||
buf.append(' ');
|
||||
}
|
||||
buf.append('?');
|
||||
break;
|
||||
case COMMA:
|
||||
buf.append(',');
|
||||
break;
|
||||
case EQ:
|
||||
buf.append('=');
|
||||
break;
|
||||
case EOF:
|
||||
break for_;
|
||||
case ERROR:
|
||||
return sql;
|
||||
case SELECT:
|
||||
buf.append("SELECT");
|
||||
break;
|
||||
case UPDATE:
|
||||
buf.append("UPDATE");
|
||||
break;
|
||||
default:
|
||||
if (buf.length() != 0) {
|
||||
buf.append(' ');
|
||||
}
|
||||
lexer.stringVal(buf);
|
||||
break;
|
||||
}
|
||||
|
||||
lexer.nextToken();
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,13 +31,13 @@ public class SQLCreateTableParser extends SQLDDLParser {
|
||||
super(exprParser);
|
||||
}
|
||||
|
||||
public SQLCreateTableStatement parseCrateTable() {
|
||||
public SQLCreateTableStatement parseCreateTable() {
|
||||
List<String> comments = null;
|
||||
if (lexer.isKeepComments() && lexer.hasComment()) {
|
||||
comments = lexer.readAndResetComments();
|
||||
}
|
||||
|
||||
SQLCreateTableStatement stmt = parseCrateTable(true);
|
||||
SQLCreateTableStatement stmt = parseCreateTable(true);
|
||||
if (comments != null) {
|
||||
stmt.addBeforeComment(comments);
|
||||
}
|
||||
@@ -45,7 +45,7 @@ public class SQLCreateTableParser extends SQLDDLParser {
|
||||
return stmt;
|
||||
}
|
||||
|
||||
public SQLCreateTableStatement parseCrateTable(boolean acceptCreate) {
|
||||
public SQLCreateTableStatement parseCreateTable(boolean acceptCreate) {
|
||||
SQLCreateTableStatement createTable = newCreateStatement();
|
||||
|
||||
if (acceptCreate) {
|
||||
|
||||
@@ -237,7 +237,14 @@ public class SQLExprParser extends SQLParser {
|
||||
expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.DIV, rightExp, getDbType());
|
||||
expr = multiplicativeRest(expr);
|
||||
} else if (lexer.identifierEquals(FnvHash.Constants.MOD)) {
|
||||
Lexer.SavePoint savePoint = lexer.mark();
|
||||
lexer.nextToken();
|
||||
|
||||
if (lexer.token == Token.COMMA) {
|
||||
lexer.reset(savePoint);
|
||||
return expr;
|
||||
}
|
||||
|
||||
SQLExpr rightExp = primary();
|
||||
|
||||
rightExp = relationalRest(rightExp);
|
||||
@@ -308,10 +315,11 @@ public class SQLExprParser extends SQLParser {
|
||||
long hash_lower = lexer.hash_lower;
|
||||
lexer.nextToken();
|
||||
|
||||
if ("DATE".equalsIgnoreCase(ident)
|
||||
if (hash_lower == FnvHash.Constants.DATE
|
||||
&& lexer.token == Token.LITERAL_CHARS
|
||||
&& (JdbcConstants.ORACLE.equals(getDbType())
|
||||
|| JdbcConstants.POSTGRESQL.equals(getDbType()))) {
|
||||
&& (JdbcConstants.ORACLE.equals(dbType)
|
||||
|| JdbcConstants.POSTGRESQL.equals(dbType)
|
||||
|| JdbcConstants.MYSQL.equals(dbType))) {
|
||||
String literal = lexer.stringVal();
|
||||
lexer.nextToken();
|
||||
|
||||
@@ -450,6 +458,7 @@ public class SQLExprParser extends SQLParser {
|
||||
case DESC:
|
||||
case DO:
|
||||
case GROUP:
|
||||
case MOD:
|
||||
sqlExpr = new SQLIdentifierExpr(lexer.stringVal());
|
||||
lexer.nextToken();
|
||||
break;
|
||||
@@ -1021,42 +1030,7 @@ public class SQLExprParser extends SQLParser {
|
||||
}
|
||||
|
||||
if (lexer.token == Token.LPAREN) {
|
||||
lexer.nextToken();
|
||||
|
||||
if (lexer.token == Token.DISTINCT) {
|
||||
lexer.nextToken();
|
||||
|
||||
String aggreateMethodName = expr.toString() + "." + name;
|
||||
SQLAggregateExpr aggregateExpr = new SQLAggregateExpr(aggreateMethodName, SQLAggregateOption.DISTINCT);
|
||||
|
||||
if (lexer.token == Token.RPAREN) {
|
||||
lexer.nextToken();
|
||||
} else {
|
||||
if (lexer.token == Token.PLUS) {
|
||||
aggregateExpr.getArguments().add(new SQLIdentifierExpr("+"));
|
||||
lexer.nextToken();
|
||||
} else {
|
||||
exprList(aggregateExpr.getArguments(), aggregateExpr);
|
||||
}
|
||||
accept(Token.RPAREN);
|
||||
}
|
||||
expr = aggregateExpr;
|
||||
} else {
|
||||
SQLMethodInvokeExpr methodInvokeExpr = new SQLMethodInvokeExpr(name);
|
||||
methodInvokeExpr.setOwner(expr);
|
||||
if (lexer.token == Token.RPAREN) {
|
||||
lexer.nextToken();
|
||||
} else {
|
||||
if (lexer.token == Token.PLUS) {
|
||||
methodInvokeExpr.addParameter(new SQLIdentifierExpr("+"));
|
||||
lexer.nextToken();
|
||||
} else {
|
||||
exprList(methodInvokeExpr.getParameters(), methodInvokeExpr);
|
||||
}
|
||||
accept(Token.RPAREN);
|
||||
}
|
||||
expr = methodInvokeExpr;
|
||||
}
|
||||
expr = methodRest(expr, name);
|
||||
} else {
|
||||
expr = new SQLPropertyExpr(expr, name, hash_lower);
|
||||
}
|
||||
@@ -1066,6 +1040,46 @@ public class SQLExprParser extends SQLParser {
|
||||
return expr;
|
||||
}
|
||||
|
||||
private SQLExpr methodRest(SQLExpr expr, String name) {
|
||||
lexer.nextToken();
|
||||
|
||||
if (lexer.token == Token.DISTINCT) {
|
||||
lexer.nextToken();
|
||||
|
||||
String aggreateMethodName = expr.toString() + "." + name;
|
||||
SQLAggregateExpr aggregateExpr = new SQLAggregateExpr(aggreateMethodName, SQLAggregateOption.DISTINCT);
|
||||
|
||||
if (lexer.token == Token.RPAREN) {
|
||||
lexer.nextToken();
|
||||
} else {
|
||||
if (lexer.token == Token.PLUS) {
|
||||
aggregateExpr.getArguments().add(new SQLIdentifierExpr("+"));
|
||||
lexer.nextToken();
|
||||
} else {
|
||||
exprList(aggregateExpr.getArguments(), aggregateExpr);
|
||||
}
|
||||
accept(Token.RPAREN);
|
||||
}
|
||||
expr = aggregateExpr;
|
||||
} else {
|
||||
SQLMethodInvokeExpr methodInvokeExpr = new SQLMethodInvokeExpr(name);
|
||||
methodInvokeExpr.setOwner(expr);
|
||||
if (lexer.token == Token.RPAREN) {
|
||||
lexer.nextToken();
|
||||
} else {
|
||||
if (lexer.token == Token.PLUS) {
|
||||
methodInvokeExpr.addParameter(new SQLIdentifierExpr("+"));
|
||||
lexer.nextToken();
|
||||
} else {
|
||||
exprList(methodInvokeExpr.getParameters(), methodInvokeExpr);
|
||||
}
|
||||
accept(Token.RPAREN);
|
||||
}
|
||||
expr = methodInvokeExpr;
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
public final SQLExpr groupComparisionRest(SQLExpr expr) {
|
||||
return expr;
|
||||
}
|
||||
@@ -2089,7 +2103,7 @@ public class SQLExprParser extends SQLParser {
|
||||
}
|
||||
|
||||
SQLDataType dataType = new SQLDataTypeImpl(typeName);
|
||||
|
||||
dataType.setDbType(dbType);
|
||||
|
||||
return parseDataTypeRest(dataType);
|
||||
}
|
||||
@@ -2576,6 +2590,39 @@ public class SQLExprParser extends SQLParser {
|
||||
}
|
||||
|
||||
token = lexer.token;
|
||||
|
||||
if (token == Token.DOT) {
|
||||
lexer.nextToken();
|
||||
String name;
|
||||
long name_hash_lower;
|
||||
|
||||
if (lexer.token == Token.STAR) {
|
||||
name = "*";
|
||||
name_hash_lower = FnvHash.Constants.STAR;
|
||||
} else {
|
||||
name = lexer.stringVal();
|
||||
name_hash_lower = lexer.hash_lower();
|
||||
}
|
||||
|
||||
lexer.nextTokenComma();
|
||||
|
||||
token = lexer.token;
|
||||
if (token == Token.LPAREN) {
|
||||
expr = methodRest(expr, name);
|
||||
token = lexer.token;
|
||||
} else {
|
||||
if (name_hash_lower == FnvHash.Constants.NEXTVAL) {
|
||||
expr = new SQLSequenceExpr((SQLIdentifierExpr) expr, SQLSequenceExpr.Function.NextVal);
|
||||
} else if (name_hash_lower == FnvHash.Constants.CURRVAL) {
|
||||
expr = new SQLSequenceExpr((SQLIdentifierExpr) expr, SQLSequenceExpr.Function.CurrVal);
|
||||
} else if (name_hash_lower == FnvHash.Constants.PREVVAL) {
|
||||
expr = new SQLSequenceExpr((SQLIdentifierExpr) expr, SQLSequenceExpr.Function.PrevVal);
|
||||
} else {
|
||||
expr = new SQLPropertyExpr(expr, name, name_hash_lower);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (token == Token.COMMA) {
|
||||
return new SQLSelectItem(expr, null, connectByRoot);
|
||||
}
|
||||
@@ -2583,6 +2630,7 @@ public class SQLExprParser extends SQLParser {
|
||||
if (token == Token.AS) {
|
||||
lexer.nextToken();
|
||||
String as = lexer.stringVal();
|
||||
|
||||
lexer.nextTokenComma();
|
||||
return new SQLSelectItem(expr, as, connectByRoot);
|
||||
}
|
||||
|
||||
@@ -103,8 +103,8 @@ public class SQLParser {
|
||||
|
||||
if (token == Token.AS) {
|
||||
lexer.nextToken();
|
||||
|
||||
alias = alias();
|
||||
alias = lexer.stringVal();
|
||||
lexer.nextToken();
|
||||
|
||||
if (alias != null) {
|
||||
while (lexer.token == Token.DOT) {
|
||||
@@ -142,6 +142,7 @@ public class SQLParser {
|
||||
case OUTER:
|
||||
case DO:
|
||||
case STORE:
|
||||
case MOD:
|
||||
alias = lexer.stringVal();
|
||||
lexer.nextToken();
|
||||
break;
|
||||
|
||||
@@ -17,7 +17,9 @@ package com.alibaba.druid.sql.parser;
|
||||
|
||||
public enum SQLParserFeature {
|
||||
KeepInsertValueClauseOriginalString,
|
||||
EnableSQLBinaryOpExprGroup
|
||||
EnableSQLBinaryOpExprGroup,
|
||||
OptimizedForParameterized,
|
||||
KeepComments
|
||||
;
|
||||
|
||||
private SQLParserFeature(){
|
||||
|
||||
@@ -42,26 +42,37 @@ import com.alibaba.druid.util.JdbcUtils;
|
||||
public class SQLParserUtils {
|
||||
|
||||
public static SQLStatementParser createSQLStatementParser(String sql, String dbType) {
|
||||
boolean keepComments;
|
||||
SQLParserFeature[] features;
|
||||
if (JdbcConstants.ODPS.equals(dbType) || JdbcConstants.MYSQL.equals(dbType)) {
|
||||
keepComments = true;
|
||||
features = new SQLParserFeature[] {SQLParserFeature.KeepComments};
|
||||
} else {
|
||||
keepComments = false;
|
||||
features = new SQLParserFeature[] {};
|
||||
}
|
||||
return createSQLStatementParser(sql, dbType, keepComments);
|
||||
return createSQLStatementParser(sql, dbType, features);
|
||||
}
|
||||
|
||||
public static SQLStatementParser createSQLStatementParser(String sql, String dbType, boolean keepComments) {
|
||||
SQLParserFeature[] features;
|
||||
if (keepComments) {
|
||||
features = new SQLParserFeature[] {SQLParserFeature.KeepComments};
|
||||
} else {
|
||||
features = new SQLParserFeature[] {};
|
||||
}
|
||||
|
||||
return createSQLStatementParser(sql, dbType, features);
|
||||
}
|
||||
|
||||
public static SQLStatementParser createSQLStatementParser(String sql, String dbType, SQLParserFeature... features) {
|
||||
if (JdbcUtils.ORACLE.equals(dbType) || JdbcUtils.ALI_ORACLE.equals(dbType)) {
|
||||
return new OracleStatementParser(sql);
|
||||
}
|
||||
|
||||
if (JdbcUtils.MYSQL.equals(dbType)) {
|
||||
return new MySqlStatementParser(sql, keepComments);
|
||||
return new MySqlStatementParser(sql, features);
|
||||
}
|
||||
|
||||
if (JdbcUtils.MARIADB.equals(dbType)) {
|
||||
return new MySqlStatementParser(sql, keepComments);
|
||||
return new MySqlStatementParser(sql, features);
|
||||
}
|
||||
|
||||
if (JdbcUtils.POSTGRESQL.equals(dbType)
|
||||
|
||||
@@ -24,7 +24,6 @@ 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.statement.*;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLCreateTriggerStatement.TriggerEvent;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLCreateTriggerStatement.TriggerType;
|
||||
import com.alibaba.druid.sql.dialect.oracle.parser.OracleExprParser;
|
||||
import com.alibaba.druid.util.FnvHash;
|
||||
@@ -1814,7 +1813,7 @@ public class SQLStatementParser extends SQLParser {
|
||||
|
||||
if (token == Token.TABLE || lexer.identifierEquals("GLOBAL")) {
|
||||
SQLCreateTableParser createTableParser = getSQLCreateTableParser();
|
||||
SQLCreateTableStatement stmt = createTableParser.parseCrateTable(false);
|
||||
SQLCreateTableStatement stmt = createTableParser.parseCreateTable(false);
|
||||
|
||||
if (comments != null) {
|
||||
stmt.addBeforeComment(comments);
|
||||
@@ -2230,7 +2229,7 @@ public class SQLStatementParser extends SQLParser {
|
||||
|
||||
public SQLCreateTableStatement parseCreateTable() {
|
||||
// SQLCreateTableParser parser = new SQLCreateTableParser(this.lexer);
|
||||
// return parser.parseCrateTable();
|
||||
// return parser.parseCreateTable();
|
||||
throw new ParserException("TODO");
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,6 @@ public class SymbolTable {
|
||||
public SymbolTable(int tableSize){
|
||||
this.indexMask = tableSize - 1;
|
||||
this.entries = new Entry[tableSize];
|
||||
|
||||
// this.addSymbol("id", 0, 2, "id".hashCode());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.alibaba.druid.sql.ast.expr.*;
|
||||
import com.alibaba.druid.sql.ast.statement.*;
|
||||
import com.alibaba.druid.sql.dialect.db2.ast.stmt.DB2SelectQueryBlock;
|
||||
import com.alibaba.druid.sql.dialect.db2.visitor.DB2ASTVisitorAdapter;
|
||||
import com.alibaba.druid.sql.dialect.mysql.ast.MysqlForeignKey;
|
||||
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorDeclareStatement;
|
||||
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlDeclareStatement;
|
||||
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlRepeatStatement;
|
||||
@@ -74,6 +75,11 @@ class SchemaResolveVisitorFactory {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean visit(MysqlForeignKey x) {
|
||||
resolve(this, x);
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean visit(SQLExprTableSource x) {
|
||||
resolve(this, x);
|
||||
return false;
|
||||
@@ -251,6 +257,11 @@ class SchemaResolveVisitorFactory {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public boolean visit(SQLForeignKeyImpl x) {
|
||||
resolve(this, x);
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean visit(SQLSelectStatement x) {
|
||||
resolve(this, x.getSelect());
|
||||
return false;
|
||||
@@ -456,6 +467,11 @@ class SchemaResolveVisitorFactory {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean visit(OracleForeignKey x) {
|
||||
resolve(this, x);
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean visit(SQLIfStatement x) {
|
||||
resolve(this, x);
|
||||
return false;
|
||||
@@ -665,6 +681,11 @@ class SchemaResolveVisitorFactory {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public boolean visit(SQLForeignKeyImpl x) {
|
||||
resolve(this, x);
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean visit(SQLSelectStatement x) {
|
||||
resolve(this, x.getSelect());
|
||||
return false;
|
||||
@@ -843,6 +864,11 @@ class SchemaResolveVisitorFactory {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public boolean visit(SQLForeignKeyImpl x) {
|
||||
resolve(this, x);
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean visit(SQLSelectStatement x) {
|
||||
resolve(this, x.getSelect());
|
||||
return false;
|
||||
@@ -1032,6 +1058,11 @@ class SchemaResolveVisitorFactory {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public boolean visit(SQLForeignKeyImpl x) {
|
||||
resolve(this, x);
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean visit(SQLSelectStatement x) {
|
||||
resolve(this, x.getSelect());
|
||||
return false;
|
||||
@@ -1193,6 +1224,11 @@ class SchemaResolveVisitorFactory {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public boolean visit(SQLForeignKeyImpl x) {
|
||||
resolve(this, x);
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean visit(SQLSelectStatement x) {
|
||||
resolve(this, x.getSelect());
|
||||
return false;
|
||||
@@ -2408,6 +2444,62 @@ class SchemaResolveVisitorFactory {
|
||||
return false;
|
||||
}
|
||||
|
||||
static void resolve(SchemaResolveVisitor visitor, SQLForeignKeyConstraint x) {
|
||||
SchemaRepository repository = visitor.getRepository();
|
||||
SQLObject parent = x.getParent();
|
||||
|
||||
if (parent instanceof SQLCreateTableStatement) {
|
||||
SQLCreateTableStatement createTableStmt = (SQLCreateTableStatement) parent;
|
||||
SQLTableSource table = createTableStmt.getTableSource();
|
||||
for (SQLName item : x.getReferencingColumns()) {
|
||||
SQLIdentifierExpr columnName = (SQLIdentifierExpr) item;
|
||||
columnName.setResolvedTableSource(table);
|
||||
|
||||
SQLColumnDefinition column = createTableStmt.findColumn(columnName.nameHashCode64());
|
||||
if (column != null) {
|
||||
columnName.setResolvedColumn(column);
|
||||
}
|
||||
}
|
||||
} else if (parent instanceof SQLAlterTableAddConstraint) {
|
||||
SQLAlterTableStatement stmt = (SQLAlterTableStatement) parent.getParent();
|
||||
SQLTableSource table = stmt.getTableSource();
|
||||
for (SQLName item : x.getReferencingColumns()) {
|
||||
SQLIdentifierExpr columnName = (SQLIdentifierExpr) item;
|
||||
columnName.setResolvedTableSource(table);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (repository == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
SQLExprTableSource table = x.getReferencedTable();
|
||||
for (SQLName item : x.getReferencedColumns()) {
|
||||
SQLIdentifierExpr columnName = (SQLIdentifierExpr) item;
|
||||
columnName.setResolvedTableSource(table);
|
||||
}
|
||||
|
||||
SQLName tableName = table.getName();
|
||||
|
||||
SchemaObject tableObject = repository.findTable(tableName);
|
||||
if (tableObject == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
SQLStatement tableStmt = tableObject.getStatement();
|
||||
if (tableStmt instanceof SQLCreateTableStatement) {
|
||||
SQLCreateTableStatement refCreateTableStmt = (SQLCreateTableStatement) tableStmt;
|
||||
for (SQLName item : x.getReferencedColumns()) {
|
||||
SQLIdentifierExpr columnName = (SQLIdentifierExpr) item;
|
||||
SQLColumnDefinition column = refCreateTableStmt.findColumn(columnName.nameHashCode64());
|
||||
if (column != null) {
|
||||
columnName.setResolvedColumn(column);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for performance
|
||||
static void resolveExpr(SchemaResolveVisitor visitor, SQLExpr x) {
|
||||
if (x == null) {
|
||||
@@ -2425,4 +2517,6 @@ class SchemaResolveVisitorFactory {
|
||||
|
||||
x.accept(visitor);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -15,30 +15,23 @@
|
||||
*/
|
||||
package com.alibaba.druid.sql.visitor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.druid.sql.ast.*;
|
||||
import com.alibaba.druid.sql.ast.expr.*;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
|
||||
import com.alibaba.druid.sql.dialect.db2.visitor.DB2OutputVisitor;
|
||||
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;
|
||||
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleParameterizedOutputVisitor;
|
||||
import com.alibaba.druid.sql.dialect.phoenix.visitor.PhoenixOutputVisitor;
|
||||
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGOutputVisitor;
|
||||
import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerTop;
|
||||
import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerOutputVisitor;
|
||||
import com.alibaba.druid.sql.parser.SQLParserFeature;
|
||||
import com.alibaba.druid.sql.parser.SQLParserUtils;
|
||||
import com.alibaba.druid.sql.parser.SQLStatementParser;
|
||||
import com.alibaba.druid.util.JdbcConstants;
|
||||
import com.alibaba.druid.sql.parser.*;
|
||||
import com.alibaba.druid.util.JdbcUtils;
|
||||
|
||||
public class ParameterizedOutputVisitorUtils {
|
||||
public static String parameterize(String sql, String dbType) {
|
||||
SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, dbType);
|
||||
parser.config(SQLParserFeature.EnableSQLBinaryOpExprGroup, true);
|
||||
parser.config(SQLParserFeature.OptimizedForParameterized, true);
|
||||
List<SQLStatement> statementList = parser.parseStatementList();
|
||||
if (statementList.size() == 0) {
|
||||
return sql;
|
||||
|
||||
@@ -834,6 +834,12 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
|
||||
visit((SQLVariantRefExpr) x);
|
||||
} else if (clazz == SQLBinaryOpExprGroup.class) {
|
||||
visit((SQLBinaryOpExprGroup) x);
|
||||
} else if (clazz == SQLCaseExpr.class) {
|
||||
visit((SQLCaseExpr) x);
|
||||
} else if (clazz == SQLInListExpr.class) {
|
||||
visit((SQLInListExpr) x);
|
||||
} else if (clazz == SQLNotExpr.class) {
|
||||
visit((SQLNotExpr) x);
|
||||
} else {
|
||||
x.accept(this);
|
||||
}
|
||||
@@ -861,7 +867,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
|
||||
if (elExpr instanceof SQLCaseExpr) {
|
||||
this.indentCount++;
|
||||
println();
|
||||
printExpr(elExpr);
|
||||
visit((SQLCaseExpr) elExpr);
|
||||
this.indentCount--;
|
||||
} else {
|
||||
printExpr(elExpr);
|
||||
@@ -1831,14 +1837,22 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
|
||||
}
|
||||
|
||||
public boolean visit(SQLOrderBy x) {
|
||||
if (x.getItems().size() > 0) {
|
||||
List<SQLSelectOrderByItem> items = x.getItems();
|
||||
|
||||
if (items.size() > 0) {
|
||||
if (x.isSibings()) {
|
||||
print0(ucase ? "ORDER SIBLINGS BY " : "order siblings by ");
|
||||
} else {
|
||||
print0(ucase ? "ORDER BY " : "order by ");
|
||||
}
|
||||
|
||||
printAndAccept(x.getItems(), ", ");
|
||||
for (int i = 0, size = items.size(); i < size; ++i) {
|
||||
if (i != 0) {
|
||||
print0(", ");
|
||||
}
|
||||
SQLSelectOrderByItem item = items.get(i);
|
||||
visit(item);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1851,20 +1865,23 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
|
||||
} else {
|
||||
printExpr(expr);
|
||||
}
|
||||
if (x.getType() != null) {
|
||||
|
||||
SQLOrderingSpecification type = x.getType();
|
||||
if (type != null) {
|
||||
print(' ');
|
||||
SQLOrderingSpecification type = x.getType();
|
||||
print0(ucase ? type.name : type.name_lcase);
|
||||
}
|
||||
|
||||
if (x.getCollate() != null) {
|
||||
String collate = x.getCollate();
|
||||
if (collate != null) {
|
||||
print0(ucase ? " COLLATE " : " collate ");
|
||||
print0(x.getCollate());
|
||||
print0(collate);
|
||||
}
|
||||
|
||||
if (x.getNullsOrderType() != null) {
|
||||
SQLSelectOrderByItem.NullsOrderType nullsOrderType = x.getNullsOrderType();
|
||||
if (nullsOrderType != null) {
|
||||
print(' ');
|
||||
print0(x.getNullsOrderType().toFormalString());
|
||||
print0(nullsOrderType.toFormalString());
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -4887,11 +4904,14 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
|
||||
|
||||
public boolean visit(SQLLimit x) {
|
||||
print0(ucase ? "LIMIT " : "limit ");
|
||||
if (x.getOffset() != null) {
|
||||
x.getOffset().accept(this);
|
||||
SQLExpr offset = x.getOffset();
|
||||
if (offset != null) {
|
||||
printExpr(offset);
|
||||
print0(", ");
|
||||
}
|
||||
x.getRowCount().accept(this);
|
||||
|
||||
SQLExpr rowCount = x.getRowCount();
|
||||
printExpr(rowCount);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -414,5 +414,10 @@ public final class FnvHash {
|
||||
long BEFORE = fnv1a_64_lower("BEFORE");
|
||||
long AFTER = fnv1a_64_lower("AFTER");
|
||||
long INSTEAD = fnv1a_64_lower("INSTEAD");
|
||||
|
||||
long DEFERRABLE = fnv1a_64_lower("DEFERRABLE");
|
||||
long AS = fnv1a_64_lower("AS");
|
||||
|
||||
long STAR = fnv1a_64_lower("*");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user