1 /*
2 * Hibernate, Relational Persistence for Idiomatic Java
3 *
4 * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
5 * indicated by the @author tags or express copyright attribution
6 * statements applied by the authors. All third-party contributions are
7 * distributed under license by Red Hat Middleware LLC.
8 *
9 * This copyrighted material is made available to anyone wishing to use, modify,
10 * copy, or redistribute it subject to the terms and conditions of the GNU
11 * Lesser General Public License, as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this distribution; if not, write to:
20 * Free Software Foundation, Inc.
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02110-1301 USA
23 *
24 */
25 package org.hibernate.loader.criteria;
26
27 import java.sql.ResultSet;
28 import java.sql.SQLException;
29 import java.util.HashMap;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Set;
33 import java.util.Iterator;
34
35 import org.hibernate.HibernateException;
36 import org.hibernate.LockMode;
37 import org.hibernate.QueryException;
38 import org.hibernate.ScrollMode;
39 import org.hibernate.ScrollableResults;
40 import org.hibernate.dialect.Dialect;
41 import org.hibernate.engine.QueryParameters;
42 import org.hibernate.engine.SessionFactoryImplementor;
43 import org.hibernate.engine.SessionImplementor;
44 import org.hibernate.impl.CriteriaImpl;
45 import org.hibernate.loader.OuterJoinLoader;
46 import org.hibernate.persister.entity.OuterJoinLoadable;
47 import org.hibernate.persister.entity.Lockable;
48 import org.hibernate.transform.ResultTransformer;
49 import org.hibernate.type.Type;
50
51 /**
52 * A <tt>Loader</tt> for <tt>Criteria</tt> queries. Note that criteria queries are
53 * more like multi-object <tt>load()</tt>s than like HQL queries.
54 *
55 * @author Gavin King
56 */
57 public class CriteriaLoader extends OuterJoinLoader {
58
59 //TODO: this class depends directly upon CriteriaImpl,
60 // in the impl package ... add a CriteriaImplementor
61 // interface
62
63 //NOTE: unlike all other Loaders, this one is NOT
64 // multithreaded, or cacheable!!
65
66 private final CriteriaQueryTranslator translator;
67 private final Set querySpaces;
68 private final Type[] resultTypes;
69 //the user visible aliases, which are unknown to the superclass,
70 //these are not the actual "physical" SQL aliases
71 private final String[] userAliases;
72
73 public CriteriaLoader(
74 final OuterJoinLoadable persister,
75 final SessionFactoryImplementor factory,
76 final CriteriaImpl criteria,
77 final String rootEntityName,
78 final Map enabledFilters)
79 throws HibernateException {
80 super(factory, enabledFilters);
81
82 translator = new CriteriaQueryTranslator(
83 factory,
84 criteria,
85 rootEntityName,
86 CriteriaQueryTranslator.ROOT_SQL_ALIAS
87 );
88
89 querySpaces = translator.getQuerySpaces();
90
91 CriteriaJoinWalker walker = new CriteriaJoinWalker(
92 persister,
93 translator,
94 factory,
95 criteria,
96 rootEntityName,
97 enabledFilters
98 );
99
100 initFromWalker(walker);
101
102 userAliases = walker.getUserAliases();
103 resultTypes = walker.getResultTypes();
104
105 postInstantiate();
106
107 }
108
109 public ScrollableResults scroll(SessionImplementor session, ScrollMode scrollMode)
110 throws HibernateException {
111 QueryParameters qp = translator.getQueryParameters();
112 qp.setScrollMode(scrollMode);
113 return scroll(qp, resultTypes, null, session);
114 }
115
116 public List list(SessionImplementor session)
117 throws HibernateException {
118 return list( session, translator.getQueryParameters(), querySpaces, resultTypes );
119
120 }
121
122 protected Object getResultColumnOrRow(Object[] row, ResultTransformer transformer, ResultSet rs, SessionImplementor session)
123 throws SQLException, HibernateException {
124 final Object[] result;
125 final String[] aliases;
126 if ( translator.hasProjection() ) {
127 Type[] types = translator.getProjectedTypes();
128 result = new Object[types.length];
129 String[] columnAliases = translator.getProjectedColumnAliases();
130 for ( int i=0; i<result.length; i++ ) {
131 result[i] = types[i].nullSafeGet(rs, columnAliases[i], session, null);
132 }
133 aliases = translator.getProjectedAliases();
134 }
135 else {
136 result = row;
137 aliases = userAliases;
138 }
139 return translator.getRootCriteria().getResultTransformer()
140 .transformTuple(result, aliases);
141 }
142
143 public Set getQuerySpaces() {
144 return querySpaces;
145 }
146
147 protected String applyLocks(String sqlSelectString, Map lockModes, Dialect dialect) throws QueryException {
148 if ( lockModes == null || lockModes.isEmpty() ) {
149 return sqlSelectString;
150 }
151
152 final Map aliasedLockModes = new HashMap();
153 final Map keyColumnNames = dialect.forUpdateOfColumns() ? new HashMap() : null;
154 final String[] drivingSqlAliases = getAliases();
155 for ( int i = 0; i < drivingSqlAliases.length; i++ ) {
156 final LockMode lockMode = ( LockMode ) lockModes.get( drivingSqlAliases[i] );
157 if ( lockMode != null ) {
158 final Lockable drivingPersister = ( Lockable ) getEntityPersisters()[i];
159 final String rootSqlAlias = drivingPersister.getRootTableAlias( drivingSqlAliases[i] );
160 aliasedLockModes.put( rootSqlAlias, lockMode );
161 if ( keyColumnNames != null ) {
162 keyColumnNames.put( rootSqlAlias, drivingPersister.getRootTableIdentifierColumnNames() );
163 }
164 }
165 }
166 return dialect.applyLocksToSql( sqlSelectString, aliasedLockModes, keyColumnNames );
167 }
168
169 protected LockMode[] getLockModes(Map lockModes) {
170 final String[] entityAliases = getAliases();
171 if ( entityAliases == null ) {
172 return null;
173 }
174 final int size = entityAliases.length;
175 LockMode[] lockModesArray = new LockMode[size];
176 for ( int i=0; i<size; i++ ) {
177 LockMode lockMode = (LockMode) lockModes.get( entityAliases[i] );
178 lockModesArray[i] = lockMode==null ? LockMode.NONE : lockMode;
179 }
180 return lockModesArray;
181 }
182
183 protected boolean isSubselectLoadingEnabled() {
184 return hasSubselectLoadableCollections();
185 }
186
187 protected List getResultList(List results, ResultTransformer resultTransformer) {
188 return translator.getRootCriteria().getResultTransformer().transformList( results );
189 }
190
191 }