package jef.database.dialect.handler;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import jef.common.log.LogUtil;
import jef.database.jdbc.statement.ResultSetLaterProcess;
import jef.database.wrapper.clause.BindSql;
import org.apache.commons.lang.StringUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLOrderBy;
import com.alibaba.druid.sql.ast.SQLOrderingSpecification;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource;
import com.alibaba.druid.sql.ast.statement.SQLUnionQuery;
import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerSelectQueryBlock;
import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerTop;
import com.alibaba.druid.sql.dialect.sqlserver.parser.SQLServerSelectParser;
import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerOutputVisitor;
import com.alibaba.druid.sql.parser.ParserException;
public class SQL2000LimitHandler implements LimitHandler {
public BindSql toPageSQL(String sql, int[] offsetLimit) {
int offset = offsetLimit[0];
if (offset == 0) {// 没有offset可以简化处理
int indexDistinct = StringUtils.indexOfIgnoreCase(sql, "select distinct");
int index = StringUtils.indexOfIgnoreCase(sql, "select");
return new BindSql(new StringBuilder(sql.length() + 8).append(sql).insert(index + (indexDistinct == index ? 15 : 6), " top " + offsetLimit[1]).toString());
}
return processToPageSQL(sql, offsetLimit);
}
private BindSql processToPageSQL(String sql, int[] offsetLimit) {
SQLServerSelectParser parser = new SQLServerSelectParser(sql);
try{
SQLSelect select = parser.select();
if(select.getQuery() instanceof SQLUnionQuery){
return toPage(offsetLimit,(SQLUnionQuery)select.getQuery(),select,sql);
}else{
return toPage(offsetLimit,(SQLServerSelectQueryBlock)select.getQuery(),select ,sql);
}
}catch(ParserException ex){
LogUtil.error(sql, ex);
throw ex;
}
}
protected BindSql toPage(int[] offsetLimit, SQLServerSelectQueryBlock selectBody, SQLSelect select, String raw) {
SQLOrderBy order = select.getOrderBy();
if (order == null) {
throw new UnsupportedOperationException("Select must have order to page");
}
SQLServerTop top=new SQLServerTop();
top.setExpr(new SQLIntegerExpr(offsetLimit[0] + offsetLimit[1]));
selectBody.setTop(top);
StringBuilder sb = new StringBuilder(raw.length() + 30);
//sb.append("SELECT TOP ").append(offsetLimit[1]).append(" * FROM (");
SQLServerOutputVisitor visitor=new SQLServerOutputVisitor(sb);
visitor.setPrettyFormat(false);
select.accept(visitor);
//sb.append(") __ef_t");
//appendOrderReverse(order,visitor, "__ef_t", selectBody.getSelectList());
return new BindSql(sb.toString()).setReverseResult(new ResultSetLaterProcess(offsetLimit[0]));
}
protected BindSql toPage(int[] offsetLimit, SQLUnionQuery union,SQLSelect select, String raw) {
SQLOrderBy order=removeOrder(union);
if(order==null){
throw new UnsupportedOperationException("Select must have order to page");
}
StringBuilder sb = new StringBuilder(raw.length() + 40);
// sb.append("SELECT TOP ").append(offsetLimit[1]).append(" * FROM (\n");
sb.append("SELECT TOP ");
sb.append(offsetLimit[0] + offsetLimit[1]).append(" * FROM");
SQLSubqueryTableSource s = new SQLSubqueryTableSource(select,"__ef_tmp1");
SQLServerOutputVisitor visitor=new SQLServerOutputVisitor(sb);
visitor.setPrettyFormat(false);
s.accept(visitor);
sb.append('\n');
order.accept(visitor);
// sb.append(") __ef_tmp2\n");
// appendOrderReverse(order,visitor,"__ef_tmp2",null);
return new BindSql(sb.toString()).setReverseResult(new ResultSetLaterProcess(offsetLimit[0]));
}
private void appendOrderReverse(SQLOrderBy order, SQLServerOutputVisitor visitor,String tmpTableAlias,List<SQLSelectItem> items) {
StringBuilder sb=(StringBuilder)visitor.getAppender();
sb.append( " ORDER BY ");
Iterator<SQLSelectOrderByItem> iter=order.getItems().iterator();
if(iter.hasNext()){
reverseAppendTo(iter.next(),visitor,tmpTableAlias,items);
}
for(;iter.hasNext();){
sb.append(',');
reverseAppendTo(iter.next(),visitor,tmpTableAlias,items);
}
}
private void reverseAppendTo(SQLSelectOrderByItem order, SQLServerOutputVisitor visitor, String tmpTableAlias, List<SQLSelectItem> items) {
SQLExpr expression=order.getExpr();
if(expression instanceof SQLPropertyExpr){
SQLPropertyExpr c=(SQLPropertyExpr)expression;
if(items!=null){
fixWithSelects(c,items);
}
if(c.getOwner()!=null){
c.setOwner(new SQLIdentifierExpr(tmpTableAlias));
}
}
expression.accept(visitor);
if(order.getType()==SQLOrderingSpecification.ASC || order.getType()==null){
try {
visitor.getAppender().append(" DESC");
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void fixWithSelects(SQLPropertyExpr c, List<SQLSelectItem> items) {
for(SQLSelectItem item:items){
SQLExpr ex=item.getExpr();
if(ex instanceof SQLPropertyExpr){
SQLPropertyExpr exc=(SQLPropertyExpr)ex;
if(isMatch(exc,c)){
if(item.getAlias()!=null){
c.setName(item.getAlias());
}
}
}
}
}
private boolean isMatch(SQLPropertyExpr exc, SQLPropertyExpr c) {
if(StringUtils.equalsIgnoreCase(exc.getName(), c.getName())){
if(c.getOwner()==exc.getOwner()){
return true;
}
return StringUtils.equalsIgnoreCase(String.valueOf(c.getOwner()), String.valueOf(exc.getOwner()));
}
return false;
}
protected SQLOrderBy removeOrder(SQLUnionQuery union) {
if(union.getRight() instanceof SQLUnionQuery){
return removeOrder((SQLUnionQuery)union.getRight());
}else{
SQLOrderBy order=union.getOrderBy();
union.setOrderBy(null);
return order;
}
}
@Override
public BindSql toPageSQL(String sql, int[] offsetLimit, boolean isUnion) {
return toPageSQL(sql, offsetLimit);
}
}