package com.taobao.tddl.executor.cursor.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.taobao.tddl.common.exception.TddlException;
import com.taobao.tddl.executor.codec.CodecFactory;
import com.taobao.tddl.executor.codec.RecordCodec;
import com.taobao.tddl.executor.common.DuplicateKVPair;
import com.taobao.tddl.executor.common.ExecutionContext;
import com.taobao.tddl.executor.cursor.IBlockNestedLoopCursor;
import com.taobao.tddl.executor.cursor.ISchematicCursor;
import com.taobao.tddl.executor.cursor.IValueFilterCursor;
import com.taobao.tddl.executor.record.CloneableRecord;
import com.taobao.tddl.executor.rowset.IRowSet;
import com.taobao.tddl.executor.spi.ICursorFactory;
import com.taobao.tddl.executor.utils.ExecUtils;
import com.taobao.tddl.optimizer.core.ASTNodeFactory;
import com.taobao.tddl.optimizer.core.expression.IBooleanFilter;
import com.taobao.tddl.optimizer.core.expression.IColumn;
import com.taobao.tddl.optimizer.core.expression.IFilter.OPERATION;
import com.taobao.tddl.optimizer.core.plan.query.IJoin;
/**
* @author mengshi <mengshi.sunmengshi@taobao.com> Block Nested Loop Join
*/
public class BlockNestedtLoopCursor extends IndexNestedLoopMgetImpCursor implements IBlockNestedLoopCursor {
ICursorFactory cursorFactory = null;
ExecutionContext executionContext = null;
// ICursorMeta rightCursorMeta = null;
private final IJoin join;
private RecordCodec leftCodec;
public BlockNestedtLoopCursor(ISchematicCursor leftCursor, ISchematicCursor rightCursor, List leftColumns,
List rightColumns, List columns, ICursorFactory cursorFactory, IJoin join,
ExecutionContext executionContext, List leftRetColumns, List rightRetColumns)
throws Exception{
super(leftCursor, rightCursor, leftColumns, rightColumns, columns, leftRetColumns, rightRetColumns, join);
this.cursorFactory = cursorFactory;
this.leftCodec = CodecFactory.getInstance(CodecFactory.FIXED_LENGTH)
.getCodec(ExecUtils.getColumnMetas(rightColumns));
this.left_key = leftCodec.newEmptyRecord();
this.executionContext = executionContext;
// rightCursorMeta =
// CursorMetaImp.buildNew(ExecUtils.convertISelectablesToColumnMeta(rightRetColumns,
// join.getRightNode().getAlias(),
// join.isSubQuery()));
this.join = join;
}
public BlockNestedtLoopCursor(ISchematicCursor leftCursor, ISchematicCursor rightCursor, List leftColumns,
List rightColumns, List columns, boolean prefix, ICursorFactory cursorFactory,
List leftRetColumns, List rightRetColumns, IJoin join) throws Exception{
super(leftCursor,
rightCursor,
leftColumns,
rightColumns,
columns,
prefix,
leftRetColumns,
rightRetColumns,
join);
this.join = join;
this.cursorFactory = cursorFactory;
}
protected Map<CloneableRecord, DuplicateKVPair> getRecordFromRightByValueFilter(List<CloneableRecord> leftJoinOnColumnCache)
throws TddlException {
right_cursor.beforeFirst();
if (isLeftOutJoin() && this.rightCursorMeta == null) {
IRowSet kv = right_cursor.next();
if (kv != null) {
this.rightCursorMeta = kv.getParentCursorMeta();
} else {
rightCursorMeta = CursorMetaImp.buildNew(right_cursor.getReturnColumns());
}
right_cursor.beforeFirst();
}
IBooleanFilter filter = ASTNodeFactory.getInstance().createBooleanFilter();
List<Object> values = new ArrayList<Object>();
for (CloneableRecord record : leftJoinOnColumnCache) {
Map<String, Object> recordMap = record.getMap();
if (recordMap.size() != 1) {
throw new IllegalArgumentException("目前只支持单值查询吧。。简化一点");
}
Comparable comp = (Comparable) record.getMap().values().iterator().next();
values.add(comp);
}
filter.setOperation(OPERATION.IN);
filter.setValues(values);
filter.setColumn(this.rightJoinOnColumns.get(0));
IColumn rightColumn = (IColumn) this.rightJoinOnColumns.get(0);
IValueFilterCursor vfc = this.cursorFactory.valueFilterCursor(executionContext, right_cursor, filter);
Map<CloneableRecord, DuplicateKVPair> records = new HashMap();
if (isLeftOutJoin() && !isRightOutJoin()) {
blockNestedLoopJoin(leftJoinOnColumnCache, rightColumn, vfc, records);
} else if (!isLeftOutJoin() && !isRightOutJoin()) {
// inner join
blockNestedLoopJoin(leftJoinOnColumnCache, rightColumn, vfc, records);
} else {
throw new UnsupportedOperationException("不支持该操作 leftOutJoin:" + isLeftOutJoin() + " ; rightOutJoin:"
+ isRightOutJoin());
}
return records;
}
@Override
protected Map<CloneableRecord, DuplicateKVPair> getRecordFromRight(List<CloneableRecord> leftJoinOnColumnCache)
throws TddlException {
// 子查询的话不能用mget
// 因为子查询的话,join的列可以是函数,函数应该放在having里,而不是放在valueFilter里
if (this.join.getRightNode().isSubQuery()) {
return this.getRecordFromRightByValueFilter(leftJoinOnColumnCache);
} else {
return right_cursor.mgetWithDuplicate(leftJoinOnColumnCache, false, false);
}
}
// private void leftOutJoin(List<CloneableRecord> leftJoinOnColumnCache,
// IColumn rightColumn, IValueFilterCursor vfc,
// Map<CloneableRecord, DuplicateKVPair> records) throws TddlException {
// Map<Comparable, CloneableRecord> leftMap = new HashMap<Comparable,
// CloneableRecord>();
// Map<Comparable, CloneableRecord> tempMap = new HashMap<Comparable,
// CloneableRecord>();
// for (CloneableRecord record : leftJoinOnColumnCache) {
// // 去重
// Comparable comp = (Comparable)
// record.getMap().values().iterator().next();
// leftMap.put(comp, record);
// tempMap.put(comp, record);
// }
//
// IRowSet kv = ExecUtils.fromIRowSetToArrayRowSet(vfc.next());
// if (kv != null) {
// do {
// kv = ExecUtils.fromIRowSetToArrayRowSet(kv);
// Object rightValue = ExecUtils.getValueByIColumn(kv, rightColumn);
// if (leftMap.containsKey(rightValue)) {
// tempMap.remove(rightValue);
// CloneableRecord record = leftMap.get(rightValue);
// buildDuplicate(records, kv, record);
// }
// } while ((kv = vfc.next()) != null);
// }
// if (!tempMap.isEmpty() && !leftJoinOnColumnCache.isEmpty()) {
// kv = new ArrayRowSet(rightCursorMeta, new
// Object[rightCursorMeta.getColumns().size()]);
// for (CloneableRecord record : tempMap.values()) {
// buildDuplicate(records, kv, record);
// }
// }
// }
private void blockNestedLoopJoin(List<CloneableRecord> leftJoinOnColumnCache, IColumn rightColumn,
IValueFilterCursor vfc, Map<CloneableRecord, DuplicateKVPair> records)
throws TddlException {
IRowSet kv = null;
while ((kv = vfc.next()) != null) {
kv = ExecUtils.fromIRowSetToArrayRowSet(kv);
Object rightValue = ExecUtils.getValueByIColumn(kv, rightColumn);
for (CloneableRecord record : leftJoinOnColumnCache) {
Comparable comp = (Comparable) record.getMap().values().iterator().next();
if (rightValue.equals(comp)) {
buildDuplicate(records, kv, record);
break;
}
}
}
}
private void buildDuplicate(Map<CloneableRecord, DuplicateKVPair> records, IRowSet kv, CloneableRecord record) {
DuplicateKVPair dkv = records.get(record);
if (dkv == null) {
dkv = new DuplicateKVPair(kv);
records.put(record, dkv);
} else {
while (dkv.next != null) {
dkv = dkv.next;
}
dkv.next = new DuplicateKVPair(kv);
}
}
}