/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
 * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
 */
package org.hibernate.criterion;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.internal.CriteriaImpl;
import org.hibernate.loader.criteria.CriteriaJoinWalker;
import org.hibernate.loader.criteria.CriteriaQueryTranslator;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.type.Type;

A criterion that involves a subquery
Author:Gavin King, Steve Ebersole
/** * A criterion that involves a subquery * * @author Gavin King * @author Steve Ebersole */
public abstract class SubqueryExpression implements Criterion { private CriteriaImpl criteriaImpl; private String quantifier; private String op; private QueryParameters params; private Type[] types; private CriteriaQueryTranslator innerQuery; protected SubqueryExpression(String op, String quantifier, DetachedCriteria dc) { this.criteriaImpl = dc.getCriteriaImpl(); this.quantifier = quantifier; this.op = op; } protected Type[] getTypes() { return types; } protected abstract String toLeftSqlString(Criteria criteria, CriteriaQuery outerQuery); @Override public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException { final StringBuilder buf = new StringBuilder( toLeftSqlString( criteria, criteriaQuery ) ); if ( op != null ) { buf.append( ' ' ).append( op ).append( ' ' ); } if ( quantifier != null ) { buf.append( quantifier ).append( ' ' ); } final SessionFactoryImplementor factory = criteriaQuery.getFactory(); final OuterJoinLoadable persister = (OuterJoinLoadable) factory.getMetamodel().entityPersister( criteriaImpl.getEntityOrClassName() ); createAndSetInnerQuery( criteriaQuery, factory ); criteriaImpl.setSession( deriveRootSession( criteria ) ); final CriteriaJoinWalker walker = new CriteriaJoinWalker( persister, innerQuery, factory, criteriaImpl, criteriaImpl.getEntityOrClassName(), criteriaImpl.getSession().getLoadQueryInfluencers(), innerQuery.getRootSQLALias() ); return buf.append( '(' ).append( walker.getSQLString() ).append( ')' ).toString(); } private SharedSessionContractImplementor deriveRootSession(Criteria criteria) { if ( criteria instanceof CriteriaImpl ) { return ( (CriteriaImpl) criteria ).getSession(); } else if ( criteria instanceof CriteriaImpl.Subcriteria ) { return deriveRootSession( ( (CriteriaImpl.Subcriteria) criteria ).getParent() ); } else { // could happen for custom Criteria impls. Not likely, but... // for long term solution, see HHH-3514 return null; } } @Override public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException { //the following two lines were added to ensure that this.params is not null, which //can happen with two-deep nested subqueries final SessionFactoryImplementor factory = criteriaQuery.getFactory(); createAndSetInnerQuery( criteriaQuery, factory ); final Type[] ppTypes = params.getPositionalParameterTypes(); final Object[] ppValues = params.getPositionalParameterValues(); final TypedValue[] tv = new TypedValue[ppTypes.length]; for ( int i=0; i<ppTypes.length; i++ ) { tv[i] = new TypedValue( ppTypes[i], ppValues[i] ); } return tv; }
Creates the inner query used to extract some useful information about types, since it is needed in both methods.
Params:
  • criteriaQuery – The criteria query
  • factory – The session factory.
/** * Creates the inner query used to extract some useful information about types, since it is needed in both methods. * * @param criteriaQuery The criteria query * @param factory The session factory. */
private void createAndSetInnerQuery(CriteriaQuery criteriaQuery, SessionFactoryImplementor factory) { if ( innerQuery == null ) { //with two-deep subqueries, the same alias would get generated for //both using the old method (criteriaQuery.generateSQLAlias()), so //that is now used as a fallback if the main criteria alias isn't set String alias; if ( this.criteriaImpl.getAlias() == null ) { alias = criteriaQuery.generateSQLAlias(); } else { alias = this.criteriaImpl.getAlias() + "_"; } innerQuery = new CriteriaQueryTranslator( factory, criteriaImpl, criteriaImpl.getEntityOrClassName(), alias, criteriaQuery ); params = innerQuery.getQueryParameters(); types = innerQuery.getProjectedTypes(); } } }