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:
parent
f8a75994e1
commit
d0116d7caa
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,14 +37,9 @@ 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;
|
||||
private Map<String, TypedValue> namedParameters;
|
||||
|
||||
private LockOptions lockOptions;
|
||||
private RowSelection rowSelection;
|
||||
|
@ -109,7 +103,7 @@ public final class QueryParameters {
|
|||
public QueryParameters(
|
||||
final Type[] positionalParameterTypes,
|
||||
final Object[] positionalParameterValues,
|
||||
final Map<String,TypedValue> namedParameters,
|
||||
final Map<String, TypedValue> namedParameters,
|
||||
final Serializable[] collectionKeys) {
|
||||
this(
|
||||
positionalParameterTypes,
|
||||
|
@ -163,7 +157,7 @@ public final class QueryParameters {
|
|||
public QueryParameters(
|
||||
final Type[] positionalParameterTypes,
|
||||
final Object[] positionalParameterValues,
|
||||
final Map<String,TypedValue> namedParameters,
|
||||
final Map<String, TypedValue> namedParameters,
|
||||
final LockOptions lockOptions,
|
||||
final RowSelection rowSelection,
|
||||
final boolean isReadOnlyInitialized,
|
||||
|
@ -194,7 +188,7 @@ public final class QueryParameters {
|
|||
public QueryParameters(
|
||||
final Type[] positionalParameterTypes,
|
||||
final Object[] positionalParameterValues,
|
||||
final Map<String,TypedValue> namedParameters,
|
||||
final Map<String, TypedValue> namedParameters,
|
||||
final LockOptions lockOptions,
|
||||
final RowSelection rowSelection,
|
||||
final boolean isReadOnlyInitialized,
|
||||
|
@ -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,
|
||||
|
@ -270,7 +264,7 @@ public final class QueryParameters {
|
|||
return rowSelection != null;
|
||||
}
|
||||
|
||||
public Map<String,TypedValue> getNamedParameters() {
|
||||
public Map<String, TypedValue> getNamedParameters() {
|
||||
return namedParameters;
|
||||
}
|
||||
|
||||
|
@ -291,7 +285,7 @@ public final class QueryParameters {
|
|||
}
|
||||
|
||||
@SuppressWarnings( {"UnusedDeclaration"})
|
||||
public void setNamedParameters(Map<String,TypedValue> map) {
|
||||
public void setNamedParameters(Map<String, TypedValue> map) {
|
||||
namedParameters = map;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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() );
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
|
@ -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>
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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> {
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 {
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 {
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() ) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue