Skip to content

Commit bf030b2

Browse files
Merge pull request #81 from oracle/79-timezone-as-region
Add a timezone as region option
2 parents 5fae717 + ab61bd8 commit bf030b2

File tree

4 files changed

+71
-11
lines changed

4 files changed

+71
-11
lines changed

README.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -290,13 +290,17 @@ supported by Oracle R2DBC:
290290
- Out of band (OOB) breaks effect statement timeouts. Set this to "true" if statement timeouts are not working correctly.
291291
- [oracle.jdbc.enableQueryResultCache](https://docs.oracle.com/en/database/oracle/oracle-database/21/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_ENABLE_QUERY_RESULT_CACHE)
292292
- Cached query results can cause phantom reads even if the serializable
293-
transaction isolation level is set. Set this to "false" if using the
293+
transaction isolation level is set. Set this to "false" if using the
294294
serializable isolation level.
295295
- [v$session.terminal](https://docs.oracle.com/en/database/oracle/oracle-database/21/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_VSESSION_TERMINAL)
296296
- [v$session.machine](https://docs.oracle.com/en/database/oracle/oracle-database/21/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_VSESSION_MACHINE)
297297
- [v$session.osuser](https://docs.oracle.com/en/database/oracle/oracle-database/21/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_VSESSION_OSUSER)
298298
- [v$session.program](https://docs.oracle.com/en/database/oracle/oracle-database/21/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_VSESSION_PROGRAM)
299299
- [v$session.process](https://docs.oracle.com/en/database/oracle/oracle-database/21/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_VSESSION_PROCESS)
300+
- (For inclusion in the next release) [oracle.jdbc.timeZoneAsRegion](https://docs.oracle.com/en/database/oracle/oracle-database/21/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_TIMEZONE_AS_REGION)
301+
- Setting this option to "false" may resolve "ORA-01882: timezone region not
302+
found". The ORA-01882 error happens when Oracle Database doesn't recognize
303+
the name returned by `java.util.TimeZone.getDefault().getId()`.
300304

301305
### Thread Safety and Parallel Execution
302306
Oracle R2DBC's `ConnectionFactory` and `ConnectionFactoryProvider` are the only

src/main/java/oracle/r2dbc/OracleR2dbcOptions.java

+7
Original file line numberDiff line numberDiff line change
@@ -259,4 +259,11 @@ private OracleR2dbcOptions() {}
259259
public static final Option<CharSequence> VSESSION_PROCESS =
260260
Option.valueOf(OracleConnection.CONNECTION_PROPERTY_THIN_VSESSION_PROCESS);
261261

262+
/**
263+
* Configures the Oracle JDBC Connection used by Oracle R2DBC as specified by:
264+
* {@link OracleConnection#CONNECTION_PROPERTY_TIMEZONE_AS_REGION}
265+
*/
266+
public static final Option<CharSequence> TIMEZONE_AS_REGION =
267+
Option.valueOf(OracleConnection.CONNECTION_PROPERTY_TIMEZONE_AS_REGION);
268+
262269
}

src/main/java/oracle/r2dbc/impl/OracleReactiveJdbcAdapter.java

+10-9
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,13 @@ final class OracleReactiveJdbcAdapter implements ReactiveJdbcAdapter {
205205
OracleR2dbcOptions.VSESSION_TERMINAL,
206206
OracleR2dbcOptions.VSESSION_PROCESS,
207207
OracleR2dbcOptions.VSESSION_PROGRAM,
208-
OracleR2dbcOptions.VSESSION_MACHINE
208+
OracleR2dbcOptions.VSESSION_MACHINE,
209+
210+
// Allow JDBC to configure the session timezone as an offset of UTC
211+
// (ie: +09:00), rather than a name (ie: Etc/UTC). This avoids
212+
// "ORA-01882: timezone region not found" when the name of the JVM's
213+
// default timezone is not recognized by Oracle Database.
214+
OracleR2dbcOptions.TIMEZONE_AS_REGION
209215
);
210216

211217
/** Guards access to a JDBC {@code Connection} created by this adapter */
@@ -401,17 +407,12 @@ public AsyncLock getLock() {
401407
* </li><li>
402408
* {@linkplain OracleConnection#CONNECTION_PROPERTY_THIN_VSESSION_MACHINE
403409
* v$session.machine}
410+
* </li><li>
411+
* {@linkplain OracleConnection#CONNECTION_PROPERTY_TIMEZONE_AS_REGION
412+
* oracle.jdbc.timezoneAsRegion}
404413
* </li>
405414
* </ul>
406415
*
407-
* @implNote The returned {@code DataSource} is configured to create
408-
* connections that encode character bind values using the National
409-
* Character Set of an Oracle Database. In 21c, the National Character Set
410-
* must be either UTF-8 or UTF-16; This ensures that unicode bind data is
411-
* properly encoded by Oracle JDBC. If the data source is not configured
412-
* this way, the Oracle JDBC Driver uses the default character set of the
413-
* database, which may not support Unicode characters.
414-
*
415416
* @throws IllegalArgumentException If the {@code oracleNetDescriptor}
416417
* {@code Option} is provided with any other options that might have
417418
* conflicting values, such as {@link ConnectionFactoryOptions#HOST}.

src/test/java/oracle/r2dbc/impl/OracleReactiveJdbcAdapterTest.java

+49-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import oracle.jdbc.OracleConnection;
3131
import oracle.jdbc.datasource.OracleDataSource;
3232
import oracle.r2dbc.OracleR2dbcOptions;
33-
import oracle.r2dbc.test.DatabaseConfig;
3433
import org.junit.jupiter.api.Test;
3534
import reactor.core.publisher.Flux;
3635
import reactor.core.publisher.Mono;
@@ -43,8 +42,10 @@
4342
import java.nio.file.StandardOpenOption;
4443
import java.sql.SQLException;
4544
import java.time.Duration;
45+
import java.time.ZonedDateTime;
4646
import java.util.Properties;
4747
import java.util.Set;
48+
import java.util.TimeZone;
4849
import java.util.concurrent.CompletableFuture;
4950
import java.util.concurrent.CompletionException;
5051
import java.util.concurrent.ExecutionException;
@@ -528,6 +529,53 @@ public void testVSessionOptions() {
528529
}
529530
}
530531

532+
/**
533+
* Verifies the {@link OracleR2dbcOptions#TIMEZONE_AS_REGION} option
534+
*/
535+
@Test
536+
public void testTimezoneAsRegion() {
537+
// Set the timezone to that of Warsaw. When JDBC opens a connection, it will
538+
// read the Warsaw timezone from TimeZone.getDefault().
539+
TimeZone warsawTimeZone = TimeZone.getTimeZone("Europe/Warsaw");
540+
TimeZone timeZoneRestored = TimeZone.getDefault();
541+
TimeZone.setDefault(warsawTimeZone);
542+
try {
543+
544+
// Configure the JDBC connection property with a URL parameter. This has
545+
// JDBC express the session timezone as an offset of UTC (+02:00), rather
546+
// than a name (Europe/Warsaw).
547+
Connection connection = awaitOne(ConnectionFactories.get(
548+
ConnectionFactoryOptions.parse(format(
549+
"r2dbc:oracle://%s:%d/%s?oracle.jdbc.timezoneAsRegion=false",
550+
host(), port(), serviceName()))
551+
.mutate()
552+
.option(USER, user())
553+
.option(PASSWORD, password())
554+
.build())
555+
.create());
556+
try {
557+
558+
// Query the session timezone, and expect it to be expressed as an
559+
// offset, rather than a name.
560+
assertEquals(
561+
ZonedDateTime.now(warsawTimeZone.toZoneId())
562+
.getOffset()
563+
.toString(),
564+
awaitOne(awaitOne(connection.createStatement(
565+
"SELECT sessionTimeZone FROM sys.dual")
566+
.execute())
567+
.map(row ->
568+
row.get(0, String.class))));
569+
}
570+
finally {
571+
tryAwaitNone(connection.close());
572+
}
573+
}
574+
finally {
575+
TimeZone.setDefault(timeZoneRestored);
576+
}
577+
}
578+
531579
/**
532580
* Verifies that an attempt to connect with a {@code listeningChannel}
533581
* results in an {@link R2dbcTimeoutException}.

0 commit comments

Comments
 (0)