sql parser support oracle merge

This commit is contained in:
温少
2012-02-24 22:19:40 +08:00
parent 5fc9acdb4c
commit 2c87b27d0f
15 changed files with 698 additions and 9 deletions
@@ -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);
}
@@ -1002,9 +1002,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());
}
}
@@ -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;
}
}
@@ -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) {
}
}
@@ -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;
@@ -820,4 +824,44 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle
}
@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) {
}
}
@@ -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"),