Skip to content

HHH-18639 Remove support for DB2 versions older than 11.1 and start testing with DB2 12.1 #10470

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 2 commits into from
Jul 4, 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
4 changes: 1 addition & 3 deletions ci/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,8 @@ elif [ "$RDBMS" == "oracle_db23c" ]; then
export SERVICE=$(echo $INFO | jq -r '.database' | jq -r '.service')
# I have no idea why, but these tests don't seem to work on CI...
goal="-Pdb=oracle_cloud_db23c -DrunID=$RUNID -DdbHost=$HOST -DdbService=$SERVICE"
elif [ "$RDBMS" == "db2" ]; then
elif [ "$RDBMS" == "db2" ] || [ "$RDBMS" == "db2_11_5" ]; then
goal="-Pdb=db2_ci"
elif [ "$RDBMS" == "db2_10_5" ]; then
goal="-Pdb=db2"
elif [ "$RDBMS" == "mssql" ] || [ "$RDBMS" == "mssql_2017" ]; then
goal="-Pdb=mssql_ci"
# Exclude some Sybase tests on CI because they use `xmltable` function which has a memory leak on the DB version in CI
Expand Down
19 changes: 5 additions & 14 deletions docker_db.sh
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ edb_17() {
}

db2() {
db2_11_5
db2_12_1
}

db2_11_5() {
Expand All @@ -306,26 +306,17 @@ db2_11_5() {
$PRIVILEGED_CLI $CONTAINER_CLI exec -t db2 su - orm_test bash -c ". /database/config/orm_test/sqllib/db2profile; /database/config/orm_test/sqllib/bin/db2 'connect to orm_test'; /database/config/orm_test/sqllib/bin/db2 'CREATE USER TEMPORARY TABLESPACE usr_tbsp MANAGED BY AUTOMATIC STORAGE'"
}

db2_10_5() {
db2_12_1() {
$PRIVILEGED_CLI $CONTAINER_CLI rm -f db2 || true
# The sha represents the tag 10.5.0.5-3.10.0
$PRIVILEGED_CLI $CONTAINER_CLI run --name db2 --privileged -e DB2INST1_PASSWORD=db2inst1-pwd -e LICENSE=accept -p 50000:50000 -d ${DB_IMAGE_DB2_10_5:-quay.io/hibernate/db2express-c@sha256:a499afd9709a1f69fb41703e88def9869955234c3525547e2efc3418d1f4ca2b} db2start
$PRIVILEGED_CLI $CONTAINER_CLI run --name db2 --privileged -e DB2INSTANCE=orm_test -e DB2INST1_PASSWORD=orm_test -e DBNAME=orm_test -e LICENSE=accept -e AUTOCONFIG=false -e ARCHIVE_LOGS=false -e TO_CREATE_SAMPLEDB=false -e REPODB=false -p 50000:50000 -d ${DB_IMAGE_DB2_11_5:-icr.io/db2_community/db2:12.1.2.0}
# Give the container some time to start
OUTPUT=
while [[ $OUTPUT != *"DB2START"* ]]; do
while [[ $OUTPUT != *"INSTANCE"* ]]; do
echo "Waiting for DB2 to start..."
sleep 10
OUTPUT=$($PRIVILEGED_CLI $CONTAINER_CLI logs db2 2>&1)
done
$PRIVILEGED_CLI $CONTAINER_CLI exec -t db2 su - db2inst1 bash -c "/home/db2inst1/sqllib/bin/db2 create database orm_test &&
/home/db2inst1/sqllib/bin/db2 'connect to orm_test' &&
/home/db2inst1/sqllib/bin/db2 'CREATE BUFFERPOOL BP8K pagesize 8K' &&
/home/db2inst1/sqllib/bin/db2 'CREATE SYSTEM TEMPORARY TABLESPACE STB_8 PAGESIZE 8K BUFFERPOOL BP8K' &&
/home/db2inst1/sqllib/bin/db2 'CREATE BUFFERPOOL BP16K pagesize 16K' &&
/home/db2inst1/sqllib/bin/db2 'CREATE SYSTEM TEMPORARY TABLESPACE STB_16 PAGESIZE 16K BUFFERPOOL BP16K' &&
/home/db2inst1/sqllib/bin/db2 'CREATE BUFFERPOOL BP32K pagesize 32K' &&
/home/db2inst1/sqllib/bin/db2 'CREATE SYSTEM TEMPORARY TABLESPACE STB_32 PAGESIZE 32K BUFFERPOOL BP32K' &&
/home/db2inst1/sqllib/bin/db2 'CREATE USER TEMPORARY TABLESPACE usr_tbsp MANAGED BY AUTOMATIC STORAGE'"
$PRIVILEGED_CLI $CONTAINER_CLI exec -t db2 su - orm_test bash -c ". /database/config/orm_test/sqllib/db2profile; /database/config/orm_test/sqllib/bin/db2 'connect to orm_test'; /database/config/orm_test/sqllib/bin/db2 'CREATE USER TEMPORARY TABLESPACE usr_tbsp MANAGED BY AUTOMATIC STORAGE'"
}

db2_spatial() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import org.hibernate.boot.model.FunctionContributions;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.community.dialect.sequence.LegacyDB2SequenceSupport;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.DB2GetObjectExtractor;
import org.hibernate.dialect.DatabaseVersion;
import org.hibernate.dialect.Dialect;
Expand Down Expand Up @@ -484,6 +483,12 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
if ( supportsRecursiveCTE() ) {
functionFactory.generateSeries_recursive( getMaximumSeriesSize(), false, true );
}

functionFactory.hex( "hex(?1)" );
if ( getDB2Version().isSameOrAfter( 11 ) ) {
functionFactory.sha( "hash(?1, 2)" );
functionFactory.md5( "hash(?1, 0)" );
}
}

/**
Expand Down Expand Up @@ -522,7 +527,7 @@ public long getFractionalSecondPrecisionInNanos() {
@Override
public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) {
if ( getDB2Version().isBefore( 11 ) ) {
return DB2Dialect.timestampdiffPatternV10( unit, fromTemporalType, toTemporalType );
return timestampdiffPatternV10( unit, fromTemporalType, toTemporalType );
}
final StringBuilder pattern = new StringBuilder();
final String fromExpression;
Expand Down Expand Up @@ -558,22 +563,30 @@ public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalT
switch ( unit ) {
case NATIVE:
case NANOSECOND:
pattern.append( "(seconds_between(" );
pattern.append( "(seconds_between(date_trunc('second'," );
pattern.append( toExpression );
pattern.append( "),date_trunc('second'," );
pattern.append( fromExpression );
pattern.append( "))" );
break;
//note: DB2 does have weeks_between()
case MONTH:
case QUARTER:
// the months_between() function results
// in a non-integral value, so trunc() it
pattern.append( "trunc(months_between(" );
pattern.append( toExpression );
pattern.append( ',' );
pattern.append( fromExpression );
pattern.append( ')' );
break;
default:
pattern.append( "?1s_between(" );
pattern.append( toExpression );
pattern.append( ',' );
pattern.append( fromExpression );
pattern.append( ')' );
}
pattern.append( toExpression );
pattern.append( ',' );
pattern.append( fromExpression );
pattern.append( ')' );
switch ( unit ) {
case NATIVE:
pattern.append( "+(microsecond(");
Expand All @@ -599,6 +612,97 @@ public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalT
return pattern.toString();
}

@SuppressWarnings("deprecation")
public static String timestampdiffPatternV10(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) {
final boolean isTime = fromTemporalType == TemporalType.TIME || toTemporalType == TemporalType.TIME;
final String fromExpression;
final String toExpression;
if ( unit.isDateUnit() ) {
if ( fromTemporalType == TemporalType.TIME ) {
fromExpression = "timestamp('1970-01-01',?2)";
}
else {
fromExpression = "?2";
}
if ( toTemporalType == TemporalType.TIME ) {
toExpression = "timestamp('1970-01-01',?3)";
}
else {
toExpression = "?3";
}
}
else {
if ( fromTemporalType == TemporalType.DATE ) {
fromExpression = "cast(?2 as timestamp)";
}
else {
fromExpression = "?2";
}
if ( toTemporalType == TemporalType.DATE ) {
toExpression = "cast(?3 as timestamp)";
}
else {
toExpression = "?3";
}
}
switch ( unit ) {
case NATIVE:
if ( isTime ) {
return "(midnight_seconds(" + toExpression + ")-midnight_seconds(" + fromExpression + "))";
}
else {
return "(select (days(t2)-days(t1))*86400+(midnight_seconds(t2)-midnight_seconds(t1))+(microsecond(t2)-microsecond(t1))/1e6 " +
"from lateral(values(" + fromExpression + ',' + toExpression + ")) as temp(t1,t2))";
}
case NANOSECOND:
if ( isTime ) {
return "(midnight_seconds(" + toExpression + ")-midnight_seconds(" + fromExpression + "))*1e9";
}
else {
return "(select (days(t2)-days(t1))*86400+(midnight_seconds(t2)-midnight_seconds(t1))*1e9+(microsecond(t2)-microsecond(t1))*1e3 " +
"from lateral(values(" + fromExpression + ',' + toExpression + ")) as temp(t1,t2))";
}
case SECOND:
if ( isTime ) {
return "(midnight_seconds(" + toExpression + ")-midnight_seconds(" + fromExpression + "))";
}
else {
return "(select (days(t2)-days(t1))*86400+(midnight_seconds(t2)-midnight_seconds(t1)) " +
"from lateral(values(" + fromExpression + ',' + toExpression + ")) as temp(t1,t2))";
}
case MINUTE:
if ( isTime ) {
return "(midnight_seconds(" + toExpression + ")-midnight_seconds(" + fromExpression + "))/60";
}
else {
return "(select (days(t2)-days(t1))*1440+(midnight_seconds(t2)-midnight_seconds(t1))/60 from " +
"lateral(values(" + fromExpression + ',' + toExpression + ")) as temp(t1,t2))";
}
case HOUR:
if ( isTime ) {
return "(midnight_seconds(" + toExpression + ")-midnight_seconds(" + fromExpression + "))/3600";
}
else {
return "(select (days(t2)-days(t1))*24+(midnight_seconds(t2)-midnight_seconds(t1))/3600 " +
"from lateral(values(" + fromExpression + ',' + toExpression + ")) as temp(t1,t2))";
}
case YEAR:
return "(year(" + toExpression + ")-year(" + fromExpression + "))";
// the months_between() function results
// in a non-integral value, so trunc() it
case MONTH:
return "trunc(months_between(" + toExpression + ',' + fromExpression + "))";
case QUARTER:
return "trunc(months_between(" + toExpression + ',' + fromExpression + ")/3)";
case WEEK:
return "int((days" + toExpression + ")-days(" + fromExpression + "))/7)";
case DAY:
return "(days(" + toExpression + ")-days(" + fromExpression + "))";
default:
throw new UnsupportedOperationException( "Unsupported unit: " + unit );
}
}

@Override
public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType, IntervalType intervalType) {
final StringBuilder pattern = new StringBuilder();
Expand Down Expand Up @@ -902,13 +1006,34 @@ public boolean supportsCommentOn() {
return true;
}

@Override
public String getAlterColumnTypeString(String columnName, String columnType, String columnDefinition) {
// would need multiple statements to 'set not null'/'drop not null', 'set default'/'drop default', 'set generated', etc
return "alter column " + columnName + " set data type " + columnType;
}

@Override
public boolean supportsAlterColumnType() {
return getVersion().isSameOrAfter( 10, 5 );
}

@Override
public boolean supportsIfExistsBeforeTableName() {
return getVersion().isSameOrAfter( 11, 5 );
}

@Override
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
EntityMappingType rootEntityDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
return new CteMutationStrategy( rootEntityDescriptor, runtimeModelCreationContext );
}

@Override
public boolean supportsIsTrue() {
return getDB2Version().isSameOrAfter( 11 );
}

@Override
public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(
EntityMappingType rootEntityDescriptor,
Expand Down Expand Up @@ -950,6 +1075,11 @@ public boolean supportsLobValueChangePropagation() {
return false;
}

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

@Override
public boolean doesReadCommittedCauseWritersToBlockReaders() {
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ protected boolean shouldEmulateFetchClause(QueryPart queryPart) {
if ( useOffsetFetchClause( queryPart ) && !isRowsOnlyFetchClauseType( queryPart ) ) {
return true;
}
// According to LegacyDB2LimitHandler, variable limit also isn't supported before 7.10
return version.isBefore(7, 10)
// According to LegacyDB2LimitHandler, variable limit also isn't supported before 7.1
return version.isBefore(7, 1)
&& queryPart.getFetchClauseExpression() != null
&& !( queryPart.getFetchClauseExpression() instanceof Literal );
}

@Override
protected boolean supportsOffsetClause() {
return version.isSameOrAfter(7, 10);
return version.isSameOrAfter(7, 1);
}

@Override
Expand Down
Loading