44 */
55package org .hibernate .dialect ;
66
7- import java .lang .reflect .Field ;
87import java .lang .reflect .Method ;
98import java .sql .Connection ;
109import java .sql .DatabaseMetaData ;
10+ import java .sql .Driver ;
11+ import java .sql .DriverManager ;
1112import java .sql .ResultSet ;
1213import java .sql .SQLException ;
1314import java .sql .Statement ;
14- import java .util .List ;
15+ import java .util .Map ;
1516
1617import org .hibernate .engine .jdbc .dialect .spi .DialectResolutionInfo ;
17- import org .hibernate .internal .util .config .ConfigurationHelper ;
1818
1919import static org .hibernate .cfg .DialectSpecificSettings .ORACLE_APPLICATION_CONTINUITY ;
2020import static org .hibernate .cfg .DialectSpecificSettings .ORACLE_AUTONOMOUS_DATABASE ;
2121import static org .hibernate .cfg .DialectSpecificSettings .ORACLE_EXTENDED_STRING_SIZE ;
22+ import static org .hibernate .internal .util .config .ConfigurationHelper .getBoolean ;
2223
2324/**
2425 * Utility class that extract some initial configuration from the database for {@link OracleDialect}.
@@ -62,7 +63,7 @@ public OracleServerConfiguration(
6263 boolean extended ,
6364 int driverMajorVersion ,
6465 int driverMinorVersion ) {
65- this (autonomous , extended , false , driverMajorVersion , driverMinorVersion );
66+ this ( autonomous , extended , false , driverMajorVersion , driverMinorVersion );
6667 }
6768
6869 public OracleServerConfiguration (
@@ -79,129 +80,124 @@ public OracleServerConfiguration(
7980 }
8081
8182 public static OracleServerConfiguration fromDialectResolutionInfo (DialectResolutionInfo info ) {
82- Boolean extended = null ;
83- Boolean autonomous = null ;
84- Boolean applicationContinuity = null ;
85- Integer majorVersion = null ;
86- Integer minorVersion = null ;
87- final DatabaseMetaData databaseMetaData = info .getDatabaseMetadata ();
88- if ( databaseMetaData != null ) {
89- majorVersion = databaseMetaData .getDriverMajorVersion ();
90- minorVersion = databaseMetaData .getDriverMinorVersion ();
9183
92-
93- try {
94- final Connection c = databaseMetaData .getConnection ();
95-
96- try (final Statement statement = c .createStatement ()) {
97-
98- // Use Oracle JDBC replay statistics information to determine if this
99- // connection is protected by Application Continuity
100- try {
101- final Class statisticReportTypeEnum = Class .forName ("oracle.jdbc.replay.ReplayableConnection$StatisticsReportType" ,false , Thread .currentThread ().getContextClassLoader ());
102- final Field forCurrentConnection = statisticReportTypeEnum .getField ("FOR_CURRENT_CONNECTION" );
103-
104- final Method getReplayStatistics = c .getClass ().getMethod ("getReplayStatistics" , statisticReportTypeEnum );
105-
106- Object stats = getReplayStatistics .invoke (c ,forCurrentConnection .get (null ));
107-
108- final Method getTotalRequests = stats .getClass ().getMethod ("getTotalRequests" );
109- final Method getTotalProtectedCalls = stats .getClass ().getMethod ("getTotalProtectedCalls" );
110-
111- final Long totalRequestsBefore = (Long )getTotalRequests .invoke (stats );
112- final Long protectedCallsBefore = (Long )getTotalProtectedCalls .invoke (stats );
113-
114- try (ResultSet r = statement .executeQuery ("select 1" )) {
115- r .next ();
116- }
117-
118- stats = getReplayStatistics .invoke (c ,forCurrentConnection .get (null ));
119-
120- final Long totalRequestsAfter = (Long )getTotalRequests .invoke (stats );
121- final Long protectedCallsAfter = (Long )getTotalProtectedCalls .invoke (stats );
122-
123- // Application continuity is enabled on this database service if the number of
124- // total requests and the number of protected calls for this connection have
125- // both increased.
126- applicationContinuity = totalRequestsAfter > totalRequestsBefore && protectedCallsAfter > protectedCallsBefore ;
127- }
128- catch (Exception e ) {
129- // A ClassCastException or a NullPointerException are expected here in the case
130- // the Connection Factory is not the right one (not Replayable: ClassCastException)
131- // or if the database service has not been configured (server side) to enable
132- // application continuity (NullPointerException).
133- applicationContinuity = false ;
134- }
135-
136- // continue the checks...
137- final ResultSet rs = statement .executeQuery (
138- "select cast('string' as varchar2(32000)), " +
139- "sys_context('USERENV','CLOUD_SERVICE') from dual"
140- );
141- if (rs .next ()) {
142- // succeeded, so MAX_STRING_SIZE == EXTENDED
143- extended = true ;
144- autonomous = isAutonomous (rs .getString (2 ));
145- }
146- }
147- }
148- catch (SQLException ex ) {
149- // failed, so MAX_STRING_SIZE == STANDARD, still need to check autonomous
150- extended = false ;
151- autonomous = isAutonomous ( databaseMetaData );
152- }
153- }
15484 // default to the dialect-specific configuration settings
155- if ( extended == null ) {
156- extended = ConfigurationHelper .getBoolean (
157- ORACLE_EXTENDED_STRING_SIZE ,
158- info .getConfigurationValues (),
159- false
160- );
161- }
162- if ( autonomous == null ) {
163- autonomous = ConfigurationHelper .getBoolean (
164- ORACLE_AUTONOMOUS_DATABASE ,
165- info .getConfigurationValues (),
166- false
167- );
168- }
169- if ( applicationContinuity == null ) {
170- applicationContinuity = ConfigurationHelper .getBoolean (
171- ORACLE_APPLICATION_CONTINUITY ,
172- info .getConfigurationValues (),
173- false
174- );
175- }
176- if ( majorVersion == null ) {
85+ final Map <String , Object > configuration = info .getConfigurationValues ();
86+ final boolean defaultExtended = getBoolean ( ORACLE_EXTENDED_STRING_SIZE , configuration , false );
87+ final boolean defaultAutonomous = getBoolean ( ORACLE_AUTONOMOUS_DATABASE , configuration , false );
88+ final boolean defaultContinuity = getBoolean ( ORACLE_APPLICATION_CONTINUITY , configuration , false );
89+
90+ boolean extended ;
91+ boolean autonomous ;
92+ boolean applicationContinuity ;
93+ int majorVersion ;
94+ int minorVersion ;
95+ final DatabaseMetaData databaseMetaData = info .getDatabaseMetadata ();
96+ if ( databaseMetaData == null ) {
97+ extended = defaultExtended ;
98+ autonomous = defaultAutonomous ;
99+ applicationContinuity = defaultContinuity ;
177100 try {
178- java . sql . Driver driver = java . sql . DriverManager .getDriver ( "jdbc:oracle:thin:" );
101+ final Driver driver = DriverManager .getDriver ( "jdbc:oracle:thin:" );
179102 majorVersion = driver .getMajorVersion ();
180103 minorVersion = driver .getMinorVersion ();
181104 }
182105 catch (SQLException ex ) {
183106 majorVersion = 19 ;
184107 minorVersion = 0 ;
185108 }
186-
187109 }
110+ else {
111+ majorVersion = databaseMetaData .getDriverMajorVersion ();
112+ minorVersion = databaseMetaData .getDriverMinorVersion ();
113+ try {
114+ final Connection connection = databaseMetaData .getConnection (); // we should not close this
115+ try ( final Statement statement = connection .createStatement () ) {
116+ applicationContinuity = determineApplicationContinuity ( connection , statement );
117+ autonomous = isAutonomous ( statement );
118+ extended = isExtended ( statement );
119+ }
120+ }
121+ catch (SQLException sqle ) {
122+ extended = defaultExtended ;
123+ autonomous = defaultAutonomous ;
124+ applicationContinuity = defaultContinuity ;
125+ }
126+ }
127+
188128 return new OracleServerConfiguration ( autonomous , extended , applicationContinuity , majorVersion , minorVersion );
189129 }
190130
191- private static boolean isAutonomous (String cloudServiceParam ) {
192- return cloudServiceParam != null && List .of ( "OLTP" , "DWCS" , "JDCS" ).contains ( cloudServiceParam );
131+ private static boolean isExtended (Statement statement ) {
132+ try ( final ResultSet resultSet =
133+ statement .executeQuery ( "select cast('string' as varchar2(32000)) from dual" ) ) {
134+ resultSet .next ();
135+ // succeeded, so MAX_STRING_SIZE == EXTENDED
136+ return true ;
137+ }
138+ catch (SQLException ex ) {
139+ // failed, so MAX_STRING_SIZE == STANDARD, still need to check autonomous
140+ return false ;
141+ }
193142 }
194143
195- private static boolean isAutonomous (DatabaseMetaData databaseMetaData ) {
196- try (final Statement statement = databaseMetaData .getConnection ().createStatement ()) {
197- return statement .executeQuery (
198- "select 1 from dual where sys_context('USERENV','CLOUD_SERVICE') in ('OLTP','DWCS','JDCS')" )
199- .next ();
144+ private static Boolean determineApplicationContinuity (Connection connection , Statement statement ) {
145+ // Use Oracle JDBC replay statistics information to determine if this
146+ // connection is protected by Application Continuity
147+ try {
148+ final Class <?> statisticReportTypeEnum =
149+ Class .forName ( "oracle.jdbc.replay.ReplayableConnection$StatisticsReportType" ,
150+ false , Thread .currentThread ().getContextClassLoader () );
151+ final Object forCurrentConnection =
152+ statisticReportTypeEnum .getField ( "FOR_CURRENT_CONNECTION" ).get ( null );
153+ final Method getReplayStatistics =
154+ connection .getClass ().getMethod ( "getReplayStatistics" , statisticReportTypeEnum );
155+ final Class <?> replayStatistics = getReplayStatistics .getReturnType ();
156+ final Method getTotalRequests = replayStatistics .getMethod ("getTotalRequests" );
157+ final Method getTotalProtectedCalls = replayStatistics .getMethod ("getTotalProtectedCalls" );
158+
159+ final Object before = getReplayStatistics .invoke ( connection , forCurrentConnection );
160+ final Long totalRequestsBefore = (Long ) getTotalRequests .invoke ( before );
161+ final Long protectedCallsBefore = (Long ) getTotalProtectedCalls .invoke ( before );
162+
163+ try ( final ResultSet resultSet = statement .executeQuery ("select 1" ) ) {
164+ resultSet .next ();
165+ }
166+
167+ final Object after = getReplayStatistics .invoke ( connection , forCurrentConnection );
168+ final Long totalRequestsAfter = (Long ) getTotalRequests .invoke ( after );
169+ final Long protectedCallsAfter = (Long ) getTotalProtectedCalls .invoke ( after );
170+
171+ // Application continuity is enabled on this database service if the number of
172+ // total requests and the number of protected calls for this connection have
173+ // both increased.
174+ return totalRequestsAfter > totalRequestsBefore
175+ && protectedCallsAfter > protectedCallsBefore ;
176+ }
177+ catch (Exception e ) {
178+ // A ClassCastException or a NullPointerException are expected here in the case
179+ // the Connection Factory is not the right one (not Replayable: ClassCastException)
180+ // or if the database service has not been configured (server side) to enable
181+ // application continuity (NullPointerException).
182+ return false ;
183+ }
184+ }
185+
186+ private static boolean isAutonomous (Statement statement ) {
187+ try ( final ResultSet resultSet =
188+ statement .executeQuery ( "select sys_context('USERENV','CLOUD_SERVICE') from dual" ) ) {
189+ return resultSet .next ()
190+ && isAutonomous ( resultSet .getString (1 ) );
200191 }
201192 catch (SQLException ex ) {
202- // Ignore
193+ return false ;
203194 }
204- return false ;
205195 }
206196
197+ private static boolean isAutonomous (String type ) {
198+ return type != null && switch ( type ) {
199+ case "OLTP" , "DWCS" , "JDCS" -> true ;
200+ default -> false ;
201+ };
202+ }
207203}
0 commit comments