Open Source Repository

Home /hibernate/hibernate-3.2.4.ga | Repository Home


org/hibernate/impl/SQLQueryImpl.java
//$Id: SQLQueryImpl.java 10861 2006-11-22 00:11:25Z [email protected] $
package org.hibernate.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.io.Serializable;

import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.QueryException;
import org.hibernate.SQLQuery;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.MappingException;
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.NamedSQLQueryDefinition;
import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.query.ParameterMetadata;
import org.hibernate.engine.query.sql.NativeSQLQueryJoinReturn;
import org.hibernate.engine.query.sql.NativeSQLQueryScalarReturn;
import org.hibernate.engine.query.sql.NativeSQLQueryRootReturn;
import org.hibernate.engine.query.sql.NativeSQLQueryReturn;
import org.hibernate.type.Type;
import org.hibernate.util.CollectionHelper;
import org.hibernate.util.StringHelper;

/**
 * Implements SQL query passthrough.
 *
 <pre>
 <sql-query name="mySqlQuery">
 <return alias="person" class="eg.Person"/>
 *   SELECT {person}.NAME AS {person.name}, {person}.AGE AS {person.age}, {person}.SEX AS {person.sex}
 *   FROM PERSON {person} WHERE {person}.NAME LIKE 'Hiber%'
 </sql-query>
 </pre>
 *
 @author Max Andersen
 */
public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {

  private final List queryReturns;
  private Collection querySpaces;
  private final boolean callable;
  private boolean autodiscovertypes;

  /**
   * Constructs a SQLQueryImpl given a sql query defined in the mappings.
   *
   @param queryDef The representation of the defined <sql-query/>.
   @param session The session to which this SQLQueryImpl belongs.
   @param parameterMetadata Metadata about parameters found in the query.
   */
  SQLQueryImpl(NamedSQLQueryDefinition queryDef, SessionImplementor session, ParameterMetadata parameterMetadata) {
    superqueryDef.getQueryString(), queryDef.getFlushMode(), session, parameterMetadata );
    if queryDef.getResultSetRef() != null ) {
      ResultSetMappingDefinition definition = session.getFactory()
          .getResultSetMappingqueryDef.getResultSetRef() );
      if (definition == null) {
        throw new MappingException(
            "Unable to find resultset-ref definition: " +
            queryDef.getResultSetRef() 
          );
      }
      this.queryReturns = Arrays.asListdefinition.getQueryReturns() );
    }
    else {
      this.queryReturns = Arrays.asListqueryDef.getQueryReturns() );
    }

    this.querySpaces = queryDef.getQuerySpaces();
    this.callable = queryDef.isCallable();
  }

  SQLQueryImpl(
      final String sql,
          final List queryReturns,
          final Collection querySpaces,
          final FlushMode flushMode,
          boolean callable,
          final SessionImplementor session,
          ParameterMetadata parameterMetadata) {
    // TODO : absolutely no usages of this constructor form; can it go away?
    supersql, flushMode, session, parameterMetadata );
    this.queryReturns = queryReturns;
    this.querySpaces = querySpaces;
    this.callable = callable;
  }

  SQLQueryImpl(
      final String sql,
          final String returnAliases[],
          final Class returnClasses[],
          final LockMode[] lockModes,
          final SessionImplementor session,
          final Collection querySpaces,
          final FlushMode flushMode,
          ParameterMetadata parameterMetadata) {
    // TODO : this constructor form is *only* used from constructor directly below us; can it go away?
    supersql, flushMode, session, parameterMetadata );
    queryReturns = new ArrayList(returnAliases.length);
    for int i=0; i<returnAliases.length; i++ ) {
      NativeSQLQueryRootReturn ret = new NativeSQLQueryRootReturn(
          returnAliases[i],
          returnClasses[i].getName(),
          lockModes==null ? LockMode.NONE : lockModes[i]
      );
      queryReturns.add(ret);
    }
    this.querySpaces = querySpaces;
    this.callable = false;
  }

  SQLQueryImpl(
      final String sql,
          final String returnAliases[],
          final Class returnClasses[],
          final SessionImplementor session,
          ParameterMetadata parameterMetadata) {
    thissql, returnAliases, returnClasses, null, session, null, null, parameterMetadata );
  }
  
  SQLQueryImpl(String sql, SessionImplementor session, ParameterMetadata parameterMetadata) {
    supersql, null, session, parameterMetadata );
    queryReturns = new ArrayList();
    querySpaces = null;
    callable = false;
  }
  
  private static final NativeSQLQueryReturn[] NO_SQL_RETURNS = new NativeSQLQueryReturn[0];
  
  private NativeSQLQueryReturn[] getQueryReturns() {
    return NativeSQLQueryReturn[] ) queryReturns.toArrayNO_SQL_RETURNS );
  }

  public List list() throws HibernateException {
    verifyParameters();
    before();

    Map namedParams = getNamedParams();
    NativeSQLQuerySpecification spec = generateQuerySpecificationnamedParams );

    try {
      return getSession().listspec, getQueryParametersnamedParams ) );
    }
    finally {
      after();
    }
  }

  private NativeSQLQuerySpecification generateQuerySpecification(Map namedParams) {
    return new NativeSQLQuerySpecification(
            expandParameterLists(namedParams),
            getQueryReturns(),
            querySpaces
    );
  }

  public ScrollableResults scroll(ScrollMode scrollModethrows HibernateException {
    verifyParameters();
    before();

    Map namedParams = getNamedParams();
    NativeSQLQuerySpecification spec = generateQuerySpecificationnamedParams );

    QueryParameters qp = getQueryParametersnamedParams );
    qp.setScrollModescrollMode );

    try {
      return getSession().scrollspec, qp );
    }
    finally {
      after();
    }
  }

  public ScrollableResults scroll() throws HibernateException {
    return scroll(ScrollMode.SCROLL_INSENSITIVE);
  }

  public Iterator iterate() throws HibernateException {
    throw new UnsupportedOperationException("SQL queries do not currently support iteration");
  }

  public QueryParameters getQueryParameters(Map namedParams) {
    QueryParameters qp = super.getQueryParameters(namedParams);
    qp.setCallable(callable);
    qp.setAutoDiscoverScalarTypes(autodiscovertypes);
    return qp;
  }

  protected void verifyParameters() {
    verifyParameterscallable );
    boolean noReturns = queryReturns==null || queryReturns.isEmpty();
    if noReturns ) {
      this.autodiscovertypes = noReturns;
    }
    else {
      Iterator itr = queryReturns.iterator();
      while itr.hasNext() ) {
        NativeSQLQueryReturn rtn = NativeSQLQueryReturn itr.next();
        if rtn instanceof NativeSQLQueryScalarReturn ) {
          NativeSQLQueryScalarReturn scalar = NativeSQLQueryScalarReturn rtn;
          if scalar.getType() == null ) {
            autodiscovertypes = true;
            break;
          }
        }
      }
    }
  }

  public String[] getReturnAliases() throws HibernateException {
    throw new UnsupportedOperationException("SQL queries do not currently support returning aliases");
  }

  public Type[] getReturnTypes() throws HibernateException {
    throw new UnsupportedOperationException("not yet implemented for SQL queries");
  }
  
  public Query setLockMode(String alias, LockMode lockMode) {
    throw new UnsupportedOperationException("cannot set the lock mode for a native SQL query");
  }
  
  protected Map getLockModes() {
    //we never need to apply locks to the SQL
    return CollectionHelper.EMPTY_MAP;
  }

  public SQLQuery addScalar(String columnAlias, Type type) {
    queryReturns.addnew NativeSQLQueryScalarReturncolumnAlias, type ) );
    return this;
  }

  public SQLQuery addScalar(String columnAlias) {
    autodiscovertypes = true;
    queryReturns.addnew NativeSQLQueryScalarReturncolumnAlias, null ) );
    return this;
  }

  public SQLQuery addJoin(String alias, String path) {
    return addJoin(alias, path, LockMode.READ);
  }

  public SQLQuery addEntity(Class entityClass) {
    return addEntityStringHelper.unqualifyentityClass.getName() ), entityClass );
  }

  public SQLQuery addEntity(String entityName) {
    return addEntityStringHelper.unqualifyentityName ), entityName );
  }

  public SQLQuery addEntity(String alias, String entityName) {
    return addEntity(alias, entityName, LockMode.READ);
  }

  public SQLQuery addEntity(String alias, Class entityClass) {
    return addEntityalias, entityClass.getName() );
  }
  
  public SQLQuery addJoin(String alias, String path, LockMode lockMode) {
    int loc = path.indexOf('.');
    if loc < ) {
      throw new QueryException"not a property path: " + path );
    }
    String ownerAlias = path.substring(0, loc);
    String role = path.substring(loc+1);
    queryReturns.addnew NativeSQLQueryJoinReturn(alias, ownerAlias, role, CollectionHelper.EMPTY_MAP, lockMode) );
    return this;
  }

  public SQLQuery addEntity(String alias, String entityName, LockMode lockMode) {
    queryReturns.addnew NativeSQLQueryRootReturn(alias, entityName, lockMode) );
    return this;
  }

  public SQLQuery addEntity(String alias, Class entityClass, LockMode lockMode) {
    return addEntityalias, entityClass.getName(), lockMode );
  }

  public SQLQuery setResultSetMapping(String name) {
    ResultSetMappingDefinition mapping = session.getFactory().getResultSetMappingname );
    if mapping == null ) {
      throw new MappingException"Unknown SqlResultSetMapping [" + name + "]" );
    }
    NativeSQLQueryReturn[] returns = mapping.getQueryReturns();
    int length = returns.length;
    for int index = ; index < length ; index++ ) {
      queryReturns.addreturns[index] );
    }
    return this;
  }

  public SQLQuery addSynchronizedQuerySpace(String querySpace) {
    if querySpaces == null ) {
      querySpaces = new ArrayList();
    }
    querySpaces.addquerySpace );
    return this;
  }

  public SQLQuery addSynchronizedEntityName(String entityName) {
    return addQuerySpacesgetSession().getFactory().getEntityPersisterentityName ).getQuerySpaces() );
  }

  public SQLQuery addSynchronizedEntityClass(Class entityClass) {
    return addQuerySpacesgetSession().getFactory().getEntityPersisterentityClass.getName() ).getQuerySpaces() );
  }

  private SQLQuery addQuerySpaces(Serializable[] spaces) {
    if spaces != null ) {
      if querySpaces == null ) {
        querySpaces = new ArrayList();
      }
      for int i = 0; i < spaces.length; i++ ) {
        querySpaces.addspaces[i] );
      }
    }
    return this;
  }

  public int executeUpdate() throws HibernateException {
    Map namedParams = getNamedParams();
    before();
    try {
      return getSession().executeNativeUpdate(
          generateQuerySpecificationnamedParams ),
          getQueryParametersnamedParams )
      );
    }
    finally {
      after();
    }
  }

}