/* * JEF - Copyright 2009-2010 Jiyi (mr.jiyi@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jef.database.wrapper.clause; import java.util.List; import jef.database.ORMConfig; import jef.database.cache.CacheImpl; import jef.database.cache.CacheKey; import jef.database.cache.KeyDimension; import jef.database.cache.SqlCacheKey; import jef.database.dialect.DatabaseDialect; import jef.database.jdbc.result.ResultSetContainer; import jef.database.jdbc.statement.ResultSetLaterProcess; import jef.database.routing.PartitionResult; import jef.database.routing.sql.SqlAnalyzer; import jef.database.wrapper.variable.Variable; import jef.tools.Assert; import jef.tools.PageLimit; /** * 必要Part五部分, 4+1 * * @author Administrator * */ public class QueryClauseImpl implements QueryClause { /* * 这两部分总是只有一个有值 当单表查询时支持分表,所以是PartitionResult 当多表关联时,目前不支持分表,所以是string */ private String tableDefinition; private PartitionResult[] tables = P; public static final QueryClauseImpl EMPTY = new QueryClauseImpl(new PartitionResult[0]); // //是否为union // private boolean isUnion = false; // Select部分 private SelectPart selectPart; // Where private String wherePart; // groupBy private GroupClause grouphavingPart;// =GroupClause.DEFAULT // 排序 private OrderClause orderbyPart = OrderClause.DEFAULT; // 绑定变量 private List<Variable> bind; // 范围 private PageLimit pageRange; private DatabaseDialect profile; public QueryClauseImpl(DatabaseDialect profile) { this.profile = profile; } private QueryClauseImpl(PartitionResult[] partitionResults) { this.tables = partitionResults; } public PageLimit getPageRange() { return pageRange; } public void setPageRange(PageLimit pageRange) { this.pageRange = pageRange; } public OrderClause getOrderbyPart() { return orderbyPart; } public void setOrderbyPart(OrderClause orderbyPart) { this.orderbyPart = orderbyPart; } public GroupClause getGrouphavingPart() { return grouphavingPart; } public void setGrouphavingPart(GroupClause grouphavingPart) { this.grouphavingPart = grouphavingPart; } public SelectPart getSelectPart() { return selectPart; } public void setSelectPart(SelectPart selectPart) { this.selectPart = selectPart; } public String getWherePart() { return wherePart; } public void setWherePart(String wherePart) { this.wherePart = wherePart; } public String getTableDefinition() { return tableDefinition; } public void setTableDefinition(String tableDefinition) { this.tableDefinition = tableDefinition; } public void setBind(List<Variable> bind) { this.bind = bind; } public PartitionResult[] getTables() { return tables; } public void setTables(String baseTableName,PartitionResult[] tables) { this.baseTableName = baseTableName; this.tables = tables; } @Override public String toString() { return String.valueOf(getSql(null)); } /* * * @param tableDef * * @param delayProcessGroupClause 说明是在union字句中,需要确保是先把unionall 再groupby * * @return */ private String getSql(String tableDef, boolean delayProcessGroupClause) { StringBuilder sb = new StringBuilder(200); if(delayProcessGroupClause){ selectPart.appendNoGroupFunc(sb); }else{ selectPart.append(sb); } sb.append(" from "); sb.append(tableDef); if (wherePart.length() > 0) { sb.append(ORMConfig.getInstance().wrap); sb.append(wherePart); } if (!delayProcessGroupClause) sb.append(grouphavingPart); return sb.toString(); } public BindSql getSql(PartitionResult site) { if (tableDefinition != null) { return withPage(getSql(tableDefinition, false).concat(orderbyPart.getSql()), false).setBind(bind); } if (site == null) { if (tables.length == 0) { throw new IllegalArgumentException("The partition result does not return any result!"); } site = this.tables[0]; } StringBuilder sb = new StringBuilder(200); List<Variable> bind = this.bind; boolean moreTable = site.tableSize() > 1; for (int i = 0; i < site.tableSize(); i++) { if (i > 0) { sb.append("\n union all \n"); } String tableName = site.getTablesEscaped(profile).get(i); sb.append(getSql(tableName.concat(" t"), moreTable && grouphavingPart.isNotEmpty()));// 为多表、并且有groupby时需要特殊处理.grouphavingPart.isNotEmpty()不能省略。 //如果省略掉,则多表union时造成所有内部表的字段均未使用别名。此时外部又没有套一层将列转为别名,最终效果是别名无效。 } // 不带group by、having、order by从句的情况下,无需再union一层, // 否则,对查询列指定别名时会产生异常。 if (moreTable && (grouphavingPart.isNotEmpty() || orderbyPart.isNotEmpty())) { StringBuilder sb2 = new StringBuilder(); selectPart.append(sb2); sb2.append(" from (").append(sb).append(") t"); sb2.append(ORMConfig.getInstance().wrap); sb2.append(grouphavingPart.getSql(false)); sb = sb2; } if (moreTable) { // 当复杂情况下,绑定变量也要翻倍 bind = SqlAnalyzer.repeat(this.bind, site.tableSize()); } sb.append(orderbyPart.getSql()); return withPage(sb.toString(), moreTable).setBind(bind); } private BindSql withPage(String sql, boolean union) { if (pageRange != null) { if(isMultiDatabase()){ if(grouphavingPart==null || !grouphavingPart.isNotEmpty()){ return profile.getLimitHandler().toPageSQL(sql, new int[]{0,pageRange.getEndAsInt()}, union); } }else{ return profile.getLimitHandler().toPageSQL(sql, pageRange.toArray(), union); } } return new BindSql(sql); } private CacheKey cacheKey; private String baseTableName; public CacheKey getCacheKey() { if (cacheKey != null) return cacheKey; try{ if(baseTableName == null) { this.cacheKey=new SqlCacheKey(new KeyDimension(tableDefinition,wherePart, orderbyPart.getSql(),profile), CacheImpl.toParamList(this.bind)); }else { this.cacheKey=new SqlCacheKey(KeyDimension.forSingleTable(baseTableName,wherePart, orderbyPart.getSql(),profile), CacheImpl.toParamList(this.bind)); } return cacheKey; }catch(RuntimeException e){ return null; } } public boolean isEmpty() { return this.tables != null && tables.length == 0; } public boolean isMultiDatabase() { return this.tables != null && tables.length > 1; } public boolean isDistinct() { return selectPart.isDistinct(); } @Override public boolean hasInMemoryOperate() { return isMultiDatabase(); } @Override public void parepareInMemoryProcess(PageLimit range, ResultSetContainer rs) { if (getOrderbyPart().isNotEmpty()) { rs.setInMemoryOrder(getOrderbyPart().parseAsSelectOrder(getSelectPart(), rs.getColumns())); } if (getGrouphavingPart().isNotEmpty()) { rs.setInMemoryGroups(getGrouphavingPart().parseSelectFunction(getSelectPart())); } if (isDistinct()) { rs.setInMemoryDistinct(InMemoryDistinct.instance); } Assert.isNull(range); if (this.pageRange != null) { rs.setInMemoryPage(new InMemoryPaging(this.pageRange)); } } @Override public ResultSetLaterProcess getRsLaterProcessor() { return null; } }