package com.taobao.tddl.optimizer.parse.cobar;
import java.util.List;
import java.util.Map;
import com.alibaba.cobar.parser.ast.expression.Expression;
import com.alibaba.cobar.parser.ast.expression.primary.SysVarPrimary;
import com.alibaba.cobar.parser.ast.fragment.tableref.TableReferences;
import com.alibaba.cobar.parser.ast.stmt.SQLStatement;
import com.alibaba.cobar.parser.ast.stmt.dal.ShowColumns;
import com.alibaba.cobar.parser.ast.stmt.dal.ShowCreate;
import com.alibaba.cobar.parser.ast.stmt.dal.ShowCreate.Type;
import com.alibaba.cobar.parser.ast.stmt.dal.ShowIndex;
import com.alibaba.cobar.parser.ast.stmt.ddl.DDLStatement;
import com.alibaba.cobar.parser.ast.stmt.dml.DMLDeleteStatement;
import com.alibaba.cobar.parser.ast.stmt.dml.DMLInsertStatement;
import com.alibaba.cobar.parser.ast.stmt.dml.DMLReplaceStatement;
import com.alibaba.cobar.parser.ast.stmt.dml.DMLSelectStatement;
import com.alibaba.cobar.parser.ast.stmt.dml.DMLUpdateStatement;
import com.alibaba.cobar.parser.util.Pair;
import com.alibaba.cobar.parser.visitor.SQLASTVisitor;
import com.taobao.tddl.common.exception.NotSupportException;
import com.taobao.tddl.common.jdbc.ParameterContext;
import com.taobao.tddl.common.model.SqlType;
import com.taobao.tddl.optimizer.core.ast.ASTNode;
import com.taobao.tddl.optimizer.core.ast.QueryTreeNode;
import com.taobao.tddl.optimizer.core.ast.dml.DeleteNode;
import com.taobao.tddl.optimizer.core.ast.dml.InsertNode;
import com.taobao.tddl.optimizer.core.ast.dml.PutNode;
import com.taobao.tddl.optimizer.core.ast.dml.UpdateNode;
import com.taobao.tddl.optimizer.core.ast.query.TableNode;
import com.taobao.tddl.optimizer.parse.SqlAnalysisResult;
import com.taobao.tddl.optimizer.parse.cobar.visitor.MySqlDeleteVisitor;
import com.taobao.tddl.optimizer.parse.cobar.visitor.MySqlInsertVisitor;
import com.taobao.tddl.optimizer.parse.cobar.visitor.MySqlReplaceIntoVisitor;
import com.taobao.tddl.optimizer.parse.cobar.visitor.MySqlSelectVisitor;
import com.taobao.tddl.optimizer.parse.cobar.visitor.MySqlUpdateVisitor;
/**
* 基于cobar构造的parse结果
*/
public class CobarSqlAnalysisResult implements SqlAnalysisResult {
private SqlType sqlType;
private SQLASTVisitor visitor;
private QueryTreeNode dalQueryTreeNode;
private SQLStatement statement;
private boolean hasVisited;
private String sql;
public void build(String sql, SQLStatement statement) {
if (sql != null) {
this.sql = sql;
this.statement = statement;
if (statement instanceof DMLSelectStatement) {
if (isSysSelectStatement((DMLSelectStatement) statement, sql)) {
sqlType = SqlType.SHOW_WITHOUT_TABLE;
return;
}
sqlType = SqlType.SELECT;
visitor = new MySqlSelectVisitor();
} else if (statement instanceof DMLUpdateStatement) {
sqlType = SqlType.UPDATE;
visitor = new MySqlUpdateVisitor();
} else if (statement instanceof DMLDeleteStatement) {
sqlType = SqlType.DELETE;
visitor = new MySqlDeleteVisitor();
} else if (statement instanceof DMLInsertStatement) {
sqlType = SqlType.INSERT;
visitor = new MySqlInsertVisitor();
} else if (statement instanceof DMLReplaceStatement) {
sqlType = SqlType.REPLACE;
visitor = new MySqlReplaceIntoVisitor();
} else if (statement instanceof DDLStatement) {
throw new IllegalArgumentException("tddl not support DDL statement:'" + sql + "'");
} else if (statement instanceof ShowCreate) {
if (((ShowCreate) statement).getType() == Type.TABLE) {
dalQueryTreeNode = new TableNode(((ShowCreate) statement).getId().getIdTextUpUnescape());
sqlType = SqlType.SHOW_WITH_TABLE;
} else {
sqlType = SqlType.SHOW_WITHOUT_TABLE;
}
} else if (statement instanceof ShowColumns) {
dalQueryTreeNode = new TableNode(((ShowColumns) statement).getTable().getIdTextUpUnescape());
sqlType = SqlType.SHOW_WITH_TABLE;
} else if (statement instanceof ShowIndex) {
dalQueryTreeNode = new TableNode(((ShowIndex) statement).getTable().getIdTextUpUnescape());
sqlType = SqlType.SHOW_WITH_TABLE;
} else {
sqlType = SqlType.SHOW_WITHOUT_TABLE;
}
}
}
public void visited() {
if (hasVisited == false && statement != null && visitor != null) {
statement.accept(visitor);
hasVisited = true;
}
}
private boolean isSysSelectStatement(DMLSelectStatement statement, String sql) {
TableReferences tables = statement.getTables();
if (tables == null) {
List<Pair<Expression, String>> exprs = statement.getSelectExprList();
if (exprs != null && exprs.size() == 1) {
if (exprs.get(0).getKey() instanceof SysVarPrimary) {
SysVarPrimary pri = (SysVarPrimary) exprs.get(0).getKey();
if ("AUTOCOMMIT".equals(pri.getVarTextUp()) || "LASTINSERTID".equals(pri.getVarTextUp())) {
throw new IllegalArgumentException("not support such SysVarPrimary:'" + pri.getVarTextUp()
+ "'");
} else {
return true;
}
} else {
return true;
}
} else if (exprs != null && exprs.size() > 1) {
throw new IllegalArgumentException("not support multi SysVarPrimary:'" + sql + "'");
} else {
throw new IllegalArgumentException("not supported sql:'" + sql + "'");
}
} else {
return false;
}
}
public SqlType getSqlType() {
return sqlType;
}
public QueryTreeNode getQueryTreeNode(Map<Integer, ParameterContext> parameterSettings) {
visited();
if (dalQueryTreeNode == null) {
return ((MySqlSelectVisitor) visitor).getTableNode();
} else {
return this.dalQueryTreeNode;
}
}
public UpdateNode getUpdateNode(Map<Integer, ParameterContext> parameterSettings) {
visited();
return (UpdateNode) ((MySqlUpdateVisitor) visitor).getUpdateNode().setParameterSettings(parameterSettings);
}
public InsertNode getInsertNode(Map<Integer, ParameterContext> parameterSettings) {
visited();
return (InsertNode) ((MySqlInsertVisitor) visitor).getInsertNode().setParameterSettings(parameterSettings);
}
public PutNode getReplaceNode(Map<Integer, ParameterContext> parameterSettings) {
visited();
return (PutNode) ((MySqlReplaceIntoVisitor) visitor).getReplaceNode().setParameterSettings(parameterSettings);
}
public DeleteNode getDeleteNode(Map<Integer, ParameterContext> parameterSettings) {
visited();
return (DeleteNode) ((MySqlDeleteVisitor) visitor).getDeleteNode().setParameterSettings(parameterSettings);
}
public ASTNode getAstNode(Map<Integer, ParameterContext> parameterSettings) {
if (sqlType == SqlType.SELECT || sqlType == SqlType.SHOW_WITH_TABLE) {
return getQueryTreeNode(parameterSettings);
} else if (sqlType == SqlType.UPDATE) {
return getUpdateNode(parameterSettings);
} else if (sqlType == SqlType.INSERT) {
return getInsertNode(parameterSettings);
} else if (sqlType == SqlType.REPLACE) {
return getReplaceNode(parameterSettings);
} else if (sqlType == SqlType.DELETE) {
return getDeleteNode(parameterSettings);
}
throw new NotSupportException(sqlType.toString());
}
public SQLStatement getStatement() {
return statement;
}
public String getSql() {
return this.sql;
}
}