package com.taobao.tddl.executor.cursor.impl;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.taobao.tddl.common.exception.TddlException;
import com.taobao.tddl.common.utils.GeneralUtil;
import com.taobao.tddl.common.utils.TStringUtil;
import com.taobao.tddl.executor.common.DuplicateKVPair;
import com.taobao.tddl.executor.common.ExecutionContext;
import com.taobao.tddl.executor.common.KVPair;
import com.taobao.tddl.executor.cursor.ISchematicCursor;
import com.taobao.tddl.executor.cursor.IValueFilterCursor;
import com.taobao.tddl.executor.cursor.SchematicCursor;
import com.taobao.tddl.executor.function.ExtraFunction;
import com.taobao.tddl.executor.record.CloneableRecord;
import com.taobao.tddl.executor.rowset.IRowSet;
import com.taobao.tddl.executor.utils.ExecUtils;
import com.taobao.tddl.optimizer.core.expression.IBooleanFilter;
import com.taobao.tddl.optimizer.core.expression.IColumn;
import com.taobao.tddl.optimizer.core.expression.IFilter;
import com.taobao.tddl.optimizer.core.expression.IFilter.OPERATION;
import com.taobao.tddl.optimizer.core.expression.IFunction;
import com.taobao.tddl.optimizer.core.expression.IFunction.FunctionType;
import com.taobao.tddl.optimizer.core.expression.ILogicalFilter;
import com.taobao.tddl.optimizer.core.expression.ISelectable;
/**
* 用于做没法走索引的条件过滤
*
* @author mengshi.sunmengshi 2013-12-3 上午11:01:53
* @since 5.0.0
*/
public class ValueFilterCursor extends SchematicCursor implements IValueFilterCursor {
protected IFilter filter;
Pattern pattern;
String tarCache;
protected ExecutionContext executionContext;
public ValueFilterCursor(ISchematicCursor cursor, IFilter filter, ExecutionContext executionContext){
super(cursor, cursor == null ? null : null, cursor == null ? null : cursor.getOrderBy());
// 将filter中的函数用规则引擎里的,带实际
this.filter = filter;
this.executionContext = executionContext;
}
DuplicateKVPair allow(IFilter f, DuplicateKVPair dkv) throws TddlException {
if (f == null) {
return dkv;
}
// 链表头,第一个allow的DKV放在这里,如果所有都不allow,那么这里为空
DuplicateKVPair rootAllowDKV = null;
// 链表尾,用于append新元素
DuplicateKVPair rootAllowDKVTail = null;
// 遍历用dkv
DuplicateKVPair currentDKV = dkv;
if (allowOneDKV(f, currentDKV)) {
rootAllowDKV = currentDKV;
rootAllowDKVTail = currentDKV;
}
while ((currentDKV = dkv.next) != null) {
if (allowOneDKV(f, currentDKV)) {
if (rootAllowDKV == null) {
// 如果这是第一个满足要求的DKV.设置tail和root
rootAllowDKV = currentDKV;
rootAllowDKVTail = currentDKV;
} else {// 前面已经有满足要求的DVK了,设置tail.next并更新tail
rootAllowDKVTail.next = currentDKV;
rootAllowDKVTail = currentDKV;
}
}
}
if (rootAllowDKVTail != null && rootAllowDKVTail.next != null) {// 最后一个元素,可能有next,但next不满足要求
rootAllowDKVTail.next = null;
}
return rootAllowDKV;
}
@Override
public IRowSet next() throws TddlException {
IRowSet kv = null;
while ((kv = parentCursorNext()) != null) {
if (allow(filter, kv)) {
return kv;
}
}
return null;
}
private boolean allowOneDKV(IFilter f, DuplicateKVPair dkv) throws TddlException {
// 遍历链表,如果有notallow,就丢掉他。
boolean ok = allow(f, dkv.currentKey);
return ok;
}
@SuppressWarnings("unchecked")
boolean allow(IFilter f, IRowSet iRowSet) throws TddlException {
if (f == null) {
return true;
}
if (f instanceof IBooleanFilter) {
IBooleanFilter bf = (IBooleanFilter) f;
Object column_value = null;
Object col = bf.getColumn();
if (col instanceof ISelectable) {
try {
if (col instanceof IFunction && ((IFunction) col).getFunctionType().equals(FunctionType.Scalar)) {
column_value = processFunction(iRowSet, col);
} else {
// TODO shenxun : 这是否应该用cursorMeta?
column_value = ExecUtils.getValueByIColumn(iRowSet, (ISelectable) col);
}
} catch (Exception e) {
throw new TddlException(e);
}
} else {
throw new IllegalArgumentException("" + "暂时不支持左值为非IExpression");
}
// if (column_value instanceof Utf8) {
// column_value = column_value.toString();
// }
Object v = null;
List values = bf.getValues();
if (bf.getValue() instanceof IColumn) {
IColumn c = (IColumn) bf.getValue();
if (c instanceof ISelectable) {
try {
if (c instanceof IFunction) {
{
v = processFunction(iRowSet, c);
}
} else {
v = ExecUtils.getValueByIColumn(iRowSet, (IColumn) col);
}
} catch (Exception e) {
throw new TddlException(e);
}
} else {
throw new IllegalArgumentException("" + "暂时不支持左值为非IExpression");
}
} else {
v = bf.getValue();
}
// if (v instanceof Utf8) {
// v = v.toString();
// }
// shenxun bug fix : 这里未考虑参数为null的情况
if (v == null && values == null) {
if ((bf.getOperation() == OPERATION.EQ || bf.getOperation() == OPERATION.IS_NULL)) {
if (column_value == null) {
return true;
}
} else if (bf.getOperation() == OPERATION.NOT_EQ || bf.getOperation() == OPERATION.IS_NOT_NULL) {
if (column_value != null) {
return true;
}
}
// 其他情况,比如> < >= <= ....
return false;
}
if (column_value == null) {
// shenxun:前面已经判断过,v不为空了,走到这里的话就是v不为空,但当前列为空,那么应该返回false;
return false;
}
if (v instanceof IFunction) {
try {
if (((IFunction) v).getFunctionType().equals(FunctionType.Aggregate)) {
throw new RuntimeException("Invalid use of group function");
}
((ExtraFunction) ((IFunction) v).getExtraFunction()).serverMap(iRowSet);
v = processFunction(iRowSet, v);
} catch (Exception e) {
throw new TddlException(e);
}
}
OPERATION op = bf.getOperation();
if (op == OPERATION.LIKE) {
return processLike(column_value, v);
}
if (op == OPERATION.IN) {
return processIn(column_value, bf.getValues());
}
int n = ((Comparable) v).compareTo(column_value);
if (n == 0) {
if (op == OPERATION.EQ || op == OPERATION.GT_EQ || op == OPERATION.LT_EQ) {
return true;
}
} else if (n < 0) {
if (op == OPERATION.GT || op == OPERATION.GT_EQ || op == OPERATION.NOT_EQ) {
return true;
}
} else {
if (op == OPERATION.LT || op == OPERATION.LT_EQ || op == OPERATION.NOT_EQ) {
return true;
}
}
} else if (f instanceof ILogicalFilter) {
ILogicalFilter lf = (ILogicalFilter) f;
if (f.getOperation().equals(OPERATION.AND)) {
for (IFilter f1 : lf.getSubFilter()) {
if (!allow(f1, iRowSet)) {
return false;
}
}
} else if (f.getOperation().equals(OPERATION.OR)) {// shenxun :
// 增加一个or条件全部匹配的逻辑
for (IFilter f1 : lf.getSubFilter()) {
if (allow(f1, iRowSet)) {
return true;
}
}
return false;
} else {
throw new IllegalArgumentException("should not be here ");
}
return true;
}
return false;
}
private Object processFunction(IRowSet iRowSet, Object c) throws TddlException {
Object v = null;
// 在Filter里面是不能出现聚合函数的
if (((IFunction) c).getFunctionType().equals(FunctionType.Aggregate)) throw new RuntimeException("Invalid use of group function");
((ExtraFunction) ((IFunction) c).getExtraFunction()).serverMap(iRowSet);
v = ((IFunction) c).getExtraFunction().getResult();
return v;
}
private boolean processIn(Object column_value, List<Object> values) {
if (values.contains(column_value)) return true;
return false;
}
@Override
public boolean skipTo(CloneableRecord key) throws TddlException {
if (super.skipTo(key)) {
IRowSet kv = parentCursorCurrent();
if (kv != null && allow(filter, kv)) {
return true;
}
}
return false;
}
protected boolean processLike(Object column_value, Object v) {
if (!(v == null || v instanceof String)) {// TODO shenxun
// 丢异常才对,但老实现丢异常会出现无法关闭cursor的问题。所以返回false.
return false;
}
String colValString = "";
if (column_value != null) {
colValString = String.valueOf(column_value);
}
String tar = (String) v;
if (tarCache == null || !tarCache.equals(tar)) {
if (pattern != null) {
throw new IllegalArgumentException("should not be here");
}
tarCache = tar;
// trim and remove %%
tar = TStringUtil.trim(tar);
tar = TStringUtil.replace(tar, "\\_", "[uANDOR]");
tar = TStringUtil.replace(tar, "\\%", "[pANDOR]");
tar = TStringUtil.replace(tar, "%", ".*");
tar = TStringUtil.replace(tar, "_", ".");
tar = TStringUtil.replace(tar, "[uANDOR]", "\\_");
tar = TStringUtil.replace(tar, "[pANDOR]", "\\%");
// case insensitive
tar = "(?i)" + tar;
tar = "^" + tar;
tar = tar + "$";
pattern = Pattern.compile(tar);
}
Matcher matcher = pattern.matcher(colValString);
return matcher.find();
}
@Override
public boolean skipTo(KVPair key) throws TddlException {
return skipTo(key.getKey());
}
@Override
public IRowSet first() throws TddlException {
IRowSet kv = parentCursorFirst();
if (kv != null) {
do {
if (kv != null && allow(filter, kv)) {
return kv;
}
} while ((kv = parentCursorNext()) != null);
}
return null;
}
// @Override
// public KVPair get(KVPair key) throws Exception {
// return get(key.getKey());
// }
//
// @Override
// public KVPair get(CloneableRecord key) throws Exception {
// KVPair kv = super.get(key);
// return kv!=null && allow(filter, kv.getKey(), kv.getValue())?kv:null;
// }
@Override
public IRowSet last() throws TddlException {
IRowSet kv = parentCursorLast();
do {
if (kv != null && allow(filter, kv)) {
return kv;
}
} while ((kv = parentCursorPrev()) != null);
return null;
}
@Override
public IRowSet prev() throws TddlException {
IRowSet kv = parentCursorPrev();
do {
if (kv != null && allow(filter, kv)) {
return kv;
}
} while ((kv = parentCursorPrev()) != null);
return null;
}
@SuppressWarnings("unused")
private Map<String, Object> getRecordMap(CloneableRecord key, CloneableRecord value) {
int size = 0;
if (value != null) {
size += value.getColumnList().size();
}
if (key != null) {
size += key.getColumnList().size();
}
Map<String, Object> eachRow = new HashMap<String, Object>(size);
if (value != null) {
eachRow.putAll(value.getMap());
}
if (key != null) {
eachRow.putAll(key.getMap());
}
return eachRow;
}
@Override
public Map<CloneableRecord, DuplicateKVPair> mgetWithDuplicate(List<CloneableRecord> keys, boolean prefixMatch,
boolean keyFilterOrValueFilter) throws TddlException {
Map<CloneableRecord, DuplicateKVPair> map = super.mgetWithDuplicate(keys, prefixMatch, keyFilterOrValueFilter);
if (map == null) {
return null;
}
Map<CloneableRecord, DuplicateKVPair> retMap = new HashMap<CloneableRecord, DuplicateKVPair>(map.size());
Iterator<Entry<CloneableRecord, DuplicateKVPair>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Entry<CloneableRecord, DuplicateKVPair> entry = iterator.next();
DuplicateKVPair dkv = entry.getValue();
dkv = allow(filter, dkv);
if (dkv != null) {
retMap.put(entry.getKey(), dkv);
}
}
return retMap;
}
@Override
public String toStringWithInden(int inden) {
StringBuilder sb = new StringBuilder();
String subQueryTab = GeneralUtil.getTab(inden);
sb.append(subQueryTab).append("【Value Filter Cursor : ").append("\n");
sb.append(subQueryTab).append(filter).append("\n");
ExecUtils.printOrderBy(orderBys, inden, sb);
sb.append(super.toStringWithInden(inden));
return sb.toString();
}
@Override
public String toString() {
return toStringWithInden(0);
}
}