package com.taobao.tddl.optimizer.parse.cobar.visitor;
import java.util.List;
import java.util.Map;
import com.alibaba.cobar.parser.ast.expression.Expression;
import com.alibaba.cobar.parser.ast.expression.misc.QueryExpression;
import com.alibaba.cobar.parser.ast.expression.primary.Identifier;
import com.alibaba.cobar.parser.ast.expression.primary.ParamMarker;
import com.alibaba.cobar.parser.ast.expression.primary.RowExpression;
import com.alibaba.cobar.parser.ast.fragment.Limit;
import com.alibaba.cobar.parser.ast.fragment.OrderBy;
import com.alibaba.cobar.parser.ast.fragment.tableref.IndexHint;
import com.alibaba.cobar.parser.ast.fragment.tableref.TableRefFactor;
import com.alibaba.cobar.parser.ast.fragment.tableref.TableReferences;
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.util.Pair;
import com.alibaba.cobar.parser.visitor.MySQLOutputASTVisitor;
import com.taobao.tddl.optimizer.exceptions.OptimizerException;
/**
* 将cobar parser的语法树直接生成sql,允许替换表名
*
* @author jianghang 2014-1-13 下午3:27:56
* @since 5.0.0
*/
public class MysqlOutputVisitor extends MySQLOutputASTVisitor {
// 表名替换使用,注意表名都需为大写
private Map<String/* logic table */, String/* real table */> logicTable2RealTable;
// 路由结果是否为单库单表,是则limit参数不做改变
private boolean singleNode;
public MysqlOutputVisitor(StringBuilder appendable, boolean singleNode, Map<String, String> logicTable2RealTable){
this(appendable, null, singleNode, logicTable2RealTable);
}
public MysqlOutputVisitor(StringBuilder appendable, Object[] args, boolean singleNode,
Map<String, String> logicTable2RealTable){
super(appendable, args);
this.singleNode = singleNode;
this.logicTable2RealTable = logicTable2RealTable;
}
private String convertToRealTable(String tableName) {
if (tableName == null) {
return null;
}
if (logicTable2RealTable == null || logicTable2RealTable.isEmpty()) {
return tableName;
}
// String upperTableName = tableName.toUpperCase();
return logicTable2RealTable.get(tableName);
}
public void visit(TableRefFactor node) {
// 逻辑表名
Identifier table = node.getTable();
// 表名替换
String tableName = convertToRealTable(table.getIdText());
if (tableName != null) {
Identifier realTable = new Identifier(table.getParent(), tableName);
realTable.accept(this);
} else {
table.accept(this);
}
String alias = node.getAlias();
if (alias != null) {
appendable.append(" AS ").append(alias);
}
List<IndexHint> list = node.getHintList();
if (list != null && !list.isEmpty()) {
appendable.append(' ');
printList(list, " ");
}
}
public void visit(Limit node) {
appendable.append("LIMIT ");
Object offset = node.getOffset();
Object size = node.getSize();
if (offset instanceof ParamMarker || size instanceof ParamMarker) {
throw new OptimizerException("暂时不支持limit的占位符替换");
}
long offsetLong = ((Number) offset).longValue();
long sizeLong = ((Number) size).longValue();
if (!this.singleNode) {
// 处理分库分表条件下的limit,对于路由结果是单库单表的情况,limit不做处理
sizeLong += offsetLong;
offsetLong = 0L;
}
appendable.append(offsetLong);
appendable.append(", ");
appendable.append(sizeLong);
}
@Override
public void visit(DMLDeleteStatement node) {
appendable.append("DELETE ");
if (node.isLowPriority()) appendable.append("LOW_PRIORITY ");
if (node.isQuick()) appendable.append("QUICK ");
if (node.isIgnore()) appendable.append("IGNORE ");
TableReferences tableRefs = node.getTableRefs();
if (tableRefs == null) {
appendable.append("FROM ");
// 表名替换
Identifier logicTable = node.getTableNames().get(0);
String tableName = convertToRealTable(logicTable.getIdText());
if (tableName != null) {
Identifier realTable = new Identifier(logicTable.getParent(), tableName);
realTable.accept(this);
} else {
logicTable.accept(this);
}
} else {
printList(node.getTableNames());
appendable.append(" FROM ");
node.getTableRefs().accept(this);
}
Expression where = node.getWhereCondition();
if (where != null) {
appendable.append(" WHERE ");
where.accept(this);
}
OrderBy orderBy = node.getOrderBy();
if (orderBy != null) {
appendable.append(' ');
orderBy.accept(this);
}
Limit limit = node.getLimit();
if (limit != null) {
appendable.append(' ');
limit.accept(this);
}
}
@Override
public void visit(DMLInsertStatement node) {
appendable.append("INSERT ");
switch (node.getMode()) {
case DELAY:
appendable.append("DELAYED ");
break;
case HIGH:
appendable.append("HIGH_PRIORITY ");
break;
case LOW:
appendable.append("LOW_PRIORITY ");
break;
case UNDEF:
break;
default:
throw new IllegalArgumentException("unknown mode for INSERT: " + node.getMode());
}
if (node.isIgnore()) appendable.append("IGNORE ");
appendable.append("INTO ");
// 表名替换
Identifier logicTable = node.getTable();
String tableName = convertToRealTable(logicTable.getIdText());
if (tableName != null) {
Identifier realTable = new Identifier(logicTable.getParent(), tableName);
realTable.accept(this);
} else {
logicTable.accept(this);
}
appendable.append(' ');
List<Identifier> cols = node.getColumnNameList();
if (cols != null && !cols.isEmpty()) {
appendable.append('(');
printList(cols);
appendable.append(") ");
}
QueryExpression select = node.getSelect();
if (select == null) {
appendable.append("VALUES ");
List<RowExpression> rows = node.getRowList();
if (rows != null && !rows.isEmpty()) {
boolean isFst = true;
for (RowExpression row : rows) {
if (row == null || row.getRowExprList().isEmpty()) continue;
if (isFst) isFst = false;
else appendable.append(", ");
appendable.append('(');
printList(row.getRowExprList());
appendable.append(')');
}
} else {
throw new IllegalArgumentException("at least one row for INSERT");
}
} else {
select.accept(this);
}
List<Pair<Identifier, Expression>> dup = node.getDuplicateUpdate();
if (dup != null && !dup.isEmpty()) {
appendable.append(" ON DUPLICATE KEY UPDATE ");
boolean isFst = true;
for (Pair<Identifier, Expression> p : dup) {
if (isFst) isFst = false;
else appendable.append(", ");
p.getKey().accept(this);
appendable.append(" = ");
p.getValue().accept(this);
}
}
}
@Override
public void visit(DMLReplaceStatement node) {
appendable.append("REPLACE ");
switch (node.getMode()) {
case DELAY:
appendable.append("DELAYED ");
break;
case LOW:
appendable.append("LOW_PRIORITY ");
break;
case UNDEF:
break;
default:
throw new IllegalArgumentException("unknown mode for INSERT: " + node.getMode());
}
appendable.append("INTO ");
// 表名替换
Identifier logicTable = node.getTable();
String tableName = convertToRealTable(logicTable.getIdText());
if (tableName != null) {
Identifier realTable = new Identifier(logicTable.getParent(), tableName);
realTable.accept(this);
} else {
logicTable.accept(this);
}
appendable.append(' ');
List<Identifier> cols = node.getColumnNameList();
if (cols != null && !cols.isEmpty()) {
appendable.append('(');
printList(cols);
appendable.append(") ");
}
QueryExpression select = node.getSelect();
if (select == null) {
appendable.append("VALUES ");
List<RowExpression> rows = node.getRowList();
if (rows != null && !rows.isEmpty()) {
boolean isFst = true;
for (RowExpression row : rows) {
if (row == null || row.getRowExprList().isEmpty()) continue;
if (isFst) isFst = false;
else appendable.append(", ");
appendable.append('(');
printList(row.getRowExprList());
appendable.append(')');
}
} else {
throw new IllegalArgumentException("at least one row for REPLACE");
}
} else {
select.accept(this);
}
}
public void setLogicTable2RealTable(Map<String, String> logicTable2RealTable) {
this.logicTable2RealTable = logicTable2RealTable;
}
public void setSingleNode(boolean singleNode) {
this.singleNode = singleNode;
}
}