oracle / oracle-r2dbc Goto Github PK
View Code? Open in Web Editor NEWR2DBC Driver for Oracle Database
Home Page: https://oracle.com
License: Other
R2DBC Driver for Oracle Database
Home Page: https://oracle.com
License: Other
With version 0.4.0, calling returnGeneratedValues()
upon an insert leads to a NullPointerException
. Omitting returnGeneratedValues()
does not raise the exception.
DDL:
CREATE TABLE legoset (
id INTEGER PRIMARY KEY,
version INTEGER NULL,
name VARCHAR2(255) NOT NULL,
manual INTEGER NULL,
cert RAW(255) NULL
)
Statement:
INSERT INTO legoset (ID, NAME, MANUAL) VALUES (:P0_id, :P1_name, :P2_manual)
Code to reproduce:
ConnectionFactory connectionFactory = ConnectionFactories.get(options);
Connection connection = Mono.from(connectionFactory.create()).block();
Flux.from(connection.createStatement("DROP TABLE legoset").execute())
.flatMap(Result::getRowsUpdated).onErrorResume(it -> Mono.empty()).blockLast();
String CREATE_TABLE_LEGOSET = "CREATE TABLE legoset (\n" //
+ " id INTEGER PRIMARY KEY,\n" //
+ " version INTEGER NULL,\n" //
+ " name VARCHAR2(255) NOT NULL,\n" //
+ " manual INTEGER NULL,\n" //
+ " cert RAW(255) NULL\n" //
+ ")";
Flux.from(connection.createStatement(CREATE_TABLE_LEGOSET).execute())
.flatMap(Result::getRowsUpdated).blockLast();
Flux.from(connection.createStatement("INSERT INTO legoset (ID, NAME, MANUAL) VALUES (:P0_id, :P1_name, :P2_manual)")
.bind("P0_id", 42055)
.bind("P1_name", "SCHAUFELRADBAGGER")
.bind("P2_manual", 12)
.returnGeneratedValues()
.execute()).flatMap(Result::getRowsUpdated)
.blockLast();
Stack trace:
java.lang.NullPointerException
at oracle.jdbc.driver.OracleStatement.getMoreResults(OracleStatement.java:5851)
at oracle.jdbc.driver.OracleStatementWrapper.getMoreResults(OracleStatementWrapper.java:298)
at oracle.r2dbc.impl.OracleStatementImpl$JdbcReturningGenerated.lambda$executeJdbc$0(OracleStatementImpl.java:1582)
at oracle.r2dbc.impl.AsyncLock.lambda$get$2(AsyncLock.java:161)
at oracle.r2dbc.impl.AsyncLock.unlock(AsyncLock.java:122)
at oracle.r2dbc.impl.AsyncLock$UsingConnectionSubscriber.terminate(AsyncLock.java:510)
at oracle.r2dbc.impl.AsyncLock$UsingConnectionSubscriber.onComplete(AsyncLock.java:496)
at reactor.core.publisher.StrictSubscriber.onComplete(StrictSubscriber.java:123)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2058)
at org.reactivestreams.FlowAdapters$FlowToReactiveSubscriber.onComplete(FlowAdapters.java:228)
at oracle.jdbc.internal.CompletionStageUtil$IteratorSubscription.emitComplete(CompletionStageUtil.java:681)
at oracle.jdbc.internal.CompletionStageUtil$IteratorSubscription.emitItems(CompletionStageUtil.java:628)
at oracle.jdbc.driver.PhysicalConnection.lambda$createUserCodeExecutor$10(PhysicalConnection.java:11713)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at oracle.jdbc.driver.PhysicalConnection.lambda$createUserCodeExecutor$11(PhysicalConnection.java:11711)
at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1426)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
Suppressed: java.lang.Exception: #block terminated with an error
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:99)
at reactor.core.publisher.Flux.blockLast(Flux.java:2645)
at org.springframework.data.r2dbc.core.Repro.reproducer(Repro.java:86)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
Hi, I am facing a weird problem using:
Java Version: Oracle JDK 17
implementation 'io.r2dbc:r2dbc-pool:0.9.0.RELEASE'
implementation 'io.r2dbc:r2dbc-spi:0.9.0.RELEASE'
runtimeOnly 'com.oracle.database.r2dbc:oracle-r2dbc:0.4.0'
First of all, I was using the version 0.1.0 with R2DBC POOL, and, it works when executing a single statement, but, with paralell calls, I face the problem with: Multiple subscribers ...
So, I came here, and, read that thats a know problem with version 0.1.0. Then, I upgrade to the version 0.4.0 which, is the latest.
But, trying to execute the same query(which works with version 0.1.0) , but, I am receiving a NullPointer inside oracle r2dbc classes.
StackTrace:
java.lang.NullPointerException: Cannot invoke "java.util.ArrayDeque.size()" because "this.implicitResultSetStatements" is null
at oracle.jdbc.driver.OracleStatement.getMoreResults(OracleStatement.java:5851)
at oracle.jdbc.driver.OracleStatementWrapper.getMoreResults(OracleStatementWrapper.java:298)
at oracle.r2dbc.impl.OracleStatementImpl$JdbcStatement.lambda$getResults$4(OracleStatementImpl.java:1053)
at oracle.r2dbc.impl.AsyncLock.lambda$get$2(AsyncLock.java:161)
at oracle.r2dbc.impl.AsyncLock.unlock(AsyncLock.java:122)
at oracle.r2dbc.impl.AsyncLock$UsingConnectionSubscriber.terminate(AsyncLock.java:510)
at oracle.r2dbc.impl.AsyncLock$UsingConnectionSubscriber.onComplete(AsyncLock.java:496)
at reactor.core.publisher.StrictSubscriber.onComplete(StrictSubscriber.java:123)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2058)
at org.reactivestreams.FlowAdapters$FlowToReactiveSubscriber.onComplete(FlowAdapters.java:228)
at oracle.jdbc.internal.CompletionStageUtil$IteratorSubscription.emitComplete(CompletionStageUtil.java:681)
at oracle.jdbc.internal.CompletionStageUtil$IteratorSubscription.emitItems(CompletionStageUtil.java:628)
at oracle.jdbc.driver.PhysicalConnection.lambda$createUserCodeExecutor$10(PhysicalConnection.java:11713)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at oracle.jdbc.driver.PhysicalConnection.lambda$createUserCodeExecutor$11(PhysicalConnection.java:11711)
at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1395)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
How I execute the query:
return Mono.usingWhen(
connectionPool.create(),
connection -> Mono.from(connection.createStatement(QUERY)
.bind(0, destinationState)
.bind(1, subsidiaryId)
.bind(2, itemId)
.execute()
),
Connection::close,
((connection, throwable) -> connection.close()),
Connection::close
)
.flatMapMany(it -> it.map(mapper))
.next();
How I create the connection pool:
public ConnectionPool connectionFactory() {
return new ConnectionPool(ConnectionPoolConfiguration
.builder()
.connectionFactory(ConnectionFactories.get(
ConnectionFactoryOptions
.builder()
.from(ConnectionFactoryOptions.parse(url))
.option(ConnectionFactoryOptions.USER, user)
.option(ConnectionFactoryOptions.PASSWORD, password)
.option(ConnectionFactoryOptions.DRIVER, DRIVER)
.option(Option.valueOf("applicationName"), "catalog-service-app")
.build()
)
)
.initialSize(INITIAL_CONNECTIONS)
.maxSize(maxConnections)
.maxIdleTime(Duration.ofSeconds(maxIdleTime))
.validationQuery(VALIDATION_QUERY)
.build()
);
}
I thought that I would be a problem with dependency versions, but, I checked the dependencies and, I am using the correct ones.
Please, tell me where I am making a mistake
I'm using Spring Data R2DBC with Oracle 11g and I have the following error using method findById
of R2dbcCrudRepository
executeMany; bad SQL grammar [SELECT GAME_PHASE.* FROM GAME_PHASE WHERE GAME_PHASE.ID = :P0_id FETCH FIRST 2 ROWS ONLY]
This is the repository declaration
public interface ReactiveGamePhaseRepository extends R2dbcRepository<GamePhase, Long> {
}
I don't understand why FETCH FIRST 2 ROWS ONLY is added to the query and it's the cause of problem.
I have the same problem writing the query using R2dbcEntityTemplate like below:
r2dbcEntityTemplate.selectOne(query(where("id").is(id)), GamePhase.class);
And these are the used dependancies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
<version>2.5.12</version>
</dependency>
<dependency>
<groupId>com.oracle.database.r2dbc</groupId>
<artifactId>oracle-r2dbc</artifactId>
<version>1.0.0</version>
</dependency>
Sample Code:
Exception takes place in the highlighted code in bold below
testSubscriptionMono.flatMap(testSubscription -> {
testSubscription.setMembershipStatus("ENROLLED");
return repositoryService.saveTestSubscription(testSubscription);
}).subscribe(value -> System.out.println("RECEIVED " + value),
error -> error.printStackTrace());
Depdendencies:
Error Logs:
java.lang.ClassCastException: class java.lang.Long cannot be cast to class java.lang.Integer (java.lang.Long and java.lang.Integer are in module java.base of loader 'bootstrap')
at java.base/java.util.stream.Collectors.lambda$summingInt$19(Collectors.java:673)
at reactor.core.publisher.MonoStreamCollector$StreamCollectorSubscriber.onNext(MonoStreamCollector.java:132)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.tryEmit(FluxFlatMap.java:543)
at reactor.core.publisher.FluxFlatMap$FlatMapInner.onNext(FluxFlatMap.java:984)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:200)
at reactor.core.publisher.FluxConcatArray$ConcatArrayDelayErrorSubscriber.onNext(FluxConcatArray.java:364)
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onNext(FluxFilterFuseable.java:118)
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:299)
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2398)
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.request(FluxMapFuseable.java:360)
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.request(FluxFilterFuseable.java:191)
at reactor.core.publisher.FluxConcatArray$ConcatArrayDelayErrorSubscriber.request(FluxConcatArray.java:461)
at reactor.core.publisher.FluxPeek$PeekSubscriber.request(FluxPeek.java:138)
at reactor.core.publisher.FluxFlatMap$FlatMapInner.onSubscribe(FluxFlatMap.java:964)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onSubscribe(FluxPeek.java:171)
at reactor.core.publisher.FluxConcatArray$ConcatArrayDelayErrorSubscriber.onSubscribe(FluxConcatArray.java:350)
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onSubscribe(FluxFilterFuseable.java:87)
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onSubscribe(FluxMapFuseable.java:265)
at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55)
at reactor.core.publisher.Flux.subscribe(Flux.java:8466)
at reactor.core.publisher.FluxConcatArray$ConcatArrayDelayErrorSubscriber.onComplete(FluxConcatArray.java:443)
at reactor.core.publisher.FluxConcatArray.subscribe(FluxConcatArray.java:73)
at reactor.core.publisher.Flux.subscribe(Flux.java:8466)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onNext(FluxFlatMap.java:426)
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:539)
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122)
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyInner.onNext(MonoFlatMapMany.java:250)
at reactor.core.publisher.FluxUsingWhen$UsingWhenSubscriber.onNext(FluxUsingWhen.java:345)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:200)
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122)
at reactor.core.publisher.FluxConcatArray$ConcatArraySubscriber.onNext(FluxConcatArray.java:201)
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyInner.onNext(MonoFlatMapMany.java:250)
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2398)
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyMain.onSubscribeInner(MonoFlatMapMany.java:150)
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyMain.onNext(MonoFlatMapMany.java:189)
at reactor.core.publisher.MonoCreate$DefaultMonoSink.success(MonoCreate.java:172)
at oracle.r2dbc.impl.AsyncLock.lambda$get$2(AsyncLock.java:167)
at oracle.r2dbc.impl.AsyncLock.unlock(AsyncLock.java:125)
at oracle.r2dbc.impl.AsyncLock$UsingConnectionSubscriber.terminate(AsyncLock.java:516)
at oracle.r2dbc.impl.AsyncLock$UsingConnectionSubscriber.onComplete(AsyncLock.java:502)
at reactor.core.publisher.StrictSubscriber.onComplete(StrictSubscriber.java:123)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2058)
at org.reactivestreams.FlowAdapters$FlowToReactiveSubscriber.onComplete(FlowAdapters.java:221)
at oracle.jdbc.internal.CompletionStageUtil$IteratorSubscription.emitComplete(CompletionStageUtil.java:805)
at oracle.jdbc.internal.CompletionStageUtil$IteratorSubscription.emitItems(CompletionStageUtil.java:752)
at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1426)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)
I try to run r2dbc application with spring-boot-starter-data-r2dbc and oracle-r2dbc but it gives me an exception " org.springframework.dao.DataAccessResourceFailureException: Failed to obtain R2DBC Connection; nested exception is java.lang.IllegalStateException: This publisher does not support multiple subscribers".
Here is my properties file:
spring.r2dbc.url=r2dbc:oracle:thin://localhost:1521:orcl spring.r2dbc.username=user spring.r2dbc.password=password
and dependenices part of gradle file:
dependencies { ktlint 'com.pinterest:ktlint:0.41.0' implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion") implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion") implementation('com.fasterxml.jackson.module:jackson-module-kotlin') implementation('org.codehaus.janino:janino') implementation('org.springframework.cloud:spring-cloud-starter-stream-kafka') implementation('org.springframework.cloud:spring-cloud-stream') implementation('org.springframework.boot:spring-boot-configuration-processor') implementation('org.apache.httpcomponents:httpclient:4.5.8') implementation('org.springframework.retry:spring-retry') implementation("org.springframework.boot:spring-boot-starter-webflux") implementation('org.springframework.boot:spring-boot-starter-data-r2dbc') implementation('com.oracle.database.r2dbc:oracle-r2dbc') implementation('com.oracle.database.jdbc:ojdbc11:21.1.0.0') }
Am I missing any configuration or is this a known limitation?
Any timeline that oracle-r2dbc-1.0.0 will be available on maven central repository ?
The test suite reads database connection configuration from a "config.properties" file. If this file does not exist, then the DatabaseConfig class fails to initialize, and test execution will report an error like this:
[ERROR] oracle.r2dbc.OracleTestKit.compoundStatement Time elapsed: 0 s <<< ERROR!
java.lang.NoClassDefFoundError: Could not initialize class oracle.r2dbc.DatabaseConfig
at [email protected]/oracle.r2dbc.OracleTestKit.<init>(OracleTestKit.java:94)
This error message is not helpful because it doesn't inform the reader that the config.properties file is missing.
This is perfectly valid Oracle SQL:
create table t (id number generated always as identity primary key, val number);
insert into t (val) select 1 from dual union all select 2 from dual;
But when I try to run the INSERT .. SELECT
statement with r2dbc trying to fetch the generated identity values:
System.out.println((
Flux.from(connectionFactory.create())
.flatMap(c -> c
.createStatement("insert into t (val) select 1 from dual union all select 2 from dual")
.returnGeneratedValues("id")
.execute())
.flatMap(it -> it.map((r, m) -> r.get(0)))
.collectList()
.block().get(0)
));
Then I'm getting the following errors:
Exception in thread "main" io.r2dbc.spi.R2dbcBadGrammarException: [933] [42000] ORA-00933: SQL-Befehl wurde nicht korrekt beendet
at oracle.r2dbc.impl.OracleR2dbcExceptions.toR2dbcException(OracleR2dbcExceptions.java:162)
at reactor.core.publisher.Flux.lambda$onErrorMap$29(Flux.java:6670)
at reactor.core.publisher.Flux.lambda$onErrorResume$30(Flux.java:6723)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:94)
at org.reactivestreams.FlowAdapters$FlowToReactiveSubscriber.onError(FlowAdapters.java:223)
at oracle.jdbc.internal.CompletionStageUtil$BatchItemPublisher.subscribeToFailedBatch(CompletionStageUtil.java:544)
at oracle.jdbc.internal.CompletionStageUtil$BatchItemPublisher.lambda$subscribe$0(CompletionStageUtil.java:507)
at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:859)
at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:837)
at java.base/java.util.concurrent.CompletableFuture$Completion.run(CompletableFuture.java:478)
at oracle.jdbc.driver.PhysicalConnection.lambda$createUserCodeExecutor$10(PhysicalConnection.java:11713)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at oracle.jdbc.driver.PhysicalConnection.lambda$createUserCodeExecutor$11(PhysicalConnection.java:11711)
at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1426)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)
Suppressed: java.lang.Exception: #block terminated with an error
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:99)
at reactor.core.publisher.Mono.block(Mono.java:1703)
at org.jooq.testscripts.R2DBC.main(R2DBC.java:35)
Caused by: java.sql.SQLSyntaxErrorException: ORA-00933: SQL-Befehl wurde nicht korrekt beendet
at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:628)
at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:562)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:1207)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:727)
at oracle.jdbc.driver.T4CTTIfun.lambda$receiveRPCAsync$2(T4CTTIfun.java:426)
at oracle.jdbc.internal.CompletionStageUtil.handleNormalCompletion(CompletionStageUtil.java:176)
at oracle.jdbc.internal.CompletionStageUtil.lambda$normalCompletionHandler$1(CompletionStageUtil.java:227)
at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1072)
at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506)
at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2073)
at oracle.jdbc.driver.T4CTTIfun.lambda$receiveRPCAsync$0(T4CTTIfun.java:406)
at oracle.jdbc.driver.RestrictedLock.lambda$runUnrestricted$0(RestrictedLock.java:253)
at oracle.jdbc.driver.RestrictedLock.callUnrestricted(RestrictedLock.java:273)
at oracle.jdbc.driver.RestrictedLock.runUnrestricted(RestrictedLock.java:252)
at oracle.jdbc.driver.PhysicalConnection.lambda$createInternalCodeExecutor$7(PhysicalConnection.java:11647)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at oracle.jdbc.driver.PhysicalConnection.lambda$createInternalCodeExecutor$8(PhysicalConnection.java:11644)
... 6 more
Caused by: Error : 933, Position : 78, Sql = insert into t (val) select 1 from dual union all select 2 from dual RETURNING id INTO :1 , OriginalSql = insert into t (val) select 1 from dual union all select 2 from dual RETURNING id INTO ?, Error Msg = ORA-00933: SQL-Befehl wurde nicht korrekt beendet
at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:632)
... 22 more
Hi,
I got an oracle.r2dbc.impl.OracleR2dbcExceptions$OracleR2dbcException: [17110] [99999] Warning: ...
when I ran query with more than 9 element in a IN
statement.
There is no problems with JDBC so I don't think this is a database issue. Is there a specific option to turn on or something to do to make it work ?
Thanks
While Oracle SQL doesn't (yet?) support the standard SQL BOOLEAN
type, JDBC does to some extent, mapping BOOLEAN
values to 1=TRUE
and 0=FALSE
. Unfortunately, this is currently not possible with the oracle-r2dbc driver. This fails:
System.out.println(
Flux.from(cf.create())
.flatMap(c -> c.createStatement("select ? from dual").bind(0, true).execute())
.flatMap(it -> it.map((r, m) -> r.get(0, Boolean.class)))
.collectList()
.block()
);
The exception being:
Exception in thread "main" oracle.r2dbc.impl.OracleR2dbcExceptions$OracleR2dbcException: [17004] [99999] Ungültiger Spaltentyp
at oracle.r2dbc.impl.OracleR2dbcExceptions.toR2dbcException(OracleR2dbcExceptions.java:215)
at oracle.r2dbc.impl.OracleR2dbcExceptions.runOrHandleSQLException(OracleR2dbcExceptions.java:247)
at oracle.r2dbc.impl.OracleStatementImpl.setInParameters(OracleStatementImpl.java:1144)
at oracle.r2dbc.impl.OracleStatementImpl.lambda$executeSql$2(OracleStatementImpl.java:674)
at oracle.r2dbc.impl.OracleStatementImpl.lambda$execute$37(OracleStatementImpl.java:1342)
at reactor.core.publisher.FluxUsingWhen.deriveFluxFromResource(FluxUsingWhen.java:119)
at reactor.core.publisher.FluxUsingWhen.subscribe(FluxUsingWhen.java:85)
at reactor.core.publisher.Flux.subscribe(Flux.java:8185)
at reactor.core.publisher.FluxUsingWhen.subscribe(FluxUsingWhen.java:93)
at reactor.core.publisher.FluxDefer.subscribe(FluxDefer.java:54)
at reactor.core.publisher.Flux.subscribe(Flux.java:8185)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onNext(FluxFlatMap.java:426)
at org.jooq.test.setup.DatabaseSetup$1.lambda$2(DatabaseSetup.java:283)
at org.jooq.impl.Internal$1.onNext(Internal.java:433)
at reactor.core.publisher.StrictSubscriber.onNext(StrictSubscriber.java:89)
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:120)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
at org.reactivestreams.FlowAdapters$FlowToReactiveSubscriber.onNext(FlowAdapters.java:218)
at oracle.jdbc.datasource.impl.OracleDataSource$ConnectionPublisher$ConnectionSubscription.emitConnection(OracleDataSource.java:2746)
at oracle.jdbc.datasource.impl.OracleDataSource$ConnectionPublisher$ConnectionSubscription.lambda$publishConnectionAsync$0(OracleDataSource.java:2733)
at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863)
at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:841)
at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
at java.base/java.util.concurrent.CompletableFuture.postFire(CompletableFuture.java:614)
at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:844)
at java.base/java.util.concurrent.CompletableFuture$Completion.run(CompletableFuture.java:482)
at oracle.jdbc.driver.PhysicalConnection.lambda$createUserCodeExecutor$10(PhysicalConnection.java:11713)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at oracle.jdbc.driver.PhysicalConnection.lambda$createUserCodeExecutor$11(PhysicalConnection.java:11711)
at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1395)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1176)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1647)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1614)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
Suppressed: java.lang.Exception: #block terminated with an error
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:99)
at reactor.core.publisher.Mono.block(Mono.java:1703)
at org.jooq.testscripts.R2DBC.main(R2DBC.java:42)
Caused by: java.sql.SQLException: Ungültiger Spaltentyp
at oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:8722)
at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:8204)
at oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:8173)
at oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:12300)
at oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:12249)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:1230)
at oracle.r2dbc.impl.OracleStatementImpl.lambda$setInParameters$29(OracleStatementImpl.java:1145)
at oracle.r2dbc.impl.OracleR2dbcExceptions.runOrHandleSQLException(OracleR2dbcExceptions.java:244)
... 35 more
Binding a NULL
value also fails:
System.out.println(
Flux.from(cf.create())
.flatMap(c -> c.createStatement("select ? from dual").bindNull(0, Boolean.class).execute())
.flatMap(it -> it.map((r, m) -> r.get(0, Boolean.class)))
.collectList()
.block()
);
... with a slightly different stack trace
Exception in thread "main" oracle.r2dbc.impl.OracleR2dbcExceptions$OracleR2dbcException: [17004] [99999] Ungültiger Spaltentyp: 16
at oracle.r2dbc.impl.OracleR2dbcExceptions.toR2dbcException(OracleR2dbcExceptions.java:215)
at oracle.r2dbc.impl.OracleR2dbcExceptions.runOrHandleSQLException(OracleR2dbcExceptions.java:247)
at oracle.r2dbc.impl.OracleStatementImpl.setInParameters(OracleStatementImpl.java:1144)
at oracle.r2dbc.impl.OracleStatementImpl.lambda$executeSql$2(OracleStatementImpl.java:674)
at oracle.r2dbc.impl.OracleStatementImpl.lambda$execute$37(OracleStatementImpl.java:1342)
at reactor.core.publisher.FluxUsingWhen.deriveFluxFromResource(FluxUsingWhen.java:119)
at reactor.core.publisher.FluxUsingWhen.subscribe(FluxUsingWhen.java:85)
at reactor.core.publisher.Flux.subscribe(Flux.java:8185)
at reactor.core.publisher.FluxUsingWhen.subscribe(FluxUsingWhen.java:93)
at reactor.core.publisher.FluxDefer.subscribe(FluxDefer.java:54)
at reactor.core.publisher.Flux.subscribe(Flux.java:8185)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onNext(FluxFlatMap.java:426)
at org.jooq.test.setup.DatabaseSetup$1.lambda$2(DatabaseSetup.java:283)
at org.jooq.impl.Internal$1.onNext(Internal.java:433)
at reactor.core.publisher.StrictSubscriber.onNext(StrictSubscriber.java:89)
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:120)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
at org.reactivestreams.FlowAdapters$FlowToReactiveSubscriber.onNext(FlowAdapters.java:218)
at oracle.jdbc.datasource.impl.OracleDataSource$ConnectionPublisher$ConnectionSubscription.emitConnection(OracleDataSource.java:2746)
at oracle.jdbc.datasource.impl.OracleDataSource$ConnectionPublisher$ConnectionSubscription.lambda$publishConnectionAsync$0(OracleDataSource.java:2733)
at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863)
at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:841)
at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
at java.base/java.util.concurrent.CompletableFuture.postFire(CompletableFuture.java:614)
at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:844)
at java.base/java.util.concurrent.CompletableFuture$Completion.run(CompletableFuture.java:482)
at oracle.jdbc.driver.PhysicalConnection.lambda$createUserCodeExecutor$10(PhysicalConnection.java:11713)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at oracle.jdbc.driver.PhysicalConnection.lambda$createUserCodeExecutor$11(PhysicalConnection.java:11711)
at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1395)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1176)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1647)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1614)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
Suppressed: java.lang.Exception: #block terminated with an error
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:99)
at reactor.core.publisher.Mono.block(Mono.java:1703)
at org.jooq.testscripts.R2DBC.main(R2DBC.java:42)
Caused by: java.sql.SQLException: Ungültiger Spaltentyp: 16
at oracle.jdbc.driver.OracleStatement.getInternalType(OracleStatement.java:4822)
at oracle.jdbc.driver.OraclePreparedStatement.setNullCritical(OraclePreparedStatement.java:4564)
at oracle.jdbc.driver.OraclePreparedStatement.setNullInternal(OraclePreparedStatement.java:4437)
at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:8190)
at oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:8173)
at oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:12268)
at oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:12249)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:1230)
at oracle.r2dbc.impl.OracleStatementImpl.lambda$setInParameters$29(OracleStatementImpl.java:1145)
at oracle.r2dbc.impl.OracleR2dbcExceptions.runOrHandleSQLException(OracleR2dbcExceptions.java:244)
... 35 more
Binding an int
works:
System.out.println(
Flux.from(cf.create())
.flatMap(c -> c.createStatement("select ? from dual").bind(0, 1).execute())
.flatMap(it -> it.map((r, m) -> r.get(0, Boolean.class)))
.collectList()
.block()
);
System.out.println(
Flux.from(cf.create())
.flatMap(c -> c.createStatement("select ? from dual").bindNull(0, Integer.class).execute())
.flatMap(it -> it.map((r, m) -> Optional.ofNullable(r.get(0, Boolean.class))))
.collectList()
.block()
);
Producing
[true]
[Optional.empty]
Notice how I can read a Boolean.class
from a Row
, but I can't bind it to the Statement
. Given that ojdbc implements java.sql.Statement.setBoolean()
, I think this is a bug or oversight.
I'm trying to use this driver with spring-boot-data-r2dbc (v2.4.4), but when I configure the connection factory to use the connection pool like this:
return ConnectionFactories.get(ConnectionFactoryOptions.builder()
.option(ConnectionFactoryOptions.DRIVER, "pool")
.option(ConnectionFactoryOptions.PROTOCOL, "oracle")
.option(ConnectionFactoryOptions.HOST, "127.0.0.1")
.option(ConnectionFactoryOptions.PORT, 1521)
.option(ConnectionFactoryOptions.DATABASE, "XE")
.option(ConnectionFactoryOptions.USER, "APP_USER")
.option(ConnectionFactoryOptions.PASSWORD, "********************")
.option(Option.valueOf(OracleConnection.CONNECTION_PROPERTY_FAN_ENABLED), "false")
.build());
With this settings:
application.yaml
spring:
r2dbc:
pool:
initialSize: 10
maxSize: 50
Around 80% of my application requests ends with the following error:
java.lang.IllegalStateException: This publisher does not support multiple subscribers.
at oracle.jdbc.datasource.impl.OracleDataSource$ConnectionPublisher.rejectSubscriber(OracleDataSource.java:2676) ~[ojdbc11-21.1.0.0.jar:21.1.0.0.0]
at oracle.jdbc.datasource.impl.OracleDataSource$ConnectionPublisher.subscribe(OracleDataSource.java:2655) ~[ojdbc11-21.1.0.0.jar:21.1.0.0.0]
at org.reactivestreams.FlowAdapters$ReactivePublisherFromFlow.subscribe(FlowAdapters.java:355) ~[reactive-streams-1.0.3.jar:na]
at oracle.r2dbc.impl.OracleReactiveJdbcAdapter.lambda$deferOnce$22(OracleReactiveJdbcAdapter.java:1071) ~[oracle-r2dbc-0.1.0.jar:0.1.0]
at oracle.r2dbc.impl.OracleReactiveJdbcAdapter$$Lambda$1775/00000000C46540E0.accept(Unknown Source) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.uniAcceptNow(CompletableFuture.java:753) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.uniAcceptStage(CompletableFuture.java:731) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.thenAccept(CompletableFuture.java:2172) ~[na:na]
at oracle.r2dbc.impl.OracleReactiveJdbcAdapter.lambda$deferOnce$23(OracleReactiveJdbcAdapter.java:1070) ~[oracle-r2dbc-0.1.0.jar:0.1.0]
at oracle.r2dbc.impl.OracleReactiveJdbcAdapter$$Lambda$595/0000000039BC68E0.subscribe(Unknown Source) ~[na:na]
at reactor.core.publisher.FluxSource.subscribe(FluxSource.java:66) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.Mono.subscribe(Mono.java:4099) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxConcatArray$ConcatArraySubscriber.onComplete(FluxConcatArray.java:208) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxConcatArray.subscribe(FluxConcatArray.java:80) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.Flux.subscribe(Flux.java:8185) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.Flux.subscribeWith(Flux.java:8358) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.Flux.subscribe(Flux.java:8155) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.Flux.subscribe(Flux.java:8079) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.pool.SimpleDequePool.drainLoop(SimpleDequePool.java:404) ~[reactor-pool-0.2.3.jar:0.2.3]
at reactor.pool.SimpleDequePool.pendingOffer(SimpleDequePool.java:521) ~[reactor-pool-0.2.3.jar:0.2.3]
at reactor.pool.SimpleDequePool.doAcquire(SimpleDequePool.java:254) ~[reactor-pool-0.2.3.jar:0.2.3]
at reactor.pool.AbstractPool$Borrower.request(AbstractPool.java:382) ~[reactor-pool-0.2.3.jar:0.2.3]
at reactor.core.publisher.FluxPeek$PeekSubscriber.request(FluxPeek.java:137) ~[reactor-core-3.4.4.jar:3.4.4]
at org.springframework.cloud.sleuth.instrument.reactor.ScopePassingSpanSubscriber.request(ScopePassingSpanSubscriber.java:74) ~[spring-cloud-sleuth-instrumentation-3.0.0.jar:3.0.0]
at reactor.core.publisher.FluxPeek$PeekSubscriber.request(FluxPeek.java:137) ~[reactor-core-3.4.4.jar:3.4.4]
at org.springframework.cloud.sleuth.instrument.reactor.ScopePassingSpanSubscriber.request(ScopePassingSpanSubscriber.java:74) ~[spring-cloud-sleuth-instrumentation-3.0.0.jar:3.0.0]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:110) ~[reactor-core-3.4.4.jar:3.4.4]
at org.springframework.cloud.sleuth.instrument.reactor.ScopePassingSpanSubscriber.onSubscribe(ScopePassingSpanSubscriber.java:67) ~[spring-cloud-sleuth-instrumentation-3.0.0.jar:3.0.0]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onSubscribe(FluxPeek.java:170) ~[reactor-core-3.4.4.jar:3.4.4]
at org.springframework.cloud.sleuth.instrument.reactor.ScopePassingSpanSubscriber.onSubscribe(ScopePassingSpanSubscriber.java:67) ~[spring-cloud-sleuth-instrumentation-3.0.0.jar:3.0.0]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onSubscribe(FluxPeek.java:170) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.pool.SimpleDequePool$QueueBorrowerMono.subscribe(SimpleDequePool.java:632) ~[reactor-pool-0.2.3.jar:0.2.3]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxRetry$RetrySubscriber.resubscribe(FluxRetry.java:116) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.MonoRetry.subscribeOrReturn(MonoRetry.java:49) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.Mono.subscribe(Mono.java:4084) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:103) ~[reactor-core-3.4.4.jar:3.4.4]
at org.springframework.cloud.sleuth.instrument.reactor.ScopePassingSpanSubscriber.onError(ScopePassingSpanSubscriber.java:95) ~[spring-cloud-sleuth-instrumentation-3.0.0.jar:3.0.0]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onError(MonoFlatMap.java:172) ~[reactor-core-3.4.4.jar:3.4.4]
at org.springframework.cloud.sleuth.instrument.reactor.ScopePassingSpanSubscriber.onError(ScopePassingSpanSubscriber.java:95) ~[spring-cloud-sleuth-instrumentation-3.0.0.jar:3.0.0]
at reactor.core.publisher.FluxMap$MapSubscriber.onError(FluxMap.java:132) ~[reactor-core-3.4.4.jar:3.4.4]
at org.springframework.cloud.sleuth.instrument.reactor.ScopePassingSpanSubscriber.onError(ScopePassingSpanSubscriber.java:95) ~[spring-cloud-sleuth-instrumentation-3.0.0.jar:3.0.0]
at reactor.core.publisher.Operators.error(Operators.java:197) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.MonoError.subscribe(MonoError.java:52) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.Mono.subscribe(Mono.java:4099) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxUsingWhen.subscribe(FluxUsingWhen.java:103) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.Mono.subscribe(Mono.java:4099) ~[reactor-core-3.4.4.jar:3.4.4]
at kotlinx.coroutines.reactive.AwaitKt.awaitOne(Await.kt:137) ~[kotlinx-coroutines-reactive-1.4.3.jar:na]
at kotlinx.coroutines.reactive.AwaitKt.awaitOne$default(Await.kt:135) ~[kotlinx-coroutines-reactive-1.4.3.jar:na]
at kotlinx.coroutines.reactive.AwaitKt.awaitFirst(Await.kt:26) ~[kotlinx-coroutines-reactive-1.4.3.jar:na]
Without the connection pool, everything runs fine, but with a low throughput. Am I missing any configuration or is this a known limitation?
We need a way to set the v$session.program at the connection from a R2DBC Oracle connection and after reviewing documentation and stack overflow I haven't found a way to do it
(my case is within a Spring application, but I believe this to be irrelevant)
We've added an issue at StackOverflow without answers: https://stackoverflow.com/questions/72048278/specify-vsession-program-for-r2dbc-oracle-connection
We've tried some solutions including this but without success.
ConnectionFactories.get( ConnectionFactoryOptions.parse(dbUrl) .mutate() .option(Option.valueOf("v$session.program"), "PROGRAMNAME") .build());
After reviewing the driver source code, it seems the property would need to be supported at the OracleReactiveJdbcAdapter::JDBC_CONNECTION_PROPERTY_OPTIONS Set
but any other way to achieve the same goal would be useful.
If this is already possible please excuse me, but I haven't found one.
oracle-r2dbc version: 0.2.0
spring-boot: 2.5.2
Database: Oracle 19c
r2dbc:oracle:thin:@LDAP://server:port/database,cn=OracleContext,dc=WORLD
Error:
reactor.core.Exceptions$ErrorCallbackNotImplemented: io.r2dbc.spi.R2dbcTransientResourceException: [17002] [08006] Error de E/S: Invalid connection string format, a valid format is: "host:port:sid" (CONNECTION_ID=qyq8AuNhQreSmex/HBjgiA==)
Caused by: io.r2dbc.spi.R2dbcTransientResourceException: Error de E/S: Invalid connection string format, a valid format is: "host:port:sid" (CONNECTION_ID=qyq8AuNhQreSmex/HBjgiA==)
at oracle.r2dbc.impl.OracleR2dbcExceptions.toR2dbcException(OracleR2dbcExceptions.java:211)
at oracle.r2dbc.impl.OracleReactiveJdbcAdapter$$Lambda$1262/00000000A3888C30.apply(Unknown Source)
at reactor.core.publisher.Flux.lambda$onErrorMap$29(Flux.java:6720)
at reactor.core.publisher.Flux$$Lambda$1264/000000008D4CE270.apply(Unknown Source)
code for test:
ConnectionFactory connectionFactory = ConnectionFactories.get(
"r2dbc:oracle:thin:@ldap://server:port/database,cn=OracleContext,dc=WORLD");
Mono.from(connectionFactory.create())
.flatMapMany(connection ->
Flux.from(connection.createStatement(
"SELECT 'Hello, Oracle' FROM sys.dual")
.execute())
.flatMap(result ->
result.map((row, metadata) -> row.get(0, String.class)))
.doOnNext(System.out::println)
.thenMany(connection.close()))
.subscribe();
thanks
Hi,
Although the existing previous issues but I feel confused about what to do. So In this issue I will summarize what I am facing.
Development environment: Spring, R2DBC, Oracle DB
Versions: spring boot --> 2.7.0 , Oracle R2DBC --> 0.4.0
Task Objective: reading a specific entity from the db with its related entities using a customized written sql statement to make one single DB query for all data.
The repository code that retrieves the data:
@repository public class MyCustomRepository { private static final String query ="..."; private final DatabaseClient databaseClient; //org.springframework.r2dbc.core.DatabaseClient this.databaseClient.sql(query) // .bind("fName", fName) // .bind("lName", lName) // .fetch().all() // s .bufferUntilChanged(person -> person.get("id")) // .map(.......) }
Observations:
previous observation: primarily, I got the error "Failed to obtain R2DBC, this publisher does not support multiple subscribers", even if I specify the version of oracle-r2db, r2dbc-spi and r2dbc-pool explicitly to be
<oracle-r2dbc.version>0.2.0</oracle-r2dbc.version> <r2dbc-spi.version>0.9.0.M1</r2dbc-spi.version> <r2dbc-pool.version>0.9.0.M1</r2dbc-pool.version>
current observation: java.lang.UnsupportedOperationException: This method is deprecated for removal getColumnNames().
Based on the previous observation, I tried two different solutions:
I think this method is called in bufferUntilChanged(), so execluding it exciplicitly is not possible. The method bufferUntilChanged() helps me to aggregate each person entity with its related entities in map().
Questions:
Sorry for the long description but as I am new to the thema I wanted o make sure to pull all the info. as much as spossible
Is there support for list in bind method?
I'm trying to perform a query with an "IN (list of numbers)" clause and an exception is thrown
java.lang.IllegalArgumentException: Unsupported Java type:class java.util.ArrayList
at oracle.r2dbc.impl.OracleStatementImpl.requireSupportedJavaType(OracleStatementImpl.java:1554) ~[oracle-r2dbc-0.3.0.jar:0.3.0]
I'm using the following artifact and I would like to open an issue related to it:
com.oracle.database.jdbc
ojdbc8
21.4.0.0.1
The Result object for DML operations that update zero rows returns an empty Publisher. The expected behavior is to return a Publisher that emits a single Integer value of 0.
I come to you because I am stuck with my Jhipster Spring Boot application,
which uses the oracle-r2dbc dependency, when I try to uses my Oracle dependency
My JHipster application also contains the dependency spring-boot-starter-data-r2dbc version 2.6.3 which contains spring-data-r2dbc v1.4.1, r2dbc-spi v0.8.6.RELEASE (which contains oracle-r2dbc version 0.1.0) and r2dbc-pool v0.8.8.RELEASE.
My Oracle Database version is Oracle Database 21c Express Edition Release 21.0.0.0.0 - Production
In my case I have no problem at startup time, liquibase scripts work well, but when calling database from R2dbc api.
Thanks a lot in advance
The following sections give more details about my application, my configuration files, the code that provoke the error and the error stack trace.
I have multiple maven profiles. One is called "dev" and it uses embeded H2 database. Everything works fine with it. I created a new maven Profile called 'local' in order to connect to my local Oracle Database. No problem at startutp and new tables located in liquibase changelog files are properly created with data in my Oracle database without any errors. Oracle version: Oracle Database 21c Express Edition Release 21.0.0.0.0 - Production
But If i call one of my apis that need to execute some queries then an error is raised with Oracle. Although it works fine when using h2 database. Do you know how I could resolve this problem ?
Below are listed the details of the error and some relevant parts of my configuration files.
Thanks a lot in advance
In my controller class
@GetMapping("/authorities")
public Mono<List<String>> getAuthorities() {
return userService.getAuthorities().collectList();
}
In my service class
@Transactional(readOnly = true)
public Flux<String> getAuthorities() {
return authorityRepository.findAll().map(Authority::getName);
}
java.lang.NoSuchMethodError: 'java.util.concurrent.Flow$Publisher oracle.jdbc.OracleConnectionBuilder.buildConnectionPublisherOracle()'
at oracle.r2dbc.impl.OracleReactiveJdbcAdapter.lambda$publishConnection$8(OracleReactiveJdbcAdapter.java:643)
at oracle.r2dbc.impl.OracleR2dbcExceptions.getOrHandleSQLException(OracleR2dbcExceptions.java:267)
at oracle.r2dbc.impl.OracleReactiveJdbcAdapter.lambda$deferOnce$23(OracleReactiveJdbcAdapter.java:1060)
at reactor.core.publisher.FluxSource.subscribe(FluxSource.java:67)
at reactor.core.publisher.Mono.subscribe(Mono.java:4400)
at reactor.core.publisher.FluxConcatArray$ConcatArraySubscriber.onComplete(FluxConcatArray.java:258)
at reactor.core.publisher.FluxConcatArray.subscribe(FluxConcatArray.java:78)
at reactor.core.publisher.Flux.subscribe(Flux.java:8469)
at reactor.core.publisher.Flux.subscribeWith(Flux.java:8642)
at reactor.core.publisher.Flux.subscribe(Flux.java:8439)
at reactor.core.publisher.Flux.subscribe(Flux.java:8363)
at reactor.pool.SimpleDequePool.drainLoop(SimpleDequePool.java:423)
at reactor.pool.SimpleDequePool.pendingOffer(SimpleDequePool.java:558)
at reactor.pool.SimpleDequePool.doAcquire(SimpleDequePool.java:268)
at reactor.pool.AbstractPool$Borrower.request(AbstractPool.java:432)
Here are some configurations files that might be important:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-r2dbc</artifactId> <!-- version 2.6.3 -->
</dependency>
...
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-h2</artifactId>
</dependency>
</dependencies>
</profile>
<profile>
<id>local</id>
<dependencies>
<!-- database oracles -->
<dependency>
<groupId>com.oracle.database.r2dbc</groupId>
<artifactId>oracle-r2dbc</artifactId> <!-- version 0.1.0 -->
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<configuration>
<filesets>
<fileset>
<directory>target/classes/static/</directory>
</fileset>
</filesets>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>io.github.git-commit-id</groupId>
<artifactId>git-commit-id-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<properties>
<!-- default Spring profiles -->
<spring.profiles.active>local${profile.api-docs}${profile.tls}</spring.profiles.active>
</properties>
</profile>
liquibase:
contexts: local, faker
url: jdbc:oracle:thin:@localhost:1521/xe
mail:
host: localhost
port: 25
username:
password:
r2dbc:
url: r2dbc:oracle:thin://localhost:1521/xe
username: MY_CREDIT
password: MY_CREDIT
I tried to change the r2dbc url to r2dbc:oracle:thin://localhost:1521:xe (: at the end) but it doesn't change anything. I also tried to add other dependencies in the pom like the one below, but no differences:
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>21.1.0.0</version>
</dependency>
<dependency>
<groupId>com.oracle.database.ha</groupId>
<artifactId>ons</artifactId>
<version>21.1.0.0</version>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ucp</artifactId>
<version>21.1.0.0</version>
</dependency>
It seems that using a named parameter multiple times isn't working properly.
Consider the following statement:
SELECT id, name, manual FROM legoset WHERE name = :P0_name or name = :P0_name
Trying to run the statement with:
Mono.from(connectionFactory.create())
.flatMapMany(it -> {
return it.createStatement("SELECT id, name, manual FROM legoset WHERE name = :P0_name or name = :P0_name")
.bind("P0_name", "unknown")
.execute();
}).flatMap(it -> it.map((row, rowMetadata) -> row.get(0))).blockLast();
fails with:
java.lang.IllegalStateException: One or more parameters are not set
at oracle.r2dbc.impl.OracleStatementImpl.requireAllParametersSet(OracleStatementImpl.java:790)
at oracle.r2dbc.impl.OracleStatementImpl.add(OracleStatementImpl.java:341)
at oracle.r2dbc.impl.OracleStatementImpl.execute(OracleStatementImpl.java:458)
Running the statement as SELECT id, name, manual FROM legoset WHERE name = :P0_name
works fine.
Getting error as java.long.NosSuchFieldError : LOCK_WAIT_TIMEOUT exception..
I get the error below
Caused by: Error : 1401, Position : 14, Sql = '' Error Msg = ORA-01401: inserted value too large for column
when I have a large string in my where clause.
error:
Caused by: java.lang.NoSuchFieldError: LOCK_WAIT_TIMEOUT
at oracle.r2dbc.impl.OracleConnectionFactoryImpl.(OracleConnectionFactoryImpl.java:186) ~[oracle-r2dbc-1.0.0.jar:1.0.0]
at oracle.r2dbc.impl.OracleConnectionFactoryProviderImpl.create(OracleConnectionFactoryProviderImpl.java:99) ~[oracle-r2dbc-1.0.0.jar:1.0.0]
at io.r2dbc.spi.ConnectionFactories.find(ConnectionFactories.java:112) ~[r2dbc-spi-0.8.3.RELEASE.jar:na]
at io.r2dbc.spi.ConnectionFactories.get(ConnectionFactories.java:142) ~[r2dbc-spi-0.8.3.RELEASE.jar:na]
at org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryBuilder.build(ConnectionFactoryBuilder.java:125) ~[spring-boot-autoconfigure-2.3.7.RELEASE.jar:2.3.7.RELEASE]
at org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryConfigurations.createConnectionFactory(ConnectionFactoryConfigurations.java:56) ~[spring-boot-autoconfigure-2.3.7.RELEASE.jar:2.3.7.RELEASE]
at org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryConfigurations$Pool.connectionFactory(ConnectionFactoryConfigurations.java:68) ~[spring-boot-autoconfigure-2.3.7.RELEASE.jar:2.3.7.RELEASE]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:577) ~[na:na]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.2.12.RELEASE.jar:5.2.12.RELEASE]
... 68 common frames omitted
config:
spring.application.name=test-r2dbc
#spring.r2dbc.url=r2dbc:oracle:thin://10.19.1.208:1521:szwz
spring.r2dbc.url=r2dbc:oracle:thin://localhost:1521:orcl
#spring.r2dbc.url=r2dbc:mysql://localhost:3306/test?ssl=false
spring.r2dbc.username=***
spring.r2dbc.password=***
spring.r2dbc.pool.max-size=100
spring.r2dbc.pool.max-idle-time=2m
spring.r2dbc.pool.initial-size=100
spring.r2dbc.pool.validation-query=select 1
I'm still working on some tests with this driver, and whenever I need to read a numeric value from result set and cast it to Int like below:
return r2dbcTemplate
.databaseClient
.sql("select count(1) as total_orders from orders")
.fetch()
.one()
.flatMap { row ->
Mono.just(row["total_orders"] as Int)
}
I'm getting this error:
java.lang.ClassCastException: class java.math.BigDecimal cannot be cast to class java.lang.Integer (java.math.BigDecimal and java.lang.Integer are in module java.base of loader 'bootstrap')
...
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:125) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.tryEmitScalar(FluxFlatMap.java:488) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onNext(FluxFlatMap.java:421) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.FluxBuffer$BufferExactSubscriber.onComplete(FluxBuffer.java:185) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2057) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.FluxUsingWhen$UsingWhenSubscriber.deferredComplete(FluxUsingWhen.java:405) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.FluxUsingWhen$CommitInner.onComplete(FluxUsingWhen.java:540) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2057) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:259) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2057) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.Operators$MonoSubscriber.onComplete(Operators.java:1857) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.MonoIgnoreThen$ThenAcceptInner.onComplete(MonoIgnoreThen.java:323) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.Operators$MonoSubscriber.onComplete(Operators.java:1857) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.MonoIgnoreThen$ThenAcceptInner.onComplete(MonoIgnoreThen.java:323) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.pool.SimpleDequePool$QueuePoolRecyclerInner.onComplete(SimpleDequePool.java:678) ~[reactor-pool-0.2.3.jar!/:0.2.3]
at reactor.core.publisher.Operators.complete(Operators.java:136) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.MonoEmpty.subscribe(MonoEmpty.java:45) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.Mono.subscribe(Mono.java:4099) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.pool.SimpleDequePool$QueuePoolRecyclerMono.subscribe(SimpleDequePool.java:790) ~[reactor-pool-0.2.3.jar!/:0.2.3]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:154) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:56) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:154) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:56) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.Mono.subscribe(Mono.java:4099) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:103) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.MonoIgnoreElements$IgnoreElementsSubscriber.onError(MonoIgnoreElements.java:83) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.FluxMap$MapSubscriber.onError(FluxMap.java:132) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.FluxFilter$FilterSubscriber.onError(FluxFilter.java:157) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.FluxFilter$FilterConditionalSubscriber.onError(FluxFilter.java:291) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.FluxMap$MapConditionalSubscriber.onError(FluxMap.java:259) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.Operators.error(Operators.java:197) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.MonoError.subscribe(MonoError.java:52) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.Mono.subscribe(Mono.java:4099) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.FluxUsingWhen$UsingWhenSubscriber.onComplete(FluxUsingWhen.java:397) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.checkTerminated(FluxFlatMap.java:846) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.drainLoop(FluxFlatMap.java:608) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.innerComplete(FluxFlatMap.java:894) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.FluxFlatMap$FlatMapInner.onComplete(FluxFlatMap.java:997) ~[reactor-core-3.4.4.jar!/:3.4.4]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2057) ~[reactor-core-3.4.4.jar!/:3.4.4]
at org.reactivestreams.FlowAdapters$FlowToReactiveSubscriber.onComplete(FlowAdapters.java:228) ~[reactive-streams-1.0.3.jar!/:na]
at oracle.jdbc.driver.PhasedPublisher$PhasedSubscription.emitComplete(PhasedPublisher.java:434) ~[ojdbc11-21.1.0.0.jar!/:21.1.0.0.0]
at oracle.jdbc.driver.PhasedPublisher.lambda$subscribe$3(PhasedPublisher.java:343) ~[ojdbc11-21.1.0.0.jar!/:21.1.0.0.0]
at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:859) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:837) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture$Completion.run(CompletableFuture.java:478) ~[na:na]
at oracle.jdbc.driver.PhysicalConnection.lambda$createUserCodeExecutor$10(PhysicalConnection.java:11713) ~[ojdbc11-21.1.0.0.jar!/:21.1.0.0.0]
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391) ~[na:na]
at oracle.jdbc.driver.PhysicalConnection.lambda$createUserCodeExecutor$11(PhysicalConnection.java:11711) ~[ojdbc11-21.1.0.0.jar!/:21.1.0.0.0]
at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1429) ~[na:na]
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290) ~[na:na]
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1016) ~[na:na]
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1665) ~[na:na]
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1598) ~[na:na]
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183) ~[na:na]
Off course, it is possible to use BigDecimal for any numeric value (and then converting it to Int/Long, etc), but I don't know if this is some compatibility error between spring/ojdbc11/oracle-r2dbc, or something expected at this moment.
Are other numeric types (besides BigDecimal) supported already?
A failure similar to the following is reported during test runs:
[INFO] Running oracle.r2dbc.impl.TypeMappingTest
[ERROR] Tests run: 6, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 3.482 s <<< FAILURE! - in oracle.r2dbc.impl.TypeMappingTest
[ERROR] oracle.r2dbc.impl.TypeMappingTest.testDatetimeTypeMappings Time elapsed: 0.43 s <<< FAILURE!
org.opentest4j.AssertionFailedError: expected: <2038-10-23T09:42:01.000000001> but was: <2038-10-23T16:42:01.000000001>
at [email protected]/oracle.r2dbc.impl.TypeMappingTest.verifyTypeMapping(TypeMappingTest.java:458)
at [email protected]/oracle.r2dbc.impl.TypeMappingTest.verifyTypeMapping(TypeMappingTest.java:415)
at [email protected]/oracle.r2dbc.impl.TypeMappingTest.testDatetimeTypeMappings(TypeMappingTest.java:308)
Not supporting BLOB/CLOB to ByteBuffer/String mapping is a known limitation of Oracle R2DBC. Only io.r2dbc.spi.Blob/Clob mapping is supported. This is noted in the documentation, but the reasoning is not explained in depth. So I’d like to share the full extent of my thoughts on this, and see if we can get to a better solution.
When a query returns a LOB value, Oracle Database returns a locator for that value. For the purpose of this discussion, we can think of the locator as a pointer to the actual value. To get the actual value into a buffer, a database driver makes another database call requesting to read the value which a locator points to.
Although the LOB read requires a database call, Oracle R2DBC could still support the ByteBuffer mapping without Row.get(int/String, ByteBuffer.class) having to make a blocking database call. Before emitting the Row to the mapping function, the driver could execute non-blocking database calls to read the LOB content into a buffer. After the content had been buffered, then the Row can be input to the mapping function and the ByteBuffer would be ready to go.
Of course, if the LOB exceeded 2GB, then it would not fit into a ByteBuffer and the driver would need to handle that. But we can ignore this case for the moment, as it doesn't completely prevent Oracle R2DBC from supporting the ByteBuffer mapping.
So, pre-buffering the LOB content is one option to consider. However, this approach seems to devalue the case where user code wants to use io.r2dbc.spi.Blob. Rather than have Blob.stream() respond to backpressure from a Subscriber, the stream() implementation has decided to allocate memory for the entire content of the LOB before a Subscriber has even subscribed.
On the other hand, if Oracle R2DBC only supports the io.r2dbc.spi.Blob mapping, and user code want to map that into a ByteBuffer, it still has the freedom to implement that mapping. If the user code knows that the BLOB value won’t exhaust memory, or exceed the 2GB ByteBuffer capacity, then it can map the BLOB into a ByteBuffer like this:
Flux.usingWhen(ConnectionFactories.get(
"r2dbc:oracle://test:test@localhost:1521/xepdb1")
.create(),
connection ->
Flux.from(connection.createStatement("DROP TABLE BlobTest")
.execute())
.flatMap(Result::getRowsUpdated)
.onErrorResume(throwable ->
// If the table doesn't exist, don't emit ORA-00942
(throwable instanceof R2dbcException)
&& ((R2dbcException)throwable).getErrorCode() == 942,
throwable -> Mono.empty())
.thenMany(connection.createStatement(
"CREATE TABLE BlobTest (value BLOB)")
.execute())
.flatMap(Result::getRowsUpdated)
.thenMany(connection.createStatement(
"INSERT INTO BlobTest VALUES(?)")
.bind(0, ByteBuffer.wrap(new byte[128_000]))
.execute())
.flatMap(Result::getRowsUpdated)
.thenMany(connection.createStatement(
"SELECT value FROM BlobTest")
.execute())
.flatMap(result ->
result.map((row, metadata) -> row.get(0, Blob.class)))
.flatMap(blob ->
Flux.from(blob.stream())
.reduce(ByteBuffer.allocate(8192),
(buffer, next) -> {
// Ensure capacity for all remaining bytes in the next buffer.
if (buffer.remaining() < next.remaining()) {
ByteBuffer newBuffer = ByteBuffer.allocate(Math.max(
buffer.capacity()
+ (next.remaining() - buffer.remaining()),
buffer.capacity() << 1));
buffer = newBuffer.put(buffer.flip());
}
buffer.put(next);
return buffer;
})),
Connection::close)
.toStream()
.map(ByteBuffer::flip)
.forEach(System.out::println);
As shown above, the ability for user code to implement a Blob to ByteBuffer mapping is what ultimately lead to the decision for Oracle R2DBC to only support Blob mapping. With Blob, user code still has the option to map it into a ByteBuffer if wants to, but user code can also choose to process the Blob as a stream of smaller buffers if it wants to do that instead.
So far, we’ve only considered solutions that represent two extremes. Either: A) Buffer everything, or B) Buffer nothing. Option C might look like this:
I find the solution described above to be problematic because the cases where errors and blocking database calls occur seem like like pitfalls that are easy to miss. It seems too likely that a system would be verified by tests that miss the case where a LOB exceeds 2GB, and then fail in production when the >2GB case occurs. And for blocking database calls, that’s really hard to detect unless you have something like Java Mission control to measure socket read time.
Although having to implement a ByteBuffer mapping with something like the reduce operator above puts some burden on user code, it seemed like a better alternative than to introduce the pitfalls I’ve described.
Of course, it would be excellent if Oracle R2DBC could support the ByteBuffer mapping. I’m happy to discuss new solutions with anyone that wants to explore this further.
As asked here: https://stackoverflow.com/questions/73061887/how-to-specify-parameter-type-in-r2dbc-when-using-stored-procedures
Parameters.out
seems to call JDBCs registerOutputParameters
within it, but it seems to pass only the binding index and the type (I want to pass the type name too).
Quote from the readme: "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."
Is there any plan for implementing this feature for DELETE commands? To support such statement:
"DELETE cars RETURNING listagg(distinct cars.registration_number, ',') INTO :registration_numbers;"
I'm hitting a lot of errors trying to upgrade the dependency to 0.2 in Micronaut R2dbc integration
NUMBER(3)
and it used to work, now it fails because every boolean is expected to be BOOLEAN
type which we don't have in version 18, the only one available officially at https://hub.docker.com/r/gvenzl/oracle-xebyte[]
type is not supported anymore and ByteBuffer
is the only one supported@neibarbosa Thanks for sharing this. Providing a code sample and details about how to recreate the issue is very much appreciated!
I think that you are testing with the 0.1.0 version of Oracle R2DBC. Is this correct?
The 0.1.0 release did not integrate with r2dbc-pool for the reason you have noticed: The Publisher returned by ConnectionFactory.create() did not support multiple subscribers. The r2dbc-pool project expects the Publisher to support multiple subscribers.
In the 0.2.0 release, we fixed this so that multiple subscribers are now supported. With this fix, Oracle R2DBC should now work with r2dbc-pool. The pull request for that fix is here: #24
You might want to try testing with oracle-r2dbc:0.2.0 and r2dbc-pool:0.9.0.M1. These versions both support the 0.9.0.M1 R2DBC SPI.
Originally posted by @Michael-A-McMahon in #29 (comment)
I understand that I have to use oracle-r2dbc:0.2.0 and r2dbc-pool:0.9.0.M1 together. However I am using Spring and according to their README.md I cannot use oracle-r2dbc:0.2.0, but oracle-r2dbc:0.1.0. What version should I use to for these dependencies to use them with Spring? I've created a project for testing https://github.com/7Mircea/R2dbc_Oracle_Spring.
Hi, just wondering where support for transaction isolation levels other than READ COMMITED might be on the roadmap? Thanks.
Hi,
It has been unclear if there is Oracle database support for spring r2dbc. Is it active after Oracles odbc extention api?
When is the first lease planned ?
Oracle R2DBC uses the common ForkJoinPool (FJP) by default. For some systems, this is not ideal as the FJP threads may be abused with blocking or long running operations.
It would be valuable if Oracle R2DBC allowed a non-default Executor to be configured.
Right now, the ServiceLoader information is only activated when using the module path. It would be nice to not be required to use Java Modules to use the driver (i.e being able to use classpath mode).
HI team,
Getting this below error while connecting to remote oracle instance using r2dbc. attaching pom.xml
Failed to obtain R2DBC Connection; nested exception is io.r2dbc.spi.R2dbcTransientResourceException: [12514] [08006] Listener refused the connection with the following error: ORA-12514, TNS:listener does not currently know of service requested in connect descriptor (CONNECTION_ID=PzBG3pX8QteIbP4da43kpA==)
org.springframework.dao.DataAccessResourceFailureException: Failed to obtain R2DBC Connection; nested exception is io.r2dbc.spi.R2dbcTransientResourceException: [12514] [08006] Listener refused the connection with the following error:
ORA-12514, TNS:listener does not currently know of service requested in connect descriptor
(CONNECTION_ID=PzBG3pX8QteIbP4da43kpA==)
at org.springframework.r2dbc.connection.ConnectionFactoryUtils.lambda$getConnection$0(ConnectionFactoryUtils.java:88)
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
|_ checkpoint ⇢ Handler com.example.demo.StudentController#getAllTaskStateEnum() [DispatcherHandler]
|_ checkpoint ⇢ org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ HTTP GET "/students/getAllTaskStateEnum" [ExceptionHandlingWebHandler]
Stack trace:
at org.springframework.r2dbc.connection.ConnectionFactoryUtils.lambda$getConnection$0(ConnectionFactoryUtils.java:88)
at reactor.core.publisher.Mono.lambda$onErrorMap$31(Mono.java:3676)
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.6.0-M1
com.example
demo-2
0.0.1-SNAPSHOT
demo-2
Demo project for Spring Boot
<java.version>11</java.version>
org.springframework.boot
spring-boot-starter-actuator
org.springframework.boot
spring-boot-starter-data-r2dbc
org.springframework.boot
spring-boot-starter-webflux
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.oracle.database.r2dbc</groupId>
<artifactId>oracle-r2dbc</artifactId>
<version>0.2.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
Hello,
First, and completely out of scope for a github issue, I've enjoyed both parts of your Reactive Summit presentation.
This is a little bit of a drive-by comment because I am not an Oracle R2DBC driver user, but we've ran into similar scenarios when implementing the Cloud Spanner R2DBC driver. In OracleConnectionImpl
(for example when beginning a transaction), the validation of whether the connection is currently open happens in the beginning of the method, outside of the reactive stream creation. That can lead to the validation passing at the time the method is called (when the reactive stream operation chain is defined), but the connection becoming closed by the time the resulting publisher is subscribed to.
When trying to use with spring-boot-starter-data-r2dbc and enabled pool
I get the following exception
2021-06-16 23:08:35,144 [RMI TCP Connection(2)-100.64.118.0] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver [logKeyFound] [RMI TCP Connection(2)-100.64.118.0] [] : Found key 'local.server.port' in PropertySource 'server.ports' with value of type Integer
2021-06-16 23:08:35,377 [RMI TCP Connection(3)-100.64.118.0] DEBUG reactor.util.Loggers$Slf4JLogger [debug] [RMI TCP Connection(3)-100.64.118.0] [] : Obtaining new connection from the driver
2021-06-16 23:08:35,379 [RMI TCP Connection(3)-100.64.118.0] DEBUG reactor.util.Loggers$Slf4JLogger [debug] [RMI TCP Connection(3)-100.64.118.0] [] : should warm up 4 extra resources
2021-06-16 23:08:37,571 [ForkJoinPool.commonPool-worker-3] DEBUG reactor.util.Loggers$Slf4JLogger [debug] [ForkJoinPool.commonPool-worker-3] [] : Duplicate Subscription has been detected
java.lang.IllegalStateException: Spec. Rule 2.12 - Subscriber.onSubscribe MUST NOT be called more than once (based on object equality)
at reactor.core.Exceptions.duplicateOnSubscribeException(Exceptions.java:180)
at reactor.core.publisher.Operators.reportSubscriptionSet(Operators.java:1083)
at reactor.core.publisher.Operators.setOnce(Operators.java:1188)
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onSubscribe(MonoFlatMap.java:237)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onSubscribe(FluxOnErrorResume.java:72)
at reactor.core.publisher.Operators.reportThrowInSubscribe(Operators.java:225)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:71)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:157)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:199)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:199)
at reactor.pool.AbstractPool$Borrower.deliver(AbstractPool.java:410)
at reactor.pool.SimpleDequePool.lambda$drainLoop$7(SimpleDequePool.java:382)
at reactor.core.publisher.FluxDoOnEach$DoOnEachSubscriber.onNext(FluxDoOnEach.java:154)
at reactor.core.publisher.FluxMap$MapConditionalSubscriber.onNext(FluxMap.java:220)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
at org.reactivestreams.FlowAdapters$FlowToReactiveSubscriber.onNext(FlowAdapters.java:218)
at oracle.jdbc.datasource.impl.OracleDataSource$ConnectionPublisher$ConnectionSubscription.emitConnection(OracleDataSource.java:2746)
at oracle.jdbc.datasource.impl.OracleDataSource$ConnectionPublisher$ConnectionSubscription.lambda$publishConnectionAsync$0(OracleDataSource.java:2733)
at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:859)
at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:837)
at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506)
at java.base/java.util.concurrent.CompletableFuture.postFire(CompletableFuture.java:610)
at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:840)
at java.base/java.util.concurrent.CompletableFuture$Completion.run(CompletableFuture.java:478)
at oracle.jdbc.driver.PhysicalConnection.lambda$createUserCodeExecutor$10(PhysicalConnection.java:11713)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at oracle.jdbc.driver.PhysicalConnection.lambda$createUserCodeExecutor$11(PhysicalConnection.java:11711)
at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1426)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
my pool configuration
spring:
r2dbc:
username: ....
password: ....
url: r2dbc:...
pool:
initial-size: 5
max-idle-time: 10m
max-size: 30
enabled: true
data:
r2dbc:
repositories:
enabled: true
Is working with pool currently supported?
I'm trying to fetch the result of a NULL
literal without explicit type from an R2DBC result, but I can't seem to do it:
System.out.println((
Flux.from(connectionFactory.create())
.flatMap(c -> c
.createStatement("select null from dual")
.execute())
.flatMap(it -> it.map((r, m) -> r.get(0, Integer.class)))
.collectList()
.block().get(0)
));
This produces:
Exception in thread "main" java.lang.NullPointerException: Row mapping function returned null
at oracle.jdbc.driver.InsensitiveScrollableResultSet$RowPublisher.mapCurrentRow(InsensitiveScrollableResultSet.java:1302)
at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700)
at oracle.jdbc.driver.PhysicalConnection.lambda$createUserCodeExecutor$10(PhysicalConnection.java:11713)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at oracle.jdbc.driver.PhysicalConnection.lambda$createUserCodeExecutor$11(PhysicalConnection.java:11711)
at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1426)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)
Suppressed: java.lang.Exception: #block terminated with an error
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:99)
at reactor.core.publisher.Mono.block(Mono.java:1703)
When I try fetching binary data:
System.out.println((
Flux.from(connectionFactory.create())
.flatMap(c -> c
.createStatement("select null from dual")
.execute())
.flatMap(it -> it.map((r, m) -> r.get(0, ByteBuffer.class)))
.collectList()
.block().get(0)
));
I'm getting:
Exception in thread "main" java.lang.IllegalArgumentException: java.sql.SQLException: Ungültiger Spaltentyp
at oracle.r2dbc.impl.OracleReactiveJdbcAdapter$OracleJdbcRow.getObject(OracleReactiveJdbcAdapter.java:1193)
at oracle.r2dbc.impl.OracleRowImpl.getByteBuffer(OracleRowImpl.java:272)
at oracle.r2dbc.impl.OracleRowImpl.convertColumnValue(OracleRowImpl.java:245)
at oracle.r2dbc.impl.OracleRowImpl.get(OracleRowImpl.java:137)
at org.jooq.testscripts.R2DBC.lambda$2(R2DBC.java:30)
at oracle.r2dbc.impl.OracleResultImpl$2.lambda$publishRows$0(OracleResultImpl.java:119)
at oracle.r2dbc.impl.OracleReactiveJdbcAdapter.lambda$publishRows$10(OracleReactiveJdbcAdapter.java:698)
at oracle.jdbc.driver.InsensitiveScrollableResultSet$RowPublisher.mapCurrentRow(InsensitiveScrollableResultSet.java:1299)
at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700)
at oracle.jdbc.driver.PhysicalConnection.lambda$createUserCodeExecutor$10(PhysicalConnection.java:11713)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at oracle.jdbc.driver.PhysicalConnection.lambda$createUserCodeExecutor$11(PhysicalConnection.java:11711)
at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1426)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)
Suppressed: java.lang.Exception: #block terminated with an error
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:99)
at reactor.core.publisher.Mono.block(Mono.java:1703)
at org.jooq.testscripts.R2DBC.main(R2DBC.java:32)
Caused by: java.sql.SQLException: Ungültiger Spaltentyp
at oracle.jdbc.driver.Redirector$99.redirect(Redirector.java:1448)
at oracle.jdbc.driver.Redirector$99.redirect(Redirector.java:1444)
at oracle.jdbc.driver.Representation.getObject(Representation.java:567)
at oracle.jdbc.driver.Accessor.getObject(Accessor.java:1025)
at oracle.jdbc.driver.OracleStatement.getObject(OracleStatement.java:6827)
at oracle.jdbc.driver.InsensitiveScrollableResultSet$RowPublisher$ExpiringRow.getObject(InsensitiveScrollableResultSet.java:1390)
at oracle.r2dbc.impl.OracleReactiveJdbcAdapter$OracleJdbcRow.getObject(OracleReactiveJdbcAdapter.java:1185)
I'm using:
<dependency>
<groupId>com.oracle.database.r2dbc</groupId>
<artifactId>oracle-r2dbc</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-spi</artifactId>
<version>0.9.0.M1</version>
</dependency>
To follow up my stackoverflow question, where jdbc connects, but r2dbc doesn't.
How can I print the ConnectionFactoryOption that are actually used for the jdbc and r2dbc connection?
Hi,
I can't find a way to set the connect descriptor in the URL like recommended here: https://docs.oracle.com/database/121/HABPT/config_fcf.htm#HABPT4967
Am I missing something or is this not supported?
Hello, i have a simple User entity class.
when i tried to save, i hit this exception. tired using different other database like Mysql, and there isn't such exception.
reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.ClassCastException: class java.lang.Long cannot be cast to class java.lang.Integer (java.lang.Long and java.lang.Integer are in module java.base of loader 'bootstrap')
Caused by: java.lang.ClassCastException: class java.lang.Long cannot be cast to class java.lang.Integer (java.lang.Long and java.lang.Integer are in module java.base of loader 'bootstrap')
at java.base/java.util.stream.Collectors.lambda$summingInt$19(Collectors.java:681) ~[na:na]
at reactor.core.publisher.MonoStreamCollector$StreamCollectorSubscriber.onNext(MonoStreamCollector.java:132) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.tryEmit(FluxFlatMap.java:543) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxFlatMap$FlatMapInner.onNext(FluxFlatMap.java:984) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:200) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxConcatArray$ConcatArrayDelayErrorSubscriber.onNext(FluxConcatArray.java:364) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onNext(FluxFilterFuseable.java:118) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:299) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2398) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.request(FluxMapFuseable.java:360) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.request(FluxFilterFuseable.java:191) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxConcatArray$ConcatArrayDelayErrorSubscriber.request(FluxConcatArray.java:461) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxPeek$PeekSubscriber.request(FluxPeek.java:138) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxFlatMap$FlatMapInner.onSubscribe(FluxFlatMap.java:964) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onSubscribe(FluxPeek.java:171) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxConcatArray$ConcatArrayDelayErrorSubscriber.onSubscribe(FluxConcatArray.java:350) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onSubscribe(FluxFilterFuseable.java:87) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onSubscribe(FluxMapFuseable.java:265) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.Flux.subscribe(Flux.java:8466) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxConcatArray$ConcatArrayDelayErrorSubscriber.onComplete(FluxConcatArray.java:443) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxConcatArray.subscribe(FluxConcatArray.java:73) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.Flux.subscribe(Flux.java:8466) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onNext(FluxFlatMap.java:426) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:539) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyInner.onNext(MonoFlatMapMany.java:250) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxUsingWhen$UsingWhenSubscriber.onNext(FluxUsingWhen.java:345) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:200) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.FluxConcatArray$ConcatArraySubscriber.onNext(FluxConcatArray.java:201) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyInner.onNext(MonoFlatMapMany.java:250) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2398) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyMain.onSubscribeInner(MonoFlatMapMany.java:150) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyMain.onNext(MonoFlatMapMany.java:189) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.MonoCreate$DefaultMonoSink.success(MonoCreate.java:172) ~[reactor-core-3.4.22.jar:3.4.22]
at oracle.r2dbc.impl.AsyncLock.lambda$get$2(AsyncLock.java:167) ~[oracle-r2dbc-1.0.0.jar:1.0.0]
at oracle.r2dbc.impl.AsyncLock.unlock(AsyncLock.java:125) ~[oracle-r2dbc-1.0.0.jar:1.0.0]
at oracle.r2dbc.impl.AsyncLock$UsingConnectionSubscriber.terminate(AsyncLock.java:516) ~[oracle-r2dbc-1.0.0.jar:1.0.0]
at oracle.r2dbc.impl.AsyncLock$UsingConnectionSubscriber.onComplete(AsyncLock.java:502) ~[oracle-r2dbc-1.0.0.jar:1.0.0]
at reactor.core.publisher.StrictSubscriber.onComplete(StrictSubscriber.java:123) ~[reactor-core-3.4.22.jar:3.4.22]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2058) ~[reactor-core-3.4.22.jar:3.4.22]
at org.reactivestreams.FlowAdapters$FlowToReactiveSubscriber.onComplete(FlowAdapters.java:221) ~[reactive-streams-1.0.4.jar:na]
at oracle.jdbc.internal.CompletionStageUtil$IteratorSubscription.emitComplete(CompletionStageUtil.java:804) ~[ojdbc11-21.7.0.0.jar:21.6.0.0.0]
at oracle.jdbc.internal.CompletionStageUtil$IteratorSubscription.emitItems(CompletionStageUtil.java:751) ~[ojdbc11-21.7.0.0.jar:21.6.0.0.0]
at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1395) ~[na:na]
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373) ~[na:na]
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182) ~[na:na]
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655) ~[na:na]
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622) ~[na:na]
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165) ~[na:na]
This is my Repository class
@Repository
interface UsersRepository : ReactiveCrudRepository<Users, Long> {
@Query("SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') tschema FROM DUAL")
fun getCurrentSchema(): Mono<String>
}
This is my Entity Class
@Table(name = "users")
class Users {
@Id
@Column
@GeneratedValue(strategy= GenerationType.IDENTITY)
var id: Long? = null
@Column
var username: String? = null
@Column
var email: String? = null
@Column
var password: String? = null
@Column
var resetUuid: String? = null
@Column
var expiryDatetime: LocalDateTime? = null
}
I'm running Oracle tests on a remote docker with a slow connection and if .options.connectTimeout
is set to anything (20 hours etc) after some time connection fails almost immediately:
Caused by: io.r2dbc.spi.R2dbcTimeoutException: [18714] [08006] Login timeout specified by DataSource.setLoginTimeout(int) or by the oracle.jdbc.loginTimeout property has expired
at oracle.r2dbc.impl.OracleReactiveJdbcAdapter.lambda$publishConnection$9(OracleReactiveJdbcAdapter.java:647)
at reactor.core.publisher.Mono.lambda$onErrorMap$30(Mono.java:3474)
at reactor.core.publisher.Mono.lambda$onErrorResume$32(Mono.java:3564)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:94)
at reactor.core.publisher.MonoNext$NextSubscriber.onError(MonoNext.java:93)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:106)
at reactor.core.publisher.Operators.error(Operators.java:197)
The problem disappears when the property is removed.
When using the docker image provided at https://registry.hub.docker.com/r/gvenzl/oracle-xe with Testcontainers, specifically the gvenzl/oracle-xe:11-slim
image, connections fail if the JVM's timezone is set to Etc/UTC
.
Setting the property oracle.jdbc.timezoneAsRegion
as a system property, as described here, https://gist.github.com/jarek-przygodzki/cbea3cedae3aef2bbbe0ff6b057e8321 is a fix.
It would be nice if this property were supported directly by this driver, so it could be scoped to the connection.
I am new to both reactive-programming and R2DBC. I have recently come to know about a reactive oracle API (R2DBC) and wanted to see how I can integrate this inside my Quarkus/Kotlin project using Mutiny. I've seen the Mutiny example on https://r2dbc.io but wanted to know how I can convert this to, let's say, an entity that maps to a table? Essentially, I want to only perform database inserts based on the given entities but I see that R2DBC's example is just a simple native query. How can I accomplish this? I am currently using Hibernate ORM with Panache.
I will post here a sample snippet of my current code using only Mutiny:
fun save(entity: SomeDatabaseEntity): Uni<Void> =
Uni.createFrom().voidItem().invoke { -> someDatabaseRepository.persistEntity(entity) }
Is there a similar way that I can achieve the above with R2DBC? Any suggestions/tips are greatly appreciated, thanks!
Executing Oracle R2DBC's implementation of io.r2dbc.spi.Batch can result in a deadlock. The cause is rooted in Oracle JDBC's use of locks to ensure thread safe APIs.
A stack trace similar to the following is a symptom:
"ForkJoinPool.commonPool-worker-3" #16 daemon prio=5 os_prio=0 cpu=844.91ms elapsed=2204.18s tid=0x00007fb818004800 nid=0xbb1 waiting on condition [0x00007fb80dfb8000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park([email protected]/Native Method)
- parking to wait for <0x00000000e13d1a38> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park([email protected]/LockSupport.java:194)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await([email protected]/AbstractQueuedSynchronizer.java:2081)
at oracle.jdbc.driver.RestrictedLock.awaitRestrictedModeExit([email protected]/RestrictedLock.java:208)
at oracle.jdbc.driver.RestrictedLock.lock([email protected]/RestrictedLock.java:140)
at oracle.jdbc.internal.Monitor.acquireLock([email protected]/Monitor.java:131)
at oracle.jdbc.internal.Monitor.acquireCloseableLock([email protected]/Monitor.java:109)
at oracle.jdbc.driver.InsensitiveScrollableResultSet$RowPublisher$ExpiringRow.getObject([email protected]/InsensitiveScrollableResultSet.java:1388)
at oracle.r2dbc.impl.OracleReactiveJdbcAdapter$OracleJdbcRow.getObject([email protected]/OracleReactiveJdbcAdapter.java:1185)
at oracle.r2dbc.impl.OracleRowImpl.convertColumnValue([email protected]/OracleRowImpl.java:251)
at oracle.r2dbc.impl.OracleRowImpl.get([email protected]/OracleRowImpl.java:137)
The deadlock comes about as follows, where a Batch of two SQL commands is executed and Oracle JDBC's thread pool consists of 1 thread:
Note that this issue exists regardless of the thread pool size. If enough Batch results are being processed concurrently, there is potential to exhaust the thread pool as more threads become blocked waiting for the connection lock.
Note that the general limitation of blocked threads arising from concurrent calls on one connection is known. The Oracle R2DBC documentation advises programmers against doing this. Resolving this limitation is outside the scope of this issue.
This issue is filed because Oracle R2DBC's Batch implementation is not respecting it's own limitations. The implementation is executing a SQL command while application code is processing the result of another command concurrently.
Recently, I updated oracle r2dbc to v 0.2.0 and no queries are able to execute. It just hangs.
last records in logs
2021-06-16 23:16:18,861 [reactor-http-nio-4] DEBUG org.springframework.core.log.LogFormatUtils [traceDebug] [reactor-http-nio-4] [] : [acae8c1f-1, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:53282] HTTP GET "/api/getToken?token=asdasd"
2021-06-16 23:16:18,878 [reactor-http-nio-4] DEBUG org.springframework.web.reactive.handler.AbstractHandlerMapping [lambda$getHandler$1] [reactor-http-nio-4] [] : [acae8c1f-1, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:53282] Mapped to acme.TokenController#request(String)
2021-06-16 23:16:20,482 [ForkJoinPool.commonPool-worker-3] DEBUG org.springframework.r2dbc.core.DefaultDatabaseClient$DefaultGenericExecuteSpec [lambda$execute$2] [ForkJoinPool.commonPool-worker-3] [] : Executing SQL statement [SELECT ssn.ssn_id, ssn.a_tkn, ssn.a_typ, ssn.a_id, ssn.a_sbj FROM ssn WHERE ssn.a_tkn = :P0_atkn]
after the last record, it is just hangs
If I change the version back, it works
I am using ReactiveCrudRepository and spring-boot-starter-data-r2dbc
In the samples you provide it looks like it commands are operating off the default schema (or it's set in a way I can't divine).
Can you provide an example on how to change the schema?
I'm using this driver in a r2dbc connection pool which is meant to have variable size.
The password for the database I'm accessing rotates hourly...
I was hoping to extend the classes
https://github.com/oracle/oracle-r2dbc/blob/main/src/main/java/oracle/r2dbc/impl/OracleConnectionFactoryImpl.java
https://github.com/oracle/oracle-r2dbc/blob/main/src/main/java/oracle/r2dbc/impl/OracleReactiveJdbcAdapter.java
to use an extended version of OracleDataSource where the getConnection() functions can call out to retrieve updated passwords.
However, it seems nearly everything in this lib is a final or protected class and cannot be extended...
Is there a better solution to this? Do I have to just destroy my connection pool every time it fails to create a new connection and recreate it entirely?
Would it be possible to make these classes public and non-final? Or even allow a supplier like Mono<String> for the password?
Our R2dbc test suite is deadlocking on JDK 11 micronaut-projects/micronaut-data#1152
I have managed to provide the thread dump.
blocked.txt
Hi, i am so glad to be using this wonderful reactive driver for Oracle!
Thanks
I have in production an application which, servers a lot of data, and, have many hits per second.
Basically, it uses cache-aside technique with redis.
So, go redis, key not in redis, go to oracle, do some mappings, store it into redis.
It works like a charm, but, when the application is running on a day without interruption, on our apm, I start to see a memory consumption growth, and the garbage collector can not clean the memory and, the memory average starts to growth, and growth and growth.
I took a heap dump, and, with eclipse memory analyzer I saw that, the heap has a lot of ForwardOnlyResultSet objects, which, it seems that its not closed after the use.
Here, we can see that we have a lot of instances of ForwardOnlyResultSet
Since, we are using r2dbc-pool, with a pool of 5 connections,
I might be missing something, and forgetting to close the result set. Which, is something that I would to on pure jdbc. But, I havent seen nothing here in the docs about that.
I suspect that I am not closing the result set below, I am just closing(returning the connection back to the pool) after each statement
public Mono<CouponDto> fetchCoupon(final long itemId, final long couponId, final long subsidiaryId) {
return Flux.usingWhen(
connectionPool.create(),
connection -> Mono.from(connection.createStatement(QUERY)
.bind(0, subsidiaryId)
.bind(1, itemId)
.bind(2, couponId)
.execute()
).flatMapMany(it -> it.map(mapper)),
Connection::close,
((connection, throwable) -> connection.close()),
Connection::close
).next();
}
private final BiFunction<Row, RowMetadata, CouponDto> mapper = (row, rowMetadata) ->
new CouponDto(
row.get("id", Long.class),
row.get("discountPercentage", Double.class),
row.get("listPrice", Double.class),
row.get("discountType", Integer.class)
);
Again, thanks for your help & time!
Best Regards, Matheus Rambo
Maybe it's premature, but I can hope :)
One awesome Oracle feature that could greatly profit from R2DBC support is Oracle AQ. Instead of blocking on DBMS_AQ.DEQUEUE
calls, I could imagine a Publisher
per queue that clients could subscribe to in various ways. Are there any plans for this yet, or too soon?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.