6 - SQM based on JPA type system

- work on `org.hibernate.query` (especially `NamedQueryRepository` and friends)
- work on `org.hibernate.sql.exec`
- work on `org.hibernate.sql.results`
- work on `org.hibernate.sql.exec`
- work on `org.hibernate.sql.results`
- work related to `org.hibernate.metamodel.model.mapping.spi.ValueMapping` - including "sketching in" the hooks with `org.hibernate.persister.walking`
This commit is contained in:
Steve Ebersole 2019-07-03 07:33:44 -05:00 committed by Andrea Boriero
parent f8a75994e1
commit d0116d7caa
125 changed files with 759 additions and 3505 deletions

View File

@ -13,6 +13,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.TypedValue;

View File

@ -400,8 +400,8 @@ public abstract class AbstractHANADialect extends Dialect {
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
@Override
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
Blob rsBlob = rs.getBlob( name );
protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
Blob rsBlob = rs.getBlob( paramIndex );
if ( rsBlob == null || rsBlob.length() < HANAStreamBlobTypeDescriptor.this.maxLobPrefetchSize ) {
return javaTypeDescriptor.wrap( rsBlob, options );
}
@ -490,13 +490,13 @@ public abstract class AbstractHANADialect extends Dialect {
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
@Override
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
Clob rsClob;
if ( HANAClobTypeDescriptor.this.useUnicodeStringTypes ) {
rsClob = rs.getNClob( name );
rsClob = rs.getNClob( paramIndex );
}
else {
rsClob = rs.getClob( name );
rsClob = rs.getClob( paramIndex );
}
if ( rsClob == null || rsClob.length() < HANAClobTypeDescriptor.this.maxLobPrefetchSize ) {
@ -584,8 +584,8 @@ public abstract class AbstractHANADialect extends Dialect {
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
@Override
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
NClob rsNClob = rs.getNClob( name );
protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
NClob rsNClob = rs.getNClob( paramIndex );
if ( rsNClob == null || rsNClob.length() < HANANClobTypeDescriptor.this.maxLobPrefetchSize ) {
return javaTypeDescriptor.wrap( rsNClob, options );
}
@ -638,8 +638,8 @@ public abstract class AbstractHANADialect extends Dialect {
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
@Override
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
Blob rsBlob = rs.getBlob( name );
protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
Blob rsBlob = rs.getBlob( paramIndex );
if ( rsBlob == null || rsBlob.length() < HANABlobTypeDescriptor.this.maxLobPrefetchSize ) {
return javaTypeDescriptor.wrap( rsBlob, options );
}

View File

@ -71,6 +71,7 @@ import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport;
import org.hibernate.engine.jdbc.env.spi.SchemaNameResolver;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.exception.spi.ConversionContext;
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;

View File

@ -1,8 +1,8 @@
/*
* 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>.
* 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;
@ -19,12 +19,11 @@ import org.hibernate.LockOptions;
import org.hibernate.QueryException;
import org.hibernate.ScrollMode;
import org.hibernate.engine.query.spi.HQLQueryPlan;
import org.hibernate.hql.internal.classic.ParserHelper;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.FilterImpl;
import org.hibernate.internal.util.EntityPrinter;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.query.internal.QueryParameterBindingsImpl;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.ComponentType;
@ -38,11 +37,6 @@ import org.jboss.logging.Logger;
public final class QueryParameters {
private static final Logger LOG = CoreLogging.logger( QueryParameters.class );
/**
* Symbols used to split SQL string into tokens in {@link #processFilters(String, Map, SessionFactoryImplementor)}.
*/
private static final String SYMBOLS = ParserHelper.HQL_SEPARATORS.replace( "'", "" );
private Type[] positionalParameterTypes;
private Object[] positionalParameterValues;
private Map<String, TypedValue> namedParameters;
@ -245,9 +239,9 @@ public final class QueryParameters {
final Serializable optionalId,
ResultTransformer resultTransformer) {
this(
queryParameterBindings.collectPositionalBindTypes(),
queryParameterBindings.collectPositionalBindValues(),
queryParameterBindings.collectNamedParameterBindings(),
null,
null,
null,
lockOptions,
selection,
isReadOnlyInitialized,
@ -526,71 +520,71 @@ public final class QueryParameters {
@SuppressWarnings( {"unchecked"})
public void processFilters(String sql, Map filters, SessionFactoryImplementor factory) {
if ( filters.size() == 0 || !sql.contains( ParserHelper.HQL_VARIABLE_PREFIX ) ) {
// HELLA IMPORTANT OPTIMIZATION!!!
processedPositionalParameterValues = getPositionalParameterValues();
processedPositionalParameterTypes = getPositionalParameterTypes();
processedSQL = sql;
}
else {
final StringTokenizer tokens = new StringTokenizer( sql, SYMBOLS, true );
StringBuilder result = new StringBuilder();
List parameters = new ArrayList();
List parameterTypes = new ArrayList();
int positionalIndex = 0;
while ( tokens.hasMoreTokens() ) {
final String token = tokens.nextToken();
if ( token.startsWith( ParserHelper.HQL_VARIABLE_PREFIX ) ) {
final String filterParameterName = token.substring( 1 );
final String[] parts = LoadQueryInfluencers.parseFilterParameterName( filterParameterName );
final FilterImpl filter = (FilterImpl) filters.get( parts[0] );
final Object value = filter.getParameter( parts[1] );
final Type type = filter.getFilterDefinition().getParameterType( parts[1] );
if ( value != null && Collection.class.isAssignableFrom( value.getClass() ) ) {
Iterator itr = ( (Collection) value ).iterator();
while ( itr.hasNext() ) {
final Object elementValue = itr.next();
result.append( '?' );
parameters.add( elementValue );
parameterTypes.add( type );
if ( itr.hasNext() ) {
result.append( ", " );
}
}
}
else {
result.append( '?' );
parameters.add( value );
parameterTypes.add( type );
}
}
else {
result.append( token );
if ( "?".equals( token ) && positionalIndex < getPositionalParameterValues().length ) {
final Type type = getPositionalParameterTypes()[positionalIndex];
if ( type.isComponentType() ) {
// should process tokens till reaching the number of "?" corresponding to the
// numberOfParametersCoveredBy of the compositeType
int paramIndex = 1;
final int numberOfParametersCoveredBy = getNumberOfParametersCoveredBy( ((ComponentType) type).getSubtypes() );
while ( paramIndex < numberOfParametersCoveredBy ) {
final String nextToken = tokens.nextToken();
if ( "?".equals( nextToken ) ) {
paramIndex++;
}
result.append( nextToken );
}
}
parameters.add( getPositionalParameterValues()[positionalIndex] );
parameterTypes.add( type );
positionalIndex++;
}
}
}
processedPositionalParameterValues = parameters.toArray();
processedPositionalParameterTypes = ( Type[] ) parameterTypes.toArray( new Type[parameterTypes.size()] );
processedSQL = result.toString();
}
// if ( filters.size() == 0 || !sql.contains( ParserHelper.HQL_VARIABLE_PREFIX ) ) {
// // HELLA IMPORTANT OPTIMIZATION!!!
// processedPositionalParameterValues = getPositionalParameterValues();
// processedPositionalParameterTypes = getPositionalParameterTypes();
// processedSQL = sql;
// }
// else {
// final StringTokenizer tokens = new StringTokenizer( sql, SYMBOLS, true );
// StringBuilder result = new StringBuilder();
// List parameters = new ArrayList();
// List parameterTypes = new ArrayList();
// int positionalIndex = 0;
// while ( tokens.hasMoreTokens() ) {
// final String token = tokens.nextToken();
// if ( token.startsWith( ParserHelper.HQL_VARIABLE_PREFIX ) ) {
// final String filterParameterName = token.substring( 1 );
// final String[] parts = LoadQueryInfluencers.parseFilterParameterName( filterParameterName );
// final FilterImpl filter = (FilterImpl) filters.get( parts[0] );
// final Object value = filter.getParameter( parts[1] );
// final Type type = filter.getFilterDefinition().getParameterType( parts[1] );
// if ( value != null && Collection.class.isAssignableFrom( value.getClass() ) ) {
// Iterator itr = ( (Collection) value ).iterator();
// while ( itr.hasNext() ) {
// final Object elementValue = itr.next();
// result.append( '?' );
// parameters.add( elementValue );
// parameterTypes.add( type );
// if ( itr.hasNext() ) {
// result.append( ", " );
// }
// }
// }
// else {
// result.append( '?' );
// parameters.add( value );
// parameterTypes.add( type );
// }
// }
// else {
// result.append( token );
// if ( "?".equals( token ) && positionalIndex < getPositionalParameterValues().length ) {
// final Type type = getPositionalParameterTypes()[positionalIndex];
// if ( type.isComponentType() ) {
// // should process tokens till reaching the number of "?" corresponding to the
// // numberOfParametersCoveredBy of the compositeType
// int paramIndex = 1;
// final int numberOfParametersCoveredBy = getNumberOfParametersCoveredBy( ((ComponentType) type).getSubtypes() );
// while ( paramIndex < numberOfParametersCoveredBy ) {
// final String nextToken = tokens.nextToken();
// if ( "?".equals( nextToken ) ) {
// paramIndex++;
// }
// result.append( nextToken );
// }
// }
// parameters.add( getPositionalParameterValues()[positionalIndex] );
// parameterTypes.add( type );
// positionalIndex++;
// }
// }
// }
// processedPositionalParameterValues = parameters.toArray();
// processedPositionalParameterTypes = ( Type[] ) parameterTypes.toArray( new Type[parameterTypes.size()] );
// processedSQL = result.toString();
// }
}
private int getNumberOfParametersCoveredBy(Type[] subtypes) {

View File

@ -11,6 +11,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.hql.internal.HolderInstantiator;
import org.hibernate.loader.Loader;

View File

@ -14,6 +14,7 @@ import org.hibernate.HibernateException;
import org.hibernate.JDBCException;
import org.hibernate.ScrollableResults;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.Loader;
import org.hibernate.type.Type;
@ -43,7 +44,8 @@ public class ScrollableResultsImpl extends AbstractScrollableResults implements
SharedSessionContractImplementor sess,
Loader loader,
QueryParameters queryParameters,
Type[] types, HolderInstantiator holderInstantiator) {
Type[] types,
HolderInstantiator holderInstantiator) {
super( rs, ps, sess, loader, queryParameters, types, holderInstantiator );
}

View File

@ -54,6 +54,7 @@ import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.EntityUniqueKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
import org.hibernate.engine.spi.RowSelection;

View File

@ -18,6 +18,7 @@ import org.hibernate.HibernateException;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;

View File

@ -13,6 +13,7 @@ import java.sql.SQLException;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.LockOptions;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;

View File

@ -1,69 +0,0 @@
/*
* 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.loader.criteria;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.PropertyMapping;
import org.hibernate.type.CompositeType;
import org.hibernate.type.Type;
/**
* @author David Mansfield
*/
class ComponentCollectionCriteriaInfoProvider implements CriteriaInfoProvider {
private final QueryableCollection persister;
private final Map<String, Type> subTypes = new HashMap<String, Type>();
ComponentCollectionCriteriaInfoProvider(QueryableCollection persister) {
this.persister = persister;
if ( !persister.getElementType().isComponentType() ) {
throw new IllegalArgumentException( "persister for role " + persister.getRole() + " is not a collection-of-component" );
}
CompositeType componentType = (CompositeType) persister.getElementType();
String[] names = componentType.getPropertyNames();
Type[] types = componentType.getSubtypes();
for ( int i = 0; i < names.length; i++ ) {
subTypes.put( names[i], types[i] );
}
}
@Override
public String getName() {
return persister.getRole();
}
@Override
public Serializable[] getSpaces() {
return persister.getCollectionSpaces();
}
@Override
public PropertyMapping getPropertyMapping() {
return persister;
}
@Override
public Type getType(String relativePath) {
// TODO: can a component have a nested component? then we may need to do something more here...
if ( relativePath.indexOf( '.' ) >= 0 ) {
throw new IllegalArgumentException( "dotted paths not handled (yet?!) for collection-of-component" );
}
Type type = subTypes.get( relativePath );
if ( type == null ) {
throw new IllegalArgumentException( "property " + relativePath + " not found in component of collection " + getName() );
}
return type;
}
}

View File

@ -1,26 +0,0 @@
/*
* 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.loader.criteria;
import java.io.Serializable;
import org.hibernate.persister.entity.PropertyMapping;
import org.hibernate.type.Type;
/**
* @author David Mansfield
*/
interface CriteriaInfoProvider {
String getName();
Serializable[] getSpaces();
PropertyMapping getPropertyMapping();
Type getType(String relativePath);
}

View File

@ -1,316 +0,0 @@
/*
* 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.loader.criteria;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CriteriaImpl;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.AbstractEntityJoinWalker;
import org.hibernate.loader.PropertyPath;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.sql.JoinType;
import org.hibernate.type.AssociationType;
import org.hibernate.type.Type;
/**
* A <tt>JoinWalker</tt> for <tt>Criteria</tt> queries.
*
* @author Gavin King
* @see CriteriaLoader
*/
public class CriteriaJoinWalker extends AbstractEntityJoinWalker {
//TODO: add a CriteriaImplementor interface
// this class depends directly upon CriteriaImpl in the impl package...
private final CriteriaQueryTranslator translator;
private final Set querySpaces;
private final Type[] resultTypes;
private final boolean[] includeInResultRow;
//the user visible aliases, which are unknown to the superclass,
//these are not the actual "physical" SQL aliases
private final String[] userAliases;
private final List<String> userAliasList = new ArrayList<String>();
private final List<Type> resultTypeList = new ArrayList<Type>();
private final List<Boolean> includeInResultRowList = new ArrayList<Boolean>();
public Type[] getResultTypes() {
return resultTypes;
}
public String[] getUserAliases() {
return userAliases;
}
public boolean[] includeInResultRow() {
return includeInResultRow;
}
public CriteriaJoinWalker(
final OuterJoinLoadable persister,
final CriteriaQueryTranslator translator,
final SessionFactoryImplementor factory,
final CriteriaImpl criteria,
final String rootEntityName,
final LoadQueryInfluencers loadQueryInfluencers) {
this( persister, translator, factory, criteria, rootEntityName, loadQueryInfluencers, null );
}
public CriteriaJoinWalker(
final OuterJoinLoadable persister,
final CriteriaQueryTranslator translator,
final SessionFactoryImplementor factory,
final CriteriaImpl criteria,
final String rootEntityName,
final LoadQueryInfluencers loadQueryInfluencers,
final String alias) {
super( persister, factory, loadQueryInfluencers, alias );
this.translator = translator;
querySpaces = translator.getQuerySpaces();
if ( translator.hasProjection() ) {
initProjection(
translator.getSelect(),
translator.getWhereCondition(),
translator.getOrderBy(),
translator.getGroupBy(),
LockOptions.NONE
);
resultTypes = translator.getProjectedTypes();
userAliases = translator.getProjectedAliases();
includeInResultRow = new boolean[resultTypes.length];
Arrays.fill( includeInResultRow, true );
}
else {
initAll( translator.getWhereCondition(), translator.getOrderBy(), LockOptions.NONE );
// root entity comes last
userAliasList.add( criteria.getAlias() ); //root entity comes *last*
resultTypeList.add( translator.getResultType( criteria ) );
includeInResultRowList.add( true );
userAliases = ArrayHelper.toStringArray( userAliasList );
resultTypes = ArrayHelper.toTypeArray( resultTypeList );
includeInResultRow = ArrayHelper.toBooleanArray( includeInResultRowList );
}
}
@Override
protected JoinType getJoinType(
OuterJoinLoadable persister,
final PropertyPath path,
int propertyNumber,
AssociationType associationType,
FetchMode metadataFetchMode,
CascadeStyle metadataCascadeStyle,
String lhsTable,
String[] lhsColumns,
final boolean nullable,
final int currentDepth) throws MappingException {
final JoinType resolvedJoinType;
if ( translator.isJoin( path.getFullPath() ) ) {
resolvedJoinType = translator.getJoinType( path.getFullPath() );
}
else {
if ( translator.hasProjection() ) {
resolvedJoinType = JoinType.NONE;
}
else {
String fullPathWithAlias = path.getFullPath();
String rootAlias = translator.getRootCriteria().getAlias();
String rootAliasPathPrefix = rootAlias + ".";
if (rootAlias != null && !fullPathWithAlias.startsWith(rootAliasPathPrefix)) {
fullPathWithAlias = rootAliasPathPrefix + fullPathWithAlias;
}
FetchMode fetchMode = translator.getRootCriteria().getFetchMode( fullPathWithAlias );
if ( isDefaultFetchMode( fetchMode ) ) {
if ( persister != null ) {
if ( isJoinFetchEnabledByProfile( persister, path, propertyNumber ) ) {
if ( isDuplicateAssociation( lhsTable, lhsColumns, associationType ) ) {
resolvedJoinType = JoinType.NONE;
}
else if ( isTooDeep( currentDepth ) || ( associationType.isCollectionType() && isTooManyCollections() ) ) {
resolvedJoinType = JoinType.NONE;
}
else {
resolvedJoinType = getJoinType( nullable, currentDepth );
}
}
else {
resolvedJoinType = super.getJoinType(
persister,
path,
propertyNumber,
associationType,
metadataFetchMode,
metadataCascadeStyle,
lhsTable,
lhsColumns,
nullable,
currentDepth
);
}
}
else {
resolvedJoinType = super.getJoinType(
associationType,
metadataFetchMode,
path,
lhsTable,
lhsColumns,
nullable,
currentDepth,
metadataCascadeStyle
);
}
}
else {
if ( fetchMode == FetchMode.JOIN ) {
isDuplicateAssociation(
lhsTable,
lhsColumns,
associationType
); //deliberately ignore return value!
resolvedJoinType = getJoinType( nullable, currentDepth );
}
else {
resolvedJoinType = JoinType.NONE;
}
}
}
}
return resolvedJoinType;
}
@Override
protected JoinType getJoinType(
AssociationType associationType,
FetchMode config,
PropertyPath path,
String lhsTable,
String[] lhsColumns,
boolean nullable,
int currentDepth,
CascadeStyle cascadeStyle) throws MappingException {
return getJoinType(
null,
path,
-1,
associationType,
config,
cascadeStyle,
lhsTable,
lhsColumns,
nullable,
currentDepth
);
}
private static boolean isDefaultFetchMode(FetchMode fetchMode) {
return fetchMode == null || fetchMode == FetchMode.DEFAULT;
}
/**
* Use the discriminator, to narrow the select to instances
* of the queried subclass, also applying any filters.
*/
@Override
protected String getWhereFragment() throws MappingException {
return super.getWhereFragment() +
( (Queryable) getPersister() ).filterFragment(
getAlias(),
getLoadQueryInfluencers().getEnabledFilters()
);
}
@Override
protected String generateTableAlias(int n, PropertyPath path, Joinable joinable) {
// TODO: deal with side-effects (changes to includeInResultRowList, userAliasList, resultTypeList)!!!
// for collection-of-entity, we are called twice for given "path"
// once for the collection Joinable, once for the entity Joinable.
// the second call will/must "consume" the alias + perform side effects according to consumesEntityAlias()
// for collection-of-other, however, there is only one call
// it must "consume" the alias + perform side effects, despite what consumeEntityAlias() return says
//
// note: the logic for adding to the userAliasList is still strictly based on consumesEntityAlias return value
boolean checkForSqlAlias = joinable.consumesEntityAlias();
if ( !checkForSqlAlias && joinable.isCollection() ) {
// is it a collection-of-other (component or value) ?
CollectionPersister collectionPersister = (CollectionPersister) joinable;
Type elementType = collectionPersister.getElementType();
if ( elementType.isComponentType() || !elementType.isEntityType() ) {
checkForSqlAlias = true;
}
}
String sqlAlias = null;
if ( checkForSqlAlias ) {
final Criteria subcriteria = translator.getCriteria( path.getFullPath() );
sqlAlias = subcriteria == null ? null : translator.getSQLAlias( subcriteria );
if ( joinable.consumesEntityAlias() && !translator.hasProjection() ) {
includeInResultRowList.add( subcriteria != null && subcriteria.getAlias() != null );
if ( sqlAlias != null ) {
if ( subcriteria.getAlias() != null ) {
userAliasList.add( subcriteria.getAlias() );
resultTypeList.add( translator.getResultType( subcriteria ) );
}
}
}
}
if ( sqlAlias == null ) {
sqlAlias = super.generateTableAlias( n + translator.getSQLAliasCount(), path, joinable );
}
return sqlAlias;
}
@Override
protected String generateRootAlias(String tableName) {
return CriteriaQueryTranslator.ROOT_SQL_ALIAS;
}
public Set getQuerySpaces() {
return querySpaces;
}
@Override
public String getComment() {
return "criteria query";
}
@Override
protected String getWithClause(PropertyPath path) {
return translator.getWithClause( path.getFullPath() );
}
@Override
protected boolean hasRestriction(PropertyPath path) {
return translator.hasRestriction( path.getFullPath() );
}
}

View File

@ -1,294 +0,0 @@
/*
* 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.loader.criteria;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.QueryException;
import org.hibernate.ScrollMode;
import org.hibernate.Session;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.CriteriaImpl;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.OuterJoinLoader;
import org.hibernate.loader.spi.AfterLoadAction;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.Lockable;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.query.spi.ScrollableResultsImplementor;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.Type;
/**
* A <tt>Loader</tt> for <tt>Criteria</tt> queries. Note that criteria queries are
* more like multi-object <tt>load()</tt>s than like HQL queries.
*
* @author Gavin King
*/
public class CriteriaLoader extends OuterJoinLoader {
//TODO: this class depends directly upon CriteriaImpl,
// in the impl package ... add a CriteriaImplementor
// interface
//NOTE: unlike all other Loaders, this one is NOT
// multithreaded, or cacheable!!
private final CriteriaQueryTranslator translator;
private final Set<Serializable> querySpaces;
private final Type[] resultTypes;
//the user visible aliases, which are unknown to the superclass,
//these are not the actual "physical" SQL aliases
private final String[] userAliases;
private final boolean[] includeInResultRow;
private final int resultRowLength;
public CriteriaLoader(
final OuterJoinLoadable persister,
final SessionFactoryImplementor factory,
final CriteriaImpl criteria,
final String rootEntityName,
final LoadQueryInfluencers loadQueryInfluencers) throws HibernateException {
super( factory, loadQueryInfluencers );
translator = new CriteriaQueryTranslator(
factory,
criteria,
rootEntityName,
CriteriaQueryTranslator.ROOT_SQL_ALIAS
);
querySpaces = translator.getQuerySpaces();
CriteriaJoinWalker walker = new CriteriaJoinWalker(
persister,
translator,
factory,
criteria,
rootEntityName,
loadQueryInfluencers
);
initFromWalker(walker);
userAliases = walker.getUserAliases();
resultTypes = walker.getResultTypes();
includeInResultRow = walker.includeInResultRow();
resultRowLength = ArrayHelper.countTrue( includeInResultRow );
postInstantiate();
}
public ScrollableResultsImplementor scroll(SharedSessionContractImplementor session, ScrollMode scrollMode)
throws HibernateException {
QueryParameters qp = translator.getQueryParameters();
qp.setScrollMode(scrollMode);
return scroll(qp, resultTypes, null, session);
}
public List list(SharedSessionContractImplementor session)
throws HibernateException {
return list( session, translator.getQueryParameters(), querySpaces, resultTypes );
}
@Override
protected String[] getResultRowAliases() {
return userAliases;
}
@Override
protected ResultTransformer resolveResultTransformer(ResultTransformer resultTransformer) {
return translator.getRootCriteria().getResultTransformer();
}
@Override
protected boolean areResultSetRowsTransformedImmediately() {
return true;
}
@Override
protected boolean[] includeInResultRow() {
return includeInResultRow;
}
@Override
protected Object getResultColumnOrRow(
Object[] row,
ResultTransformer transformer,
ResultSet rs,
SharedSessionContractImplementor session)
throws SQLException, HibernateException {
return resolveResultTransformer( transformer ).transformTuple(
getResultRow( row, rs, session),
getResultRowAliases()
);
}
@Override
protected Object[] getResultRow(Object[] row, ResultSet rs, SharedSessionContractImplementor session)
throws SQLException, HibernateException {
final Object[] result;
if ( translator.hasProjection() ) {
Type[] types = translator.getProjectedTypes();
result = new Object[types.length];
String[] columnAliases = translator.getProjectedColumnAliases();
for ( int i=0, pos=0; i<result.length; i++ ) {
int numColumns = types[i].getColumnSpan( session.getFactory() );
if ( numColumns > 1 ) {
String[] typeColumnAliases = ArrayHelper.slice( columnAliases, pos, numColumns );
result[i] = types[i].nullSafeGet(rs, typeColumnAliases, session, null);
}
else {
result[i] = types[i].nullSafeGet(rs, columnAliases[pos], session, null);
}
pos += numColumns;
}
}
else {
result = toResultRow( row );
}
return result;
}
private Object[] toResultRow(Object[] row) {
if ( resultRowLength == row.length ) {
return row;
}
else {
Object[] result = new Object[ resultRowLength ];
int j = 0;
for ( int i = 0; i < row.length; i++ ) {
if ( includeInResultRow[i] ) {
result[j++] = row[i];
}
}
return result;
}
}
public Set getQuerySpaces() {
return querySpaces;
}
@Override
protected String applyLocks(
String sql,
QueryParameters parameters,
Dialect dialect,
List<AfterLoadAction> afterLoadActions) throws QueryException {
final LockOptions lockOptions = parameters.getLockOptions();
if ( lockOptions == null ||
( lockOptions.getLockMode() == LockMode.NONE && ( lockOptions.getAliasLockCount() == 0
|| ( lockOptions.getAliasLockCount() == 1 && lockOptions
.getAliasSpecificLockMode( "this_" ) == LockMode.NONE )
) ) ) {
return sql;
}
if ( ( parameters.getLockOptions().getFollowOnLocking() == null && dialect.useFollowOnLocking( parameters ) ) ||
( parameters.getLockOptions().getFollowOnLocking() != null && parameters.getLockOptions().getFollowOnLocking() ) ) {
final LockMode lockMode = determineFollowOnLockMode( lockOptions );
if ( lockMode != LockMode.UPGRADE_SKIPLOCKED ) {
// Dialect prefers to perform locking in a separate step
LOG.usingFollowOnLocking();
final LockOptions lockOptionsToUse = new LockOptions( lockMode );
lockOptionsToUse.setTimeOut( lockOptions.getTimeOut() );
lockOptionsToUse.setScope( lockOptions.getScope() );
afterLoadActions.add(
new AfterLoadAction() {
@Override
public void afterLoad(SharedSessionContractImplementor session, Object entity, Loadable persister) {
( (Session) session ).buildLockRequest( lockOptionsToUse )
.lock( persister.getEntityName(), entity );
}
}
);
parameters.setLockOptions( new LockOptions() );
return sql;
}
}
final LockOptions locks = new LockOptions(lockOptions.getLockMode());
locks.setScope( lockOptions.getScope());
locks.setTimeOut( lockOptions.getTimeOut());
final Map<String,String[]> keyColumnNames = dialect.forUpdateOfColumns() ? new HashMap() : null;
final String[] drivingSqlAliases = getAliases();
for ( int i = 0; i < drivingSqlAliases.length; i++ ) {
final LockMode lockMode = lockOptions.getAliasSpecificLockMode( drivingSqlAliases[i] );
if ( lockMode != null ) {
final Lockable drivingPersister = ( Lockable ) getEntityPersisters()[i];
final String rootSqlAlias = drivingPersister.getRootTableAlias( drivingSqlAliases[i] );
locks.setAliasSpecificLockMode( rootSqlAlias, lockMode );
if ( keyColumnNames != null ) {
keyColumnNames.put( rootSqlAlias, drivingPersister.getRootTableIdentifierColumnNames() );
}
}
}
return dialect.applyLocksToSql( sql, locks, keyColumnNames );
}
@Override
protected LockMode determineFollowOnLockMode(LockOptions lockOptions) {
final LockMode lockModeToUse = lockOptions.findGreatestLockMode();
if ( lockOptions.getAliasLockCount() > 1 ) {
// > 1 here because criteria always uses alias map for the root lock mode (under 'this_')
LOG.aliasSpecificLockingWithFollowOnLocking( lockModeToUse );
}
return lockModeToUse;
}
@Override
protected LockMode[] getLockModes(LockOptions lockOptions) {
final String[] entityAliases = getAliases();
if ( entityAliases == null ) {
return null;
}
final int size = entityAliases.length;
LockMode[] lockModesArray = new LockMode[size];
for ( int i=0; i<size; i++ ) {
LockMode lockMode = lockOptions.getAliasSpecificLockMode( entityAliases[i] );
lockModesArray[i] = lockMode==null ? lockOptions.getLockMode() : lockMode;
}
return lockModesArray;
}
@Override
protected boolean isSubselectLoadingEnabled() {
return hasSubselectLoadableCollections();
}
@Override
protected List getResultList(List results, ResultTransformer resultTransformer) {
return resolveResultTransformer( resultTransformer ).transformList( results );
}
@Override
protected String getQueryIdentifier() {
return "[CRITERIA] " + getSQLString();
}
}

View File

@ -1,692 +0,0 @@
/*
* 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.loader.criteria;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.QueryException;
import org.hibernate.criterion.CriteriaQuery;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.EnhancedProjection;
import org.hibernate.criterion.Projection;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.hql.internal.ast.util.SessionFactoryHelper;
import org.hibernate.internal.CriteriaImpl;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.PropertyMapping;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.sql.JoinType;
import org.hibernate.type.AssociationType;
import org.hibernate.type.CollectionType;
import org.hibernate.type.StringRepresentableType;
import org.hibernate.type.Type;
/**
* @author Gavin King
*/
public class CriteriaQueryTranslator implements CriteriaQuery {
public static final String ROOT_SQL_ALIAS = Criteria.ROOT_ALIAS + '_';
private CriteriaQuery outerQueryTranslator;
private final CriteriaImpl rootCriteria;
private final String rootEntityName;
private final String rootSQLAlias;
private final Map<Criteria, CriteriaInfoProvider> criteriaInfoMap = new LinkedHashMap<Criteria, CriteriaInfoProvider>();
private final Map<String, CriteriaInfoProvider> nameCriteriaInfoMap = new LinkedHashMap<String, CriteriaInfoProvider>();
private final Map<Criteria, String> criteriaSQLAliasMap = new HashMap<Criteria, String>();
private final Map<String, Criteria> aliasCriteriaMap = new HashMap<String, Criteria>();
private final Map<String, Criteria> associationPathCriteriaMap = new LinkedHashMap<String, Criteria>();
private final Map<String, JoinType> associationPathJoinTypesMap = new LinkedHashMap<String,JoinType>();
private final Map<String, Criterion> withClauseMap = new HashMap<String, Criterion>();
private Set<String> associations;
private final SessionFactoryImplementor sessionFactory;
private final SessionFactoryHelper helper;
public CriteriaQueryTranslator(
final SessionFactoryImplementor factory,
final CriteriaImpl criteria,
final String rootEntityName,
final String rootSQLAlias,
CriteriaQuery outerQuery) throws HibernateException {
this( factory, criteria, rootEntityName, rootSQLAlias );
outerQueryTranslator = outerQuery;
}
public CriteriaQueryTranslator(
final SessionFactoryImplementor factory,
final CriteriaImpl criteria,
final String rootEntityName,
final String rootSQLAlias) throws HibernateException {
this.rootCriteria = criteria;
this.rootEntityName = rootEntityName;
this.sessionFactory = factory;
this.rootSQLAlias = rootSQLAlias;
this.helper = new SessionFactoryHelper(factory);
createAliasCriteriaMap();
createAssociationPathCriteriaMap();
createCriteriaEntityNameMap();
createCriteriaSQLAliasMap();
}
public void setAssociations(Set<String> associations) {
this.associations = associations;
}
@Override
public String generateSQLAlias() {
int aliasCount = 0;
return StringHelper.generateAlias( Criteria.ROOT_ALIAS, aliasCount ) + '_';
}
public String getRootSQLALias() {
return rootSQLAlias;
}
private Criteria getAliasedCriteria(String alias) {
return aliasCriteriaMap.get( alias );
}
public boolean isJoin(String path) {
return associationPathCriteriaMap.containsKey( path );
}
public JoinType getJoinType(String path) {
JoinType result = associationPathJoinTypesMap.get( path );
return ( result == null ? JoinType.INNER_JOIN : result );
}
public Criteria getCriteria(String path) {
return associationPathCriteriaMap.get( path );
}
public Set<Serializable> getQuerySpaces() {
Set<Serializable> result = new HashSet<>();
for ( CriteriaInfoProvider info : criteriaInfoMap.values() ) {
result.addAll( Arrays.asList( info.getSpaces() ) );
}
for ( final Map.Entry<String, Criteria> entry : associationPathCriteriaMap.entrySet() ) {
String path = entry.getKey();
CriteriaImpl.Subcriteria crit = (CriteriaImpl.Subcriteria) entry.getValue();
int index = path.lastIndexOf( '.' );
if ( index > 0 ) {
path = path.substring( index + 1, path.length() );
}
CriteriaInfoProvider info = criteriaInfoMap.get( crit.getParent() );
CollectionPersister persister = getFactory().getMetamodel().collectionPersisters().get( info.getName() + "." + path );
if ( persister != null ) {
result.addAll( Arrays.asList( persister.getCollectionSpaces() ) );
}
}
return result;
}
private void createAliasCriteriaMap() {
aliasCriteriaMap.put( rootCriteria.getAlias(), rootCriteria );
Iterator<CriteriaImpl.Subcriteria> iter = rootCriteria.iterateSubcriteria();
while ( iter.hasNext() ) {
Criteria subcriteria = iter.next();
if ( subcriteria.getAlias() != null ) {
Object old = aliasCriteriaMap.put( subcriteria.getAlias(), subcriteria );
if ( old != null ) {
throw new QueryException( "duplicate alias: " + subcriteria.getAlias() );
}
}
}
}
private void createAssociationPathCriteriaMap() {
final Iterator<CriteriaImpl.Subcriteria> iter = rootCriteria.iterateSubcriteria();
while ( iter.hasNext() ) {
CriteriaImpl.Subcriteria crit = iter.next();
String wholeAssociationPath = getWholeAssociationPath( crit );
Object old = associationPathCriteriaMap.put( wholeAssociationPath, crit );
if ( old != null ) {
throw new QueryException( "duplicate association path: " + wholeAssociationPath );
}
JoinType joinType = crit.getJoinType();
old = associationPathJoinTypesMap.put( wholeAssociationPath, joinType );
if ( old != null ) {
// TODO : not so sure this is needed...
throw new QueryException( "duplicate association path: " + wholeAssociationPath );
}
if ( crit.getWithClause() != null ) {
this.withClauseMap.put( wholeAssociationPath, crit.getWithClause() );
}
}
}
private String getWholeAssociationPath(CriteriaImpl.Subcriteria subcriteria) {
String path = subcriteria.getPath();
// some messy, complex stuff here, since createCriteria() can take an
// aliased path, or a path rooted at the creating criteria instance
Criteria parent = null;
if ( path.indexOf( '.' ) > 0 ) {
// if it is a compound path
String testAlias = StringHelper.root( path );
if ( !testAlias.equals( subcriteria.getAlias() ) ) {
// and the qualifier is not the alias of this criteria
// -> check to see if we belong to some criteria other
// than the one that created us
parent = aliasCriteriaMap.get( testAlias );
}
}
if ( parent == null ) {
// otherwise assume the parent is the the criteria that created us
parent = subcriteria.getParent();
}
else {
path = StringHelper.unroot( path );
}
if ( parent.equals( rootCriteria ) ) {
// if its the root criteria, we are done
return path;
}
else {
// otherwise, recurse
return getWholeAssociationPath( ( CriteriaImpl.Subcriteria ) parent ) + '.' + path;
}
}
private void createCriteriaEntityNameMap() {
// initialize the rootProvider first
final CriteriaInfoProvider rootProvider = new EntityCriteriaInfoProvider(
(Queryable) sessionFactory.getEntityPersister( rootEntityName )
);
criteriaInfoMap.put( rootCriteria, rootProvider);
nameCriteriaInfoMap.put( rootProvider.getName(), rootProvider );
for ( Map.Entry<String, Criteria> entry : associationPathCriteriaMap.entrySet() ) {
final String key = entry.getKey();
final Criteria value = entry.getValue();
final CriteriaInfoProvider info = getPathInfo( key );
criteriaInfoMap.put( value, info );
nameCriteriaInfoMap.put( info.getName(), info );
}
}
private CriteriaInfoProvider getPathInfo(String path) {
StringTokenizer tokens = new StringTokenizer( path, "." );
String componentPath = "";
// start with the 'rootProvider'
CriteriaInfoProvider provider = nameCriteriaInfoMap.get( rootEntityName );
while ( tokens.hasMoreTokens() ) {
componentPath += tokens.nextToken();
final Type type = provider.getType( componentPath );
if ( type.isAssociationType() ) {
// CollectionTypes are always also AssociationTypes - but there's not always an associated entity...
final AssociationType atype = (AssociationType) type;
final CollectionType ctype = type.isCollectionType() ? (CollectionType)type : null;
final Type elementType = (ctype != null) ? ctype.getElementType( sessionFactory ) : null;
// is the association a collection of components or value-types? (i.e a colloction of valued types?)
if ( ctype != null && elementType.isComponentType() ) {
provider = new ComponentCollectionCriteriaInfoProvider( helper.getCollectionPersister(ctype.getRole()) );
}
else if ( ctype != null && !elementType.isEntityType() ) {
provider = new ScalarCollectionCriteriaInfoProvider( helper, ctype.getRole() );
}
else {
provider = new EntityCriteriaInfoProvider(
(Queryable) sessionFactory.getEntityPersister( atype.getAssociatedEntityName( sessionFactory ) )
);
}
componentPath = "";
}
else if ( type.isComponentType() ) {
if (!tokens.hasMoreTokens()) {
throw new QueryException(
"Criteria objects cannot be created directly on components. Create a criteria on " +
"owning entity and use a dotted property to access component property: " + path
);
}
else {
componentPath += '.';
}
}
else {
throw new QueryException( "not an association: " + componentPath );
}
}
return provider;
}
public int getSQLAliasCount() {
return criteriaSQLAliasMap.size();
}
private void createCriteriaSQLAliasMap() {
int i = 0;
for ( Map.Entry<Criteria, CriteriaInfoProvider> entry : criteriaInfoMap.entrySet() ) {
final Criteria crit = entry.getKey();
final CriteriaInfoProvider value = entry.getValue();
String alias = crit.getAlias();
if ( alias == null ) {
// the entity name
alias = value.getName();
}
criteriaSQLAliasMap.put( crit, StringHelper.generateAlias( alias, i++ ) );
}
criteriaSQLAliasMap.put( rootCriteria, rootSQLAlias );
}
public CriteriaImpl getRootCriteria() {
return rootCriteria;
}
public QueryParameters getQueryParameters() {
final RowSelection selection = new RowSelection();
selection.setFirstRow( rootCriteria.getFirstResult() );
selection.setMaxRows( rootCriteria.getMaxResults() );
selection.setTimeout( rootCriteria.getTimeout() );
selection.setFetchSize( rootCriteria.getFetchSize() );
final LockOptions lockOptions = new LockOptions();
final Map<String, LockMode> lockModeMap = rootCriteria.getLockModes();
for ( Map.Entry<String, LockMode> entry : lockModeMap.entrySet() ) {
final String key = entry.getKey();
final LockMode value = entry.getValue();
final Criteria subcriteria = getAliasedCriteria( key );
lockOptions.setAliasSpecificLockMode( getSQLAlias( subcriteria ), value );
}
final List<Object> values = new ArrayList<Object>();
final List<Type> types = new ArrayList<Type>();
final Iterator<CriteriaImpl.Subcriteria> subcriteriaIterator = rootCriteria.iterateSubcriteria();
while ( subcriteriaIterator.hasNext() ) {
final CriteriaImpl.Subcriteria subcriteria = subcriteriaIterator.next();
final LockMode lm = subcriteria.getLockMode();
if ( lm != null ) {
lockOptions.setAliasSpecificLockMode( getSQLAlias( subcriteria ), lm );
}
if ( subcriteria.getWithClause() != null ) {
final TypedValue[] tv = subcriteria.getWithClause().getTypedValues( subcriteria, this );
for ( TypedValue aTv : tv ) {
values.add( aTv.getValue() );
types.add( aTv.getType() );
}
}
}
// Type and value gathering for the WHERE clause needs to come AFTER lock mode gathering,
// because the lock mode gathering loop now contains join clauses which can contain
// parameter bindings (as in the HQL WITH clause).
final Iterator<CriteriaImpl.CriterionEntry> iter = rootCriteria.iterateExpressionEntries();
while ( iter.hasNext() ) {
final CriteriaImpl.CriterionEntry ce = iter.next();
final TypedValue[] tv = ce.getCriterion().getTypedValues( ce.getCriteria(), this );
for ( TypedValue aTv : tv ) {
values.add( aTv.getValue() );
types.add( aTv.getType() );
}
}
final Object[] valueArray = values.toArray();
final Type[] typeArray = ArrayHelper.toTypeArray( types );
return new QueryParameters(
typeArray,
valueArray,
lockOptions,
selection,
rootCriteria.isReadOnlyInitialized(),
( rootCriteria.isReadOnlyInitialized() && rootCriteria.isReadOnly() ),
rootCriteria.getCacheable(),
rootCriteria.getCacheRegion(),
rootCriteria.getComment(),
rootCriteria.getQueryHints(),
rootCriteria.isLookupByNaturalKey(),
rootCriteria.getResultTransformer()
);
}
public boolean hasProjection() {
return rootCriteria.getProjection() != null;
}
public String getGroupBy() {
if ( rootCriteria.getProjection().isGrouped() ) {
return rootCriteria.getProjection()
.toGroupSqlString( rootCriteria.getProjectionCriteria(), this );
}
else {
return "";
}
}
public String getSelect() {
return rootCriteria.getProjection().toSqlString(
rootCriteria.getProjectionCriteria(),
0,
this
);
}
/* package-protected */
Type getResultType(Criteria criteria) {
return getFactory().getTypeResolver().getTypeFactory().manyToOne( getEntityName( criteria ) );
}
public Type[] getProjectedTypes() {
return rootCriteria.getProjection().getTypes( rootCriteria, this );
}
public String[] getProjectedColumnAliases() {
return rootCriteria.getProjection() instanceof EnhancedProjection ?
( ( EnhancedProjection ) rootCriteria.getProjection() ).getColumnAliases( 0, rootCriteria, this ) :
rootCriteria.getProjection().getColumnAliases( 0 );
}
public String[] getProjectedAliases() {
return rootCriteria.getProjection().getAliases();
}
public String getWhereCondition() {
StringBuilder condition = new StringBuilder( 30 );
Iterator<CriteriaImpl.CriterionEntry> criterionIterator = rootCriteria.iterateExpressionEntries();
while ( criterionIterator.hasNext() ) {
CriteriaImpl.CriterionEntry entry = criterionIterator.next();
String sqlString = entry.getCriterion().toSqlString( entry.getCriteria(), this );
condition.append( sqlString );
if ( criterionIterator.hasNext() ) {
condition.append( " and " );
}
}
return condition.toString();
}
public String getOrderBy() {
StringBuilder orderBy = new StringBuilder( 30 );
Iterator<CriteriaImpl.OrderEntry> criterionIterator = rootCriteria.iterateOrderings();
while ( criterionIterator.hasNext() ) {
CriteriaImpl.OrderEntry oe = criterionIterator.next();
orderBy.append( oe.getOrder().toSqlString( oe.getCriteria(), this ) );
if ( criterionIterator.hasNext() ) {
orderBy.append( ", " );
}
}
return orderBy.toString();
}
@Override
public SessionFactoryImplementor getFactory() {
return sessionFactory;
}
@Override
public String getSQLAlias(Criteria criteria) {
return criteriaSQLAliasMap.get( criteria );
}
@Override
public String getEntityName(Criteria criteria) {
final CriteriaInfoProvider infoProvider = criteriaInfoMap.get( criteria );
return infoProvider != null ? infoProvider.getName() : null;
}
@Override
public String getColumn(Criteria criteria, String propertyName) {
String[] cols = getColumns( propertyName, criteria );
if ( cols.length != 1 ) {
throw new QueryException( "property does not map to a single column: " + propertyName );
}
return cols[0];
}
/**
* Get the names of the columns constrained
* by this criterion.
*/
@Override
public String[] getColumnsUsingProjection(
Criteria subcriteria,
String propertyName) throws HibernateException {
//first look for a reference to a projection alias
final Projection projection = rootCriteria.getProjection();
String[] projectionColumns = null;
if ( projection != null ) {
projectionColumns = ( projection instanceof EnhancedProjection ?
( ( EnhancedProjection ) projection ).getColumnAliases( propertyName, 0, rootCriteria, this ) :
projection.getColumnAliases( propertyName, 0 )
);
}
if ( projectionColumns == null ) {
//it does not refer to an alias of a projection,
//look for a property
try {
return getColumns( propertyName, subcriteria );
}
catch ( HibernateException he ) {
//not found in inner query , try the outer query
if ( outerQueryTranslator != null ) {
return outerQueryTranslator.getColumnsUsingProjection( subcriteria, propertyName );
}
else {
throw he;
}
}
}
else {
//it refers to an alias of a projection
return projectionColumns;
}
}
@Override
public String[] getIdentifierColumns(Criteria criteria) {
String[] idcols =
( ( Loadable ) getPropertyMapping( getEntityName( criteria ) ) ).getIdentifierColumnNames();
return StringHelper.qualify( getSQLAlias( criteria ), idcols );
}
@Override
public Type getIdentifierType(Criteria criteria) {
return ( ( Loadable ) getPropertyMapping( getEntityName( criteria ) ) ).getIdentifierType();
}
@Override
public TypedValue getTypedIdentifierValue(Criteria criteria, Object value) {
final Loadable loadable = ( Loadable ) getPropertyMapping( getEntityName( criteria ) );
return new TypedValue( loadable.getIdentifierType(), value );
}
@Override
public String[] getColumns(
String propertyName,
Criteria subcriteria) throws HibernateException {
return getPropertyMapping( getEntityName( subcriteria, propertyName ) )
.toColumns(
getSQLAlias( subcriteria, propertyName ),
getPropertyName( propertyName )
);
}
/**
* Get the names of the columns mapped by a property path; if the
* property path is not found in subcriteria, try the "outer" query.
* Projection aliases are ignored.
*/
@Override
public String[] findColumns(String propertyName, Criteria subcriteria )
throws HibernateException {
try {
return getColumns( propertyName, subcriteria );
}
catch ( HibernateException he ) {
//not found in inner query, try the outer query
if ( outerQueryTranslator != null ) {
return outerQueryTranslator.findColumns( propertyName, subcriteria );
}
else {
throw he;
}
}
}
@Override
public Type getTypeUsingProjection(Criteria subcriteria, String propertyName)
throws HibernateException {
//first look for a reference to a projection alias
final Projection projection = rootCriteria.getProjection();
Type[] projectionTypes = projection == null ?
null :
projection.getTypes( propertyName, subcriteria, this );
if ( projectionTypes == null ) {
try {
//it does not refer to an alias of a projection,
//look for a property
return getType( subcriteria, propertyName );
}
catch ( HibernateException he ) {
//not found in inner query , try the outer query
if ( outerQueryTranslator != null ) {
return outerQueryTranslator.getType( subcriteria, propertyName );
}
else {
throw he;
}
}
}
else {
if ( projectionTypes.length != 1 ) {
//should never happen, i think
throw new QueryException( "not a single-length projection: " + propertyName );
}
return projectionTypes[0];
}
}
@Override
public Type getType(Criteria subcriteria, String propertyName)
throws HibernateException {
return getPropertyMapping( getEntityName( subcriteria, propertyName ) )
.toType( getPropertyName( propertyName ) );
}
/**
* Get the a typed value for the given property value.
*/
@Override
public TypedValue getTypedValue(Criteria subcriteria, String propertyName, Object value) throws HibernateException {
// Detect discriminator values...
if ( value instanceof Class ) {
final Class entityClass = (Class) value;
final Queryable q = SessionFactoryHelper.findQueryableUsingImports( sessionFactory, entityClass.getName() );
if ( q != null ) {
final Type type = q.getDiscriminatorType();
String stringValue = q.getDiscriminatorSQLValue();
if ( stringValue != null
&& stringValue.length() > 2
&& stringValue.startsWith( "'" )
&& stringValue.endsWith( "'" ) ) {
// remove the single quotes
stringValue = stringValue.substring( 1, stringValue.length() - 1 );
}
// Convert the string value into the proper type.
if ( type instanceof StringRepresentableType ) {
final StringRepresentableType nullableType = (StringRepresentableType) type;
value = nullableType.fromStringValue( stringValue );
}
else {
throw new QueryException( "Unsupported discriminator type " + type );
}
return new TypedValue( type, value );
}
}
// Otherwise, this is an ordinary value.
return new TypedValue( getTypeUsingProjection( subcriteria, propertyName ), value );
}
private PropertyMapping getPropertyMapping(String entityName) throws MappingException {
final CriteriaInfoProvider info = nameCriteriaInfoMap.get( entityName );
if ( info == null ) {
throw new HibernateException( "Unknown entity: " + entityName );
}
return info.getPropertyMapping();
}
//TODO: use these in methods above
@Override
public String getEntityName(Criteria subcriteria, String propertyName) {
if ( propertyName.indexOf( '.' ) > 0 ) {
final String root = StringHelper.root( propertyName );
final Criteria crit = getAliasedCriteria( root );
if ( crit != null ) {
return getEntityName( crit );
}
}
return getEntityName( subcriteria );
}
@Override
public String getSQLAlias(Criteria criteria, String propertyName) {
if ( propertyName.indexOf( '.' ) > 0 ) {
final String root = StringHelper.root( propertyName );
final Criteria subcriteria = getAliasedCriteria( root );
if ( subcriteria != null ) {
return getSQLAlias( subcriteria );
}
}
return getSQLAlias( criteria );
}
@Override
public String getPropertyName(String propertyName) {
if ( propertyName.indexOf( '.' ) > 0 ) {
final String root = StringHelper.root( propertyName );
final Criteria criteria = getAliasedCriteria( root );
if ( criteria != null ) {
return propertyName.substring( root.length() + 1 );
}
}
return propertyName;
}
public String getWithClause(String path) {
final Criterion criterion = withClauseMap.get( path );
return criterion == null ? null : criterion.toSqlString( getCriteria( path ), this );
}
public boolean hasRestriction(String path) {
final CriteriaImpl.Subcriteria subcriteria = (CriteriaImpl.Subcriteria) getCriteria( path );
return subcriteria != null && subcriteria.hasRestriction();
}
}

View File

@ -1,41 +0,0 @@
/*
* 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.loader.criteria;
import java.io.Serializable;
import org.hibernate.persister.entity.PropertyMapping;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.type.Type;
/**
* @author David Mansfield
*/
class EntityCriteriaInfoProvider implements CriteriaInfoProvider {
private final Queryable persister;
EntityCriteriaInfoProvider(Queryable persister) {
this.persister = persister;
}
@Override
public String getName() {
return persister.getEntityName();
}
@Override
public Serializable[] getSpaces() {
return persister.getQuerySpaces();
}
@Override
public PropertyMapping getPropertyMapping() {
return persister;
}
@Override
public Type getType(String relativePath) {
return persister.toType( relativePath );
}
}

View File

@ -1,53 +0,0 @@
/*
* 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.loader.criteria;
import java.io.Serializable;
import org.hibernate.hql.internal.ast.util.SessionFactoryHelper;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.PropertyMapping;
import org.hibernate.type.Type;
/**
* @author David Mansfield
*/
class ScalarCollectionCriteriaInfoProvider implements CriteriaInfoProvider {
private final String role;
private final QueryableCollection persister;
private final SessionFactoryHelper helper;
ScalarCollectionCriteriaInfoProvider(SessionFactoryHelper helper, String role) {
this.role = role;
this.helper = helper;
this.persister = helper.requireQueryableCollection( role );
}
@Override
public String getName() {
return role;
}
@Override
public Serializable[] getSpaces() {
return persister.getCollectionSpaces();
}
@Override
public PropertyMapping getPropertyMapping() {
return helper.getCollectionPropertyMapping( role );
}
@Override
public Type getType(String relativePath) {
//not sure what things are going to be passed here, how about 'id', maybe 'index' or 'key' or 'elements' ???
// todo: wtf!
return getPropertyMapping().toType( relativePath );
}
}

View File

@ -1,15 +0,0 @@
<!--
~ 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>.
-->
<html>
<head></head>
<body>
<p>
This package defines the criteria query compiler and loader
</p>
</body>
</html>

View File

@ -13,6 +13,7 @@ import java.util.List;
import org.hibernate.LockOptions;
import org.hibernate.engine.internal.BatchFetchQueueHelper;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.Loader;
import org.hibernate.persister.entity.EntityPersister;

View File

@ -25,6 +25,7 @@ import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;

View File

@ -16,6 +16,7 @@ import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.LockOptions;
import org.hibernate.engine.spi.EffectiveEntityGraph;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.graph.GraphSemantic;

View File

@ -12,6 +12,7 @@ import java.util.Arrays;
import java.util.List;
import org.hibernate.LockOptions;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.Loader;
import org.hibernate.loader.entity.UniqueEntityLoader;

View File

@ -1,651 +0,0 @@
/*
* 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.loader.hql;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.QueryException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.spi.EventSource;
import org.hibernate.hql.internal.HolderInstantiator;
import org.hibernate.hql.internal.ast.QueryTranslatorImpl;
import org.hibernate.hql.internal.ast.tree.AggregatedSelectExpression;
import org.hibernate.hql.internal.ast.tree.FromElement;
import org.hibernate.hql.internal.ast.tree.QueryNode;
import org.hibernate.hql.internal.ast.tree.SelectClause;
import org.hibernate.hql.spi.NamedParameterInformation;
import org.hibernate.hql.spi.ParameterInformation;
import org.hibernate.internal.IteratorImpl;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.BasicLoader;
import org.hibernate.loader.internal.AliasConstantsHelper;
import org.hibernate.loader.spi.AfterLoadAction;
import org.hibernate.param.ParameterSpecification;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.Lockable;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.query.spi.ScrollableResultsImplementor;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
/**
* A delegate that implements the Loader part of QueryTranslator.
*
* @author josh
*/
public class QueryLoader extends BasicLoader {
/**
* The query translator that is delegating to this object.
*/
private QueryTranslatorImpl queryTranslator;
private Queryable[] entityPersisters;
private String[] entityAliases;
private String[] sqlAliases;
private String[] sqlAliasSuffixes;
private boolean[] includeInSelect;
private String[] collectionSuffixes;
private boolean hasScalars;
private String[][] scalarColumnNames;
//private Type[] sqlResultTypes;
private Type[] queryReturnTypes;
private final Map<String, String> sqlAliasByEntityAlias = new HashMap<>( 8 );
private EntityType[] ownerAssociationTypes;
private int[] owners;
private boolean[] entityEagerPropertyFetches;
private int[] collectionOwners;
private QueryableCollection[] collectionPersisters;
private int selectLength;
private AggregatedSelectExpression aggregatedSelectExpression;
private String[] queryReturnAliases;
private LockMode[] defaultLockModes;
/**
* Creates a new Loader implementation.
*
* @param queryTranslator The query translator that is the delegator.
* @param factory The factory from which this loader is being created.
* @param selectClause The AST representing the select clause for loading.
*/
public QueryLoader(
final QueryTranslatorImpl queryTranslator,
final SessionFactoryImplementor factory,
final SelectClause selectClause) {
super( factory );
this.queryTranslator = queryTranslator;
initialize( selectClause );
postInstantiate();
}
private void initialize(SelectClause selectClause) {
List fromElementList = selectClause.getFromElementsForLoad();
hasScalars = selectClause.isScalarSelect();
scalarColumnNames = selectClause.getColumnNames();
//sqlResultTypes = selectClause.getSqlResultTypes();
queryReturnTypes = selectClause.getQueryReturnTypes();
aggregatedSelectExpression = selectClause.getAggregatedSelectExpression();
queryReturnAliases = selectClause.getQueryReturnAliases();
List collectionFromElements = selectClause.getCollectionFromElements();
if ( collectionFromElements != null && collectionFromElements.size() != 0 ) {
int length = collectionFromElements.size();
collectionPersisters = new QueryableCollection[length];
collectionOwners = new int[length];
collectionSuffixes = new String[length];
for ( int i = 0; i < length; i++ ) {
FromElement collectionFromElement = (FromElement) collectionFromElements.get( i );
collectionPersisters[i] = collectionFromElement.getQueryableCollection();
collectionOwners[i] = fromElementList.indexOf( collectionFromElement.getOrigin() );
// collectionSuffixes[i] = collectionFromElement.getColumnAliasSuffix();
// collectionSuffixes[i] = Integer.toString( i ) + "_";
collectionSuffixes[i] = collectionFromElement.getCollectionSuffix();
}
}
int size = fromElementList.size();
entityPersisters = new Queryable[size];
entityEagerPropertyFetches = new boolean[size];
entityAliases = new String[size];
sqlAliases = new String[size];
sqlAliasSuffixes = new String[size];
includeInSelect = new boolean[size];
owners = new int[size];
ownerAssociationTypes = new EntityType[size];
for ( int i = 0; i < size; i++ ) {
final FromElement element = (FromElement) fromElementList.get( i );
entityPersisters[i] = (Queryable) element.getEntityPersister();
if ( entityPersisters[i] == null ) {
throw new IllegalStateException( "No entity persister for " + element.toString() );
}
entityEagerPropertyFetches[i] = element.isAllPropertyFetch();
sqlAliases[i] = element.getTableAlias();
entityAliases[i] = element.getClassAlias();
sqlAliasByEntityAlias.put( entityAliases[i], sqlAliases[i] );
// TODO should we just collect these like with the collections above?
sqlAliasSuffixes[i] = ( size == 1 ) ? "" : AliasConstantsHelper.get( i );
// sqlAliasSuffixes[i] = element.getColumnAliasSuffix();
includeInSelect[i] = !element.isFetch();
if ( includeInSelect[i] ) {
selectLength++;
}
owners[i] = -1; //by default
if ( element.isFetch() ) {
//noinspection StatementWithEmptyBody
if ( element.isCollectionJoin() || element.getQueryableCollection() != null ) {
// This is now handled earlier in this method.
}
else if ( element.getDataType().isEntityType() ) {
EntityType entityType = (EntityType) element.getDataType();
if ( entityType.isOneToOne() ) {
owners[i] = fromElementList.indexOf( element.getOrigin() );
}
ownerAssociationTypes[i] = entityType;
}
}
}
//NONE, because its the requested lock mode, not the actual!
defaultLockModes = ArrayHelper.fillArray( LockMode.NONE, size );
}
public AggregatedSelectExpression getAggregatedSelectExpression() {
return aggregatedSelectExpression;
}
// -- Loader implementation --
public final void validateScrollability() throws HibernateException {
queryTranslator.validateScrollability();
}
@Override
protected boolean needsFetchingScroll() {
return queryTranslator.containsCollectionFetches();
}
@Override
public Loadable[] getEntityPersisters() {
return entityPersisters;
}
@Override
public String[] getAliases() {
return sqlAliases;
}
public String[] getSqlAliasSuffixes() {
return sqlAliasSuffixes;
}
@Override
public String[] getSuffixes() {
return getSqlAliasSuffixes();
}
@Override
public String[] getCollectionSuffixes() {
return collectionSuffixes;
}
@Override
protected String getQueryIdentifier() {
return queryTranslator.getQueryIdentifier();
}
/**
* The SQL query string to be called.
*/
@Override
public String getSQLString() {
return queryTranslator.getSQLString();
}
/**
* An (optional) persister for a collection to be initialized; only collection loaders
* return a non-null value
*/
@Override
protected CollectionPersister[] getCollectionPersisters() {
return collectionPersisters;
}
@Override
protected int[] getCollectionOwners() {
return collectionOwners;
}
@Override
protected boolean[] getEntityEagerPropertyFetches() {
return entityEagerPropertyFetches;
}
/**
* An array of indexes of the entity that owns a one-to-one association
* to the entity at the given index (-1 if there is no "owner")
*/
@Override
protected int[] getOwners() {
return owners;
}
@Override
protected EntityType[] getOwnerAssociationTypes() {
return ownerAssociationTypes;
}
// -- Loader overrides --
@Override
protected boolean isSubselectLoadingEnabled() {
return hasSubselectLoadableCollections();
}
/**
* @param lockOptions a collection of lock modes specified dynamically via the Query interface
*/
@Override
protected LockMode[] getLockModes(LockOptions lockOptions) {
if ( lockOptions == null ) {
return defaultLockModes;
}
if ( lockOptions.getAliasLockCount() == 0
&& ( lockOptions.getLockMode() == null || LockMode.NONE.equals( lockOptions.getLockMode() ) ) ) {
return defaultLockModes;
}
// unfortunately this stuff can't be cached because
// it is per-invocation, not constant for the
// QueryTranslator instance
LockMode[] lockModesArray = new LockMode[entityAliases.length];
for ( int i = 0; i < entityAliases.length; i++ ) {
LockMode lockMode = lockOptions.getEffectiveLockMode( entityAliases[i] );
if ( lockMode == null ) {
//NONE, because its the requested lock mode, not the actual!
lockMode = LockMode.NONE;
}
lockModesArray[i] = lockMode;
}
return lockModesArray;
}
@Override
protected String applyLocks(
String sql,
QueryParameters parameters,
Dialect dialect,
List<AfterLoadAction> afterLoadActions) throws QueryException {
// can't cache this stuff either (per-invocation)
// we are given a map of user-alias -> lock mode
// create a new map of sql-alias -> lock mode
final LockOptions lockOptions = parameters.getLockOptions();
if ( lockOptions == null ||
( lockOptions.getLockMode() == LockMode.NONE && lockOptions.getAliasLockCount() == 0 ) ) {
return sql;
}
// user is request locking, lets see if we can apply locking directly to the SQL...
// some dialects wont allow locking with paging...
if ( shouldUseFollowOnLocking( parameters, dialect, afterLoadActions ) ) {
return sql;
}
// there are other conditions we might want to add here, such as checking the result types etc
// but those are better served after we have redone the SQL generation to use ASTs.
// we need both the set of locks and the columns to reference in locks
// as the ultimate output of this section...
final LockOptions locks = new LockOptions( lockOptions.getLockMode() );
final Map<String, String[]> keyColumnNames = dialect.forUpdateOfColumns()
? new HashMap<>()
: null;
locks.setScope( lockOptions.getScope() );
locks.setTimeOut( lockOptions.getTimeOut() );
for ( Map.Entry<String, String> entry : sqlAliasByEntityAlias.entrySet() ) {
final String userAlias = entry.getKey();
final String drivingSqlAlias = entry.getValue();
if ( drivingSqlAlias == null ) {
throw new IllegalArgumentException( "could not locate alias to apply lock mode : " + userAlias );
}
// at this point we have (drivingSqlAlias) the SQL alias of the driving table
// corresponding to the given user alias. However, the driving table is not
// (necessarily) the table against which we want to apply locks. Mainly,
// the exception case here is joined-subclass hierarchies where we instead
// want to apply the lock against the root table (for all other strategies,
// it just happens that driving and root are the same).
final QueryNode select = (QueryNode) queryTranslator.getSqlAST();
final Lockable drivingPersister = (Lockable) select.getFromClause()
.findFromElementByUserOrSqlAlias( userAlias, drivingSqlAlias )
.getQueryable();
final String sqlAlias = drivingPersister.getRootTableAlias( drivingSqlAlias );
final LockMode effectiveLockMode = lockOptions.getEffectiveLockMode( userAlias );
locks.setAliasSpecificLockMode( sqlAlias, effectiveLockMode );
if ( keyColumnNames != null ) {
keyColumnNames.put( sqlAlias, drivingPersister.getRootTableIdentifierColumnNames() );
}
}
// apply the collected locks and columns
return dialect.applyLocksToSql( sql, locks, keyColumnNames );
}
@Override
protected void applyPostLoadLocks(Object[] row, LockMode[] lockModesArray, SharedSessionContractImplementor session) {
// todo : scalars???
// if ( row.length != lockModesArray.length ) {
// return;
// }
//
// for ( int i = 0; i < lockModesArray.length; i++ ) {
// if ( LockMode.OPTIMISTIC_FORCE_INCREMENT.equals( lockModesArray[i] ) ) {
// final EntityEntry pcEntry =
// }
// else if ( LockMode.PESSIMISTIC_FORCE_INCREMENT.equals( lockModesArray[i] ) ) {
//
// }
// }
}
@Override
protected boolean upgradeLocks() {
return true;
}
private boolean hasSelectNew() {
return aggregatedSelectExpression != null && aggregatedSelectExpression.getResultTransformer() != null;
}
@Override
protected String[] getResultRowAliases() {
return queryReturnAliases;
}
@Override
protected ResultTransformer resolveResultTransformer(ResultTransformer resultTransformer) {
final ResultTransformer implicitResultTransformer = aggregatedSelectExpression == null
? null
: aggregatedSelectExpression.getResultTransformer();
return HolderInstantiator.resolveResultTransformer( implicitResultTransformer, resultTransformer );
}
@Override
protected boolean[] includeInResultRow() {
boolean[] includeInResultTuple = includeInSelect;
if ( hasScalars ) {
includeInResultTuple = new boolean[queryReturnTypes.length];
Arrays.fill( includeInResultTuple, true );
}
return includeInResultTuple;
}
@Override
protected Object getResultColumnOrRow(
Object[] row,
ResultTransformer transformer,
ResultSet rs,
SharedSessionContractImplementor session)
throws SQLException, HibernateException {
Object[] resultRow = getResultRow( row, rs, session );
boolean hasTransform = hasSelectNew() || transformer != null;
return ( !hasTransform && resultRow.length == 1 ?
resultRow[0] :
resultRow
);
}
@Override
protected Object[] getResultRow(Object[] row, ResultSet rs, SharedSessionContractImplementor session)
throws SQLException, HibernateException {
Object[] resultRow;
if ( hasScalars ) {
String[][] scalarColumns = scalarColumnNames;
int queryCols = queryReturnTypes.length;
resultRow = new Object[queryCols];
for ( int i = 0; i < queryCols; i++ ) {
resultRow[i] = queryReturnTypes[i].nullSafeGet( rs, scalarColumns[i], session, null );
}
}
else {
resultRow = toResultRow( row );
}
return resultRow;
}
@SuppressWarnings("unchecked")
@Override
protected List getResultList(List results, ResultTransformer resultTransformer) throws QueryException {
// meant to handle dynamic instantiation queries...
HolderInstantiator holderInstantiator = buildHolderInstantiator( resultTransformer );
if ( holderInstantiator.isRequired() ) {
for ( int i = 0; i < results.size(); i++ ) {
Object[] row = (Object[]) results.get( i );
Object result = holderInstantiator.instantiate( row );
results.set( i, result );
}
if ( !hasSelectNew() && resultTransformer != null ) {
return resultTransformer.transformList( results );
}
else {
return results;
}
}
else {
return results;
}
}
private HolderInstantiator buildHolderInstantiator(ResultTransformer queryLocalResultTransformer) {
final ResultTransformer implicitResultTransformer = aggregatedSelectExpression == null
? null
: aggregatedSelectExpression.getResultTransformer();
return HolderInstantiator.getHolderInstantiator(
implicitResultTransformer,
queryLocalResultTransformer,
queryReturnAliases
);
}
// --- Query translator methods ---
public List list(
SharedSessionContractImplementor session,
QueryParameters queryParameters) throws HibernateException {
checkQuery( queryParameters );
return list( session, queryParameters, queryTranslator.getQuerySpaces(), queryReturnTypes );
}
private void checkQuery(QueryParameters queryParameters) {
if ( hasSelectNew() && queryParameters.getResultTransformer() != null ) {
throw new QueryException( "ResultTransformer is not allowed for 'select new' queries." );
}
}
public Iterator iterate(
QueryParameters queryParameters,
EventSource session) throws HibernateException {
checkQuery( queryParameters );
final StatisticsImplementor statistics = session.getFactory().getStatistics();
final boolean stats = statistics.isStatisticsEnabled();
long startTime = 0;
if ( stats ) {
startTime = System.nanoTime();
}
try {
if ( queryParameters.isCallable() ) {
throw new QueryException( "iterate() not supported for callable statements" );
}
final SqlStatementWrapper wrapper = executeQueryStatement(
queryParameters,
false,
Collections.emptyList(),
session
);
final ResultSet rs = wrapper.getResultSet();
final PreparedStatement st = (PreparedStatement) wrapper.getStatement();
final Iterator result = new IteratorImpl(
rs,
st,
session,
queryParameters.isReadOnly( session ),
queryReturnTypes,
queryTranslator.getColumnNames(),
buildHolderInstantiator( queryParameters.getResultTransformer() )
);
if ( stats ) {
final long endTime = System.nanoTime();
final long milliseconds = TimeUnit.MILLISECONDS.convert( endTime - startTime, TimeUnit.NANOSECONDS );
statistics.queryExecuted(
// "HQL: " + queryTranslator.getQueryString(),
getQueryIdentifier(),
0,
milliseconds
);
}
return result;
}
catch (SQLException sqle) {
throw session.getJdbcServices().getSqlExceptionHelper().convert(
sqle,
"could not execute query using iterate",
getSQLString()
);
}
}
public ScrollableResultsImplementor scroll(
final QueryParameters queryParameters,
final SharedSessionContractImplementor session) throws HibernateException {
checkQuery( queryParameters );
return scroll(
queryParameters,
queryReturnTypes,
buildHolderInstantiator( queryParameters.getResultTransformer() ),
session
);
}
// -- Implementation private methods --
private Object[] toResultRow(Object[] row) {
if ( selectLength == row.length ) {
return row;
}
else {
Object[] result = new Object[selectLength];
int j = 0;
for ( int i = 0; i < row.length; i++ ) {
if ( includeInSelect[i] ) {
result[j++] = row[i];
}
}
return result;
}
}
/**
* Returns the locations of all occurrences of the named parameter.
*/
@Override
public int[] getNamedParameterLocs(String name) throws QueryException {
ParameterInformation info = queryTranslator.getParameterTranslations().getNamedParameterInformation( name );
if ( info == null ) {
try {
info = queryTranslator.getParameterTranslations().getPositionalParameterInformation(
Integer.parseInt( name )
);
}
catch (Exception ignore) {
}
}
if ( info == null ) {
throw new QueryException( "Unrecognized parameter label : " + name );
}
return info.getSourceLocations();
}
/**
* We specifically override this method here, because in general we know much more
* about the parameters and their appropriate bind positions here then we do in
* our super because we track them explicitly here through the ParameterSpecification
* interface.
*
* @param queryParameters The encapsulation of the parameter values to be bound.
* @param startIndex The position from which to start binding parameter values.
* @param session The originating session.
*
* @return The number of JDBC bind positions actually bound during this method execution.
*
* @throws SQLException Indicates problems performing the binding.
*/
@Override
protected int bindParameterValues(
final PreparedStatement statement,
final QueryParameters queryParameters,
final int startIndex,
final SharedSessionContractImplementor session) throws SQLException {
int position = startIndex;
List<ParameterSpecification> parameterSpecs = queryTranslator.getCollectedParameterSpecifications();
for ( ParameterSpecification spec : parameterSpecs ) {
position += spec.bind( statement, queryParameters, session, position );
}
return position - startIndex;
}
}

View File

@ -28,6 +28,7 @@ import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.ResultSetWrapper;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;

View File

@ -10,6 +10,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.plan.exec.query.spi.NamedParameterContext;
import org.hibernate.loader.spi.AfterLoadAction;

View File

@ -10,15 +10,13 @@ import java.sql.CallableStatement;
import java.sql.SQLException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
/**
* Specialization of DomainType for types that can be used as a
* parameter output for a {@link org.hibernate.procedure.ProcedureCall}
*
* @apiNote We assume a type that maps to exactly one SQL value, hence
* {@link #getSqlTypeDescriptor()}
* @apiNote We assume a type that maps to exactly one SQL value, hence {@link #getSqlTypeDescriptor()}
*
* @author Steve Ebersole
*/
@ -26,7 +24,7 @@ public interface AllowableOutputParameterType<J> extends AllowableParameterType<
/**
* Can the given instance of this type actually perform the parameter value extractions?
*
* @return {@code true} indicates that @{link #extract} calls will not fail due to {@link IllegalStateException}.
* @return {@code true} indicates that {@link #extract} calls will not fail due to {@link IllegalStateException}.
*/
boolean canDoExtraction();
@ -35,14 +33,11 @@ public interface AllowableOutputParameterType<J> extends AllowableParameterType<
*/
SqlTypeDescriptor getSqlTypeDescriptor();
ValueBinder<J> getValueBinder();
/**
* Perform the extraction
*
* @param statement The CallableStatement from which to extract the parameter value(s).
* @param startIndex The parameter index from which to start extracting; assumes the values (if multiple) are contiguous
* @param paramIndex The parameter index from which to extract
* @param session The originating session
*
* @return The extracted value.
@ -50,7 +45,7 @@ public interface AllowableOutputParameterType<J> extends AllowableParameterType<
* @throws SQLException Indicates an issue calling into the CallableStatement
* @throws IllegalStateException Thrown if this method is called on instances that return {@code false} for {@link #canDoExtraction}
*/
J extract(CallableStatement statement, int startIndex, SharedSessionContractImplementor session) throws SQLException;
J extract(CallableStatement statement, int paramIndex, SharedSessionContractImplementor session) throws SQLException;
/**
* Perform the extraction

View File

@ -6,13 +6,17 @@
*/
package org.hibernate.metamodel.model.domain;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.Incubating;
import org.hibernate.metamodel.model.mapping.spi.Writeable;
import org.hibernate.query.Query;
/**
* Specialization of DomainType for types that can be used as query parameter bind values
* Specialization of DomainType for types that can be used as {@link Query} parameter bind values
*
* todo (6.0) : extend Writeable (and therefore Readable too)? or composition?
*
* @author Steve Ebersole
*/
public interface AllowableParameterType<J> extends SimpleDomainType<J> {
ValueExtractor<J> getValueExtractor();
@Incubating
public interface AllowableParameterType<J> extends Writeable<J> {
}

View File

@ -16,7 +16,7 @@ import org.hibernate.type.spi.TypeConfiguration;
*
* @author Steve Ebersole
*/
public interface AllowableTemporalParameterType extends AllowableParameterType {
public interface AllowableTemporalParameterType<T> extends AllowableParameterType<T> {
/**
* Convert the value and/or type to the specified temporal precision
*/

View File

@ -8,7 +8,6 @@ package org.hibernate.metamodel.model.mapping.spi;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.DomainResultProducer;
@ -17,14 +16,14 @@ import org.hibernate.sql.results.spi.DomainResultProducer;
* Describes a mapping of related to any part of the app's domain model - e.g.
* an attribute, an entity identifier, collection elements, etc
*
* @see DomainResultProducer
* @see javax.persistence.metamodel.Bindable
*
* @author Steve Ebersole
*/
public interface ModelPart<T> {
public interface ModelPart<T> extends Readable, Writeable {
/**
* Create a QueryResult for a specific reference to this ModelPart.
*
* Ultimately this is called from the {@link SqmPath} implementation of
* {@link DomainResultProducer}
* Create a DomainResult for a specific reference to this ModelPart.
*/
default DomainResult<T> createDomainResult(
NavigablePath navigablePath,
@ -33,4 +32,13 @@ public interface ModelPart<T> {
DomainResultCreationState creationState) {
throw new NotYetImplementedFor6Exception( getClass() );
}
/**
* Apply SQL selections for a specific reference to this ModelPart outside the domain query's root select clause.
*/
default void applySqlSelections(
NavigablePath navigablePath,
DomainResultCreationState creationState) {
throw new NotYetImplementedFor6Exception( getClass() );
}
}

View File

@ -0,0 +1,57 @@
/*
* 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.metamodel.model.mapping.spi;
import java.util.function.Consumer;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.persister.SqlExpressableType;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.type.spi.TypeConfiguration;
/**
* Contract for things at the domain/mapping level that can be extracted from a JDBC result
*
* Really, reading/loading stuff is defined via {@link DomainResult} and
* {@link org.hibernate.sql.results.spi.Initializer}. This contract simply works as a sort
* of extended `DomainResultProducer` specifically for mapped-parts of a domain model
*
* @author Steve Ebersole
*/
public interface Readable {
/**
* Visit all of the SqlExpressableTypes associated with this this Readable.
*
* Used during cacheable SQL AST creation.
*/
default void visitJdbcTypes(Consumer<SqlExpressableType> action, TypeConfiguration typeConfiguration) {
throw new NotYetImplementedFor6Exception( getClass() );
}
/**
* Create a DomainResult for a specific reference to this ModelPart.
*/
default DomainResult<?> createDomainResult(
NavigablePath navigablePath,
int valuesArrayPosition,
String resultVariable,
DomainResultCreationState creationState) {
throw new NotYetImplementedFor6Exception( getClass() );
}
/**
* Apply SQL selections for a specific reference to this ModelPart outside the domain query's root select clause.
*/
default void applySqlSelections(
NavigablePath navigablePath,
DomainResultCreationState creationState) {
throw new NotYetImplementedFor6Exception( getClass() );
}
}

View File

@ -8,6 +8,7 @@ package org.hibernate.metamodel.model.mapping.spi;
import java.util.Locale;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.type.Type;
/**
@ -20,12 +21,14 @@ import org.hibernate.type.Type;
*
* @author Steve Ebersole
*/
public interface ValueMapping {
public interface ValueMapping<D> extends ModelPart<D> {
/**
* Get the Type associated with this mapping
*/
Type getValueType();
default Type getValueType() {
throw new NotYetImplementedFor6Exception( getClass() );
}
/**
* Treat operation. Asks the ValueMapping to treat itself as the

View File

@ -9,18 +9,24 @@ package org.hibernate.metamodel.model.mapping.spi;
import java.util.function.Consumer;
/**
* Container for ValueMappings
* Access to a group of ValueMappings by name or for iteration
*
* @author Steve Ebersole
*/
public interface ValueMappingContainer {
public interface ValueMappingContainer<D> extends ModelPart<D> {
/**
* Find a sub-ValueMapping by name
*/
ValueMapping findValueMapping(String name);
<X> ValueMapping<X> findValueMapping(String name);
/**
* Visit all of this container's sub-ValueMappings
*/
void visitValueMappings(Consumer<ValueMapping> consumer);
void visitValueMappings(Consumer<ValueMapping<?>> consumer);
// todo (6.0) : consider for SQM -> SQL conversion :
// ````
// ColumnReferenceQualifier resolveColumnReferenceQualifier(String name);
// ````
// - the one concern to that is properly handling needing the join versus not needing it wrt joinable fk references
}

View File

@ -0,0 +1,140 @@
/*
* 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.metamodel.model.mapping.spi;
import java.util.function.Consumer;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.persister.SqlExpressableType;
import org.hibernate.sql.ast.Clause;
import org.hibernate.type.spi.TypeConfiguration;
/**
* Contract for things at the domain/mapping level that can be bound into a JDBC query
*
* @author Steve Ebersole
*/
public interface Writeable {
/**
* Visit all of the SqlExpressableTypes associated with this this Writeable.
* <p>
* Used during cacheable SQL AST creation.
*/
default void visitJdbcTypes(
Consumer<SqlExpressableType> action,
Clause clause,
TypeConfiguration typeConfiguration) {
throw new NotYetImplementedFor6Exception( getClass() );
}
/**
* @asciidoc
*
* Breaks down a value of `J` into its simple pieces. E.g., an embedded
* value gets broken down into an array of its attribute state; a basic
* value converts to itself; etc.
* <p>
* Generally speaking, this is the form in which entity state is kept relative to a
* Session via `EntityEntry`.
*
* @see org.hibernate.engine.spi.EntityEntry
*
* As an example, consider the following domain model:
*
* ````
* @Entity
* class Person {
* @Id Integer id;
* @Embedded Name name;
* int age;
* }
*
* @Embeddable
* class Name {
* String familiarName;
* String familyName;
* }
* ````
*
* At the top-level, we would want to disassemble a `Person` value so we'd ask the
* `Writeable` for the `Person` entity to disassemble. Given a Person value:
*
* ````
* Person( id=1, name=Name( 'Steve', 'Ebersole' ), 28 )
* ````
*
* this disassemble would result in a multi-dimensional array:
*
* ````
* [ ["Steve", "Ebersole"], 28 ]
* ````
*
* ````
* JdbcValues( "Steve", "Ebersole", 28 )
* ````
*
* Note that the identifier is not part of this disassembled state. Note also
* how the embedded value results in a sub-array.
*/
default Object disassemble(Object value, SharedSessionContractImplementor session) {
throw new NotYetImplementedFor6Exception( getClass() );
}
/**
* @asciidoc
*
* Visit each constituent JDBC value over the result from {@link #disassemble}.
*
* Given the example in {@link #disassemble}, this results in the consumer being
* called for each simple value. E.g.:
*
* ````
* consumer.consume( "Steve" );
* consumer.consume( "Ebersole" );
* consumer.consume( 28 );
* ````
*
* Think of it as breaking the multi-dimensional array into a visitable flat array
*/
default void visitDisassembledJdbcValues(
Object value,
Clause clause,
JdbcValuesConsumer valuesConsumer,
SharedSessionContractImplementor session) {
throw new NotYetImplementedFor6Exception( getClass() );
}
/**
* Visit each constituent JDBC value extracted from the entity instance itself.
*
* Short-hand form of calling {@link #disassemble} and piping its result to
* {@link #visitDisassembledJdbcValues}
*
* todo (6.0) : Would this would ever be used?
*/
default void visitJdbcValues(
Object value,
Clause clause,
JdbcValuesConsumer valuesConsumer,
SharedSessionContractImplementor session) {
visitDisassembledJdbcValues( disassemble( value, session ), clause, valuesConsumer, session );
}
/**
* Functional interface for consuming the JDBC values. Essentially a {@link java.util.function.BiConsumer}
*/
@FunctionalInterface
interface JdbcValuesConsumer {
/**
* Consume a JDBC-level value. The JDBC type descriptor is also passed in
*/
void consume(Object value, SqlExpressableType type);
}
}

View File

@ -6,8 +6,8 @@
*/
package org.hibernate.persister;
import org.hibernate.sql.exec.spi.JdbcValueBinder;
import org.hibernate.sql.exec.spi.JdbcValueExtractor;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
@ -33,11 +33,11 @@ public interface SqlExpressableType {
* The strategy for extracting values of this expressable
* type from JDBC ResultSets, CallableStatements, etc
*/
JdbcValueExtractor getJdbcValueExtractor();
ValueExtractor getJdbcValueExtractor();
/**
* The strategy for binding values of this expressable
* type to JDBC PreparedStatements, CallableStatements, etc
*/
JdbcValueBinder getJdbcValueBinder();
ValueBinder getJdbcValueBinder();
}

View File

@ -1064,8 +1064,8 @@ public abstract class AbstractEntityPersister
}
@Override
public void visitValueMappings(Consumer<ValueMapping> consumer) {
attributeDefinitions.forEach( consumer );
public void visitValueMappings(Consumer consumer) {
}
public Object initializeLazyProperty(String fieldName, Object entity, SharedSessionContractImplementor session) {

View File

@ -77,6 +77,7 @@ import org.hibernate.query.sqm.tree.select.SqmSubQuery;
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.FromClauseAccess;
import org.hibernate.sql.ast.spi.SqlAliasBaseManager;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.query.sqm.tree.expression.function.SqmFunction;
@ -562,11 +563,6 @@ public abstract class BaseSqmToSqlAstConverter
throw new NotYetImplementedFor6Exception();
}
@Override
public GraphImplementor getCurrentResultGraphNode() {
return null;
}
private final Map<SqmParameter,List<JdbcParameter>> jdbcParamsBySqmParam = new IdentityHashMap<>();
private final JdbcParameters jdbcParameters = new JdbcParametersImpl();

View File

@ -0,0 +1,117 @@
/*
* 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.query.sqm.consume.spi;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.from.SqmFrom;
import org.hibernate.sql.ast.spi.SimpleFromClauseAccessImpl;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.jboss.logging.Logger;
/**
* An index of various FROM CLAUSE resolutions.
*
* @author Steve Ebersole
*/
public class FromClauseIndex extends SimpleFromClauseAccessImpl {
private static final Logger log = Logger.getLogger( FromClauseIndex.class );
private Map<NavigablePath, TableGroupJoin> tableGroupJoinMap;
private final Map<String, TableGroup> tableGroupByAliasXref = new HashMap<>();
/**
* Holds *explicitly* fetched joins
*/
private Map<NavigablePath, SqmAttributeJoin> fetchesByPath;
private Map<NavigablePath, Map<NavigablePath, SqmAttributeJoin>> fetchesByParentPath;
private final Set<String> affectedTableNames = new HashSet<>();
public FromClauseIndex() {
}
public Set<String> getAffectedTableNames() {
return affectedTableNames;
}
public void register(SqmFrom sqmPath, TableGroup tableGroup) {
if ( sqmPath instanceof SqmAttributeJoin ) {
throw new IllegalArgumentException(
"Passed SqmPath [" + sqmPath + "] is a SqmNavigableJoin - use the form of #register specific to joins"
);
}
performRegistration( sqmPath, tableGroup );
}
private void performRegistration(SqmFrom sqmPath, TableGroup tableGroup) {
registerTableGroup( sqmPath.getNavigablePath(), tableGroup );
if ( sqmPath.getExplicitAlias() != null ) {
final TableGroup previousAliasReg = tableGroupByAliasXref.put( sqmPath.getExplicitAlias(), tableGroup );
if ( previousAliasReg != null ) {
log.debugf(
"Encountered previous TableGroup registration [%s] for alias : %s",
previousAliasReg,
sqmPath.getExplicitAlias()
);
}
}
}
public boolean isResolved(SqmFrom fromElement) {
return tableGroupMap.containsKey( fromElement.getNavigablePath() );
}
@Override
public void registerTableGroup(NavigablePath navigablePath, TableGroup tableGroup) {
super.registerTableGroup( navigablePath, tableGroup );
tableGroup.applyAffectedTableNames( affectedTableNames::add );
}
public void register(SqmAttributeJoin join, TableGroupJoin tableGroupJoin) {
performRegistration( join, tableGroupJoin.getJoinedGroup() );
if ( tableGroupJoinMap == null ) {
tableGroupJoinMap = new HashMap<>();
}
tableGroupJoinMap.put( join.getNavigablePath(), tableGroupJoin );
if ( join.isFetched() ) {
if ( fetchesByPath == null ) {
fetchesByPath = new HashMap<>();
}
fetchesByPath.put( join.getNavigablePath(), join );
if ( fetchesByParentPath == null ) {
fetchesByParentPath = new HashMap<>();
}
final Map<NavigablePath, SqmAttributeJoin> fetchesForParent = fetchesByParentPath.computeIfAbsent(
join.getNavigablePath().getParent(),
navigablePath -> new HashMap<>()
);
fetchesForParent.put( join.getNavigablePath(), join );
}
}
public TableGroupJoin findTableGroupJoin(NavigablePath navigablePath) {
return tableGroupJoinMap == null ? null : tableGroupJoinMap.get( navigablePath );
}
public SqmAttributeJoin findFetchedJoinByPath(NavigablePath path) {
return fetchesByPath == null ? null : fetchesByPath.get( path );
}
}

View File

@ -106,14 +106,6 @@ public abstract class AbstractSqmAttributeJoin<O,T>
return walker.visitQualifiedAttributeJoin( this );
}
@Override
public void prepareForSubNavigableReference(
SqmPathSource subNavigable,
boolean isSubReferenceTerminal,
SqmCreationState creationState) {
// nothing to prepare
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// JPA

View File

@ -10,17 +10,12 @@ import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.PathException;
import org.hibernate.query.hql.spi.SemanticPathPart;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmJoinable;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.UnknownPathException;
import org.hibernate.query.sqm.consume.spi.SemanticQueryWalker;
import org.hibernate.query.hql.spi.SqmPathRegistry;
import org.hibernate.query.hql.spi.SemanticPathPart;
import org.hibernate.query.sqm.produce.spi.SqmCreationState;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.from.SqmFrom;
/**
* @author Steve Ebersole
@ -58,8 +53,6 @@ public class SqmEmbeddedValuedSimplePath<T> extends AbstractSqmSimplePath<T> {
throw UnknownPathException.unknownSubPath( this, name );
}
prepareForSubNavigableReference( subPathSource, isTerminal, creationState );
return subPathSource.createSqmPath( this, creationState );
}
@ -68,49 +61,6 @@ public class SqmEmbeddedValuedSimplePath<T> extends AbstractSqmSimplePath<T> {
return walker.visitEmbeddableValuedPath( this );
}
private boolean dereferenced;
@Override
public void prepareForSubNavigableReference(
SqmPathSource subNavigable,
boolean isSubReferenceTerminal,
SqmCreationState creationState) {
if ( dereferenced ) {
// nothing to do
return;
}
log.tracef(
"`SqmEmbeddedValuedSimplePath#prepareForSubNavigableReference` : %s -> %s",
getNavigablePath().getFullPath(),
subNavigable.getPathName()
);
final SqmPathRegistry pathRegistry = creationState.getProcessingStateStack().getCurrent().getPathRegistry();
final SqmFrom fromByPath = pathRegistry.findFromByPath( getNavigablePath() );
if ( fromByPath == null ) {
getLhs().prepareForSubNavigableReference( getReferencedPathSource(), false, creationState );
final SqmFrom<?,?> lhsFrom = pathRegistry.findFromByPath( getLhs().getNavigablePath() );
if ( getReferencedPathSource() instanceof SqmJoinable ) {
final SqmAttributeJoin sqmJoin = ( (SqmJoinable) getReferencedPathSource() ).createSqmJoin(
lhsFrom,
SqmJoinType.INNER,
null,
false,
creationState
);
pathRegistry.register( sqmJoin );
//noinspection unchecked
lhsFrom.addSqmJoin( sqmJoin );
}
}
dereferenced = true;
}
@Override
public <S extends T> SqmTreatedPath<T, S> treatAs(Class<S> treatJavaType) throws PathException {

View File

@ -52,6 +52,7 @@ public interface SqmPath<T> extends SqmExpression<T>, SemanticPathPart, JpaPath<
*/
void setExplicitAlias(String explicitAlias);
/**
* Get the left-hand side of this path - may be null, indicating a
* root, cross-join or entity-join

View File

@ -21,7 +21,6 @@ import javax.persistence.metamodel.SingularAttribute;
import org.hibernate.query.criteria.JpaFrom;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.produce.spi.SqmCreationState;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
import org.hibernate.query.sqm.tree.domain.SqmBagJoin;
import org.hibernate.query.sqm.tree.domain.SqmListJoin;
@ -62,19 +61,10 @@ public interface SqmFrom<O,T> extends SqmVisitableNode, SqmPath<T>, JpaFrom<O, T
*/
void visitSqmJoins(Consumer<SqmJoin<T, ?>> consumer);
@Override
default void prepareForSubNavigableReference(
SqmPathSource subNavigableSource,
boolean isSubReferenceTerminal,
SqmCreationState creationState) {
// nothing to do, already prepared
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// JPA
@Override
SqmFrom<O, T> getCorrelationParent();

View File

@ -0,0 +1,21 @@
/*
* 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.sql.ast;
import org.jboss.logging.Logger;
/**
* @author Steve Ebersole
*/
public interface SqlTreeCreationLogger {
String LOGGER_NAME = "org.hibernate.orm.sql.ast.create";
Logger LOGGER = Logger.getLogger( LOGGER_NAME );
boolean DEBUG_ENABLED = LOGGER.isDebugEnabled();
boolean TRACE_ENABLED = LOGGER.isTraceEnabled();
}

View File

@ -0,0 +1,64 @@
/*
* 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.sql.ast.spi;
import java.util.function.Function;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.SqlTreeCreationException;
import org.hibernate.sql.ast.tree.from.TableGroup;
/**
* Access to TableGroup indexing. The indexing is defined in terms
* of {@link NavigablePath}
*
* @author Steve Ebersole
*/
public interface FromClauseAccess {
/**
* Find a TableGroup by the NavigablePath it is registered under. Returns
* {@code null} if no TableGroup is registered under that NavigablePath
*/
TableGroup findTableGroup(NavigablePath navigablePath);
/**
* Get a TableGroup by the NavigablePath it is registered under. If there is
* no registration, an exception is thrown.
*/
default TableGroup getTableGroup(NavigablePath navigablePath) throws SqlTreeCreationException {
final TableGroup tableGroup = findTableGroup( navigablePath );
if ( tableGroup == null ) {
throw new SqlTreeCreationException( "Could not locate TableGroup - " + navigablePath );
}
return tableGroup;
}
/**
* Register a TableGroup under the given `navigablePath`. Logs a message
* if thhis registration over-writes an existing one.
*/
void registerTableGroup(NavigablePath navigablePath, TableGroup tableGroup);
/**
* Finds the TableGroup associated with the given `navigablePath`. If one is not found,
* it is created via the given `creator`, registered under `navigablePath` and returned.
*
* @apiNote If the `creator` is called, there is no need for it to register the TableGroup
* it creates. It will be registered by this method after.
*
* @see #findTableGroup
* @see #registerTableGroup
*/
default TableGroup resolveTableGroup(NavigablePath navigablePath, Function<NavigablePath, TableGroup> creator) {
TableGroup tableGroup = findTableGroup( navigablePath );
if ( tableGroup == null ) {
tableGroup = creator.apply( navigablePath );
registerTableGroup( navigablePath, tableGroup );
}
return tableGroup;
}
}

View File

@ -0,0 +1,42 @@
/*
* 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.sql.ast.spi;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.SqlTreeCreationLogger;
import org.hibernate.sql.ast.tree.from.TableGroup;
/**
* Simple implementation of FromClauseAccess
*
* @author Steve Ebersole
*/
public class SimpleFromClauseAccessImpl implements FromClauseAccess {
protected final Map<NavigablePath, TableGroup> tableGroupMap = new HashMap<>();
@Override
public TableGroup findTableGroup(NavigablePath navigablePath) {
return tableGroupMap.get( navigablePath );
}
@Override
public void registerTableGroup(NavigablePath navigablePath, TableGroup tableGroup) {
final TableGroup previous = tableGroupMap.put( navigablePath, tableGroup );
if ( previous != null ) {
SqlTreeCreationLogger.LOGGER.debugf(
"Registration of TableGroup [%s] for NavigablePath [%s] overrode previous registration : %s",
tableGroup,
navigablePath,
previous
);
}
}
}

View File

@ -10,7 +10,8 @@ import org.hibernate.metamodel.spi.DomainMetamodel;
import org.hibernate.service.ServiceRegistry;
/**
* The "context" in which creation of SQL AST occurs.
* The "context" in which creation of SQL AST occurs. Exposes access to
* services generally needed in creating SQL AST nodes
*
* @author Steve Ebersole
*/

View File

@ -9,8 +9,6 @@ package org.hibernate.sql.ast.spi;
import java.util.List;
import org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.graph.spi.GraphImplementor;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParent;
@ -28,10 +26,6 @@ public interface SqlAstCreationState {
SqlAliasBaseManager getSqlAliasBaseManager();
default GraphImplementor getCurrentResultGraphNode() {
throw new NotYetImplementedFor6Exception( getClass() );
}
LockMode determineLockMode(String identificationVariable);
/**

View File

@ -9,11 +9,10 @@ package org.hibernate.sql.ast.spi;
import java.util.function.Consumer;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.sql.exec.spi.JdbcValueExtractor;
import org.hibernate.sql.results.spi.JdbcValuesMappingDescriptor;
import org.hibernate.sql.results.spi.RowProcessingState;
import org.hibernate.sql.results.spi.SqlSelectionGroupNode;
import org.hibernate.type.descriptor.ValueExtractor;
/**
* Represents a selection at the SQL/JDBC level. Essentially made up of:
@ -28,7 +27,7 @@ public interface SqlSelection extends SqlSelectionGroupNode {
/**
* Get the extractor that can be used to extract JDBC values for this selection
*/
JdbcValueExtractor getJdbcValueExtractor();
ValueExtractor getJdbcValueExtractor();
// todo (6.0) : add proper support for "virtual" selections
// - things like selecting a literal or a parameter

View File

@ -14,8 +14,8 @@ import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.persister.SqlExpressableType;
import org.hibernate.sql.ast.spi.SqlAstWalker;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.exec.spi.JdbcValueExtractor;
import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
@ -63,7 +63,7 @@ public class ColumnReference implements Expression {
int valuesArrayPosition,
JavaTypeDescriptor<?> javaTypeDescriptor,
TypeConfiguration typeConfiguration) {
final JdbcValueExtractor jdbcValueExtractor = sqlExpressableType.getJdbcValueExtractor();
final ValueExtractor jdbcValueExtractor = sqlExpressableType.getJdbcValueExtractor();
return new SqlSelectionImpl(
jdbcPosition,
valuesArrayPosition,

View File

@ -28,11 +28,11 @@ import org.hibernate.sql.results.spi.DomainResultProducer;
* @author Steve Ebersole
*/
public interface TableGroup extends SqlAstNode, DomainResultProducer, NavigableReference, ColumnReferenceQualifier {
LockMode getLockMode();
NavigablePath getNavigablePath();
ModelPart getModelPart();
NavigablePath getNavigablePath();
LockMode getLockMode();
Set<TableGroupJoin> getTableGroupJoins();

View File

@ -1,36 +0,0 @@
/*
* 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.sql.exec.spi;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* The low-level contract for binding (writing) values to JDBC.
*
* @apiNote At the JDBC-level we always deal with simple/basic values; never
* composites, entities, collections, etc
*
* @author Steve Ebersole
*
* @see JdbcValueExtractor
*/
public interface JdbcValueBinder<J> {
/**
* Bind a value to a prepared statement.
*/
void bind(PreparedStatement statement, int parameterPosition, J value, ExecutionContext executionContext) throws SQLException;
/**
* Bind a value to a CallableStatement.
*
* @apiNote Binding to a CallableStatement by position is done via {@link #bind(PreparedStatement, int, Object, ExecutionContext)} -
* CallableStatement extends PreparedStatement
*/
void bind(CallableStatement statement, String parameterName, J value, ExecutionContext executionContext) throws SQLException;
}

View File

@ -1,42 +0,0 @@
/*
* 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.sql.exec.spi;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* The low-level contract for extracting (reading) values to JDBC.
*
* @apiNote At the JDBC-level we always deal with simple/basic values; never
* composites, entities, collections, etc
*
* @author Steve Ebersole
*
* @see JdbcValueBinder
* @see SqlExpressableType
*/
public interface JdbcValueExtractor<J> {
/**
* Extract value from result set
*/
J extract(ResultSet resultSet, int jdbcParameterPosition, ExecutionContext executionContext) throws SQLException;
/**
* Extract value from CallableStatement
*/
J extract(
CallableStatement statement,
int jdbcParameterPosition,
ExecutionContext executionContext) throws SQLException;
/**
* Extract value from CallableStatement, by name
*/
J extract(CallableStatement statement, String jdbcParameterName, ExecutionContext executionContext) throws SQLException;
}

View File

@ -1,16 +0,0 @@
/*
* 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.sql.ordering.antlr;
/**
* Models a collation specification (<tt>COLLATE</tt> using a specific character-set) within a
* {@link SortSpecification}.
*
* @author Steve Ebersole
*/
public class CollationSpecification extends NodeSupport {
}

View File

@ -1,29 +0,0 @@
/*
* 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.sql.ordering.antlr;
import org.hibernate.HibernateException;
/**
* Contract for mapping a (an assumed) property reference to its columns.
*
* @author Steve Ebersole
*/
public interface ColumnMapper {
/**
* Resolve the property reference to its underlying columns.
*
* @param reference The property reference name.
*
* @return References to the columns/formulas that define the value mapping for the given property, or null
* if the property reference is unknown.
*
* @throws HibernateException Generally indicates that the property reference is unknown; interpretation
* should be the same as a null return.
*/
public SqlValueReference[] map(String reference) throws HibernateException;
}

View File

@ -1,21 +0,0 @@
/*
* 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.sql.ordering.antlr;
/**
* Reference to a column name.
*
* @author Steve Ebersole
*/
public interface ColumnReference extends SqlValueReference {
/**
* Retrieve the column name.
*
* @return THe column name
*/
public String getColumnName();
}

View File

@ -1,34 +0,0 @@
/*
* 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.sql.ordering.antlr;
import antlr.ASTFactory;
/**
* Acts as a {@link ASTFactory} for injecting our specific AST node classes into the Antlr generated trees.
*
* @author Steve Ebersole
*/
public class Factory extends ASTFactory implements OrderByTemplateTokenTypes {
@Override
public Class getASTNodeType(int i) {
switch ( i ) {
case ORDER_BY:
return OrderByFragment.class;
case SORT_SPEC:
return SortSpecification.class;
case ORDER_SPEC:
return OrderingSpecification.class;
case COLLATE:
return CollationSpecification.class;
case SORT_KEY:
return SortKey.class;
default:
return NodeSupport.class;
}
}
}

View File

@ -1,23 +0,0 @@
/*
* 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.sql.ordering.antlr;
/**
* Reference to a formula fragment.
*
* @author Steve Ebersole
*/
public interface FormulaReference extends SqlValueReference {
/**
* Retrieve the formula fragment. It is important to note that this is what the persister calls the
* "formula template", which has the $PlaceHolder$ (see {@link org.hibernate.sql.Template#TEMPLATE})
* markers injected.
*
* @return The formula fragment template.
*/
public String getFormulaFragment();
}

View File

@ -1,35 +0,0 @@
/*
* 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.sql.ordering.antlr;
/**
* General contract for AST nodes.
*
* @author Steve Ebersole
*/
public interface Node {
/**
* Get the intrinsic text of this node.
*
* @return The node's text.
*/
public String getText();
/**
* Get a string representation of this node usable for debug logging or similar.
*
* @return The node's debugging text.
*/
public String getDebugText();
/**
* Build the node's representation for use in the resulting rendering.
*
* @return The text for use in the translated output.
*/
public String getRenderableText();
}

View File

@ -1,26 +0,0 @@
/*
* 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.sql.ordering.antlr;
import antlr.CommonAST;
/**
* Basic implementation of a {@link Node} briding to the Antlr {@link CommonAST} hierarchy.
*
* @author Steve Ebersole
*/
public class NodeSupport extends CommonAST implements Node {
@Override
public String getDebugText() {
return getText();
}
@Override
public String getRenderableText() {
return getText();
}
}

View File

@ -1,18 +0,0 @@
/*
* 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.sql.ordering.antlr;
/**
* Given a column reference, resolve the table alias to apply to the column to qualify it.
*/
public interface OrderByAliasResolver {
/**
* Given a column reference, resolve the table alias to apply to the column to qualify it.
*
*/
public String resolveTableAlias(String columnReference);
}

View File

@ -1,15 +0,0 @@
/*
* 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.sql.ordering.antlr;
/**
* Represents a parsed <tt>order-by</tt> mapping fragment. This holds the tree of all {@link SortSpecification}s.
*
* @author Steve Ebersole
*/
public class OrderByFragment extends NodeSupport {
}

View File

@ -1,316 +0,0 @@
/*
* 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.sql.ordering.antlr;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.hibernate.dialect.function.SQLFunction;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.sql.Template;
import org.jboss.logging.Logger;
import antlr.CommonAST;
import antlr.TokenStream;
import antlr.collections.AST;
/**
* Extension of the Antlr-generated parser for the purpose of adding our custom parsing behavior
* (semantic analysis, etc).
*
* @author Steve Ebersole
*/
public class OrderByFragmentParser extends GeneratedOrderByFragmentParser {
private static final Logger LOG = Logger.getLogger( OrderByFragmentParser.class.getName() );
private final TranslationContext context;
private Set<String> columnReferences = new HashSet<String>();
public OrderByFragmentParser(TokenStream lexer, TranslationContext context) {
super( lexer );
super.setASTFactory( new Factory() );
this.context = context;
}
public Set<String> getColumnReferences() {
return columnReferences;
}
@Override
protected AST quotedIdentifier(AST ident) {
/*
* Semantic action used during recognition of quoted identifiers (quoted column names)
*/
final String columnName = context.getDialect().quote( '`' + ident.getText() + '`' );
columnReferences.add( columnName );
final String marker = '{' + columnName + '}';
return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, marker );
}
@Override
protected AST quotedString(AST ident) {
/*
* Semantic action used during recognition of quoted strings (string literals)
*/
return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, context.getDialect().quote( ident.getText() ) );
}
@Override
@SuppressWarnings("SimplifiableIfStatement")
protected boolean isFunctionName(AST ast) {
/*
* Semantic predicate used to determine whether a given AST node represents a function call
*/
AST child = ast.getFirstChild();
// assume it is a function if it has parameters
if ( child != null && "{param list}".equals( child.getText() ) ) {
return true;
}
// otherwise, in order for this to be a function logically it has to be a function that does not
// have arguments. So try to assert that using the registry of known functions
final SQLFunction function = context.getSqlFunctionRegistry().findSQLFunction( ast.getText() );
if ( function == null ) {
// no registered function, so we cannot know for certain
return false;
}
else {
// if function.hasParenthesesIfNoArguments() is true, then assume the node is not a function
return !function.hasParenthesesIfNoArguments();
}
}
@SuppressWarnings("unchecked")
@Override
protected AST resolveFunction(AST ast) {
/*
* Semantic action used during recognition of a *known* function
*/
AST child = ast.getFirstChild();
if ( child != null ) {
assert "{param list}".equals( child.getText() );
child = child.getFirstChild();
}
final String functionName = ast.getText();
final SQLFunction function = context.getSqlFunctionRegistry().findSQLFunction( functionName );
if ( function == null ) {
String text = functionName;
if ( child != null ) {
text += '(';
while ( child != null ) {
text += resolveFunctionArgument( child );
child = child.getNextSibling();
if ( child != null ) {
text += ", ";
}
}
text += ')';
}
return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, text );
}
else {
ArrayList expressions = new ArrayList();
while ( child != null ) {
expressions.add( resolveFunctionArgument( child ) );
child = child.getNextSibling();
}
final String text = function.render( null, expressions, context.getSessionFactory() );
return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, text );
}
}
private String resolveFunctionArgument(AST argumentNode) {
final String nodeText = argumentNode.getText();
final String adjustedText;
if ( nodeText.contains( Template.TEMPLATE ) ) {
// we have a SQL order-by fragment
adjustedText = adjustTemplateReferences( nodeText );
}
else if ( nodeText.startsWith( "{" ) && nodeText.endsWith( "}" ) ) {
columnReferences.add( nodeText.substring( 1, nodeText.length() - 1 ) );
return nodeText;
}
else {
adjustedText = nodeText;
// because we did not process the node text, we need to attempt to find any column references
// contained in it.
// NOTE : uses regex for the time being; we should check the performance of this
Pattern pattern = Pattern.compile( "\\{(.*)\\}" );
Matcher matcher = pattern.matcher( adjustedText );
while ( matcher.find() ) {
columnReferences.add( matcher.group( 1 ) );
}
}
return adjustedText;
}
@Override
protected AST resolveIdent(AST ident) {
/*
* Semantic action used during recognition of an identifier. This identifier might be a column name, it might
* be a property name.
*/
String text = ident.getText();
SqlValueReference[] sqlValueReferences;
try {
sqlValueReferences = context.getColumnMapper().map( text );
}
catch (Throwable t) {
sqlValueReferences = null;
}
if ( sqlValueReferences == null || sqlValueReferences.length == 0 ) {
return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, makeColumnReference( text ) );
}
else if ( sqlValueReferences.length == 1 ) {
return processSqlValueReference( sqlValueReferences[0] );
}
else {
final AST root = getASTFactory().create( OrderByTemplateTokenTypes.IDENT_LIST, "{ident list}" );
for ( SqlValueReference sqlValueReference : sqlValueReferences ) {
root.addChild( processSqlValueReference( sqlValueReference ) );
}
return root;
}
}
private AST processSqlValueReference(SqlValueReference sqlValueReference) {
if ( ColumnReference.class.isInstance( sqlValueReference ) ) {
final String columnName = ( (ColumnReference) sqlValueReference ).getColumnName();
return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, makeColumnReference( columnName ) );
}
else {
final String formulaFragment = ( (FormulaReference) sqlValueReference ).getFormulaFragment();
// formulas have already been "adjusted" for aliases by appending Template.TEMPLATE to places
// where we believe column references are. Fixing that is beyond scope of this work. But we need
// to re-adjust that to use the order-by expectation of wrapping the column names in curly
// braces (i.e., `{column_name}`).
final String adjustedText = adjustTemplateReferences( formulaFragment );
return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, adjustedText );
}
}
private String makeColumnReference(String text) {
columnReferences.add( text );
return "{" + text + "}";
}
private static final int TEMPLATE_MARKER_LENGTH = Template.TEMPLATE.length();
private String adjustTemplateReferences(String template) {
int templateLength = template.length();
int startPos = template.indexOf( Template.TEMPLATE );
while ( startPos != -1 && startPos < templateLength ) {
int dotPos = startPos + TEMPLATE_MARKER_LENGTH;
// from here we need to seek the end of the qualified identifier
int pos = dotPos + 1;
while ( pos < templateLength && isValidIdentifierCharacter( template.charAt( pos ) ) ) {
pos++;
}
// At this point we know all 3 points in the template that are needed for replacement.
// Basically we will be replacing the whole match with the bit following the dot, but will wrap
// the replacement in curly braces.
final String columnReference = template.substring( dotPos + 1, pos );
final String replacement = "{" + columnReference + "}";
template = template.replace( template.substring( startPos, pos ), replacement );
columnReferences.add( columnReference );
// prep for the next seek
startPos = template.indexOf( Template.TEMPLATE, ( pos - TEMPLATE_MARKER_LENGTH ) + 1 );
templateLength = template.length();
}
return template;
}
private static boolean isValidIdentifierCharacter(char c) {
return Character.isLetter( c )
|| Character.isDigit( c )
|| '_' == c
|| '\"' == c;
}
@Override
protected AST postProcessSortSpecification(AST sortSpec) {
assert SORT_SPEC == sortSpec.getType();
SortSpecification sortSpecification = (SortSpecification) sortSpec;
AST sortKey = sortSpecification.getSortKey();
if ( IDENT_LIST == sortKey.getFirstChild().getType() ) {
AST identList = sortKey.getFirstChild();
AST ident = identList.getFirstChild();
AST holder = new CommonAST();
do {
holder.addChild(
createSortSpecification(
ident,
sortSpecification.getCollation(),
sortSpecification.getOrdering()
)
);
ident = ident.getNextSibling();
} while ( ident != null );
sortSpec = holder.getFirstChild();
}
return sortSpec;
}
private SortSpecification createSortSpecification(
AST ident,
CollationSpecification collationSpecification,
OrderingSpecification orderingSpecification) {
AST sortSpecification = getASTFactory().create( SORT_SPEC, "{{sort specification}}" );
AST sortKey = getASTFactory().create( SORT_KEY, "{{sort key}}" );
AST newIdent = getASTFactory().create( ident.getType(), ident.getText() );
sortKey.setFirstChild( newIdent );
sortSpecification.setFirstChild( sortKey );
if ( collationSpecification != null ) {
sortSpecification.addChild( collationSpecification );
}
if ( orderingSpecification != null ) {
sortSpecification.addChild( orderingSpecification );
}
return (SortSpecification) sortSpecification;
}
// trace logging ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private int traceDepth = 0;
@Override
public void traceIn(String ruleName) {
if ( inputState.guessing > 0 ) {
return;
}
String prefix = StringHelper.repeat( '-', ( traceDepth++ * 2 ) ) + "-> ";
LOG.trace( prefix + ruleName );
}
@Override
public void traceOut(String ruleName) {
if ( inputState.guessing > 0 ) {
return;
}
String prefix = "<-" + StringHelper.repeat( '-', ( --traceDepth * 2 ) ) + " ";
LOG.trace( prefix + ruleName );
}
@Override
protected void trace(String msg) {
LOG.trace( msg );
}
}

View File

@ -1,79 +0,0 @@
/*
* 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.sql.ordering.antlr;
import org.hibernate.NullPrecedence;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.hql.internal.ast.util.ASTPrinter;
import org.hibernate.hql.internal.ast.util.TokenPrinters;
import org.hibernate.internal.util.StringHelper;
import org.jboss.logging.Logger;
import antlr.collections.AST;
/**
* Extension of the Antlr-generated tree walker for rendering the parsed order-by tree back to String form.
* {@link #out(antlr.collections.AST)} is the sole semantic action here and it is used to utilize our
* split between text (tree debugging text) and "renderable text" (text to use during rendering).
*
* @author Steve Ebersole
*/
public class OrderByFragmentRenderer extends GeneratedOrderByFragmentRenderer {
private static final Logger LOG = Logger.getLogger( OrderByFragmentRenderer.class.getName() );
private final SessionFactoryImplementor sessionFactory;
public OrderByFragmentRenderer(SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
protected void out(AST ast) {
out( ( (Node) ast ).getRenderableText() );
}
// handle trace logging ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private int traceDepth = 0;
@Override
public void traceIn(String ruleName, AST tree) {
if ( inputState.guessing > 0 ) {
return;
}
String prefix = StringHelper.repeat( '-', ( traceDepth++ * 2 ) ) + "-> ";
String traceText = ruleName + " (" + buildTraceNodeName( tree ) + ")";
LOG.trace( prefix + traceText );
}
private String buildTraceNodeName(AST tree) {
return tree == null
? "???"
: tree.getText() + " [" + TokenPrinters.ORDERBY_FRAGMENT_PRINTER.getTokenTypeName( tree.getType() ) + "]";
}
@Override
public void traceOut(String ruleName, AST tree) {
if ( inputState.guessing > 0 ) {
return;
}
String prefix = "<-" + StringHelper.repeat( '-', ( --traceDepth * 2 ) ) + " ";
LOG.trace( prefix + ruleName );
}
@Override
protected String renderOrderByElement(String expression, String collation, String order, String nulls) {
final NullPrecedence nullPrecedence = NullPrecedence.parse(
nulls,
sessionFactory.getSessionFactoryOptions().getDefaultNullPrecedence()
);
return sessionFactory.getDialect().renderOrderByElement( expression, collation, order, nullPrecedence );
}
}

View File

@ -1,99 +0,0 @@
/*
* 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.sql.ordering.antlr;
import java.io.StringReader;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.hql.internal.ast.util.ASTPrinter;
import org.hibernate.hql.internal.ast.util.TokenPrinters;
import org.jboss.logging.Logger;
/**
* A translator for order-by mappings, whether specified by hbm.xml files, Hibernate
* {@link org.hibernate.annotations.OrderBy} annotation or JPA {@link javax.persistence.OrderBy} annotation.
*
* @author Steve Ebersole
*/
public class OrderByFragmentTranslator {
private static final Logger LOG = Logger.getLogger( OrderByFragmentTranslator.class.getName() );
/**
* Perform the translation of the user-supplied fragment, returning the translation.
* <p/>
* The important distinction to this split between (1) translating and (2) resolving aliases is that
* both happen at different times
*
*
* @param context Context giving access to delegates needed during translation.
* @param fragment The user-supplied order-by fragment
*
* @return The translation.
*/
public static OrderByTranslation translate(TranslationContext context, String fragment) {
LOG.tracef( "Beginning parsing of order-by fragment : ", fragment );
GeneratedOrderByLexer lexer = new GeneratedOrderByLexer( new StringReader( fragment ) );
// Perform the parsing (and some analysis/resolution). Another important aspect is the collection
// of "column references" which are important later to seek out replacement points in the
// translated fragment.
OrderByFragmentParser parser = new OrderByFragmentParser( lexer, context );
try {
parser.orderByFragment();
}
catch ( HibernateException e ) {
throw e;
}
catch ( Throwable t ) {
throw new HibernateException( "Unable to parse order-by fragment", t );
}
if ( LOG.isTraceEnabled() ) {
LOG.trace( TokenPrinters.ORDERBY_FRAGMENT_PRINTER.showAsString( parser.getAST(), "--- {order-by fragment} ---" ) );
}
// Render the parsed tree to text.
OrderByFragmentRenderer renderer = new OrderByFragmentRenderer( context.getSessionFactory() );
try {
renderer.orderByFragment( parser.getAST() );
}
catch ( HibernateException e ) {
throw e;
}
catch ( Throwable t ) {
throw new HibernateException( "Unable to render parsed order-by fragment", t );
}
return new StandardOrderByTranslationImpl( renderer.getRenderedFragment(), parser.getColumnReferences() );
}
public static class StandardOrderByTranslationImpl implements OrderByTranslation {
private final String sqlTemplate;
private final Set<String> columnReferences;
public StandardOrderByTranslationImpl(String sqlTemplate, Set<String> columnReferences) {
this.sqlTemplate = sqlTemplate;
this.columnReferences = columnReferences;
}
@Override
public String injectAliases(OrderByAliasResolver aliasResolver) {
String sql = sqlTemplate;
for ( String columnReference : columnReferences ) {
final String replacementToken = "{" + columnReference + "}";
sql = sql.replace(
replacementToken,
aliasResolver.resolveTableAlias( columnReference ) + '.' + columnReference
);
}
return sql;
}
}
}

View File

@ -1,24 +0,0 @@
/*
* 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.sql.ordering.antlr;
/**
* Represents the result of an order-by translation by {@link @OrderByTranslator}
*
* @author Steve Ebersole
*/
public interface OrderByTranslation {
/**
* Inject table aliases into the translated fragment to properly qualify column references, using
* the given 'aliasResolver' to determine the the proper table alias to use for each column reference.
*
* @param aliasResolver The strategy to resolver the proper table alias to use per column
*
* @return The fully translated and replaced fragment.
*/
public String injectAliases(OrderByAliasResolver aliasResolver);
}

View File

@ -1,52 +0,0 @@
/*
* 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.sql.ordering.antlr;
/**
* Models an ordering specification (<tt>ASCENDING</tt> or <tt>DESCENDING</tt>) within a {@link SortSpecification}.
*
* @author Steve Ebersole
*/
public class OrderingSpecification extends NodeSupport {
public static class Ordering {
public static final Ordering ASCENDING = new Ordering( "asc" );
public static final Ordering DESCENDING = new Ordering( "desc" );
private final String name;
private Ordering(String name) {
this.name = name;
}
}
private boolean resolved;
private Ordering ordering;
public Ordering getOrdering() {
if ( !resolved ) {
ordering = resolve( getText() );
resolved = true;
}
return ordering;
}
private static Ordering resolve(String text) {
if ( Ordering.ASCENDING.name.equals( text ) ) {
return Ordering.ASCENDING;
}
else if ( Ordering.DESCENDING.name.equals( text ) ) {
return Ordering.DESCENDING;
}
else {
throw new IllegalStateException( "Unknown ordering [" + text + "]" );
}
}
public String getRenderableText() {
return getOrdering().name;
}
}

View File

@ -1,17 +0,0 @@
/*
* 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.sql.ordering.antlr;
/**
* Models the container node for the <tt>sort key</tt>, which is the term given by the ANSI SQL specification to the
* expression upon which to sort for each {@link SortSpecification}
*
* @author Steve Ebersole
*/
public class SortKey extends NodeSupport {
}

View File

@ -1,62 +0,0 @@
/*
* 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.sql.ordering.antlr;
import antlr.collections.AST;
/**
* Models each sorting expression.
*
* @author Steve Ebersole
*/
public class SortSpecification extends NodeSupport {
/**
* Locate the specified {@link SortKey}.
*
* @return The sort key.
*/
public SortKey getSortKey() {
return ( SortKey ) getFirstChild();
}
/**
* Locate the specified <tt>collation specification</tt>, if one.
*
* @return The <tt>collation specification</tt>, or null if none was specified.
*/
public CollationSpecification getCollation() {
AST possible = getSortKey().getNextSibling();
return possible != null && OrderByTemplateTokenTypes.COLLATE == possible.getType()
? ( CollationSpecification ) possible
: null;
}
/**
* Locate the specified <tt>ordering specification</tt>, if one.
*
* @return The <tt>ordering specification</tt>, or null if none was specified.
*/
public OrderingSpecification getOrdering() {
// IMPL NOTE : the ordering-spec would be either the 2nd or 3rd child (of the overall sort-spec), if it existed,
// depending on whether a collation-spec was specified.
AST possible = getSortKey().getNextSibling();
if ( possible == null ) {
// There was no sort-spec parts specified other then the sort-key so there can be no ordering-spec...
return null;
}
if ( OrderByTemplateTokenTypes.COLLATE == possible.getType() ) {
// the 2nd child was a collation-spec, so we need to check the 3rd child instead.
possible = possible.getNextSibling();
}
return possible != null && OrderByTemplateTokenTypes.ORDER_SPEC == possible.getType()
? ( OrderingSpecification ) possible
: null;
}
}

View File

@ -1,19 +0,0 @@
/*
* 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.sql.ordering.antlr;
/**
* Unifying interface between column and formula references mainly to give more strictly typed result
* to {@link ColumnMapper#map(String)}
*
* @see ColumnReference
* @see FormulaReference
*
* @author Steve Ebersole
*/
public interface SqlValueReference {
}

View File

@ -1,46 +0,0 @@
/*
* 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.sql.ordering.antlr;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.function.SQLFunctionRegistry;
import org.hibernate.engine.spi.SessionFactoryImplementor;
/**
* Contract for contextual information required to perform translation.
*
* @author Steve Ebersole
*/
public interface TranslationContext {
/**
* Retrieves the <tt>session factory</tt> for this context.
*
* @return The <tt>session factory</tt>
*/
public SessionFactoryImplementor getSessionFactory();
/**
* Retrieves the <tt>dialect</tt> for this context.
*
* @return The <tt>dialect</tt>
*/
public Dialect getDialect();
/**
* Retrieves the <tt>SQL function registry/tt> for this context.
*
* @return The SQL function registry.
*/
public SQLFunctionRegistry getSqlFunctionRegistry();
/**
* Retrieves the <tt>column mapper</tt> for this context.
*
* @return The <tt>column mapper</tt>
*/
public ColumnMapper getColumnMapper();
}

View File

@ -12,7 +12,7 @@ import org.hibernate.persister.SqlExpressableType;
import org.hibernate.sql.ast.spi.SqlAstWalker;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.exec.spi.JdbcValueExtractor;
import org.hibernate.type.descriptor.ValueExtractor;
/**
* @author Steve Ebersole
@ -21,13 +21,13 @@ public class SqlSelectionImpl implements SqlSelection {
private final int jdbcPosition;
private final int valuesArrayPosition;
private final Expression sqlExpression;
private final JdbcValueExtractor jdbcValueExtractor;
private final ValueExtractor jdbcValueExtractor;
public SqlSelectionImpl(int jdbcPosition, int valuesArrayPosition, Expression sqlExpression, SqlExpressableType sqlExpressableType) {
this( jdbcPosition, valuesArrayPosition, sqlExpression, sqlExpressableType.getJdbcValueExtractor() );
}
public SqlSelectionImpl(int jdbcPosition, int valuesArrayPosition, Expression sqlExpression, JdbcValueExtractor jdbcValueExtractor) {
public SqlSelectionImpl(int jdbcPosition, int valuesArrayPosition, Expression sqlExpression, ValueExtractor jdbcValueExtractor) {
this.jdbcPosition = jdbcPosition;
this.valuesArrayPosition = valuesArrayPosition;
this.sqlExpression = sqlExpression;
@ -35,7 +35,7 @@ public class SqlSelectionImpl implements SqlSelection {
}
@Override
public JdbcValueExtractor getJdbcValueExtractor() {
public ValueExtractor getJdbcValueExtractor() {
return jdbcValueExtractor;
}

View File

@ -6,6 +6,8 @@
*/
package org.hibernate.sql.results.spi;
import org.hibernate.NotYetImplementedFor6Exception;
/**
* Represents something that can produce a {@link DomainResult}
* instances which can be used as selection items and
@ -29,6 +31,7 @@ public interface DomainResultProducer<T> {
* This default impl assumes this producer is a true (Sql)Expression
*/
default void applySqlSelections(DomainResultCreationState creationState) {
throw new NotYetImplementedFor6Exception( getClass() );
// // this form works for basic-valued nodes
// creationState.getSqlExpressionResolver().resolveSqlSelection(
// (Expression) this,

View File

@ -7,9 +7,11 @@
package org.hibernate.tuple.component;
import java.util.Iterator;
import java.util.function.Consumer;
import org.hibernate.engine.internal.JoinHelper;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.model.mapping.spi.ValueMapping;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable;

View File

@ -22,6 +22,7 @@ import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.MutabilityPlan;
@ -34,7 +35,7 @@ import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
* @author Brett Meyer
*/
public abstract class AbstractStandardBasicType<T>
implements BasicType, StringRepresentableType<T>, ProcedureParameterExtractionAware<T>, ProcedureParameterNamedBinder {
implements BasicType<T>, StringRepresentableType<T>, ProcedureParameterExtractionAware<T>, ProcedureParameterNamedBinder {
private static final Size DEFAULT_SIZE = new Size( 19, 2, 255, Size.LobMultiplier.NONE ); // to match legacy behavior
private final Size dictatedSize = new Size();
@ -376,6 +377,11 @@ public abstract class AbstractStandardBasicType<T>
return true;
}
@Override
public ValueExtractor<T> getValueExtractor() {
return getSqlTypeDescriptor().getExtractor( getJavaTypeDescriptor() );
}
@Override
public T extract(CallableStatement statement, int startIndex, final SharedSessionContractImplementor session) throws SQLException {
return remapSqlTypeDescriptor( session ).getExtractor( javaTypeDescriptor ).extract(

View File

@ -13,7 +13,7 @@ import org.hibernate.metamodel.model.domain.BasicDomainType;
*
* @author Steve Ebersole
*/
public interface BasicType extends Type, BasicDomainType {
public interface BasicType<T> extends Type, BasicDomainType<T> {
/**
* Get the names under which this type should be registered in the type registry.
*

View File

@ -24,7 +24,7 @@ import org.hibernate.type.spi.TypeConfiguration;
*/
public class CalendarDateType
extends AbstractSingleColumnStandardBasicType<Calendar>
implements AllowableTemporalParameterType {
implements AllowableTemporalParameterType<Calendar> {
public static final CalendarDateType INSTANCE = new CalendarDateType();
public CalendarDateType() {

View File

@ -26,7 +26,7 @@ import org.hibernate.type.spi.TypeConfiguration;
*/
public class CalendarTimeType
extends AbstractSingleColumnStandardBasicType<Calendar>
implements AllowableTemporalParameterType {
implements AllowableTemporalParameterType<Calendar> {
public static final CalendarTimeType INSTANCE = new CalendarTimeType();
public CalendarTimeType() {

View File

@ -27,7 +27,7 @@ import org.hibernate.type.spi.TypeConfiguration;
*/
public class CalendarType
extends AbstractSingleColumnStandardBasicType<Calendar>
implements VersionType<Calendar>, AllowableTemporalParameterType {
implements VersionType<Calendar>, AllowableTemporalParameterType<Calendar> {
public static final CalendarType INSTANCE = new CalendarType();

View File

@ -24,7 +24,7 @@ import org.hibernate.type.spi.TypeConfiguration;
*/
public class DateType
extends AbstractSingleColumnStandardBasicType<Date>
implements IdentifierType<Date>, LiteralType<Date>, AllowableTemporalParameterType {
implements IdentifierType<Date>, LiteralType<Date>, AllowableTemporalParameterType<Date> {
public static final DateType INSTANCE = new DateType();

View File

@ -31,7 +31,7 @@ import org.hibernate.type.spi.TypeConfiguration;
*/
public class InstantType
extends AbstractSingleColumnStandardBasicType<Instant>
implements VersionType<Instant>, LiteralType<Instant>, AllowableTemporalParameterType {
implements VersionType<Instant>, LiteralType<Instant>, AllowableTemporalParameterType<Instant> {
/**
* Singleton access
*/

View File

@ -29,7 +29,7 @@ import org.hibernate.type.spi.TypeConfiguration;
*/
public class LocalDateTimeType
extends AbstractSingleColumnStandardBasicType<LocalDateTime>
implements VersionType<LocalDateTime>, LiteralType<LocalDateTime>, AllowableTemporalParameterType {
implements VersionType<LocalDateTime>, LiteralType<LocalDateTime>, AllowableTemporalParameterType<LocalDateTime> {
/**
* Singleton access
*/

View File

@ -23,7 +23,7 @@ import org.hibernate.type.spi.TypeConfiguration;
*/
public class LocalDateType
extends AbstractSingleColumnStandardBasicType<LocalDate>
implements LiteralType<LocalDate>, AllowableTemporalParameterType {
implements LiteralType<LocalDate>, AllowableTemporalParameterType<LocalDate> {
/**
* Singleton access

View File

@ -25,7 +25,7 @@ import org.hibernate.type.spi.TypeConfiguration;
*/
public class LocalTimeType
extends AbstractSingleColumnStandardBasicType<LocalTime>
implements LiteralType<LocalTime>, AllowableTemporalParameterType {
implements LiteralType<LocalTime>, AllowableTemporalParameterType<LocalTime> {
/**
* Singleton access
*/

View File

@ -7,8 +7,13 @@
package org.hibernate.type;
import java.sql.CallableStatement;
import java.sql.SQLException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.type.descriptor.java.JavaObjectTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
/**
* Specific adaptation of the "any" type to the old deprecated "object" type
@ -45,4 +50,30 @@ public class ObjectType extends AnyType implements BasicType {
public String[] getRegistrationKeys() {
return new String[] { getName(), Object.class.getName() };
}
@Override
public boolean canDoExtraction() {
return false;
}
@Override
public Object extract(
CallableStatement statement,
String paramName,
SharedSessionContractImplementor session) throws SQLException {
throw new UnsupportedOperationException( "Cannot extract ANY-valued data from CallableStatements" );
}
@Override
public Object extract(
CallableStatement statement,
int paramIndex,
SharedSessionContractImplementor session) throws SQLException {
throw new UnsupportedOperationException( "Cannot extract ANY-valued data from CallableStatements" );
}
@Override
public SqlTypeDescriptor getSqlTypeDescriptor() {
throw new UnsupportedOperationException( "Cannot extract ANY-valued data from CallableStatements" );
}
}

View File

@ -26,7 +26,7 @@ import org.hibernate.type.spi.TypeConfiguration;
*/
public class OffsetDateTimeType
extends AbstractSingleColumnStandardBasicType<OffsetDateTime>
implements VersionType<OffsetDateTime>, LiteralType<OffsetDateTime>, AllowableTemporalParameterType {
implements VersionType<OffsetDateTime>, LiteralType<OffsetDateTime>, AllowableTemporalParameterType<OffsetDateTime> {
/**
* Singleton access
@ -55,7 +55,6 @@ public class OffsetDateTimeType
}
@Override
@SuppressWarnings("unchecked")
public Comparator<OffsetDateTime> getComparator() {
return OffsetDateTime.timeLineOrder();
}
@ -84,6 +83,10 @@ public class OffsetDateTimeType
case DATE: {
return DateType.INSTANCE;
}
default: {
// should never happen, but switch requires this branch so...
throw new QueryException( "OffsetDateTime type cannot be treated using `" + temporalPrecision.name() + "` precision" );
}
}
}
}

View File

@ -24,7 +24,7 @@ import org.hibernate.type.spi.TypeConfiguration;
*/
public class OffsetTimeType
extends AbstractSingleColumnStandardBasicType<OffsetTime>
implements LiteralType<OffsetTime>, AllowableTemporalParameterType {
implements LiteralType<OffsetTime>, AllowableTemporalParameterType<OffsetTime> {
/**
* Singleton access

View File

@ -85,7 +85,7 @@ public class PostgresUUIDType extends AbstractSingleColumnStandardBasicType<UUID
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
@Override
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
protected X doExtract(ResultSet rs, int name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getObject( name ), options );
}

View File

@ -25,7 +25,7 @@ import org.hibernate.type.spi.TypeConfiguration;
*/
public class TimeType
extends AbstractSingleColumnStandardBasicType<Date>
implements LiteralType<Date>, AllowableTemporalParameterType {
implements LiteralType<Date>, AllowableTemporalParameterType<Date> {
public static final TimeType INSTANCE = new TimeType();

View File

@ -29,7 +29,7 @@ import org.hibernate.type.spi.TypeConfiguration;
*/
public class TimestampType
extends AbstractSingleColumnStandardBasicType<Date>
implements VersionType<Date>, LiteralType<Date>, AllowableTemporalParameterType {
implements VersionType<Date>, LiteralType<Date>, AllowableTemporalParameterType<Date> {
public static final TimestampType INSTANCE = new TimestampType();

View File

@ -27,7 +27,7 @@ import org.hibernate.type.spi.TypeConfiguration;
*/
public class ZonedDateTimeType
extends AbstractSingleColumnStandardBasicType<ZonedDateTime>
implements VersionType<ZonedDateTime>, LiteralType<ZonedDateTime>, AllowableTemporalParameterType {
implements VersionType<ZonedDateTime>, LiteralType<ZonedDateTime>, AllowableTemporalParameterType<ZonedDateTime> {
/**
* Singleton access

View File

@ -5,6 +5,7 @@
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.type.descriptor;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.SQLException;

View File

@ -22,19 +22,19 @@ public interface ValueExtractor<X> {
*
* @throws SQLException Indicates a JDBC error occurred.
*/
X extract(ResultSet rs, String name, WrapperOptions options) throws SQLException;
X extract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException;
/**
* Extract value from a callable output parameter by index
*
* @throws SQLException Indicates a JDBC error occurred.
*/
X extract(CallableStatement statement, int index, WrapperOptions options) throws SQLException;
X extract(CallableStatement statement, int paramIndex, WrapperOptions options) throws SQLException;
/**
* Extract value from a callable output parameter by name
*
* @throws SQLException Indicates a JDBC error occurred.
*/
X extract(CallableStatement statement, String[] paramNames, WrapperOptions options) throws SQLException;
X extract(CallableStatement statement, String paramName, WrapperOptions options) throws SQLException;
}

View File

@ -33,6 +33,7 @@ import org.jboss.logging.Logger;
*
* @author Steve Ebersole
*/
@SuppressWarnings("JavadocReference")
public class AttributeConverterSqlTypeDescriptorAdapter implements SqlTypeDescriptor {
private static final Logger log = Logger.getLogger( AttributeConverterSqlTypeDescriptorAdapter.class );
@ -117,21 +118,18 @@ public class AttributeConverterSqlTypeDescriptorAdapter implements SqlTypeDescri
return new ValueExtractor<X>() {
@Override
public X extract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
return doConversion( realExtractor.extract( rs, name, options ) );
public X extract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
return doConversion( realExtractor.extract( rs, paramIndex, options ) );
}
@Override
public X extract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
return doConversion( realExtractor.extract( statement, index, options ) );
public X extract(CallableStatement statement, int paramIndex, WrapperOptions options) throws SQLException {
return doConversion( realExtractor.extract( statement, paramIndex, options ) );
}
@Override
public X extract(CallableStatement statement, String[] paramNames, WrapperOptions options) throws SQLException {
if ( paramNames.length > 1 ) {
throw new IllegalArgumentException( "Basic value extraction cannot handle multiple output parameters" );
}
return doConversion( realExtractor.extract( statement, paramNames, options ) );
public X extract(CallableStatement statement, String paramName, WrapperOptions options) throws SQLException {
return doConversion( realExtractor.extract( statement, paramName, options ) );
}
@SuppressWarnings("unchecked")

View File

@ -6,7 +6,7 @@
*/
package org.hibernate.type.descriptor.java;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.type.descriptor.WrapperOptions;
/**
* @author Steve Ebersole
@ -22,12 +22,13 @@ public class JavaObjectTypeDescriptor extends AbstractTypeDescriptor<Object> {
}
@Override
public <X> X unwrap(Object value, Class<X> type, SharedSessionContractImplementor options) {
public <X> X unwrap(Object value, Class<X> type, WrapperOptions options) {
//noinspection unchecked
return (X) value;
}
@Override
public <X> Object wrap(X value, SharedSessionContractImplementor options) {
public <X> Object wrap(X value, WrapperOptions options) {
return value;
}
}

View File

@ -10,7 +10,6 @@ import java.io.Serializable;
import java.util.Comparator;
import java.util.Objects;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.compare.ComparableComparator;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;

View File

@ -43,13 +43,13 @@ public abstract class BasicExtractor<J> implements ValueExtractor<J> {
}
@Override
public J extract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
final J value = doExtract( rs, name, options );
public J extract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
final J value = doExtract( rs, paramIndex, options );
if ( value == null || rs.wasNull() ) {
if ( log.isTraceEnabled() ) {
log.tracef(
"extracted value ([%s] : [%s]) - [null]",
name,
paramIndex,
JdbcTypeNameMapper.getTypeName( getSqlDescriptor().getSqlType() )
);
}
@ -59,7 +59,7 @@ public abstract class BasicExtractor<J> implements ValueExtractor<J> {
if ( log.isTraceEnabled() ) {
log.tracef(
"extracted value ([%s] : [%s]) - [%s]",
name,
paramIndex,
JdbcTypeNameMapper.getTypeName( getSqlDescriptor().getSqlType() ),
getJavaDescriptor().extractLoggableRepresentation( value )
);
@ -74,24 +74,20 @@ public abstract class BasicExtractor<J> implements ValueExtractor<J> {
* Called from {@link #extract}. Null checking of the value (as well as consulting {@link ResultSet#wasNull}) is
* done there.
*
* @param rs The result set
* @param name The value name in the result set
* @param options The binding options
*
* @return The extracted value.
*
* @throws SQLException Indicates a problem access the result set
*/
protected abstract J doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException;
protected abstract J doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException;
@Override
public J extract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
final J value = doExtract( statement, index, options );
public J extract(CallableStatement statement, int paramIndex, WrapperOptions options) throws SQLException {
final J value = doExtract( statement, paramIndex, options );
if ( value == null || statement.wasNull() ) {
if ( log.isTraceEnabled() ) {
log.tracef(
"extracted procedure output parameter ([%s] : [%s]) - [null]",
index,
paramIndex,
JdbcTypeNameMapper.getTypeName( getSqlDescriptor().getSqlType() )
);
}
@ -101,7 +97,7 @@ public abstract class BasicExtractor<J> implements ValueExtractor<J> {
if ( log.isTraceEnabled() ) {
log.tracef(
"extracted procedure output parameter ([%s] : [%s]) - [%s]",
index,
paramIndex,
JdbcTypeNameMapper.getTypeName( getSqlDescriptor().getSqlType() ),
getJavaDescriptor().extractLoggableRepresentation( value )
);
@ -116,10 +112,6 @@ public abstract class BasicExtractor<J> implements ValueExtractor<J> {
* Called from {@link #extract}. Null checking of the value (as well as consulting {@link ResultSet#wasNull}) is
* done there.
*
* @param statement The callable statement containing the output parameter
* @param index The index (position) of the output parameter
* @param options The binding options
*
* @return The extracted value.
*
* @throws SQLException Indicates a problem accessing the parameter value
@ -127,11 +119,7 @@ public abstract class BasicExtractor<J> implements ValueExtractor<J> {
protected abstract J doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException;
@Override
public J extract(CallableStatement statement, String[] paramNames, WrapperOptions options) throws SQLException {
if ( paramNames.length > 1 ) {
throw new IllegalArgumentException( "Basic value extraction cannot handle multiple output parameters" );
}
final String paramName = paramNames[0];
public J extract(CallableStatement statement, String paramName, WrapperOptions options) throws SQLException {
final J value = doExtract( statement, paramName, options );
if ( value == null || statement.wasNull() ) {
if ( log.isTraceEnabled() ) {

View File

@ -59,8 +59,8 @@ public class BigIntTypeDescriptor implements SqlTypeDescriptor {
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
@Override
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getLong( name ), options );
protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getLong( paramIndex ), options );
}
@Override

View File

@ -60,8 +60,8 @@ public class BitTypeDescriptor implements SqlTypeDescriptor {
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
@Override
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getBoolean( name ), options );
protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getBoolean( paramIndex ), options );
}
@Override

View File

@ -44,8 +44,8 @@ public abstract class BlobTypeDescriptor implements SqlTypeDescriptor {
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
@Override
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getBlob( name ), options );
protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getBlob( paramIndex ), options );
}
@Override

View File

@ -55,8 +55,8 @@ public class BooleanTypeDescriptor implements SqlTypeDescriptor {
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
@Override
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getBoolean( name ), options );
protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getBoolean( paramIndex ), options );
}
@Override

View File

@ -40,8 +40,8 @@ public abstract class ClobTypeDescriptor implements SqlTypeDescriptor {
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
@Override
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getClob( name ), options );
protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getClob( paramIndex ), options );
}
@Override
@ -175,8 +175,8 @@ public abstract class ClobTypeDescriptor implements SqlTypeDescriptor {
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
@Override
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getCharacterStream( name ), options );
protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getCharacterStream( paramIndex ), options );
}
@Override

View File

@ -72,8 +72,8 @@ public class DateTypeDescriptor implements SqlTypeDescriptor {
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
@Override
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getDate( name ), options );
protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getDate( paramIndex ), options );
}
@Override

Some files were not shown because too many files have changed in this diff Show More