package com.taobao.tddl.executor.cursor.impl;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import com.taobao.tddl.common.exception.TddlException;
import com.taobao.tddl.executor.cursor.ICursorMeta;
import com.taobao.tddl.executor.cursor.ISchematicCursor;
import com.taobao.tddl.executor.cursor.SchematicCursor;
import com.taobao.tddl.executor.rowset.IRowSet;
import com.taobao.tddl.executor.rowset.JoinRowSet;
import com.taobao.tddl.executor.utils.ExecUtils;
import com.taobao.tddl.optimizer.config.table.ColumnMeta;
import com.taobao.tddl.optimizer.core.expression.IOrderBy;
import com.taobao.tddl.optimizer.core.expression.ISelectable;
import com.taobao.tddl.optimizer.core.plan.query.IJoin;
/**
* join的结果
*
* @author mengshi.sunmengshi 2013-12-3 上午10:56:08
* @since 5.0.0
*/
public class JoinSchematicCursor extends SchematicCursor {
protected ISchematicCursor left_cursor;
protected ISchematicCursor right_cursor;
/**
* 因为左右cursor要拼到一起,所以右值必须加一个偏移量
*/
protected Integer rightCursorOffset;
private boolean schemaInited = false;
protected ICursorMeta joinCursorMeta = null;
protected Comparator<IRowSet> kvPairComparator;
protected List<ISelectable> leftJoinOnColumns;
protected List<ISelectable> rightJoinOnColumns;
/**
* <pre>
* 见 com.taobao.tddl.optimizer.core.ast.query.JoinNode
* leftOuterJoin:
* leftOuter=true && rightOuter=false
* rightOuterJoin:
* leftOuter=false && rightOuter=true
* innerJoin:
* leftOuter=false && rightOuter=false
* outerJoin:
* leftOuter=true && rightOuter=true
* </pre>
*/
protected boolean leftOutJoin = false;
protected boolean rightOutJoin = false;
private List<ColumnMeta> returnColumns;
public JoinSchematicCursor(ISchematicCursor left_cursor, ISchematicCursor right_cursor, List leftJoinOnColumns,
List rightJoinOnColumns){
super(null, null, null);
this.left_cursor = left_cursor;
this.right_cursor = right_cursor;
this.leftJoinOnColumns = leftJoinOnColumns;
this.rightJoinOnColumns = rightJoinOnColumns;
schemaInited = false;
}
public void setLeftJoin(boolean left) {
this.leftOutJoin = left;
}
public void setRightJoin(boolean right) {
this.rightOutJoin = right;
}
public void setLeftRightJoin(IJoin join) {
if (join != null) {
this.leftOutJoin = join.getLeftOuter();
this.rightOutJoin = join.getRightOuter();
} else {
throw new RuntimeException("IJoin join is null");
}
}
public boolean isLeftOutJoin() {
return leftOutJoin;
}
public boolean isRightOutJoin() {
return rightOutJoin;
}
protected void buildSchemaInJoin(ICursorMeta leftCursorMeta, ICursorMeta rightCursorMeta) {
if (schemaInited) {
return;
}
schemaInited = true;
// 以左面数据顺序,作为排序
setOrderBy(left_cursor);
List<ColumnMeta> leftColumns = leftCursorMeta.getColumns();
List<ColumnMeta> rightColumns = rightCursorMeta.getColumns();
this.kvPairComparator = ExecUtils.getComp(this.leftJoinOnColumns,
this.rightJoinOnColumns,
leftCursorMeta,
rightCursorMeta);
List<ColumnMeta> newJoinColumnMsg = new ArrayList<ColumnMeta>(leftColumns.size() + rightColumns.size());
rightCursorOffset = leftCursorMeta.getIndexRange();
newJoinColumnMsg.addAll(leftColumns);
newJoinColumnMsg.addAll(rightColumns);
List<Integer> indexes = new ArrayList<Integer>(newJoinColumnMsg.size());
addIndexToNewIndexes(leftCursorMeta, leftColumns, indexes, 0);
addIndexToNewIndexes(rightCursorMeta, rightColumns, indexes, rightCursorOffset);
ICursorMeta cursorMetaImpJoin = CursorMetaImp.buildNew(newJoinColumnMsg,
indexes,
(leftCursorMeta.getIndexRange() + rightCursorMeta.getIndexRange()));
// setMeta(cursorMetaImpJoin);
this.joinCursorMeta = cursorMetaImpJoin;
}
protected void buildSchemaFromReturnColumns(List<ColumnMeta> leftColumns, List<ColumnMeta> rightColumns) {
if (schemaInited) {
return;
}
schemaInited = true;
// 以左面数据顺序,作为排序
setOrderBy(left_cursor);
List<ColumnMeta> newJoinColumnMsg = new ArrayList<ColumnMeta>(leftColumns.size() + rightColumns.size());
newJoinColumnMsg.addAll(leftColumns);
newJoinColumnMsg.addAll(rightColumns);
ICursorMeta cursorMetaImpJoin = CursorMetaImp.buildNew(newJoinColumnMsg);
rightCursorOffset = leftColumns.size();
this.joinCursorMeta = cursorMetaImpJoin;
}
private void addIndexToNewIndexes(ICursorMeta cursorMeta, List<ColumnMeta> columns, List<Integer> indexes,
int offset) {
for (ColumnMeta cm : columns) {
Integer index = cursorMeta.getIndex(cm.getTableName(), cm.getName());
if (index == null) {
index = cursorMeta.getIndex(cm.getTableName(), cm.getAlias());
}
indexes.add(offset + index);
}
}
public IRowSet joinRecord(IRowSet kv1, IRowSet kv2) {
ICursorMeta leftCursorMeta = null;
ICursorMeta rightCursorMeta = null;
if (kv1 != null) {
leftCursorMeta = kv1.getParentCursorMeta();
}
if (kv2 != null) {
rightCursorMeta = kv2.getParentCursorMeta();
}
buildSchemaInJoin(leftCursorMeta, rightCursorMeta);
IRowSet joinedRowSet = new JoinRowSet(rightCursorOffset, kv1, kv2, joinCursorMeta);
return joinedRowSet;
}
private void setOrderBy(ISchematicCursor left_cursor) {
List<IOrderBy> orderBys = left_cursor.getOrderBy();
setOrderBy(orderBys);
}
@Override
public List<TddlException> close(List<TddlException> exs) {
if (left_cursor != null) {
exs = left_cursor.close(exs);
}
if (right_cursor != null) {
exs = right_cursor.close(exs);
}
return exs;
}
@Override
public List<ColumnMeta> getReturnColumns() throws TddlException {
if (this.returnColumns != null) {
return this.returnColumns;
}
List<ColumnMeta> leftColumns = this.left_cursor.getReturnColumns();
List<ColumnMeta> rightColumns = this.right_cursor.getReturnColumns();
returnColumns = new ArrayList(leftColumns.size() + rightColumns.size());
returnColumns.addAll(leftColumns);
returnColumns.addAll(rightColumns);
return returnColumns;
}
}