package com.taobao.tddl.optimizer.core.ast;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.taobao.tddl.common.jdbc.ParameterContext;
import com.taobao.tddl.common.utils.logger.Logger;
import com.taobao.tddl.common.utils.logger.LoggerFactory;
import com.taobao.tddl.optimizer.config.table.TableMeta;
import com.taobao.tddl.optimizer.core.ast.query.TableNode;
import com.taobao.tddl.optimizer.core.datatype.DataType;
import com.taobao.tddl.optimizer.core.expression.IBindVal;
import com.taobao.tddl.optimizer.core.expression.ISelectable;
import com.taobao.tddl.optimizer.core.expression.bean.NullValue;
import com.taobao.tddl.optimizer.utils.OptimizerToString;
import com.taobao.tddl.optimizer.utils.OptimizerUtils;
/**
* DML操作树
*
* @since 5.0.0
*/
public abstract class DMLNode<RT extends DMLNode> extends ASTNode<RT> {
protected static final Logger logger = LoggerFactory.getLogger(DMLNode.class);
protected List<ISelectable> columns;
protected List<Object> values;
// 直接依赖为tableNode,如果涉及多库操作,会是一个Merge下面挂多个DML
protected TableNode table = null;
protected Map<Integer, ParameterContext> parameterSettings = null;
protected boolean needBuild = true;
public DMLNode(TableNode table){
this.table = table;
}
public DMLNode setParameterSettings(Map<Integer, ParameterContext> parameterSettings) {
this.parameterSettings = parameterSettings;
return this;
}
public TableNode getNode() {
return this.table;
}
public DMLNode setNode(TableNode table) {
this.table = table;
return this;
}
public DMLNode setColumns(List<ISelectable> columns) {
this.columns = columns;
return this;
}
public List<ISelectable> getColumns() {
return this.columns;
}
public DMLNode setValues(List<Object> values) {
this.values = values;
return this;
}
public List<Object> getValues() {
return this.values;
}
public TableMeta getTableMeta() {
return getNode().getTableMeta();
}
@Override
public boolean isNeedBuild() {
return needBuild;
}
protected void setNeedBuild(boolean needBuild) {
this.needBuild = needBuild;
}
@Override
public void build() {
if (this.table != null) {
table.build();
}
if ((this.getColumns() == null || this.getColumns().isEmpty())
&& (this.getValues() == null || this.getValues().isEmpty())) {
return;
}
if (columns == null || columns.isEmpty()) { // 如果字段为空,默认为所有的字段数据的,比如insert所有字段
columns = OptimizerUtils.columnMetaListToIColumnList(this.getTableMeta().getAllColumns(),
this.getTableMeta().getTableName());
}
if (columns.size() != values.size()) {
if (!columns.isEmpty()) {
throw new IllegalArgumentException("The size of the columns and values is not matched."
+ " columns' size is " + columns.size() + ". values' size is "
+ values.size());
}
}
for (ISelectable s : this.getColumns()) {
ISelectable res = null;
for (Object obj : table.getColumnsReferedForParent()) {
ISelectable querySelected = (ISelectable) obj;
if (s.isSameName(querySelected)) { // 尝试查找对应的字段信息
res = querySelected;
break;
}
}
if (res == null) {
throw new IllegalArgumentException("column: " + s.getColumnName() + " is not existed in either "
+ table.getName() + " or select clause");
}
}
convertTypeToSatifyColumnMeta(this.getColumns(), this.getValues());
}
/**
* 尝试根据字段类型进行value转化
*/
protected List<Object> convertTypeToSatifyColumnMeta(List<ISelectable> cs, List<Object> vs) {
for (int i = 0; i < cs.size(); i++) {
Comparable c = cs.get(i);
Object v = vs.get(i);
DataType type = null;
if (v == null || v instanceof IBindVal || v instanceof NullValue) {
continue;
}
if (c instanceof ISelectable) {
type = ((ISelectable) c).getDataType();
}
vs.set(i, OptimizerUtils.convertType(v, type));
}
return vs;
}
@Override
public RT executeOn(String dataNode) {
super.executeOn(dataNode);
return (RT) this;
}
@Override
public void assignment(Map<Integer, ParameterContext> parameterSettings) {
QueryTreeNode qct = getNode();
if (qct != null) {
qct.assignment(parameterSettings);
}
if (values != null) {
List<Object> comps = new ArrayList<Object>(values.size());
for (Object comp : values) {
if (comp instanceof IBindVal) {
comps.add(((IBindVal) comp).assignment(parameterSettings));
} else if (comp instanceof ISelectable) {
comps.add(((ISelectable) comp).assignment(parameterSettings));
} else {
comps.add(comp);
}
}
this.setValues(comps);
}
}
protected void copySelfTo(DMLNode to) {
to.columns = this.columns;
to.values = this.values;
to.table = this.table;
}
protected void deepCopySelfTo(DMLNode to) {
to.columns = OptimizerUtils.copySelectables(this.columns);
if (this.values != null) {
to.values = new ArrayList(this.values.size());
for (Object value : this.values) {
if (value instanceof ISelectable) {
to.values.add(((ISelectable) value).copy());
} else to.values.add(value);
}
}
to.table = this.table.deepCopy();
}
@Override
public String toString(int inden) {
String tabTittle = OptimizerToString.getTab(inden);
String tabContent = OptimizerToString.getTab(inden + 1);
StringBuilder sb = new StringBuilder();
OptimizerToString.appendln(sb, tabTittle + this.getClass().getSimpleName());
OptimizerToString.appendField(sb, "columns", this.getColumns(), tabContent);
OptimizerToString.appendField(sb, "values", this.getValues(), tabContent);
if (this.getNode() != null) {
OptimizerToString.appendln(sb, tabContent + "query:");
sb.append(this.getNode().toString(inden + 2));
}
return sb.toString();
}
@Override
public String toString() {
return this.toString(0);
}
}