package jef.database.query;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import jef.database.DbUtils;
import jef.database.Field;
import jef.database.SelectProcessor;
import jef.database.dialect.DatabaseDialect;
import jef.database.meta.FBIField;
import jef.database.meta.Feature;
import jef.database.meta.ITableMetadata;
import jef.database.wrapper.clause.BindSql;
import jef.database.wrapper.clause.CountClause;
import jef.database.wrapper.clause.QueryClause;
import jef.database.wrapper.clause.QueryClauseImpl;
import jef.database.wrapper.clause.QueryClauseSqlImpl;
import jef.database.wrapper.populator.Transformer;
import jef.database.wrapper.variable.Variable;
import jef.tools.StringUtils;
import org.apache.commons.lang.RandomStringUtils;
/**
* 描述union的查询请求
*
* @author Administrator
*
* @param <T>
*/
public class UnionQuery<T> implements ComplexQuery, TypedQuery<T> {
private List<ConditionQuery> querys;
private List<OrderField> orderBy = new ArrayList<OrderField>();
private boolean isAll = true;
private Transformer t;
private boolean cacheable = true;
UnionQuery(List<ConditionQuery> ts, ITableMetadata meta) {
this.querys = ts;
this.t = new Transformer(meta);
}
UnionQuery(List<ConditionQuery> ts, Class<T> clz) {
this.querys = ts;
this.t = new Transformer(clz);
}
public void clearQuery() {
for (ConditionQuery q : querys) {
q.clearQuery();
}
}
public List<OrderField> getOrderBy() {
return orderBy;
}
@SuppressWarnings("unchecked")
public Class<T> getType() {
return (Class<T>) t.getResultClazz();
}
/**
* 是否为 union all语句
*
* @return 如果是union语句返回false, union all 语句返回true
*/
public boolean isAll() {
return isAll;
}
/**
* 设置为 union all 语句
*
* @param isAll
*/
public void setAll(boolean isAll) {
this.isAll = isAll;
}
public void setOrderBy(List<OrderField> orderBy) {
this.orderBy = orderBy;
}
public void addOrderBy(boolean asc, Field... orderbys) {
for (Field f : orderbys) {
if (f instanceof RefField) {
orderBy.add(new OrderField(((RefField) f).getField(), asc));
} else if (f instanceof FBIField) {
orderBy.add(new OrderField(f, asc));
} else {
// Assert.isTrue(DbUtils.getDoClass(f)==this.getType());
orderBy.add(new OrderField(f, asc));
}
}
}
public UnionQuery<T> orderByAsc(String... ascFields) {
for (String f : ascFields) {
addOrderBy(true, new SqlExpression(f));
}
return this;
}
public UnionQuery<T> orderByAsc(Field... ascFields) {
addOrderBy(true, ascFields);
return this;
}
public UnionQuery<T> orderByDesc(Field... descFields) {
addOrderBy(false, descFields);
return this;
}
public UnionQuery<T> orderByDesc(String... descFields) {
for (String f : descFields) {
addOrderBy(false, new SqlExpression(f));
}
return this;
}
public void setOrderBy(boolean asc, Field... orderbys) {
orderBy.clear();
addOrderBy(asc, orderbys);
}
public SqlContext prepare() {
return null;
}
public int size() {
return querys.size();
}
public CountClause toCountSql(SelectProcessor processor) throws SQLException {
CountClause count = new CountClause();
if (isAll) {// union all是可以优化的,union是没有办法的
for (int i = 0; i < size(); i++) {
ConditionQuery cq = querys.get(i);
if (cq instanceof Query) {
Query<?> qq = (Query<?>) cq;
if (qq.getOtherQueryProvider().length > 0) {
cq = DbUtils.toReferenceJoinQuery(qq, null);
}
}
CountClause result1 = processor.toCountSql(cq);
for (Map.Entry<String, List<BindSql>> dbAndSql : result1.getSqls().entrySet()) {
count.addSql(dbAndSql.getKey(), dbAndSql.getValue());
}
}
} else {// union,无法优化
String sql = toQuerySql(processor);
count.addSql(null, wrapCount(sql));
}
return count;
}
public CountClause toPrepareCountSql(SelectProcessor processor, SqlContext context) throws SQLException {
CountClause count = new CountClause();
if (isAll) {// union all是可以优化的,union是没有办法的
for (int i = 0; i < size(); i++) {// 拆成很多个count单句,每个单句进行count
ConditionQuery cq = querys.get(i);
if (cq instanceof Query) {
Query<?> qq = (Query<?>) cq;
if (qq.getOtherQueryProvider().length > 0) {
cq = DbUtils.toReferenceJoinQuery(qq, null);
}
}
CountClause cr = processor.toCountSql(cq);
for (Map.Entry<String, List<BindSql>> dbAndSql : cr.getSqls().entrySet()) {
count.addSql(dbAndSql.getKey(), dbAndSql.getValue());
}
}
} else {// union,无法优化只能直接查询,最简单粗暴
BindSql sql = toPrepareQuerySql0(processor, context, true);
if (sql == null) {
return count;
}
sql.setSql(wrapCount(sql.getSql()));
count.addSql(null, sql);
}
return count;
}
private static String wrapCount(String sql) {
return StringUtils.concat("select count(*) from (", sql, ") t", RandomStringUtils.randomAlphanumeric(3));
}
private BindSql toPrepareQuerySql0(SelectProcessor processor, SqlContext context, boolean isCount) {
List<Variable> binds = new ArrayList<Variable>();
List<String> sqls = new ArrayList<String>(size());
boolean withBuck = processor.getProfile().has(Feature.UNION_WITH_BUCK);
for (int i = 0; i < size(); i++) {
ConditionQuery cq = querys.get(i);
if (cq instanceof Query) {
Query<?> qq = (Query<?>) cq;
if (qq.getOtherQueryProvider().length > 0) {
cq = DbUtils.toReferenceJoinQuery(qq, null);
}
}
QueryClause sql = processor.toQuerySql(cq, null, false);
if (sql.isEmpty()) {
continue;
}
BindSql qresult = sql.getSql(null);
if (withBuck && !isCount) {
sqls.add("(" + qresult.getSql() + ")");
} else {
sqls.add(qresult.getSql());
}
binds.addAll(qresult.getBind());
}
if (sqls.isEmpty()) {
return null;
}
String union = isAll ? "\n union all\n" : "\n union\n";
String sql = StringUtils.join(sqls, union);// QuerySqlResult.toString()已经能自动转换为SQL语句
return new BindSql(sql, binds);
}
public String toQuerySql(SelectProcessor processor) {
String[] sqls = new String[size()];
boolean withBuck = processor.getProfile().has(Feature.UNION_WITH_BUCK);
for (int i = 0; i < size(); i++) {
ConditionQuery cq = querys.get(i);
if (cq instanceof Query) {
Query<?> qq = (Query<?>) cq;
if (qq.getOtherQueryProvider().length > 0) {
cq = DbUtils.toReferenceJoinQuery(qq, null);
}
}
QueryClause sql = processor.toQuerySql(cq, null, false);
if (withBuck) {
sqls[i] = "(" + sql.toString() + ")";
} else {
sqls[i] = sql.toString();
}
}
String union = isAll ? "\n union all\n" : "\n union\n";
return StringUtils.join(sqls, union);
}
private int maxResult;
private int fetchSize;
private int queryTimeout;
public void setMaxResult(int size) {
this.maxResult = size;
}
public void setFetchSize(int size) {
this.fetchSize = size;
}
public void setQueryTimeout(int timout) {
this.queryTimeout = timout;
}
public int getMaxResult() {
return maxResult;
}
public int getFetchSize() {
return fetchSize;
}
public int getQueryTimeout() {
return queryTimeout;
}
public ITableMetadata getMeta() {
return t.getResultMeta();
}
public Transformer getResultTransformer() {
return t;
}
// @Override
// public QueryClause toQuerySql(SelectProcessor processor, SqlContext context, boolean order) {
// @SuppressWarnings("deprecation")
// QueryClauseSqlImpl clause = new QueryClauseSqlImpl(processor.getProfile(), true);
// clause.setBody(toQuerySql(processor));
// if (order) {
// clause.setOrderbyPart(processor.toOrderClause(this, context, processor.getProfile()));
// }
// return clause;
// }
public QueryClause toQuerySql(SelectProcessor processor, SqlContext context, boolean order) {
BindSql sql = toPrepareQuerySql0(processor, context, false);
@SuppressWarnings("deprecation")
DatabaseDialect profile=processor.getProfile();
if (sql == null)
return QueryClauseImpl.EMPTY;
QueryClauseSqlImpl result = new QueryClauseSqlImpl(profile, true);
result.setBody(sql.getSql());
result.setBind(sql.getBind());
if (order) {
result.setOrderbyPart(SelectProcessor.toOrderClause(this, context, profile));
}
return result;
}
@Override
public boolean isSelectCustomized() {
return false;
}
public boolean isCacheable() {
return cacheable;
}
public void setCacheable(boolean cacheable) {
this.cacheable = cacheable;
}
}