Skip to content

Commit 11cea82

Browse files
authored
Merge branch '6.6' into timesten_dialect_updates
2 parents 7d28099 + 9bfabbd commit 11cea82

File tree

9 files changed

+272
-30
lines changed

9 files changed

+272
-30
lines changed

changelog.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,23 @@ Hibernate 6 Changelog
33

44
Note: Please refer to JIRA to learn more about each issue.
55

6+
Changes in 6.6.20.Final (July 06, 2025)
7+
------------------------------------------------------------------------------------------------------------------------
8+
9+
https://hibernate.atlassian.net/projects/HHH/versions/34165
10+
11+
** Bug
12+
* [HHH-19464] - Storing a binary data into BLOB on Oracle cutting off its content.
13+
* [HHH-19396] - Cannot select the same column twice (with different aliases) while using CTE
14+
* [HHH-19076] - expecting IdClass mapping sessionfactory error with specific @IdClass setup with inheritence
15+
* [HHH-18898] - Specific mistake in HQL gives NullPointerException in AbstractSqlAstTranslator
16+
* [HHH-18837] - Oracle epoch extraction doesn't work with dates
17+
* [HHH-18581] - Performance degradation from Hibernate 5 to 6 on NativeQuery
18+
19+
** Improvement
20+
* [HHH-19558] - allow JDBC escapes in native SQL queries
21+
22+
623
Changes in 6.6.19.Final (June 29, 2025)
724
------------------------------------------------------------------------------------------------------------------------
825

ci/quarkus.Jenkinsfile

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,6 @@ pipeline {
4848
}
4949
dir('quarkus') {
5050
sh "git clone -b 3.15 --single-branch https://github.com/quarkusio/quarkus.git . || git reset --hard && git clean -fx && git pull"
51-
// This is a temporary workaround because Quarkus reverted the Hibernate ORM and Reactive upgrade.
52-
// Remove this once Quarkus upgrades the versions again
53-
sh "git reset --hard f42166ee7041ed09b7183d5dbf3ece2439b16676"
5451
script {
5552
def sedStatus = sh (script: "sed -i 's@<hibernate-orm.version>.*</hibernate-orm.version>@<hibernate-orm.version>${env.HIBERNATE_VERSION}</hibernate-orm.version>@' pom.xml", returnStatus: true)
5653
if ( sedStatus != 0 ) {

gradle/version.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
hibernateVersion=6.6.20-SNAPSHOT
1+
hibernateVersion=6.6.21-SNAPSHOT

hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedColumns.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public boolean isSecondary() {
106106
final String explicitTableName = firstColumn.getExplicitTableName();
107107
//note: checkPropertyConsistency() is responsible for ensuring they all have the same table name
108108
return isNotEmpty( explicitTableName )
109-
&& !getPropertyHolder().getTable().getName().equals( explicitTableName );
109+
&& !getOwnerTable().getName().equals( explicitTableName );
110110
}
111111

112112
/**
@@ -125,10 +125,18 @@ public Table getTable() {
125125
// all the columns have to be mapped to the same table
126126
// even though at the annotation level it looks like
127127
// they could each specify a different table
128-
return isSecondary() ? getJoin().getTable() : getPropertyHolder().getTable();
128+
return isSecondary() ? getJoin().getTable() : getOwnerTable();
129129
}
130130
}
131131

132+
private Table getOwnerTable() {
133+
PropertyHolder holder = getPropertyHolder();
134+
while ( holder instanceof ComponentPropertyHolder ) {
135+
holder = ( (ComponentPropertyHolder) holder ).parent;
136+
}
137+
return holder.getTable();
138+
}
139+
132140
public void setTable(Table table) {
133141
this.table = table;
134142
}

hibernate-core/src/main/java/org/hibernate/boot/model/internal/ComponentPropertyHolder.java

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -266,26 +266,31 @@ public String getEntityName() {
266266

267267
@Override
268268
public void addProperty(Property property, AnnotatedColumns columns, XClass declaringClass) {
269-
//Ejb3Column.checkPropertyConsistency( ); //already called earlier
269+
//AnnotatedColumns.checkPropertyConsistency( ); //already called earlier
270270
// Check table matches between the component and the columns
271271
// if not, change the component table if no properties are set
272272
// if a property is set already the core cannot support that
273-
if ( columns != null ) {
274-
final Table table = columns.getTable();
275-
if ( !table.equals( getTable() ) ) {
276-
if ( component.getPropertySpan() == 0 ) {
277-
component.setTable( table );
278-
}
279-
else {
280-
throw new AnnotationException(
281-
"Embeddable class '" + component.getComponentClassName()
282-
+ "' has properties mapped to two different tables"
283-
+ " (all properties of the embeddable class must map to the same table)"
284-
);
285-
}
273+
assert columns == null || property.getValue().getTable() == columns.getTable();
274+
setTable( property.getValue().getTable() );
275+
addProperty( property, declaringClass );
276+
}
277+
278+
private void setTable(Table table) {
279+
if ( !table.equals( getTable() ) ) {
280+
if ( component.getPropertySpan() == 0 ) {
281+
component.setTable( table );
282+
}
283+
else {
284+
throw new AnnotationException(
285+
"Embeddable class '" + component.getComponentClassName()
286+
+ "' has properties mapped to two different tables"
287+
+ " (all properties of the embeddable class must map to the same table)"
288+
);
289+
}
290+
if ( parent instanceof ComponentPropertyHolder ) {
291+
( (ComponentPropertyHolder) parent ).setTable( table );
286292
}
287293
}
288-
addProperty( property, declaringClass );
289294
}
290295

291296
@Override

hibernate-core/src/main/java/org/hibernate/boot/model/internal/EmbeddableBinder.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -244,15 +244,15 @@ private static PropertyBinder createEmbeddedProperty(
244244
final PropertyBinder binder = new PropertyBinder();
245245
binder.setDeclaringClass( inferredData.getDeclaringClass() );
246246
binder.setName( inferredData.getPropertyName() );
247-
binder.setValue(component);
247+
binder.setValue( component );
248248
binder.setProperty( inferredData.getProperty() );
249249
binder.setAccessType( inferredData.getDefaultAccess() );
250-
binder.setEmbedded(isComponentEmbedded);
251-
binder.setHolder(propertyHolder);
252-
binder.setId(isId);
253-
binder.setEntityBinder(entityBinder);
254-
binder.setInheritanceStatePerClass(inheritanceStatePerClass);
255-
binder.setBuildingContext(context);
250+
binder.setEmbedded( isComponentEmbedded );
251+
binder.setHolder( propertyHolder );
252+
binder.setId( isId );
253+
binder.setEntityBinder( entityBinder );
254+
binder.setInheritanceStatePerClass( inheritanceStatePerClass );
255+
binder.setBuildingContext( context );
256256
binder.makePropertyAndBind();
257257
return binder;
258258
}

hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/annotations/embedded/EmbeddableA.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@
1717
*/
1818
@Embeddable
1919
public class EmbeddableA {
20-
20+
2121
@Embedded
2222
@AttributeOverrides({@AttributeOverride(name = "embedAttrB" , column = @Column(table = "TableB"))})
2323
private EmbeddableB embedB;
24-
24+
@Column(table = "TableB")
2525
private String embedAttrA;
2626

2727
public EmbeddableB getEmbedB() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
6+
*/
7+
package org.hibernate.orm.test.mapping.embeddable;
8+
9+
import jakarta.persistence.AttributeOverride;
10+
import jakarta.persistence.Column;
11+
import jakarta.persistence.Embeddable;
12+
import jakarta.persistence.Embedded;
13+
import jakarta.persistence.Entity;
14+
import jakarta.persistence.GeneratedValue;
15+
import jakarta.persistence.Id;
16+
import jakarta.persistence.SecondaryTable;
17+
import jakarta.persistence.Table;
18+
import org.hibernate.boot.MetadataSources;
19+
import org.hibernate.testing.orm.junit.JiraKey;
20+
import org.hibernate.testing.orm.junit.ServiceRegistry;
21+
import org.hibernate.testing.orm.junit.ServiceRegistryScope;
22+
import org.junit.jupiter.api.Test;
23+
24+
/**
25+
* Test passes if Author#name is renamed to Author#aname because it will be read before house (alphabetical order).
26+
* The issue occurs if the nested embedded is read first, due to the table calculation (ComponentPropertyHolder#addProperty) used by the embedded, which retrieves the table from the first property.
27+
*
28+
* @author Vincent Bouthinon
29+
*/
30+
@SuppressWarnings("JUnitMalformedDeclaration")
31+
@ServiceRegistry()
32+
@JiraKey("HHH-19272")
33+
class NestedEmbeddedObjectWithASecondaryTableTest {
34+
35+
@Test
36+
void testNestedEmbeddedAndSecondaryTables(ServiceRegistryScope registryScope) {
37+
final MetadataSources metadataSources = new MetadataSources( registryScope.getRegistry() )
38+
.addAnnotatedClasses( Book.class, Author.class, House.class );
39+
metadataSources.buildMetadata();
40+
}
41+
42+
@Entity(name = "book")
43+
@Table(name = "TBOOK")
44+
@SecondaryTable(name = "TSECONDARYTABLE")
45+
public static class Book {
46+
47+
@Id
48+
@GeneratedValue
49+
private Long id;
50+
51+
@AttributeOverride(name = "name", column = @Column(name = "authorName", table = "TSECONDARYTABLE"))
52+
@Embedded
53+
private Author author;
54+
55+
}
56+
57+
@Embeddable
58+
public static class Author {
59+
60+
@AttributeOverride(name = "name", column = @Column(name = "houseName", table = "TSECONDARYTABLE"))
61+
@Embedded
62+
private House house;
63+
64+
private String name;
65+
}
66+
67+
@Embeddable
68+
public static class House {
69+
private String name;
70+
}
71+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
6+
*/
7+
package org.hibernate.orm.test.records;
8+
9+
import jakarta.persistence.Column;
10+
import jakarta.persistence.Embeddable;
11+
import jakarta.persistence.Entity;
12+
import jakarta.persistence.GeneratedValue;
13+
import jakarta.persistence.Id;
14+
import jakarta.persistence.SecondaryTable;
15+
import jakarta.persistence.Table;
16+
import org.hibernate.AnnotationException;
17+
import org.hibernate.boot.MetadataSources;
18+
import org.hibernate.boot.registry.StandardServiceRegistry;
19+
import org.hibernate.testing.orm.junit.DomainModel;
20+
import org.hibernate.testing.orm.junit.JiraKey;
21+
import org.hibernate.testing.orm.junit.ServiceRegistryScope;
22+
import org.hibernate.testing.orm.junit.SessionFactory;
23+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
24+
import org.junit.jupiter.api.BeforeAll;
25+
import org.junit.jupiter.api.Test;
26+
27+
import static org.assertj.core.api.Assertions.assertThat;
28+
import static org.assertj.core.api.Assertions.fail;
29+
30+
@JiraKey("HHH-19542")
31+
@DomainModel(annotatedClasses = {
32+
RecordNestedEmbeddedWithASecondaryTableTest.UserEntity.class
33+
})
34+
@SessionFactory
35+
class RecordNestedEmbeddedWithASecondaryTableTest {
36+
37+
private UserEntity user;
38+
39+
@BeforeAll
40+
void prepare(SessionFactoryScope scope) {
41+
scope.inTransaction( session -> {
42+
Person person = new Person( new FullName( "Sylvain", "Lecoy" ), 38 );
43+
user = new UserEntity( person );
44+
session.persist( user );
45+
} );
46+
}
47+
48+
@Test
49+
void test(SessionFactoryScope scope) {
50+
scope.inTransaction(session -> {
51+
UserEntity entity = session.find( UserEntity.class, user.id );
52+
assertThat( entity ).isNotNull();
53+
assertThat( entity.id ).isEqualTo( user.id );
54+
assertThat( entity.person ).isNotNull();
55+
assertThat( entity.person.age ).isEqualTo( 38 );
56+
assertThat( entity.person.fullName.firstName ).isEqualTo( "Sylvain" );
57+
assertThat( entity.person.fullName.lastName ).isEqualTo( "Lecoy" );
58+
});
59+
}
60+
61+
@Test
62+
void test(ServiceRegistryScope scope) {
63+
final StandardServiceRegistry registry = scope.getRegistry();
64+
final MetadataSources sources = new MetadataSources( registry ).addAnnotatedClass( UserEntity1.class );
65+
66+
try {
67+
sources.buildMetadata();
68+
fail( "Expecting to fail" );
69+
} catch (AnnotationException expected) {
70+
assertThat( expected ).hasMessageContaining( "all properties of the embeddable class must map to the same table" );
71+
}
72+
}
73+
74+
@Entity
75+
@Table(name = "UserEntity")
76+
@SecondaryTable(name = "Person")
77+
static class UserEntity {
78+
@Id
79+
@GeneratedValue
80+
private Integer id;
81+
private Person person;
82+
83+
public UserEntity(
84+
final Person person) {
85+
this.person = person;
86+
}
87+
88+
protected UserEntity() {
89+
90+
}
91+
}
92+
93+
@Embeddable
94+
record Person(
95+
FullName fullName,
96+
@Column(table = "Person")
97+
Integer age) {
98+
99+
}
100+
101+
@Embeddable
102+
record FullName(
103+
@Column(table = "Person")
104+
String firstName,
105+
@Column(table = "Person")
106+
String lastName) {
107+
108+
}
109+
110+
@Entity
111+
@Table(name = "UserEntity")
112+
@SecondaryTable(name = "Person")
113+
public static class UserEntity1 {
114+
@Id
115+
@GeneratedValue
116+
private Integer id;
117+
private Person1 person;
118+
119+
public UserEntity1(
120+
final Person1 person) {
121+
this.person = person;
122+
}
123+
124+
protected UserEntity1() {
125+
126+
}
127+
}
128+
129+
@Embeddable
130+
public record Person1(
131+
FullName1 fullName,
132+
@Column(table = "Person")
133+
Integer age) {
134+
135+
}
136+
137+
@Embeddable
138+
public record FullName1(
139+
@Column(table = "Person")
140+
String firstName,
141+
String lastName) {
142+
143+
}
144+
}

0 commit comments

Comments
 (0)