HHH-18220 Detect if Application Continuity is enabled for Oracle dialect

This commit is contained in:
LLEFEVRE 2024-06-03 12:08:00 +02:00 committed by Christian Beikov
parent 58e814965e
commit 7c711751dd
3 changed files with 95 additions and 11 deletions

View File

@ -12,6 +12,7 @@ package org.hibernate.cfg;
* its underlying JDBC {@link java.sql.Connection}. * its underlying JDBC {@link java.sql.Connection}.
* *
* @author Marco Belladelli * @author Marco Belladelli
* @author Loïc Lefèvre
*/ */
public interface DialectSpecificSettings { public interface DialectSpecificSettings {
/** /**
@ -28,6 +29,15 @@ public interface DialectSpecificSettings {
*/ */
public static final String ORACLE_EXTENDED_STRING_SIZE = "hibernate.dialect.oracle.extended_string_size"; public static final String ORACLE_EXTENDED_STRING_SIZE = "hibernate.dialect.oracle.extended_string_size";
/**
* Specifies whether this database is accessed using a database service protected by Application Continuity.
*
* @settingDefault {@code false}
*
* @see <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/jjdbc/application-continuity.html">Application Continuity for Java</a>
*/
public static final String ORACLE_APPLICATION_CONTINUITY = "hibernate.dialect.oracle.application_continuity";
/** /**
* Specifies whether this database's {@code ansinull} setting is enabled. * Specifies whether this database's {@code ansinull} setting is enabled.
* *

View File

@ -187,6 +187,9 @@ public class OracleDialect extends Dialect {
// Is MAX_STRING_SIZE set to EXTENDED? // Is MAX_STRING_SIZE set to EXTENDED?
protected final boolean extended; protected final boolean extended;
// Is the database accessed using a database service protected by Application Continuity.
protected final boolean applicationContinuity;
protected final int driverMajorVersion; protected final int driverMajorVersion;
protected final int driverMinorVersion; protected final int driverMinorVersion;
@ -200,6 +203,7 @@ public class OracleDialect extends Dialect {
super(version); super(version);
autonomous = false; autonomous = false;
extended = false; extended = false;
applicationContinuity = false;
driverMajorVersion = 19; driverMajorVersion = 19;
driverMinorVersion = 0; driverMinorVersion = 0;
} }
@ -212,6 +216,7 @@ public class OracleDialect extends Dialect {
super( info ); super( info );
autonomous = serverConfiguration.isAutonomous(); autonomous = serverConfiguration.isAutonomous();
extended = serverConfiguration.isExtended(); extended = serverConfiguration.isExtended();
applicationContinuity = serverConfiguration.isApplicationContinuity();
this.driverMinorVersion = serverConfiguration.getDriverMinorVersion(); this.driverMinorVersion = serverConfiguration.getDriverMinorVersion();
this.driverMajorVersion = serverConfiguration.getDriverMajorVersion(); this.driverMajorVersion = serverConfiguration.getDriverMajorVersion();
} }
@ -258,6 +263,10 @@ public class OracleDialect extends Dialect {
return extended; return extended;
} }
public boolean isApplicationContinuity() {
return applicationContinuity;
}
@Override @Override
protected DatabaseVersion getMinimumSupportedVersion() { protected DatabaseVersion getMinimumSupportedVersion() {
return MINIMUM_VERSION; return MINIMUM_VERSION;

View File

@ -6,15 +6,20 @@
*/ */
package org.hibernate.dialect; package org.hibernate.dialect;
import java.sql.Connection;
import java.sql.DatabaseMetaData; import java.sql.DatabaseMetaData;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.List; import java.util.List;
import oracle.jdbc.replay.ReplayStatistics;
import oracle.jdbc.replay.ReplayableConnection;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo; import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.internal.util.config.ConfigurationHelper;
import static oracle.jdbc.replay.ReplayableConnection.StatisticsReportType.FOR_CURRENT_CONNECTION;
import static org.hibernate.cfg.DialectSpecificSettings.ORACLE_APPLICATION_CONTINUITY;
import static org.hibernate.cfg.DialectSpecificSettings.ORACLE_AUTONOMOUS_DATABASE; import static org.hibernate.cfg.DialectSpecificSettings.ORACLE_AUTONOMOUS_DATABASE;
import static org.hibernate.cfg.DialectSpecificSettings.ORACLE_EXTENDED_STRING_SIZE; import static org.hibernate.cfg.DialectSpecificSettings.ORACLE_EXTENDED_STRING_SIZE;
@ -22,10 +27,12 @@ import static org.hibernate.cfg.DialectSpecificSettings.ORACLE_EXTENDED_STRING_S
* Utility class that extract some initial configuration from the database for {@link OracleDialect}. * Utility class that extract some initial configuration from the database for {@link OracleDialect}.
* *
* @author Marco Belladelli * @author Marco Belladelli
* @author Loïc Lefèvre
*/ */
public class OracleServerConfiguration { public class OracleServerConfiguration {
private final boolean autonomous; private final boolean autonomous;
private final boolean extended; private final boolean extended;
private final boolean applicationContinuity;
private final int driverMajorVersion; private final int driverMajorVersion;
private final int driverMinorVersion; private final int driverMinorVersion;
@ -37,6 +44,10 @@ public class OracleServerConfiguration {
return extended; return extended;
} }
public boolean isApplicationContinuity() {
return applicationContinuity;
}
public int getDriverMajorVersion() { public int getDriverMajorVersion() {
return driverMajorVersion; return driverMajorVersion;
} }
@ -46,7 +57,7 @@ public class OracleServerConfiguration {
} }
public OracleServerConfiguration(boolean autonomous, boolean extended) { public OracleServerConfiguration(boolean autonomous, boolean extended) {
this( autonomous, extended, 19, 0 ); this( autonomous, extended, false, 19, 0 );
} }
public OracleServerConfiguration( public OracleServerConfiguration(
@ -54,8 +65,18 @@ public class OracleServerConfiguration {
boolean extended, boolean extended,
int driverMajorVersion, int driverMajorVersion,
int driverMinorVersion) { int driverMinorVersion) {
this(autonomous, extended, false, driverMajorVersion, driverMinorVersion);
}
public OracleServerConfiguration(
boolean autonomous,
boolean extended,
boolean applicationContinuity,
int driverMajorVersion,
int driverMinorVersion) {
this.autonomous = autonomous; this.autonomous = autonomous;
this.extended = extended; this.extended = extended;
this.applicationContinuity = applicationContinuity;
this.driverMajorVersion = driverMajorVersion; this.driverMajorVersion = driverMajorVersion;
this.driverMinorVersion = driverMinorVersion; this.driverMinorVersion = driverMinorVersion;
} }
@ -63,6 +84,7 @@ public class OracleServerConfiguration {
public static OracleServerConfiguration fromDialectResolutionInfo(DialectResolutionInfo info) { public static OracleServerConfiguration fromDialectResolutionInfo(DialectResolutionInfo info) {
Boolean extended = null; Boolean extended = null;
Boolean autonomous = null; Boolean autonomous = null;
Boolean applicationContinuity = null;
Integer majorVersion = null; Integer majorVersion = null;
Integer minorVersion = null; Integer minorVersion = null;
final DatabaseMetaData databaseMetaData = info.getDatabaseMetadata(); final DatabaseMetaData databaseMetaData = info.getDatabaseMetadata();
@ -70,7 +92,42 @@ public class OracleServerConfiguration {
majorVersion = databaseMetaData.getDriverMajorVersion(); majorVersion = databaseMetaData.getDriverMajorVersion();
minorVersion = databaseMetaData.getDriverMinorVersion(); minorVersion = databaseMetaData.getDriverMinorVersion();
try (final Statement statement = databaseMetaData.getConnection().createStatement()) {
try {
final Connection c = databaseMetaData.getConnection();
// Use Oracle JDBC replay statistics information to determine if this
// connection is protected by Application Continuity
try {
final ReplayableConnection re = (ReplayableConnection) c;
ReplayStatistics stats = re.getReplayStatistics(FOR_CURRENT_CONNECTION);
final long totalRequests = stats.getTotalRequests();
final long protectedCalls = stats.getTotalProtectedCalls();
try (final Statement s = c.createStatement()) {
try (final ResultSet r = s.executeQuery("select 1 from dual")) {
r.next();
}
}
stats = re.getReplayStatistics(FOR_CURRENT_CONNECTION);
// Application continuity is enabled on this database service if the number of
// total requests and the number of protected calls for this connection have
// both increased.
applicationContinuity = stats.getTotalRequests() > totalRequests && stats.getTotalProtectedCalls() > protectedCalls;
}
catch(Exception e) {
// A ClassCastException or a NullPointerException are expected here in the case
// the Connection Factory is not the right one (not Replayable: ClassCastException)
// or if the database service has not been configured (server side) to enable
// application continuity (NullPointerException).
applicationContinuity = false;
}
// continue the checks...
try (final Statement statement = c.createStatement()) {
final ResultSet rs = statement.executeQuery( final ResultSet rs = statement.executeQuery(
"select cast('string' as varchar2(32000)), " + "select cast('string' as varchar2(32000)), " +
"sys_context('USERENV','CLOUD_SERVICE') from dual" "sys_context('USERENV','CLOUD_SERVICE') from dual"
@ -81,6 +138,7 @@ public class OracleServerConfiguration {
autonomous = isAutonomous(rs.getString(2)); autonomous = isAutonomous(rs.getString(2));
} }
} }
}
catch (SQLException ex) { catch (SQLException ex) {
// failed, so MAX_STRING_SIZE == STANDARD, still need to check autonomous // failed, so MAX_STRING_SIZE == STANDARD, still need to check autonomous
extended = false; extended = false;
@ -102,6 +160,13 @@ public class OracleServerConfiguration {
false false
); );
} }
if ( applicationContinuity == null ) {
applicationContinuity = ConfigurationHelper.getBoolean(
ORACLE_APPLICATION_CONTINUITY,
info.getConfigurationValues(),
false
);
}
if ( majorVersion == null ) { if ( majorVersion == null ) {
try { try {
java.sql.Driver driver = java.sql.DriverManager.getDriver( "jdbc:oracle:thin:" ); java.sql.Driver driver = java.sql.DriverManager.getDriver( "jdbc:oracle:thin:" );
@ -114,7 +179,7 @@ public class OracleServerConfiguration {
} }
} }
return new OracleServerConfiguration( autonomous, extended, majorVersion, minorVersion ); return new OracleServerConfiguration( autonomous, extended, applicationContinuity, majorVersion, minorVersion );
} }
private static boolean isAutonomous(String cloudServiceParam) { private static boolean isAutonomous(String cloudServiceParam) {