Skip to content

Commit 16237ea

Browse files
committed
HHH-19300 tests for constraint interpretation and tiny bugfixes
1 parent 5ecfd2b commit 16237ea

File tree

4 files changed

+147
-5
lines changed

4 files changed

+147
-5
lines changed

hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,7 @@ public ViolatedConstraintNameExtractor getViolatedConstraintNameExtractor() {
453453
new TemplatedViolatedConstraintNameExtractor( sqle ->
454454
switch ( extractErrorCode( sqle ) ) {
455455
case -8, -9, -104, -177, -157 -> extractUsingTemplate( "; ", " table: ", sqle.getMessage() );
456+
case -10 -> extractUsingTemplate( " column: ", "\n", sqle.getMessage() );
456457
default -> null;
457458
});
458459

@@ -463,7 +464,8 @@ public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
463464
case -10 ->
464465
// Not null constraint violation
465466
new ConstraintViolationException( message, sqlException, sql,
466-
ConstraintViolationException.ConstraintKind.NOT_NULL, null );
467+
ConstraintViolationException.ConstraintKind.NOT_NULL,
468+
getViolatedConstraintNameExtractor().extractConstraintName(sqlException) );
467469
case -104 ->
468470
// Unique constraint violation
469471
new ConstraintViolationException( message, sqlException, sql,
@@ -477,7 +479,7 @@ public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
477479
case -177 ->
478480
// Foreign key constraint violation
479481
new ConstraintViolationException( message, sqlException, sql,
480-
ConstraintViolationException.ConstraintKind.CHECK,
482+
ConstraintViolationException.ConstraintKind.FOREIGN_KEY,
481483
getViolatedConstraintNameExtractor().extractConstraintName(sqlException) );
482484
default -> null;
483485
};

hibernate-core/src/main/java/org/hibernate/dialect/SybaseASEDialect.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -678,9 +678,12 @@ public ViolatedConstraintNameExtractor getViolatedConstraintNameExtractor() {
678678
case 546, 548 ->
679679
// Foreign key or check constraint violation
680680
extractUsingTemplate( "constraint name = '", "'", sqle.getMessage() );
681-
case 151 ->
681+
case 515 ->
682682
// Not null violation
683683
extractUsingTemplate( "column '", "'", sqle.getMessage() );
684+
case 233 ->
685+
// Not null violation
686+
extractUsingTemplate( "The column ", " ", sqle.getMessage() );
684687
default -> null;
685688
};
686689
default -> null;
@@ -704,7 +707,7 @@ public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
704707
case "S1000":
705708
case "23000":
706709
switch ( errorCode ) {
707-
case 515:
710+
case 515, 233:
708711
// Attempt to insert NULL value into column; column does not allow nulls.
709712
return new ConstraintViolationException( message, sqlException, sql,
710713
ConstraintViolationException.ConstraintKind.NOT_NULL,

hibernate-core/src/main/java/org/hibernate/exception/spi/TemplatedViolatedConstraintNameExtractor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public TemplatedViolatedConstraintNameExtractor(Function<SQLException,String> ex
6666
}
6767

6868
int start = templateStartPosition + templateStart.length();
69-
int end = message.indexOf( templateEnd, start );
69+
int end = templateEnd.equals("\n") ? -1 : message.indexOf( templateEnd, start );
7070
if ( end < 0 ) {
7171
end = message.length();
7272
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.orm.test.constraint;
6+
7+
import jakarta.persistence.CheckConstraint;
8+
import jakarta.persistence.Column;
9+
import jakarta.persistence.Entity;
10+
import jakarta.persistence.ForeignKey;
11+
import jakarta.persistence.Id;
12+
import jakarta.persistence.JoinColumn;
13+
import jakarta.persistence.ManyToOne;
14+
import jakarta.persistence.Table;
15+
import jakarta.persistence.UniqueConstraint;
16+
import org.hibernate.dialect.DB2Dialect;
17+
import org.hibernate.dialect.H2Dialect;
18+
import org.hibernate.dialect.HSQLDialect;
19+
import org.hibernate.dialect.MySQLDialect;
20+
import org.hibernate.dialect.OracleDialect;
21+
import org.hibernate.dialect.PostgreSQLDialect;
22+
import org.hibernate.dialect.SQLServerDialect;
23+
import org.hibernate.dialect.SybaseASEDialect;
24+
import org.hibernate.exception.ConstraintViolationException;
25+
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
26+
import org.hibernate.testing.orm.junit.Jpa;
27+
import org.hibernate.testing.orm.junit.RequiresDialect;
28+
import org.junit.jupiter.api.Test;
29+
30+
31+
import static org.junit.jupiter.api.Assertions.assertEquals;
32+
import static org.junit.jupiter.api.Assertions.assertTrue;
33+
import static org.junit.jupiter.api.Assertions.fail;
34+
35+
36+
@Jpa(annotatedClasses = {ConstraintInterpretationTest.Enttity1.class, ConstraintInterpretationTest.Entity2.class})
37+
@RequiresDialect( PostgreSQLDialect.class )
38+
@RequiresDialect( MySQLDialect.class )
39+
@RequiresDialect( H2Dialect.class )
40+
@RequiresDialect( HSQLDialect.class )
41+
@RequiresDialect( SQLServerDialect.class )
42+
@RequiresDialect( SybaseASEDialect.class )
43+
@RequiresDialect( OracleDialect.class )
44+
@RequiresDialect( DB2Dialect.class )
45+
public class ConstraintInterpretationTest {
46+
@Test void testNotNullPrimaryKey(EntityManagerFactoryScope scope) {
47+
scope.inTransaction( em -> {
48+
try {
49+
em.createNativeQuery( "insert into table_1 (id, name, ssn) values (null, 'test', 'abc123')" ).executeUpdate();
50+
fail();
51+
}
52+
catch (ConstraintViolationException cve) {
53+
assertEquals( ConstraintViolationException.ConstraintKind.NOT_NULL, cve.getKind() );
54+
assertTrue( cve.getConstraintName().toLowerCase().endsWith( "id" ) );
55+
}
56+
} );
57+
}
58+
@Test void testUniquePrimaryKey(EntityManagerFactoryScope scope) {
59+
scope.inTransaction( em -> {
60+
try {
61+
em.createNativeQuery( "insert into table_1 (id, name, ssn) values (1, 'test1', 'abc123')" ).executeUpdate();
62+
em.createNativeQuery( "insert into table_1 (id, name, ssn) values (1, 'test2', 'xyz456')" ).executeUpdate();
63+
fail();
64+
}
65+
catch (ConstraintViolationException cve) {
66+
assertEquals( ConstraintViolationException.ConstraintKind.UNIQUE, cve.getKind() );
67+
}
68+
} );
69+
}
70+
@Test void testNotNull(EntityManagerFactoryScope scope) {
71+
scope.inTransaction( em -> {
72+
try {
73+
em.createNativeQuery( "insert into table_1 (id, name, ssn) values (1, null, 'abc123')" ).executeUpdate();
74+
fail();
75+
}
76+
catch (ConstraintViolationException cve) {
77+
assertEquals( ConstraintViolationException.ConstraintKind.NOT_NULL, cve.getKind() );
78+
assertTrue( cve.getConstraintName().toLowerCase().endsWith( "name" ) );
79+
}
80+
} );
81+
}
82+
@Test void testUnique(EntityManagerFactoryScope scope) {
83+
scope.inTransaction( em -> {
84+
try {
85+
em.createNativeQuery( "insert into table_1 (id, name, ssn) values (1, 'test1', 'abc123')" ).executeUpdate();
86+
em.createNativeQuery( "insert into table_1 (id, name, ssn) values (2, 'test2', 'abc123')" ).executeUpdate();
87+
fail();
88+
}
89+
catch (ConstraintViolationException cve) {
90+
assertEquals( ConstraintViolationException.ConstraintKind.UNIQUE, cve.getKind() );
91+
assertTrue( cve.getConstraintName().toLowerCase().contains( "ssnuk" ) );
92+
}
93+
} );
94+
}
95+
@Test void testCheck(EntityManagerFactoryScope scope) {
96+
scope.inTransaction( em -> {
97+
try {
98+
em.createNativeQuery( "insert into table_1 (id, name, ssn) values (1, ' ', 'abc123')" ).executeUpdate();
99+
fail();
100+
}
101+
catch (ConstraintViolationException cve) {
102+
assertEquals( ConstraintViolationException.ConstraintKind.CHECK, cve.getKind() );
103+
assertTrue( cve.getConstraintName().toLowerCase().endsWith( "namecheck" ) );
104+
}
105+
} );
106+
}
107+
@Test void testForeignKey(EntityManagerFactoryScope scope) {
108+
scope.inTransaction( em -> {
109+
try {
110+
em.createNativeQuery( "insert into table_2 (id, id1) values (1, 69)" ).executeUpdate();
111+
fail();
112+
}
113+
catch (ConstraintViolationException cve) {
114+
assertEquals( ConstraintViolationException.ConstraintKind.FOREIGN_KEY, cve.getKind() );
115+
assertTrue( cve.getConstraintName().toLowerCase().endsWith( "id2to1fk" ) );
116+
}
117+
} );
118+
}
119+
@Entity @Table(name = "table_1",
120+
uniqueConstraints = @UniqueConstraint(name = "ssnuk", columnNames = "ssn"))
121+
static class Enttity1 {
122+
@Id Long id;
123+
@Column(nullable = false,
124+
check = @CheckConstraint(name = "namecheck", constraint = "name <> ' '"))
125+
String name;
126+
@Column(nullable = false)
127+
String ssn;
128+
}
129+
@Entity @Table(name = "table_2")
130+
static class Entity2 {
131+
@Id Long id;
132+
@JoinColumn(name = "id1", foreignKey = @ForeignKey(name = "id2to1fk"))
133+
@ManyToOne Enttity1 other;
134+
@Column(unique = true)
135+
String whatever;
136+
}
137+
}

0 commit comments

Comments
 (0)