1
2 package org.hibernate.impl;
3
4 import java.util.ArrayList;
5 import java.util.Arrays;
6 import java.util.Collection;
7 import java.util.Iterator;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11 import java.io.Serializable;
12 import java.math.BigInteger;
13
14 import org.hibernate.FlushMode;
15 import org.hibernate.HibernateException;
16 import org.hibernate.LockMode;
17 import org.hibernate.Query;
18 import org.hibernate.QueryException;
19 import org.hibernate.SQLQuery;
20 import org.hibernate.ScrollMode;
21 import org.hibernate.ScrollableResults;
22 import org.hibernate.MappingException;
23 import org.hibernate.Session;
24 import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
25 import org.hibernate.engine.ResultSetMappingDefinition;
26 import org.hibernate.engine.NamedSQLQueryDefinition;
27 import org.hibernate.engine.QueryParameters;
28 import org.hibernate.engine.SessionImplementor;
29 import org.hibernate.engine.TypedValue;
30 import org.hibernate.engine.query.ParameterMetadata;
31 import org.hibernate.engine.query.sql.NativeSQLQueryJoinReturn;
32 import org.hibernate.engine.query.sql.NativeSQLQueryScalarReturn;
33 import org.hibernate.engine.query.sql.NativeSQLQueryRootReturn;
34 import org.hibernate.engine.query.sql.NativeSQLQueryReturn;
35 import org.hibernate.type.Type;
36 import org.hibernate.util.CollectionHelper;
37 import org.hibernate.util.StringHelper;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
53
54 private final List queryReturns;
55 private Collection querySpaces;
56 private final boolean callable;
57 private boolean autodiscovertypes;
58
59
60
61
62
63
64
65
66 SQLQueryImpl(NamedSQLQueryDefinition queryDef, SessionImplementor session, ParameterMetadata parameterMetadata) {
67 super( queryDef.getQueryString(), queryDef.getFlushMode(), session, parameterMetadata );
68 if ( queryDef.getResultSetRef() != null ) {
69 ResultSetMappingDefinition definition = session.getFactory()
70 .getResultSetMapping( queryDef.getResultSetRef() );
71 if (definition == null) {
72 throw new MappingException(
73 "Unable to find resultset-ref definition: " +
74 queryDef.getResultSetRef()
75 );
76 }
77 this.queryReturns = Arrays.asList( definition.getQueryReturns() );
78 }
79 else {
80 this.queryReturns = Arrays.asList( queryDef.getQueryReturns() );
81 }
82
83 this.querySpaces = queryDef.getQuerySpaces();
84 this.callable = queryDef.isCallable();
85 }
86
87 SQLQueryImpl(
88 final String sql,
89 final List queryReturns,
90 final Collection querySpaces,
91 final FlushMode flushMode,
92 boolean callable,
93 final SessionImplementor session,
94 ParameterMetadata parameterMetadata) {
95
96 super( sql, flushMode, session, parameterMetadata );
97 this.queryReturns = queryReturns;
98 this.querySpaces = querySpaces;
99 this.callable = callable;
100 }
101
102 SQLQueryImpl(
103 final String sql,
104 final String returnAliases[],
105 final Class returnClasses[],
106 final LockMode[] lockModes,
107 final SessionImplementor session,
108 final Collection querySpaces,
109 final FlushMode flushMode,
110 ParameterMetadata parameterMetadata) {
111
112 super( sql, flushMode, session, parameterMetadata );
113 queryReturns = new ArrayList(returnAliases.length);
114 for ( int i=0; i<returnAliases.length; i++ ) {
115 NativeSQLQueryRootReturn ret = new NativeSQLQueryRootReturn(
116 returnAliases[i],
117 returnClasses[i].getName(),
118 lockModes==null ? LockMode.NONE : lockModes[i]
119 );
120 queryReturns.add(ret);
121 }
122 this.querySpaces = querySpaces;
123 this.callable = false;
124 }
125
126 SQLQueryImpl(
127 final String sql,
128 final String returnAliases[],
129 final Class returnClasses[],
130 final SessionImplementor session,
131 ParameterMetadata parameterMetadata) {
132 this( sql, returnAliases, returnClasses, null, session, null, null, parameterMetadata );
133 }
134
135 SQLQueryImpl(String sql, SessionImplementor session, ParameterMetadata parameterMetadata) {
136 super( sql, null, session, parameterMetadata );
137 queryReturns = new ArrayList();
138 querySpaces = null;
139 callable = false;
140 }
141
142 private static final NativeSQLQueryReturn[] NO_SQL_RETURNS = new NativeSQLQueryReturn[0];
143
144 private NativeSQLQueryReturn[] getQueryReturns() {
145 return ( NativeSQLQueryReturn[] ) queryReturns.toArray( NO_SQL_RETURNS );
146 }
147
148 public List list() throws HibernateException {
149 verifyParameters();
150 before();
151
152 Map namedParams = getNamedParams();
153 NativeSQLQuerySpecification spec = generateQuerySpecification( namedParams );
154
155 try {
156 return getSession().list( spec, getQueryParameters( namedParams ) );
157 }
158 finally {
159 after();
160 }
161 }
162
163 private NativeSQLQuerySpecification generateQuerySpecification(Map namedParams) {
164 return new NativeSQLQuerySpecification(
165 expandParameterLists(namedParams),
166 getQueryReturns(),
167 querySpaces
168 );
169 }
170
171 public ScrollableResults scroll(ScrollMode scrollMode) throws HibernateException {
172 verifyParameters();
173 before();
174
175 Map namedParams = getNamedParams();
176 NativeSQLQuerySpecification spec = generateQuerySpecification( namedParams );
177
178 QueryParameters qp = getQueryParameters( namedParams );
179 qp.setScrollMode( scrollMode );
180
181 try {
182 return getSession().scroll( spec, qp );
183 }
184 finally {
185 after();
186 }
187 }
188
189 public ScrollableResults scroll() throws HibernateException {
190 return scroll(ScrollMode.SCROLL_INSENSITIVE);
191 }
192
193 public Iterator iterate() throws HibernateException {
194 throw new UnsupportedOperationException("SQL queries do not currently support iteration");
195 }
196
197 public QueryParameters getQueryParameters(Map namedParams) {
198 QueryParameters qp = super.getQueryParameters(namedParams);
199 qp.setCallable(callable);
200 qp.setAutoDiscoverScalarTypes(autodiscovertypes);
201 return qp;
202 }
203
204 protected void verifyParameters() {
205 verifyParameters( callable );
206 boolean noReturns = queryReturns==null || queryReturns.isEmpty();
207 if ( noReturns ) {
208 this.autodiscovertypes = noReturns;
209 }
210 else {
211 Iterator itr = queryReturns.iterator();
212 while ( itr.hasNext() ) {
213 NativeSQLQueryReturn rtn = ( NativeSQLQueryReturn ) itr.next();
214 if ( rtn instanceof NativeSQLQueryScalarReturn ) {
215 NativeSQLQueryScalarReturn scalar = ( NativeSQLQueryScalarReturn ) rtn;
216 if ( scalar.getType() == null ) {
217 autodiscovertypes = true;
218 break;
219 }
220 }
221 }
222 }
223 }
224
225 public String[] getReturnAliases() throws HibernateException {
226 throw new UnsupportedOperationException("SQL queries do not currently support returning aliases");
227 }
228
229 public Type[] getReturnTypes() throws HibernateException {
230 throw new UnsupportedOperationException("not yet implemented for SQL queries");
231 }
232
233 public Query setLockMode(String alias, LockMode lockMode) {
234 throw new UnsupportedOperationException("cannot set the lock mode for a native SQL query");
235 }
236
237 protected Map getLockModes() {
238
239 return CollectionHelper.EMPTY_MAP;
240 }
241
242 public SQLQuery addScalar(String columnAlias, Type type) {
243 queryReturns.add( new NativeSQLQueryScalarReturn( columnAlias, type ) );
244 return this;
245 }
246
247 public SQLQuery addScalar(String columnAlias) {
248 autodiscovertypes = true;
249 queryReturns.add( new NativeSQLQueryScalarReturn( columnAlias, null ) );
250 return this;
251 }
252
253 public SQLQuery addJoin(String alias, String path) {
254 return addJoin(alias, path, LockMode.READ);
255 }
256
257 public SQLQuery addEntity(Class entityClass) {
258 return addEntity( StringHelper.unqualify( entityClass.getName() ), entityClass );
259 }
260
261 public SQLQuery addEntity(String entityName) {
262 return addEntity( StringHelper.unqualify( entityName ), entityName );
263 }
264
265 public SQLQuery addEntity(String alias, String entityName) {
266 return addEntity(alias, entityName, LockMode.READ);
267 }
268
269 public SQLQuery addEntity(String alias, Class entityClass) {
270 return addEntity( alias, entityClass.getName() );
271 }
272
273 public SQLQuery addJoin(String alias, String path, LockMode lockMode) {
274 int loc = path.indexOf('.');
275 if ( loc < 0 ) {
276 throw new QueryException( "not a property path: " + path );
277 }
278 String ownerAlias = path.substring(0, loc);
279 String role = path.substring(loc+1);
280 queryReturns.add( new NativeSQLQueryJoinReturn(alias, ownerAlias, role, CollectionHelper.EMPTY_MAP, lockMode) );
281 return this;
282 }
283
284 public SQLQuery addEntity(String alias, String entityName, LockMode lockMode) {
285 queryReturns.add( new NativeSQLQueryRootReturn(alias, entityName, lockMode) );
286 return this;
287 }
288
289 public SQLQuery addEntity(String alias, Class entityClass, LockMode lockMode) {
290 return addEntity( alias, entityClass.getName(), lockMode );
291 }
292
293 public SQLQuery setResultSetMapping(String name) {
294 ResultSetMappingDefinition mapping = session.getFactory().getResultSetMapping( name );
295 if ( mapping == null ) {
296 throw new MappingException( "Unknown SqlResultSetMapping [" + name + "]" );
297 }
298 NativeSQLQueryReturn[] returns = mapping.getQueryReturns();
299 int length = returns.length;
300 for ( int index = 0 ; index < length ; index++ ) {
301 queryReturns.add( returns[index] );
302 }
303 return this;
304 }
305
306 public SQLQuery addSynchronizedQuerySpace(String querySpace) {
307 if ( querySpaces == null ) {
308 querySpaces = new ArrayList();
309 }
310 querySpaces.add( querySpace );
311 return this;
312 }
313
314 public SQLQuery addSynchronizedEntityName(String entityName) {
315 return addQuerySpaces( getSession().getFactory().getEntityPersister( entityName ).getQuerySpaces() );
316 }
317
318 public SQLQuery addSynchronizedEntityClass(Class entityClass) {
319 return addQuerySpaces( getSession().getFactory().getEntityPersister( entityClass.getName() ).getQuerySpaces() );
320 }
321
322 private SQLQuery addQuerySpaces(Serializable[] spaces) {
323 if ( spaces != null ) {
324 if ( querySpaces == null ) {
325 querySpaces = new ArrayList();
326 }
327 for ( int i = 0; i < spaces.length; i++ ) {
328 querySpaces.add( spaces[i] );
329 }
330 }
331 return this;
332 }
333
334 public int executeUpdate() throws HibernateException {
335 Map namedParams = getNamedParams();
336 before();
337 try {
338 return getSession().executeNativeUpdate(
339 generateQuerySpecification( namedParams ),
340 getQueryParameters( namedParams )
341 );
342 }
343 finally {
344 after();
345 }
346 }
347
348
349
350
351 public int count() throws HibernateException {
352 StringBuffer sqlQuery = new StringBuffer(this.getQueryString().toUpperCase());
353 StringBuffer sqlQueryBuffer = new StringBuffer();
354 sqlQueryBuffer.append("SELECT COUNT(*) ");
355 int start = sqlQuery.indexOf("FROM");
356 int stop = sqlQuery.indexOf("ORDER BY");
357 if (stop >= 0) {
358 sqlQueryBuffer.append(this.getQueryString().substring(start, stop));
359 } else {
360 sqlQueryBuffer.append(this.getQueryString().substring(start));
361 }
362 Query countQuery = ((Session)this.session).createSQLQuery(sqlQueryBuffer.toString());
363
364
365 Map parameters = this.getNamedParams();
366 Set parameterNames = parameters.keySet();
367 Iterator iter = parameterNames.iterator();
368 while (iter.hasNext()) {
369 String name = (String)iter.next();
370 TypedValue typedValue = (TypedValue)parameters.get(name);
371 countQuery.setParameter(name, typedValue.getValue(), typedValue.getType());
372 }
373
374
375 List paramTypes = this.getTypes();
376 List paramValues = this.getValues();
377 if (paramTypes != null && paramTypes.size() > 0) {
378 for (int i = 0; i < paramTypes.size(); i++) {
379 countQuery.setParameter(i, paramValues.get(i), (Type)paramTypes.get(i));
380 }
381 }
382 int count = ((BigInteger)countQuery.uniqueResult()).intValue();
383 return count;
384 }
385
386 }