package jef.database.wrapper.clause;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import jef.database.Condition.Operator;
import jef.database.jdbc.rowset.CachedRowSetImpl;
import jef.database.jdbc.rowset.Row;
import jef.tools.StringUtils;
import org.apache.commons.lang.ObjectUtils;
import com.google.common.base.Objects;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
/**
* 在内存中实现结果集的递归查询
*
* 对于Oracle或Postgres的递归查询,在不支持的数据库上或者在分库分表后,只能通过人工在内存中连接来支持。
*
* start with connectBy如果去掉,可以理解是查出了整个树的所有节点。本方法的目的就是过滤掉那些挂不到树上去的节点。
*
* @author jiyi
* TODO implement it
*/
public class InMemoryStartWithConnectBy implements InMemoryProcessor{
//要连接的当前ID
public int connectPrior;
//要连接的父ID
public int connectParent;
public int startWithColumn;
public Operator startWithOperator;
public Object startWithValue;
public void process(CachedRowSetImpl rows) throws SQLException {
Set<Row> result=new LinkedHashSet<Row>();
Multimap<Object,Row> index=index(rows.getRvh(),result);
List<Row> newComing=Arrays.asList(result.toArray(new Row[result.size()]));
while(!newComing.isEmpty()){ //找不到新的孩子就结束循环
newComing=appendResults(result,newComing,index);
}
if(result.isEmpty()){
rows.getRvh().clear();
rows.refresh();
}else{
rows.setRvh(Arrays.asList(result.toArray(new Row[result.size()])));
rows.refresh();
}
}
private List<Row> appendResults(Set<Row> result, List<Row> toScan,Multimap<Object,Row> index) {
List<Row> newComing=new ArrayList<Row>();
for(Row row:toScan){
Collection<Row> children=index.get(row.getColumnObject(connectPrior));
for(Row child:children){
if(result.add(child)){
newComing.add(child);
}
}
}
return newComing;
}
//根据父ID索引
private Multimap<Object, Row> index(List<Row> rvh,Set<Row> result) {
Multimap<Object, Row> index=ArrayListMultimap.create();
for(Row row:rvh){
index.put(row.getColumnObject(connectParent), row);
if(matchStart(row)){
result.add(row);
}
}
return index;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private boolean matchStart(Row row) {
Object obj=row.getColumnObject(startWithColumn);
if(obj instanceof Integer){
obj=Long.valueOf(((Integer) obj).longValue());
}
if(obj instanceof Float){
obj=Double.valueOf(((Float) obj).doubleValue());
}
switch(startWithOperator){
case EQUALS:
return Objects.equal(obj, startWithValue);
case GREAT:
return ObjectUtils.compare((Comparable)obj, (Comparable)startWithValue)>0;
case GREAT_EQUALS:
return ObjectUtils.compare((Comparable)obj, (Comparable)startWithValue)>=0;
case IS_NOT_NULL:
return obj!=null;
case IS_NULL:
return obj==null;
case LESS:
return ObjectUtils.compare((Comparable)obj, (Comparable)startWithValue)<0;
case LESS_EQUALS:
return ObjectUtils.compare((Comparable)obj, (Comparable)startWithValue)<=0;
case MATCH_ANY:{
//当startWithOperator是基于SQL时,要注意其实现
String s1=StringUtils.toString(obj);
String s2=String.valueOf(startWithValue);
s2=StringUtils.replaceChars(s2, "%_", "*?");
return StringUtils.matches(s1, s2, false);
}
case MATCH_END:{
String s1=StringUtils.toString(obj);
String s2=String.valueOf(startWithValue);
return s1.endsWith(s2);
}
case MATCH_START:{
String s1=StringUtils.toString(obj);
String s2=String.valueOf(startWithValue);
return s1.startsWith(s2);
}
case NOT_EQUALS:
return !Objects.equal(obj, startWithValue);
case NOT_IN:{
List<Object> values=(List<Object>)startWithValue;
return !values.contains(obj);
}
case IN:{
List<Object> values=(List<Object>)startWithValue;
return values.contains(obj);
}
case BETWEEN_L_L:{
List<Object> values=(List<Object>)startWithValue;
return ObjectUtils.compare((Comparable)obj, (Comparable)values.get(0))>=0 && ObjectUtils.compare((Comparable)obj, (Comparable)values.get(1))<=0;
}
default:
throw new UnsupportedOperationException();
}
}
public String getName() {
return "CONNECT_BY";
}
}