/* * 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; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.persistence.NoResultException; import jef.database.Session.UpdateContext; import jef.database.dialect.DatabaseDialect; import jef.database.dialect.type.ColumnMapping; import jef.database.innerpool.PartitionSupport; import jef.database.jsqlparser.parser.ParseException; import jef.database.jsqlparser.visitor.Expression; import jef.database.meta.FBIField; import jef.database.meta.Feature; import jef.database.meta.ITableMetadata; import jef.database.query.AbstractJoinImpl; import jef.database.query.JoinElement; import jef.database.query.Query; import jef.database.query.SqlContext; import jef.database.routing.PartitionResult; import jef.database.wrapper.clause.BindSql; import jef.database.wrapper.clause.SqlBuilder; import jef.tools.reflect.BeanWrapper; /** * SQL语句生成器 * * @author jiyi * */ public abstract class SqlProcessor { private DatabaseDialect profile; private DbClient parent; public SqlProcessor(DatabaseDialect profile, DbClient parent) { this.profile = profile; this.parent = parent; } private static Expression EXP_ROWID; static { try { EXP_ROWID = DbUtils.parseExpression("ROWID"); } catch (ParseException e) { e.printStackTrace(); } } /** * 转换为Where子句 * * @param joinElement * @param context * SQL语句上下文 * @param update * @param profile * @return */ public abstract BindSql toWhereClause(JoinElement joinElement, SqlContext context, UpdateContext update, DatabaseDialect profile,boolean isBatch); /** * 获取数据库Dialect * * @return * @deprecated */ public DatabaseDialect getProfile() { return profile; } public DatabaseDialect getProfile(PartitionResult[] prs) { if (prs == null || prs.length == 0) { return profile; } return this.parent.getProfile(prs[0].getDatabase()); } public PartitionSupport getPartitionSupport() { return parent.getPartitionSupport(); } // 获得容器需要的值 @SuppressWarnings({ "unchecked", "rawtypes" }) static Object collectValueToContainer(List<? extends IQueryableEntity> records, Class<?> containerType, String targetField) { Collection c = null; if (containerType == Set.class) { c = new HashSet(); } else if (containerType == List.class || containerType.isArray()) { c = new ArrayList(); } else { if (!records.isEmpty()) { BeanWrapper bean = BeanWrapper.wrap(records.get(0)); return bean.getPropertyValue(targetField); } return null; // throw new IllegalArgumentException(containerType + // " is not a known collection type."); } for (IQueryableEntity d : records) { BeanWrapper bean = BeanWrapper.wrap(d); c.add(bean.getPropertyValue(targetField)); } if (containerType.isArray()) { return c.toArray((Object[]) Array.newInstance(containerType.getComponentType(), c.size())); } else { return c; } } private static boolean checkPKCondition(List<Condition> conditions, ITableMetadata meta) { List<ColumnMapping> pks = meta.getPKFields(); if (conditions.size() != pks.size()) return false; for (Condition c : conditions) { if (c.getOperator() != jef.database.Condition.Operator.EQUALS) { return false; } if (!c.getField().getClass().isEnum()) { return false; } if (!isFieldOfPK(c.getField(), pks)) { return false; } } return true; } private static boolean isFieldOfPK(Field field, List<ColumnMapping> pks) { for (ColumnMapping c : pks) { if (field == c.field()) { return true; } } return false; } static final class PrepareImpl extends SqlProcessor { public PrepareImpl(DatabaseDialect profile, DbClient parent) { super(profile, parent); } /** * 转换到绑定类Where字句 */ public BindSql toWhereClause(JoinElement obj, SqlContext context, UpdateContext update, DatabaseDialect profile, boolean batch) { SqlBuilder builder=new SqlBuilder(); toWhere1(builder,obj, context, update, profile,batch); if (builder.isNotEmpty()) { builder.addBefore(" where "); } return builder.build(); } private void toWhere1(SqlBuilder builder,JoinElement query, SqlContext context, UpdateContext update, DatabaseDialect profile, boolean batch) { if (query instanceof AbstractJoinImpl) { AbstractJoinImpl join = (AbstractJoinImpl) query; for (Query<?> ele : join.elements()) { builder.startSection(" and "); toWhereElement1(builder,ele, context.getContextOf(ele), ele.getConditions(), null, profile, batch); builder.endSection(); } for (Map.Entry<Query<?>, List<Condition>> entry : join.getRefConditions().entrySet()) { Query<?> q = entry.getKey(); builder.startSection(" and "); toWhereElement1(builder, q, context.getContextOf(q), entry.getValue(), null, profile, batch); builder.endSection(); } } else if (query instanceof Query<?>) { Query<?> q=(Query<?>) query; toWhereElement1(builder,q, context, query.getConditions(), update, profile,batch); if(update!=null && update.needVersionCondition()){ update.appendVersionCondition(builder,context,this,((Query<?>) query).getInstance(),profile, batch); } if (builder.isNotEmpty() || ORMConfig.getInstance().isAllowEmptyQuery()) { return; } else { throw new NoResultException("Illegal usage of Query object, must including any condition in query:" + q.getInstance().getClass()); } } else { throw new IllegalArgumentException("Unknown Query class:" + query.getClass().getName()); } } /** * * @param obj * @param context * @param removePKUpdate * @param profile * @param checkIsPK * 需要监测该条件是否恰好等于主键条件,如果是则返回true,如果为null则说明不需要检查 * @return */ private void toWhereElement1(SqlBuilder builder,Query<?> q, SqlContext context, List<Condition> conditions, UpdateContext update, DatabaseDialect profile, boolean batch) { IQueryableEntity obj = q.getInstance(); // 这里必须用双条件判断,因为Join当中的RefCondition是额外增加的条件,如果去除将造成RefCondition丢失。 if (q.isAll() && conditions.isEmpty()) return; if (conditions.isEmpty()) { if (getProfile().has(Feature.SELECT_ROW_NUM) && obj.rowid() != null) { q.addCondition(new FBIField(EXP_ROWID, q), obj.rowid()); } else {// 自动将主键作为条件 DbUtils.fillConditionFromField(obj, q, update, false); } } // 检查当前的查询条件是否为一个主键条件 if (update != null && update.checkIsPKCondition()) { update.setIsPkQuery(checkPKCondition(conditions, q.getMeta())); } for (Condition c : conditions) { builder.startSection(" and "); c.toPrepareSqlClause(builder, q.getMeta(), context, this, obj, profile, batch); builder.endSection(); } } } // static class NormalImpl extends SqlProcessor { // NormalImpl(DatabaseDialect profile, DbClient parent) { // super(profile, parent); // } // // /** // * 转换到Where子句 // */ // public BindSql toWhereClause(JoinElement obj, SqlContext context, UpdateContext update, DatabaseDialect profile) { // String sb = toWhere0(obj, context, update, profile); // if (sb.length() > 0) { // return new BindSql(" where " + sb); // } else { // return new BindSql(sb); // } // } // // private String toWhere0(JoinElement obj, SqlContext context, UpdateContext update, DatabaseDialect profile) { // if (obj instanceof AbstractJoinImpl) { // AbstractJoinImpl join = (AbstractJoinImpl) obj; // StringBuilder sb = new StringBuilder(); // for (Query<?> ele : join.elements()) { // String condStr = toWhereElement(ele, context.getContextOf(ele), ele.getConditions(), null, profile); // if (StringUtils.isEmpty(condStr)) { // continue; // } // if (sb.length() > 0) { // sb.append(" and "); // } // sb.append(condStr); // } // for (Map.Entry<Query<?>, List<Condition>> entry : join.getRefConditions().entrySet()) { // Query<?> q = entry.getKey(); // String condStr = toWhereElement(q, context.getContextOf(q), entry.getValue(), null, profile); // if (StringUtils.isEmpty(condStr)) { // continue; // } // if (sb.length() > 0) { // sb.append(" and "); // } // sb.append(condStr); // } // return sb.toString(); // } else if (obj instanceof Query<?>) { // return toWhereElement((Query<?>) obj, context, obj.getConditions(), update, profile); // } else { // throw new IllegalArgumentException("Unknown Query class:" + obj.getClass().getName()); // } // } // // private String toWhereElement(Query<?> q, SqlContext context, List<Condition> conditions, UpdateContext update, DatabaseDialect profile) { // if (q.isAll() && conditions.isEmpty()) // return ""; // if (conditions.isEmpty()) { // IQueryableEntity instance = q.getInstance(); // if (profile.has(Feature.SELECT_ROW_NUM) && instance.rowid() != null) { // q.addCondition(new FBIField(EXP_ROWID, q), instance.rowid()); // } else {// 自动将主键作为条件 // DbUtils.fillConditionFromField(q.getInstance(), q, update, false); // } // } // // 检查当前的查询条件是否为一个主键条件 // if (update != null && update.checkIsPKCondition()) { // update.setIsPkQuery(checkPKCondition(conditions, q.getMeta())); // } // // ITableMetadata meta = MetaHolder.getMeta(q.getInstance()); // StringBuilder sb = new StringBuilder(); // for (Condition c : conditions) { // if (sb.length() > 0) // sb.append(" and "); // sb.append(c.toSqlClause(meta, context, this, q.getInstance(), profile)); // 递归的,当do是属于Join中的一部分时,需要为其增加前缀 // } // if (sb.length() > 0 || ORMConfig.getInstance().isAllowEmptyQuery()) { // return sb.toString(); // } else { // throw new NoResultException("Illegal usage of query:" + q.getClass().getName() // + " object, must including any condition in query. or did you forget to set the primary key for the entity?"); // } // } // } }