improved sql parser.

This commit is contained in:
wenshao
2017-06-07 13:54:41 +08:00
parent 3165a86e3c
commit 2b75d0f853
26 changed files with 746 additions and 152 deletions
@@ -425,7 +425,7 @@ public class SQLUtils {
SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, dbType);
List<SQLStatement> stmtList = parser.parseStatementList();
if (parser.getLexer().token() != Token.EOF) {
throw new DruidRuntimeException("syntax error : " + sql);
throw new ParserException("syntax error : " + sql);
}
return stmtList;
}
@@ -434,7 +434,7 @@ public class SQLUtils {
SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, dbType, keepComments);
List<SQLStatement> stmtList = parser.parseStatementList();
if (parser.getLexer().token() != Token.EOF) {
throw new DruidRuntimeException("syntax error : " + sql);
throw new ParserException("syntax error : " + sql);
}
return stmtList;
}
@@ -33,6 +33,21 @@ public class SQLDeclareItem extends SQLObjectImpl {
protected List<SQLTableElement> tableElementList = new ArrayList<SQLTableElement>();
public SQLDeclareItem() {
}
public SQLDeclareItem(SQLExpr name, SQLDataType dataType) {
this.setName(name);
this.setDataType(dataType);
}
public SQLDeclareItem(SQLExpr name, SQLDataType dataType, SQLExpr value) {
this.setName(name);
this.setDataType(dataType);
this.setValue(value);
}
@Override
protected void accept0(SQLASTVisitor visitor) {
if (visitor.visit(this)) {
@@ -49,6 +64,9 @@ public class SQLDeclareItem extends SQLObjectImpl {
}
public void setName(SQLExpr name) {
if (name != null) {
name.setParent(this);
}
this.name = name;
}
@@ -57,6 +75,9 @@ public class SQLDeclareItem extends SQLObjectImpl {
}
public void setDataType(SQLDataType dataType) {
if (dataType != null) {
dataType.setParent(this);
}
this.dataType = dataType;
}
@@ -65,6 +86,9 @@ public class SQLDeclareItem extends SQLObjectImpl {
}
public void setValue(SQLExpr value) {
if (value != null) {
value.setParent(this);
}
this.value = value;
}
@@ -37,6 +37,9 @@ public class SQLParameter extends SQLObjectImpl {
}
public void setDefaultValue(SQLExpr deaultValue) {
if (deaultValue != null) {
deaultValue.setParent(this);
}
this.defaultValue = deaultValue;
}
@@ -45,6 +48,9 @@ public class SQLParameter extends SQLObjectImpl {
}
public void setName(SQLExpr name) {
if (name != null) {
name.setParent(this);
}
this.name = name;
}
@@ -40,6 +40,12 @@ public class SQLCreateFunctionStatement extends SQLStatementImpl {
SQLDataType returnDataType;
// for mysql
private String comment;
private boolean deterministic = false;
@Override
public void accept0(SQLASTVisitor visitor) {
if (visitor.visit(this)) {
@@ -131,4 +137,20 @@ public class SQLCreateFunctionStatement extends SQLStatementImpl {
}
this.returnDataType = returnDataType;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public boolean isDeterministic() {
return deterministic;
}
public void setDeterministic(boolean deterministic) {
this.deterministic = deterministic;
}
}
@@ -18,9 +18,7 @@ package com.alibaba.druid.sql.ast.statement;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.druid.sql.ast.SQLDeclareItem;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.SQLStatementImpl;
import com.alibaba.druid.sql.ast.*;
import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerObjectImpl;
import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerStatement;
import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerASTVisitor;
@@ -30,7 +28,17 @@ public class SQLDeclareStatement extends SQLStatementImpl {
protected List<SQLDeclareItem> items = new ArrayList<SQLDeclareItem>();
private String dbType;
public SQLDeclareStatement() {
}
public SQLDeclareStatement(SQLExpr name, SQLDataType dataType) {
this.addItem(new SQLDeclareItem(name, dataType));
}
public SQLDeclareStatement(SQLExpr name, SQLDataType dataType, SQLExpr value) {
this.addItem(new SQLDeclareItem(name, dataType, value));
}
@Override
public void accept0(SQLASTVisitor visitor) {
@@ -50,12 +58,4 @@ public class SQLDeclareStatement extends SQLStatementImpl {
}
this.items.add(item);
}
public String getDbType() {
return dbType;
}
public void setDbType(String dbType) {
this.dbType = dbType;
}
}
@@ -57,17 +57,15 @@ public class SQLIfStatement extends SQLStatementImpl {
return statements;
}
public void setStatements(List<SQLStatement> statements) {
this.statements = statements;
}
public List<ElseIf> getElseIfList() {
return elseIfList;
public void addStatement(SQLStatement statement) {
if (statement != null) {
statement.setParent(this);
}
this.statements.add(statement);
}
public void setElseIfList(List<ElseIf> elseIfList) {
this.elseIfList = elseIfList;
public List<ElseIf> getElseIfList() {
return elseIfList;
}
public Else getElseItem() {
@@ -30,7 +30,7 @@ public abstract class SQLInsertInto extends SQLObjectImpl {
protected final List<SQLExpr> columns = new ArrayList<SQLExpr>();
protected SQLSelect query;
protected List<ValuesClause> valuesList = new ArrayList<ValuesClause>();
protected final List<ValuesClause> valuesList = new ArrayList<ValuesClause>();
public SQLInsertInto(){
@@ -105,7 +105,10 @@ public abstract class SQLInsertInto extends SQLObjectImpl {
return valuesList;
}
public void setValuesList(List<ValuesClause> valuesList) {
this.valuesList = valuesList;
public void addValueCause(ValuesClause valueClause) {
if (valueClause != null) {
valueClause.setParent(this);
}
valuesList.add(valueClause);
}
}
@@ -48,4 +48,10 @@ public class SQLLoopStatement extends SQLStatementImpl {
this.labelName = labelName;
}
public void addStatement(SQLStatement stmt) {
if (stmt != null) {
stmt.setParent(this);
}
statements.add(stmt);
}
}
@@ -80,6 +80,14 @@ public class SQLSelect extends SQLObjectImpl {
this.query = query;
}
public SQLSelectQueryBlock getQueryBlock() {
if (query instanceof SQLSelectQueryBlock) {
return (SQLSelectQueryBlock) query;
}
return null;
}
public SQLOrderBy getOrderBy() {
return this.orderBy;
}
@@ -20,7 +20,11 @@ import java.util.List;
import com.alibaba.druid.sql.ast.SQLCommentHint;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.SQLStatementImpl;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator;
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class SQLSetStatement extends SQLStatementImpl {
@@ -45,6 +49,11 @@ public class SQLSetStatement extends SQLStatementImpl {
this.items.add(new SQLAssignItem(target, value));
}
public static SQLSetStatement plus(SQLName target) {
SQLExpr value = new SQLBinaryOpExpr(target.clone(), SQLBinaryOperator.Add, new SQLIntegerExpr(1));
return new SQLSetStatement(target, value);
}
public List<SQLAssignItem> getItems() {
return items;
}
@@ -25,7 +25,15 @@ import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor;
public class MySqlLeaveStatement extends MySqlStatementImpl {
private String labelName;
public MySqlLeaveStatement() {
}
public MySqlLeaveStatement(String labelName) {
this.labelName = labelName;
}
@Override
public void accept0(MySqlASTVisitor visitor) {
visitor.visit(this);
@@ -15,16 +15,8 @@
*/
package com.alibaba.druid.sql.dialect.mysql.parser;
import com.alibaba.druid.sql.ast.SQLCommentHint;
import com.alibaba.druid.sql.ast.SQLDataTypeImpl;
import com.alibaba.druid.sql.ast.SQLDeclareItem;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.SQLOrderBy;
import com.alibaba.druid.sql.ast.SQLParameter;
import com.alibaba.druid.sql.ast.*;
import com.alibaba.druid.sql.ast.SQLParameter.ParameterType;
import com.alibaba.druid.sql.ast.SQLPartition;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator;
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
@@ -355,6 +347,13 @@ public class MySqlStatementParser extends SQLStatementParser {
return parseCreateProcedure();
}
if (lexer.token() == Token.FUNCTION) {
if (replace) {
lexer.reset(markBp, markChar, Token.CREATE);
}
return parseCreateFunction();
}
throw new ParserException("TODO " + lexer.info());
}
@@ -1750,6 +1749,7 @@ public class MySqlStatementParser extends SQLStatementParser {
lexer.nextToken();
SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause();
values.setParent(stmt);
stmt.getValuesList().add(values);
for (; ; ) {
stmt.addColumn(this.exprParser.name());
@@ -2100,7 +2100,7 @@ public class MySqlStatementParser extends SQLStatementParser {
lexer.nextToken();
SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause();
insertStatement.getValuesList().add(values);
insertStatement.addValueCause(values);
for (; ; ) {
SQLName name = this.exprParser.name();
@@ -3141,6 +3141,61 @@ public class MySqlStatementParser extends SQLStatementParser {
}
public SQLCreateFunctionStatement parseCreateFunction() {
SQLCreateFunctionStatement stmt = new SQLCreateFunctionStatement();
stmt.setDbType(dbType);
if (lexer.token() != Token.FUNCTION) {
if (identifierEquals("DEFINER")) {
lexer.nextToken();
accept(Token.EQ);
SQLName definer = this.exprParser.name();
stmt.setDefiner(definer);
} else {
accept(Token.CREATE);
if (lexer.token() == Token.OR) {
lexer.nextToken();
accept(Token.REPLACE);
stmt.setOrReplace(true);
}
}
}
accept(Token.FUNCTION);
stmt.setName(this.exprParser.name());
if (lexer.token() == Token.LPAREN) {// match "("
lexer.nextToken();
parserParameters(stmt.getParameters(), stmt);
accept(Token.RPAREN);// match ")"
}
acceptIdentifier("RETURNS");
SQLDataType dataType = this.exprParser.parseDataType();
stmt.setReturnDataType(dataType);
for (;;) {
if (identifierEquals("DETERMINISTIC")) {
lexer.nextToken();
stmt.setDeterministic(true);
continue;
}
break;
}
SQLStatement block;
if (lexer.token() == Token.BEGIN) {
block = this.parseBlock();
} else {
block = this.parseStatement();
}
stmt.setBlock(block);
return stmt;
}
/**
* parse create procedure statement
*/
@@ -3173,7 +3228,7 @@ public class MySqlStatementParser extends SQLStatementParser {
if (lexer.token() == Token.LPAREN) {// match "("
lexer.nextToken();
parserParameters(stmt.getParameters());
parserParameters(stmt.getParameters(), stmt);
accept(Token.RPAREN);// match ")"
}
SQLStatement block;
@@ -3194,7 +3249,7 @@ public class MySqlStatementParser extends SQLStatementParser {
*
* @param parameters
*/
private void parserParameters(List<SQLParameter> parameters) {
private void parserParameters(List<SQLParameter> parameters, SQLObject parent) {
if (lexer.token() == Token.RPAREN) {
return;
}
@@ -3587,4 +3587,46 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV
}
return false;
}
@Override
public boolean visit(SQLCreateFunctionStatement x) {
print0(ucase ? "CREATE FUNCTION " : "create function ");
x.getName().accept(this);
int paramSize = x.getParameters().size();
if (paramSize > 0) {
print0(" (");
incrementIndent();
println();
for (int i = 0; i < paramSize; ++i) {
if (i != 0) {
print0(", ");
println();
}
SQLParameter param = x.getParameters().get(i);
param.accept(this);
}
decrementIndent();
println();
print(')');
}
println();
print(ucase ? "RETURNS " : "returns ");
x.getReturnDataType().accept(this);
if (x.isDeterministic()) {
print(ucase ? " DETERMINISTIC" : " deterministic");
}
SQLStatement block = x.getBlock();
println();
block.accept(this);
return false;
}
} //
@@ -17,12 +17,14 @@ package com.alibaba.druid.sql.dialect.oracle.ast.stmt;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.ast.statement.SQLCreateIndexStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.OracleSegmentAttributes;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitor;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
import com.alibaba.druid.util.JdbcConstants;
public class OracleCreateIndexStatement extends SQLCreateIndexStatement implements OracleDDLStatement {
public class OracleCreateIndexStatement extends SQLCreateIndexStatement implements OracleDDLStatement, OracleSegmentAttributes {
private boolean online = false;
@@ -32,12 +34,22 @@ public class OracleCreateIndexStatement extends SQLCreateIndexStatement implemen
private SQLExpr parallel;
private SQLName tablespace;
private Integer pctfree;
private Integer pctused;
private Integer initrans;
private SQLExpr ptcfree;
private SQLExpr pctused;
private SQLExpr initrans;
private SQLExpr maxtrans;
private Integer maxtrans;
private Integer pctincrease;
private Integer freeLists;
private Boolean compress;
private Integer compressLevel;
private boolean compressForOltp;
private Integer pctthreshold;
private Boolean logging;
protected SQLName tablespace;
protected SQLObject storage;
private Boolean enable = null;
@@ -47,14 +59,6 @@ public class OracleCreateIndexStatement extends SQLCreateIndexStatement implemen
super (JdbcConstants.ORACLE);
}
public SQLName getTablespace() {
return tablespace;
}
public void setTablespace(SQLName tablespace) {
this.tablespace = tablespace;
}
public SQLExpr getParallel() {
return parallel;
}
@@ -95,37 +99,6 @@ public class OracleCreateIndexStatement extends SQLCreateIndexStatement implemen
visitor.endVisit(this);
}
public SQLExpr getPtcfree() {
return ptcfree;
}
public void setPtcfree(SQLExpr ptcfree) {
this.ptcfree = ptcfree;
}
public SQLExpr getPctused() {
return pctused;
}
public void setPctused(SQLExpr pctused) {
this.pctused = pctused;
}
public SQLExpr getInitrans() {
return initrans;
}
public void setInitrans(SQLExpr initrans) {
this.initrans = initrans;
}
public SQLExpr getMaxtrans() {
return maxtrans;
}
public void setMaxtrans(SQLExpr maxtrans) {
this.maxtrans = maxtrans;
}
public Boolean getEnable() {
return enable;
@@ -151,4 +124,113 @@ public class OracleCreateIndexStatement extends SQLCreateIndexStatement implemen
this.online = online;
}
//////////////
public SQLName getTablespace() {
return tablespace;
}
public void setTablespace(SQLName tablespace) {
if (tablespace != null) {
tablespace.setParent(this);
}
this.tablespace = tablespace;
}
public Boolean getCompress() {
return compress;
}
public void setCompress(Boolean compress) {
this.compress = compress;
}
public Integer getCompressLevel() {
return compressLevel;
}
public void setCompressLevel(Integer compressLevel) {
this.compressLevel = compressLevel;
}
public Integer getPctthreshold() {
return pctthreshold;
}
public void setPctthreshold(Integer pctthreshold) {
this.pctthreshold = pctthreshold;
}
public Integer getPctfree() {
return pctfree;
}
public void setPctfree(Integer ptcfree) {
this.pctfree = ptcfree;
}
public Integer getPctused() {
return pctused;
}
public void setPctused(Integer ptcused) {
this.pctused = ptcused;
}
public Integer getInitrans() {
return initrans;
}
public void setInitrans(Integer initrans) {
this.initrans = initrans;
}
public Integer getMaxtrans() {
return maxtrans;
}
public void setMaxtrans(Integer maxtrans) {
this.maxtrans = maxtrans;
}
public Integer getPctincrease() {
return pctincrease;
}
public void setPctincrease(Integer pctincrease) {
this.pctincrease = pctincrease;
}
public Integer getFreeLists() {
return freeLists;
}
public void setFreeLists(Integer freeLists) {
this.freeLists = freeLists;
}
public Boolean getLogging() {
return logging;
}
public void setLogging(Boolean logging) {
this.logging = logging;
}
public SQLObject getStorage() {
return storage;
}
public void setStorage(SQLObject storage) {
this.storage = storage;
}
public boolean isCompressForOltp() {
return compressForOltp;
}
public void setCompressForOltp(boolean compressForOltp) {
this.compressForOltp = compressForOltp;
}
}
@@ -77,6 +77,27 @@ public class OracleLockTableStatement extends OracleStatementImpl {
}
public static enum LockMode {
EXCLUSIVE, SHARE
ROW_SHARE,
ROW_EXCLUSIVE,
SHARE_UPDATE,
SHARE,
SHARE_ROW_EXCLUSIVE,
EXCLUSIVE,
;
public String toString() {
switch (this) {
case ROW_SHARE:
return "ROW SHARE";
case ROW_EXCLUSIVE:
return "ROW EXCLUSIVE";
case SHARE_UPDATE:
return "SHARE UPDATE";
case SHARE_ROW_EXCLUSIVE:
return "SHARE ROW EXCLUSIVE";
default:
return this.name();
}
}
}
}
@@ -1442,12 +1442,38 @@ public class OracleStatementParser extends SQLStatementParser {
stmt.setTable(this.exprParser.name());
accept(Token.IN);
if (lexer.token() == Token.SHARE) {
stmt.setLockMode(LockMode.SHARE);
Token token = lexer.token();
if (token == Token.SHARE) {
lexer.nextToken();
} else if (lexer.token() == Token.EXCLUSIVE) {
if (lexer.token() == Token.ROW) {
lexer.nextToken();
accept(Token.EXCLUSIVE);
stmt.setLockMode(LockMode.SHARE_ROW_EXCLUSIVE);
} else if (lexer.token() == Token.UPDATE) {
lexer.nextToken();
stmt.setLockMode(LockMode.SHARE_UPDATE);
} else {
stmt.setLockMode(LockMode.SHARE);
}
} else if (token == Token.EXCLUSIVE) {
stmt.setLockMode(LockMode.EXCLUSIVE);
lexer.nextToken();
} else if(token == Token.ROW) {
lexer.nextToken();
token = lexer.token();
if (token == Token.SHARE) {
stmt.setLockMode(LockMode.ROW_SHARE);
lexer.nextToken();
} else if (token == Token.EXCLUSIVE) {
stmt.setLockMode(LockMode.ROW_EXCLUSIVE);
lexer.nextToken();
} else {
throw new ParserException(lexer.info());
}
} else {
throw new ParserException(lexer.info());
}
accept(Token.MODE);
@@ -1944,23 +1970,9 @@ public class OracleStatementParser extends SQLStatementParser {
accept(Token.RPAREN);
for (;;) {
if (lexer.token() == Token.TABLESPACE) {
lexer.nextToken();
stmt.setTablespace(this.exprParser.name());
continue;
} else if (lexer.token() == Token.PCTFREE) {
lexer.nextToken();
stmt.setPtcfree(this.exprParser.expr());
continue;
} else if (lexer.token() == Token.INITRANS) {
lexer.nextToken();
stmt.setInitrans(this.exprParser.expr());
continue;
} else if (lexer.token() == Token.MAXTRANS) {
lexer.nextToken();
stmt.setMaxtrans(this.exprParser.expr());
continue;
} else if (lexer.token() == Token.COMPUTE) {
this.getExprParser().parseSegmentAttributes(stmt);
if (lexer.token() == Token.COMPUTE) {
lexer.nextToken();
acceptIdentifier("STATISTICS");
stmt.setComputeStatistics(true);
@@ -1363,7 +1363,7 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS
print0(ucase ? "LOCK TABLE " : "lock table ");
x.getTable().accept(this);
print0(ucase ? " IN " : " in ");
print0(x.getLockMode().name());
print0(x.getLockMode().toString());
print0(ucase ? " MODE " : " mode ");
if (x.isNoWait()) {
print0(ucase ? "NOWAIT" : "nowait");
@@ -1752,24 +1752,6 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS
print0(ucase ? "INDEX ONLY TOPLEVEL" : "index only toplevel");
}
if (x.getPtcfree() != null) {
println();
print0(ucase ? "PCTFREE " : "pctfree ");
x.getPtcfree().accept(this);
}
if (x.getInitrans() != null) {
println();
print0(ucase ? "INITRANS " : "initrans ");
x.getInitrans().accept(this);
}
if (x.getMaxtrans() != null) {
println();
print0(ucase ? "MAXTRANS " : "maxtrans ");
x.getMaxtrans().accept(this);
}
if (x.isComputeStatistics()) {
println();
print0(ucase ? "COMPUTE STATISTICS" : "compute statistics");
@@ -1791,6 +1773,9 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS
print0(ucase ? " PARALLEL " : " parallel ");
x.getParallel().accept(this);
}
this.printOracleSegmentAttributes(x);
return false;
}
@@ -27,33 +27,12 @@ import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class SQLServerInsertStatement extends SQLInsertStatement implements SQLServerObject {
private List<ValuesClause> valuesList = new ArrayList<ValuesClause>();
private boolean defaultValues;
private SQLServerTop top;
private SQLServerOutput output;
public ValuesClause getValues() {
if (valuesList.size() == 0) {
return null;
}
return valuesList.get(0);
}
public void setValues(ValuesClause values) {
if (valuesList.size() == 0) {
valuesList.add(values);
} else {
valuesList.set(0, values);
}
}
public List<ValuesClause> getValuesList() {
return valuesList;
}
@Override
protected void accept0(SQLASTVisitor visitor) {
this.accept0((SQLServerASTVisitor) visitor);
@@ -283,7 +283,7 @@ public class SQLServerStatementParser extends SQLStatementParser {
accept(Token.LPAREN);
SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause();
this.exprParser.exprList(values.getValues(), values);
insertStatement.getValuesList().add(values);
insertStatement.addValueCause(values);
accept(Token.RPAREN);
if (!parseCompleteValues && insertStatement.getValuesList().size() >= parseValuesSize) {
@@ -361,6 +361,12 @@ public class SQLStatementParser extends SQLParser {
continue;
}
if (identifierEquals("RETURN")) {
SQLStatement stmt = parseReturn();
statementList.add(stmt);
continue;
}
// throw new ParserException("syntax error, " + lexer.token() + " "
// + lexer.stringVal() + ", pos "
// + lexer.pos());
@@ -368,6 +374,24 @@ public class SQLStatementParser extends SQLParser {
}
}
public SQLStatement parseReturn() {
if (lexer.token() == Token.RETURN
|| identifierEquals("RETURN")) {
lexer.nextToken();
}
SQLReturnStatement stmt = new SQLReturnStatement();
if (lexer.token() != Token.SEMI) {
SQLExpr expr = this.exprParser.expr();
stmt.setExpr(expr);
}
accept(Token.SEMI);
stmt.setAfterSemi(true);
return stmt;
}
public SQLStatement parseUpsert() {
SQLInsertStatement insertStatement = new SQLInsertStatement();
@@ -1539,7 +1563,7 @@ public class SQLStatementParser extends SQLParser {
accept(Token.LPAREN);
SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause();
this.exprParser.exprList(values.getValues(), values);
insertStatement.getValuesList().add(values);
insertStatement.addValueCause(values);
accept(Token.RPAREN);
if (lexer.token() == Token.COMMA) {
@@ -42,7 +42,7 @@ public class SchemaObject {
}
public static enum Type {
Sequence, Table, Index
Sequence, Table, Index, Function
}
public SQLStatement getStatement() {
@@ -17,13 +17,17 @@ package com.alibaba.druid.sql.repository;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr;
import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateTableStatement;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitorAdapter;
import com.alibaba.druid.util.JdbcUtils;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@@ -33,9 +37,11 @@ import java.util.concurrent.ConcurrentSkipListMap;
* Created by wenshao on 03/06/2017.
*/
public class SchemaRepository {
public Map<String, SchemaObject> objects = new ConcurrentSkipListMap<String, SchemaObject>();
private final Map<String, SchemaObject> objects = new ConcurrentSkipListMap<String, SchemaObject>();
public final SchemaVisitor visitor = new SchemaVisitor();
private final Map<String, SchemaObject> functions = new ConcurrentSkipListMap<String, SchemaObject>();
private final SchemaVisitor visitor = new SchemaVisitor();
public SchemaObject findTable(String tableName) {
String lowerName = tableName.toLowerCase();
@@ -48,6 +54,11 @@ public class SchemaRepository {
return null;
}
public SchemaObject findFunction(String functionName) {
String lowerName = functionName.toLowerCase();
return functions.get(lowerName);
}
public void acceptDDL(String ddl, String dbType) {
List<SQLStatement> stmtList = SQLUtils.parseStatements(ddl, dbType);
for (SQLStatement stmt : stmtList) {
@@ -103,6 +114,15 @@ public class SchemaRepository {
return false;
}
public boolean visit(SQLCreateFunctionStatement x) {
String name = x.getName().getSimpleName();
SchemaObject object = new SchemaObject(name, SchemaObject.Type.Function, x);
functions.put(name.toLowerCase(), object);
return false;
}
}
public SchemaObject findTable(SQLTableSource tableSource, String alias) {
@@ -134,4 +154,103 @@ public class SchemaRepository {
return null;
}
public SQLColumnDefinition findColumn(SQLTableSource tableSource, SQLSelectItem selectItem) {
if (selectItem == null) {
return null;
}
return findColumn(tableSource, selectItem.getExpr());
}
public SQLColumnDefinition findColumn(SQLTableSource tableSource, SQLExpr expr) {
SchemaObject object = findTable(tableSource, expr);
if (object != null) {
if (expr instanceof SQLAggregateExpr) {
SQLAggregateExpr aggregateExpr = (SQLAggregateExpr) expr;
String function = aggregateExpr.getMethodName();
if ("min".equalsIgnoreCase(function)
|| "max".equalsIgnoreCase(function)) {
SQLExpr arg = aggregateExpr.getArguments().get(0);
expr = arg;
}
}
if (expr instanceof SQLName) {
return object.findColumn(((SQLName) expr).getSimpleName());
}
}
return null;
}
public SchemaObject findTable(SQLTableSource tableSource, SQLSelectItem selectItem) {
if (selectItem == null) {
return null;
}
return findTable(tableSource, selectItem.getExpr());
}
public SchemaObject findTable(SQLTableSource tableSource, SQLExpr expr) {
if (expr instanceof SQLAggregateExpr) {
SQLAggregateExpr aggregateExpr = (SQLAggregateExpr) expr;
String function = aggregateExpr.getMethodName();
if ("min".equalsIgnoreCase(function)
|| "max".equalsIgnoreCase(function)) {
SQLExpr arg = aggregateExpr.getArguments().get(0);
return findTable(tableSource, arg);
}
}
if (expr instanceof SQLPropertyExpr) {
String ownerName = ((SQLPropertyExpr) expr).getOwnernName();
return findTable(tableSource, ownerName);
}
if (expr instanceof SQLAllColumnExpr || expr instanceof SQLIdentifierExpr) {
if (tableSource instanceof SQLExprTableSource) {
return findTable(tableSource, tableSource.computeAlias());
}
return null;
}
return null;
}
public Map<String, SchemaObject> getTables(SQLTableSource x) {
Map<String, SchemaObject> tables = new LinkedHashMap<String, SchemaObject>();
computeTable(x, tables);
return tables;
}
private void computeTable(SQLTableSource x, Map<String, SchemaObject> tables) {
if (x == null) {
return;
}
if (x instanceof SQLExprTableSource) {
SQLExpr expr = ((SQLExprTableSource) x).getExpr();
if (expr instanceof SQLIdentifierExpr) {
String tableName = ((SQLIdentifierExpr) expr).getName();
SchemaObject table = findTable(tableName);
if (table != null) {
tables.put(tableName, table);
String alias = x.getAlias();
if (alias != null && !alias.equalsIgnoreCase(tableName)) {
tables.put(alias, table);
}
}
}
return;
}
if (x instanceof SQLJoinTableSource) {
SQLJoinTableSource join = (SQLJoinTableSource) x;
computeTable(join.getLeft(), tables);
computeTable(join.getRight(), tables);
}
}
}
@@ -3606,7 +3606,12 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
}
} else {
if (x.getParamType() == SQLParameter.ParameterType.IN) {
print0(ucase ? "IN " : "in ");
boolean skip = JdbcConstants.MYSQL.equals(dbType)
&& x.getParent() instanceof SQLCreateFunctionStatement;
if (!skip) {
print0(ucase ? "IN " : "in ");
}
} else if (x.getParamType() == SQLParameter.ParameterType.OUT) {
print0(ucase ? "OUT " : "out ");
} else if (x.getParamType() == SQLParameter.ParameterType.INOUT) {