{"id":18554401,"url":"https://github.com/oracle/oracle-r2dbc","last_synced_at":"2025-04-08T09:06:24.816Z","repository":{"id":37050025,"uuid":"344620750","full_name":"oracle/oracle-r2dbc","owner":"oracle","description":"R2DBC Driver for Oracle Database","archived":false,"fork":false,"pushed_at":"2024-12-09T13:48:32.000Z","size":1082,"stargazers_count":205,"open_issues_count":7,"forks_count":43,"subscribers_count":17,"default_branch":"main","last_synced_at":"2025-04-01T07:45:27.349Z","etag":null,"topics":["oracle-database","oracle-jdbc","oracle-r2dbc","r2dbc-driver","r2dbc-spi","reactive-streams"],"latest_commit_sha":null,"homepage":"https://oracle.com","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oracle.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-03-04T22:00:08.000Z","updated_at":"2025-02-14T07:40:52.000Z","dependencies_parsed_at":"2024-11-13T22:02:56.727Z","dependency_job_id":null,"html_url":"https://github.com/oracle/oracle-r2dbc","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oracle%2Foracle-r2dbc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oracle%2Foracle-r2dbc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oracle%2Foracle-r2dbc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oracle%2Foracle-r2dbc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oracle","download_url":"https://codeload.github.com/oracle/oracle-r2dbc/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247809963,"owners_count":20999816,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["oracle-database","oracle-jdbc","oracle-r2dbc","r2dbc-driver","r2dbc-spi","reactive-streams"],"created_at":"2024-11-06T21:21:46.620Z","updated_at":"2025-04-08T09:06:24.794Z","avatar_url":"https://github.com/oracle.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# About Oracle R2DBC\n\nThe Oracle R2DBC Driver is a Java library that supports reactive programming with Oracle Database.\n\nOracle R2DBC implements the R2DBC Service Provider Interface (SPI) as specified\nby the Reactive Relational Database Connectivity (R2DBC) project. The R2DBC SPI\nexposes Reactive Streams as an abstraction for remote database operations.\nReactive Streams is a well defined standard for asynchronous, non-blocking, and\nback-pressured communication. This standard allows an R2DBC driver to\ninteroperate with other reactive libraries and frameworks, such as Spring,\nProject Reactor, RxJava, and Akka Streams.\n\n### Learn More About R2DBC:\n[R2DBC Project Home Page](https://r2dbc.io)\n\n[R2DBC Javadocs v1.0.0.RELEASE](https://r2dbc.io/spec/1.0.0.RELEASE/api/)\n\n[R2DBC Specification v1.0.0.RELEASE](https://r2dbc.io/spec/1.0.0.RELEASE/spec/html/)\n\n### Learn More About Reactive Streams:\n[Reactive Streams Project Home Page](http://www.reactive-streams.org)\n\n[Reactive Streams Javadocs v1.0.3](http://www.reactive-streams.org/reactive-streams-1.0.3-javadoc/org/reactivestreams/package-summary.html)\n\n[Reactive Streams Specification v1.0.3](https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.3/README.md)\n\n# About This Version\nThe 1.3.0 release Oracle R2DBC implements version 1.0.0.RELEASE of the R2DBC SPI.\n\nNew features in this release:\n- [Pipelining](#pipelining)\n- [Vector Data Type](#vector)\n- [Fetch Size and Proxy Authentication Options](https://github.com/oracle/oracle-r2dbc/pull/155)\n\nUpdated dependencies:\n- Updated Oracle JDBC from 21.11.0.0 to 23.6.0.24.10\n- Updated Project Reactor from 3.5.11 to 3.6.11\n\n## Installation\nOracle R2DBC can be obtained from Maven Central.\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.oracle.database.r2dbc\u003c/groupId\u003e\n  \u003cartifactId\u003eoracle-r2dbc\u003c/artifactId\u003e\n  \u003cversion\u003e1.3.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nOracle R2DBC can also be built from source using Maven:\n`mvn clean install -DskipTests=true`\n\n\u003e If -DskipTests=true is omitted from the command above, then it will execute \n\u003e end-to-end tests which connect to an Oracle Database. Tests read the connection \n\u003e configuration from\n\u003e [src/test/resources/config.properties](src/test/resources/example-config.properties).\n\nOracle R2DBC is compatible with JDK 11 (or newer), and has the following runtime dependencies:\n- R2DBC SPI 1.0.0.RELEASE\n- Reactive Streams 1.0.3\n- Project Reactor 3.6.11\n- Oracle JDBC 23.6.0.24.10 for JDK 11 (ojdbc11.jar)\n  - Oracle R2DBC relies on the Oracle JDBC Driver's [Reactive Extensions\n  ](https://docs.oracle.com/en/database/oracle/oracle-database/23/jjdbc/jdbc-reactive-extensions.html#GUID-1C40C43B-3823-4848-8B5A-D2F97A82F79B) APIs.\n\nThe Oracle R2DBC Driver has been verified with Oracle Database versions 18, 19,\n21, and 23.\n\n### Integration with Spring and Other Libraries\nOracle R2DBC can only interoperate with libraries that support the 1.0.0.RELEASE\nversion of the R2DBC SPI. When using libraries like Spring and r2dbc-pool, be\nsure to use a version which supports the 1.0.0.RELEASE of the SPI.\n\nOracle R2DBC depends on the JDK 11 build of Oracle JDBC 23.6.0.24.10. Other\nlibraries may depend on a different version of Oracle JDBC, and this version may\nbe incompatible. To resolve incompatibilities, it may be necessary to explicitly\ndeclare the dependency in your project, ie:\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.oracle.database.jdbc\u003c/groupId\u003e\n    \u003cartifactId\u003eojdbc11\u003c/artifactId\u003e\n    \u003cversion\u003e23.6.0.24.10\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Basic Code Examples\n\nThe following method returns an Oracle R2DBC `ConnectionFactory`\n```java\n  static ConnectionFactory getConnectionFactory() {\n    String user = getUser();\n    char[] password = getPassword();\n    try {\n      return ConnectionFactories.get(\n        ConnectionFactoryOptions.builder()\n          .option(ConnectionFactoryOptions.DRIVER, \"oracle\")\n          .option(ConnectionFactoryOptions.HOST, \"db.host.example.com\")\n          .option(ConnectionFactoryOptions.PORT, 1521)\n          .option(ConnectionFactoryOptions.DATABASE, \"db.service.name\")\n          .option(ConnectionFactoryOptions.USER, user)\n          .option(ConnectionFactoryOptions.PASSWORD, CharBuffer.wrap(password))\n          .build());\n    }\n    finally {\n      Arrays.fill(password, (char)0);\n    }\n  }\n```\n\nThe following method uses Project Reactor's\n[Flux](https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Flux.html)\nto open a connection, execute a SQL query, and then close the connection:\n```java\nFlux.usingWhen(\n  getConnectionFactory().create(),\n  connection -\u003e\n    Flux.from(connection.createStatement(\n      \"SELECT 'Hello, Oracle' FROM sys.dual\")\n      .execute())\n      .flatMap(result -\u003e\n        result.map(row -\u003e row.get(0, String.class))),\n  Connection::close)\n  .doOnNext(System.out::println)\n  .doOnError(Throwable::printStackTrace)\n  .subscribe();\n```\nWhen executed, the code above will _asynchronously_ print the result of the SQL query.\n\nThe next example uses a named parameter marker, `:locale_name`, in the SQL command:\n```java\nFlux.usingWhen(\n  getConnectionFactory().create(),\n  connection -\u003e\n    Flux.from(connection.createStatement(\n      \"SELECT greeting FROM locale WHERE locale_name = :locale_name\")\n      .bind(\"locale_name\", \"France\")\n      .execute())\n      .flatMap(result -\u003e\n        result.map(row -\u003e\n          String.format(\"%s, Oracle\", row.get(\"greeting\", String.class)))),\n  Connection::close)\n  .doOnNext(System.out::println)\n  .doOnError(Throwable::printStackTrace)\n  .subscribe();\n```\nLike the previous example, executing the code above will _asynchronously_ print \na greeting message. \"France\" is set as the bind value for `locale_name`, so the\nquery should return a greeting like \"Bonjour\" when `row.get(\"greeting\")`\nis called.\n\nAdditional code examples appear throughout this document, and can also be found\n[here](sample).\n\n## Help\nFor help programming with Oracle R2DBC, ask questions on Stack Overflow tagged with [[oracle] and [r2dbc]](https://stackoverflow.com/tags/oracle+r2dbc). The development team monitors Stack Overflow regularly.\n\nIssues may be opened as described in [our contribution guide](CONTRIBUTING.md).\n\n## Contributing\n\nThis project welcomes contributions from the community. Before submitting a pull\nrequest, please [review our contribution guide](./CONTRIBUTING.md).\n\n## Security\n\nPlease consult the [security guide](./SECURITY.md) for our responsible security\nvulnerability disclosure process.\n\n## License\n\nCopyright (c) 2021, 2024 Oracle and/or its affiliates.\n\nThis software is dual-licensed to you under the Universal Permissive License\n(UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License\n2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose\neither license.\n\n## Documentation\nThis document specifies the behavior of the R2DBC SPI as implemented for the \nOracle Database. This SPI implementation is referred to as the \"Oracle R2DBC\nDriver\" or \"Oracle R2DBC\" throughout the remainder of this document.\n\nThe Oracle R2DBC Driver implements behavior specified by the R2DBC 1.0.0.RELEASE \n[Specification](https://r2dbc.io/spec/1.0.0.RELEASE/spec/html/)\nand [Javadoc](https://r2dbc.io/spec/1.0.0.RELEASE/api/)\n\nPublisher objects created by Oracle R2DBC implement behavior specified by\nthe Reactive Streams 1.0.3 [Specification](https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.3/README.md)\nand [Javadoc](http://www.reactive-streams.org/reactive-streams-1.0.3-javadoc/org/reactivestreams/package-summary.html)\n\nThe R2DBC and Reactive Streams specifications include requirements that are\noptional for a compliant implementation. Oracle R2DBC's implementation of these\noptional are specified in this document. This document also specifies additional\nfunctionality that is supported by Oracle R2DBC, but is not part of the R2DBC\n1.0.0 Specification.\n\n### Connection Creation\nThe Oracle R2DBC Driver is identified by the name \"oracle\". The driver \nimplements a ConnectionFactoryProvider located by an R2DBC URL identifing\n\"oracle\" as a driver, or by a DRIVER `ConnectionFactoryOption` with the value\nof \"oracle\".\n\n#### Support for Standard R2DBC Options\nThe following standard [ConnectionFactoryOptions](https://r2dbc.io/spec/1.0.0.RELEASE/api/io/r2dbc/spi/ConnectionFactoryOptions.html)\nare supported by Oracle R2DBC: \n - `DRIVER`\n - `HOST`\n - `PORT`\n - `DATABASE`\n   - The database option is interpreted as the\n     [service name](https://docs.oracle.com/en/database/oracle/oracle-database/23/netag/identifying-and-accessing-database.html#GUID-153861C1-16AD-41EC-A179-074146B722E6)\n      of an Oracle Database instance. _System Identifiers (SID) are not recognized_.\n - `USER`\n - `PASSWORD`\n - `SSL`\n - `CONNECT_TIMEOUT`\n - `STATEMENT_TIMEOUT`.\n - `PROTOCOL`\n   - Accepted protocol values are \"tcps\", \"ldap\", and \"ldaps\"\n\n#### Support for Extended R2DBC Options\nOracle R2DBC extends the standard set of R2DBC options to offer functionality \nthat is specific to Oracle Database and the Oracle JDBC Driver. Extended options\nare declared in the\n[OracleR2dbcOptions](src/main/java/oracle/r2dbc/OracleR2dbcOptions.java) class.\n\n#### Support for Supplier and Publisher as Option Values\nMost options can have a value provided by a `Supplier` or `Publisher`.\n\nOracle R2DBC requests the value of an `Option` from a `Supplier` or `Publisher`\neach time the `Publisher` returned by `ConnectionFactory.create()` creates a new\n`Connection`. Each `Connection` can then be configured with values that change \nover time, such as a password which is periodically rotated.\n\nIf a `Supplier` provides the value of an `Option`, then Oracle R2DBC requests \nthe value by invoking `Supplier.get()`. If `get()` returns `null`,\nthen no value is configured for the `Option`. If `get()` throws a\n`RuntimeException`, then it is set as the initial cause of an\n`R2dbcException` emitted by the `Publisher` returned by\n`ConnectionFactory.create()`. The `Supplier` must have a thread safe `get()` \nmethod, as multiple subscribers may request connections concurrently.\n\nIf a `Publisher` provides the value of an `Option`, then Oracle R2DBC requests\nthe value by subscribing to the `Publisher` and signalling demand.\nThe first value emitted to `onNext` will be used as the value of the `Option`.\nIf the `Publisher` emits `onComplete` before `onNext`, then no value is\nconfigured for the `Option`. If the `Publisher` emits `onError` before `onNext`, \nthen the `Throwable` is set as the initial cause of an\n`R2dbcException` emitted by the `Publisher` returned by\n`ConnectionFactory.create()`.\n\nThe following example configures the `PASSWORD` option with a `Supplier`:\n```java\n  void configurePassword(ConnectionFactoryOptions.Builder optionsBuilder) {\n  \n    // Cast the PASSWORD option\n    Option\u003cSupplier\u003cCharSequence\u003e\u003e suppliedOption = OracleR2dbcOptions.supplied(PASSWORD);\n    \n    // Supply a password\n    Supplier\u003cCharSequence\u003e supplier = () -\u003e getPassword();\n    \n    // Configure the builder\n    optionsBuilder.option(suppliedOption, supplier); \n  }\n```\nA more concise example configures `TLS_WALLET_PASSWORD` as a `Publisher`\n```java\n  void configurePassword(ConnectionFactoryOptions.Builder optionsBuilder) {\n    optionsBuilder.option(\n      OracleR2dbcOptions.published(TLS_WALLET_PASSWORD),\n      Mono.fromSupplier(() -\u003e getWalletPassword()));\n  }\n```\nThese examples use the `supplied(Option)` and `published(Option)` methods \ndeclared by `oracle.r2dbc.OracleR2dbcOptions`. These methods cast an `Option\u003cT\u003e`\nto `Option\u003cSupplier\u003cT\u003e\u003e` and `Option\u003cPublisher\u003cT\u003e\u003e`, respectively. It is \nnecessary to cast the generic type of the `Option` when calling\n`ConnectionFactoryOptions.Builder.option(Option\u003cT\u003e, T)` in order for the call to\ncompile and not throw a `ClassCastException` at runtime. It is not strictly \nrequired that `supplied(Option)` or `published(Option)` be used to cast the \n`Option`. These methods are only meant to offer code readability and\nconvenience.\n\nNote that the following code would compile, but fails at runtime with a\n`ClassCastException`:\n```java\n  void configurePassword(ConnectionFactoryOptions.Builder optionsBuilder) {\n    Publisher\u003cCharSequence\u003e publisher = Mono.fromSupplier(() -\u003e getPassword());\n    // Doesn't work. Throws ClassCastException at runtime:\n    optionsBuilder.option(PASSWORD, PASSWORD.cast(publisher));\n  }\n```\nTo avoid a `ClassCastException`, the generic type of an `Option` must match the\nactual type of the value passed to \n`ConnectionFactoryOptions.Builder.option(Option\u003cT\u003e, T)`.\n\nFor a small set of options, providing values with a `Supplier` or `Publisher` \nis not supported:\n- `DRIVER`\n- `PROTOCOL`\n\nProviding values for these options would not be interoperable with\n`io.r2dbc.spi.ConnectionFactories` and `r2dbc-pool`.\n\nNormally, Oracle R2DBC will not retain references to `Option` values after\n`ConnectionFactories.create(ConnectionFactoryOptions)` returns. However, if\nthe value of at least one `Option` is provided by a `Supplier` or `Publisher`, \nthen Oracle R2DBC will retain a reference to all `Option` values until the \n`ConnectionFactory.create()` `Publisher` emits a `Connection` or error. This is\nimportant to keep in mind when `Option` values may be mutated. In particular,\na password may only be cleared from memory after the `create()` `Publisher` \nemits a `Connection` or error.\n\n#### Configuring an Oracle Net Descriptor\nThe `oracle.r2dbc.OracleR2dbcOptions.DESCRIPTOR` option may be used to configure\nan Oracle Net Descriptor of the form ```(DESCRIPTION=...)```. If this option is\nused to configure a descriptor, then it is invalid to specify any \nother option that conflicts with information in the descriptor. Conflicting\noptions include `HOST`, `PORT`, `DATABASE`, and `SSL`. These options all \nconflict with information that appears in a descriptor.\n\nThe `DESCRIPTOR` option has the name `oracle.r2dbc.descriptor`. This name can \nbe used to configure a descriptor in the query section of an R2DBC URL: \n```\nr2dbc:oracle://?oracle.r2dbc.descriptor=(DESCRIPTION=...)\n```\nThe `DESCRIPTOR` constant may also be used to configure a descriptor \nprogrammatically:\n```java\nConnectionFactoryOptions.builder()\n  .option(OracleR2dbcOptions.DESCRIPTOR, \"(DESCRIPTION=...)\")\n```\nThe `DESCRIPTOR` option may be set to an aliased entry of a `tnsnames.ora` file.\nUse the `TNS_ADMIN` option to specify the directory where `tnsnames.ora` is \nlocated:\n```\nr2dbc:oracle://?oracle.r2dbc.descriptor=myAlias\u0026TNS_ADMIN=/path/to/tnsnames/\n```\n\n#### Configuring an LDAP URL\nUse `ldap` or `ldaps` as the URL protocol to have an Oracle Net Descriptor \nretrieved from an LDAP server:\n```\nr2dbc:oracle:ldap://ldap.example.com:7777/sales,cn=OracleContext,dc=com\nr2dbc:oracle:ldaps://ldap.example.com:7778/sales,cn=OracleContext,dc=com\n```\nUse a space separated list of LDAP URIs for fail over and load balancing:\n```\nr2dbc:oracle:ldap://ldap1.example.com:7777/sales,cn=OracleContext,dc=com%20ldap://ldap2.example.com:7777/sales,cn=OracleContext,dc=com%20ldap://ldap3.example.com:7777/sales,cn=OracleContext,dc=com\n```\n\u003e Space characters in a URL must be percent encoded as `%20`\n\nAn LDAP server request will **block a thread for network I/O** when Oracle R2DBC\ncreates a new connection.\n\n#### Configuring a java.util.concurrent.Executor\nThe `oracle.r2dbc.OracleR2dbcOptions.EXECUTOR` option configures a \n`java.util.concurrent.Executor` for executing asynchronous callbacks. The \n`EXECUTOR` option may be used to configure an `Executor` programmatically:\n```java\nConnectionFactoryOptions.builder()\n  .option(OracleR2dbcOptions.EXECUTOR, getExecutor())\n```\n\u003e There is no way to configure an executor with a URL query parameter\n\nIf this option is not configured, then the common \n`java.util.concurrent.ForkJoinPool` is used as a default.\n\n#### Configuring Oracle JDBC Connection Properties\nA subset of Oracle JDBC's connection properties are defined as `Option` \nconstants in the\n[OracleR2dbcOptions](src/main/java/oracle/r2dbc/OracleR2dbcOptions.java) class.\nIf an Oracle JDBC property is not defined as an `Option`, in most cases it can \ninstead be configured by a\n[connection properties file](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_CONFIG_FILE)\nor a JVM system property instead.\n[Pull requests to add missing options](https://github.com/oracle/oracle-r2dbc/pull/124)\nare also a welcome addition.\n\nWhen a connection property is defined in `OracleR2dbcOptions`, it may be\nconfigured as an R2DBC URL parameter. For example, the following URL configures\nthe `oracle.net.wallet_location` connection property:\n```\nr2dbcs:oracle://db.host.example.com:1522/db.service.name?oracle.net.wallet_location=/path/to/wallet/\n```\nAnd, the `OracleR2dbcOptions` constants can be used in programmatic \nconfiguration:\n```java\n ConnectionFactoryOptions.builder()\n  .option(OracleR2dbcOptions.TLS_WALLET_LOCATION, \"/path/to/wallet\")\n```\n\nAll Oracle JDBC connection properties defined in `OracleR2dbcOptions` are listed\nin the next sections.\n\n##### TLS/SSL Connection Properties\n  - [oracle.net.tns_admin](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_TNS_ADMIN)\n  - [oracle.net.wallet_location](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_WALLET_LOCATION)\n  - [oracle.net.wallet_password](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_WALLET_PASSWORD)\n  - [javax.net.ssl.keyStore](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_THIN_JAVAX_NET_SSL_KEYSTORE)\n  - [javax.net.ssl.keyStorePassword](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_THIN_JAVAX_NET_SSL_KEYSTOREPASSWORD)\n  - [javax.net.ssl.keyStoreType](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_THIN_JAVAX_NET_SSL_KEYSTORETYPE)\n  - [javax.net.ssl.trustStore](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_THIN_JAVAX_NET_SSL_TRUSTSTORE)\n  - [javax.net.ssl.trustStorePassword](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_THIN_JAVAX_NET_SSL_TRUSTSTOREPASSWORD)\n  - [javax.net.ssl.trustStoreType](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_THIN_JAVAX_NET_SSL_TRUSTSTORETYPE)\n  - [oracle.net.authentication_services](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_THIN_NET_AUTHENTICATION_SERVICES)\n  - [oracle.net.ssl_certificate_alias](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_THIN_SSL_CERTIFICATE_ALIAS)\n  - [oracle.net.ssl_server_dn_match](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_THIN_SSL_SERVER_DN_MATCH)\n  - [oracle.net.ssl_server_cert_dn](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_THIN_SSL_SERVER_CERT_DN)\n  - [oracle.net.ssl_version](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_THIN_SSL_VERSION)\n  - [oracle.net.ssl_cipher_suites](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_THIN_SSL_CIPHER_SUITES)\n  - [ssl.keyManagerFactory.algorithm](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_THIN_SSL_KEYMANAGERFACTORY_ALGORITHM)\n  - [ssl.trustManagerFactory.algorithm](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_THIN_SSL_TRUSTMANAGERFACTORY_ALGORITHM)\n  - [oracle.net.ssl_context_protocol](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_SSL_CONTEXT_PROTOCOL)\n\n##### Database Tracing Connection Properties\n  - [v$session.terminal](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_VSESSION_TERMINAL)\n  - [v$session.machine](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_VSESSION_MACHINE)\n  - [v$session.osuser](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_VSESSION_OSUSER)\n  - [v$session.program](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_VSESSION_PROGRAM)\n  - [v$session.process](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_VSESSION_PROCESS)\n\n##### Oracle Net Encryption Connection Properties\n  - [oracle.net.encryption_client](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_NET_ENCRYPTION_LEVEL)\n  - [oracle.net.encryption_types_client](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_NET_ENCRYPTION_TYPES)\n  - [oracle.net.crypto_checksum_client](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_NET_CHECKSUM_LEVEL)\n  - [oracle.net.crypto_checksum_types_client](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_NET_CHECKSUM_TYPES)\n\n##### Kerberos Connection Properties\n  - [oracle.net.kerberos5_cc_name](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_NET_AUTHENTICATION_KRB5_CC_NAME)\n  - [oracle.net.kerberos5_mutual_authentication](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_NET_AUTHENTICATION_KRB5_MUTUAL)\n  - [oracle.net.KerberosRealm](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_NET_AUTHENTICATION_KRB_REALM)\n  - [oracle.net.KerberosJaasLoginModule](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_NET_AUTHENTICATION_KRB_JAAS_LOGIN_MODULE)\n\n##### LDAP Connection Properties\n  - [oracle.net.ldap.security.authentication](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_LDAP_SECURITY_AUTHENTICATION)\n  - [oracle.net.ldap.security.principal](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_LDAP_SECURITY_PRINCIPAL)\n  - [oracle.net.ldap.security.credentials](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_LDAP_SECURITY_CREDENTIALS)\n  - [com.sun.jndi.ldap.connect.timeout](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_JNDI_LDAP_CONNECT_TIMEOUT)\n  - [com.sun.jndi.ldap.read.timeout](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_JNDI_LDAP_READ_TIMEOUT)\n  - [oracle.net.ldap.ssl.walletLocation](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_LDAP_SSL_WALLET_LOCATION)\n  - [oracle.net.ldap.ssl.walletPassword](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_LDAP_SSL_WALLET_PASSWORD)\n  - [oracle.net.ldap.ssl.keyStoreType](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_LDAP_SSL_KEYSTORE_TYPE)\n  - [oracle.net.ldap.ssl.keyStore](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_LDAP_SSL_KEYSTORE)\n  - [oracle.net.ldap.ssl.keyStorePassword](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_LDAP_SSL_KEYSTORE_PASSWORD)\n  - [oracle.net.ldap.ssl.trustStoreType](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_LDAP_SSL_TRUSTSTORE_TYPE)\n  - [oracle.net.ldap.ssl.trustStore](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_LDAP_SSL_TRUSTSTORE)\n  - [oracle.net.ldap.ssl.trustStorePassword](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_LDAP_SSL_TRUSTSTORE_PASSWORD)\n  - [oracle.net.ldap.ssl.supportedCiphers](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_LDAP_SSL_CIPHER_SUITES)\n  - [oracle.net.ldap.ssl.supportedVersions](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_LDAP_SSL_VERSIONS)\n  - [oracle.net.ldap.ssl.keyManagerFactory.algorithm](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_LDAP_SSL_KEYMANAGER_FACTORY_ALGORITHM)\n  - [oracle.net.ldap.ssl.trustManagerFactory.algorithm](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_LDAP_SSL_TRUSTMANAGER_FACTORY_ALGORITHM)\n  - [oracle.net.ldap.ssl.ssl_context_protocol](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_THIN_LDAP_SSL_CONTEXT_PROTOCOL)\n\n##### Miscellaneous Connection Properties\n- [oracle.jdbc.fanEnabled](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_FAN_ENABLED)\n- [oracle.jdbc.implicitStatementCacheSize](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_IMPLICIT_STATEMENT_CACHE_SIZE)\n- [oracle.jdbc.defaultLobPrefetchSize](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_DEFAULT_LOB_PREFETCH_SIZE)\n- [oracle.net.disableOob](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_THIN_NET_DISABLE_OUT_OF_BAND_BREAK)\n    - Out of band (OOB) breaks effect statement timeouts. Set this to \"true\" if\n      statement timeouts are not working correctly. OOB breaks are a\n      [requirement for pipelining](#requirements-for-pipelining)\n- [oracle.jdbc.enableQueryResultCache](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_ENABLE_QUERY_RESULT_CACHE)\n    - Cached query results can cause phantom reads even if the serializable\n      transaction isolation level is set. Set this to \"false\" if using the\n      serializable isolation level.\n- [oracle.jdbc.timezoneAsRegion](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_TIMEZONE_AS_REGION)\n    - Setting this option to \"false\" may resolve \"ORA-01882: timezone region not\n      found\". The ORA-01882 error happens when Oracle Database doesn't recognize\n      the name returned by `java.util.TimeZone.getDefault().getId()`.\n- [oracle.jdbc.defaultRowPrefetch](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_DEFAULT_ROW_PREFETCH)\n- [oracle.jdbc.proxyClientName](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_PROXY_CLIENT_NAME)\n\n### Thread Safety\nOracle R2DBC's `ConnectionFactory` and `ConnectionFactoryProvider` are the only \nclasses that have a thread safe implementation. All other classes implemented \nby Oracle R2DBC are not thread safe. For instance, it is not safe for multiple\nthreads to concurrently access a single instance of `Result`.\n\u003e It is recommended to use a Reactive Streams library such as Project Reactor\n\u003e or RxJava to manage the consumption of non-thread safe objects\n\nWhile it is not safe for multiple threads to concurrently access the _same_ \nobject, it is safe from them to do so with _different_ objects from the _same_\n`Connection`. For example, two threads can concurrently subscribe to two\n`Statement` objects from the same `Connection`. When this happens, the two \nstatements are executed in a \"pipeline\". Pipelining will be covered in the next\nsection.\n\n### Pipelining\nPipelining allows Oracle R2DBC to send a call without having to wait for a previous call\nto complete. [If all requirements are met](#requirements-for-pipelining), then\npipelining will be activated by concurrently subscribing to publishers \nfrom the same connection. For example, the following code concurrently\nsubscribes to two statements:\n```java\nFlux.merge(\n  connection.createStatement(\n    \"INSERT INTO example (id, value) VALUES (0, 'X')\")\n    .execute(),\n  connection.createStatement(\n    \"INSERT INTO example (id, value) VALUES (1, 'Y')\")\n    .execute())\n```\nWhen the `Publisher` returned by `merge` is subscribed to, both INSERTs are \nimmediately sent to the database. The network traffic can be visualized as:\n```\nTIME | ORACLE R2DBC     | NETWORK | ORACLE DATABASE\n-----+------------------+---------+-----------------\n   0 | Send INSERT-X    | ------\u003e | WAITING\n   0 | Send INSERT-Y    | ------\u003e | WAITING\n   1 | WAITING          | \u003c------ | Send Result-X\n   1 | WAITING          | \u003c------ | Send Result-Y\n   2 | Receive Result-X |         | WAITING\n   2 | Receive Result-Y |         | WAITING\n\n```\nIn this visual, 1 unit of TIME is required to transfer data over the\nnetwork. The TIME column is only measuring network latency. It does not include \ncomputational time spent on executing the INSERTs.\n\nThe key takeaway from this visual is that the INSERTs are sent and \nreceived _concurrently_, rather than _sequentially_. Both INSERTs are sent at\nTIME=0, and both are received at TIME=1. And, the results are both sent at TIME=1,\nand are received at TIME=2. \n\n\u003e Recall that TIME is not measuring computational time. If each action by Oracle\n\u003e R2DBC and Oracle Database requires 0.1 units of computational TIME, then we \n\u003e can say:\n\u003e \n\u003e INSERTs are sent at TIME=0.1 and TIME=0.2, and are received at TIME=1.1 and\n\u003e TIME=1.2. And, the results are sent at TIME=1.2 and\n\u003e TIME=1.3, and are received at TIME=2.2 and TIME=2.3. \n\u003e \n\u003e This is a bit more complicated to think about, but it is important to keep in \n\u003e mind. All database calls will require at least some computational time.\n\nBelow is another visual of the network traffic, but in this case the INSERTs are\nsent and received _without pipelining_:\n```\nTIME | ORACLE R2DBC     | NETWORK | ORACLE DATABASE\n-----+------------------+---------+-----------------\n   0 | Send INSERT-X    | ------\u003e | WAITING\n   1 | WAITING          | \u003c------ | Send Result-X\n   2 | Receive Result-X |         | WAITING\n   2 | Send INSERT-Y    | ------\u003e | WAITING\n   3 | WAITING          | \u003c------ | Send Result-Y\n   4 | Receive Result-Y |         | WAITING\n\n```\nThis visual shows a _sequential_ process of sending and receiving. It can be\ncompared to the _concurrent_ process seen in the previous visual. In both cases,\nOracle R2DBC and Oracle Database have the same number of WAITING actions. These\nactions are waiting for network transfers. And in both cases, each network \ntransfer requires 1 unit of TIME.\n\nSo if network latency is the same, and the number of\nWAITING actions are the same (,and the\ncomputational times are the same), then how are these INSERTs completing in less\nTIME with pipelining? The answer is that _pipelining allowed the\nnetwork transfer times to be waited for __concurrently___.\n\nIn the first visual, with pipelining, the database waits for _both_ INSERT-X and\nINSERT-Y at TIME=0. Compare that to the second visual, without pipelining, where\nthe database waits for INSERT-X at TIME=0, and then _waits again_ for INSERT-Y\nat TIME=2. That's 1 additional unit of TIME when compared to pipelining. The \nother additional unit of TIME happens on the Oracle R2DBC side. Without \npipelining, it waits for Result-X at TIME=1, and then _waits again_ for Result-Y\nat TIME=3. With pipelining, it _waits for both results concurrently_ at TIME=1.\n\n### Requirements for Pipelining\n\nThere are some requirements which must be met in order to use pipelining. As\nexplained in the previous section, the availability of pipelining can have a\nsignificant impact on performance. Users should review the requirements listed\nin this section when developing applications that rely on this performance gain.\n\nIn terms of functional behavior, the availability of pipelining will have no\nimpact: With or without it, the same database calls are going be executed. Users\nwho are not relying on pipelining performance do not necessarily need to review \nthe requirements listed in this section. Oracle JDBC is designed to \nautomatically check for these requirements, and it will fallback to using\nsequential network transfers if any requirement is not met.\n\n#### Product Versions\nPipelining is only available with Oracle Database version 23.4 or newer. It also\nrequires an Oracle JDBC version of 23.4 or newer, but this is already a \ntransitive dependency of Oracle R2DBC.\n\n#### Out Of Band Breaks\nPipelining requires out-of-band (OOB) breaks (ie: TCP urgent data) for cancelling \nstatement execution. The Oracle JDBC Driver automatically checks if OOB is \navailable, and will disable pipelining if it is not. The availability of OOB may \ndepend on the operating system where Oracle R2DBC is running. Notably, _OOB is \nnot available on Mac OS_ (or at least not available in the way which Oracle JDBC\nneeds it to be for sending TCP urgent data to Oracle Database).\n\n__For experimentation only__, Mac OS users can choose to by-pass the OOB \nrequirement by setting a JVM system property:\n```\n-Doracle.jdbc.disablePipeline=false\n```\nBypassing the OOB requirement on Mac OS will result in non-functional \nimplementations of `Connection.setStatementTimeout(Duration)`, and \n`Subscription.cancel()` for a `Subscription` from `Statement.execute()`.\n\n### Reactive Streams\nEvery method implemented by Oracle R2DBC that returns a Publisher has a JavaDoc\nwhich specifies the Publisher's behavior with regard to deferred execution and \nsupport for multiple Subscribers.\n\nOracle R2DBC's implementation of Publishers that emit one or zero items will\ntypically defer execution until a Subscriber subscribes, support multiple \nSubscribers, and cache the result of a database call (the same result of the \nsame call is emitted to each Subscriber).\n\nOracle R2DBC's implementation of Publishers that emit multiple items will \ntypically defer execution until a Subscriber signals demand, and not support \nmultiple subscribers.\n\n### Errors and Warnings\nOracle R2DBC creates R2dbcExceptions having the same ORA-XXXXX error codes \nused by Oracle Database and Oracle JDBC. The\n[Database Error Messages](https://docs.oracle.com/en/database/oracle/oracle-database/23/errmg/ORA-00000.html#GUID-27437B7F-F0C3-4F1F-9C6E-6780706FB0F6)\ndocument provides a reference for all ORA-XXXXX error codes.\n\nWarning messages from Oracle Database are emitted as \n`oracle.r2dbc.OracleR2dbcWarning` segments. These segments may be consumed using\n`Result.flatMap(Function)`:\n```java\nresult.flatMap(segment -\u003e {\n  if (segment instanceof OracleR2dbcWarning) {\n    logWarning(((OracleR2dbcWarning)segment).getMessage());\n    return emptyPublisher();\n  }\n  else if (segment instanceof Result.Message){\n    ... handle an error ...\n  }\n  else {\n    ... handle other segment types ...\n  }\n})\n```\nUnlike the errors of standard `Result.Message` segments, if a warning is not\nconsumed by `flatMap`, then it will be silently discarded when a `Result` is \nconsumed using the `map` or `getRowsUpdated` methods.\n\n### Transactions\nOracle R2DBC uses READ COMMITTED as the default transaction isolation level.\n\nOracle R2DBC also supports the SERIALIZABLE isolation level. If SERIALIZABLE\nisolation is configured, then the \n`oracle.r2dbc.OracleR2dbcOptions.ENABLE_QUERY_RESULT_CACHE` option must also be\nconfigured as `false` to avoid phantom reads.\n\n\u003e READ COMMITTED and SERIALIZABLE are the only isolation levels supported by \n\u003e Oracle Database\n\nOracle Database does not support a lock wait timeout that is configurable within\nthe scope of a transaction or session. Oracle R2DBC implements SPI methods that \nconfigure a lock wait timeout to throw ```UnsupportedOperationException```.\n\n### Statements\nOracle R2DBC supports SQL execution with the `Statement` SPI.\n\n#### Parameter Markers\nA SQL command passed to `Connection.createStatement(String)` may include \nnamed parameter markers, unnamed parameter markers, or both.\n\nUnnamed parameter markers may appear in SQL as a question mark\n(`?`):\n```java\nconnection.createStatement(\n  \"SELECT value FROM example WHERE id=?\")\n  .bind(0, 99)\n```\nThe `bind` method must be called with a zero-based index to set the value of an\nunnamed parameter.\n\nNamed parameter markers may appear in SQL as a colon character (`:`) followed by \nan alpha-numeric name:\n```java\nconnection.createStatement(\n  \"SELECT value FROM example WHERE id=:id\")\n  .bind(\"id\", 99)\n```\nThe `bind` method may be called with a `String` valued name, or with zero-based\nindex, to set the value of a named parameter. Parameter names are\ncase-sensitive.\n\n#### Batch Execution\nThe `Statement.add()` method may be used execute a DML command multiple times\nwith a batch of different bind values. Oracle Database only supports batch\nexecution for DML type SQL commands (INSERT/UPDATE/DELETE). Attempting to\nexecute a SELECT query with a batch of bind values will result in an error.\n\n#### Returning Generated Values\nThe `Statement.returnGeneratedValues(String...)` method may be called to return \ngenerated values from basic forms of `INSERT` and `UPDATE` statements.\n\nIf an empty set of column names is passed to `returnGeneratedValues`, the \n`Statement` will return the\n[ROWID](https://docs.oracle.com/en/database/oracle/oracle-database/23/cncpt/tables-and-table-clusters.html#GUID-0258C4C2-2BF2-445F-B1E1-F282A57A6859)\nof each row affected by an INSERT or UPDATE.\n\u003e Programmers are advised not to use the ROWID as if it were a primary key.\n\u003e The ROWID of a row change, or be reassigned to a different row.\n\u003e See\n\u003e https://asktom.oracle.com/pls/apex/asktom.search?tag=is-it-safe-to-use-rowid-to-locate-a-row\n\u003e for more information.\n\nReturning generated values is only supported for `INSERT` and `UPDATE` commands \nin which a `RETURNING INTO` clause would be valid. For example, if a table is \ndeclared as:\n```sql\nCREATE TABLE example (\n  id NUMBER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,\n  value VARCAHR(100))\n```\nReturning generated values is supported for the following statement:\n```java\nconnection.createStatement(\n  \"INSERT INTO example(value) VALUES (:value)\")\n  .bind(\"value\", \"x\")\n  .returningGeneratedValues(\"id\")\n```\nThis statement is supported because the `INSERT` could be written to include a \n`RETURNING INTO` clause:\n```sql\nINSERT INTO example(value) VALUES (:value) RETURING id INTO :id\n```\nAs a counter example, returning generated values is not supported for the \nfollowing statement:\n```java\nconnection.createStatement(\n  \"INSERT INTO example (value) SELECT 'y' FROM sys.dual\")\n  .returningGeneratedValues(\"id\")\n```\nThis statement is not supported because it can not be written to include a \n`RETURNING INTO` clause.\n\n\u003e The Oracle Database SQL Language Reference specifies the INSERT and UPDATE \n\u003e commands for which a RETURNING INTO clause is supported.\n\u003e \n\u003e For the INSERT syntax, see:\n\u003e https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/INSERT.html\n\u003e \n\u003e For the UPDATE syntax, see:\n\u003e https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/UPDATE.html\n\n#### Procedural Calls\nThe SQL string passed to ```Connection.createStatement(String)``` may execute a\nPL/SQL call:\n  ```java\n  connection.createStatement(\"BEGIN sayHello(:name_in, :greeting_out); END;\")\n  ```\nOUT parameters are registered by invoking \n`Statement.bind(int, Object)` or `Statement.bind(String, Object)`\n with an instance of ```io.r2dbc.spi.Parameter``` implementing the \n```io.r2dbc.spi.Parameter.Out``` marker interface:\n```java\nstatement.bind(\"greeting_out\", Parameters.out(R2dbcType.VARCHAR))\n```\nLikewise, an IN OUT parameter would be registered by invoking\n`Statement.bind(int, Object)` or `Statement.bind(String, Object)`\nwith an instance of ```io.r2dbc.spi.Parameter``` implementing both the\n`io.r2dbc.spi.Parameter.Out` and `io.r2dbc.spi.Parameter.In` marker interfaces.\n\nOUT parameters are consumed by invoking `Result.map(Function)`:\n```java\nresult.map(outParameters -\u003e outParameters.get(\"greeting_out\", String.class))\n```\nIf a procedural call returns multiple results, the publisher returned by \n`Statement.execute()` emits one `Result` for each cursor returned by \n`DBMS_SQL.RETURN_RESULT` in the procedure. The order in which each \n`Result` is emitted corresponds to the order in which the procedure returns each\ncursor.\n\nIf a procedure returns cursors, and also has out parameters, then the `Result` \nfor the out parameters is emitted last, after the `Result` for each cursor.\n\n### Type Mappings\nOracle R2DBC supports type mappings between Java and SQL for non-standard data \ntypes of Oracle Database.\n\n| Oracle SQL Type                                                                                                                                         | Java Type                                                           |\n|---------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------|\n| [JSON](https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/Data-Types.html#GUID-E441F541-BA31-4E8C-B7B4-D2FB8C42D0DF)                   | `javax.json.JsonObject` or `oracle.sql.json.OracleJsonObject`       |\n| [DATE](https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/Data-Types.html#GUID-5405B652-C30E-4F4F-9D33-9A4CB2110F1B)                   | `java.time.LocalDateTime`                                           |\n| [INTERVAL DAY TO SECOND](https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/Data-Types.html#GUID-B03DD036-66F8-4BD3-AF26-6D4433EBEC1C) | `java.time.Duration`                                                |\n| [INTERVAL YEAR TO MONTH](https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/Data-Types.html#GUID-ED59E1B3-BA8D-4711-B5C8-B0199C676A95) | `java.time.Period`                                                  |\n| [SYS_REFCURSOR](https://docs.oracle.com/en/database/oracle/oracle-database/23/lnpls/static-sql.html#GUID-470A7A99-888A-46C2-BDAF-D4710E650F27)          | `io.r2dbc.spi.Result`                                               |\n| [VECTOR](https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/Data-Types.html#GUID-801FFE49-217D-4012-9C55-66DAE1BA806F)                 | `double[]`, `float[]`, `byte[]`, `boolean[]` or `oracle.sql.VECTOR` |\n\u003e Unlike the standard SQL type named \"DATE\", the Oracle Database type named \n\u003e \"DATE\" stores values for year, month, day, hour, minute, and second. The \n\u003e standard SQL type only stores year, month, and day. LocalDateTime objects are able \n\u003e to store the same values as a DATE in Oracle Database.\n\n### BLOB, CLOB, and NCLOB\nOracle R2DBC allows large objects (LOBs) to be read and written as a reactive \nstream, or as a\nfully materialized value.\n\n#### Prefetched LOB Data\nWhen a SQL query returns a LOB column,  only a portion of the LOB's content\nis received in the response from Oracle Database. The portion received in the \nSQL query response is referred to as \"prefetched data\". Any content remaining\nafter the prefetched portion must be fetched with additional database calls. \n\nFor example, if a SQL query returns a LOB that is 100MB in size, then the \nresponse might prefetch only the first 1MB of the LOB's content. Additional \ndatabase calls would be required to fetch the remaining 99MB of content.\n\nBy default, Oracle R2DBC attempts to prefetch the entire content of a LOB. Oracle R2DBC will\nrequest up to 1GB of prefetched data from Oracle Database when executing a SQL\nquery.\n\n#### Materialzed Type Mapping\nThe `Row.get(...)` method allows LOB values to be mapped into materialized\ntypes like `ByteBuffer` and `String`. If the entire LOB has been prefetched, \nthen `Row.get(...)`  can return a `ByteBuffer/String` without any additional \ndatabase calls. However, if the LOB value is larger than the prefetch size, then\n`Row.get(...)` must execute a **blocking database call** to fetch the remainder of that value.\n\n#### Streamed Type Mapping \nIn a system that consumes very large LOBs, a very large amount of memory will be\nconsumed if the entire LOB is prefetched. When a LOB is too large to be \nprefetched entirely, a smaller prefetch size can be configured using the\n[oracle.jdbc.defaultLobPrefetchSize](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/OracleConnection.html?is-external=true#CONNECTION_PROPERTY_DEFAULT_LOB_PREFETCH_SIZE)\noption, and the LOB can be consumed as a stream. By mapping LOB columns to \n`Blob` or `Clob` objects, the content can be consumed as a reactive stream. \n\n### ARRAY\nOracle Database supports `ARRAY` as a user defined type only. A `CREATE TYPE` \ncommand is used to define an `ARRAY` type:\n```sql\nCREATE TYPE MY_ARRAY AS ARRAY(8) OF NUMBER\n```\nOracle R2DBC defines `oracle.r2dbc.OracleR2dbcType.ArrayType` as a `Type` for\nrepresenting user defined `ARRAY` types. A `Parameter` with a type of\n`ArrayType` must be used when binding array values to a `Statement`.\n```java\nPublisher\u003cResult\u003e arrayBindExample(Connection connection) {\n  Statement statement =\n    connection.createStatement(\"INSERT INTO example VALUES (:array_bind)\");\n\n  // Use the name defined for an ARRAY type:\n  // CREATE TYPE MY_ARRAY AS ARRAY(8) OF NUMBER\n  ArrayType arrayType = OracleR2dbcTypes.arrayType(\"MY_ARRAY\");\n  Integer[] arrayValues = {1, 2, 3};\n  statement.bind(\"arrayBind\", Parameters.in(arrayType, arrayValues));\n\n  return statement.execute();\n}\n```\nA `Parameter` with a type of `ArrayType` must also be used when binding OUT\nparameters of a PL/SQL call.\n```java\nPublisher\u003cResult\u003e arrayOutBindExample(Connection connection) {\n  Statement statement =\n    connection.createStatement(\"BEGIN; exampleCall(:array_bind); END;\");\n\n  // Use the name defined for an ARRAY type:\n  // CREATE TYPE MY_ARRAY AS ARRAY(8) OF NUMBER\n  ArrayType arrayType = OracleR2dbcTypes.arrayType(\"MY_ARRAY\");\n  statement.bind(\"arrayBind\", Parameters.out(arrayType));\n\n  return statement.execute();\n}\n```\n`ARRAY` values may be consumed from a `Row` or `OutParameter` as a Java array.\nThe element type of the Java array may be any Java type that is supported as\na mapping for the SQL type of the `ARRAY`. For instance, if the `ARRAY` type is\n`NUMBER`, then a `Integer[]` mapping is supported:\n```java\nPublisher\u003cInteger[]\u003e arrayMapExample(Result result) {\n  return result.map(readable -\u003e readable.get(\"arrayValue\", Integer[].class));\n}\n```\n\n### OBJECT\nOracle Database supports `OBJECT` as a user defined type. A `CREATE TYPE`\ncommand is used to define an `OBJECT` type:\n```sql\nCREATE TYPE PET AS OBJECT(\n  name VARCHAR(128),\n  species VARCHAR(128),\n  weight NUMBER,\n  birthday DATE)\n```\nOracle R2DBC defines `oracle.r2dbc.OracleR2dbcType.ObjectType` as a `Type` for\nrepresenting user defined `OBJECT` types. A `Parameter` with a type of\n`ObjectType` may be used to bind `OBJECT` values to a `Statement`.\n\nUse an `Object[]` to bind the attribute values of an `OBJECT` by index:\n```java\nPublisher\u003cResult\u003e objectArrayBindExample(Connection connection) {\n  Statement statement =\n    connection.createStatement(\"INSERT INTO petTable VALUES (:petObject)\");\n\n  // Bind the attributes of the PET OBJECT defined above\n  ObjectType objectType = OracleR2dbcTypes.objectType(\"PET\");\n  Object[] attributeValues = {\n    \"Derby\",\n    \"Dog\",\n    22.8,\n    LocalDate.of(2015, 11, 07)\n  };\n  statement.bind(\"petObject\", Parameters.in(objectType, attributeValues));\n\n  return statement.execute();\n}\n```\n\nUse a `Map\u003cString,Object\u003e` to bind the attribute values of an `OBJECT` by name:\n```java\nPublisher\u003cResult\u003e objectMapBindExample(Connection connection) {\n  Statement statement =\n    connection.createStatement(\"INSERT INTO petTable VALUES (:petObject)\");\n\n  // Bind the attributes of the PET OBJECT defined above\n  ObjectType objectType = OracleR2dbcTypes.objectType(\"PET\");\n  Map\u003cString,Object\u003e attributeValues = Map.of(\n    \"name\", \"Derby\",\n    \"species\", \"Dog\",\n    \"weight\", 22.8,\n    \"birthday\", LocalDate.of(2015, 11, 07));\n  statement.bind(\"petObject\", Parameters.in(objectType, attributeValues));\n\n  return statement.execute();\n}\n```\nA `Parameter` with a type of `ObjectType` must be used when binding OUT\nparameters of `OBJECT` types for a PL/SQL call:\n```java\nPublisher\u003cResult\u003e objectOutBindExample(Connection connection) {\n  Statement statement =\n    connection.createStatement(\"BEGIN; getPet(:petObject); END;\");\n\n  ObjectType objectType = OracleR2dbcTypes.objectType(\"PET\");\n  statement.bind(\"petObject\", Parameters.out(objectType));\n\n  return statement.execute();\n}\n```\n`OBJECT` values may be consumed from a `Row` or `OutParameter` as an\n`oracle.r2dbc.OracleR2dbcObject`. The `OracleR2dbcObject` interface is a subtype\nof `io.r2dbc.spi.Readable`. Attribute values may be accessed using the standard\n`get` methods of `Readable`. The `get` methods of `OracleR2dbcObject` support\nall SQL to Java type mappings defined by the\n[R2DBC Specification](https://r2dbc.io/spec/1.0.0.RELEASE/spec/html/#datatypes.mapping):\n```java\nPublisher\u003cPet\u003e objectMapExample(Result result) {\n  return result.map(row -\u003e {\n    OracleR2dbcObject oracleObject = row.get(0, OracleR2dbcObject.class); \n    return new Pet(\n      oracleObject.get(\"name\", String.class),\n      oracleObject.get(\"species\", String.class),\n      oracleObject.get(\"weight\", Float.class),\n      oracleObject.get(\"birthday\", LocalDate.class));\n  });\n}\n```\n\nInstances of `OracleR2dbcObject` may be passed directly to `Statement` bind \nmethods:\n```java\nPublisher\u003cResult\u003e objectBindExample(\n  OracleR2dbcObject oracleObject, Connection connection) {\n  Statement statement =\n    connection.createStatement(\"INSERT INTO petTable VALUES (:petObject)\");\n  \n  statement.bind(\"petObject\", oracleObject);\n\n  return statement.execute();\n}\n```\nAttribute metadata is exposed by the `getMetadata` method of\n`OracleR2dbcObject`:\n```java\nvoid printObjectMetadata(OracleR2dbcObject oracleObject) {\n  OracleR2dbcObjectMetadata metadata = oracleObject.getMetadata();\n  OracleR2dbcTypes.ObjectType objectType = metadata.getObjectType();\n  \n  System.out.println(\"Object Type: \" + objectType);\n  metadata.getAttributeMetadatas()\n    .stream()\n    .forEach(attributeMetadata -\u003e {\n      System.out.println(\"\\tAttribute Name: \" + attributeMetadata.getName()));\n      System.out.println(\"\\tAttribute Type: \" + attributeMetadata.getType()));\n    });\n}\n```\n\n### REF Cursor\nUse the `oracle.r2dbc.OracleR2dbcTypes.REF_CURSOR` type to bind `SYS_REFCURSOR`\nout parameters:\n```java\nPublisher\u003cResult\u003e executeProcedure(Connection connection) {\n  return connection.createStatement(\n    \"BEGIN example_procedure(:cursor_parameter); END;\")\n  .bind(\"cursor_parameter\", Parameters.out(OracleR2dbcTypes.REF_CURSOR))\n  .execute()\n}\n```\nA `SYS_REFCURSOR` out parameter can be mapped to an `io.r2dbc.spi.Result`:\n```java\nPublisher\u003cResult\u003e mapOutParametersResult(Result outParametersResult) {\n  return outParametersResult.map(outParameters -\u003e\n    outParameters.get(\"cursor_parameter\", Result.class));\n}\n```\nThe rows of a `SYS_REFCURSOR` may be consumed from the `Result` it is \nmapped to:\n```java\nPublisher\u003cExampleObject\u003e mapRefCursorRows(Result refCursorResult) {\n  return refCursorResult.map(row -\u003e\n    new ExampleObject(\n      row.get(\"id_column\", Long.class),\n      row.get(\"value_column\", String.class)));\n}\n```\n\n### VECTOR\nThe default mapping for the VECTOR data type is the\n[oracle.sql.VECTOR](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/sql/VECTOR.html)\nclass. Instances of this class may be passed to\n`Statement.bind(int/String, Object)`:\n```java\nvoid bindVector(Statement statement, float[] floatArray) throws SQLException {\n  final VECTOR vector;\n  try {\n    vector = VECTOR.ofFloat32Values(floatArray);\n  }\n  catch (SQLException sqlException) {\n    throw new IllegalArgumentException(sqlException);\n  }\n  statement.bind(\"vector\", vector);\n}\n```\nThe `oracle.sql.VECTOR` class defines factory methods that convert a\n`double[]`, `float[]`, `long[]`, `int[]`, `short[]`, `byte[]`, or `boolean[]`\ninto a VECTOR of a specific dimension type:\n- `ofFloat64Values`\n- `ofFloat32Values`\n- `ofInt8Values`\n- `ofBinaryValues` (only supports `boolean[]` and `byte[]`)\n\nThese factory methods may perform a lossy conversion, such\nas when converting a `double[]` into a VECTOR of FLOAT32 dimensions. \n[The JavaDocs of these methods specify which conversions are lossy](https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/sql/VECTOR.html).\n\nThe `OracleR2dbcTypes.VECTOR` type descriptor can be used to register an OUT or \nIN/OUT parameter:\n```java\nvoid registerOutVector(Statement statement) {\n  Parameter outVector = Parameters.out(OracleR2dbcTypes.VECTOR);\n  statement.bind(\"out_vector\", outVector);\n}\n```\nThe `OracleR2dbcTypes.VECTOR` type descriptor can also be used as an alternative\nto `oracle.sql.VECTOR` for binding a `double[]`, `float[]`, `byte[]`, or\n`boolean[]`. Arrays of these types are respectively converted into a VECTOR of \nFLOAT64, FLOAT32, INT8, or BINARY dimensions.\n```java\nvoid bindVector(Statement statement, float[] floatArray) {\n  Parameter inVector = Parameters.in(OracleR2dbcTypes.VECTOR, floatArray);\n  statement.bind(\"in_vector\", inVector);\n}\n```\nNote that passing arrays directly into `Statement.bind(int/String, Object)` will \nNOT create a VECTOR bind. The R2DBC Specification already defines ARRAY as\nthe default mapping for Java arrays, not VECTOR.\n\nA VECTOR column or OUT parameter is converted to `oracle.sql.VECTOR` by \ndefault. But a VECTOR column or OUT parameter having FLOAT64, FLOAT32, or INT8\ndimensions may also be converted to\n`double[]`, `float[]`, `long[]`, `int[]`, `short[]`, `byte[]`, or `boolean[]`. \nA VECTOR of BINARY dimensions may only be converted to `boolean[]` or `byte[]`.\nThese array classes may be passed to the `get` methods of a `Readable`:\n```java\nfloat[] getVector(io.r2dbc.Readable readable) {\n  return readable.get(\"vector\", float[].class);\n}\n```\n\n## Secure Programming Guidelines\nThe following security related guidelines should be adhered to when programming\nwith the Oracle R2DBC Driver.\n### Defend Against SQL Injection Attacks\n- Always specify the parameters of a SQL command using the bind methods of io.r2dbc.spi.Statement. \n  - Do not use String concatenation to specify parameters of a SQL command. \n  - Do not use format Strings to specify parameters of a SQL command.\n### Protect Passwords\n- Do not hard code passwords in your source code.\n- Avoid hard coding passwords in the R2DBC URL.\n  - When handling URL strings in code, be aware that a clear text password may appear in the user info section.\n- Use a sensitive io.r2dbc.spi.Option to specify passwords.\n  - If possible, specify the Option's value as an instance of java.nio.CharBuffer or java.lang.StringBuffer and clear the contents immediately after ConnectionFactories.get(ConnectionFactoryOptions) has returned. Oracle R2DBC's implementation of ConnectionFactory does not retain a reference to the clear text password.\n### Protect Network Communications\n- Use SSL/TLS if possible. Use any of the following methods to enable SSL/TLS:\n  - Specify the boolean value of true for io.r2dbc.spi.ConnectionFactoryOptions.SSL\n  - Specify \"r2dbcs:\" as the R2DBC URL schema.\n  - Specify \"ssl=true\" in the query section of the R2DBC URL.\n- Use Option.sensitiveValueOf(String) when creating an Option that specifies a password.\n  - Option.sensitiveValueOf(OracleConnection.CONNECTION_PROPERTY_WALLET_PASSWORD)\n    - An SSO wallet does not require a password.\n  - Option.sensitiveValueOf(OracleConnection.CONNECTION_PROPERTY_THIN_JAVAX_NET_SSL_KEYSTOREPASSWORD)\n  - Option.sensitiveValueOf(OracleConnection.CONNECTION_PROPERTY_THIN_JAVAX_NET_SSL_TRUSTSTOREPASSWORD)\n### Defend Against Denial-of-Service Attacks\n- Use a connection pool and configure a maximum size to limit the number of database sessions created by ConnectionFactory.create()\n- Enforce a maximum batch size to limit invocations of Statement.add() or Batch.add(String).\n- Enforce a maximum fetch size to limit values supplied to Statement.fetchSize(int).\n- Enforce a maximum buffer size to limit memory usage when reading Blob and Clob objects.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foracle%2Foracle-r2dbc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foracle%2Foracle-r2dbc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foracle%2Foracle-r2dbc/lists"}