Skip to content

HHH-19726 Update MariaDB CI testing to 12.0 and the MariaDB JDBC driver #10801

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 21, 2025
Merged
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
25 changes: 9 additions & 16 deletions docker_db.sh
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ mysql_setup() {
}

mariadb() {
mariadb_11_8
mariadb_12_0
}

mariadb_wait_until_start()
Expand All @@ -117,37 +117,31 @@ mariadb_wait_until_start()

mariadb_10_6() {
$CONTAINER_CLI rm -f mariadb || true
$CONTAINER_CLI run --name mariadb -e MARIADB_USER=hibernate_orm_test -e MARIADB_PASSWORD=hibernate_orm_test -e MARIADB_DATABASE=hibernate_orm_test -e MARIADB_ROOT_PASSWORD=hibernate_orm_test -p3306:3306 -d ${DB_IMAGE_MARIADB_10_6:-docker.io/mariadb:10.6.20} --character-set-server=utf8mb4 --collation-server=utf8mb4_bin --skip-character-set-client-handshake --lower_case_table_names=2
$CONTAINER_CLI run --name mariadb -e MARIADB_USER=hibernate_orm_test -e MARIADB_PASSWORD=hibernate_orm_test -e MARIADB_DATABASE=hibernate_orm_test -e MARIADB_ROOT_PASSWORD=hibernate_orm_test -p3306:3306 -d ${DB_IMAGE_MARIADB_10_6:-docker.io/mariadb:10.6.23} --character-set-server=utf8mb4 --collation-server=utf8mb4_bin --skip-character-set-client-handshake --lower_case_table_names=2
mariadb_wait_until_start
}

mariadb_10_11() {
$CONTAINER_CLI rm -f mariadb || true
$CONTAINER_CLI run --name mariadb -e MARIADB_USER=hibernate_orm_test -e MARIADB_PASSWORD=hibernate_orm_test -e MARIADB_DATABASE=hibernate_orm_test -e MARIADB_ROOT_PASSWORD=hibernate_orm_test -p3306:3306 -d ${DB_IMAGE_MARIADB_10_11:-docker.io/mariadb:10.11.8} --character-set-server=utf8mb4 --collation-server=utf8mb4_bin --skip-character-set-client-handshake --lower_case_table_names=2
mariadb_wait_until_start
}

mariadb_11_1() {
$CONTAINER_CLI rm -f mariadb || true
$CONTAINER_CLI run --name mariadb -e MARIADB_USER=hibernate_orm_test -e MARIADB_PASSWORD=hibernate_orm_test -e MARIADB_DATABASE=hibernate_orm_test -e MARIADB_ROOT_PASSWORD=hibernate_orm_test -p3306:3306 -d ${DB_IMAGE_MARIADB_11_1:-docker.io/mariadb:11.1.2} --character-set-server=utf8mb4 --collation-server=utf8mb4_bin --skip-character-set-client-handshake --lower_case_table_names=2
$CONTAINER_CLI run --name mariadb -e MARIADB_USER=hibernate_orm_test -e MARIADB_PASSWORD=hibernate_orm_test -e MARIADB_DATABASE=hibernate_orm_test -e MARIADB_ROOT_PASSWORD=hibernate_orm_test -p3306:3306 -d ${DB_IMAGE_MARIADB_10_11:-docker.io/mariadb:10.11.14} --character-set-server=utf8mb4 --collation-server=utf8mb4_bin --skip-character-set-client-handshake --lower_case_table_names=2
mariadb_wait_until_start
}

mariadb_11_4() {
$CONTAINER_CLI rm -f mariadb || true
$CONTAINER_CLI run --name mariadb -e MARIADB_USER=hibernate_orm_test -e MARIADB_PASSWORD=hibernate_orm_test -e MARIADB_DATABASE=hibernate_orm_test -e MARIADB_ROOT_PASSWORD=hibernate_orm_test -p3306:3306 -d ${DB_IMAGE_MARIADB_11_4:-docker.io/mariadb:11.4.2} --character-set-server=utf8mb4 --collation-server=utf8mb4_bin --skip-character-set-client-handshake --lower_case_table_names=2
$CONTAINER_CLI run --name mariadb -e MARIADB_USER=hibernate_orm_test -e MARIADB_PASSWORD=hibernate_orm_test -e MARIADB_DATABASE=hibernate_orm_test -e MARIADB_ROOT_PASSWORD=hibernate_orm_test -p3306:3306 -d ${DB_IMAGE_MARIADB_11_4:-docker.io/mariadb:11.4.8} --character-set-server=utf8mb4 --collation-server=utf8mb4_bin --skip-character-set-client-handshake --lower_case_table_names=2
mariadb_wait_until_start
}

mariadb_11_7() {
mariadb_11_8() {
$CONTAINER_CLI rm -f mariadb || true
$CONTAINER_CLI run --name mariadb -e MARIADB_USER=hibernate_orm_test -e MARIADB_PASSWORD=hibernate_orm_test -e MARIADB_DATABASE=hibernate_orm_test -e MARIADB_ROOT_PASSWORD=hibernate_orm_test -p3306:3306 -d ${DB_IMAGE_MARIADB_11_7:-docker.io/mariadb:11.7.2} --character-set-server=utf8mb4 --collation-server=utf8mb4_bin --skip-character-set-client-handshake --lower_case_table_names=2
$CONTAINER_CLI run --name mariadb -e MARIADB_USER=hibernate_orm_test -e MARIADB_PASSWORD=hibernate_orm_test -e MARIADB_DATABASE=hibernate_orm_test -e MARIADB_ROOT_PASSWORD=hibernate_orm_test -p3306:3306 -d ${DB_IMAGE_MARIADB_11_8:-docker.io/mariadb:11.8.3} --character-set-server=utf8mb4 --collation-server=utf8mb4_bin --skip-character-set-client-handshake --lower_case_table_names=2
mariadb_wait_until_start
}

mariadb_11_8() {
mariadb_12_0() {
$CONTAINER_CLI rm -f mariadb || true
$CONTAINER_CLI run --name mariadb -e MARIADB_USER=hibernate_orm_test -e MARIADB_PASSWORD=hibernate_orm_test -e MARIADB_DATABASE=hibernate_orm_test -e MARIADB_ROOT_PASSWORD=hibernate_orm_test -p3306:3306 -d ${DB_IMAGE_MARIADB_11_8:-docker.io/mariadb:11.8.2} --character-set-server=utf8mb4 --collation-server=utf8mb4_bin --skip-character-set-client-handshake --lower_case_table_names=2
$CONTAINER_CLI run --name mariadb -e MARIADB_USER=hibernate_orm_test -e MARIADB_PASSWORD=hibernate_orm_test -e MARIADB_DATABASE=hibernate_orm_test -e MARIADB_ROOT_PASSWORD=hibernate_orm_test -p3306:3306 -d ${DB_IMAGE_MARIADB_12_0:-docker.io/mariadb:12.0.2} --character-set-server=utf8mb4 --collation-server=utf8mb4_bin --skip-character-set-client-handshake --lower_case_table_names=2
mariadb_wait_until_start
}

Expand Down Expand Up @@ -1100,9 +1094,8 @@ if [ -z ${1} ]; then
echo -e "\thana"
echo -e "\tmariadb"
echo -e "\tmariadb_verylatest"
echo -e "\tmariadb_11_7"
echo -e "\tmariadb_11_8"
echo -e "\tmariadb_11_4"
echo -e "\tmariadb_11_1"
echo -e "\tmariadb_10_11"
echo -e "\tmariadb_10_6"
echo -e "\tmssql"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,11 @@ public boolean supportsColumnCheck() {
return getVersion().isSameOrAfter( 10, 2 );
}

@Override
public boolean supportsNamedColumnCheck() {
return false;
}

@Override
public boolean doesRoundTemporalOnOverflow() {
// See https://jira.mariadb.org/browse/MDEV-16991
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -967,7 +967,7 @@ void applyCheckConstraints(jakarta.persistence.CheckConstraint[] checkConstraint
if ( isNotEmpty( checkConstraintAnnotationUsages ) ) {
for ( jakarta.persistence.CheckConstraint checkConstraintAnnotationUsage : checkConstraintAnnotationUsages ) {
addCheckConstraint(
checkConstraintAnnotationUsage.name(),
nullIfEmpty( checkConstraintAnnotationUsage.name() ),
checkConstraintAnnotationUsage.constraint(),
checkConstraintAnnotationUsage.options()
);
Expand All @@ -983,7 +983,7 @@ void applyCheckConstraint(PropertyData inferredData, int length) {
if ( checksAnn != null ) {
final Check[] checkAnns = checksAnn.value();
for ( Check checkAnn : checkAnns ) {
addCheckConstraint( checkAnn.name(), checkAnn.constraints() );
addCheckConstraint( nullIfEmpty( checkAnn.name() ), checkAnn.constraints() );
}
}
else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
import static org.hibernate.internal.util.StringHelper.isQuoted;
import static org.hibernate.internal.util.StringHelper.nullIfBlank;
import static org.hibernate.internal.util.StringHelper.nullIfEmpty;
import static org.hibernate.internal.util.StringHelper.unquote;
import static org.hibernate.internal.util.collections.CollectionHelper.isNotEmpty;

Expand Down Expand Up @@ -896,7 +897,7 @@ static void addTableCheck(
for ( jakarta.persistence.CheckConstraint checkConstraintAnnotationUsage : checkConstraintAnnotationUsages ) {
table.addCheck(
new CheckConstraint(
checkConstraintAnnotationUsage.name(),
nullIfEmpty( checkConstraintAnnotationUsage.name() ),
checkConstraintAnnotationUsage.constraint(),
checkConstraintAnnotationUsage.options()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,56 @@
|| ( major == otherMajor && minor == otherMinor && micro >= otherMicro );
}

/**
* {@link #isSame} or {@link #isBefore}
*/
default boolean isSameOrBefore(DatabaseVersion other) {
return isSameOrBefore( other.getDatabaseMajorVersion(), other.getDatabaseMinorVersion() );
}

/**
* {@link #isSame} or {@link #isBefore}
*/
default boolean isSameOrBefore(Integer otherMajor, Integer otherMinor) {
return isSameOrBefore(
(int) otherMajor,
otherMinor == null ? NO_VERSION : otherMinor
);
}

/**
* {@link #isSame} or {@link #isBefore}
*/
default boolean isSameOrBefore(int otherMajor) {
final int major = getDatabaseMajorVersion();

return major <= otherMajor;
}

/**
* {@link #isSame} or {@link #isBefore}
*/
default boolean isSameOrBefore(int otherMajor, int otherMinor) {

Check notice

Code scanning / CodeQL

Confusing overloading of methods Note

Method DatabaseVersion.isSameOrBefore(..) could be confused with overloaded method
isSameOrBefore
, since dispatch depends on static types.
final int major = getDatabaseMajorVersion();
final int minor = getDatabaseMinorVersion();

return major < otherMajor
|| ( major == otherMajor && minor <= otherMinor );
}

/**
* {@link #isSame} or {@link #isBefore}
*/
default boolean isSameOrBefore(int otherMajor, int otherMinor, int otherMicro) {
final int major = getDatabaseMajorVersion();
final int minor = getDatabaseMinorVersion();
final int micro = getDatabaseMicroVersion();

return major < otherMajor
|| ( major == otherMajor && minor < otherMinor )
|| ( major == otherMajor && minor == otherMinor && micro <= otherMicro );
}

/**
* Determine whether this version comes after the passed one
*/
Expand Down
10 changes: 10 additions & 0 deletions hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java
Original file line number Diff line number Diff line change
Expand Up @@ -4188,6 +4188,16 @@ public boolean supportsColumnCheck() {
return true;
}

/**
* Does this dialect support named column-level check constraints?
*
* @return True if named column-level {@code check} constraints are supported;
* false otherwise.
*/
public boolean supportsNamedColumnCheck() {
return supportsColumnCheck();
}

/**
* Does this dialect support table-level check constraints?
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,11 @@ public boolean supportsColumnCheck() {
return true;
}

@Override
public boolean supportsNamedColumnCheck() {
return false;
}

@Override
public boolean doesRoundTemporalOnOverflow() {
// See https://jira.mariadb.org/browse/MDEV-16991
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,34 +144,41 @@ private static void appendConstraints(
}

if ( dialect.supportsColumnCheck() ) {
// some databases (Maria, SQL Server) don't like multiple 'check' clauses
final List<CheckConstraint> checkConstraints = column.getCheckConstraints();
long anonConstraints = checkConstraints.stream().filter(CheckConstraint::isAnonymous).count();
if ( anonConstraints == 1 ) {
for ( CheckConstraint constraint : checkConstraints ) {
definition.append( constraint.constraintString( dialect ) );
boolean hasAnonymousConstraints = false;
for ( CheckConstraint constraint : checkConstraints ) {
if ( constraint.isAnonymous() ) {
if ( !hasAnonymousConstraints ) {
definition.append(" check (");
hasAnonymousConstraints = true;
}
else {
definition.append(" and ");
}
definition.append( constraint.getConstraintInParens() );
}
}
else {
boolean first = true;
if ( hasAnonymousConstraints ) {
definition.append( ')' );
}

if ( !dialect.supportsTableCheck() ) {
// When table check constraints are not supported, try to render all named constraints
for ( CheckConstraint constraint : checkConstraints ) {
if ( constraint.isAnonymous() ) {
if ( first ) {
definition.append(" check (");
first = false;
}
else {
definition.append(" and ");
}
definition.append( constraint.getConstraintInParens() );
if ( constraint.isNamed() ) {
definition.append( constraint.constraintString( dialect ) );
}
}
if ( !first ) {
definition.append(")");
}
}
else if ( !hasAnonymousConstraints && dialect.supportsNamedColumnCheck() ) {
// Otherwise only render the first named constraint as column constraint if there are no anonymous
// constraints and named column check constraint are supported, because some database don't like
// multiple check clauses.
// Note that the TableExporter will take care of named constraints then
for ( CheckConstraint constraint : checkConstraints ) {
if ( constraint.isNamed() ) {
definition.append( constraint.constraintString( dialect ) );
break;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,37 +197,43 @@ protected void applyTableTypeString(StringBuilder buf) {

protected void applyTableCheck(Table table, StringBuilder buf) {
if ( dialect.supportsTableCheck() ) {
if ( !dialect.supportsColumnCheck() ) {
for ( Column column : table.getColumns() ) {
// some databases (Maria, SQL Server) don't like multiple 'check' clauses
final List<CheckConstraint> checkConstraints = column.getCheckConstraints();
long anonConstraints = checkConstraints.stream().filter( CheckConstraint::isAnonymous ).count();
if ( anonConstraints == 1 ) {
for ( CheckConstraint constraint : checkConstraints ) {
buf.append( "," ).append( constraint.constraintString( dialect ) );
}
}
else {
boolean first = true;
for ( CheckConstraint constraint : checkConstraints ) {
if ( constraint.isAnonymous() ) {
if ( first ) {
buf.append( "," ).append( " check (" );
first = false;
}
else {
buf.append( " and " );
}
buf.append( constraint.getConstraintInParens() );
for ( Column column : table.getColumns() ) {
final List<CheckConstraint> checkConstraints = column.getCheckConstraints();
boolean hasAnonymousConstraints = false;
if ( !dialect.supportsColumnCheck() ) {
for ( CheckConstraint constraint : checkConstraints ) {
if ( constraint.isAnonymous() ) {
if ( !hasAnonymousConstraints ) {
buf.append( ", check (" );
hasAnonymousConstraints = true;
}
else {
buf.append( " and " );
}
buf.append( constraint.getConstraintInParens() );
}
if ( !first ) {
buf.append( ")" );
}
if ( hasAnonymousConstraints ) {
buf.append( ')' );
}
}
else {
hasAnonymousConstraints = checkConstraints.stream().anyMatch( CheckConstraint::isAnonymous );
}

// Since some databases don't like when multiple check clauses appear for a colum definition,
// named constraints need to be hoisted to the table definition.
// Skip the first named constraint if the column has no anonymous constraints and the dialect
// supports named column check constraints, because ColumnDefinitions will render the first check
// constraint already.
boolean skipNextNamedConstraint = !hasAnonymousConstraints && dialect.supportsNamedColumnCheck();
for ( CheckConstraint constraint : checkConstraints ) {
if ( constraint.isNamed() ) {
if ( skipNextNamedConstraint ) {
skipNextNamedConstraint = false;
}
for ( CheckConstraint constraint : checkConstraints ) {
if ( constraint.isNamed() ) {
buf.append( constraint.constraintString( dialect ) );
}
else {
buf.append( ',' ).append( constraint.constraintString( dialect ) );
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
@ServiceRegistry(settings = @Setting(name = Environment.AUTO_CLOSE_SESSION, value = "true"))
public class GenericsTest {

@SkipForDialect(dialectClass = HANADialect.class, matchSubTypes = true, reason = "known bug in HANA: rs.next() returns false for org.hibernate.id.enhanced.SequenceStructure$1.getNextValue() for this test")
@SkipForDialect(dialectClass = HANADialect.class, reason = "known bug in HANA: rs.next() returns false for org.hibernate.id.enhanced.SequenceStructure$1.getNextValue() for this test")
@Test
public void testManyToOneGenerics(SessionFactoryScope scope) {
Paper white = new Paper();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.HANADialect;
import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.Query;
Expand Down Expand Up @@ -119,7 +118,7 @@ public void testNativeQueryWithFormulaAttribute(SessionFactoryScope scope) {
}

@Test
@SkipForDialect(dialectClass = HANADialect.class, matchSubTypes = true, reason = "invalid name of function or procedure: SYSDATE")
@SkipForDialect(dialectClass = HANADialect.class, reason = "invalid name of function or procedure: SYSDATE")
public void testNativeQueryWithFormulaAttributeWithoutAlias(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
Expand Down Expand Up @@ -596,8 +595,6 @@ public void testDiscriminator(SessionFactoryScope scope) {
}

@Test
@SkipForDialect(dialectClass = PostgreSQLDialect.class, matchSubTypes = true,
reason = "postgresql jdbc driver does not implement the setQueryTimeout method")
public void testCache(SessionFactoryScope scope) {
Plane plane = new Plane();
scope.inTransaction(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
@DomainModel( annotatedClasses = { Room.class, Building.class, House.class } )
@SessionFactory
@SkipForDialect( dialectClass = InformixDialect.class,
matchSubTypes = true,
reason = "Informix does not properly support unique constraints on nullable columns" )
@SkipForDialect( dialectClass = SybaseDialect.class,
matchSubTypes = true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@


@SkipForDialect(dialectClass = MySQLDialect.class, majorVersion = 5, reason = "BLOB/TEXT column 'id' used in key specification without a key length")
@SkipForDialect(dialectClass = OracleDialect.class, matchSubTypes = true, reason = "ORA-02329: column of datatype LOB cannot be unique or a primary key")
@SkipForDialect(dialectClass = OracleDialect.class, reason = "ORA-02329: column of datatype LOB cannot be unique or a primary key")
@SkipForDialect(dialectClass = InformixDialect.class, reason = "Informix does not support unique / primary constraints on binary columns")
@DomainModel(
annotatedClasses = {
Expand Down
Loading