Package org.hibernate.internal

Source Code of org.hibernate.internal.SQLQueryImpl

/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors.  All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA  02110-1301  USA
*/
package org.hibernate.internal;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

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

/**
* Implementation of the {@link SQLQuery} contract.
*
* @author Max Andersen
* @author Steve Ebersole
*/
public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {

  private List<NativeSQLQueryReturn> queryReturns;
  private List<ReturnBuilder> queryReturnBuilders;
  private boolean autoDiscoverTypes;

  private Collection<String> querySpaces;

  private final boolean callable;
  private final LockOptions lockOptions = new LockOptions();

  /**
   * 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) {
    super( queryDef.getQueryString(), queryDef.getFlushMode(), session, parameterMetadata );
    if ( queryDef.getResultSetRef() != null ) {
      ResultSetMappingDefinition definition = session.getFactory()
          .getResultSetMapping( queryDef.getResultSetRef() );
      if (definition == null) {
        throw new MappingException(
            "Unable to find resultset-ref definition: " +
            queryDef.getResultSetRef()
          );
      }
      this.queryReturns = Arrays.asList( definition.getQueryReturns() );
    }
    else if ( queryDef.getQueryReturns() != null && queryDef.getQueryReturns().length > 0 ) {
      this.queryReturns = Arrays.asList( queryDef.getQueryReturns() );
    }
    else {
      this.queryReturns = new ArrayList<NativeSQLQueryReturn>();
    }

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

  SQLQueryImpl(
      final String sql,
          final String returnAliases[],
          final Class returnClasses[],
          final LockMode[] lockModes,
          final SessionImplementor session,
          final Collection<String> querySpaces,
          final FlushMode flushMode,
          ParameterMetadata parameterMetadata) {
    // TODO : this constructor form is *only* used from constructor directly below us; can it go away?
    super( sql, flushMode, session, parameterMetadata );
    queryReturns = new ArrayList<NativeSQLQueryReturn>( 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) {
    this( sql, returnAliases, returnClasses, null, session, null, null, parameterMetadata );
  }

  SQLQueryImpl(String sql, SessionImplementor session, ParameterMetadata parameterMetadata) {
    super( sql, null, session, parameterMetadata );
    queryReturns = new ArrayList<NativeSQLQueryReturn>();
    querySpaces = null;
    callable = false;
  }

  private NativeSQLQueryReturn[] getQueryReturns() {
    return queryReturns.toArray( new NativeSQLQueryReturn[queryReturns.size()] );
  }

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

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

    try {
      return getSession().list( spec, getQueryParameters( namedParams ) );
    }
    finally {
      after();
    }
  }

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

  public ScrollableResults scroll(ScrollMode scrollMode) throws HibernateException {
    verifyParameters();
    before();

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

    QueryParameters qp = getQueryParameters( namedParams );
    qp.setScrollMode( scrollMode );

    try {
      return getSession().scroll( spec, 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");
  }

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

  @Override
    protected void verifyParameters() {
    // verifyParameters is called at the start of all execution type methods, so we use that here to perform
    // some preparation work.
    prepare();
    verifyParameters( callable );
    boolean noReturns = queryReturns==null || queryReturns.isEmpty();
    if ( noReturns ) {
      this.autoDiscoverTypes = noReturns;
    }
    else {
      for ( NativeSQLQueryReturn queryReturn : queryReturns ) {
        if ( queryReturn instanceof NativeSQLQueryScalarReturn ) {
          NativeSQLQueryScalarReturn scalar = (NativeSQLQueryScalarReturn) queryReturn;
          if ( scalar.getType() == null ) {
            autoDiscoverTypes = true;
            break;
          }
        }
      }
    }
  }

  private void prepare() {
    if ( queryReturnBuilders != null ) {
      if ( ! queryReturnBuilders.isEmpty() ) {
        if ( queryReturns != null ) {
          queryReturns.clear();
          queryReturns = null;
        }
        queryReturns = new ArrayList<NativeSQLQueryReturn>();
        for ( ReturnBuilder builder : queryReturnBuilders ) {
          queryReturns.add( builder.buildReturn() );
        }
        queryReturnBuilders.clear();
      }
      queryReturnBuilders = null;
    }
  }

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

  @Override
    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");
  }

  public Query setLockOptions(LockOptions lockOptions) {
    throw new UnsupportedOperationException("cannot set lock options for a native SQL query");
  }

  @Override
    public LockOptions getLockOptions() {
    //we never need to apply locks to the SQL, however the native-sql loader handles this specially
    return lockOptions;
  }

  public SQLQuery addScalar(final String columnAlias, final Type type) {
    if ( queryReturnBuilders == null ) {
      queryReturnBuilders = new ArrayList<ReturnBuilder>();
    }
    queryReturnBuilders.add(
        new ReturnBuilder() {
          public NativeSQLQueryReturn buildReturn() {
            return new NativeSQLQueryScalarReturn( columnAlias, type );
          }
        }
    );
    return this;
  }

  public SQLQuery addScalar(String columnAlias) {
    return addScalar( columnAlias, null );
  }

  public RootReturn addRoot(String tableAlias, String entityName) {
    RootReturnBuilder builder = new RootReturnBuilder( tableAlias, entityName );
    if ( queryReturnBuilders == null ) {
      queryReturnBuilders = new ArrayList<ReturnBuilder>();
    }
    queryReturnBuilders.add( builder );
    return builder;
  }

  public RootReturn addRoot(String tableAlias, Class entityType) {
    return addRoot( tableAlias, entityType.getName() );
  }

  public SQLQuery addEntity(String entityName) {
    return addEntity( StringHelper.unqualify( entityName ), entityName );
  }

  public SQLQuery addEntity(String alias, String entityName) {
    addRoot( alias, entityName );
    return this;
  }

  public SQLQuery addEntity(String alias, String entityName, LockMode lockMode) {
    addRoot( alias, entityName ).setLockMode( lockMode );
    return this;
  }

  public SQLQuery addEntity(Class entityType) {
    return addEntity( entityType.getName() );
  }

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

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

  public FetchReturn addFetch(String tableAlias, String ownerTableAlias, String joinPropertyName) {
    FetchReturnBuilder builder = new FetchReturnBuilder( tableAlias, ownerTableAlias, joinPropertyName );
    if ( queryReturnBuilders == null ) {
      queryReturnBuilders = new ArrayList<ReturnBuilder>();
    }
    queryReturnBuilders.add( builder );
    return builder;
  }

  public SQLQuery addJoin(String tableAlias, String ownerTableAlias, String joinPropertyName) {
    addFetch( tableAlias, ownerTableAlias, joinPropertyName );
    return this;
  }

  public SQLQuery addJoin(String alias, String path) {
    createFetchJoin( alias, path );
    return this;
  }

  private FetchReturn createFetchJoin(String tableAlias, String path) {
    int loc = path.indexOf('.');
    if ( loc < 0 ) {
      throw new QueryException( "not a property path: " + path );
    }
    final String ownerTableAlias = path.substring( 0, loc );
    final String joinedPropertyName = path.substring( loc+1 );
    return addFetch( tableAlias, ownerTableAlias, joinedPropertyName );
  }

  public SQLQuery addJoin(String alias, String path, LockMode lockMode) {
    createFetchJoin( alias, path ).setLockMode( lockMode );
    return this;
  }

  public SQLQuery setResultSetMapping(String name) {
    ResultSetMappingDefinition mapping = session.getFactory().getResultSetMapping( name );
    if ( mapping == null ) {
      throw new MappingException( "Unknown SqlResultSetMapping [" + name + "]" );
    }
    NativeSQLQueryReturn[] returns = mapping.getQueryReturns();
    queryReturns.addAll( Arrays.asList( returns ) );
    return this;
  }

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

  public SQLQuery addSynchronizedEntityName(String entityName) {
    return addQuerySpaces( getSession().getFactory().getEntityPersister( entityName ).getQuerySpaces() );
  }

  public SQLQuery addSynchronizedEntityClass(Class entityClass) {
    return addQuerySpaces( getSession().getFactory().getEntityPersister( entityClass.getName() ).getQuerySpaces() );
  }

  private SQLQuery addQuerySpaces(Serializable[] spaces) {
    if ( spaces != null ) {
      if ( querySpaces == null ) {
        querySpaces = new ArrayList<String>();
      }
      querySpaces.addAll( Arrays.asList( (String[]) spaces ) );
    }
    return this;
  }

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

  private class RootReturnBuilder implements RootReturn, ReturnBuilder {
    private final String alias;
    private final String entityName;
    private LockMode lockMode = LockMode.READ;
    private Map<String,String[]> propertyMappings;

    private RootReturnBuilder(String alias, String entityName) {
      this.alias = alias;
      this.entityName = entityName;
    }

    public RootReturn setLockMode(LockMode lockMode) {
      this.lockMode = lockMode;
      return this;
    }

    public RootReturn setDiscriminatorAlias(String alias) {
      addProperty( "class", alias );
      return this;
    }

    public RootReturn addProperty(String propertyName, String columnAlias) {
      addProperty( propertyName ).addColumnAlias( columnAlias );
      return this;
    }

    public ReturnProperty addProperty(final String propertyName) {
      if ( propertyMappings == null ) {
        propertyMappings = new HashMap<String,String[]>();
      }
      return new ReturnProperty() {
        public ReturnProperty addColumnAlias(String columnAlias) {
          String[] columnAliases = propertyMappings.get( propertyName );
          if ( columnAliases == null ) {
            columnAliases = new String[]{columnAlias};
          }else{
             String[] newColumnAliases = new String[columnAliases.length + 1];
            System.arraycopy( columnAliases, 0, newColumnAliases, 0, columnAliases.length );
            newColumnAliases[columnAliases.length] = columnAlias;
            columnAliases = newColumnAliases;
          }
          propertyMappings.put( propertyName,columnAliases );
          return this;
        }
      };
    }

    public NativeSQLQueryReturn buildReturn() {
      return new NativeSQLQueryRootReturn( alias, entityName, propertyMappings, lockMode );
    }
  }
  private class FetchReturnBuilder implements FetchReturn, ReturnBuilder {
    private final String alias;
    private String ownerTableAlias;
    private final String joinedPropertyName;
    private LockMode lockMode = LockMode.READ;
    private Map<String,String[]> propertyMappings;

    private FetchReturnBuilder(String alias, String ownerTableAlias, String joinedPropertyName) {
      this.alias = alias;
      this.ownerTableAlias = ownerTableAlias;
      this.joinedPropertyName = joinedPropertyName;
    }

    public FetchReturn setLockMode(LockMode lockMode) {
      this.lockMode = lockMode;
      return this;
    }

    public FetchReturn addProperty(String propertyName, String columnAlias) {
      addProperty( propertyName ).addColumnAlias( columnAlias );
      return this;
    }

    public ReturnProperty addProperty(final String propertyName) {
      if ( propertyMappings == null ) {
        propertyMappings = new HashMap<String,String[]>();
      }
      return new ReturnProperty() {
        public ReturnProperty addColumnAlias(String columnAlias) {
          String[] columnAliases = propertyMappings.get( propertyName );
          if ( columnAliases == null ) {
            columnAliases = new String[]{columnAlias};
          }else{
             String[] newColumnAliases = new String[columnAliases.length + 1];
            System.arraycopy( columnAliases, 0, newColumnAliases, 0, columnAliases.length );
            newColumnAliases[columnAliases.length] = columnAlias;
            columnAliases = newColumnAliases;
          }
          propertyMappings.put( propertyName,columnAliases );
          return this;
        }
      };
    }

    public NativeSQLQueryReturn buildReturn() {
      return new NativeSQLQueryJoinReturn( alias, ownerTableAlias, joinedPropertyName, propertyMappings, lockMode );
    }
  }

  private interface ReturnBuilder {
    NativeSQLQueryReturn buildReturn();
  }
}
TOP

Related Classes of org.hibernate.internal.SQLQueryImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.