Skip to content

Commit 1c0740b

Browse files
Merge branch 'main' of https://github.com/oracle/oracle-r2dbc into 22-poolable-connections
2 parents 6198f50 + a4c8dc4 commit 1c0740b

File tree

6 files changed

+205
-46
lines changed

6 files changed

+205
-46
lines changed

README.md

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,17 @@ Oracle R2DBC can be built from source using Maven:
2525

2626
`mvn clean install -DskipTests=true`
2727

28-
> The build is not yet available on the Maven Central Repository. It will be published there soon.
29-
3028
> Omitting -DskipTests=true from the command above will execute the test suite, where end-to-end tests connect to an Oracle Database instance. The connection configuration is read from [src/test/resources/config.properties](src/test/resources/example-config.properties).
3129
30+
Artifacts can also be found on Maven Central.
31+
```
32+
<dependency>
33+
<groupId>com.oracle.database.r2dbc</groupId>
34+
<artifactId>oracle-r2dbc</artifactId>
35+
<version>${version}</version>
36+
</dependency>
37+
```
38+
3239
Oracle R2DBC is compatible with JDK 11 (or newer), and has the following runtime dependencies:
3340
- R2DBC SPI 0.8.2
3441
- Reactive Streams 1.0.3
@@ -150,6 +157,10 @@ Options. For Options having any of the following names, a CharSequence value may
150157
- [oracle.net.ssl_context_protocol](https://docs.oracle.com/en/database/oracle/oracle-database/21/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_SSL_CONTEXT_PROTOCOL)
151158
- [oracle.jdbc.fanEnabled](https://docs.oracle.com/en/database/oracle/oracle-database/21/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_FAN_ENABLED)
152159
- [oracle.jdbc.implicitStatementCacheSize](https://docs.oracle.com/en/database/oracle/oracle-database/21/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_IMPLICIT_STATEMENT_CACHE_SIZE)
160+
- Descriptor URLs of the form ```(DESCRIPTION=...)``` may be specified in a tnsnames.ora file.
161+
- The directory containing the tnsnames.ora file may be specified as an ```Option``` having the name "TNS_ADMIN"
162+
- An alias of a tnsnames.ora file may be specified as the value of ```ConnectionFactoryOptions.HOST```.
163+
- An alias of a tnsnames.ora file may be specified with an R2DBC URL: ```r2dbc:oracle://my_alias?TNS_ADMIN=/path/to/tnsnames/```
153164

154165

155166
### Thread Safety and Parallel Execution
@@ -188,15 +199,25 @@ be used when setting the bind value of an unnamed parameter.
188199
colon character (:) is followed by an alphanumeric parameter name. A name
189200
or numeric index may be used when setting the bind value of a named parameter.
190201
- Parameter names are case-sensitive.
191-
- The [ROWID](https://docs.oracle.com/en/database/oracle/oracle-database/21/cncpt/tables-and-table-clusters.html#GUID-0258C4C2-2BF2-445F-B1E1-F282A57A6859)
192-
of each row affected by an INSERT or UPDATE is returned as the generated value
193-
for the empty set of column names.
202+
- When an empty set of column names is specified to Statement.returnGeneratedValues(String...), executing that ```Statement``` returns the [ROWID](https://docs.oracle.com/en/database/oracle/oracle-database/21/cncpt/tables-and-table-clusters.html#GUID-0258C4C2-2BF2-445F-B1E1-F282A57A6859)
203+
of each row affected by an INSERT or UPDATE.
204+
- This behavior may change in a later release.
205+
- Programmers are advised not to use the ROWID as if it were a primary key.
206+
- The ROWID of a row may change.
207+
- After a row is deleted, it's ROWID may be reassigned to a new row.
208+
- Further Reading: https://asktom.oracle.com/pls/apex/asktom.search?tag=is-it-safe-to-use-rowid-to-locate-a-row
194209
- A **blocking database call** is executed by a Statement returning generated
195210
values for a non-empty set of column names.
196211
- The **blocking database call** is a known limitation that will be resolved
197212
with a non-blocking implementation of
198213
java.sql.Connection.prepareStatement(String, String[]) in the Oracle JDBC Driver.
199214
The Oracle JDBC Team is aware of this problem and is working on a fix.
215+
- Returning generated values is only supported for INSERT and UPDATE commands when a RETURNING INTO clause can be appended to the end of that command. (This limitation may be resolved in a later release)
216+
- Example: `INSERT INTO my_table(val) VALUES (:val)` is supported because a RETURNING INTO clause may be appended to this command.
217+
- Example: `INSERT INTO my_table(val) SELECT 1 FROM sys.dual` is not supported because a RETURNING INTO clause may not be appended to this command.
218+
- The Oracle Database SQL Language Reference defines INSERT and UPDATE commands for which a RETURNING INTO clause is supported.
219+
- INSERT: https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/INSERT.html#GUID-903F8043-0254-4EE9-ACC1-CB8AC0AF3423
220+
- UPDATE: https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/UPDATE.html#GUID-027A462D-379D-4E35-8611-410F3AC8FDA5
200221

201222
### Type Mappings
202223
- Blob and Clob objects are the default mapping implemented by Row.get(...) for

sample/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ dependencies {
3636
sourceCompatibility = 1.11
3737
targetCompatibility = 1.11
3838

39-
mainClassName = 'TcpsConnectDemo'
39+
mainClassName = 'oracle.r2dbc.samples.TcpsConnectDemo'
4040

4141
run {
4242
// To enable network debugging:

sample/example-config.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ HOST=db.host.example.com
1111
PORT=1521
1212

1313
# Service name of a test database
14-
DATABASE=db.service.name
14+
SERVICE_NAME=db.service.name
1515

1616
# User name authenticated by a test database
1717
USER=db_user
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
Copyright (c) 2020, 2021, Oracle and/or its affiliates.
3+
4+
This software is dual-licensed to you under the Universal Permissive License
5+
(UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License
6+
2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
7+
either license.
8+
9+
Licensed under the Apache License, Version 2.0 (the "License");
10+
you may not use this file except in compliance with the License.
11+
You may obtain a copy of the License at
12+
13+
https://www.apache.org/licenses/LICENSE-2.0
14+
15+
Unless required by applicable law or agreed to in writing, software
16+
distributed under the License is distributed on an "AS IS" BASIS,
17+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
See the License for the specific language governing permissions and
19+
limitations under the License.
20+
*/
21+
22+
package oracle.r2dbc.samples;
23+
24+
import java.io.IOException;
25+
import java.io.UncheckedIOException;
26+
import java.nio.file.Files;
27+
import java.nio.file.Path;
28+
import java.util.Properties;
29+
30+
/**
31+
* <p>
32+
* Configuration for connecting code samples to an Oracle Database instance.
33+
* </p><p>
34+
* The configuration is read from a properties file in the current directory
35+
* by default, or from a file specified as
36+
* <code>-DCONFIG_FILE=/path/to/your/config.properties</code>
37+
* </p>
38+
*/
39+
public class DatabaseConfig {
40+
41+
/** Path to a configuration file: config.properties */
42+
private static final Path CONFIG_PATH =
43+
Path.of(System.getProperty("CONFIG_FILE", "config.properties"));
44+
45+
/** Configuration that is read from a file at {@link #CONFIG_PATH} */
46+
private static final Properties CONFIG;
47+
static {
48+
try (var fileStream = Files.newInputStream(CONFIG_PATH)) {
49+
CONFIG = new Properties();
50+
CONFIG.load(fileStream);
51+
}
52+
catch (IOException readFailure) {
53+
throw new UncheckedIOException(readFailure);
54+
}
55+
}
56+
57+
/** Host name where an Oracle Database instance is running */
58+
static final String HOST = CONFIG.getProperty("HOST");
59+
60+
/** Port number where an Oracle Database instance is listening */
61+
static final int PORT = Integer.parseInt(CONFIG.getProperty("PORT"));
62+
63+
/** Service name of an Oracle Database */
64+
static final String SERVICE_NAME = CONFIG.getProperty("SERVICE_NAME");
65+
66+
/** User name that connects to an Oracle Database */
67+
static final String USER = CONFIG.getProperty("USER");
68+
69+
/** Password of the user that connects to an Oracle Database */
70+
static final String PASSWORD = CONFIG.getProperty("PASSWORD");
71+
72+
/** The file system path of a wallet directory */
73+
static final String WALLET_LOCATION =
74+
CONFIG.getProperty("WALLET_LOCATION");
75+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
Copyright (c) 2020, 2021, Oracle and/or its affiliates.
3+
4+
This software is dual-licensed to you under the Universal Permissive License
5+
(UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License
6+
2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
7+
either license.
8+
9+
Licensed under the Apache License, Version 2.0 (the "License");
10+
you may not use this file except in compliance with the License.
11+
You may obtain a copy of the License at
12+
13+
https://www.apache.org/licenses/LICENSE-2.0
14+
15+
Unless required by applicable law or agreed to in writing, software
16+
distributed under the License is distributed on an "AS IS" BASIS,
17+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
See the License for the specific language governing permissions and
19+
limitations under the License.
20+
*/
21+
22+
package oracle.r2dbc.samples;
23+
24+
import io.r2dbc.spi.ConnectionFactories;
25+
import io.r2dbc.spi.ConnectionFactoryOptions;
26+
import reactor.core.publisher.Mono;
27+
28+
import static oracle.r2dbc.samples.DatabaseConfig.HOST;
29+
import static oracle.r2dbc.samples.DatabaseConfig.PORT;
30+
import static oracle.r2dbc.samples.DatabaseConfig.SERVICE_NAME;
31+
import static oracle.r2dbc.samples.DatabaseConfig.USER;
32+
import static oracle.r2dbc.samples.DatabaseConfig.PASSWORD;
33+
34+
/**
35+
* This code example shows how to use TNS descriptor URLs with Oracle R2DBC.
36+
* The TNS descriptor has the form:
37+
* <pre>
38+
* (DESCRIPTION=...)
39+
* </pre>
40+
* The full syntax of the TNS descriptor is described in the
41+
* <a href=https://docs.oracle.com/en/database/oracle/oracle-database/21/netag/identifying-and-accessing-database.html#GUID-8D28E91B-CB72-4DC8-AEFC-F5D583626CF6>
42+
* Oracle Net Services Administrator's Guide
43+
* </a>
44+
*/
45+
public class DescriptorURL {
46+
47+
/**
48+
* A TNS descriptor specifying the HOST, PORT, and SERVICE_NAME read from
49+
* {@link DatabaseConfig}.
50+
*/
51+
private static final String DESCRIPTOR = "(DESCRIPTION=" +
52+
"(ADDRESS=(HOST="+HOST+")(PORT="+PORT+")(PROTOCOL=tcp))" +
53+
"(CONNECT_DATA=(SERVICE_NAME="+SERVICE_NAME+")))";
54+
55+
public static void main(String[] args) {
56+
// A descriptor may appear in the host section of an R2DBC URL:
57+
String r2dbcUrl = "r2dbc:oracle://"+DESCRIPTOR;
58+
Mono.from(ConnectionFactories.get(ConnectionFactoryOptions.parse(r2dbcUrl)
59+
.mutate()
60+
.option(ConnectionFactoryOptions.USER, USER)
61+
.option(ConnectionFactoryOptions.PASSWORD, PASSWORD)
62+
.build())
63+
.create())
64+
.flatMapMany(connection ->
65+
Mono.from(connection.createStatement(
66+
"SELECT 'Connected with TNS descriptor' FROM sys.dual")
67+
.execute())
68+
.flatMapMany(result ->
69+
result.map((row, metadata) -> row.get(0, String.class)))
70+
.concatWith(Mono.from(connection.close()).cast(String.class)))
71+
.toStream()
72+
.forEach(System.out::println);
73+
74+
// A descriptor may also be specified as the value of
75+
// ConnectionFactoryOptions.HOST
76+
Mono.from(ConnectionFactories.get(ConnectionFactoryOptions.builder()
77+
.option(ConnectionFactoryOptions.DRIVER, "oracle")
78+
.option(ConnectionFactoryOptions.HOST, DESCRIPTOR)
79+
.option(ConnectionFactoryOptions.USER, USER)
80+
.option(ConnectionFactoryOptions.PASSWORD, PASSWORD)
81+
.build())
82+
.create())
83+
.flatMapMany(connection ->
84+
Mono.from(connection.createStatement(
85+
"SELECT 'Connected with TNS descriptor' FROM sys.dual")
86+
.execute())
87+
.flatMapMany(result ->
88+
result.map((row, metadata) -> row.get(0, String.class)))
89+
.concatWith(Mono.from(connection.close()).cast(String.class)))
90+
.toStream()
91+
.forEach(System.out::println);
92+
}
93+
}

sample/src/main/java/TcpsConnectDemo.java renamed to sample/src/main/java/oracle/r2dbc/samples/TcpsConnectDemo.java

Lines changed: 9 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
limitations under the License.
2020
*/
2121

22+
package oracle.r2dbc.samples;
23+
2224
import io.r2dbc.spi.ConnectionFactories;
2325
import io.r2dbc.spi.ConnectionFactory;
2426
import io.r2dbc.spi.ConnectionFactoryOptions;
@@ -28,14 +30,16 @@
2830
import reactor.core.publisher.Flux;
2931
import reactor.core.publisher.Mono;
3032

31-
import java.io.IOException;
32-
import java.io.UncheckedIOException;
3333
import java.net.URI;
3434
import java.net.URISyntaxException;
35-
import java.nio.file.Files;
36-
import java.nio.file.Path;
3735
import java.time.Duration;
38-
import java.util.Properties;
36+
37+
import static oracle.r2dbc.samples.DatabaseConfig.HOST;
38+
import static oracle.r2dbc.samples.DatabaseConfig.PASSWORD;
39+
import static oracle.r2dbc.samples.DatabaseConfig.PORT;
40+
import static oracle.r2dbc.samples.DatabaseConfig.SERVICE_NAME;
41+
import static oracle.r2dbc.samples.DatabaseConfig.USER;
42+
import static oracle.r2dbc.samples.DatabaseConfig.WALLET_LOCATION;
3943

4044
/**
4145
* Sample code that uses an Oracle Wallet to authenticate with an Oracle
@@ -67,40 +71,6 @@
6771
*/
6872
public class TcpsConnectDemo {
6973

70-
/** Path to a configuration file: config.properties */
71-
private static final Path CONFIG_PATH =
72-
Path.of(System.getProperty("CONFIG_FILE", "config.properties"));
73-
74-
/** Configuration that is read from a file at {@link #CONFIG_PATH} */
75-
private static final Properties CONFIG;
76-
static {
77-
try (var fileStream = Files.newInputStream(CONFIG_PATH)) {
78-
CONFIG = new Properties();
79-
CONFIG.load(fileStream);
80-
}
81-
catch (IOException readFailure) {
82-
throw new UncheckedIOException(readFailure);
83-
}
84-
}
85-
86-
/** Host name where an Oracle Database instance is running */
87-
private static final String HOST = CONFIG.getProperty("HOST");
88-
89-
/** Port number where an Oracle Database instance is listening */
90-
private static final int PORT = Integer.parseInt(CONFIG.getProperty("PORT"));
91-
92-
/** Service name of an Oracle Database */
93-
private static final String SERVICE_NAME = CONFIG.getProperty("SERVICE_NAME");
94-
95-
/** User name that connects to an Oracle Database */
96-
private static final String USER = CONFIG.getProperty("USER");
97-
98-
/** Password of the user that connects to an Oracle Database */
99-
private static final String PASSWORD = CONFIG.getProperty("PASSWORD");
100-
101-
/** The file system path of a wallet directory */
102-
private static final String WALLET_LOCATION =
103-
CONFIG.getProperty("WALLET_LOCATION");
10474

10575
public static void main(String[] args) throws URISyntaxException {
10676

0 commit comments

Comments
 (0)