Java tutorial
/* * 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 */ 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 * {@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, * {@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 {@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 */ 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; } }