- * The default mode is {@link org.hibernate.query.criteria.ValueHandlingMode#BIND}.
+ *
+ * @settingDefault {@link org.hibernate.query.criteria.ValueHandlingMode#BIND}.
*
* @since 6.0.0
*
@@ -101,8 +103,8 @@ public interface QuerySettings {
* Specifies the default {@linkplain NullPrecedence precedence of null values} in the
* HQL {@code ORDER BY} clause, either {@code none}, {@code first}, or {@code last},
* or an instance of {@link NullPrecedence}.
- *
- * The default is {@code none}.
+ *
+ * @settingDefault {@code none}.
*
* @see NullPrecedence
* @see org.hibernate.boot.SessionFactoryBuilder#applyDefaultNullPrecedence(NullPrecedence)
@@ -135,10 +137,10 @@ public interface QuerySettings {
String CRITERIA_COPY_TREE = "hibernate.criteria.copy_tree";
/**
- * When set to true, indicates that ordinal parameters (represented by the '?' placeholder) in native queries will be ignored.
- *
- * By default, this is set to false, i.e. native queries will be checked for ordinal placeholders.
- *
+ * When enabled, ordinal parameters (represented by the {@code ?} placeholder) in
+ * native queries will be ignored.
+ *
+ * @settingDefault {@code false} (disabled) - native queries are checked for ordinal placeholders.
*
* @see SessionFactoryOptions#getNativeJdbcParametersIgnored()
*/
@@ -152,9 +154,9 @@ public interface QuerySettings {
*
* When enabled, this setting specifies that an exception should be thrown for any
* query which would result in the limit being applied in-memory.
- *
{@link org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode#EXCEPTION "exception"}
* specifies that a {@link org.hibernate.HibernateException} should be thrown.
*
- *
- * By default, a warning is logged.
+ *
+ * @settingDefault {@link org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode#WARNING "warning"}
*
* @since 5.2.17
*
diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/SchemaToolingSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/SchemaToolingSettings.java
index 86f7a9153076..39c52f577131 100644
--- a/hibernate-core/src/main/java/org/hibernate/cfg/SchemaToolingSettings.java
+++ b/hibernate-core/src/main/java/org/hibernate/cfg/SchemaToolingSettings.java
@@ -391,6 +391,14 @@ public interface SchemaToolingSettings {
@Deprecated
String HBM2DDL_IMPORT_FILES = "hibernate.hbm2ddl.import_files";
+ /**
+ * Specifies if the default {@code /import.sql} script file should not be executed
+ * when {@link #HBM2DDL_IMPORT_FILES} is not specified and {@value #HBM2DDL_AUTO} is set to {@code create} or {@code create-drop}.
+ *
+ * The default value is {@code false}.
+ */
+ String HBM2DDL_SKIP_DEFAULT_IMPORT_FILE = "hibernate.hbm2ddl.skip_default_import_file";
+
/**
* Specifies whether to automatically create also the database schema/catalog.
* The default is false.
diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/TransactionSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/TransactionSettings.java
index 94d284499b23..6783f87eb9f7 100644
--- a/hibernate-core/src/main/java/org/hibernate/cfg/TransactionSettings.java
+++ b/hibernate-core/src/main/java/org/hibernate/cfg/TransactionSettings.java
@@ -6,6 +6,7 @@
*/
package org.hibernate.cfg;
+
import jakarta.persistence.spi.PersistenceUnitInfo;
/**
@@ -129,6 +130,26 @@ public interface TransactionSettings {
*/
String ALLOW_JTA_TRANSACTION_ACCESS = "hibernate.jta.allowTransactionAccess";
+ /**
+ * When enabled, specifies that the {@link org.hibernate.Session} should be
+ * closed automatically at the end of each transaction.
+ *
+ * @settingDefault {@code false}
+ *
+ * @see org.hibernate.boot.SessionFactoryBuilder#applyAutoClosing(boolean)
+ */
+ String AUTO_CLOSE_SESSION = "hibernate.transaction.auto_close_session";
+
+ /**
+ * When enabled, specifies that automatic flushing should occur during the JTA
+ * {@link jakarta.transaction.Synchronization#beforeCompletion()} callback.
+ *
+ * @settingDefault {@code true} unless using JPA bootstrap
+ *
+ * @see org.hibernate.boot.SessionFactoryBuilder#applyAutoFlushing(boolean)
+ */
+ String FLUSH_BEFORE_COMPLETION = "hibernate.transaction.flush_before_completion";
+
/**
* Allows a detached proxy or lazy collection to be fetched even when not
* associated with an open persistence context, by creating a temporary
@@ -138,8 +159,11 @@ public interface TransactionSettings {
*
* @settingDefault {@code false} (disabled)
*
+ * @apiNote Generally speaking, all access to transactional data should be done in a transaction.
+ *
* @see org.hibernate.boot.SessionFactoryBuilder#applyLazyInitializationOutsideTransaction(boolean)
*/
+ @Unsafe
String ENABLE_LAZY_LOAD_NO_TRANS = "hibernate.enable_lazy_load_no_trans";
/**
@@ -153,29 +177,15 @@ public interface TransactionSettings {
*
* The default behavior is to disallow update operations outside a transaction.
*
+ * @settingDefault {@code false} (disabled)
+ *
+ * @apiNote Generally speaking, all access to transactional data should be done in a transaction.
+ * Combining this with second-level caching, e.g., will cause problems.
+ *
* @see org.hibernate.boot.SessionFactoryBuilder#allowOutOfTransactionUpdateOperations(boolean)
*
* @since 5.2
*/
+ @Unsafe
String ALLOW_UPDATE_OUTSIDE_TRANSACTION = "hibernate.allow_update_outside_transaction";
-
- /**
- * When enabled, specifies that the {@link org.hibernate.Session} should be
- * closed automatically at the end of each transaction.
- *
- * @settingDefault {@code false}
- *
- * @see org.hibernate.boot.SessionFactoryBuilder#applyAutoClosing(boolean)
- */
- String AUTO_CLOSE_SESSION = "hibernate.transaction.auto_close_session";
-
- /**
- * When enabled, specifies that automatic flushing should occur during the JTA
- * {@link jakarta.transaction.Synchronization#beforeCompletion()} callback.
- *
- * @settingDefault {@code true} unless using JPA bootstrap
- *
- * @see org.hibernate.boot.SessionFactoryBuilder#applyAutoFlushing(boolean)
- */
- String FLUSH_BEFORE_COMPLETION = "hibernate.transaction.flush_before_completion";
}
diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Unsafe.java b/hibernate-core/src/main/java/org/hibernate/cfg/Unsafe.java
new file mode 100644
index 000000000000..ca9056957d72
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/cfg/Unsafe.java
@@ -0,0 +1,24 @@
+/*
+ * 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.cfg;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+
+/**
+ * Denotes that a setting is considered unsafe. Generally these are settings
+ * added for temporary use during porting of applications. Unsafe settings
+ * are largely considered unsupported.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.CLASS)
+@Documented
+public @interface Unsafe {
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/collection/spi/AbstractPersistentCollection.java b/hibernate-core/src/main/java/org/hibernate/collection/spi/AbstractPersistentCollection.java
index 1df1aed42822..f90dde51591c 100644
--- a/hibernate-core/src/main/java/org/hibernate/collection/spi/AbstractPersistentCollection.java
+++ b/hibernate-core/src/main/java/org/hibernate/collection/spi/AbstractPersistentCollection.java
@@ -238,31 +238,30 @@ else if ( !session.isConnected() ) {
SharedSessionContractImplementor originalSession = null;
boolean isJTA = false;
+ try {
+ if ( tempSession != null ) {
+ isTempSession = true;
+ originalSession = session;
+ session = tempSession;
+
+ isJTA = session.getTransactionCoordinator().getTransactionCoordinatorBuilder().isJta();
+
+ if ( !isJTA ) {
+ // Explicitly handle the transactions only if we're not in
+ // a JTA environment. A lazy loading temporary session can
+ // be created even if a current session and transaction are
+ // open (ex: session.clear() was used). We must prevent
+ // multiple transactions.
+ session.beginTransaction();
+ }
- if ( tempSession != null ) {
- isTempSession = true;
- originalSession = session;
- session = tempSession;
-
- isJTA = session.getTransactionCoordinator().getTransactionCoordinatorBuilder().isJta();
-
- if ( !isJTA ) {
- // Explicitly handle the transactions only if we're not in
- // a JTA environment. A lazy loading temporary session can
- // be created even if a current session and transaction are
- // open (ex: session.clear() was used). We must prevent
- // multiple transactions.
- session.beginTransaction();
+ final CollectionPersister collectionDescriptor =
+ session.getSessionFactory()
+ .getMappingMetamodel()
+ .getCollectionDescriptor( getRole() );
+ session.getPersistenceContextInternal()
+ .addUninitializedDetachedCollection( collectionDescriptor, this );
}
-
- final CollectionPersister collectionDescriptor =
- session.getSessionFactory()
- .getMappingMetamodel()
- .getCollectionDescriptor( getRole() );
- session.getPersistenceContextInternal().addUninitializedDetachedCollection( collectionDescriptor, this );
- }
-
- try {
return lazyInitializationWork.doWork();
}
finally {
@@ -1298,8 +1297,8 @@ protected static Collection getOrphans(
// iterate over the *old* list
for ( E old : oldElements ) {
if ( !currentSaving.contains( old ) ) {
- final Object oldId = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, old, session );
- if ( !currentIds.contains( useIdDirect ? oldId : new TypedValue( idType, oldId ) ) ) {
+ final Object oldId = ForeignKeys.getEntityIdentifier( entityName, old, session );
+ if ( oldId != null && !currentIds.contains( useIdDirect ? oldId : new TypedValue( idType, oldId ) ) ) {
res.add( old );
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentArrayHolder.java b/hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentArrayHolder.java
index 778dce73413e..4e718070bb5a 100644
--- a/hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentArrayHolder.java
+++ b/hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentArrayHolder.java
@@ -9,6 +9,7 @@
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
@@ -94,6 +95,9 @@ public boolean isSnapshotEmpty(Serializable snapshot) {
public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
final Object[] sn = (Object[]) snapshot;
final Object[] arr = (Object[]) array;
+ if ( arr.length == 0 ) {
+ return Arrays.asList( sn );
+ }
final ArrayList result = new ArrayList();
Collections.addAll( result, sn );
for ( int i=0; i returningColumns) {
// For DB2 we use #renderReturningClause to render a wrapper around the DML statement
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DB2iDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DB2iDialect.java
index 3b0a9fcc1212..e52bf220646d 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2iDialect.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2iDialect.java
@@ -6,6 +6,7 @@
*/
package org.hibernate.dialect;
+import org.hibernate.LockOptions;
import org.hibernate.boot.model.FunctionContributions;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.identity.DB2IdentityColumnSupport;
@@ -41,6 +42,9 @@ public class DB2iDialect extends DB2Dialect {
private final static DatabaseVersion MINIMUM_VERSION = DatabaseVersion.make( 7, 1 );
final static DatabaseVersion DB2_LUW_VERSION = DB2Dialect.MINIMUM_VERSION;
+ private static final String FOR_UPDATE_SQL = " for update with rs";
+ private static final String FOR_UPDATE_SKIP_LOCKED_SQL = FOR_UPDATE_SQL + " skip locked data";
+
public DB2iDialect(DialectResolutionInfo info) {
this( info.makeCopyOrDefault( MINIMUM_VERSION ) );
registerKeywords( info );
@@ -124,6 +128,7 @@ public String getQuerySequencesString() {
}
}
+
@Override
public LimitHandler getLimitHandler() {
return getVersion().isSameOrAfter(7, 3)
@@ -171,4 +176,35 @@ public int rowIdSqlType() {
public String getRowIdColumnString(String rowId) {
return rowId( rowId ) + " rowid not null generated always";
}
+
+ @Override
+ public String getForUpdateString() {
+ return FOR_UPDATE_SQL;
+ }
+
+ @Override
+ public String getForUpdateSkipLockedString() {
+ return supportsSkipLocked()
+ ? FOR_UPDATE_SKIP_LOCKED_SQL
+ : FOR_UPDATE_SQL;
+ }
+
+ @Override
+ public String getForUpdateSkipLockedString(String aliases) {
+ return getForUpdateSkipLockedString();
+ }
+
+ @Override
+ public String getWriteLockString(int timeout) {
+ return timeout == LockOptions.SKIP_LOCKED && supportsSkipLocked()
+ ? FOR_UPDATE_SKIP_LOCKED_SQL
+ : FOR_UPDATE_SQL;
+ }
+
+ @Override
+ public String getReadLockString(int timeout) {
+ return timeout == LockOptions.SKIP_LOCKED && supportsSkipLocked()
+ ? FOR_UPDATE_SKIP_LOCKED_SQL
+ : FOR_UPDATE_SQL;
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DB2iSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/DB2iSqlAstTranslator.java
index 0ea3a26bfabf..3abf55648652 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2iSqlAstTranslator.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2iSqlAstTranslator.java
@@ -60,4 +60,9 @@ protected void renderComparison(Expression lhs, ComparisonOperator operator, Exp
public DatabaseVersion getDB2Version() {
return DB2_LUW_VERSION;
}
+
+ @Override
+ protected String getForUpdate() {
+ return " for update with rs";
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DerbyDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DerbyDialect.java
index d4a5e9ff15ce..1b0ddc2fee2b 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/DerbyDialect.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/DerbyDialect.java
@@ -1040,6 +1040,11 @@ public boolean supportsWindowFunctions() {
return true;
}
+ @Override
+ public boolean supportsValuesList() {
+ return true;
+ }
+
@Override
public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData)
throws SQLException {
@@ -1057,4 +1062,14 @@ public DmlTargetColumnQualifierSupport getDmlTargetColumnQualifierSupport() {
return DmlTargetColumnQualifierSupport.TABLE_ALIAS;
}
+ @Override
+ public String getDual() {
+ return "(values 0)";
+ }
+
+ @Override
+ public String getFromDualForSelectOnly() {
+ return " from " + getDual() + " dual";
+ }
+
}
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DerbySqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/DerbySqlAstTranslator.java
index 2788fca3a688..a830f79ada6c 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/DerbySqlAstTranslator.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/DerbySqlAstTranslator.java
@@ -302,16 +302,6 @@ protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
- @Override
- protected String getDual() {
- return "(values 0)";
- }
-
- @Override
- protected String getFromDualForSelectOnly() {
- return " from " + getDual() + " dual";
- }
-
@Override
protected boolean needsRowsToSkip() {
return !supportsOffsetFetchClause();
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java
index 597c2d248677..1d686d28dacd 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java
@@ -1441,7 +1441,7 @@ public String castPattern(CastType from, CastType to) {
case INTEGER_BOOLEAN:
switch ( from ) {
case STRING:
- return "case ?1 when 'T' then 1 when 'Y' then 1 when 'F' then 0 when 'N' then 0 else null end";
+ return buildStringToBooleanCast( "1", "0" );
case INTEGER:
case LONG:
return "abs(sign(?1))";
@@ -1456,7 +1456,7 @@ public String castPattern(CastType from, CastType to) {
case YN_BOOLEAN:
switch ( from ) {
case STRING:
- return "case ?1 when 'T' then 'Y' when 'Y' then 'Y' when 'F' then 'N' when 'N' then 'N' else null end";
+ return buildStringToBooleanCast( "'Y'", "'N'" );
case INTEGER_BOOLEAN:
return "case ?1 when 1 then 'Y' when 0 then 'N' else null end";
case INTEGER:
@@ -1471,7 +1471,7 @@ public String castPattern(CastType from, CastType to) {
case TF_BOOLEAN:
switch ( from ) {
case STRING:
- return "case ?1 when 'T' then 'T' when 'Y' then 'T' when 'F' then 'F' when 'N' then 'F' else null end";
+ return buildStringToBooleanCast( "'T'", "'F'" );
case INTEGER_BOOLEAN:
return "case ?1 when 1 then 'T' when 0 then 'F' else null end";
case INTEGER:
@@ -1486,7 +1486,7 @@ public String castPattern(CastType from, CastType to) {
case BOOLEAN:
switch ( from ) {
case STRING:
- return "case ?1 when 'T' then true when 'Y' then true when 'F' then false when 'N' then false else null end";
+ return buildStringToBooleanCast( "true", "false" );
case INTEGER_BOOLEAN:
case INTEGER:
case LONG:
@@ -1501,6 +1501,153 @@ public String castPattern(CastType from, CastType to) {
return "cast(?1 as ?2)";
}
+ protected static final String[] TRUE_STRING_VALUES = new String[] { "t", "true", "y", "1" };
+ protected static final String[] FALSE_STRING_VALUES = new String[] { "f", "false", "n", "0" };
+
+ protected String buildStringToBooleanCast(String trueValue, String falseValue) {
+ final boolean supportsValuesList = supportsValuesList();
+ final StringBuilder sb = new StringBuilder();
+ sb.append( "(select v.x from (" );
+ if ( supportsValuesList ) {
+ sb.append( "values (" );
+ sb.append( trueValue );
+ sb.append( "),(" );
+ sb.append( falseValue );
+ sb.append( ")) v(x)" );
+ }
+ else {
+ sb.append( "select " );
+ sb.append( trueValue );
+ sb.append( " x");
+ sb.append( getFromDualForSelectOnly() );
+ sb.append(" union all select " );
+ sb.append( falseValue );
+ sb.append( getFromDualForSelectOnly() );
+ sb.append( ") v" );
+ }
+ sb.append( " left join (" );
+ if ( supportsValuesList ) {
+ sb.append( "values" );
+ char separator = ' ';
+ for ( String trueStringValue : Dialect.TRUE_STRING_VALUES ) {
+ sb.append( separator );
+ sb.append( "('" );
+ sb.append( trueStringValue );
+ sb.append( "'," );
+ sb.append( trueValue );
+ sb.append( ')' );
+ separator = ',';
+ }
+ for ( String falseStringValue : Dialect.FALSE_STRING_VALUES ) {
+ sb.append( ",('" );
+ sb.append( falseStringValue );
+ sb.append( "'," );
+ sb.append( falseValue );
+ sb.append( ')' );
+ }
+ sb.append( ") t(k,v)" );
+ }
+ else {
+ sb.append( "select '" );
+ sb.append( Dialect.TRUE_STRING_VALUES[0] );
+ sb.append( "' k," );
+ sb.append( trueValue );
+ sb.append( " v" );
+ sb.append( getFromDualForSelectOnly() );
+ for ( int i = 1; i < Dialect.TRUE_STRING_VALUES.length; i++ ) {
+ sb.append( " union all select '" );
+ sb.append( Dialect.TRUE_STRING_VALUES[i] );
+ sb.append( "'," );
+ sb.append( trueValue );
+ sb.append( getFromDualForSelectOnly() );
+ }
+ for ( String falseStringValue : Dialect.FALSE_STRING_VALUES ) {
+ sb.append( " union all select '" );
+ sb.append( falseStringValue );
+ sb.append( "'," );
+ sb.append( falseValue );
+ sb.append( getFromDualForSelectOnly() );
+ }
+ sb.append( ") t" );
+ }
+ sb.append( " on " );
+ sb.append( getLowercaseFunction() );
+ sb.append( "(?1)=t.k where t.v is null or v.x=t.v)" );
+ return sb.toString();
+ }
+
+ protected String buildStringToBooleanCastDecode(String trueValue, String falseValue) {
+ final boolean supportsValuesList = supportsValuesList();
+ final StringBuilder sb = new StringBuilder();
+ sb.append( "(select v.x from (" );
+ if ( supportsValuesList ) {
+ sb.append( "values (" );
+ sb.append( trueValue );
+ sb.append( "),(" );
+ sb.append( falseValue );
+ sb.append( ")) v(x)" );
+ }
+ else {
+ sb.append( "select " );
+ sb.append( trueValue );
+ sb.append( " x");
+ sb.append( getFromDualForSelectOnly() );
+ sb.append(" union all select " );
+ sb.append( falseValue );
+ sb.append( getFromDualForSelectOnly() );
+ sb.append( ") v" );
+ }
+ sb.append( ", (" );
+ if ( supportsValuesList ) {
+ sb.append( "values (" );
+ sb.append( buildStringToBooleanDecode( trueValue, falseValue ) );
+ sb.append( ")) t(v)" );
+ }
+ else {
+ sb.append( "select " );
+ sb.append( buildStringToBooleanDecode( trueValue, falseValue ) );
+ sb.append( " v");
+ sb.append( getFromDualForSelectOnly() );
+ sb.append(") t" );
+ }
+ sb.append( " where t.v is null or v.x=t.v)" );
+ return sb.toString();
+ }
+
+ protected String buildStringToBooleanDecode(String trueValue, String falseValue) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append( "decode(" );
+ sb.append( getLowercaseFunction() );
+ sb.append( "(?1)" );
+ for ( String trueStringValue : TRUE_STRING_VALUES ) {
+ sb.append( ",'" );
+ sb.append( trueStringValue );
+ sb.append( "'," );
+ sb.append( trueValue );
+ }
+ for ( String falseStringValue : FALSE_STRING_VALUES ) {
+ sb.append( ",'" );
+ sb.append( falseStringValue );
+ sb.append( "'," );
+ sb.append( falseValue );
+ }
+ sb.append( ",null)" );
+ return sb.toString();
+ }
+
+ /**
+ * Returns a table expression that has one row.
+ *
+ * @return the SQL equivalent to Oracle's {@code dual}.
+ */
+ public String getDual() {
+ return "(values(0))";
+ }
+
+ public String getFromDualForSelectOnly() {
+ return "";
+ }
+
/**
* Obtain a pattern for the SQL equivalent to a
* {@code trim()} function call. The resulting
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java
index 622479b703e7..6aa5aba5726a 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java
@@ -44,6 +44,7 @@
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.entity.mutation.EntityMutationTarget;
+import org.hibernate.query.sqm.CastType;
import org.hibernate.query.sqm.FetchClauseType;
import org.hibernate.query.sqm.IntervalType;
import org.hibernate.query.sqm.TemporalUnit;
@@ -445,6 +446,16 @@ public String extractPattern(TemporalUnit unit) {
: super.extractPattern(unit);
}
+ @Override
+ public String castPattern(CastType from, CastType to) {
+ if ( from == CastType.STRING && to == CastType.BOOLEAN ) {
+ return "cast(?1 as ?2)";
+ }
+ else {
+ return super.castPattern( from, to );
+ }
+ }
+
@Override
public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType, IntervalType intervalType) {
if ( intervalType != null ) {
@@ -1007,4 +1018,14 @@ public boolean supportsCaseInsensitiveLike(){
return true;
}
+ @Override
+ public boolean supportsValuesList() {
+ return true;
+ }
+
+ @Override
+ public String getDual() {
+ return "dual";
+ }
+
}
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/H2SqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/H2SqlAstTranslator.java
index 4554d948dac5..fe824b0dd052 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/H2SqlAstTranslator.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/H2SqlAstTranslator.java
@@ -314,13 +314,9 @@ protected boolean renderPrimaryTableReference(TableGroup tableGroup, LockMode lo
final TableReference tableRef = tableGroup.getPrimaryTableReference();
// The H2 parser can't handle a sub-query as first element in a nested join
// i.e. `join ( (select ...) alias join ... )`, so we have to introduce a dummy table reference
- if ( tableRef instanceof QueryPartTableReference || tableRef.getTableId().startsWith( "(select" ) ) {
- final boolean realTableGroup = tableGroup.isRealTableGroup()
- && ( isNotEmpty( tableGroup.getTableReferenceJoins() )
- || hasNestedTableGroupsToRender( tableGroup.getNestedTableGroupJoins() ) );
- if ( realTableGroup ) {
- appendSql( "dual cross join " );
- }
+ if ( getSqlBuffer().charAt( getSqlBuffer().length() - 1 ) == '('
+ && ( tableRef instanceof QueryPartTableReference || tableRef.getTableId().startsWith( "(select" ) ) ) {
+ appendSql( "dual cross join " );
}
return super.renderPrimaryTableReference( tableGroup, lockMode );
}
@@ -365,11 +361,6 @@ protected boolean supportsNullPrecedence() {
return true;
}
- @Override
- protected String getDual() {
- return "dual";
- }
-
private boolean supportsOffsetFetchClause() {
return true;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/HANASqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/HANASqlAstTranslator.java
index c77eac47d6ce..859e1fa38f26 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/HANASqlAstTranslator.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/HANASqlAstTranslator.java
@@ -252,16 +252,6 @@ protected boolean supportsRowValueConstructorGtLtSyntax() {
return false;
}
- @Override
- protected String getDual() {
- return "sys.dummy";
- }
-
- @Override
- protected String getFromDualForSelectOnly() {
- return " from " + getDual();
- }
-
@Override
protected void renderInsertIntoNoColumns(TableInsertStandard tableInsert) {
throw new MappingException(
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java
index fa0ca8189f4a..91f831288e19 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java
@@ -255,25 +255,33 @@ public String castPattern(CastType from, CastType to) {
}
break;
case BOOLEAN:
- result = BooleanDecoder.toBoolean( from );
+ result = from == CastType.STRING
+ ? buildStringToBooleanCastDecode( "true", "false" )
+ : BooleanDecoder.toBoolean( from );
if ( result != null ) {
return result;
}
break;
case INTEGER_BOOLEAN:
- result = BooleanDecoder.toIntegerBoolean( from );
+ result = from == CastType.STRING
+ ? buildStringToBooleanCastDecode( "1", "0" )
+ : BooleanDecoder.toIntegerBoolean( from );
if ( result != null ) {
return result;
}
break;
case YN_BOOLEAN:
- result = BooleanDecoder.toYesNoBoolean( from );
+ result = from == CastType.STRING
+ ? buildStringToBooleanCastDecode( "'Y'", "'N'" )
+ : BooleanDecoder.toYesNoBoolean( from );
if ( result != null ) {
return result;
}
break;
case TF_BOOLEAN:
- result = BooleanDecoder.toTrueFalseBoolean( from );
+ result = from == CastType.STRING
+ ? buildStringToBooleanCastDecode( "'T'", "'F'" )
+ : BooleanDecoder.toTrueFalseBoolean( from );
if ( result != null ) {
return result;
}
@@ -647,6 +655,11 @@ public boolean requiresFloatCastingOfIntegerDivision() {
return true;
}
+ @Override
+ public boolean supportsValuesList() {
+ return true;
+ }
+
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return identityColumnSupport;
@@ -727,4 +740,9 @@ public String quoteCollation(String collation) {
public DmlTargetColumnQualifierSupport getDmlTargetColumnQualifierSupport() {
return DmlTargetColumnQualifierSupport.TABLE_ALIAS;
}
+
+ @Override
+ public String getFromDualForSelectOnly() {
+ return " from " + getDual();
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLSqlAstTranslator.java
index f458720b9b7a..1357e12f522c 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLSqlAstTranslator.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLSqlAstTranslator.java
@@ -12,14 +12,12 @@
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
import org.hibernate.query.IllegalQueryOperationException;
-import org.hibernate.query.sqm.BinaryArithmeticOperator;
import org.hibernate.query.sqm.ComparisonOperator;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
-import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
import org.hibernate.sql.ast.tree.expression.Expression;
@@ -152,8 +150,7 @@ protected void visitRecursivePath(Expression recursivePath, int sizeEstimate) {
protected void visitAnsiCaseSearchedExpression(
CaseSearchedExpression expression,
Consumer resultRenderer) {
- if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( expression )
- || areAllResultsPlainParametersOrLiterals( expression ) ) {
+ if ( areAllResultsPlainParametersOrStringLiterals( expression ) ) {
final List whenFragments = expression.getWhenFragments();
final Expression firstResult = whenFragments.get( 0 ).getResult();
super.visitAnsiCaseSearchedExpression(
@@ -177,8 +174,7 @@ protected void visitAnsiCaseSearchedExpression(
protected void visitAnsiCaseSimpleExpression(
CaseSimpleExpression expression,
Consumer resultRenderer) {
- if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( expression )
- || areAllResultsPlainParametersOrLiterals( expression ) ) {
+ if ( areAllResultsPlainParametersOrStringLiterals( expression ) ) {
final List whenFragments = expression.getWhenFragments();
final Expression firstResult = whenFragments.get( 0 ).getResult();
super.visitAnsiCaseSimpleExpression(
@@ -198,11 +194,11 @@ protected void visitAnsiCaseSimpleExpression(
}
}
- protected boolean areAllResultsPlainParametersOrLiterals(CaseSearchedExpression caseSearchedExpression) {
+ protected boolean areAllResultsPlainParametersOrStringLiterals(CaseSearchedExpression caseSearchedExpression) {
final List whenFragments = caseSearchedExpression.getWhenFragments();
final Expression firstResult = whenFragments.get( 0 ).getResult();
if ( isParameter( firstResult ) && getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT
- || isLiteral( firstResult ) ) {
+ || isStringLiteral( firstResult ) ) {
for ( int i = 1; i < whenFragments.size(); i++ ) {
final Expression result = whenFragments.get( i ).getResult();
if ( isParameter( result ) ) {
@@ -210,7 +206,7 @@ protected boolean areAllResultsPlainParametersOrLiterals(CaseSearchedExpression
return false;
}
}
- else if ( !isLiteral( result ) ) {
+ else if ( !isStringLiteral( result ) ) {
return false;
}
}
@@ -219,11 +215,11 @@ else if ( !isLiteral( result ) ) {
return false;
}
- protected boolean areAllResultsPlainParametersOrLiterals(CaseSimpleExpression caseSimpleExpression) {
+ protected boolean areAllResultsPlainParametersOrStringLiterals(CaseSimpleExpression caseSimpleExpression) {
final List whenFragments = caseSimpleExpression.getWhenFragments();
final Expression firstResult = whenFragments.get( 0 ).getResult();
if ( isParameter( firstResult ) && getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT
- || isLiteral( firstResult ) ) {
+ || isStringLiteral( firstResult ) ) {
for ( int i = 1; i < whenFragments.size(); i++ ) {
final Expression result = whenFragments.get( i ).getResult();
if ( isParameter( result ) ) {
@@ -231,7 +227,7 @@ protected boolean areAllResultsPlainParametersOrLiterals(CaseSimpleExpression ca
return false;
}
}
- else if ( !isLiteral( result ) ) {
+ else if ( !isStringLiteral( result ) ) {
return false;
}
}
@@ -240,6 +236,13 @@ else if ( !isLiteral( result ) ) {
return false;
}
+ private boolean isStringLiteral( Expression expression ) {
+ if ( expression instanceof Literal ) {
+ return ( (Literal) expression ).getJdbcMapping().getJdbcType().isStringLike();
+ }
+ return false;
+ }
+
@Override
public boolean supportsFilterClause() {
return true;
@@ -332,11 +335,6 @@ protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
- @Override
- protected String getFromDualForSelectOnly() {
- return " from " + getDual();
- }
-
private boolean supportsOffsetFetchClause() {
return true;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java
index c77ee258a435..75b9335dafbc 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java
@@ -276,4 +276,9 @@ public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, D
return super.buildIdentifierHelper( builder, dbMetaData );
}
+
+ @Override
+ public String getDual() {
+ return "dual";
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBSqlAstTranslator.java
index 78272afe716e..a243e96979f7 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBSqlAstTranslator.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBSqlAstTranslator.java
@@ -369,11 +369,6 @@ protected boolean supportsDistinctFromPredicate() {
return true;
}
- @Override
- protected String getDual() {
- return "dual";
- }
-
@Override
public MariaDBDialect getDialect() {
return this.dialect;
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java
index 08a425ddda31..20ce0f69b5eb 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java
@@ -47,6 +47,7 @@
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor;
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
import org.hibernate.internal.util.JdbcExceptionHelper;
+import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.query.sqm.CastType;
@@ -210,7 +211,7 @@ protected static DatabaseVersion createVersion(DialectResolutionInfo info) {
protected static DatabaseVersion createVersion(DialectResolutionInfo info, DatabaseVersion defaultVersion) {
final String versionString = info.getDatabaseVersion();
if ( versionString != null ) {
- final String[] components = versionString.split( "\\." );
+ final String[] components = StringHelper.split(".-", versionString);
if ( components.length >= 3 ) {
try {
final int majorVersion = Integer.parseInt( components[0] );
@@ -1571,4 +1572,9 @@ public DmlTargetColumnQualifierSupport getDmlTargetColumnQualifierSupport() {
public boolean supportsFromClauseInUpdate() {
return true;
}
+
+ @Override
+ public String getDual() {
+ return "dual";
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLSqlAstTranslator.java
index 6be62a55c40e..dd78fb8e0ea2 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLSqlAstTranslator.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLSqlAstTranslator.java
@@ -443,11 +443,6 @@ protected boolean supportsWithClause() {
return true;
}
- @Override
- protected String getDual() {
- return "dual";
- }
-
@Override
public MySQLDialect getDialect() {
return (MySQLDialect) DialectDelegateWrapper.extractRealDialect( super.getDialect() );
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java
index 24e33db59d31..1b9b313b71c7 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java
@@ -462,25 +462,33 @@ public String castPattern(CastType from, CastType to) {
}
break;
case INTEGER_BOOLEAN:
- result = BooleanDecoder.toIntegerBoolean( from );
+ result = from == CastType.STRING
+ ? buildStringToBooleanCastDecode( "1", "0" )
+ : BooleanDecoder.toIntegerBoolean( from );
if ( result != null ) {
return result;
}
break;
case YN_BOOLEAN:
- result = BooleanDecoder.toYesNoBoolean( from );
+ result = from == CastType.STRING
+ ? buildStringToBooleanCastDecode( "'Y'", "'N'" )
+ : BooleanDecoder.toYesNoBoolean( from );
if ( result != null ) {
return result;
}
break;
case BOOLEAN:
- result = BooleanDecoder.toBoolean( from );
+ result = from == CastType.STRING
+ ? buildStringToBooleanCastDecode( "true", "false" )
+ : BooleanDecoder.toBoolean( from );
if ( result != null ) {
return result;
}
break;
case TF_BOOLEAN:
- result = BooleanDecoder.toTrueFalseBoolean( from );
+ result = from == CastType.STRING
+ ? buildStringToBooleanCastDecode( "'T'", "'F'" )
+ : BooleanDecoder.toTrueFalseBoolean( from );
if ( result != null ) {
return result;
}
@@ -1687,4 +1695,14 @@ public boolean useInputStreamToInsertBlob() {
return false;
}
+ @Override
+ public String getDual() {
+ return "dual";
+ }
+
+ @Override
+ public String getFromDualForSelectOnly() {
+ return getVersion().isSameOrAfter( 23 ) ? "" : ( " from " + getDual() );
+ }
+
}
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java
index 00558358553b..6f87c4f0cf65 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java
@@ -617,16 +617,6 @@ protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
- @Override
- protected String getDual() {
- return "dual";
- }
-
- @Override
- protected String getFromDualForSelectOnly() {
- return getDialect().getVersion().isSameOrAfter( 23 ) ? "" : ( " from " + getDual() );
- }
-
private boolean supportsOffsetFetchClause() {
return getDialect().supportsFetchClause( FetchClauseType.ROWS_ONLY );
}
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java
index 67fa1ce56a10..404f10609cba 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java
@@ -58,6 +58,7 @@
import org.hibernate.procedure.spi.CallableStatementSupport;
import org.hibernate.query.SemanticException;
import org.hibernate.query.spi.QueryOptions;
+import org.hibernate.query.sqm.CastType;
import org.hibernate.query.sqm.FetchClauseType;
import org.hibernate.query.sqm.IntervalType;
import org.hibernate.query.sqm.TemporalUnit;
@@ -467,6 +468,16 @@ public String extractPattern(TemporalUnit unit) {
}
}
+ @Override
+ public String castPattern(CastType from, CastType to) {
+ if ( from == CastType.STRING && to == CastType.BOOLEAN ) {
+ return "cast(?1 as ?2)";
+ }
+ else {
+ return super.castPattern( from, to );
+ }
+ }
+
/**
* {@code microsecond} is the smallest unit for an {@code interval},
* and the highest precision for a {@code timestamp}, so we could
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/StructHelper.java b/hibernate-core/src/main/java/org/hibernate/dialect/StructHelper.java
index 1b9ab7c6369e..8458d4adbfc3 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/StructHelper.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/StructHelper.java
@@ -12,6 +12,7 @@
import java.sql.NClob;
import java.sql.SQLException;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.Internal;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
@@ -130,13 +131,13 @@ public static Object[] getJdbcValues(
private static int injectJdbcValues(
EmbeddableMappingType embeddableMappingType,
- Object domainValue,
+ @Nullable Object domainValue,
Object[] jdbcValues,
int jdbcIndex,
WrapperOptions options) throws SQLException {
return injectJdbcValues(
embeddableMappingType,
- embeddableMappingType.getValues( domainValue ),
+ domainValue == null ? null : embeddableMappingType.getValues( domainValue ),
jdbcValues,
jdbcIndex,
options
@@ -145,12 +146,15 @@ private static int injectJdbcValues(
private static int injectJdbcValues(
EmbeddableMappingType embeddableMappingType,
- Object[] values,
+ @Nullable Object[] values,
Object[] jdbcValues,
int jdbcIndex,
WrapperOptions options) throws SQLException {
final int jdbcValueCount = embeddableMappingType.getJdbcValueCount();
final int valueCount = jdbcValueCount + ( embeddableMappingType.isPolymorphic() ? 1 : 0 );
+ if ( values == null ) {
+ return valueCount;
+ }
int offset = 0;
for ( int i = 0; i < values.length; i++ ) {
offset += injectJdbcValue(
@@ -255,22 +259,13 @@ else if ( attributeMapping instanceof EmbeddableValuedModelPart ) {
);
}
else {
- jdbcValueCount = embeddableMappingType.getJdbcValueCount() + ( embeddableMappingType.isPolymorphic() ? 1 : 0 );
- final int numberOfAttributeMappings = embeddableMappingType.getNumberOfAttributeMappings();
- final int numberOfValues = numberOfAttributeMappings + ( embeddableMappingType.isPolymorphic() ? 1 : 0 );
- final Object[] subValues = embeddableMappingType.getValues( attributeValues[attributeIndex] );
- int offset = 0;
- for ( int i = 0; i < numberOfValues; i++ ) {
- offset += injectJdbcValue(
- getEmbeddedPart( embeddableMappingType, i ),
- subValues,
- i,
- jdbcValues,
- jdbcIndex + offset,
- options
- );
- }
- assert offset == jdbcValueCount;
+ jdbcValueCount = injectJdbcValues(
+ embeddableMappingType,
+ attributeValues[attributeIndex],
+ jdbcValues,
+ jdbcIndex,
+ options
+ );
}
}
else {
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASEDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASEDialect.java
index 52d320a52b4f..0eaf758b2dd9 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASEDialect.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASEDialect.java
@@ -142,13 +142,8 @@ protected void registerColumnTypes(TypeContributions typeContributions, ServiceR
// But with jTDS we can't use them as the driver can't handle the types
if ( getDriverKind() != SybaseDriverKind.JTDS ) {
ddlTypeRegistry.addDescriptor(
- CapacityDependentDdlType.builder( DATE, "bigdatetime", "bigdatetime", this )
- .withTypeCapacity( 3, "datetime" )
- .build()
- );
- ddlTypeRegistry.addDescriptor(
- CapacityDependentDdlType.builder( TIME, "bigdatetime", "bigdatetime", this )
- .withTypeCapacity( 3, "datetime" )
+ CapacityDependentDdlType.builder( TIME, "bigtime", "bigtime", this )
+ .withTypeCapacity( 3, "time" )
.build()
);
ddlTypeRegistry.addDescriptor(
@@ -712,4 +707,9 @@ public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
public LimitHandler getLimitHandler() {
return new TopLimitHandler(false);
}
+
+ @Override
+ public String getDual() {
+ return "(select 1 c1)";
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASESqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASESqlAstTranslator.java
index eee92fa20b04..6fd185de98bc 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASESqlAstTranslator.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASESqlAstTranslator.java
@@ -508,11 +508,6 @@ protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
- @Override
- protected String getDual() {
- return "(select 1 c1)";
- }
-
private boolean supportsParameterOffsetFetchExpression() {
return false;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/TiDBDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/TiDBDialect.java
index 524128640903..4557bbfb53c8 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/TiDBDialect.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/TiDBDialect.java
@@ -190,4 +190,9 @@ public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType,
}
return super.timestampaddPattern( unit, temporalType, intervalType );
}
+
+ @Override
+ public String getDual() {
+ return "dual";
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/TiDBSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/TiDBSqlAstTranslator.java
index 1a4320239020..751e3ba6c810 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/TiDBSqlAstTranslator.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/TiDBSqlAstTranslator.java
@@ -332,11 +332,6 @@ protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
- @Override
- protected String getDual() {
- return "dual";
- }
-
@Override
protected String getForShare(int timeoutMillis) {
if ( timeoutMillis == LockOptions.NO_WAIT ) {
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayConstructorFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayConstructorFunction.java
index 233232cfd7d7..b7a658008f5f 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayConstructorFunction.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayConstructorFunction.java
@@ -109,13 +109,13 @@ public void validateSqlTypes(List extends SqlAstNode> arguments, String functi
if ( firstType == null ) {
firstType = argumentType;
}
- else if ( firstType != argumentType ) {
+ else if ( firstType.getSingleJdbcMapping() != argumentType.getSingleJdbcMapping() ) {
throw new FunctionArgumentException(
String.format(
"All array arguments must have a type compatible to the first argument type [%s], but argument %d has type '%s'",
- firstType,
+ firstType.getSingleJdbcMapping(),
i + 1,
- argumentType
+ argumentType.getSingleJdbcMapping()
)
);
}
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsArgumentTypeResolver.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsArgumentTypeResolver.java
index af076cb3aa58..f52ce438e3c5 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsArgumentTypeResolver.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsArgumentTypeResolver.java
@@ -47,10 +47,15 @@ public MappingModelExpressible> resolveFunctionArgumentType(
}
}
else if ( argumentIndex == 1 ) {
+ final SqmTypedNode> nodeToResolve = function.getArguments().get( 1 );
+ if ( nodeToResolve.getExpressible() instanceof MappingModelExpressible> ) {
+ // If the node already has suitable type, don't infer it to be treated as an array
+ return null;
+ }
final SqmTypedNode> node = function.getArguments().get( 0 );
if ( node instanceof SqmExpression> ) {
final MappingModelExpressible> expressible = converter.determineValueMapping( (SqmExpression>) node );
- if ( expressible != null ) {
+ if ( expressible instanceof BasicPluralType, ?> ) {
return expressible;
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/hint/IndexQueryHintHandler.java b/hibernate-core/src/main/java/org/hibernate/dialect/hint/IndexQueryHintHandler.java
index 9a70d556786c..ae4134de5e10 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/hint/IndexQueryHintHandler.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/hint/IndexQueryHintHandler.java
@@ -25,8 +25,7 @@ public class IndexQueryHintHandler implements QueryHintHandler {
public static final IndexQueryHintHandler INSTANCE = new IndexQueryHintHandler();
- private static final Pattern QUERY_PATTERN = Pattern.compile( "^\\s*(select\\b.+?\\bfrom\\b.+?)(\\bwhere\\b.+?)$" );
-
+ private static final Pattern QUERY_PATTERN = Pattern.compile( "^\\s*(select\\b.+?\\bfrom\\b.+?)(\\b(where|join)\\b.+?)$" );
@Override
public String addQueryHints(String query, String hints) {
Matcher matcher = QUERY_PATTERN.matcher( query );
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/temptable/TemporaryTableHelper.java b/hibernate-core/src/main/java/org/hibernate/dialect/temptable/TemporaryTableHelper.java
index 1f1c6e93f2f4..43cd8d4dc46d 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/temptable/TemporaryTableHelper.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/temptable/TemporaryTableHelper.java
@@ -14,6 +14,7 @@
import java.util.function.Function;
import org.hibernate.engine.jdbc.internal.FormatStyle;
+import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
@@ -149,18 +150,19 @@ public static void cleanTemporaryTableRows(
TemporaryTableExporter exporter,
Function sessionUidAccess,
SharedSessionContractImplementor session) {
+ final JdbcCoordinator jdbcCoordinator = session.getJdbcCoordinator();
PreparedStatement ps = null;
try {
final String sql = exporter.getSqlTruncateCommand( temporaryTable, sessionUidAccess, session );
- ps = session.getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false );
+ ps = jdbcCoordinator.getStatementPreparer().prepareStatement( sql, false );
if ( temporaryTable.getSessionUidColumn() != null ) {
final String sessionUid = sessionUidAccess.apply( session );
ps.setString( 1, sessionUid );
}
- session.getJdbcCoordinator().getResultSetReturn().executeUpdate( ps, sql );
+ jdbcCoordinator.getResultSetReturn().executeUpdate( ps, sql );
}
catch( Throwable t ) {
log.unableToCleanupTemporaryIdTable(t);
@@ -168,11 +170,12 @@ public static void cleanTemporaryTableRows(
finally {
if ( ps != null ) {
try {
- session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( ps );
+ jdbcCoordinator.getLogicalConnection().getResourceRegistry().release( ps );
}
catch( Throwable ignore ) {
// ignore
}
+ jdbcCoordinator.afterStatementExecution();
}
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/Cascade.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/Cascade.java
index ecf12dcb2af6..1250ba154721 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/internal/Cascade.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/Cascade.java
@@ -10,6 +10,7 @@
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
+import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
@@ -19,6 +20,7 @@
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.PersistenceContext;
+import org.hibernate.engine.spi.SelfDirtinessTracker;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.event.spi.DeleteContext;
@@ -27,19 +29,22 @@
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.type.AnyType;
import org.hibernate.type.AssociationType;
import org.hibernate.type.CollectionType;
import org.hibernate.type.ComponentType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.EntityType;
+import org.hibernate.type.ForeignKeyDirection;
import org.hibernate.type.ManyToOneType;
import org.hibernate.type.OneToOneType;
import org.hibernate.type.Type;
+import static org.hibernate.engine.internal.ManagedTypeHelper.asManagedEntity;
+import static org.hibernate.engine.internal.ManagedTypeHelper.asSelfDirtinessTrackerOrNull;
import static org.hibernate.engine.internal.ManagedTypeHelper.isHibernateProxy;
import static org.hibernate.engine.spi.CascadingActions.CHECK_ON_FLUSH;
import static org.hibernate.pretty.MessageHelper.infoString;
-import static org.hibernate.type.ForeignKeyDirection.TO_PARENT;
/**
* Delegate responsible for, in conjunction with the various
@@ -92,15 +97,29 @@ public static void cascade(
final PersistenceContext persistenceContext = eventSource.getPersistenceContextInternal();
final boolean enhancedForLazyLoading = persister.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading();
final EntityEntry entry;
+ final Set dirtyAttributes;
if ( enhancedForLazyLoading ) {
entry = persistenceContext.getEntry( parent );
- if ( entry != null
- && entry.getLoadedState() == null
- && entry.getStatus() == Status.MANAGED ) {
- return;
+ if ( entry != null && entry.getLoadedState() == null && entry.getStatus() == Status.MANAGED ) {
+ final SelfDirtinessTracker selfDirtinessTracker = asSelfDirtinessTrackerOrNull( parent );
+ if ( selfDirtinessTracker == null ) {
+ return;
+ }
+ else {
+ if ( asManagedEntity( parent ).$$_hibernate_useTracker() ) {
+ dirtyAttributes = Set.of( selfDirtinessTracker.$$_hibernate_getDirtyAttributes() );
+ }
+ else {
+ dirtyAttributes = null;
+ }
+ }
+ }
+ else {
+ dirtyAttributes = null;
}
}
else {
+ dirtyAttributes = null;
entry = null;
}
final Type[] types = persister.getPropertyTypes();
@@ -109,8 +128,11 @@ public static void cascade(
final boolean hasUninitializedLazyProperties = persister.hasUninitializedLazyProperties( parent );
for ( int i = 0; i < types.length; i++) {
- final CascadeStyle style = cascadeStyles[ i ];
final String propertyName = propertyNames[ i ];
+ if ( dirtyAttributes != null && !dirtyAttributes.contains( propertyName ) ) {
+ return;
+ }
+ final CascadeStyle style = cascadeStyles[ i ];
final Type type = types[i];
final boolean isUninitializedProperty =
hasUninitializedLazyProperties &&
@@ -130,7 +152,7 @@ public static void cascade(
// parent was not in the PersistenceContext
continue;
}
- if ( type.isCollectionType() ) {
+ if ( type instanceof CollectionType ) {
// CollectionType#getCollection gets the PersistentCollection
// that corresponds to the uninitialized collection from the
// PersistenceContext. If not present, an uninitialized
@@ -145,13 +167,13 @@ public static void cascade(
null
);
}
- else if ( type.isComponentType() ) {
+ else if ( type instanceof AnyType || type instanceof ComponentType ) {
// Hibernate does not support lazy embeddables, so this shouldn't happen.
throw new UnsupportedOperationException(
"Lazy components are not supported."
);
}
- else if ( action.performOnLazyProperty() && type.isEntityType() ) {
+ else if ( action.performOnLazyProperty() && type instanceof EntityType ) {
// Only need to initialize a lazy entity attribute when action.performOnLazyProperty()
// returns true.
LazyAttributeLoadingInterceptor interceptor = persister.getBytecodeEnhancementMetadata()
@@ -222,7 +244,7 @@ private static void cascadeProperty(
final boolean isCascadeDeleteEnabled) throws HibernateException {
if ( child != null ) {
- if ( type.isAssociationType() ) {
+ if ( type instanceof EntityType || type instanceof CollectionType || type instanceof AnyType ) {
final AssociationType associationType = (AssociationType) type;
final boolean unownedTransient = eventSource.getSessionFactory()
.getSessionFactoryOptions()
@@ -242,7 +264,7 @@ private static void cascadeProperty(
);
}
}
- else if ( type.isComponentType() ) {
+ else if ( type instanceof ComponentType ) {
if ( componentPath == null && propertyName != null ) {
componentPath = new ArrayList<>();
}
@@ -359,8 +381,8 @@ private static void cascadeLogicalOneToOneOrphanRemoval(
);
}
- if ( type.isAssociationType()
- && ( (AssociationType) type ).getForeignKeyDirection().equals(TO_PARENT) ) {
+ if ( type instanceof CollectionType
+ || type instanceof OneToOneType && ( (OneToOneType) type ).getForeignKeyDirection() == ForeignKeyDirection.TO_PARENT ) {
// If FK direction is to-parent, we must remove the orphan *before* the queued update(s)
// occur. Otherwise, replacing the association on a managed entity, without manually
// nulling and flushing, causes FK constraint violations.
@@ -400,19 +422,17 @@ private static boolean cascadeAssociationNow(
}
private static boolean isUnownedAssociation(AssociationType associationType, SessionFactoryImplementor factory) {
- if ( associationType.isEntityType() ) {
- if ( associationType instanceof ManyToOneType ) {
- final ManyToOneType manyToOne = (ManyToOneType) associationType;
- // logical one-to-one + non-null unique key property name indicates unowned
- return manyToOne.isLogicalOneToOne() && manyToOne.getRHSUniqueKeyPropertyName() != null;
- }
- else if ( associationType instanceof OneToOneType ) {
- final OneToOneType oneToOne = (OneToOneType) associationType;
- // constrained false + non-null unique key property name indicates unowned
- return oneToOne.isNullable() && oneToOne.getRHSUniqueKeyPropertyName() != null;
- }
+ if ( associationType instanceof ManyToOneType ) {
+ final ManyToOneType manyToOne = (ManyToOneType) associationType;
+ // logical one-to-one + non-null unique key property name indicates unowned
+ return manyToOne.isLogicalOneToOne() && manyToOne.getRHSUniqueKeyPropertyName() != null;
}
- else if ( associationType.isCollectionType() ) {
+ else if ( associationType instanceof OneToOneType ) {
+ final OneToOneType oneToOne = (OneToOneType) associationType;
+ // constrained false + non-null unique key property name indicates unowned
+ return oneToOne.isNullable() && oneToOne.getRHSUniqueKeyPropertyName() != null;
+ }
+ else if ( associationType instanceof CollectionType ) {
// for collections, we can ask the persister if we're on the inverse side
return ( (CollectionType) associationType ).isInverse( factory );
}
@@ -468,10 +488,10 @@ private static void cascadeAssociation(
final CascadeStyle style,
final T anything,
final boolean isCascadeDeleteEnabled) {
- if ( type.isEntityType() || type.isAnyType() ) {
+ if ( type instanceof EntityType || type instanceof AnyType ) {
cascadeToOne( action, eventSource, parent, child, type, style, anything, isCascadeDeleteEnabled );
}
- else if ( type.isCollectionType() ) {
+ else if ( type instanceof CollectionType ) {
cascadeCollection(
action,
cascadePoint,
@@ -510,7 +530,7 @@ private static void cascadeCollection(
}
//cascade to current collection elements
- if ( elemType.isEntityType() || elemType.isAnyType() || elemType.isComponentType() ) {
+ if ( elemType instanceof EntityType || elemType instanceof AnyType || elemType instanceof ComponentType ) {
cascadeCollectionElements(
action,
elementsCascadePoint,
@@ -539,7 +559,7 @@ private static void cascadeToOne(
final CascadeStyle style,
final T anything,
final boolean isCascadeDeleteEnabled) {
- final String entityName = type.isEntityType()
+ final String entityName = type instanceof EntityType
? ( (EntityType) type ).getAssociatedEntityName()
: null;
if ( style.reallyDoCascade( action ) ) {
@@ -601,12 +621,22 @@ private static void cascadeCollectionElements(
}
}
+ // a newly instantiated collection can't have orphans
+ final PersistentCollection> persistentCollection;
+ if ( child instanceof PersistentCollection> ) {
+ persistentCollection = (PersistentCollection>) child;
+ }
+ else {
+ persistentCollection = eventSource.getPersistenceContext()
+ .getCollectionHolder( child );
+ }
+
final boolean deleteOrphans = style.hasOrphanDelete()
&& action.deleteOrphans()
- && elemType.isEntityType()
- && child instanceof PersistentCollection
+ && elemType instanceof EntityType
+ && persistentCollection != null
// a newly instantiated collection can't have orphans
- && ! ( (PersistentCollection>) child ).isNewlyInstantiated();
+ && !persistentCollection.isNewlyInstantiated();
if ( deleteOrphans ) {
final boolean traceEnabled = LOG.isTraceEnabled();
@@ -617,7 +647,7 @@ private static void cascadeCollectionElements(
// 1. newly instantiated collections
// 2. arrays (we can't track orphans for detached arrays)
final String entityName = collectionType.getAssociatedEntityName( eventSource.getFactory() );
- deleteOrphans( eventSource, entityName, (PersistentCollection>) child );
+ deleteOrphans( eventSource, entityName, persistentCollection );
if ( traceEnabled ) {
LOG.tracev( "Done deleting orphans for collection: {0}", collectionType.getRole() );
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/ForeignKeys.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/ForeignKeys.java
index bbf6216e56de..3db99c98e0f5 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/internal/ForeignKeys.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/ForeignKeys.java
@@ -16,7 +16,8 @@
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.LazyInitializer;
-import org.hibernate.type.CompositeType;
+import org.hibernate.type.AnyType;
+import org.hibernate.type.ComponentType;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
@@ -106,21 +107,21 @@ private Object nullifyTransient(Object value, String propertyName, Type type) {
if ( value == null ) {
return null;
}
- else if ( type.isEntityType() ) {
+ else if ( type instanceof EntityType ) {
return nullifyEntityType( value, propertyName, (EntityType) type );
}
- else if ( type.isAnyType() ) {
+ else if ( type instanceof AnyType ) {
return isNullifiable( null, value) ? null : value;
}
- else if ( type.isComponentType() ) {
- return nullifyCompositeType( value, propertyName, (CompositeType) type );
+ else if ( type instanceof ComponentType ) {
+ return nullifyCompositeType( value, propertyName, (ComponentType) type );
}
else {
return value;
}
}
- private Object nullifyCompositeType(Object value, String propertyName, CompositeType compositeType) {
+ private Object nullifyCompositeType(Object value, String propertyName, ComponentType compositeType) {
final Object[] subvalues = compositeType.getPropertyValues(value, session );
final Type[] subtypes = compositeType.getSubtypes();
final String[] subPropertyNames = compositeType.getPropertyNames();
@@ -194,7 +195,7 @@ private boolean initializationIsNecessary(Object value, Type type) {
// more than just initializing the associated entity.
return isDelete
&& value == UNFETCHED_PROPERTY
- && type.isEntityType()
+ && type instanceof EntityType
&& !session.getPersistenceContextInternal().isNullifiableEntityKeysEmpty();
}
@@ -370,6 +371,21 @@ public static Object getEntityIdentifierIfNotUnsaved(
}
}
+ public static Object getEntityIdentifier(
+ final String entityName,
+ final Object object,
+ final SharedSessionContractImplementor session) {
+ if ( object == null ) {
+ return null;
+ }
+ else {
+ final Object id = session.getContextEntityIdentifier( object );
+ return id == null
+ ? session.getEntityPersister( entityName, object ).getIdentifier( object, session )
+ : id;
+ }
+ }
+
private static void throwIfTransient(String entityName, Object object, SharedSessionContractImplementor session) {
if ( isTransient( entityName, object, Boolean.FALSE, session ) ) {
throw new TransientObjectException(
@@ -432,7 +448,7 @@ private static void collectNonNullableTransientEntities(
if ( value == null ) {
// do nothing
}
- else if ( type.isEntityType() ) {
+ else if ( type instanceof EntityType ) {
final EntityType entityType = (EntityType) type;
if ( !isNullable
&& !entityType.isOneToOne()
@@ -440,13 +456,13 @@ else if ( type.isEntityType() ) {
nonNullableTransientEntities.add( propertyName, value );
}
}
- else if ( type.isAnyType() ) {
+ else if ( type instanceof AnyType ) {
if ( !isNullable && nullifier.isNullifiable( null, value ) ) {
nonNullableTransientEntities.add( propertyName, value );
}
}
- else if ( type.isComponentType() ) {
- final CompositeType compositeType = (CompositeType) type;
+ else if ( type instanceof ComponentType ) {
+ final ComponentType compositeType = (ComponentType) type;
final boolean[] subValueNullability = compositeType.getPropertyNullability();
if ( subValueNullability != null ) {
final String[] subPropertyNames = compositeType.getPropertyNames();
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/ManagedTypeHelper.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/ManagedTypeHelper.java
index 5c849ad63d2a..3b280aa78900 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/internal/ManagedTypeHelper.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/ManagedTypeHelper.java
@@ -390,6 +390,15 @@ public static SelfDirtinessTracker asSelfDirtinessTracker(final Object entity) {
throw new ClassCastException( "Object of type '" + entity.getClass() + "' can't be cast to SelfDirtinessTracker" );
}
+ public static SelfDirtinessTracker asSelfDirtinessTrackerOrNull(final Object entity) {
+ Objects.requireNonNull( entity );
+ if ( entity instanceof PrimeAmongSecondarySupertypes ) {
+ PrimeAmongSecondarySupertypes t = (PrimeAmongSecondarySupertypes) entity;
+ return t.asSelfDirtinessTracker();
+ }
+ return null;
+ }
+
/**
* Cast the object to an HibernateProxy, or return null in case it is not an instance of HibernateProxy
* @param entity the entity to cast
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/Nullability.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/Nullability.java
index a2ab620a39c8..33cf8067ae1a 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/internal/Nullability.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/Nullability.java
@@ -14,7 +14,9 @@
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.generator.Generator;
+import org.hibernate.type.AnyType;
import org.hibernate.type.CollectionType;
+import org.hibernate.type.ComponentType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.Type;
@@ -144,16 +146,19 @@ private static boolean generated(Generator generator) {
* @throws HibernateException error while getting subcomponent values
*/
private String checkSubElementsNullability(Type propertyType, Object value) throws HibernateException {
- if ( propertyType.isComponentType() ) {
- return checkComponentNullability( value, (CompositeType) propertyType );
+ if ( propertyType instanceof AnyType ) {
+ return checkComponentNullability( value, (AnyType) propertyType );
+ }
+ if ( propertyType instanceof ComponentType ) {
+ return checkComponentNullability( value, (ComponentType) propertyType );
}
- if ( propertyType.isCollectionType() ) {
+ if ( propertyType instanceof CollectionType ) {
// persistent collections may have components
final CollectionType collectionType = (CollectionType) propertyType;
final Type collectionElementType = collectionType.getElementType( session.getFactory() );
- if ( collectionElementType.isComponentType() ) {
+ if ( collectionElementType instanceof ComponentType || collectionElementType instanceof AnyType ) {
// check for all components values in the collection
final CompositeType componentType = (CompositeType) collectionElementType;
final Iterator> itr = getLoadedElementsIterator( session, collectionType, value );
@@ -189,7 +194,7 @@ private String checkComponentNullability(Object value, CompositeType compositeTy
//
// The more correct fix would be to cascade saves of the many-to-any elements before the Nullability checking
- if ( compositeType.isAnyType() ) {
+ if ( compositeType instanceof AnyType ) {
return null;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java
index f22ad6c35db0..63bcc03169ca 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java
@@ -78,6 +78,7 @@
import static org.hibernate.engine.internal.ManagedTypeHelper.asManagedEntity;
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable;
import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable;
+import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
/**
* A stateful implementation of the {@link PersistenceContext} contract, meaning that we maintain this
@@ -231,8 +232,14 @@ public void clear() {
if ( entitiesByKey != null ) {
//Strictly avoid lambdas in this case
for ( EntityHolderImpl value : entitiesByKey.values() ) {
- if ( value != null && value.proxy != null ) {
- HibernateProxy.extractLazyInitializer( value.proxy ).unsetSession();
+ if ( value != null ) {
+ value.state = EntityHolderState.DETACHED;
+ if ( value.proxy != null ) {
+ final LazyInitializer lazyInitializer = extractLazyInitializer( value.proxy );
+ if ( lazyInitializer != null ) {
+ lazyInitializer.unsetSession();
+ }
+ }
}
}
}
@@ -2243,6 +2250,11 @@ public boolean isEventuallyInitialized() {
return state == EntityHolderState.INITIALIZED || entityInitializer != null;
}
+ @Override
+ public boolean isDetached() {
+ return state == EntityHolderState.DETACHED;
+ }
+
public static EntityHolderImpl forProxy(EntityKey entityKey, EntityPersister descriptor, Object proxy) {
return new EntityHolderImpl( entityKey, descriptor, null, proxy );
}
@@ -2255,7 +2267,8 @@ public static EntityHolderImpl forEntity(EntityKey entityKey, EntityPersister de
enum EntityHolderState {
UNINITIALIZED,
ENHANCED_PROXY,
- INITIALIZED
+ INITIALIZED,
+ DETACHED
}
// NATURAL ID RESOLUTION HANDLING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2271,4 +2284,13 @@ public NaturalIdResolutions getNaturalIdResolutions() {
return naturalIdResolutions;
}
+ @Override
+ public EntityHolder detachEntity(EntityKey key) {
+ final EntityHolderImpl entityHolder = removeEntityHolder( key );
+ if ( entityHolder != null ) {
+ entityHolder.state = EntityHolderState.DETACHED;
+ }
+ return entityHolder;
+ }
+
}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/StatisticalLoggingSessionEventListener.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/StatisticalLoggingSessionEventListener.java
index 8a6b06744112..374bce7df35e 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/internal/StatisticalLoggingSessionEventListener.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/StatisticalLoggingSessionEventListener.java
@@ -250,10 +250,10 @@ public void prePartialFlushStart() {
@Override
public void prePartialFlushEnd() {
- assert prePartialFlushStart > 0 : "Unexpected call to partialFlushEnd; expecting partialFlushStart";
+ assert prePartialFlushStart > 0 : "Unexpected call to prePartialFlushEnd; expecting prePartialFlushStart";
prePartialFlushCount++;
- prePartialFlushTime += ( System.nanoTime() - partialFlushStart );
+ prePartialFlushTime += ( System.nanoTime() - prePartialFlushStart );
prePartialFlushStart = -1;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java
index 1e6c5109348b..9791b4098a24 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java
@@ -7,10 +7,16 @@
package org.hibernate.engine.internal;
import org.hibernate.LockMode;
+import org.hibernate.engine.spi.EntityEntry;
+import org.hibernate.engine.spi.EntityHolder;
import org.hibernate.engine.spi.EntityKey;
+import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.proxy.LazyInitializer;
+
+import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
/**
* Functionality relating to the Hibernate two-phase loading process, that may be reused by persisters
@@ -39,16 +45,27 @@ public static void addUninitializedCachedEntity(
final LockMode lockMode,
final Object version,
final SharedSessionContractImplementor session) {
- session.getPersistenceContextInternal().addEntity(
+ final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
+ final EntityHolder entityHolder = persistenceContext.addEntityHolder( key, object );
+ final EntityEntry entityEntry = persistenceContext.addEntry(
object,
Status.LOADING,
null,
- key,
+ null,
+ key.getIdentifier(),
version,
lockMode,
true,
persister,
false
);
+ entityHolder.setEntityEntry( entityEntry );
+ final Object proxy = entityHolder.getProxy();
+ if ( proxy != null ) {
+ // there is already a proxy for this impl
+ final LazyInitializer lazyInitializer = extractLazyInitializer( proxy );
+ assert lazyInitializer != null;
+ lazyInitializer.setImplementation( object );
+ }
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/UnsavedValueFactory.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/UnsavedValueFactory.java
index 3df891f301cd..e582ad0ab0ad 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/internal/UnsavedValueFactory.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/UnsavedValueFactory.java
@@ -21,6 +21,8 @@
import org.hibernate.type.descriptor.java.VersionJavaType;
import org.hibernate.type.descriptor.java.spi.PrimitiveJavaType;
+import static org.hibernate.engine.internal.Versioning.isNullInitialVersion;
+
/**
* Helper for dealing with unsaved value handling
*
@@ -82,25 +84,20 @@ else if ( "any".equals( unsavedValue ) ) {
public static VersionValue getUnsavedVersionValue(
KeyValue bootVersionMapping,
VersionJavaType jtd,
- Long length,
- Integer precision,
- Integer scale,
Getter getter,
- Supplier> templateInstanceAccess,
- SessionFactoryImplementor sessionFactory) {
+ Supplier> templateInstanceAccess) {
final String unsavedValue = bootVersionMapping.getNullValue();
if ( unsavedValue == null ) {
if ( getter != null && templateInstanceAccess != null ) {
- Object templateInstance = templateInstanceAccess.get();
+ final Object templateInstance = templateInstanceAccess.get();
@SuppressWarnings("unchecked")
final T defaultValue = (T) getter.get( templateInstance );
-
- // if the version of a newly instantiated object is not the same
- // as the version seed value, use that as the unsaved-value
- final T seedValue = jtd.seed( length, precision, scale, mockSession( sessionFactory ) );
- return jtd.areEqual( seedValue, defaultValue )
- ? VersionValue.UNDEFINED
- : new VersionValue( defaultValue );
+ // if the version of a newly instantiated object is null
+ // or a negative number, use that value as the unsaved-value,
+ // otherwise assume it's the initial version set by program
+ return isNullInitialVersion( defaultValue )
+ ? new VersionValue( defaultValue )
+ : VersionValue.UNDEFINED;
}
else {
return VersionValue.UNDEFINED;
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/BlobProxy.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/BlobProxy.java
index fa70329ce446..556768b41ac9 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/BlobProxy.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/BlobProxy.java
@@ -38,6 +38,8 @@ public final class BlobProxy implements Blob, BlobImplementer {
// no longer necessary. The class name could be updated to reflect this but that would break APIs.
private final BinaryStream binaryStream;
+ private final int markBytes;
+ private boolean resetAllowed;
private boolean needsReset;
/**
@@ -47,7 +49,9 @@ public final class BlobProxy implements Blob, BlobImplementer {
* @see #generateProxy(byte[])
*/
private BlobProxy(byte[] bytes) {
- binaryStream = new BinaryStreamImpl( bytes );
+ binaryStream = new BinaryStreamImpl(bytes);
+ markBytes = bytes.length + 1;
+ setStreamMark();
}
/**
@@ -59,6 +63,19 @@ private BlobProxy(byte[] bytes) {
*/
private BlobProxy(InputStream stream, long length) {
this.binaryStream = new StreamBackedBinaryStream( stream, length );
+ this.markBytes = (int) length + 1;
+ setStreamMark();
+ }
+
+ private void setStreamMark() {
+ final InputStream inputStream = binaryStream.getInputStream();
+ if ( inputStream != null && inputStream.markSupported() ) {
+ inputStream.mark( markBytes );
+ resetAllowed = true;
+ }
+ else {
+ resetAllowed = false;
+ }
}
private InputStream getStream() throws SQLException {
@@ -73,7 +90,14 @@ public BinaryStream getUnderlyingStream() throws SQLException {
private void resetIfNeeded() throws SQLException {
try {
if ( needsReset ) {
- binaryStream.getInputStream().reset();
+ final InputStream inputStream = binaryStream.getInputStream();
+ if ( !resetAllowed && inputStream != null) {
+ throw new SQLException( "Underlying stream does not allow reset" );
+ }
+ if ( inputStream != null ) {
+ inputStream.reset();
+ setStreamMark();
+ }
}
}
catch ( IOException ioe) {
@@ -96,6 +120,11 @@ public static Blob generateProxy(byte[] bytes) {
/**
* Generates a BlobImpl proxy using a given number of bytes from an InputStream.
*
+ * Be aware that certain database drivers will automatically close the provided InputStream after the
+ * contents have been written to the database. This may cause unintended side effects if the entity
+ * is also audited by Envers. In this case, it's recommended to use {@link #generateProxy(byte[])}
+ * instead as it isn't affected by this non-standard behavior.
+ *
* @param stream The input stream of bytes to be created as a Blob.
* @param length The number of bytes from stream to be written to the Blob.
*
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/JdbcBatchLogging.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/JdbcBatchLogging.java
index 10de5317c012..11edcd01c15e 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/JdbcBatchLogging.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/JdbcBatchLogging.java
@@ -15,8 +15,8 @@
import org.jboss.logging.annotations.MessageLogger;
import org.jboss.logging.annotations.ValidIdRange;
-import static org.jboss.logging.Logger.Level.ERROR;
import static org.jboss.logging.Logger.Level.INFO;
+import static org.jboss.logging.Logger.Level.WARN;
/**
* Sub-system logging related to JDBC batch execution
@@ -35,11 +35,7 @@ public interface JdbcBatchLogging extends BasicLogger {
Logger BATCH_LOGGER = Logger.getLogger( NAME );
JdbcBatchLogging BATCH_MESSAGE_LOGGER = Logger.getMessageLogger( JdbcBatchLogging.class, NAME );
- @LogMessage(level = ERROR)
- @Message(id = 100501, value = "Exception executing batch [%s], SQL: %s")
- void unableToExecuteBatch(Exception e, String sql );
-
- @LogMessage(level = ERROR)
+ @LogMessage(level = WARN)
@Message(id = 100502, value = "Unable to release batch statement...")
void unableToReleaseBatchStatement();
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchImpl.java
index 2dcd5363d88d..51c17304cfad 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchImpl.java
@@ -290,12 +290,10 @@ protected void performExecution() {
}
catch (SQLException e) {
abortBatch( e );
- BATCH_MESSAGE_LOGGER.unableToExecuteBatch( e, sql );
throw sqlExceptionHelper.convert( e, "could not execute batch", sql );
}
catch (RuntimeException re) {
abortBatch( re );
- BATCH_MESSAGE_LOGGER.unableToExecuteBatch( re, sql );
throw re;
}
} );
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/internal/DatasourceConnectionProviderImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/internal/DatasourceConnectionProviderImpl.java
index 76bdbd7f731e..fea57b07fef1 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/internal/DatasourceConnectionProviderImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/internal/DatasourceConnectionProviderImpl.java
@@ -139,7 +139,7 @@ public boolean supportsAggressiveRelease() {
@Override
public DatabaseConnectionInfo getDatabaseConnectionInfo(Dialect dialect) {
return new DatabaseConnectionInfoImpl(
- "Connecting through datasource" + dataSourceJndiName,
+ "Connecting through datasource '" + (dataSourceJndiName != null ? dataSourceJndiName : dataSource) + "'",
null,
dialect.getVersion(),
null,
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentInitiator.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentInitiator.java
index 7038b1aa9fc3..bcd86a040922 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentInitiator.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentInitiator.java
@@ -19,7 +19,6 @@
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.jdbc.batch.spi.BatchBuilder;
-import org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator;
import org.hibernate.engine.jdbc.connections.internal.DatabaseConnectionInfoImpl;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.engine.jdbc.connections.spi.DatabaseConnectionInfo;
@@ -154,10 +153,14 @@ else if ( explicitDialectConfiguration( explicitDatabaseName, configurationValue
databaseConnectionInfo = buildDbInfo( configurationValues, jdbcEnvironment.getDialect() );
}
+ logConnectionInfo( databaseConnectionInfo );
+ return jdbcEnvironment;
+ }
+
+ // For Hibernate Reactive: it needs to disable or customize the log
+ protected void logConnectionInfo(DatabaseConnectionInfo databaseConnectionInfo) {
// Standardized DB info logging
ConnectionInfoLogger.INSTANCE.logConnectionInfoDetails( databaseConnectionInfo.toInfoString() );
-
- return jdbcEnvironment;
}
private DatabaseConnectionInfo buildDbInfo(ServiceRegistryImplementor registry, Dialect dialect) {
@@ -175,7 +178,8 @@ private DatabaseConnectionInfo buildDbInfo(Map configurationValu
return new DatabaseConnectionInfoImpl( configurationValues, dialect );
}
- private static JdbcEnvironmentImpl getJdbcEnvironmentWithDefaults(
+ // Used by Hibernate Reactive
+ protected JdbcEnvironmentImpl getJdbcEnvironmentWithDefaults(
Map configurationValues,
ServiceRegistryImplementor registry,
DialectFactory dialectFactory) {
@@ -183,7 +187,8 @@ private static JdbcEnvironmentImpl getJdbcEnvironmentWithDefaults(
return new JdbcEnvironmentImpl( registry, dialect );
}
- private static JdbcEnvironmentImpl getJdbcEnvironmentWithExplicitConfiguration(
+ // Used by Hibernate Reactive
+ protected JdbcEnvironmentImpl getJdbcEnvironmentWithExplicitConfiguration(
Map configurationValues,
ServiceRegistryImplementor registry,
DialectFactory dialectFactory,
@@ -204,6 +209,15 @@ private static JdbcEnvironmentImpl getJdbcEnvironmentWithExplicitConfiguration(
null,
configurationValues
);
+ return getJdbcEnvironmentWithExplicitConfiguration( configurationValues, registry, dialectFactory, dialectResolutionInfo );
+ }
+
+ // Used by Hibernate Reactive
+ protected JdbcEnvironmentImpl getJdbcEnvironmentWithExplicitConfiguration(
+ Map configurationValues,
+ ServiceRegistryImplementor registry,
+ DialectFactory dialectFactory,
+ DialectResolutionInfo dialectResolutionInfo) {
final Dialect dialect = dialectFactory.buildDialect( configurationValues, () -> dialectResolutionInfo );
return new JdbcEnvironmentImpl( registry, dialect );
}
@@ -216,7 +230,7 @@ private static JdbcEnvironmentImpl getJdbcEnvironmentWithExplicitConfiguration(
*
* @see JdbcSettings#ALLOW_METADATA_ON_BOOT
*/
- private static boolean allowJdbcMetadataAccess(Map configurationValues) {
+ public static boolean allowJdbcMetadataAccess(Map configurationValues) {
final Boolean allow = getBooleanWrapper( ALLOW_METADATA_ON_BOOT, configurationValues, null );
if ( allow != null ) {
return allow;
@@ -296,7 +310,8 @@ private static String getExplicitDatabaseName(Map configurationV
);
}
- private JdbcEnvironmentImpl getJdbcEnvironmentUsingJdbcMetadata(
+ // Used by Hibernate Reactive
+ protected JdbcEnvironmentImpl getJdbcEnvironmentUsingJdbcMetadata(
Map configurationValues,
ServiceRegistryImplementor registry,
DialectFactory dialectFactory, String explicitDatabaseName,
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/mutation/internal/PreparedStatementDetailsStandard.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/mutation/internal/PreparedStatementDetailsStandard.java
index 1732484d5694..f4b04aae4ab2 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/mutation/internal/PreparedStatementDetailsStandard.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/mutation/internal/PreparedStatementDetailsStandard.java
@@ -12,6 +12,7 @@
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementGroup;
+import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.jdbc.Expectation;
@@ -66,8 +67,10 @@ public TableMapping getMutatingTableDetails() {
@Override
public void releaseStatement(SharedSessionContractImplementor session) {
if ( statement != null ) {
- session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( statement );
+ final JdbcCoordinator jdbcCoordinator = session.getJdbcCoordinator();
+ jdbcCoordinator.getLogicalConnection().getResourceRegistry().release( statement );
statement = null;
+ jdbcCoordinator.afterStatementExecution();
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/profile/FetchProfile.java b/hibernate-core/src/main/java/org/hibernate/engine/profile/FetchProfile.java
index 0cd02922b83c..965cc4e86e71 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/profile/FetchProfile.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/profile/FetchProfile.java
@@ -14,6 +14,7 @@
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.BagType;
+import org.hibernate.type.CollectionType;
import org.hibernate.type.Type;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -98,7 +99,7 @@ public void addFetch(final Fetch fetch) {
final String role = association.getRole();
final Type associationType =
association.getOwner().getPropertyType( association.getAssociationPath() );
- if ( associationType.isCollectionType() ) {
+ if ( associationType instanceof CollectionType ) {
LOG.tracev( "Handling request to add collection fetch [{0}]", role );
// couple of things for which to account in the case of collection
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java
index 332bcefa9b96..9922ac4c1725 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java
@@ -52,7 +52,7 @@
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.type.CollectionType;
-import org.hibernate.type.CompositeType;
+import org.hibernate.type.ComponentType;
import org.hibernate.type.EntityType;
import org.hibernate.type.ForeignKeyDirection;
import org.hibernate.type.Type;
@@ -1167,7 +1167,10 @@ public void addTransitiveDependencies(InsertInfo origin, Set visited
}
private void addDirectDependency(Type type, @Nullable Object value, IdentityHashMap