Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Iterator;
Expand Down Expand Up @@ -134,20 +135,27 @@ public ResultSetAdaptor(RowSet<Row> rows) {
this.columnDescriptors = rows.columnDescriptors();
}

public ResultSetAdaptor(RowSet<Row> rows, PropertyKind<Row> propertyKind, String idColumnName, Class<?> idClass) {
this( rows, rows.property( propertyKind ), idColumnName, idClass );
public ResultSetAdaptor(RowSet<Row> rows, PropertyKind<Row> propertyKind, List<String> generatedColumnNames, List<Class<?>> generatedColumnClasses) {
this( rows, rows.property( propertyKind ), generatedColumnNames, generatedColumnClasses );
}

public ResultSetAdaptor(RowSet<Row> rows, Collection<?> ids, String idColumnName, Class<?> idClass) {
this( rows, new RowFromId( ids, idColumnName ), idColumnName, idClass );
}

private ResultSetAdaptor(RowSet<Row> rows, Row row, String idColumnName, Class<?> idClass) {
this( rows, row, List.of( idColumnName ), List.of( idClass ) );
}

private ResultSetAdaptor(RowSet<Row> rows, Row row, List<String> columnNames, List<Class<?>> columnClasses) {
requireNonNull( rows );
requireNonNull( idColumnName );
requireNonNull( columnNames );
this.iterator = List.of( row ).iterator();
this.columnNames = List.of( idColumnName );
this.columnDescriptors = List.of( toColumnDescriptor( idClass, idColumnName ) );
this.columnNames = columnNames ;
this.columnDescriptors = new ArrayList<>(columnNames.size());
for (int i =0; i < columnNames.size(); i++) {
columnDescriptors.add( toColumnDescriptor( columnClasses.get( i ), columnNames.get(i) ) );
}
}

private static ColumnDescriptor toColumnDescriptor(Class<?> idClass, String idColumnName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.hibernate.event.spi.EventSource;
import org.hibernate.generator.values.GeneratedValues;
import org.hibernate.internal.util.NullnessUtil;
import org.hibernate.metamodel.mapping.EntityRowIdMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister;
import org.hibernate.stat.spi.StatisticsImplementor;
Expand All @@ -31,6 +32,7 @@ public class ReactiveEntityIdentityInsertAction extends EntityIdentityInsertActi
private final boolean isVersionIncrementDisabled;
private boolean executed;
private boolean transientReferencesNullified;
private Object rowId;

public ReactiveEntityIdentityInsertAction(
Object[] state,
Expand Down Expand Up @@ -108,6 +110,13 @@ private CompletionStage<Void> processInsertGeneratedProperties(
Object instance,
GeneratedValues generatedValues,
SharedSessionContractImplementor session) {
final EntityRowIdMapping rowIdMapping = persister.getRowIdMapping();
if ( rowIdMapping != null ) {
rowId = generatedValues.getGeneratedValue( rowIdMapping );
if ( rowId != null && !isEarlyInsert() ) {
session.getPersistenceContext().replaceEntityEntryRowId( getInstance(), rowId );
}
}
return persister.hasInsertGeneratedProperties()
? persister.reactiveProcessInsertGenerated( generatedId, instance, getState(), generatedValues, session )
: voidFuture();
Expand Down Expand Up @@ -153,4 +162,9 @@ public boolean areTransientReferencesNullified() {
public void setTransientReferencesNullified() {
transientReferencesNullified = true;
}

@Override
public Object getRowId() {
return rowId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.spi.EventSource;
import org.hibernate.generator.values.GeneratedValues;
import org.hibernate.metamodel.mapping.EntityRowIdMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister;
import org.hibernate.stat.spi.StatisticsImplementor;
Expand Down Expand Up @@ -111,8 +112,19 @@ private CompletionStage<Void> processInsertGeneratedProperties(
// setVersion( Versioning.getVersion( getState(), persister ) );
}
return persister.reactiveProcessInsertGenerated( id, instance, getState(), generatedValues, session )
.thenAccept( v -> entry.postUpdate( instance, getState(), getVersion() ) );

.thenAccept( v -> {
// Process row-id values when available early by replacing the entity entry
if ( generatedValues != null ) {
final EntityRowIdMapping rowIdMapping = persister.getRowIdMapping();
if ( rowIdMapping != null ) {
final Object rowId = generatedValues.getGeneratedValue( rowIdMapping );
if ( rowId != null ) {
session.getPersistenceContext().replaceEntityEntryRowId( getInstance(), rowId );
}
}
}
entry.postUpdate( instance, getState(), getVersion() );
} );
}
else {
return voidFuture();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.hibernate.engine.spi.Status;
import org.hibernate.event.spi.EventSource;
import org.hibernate.generator.values.GeneratedValues;
import org.hibernate.metamodel.mapping.EntityRowIdMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.reactive.engine.ReactiveExecutable;
import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister;
Expand Down Expand Up @@ -143,7 +144,19 @@ private CompletionStage<Void> processGeneratedProperties(
throw new UnsupportedOperationException( "generated version attribute not supported in Hibernate Reactive" );
// setNextVersion( Versioning.getVersion( getState(), persister ) );
}
return persister.reactiveProcessUpdateGenerated( id, instance, getState(), generatedValues, session );
return persister.reactiveProcessUpdateGenerated( id, instance, getState(), generatedValues, session )
.thenAccept( v -> {
// Process row-id values when available early by replacing the entity entry
if ( generatedValues != null ) {
final EntityRowIdMapping rowIdMapping = persister.getRowIdMapping();
if ( rowIdMapping != null ) {
final Object rowId = generatedValues.getGeneratedValue( rowIdMapping );
if ( rowId != null ) {
session.getPersistenceContext().replaceEntityEntryRowId( getInstance(), rowId );
}
}
}
} );

}
else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@

import java.util.concurrent.CompletionStage;

import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.MariaDBDialect;
import org.hibernate.engine.jdbc.mutation.OperationResultChecker;
import org.hibernate.engine.jdbc.mutation.TableInclusionChecker;
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
Expand Down Expand Up @@ -48,7 +46,7 @@ public CompletionStage<GeneratedValues> performReactiveNonBatchedOperations(
boolean isIdentityInsert,
String[] identifierColumnsNames) {
PreparedStatementDetails singleStatementDetails = getStatementGroup().getSingleStatementDetails();
if ( generatedValuesDelegate != null && !isRegularInsertWithMariaDb( session, isIdentityInsert ) ) {
if ( generatedValuesDelegate != null ) {
return generatedValuesDelegate.reactivePerformMutation(
singleStatementDetails,
getJdbcValueBindings(),
Expand All @@ -67,14 +65,6 @@ public CompletionStage<GeneratedValues> performReactiveNonBatchedOperations(
).thenCompose( CompletionStages::nullFuture );
}

private boolean isRegularInsertWithMariaDb(SharedSessionContractImplementor session, boolean isIdentityInsert) {
if ( isIdentityInsert ) {
return false;
}
Dialect dialect = session.getJdbcServices().getDialect();
return dialect instanceof MariaDBDialect;
}

@Override
public void release() {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
import org.hibernate.sql.model.ast.builder.TableMutationBuilder;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer;

/**
* @deprecated No longer used
*/
@Deprecated(since = "7.1", forRemoval = true)
public class GeneratedValuesMutationDelegateAdaptor implements ReactiveGeneratedValuesMutationDelegate {
private final ReactiveGeneratedValuesMutationDelegate delegate;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@

import org.hibernate.HibernateException;
import org.hibernate.Internal;
import org.hibernate.dialect.CockroachDialect;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.MariaDBDialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.OracleDialect;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.generator.EventType;
import org.hibernate.generator.values.GeneratedValueBasicResultBuilder;
Expand All @@ -17,15 +21,16 @@
import org.hibernate.generator.values.internal.GeneratedValuesImpl;
import org.hibernate.generator.values.internal.GeneratedValuesMappingProducer;
import org.hibernate.id.IdentifierGeneratorHelper;
import org.hibernate.id.insert.GetGeneratedKeysDelegate;
import org.hibernate.id.insert.UniqueKeySelectingDelegate;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.reactive.id.insert.ReactiveGetGeneratedKeysDelegate;
import org.hibernate.reactive.id.insert.ReactiveInsertReturningDelegate;
import org.hibernate.reactive.id.insert.ReactiveUniqueKeySelectingDelegate;
import org.hibernate.reactive.sql.exec.spi.ReactiveRowProcessingState;
import org.hibernate.reactive.sql.exec.spi.ReactiveValuesResultSet;
import org.hibernate.reactive.sql.results.internal.ReactiveDirectResultSetAccess;
Expand All @@ -38,7 +43,6 @@
import org.hibernate.sql.results.internal.RowTransformerArrayImpl;
import org.hibernate.sql.results.jdbc.internal.JdbcValuesSourceProcessingStateStandardImpl;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.type.descriptor.WrapperOptions;

import java.sql.PreparedStatement;
Expand All @@ -51,6 +55,7 @@
import static org.hibernate.generator.values.internal.GeneratedValuesHelper.noCustomSql;
import static org.hibernate.internal.NaturalIdHelper.getNaturalIdPropertyNames;
import static org.hibernate.reactive.sql.results.spi.ReactiveListResultsConsumer.UniqueSemantic.NONE;
import static org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions.NO_OPTIONS;

/**
* @see org.hibernate.generator.values.internal.GeneratedValuesHelper
Expand All @@ -60,17 +65,21 @@ public class ReactiveGeneratedValuesHelper {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( IdentifierGeneratorHelper.class );

/**
*
* @see GeneratedValuesHelper#getGeneratedValuesDelegate(EntityPersister, EventType)
*/
public static GeneratedValuesMutationDelegate getGeneratedValuesDelegate(EntityPersister persister, EventType timing) {
final boolean hasGeneratedProperties = !persister.getGeneratedProperties( timing ).isEmpty();
final List<? extends ModelPart> generatedProperties = persister.getGeneratedProperties( timing );
final boolean hasGeneratedProperties = !generatedProperties.isEmpty();
final boolean hasRowId = timing == EventType.INSERT && persister.getRowIdMapping() != null;
final Dialect dialect = persister.getFactory().getJdbcServices().getDialect();

final boolean hasFormula = generatedProperties.stream()
.anyMatch( ReactiveGeneratedValuesHelper::isFormula );

boolean supportsInsertReturningRowId = trueIfCockroach( dialect, dialect.supportsInsertReturningRowId() );
if ( hasRowId
&& dialect.supportsInsertReturning()
&& dialect.supportsInsertReturningRowId()
&& supportsInsertReturning( dialect )
&& supportsInsertReturningRowId
&& noCustomSql( persister, timing ) ) {
// Special case for RowId on INSERT, since GetGeneratedKeysDelegate doesn't support it
// make InsertReturningDelegate the preferred method if the dialect supports it
Expand All @@ -81,26 +90,46 @@ && noCustomSql( persister, timing ) ) {
return null;
}

if ( dialect.supportsInsertReturningGeneratedKeys()
&& persister.getFactory().getSessionFactoryOptions().isGetGeneratedKeysEnabled() ) {
return new GetGeneratedKeysDelegate( persister, false, timing );
}
else if ( supportsReturning( dialect, timing ) && noCustomSql( persister, timing ) ) {
if ( supportsReturning( dialect, timing ) && noCustomSql( persister, timing ) ) {
return new ReactiveInsertReturningDelegate( persister, timing );
}
else if ( !hasFormula && dialect.supportsInsertReturningGeneratedKeys() ) {
return new ReactiveGetGeneratedKeysDelegate( persister, false, timing );
}
else if ( timing == EventType.INSERT && persister.getNaturalIdentifierProperties() != null
&& !persister.getEntityMetamodel().isNaturalIdentifierInsertGenerated() ) {
return new UniqueKeySelectingDelegate(
persister,
getNaturalIdPropertyNames( persister ),
timing
);
return new ReactiveUniqueKeySelectingDelegate( persister, getNaturalIdPropertyNames( persister ), timing );
}
return null;
}

private static boolean supportsReturning(Dialect dialect, EventType timing) {
return timing == EventType.INSERT ? dialect.supportsInsertReturning() : dialect.supportsUpdateReturning();
/**
* Cockroach supports returning SQL for insert and update statements, but the dialect wrongly returns false.
* @see <a href="https://hibernate.atlassian.net/browse/HHH-19717">HHH-19717</a>
*/
private static boolean trueIfCockroach(Dialect dialect, boolean predicate) {
return predicate || dialect instanceof CockroachDialect;
}

private static boolean isFormula(ModelPart part) {
return part instanceof SelectableMapping selectable && selectable.isFormula();
}

public static boolean supportReactiveGetGeneratedKey(Dialect dialect, List<? extends ModelPart> generatedProperties) {
return dialect instanceof OracleDialect
|| (dialect instanceof MySQLDialect && generatedProperties.size() == 1 && !(dialect instanceof MariaDBDialect));
}

public static boolean supportsReturning(Dialect dialect, EventType timing) {
return trueIfCockroach(
dialect, timing == EventType.INSERT
? dialect.supportsInsertReturning()
: dialect.supportsUpdateReturning()
);
}

public static boolean supportsInsertReturning(Dialect dialect) {
return trueIfCockroach( dialect, dialect.supportsInsertReturning() );
}

/**
Expand Down Expand Up @@ -181,31 +210,9 @@ private static CompletionStage<Object[]> readGeneratedValues(
executionContext
);

final JdbcValuesSourceProcessingOptions processingOptions = new JdbcValuesSourceProcessingOptions() {
@Override
public Object getEffectiveOptionalObject() {
return null;
}

@Override
public String getEffectiveOptionalEntityName() {
return null;
}

@Override
public Object getEffectiveOptionalId() {
return null;
}

@Override
public boolean shouldReturnProxies() {
return true;
}
};

final JdbcValuesSourceProcessingStateStandardImpl valuesProcessingState = new JdbcValuesSourceProcessingStateStandardImpl(
executionContext,
processingOptions
NO_OPTIONS
);

final ReactiveRowReader<Object[]> rowReader = ReactiveResultsHelper.createRowReader(
Expand All @@ -217,7 +224,7 @@ public boolean shouldReturnProxies() {

final ReactiveRowProcessingState rowProcessingState = new ReactiveRowProcessingState( valuesProcessingState, executionContext, rowReader, jdbcValues );
return ReactiveListResultsConsumer.<Object[]>instance( NONE )
.consume( jdbcValues, session, processingOptions, valuesProcessingState, rowProcessingState, rowReader )
.consume( jdbcValues, session, NO_OPTIONS, valuesProcessingState, rowProcessingState, rowReader )
.thenApply( results -> {
if ( results.isEmpty() ) {
throw new HibernateException( "The database returned no natively generated values : " + persister.getNavigableRole().getFullPath() );
Expand Down
Loading
Loading