6 - SQM based on JPA type system

Fix compilation errors, imports, and amend deleted files after rebasing.
This commit is contained in:
Sanne Grinovero 2019-08-30 13:40:14 +01:00 committed by Andrea Boriero
parent 5aea8bcf6a
commit fffc9e7786
28 changed files with 11 additions and 4705 deletions

View File

@ -32,10 +32,6 @@ import org.hibernate.dialect.unique.UniqueDelegate;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.exception.LockTimeoutException;
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
import org.hibernate.hql.spi.id.IdTableSupportStandardImpl;
import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
import org.hibernate.hql.spi.id.local.AfterUseAction;
import org.hibernate.hql.spi.id.local.LocalTemporaryTableBulkIdStrategy;
import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;

View File

@ -29,7 +29,6 @@ import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.LockMode;
@ -37,7 +36,6 @@ import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.NullPrecedence;
import org.hibernate.Query;
import org.hibernate.ScrollMode;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;

View File

@ -1,448 +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.engine.query.spi;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.hibernate.Filter;
import org.hibernate.MappingException;
import org.hibernate.QueryException;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.FilterImpl;
import org.hibernate.internal.util.collections.BoundedConcurrentHashMap;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.query.ParameterMetadata;
import org.hibernate.query.internal.ParameterMetadataImpl;
import org.hibernate.stat.spi.StatisticsImplementor;
/**
* Acts as a cache for compiled query plans, as well as query-parameter metadata.
*
* @see Environment#QUERY_PLAN_CACHE_PARAMETER_METADATA_MAX_SIZE
* @see Environment#QUERY_PLAN_CACHE_MAX_SIZE
*
* @author Steve Ebersole
*/
public class QueryPlanCache implements Serializable {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( QueryPlanCache.class );
/**
* The default strong reference count.
*/
public static final int DEFAULT_PARAMETER_METADATA_MAX_COUNT = 128;
/**
* The default soft reference count.
*/
public static final int DEFAULT_QUERY_PLAN_MAX_COUNT = 2048;
private final SessionFactoryImplementor factory;
/**
* the cache of the actual plans...
*/
private final BoundedConcurrentHashMap queryPlanCache;
/**
* simple cache of param metadata based on query string. Ideally, the original "user-supplied query"
* string should be used to obtain this metadata (i.e., not the para-list-expanded query string) to avoid
* unnecessary cache entries.
* <p></p>
* Used solely for caching param metadata for native-sql queries, see {@link #getSQLParameterMetadata} for a
* discussion as to why...
*/
private final BoundedConcurrentHashMap<ParameterMetadataKey,ParameterMetadataImpl> parameterMetadataCache;
private NativeQueryInterpreter nativeQueryInterpreter;
/**
* Constructs the QueryPlanCache to be used by the given SessionFactory
*
* @param factory The SessionFactory
*/
@SuppressWarnings("deprecation")
public QueryPlanCache(final SessionFactoryImplementor factory) {
this.factory = factory;
Integer maxParameterMetadataCount = ConfigurationHelper.getInteger(
Environment.QUERY_PLAN_CACHE_PARAMETER_METADATA_MAX_SIZE,
factory.getProperties()
);
if ( maxParameterMetadataCount == null ) {
maxParameterMetadataCount = ConfigurationHelper.getInt(
Environment.QUERY_PLAN_CACHE_MAX_STRONG_REFERENCES,
factory.getProperties(),
DEFAULT_PARAMETER_METADATA_MAX_COUNT
);
}
Integer maxQueryPlanCount = ConfigurationHelper.getInteger(
Environment.QUERY_PLAN_CACHE_MAX_SIZE,
factory.getProperties()
);
if ( maxQueryPlanCount == null ) {
maxQueryPlanCount = ConfigurationHelper.getInt(
Environment.QUERY_PLAN_CACHE_MAX_SOFT_REFERENCES,
factory.getProperties(),
DEFAULT_QUERY_PLAN_MAX_COUNT
);
}
queryPlanCache = new BoundedConcurrentHashMap( maxQueryPlanCount, 20, BoundedConcurrentHashMap.Eviction.LIRS );
parameterMetadataCache = new BoundedConcurrentHashMap<>(
maxParameterMetadataCount,
20,
BoundedConcurrentHashMap.Eviction.LIRS
);
nativeQueryInterpreter = factory.getServiceRegistry().getService( NativeQueryInterpreter.class );
}
/**
* Obtain the parameter metadata for given native-sql query.
* <p/>
* for native-sql queries, the param metadata is determined outside any relation to a query plan, because
* query plan creation and/or retrieval for a native-sql query depends on all of the return types having been
* set, which might not be the case up-front when param metadata would be most useful
*
* @param query The query
* @return The parameter metadata
*/
public ParameterMetadata getSQLParameterMetadata(final String query, boolean isOrdinalParameterZeroBased) {
final ParameterMetadataKey key = new ParameterMetadataKey( query, isOrdinalParameterZeroBased );
return parameterMetadataCache.computeIfAbsent( key, k -> nativeQueryInterpreter.getParameterMetadata( query ) );
}
/**
* Get the query plan for the given HQL query, creating it and caching it if not already cached
*
* @param queryString The HQL query string
* @param shallow Whether the execution will be shallow
* @param enabledFilters The filters enabled on the Session
*
* @return The query plan
*
* @throws QueryException Indicates a problem translating the query
* @throws MappingException Indicates a problem translating the query
*/
@SuppressWarnings("unchecked")
public HQLQueryPlan getHQLQueryPlan(String queryString, boolean shallow, Map<String, Filter> enabledFilters)
throws QueryException, MappingException {
final HQLQueryPlanKey key = new HQLQueryPlanKey( queryString, shallow, enabledFilters );
HQLQueryPlan value = (HQLQueryPlan) queryPlanCache.get( key );
final StatisticsImplementor statistics = factory.getStatistics();
boolean stats = statistics.isStatisticsEnabled();
if ( value == null ) {
final long startTime = ( stats ) ? System.nanoTime() : 0L;
LOG.tracev( "Unable to locate HQL query plan in cache; generating ({0})", queryString );
value = new HQLQueryPlan( queryString, shallow, enabledFilters, factory );
if ( stats ) {
final long endTime = System.nanoTime();
final long microseconds = TimeUnit.MICROSECONDS.convert( endTime - startTime, TimeUnit.NANOSECONDS );
statistics.queryCompiled( queryString, microseconds );
}
queryPlanCache.putIfAbsent( key, value );
}
else {
LOG.tracev( "Located HQL query plan in cache ({0})", queryString );
if ( stats ) {
statistics.queryPlanCacheHit( queryString );
}
}
return value;
}
/**
* Get the query plan for the given collection HQL filter fragment, creating it and caching it if not already cached
*
* @param filterString The HQL filter fragment
* @param collectionRole The collection being filtered
* @param shallow Whether the execution will be shallow
* @param enabledFilters The filters enabled on the Session
*
* @return The query plan
*
* @throws QueryException Indicates a problem translating the query
* @throws MappingException Indicates a problem translating the query
*/
@SuppressWarnings("unchecked")
public FilterQueryPlan getFilterQueryPlan(
String filterString,
String collectionRole,
boolean shallow,
Map<String,Filter> enabledFilters) throws QueryException, MappingException {
final FilterQueryPlanKey key = new FilterQueryPlanKey( filterString, collectionRole, shallow, enabledFilters );
FilterQueryPlan value = (FilterQueryPlan) queryPlanCache.get( key );
if ( value == null ) {
LOG.tracev(
"Unable to locate collection-filter query plan in cache; generating ({0} : {1} )",
collectionRole,
filterString
);
value = new FilterQueryPlan( filterString, collectionRole, shallow, enabledFilters,factory );
queryPlanCache.putIfAbsent( key, value );
}
else {
LOG.tracev( "Located collection-filter query plan in cache ({0} : {1})", collectionRole, filterString );
}
return value;
}
/**
* Get the query plan for a native SQL query, creating it and caching it if not already cached
*
* @param spec The native SQL query specification
*
* @return The query plan
*
* @throws QueryException Indicates a problem translating the query
* @throws MappingException Indicates a problem translating the query
*/
@SuppressWarnings("unchecked")
public NativeSQLQueryPlan getNativeSQLQueryPlan(final NativeSQLQuerySpecification spec) {
NativeSQLQueryPlan value = (NativeSQLQueryPlan) queryPlanCache.get( spec );
if ( value == null ) {
LOG.tracev( "Unable to locate native-sql query plan in cache; generating ({0})", spec.getQueryString() );
value = nativeQueryInterpreter.createQueryPlan( spec, factory );
queryPlanCache.putIfAbsent( spec, value );
}
else {
LOG.tracev( "Located native-sql query plan in cache ({0})", spec.getQueryString() );
}
return value;
}
/**
* Clean up the caches when the SessionFactory is closed.
* <p>
* Note that depending on the cache strategy implementation chosen, clearing the cache might not reclaim all the
* memory.
* <p>
* Typically, when using LIRS, clearing the cache only invalidates the entries but the outdated entries are kept in
* memory until they are replaced by others. It is not considered a memory leak as the cache is bounded.
*/
public void cleanup() {
LOG.trace( "Cleaning QueryPlan Cache" );
queryPlanCache.clear();
parameterMetadataCache.clear();
}
public NativeQueryInterpreter getNativeQueryInterpreter() {
return nativeQueryInterpreter;
}
private static class ParameterMetadataKey implements Serializable {
private final String query;
private final boolean isOrdinalParameterZeroBased;
private final int hashCode;
public ParameterMetadataKey(String query, boolean isOrdinalParameterZeroBased) {
this.query = query;
this.isOrdinalParameterZeroBased = isOrdinalParameterZeroBased;
int hash = query.hashCode();
hash = 29 * hash + ( isOrdinalParameterZeroBased ? 1 : 0 );
this.hashCode = hash;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
final ParameterMetadataKey that = (ParameterMetadataKey) o;
return isOrdinalParameterZeroBased == that.isOrdinalParameterZeroBased
&& query.equals( that.query );
}
@Override
public int hashCode() {
return hashCode;
}
}
private static class HQLQueryPlanKey implements Serializable {
private final String query;
private final boolean shallow;
private final Set<DynamicFilterKey> filterKeys;
private final int hashCode;
public HQLQueryPlanKey(String query, boolean shallow, Map enabledFilters) {
this.query = query;
this.shallow = shallow;
if ( CollectionHelper.isEmpty( enabledFilters ) ) {
filterKeys = Collections.emptySet();
}
else {
final Set<DynamicFilterKey> tmp = new HashSet<DynamicFilterKey>(
CollectionHelper.determineProperSizing( enabledFilters ),
CollectionHelper.LOAD_FACTOR
);
for ( Object o : enabledFilters.values() ) {
tmp.add( new DynamicFilterKey( (FilterImpl) o ) );
}
this.filterKeys = Collections.unmodifiableSet( tmp );
}
int hash = query.hashCode();
hash = 29 * hash + ( shallow ? 1 : 0 );
hash = 29 * hash + filterKeys.hashCode();
this.hashCode = hash;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
final HQLQueryPlanKey that = (HQLQueryPlanKey) o;
return shallow == that.shallow
&& filterKeys.equals( that.filterKeys )
&& query.equals( that.query );
}
@Override
public int hashCode() {
return hashCode;
}
}
private static class DynamicFilterKey implements Serializable {
private final String filterName;
private final Map<String,Integer> parameterMetadata;
private final int hashCode;
private DynamicFilterKey(FilterImpl filter) {
this.filterName = filter.getName();
final Map<String, ?> parameters = filter.getParameters();
if ( parameters.isEmpty() ) {
parameterMetadata = Collections.emptyMap();
}
else {
parameterMetadata = new HashMap<String,Integer>(
CollectionHelper.determineProperSizing( parameters ),
CollectionHelper.LOAD_FACTOR
);
for ( Object o : parameters.entrySet() ) {
final Map.Entry entry = (Map.Entry) o;
final String key = (String) entry.getKey();
final Integer valueCount;
if ( Collection.class.isInstance( entry.getValue() ) ) {
valueCount = ( (Collection) entry.getValue() ).size();
}
else {
valueCount = 1;
}
parameterMetadata.put( key, valueCount );
}
}
int hash = filterName.hashCode();
hash = 31 * hash + parameterMetadata.hashCode();
this.hashCode = hash;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
final DynamicFilterKey that = (DynamicFilterKey) o;
return filterName.equals( that.filterName )
&& parameterMetadata.equals( that.parameterMetadata );
}
@Override
public int hashCode() {
return hashCode;
}
}
private static class FilterQueryPlanKey implements Serializable {
private final String query;
private final String collectionRole;
private final boolean shallow;
private final Set<String> filterNames;
private final int hashCode;
@SuppressWarnings({ "unchecked" })
public FilterQueryPlanKey(String query, String collectionRole, boolean shallow, Map enabledFilters) {
this.query = query;
this.collectionRole = collectionRole;
this.shallow = shallow;
if ( CollectionHelper.isEmpty( enabledFilters ) ) {
this.filterNames = Collections.emptySet();
}
else {
final Set<String> tmp = new HashSet<String>( enabledFilters.keySet() );
this.filterNames = Collections.unmodifiableSet( tmp );
}
int hash = query.hashCode();
hash = 29 * hash + collectionRole.hashCode();
hash = 29 * hash + ( shallow ? 1 : 0 );
hash = 29 * hash + filterNames.hashCode();
this.hashCode = hash;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
final FilterQueryPlanKey that = (FilterQueryPlanKey) o;
return shallow == that.shallow
&& filterNames.equals( that.filterNames )
&& query.equals( that.query )
&& collectionRole.equals( that.collectionRole );
}
@Override
public int hashCode() {
return hashCode;
}
}
}

View File

@ -174,7 +174,7 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
final Object result = source.getLoadQueryInfluencers().fromInternalFetchProfile(
InternalFetchProfile.REFRESH,
() -> doRefresh( event, source, object, e, persister, id )
() -> doRefresh( event, source, object, e, persister, id, persistenceContext )
);
UnresolvableObjectException.throwIfNull( result, id, persister.getEntityName() );
@ -187,7 +187,8 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
Object object,
EntityEntry e,
EntityPersister persister,
Serializable id) {
Serializable id,
PersistenceContext persistenceContext) {
// Handle the requested lock-mode (if one) in relation to the entry's (if one) current lock-mode

View File

@ -1,143 +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.hql.internal.ast.tree;
import java.util.Map;
import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes;
import org.hibernate.hql.internal.ast.util.ColumnHelper;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.CollectionType;
import org.hibernate.type.Type;
import antlr.SemanticException;
import antlr.collections.AST;
/**
* Basic support for KEY, VALUE and ENTRY based "qualified identification variables".
*
* @author Steve Ebersole
*/
public abstract class AbstractMapComponentNode extends FromReferenceNode implements HqlSqlTokenTypes {
private FromElement mapFromElement;
private String[] columns;
public FromReferenceNode getMapReference() {
return (FromReferenceNode) getFirstChild();
}
public String[] getColumns() {
return columns;
}
@Override
public void setScalarColumnText(int i) {
ColumnHelper.generateScalarColumns( this, getColumns(), i );
}
@Override
public void resolve(
boolean generateJoin,
boolean implicitJoin,
String classAlias,
AST parent,
AST parentPredicate) throws SemanticException {
if ( mapFromElement == null ) {
final FromReferenceNode mapReference = getMapReference();
mapReference.resolve( true, true );
FromElement sourceFromElement = null;
if ( isAliasRef( mapReference ) ) {
final QueryableCollection collectionPersister = mapReference.getFromElement().getQueryableCollection();
if ( Map.class.isAssignableFrom( collectionPersister.getCollectionType().getReturnedClass() ) ) {
sourceFromElement = mapReference.getFromElement();
}
}
else {
if ( mapReference.getDataType().isCollectionType() ) {
final CollectionType collectionType = (CollectionType) mapReference.getDataType();
if ( Map.class.isAssignableFrom( collectionType.getReturnedClass() ) ) {
sourceFromElement = mapReference.getFromElement();
}
}
}
if ( sourceFromElement == null ) {
throw nonMap();
}
mapFromElement = sourceFromElement;
}
setFromElement( mapFromElement );
setDataType( resolveType( mapFromElement.getQueryableCollection() ) );
this.columns = resolveColumns( mapFromElement.getQueryableCollection() );
initText( this.columns );
setFirstChild( null );
}
public FromElement getMapFromElement() {
return mapFromElement;
}
private boolean isAliasRef(FromReferenceNode mapReference) {
return ALIAS_REF == mapReference.getType();
}
private void initText(String[] columns) {
String text = String.join( ", ", columns );
if ( columns.length > 1 && getWalker().isComparativeExpressionClause() ) {
text = "(" + text + ")";
}
setText( text );
}
protected abstract String expressionDescription();
protected abstract String[] resolveColumns(QueryableCollection collectionPersister);
protected abstract Type resolveType(QueryableCollection collectionPersister);
protected SemanticException nonMap() {
return new SemanticException( expressionDescription() + " expression did not reference map property" );
}
@Override
public void resolveIndex(AST parent) {
throw new UnsupportedOperationException( expressionDescription() + " expression cannot be the source for an index operation" );
}
protected MapKeyEntityFromElement findOrAddMapKeyEntityFromElement(QueryableCollection collectionPersister) {
if ( !collectionPersister.getIndexType().isEntityType() ) {
return null;
}
for ( FromElement destination : getFromElement().getDestinations() ) {
if ( destination instanceof MapKeyEntityFromElement ) {
return (MapKeyEntityFromElement) destination;
}
}
return MapKeyEntityFromElement.buildKeyJoin( getFromElement() );
}
@Override
public String[] getReferencedTables() {
String[] referencedTables = null;
FromElement fromElement = getFromElement();
if ( fromElement != null ) {
EntityPersister entityPersister = fromElement.getEntityPersister();
if ( entityPersister != null && entityPersister instanceof AbstractEntityPersister ) {
AbstractEntityPersister abstractEntityPersister = (AbstractEntityPersister) entityPersister;
referencedTables = abstractEntityPersister.getTableNames();
}
}
return referencedTables;
}
}

View File

@ -1,217 +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.hql.internal.ast.tree;
import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes;
import org.hibernate.hql.internal.ast.util.ColumnHelper;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.Type;
import antlr.SemanticException;
/**
* Nodes which represent binary arithmetic operators.
*
* @author Gavin King
*/
public class BinaryArithmeticOperatorNode extends AbstractSelectExpression
implements BinaryOperatorNode, DisplayableNode {
@Override
public void initialize() throws SemanticException {
final Node lhs = getLeftHandOperand();
if ( lhs == null ) {
throw new SemanticException( "left-hand operand of a binary operator was null" );
}
final Node rhs = getRightHandOperand();
if ( rhs == null ) {
throw new SemanticException( "right-hand operand of a binary operator was null" );
}
final Type lhType = ( lhs instanceof SqlNode ) ? ( (SqlNode) lhs ).getDataType() : null;
final Type rhType = ( rhs instanceof SqlNode ) ? ( (SqlNode) rhs ).getDataType() : null;
if ( ExpectedTypeAwareNode.class.isAssignableFrom( lhs.getClass() ) && rhType != null ) {
final Type expectedType;
// we have something like : "? [op] rhs"
if ( isDateTimeType( rhType ) ) {
// more specifically : "? [op] datetime"
// 1) if the operator is MINUS, the param needs to be of
// some datetime type
// 2) if the operator is PLUS, the param needs to be of
// some numeric type
expectedType = getType() == HqlSqlTokenTypes.PLUS ? StandardBasicTypes.DOUBLE : rhType;
}
else {
expectedType = rhType;
}
( (ExpectedTypeAwareNode) lhs ).setExpectedType( expectedType );
}
else if ( ParameterNode.class.isAssignableFrom( rhs.getClass() ) && lhType != null ) {
Type expectedType = null;
// we have something like : "lhs [op] ?"
if ( isDateTimeType( lhType ) ) {
// more specifically : "datetime [op] ?"
// 1) if the operator is MINUS, we really cannot determine
// the expected type as either another datetime or
// numeric would be valid
// 2) if the operator is PLUS, the param needs to be of
// some numeric type
if ( getType() == HqlSqlTokenTypes.PLUS ) {
expectedType = StandardBasicTypes.DOUBLE;
}
}
else {
expectedType = lhType;
}
( (ExpectedTypeAwareNode) rhs ).setExpectedType( expectedType );
}
}
/**
* Figure out the type of the binary expression by looking at
* the types of the operands. Sometimes we don't know both types,
* if, for example, one is a parameter.
*/
@Override
public Type getDataType() {
if ( super.getDataType() == null ) {
super.setDataType( resolveDataType() );
}
return super.getDataType();
}
private Type resolveDataType() {
// TODO : we may also want to check that the types here map to exactly one column/JDBC-type
// can't think of a situation where arithmetic expression between multi-column mappings
// makes any sense.
final Node lhs = getLeftHandOperand();
final Node rhs = getRightHandOperand();
final Type lhType = ( lhs instanceof SqlNode ) ? ( (SqlNode) lhs ).getDataType() : null;
final Type rhType = ( rhs instanceof SqlNode ) ? ( (SqlNode) rhs ).getDataType() : null;
if ( isDateTimeType( lhType ) || isDateTimeType( rhType ) ) {
return resolveDateTimeArithmeticResultType( lhType, rhType );
}
else {
if ( lhType == null ) {
if ( rhType == null ) {
// we do not know either type
// BLIND GUESS!
return StandardBasicTypes.DOUBLE;
}
else {
// we know only the rhs-hand type, so use that
return rhType;
}
}
else {
if ( rhType == null ) {
// we know only the lhs-hand type, so use that
return lhType;
}
else {
if ( lhType == StandardBasicTypes.DOUBLE || rhType == StandardBasicTypes.DOUBLE ) {
return StandardBasicTypes.DOUBLE;
}
if ( lhType == StandardBasicTypes.FLOAT || rhType == StandardBasicTypes.FLOAT ) {
return StandardBasicTypes.FLOAT;
}
if ( lhType == StandardBasicTypes.BIG_DECIMAL || rhType == StandardBasicTypes.BIG_DECIMAL ) {
return StandardBasicTypes.BIG_DECIMAL;
}
if ( lhType == StandardBasicTypes.BIG_INTEGER || rhType == StandardBasicTypes.BIG_INTEGER ) {
return StandardBasicTypes.BIG_INTEGER;
}
if ( lhType == StandardBasicTypes.LONG || rhType == StandardBasicTypes.LONG ) {
return StandardBasicTypes.LONG;
}
if ( lhType == StandardBasicTypes.INTEGER || rhType == StandardBasicTypes.INTEGER ) {
return StandardBasicTypes.INTEGER;
}
return lhType;
}
}
}
}
private boolean isDateTimeType(Type type) {
return type != null
&& ( java.util.Date.class.isAssignableFrom( type.getReturnedClass() )
|| java.util.Calendar.class.isAssignableFrom( type.getReturnedClass() ) );
}
private Type resolveDateTimeArithmeticResultType(Type lhType, Type rhType) {
// here, we work under the following assumptions:
// ------------ valid cases --------------------------------------
// 1) datetime + {something other than datetime} : always results
// in a datetime ( db will catch invalid conversions )
// 2) datetime - datetime : always results in a DOUBLE
// 3) datetime - {something other than datetime} : always results
// in a datetime ( db will catch invalid conversions )
// ------------ invalid cases ------------------------------------
// 4) datetime + datetime
// 5) {something other than datetime} - datetime
// 6) datetime * {any type}
// 7) datetime / {any type}
// 8) {any type} / datetime
// doing so allows us to properly handle parameters as either the left
// or right side here in the majority of cases
boolean lhsIsDateTime = isDateTimeType( lhType );
boolean rhsIsDateTime = isDateTimeType( rhType );
// handle the (assumed) valid cases:
// #1 - the only valid datetime addition synatx is one or the other is a datetime (but not both)
if ( getType() == HqlSqlTokenTypes.PLUS ) {
// one or the other needs to be a datetime for us to get into this method in the first place...
return lhsIsDateTime ? lhType : rhType;
}
else if ( getType() == HqlSqlTokenTypes.MINUS ) {
// #3 - note that this is also true of "datetime - :param"...
if ( lhsIsDateTime && !rhsIsDateTime ) {
return lhType;
}
// #2
if ( lhsIsDateTime && rhsIsDateTime ) {
return StandardBasicTypes.DOUBLE;
}
}
return null;
}
@Override
public void setScalarColumnText(int i) throws SemanticException {
ColumnHelper.generateSingleScalarColumn( this, i );
}
/**
* Retrieves the left-hand operand of the operator.
*
* @return The left-hand operand
*/
@Override
public Node getLeftHandOperand() {
return (Node) getFirstChild();
}
/**
* Retrieves the right-hand operand of the operator.
*
* @return The right-hand operand
*/
@Override
public Node getRightHandOperand() {
return (Node) getFirstChild().getNextSibling();
}
@Override
public String getDisplayText() {
return "{dataType=" + getDataType() + "}";
}
}

View File

@ -1,730 +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.hql.internal.ast.tree;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.hibernate.QueryException;
import org.hibernate.engine.internal.JoinSequence;
import org.hibernate.hql.internal.CollectionProperties;
import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes;
import org.hibernate.hql.internal.antlr.SqlTokenTypes;
import org.hibernate.hql.internal.ast.TypeDiscriminatorMetadata;
import org.hibernate.hql.internal.ast.util.ASTUtil;
import org.hibernate.hql.spi.QueryTranslator;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.param.DynamicFilterParameterSpecification;
import org.hibernate.param.ParameterSpecification;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.DiscriminatorMetadata;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.PropertyMapping;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
/**
* Represents a single mapped class mentioned in an HQL FROM clause. Each
* class reference will have the following symbols:
* <ul>
* <li>A class name - This is the name of the Java class that is mapped by Hibernate.</li>
* <li>[optional] an HQL alias for the mapped class.</li>
* <li>A table name - The name of the table that is mapped to the Java class.</li>
* <li>A table alias - The alias for the table that will be used in the resulting SQL.</li>
* </ul>
*
* @author josh
*/
public class FromElement extends HqlSqlWalkerNode implements DisplayableNode, ParameterContainer {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( FromElement.class );
private String className;
private String classAlias;
private String tableAlias;
private String collectionTableAlias;
private FromClause fromClause;
private boolean includeSubclasses = true;
private boolean collectionJoin;
private FromElement origin;
private String[] columns;
private String role;
private boolean fetch;
private boolean isAllPropertyFetch;
private boolean filter;
private int sequence = -1;
private boolean useFromFragment;
private boolean initialized;
private FromElementType elementType;
private boolean useWhereFragment = true;
private List<FromElement> destinations;
private boolean manyToMany;
private String withClauseFragment;
private boolean dereferencedBySuperclassProperty;
private boolean dereferencedBySubclassProperty;
public FromElement() {
}
/**
* Constructor form used to initialize {@link ComponentJoin}
*
* @param fromClause The FROM clause to which this element belongs
* @param origin The origin (LHS) of this element
* @param alias The alias applied to this element
*/
protected FromElement(
FromClause fromClause,
FromElement origin,
String alias) {
this.fromClause = fromClause;
this.origin = origin;
this.classAlias = alias;
this.tableAlias = origin.getTableAlias();
super.initialize( fromClause.getWalker() );
}
protected void initializeComponentJoin(FromElementType elementType) {
fromClause.registerFromElement( this );
elementType.applyTreatAsDeclarations( getWalker().getTreatAsDeclarationsByPath( classAlias ) );
this.elementType = elementType;
initialized = true;
}
public String getCollectionSuffix() {
return elementType.getCollectionSuffix();
}
public void setCollectionSuffix(String suffix) {
elementType.setCollectionSuffix(suffix);
}
public void initializeCollection(FromClause fromClause, String classAlias, String tableAlias) {
doInitialize( fromClause, tableAlias, null, classAlias, null, null );
initialized = true;
}
public void initializeEntity(
FromClause fromClause,
String className,
EntityPersister persister,
EntityType type,
String classAlias,
String tableAlias) {
doInitialize( fromClause, tableAlias, className, classAlias, persister, type );
this.sequence = fromClause.nextFromElementCounter();
initialized = true;
}
protected void doInitialize(
FromClause fromClause,
String tableAlias,
String className,
String classAlias,
EntityPersister persister,
EntityType type) {
if ( initialized ) {
throw new IllegalStateException( "Already initialized!!" );
}
this.fromClause = fromClause;
this.tableAlias = tableAlias;
this.className = className;
this.classAlias = classAlias;
this.elementType = new FromElementType( this, persister, type );
// Register the FromElement with the FROM clause, now that we have the names and aliases.
fromClause.registerFromElement( this );
LOG.debugf( "%s : %s (%s) -> %s", fromClause, className, classAlias == null ? "<no alias>" : classAlias, tableAlias );
}
public EntityPersister getEntityPersister() {
return elementType.getEntityPersister();
}
@Override
public Type getDataType() {
return elementType.getDataType();
}
public Type getSelectType() {
return elementType.getSelectType();
}
public Queryable getQueryable() {
return elementType.getQueryable();
}
public String getClassName() {
return className;
}
public String getClassAlias() {
return classAlias;
//return classAlias == null ? className : classAlias;
}
public String getTableName() {
Queryable queryable = getQueryable();
return ( queryable != null ) ? queryable.getTableName() : "{none}";
}
public String getTableAlias() {
return tableAlias;
}
/**
* Render the identifier select, but in a 'scalar' context (i.e. generate the column alias).
*
* @param i the sequence of the returned type
* @return the identifier select with the column alias.
*/
String renderScalarIdentifierSelect(int i) {
return elementType.renderScalarIdentifierSelect( i );
}
void checkInitialized() {
if ( !initialized ) {
throw new IllegalStateException( "FromElement has not been initialized!" );
}
}
/**
* Returns the identifier select SQL fragment.
*
* @param size The total number of returned types.
* @param k The sequence of the current returned type.
* @return the identifier select SQL fragment.
*/
String renderIdentifierSelect(int size, int k) {
return elementType.renderIdentifierSelect( size, k );
}
/**
* Returns the property select SQL fragment.
*
* @param size The total number of returned types.
* @param k The sequence of the current returned type.
* @return the property select SQL fragment.
*/
String renderPropertySelect(int size, int k) {
return elementType.renderPropertySelect( size, k, isAllPropertyFetch );
}
public String renderMapKeyPropertySelectFragment(int size, int k) {
return elementType.renderMapKeyPropertySelectFragment( size, k );
}
public String renderMapEntryPropertySelectFragment(int size, int k) {
return elementType.renderMapEntryPropertySelectFragment( size, k );
}
String renderCollectionSelectFragment(int size, int k) {
return elementType.renderCollectionSelectFragment( size, k );
}
String renderValueCollectionSelectFragment(int size, int k) {
return elementType.renderValueCollectionSelectFragment( size, k );
}
public FromClause getFromClause() {
return fromClause;
}
/**
* Returns true if this FromElement was implied by a path, or false if this FROM element is explicitly declared in
* the FROM clause.
*
* @return true if this FromElement was implied by a path, or false if this FROM element is explicitly declared
*/
public boolean isImplied() {
return false; // This is an explicit FROM element.
}
/**
* Returns additional display text for the AST node.
*
* @return String - The additional display text.
*/
public String getDisplayText() {
StringBuilder buf = new StringBuilder();
buf.append( "FromElement{" );
appendDisplayText( buf );
buf.append( "}" );
return buf.toString();
}
protected void appendDisplayText(StringBuilder buf) {
buf.append( isImplied() ? (
isImpliedInFromClause() ? "implied in FROM clause" : "implied" )
: "explicit" );
buf.append( "," ).append( isCollectionJoin() ? "collection join" : "not a collection join" );
buf.append( "," ).append( fetch ? "fetch join" : "not a fetch join" );
buf.append( "," ).append( isAllPropertyFetch ? "fetch all properties" : "fetch non-lazy properties" );
buf.append( ",classAlias=" ).append( getClassAlias() );
buf.append( ",role=" ).append( role );
buf.append( ",tableName=" ).append( getTableName() );
buf.append( ",tableAlias=" ).append( getTableAlias() );
FromElement origin = getRealOrigin();
buf.append( ",origin=" ).append( origin == null ? "null" : origin.getText() );
buf.append( ",columns={" );
if ( columns != null ) {
for ( int i = 0; i < columns.length; i++ ) {
buf.append( columns[i] );
if ( i < columns.length - 1 ) {
buf.append( " " );
}
}
}
buf.append( ",className=" ).append( className );
buf.append( "}" );
}
@Override
public int hashCode() {
return super.hashCode();
}
@Override
public boolean equals(Object obj) {
return super.equals( obj );
}
public void setJoinSequence(JoinSequence joinSequence) {
elementType.setJoinSequence( joinSequence );
}
public JoinSequence getJoinSequence() {
return elementType.getJoinSequence();
}
public void setIncludeSubclasses(boolean includeSubclasses) {
if ( !includeSubclasses && isDereferencedBySuperclassOrSubclassProperty() && LOG.isTraceEnabled() ) {
LOG.trace( "Attempt to disable subclass-inclusions : ", new Exception( "Stack-trace source" ) );
}
this.includeSubclasses = includeSubclasses;
}
public boolean isIncludeSubclasses() {
return includeSubclasses;
}
public boolean isDereferencedBySuperclassOrSubclassProperty() {
return dereferencedBySubclassProperty || dereferencedBySuperclassProperty;
}
public String getIdentityColumn() {
final String[] cols = getIdentityColumns();
if ( cols.length == 1 ) {
return cols[0];
}
else {
return "(" + String.join( ", ", cols ) + ")";
}
}
public String[] getIdentityColumns() {
checkInitialized();
final String table = getTableAlias();
if ( table == null ) {
throw new IllegalStateException( "No table alias for node " + this );
}
final String[] propertyNames = getIdentifierPropertyNames();
List<String> columns = new ArrayList<>();
final boolean inSelect = getWalker().getStatementType() == HqlSqlTokenTypes.SELECT;
for ( String propertyName : propertyNames ) {
String[] propertyNameColumns = toColumns( table, propertyName, inSelect );
for ( String propertyNameColumn : propertyNameColumns ) {
columns.add( propertyNameColumn );
}
}
return columns.toArray( new String[columns.size()] );
}
public void setCollectionJoin(boolean collectionJoin) {
this.collectionJoin = collectionJoin;
}
public boolean isCollectionJoin() {
return collectionJoin;
}
public void setRole(String role) {
this.role = role;
applyTreatAsDeclarations( getWalker().getTreatAsDeclarationsByPath( role ) );
}
public void applyTreatAsDeclarations(Set<String> treatAsDeclarationsByPath) {
elementType.applyTreatAsDeclarations( treatAsDeclarationsByPath );
}
public String getRole() {
return role;
}
public void setQueryableCollection(QueryableCollection queryableCollection) {
elementType.setQueryableCollection( queryableCollection );
}
public QueryableCollection getQueryableCollection() {
return elementType.getQueryableCollection();
}
public void setColumns(String[] columns) {
this.columns = columns;
}
public void setOrigin(FromElement origin, boolean manyToMany) {
this.origin = origin;
this.manyToMany = manyToMany;
origin.addDestination( this );
if ( origin.getFromClause() == this.getFromClause() ) {
// TODO: Figure out a better way to get the FROM elements in a proper tree structure.
// If this is not the destination of a many-to-many, add it as a child of the origin.
if ( manyToMany ) {
ASTUtil.appendSibling( origin, this );
}
else {
if ( !getWalker().isInFrom() && !getWalker().isInSelect() && !getWalker().isInEntityGraph() ) {
getFromClause().addChild( this );
}
else {
origin.addChild( this );
}
}
}
else if ( !getWalker().isInFrom() ) {
// HHH-276 : implied joins in a subselect where clause - The destination needs to be added
// to the destination's from clause.
getFromClause().addChild( this ); // Not sure if this is will fix everything, but it works.
}
else {
// Otherwise, the destination node was implied by the FROM clause and the FROM clause processor
// will automatically add it in the right place.
}
}
public boolean isManyToMany() {
return manyToMany;
}
private void addDestination(FromElement fromElement) {
if ( destinations == null ) {
destinations = new LinkedList<FromElement>();
}
destinations.add( fromElement );
}
public List<FromElement> getDestinations() {
if ( destinations == null ) {
return Collections.emptyList();
}
else {
return destinations;
}
}
public FromElement getOrigin() {
return origin;
}
public FromElement getRealOrigin() {
if ( origin == null ) {
return null;
}
if ( StringHelper.isEmpty( origin.getText() ) ) {
return origin.getRealOrigin();
}
return origin;
}
public FromElement getFetchOrigin() {
if ( origin == null ) {
return null;
}
if ( !origin.isFetch() ) {
return origin;
}
if ( StringHelper.isEmpty( origin.getText() ) ) {
return origin.getFetchOrigin();
}
return origin;
}
public static final String DISCRIMINATOR_PROPERTY_NAME = "class";
private TypeDiscriminatorMetadata typeDiscriminatorMetadata;
private static class TypeDiscriminatorMetadataImpl implements TypeDiscriminatorMetadata {
private final DiscriminatorMetadata persisterDiscriminatorMetadata;
private final String alias;
private TypeDiscriminatorMetadataImpl(
DiscriminatorMetadata persisterDiscriminatorMetadata,
String alias) {
this.persisterDiscriminatorMetadata = persisterDiscriminatorMetadata;
this.alias = alias;
}
@Override
public String getSqlFragment() {
return persisterDiscriminatorMetadata.getSqlFragment( alias );
}
@Override
public Type getResolutionType() {
return persisterDiscriminatorMetadata.getResolutionType();
}
}
public TypeDiscriminatorMetadata getTypeDiscriminatorMetadata() {
if ( typeDiscriminatorMetadata == null ) {
typeDiscriminatorMetadata = buildTypeDiscriminatorMetadata();
}
return typeDiscriminatorMetadata;
}
private TypeDiscriminatorMetadata buildTypeDiscriminatorMetadata() {
final String aliasToUse = getTableAlias();
Queryable queryable = getQueryable();
if ( queryable == null ) {
QueryableCollection collection = getQueryableCollection();
if ( ! collection.getElementType().isEntityType() ) {
throw new QueryException( "type discrimination cannot be applied to value collection [" + collection.getRole() + "]" );
}
queryable = (Queryable) collection.getElementPersister();
}
handlePropertyBeingDereferenced( getDataType(), DISCRIMINATOR_PROPERTY_NAME );
return new TypeDiscriminatorMetadataImpl( queryable.getTypeDiscriminatorMetadata(), aliasToUse );
}
public Type getPropertyType(String propertyName, String propertyPath) {
return elementType.getPropertyType( propertyName, propertyPath );
}
public String getPropertyTableName(String propertyName) {
return elementType.getPropertyTableName( propertyName );
}
public String[] toColumns(String tableAlias, String path, boolean inSelect) {
return elementType.toColumns( tableAlias, path, inSelect );
}
public String[] toColumns(String tableAlias, String path, boolean inSelect, boolean forceAlias) {
return elementType.toColumns( tableAlias, path, inSelect, forceAlias );
}
public PropertyMapping getPropertyMapping(String propertyName) {
return elementType.getPropertyMapping( propertyName );
}
public CollectionPropertyReference getCollectionPropertyReference(String propertyName) {
return elementType.getCollectionPropertyReference( propertyName );
}
public String[] getIdentifierPropertyNames() {
return elementType.getIdentifierPropertyNames();
}
public void setFetch(boolean fetch) {
this.fetch = fetch;
// Fetch can't be used with scroll() or iterate().
if ( fetch && getWalker().isShallowQuery() ) {
throw new QueryException( QueryTranslator.ERROR_CANNOT_FETCH_WITH_ITERATE );
}
}
public boolean isFetch() {
return fetch;
}
public int getSequence() {
return sequence;
}
public void setFilter(boolean b) {
filter = b;
}
public boolean isFilter() {
return filter;
}
public boolean useFromFragment() {
checkInitialized();
// If it's not implied or it is implied and it's a many to many join where the target wasn't found.
return !isImplied() || this.useFromFragment;
}
public void setUseFromFragment(boolean useFromFragment) {
this.useFromFragment = useFromFragment;
}
public boolean useWhereFragment() {
return useWhereFragment;
}
public void setUseWhereFragment(boolean b) {
useWhereFragment = b;
}
public void setCollectionTableAlias(String collectionTableAlias) {
this.collectionTableAlias = collectionTableAlias;
}
public String getCollectionTableAlias() {
return collectionTableAlias;
}
public boolean isCollectionOfValuesOrComponents() {
return elementType.isCollectionOfValuesOrComponents();
}
public boolean isEntity() {
return elementType.isEntity();
}
public void setImpliedInFromClause(boolean flag) {
throw new UnsupportedOperationException( "Explicit FROM elements can't be implied in the FROM clause!" );
}
public boolean isImpliedInFromClause() {
return false; // Since this is an explicit FROM element, it can't be implied in the FROM clause.
}
public void setInProjectionList(boolean inProjectionList) {
// Do nothing, eplicit from elements are *always* in the projection list.
}
public boolean inProjectionList() {
return !isImplied() && isFromOrJoinFragment();
}
public boolean isFromOrJoinFragment() {
return getType() == SqlTokenTypes.FROM_FRAGMENT
|| getType() == SqlTokenTypes.JOIN_FRAGMENT
|| getType() == SqlTokenTypes.ENTITY_JOIN;
}
public boolean isAllPropertyFetch() {
return isAllPropertyFetch;
}
public void setAllPropertyFetch(boolean fetch) {
isAllPropertyFetch = fetch;
}
public String getWithClauseFragment() {
return withClauseFragment;
}
public void setWithClauseFragment(String withClauseFragment) {
this.withClauseFragment = withClauseFragment;
}
public void handlePropertyBeingDereferenced(Type propertySource, String propertyName) {
if ( getQueryableCollection() != null && CollectionProperties.isCollectionProperty( propertyName ) ) {
// propertyName refers to something like collection.size...
return;
}
if ( propertySource.isComponentType() ) {
// property name is a sub-path of a component...
return;
}
Queryable persister = getQueryable();
if ( persister != null ) {
try {
Queryable.Declarer propertyDeclarer = persister.getSubclassPropertyDeclarer( propertyName );
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Handling property dereference [{0} ({1}) -> {2} ({3})]",
persister.getEntityName(), getClassAlias(), propertyName, propertyDeclarer );
}
if ( propertyDeclarer == Queryable.Declarer.SUBCLASS ) {
dereferencedBySubclassProperty = true;
includeSubclasses = true;
}
else if ( propertyDeclarer == Queryable.Declarer.SUPERCLASS ) {
dereferencedBySuperclassProperty = true;
}
}
catch( QueryException ignore ) {
// ignore it; the incoming property could not be found so we
// cannot be sure what to do here. At the very least, the
// safest is to simply not apply any dereference toggling...
}
}
}
public boolean isDereferencedBySuperclassProperty() {
return dereferencedBySuperclassProperty;
}
public boolean isDereferencedBySubclassProperty() {
return dereferencedBySubclassProperty;
}
// ParameterContainer impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private List<ParameterSpecification> embeddedParameters = new ArrayList<>( );
@Override
public void addEmbeddedParameter(ParameterSpecification specification) {
embeddedParameters.add( specification );
}
@Override
public boolean hasEmbeddedParameters() {
return !embeddedParameters.isEmpty();
}
@Override
public ParameterSpecification[] getEmbeddedParameters() {
final List<ParameterSpecification> parameterSpecification = getParameterSpecification();
return parameterSpecification.toArray( new ParameterSpecification[ parameterSpecification.size() ] );
}
private List<ParameterSpecification> getParameterSpecification() {
List<ParameterSpecification> parameterSpecifications =
embeddedParameters.stream()
.filter( o -> o instanceof DynamicFilterParameterSpecification )
.collect( Collectors.toList() );
parameterSpecifications.addAll(
embeddedParameters.stream()
.filter( o -> ! (o instanceof DynamicFilterParameterSpecification ) )
.collect( Collectors.toList() ) );
return parameterSpecifications;
}
public ParameterSpecification getIndexCollectionSelectorParamSpec() {
return elementType.getIndexCollectionSelectorParamSpec();
}
public void setIndexCollectionSelectorParamSpec(ParameterSpecification indexCollectionSelectorParamSpec) {
if ( indexCollectionSelectorParamSpec == null ) {
if ( elementType.getIndexCollectionSelectorParamSpec() != null ) {
embeddedParameters.remove( elementType.getIndexCollectionSelectorParamSpec() );
elementType.setIndexCollectionSelectorParamSpec( null );
}
}
else {
elementType.setIndexCollectionSelectorParamSpec( indexCollectionSelectorParamSpec );
addEmbeddedParameter( indexCollectionSelectorParamSpec );
}
}
}

View File

@ -1,313 +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.hql.internal.ast.tree;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import antlr.collections.AST;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.hql.internal.NameGenerator;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.sql.AliasGenerator;
import org.hibernate.sql.SelectExpression;
import org.hibernate.sql.SelectFragment;
import org.hibernate.transform.BasicTransformerAdapter;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
import antlr.SemanticException;
/**
* Tree node representing reference to the entry ({@link Map.Entry}) of a Map association.
*
* @author Steve Ebersole
*/
public class MapEntryNode extends AbstractMapComponentNode implements AggregatedSelectExpression {
private static class LocalAliasGenerator implements AliasGenerator {
private final int base;
private int counter;
private LocalAliasGenerator(int base) {
this.base = base;
}
@Override
public String generateAlias(String sqlExpression) {
return NameGenerator.scalarName( base, counter++ );
}
}
private int scalarColumnIndex = -1;
@Override
protected String expressionDescription() {
return "entry(*)";
}
@Override
public Class getAggregationResultType() {
return Map.Entry.class;
}
@Override
public void resolve(
boolean generateJoin,
boolean implicitJoin,
String classAlias,
AST parent,
AST parentPredicate) throws SemanticException {
if (parent != null) {
throw new SemanticException( expressionDescription() + " expression cannot be further de-referenced" );
}
super.resolve(generateJoin, implicitJoin, classAlias, parent, parentPredicate);
}
@Override
@SuppressWarnings("unchecked")
protected Type resolveType(QueryableCollection collectionPersister) {
final Type keyType = collectionPersister.getIndexType();
final Type valueType = collectionPersister.getElementType();
types.add( keyType );
types.add( valueType );
mapEntryBuilder = new MapEntryBuilder();
// an entry (as an aggregated select expression) does not have a type...
return null;
}
@Override
protected String[] resolveColumns(QueryableCollection collectionPersister) {
List selections = new ArrayList();
determineKeySelectExpressions( collectionPersister, selections );
determineValueSelectExpressions( collectionPersister, selections );
final int columnNumber = selections.size();
StringBuilder text = new StringBuilder( columnNumber * 12 ); //Some guess
String[] columns = new String[columnNumber];
for ( int i = 0; i < columnNumber; i++ ) {
SelectExpression selectExpression = (SelectExpression) selections.get( i );
if ( i != 0 ) {
text.append( ", " );
}
text.append( selectExpression.getExpression() );
text.append( " as " );
text.append( selectExpression.getAlias() );
columns[i] = selectExpression.getExpression();
}
setText( text.toString() );
setResolved();
return columns;
}
private void determineKeySelectExpressions(QueryableCollection collectionPersister, List selections) {
AliasGenerator aliasGenerator = new LocalAliasGenerator( 0 );
appendSelectExpressions( collectionPersister.getIndexColumnNames(), selections, aliasGenerator );
Type keyType = collectionPersister.getIndexType();
if ( keyType.isEntityType() ) {
MapKeyEntityFromElement mapKeyEntityFromElement = findOrAddMapKeyEntityFromElement( collectionPersister );
Queryable keyEntityPersister = mapKeyEntityFromElement.getQueryable();
SelectFragment fragment = keyEntityPersister.propertySelectFragmentFragment(
mapKeyEntityFromElement.getTableAlias(),
null,
false
);
appendSelectExpressions( fragment, selections, aliasGenerator );
}
}
@SuppressWarnings({"unchecked", "ForLoopReplaceableByForEach"})
private void appendSelectExpressions(String[] columnNames, List selections, AliasGenerator aliasGenerator) {
for ( int i = 0; i < columnNames.length; i++ ) {
selections.add(
new BasicSelectExpression(
collectionTableAlias() + '.' + columnNames[i],
aliasGenerator.generateAlias( columnNames[i] )
)
);
}
}
@SuppressWarnings({"unchecked", "WhileLoopReplaceableByForEach"})
private void appendSelectExpressions(SelectFragment fragment, List selections, AliasGenerator aliasGenerator) {
Iterator itr = fragment.getColumns().iterator();
while ( itr.hasNext() ) {
final String column = (String) itr.next();
selections.add(
new BasicSelectExpression( column, aliasGenerator.generateAlias( column ) )
);
}
}
private void determineValueSelectExpressions(QueryableCollection collectionPersister, List selections) {
AliasGenerator aliasGenerator = new LocalAliasGenerator( 1 );
appendSelectExpressions( collectionPersister.getElementColumnNames(), selections, aliasGenerator );
Type valueType = collectionPersister.getElementType();
if ( valueType.isAssociationType() ) {
EntityType valueEntityType = (EntityType) valueType;
Queryable valueEntityPersister = (Queryable) sfi().getEntityPersister(
valueEntityType.getAssociatedEntityName( sfi() )
);
SelectFragment fragment = valueEntityPersister.propertySelectFragmentFragment(
elementTableAlias(),
null,
false
);
appendSelectExpressions( fragment, selections, aliasGenerator );
}
}
private String collectionTableAlias() {
return getFromElement().getCollectionTableAlias() != null
? getFromElement().getCollectionTableAlias()
: getFromElement().getTableAlias();
}
private String elementTableAlias() {
return getFromElement().getTableAlias();
}
private static class BasicSelectExpression implements SelectExpression {
private final String expression;
private final String alias;
private BasicSelectExpression(String expression, String alias) {
this.expression = expression;
this.alias = alias;
}
@Override
public String getExpression() {
return expression;
}
@Override
public String getAlias() {
return alias;
}
}
public SessionFactoryImplementor sfi() {
return getSessionFactoryHelper().getFactory();
}
@Override
public void setText(String s) {
if ( isResolved() ) {
return;
}
super.setText( s );
}
@Override
public void setScalarColumn(int i) {
this.scalarColumnIndex = i;
}
@Override
public int getScalarColumnIndex() {
return scalarColumnIndex;
}
@Override
public void setScalarColumnText(int i) {
}
@Override
public boolean isScalar() {
// Constructors are always considered scalar results.
return true;
}
private List types = new ArrayList( 4 ); // size=4 to prevent resizing
@Override
public List getAggregatedSelectionTypeList() {
return types;
}
private static final String[] ALIASES = {null, null};
@Override
public String[] getAggregatedAliases() {
return ALIASES;
}
private MapEntryBuilder mapEntryBuilder;
@Override
public ResultTransformer getResultTransformer() {
return mapEntryBuilder;
}
private static class MapEntryBuilder extends BasicTransformerAdapter {
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
if ( tuple.length != 2 ) {
throw new HibernateException( "Expecting exactly 2 tuples to transform into Map.Entry" );
}
return new EntryAdapter( tuple[0], tuple[1] );
}
}
private static class EntryAdapter implements Map.Entry {
private final Object key;
private Object value;
private EntryAdapter(Object key, Object value) {
this.key = key;
this.value = value;
}
@Override
public Object getValue() {
return value;
}
@Override
public Object getKey() {
return key;
}
@Override
public Object setValue(Object value) {
Object old = this.value;
this.value = value;
return old;
}
@Override
public boolean equals(Object o) {
// IMPL NOTE : nulls are considered equal for keys and values according to Map.Entry contract
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
EntryAdapter that = (EntryAdapter) o;
// make sure we have the same types...
return ( key == null ? that.key == null : key.equals( that.key ) )
&& ( value == null ? that.value == null : value.equals( that.value ) );
}
@Override
public int hashCode() {
int keyHash = key == null ? 0 : key.hashCode();
int valueHash = value == null ? 0 : value.hashCode();
return keyHash ^ valueHash;
}
}
}

View File

@ -1,72 +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.hql.internal.ast.util;
import java.util.Arrays;
import java.util.LinkedHashMap;
import org.hibernate.hql.internal.ast.tree.DotNode;
import org.hibernate.hql.internal.ast.tree.FromElement;
import org.hibernate.hql.internal.ast.tree.FromReferenceNode;
import org.hibernate.hql.internal.ast.tree.IdentNode;
import org.hibernate.hql.internal.ast.tree.SelectClause;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.persister.entity.EntityPersister;
import antlr.collections.AST;
public class ASTReferencedTablesPrinter extends ASTPrinter {
public ASTReferencedTablesPrinter(Class tokenTypeConstants) {
super( tokenTypeConstants );
}
@Override
public String nodeToString(AST ast) {
if ( ast == null ) {
return "{node:null}";
}
return ast.getClass().getSimpleName();
}
@Override
public LinkedHashMap<String, Object> createNodeProperties(AST node) {
LinkedHashMap<String, Object> props = new LinkedHashMap<>();
if ( node instanceof FromReferenceNode ) {
FromReferenceNode frn = (FromReferenceNode) node;
FromElement fromElement = frn.getFromElement();
EntityPersister entityPersister = fromElement != null ? fromElement.getEntityPersister() : null;
String entityPersisterStr = entityPersister != null ? entityPersister.toString() : null;
props.put( "persister", entityPersisterStr );
String referencedTablesStr = Arrays.toString( frn.getReferencedTables() );
props.put( "referencedTables", referencedTablesStr );
}
if ( node instanceof DotNode ) {
DotNode dn = (DotNode) node;
props.put( "path", dn.getPath() );
props.put( "originalPropertyName", dn.getOriginalPropertyName() );
}
if ( node instanceof IdentNode ) {
IdentNode in = (IdentNode) node;
props.put( "originalText", in.getOriginalText() );
}
if ( node instanceof SelectClause ) {
SelectClause sc = (SelectClause) node;
for ( Object element : sc.getFromElementsForLoad() ) {
FromElement fromElement = (FromElement) element;
EntityPersister entityPersister = fromElement.getEntityPersister();
if ( entityPersister != null && entityPersister instanceof AbstractEntityPersister ) {
AbstractEntityPersister aep = (AbstractEntityPersister) entityPersister;
String entityClass = aep.getMappedClass().getSimpleName();
String tables = Arrays.toString( aep.getTableNames() );
props.put( String.format( "referencedTables(entity %s)", entityClass ), tables );
}
}
}
return props;
}
}

View File

@ -1,191 +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.hql.internal.ast.util;
import java.util.Map;
import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes;
import org.hibernate.hql.internal.ast.HqlSqlWalker;
import org.hibernate.hql.internal.ast.tree.FromElement;
import org.hibernate.hql.internal.ast.tree.Node;
import org.hibernate.hql.internal.ast.tree.QueryNode;
import org.hibernate.hql.internal.ast.tree.RestrictableStatement;
import org.hibernate.hql.internal.ast.tree.SqlFragment;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.param.CollectionFilterKeyParameterSpecification;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.sql.JoinFragment;
import org.hibernate.type.Type;
import antlr.collections.AST;
/**
* Creates synthetic and nodes based on the where fragment part of a JoinSequence.
*
* @author josh
*/
public class SyntheticAndFactory implements HqlSqlTokenTypes {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( SyntheticAndFactory.class );
private HqlSqlWalker hqlSqlWalker;
private AST thetaJoins;
private AST filters;
public SyntheticAndFactory(HqlSqlWalker hqlSqlWalker) {
this.hqlSqlWalker = hqlSqlWalker;
}
private Node create(int tokenType, String text) {
return (Node) hqlSqlWalker.getASTFactory().create( tokenType, text );
}
public void addWhereFragment(
JoinFragment joinFragment,
String whereFragment,
QueryNode query,
FromElement fromElement,
HqlSqlWalker hqlSqlWalker) {
if ( whereFragment == null ) {
return;
}
if ( !fromElement.useWhereFragment() && !joinFragment.hasThetaJoins() ) {
return;
}
whereFragment = whereFragment.trim();
if ( whereFragment.isEmpty() ) {
return;
}
// Forcefully remove leading ands from where fragments; the grammar will
// handle adding them
if ( whereFragment.startsWith( "and" ) ) {
whereFragment = whereFragment.substring( 4 );
}
LOG.debugf( "Using unprocessed WHERE-fragment [%s]", whereFragment );
SqlFragment fragment = (SqlFragment) create( SQL_TOKEN, whereFragment );
fragment.setJoinFragment( joinFragment );
fragment.setFromElement( fromElement );
if ( fromElement.getIndexCollectionSelectorParamSpec() != null ) {
fragment.addEmbeddedParameter( fromElement.getIndexCollectionSelectorParamSpec() );
fromElement.setIndexCollectionSelectorParamSpec( null );
}
if ( hqlSqlWalker.isFilter() ) {
if ( whereFragment.indexOf( '?' ) >= 0 ) {
Type collectionFilterKeyType = hqlSqlWalker.getSessionFactoryHelper()
.requireQueryableCollection( hqlSqlWalker.getCollectionFilterRole() )
.getKeyType();
CollectionFilterKeyParameterSpecification paramSpec = new CollectionFilterKeyParameterSpecification(
hqlSqlWalker.getCollectionFilterRole(),
collectionFilterKeyType
);
fragment.addEmbeddedParameter( paramSpec );
}
}
JoinProcessor.processDynamicFilterParameters(
whereFragment,
fragment,
hqlSqlWalker
);
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Using processed WHERE-fragment [%s]", fragment.getText() );
}
// Filter conditions need to be inserted before the HQL where condition and the
// theta join node. This is because org.hibernate.loader.Loader binds the filter parameters first,
// then it binds all the HQL query parameters, see org.hibernate.loader.Loader.processFilterParameters().
if ( fragment.getFromElement().isFilter() || fragment.hasFilterCondition() ) {
if ( filters == null ) {
// Find or create the WHERE clause
AST where = query.getWhereClause();
// Create a new FILTERS node as a parent of all filters
filters = create( FILTERS, "{filter conditions}" );
// Put the FILTERS node before the HQL condition and theta joins
ASTUtil.insertChild( where, filters );
}
// add the current fragment to the FILTERS node
filters.addChild( fragment );
}
else {
if ( thetaJoins == null ) {
// Find or create the WHERE clause
AST where = query.getWhereClause();
// Create a new THETA_JOINS node as a parent of all filters
thetaJoins = create( THETA_JOINS, "{theta joins}" );
// Put the THETA_JOINS node before the HQL condition, after the filters.
if ( filters == null ) {
ASTUtil.insertChild( where, thetaJoins );
}
else {
ASTUtil.insertSibling( thetaJoins, filters );
}
}
// add the current fragment to the THETA_JOINS node
thetaJoins.addChild( fragment );
}
}
public void addDiscriminatorWhereFragment(
RestrictableStatement statement,
Queryable persister,
Map enabledFilters,
String alias) {
String whereFragment = persister.filterFragment( alias, enabledFilters ).trim();
if ( "".equals( whereFragment ) ) {
return;
}
if ( whereFragment.startsWith( "and" ) ) {
whereFragment = whereFragment.substring( 4 );
}
// Need to parse off the column qualifiers; this is assuming (which is true as of now)
// that this is only used from update and delete HQL statement parsing
whereFragment = StringHelper.replace(
whereFragment,
persister.generateFilterConditionAlias( alias ) + '.',
""
);
// Note: this simply constructs a "raw" SQL_TOKEN representing the
// where fragment and injects this into the tree. This "works";
// however it is probably not the best long-term solution.
//
// At some point we probably want to apply an additional grammar to
// properly tokenize this where fragment into constituent parts
// focused on the operators embedded within the fragment.
SqlFragment discrimNode = (SqlFragment) create( SQL_TOKEN, whereFragment );
JoinProcessor.processDynamicFilterParameters(
whereFragment,
discrimNode,
hqlSqlWalker
);
if ( statement.getWhereClause().getNumberOfChildren() == 0 ) {
statement.getWhereClause().setFirstChild( discrimNode );
}
else {
AST and = create( AND, "{and}" );
AST currentFirstChild = statement.getWhereClause().getFirstChild();
and.setFirstChild( discrimNode );
and.addChild( currentFirstChild );
statement.getWhereClause().setFirstChild( and );
}
}
}

View File

@ -1,141 +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.hql.spi.id.inline;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.hql.internal.ast.HqlSqlWalker;
import org.hibernate.hql.internal.ast.tree.AssignmentSpecification;
import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
import org.hibernate.param.ParameterSpecification;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.sql.Update;
/**
* Inline bulk-id delete handler that selects the identifiers of the rows to be deleted.
*
* @author Vlad Mihalcea
*/
public abstract class AbstractInlineIdsUpdateHandlerImpl
extends AbstractInlineIdsBulkIdHandler
implements MultiTableBulkIdStrategy.UpdateHandler {
private final Map<Integer, String> updates = new LinkedHashMap<>();
private ParameterSpecification[][] assignmentParameterSpecifications;
public AbstractInlineIdsUpdateHandlerImpl(
SessionFactoryImplementor factory,
HqlSqlWalker walker) {
super( factory, walker );
}
@Override
public String[] getSqlStatements() {
return updates.values().toArray( new String[updates.values().size()] );
}
@Override
public int execute(
SharedSessionContractImplementor session,
QueryParameters queryParameters) {
IdsClauseBuilder values = prepareInlineStatement( session, queryParameters );
if ( !values.getIds().isEmpty() ) {
final Queryable targetedQueryable = getTargetedQueryable();
String[] tableNames = targetedQueryable.getConstraintOrderedTableNameClosure();
String[][] columnNames = targetedQueryable.getContraintOrderedTableKeyColumnClosure();
String idSubselect = values.toStatement();
assignmentParameterSpecifications = new ParameterSpecification[tableNames.length][];
for ( int tableIndex = 0; tableIndex < tableNames.length; tableIndex++ ) {
boolean affected = false;
final List<ParameterSpecification> parameterList = new ArrayList<>();
Update update = generateUpdate( tableNames[tableIndex], columnNames[tableIndex], idSubselect, "bulk update" );
final List<AssignmentSpecification> assignmentSpecifications = walker().getAssignmentSpecifications();
for ( AssignmentSpecification assignmentSpecification : assignmentSpecifications ) {
if ( assignmentSpecification.affectsTable( tableNames[tableIndex] ) ) {
affected = true;
update.appendAssignmentFragment( assignmentSpecification.getSqlAssignmentFragment() );
if ( assignmentSpecification.getParameters() != null ) {
Collections.addAll( parameterList, assignmentSpecification.getParameters() );
}
}
}
if ( affected ) {
updates.put( tableIndex, update.toStatementString() );
assignmentParameterSpecifications[tableIndex] = parameterList.toArray( new ParameterSpecification[parameterList.size()] );
}
}
final JdbcCoordinator jdbcCoordinator = session
.getJdbcCoordinator();
// Start performing the updates
for ( Map.Entry<Integer, String> updateEntry: updates.entrySet()) {
int i = updateEntry.getKey();
String update = updateEntry.getValue();
if ( update == null) {
continue;
}
try {
try (PreparedStatement ps = jdbcCoordinator.getStatementPreparer()
.prepareStatement( update, false )) {
int position = 1; // jdbc params are 1-based
if ( assignmentParameterSpecifications[i] != null ) {
for ( ParameterSpecification assignmentParameterSpecification : assignmentParameterSpecifications[i] ) {
position += assignmentParameterSpecification
.bind( ps, queryParameters, session, position );
}
}
jdbcCoordinator.getResultSetReturn()
.executeUpdate( ps );
}
}
catch ( SQLException e ) {
throw convert(
e,
"error performing bulk update",
update
);
}
}
}
return values.getIds().size();
}
protected Update generateUpdate(
String tableName,
String[] columnNames,
String idSubselect,
String comment) {
final Update update = new Update( factory().getServiceRegistry().getService( JdbcServices.class ).getDialect() )
.setTableName( tableName )
.setWhere( "(" + String.join( ", ", (CharSequence[]) columnNames ) + ") in (" + idSubselect + ")" );
if ( factory().getSessionFactoryOptions().isCommentsEnabled() ) {
update.setComment( comment );
}
return update;
}
}

View File

@ -56,8 +56,6 @@ import org.hibernate.engine.transaction.internal.TransactionImpl;
import org.hibernate.engine.transaction.spi.TransactionImplementor;
import org.hibernate.id.uuid.StandardRandomStrategy;
import org.hibernate.jpa.internal.util.FlushModeTypeHelper;
import org.hibernate.jpa.spi.NativeQueryTupleTransformer;
import org.hibernate.jpa.spi.TupleBuilderTransformer;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.procedure.ProcedureCall;
import org.hibernate.procedure.internal.ProcedureCallImpl;

View File

@ -119,8 +119,6 @@ import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.query.sql.spi.NativeQueryImplementor;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.spi.NamedQueryRepository;
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
import org.hibernate.resource.jdbc.spi.StatementInspector;
import org.hibernate.resource.transaction.backend.jta.internal.synchronization.AfterCompletionAction;

View File

@ -46,7 +46,9 @@ import org.hibernate.dialect.pagination.NoopLimitHandler;
import org.hibernate.engine.internal.CacheHelper;
import org.hibernate.engine.internal.TwoPhaseLoad;
import org.hibernate.engine.jdbc.ColumnNameCache;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.BatchFetchQueue;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.EntityUniqueKey;
@ -82,6 +84,8 @@ import org.hibernate.persister.entity.UniqueKeyLoadable;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.query.spi.ScrollableResultsImplementor;
import org.hibernate.sql.results.spi.RowReader;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.transform.CacheableResultTransformer;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.AssociationType;

View File

@ -14,6 +14,8 @@ import java.util.List;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.spi.SharedSessionContractImplementor;

View File

@ -1,172 +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.query.criteria.internal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.criteria.CommonAbstractCriteria;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import javax.persistence.metamodel.EntityType;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.jpa.spi.HibernateEntityManagerImplementor;
import org.hibernate.query.criteria.internal.compile.CompilableCriteria;
import org.hibernate.query.criteria.internal.compile.CriteriaInterpretation;
import org.hibernate.query.criteria.internal.compile.ImplicitParameterBinding;
import org.hibernate.query.criteria.internal.compile.InterpretedParameterMetadata;
import org.hibernate.query.criteria.internal.compile.RenderingContext;
import org.hibernate.query.criteria.internal.path.RootImpl;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.sql.ast.Clause;
/**
* Base class for commonality between {@link javax.persistence.criteria.CriteriaUpdate} and
* {@link javax.persistence.criteria.CriteriaDelete}
*
* @author Steve Ebersole
*/
public abstract class AbstractManipulationCriteriaQuery<T> implements CompilableCriteria, CommonAbstractCriteria {
private final CriteriaBuilderImpl criteriaBuilder;
private RootImpl<T> root;
private Predicate restriction;
protected AbstractManipulationCriteriaQuery(CriteriaBuilderImpl criteriaBuilder) {
this.criteriaBuilder = criteriaBuilder;
}
protected CriteriaBuilderImpl criteriaBuilder() {
return criteriaBuilder;
}
// Root ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public Root from(Class<T> entityClass) {
EntityType<T> entityType = criteriaBuilder.getEntityManagerFactory()
.getMetamodel()
.entity( entityClass );
if ( entityType == null ) {
throw new IllegalArgumentException( entityClass + " is not an entity" );
}
return from( entityType );
}
public Root<T> from(EntityType<T> entityType) {
root = new RootImpl<T>( criteriaBuilder, entityType, false );
return root;
}
public Root<T> getRoot() {
return root;
}
// Restriction ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
protected void setRestriction(Expression<Boolean> restriction) {
this.restriction = criteriaBuilder.wrap( restriction );
}
public void setRestriction(Predicate... restrictions) {
this.restriction = criteriaBuilder.and( restrictions );
}
public Predicate getRestriction() {
return restriction;
}
public <U> Subquery<U> subquery(Class<U> type) {
return new CriteriaSubqueryImpl<U>( criteriaBuilder(), type, this );
}
// compiling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public void validate() {
if ( root == null ) {
throw new IllegalStateException( "UPDATE/DELETE criteria must name root entity" );
}
}
@Override
public CriteriaInterpretation interpret(RenderingContext renderingContext) {
final String jpaqlString = renderQuery( renderingContext );
return new CriteriaInterpretation() {
@Override
@SuppressWarnings("unchecked")
public QueryImplementor buildCompiledQuery(
SharedSessionContractImplementor entityManager,
final InterpretedParameterMetadata interpretedParameterMetadata) {
final Map<String,Class> implicitParameterTypes = extractTypeMap( interpretedParameterMetadata.implicitParameterBindings() );
QueryImplementor query = entityManager.createQuery(
jpaqlString,
null,
null,
new HibernateEntityManagerImplementor.QueryOptions() {
@Override
public List<ValueHandlerFactory.ValueHandler> getValueHandlers() {
return null;
}
@Override
public Map<String, Class> getNamedParameterExplicitTypes() {
return implicitParameterTypes;
}
@Override
public ResultMetadataValidator getResultMetadataValidator() {
return null;
}
}
);
for ( ImplicitParameterBinding implicitParameterBinding : interpretedParameterMetadata.implicitParameterBindings() ) {
implicitParameterBinding.bind( query );
}
return query;
}
private Map<String, Class> extractTypeMap(List<ImplicitParameterBinding> implicitParameterBindings) {
final HashMap<String,Class> map = new HashMap<>();
for ( ImplicitParameterBinding implicitParameter : implicitParameterBindings ) {
map.put( implicitParameter.getParameterName(), implicitParameter.getJavaType() );
}
return map;
}
};
}
protected abstract String renderQuery(RenderingContext renderingContext);
protected void renderRoot(StringBuilder jpaql, RenderingContext renderingContext) {
jpaql.append( ( (FromImplementor) root ).renderTableExpression( renderingContext ) );
}
protected void renderRestrictions(StringBuilder jpaql, RenderingContext renderingContext) {
if ( getRestriction() == null ) {
return;
}
renderingContext.getClauseStack().push( Clause.WHERE );
try {
jpaql.append( " where " )
.append( ( (Renderable) getRestriction() ).render( renderingContext ) );
}
finally {
renderingContext.getClauseStack().pop();
}
}
}

View File

@ -1,128 +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.query.criteria.internal.expression.function;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import javax.persistence.criteria.Expression;
import org.hibernate.query.criteria.internal.CriteriaBuilderImpl;
import org.hibernate.query.criteria.internal.ParameterContainer;
import org.hibernate.query.criteria.internal.ParameterRegistry;
import org.hibernate.query.criteria.internal.Renderable;
import org.hibernate.query.criteria.internal.compile.RenderingContext;
/**
* Support for functions with parameters.
*
* @author Steve Ebersole
*/
public class ParameterizedFunctionExpression<X>
extends BasicFunctionExpression<X>
implements FunctionExpression<X> {
public static final List<String> STANDARD_JPA_FUNCTION_NAMES = Arrays.asList(
// 4.6.17.2.1
"CONCAT",
"SUBSTRING",
"TRIM",
"UPPER",
"LOWER",
"LOCATE",
"LENGTH",
//4.6.17.2.2
"ABS",
"SQRT",
"MOD",
"SIZE",
"INDEX",
// 4.6.17.2.3
"CURRENT_DATE",
"CURRENT_TIME",
"CURRENT_TIMESTAMP"
);
private final List<Expression<?>> argumentExpressions;
private final boolean isStandardJpaFunction;
public ParameterizedFunctionExpression(
CriteriaBuilderImpl criteriaBuilder,
Class<X> javaType,
String functionName,
List<Expression<?>> argumentExpressions) {
super( criteriaBuilder, javaType, functionName );
this.argumentExpressions = argumentExpressions;
this.isStandardJpaFunction = STANDARD_JPA_FUNCTION_NAMES.contains( functionName.toUpperCase(Locale.ROOT) );
}
public ParameterizedFunctionExpression(
CriteriaBuilderImpl criteriaBuilder,
Class<X> javaType,
String functionName,
Expression<?>... argumentExpressions) {
super( criteriaBuilder, javaType, functionName );
this.argumentExpressions = Arrays.asList( argumentExpressions );
this.isStandardJpaFunction = STANDARD_JPA_FUNCTION_NAMES.contains( functionName.toUpperCase(Locale.ROOT) );
}
protected boolean isStandardJpaFunction() {
return isStandardJpaFunction;
}
protected static int properSize(int number) {
return number + (int)( number*.75 ) + 1;
}
public List<Expression<?>> getArgumentExpressions() {
return argumentExpressions;
}
@Override
public void registerParameters(ParameterRegistry registry) {
for ( Expression argument : getArgumentExpressions() ) {
if ( ParameterContainer.class.isInstance( argument ) ) {
( (ParameterContainer) argument ).registerParameters(registry);
}
}
}
@Override
public String render(RenderingContext renderingContext) {
renderingContext.getFunctionStack().push( this );
try {
final StringBuilder buffer = new StringBuilder();
if ( isStandardJpaFunction() ) {
buffer.append( getFunctionName() ).append( "(" );
}
else {
buffer.append( "function('" )
.append( getFunctionName() )
.append( "', " );
}
renderArguments( buffer, renderingContext );
return buffer.append( ')' ).toString();
}
finally {
renderingContext.getFunctionStack().pop();
}
}
protected void renderArguments(StringBuilder buffer, RenderingContext renderingContext) {
String sep = "";
for ( Expression argument : argumentExpressions ) {
buffer.append( sep ).append( ( (Renderable) argument ).render( renderingContext ) );
sep = ", ";
}
}
}

View File

@ -1,174 +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.query.criteria.internal.predicate;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import org.hibernate.query.criteria.internal.CriteriaBuilderImpl;
import org.hibernate.query.criteria.internal.ParameterRegistry;
import org.hibernate.query.criteria.internal.Renderable;
import org.hibernate.query.criteria.internal.compile.RenderingContext;
/**
* A compound {@link Predicate predicate} is a grouping of other {@link Predicate predicates} in order to convert
* either a conjunction (logical AND) or a disjunction (logical OR).
*
* @author Steve Ebersole
*/
public class CompoundPredicate
extends AbstractPredicateImpl
implements Serializable {
private BooleanOperator operator;
private final List<Expression<Boolean>> expressions = new ArrayList<Expression<Boolean>>();
/**
* Constructs an empty conjunction or disjunction.
*
* @param criteriaBuilder The query builder from which this originates.
* @param operator Indicates whether this predicate will function
* as a conjunction or disjunction.
*/
public CompoundPredicate(CriteriaBuilderImpl criteriaBuilder, BooleanOperator operator) {
super( criteriaBuilder );
this.operator = operator;
}
/**
* Constructs a conjunction or disjunction over the given expressions.
*
* @param criteriaBuilder The query builder from which this originates.
* @param operator Indicates whether this predicate will function
* as a conjunction or disjunction.
* @param expressions The expressions to be grouped.
*/
public CompoundPredicate(
CriteriaBuilderImpl criteriaBuilder,
BooleanOperator operator,
Expression<Boolean>... expressions) {
this( criteriaBuilder, operator );
applyExpressions( expressions );
}
/**
* Constructs a conjunction or disjunction over the given expressions.
*
* @param criteriaBuilder The query builder from which this originates.
* @param operator Indicates whether this predicate will function
* as a conjunction or disjunction.
* @param expressions The expressions to be grouped.
*/
public CompoundPredicate(
CriteriaBuilderImpl criteriaBuilder,
BooleanOperator operator,
List<Expression<Boolean>> expressions) {
this( criteriaBuilder, operator );
applyExpressions( expressions );
}
private void applyExpressions(Expression<Boolean>... expressions) {
applyExpressions( Arrays.asList( expressions ) );
}
private void applyExpressions(List<Expression<Boolean>> expressions) {
this.expressions.clear();
this.expressions.addAll( expressions );
}
@Override
public BooleanOperator getOperator() {
return operator;
}
@Override
public List<Expression<Boolean>> getExpressions() {
return expressions;
}
@Override
public void registerParameters(ParameterRegistry registry) {
for ( Expression expression : getExpressions() ) {
Helper.possibleParameter( expression, registry );
}
}
@Override
public String render(RenderingContext renderingContext) {
return render( isNegated(), renderingContext );
}
@Override
public boolean isJunction() {
return true;
}
@Override
public String render(boolean isNegated, RenderingContext renderingContext) {
return render( this, renderingContext );
}
/**
* Create negation of compound predicate by using logic rules:
* 1. not (x || y) is (not x && not y)
* 2. not (x && y) is (not x || not y)
*/
@Override
public Predicate not() {
return new NegatedPredicateWrapper( this );
}
private void toggleOperator() {
this.operator = reverseOperator( this.operator );
}
public static BooleanOperator reverseOperator(BooleanOperator operator) {
return operator == BooleanOperator.AND
? BooleanOperator.OR
: BooleanOperator.AND;
}
public static String render(PredicateImplementor predicate, RenderingContext renderingContext) {
if ( ! predicate.isJunction() ) {
throw new IllegalStateException( "CompoundPredicate.render should only be used to render junctions" );
}
// for junctions, the negation is already cooked into the expressions and operator; we just need to render
// them as is
if ( predicate.getExpressions().isEmpty() ) {
boolean implicitTrue = predicate.getOperator() == BooleanOperator.AND;
// AND is always true for empty; OR is always false
return implicitTrue ? "1=1" : "0=1";
}
// single valued junction ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( predicate.getExpressions().size() == 1 ) {
return ( (Renderable) predicate.getExpressions().get( 0 ) ).render( renderingContext );
}
final StringBuilder buffer = new StringBuilder();
String sep = "";
for ( Expression expression : predicate.getExpressions() ) {
buffer.append( sep )
.append( "( " )
.append( ( (Renderable) expression ).render( renderingContext ) )
.append( " )" );
sep = operatorTextWithSeparator( predicate.getOperator() );
}
return buffer.toString();
}
private static String operatorTextWithSeparator(BooleanOperator operator) {
return operator == BooleanOperator.AND
? " and "
: " or ";
}
}

View File

@ -899,7 +899,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
}
protected void collectHints(Map<String, Object> hints) {
final RowSelection queryOptions = getQueryOptions();
final MutableQueryOptions queryOptions = getQueryOptions();
final Integer queryTimeout = queryOptions.getTimeout();
if ( queryTimeout != null ) {
hints.put( HINT_TIMEOUT, queryTimeout );

View File

@ -34,6 +34,7 @@ import org.hibernate.property.access.spi.Getter;
import org.hibernate.property.access.spi.Setter;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.ProxyFactory;
import org.hibernate.tuple.IdentifierProperty;
import org.hibernate.tuple.Instantiator;
import org.hibernate.tuple.NonIdentifierAttribute;
import org.hibernate.type.AssociationType;

View File

@ -12,15 +12,12 @@ import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import javax.jws.soap.SOAPBinding;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.jdbc.AbstractWork;

View File

@ -1,167 +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.test.joinwithoutancestor;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.testing.TestForIssue;
import org.junit.Test;
@TestForIssue( jiraKey = "HHH-12993")
public class OmitAncestorJoinTest extends OmitAncestorTestCase {
@Override
protected Class[] getAnnotatedClasses() {
return new Class[] { A.class, SubA.class, SubSubA.class, B.class };
}
@Test
public void test() {
// Should not join any parent table
assertFromTables("select valSubA from SubA", SubA.TABLE);
// Should not join any parent table
assertFromTables("select sa.valSubA from SubA sa", SubA.TABLE);
// Should omit middle table from inheritance hierarchy
assertFromTables("select ssa.valA from SubSubA ssa", SubSubA.TABLE, A.TABLE);
// Should omit middle table from inheritance hierarchy
assertFromTables( "select ssa.valA, ssa.valSubSubA from SubSubA ssa", SubSubA.TABLE, A.TABLE );
// Should join parent table, because it is used in "where" part
assertFromTables("select valSubA from SubA where valA = 'foo'", SubA.TABLE, A.TABLE);
// Should join parent table, because it is used in "order by" part
assertFromTables("select valSubSubA from SubSubA order by valA", SubSubA.TABLE, A.TABLE);
// Should other tables from hierarchye, because it returns whole entity
assertFromTables("select suba from SubA suba", SubA.TABLE, A.TABLE, SubSubA.TABLE);
assertFromTables("from SubA", SubA.TABLE, A.TABLE, SubSubA.TABLE);
// Should join A table, because it has the reference to B table
assertFromTables( "select suba.b from SubA suba", SubA.TABLE, A.TABLE, B.TABLE );
assertFromTables( "select suba.b.id from SubA suba", SubA.TABLE, A.TABLE );
}
@Entity(name = "A")
@Table(name = A.TABLE)
@Inheritance(strategy = InheritanceType.JOINED)
static class A {
public static final String TABLE = "A_Table";
@Id
@GeneratedValue
private Long id;
private String valA;
@ManyToOne
private B b;
public Long getId() {
return id;
}
public String getValA() {
return valA;
}
public void setValA(String valA) {
this.valA = valA;
}
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
}
@Entity(name = "SubA")
@Table(name = SubA.TABLE)
static class SubA extends A {
public static final String TABLE = "SubA_Table";
private String valSubA;
public String getValSubA() {
return valSubA;
}
public void setValSubA(String valSubA) {
this.valSubA = valSubA;
}
}
@Entity(name = "SubSubA")
@Table(name = SubSubA.TABLE)
static class SubSubA extends SubA {
public static final String TABLE = "SubSubA_Table";
private String valSubSubA;
public String getValSubSubA() {
return valSubSubA;
}
public void setValSubSubA(String valSubSubA) {
this.valSubSubA = valSubSubA;
}
}
@Entity(name = "B")
@Table(name = B.TABLE)
static class B {
public static final String TABLE = "B_table";
@Id
@GeneratedValue
private Long id;
private String valB;
@OneToMany(mappedBy = "b")
private List<A> aList;
public Long getId() {
return id;
}
public String getValB() {
return valB;
}
public void setValB(String valB) {
this.valB = valB;
}
public List<A> getaList() {
return aList;
}
public void setaList(List<A> aList) {
this.aList = aList;
}
}
}

View File

@ -1,262 +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.test.joinwithoutancestor;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.Entity;
import javax.persistence.ForeignKey;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.ManyToOne;
import javax.persistence.SecondaryTable;
import javax.persistence.Table;
import org.hibernate.query.Query;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.transaction.TransactionUtil;
import org.junit.Assert;
import org.junit.Test;
@TestForIssue(jiraKey = "HHH-12993")
public class OmitAncestorJoinWhenCommonSecondaryTablePresentTest extends OmitAncestorTestCase {
private static final String SECONDARY_TABLE_NAME = "secondary_table";
@Override
protected Class[] getAnnotatedClasses() {
return new Class[] { A.class, SubA.class, B.class, SubB.class, C.class };
}
@Override
protected boolean isCleanupTestDataRequired() {
return true;
}
@Override
protected void cleanupTestData() throws Exception {
TransactionUtil.doInHibernate( this::sessionFactory, s -> {
s.createQuery( "from A", A.class ).list().forEach( s::remove );
s.createQuery( "from B", B.class ).list().forEach( s::remove );
s.createQuery( "from C", C.class ).list().forEach( s::remove );
} );
super.cleanupTestData();
}
@Test
public void shouldNotReturnSecondaryTableValueForSubB() {
TransactionUtil.doInHibernate( this::sessionFactory, session -> {
SubA subA = new SubA( 1L );
subA.setValSubA( "valSubA" );
subA.setValSecondaryTable( "valSecondaryTableFromSubA" );
session.persist( subA );
SubB subB = new SubB( 2L );
subB.setValSubB( "valSubB" );
subB.setValSecondaryTable( "valSecondaryTableFromSubB" );
session.persist( subB );
Query<String> query = session.createQuery( "select suba.valSecondaryTable from SubA suba", String.class );
List<String> resultList = query.getResultList();
Assert.assertEquals( 1, resultList.size() );
Assert.assertEquals( "valSecondaryTableFromSubA", resultList.get( 0 ) );
} );
}
@Test
public void shouldNotReturnSecondaryTableValueForSubB_implicitJoin() {
TransactionUtil.doInHibernate( this::sessionFactory, session -> {
SubA subA = new SubA( 1L );
subA.setValSubA( "valSubA" );
subA.setValSecondaryTable( "valSecondaryTableFromSubA" );
session.persist( subA );
SubB subB = new SubB( 2L );
subB.setValSubB( "valSubB" );
subB.setValSecondaryTable( "valSecondaryTableFromSubB" );
session.persist( subB );
C c = new C();
c.setSubA( subA );
session.persist( c );
Query<String> query = session.createQuery( "select c.subA.valSecondaryTable from C c", String.class );
List<String> resultList = query.getResultList();
Assert.assertEquals( 1, resultList.size() );
Assert.assertEquals( "valSecondaryTableFromSubA", resultList.get( 0 ) );
} );
}
@Entity(name = "A")
@Table(name = A.TABLE)
@Inheritance(strategy = InheritanceType.JOINED)
static class A {
public static final String TABLE = "A_Table";
public A() {
}
public A(Long id) {
this.id = id;
}
@Id
private Long id;
private String valA;
public Long getId() {
return id;
}
public String getValA() {
return valA;
}
public void setValA(String valA) {
this.valA = valA;
}
}
@Entity(name = "SubA")
@Table(name = SubA.TABLE)
@SecondaryTable(name = SECONDARY_TABLE_NAME, foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT))
static class SubA extends A {
public static final String TABLE = "SubA_table";
public SubA() {
}
public SubA(Long id) {
super( id );
}
private String valSubA;
@Column(table = SECONDARY_TABLE_NAME)
private String valSecondaryTable;
public String getValSubA() {
return valSubA;
}
public void setValSubA(String valSubA) {
this.valSubA = valSubA;
}
public String getValSecondaryTable() {
return valSecondaryTable;
}
public void setValSecondaryTable(String valSecondaryTable) {
this.valSecondaryTable = valSecondaryTable;
}
}
@Entity(name = "B")
@Table(name = B.TABLE)
@Inheritance(strategy = InheritanceType.JOINED)
static class B {
public static final String TABLE = "B_Table";
public B() {
}
public B(Long id) {
this.id = id;
}
@Id
private Long id;
private String valB;
public Long getId() {
return id;
}
public String getValB() {
return valB;
}
public void setValB(String valB) {
this.valB = valB;
}
}
@Entity(name = "SubB")
@Table(name = SubB.TABLE)
@SecondaryTable(name = SECONDARY_TABLE_NAME, foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT))
static class SubB extends B {
public static final String TABLE = "SubB_table";
public SubB() {
}
public SubB(Long id) {
super( id );
}
private String valSubB;
@Column(table = SECONDARY_TABLE_NAME)
private String valSecondaryTable;
public String getValSubB() {
return valSubB;
}
public void setValSubB(String valSubB) {
this.valSubB = valSubB;
}
public String getValSecondaryTable() {
return valSecondaryTable;
}
public void setValSecondaryTable(String valSecondaryTable) {
this.valSecondaryTable = valSecondaryTable;
}
}
@Entity(name = "C")
@Table(name = C.TABLE)
static class C {
public static final String TABLE = "C_table";
@Id
@GeneratedValue
private Long id;
@ManyToOne
private SubA subA;
public Long getId() {
return id;
}
public SubA getSubA() {
return subA;
}
public void setSubA(SubA subA) {
this.subA = subA;
}
}
}

View File

@ -1,107 +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.test.joinwithoutancestor;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.SecondaryTable;
import javax.persistence.Table;
import org.hibernate.testing.TestForIssue;
import org.junit.Test;
@TestForIssue(jiraKey = "HHH-12993")
public class OmitAncestorJoinWhenSecondaryTablePresentTest extends OmitAncestorTestCase {
@Override
protected Class[] getAnnotatedClasses() {
return new Class[] { A.class, SubA.class, SubSubA.class };
}
@Test
public void test() {
assertFromTables( "select valSubASecondaryTable from SubA", SubA.TABLE, SubSubA.TABLE, SubA.SECONDARY_TABLE );
}
@Entity(name = "A")
@Table(name = A.TABLE)
@Inheritance(strategy = InheritanceType.JOINED)
static class A {
public static final String TABLE = "A_Table";
@Id
@GeneratedValue
private Long id;
private String valA;
public Long getId() {
return id;
}
public String getValA() {
return valA;
}
public void setValA(String valA) {
this.valA = valA;
}
}
@Entity(name = "SubA")
@Table(name = SubA.TABLE)
@SecondaryTable(name = SubA.SECONDARY_TABLE)
static class SubA extends A {
public static final String TABLE = "SubA_Table";
public static final String SECONDARY_TABLE = "SubA_Table_Sec";
private String valSubA;
@Column(table = SECONDARY_TABLE)
private String valSubASecondaryTable;
public String getValSubA() {
return valSubA;
}
public void setValSubA(String valSubA) {
this.valSubA = valSubA;
}
public String getValSubASecondaryTable() {
return valSubASecondaryTable;
}
public void setValSubASecondaryTable(String valSubASecondaryTable) {
this.valSubASecondaryTable = valSubASecondaryTable;
}
}
@Entity(name = "SubSubA")
@Table(name = SubSubA.TABLE)
static class SubSubA extends SubA {
public static final String TABLE = "SubSubA_Table";
private String valSubSubA;
public String getValSubSubA() {
return valSubSubA;
}
public void setValSubSubA(String valSubSubA) {
this.valSubSubA = valSubSubA;
}
}
}

View File

@ -1,48 +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.test.joinwithoutancestor;
import org.hibernate.Session;
import org.hibernate.engine.query.spi.HQLQueryPlan;
import org.hibernate.engine.query.spi.QueryPlanCache;
import org.hibernate.hql.spi.QueryTranslator;
import org.hibernate.internal.SessionImpl;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.hibernate.testing.transaction.TransactionUtil;
public abstract class OmitAncestorTestCase extends BaseCoreFunctionalTestCase {
protected void assertFromTables(String query, String... tables) {
try {
TransactionUtil.doInHibernate( this::sessionFactory, session -> {
String sql = getSql( session, query );
SqlAsserts.assertFromTables( sql, tables );
session.createQuery( query ).getResultList();
} );
}
catch (AssertionError e) {
throw e;
}
}
protected String getSql(Session session, String hql) {
// Create query
session.createQuery( hql );
// Get plan from cache
QueryPlanCache queryPlanCache = sessionFactory().getQueryPlanCache();
HQLQueryPlan hqlQueryPlan = queryPlanCache.getHQLQueryPlan(
hql,
false,
( (SessionImpl) session ).getLoadQueryInfluencers().getEnabledFilters()
);
QueryTranslator queryTranslator = hqlQueryPlan.getTranslators()[0];
String sql = queryTranslator.getSQLString();
return sql;
}
}