Skip to content
Open
Show file tree
Hide file tree
Changes from all 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 @@ -25,7 +25,9 @@
import org.hibernate.id.BulkInsertionCapableIdentifierGenerator;
import org.hibernate.id.CompositeNestedGeneratedValueGenerator;
import org.hibernate.id.OptimizableGenerator;
import org.hibernate.id.enhanced.LegacyNamingStrategy;
import org.hibernate.id.enhanced.Optimizer;
import org.hibernate.id.enhanced.SequenceStyleGenerator;
import org.hibernate.internal.util.NullnessUtil;
import org.hibernate.internal.util.collections.Stack;
import org.hibernate.internal.util.collections.StandardStack;
Expand Down Expand Up @@ -138,6 +140,7 @@
import org.hibernate.query.sqm.sql.internal.SqmMapEntryResult;
import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation;
import org.hibernate.query.sqm.sql.internal.SqmPathInterpretation;
import org.hibernate.query.sqm.sql.internal.StandardSqmTranslator;
import org.hibernate.query.sqm.tree.SqmDmlStatement;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.SqmStatement;
Expand Down Expand Up @@ -441,6 +444,7 @@
import static java.util.Collections.singleton;
import static java.util.Collections.singletonList;
import static org.hibernate.boot.model.process.internal.InferredBasicValueResolver.resolveSqlTypeIndicators;
import static org.hibernate.cfg.MappingSettings.ID_DB_STRUCTURE_NAMING_STRATEGY;
import static org.hibernate.generator.EventType.INSERT;
import static org.hibernate.internal.util.NullnessHelper.coalesceSuppliedValues;
import static org.hibernate.query.QueryLogging.QUERY_MESSAGE_LOGGER;
Expand Down Expand Up @@ -1203,7 +1207,7 @@ public InsertStatement visitInsertSelectStatement(SqmInsertSelectStatement<?> sq
);

if ( hasJoins( rootTableGroup ) ) {
throw new SemanticException( "Not expecting multiple table references for an SQM INSERT-SELECT" );
throw new HibernateException( "Not expecting multiple table references for an SQM INSERT-SELECT" );
}
}
finally {
Expand Down Expand Up @@ -1438,8 +1442,9 @@ else if ( localName.equals( versionAttributeName ) ) {
else if ( identifierGenerator != null ) {
// When we have an identifier generator, we somehow must list the identifier column in the insert statement.
final boolean addIdColumn;
if ( sqmStatement instanceof SqmInsertValuesStatement<?> ) {
// For an InsertValuesStatement, we can just list the column, as we can inject a parameter in the VALUES clause.
if ( sqmStatement instanceof SqmInsertValuesStatement<?>
|| sqmStatement instanceof SqmInsertSelectStatement<?> && this instanceof StandardSqmTranslator<?> ) {
// For an InsertValuesStatement or an InsertSelectStatement, we can just list the column, as we can inject a parameter in the VALUES clause.
addIdColumn = true;
}
else if ( !( identifierGenerator instanceof BulkInsertionCapableIdentifierGenerator bulkInsertionCapableGenerator ) ) {
Expand Down Expand Up @@ -1551,6 +1556,14 @@ public boolean applySelections(QuerySpec querySpec, SessionFactoryImplementor se
throw new SemanticException(
"SQM INSERT-SELECT without bulk insertion capable identifier generator: " + identifierGenerator );
}
if ( identifierGenerator instanceof SequenceStyleGenerator && identifierGeneratorParameter == null
&& LegacyNamingStrategy.STRATEGY_NAME.equals(
sessionFactory.getProperties().get( ID_DB_STRUCTURE_NAMING_STRATEGY ) ) ) {
identifierGeneratorParameter = new IdGeneratorParameter( identifierMapping,
(BeforeExecutionGenerator) identifierGenerator );
selectClause.addSqlSelection( new SqlSelectionImpl( identifierGeneratorParameter ) );
return false;
}
if ( identifierGenerator instanceof OptimizableGenerator optimizableGenerator ) {
final Optimizer optimizer = optimizableGenerator.getOptimizer();
if ( optimizer != null && optimizer.getIncrementSize() > 1
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.orm.test.query.hql;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.id.enhanced.LegacyNamingStrategy;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

@DomainModel(
annotatedClasses = {
InsertSelectLegacyTest.Person.class,
InsertSelectLegacyTest.Document.class
}
)
@ServiceRegistry(
settings = {
@Setting(name = AvailableSettings.SHOW_SQL, value = "true"),
@Setting(name = AvailableSettings.FORMAT_SQL, value = "true"),
@Setting(name = AvailableSettings.ID_DB_STRUCTURE_NAMING_STRATEGY,
value = LegacyNamingStrategy.STRATEGY_NAME)
}
)
@SessionFactory
public class InsertSelectLegacyTest {

@Test
@JiraKey(value = "HHH-18835")
void testInsertSelect(SessionFactoryScope scope) {

scope.inTransaction( session -> {
Person person = new Person();
person.name = "Peter";
session.persist( person );

session.createMutationQuery(
"insert into Document(name,owner) select concat(p.name,'s document'), p from Person p" )
.executeUpdate();

Document document = session.createQuery( "select d from Document d", Document.class ).getSingleResult();
assertNotNull( document );
assertEquals( "Peters document", document.name );
} );
}

@Entity(name = "Person")
public static class Person {

@Id
@GeneratedValue
Long id;

String name;
}

@Entity(name = "Document")
public static class Document {

@Id
@GeneratedValue
Long id;

String name;

@ManyToOne
Person owner;
}
}