mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
sql parser support oracle merge
This commit is contained in:
+230
@@ -0,0 +1,230 @@
|
||||
package com.alibaba.druid.sql.dialect.oracle.ast.stmt;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.SQLName;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.OracleHint;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.OracleSQLObjectImpl;
|
||||
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitor;
|
||||
|
||||
public class OracleMergeStatement extends OracleStatementImpl {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final List<OracleHint> hints = new ArrayList<OracleHint>();
|
||||
|
||||
private SQLName into;
|
||||
private String alias;
|
||||
private SQLTableSource using;
|
||||
private SQLExpr on;
|
||||
private MergeUpdateClause updateClause;
|
||||
private MergeInsertClause insertClause;
|
||||
private ErrorLoggingClause errorLoggingClause;
|
||||
|
||||
public void accept0(OracleASTVisitor visitor) {
|
||||
if (visitor.visit(this)) {
|
||||
acceptChild(visitor, into);
|
||||
acceptChild(visitor, using);
|
||||
acceptChild(visitor, on);
|
||||
acceptChild(visitor, updateClause);
|
||||
acceptChild(visitor, insertClause);
|
||||
acceptChild(visitor, errorLoggingClause);
|
||||
}
|
||||
visitor.endVisit(this);
|
||||
}
|
||||
|
||||
public String getAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
public void setAlias(String alias) {
|
||||
this.alias = alias;
|
||||
}
|
||||
|
||||
public SQLName getInto() {
|
||||
return into;
|
||||
}
|
||||
|
||||
public void setInto(SQLName into) {
|
||||
this.into = into;
|
||||
}
|
||||
|
||||
public SQLTableSource getUsing() {
|
||||
return using;
|
||||
}
|
||||
|
||||
public void setUsing(SQLTableSource using) {
|
||||
this.using = using;
|
||||
}
|
||||
|
||||
public SQLExpr getOn() {
|
||||
return on;
|
||||
}
|
||||
|
||||
public void setOn(SQLExpr on) {
|
||||
this.on = on;
|
||||
}
|
||||
|
||||
public MergeUpdateClause getUpdateClause() {
|
||||
return updateClause;
|
||||
}
|
||||
|
||||
public void setUpdateClause(MergeUpdateClause updateClause) {
|
||||
this.updateClause = updateClause;
|
||||
}
|
||||
|
||||
public MergeInsertClause getInsertClause() {
|
||||
return insertClause;
|
||||
}
|
||||
|
||||
public void setInsertClause(MergeInsertClause insertClause) {
|
||||
this.insertClause = insertClause;
|
||||
}
|
||||
|
||||
public ErrorLoggingClause getErrorLoggingClause() {
|
||||
return errorLoggingClause;
|
||||
}
|
||||
|
||||
public void setErrorLoggingClause(ErrorLoggingClause errorLoggingClause) {
|
||||
this.errorLoggingClause = errorLoggingClause;
|
||||
}
|
||||
|
||||
public List<OracleHint> getHints() {
|
||||
return hints;
|
||||
}
|
||||
|
||||
public static class MergeUpdateClause extends OracleSQLObjectImpl {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private List<SQLUpdateSetItem> items = new ArrayList<SQLUpdateSetItem>();
|
||||
private SQLExpr where;
|
||||
private SQLExpr deleteWhere;
|
||||
|
||||
public List<SQLUpdateSetItem> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public void setItems(List<SQLUpdateSetItem> items) {
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
public SQLExpr getWhere() {
|
||||
return where;
|
||||
}
|
||||
|
||||
public void setWhere(SQLExpr where) {
|
||||
this.where = where;
|
||||
}
|
||||
|
||||
public SQLExpr getDeleteWhere() {
|
||||
return deleteWhere;
|
||||
}
|
||||
|
||||
public void setDeleteWhere(SQLExpr deleteWhere) {
|
||||
this.deleteWhere = deleteWhere;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept0(OracleASTVisitor visitor) {
|
||||
if (visitor.visit(this)) {
|
||||
acceptChild(visitor, items);
|
||||
acceptChild(visitor, where);
|
||||
acceptChild(visitor, deleteWhere);
|
||||
}
|
||||
visitor.endVisit(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class MergeInsertClause extends OracleSQLObjectImpl {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private List<SQLExpr> columns = new ArrayList<SQLExpr>();
|
||||
private List<SQLExpr> values = new ArrayList<SQLExpr>();
|
||||
private SQLExpr where;
|
||||
|
||||
@Override
|
||||
public void accept0(OracleASTVisitor visitor) {
|
||||
if (visitor.visit(this)) {
|
||||
acceptChild(visitor, columns);
|
||||
acceptChild(visitor, columns);
|
||||
acceptChild(visitor, columns);
|
||||
}
|
||||
visitor.endVisit(this);
|
||||
}
|
||||
|
||||
public List<SQLExpr> getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
public void setColumns(List<SQLExpr> columns) {
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
public List<SQLExpr> getValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
public void setValues(List<SQLExpr> values) {
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
public SQLExpr getWhere() {
|
||||
return where;
|
||||
}
|
||||
|
||||
public void setWhere(SQLExpr where) {
|
||||
this.where = where;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class ErrorLoggingClause extends OracleSQLObjectImpl {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private SQLName into;
|
||||
private SQLExpr simpleExpression;
|
||||
private SQLExpr limit;
|
||||
|
||||
@Override
|
||||
public void accept0(OracleASTVisitor visitor) {
|
||||
if (visitor.visit(this)) {
|
||||
acceptChild(visitor, into);
|
||||
acceptChild(visitor, simpleExpression);
|
||||
acceptChild(visitor, limit);
|
||||
}
|
||||
visitor.endVisit(this);
|
||||
}
|
||||
|
||||
public SQLName getInto() {
|
||||
return into;
|
||||
}
|
||||
|
||||
public void setInto(SQLName into) {
|
||||
this.into = into;
|
||||
}
|
||||
|
||||
public SQLExpr getSimpleExpression() {
|
||||
return simpleExpression;
|
||||
}
|
||||
|
||||
public void setSimpleExpression(SQLExpr simpleExpression) {
|
||||
this.simpleExpression = simpleExpression;
|
||||
}
|
||||
|
||||
public SQLExpr getLimit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
public void setLimit(SQLExpr limit) {
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.alibaba.druid.sql.dialect.oracle.ast.stmt;
|
||||
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.OracleSQLObject;
|
||||
|
||||
public interface OracleStatement extends OracleSQLObject {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.alibaba.druid.sql.dialect.oracle.ast.stmt;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLStatementImpl;
|
||||
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitor;
|
||||
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
|
||||
|
||||
public abstract class OracleStatementImpl extends SQLStatementImpl implements OracleStatement {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected void accept0(SQLASTVisitor visitor) {
|
||||
accept0((OracleASTVisitor) visitor);
|
||||
}
|
||||
|
||||
public abstract void accept0(OracleASTVisitor visitor);
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.alibaba.druid.sql.dialect.oracle.parser;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.SQLOrderingSpecification;
|
||||
@@ -28,6 +29,7 @@ import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLNumberExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.OracleHint;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.OracleOrderBy;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleAggregateExpr;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleAnalytic;
|
||||
@@ -590,4 +592,11 @@ public class OracleExprParser extends SQLExprParser {
|
||||
}
|
||||
return super.relationalRest(expr);
|
||||
}
|
||||
|
||||
public void parseHints(List<OracleHint> hints) {
|
||||
if (lexer.token() == Token.HINT) {
|
||||
hints.add(new OracleHint(lexer.stringVal()));
|
||||
lexer.nextToken();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +104,13 @@ public class OracleLexer extends Lexer {
|
||||
map.put("SECOND", Token.SECOND);
|
||||
map.put("TO", Token.TO);
|
||||
map.put("MODEL", Token.MODEL);
|
||||
map.put("MERGE", Token.MERGE);
|
||||
map.put("USING", Token.USING);
|
||||
map.put("MATCHED", Token.MATCHED);
|
||||
map.put("LOG", Token.LOG);
|
||||
map.put("ERRORS", Token.ERRORS);
|
||||
map.put("REJECT", Token.REJECT);
|
||||
map.put("UNLIMITED", Token.UNLIMITED);
|
||||
|
||||
DEFAULT_ORACLE_KEYWORDS = new Keywords(map);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLUnionOperator;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLUnionQuery;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.OracleHint;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.clause.CycleClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.clause.FlashbackQueryClause.AsOfFlashbackQueryClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.clause.FlashbackQueryClause.VersionsFlashbackQueryClause;
|
||||
@@ -1002,9 +1001,6 @@ public class OracleSelectParser extends SQLSelectParser {
|
||||
}
|
||||
|
||||
private void parseHints(OracleSelectQueryBlock queryBlock) {
|
||||
if (lexer.token() == Token.HINT) {
|
||||
queryBlock.getHints().add(new OracleHint(lexer.stringVal()));
|
||||
lexer.nextToken();
|
||||
}
|
||||
this.createExprParser().parseHints(queryBlock.getHints());
|
||||
}
|
||||
}
|
||||
|
||||
+134
-2
@@ -19,10 +19,12 @@ import java.util.List;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLStatement;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OraclePLSQLCommitStatement;
|
||||
import com.alibaba.druid.sql.parser.Lexer;
|
||||
import com.alibaba.druid.sql.parser.ParserException;
|
||||
import com.alibaba.druid.sql.parser.SQLExprParser;
|
||||
import com.alibaba.druid.sql.parser.SQLStatementParser;
|
||||
import com.alibaba.druid.sql.parser.Token;
|
||||
|
||||
@@ -37,7 +39,7 @@ public class OracleStatementParser extends SQLStatementParser {
|
||||
super(lexer);
|
||||
}
|
||||
|
||||
protected SQLExprParser createExprParser() {
|
||||
protected OracleExprParser createExprParser() {
|
||||
return new OracleExprParser(lexer);
|
||||
}
|
||||
|
||||
@@ -111,8 +113,138 @@ public class OracleStatementParser extends SQLStatementParser {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lexer.token() == Token.MERGE) {
|
||||
statementList.add(this.parseMerge());
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new ParserException("TODO : " + lexer.token() + " " + lexer.stringVal());
|
||||
}
|
||||
}
|
||||
|
||||
public OracleMergeStatement parseMerge() throws ParserException {
|
||||
accept(Token.MERGE);
|
||||
|
||||
OracleMergeStatement stmt = new OracleMergeStatement();
|
||||
|
||||
OracleExprParser exprParser = this.createExprParser();
|
||||
exprParser.parseHints(stmt.getHints());
|
||||
|
||||
accept(Token.INTO);
|
||||
stmt.setInto(exprParser.name());
|
||||
|
||||
stmt.setAlias(as());
|
||||
|
||||
accept(Token.USING);
|
||||
|
||||
SQLTableSource using = this.createSQLSelectParser().parseTableSource();
|
||||
stmt.setUsing(using);
|
||||
|
||||
accept(Token.ON);
|
||||
stmt.setOn(exprParser.expr());
|
||||
|
||||
boolean insertFlag = false;
|
||||
if (lexer.token() == Token.WHEN) {
|
||||
lexer.nextToken();
|
||||
if (lexer.token() == Token.MATCHED) {
|
||||
OracleMergeStatement.MergeUpdateClause updateClause = new OracleMergeStatement.MergeUpdateClause();
|
||||
lexer.nextToken();
|
||||
accept(Token.THEN);
|
||||
accept(Token.UPDATE);
|
||||
accept(Token.SET);
|
||||
|
||||
for (;;) {
|
||||
SQLUpdateSetItem item = new SQLUpdateSetItem();
|
||||
item.setColumn(this.exprParser.name());
|
||||
accept(Token.EQ);
|
||||
item.setValue(this.exprParser.expr());
|
||||
|
||||
updateClause.getItems().add(item);
|
||||
|
||||
if (lexer.token() == (Token.COMMA)) {
|
||||
lexer.nextToken();
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (lexer.token() == Token.WHERE) {
|
||||
lexer.nextToken();
|
||||
updateClause.setWhere(exprParser.expr());
|
||||
}
|
||||
|
||||
if (lexer.token() == Token.DELETE) {
|
||||
lexer.nextToken();
|
||||
accept(Token.WHERE);
|
||||
updateClause.setWhere(exprParser.expr());
|
||||
}
|
||||
|
||||
stmt.setUpdateClause(updateClause);
|
||||
} else if (lexer.token() == Token.NOT) {
|
||||
lexer.nextToken();
|
||||
insertFlag = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!insertFlag) {
|
||||
if (lexer.token() == Token.WHEN) {
|
||||
lexer.nextToken();
|
||||
}
|
||||
|
||||
if (lexer.token() == Token.NOT) {
|
||||
lexer.nextToken();
|
||||
insertFlag = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (insertFlag) {
|
||||
OracleMergeStatement.MergeInsertClause insertClause = new OracleMergeStatement.MergeInsertClause();
|
||||
|
||||
accept(Token.MATCHED);
|
||||
accept(Token.THEN);
|
||||
accept(Token.INSERT);
|
||||
accept(Token.LPAREN);
|
||||
exprParser.exprList(insertClause.getColumns());
|
||||
accept(Token.RPAREN);
|
||||
accept(Token.VALUES);
|
||||
accept(Token.LPAREN);
|
||||
exprParser.exprList(insertClause.getValues());
|
||||
accept(Token.RPAREN);
|
||||
|
||||
if (lexer.token() == Token.WHERE) {
|
||||
lexer.nextToken();
|
||||
insertClause.setWhere(exprParser.expr());
|
||||
}
|
||||
|
||||
stmt.setInsertClause(insertClause);
|
||||
}
|
||||
|
||||
if (lexer.token() == Token.LOG) {
|
||||
OracleMergeStatement.ErrorLoggingClause errorClause = new OracleMergeStatement.ErrorLoggingClause();
|
||||
|
||||
lexer.nextToken();
|
||||
accept(Token.ERRORS);
|
||||
if (lexer.token() == Token.INTO) {
|
||||
lexer.nextToken();
|
||||
errorClause.setInto(exprParser.name());
|
||||
}
|
||||
|
||||
if (lexer.token() == Token.LPAREN) {
|
||||
lexer.nextToken();
|
||||
errorClause.setSimpleExpression(exprParser.expr());
|
||||
accept(Token.RPAREN);
|
||||
}
|
||||
|
||||
if (lexer.token() == Token.REJECT) {
|
||||
lexer.nextToken();
|
||||
accept(Token.LIMIT);
|
||||
errorClause.setLimit(exprParser.expr());
|
||||
}
|
||||
|
||||
stmt.setErrorLoggingClause(errorClause);
|
||||
}
|
||||
|
||||
return stmt;
|
||||
}
|
||||
}
|
||||
|
||||
+43
@@ -36,6 +36,10 @@ import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleOuterExpr;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleTimestampExpr;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleConstraintState;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleDeleteStatement;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement.ErrorLoggingClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement.MergeInsertClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement.MergeUpdateClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleOrderByItem;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OraclePLSQLCommitStatement;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelect;
|
||||
@@ -649,4 +653,43 @@ public class OracleASTVIsitorAdapter extends SQLASTVisitorAdapter implements Ora
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(OracleMergeStatement x) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(OracleMergeStatement x) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(MergeUpdateClause x) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(MergeUpdateClause x) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(MergeInsertClause x) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(MergeInsertClause x) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(ErrorLoggingClause x) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(ErrorLoggingClause x) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleOuterExpr;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleTimestampExpr;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleConstraintState;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleDeleteStatement;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleOrderByItem;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OraclePLSQLCommitStatement;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelect;
|
||||
@@ -282,4 +283,20 @@ public interface OracleASTVisitor extends SQLASTVisitor {
|
||||
boolean visit(ModelClause x);
|
||||
|
||||
void endVisit(ModelClause x);
|
||||
|
||||
boolean visit(OracleMergeStatement x);
|
||||
|
||||
void endVisit(OracleMergeStatement x);
|
||||
|
||||
boolean visit(OracleMergeStatement.MergeUpdateClause x);
|
||||
|
||||
void endVisit(OracleMergeStatement.MergeUpdateClause x);
|
||||
|
||||
boolean visit(OracleMergeStatement.MergeInsertClause x);
|
||||
|
||||
void endVisit(OracleMergeStatement.MergeInsertClause x);
|
||||
|
||||
boolean visit(OracleMergeStatement.ErrorLoggingClause x);
|
||||
|
||||
void endVisit(OracleMergeStatement.ErrorLoggingClause x);
|
||||
}
|
||||
|
||||
@@ -67,6 +67,10 @@ import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleOuterExpr;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleTimestampExpr;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleConstraintState;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleDeleteStatement;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement.ErrorLoggingClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement.MergeInsertClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement.MergeUpdateClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleOrderByItem;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OraclePLSQLCommitStatement;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelect;
|
||||
@@ -1309,4 +1313,129 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS
|
||||
public void endVisit(CellAssignment x) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(OracleMergeStatement x) {
|
||||
print("MERGE ");
|
||||
if (x.getHints().size() > 0) {
|
||||
printAndAccept(x.getHints(), ", ");
|
||||
print(" ");
|
||||
}
|
||||
|
||||
print("INTO ");
|
||||
x.getInto().accept(this);
|
||||
|
||||
if (x.getAlias() != null) {
|
||||
print(" ");
|
||||
print(x.getAlias());
|
||||
}
|
||||
|
||||
println();
|
||||
print("USING ");
|
||||
x.getUsing().accept(this);
|
||||
|
||||
print(" ON ");
|
||||
x.getOn().accept(this);
|
||||
|
||||
if (x.getUpdateClause() != null) {
|
||||
println();
|
||||
x.getUpdateClause().accept(this);
|
||||
}
|
||||
|
||||
if (x.getInsertClause() != null) {
|
||||
println();
|
||||
x.getInsertClause().accept(this);
|
||||
}
|
||||
|
||||
if (x.getErrorLoggingClause() != null) {
|
||||
println();
|
||||
x.getErrorLoggingClause().accept(this);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(OracleMergeStatement x) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(MergeUpdateClause x) {
|
||||
print("WHEN MATCHED THEN UPDATE SET ");
|
||||
printAndAccept(x.getItems(), ", ");
|
||||
if (x.getWhere() != null) {
|
||||
incrementIndent();
|
||||
println();
|
||||
print("WHERE ");
|
||||
x.getWhere().accept(this);
|
||||
decrementIndent();
|
||||
}
|
||||
|
||||
if (x.getDeleteWhere() != null) {
|
||||
incrementIndent();
|
||||
println();
|
||||
print("DELETE WHERE ");
|
||||
x.getDeleteWhere().accept(this);
|
||||
decrementIndent();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(MergeUpdateClause x) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(MergeInsertClause x) {
|
||||
print("WHEN NOT MATCHED THEN INSERT ");
|
||||
printAndAccept(x.getColumns(), ", ");
|
||||
print(" VALUES (");
|
||||
printAndAccept(x.getValues(), ", ");
|
||||
print(")");
|
||||
if (x.getWhere() != null) {
|
||||
incrementIndent();
|
||||
println();
|
||||
print("WHERE ");
|
||||
x.getWhere().accept(this);
|
||||
decrementIndent();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(MergeInsertClause x) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(ErrorLoggingClause x) {
|
||||
print("LOG ERRORS ");
|
||||
if (x.getInto() != null) {
|
||||
print("INTO ");
|
||||
x.getInto().accept(this);
|
||||
print(" ");
|
||||
}
|
||||
|
||||
if (x.getSimpleExpression() != null) {
|
||||
print("(");
|
||||
x.getSimpleExpression().accept(this);
|
||||
print(")");
|
||||
}
|
||||
|
||||
if (x.getLimit() != null) {
|
||||
print(" REJECT LIMIT ");
|
||||
x.getLimit().accept(this);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(ErrorLoggingClause x) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+87
-23
@@ -48,6 +48,10 @@ import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleOuterExpr;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleTimestampExpr;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleConstraintState;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleDeleteStatement;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement.ErrorLoggingClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement.MergeInsertClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement.MergeUpdateClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleOrderByItem;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OraclePLSQLCommitStatement;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelect;
|
||||
@@ -70,7 +74,6 @@ import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleUpdateSetValueClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleUpdateStatement;
|
||||
import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
|
||||
import com.alibaba.druid.stat.TableStat;
|
||||
import com.alibaba.druid.stat.TableStat.Column;
|
||||
import com.alibaba.druid.stat.TableStat.Mode;
|
||||
|
||||
public class OracleSchemaStatVisitor extends SchemaStatVisitor implements OracleASTVisitor {
|
||||
@@ -106,6 +109,9 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle
|
||||
case Select:
|
||||
stat.incrementSelectCount();
|
||||
break;
|
||||
case Merge:
|
||||
stat.incrementMergeCount();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -212,22 +218,7 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle
|
||||
return false;
|
||||
}
|
||||
|
||||
if (x.getOwner() instanceof SQLIdentifierExpr) {
|
||||
String owner = ((SQLIdentifierExpr) x.getOwner()).getName();
|
||||
|
||||
if (owner != null) {
|
||||
Map<String, String> aliasMap = aliasLocal.get();
|
||||
if (aliasMap != null) {
|
||||
String table = aliasMap.get(owner);
|
||||
|
||||
// table == null时是SubQuery
|
||||
if (table != null) {
|
||||
columns.add(new Column(table, x.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return super.visit(x);
|
||||
}
|
||||
|
||||
public boolean visit(SQLIdentifierExpr x) {
|
||||
@@ -243,12 +234,7 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle
|
||||
return false;
|
||||
}
|
||||
|
||||
String currentTable = currentTableLocal.get();
|
||||
|
||||
if (currentTable != null) {
|
||||
columns.add(new Column(currentTable, x.getName()));
|
||||
}
|
||||
return false;
|
||||
return super.visit(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -820,4 +806,82 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(OracleMergeStatement x) {
|
||||
aliasLocal.set(new HashMap<String, String>());
|
||||
|
||||
x.putAttribute("_original_use_mode", modeLocal.get());
|
||||
modeLocal.set(Mode.Merge);
|
||||
|
||||
String originalTable = currentTableLocal.get();
|
||||
|
||||
x.getUsing().accept(this);
|
||||
|
||||
String ident = x.getInto().toString();
|
||||
currentTableLocal.set(ident);
|
||||
x.putAttribute("_old_local_", originalTable);
|
||||
|
||||
TableStat stat = tableStats.get(ident);
|
||||
if (stat == null) {
|
||||
stat = new TableStat();
|
||||
tableStats.put(new TableStat.Name(ident), stat);
|
||||
}
|
||||
stat.incrementMergeCount();
|
||||
|
||||
Map<String, String> aliasMap = aliasLocal.get();
|
||||
if (aliasMap != null) {
|
||||
if (x.getAlias() != null) {
|
||||
aliasMap.put(x.getAlias(), ident);
|
||||
}
|
||||
aliasMap.put(ident, ident);
|
||||
}
|
||||
|
||||
x.getOn().accept(this);
|
||||
|
||||
if (x.getUpdateClause() != null) {
|
||||
x.getUpdateClause().accept(this);
|
||||
}
|
||||
|
||||
if (x.getInsertClause() != null) {
|
||||
x.getInsertClause().accept(this);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(OracleMergeStatement x) {
|
||||
aliasLocal.set(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(MergeUpdateClause x) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(MergeUpdateClause x) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(MergeInsertClause x) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(MergeInsertClause x) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(ErrorLoggingClause x) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(ErrorLoggingClause x) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -344,4 +344,6 @@ public class SQLStatementParser extends SQLParser {
|
||||
createView.setSubQuery(new SQLSelectParser(this.lexer).select());
|
||||
return createView;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -145,6 +145,12 @@ public enum Token {
|
||||
SECOND("SECOND"),
|
||||
TO("TO"),
|
||||
MODEL("MODEL"),
|
||||
MERGE("MERGE"),
|
||||
MATCHED("MATCHED"),
|
||||
LOG("LOG"),
|
||||
ERRORS("ERRORS"),
|
||||
REJECT("REJECT"),
|
||||
UNLIMITED("UNLIMITED"),
|
||||
|
||||
// transact-sql
|
||||
TOP("TOP"),
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelect;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource;
|
||||
@@ -46,6 +47,7 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
|
||||
protected final Set<Column> orderByColumns = new LinkedHashSet<Column>();
|
||||
protected final Set<Column> groupByColumns = new LinkedHashSet<Column>();
|
||||
|
||||
private final Map<String, SQLSelectQuery> subQueryMap = new LinkedHashMap<String, SQLSelectQuery>();
|
||||
protected final static ThreadLocal<Map<String, String>> aliasLocal = new ThreadLocal<Map<String, String>>();
|
||||
protected final static ThreadLocal<String> currentTableLocal = new ThreadLocal<String>();
|
||||
protected final static ThreadLocal<Mode> modeLocal = new ThreadLocal<Mode>();
|
||||
@@ -159,7 +161,8 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
|
||||
String column = ((SQLPropertyExpr) expr).getName();
|
||||
|
||||
if (owner instanceof SQLIdentifierExpr) {
|
||||
String table = ((SQLIdentifierExpr) owner).getName();
|
||||
String tableName = ((SQLIdentifierExpr) owner).getName();
|
||||
String table = tableName;
|
||||
if (aliasMap.containsKey(table)) {
|
||||
table = aliasMap.get(table);
|
||||
}
|
||||
@@ -169,6 +172,14 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
|
||||
condition.setColumn(new Column(table, column));
|
||||
condition.setOperator(operator);
|
||||
this.conditions.add(condition);
|
||||
} else {
|
||||
Column sqlColumn = handleSubQueryColumn(tableName, column);
|
||||
if (sqlColumn != null) {
|
||||
Condition condition = new Condition();
|
||||
condition.setColumn(sqlColumn);
|
||||
condition.setOperator(operator);
|
||||
this.conditions.add(condition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,7 +368,9 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
|
||||
|
||||
// table == null时是SubQuery
|
||||
if (table != null) {
|
||||
columns.add(new Column(table, x.getName()));
|
||||
Column column = new Column(table, x.getName());
|
||||
columns.add(column);
|
||||
x.putAttribute("_column_", column);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -365,11 +378,48 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Column handleSubQueryColumn(String owner, String alias) {
|
||||
SQLSelectQuery query = subQueryMap.get(owner);
|
||||
|
||||
if (query == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<SQLSelectItem> selectList = null;
|
||||
if (query instanceof SQLSelectQueryBlock) {
|
||||
selectList = ((SQLSelectQueryBlock) query).getSelectList();
|
||||
}
|
||||
|
||||
if (selectList != null) {
|
||||
for (SQLSelectItem item : selectList) {
|
||||
String itemAlias = item.getAlias();
|
||||
SQLExpr itemExpr = item.getExpr();
|
||||
if (itemAlias == null) {
|
||||
if (itemExpr instanceof SQLIdentifierExpr) {
|
||||
itemAlias = itemExpr.toString();
|
||||
} else if (itemExpr instanceof SQLPropertyExpr) {
|
||||
itemAlias = ((SQLPropertyExpr) itemExpr).getName();
|
||||
}
|
||||
}
|
||||
|
||||
if (alias.equalsIgnoreCase(itemAlias)) {
|
||||
Column column = (Column) itemExpr.getAttribute("_column_");
|
||||
return column;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean visit(SQLIdentifierExpr x) {
|
||||
String currentTable = currentTableLocal.get();
|
||||
|
||||
if (currentTable != null) {
|
||||
columns.add(new Column(currentTable, x.getName()));
|
||||
Column column = new Column(currentTable, x.getName());
|
||||
columns.add(column);
|
||||
x.putAttribute("_column_", column);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -405,13 +455,18 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
|
||||
}
|
||||
|
||||
public boolean visit(SQLSubqueryTableSource x) {
|
||||
x.getSelect().accept(this);
|
||||
|
||||
SQLSelectQuery query = x.getSelect().getQuery();
|
||||
|
||||
Map<String, String> aliasMap = aliasLocal.get();
|
||||
if (aliasMap != null) {
|
||||
if (x.getAlias() != null) {
|
||||
aliasMap.put(x.getAlias(), null);
|
||||
subQueryMap.put(x.getAlias(), query);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isSimpleExprTableSource(SQLExprTableSource x) {
|
||||
@@ -448,6 +503,9 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
|
||||
case Select:
|
||||
stat.incrementSelectCount();
|
||||
break;
|
||||
case Merge:
|
||||
stat.incrementMergeCount();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -465,6 +523,11 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean visit(SQLSelectItem x) {
|
||||
x.getExpr().setParent(x);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean visit(SQLSelect x) {
|
||||
if (x.getOrderBy() != null) {
|
||||
x.getOrderBy().setParent(x);
|
||||
|
||||
@@ -22,6 +22,15 @@ public class TableStat {
|
||||
int deleteCount = 0;
|
||||
int insertCount = 0;
|
||||
int dropCount = 0;
|
||||
int mergeCount = 0;
|
||||
|
||||
public int getMergeCount() {
|
||||
return mergeCount;
|
||||
}
|
||||
|
||||
public void incrementMergeCount() {
|
||||
this.mergeCount++;
|
||||
}
|
||||
|
||||
public int getDropCount() {
|
||||
return dropCount;
|
||||
@@ -85,6 +94,9 @@ public class TableStat {
|
||||
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder(4);
|
||||
if (mergeCount > 0) {
|
||||
buf.append("Merge");
|
||||
}
|
||||
if (insertCount > 0) {
|
||||
buf.append("Insert");
|
||||
}
|
||||
@@ -100,6 +112,7 @@ public class TableStat {
|
||||
if (dropCount > 0) {
|
||||
buf.append("Drop");
|
||||
}
|
||||
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
@@ -272,7 +285,7 @@ public class TableStat {
|
||||
}
|
||||
|
||||
public static enum Mode {
|
||||
Insert(1), Update(2), Delete(4), Select(8);
|
||||
Insert(1), Update(2), Delete(4), Select(8), Merge(16);
|
||||
|
||||
public final int mark;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user