/*
 * 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.engine.spi;

import java.util.Map;
import java.util.Set;

import org.jboss.logging.Logger;

import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.PropertyMapping;

Author:Gavin King
/** * @author Gavin King */
public class SubselectFetch { private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, SubselectFetch.class.getName() ); private static final String FROM_STRING = " from "; private final Set resultingEntityKeys; private final String queryString; private final String alias; private final Loadable loadable; private final QueryParameters queryParameters; private final Map namedParameterLocMap;
Construct a SubselectFetch instance. The subselect fetch query fragment is generated by createSubselectFetchQueryFragment. If the same value for queryParameters is to be used when constructing multiple SubselectFetch objects, then it is preferable to generate the subselect fetch query fragment using createSubselectFetchQueryFragment, and pass the result as an argument to constructor SubselectFetch(String, String, Loadable, QueryParameters, Set, Map).
Params:
  • alias – - the table alias used in the subselect fetch query fragment (to be generated by createSubselectFetchQueryFragment(QueryParameters) that corresponds to loadable;
  • loadable – - the Loadable for the associated entities to be subselect fetched;
  • queryParameters – - the query parameters;
  • resultingEntityKeys – - the EntityKey objects for the entities to be subselect fetched;
  • namedParameterLocMap – - mapping from named parameter to the parameter index located in the subselect fetch query fragment.
See Also:
/** * Construct a SubselectFetch instance. The subselect fetch query fragment is generated by * {@link #createSubselectFetchQueryFragment}. * * If the same value for {@code queryParameters} is to be used when constructing multiple * SubselectFetch objects, then it is preferable to generate the subselect fetch query * fragment using {@link #createSubselectFetchQueryFragment}, and pass the result as an * argument to constructor {@link #SubselectFetch(String, String, Loadable, QueryParameters, Set, Map)}. * * @param alias - the table alias used in the subselect fetch query fragment * (to be generated by {@link #createSubselectFetchQueryFragment(QueryParameters)} that * corresponds to {@code loadable}; * @param loadable - the {@link Loadable} for the associated entities to be subselect fetched; * @param queryParameters - the query parameters; * @param resultingEntityKeys - the {@link EntityKey} objects for the entities to be subselect fetched; * @param namedParameterLocMap - mapping from named parameter to the parameter index located in the * subselect fetch query fragment. * * @see #SubselectFetch(String, String, Loadable, QueryParameters, Set, Map) */
public SubselectFetch( final String alias, final Loadable loadable, final QueryParameters queryParameters, final Set resultingEntityKeys, final Map namedParameterLocMap) { this( createSubselectFetchQueryFragment( queryParameters ), alias, loadable, queryParameters, resultingEntityKeys, namedParameterLocMap ); }
Construct a SubselectFetch instance using the provided subselect fetch query fragment, subselectFetchQueryFragment. It is assumed that subselectFetchQueryFragment is the result of calling createSubselectFetchQueryFragment with the same value provided for queryParameters.
Params:
  • subselectFetchQueryFragment – - the subselect fetch query fragment;
  • alias – - the table alias used in subselectFetchQueryFragment that corresponds to loadable;
  • loadable – - the Loadable for the associated entities to be subselect fetched;
  • queryParameters – - the query parameters;
  • resultingEntityKeys – - the EntityKey objects for the entities to be subselect fetched;
  • namedParameterLocMap – - mapping from named parameter to the parameter index located in the subselect fetch query fragment.
/** * Construct a SubselectFetch instance using the provided subselect fetch query fragment, * {@code subselectFetchQueryFragment}. It is assumed that {@code subselectFetchQueryFragment} * is the result of calling {@link #createSubselectFetchQueryFragment} with the same value * provided for {@code queryParameters}. * * @param subselectFetchQueryFragment - the subselect fetch query fragment; * @param alias - the table alias used in {@code subselectFetchQueryFragment} that * corresponds to {@code loadable}; * @param loadable - the {@link Loadable} for the associated entities to be subselect fetched; * @param queryParameters - the query parameters; * @param resultingEntityKeys - the {@link EntityKey} objects for the entities to be subselect fetched; * @param namedParameterLocMap - mapping from named parameter to the parameter index located in the * subselect fetch query fragment. */
public SubselectFetch( final String subselectFetchQueryFragment, final String alias, final Loadable loadable, final QueryParameters queryParameters, final Set resultingEntityKeys, final Map namedParameterLocMap) { this.resultingEntityKeys = resultingEntityKeys; this.queryParameters = queryParameters; this.namedParameterLocMap = namedParameterLocMap; this.loadable = loadable; this.alias = alias; this.queryString = subselectFetchQueryFragment; }
Create the subselect fetch query fragment for the provided QueryParameters with SELECT and ORDER BY clauses removed.
Params:
  • queryParameters – -the query parameters.
Returns:the subselect fetch query fragment.
/** * Create the subselect fetch query fragment for the provided {@link QueryParameters} * with SELECT and ORDER BY clauses removed. * * @param queryParameters -the query parameters. * @return the subselect fetch query fragment. */
public static String createSubselectFetchQueryFragment(QueryParameters queryParameters) { //TODO: ugly here: final String queryString = queryParameters.getFilteredSQL(); final int fromIndex = getFromIndex( queryString ); final int orderByIndex = queryString.lastIndexOf( "order by" ); final String subselectQueryFragment = orderByIndex > 0 ? queryString.substring( fromIndex, orderByIndex ) : queryString.substring( fromIndex ); if ( LOG.isTraceEnabled() ) { LOG.tracef( "SubselectFetch query fragment: %s", subselectQueryFragment ); } return subselectQueryFragment; } private static int getFromIndex(String queryString) { int index = queryString.indexOf( FROM_STRING ); if ( index < 0 ) { return index; } while ( !parenthesesMatch( queryString.substring( 0, index ) ) ) { String subString = queryString.substring( index + FROM_STRING.length() ); int subIndex = subString.indexOf( FROM_STRING ); if ( subIndex < 0 ) { return subIndex; } index += FROM_STRING.length() + subIndex; } return index; } private static boolean parenthesesMatch(String string) { int parenCount = 0; for ( int i = 0; i < string.length(); i++ ) { char character = string.charAt( i ); if ( character == '(' ) { parenCount++; } else if ( character == ')' ) { parenCount--; } } return parenCount == 0; } public QueryParameters getQueryParameters() { return queryParameters; }
Get the Set of EntityKeys
/** * Get the Set of EntityKeys */
public Set getResult() { return resultingEntityKeys; } public String toSubselectString(String ukname) { String[] joinColumns = ukname == null ? StringHelper.qualify( alias, loadable.getIdentifierColumnNames() ) : ( (PropertyMapping) loadable ).toColumns( alias, ukname ); return "select " + String.join( ", ", joinColumns ) + queryString; } @Override public String toString() { return "SubselectFetch(" + queryString + ')'; } public Map getNamedParameterLocMap() { return namedParameterLocMap; } }