001: //$Id: SQLQueryImpl.java 10861 2006-11-22 00:11:25Z steve.ebersole@jboss.com $
002: package org.hibernate.impl;
003:
004: import java.util.ArrayList;
005: import java.util.Arrays;
006: import java.util.Collection;
007: import java.util.Iterator;
008: import java.util.List;
009: import java.util.Map;
010: import java.io.Serializable;
011:
012: import org.hibernate.FlushMode;
013: import org.hibernate.HibernateException;
014: import org.hibernate.LockMode;
015: import org.hibernate.Query;
016: import org.hibernate.QueryException;
017: import org.hibernate.SQLQuery;
018: import org.hibernate.ScrollMode;
019: import org.hibernate.ScrollableResults;
020: import org.hibernate.MappingException;
021: import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
022: import org.hibernate.engine.ResultSetMappingDefinition;
023: import org.hibernate.engine.NamedSQLQueryDefinition;
024: import org.hibernate.engine.QueryParameters;
025: import org.hibernate.engine.SessionImplementor;
026: import org.hibernate.engine.query.ParameterMetadata;
027: import org.hibernate.engine.query.sql.NativeSQLQueryJoinReturn;
028: import org.hibernate.engine.query.sql.NativeSQLQueryScalarReturn;
029: import org.hibernate.engine.query.sql.NativeSQLQueryRootReturn;
030: import org.hibernate.engine.query.sql.NativeSQLQueryReturn;
031: import org.hibernate.type.Type;
032: import org.hibernate.util.CollectionHelper;
033: import org.hibernate.util.StringHelper;
034:
035: /**
036: * Implements SQL query passthrough.
037: *
038: * <pre>
039: * <sql-query name="mySqlQuery">
040: * <return alias="person" class="eg.Person"/>
041: * SELECT {person}.NAME AS {person.name}, {person}.AGE AS {person.age}, {person}.SEX AS {person.sex}
042: * FROM PERSON {person} WHERE {person}.NAME LIKE 'Hiber%'
043: * </sql-query>
044: * </pre>
045: *
046: * @author Max Andersen
047: */
048: public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
049:
050: private final List queryReturns;
051: private Collection querySpaces;
052: private final boolean callable;
053: private boolean autodiscovertypes;
054:
055: /**
056: * Constructs a SQLQueryImpl given a sql query defined in the mappings.
057: *
058: * @param queryDef The representation of the defined <sql-query/>.
059: * @param session The session to which this SQLQueryImpl belongs.
060: * @param parameterMetadata Metadata about parameters found in the query.
061: */
062: SQLQueryImpl(NamedSQLQueryDefinition queryDef,
063: SessionImplementor session,
064: ParameterMetadata parameterMetadata) {
065: super (queryDef.getQueryString(), queryDef.getFlushMode(),
066: session, parameterMetadata);
067: if (queryDef.getResultSetRef() != null) {
068: ResultSetMappingDefinition definition = session
069: .getFactory().getResultSetMapping(
070: queryDef.getResultSetRef());
071: if (definition == null) {
072: throw new MappingException(
073: "Unable to find resultset-ref definition: "
074: + queryDef.getResultSetRef());
075: }
076: this .queryReturns = Arrays.asList(definition
077: .getQueryReturns());
078: } else {
079: this .queryReturns = Arrays.asList(queryDef
080: .getQueryReturns());
081: }
082:
083: this .querySpaces = queryDef.getQuerySpaces();
084: this .callable = queryDef.isCallable();
085: }
086:
087: SQLQueryImpl(final String sql, final List queryReturns,
088: final Collection querySpaces, final FlushMode flushMode,
089: boolean callable, final SessionImplementor session,
090: ParameterMetadata parameterMetadata) {
091: // TODO : absolutely no usages of this constructor form; can it go away?
092: super (sql, flushMode, session, parameterMetadata);
093: this .queryReturns = queryReturns;
094: this .querySpaces = querySpaces;
095: this .callable = callable;
096: }
097:
098: SQLQueryImpl(final String sql, final String returnAliases[],
099: final Class returnClasses[], final LockMode[] lockModes,
100: final SessionImplementor session,
101: final Collection querySpaces, final FlushMode flushMode,
102: ParameterMetadata parameterMetadata) {
103: // TODO : this constructor form is *only* used from constructor directly below us; can it go away?
104: super (sql, flushMode, session, parameterMetadata);
105: queryReturns = new ArrayList(returnAliases.length);
106: for (int i = 0; i < returnAliases.length; i++) {
107: NativeSQLQueryRootReturn ret = new NativeSQLQueryRootReturn(
108: returnAliases[i], returnClasses[i].getName(),
109: lockModes == null ? LockMode.NONE : lockModes[i]);
110: queryReturns.add(ret);
111: }
112: this .querySpaces = querySpaces;
113: this .callable = false;
114: }
115:
116: SQLQueryImpl(final String sql, final String returnAliases[],
117: final Class returnClasses[],
118: final SessionImplementor session,
119: ParameterMetadata parameterMetadata) {
120: this (sql, returnAliases, returnClasses, null, session, null,
121: null, parameterMetadata);
122: }
123:
124: SQLQueryImpl(String sql, SessionImplementor session,
125: ParameterMetadata parameterMetadata) {
126: super (sql, null, session, parameterMetadata);
127: queryReturns = new ArrayList();
128: querySpaces = null;
129: callable = false;
130: }
131:
132: private static final NativeSQLQueryReturn[] NO_SQL_RETURNS = new NativeSQLQueryReturn[0];
133:
134: private NativeSQLQueryReturn[] getQueryReturns() {
135: return (NativeSQLQueryReturn[]) queryReturns
136: .toArray(NO_SQL_RETURNS);
137: }
138:
139: public List list() throws HibernateException {
140: verifyParameters();
141: before();
142:
143: Map namedParams = getNamedParams();
144: NativeSQLQuerySpecification spec = generateQuerySpecification(namedParams);
145:
146: try {
147: return getSession().list(spec,
148: getQueryParameters(namedParams));
149: } finally {
150: after();
151: }
152: }
153:
154: private NativeSQLQuerySpecification generateQuerySpecification(
155: Map namedParams) {
156: return new NativeSQLQuerySpecification(
157: expandParameterLists(namedParams), getQueryReturns(),
158: querySpaces);
159: }
160:
161: public ScrollableResults scroll(ScrollMode scrollMode)
162: throws HibernateException {
163: verifyParameters();
164: before();
165:
166: Map namedParams = getNamedParams();
167: NativeSQLQuerySpecification spec = generateQuerySpecification(namedParams);
168:
169: QueryParameters qp = getQueryParameters(namedParams);
170: qp.setScrollMode(scrollMode);
171:
172: try {
173: return getSession().scroll(spec, qp);
174: } finally {
175: after();
176: }
177: }
178:
179: public ScrollableResults scroll() throws HibernateException {
180: return scroll(ScrollMode.SCROLL_INSENSITIVE);
181: }
182:
183: public Iterator iterate() throws HibernateException {
184: throw new UnsupportedOperationException(
185: "SQL queries do not currently support iteration");
186: }
187:
188: public QueryParameters getQueryParameters(Map namedParams) {
189: QueryParameters qp = super .getQueryParameters(namedParams);
190: qp.setCallable(callable);
191: qp.setAutoDiscoverScalarTypes(autodiscovertypes);
192: return qp;
193: }
194:
195: protected void verifyParameters() {
196: verifyParameters(callable);
197: boolean noReturns = queryReturns == null
198: || queryReturns.isEmpty();
199: if (noReturns) {
200: this .autodiscovertypes = noReturns;
201: } else {
202: Iterator itr = queryReturns.iterator();
203: while (itr.hasNext()) {
204: NativeSQLQueryReturn rtn = (NativeSQLQueryReturn) itr
205: .next();
206: if (rtn instanceof NativeSQLQueryScalarReturn) {
207: NativeSQLQueryScalarReturn scalar = (NativeSQLQueryScalarReturn) rtn;
208: if (scalar.getType() == null) {
209: autodiscovertypes = true;
210: break;
211: }
212: }
213: }
214: }
215: }
216:
217: public String[] getReturnAliases() throws HibernateException {
218: throw new UnsupportedOperationException(
219: "SQL queries do not currently support returning aliases");
220: }
221:
222: public Type[] getReturnTypes() throws HibernateException {
223: throw new UnsupportedOperationException(
224: "not yet implemented for SQL queries");
225: }
226:
227: public Query setLockMode(String alias, LockMode lockMode) {
228: throw new UnsupportedOperationException(
229: "cannot set the lock mode for a native SQL query");
230: }
231:
232: protected Map getLockModes() {
233: //we never need to apply locks to the SQL
234: return CollectionHelper.EMPTY_MAP;
235: }
236:
237: public SQLQuery addScalar(String columnAlias, Type type) {
238: queryReturns.add(new NativeSQLQueryScalarReturn(columnAlias,
239: type));
240: return this ;
241: }
242:
243: public SQLQuery addScalar(String columnAlias) {
244: autodiscovertypes = true;
245: queryReturns.add(new NativeSQLQueryScalarReturn(columnAlias,
246: null));
247: return this ;
248: }
249:
250: public SQLQuery addJoin(String alias, String path) {
251: return addJoin(alias, path, LockMode.READ);
252: }
253:
254: public SQLQuery addEntity(Class entityClass) {
255: return addEntity(StringHelper.unqualify(entityClass.getName()),
256: entityClass);
257: }
258:
259: public SQLQuery addEntity(String entityName) {
260: return addEntity(StringHelper.unqualify(entityName), entityName);
261: }
262:
263: public SQLQuery addEntity(String alias, String entityName) {
264: return addEntity(alias, entityName, LockMode.READ);
265: }
266:
267: public SQLQuery addEntity(String alias, Class entityClass) {
268: return addEntity(alias, entityClass.getName());
269: }
270:
271: public SQLQuery addJoin(String alias, String path, LockMode lockMode) {
272: int loc = path.indexOf('.');
273: if (loc < 0) {
274: throw new QueryException("not a property path: " + path);
275: }
276: String ownerAlias = path.substring(0, loc);
277: String role = path.substring(loc + 1);
278: queryReturns
279: .add(new NativeSQLQueryJoinReturn(alias, ownerAlias,
280: role, CollectionHelper.EMPTY_MAP, lockMode));
281: return this ;
282: }
283:
284: public SQLQuery addEntity(String alias, String entityName,
285: LockMode lockMode) {
286: queryReturns.add(new NativeSQLQueryRootReturn(alias,
287: entityName, lockMode));
288: return this ;
289: }
290:
291: public SQLQuery addEntity(String alias, Class entityClass,
292: LockMode lockMode) {
293: return addEntity(alias, entityClass.getName(), lockMode);
294: }
295:
296: public SQLQuery setResultSetMapping(String name) {
297: ResultSetMappingDefinition mapping = session.getFactory()
298: .getResultSetMapping(name);
299: if (mapping == null) {
300: throw new MappingException("Unknown SqlResultSetMapping ["
301: + name + "]");
302: }
303: NativeSQLQueryReturn[] returns = mapping.getQueryReturns();
304: int length = returns.length;
305: for (int index = 0; index < length; index++) {
306: queryReturns.add(returns[index]);
307: }
308: return this ;
309: }
310:
311: public SQLQuery addSynchronizedQuerySpace(String querySpace) {
312: if (querySpaces == null) {
313: querySpaces = new ArrayList();
314: }
315: querySpaces.add(querySpace);
316: return this ;
317: }
318:
319: public SQLQuery addSynchronizedEntityName(String entityName) {
320: return addQuerySpaces(getSession().getFactory()
321: .getEntityPersister(entityName).getQuerySpaces());
322: }
323:
324: public SQLQuery addSynchronizedEntityClass(Class entityClass) {
325: return addQuerySpaces(getSession().getFactory()
326: .getEntityPersister(entityClass.getName())
327: .getQuerySpaces());
328: }
329:
330: private SQLQuery addQuerySpaces(Serializable[] spaces) {
331: if (spaces != null) {
332: if (querySpaces == null) {
333: querySpaces = new ArrayList();
334: }
335: for (int i = 0; i < spaces.length; i++) {
336: querySpaces.add(spaces[i]);
337: }
338: }
339: return this ;
340: }
341:
342: public int executeUpdate() throws HibernateException {
343: Map namedParams = getNamedParams();
344: before();
345: try {
346: return getSession().executeNativeUpdate(
347: generateQuerySpecification(namedParams),
348: getQueryParameters(namedParams));
349: } finally {
350: after();
351: }
352: }
353:
354: }
|