Code Monkey home page Code Monkey logo

r2dbc-mysql's People

Contributors

asyncer-io-bot avatar bhosale avatar btakeya avatar diemass avatar genzarchitect avatar jchrys avatar johnniang avatar kevin70 avatar kui avatar mirromutth avatar mobidick1969 avatar mp911de avatar saurabhyadav1985 avatar soumya-kushwaha avatar svats0001 avatar t45k avatar yujiayan0709 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

r2dbc-mysql's Issues

Application fails to reconnect with DB after connection closed

Describe the bug
I have a Spring boot application which I am migrating to Spring Boot 3. I am using the r2dbc mysql driver to connect with db. I am facing issues as queries are randomly failing. Error occurs when idle connection(s) are closed by the DB, queries coming post connection closure fail to execute with exception org.springframework.dao.DataAccessResourceFailureException: Failed to obtain R2DBC Connection

To Reproduce
platform: Ubuntu 22.04
jdk version: openjdk-20
maven version: 3.8.1
spring-boot version: 3.1.0
r2dbc-mysql version: 1.0.2

Sample repo link
Complete app log gist

Steps:

  1. Install and run mysql on local (i had used this doc for reference). It runs on port 3306 by default.
  2. Reduce idle_timeout and interactive_timeout to 180 by adding following configuration to /etc/alternatives/my.cnf (Reducing these timeout values causes the DB to close idle connections after 3 minutes thus saving time :P):
# default was 28800 seconds
[mysqld]
interactive_timeout=180
wait_timeout=180

create a test database, the reproducer application uses the database: test. On mysql CLI run:

create database test;
  1. Clone and run the reproducer spring boot application using maven, by default the application will run on port 8080.
    (Check the application.properties to configure database related properties according to your local setup)
mvn spring-boot:run
# curl to get all table rows
curl 'http://localhost:8080/get'

# api response will look something like this:
# [{"id":1,"name":"abc","age":21},{"id":2,"name":"bbd","age":12},{"id":3,"name":"abbd","age":31},{"id":4,"name":"abv","age":21},{"id":5,"name":"abd","age":25},{"id":6,"name":"aba","age":24},{"id":7,"name":"abe","age":23},{"id":8,"name":"abd","age":25},{"id":9,"name":"aba","age":24},{"id":10,"name":"abe","age":23}]
# curl to insert multiple rows to table 
curl -X POST 'http://localhost:8080/save' -d '[{"name" : "john", "age" : 33}, {"name" : "jonah", "age" : 34}]' -H "Content-Type: application/json"

# response looks like this
# [{"id":11,"name":"john","age":33},{"id":12,"name":"jonah","age":34}]%

Hit these endpoints to validate the application running correctly.

2023-06-16T12:30:09.044+05:30  INFO 1100092 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2023-06-16T12:30:09.052+05:30  INFO 1100092 --- [           main] com.example.Main                         : Started Main in 1.827 seconds (process running for 2.025)
2023-06-16T12:31:12.503+05:30  INFO 1100092 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-06-16T12:31:12.503+05:30  INFO 1100092 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2023-06-16T12:31:12.503+05:30  INFO 1100092 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 0 ms
2023-06-16T12:31:12.543+05:30 DEBUG 1100092 --- [nio-8080-exec-1] o.s.r2dbc.core.DefaultDatabaseClient     : Executing SQL statement [SELECT test.* FROM test]
2023-06-16T12:31:12.560+05:30  INFO 1100092 --- [tor-tcp-epoll-2] com.example.service.TestService          : Found data: [Test(id=1, name=abc, age=21), Test(id=2, name=bbd, age=12), Test(id=3, name=abbd, age=31), Test(id=4, name=abv, age=21), Test(id=5, name=abd, age=25), Test(id=6, name=aba, age=24), Test(id=7, name=abe, age=23), Test(id=8, name=abd, age=25), Test(id=9, name=aba, age=24), Test(id=10, name=abe, age=23)]
  1. Now wait for 3 minutes (as we set the idle and interactive timeout to 3 minutes) so that the DB starts evicting idle connections. This can be seen using the show processlist; command. It will look something like this:
mysql> show processlist;
+-----+-----------------+-----------------+------+---------+--------+------------------------+------------------+
| Id  | User            | Host            | db   | Command | Time   | State                  | Info             |
+-----+-----------------+-----------------+------+---------+--------+------------------------+------------------+
|   5 | event_scheduler | localhost       | NULL | Daemon  | 158938 | Waiting on empty queue | NULL             |
| 169 | root            | localhost:34600 | test | Sleep   |    165 |                        | NULL             |
| 170 | root            | localhost:34608 | test | Sleep   |    165 |                        | NULL             |
| 171 | root            | localhost:34624 | test | Sleep   |    165 |                        | NULL             |
| 172 | root            | localhost:34634 | test | Sleep   |    165 |                        | NULL             |
| 173 | root            | localhost:34646 | test | Sleep   |    165 |                        | NULL             |
| 174 | root            | localhost:34654 | test | Sleep   |    165 |                        | NULL             |
| 175 | root            | localhost:34658 | test | Sleep   |    165 |                        | NULL             |
| 176 | root            | localhost:34682 | test | Sleep   |    165 |                        | NULL             |
| 177 | root            | localhost:34674 | test | Sleep   |    165 |                        | NULL             |
| 178 | root            | localhost:34694 | test | Sleep   |    101 |                        | NULL             |
| 179 | root            | localhost       | test | Query   |      0 | init                   | show processlist |
+-----+-----------------+-----------------+------+---------+--------+------------------------+------------------+
12 rows in set (0.00 sec)

mysql> show processlist;
+-----+-----------------+-----------------+------+---------+--------+------------------------+------------------+
| Id  | User            | Host            | db   | Command | Time   | State                  | Info             |
+-----+-----------------+-----------------+------+---------+--------+------------------------+------------------+
|   5 | event_scheduler | localhost       | NULL | Daemon  | 158952 | Waiting on empty queue | NULL             |
| 169 | root            | localhost:34600 | test | Sleep   |    179 |                        | NULL             |
| 170 | root            | localhost:34608 | test | Sleep   |    179 |                        | NULL             |
| 171 | root            | localhost:34624 | test | Sleep   |    179 |                        | NULL             |
| 172 | root            | localhost:34634 | test | Sleep   |    179 |                        | NULL             |
| 173 | root            | localhost:34646 | test | Sleep   |    179 |                        | NULL             |
| 174 | root            | localhost:34654 | test | Sleep   |    179 |                        | NULL             |
| 175 | root            | localhost:34658 | test | Sleep   |    179 |                        | NULL             |
| 176 | root            | localhost:34682 | test | Sleep   |    179 |                        | NULL             |
| 177 | root            | localhost:34674 | test | Sleep   |    179 |                        | NULL             |
| 178 | root            | localhost:34694 | test | Sleep   |    115 |                        | NULL             |
| 179 | root            | localhost       | test | Query   |      0 | init                   | show processlist |
+-----+-----------------+-----------------+------+---------+--------+------------------------+------------------+
12 rows in set (0.01 sec)

mysql> show processlist;
+-----+-----------------+-----------------+------+---------+--------+------------------------+------------------+
| Id  | User            | Host            | db   | Command | Time   | State                  | Info             |
+-----+-----------------+-----------------+------+---------+--------+------------------------+------------------+
|   5 | event_scheduler | localhost       | NULL | Daemon  | 158955 | Waiting on empty queue | NULL             |
| 178 | root            | localhost:34694 | test | Sleep   |    118 |                        | NULL             |
| 179 | root            | localhost       | test | Query   |      0 | init                   | show processlist |
+-----+-----------------+-----------------+------+---------+--------+------------------------+------------------+
3 rows in set (0.00 sec)

mysql> show processlist;
+-----+-----------------+-----------------+------+---------+--------+------------------------+------------------+
| Id  | User            | Host            | db   | Command | Time   | State                  | Info             |
+-----+-----------------+-----------------+------+---------+--------+------------------------+------------------+
|   5 | event_scheduler | localhost       | NULL | Daemon  | 159015 | Waiting on empty queue | NULL             |
| 178 | root            | localhost:34694 | test | Sleep   |    178 |                        | NULL             |
| 179 | root            | localhost       | test | Query   |      0 | init                   | show processlist |
+-----+-----------------+-----------------+------+---------+--------+------------------------+------------------+
3 rows in set (0.00 sec)

mysql> show processlist;
+-----+-----------------+-----------+------+---------+--------+------------------------+------------------+
| Id  | User            | Host      | db   | Command | Time   | State                  | Info             |
+-----+-----------------+-----------+------+---------+--------+------------------------+------------------+
|   5 | event_scheduler | localhost | NULL | Daemon  | 159017 | Waiting on empty queue | NULL             |
| 179 | root            | localhost | test | Query   |      0 | init                   | show processlist |
+-----+-----------------+-----------+------+---------+--------+------------------------+------------------+
2 rows in set (0.00 sec)

This is also indicated in the application logs:

2023-06-16T12:33:08.833+05:30  WARN 1100092 --- [tor-tcp-epoll-2] i.a.r.mysql.client.MessageDuplexCodec    : Connection has been closed by peer
2023-06-16T12:33:08.893+05:30  WARN 1100092 --- [tor-tcp-epoll-2] i.a.r.mysql.client.MessageDuplexCodec    : Connection has been closed by peer
2023-06-16T12:33:08.905+05:30  WARN 1100092 --- [tor-tcp-epoll-2] i.a.r.mysql.client.MessageDuplexCodec    : Connection has been closed by peer
2023-06-16T12:33:08.910+05:30  WARN 1100092 --- [tor-tcp-epoll-2] i.a.r.mysql.client.MessageDuplexCodec    : Connection has been closed by peer
2023-06-16T12:33:08.913+05:30  WARN 1100092 --- [tor-tcp-epoll-2] i.a.r.mysql.client.MessageDuplexCodec    : Connection has been closed by peer
2023-06-16T12:33:08.914+05:30  WARN 1100092 --- [tor-tcp-epoll-2] i.a.r.mysql.client.MessageDuplexCodec    : Connection has been closed by peer
2023-06-16T12:33:08.914+05:30  WARN 1100092 --- [tor-tcp-epoll-2] i.a.r.mysql.client.MessageDuplexCodec    : Connection has been closed by peer
2023-06-16T12:33:08.917+05:30  WARN 1100092 --- [tor-tcp-epoll-2] i.a.r.mysql.client.MessageDuplexCodec    : Connection has been closed by peer
2023-06-16T12:33:08.917+05:30  WARN 1100092 --- [tor-tcp-epoll-2] i.a.r.mysql.client.MessageDuplexCodec    : Connection has been closed by peer
2023-06-16T12:34:12.647+05:30  WARN 1100092 --- [tor-tcp-epoll-2] i.a.r.mysql.client.MessageDuplexCodec    : Connection has been closed by peer
  1. Now hit the api using the previous curls. It will give error response:
curl -i 'http://localhost:8080/get'                                                            
## internal server error response ##
# {"timestamp":"2023-06-16T07:37:16.990+00:00","status":500,"error":"Internal Server Error","path":"/get"}% 
curl -i -X POST 'http://localhost:8080/save' -d '[{"name" : "john", "age" : 33}, {"name" : "jonah", "age" : 34}]' -H "Content-Type: application/json"
## internal server error response ##
# {"timestamp":"2023-06-16T07:37:12.222+00:00","status":500,"error":"Internal Server Error","path":"/save"}%

Stacktrace from application logs:

2023-06-16T12:34:19.019+05:30 ERROR 1100092 --- [tor-tcp-epoll-2] com.example.service.TestService          : Error

org.springframework.dao.DataAccessResourceFailureException: Failed to obtain R2DBC Connection
	at org.springframework.r2dbc.connection.ConnectionFactoryUtils.lambda$getConnection$0(ConnectionFactoryUtils.java:90) ~[spring-r2dbc-6.0.7.jar:6.0.7]
	at reactor.core.publisher.Mono.lambda$onErrorMap$28(Mono.java:3773) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:94) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:106) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.FluxRetry$RetrySubscriber.onError(FluxRetry.java:95) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.secondError(MonoFlatMap.java:241) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoFlatMap$FlatMapInner.onError(MonoFlatMap.java:315) ~[reactor-core-3.5.6.jar:3.5.6]
	at io.r2dbc.pool.MonoDiscardOnCancel$MonoDiscardOnCancelSubscriber.onError(MonoDiscardOnCancel.java:98) ~[r2dbc-pool-1.0.0.RELEASE.jar:1.0.0.RELEASE]
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:106) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onError(MonoIgnoreThen.java:278) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:231) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:203) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.FluxDoFinally$DoFinallySubscriber.onComplete(FluxDoFinally.java:128) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.FluxDoFinally$DoFinallySubscriber.onComplete(FluxDoFinally.java:128) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:209) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.Operators.complete(Operators.java:137) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.netty.FutureMono.doSubscribe(FutureMono.java:122) ~[reactor-netty-core-1.1.7.jar:1.1.7]
	at reactor.netty.FutureMono$DeferredFutureMono.subscribe(FutureMono.java:114) ~[reactor-netty-core-1.1.7.jar:1.1.7]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:240) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:203) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2205) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onComplete(MonoFlatMap.java:189) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoCreate$DefaultMonoSink.success(MonoCreate.java:140) ~[reactor-core-3.5.6.jar:3.5.6]
	at io.asyncer.r2dbc.mysql.client.ReactorNettyClient.lambda$close$11(ReactorNettyClient.java:200) ~[r2dbc-mysql-1.0.2.jar:1.0.2]
	at reactor.core.publisher.MonoCreate.subscribe(MonoCreate.java:58) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.Mono.subscribe(Mono.java:4485) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:263) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.Mono.subscribe(Mono.java:4485) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:263) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.Mono.subscribe(Mono.java:4485) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:103) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onError(MonoIgnoreThen.java:278) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoIgnoreElements$IgnoreElementsSubscriber.onError(MonoIgnoreElements.java:84) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.onNext(FluxHandleFuseable.java:200) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoSupplier$MonoSupplierSubscription.request(MonoSupplier.java:145) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.request(FluxHandleFuseable.java:259) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoIgnoreElements$IgnoreElementsSubscriber.onSubscribe(MonoIgnoreElements.java:72) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.onSubscribe(FluxHandleFuseable.java:163) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoSupplier.subscribe(MonoSupplier.java:48) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.Mono.subscribe(Mono.java:4485) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:263) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[reactor-core-3.5.6.jar:3.5.6]
	at io.r2dbc.pool.MonoDiscardOnCancel.subscribe(MonoDiscardOnCancel.java:50) ~[r2dbc-pool-1.0.0.RELEASE.jar:1.0.0.RELEASE]
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.pool.AbstractPool$Borrower.deliver(AbstractPool.java:467) ~[reactor-pool-1.0.0.jar:1.0.0]
	at reactor.pool.SimpleDequePool.lambda$drainLoop$8(SimpleDequePool.java:368) ~[reactor-pool-1.0.0.jar:1.0.0]
	at reactor.core.scheduler.ImmediateScheduler.schedule(ImmediateScheduler.java:52) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.pool.SimpleDequePool.drainLoop(SimpleDequePool.java:368) ~[reactor-pool-1.0.0.jar:1.0.0]
	at reactor.pool.SimpleDequePool.pendingOffer(SimpleDequePool.java:598) ~[reactor-pool-1.0.0.jar:1.0.0]
	at reactor.pool.SimpleDequePool.doAcquire(SimpleDequePool.java:294) ~[reactor-pool-1.0.0.jar:1.0.0]
	at reactor.pool.AbstractPool$Borrower.request(AbstractPool.java:430) ~[reactor-pool-1.0.0.jar:1.0.0]
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2341) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:2215) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.pool.SimpleDequePool$QueueBorrowerMono.subscribe(SimpleDequePool.java:716) ~[reactor-pool-1.0.0.jar:1.0.0]
	at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.FluxRetry$RetrySubscriber.resubscribe(FluxRetry.java:117) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.FluxRetry$RetrySubscriber.onError(FluxRetry.java:101) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.secondError(MonoFlatMap.java:241) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoFlatMap$FlatMapInner.onError(MonoFlatMap.java:315) ~[reactor-core-3.5.6.jar:3.5.6]
	at io.r2dbc.pool.MonoDiscardOnCancel$MonoDiscardOnCancelSubscriber.onError(MonoDiscardOnCancel.java:98) ~[r2dbc-pool-1.0.0.RELEASE.jar:1.0.0.RELEASE]
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:106) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onError(MonoIgnoreThen.java:278) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:231) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:203) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.FluxDoFinally$DoFinallySubscriber.onComplete(FluxDoFinally.java:128) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.FluxDoFinally$DoFinallySubscriber.onComplete(FluxDoFinally.java:128) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:209) ~[reactor-core-3.5.6.jar:3.5.6]
	at reactor.netty.FutureMono$FutureSubscription.operationComplete(FutureMono.java:196) ~[reactor-netty-core-1.1.7.jar:1.1.7]
	at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:590) ~[netty-common-4.1.92.Final.jar:4.1.92.Final]
	at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:557) ~[netty-common-4.1.92.Final.jar:4.1.92.Final]
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:492) ~[netty-common-4.1.92.Final.jar:4.1.92.Final]
	at io.netty.util.concurrent.DefaultPromise.setValue0(DefaultPromise.java:636) ~[netty-common-4.1.92.Final.jar:4.1.92.Final]
	at io.netty.util.concurrent.DefaultPromise.setSuccess0(DefaultPromise.java:625) ~[netty-common-4.1.92.Final.jar:4.1.92.Final]
	at io.netty.util.concurrent.DefaultPromise.trySuccess(DefaultPromise.java:105) ~[netty-common-4.1.92.Final.jar:4.1.92.Final]
	at io.netty.channel.DefaultChannelPromise.trySuccess(DefaultChannelPromise.java:84) ~[netty-transport-4.1.92.Final.jar:4.1.92.Final]
	at io.netty.channel.AbstractChannel$AbstractUnsafe.safeSetSuccess(AbstractChannel.java:990) ~[netty-transport-4.1.92.Final.jar:4.1.92.Final]
	at io.netty.channel.AbstractChannel$AbstractUnsafe.close(AbstractChannel.java:686) ~[netty-transport-4.1.92.Final.jar:4.1.92.Final]
	at io.netty.channel.AbstractChannel$AbstractUnsafe.close(AbstractChannel.java:620) ~[netty-transport-4.1.92.Final.jar:4.1.92.Final]
	at io.netty.channel.DefaultChannelPipeline$HeadContext.close(DefaultChannelPipeline.java:1352) ~[netty-transport-4.1.92.Final.jar:4.1.92.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeClose(AbstractChannelHandlerContext.java:749) ~[netty-transport-4.1.92.Final.jar:4.1.92.Final]
	at io.netty.channel.AbstractChannelHandlerContext.access$1200(AbstractChannelHandlerContext.java:61) ~[netty-transport-4.1.92.Final.jar:4.1.92.Final]
	at io.netty.channel.AbstractChannelHandlerContext$11.run(AbstractChannelHandlerContext.java:732) ~[netty-transport-4.1.92.Final.jar:4.1.92.Final]
	at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:174) ~[netty-common-4.1.92.Final.jar:4.1.92.Final]
	at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:167) ~[netty-common-4.1.92.Final.jar:4.1.92.Final]
	at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470) ~[netty-common-4.1.92.Final.jar:4.1.92.Final]
	at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:403) ~[netty-transport-classes-epoll-4.1.92.Final.jar:4.1.92.Final]
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) ~[netty-common-4.1.92.Final.jar:4.1.92.Final]
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.92.Final.jar:4.1.92.Final]
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.92.Final.jar:4.1.92.Final]
	at java.base/java.lang.Thread.run(Thread.java:1623) ~[na:na]
Caused by: io.r2dbc.spi.R2dbcNonTransientResourceException: Connection validation failed
	at io.r2dbc.pool.Validation.lambda$validate$2(Validation.java:45) ~[r2dbc-pool-1.0.0.RELEASE.jar:1.0.0.RELEASE]
	at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.onNext(FluxHandleFuseable.java:178) ~[reactor-core-3.5.6.jar:3.5.6]
	... 60 common frames omitted

Expected behavior
Expect the driver to reconnect upon connection validation failure and then execute the queries as is the case with the 'traditional' JPA which uses JDBC driver. In case of JDBC driver, application is able to recover from the connection validation error and return the response.

Additional context
If required, I can add another sample application that uses JDBC which executes queries as expected with the same reproduction steps mentioned previously, for now I have only added the application logs, config properties and relevant dependencies from pom.
application.properties:

server.port=9091
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=password

logs:

2023-06-15 16:04:32.866  INFO [,,] 1014806 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 9091 (http) with context path ''
2023-06-15 16:04:32.905  INFO [,,] 1014806 --- [  restartedMain] com.example.toy.ToyApplication           : Started ToyApplication in 4.993 seconds (JVM running for 5.295)
2023-06-15 16:04:36.379  INFO [,03342ce960139f4d,03342ce960139f4d] 1014806 --- [nio-9091-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-06-15 16:04:36.379  INFO [,03342ce960139f4d,03342ce960139f4d] 1014806 --- [nio-9091-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2023-06-15 16:04:36.380  INFO [,03342ce960139f4d,03342ce960139f4d] 1014806 --- [nio-9091-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
2023-06-15 16:04:36.491  INFO [,03342ce960139f4d,03342ce960139f4d] 1014806 --- [nio-9091-exec-1] com.example.toy.service.TestService      : [Test(id=1, name=abc, age=21), Test(id=2, name=bbd, age=12), Test(id=3, name=abbd, age=31), Test(id=4, name=abv, age=21)]
2023-06-16 13:47:04.395  WARN [,9700876eff472209,9700876eff472209] 1014806 --- [nio-9091-exec-3] com.zaxxer.hikari.pool.PoolBase          : HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@16fc706c (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.
2023-06-16 13:47:04.397  WARN [,9700876eff472209,9700876eff472209] 1014806 --- [nio-9091-exec-3] com.zaxxer.hikari.pool.PoolBase          : HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@49a960da (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.
2023-06-16 13:47:04.398  WARN [,9700876eff472209,9700876eff472209] 1014806 --- [nio-9091-exec-3] com.zaxxer.hikari.pool.PoolBase          : HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@251daf0 (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.
2023-06-16 13:47:04.399  WARN [,9700876eff472209,9700876eff472209] 1014806 --- [nio-9091-exec-3] com.zaxxer.hikari.pool.PoolBase          : HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@775bb5c6 (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.
2023-06-16 13:47:04.399  WARN [,9700876eff472209,9700876eff472209] 1014806 --- [nio-9091-exec-3] com.zaxxer.hikari.pool.PoolBase          : HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@3745444b (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.
2023-06-16 13:47:04.400  WARN [,9700876eff472209,9700876eff472209] 1014806 --- [nio-9091-exec-3] com.zaxxer.hikari.pool.PoolBase          : HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@35685dc9 (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.
2023-06-16 13:47:04.400  WARN [,9700876eff472209,9700876eff472209] 1014806 --- [nio-9091-exec-3] com.zaxxer.hikari.pool.PoolBase          : HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@396297ce (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.
2023-06-16 13:47:04.401  WARN [,9700876eff472209,9700876eff472209] 1014806 --- [nio-9091-exec-3] com.zaxxer.hikari.pool.PoolBase          : HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@133de0a1 (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.
2023-06-16 13:47:04.402  WARN [,9700876eff472209,9700876eff472209] 1014806 --- [nio-9091-exec-3] com.zaxxer.hikari.pool.PoolBase          : HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@54c73f8a (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.
2023-06-16 13:47:04.402  WARN [,9700876eff472209,9700876eff472209] 1014806 --- [nio-9091-exec-3] com.zaxxer.hikari.pool.PoolBase          : HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@2883e55b (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.
2023-06-16 13:47:04.408  INFO [,9700876eff472209,9700876eff472209] 1014806 --- [nio-9091-exec-3] com.example.toy.service.TestService      : Found: [Test(id=1, name=abc, age=21), Test(id=2, name=bbd, age=12), Test(id=3, name=abbd, age=31), Test(id=4, name=abv, age=21), Test(id=5, name=abd, age=25), Test(id=6, name=aba, age=24), Test(id=7, name=abe, age=23), Test(id=8, name=abd, age=25), Test(id=9, name=aba, age=24), Test(id=10, name=abe, age=23), Test(id=11, name=john, age=33), Test(id=12, name=jonah, age=34)]

dependencies:

		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-relational</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.33</version>
		</dependency>

[bug] re-filed from old repository: Request queue was disposed

Describe the bug
original issue: mirromutth/r2dbc-mysql#241
Hi, there was this bug in the old implementation where a connection would hang for hours, stopping the thread, and then throw this error:

java.lang.IllegalStateException: Request queue was disposed 
at dev.miku.r2dbc.mysql.client.RequestQueue.requireDisposed(RequestQueue.java:150)
  at dev.miku.r2dbc.mysql.client.RequestQueue.dispose(RequestQueue.java:139)
  at dev.miku.r2dbc.mysql.client.MessageDuplexCodec.channelInactive(MessageDuplexCodec.java:131)
  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262)
  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248)
  at io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241)
  at io.netty.handler.codec.ByteToMessageDecoder.channelInputClosed(ByteToMessageDecoder.java:389)
  at io.netty.handler.codec.ByteToMessageDecoder.channelInactive(ByteToMessageDecoder.java:354)
  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262)
  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248)

To Reproduce
Steps to reproduce the behavior:
I'm not sure what triggers this bug ๐Ÿ˜ข but there were multiple reports on the original issue


could you confirm if this issue was handled when catching up to r2dbc 1.0.0?
Also, thanks a lot for taking over maintainership of this project and supporting r2dbc 1.0.0 ๐Ÿ™‡โ€โ™‚๏ธ

Empty response received for query from Spring Boot Application even though data is present

Summary

Empty response received in Spring Boot application while querying data from table even though data is present in table.

Detailed description

I have a table that has a few columns having types BIGINT(20), VARCHAR(255), DATETIME. When I execute the query directly on the mysql shell, I am able to fetch records

SELECT * FROM TEST.ARTICLES WHERE ID IN (1234) AND URL  != 'NA';

But when I am trying to do the same thing from my Spring Boot application using the R2dbcEntityTemplate, I am getting empty response. Upon enabling the debug logs using logging.level.org.springframework.r2dbc=DEBUG, I am seeing the following log being printed:

2023-06-23 16:47:28 INFO  - Executing query with criteria: ID  IN (1234) AND URL  != 'NA'
2023-06-23 16:48:35 INFO  - Response: Eof41Message{warnings=1, serverStatuses=2}, reports 1 warning(s)

I was able to isolate the field that is causing this issue. When the fields having type BIGINT(20) in table are defined as java.lang.Long in the corresponding java entity class, I get an empty response.

However changing the same fields to java type java.math.BigInteger fixes the issue as the Eof41Message log is removed and I get the expected data in response.
According to the doc here, BIGINT should be compatible with the java 'Long' type.Since this is an existing table and part of an existing application that is being migrated to Spring Boot 3, changing the field type is not an option for me.
Can you please help me solve this?

Relevant context

Platform: Ubuntu 22
Spring Boot Version: 3.1.0
Java: openjdk-20
r2dbc-mysql driver: 1.0.2

application properties:

logging.level.org.springframework.r2dbc=DEBUG
spring.r2dbc.url=r2dbc:mysql://localhost:3306/test
spring.r2dbc.username=root
spring.r2dbc.password=password

Here's the code I am using to execute the query:

var result = template.select( Query.query( Criteria.where("id").in(idList).and("url").notIn(invalidValues) ) , Articles.class)

Use Slf4j Logger

Slf4j is defacto standard in java world. better use slf4j instead reactor's logger factory.

[feature]Add support for rewriteBatchedStatements feature in r2dbc-mysql

Is your feature request related to a problem? Please describe.
Currently, there is no built-in support for rewriting batched statements, which results in performance issues when executing multiple statements as a batch.

Describe the solution you'd like
I would like to request the addition of a feature similar to rewriteBatchedStatements in mysql-connector-j. This feature allows the driver to automatically rewrite batched statements into a single multi-row insert statement, improving performance and reducing the network round-trips.

The proposed solution would involve implementing a mechanism in r2dbc-mysql that analyzes batched statements and intelligently combines them into a single multi-row insert statement, thus optimizing the execution and reducing overhead.

Additional context
Having support for the -rewriteBatchedStatements feature in r2dbc-mysql would greatly enhance the performance and efficiency of executing batched statements. This feature is already available in mysql-connector-j and is widely used by developers who work with JDBC.

https://dev.mysql.com/doc/connector-j/8.1/en/connector-j-connp-props-performance-extensions.html

why the driver pending

Describe the bug
i just use mirromutth/r2dbc-mysql 0.9.x๏ผŒand i read this repository code history๏ผŒfind none improve about connection dispose

To Reproduce
build 300 tables and insert 1w rows into per table.
now, provide a api, to migration them to another database.
when i run the api๏ผŒit will report exception๏ผŒbecause per request keep a connection and no releaseใ€‚

it will reproduce : why the driver pending and all the request pending

Expected behavior
i can use mysql drive to migration the data success

Screenshots

Additional context

@Parameters({
        @Parameter(name = "mysqlHost", in = ParameterIn.QUERY, example = "127.0.0.1"),
        @Parameter(name = "mysqlPort", in = ParameterIn.QUERY, example = "3306"),
        @Parameter(name = "username", in = ParameterIn.QUERY, example = "root"),
        @Parameter(name = "password", in = ParameterIn.QUERY, example = "123456"),
        @Parameter(name = "migrationType", in = ParameterIn.QUERY, example = "all"),
        @Parameter(name = "startTime", in = ParameterIn.QUERY, example = "1682212299000")
    })
    @GetMapping(value = "/katchu", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    @Operation(summary = " ", description = " ")
    public Flux<MigrationResult> migrationData(
        @Parameter(hidden = true) MigrationQuery query) {
              doMigrationActive(query)
    }
    private Flux<MigrationResult> doMigrationActive(MigrationQuery query) {
        ActiveService activeService = new ActiveService(query);
        return activeService.migration(query);
    }
private final static String flag = "----";
public Flux<MigrationResult> migration(MigrationQuery query) {
        return getTableNames(fixStartTime(query.getStartTime()))
            .collectList()
            .flatMapMany(it -> {
                String msg = String.format("%s่กจ้œ€ๅŒๆญฅ็š„่กจ็š„ๆ•ฐ้‡:%d",
                    getTableName(),
                    it.size());
                log.warn(msg);
                it.add(0, flag + msg);
                return Flux.fromIterable(it);
            })
            .delayElements(Duration.ofSeconds(1))
            .flatMapSequential(tableName -> {
                if (tableName.startsWith(flag)) {
                    return Flux.just(MigrationResult.finish(tableName));
                } else {
                    return migration(tableName, query.getStartTime());
                }
            }, 1);
    }

    public Flux<MigrationResult> migration(String tableName, Long startTime) {
        log.info(tableName);
        return list(tableName, startTime)
            .doOnSubscribe(sub -> {
                log.info( tableName + " migration start ");
            })
            .doFinally(signalType -> {
                log.info(tableName + " got datas ");
            })
            .doOnError((err) -> {
                err.printStackTrace();
            })
            .buffer(100)
            .publishOn(Schedulers.single())
            .concatMap(mapList -> {
                return Flux
                    .fromIterable(mapList)
                    .flatMap(objectMap -> {
                        return convert(objectMap)
                            .flatMap(message -> {
                                // insert to other database
                            });
                    })
                    .reduce(Math::addExact)
                    .map(it -> MigrationResult.success(it, tableName));
            })
            .onErrorResume(err -> LocaleUtils.resolveThrowable(err, (throwable, s) -> MigrationResult.error(s)))
            .switchIfEmpty(Mono.defer(() -> {
                String msg =  tableName + " no match data ";
                log.info(msg);
                return Mono.just(MigrationResult.error(msg));
            }))
            .doFinally(signalType -> {
                log.info(tableName + " finish migration ");
            });
    }

Support r2dbc-spi's extension(optional) interface 'Wrapped'

The Wrapped interface is an optional extension provided by the R2DBC specification to
access an instance of a resource which has been wrapped and for implementers to expose wrapped resources.

By implementing the Wrapped interface, vendors can expose their vendor-specific resources in a standard way.

This feature is not mandatory to implement, but we would like to add support for it in our implementation.

Refer to the R2DBC specification for more details: https://r2dbc.io/spec/1.0.0.RELEASE/spec/html/#wrapped.

Need to Update GH actions

We used to maintain 'trunk' branch.

but we need to support '0.9' branch as well for bugfixes and minor feature updates.

so we need to update gh actions yml files to support both 'trunk' and '0.9' branches.

[bug] Wrong timestamp read to Instant

Describe the bug
If reading timestamp field as Instant, it gets wrong value but write Instant to timestamp works fine.

To Reproduce
Map timestamp field on Instant Java type. E.g. database stores 2020-09-11 14:42:32 but when reading as Instant, the obtained value is 2020-09-11T11:42:32Z. This looks like it is doing some timezone offset.

Expected behavior
The obtained value must be the same as the value in database.

Additional context
This was fine in version 1.0.2 and it is broken in 1.0.3.

[feature] Java LTS versions compatibility tests

Is your feature request related to a problem? Please describe.
We're lack of java LTS versions compatibility tests

Describe the solution you'd like
Adding compatibility test using github actions.

Additional context

[feature]Supports Multiple host configuration.

Is your feature request related to a problem? Please describe.
The probleme is that tve driver doesn't support multiple host configuration

Describe the solution you'd like
support multiple hosts configuration, for example: r2dbc:mysql//host1,host2/db

New Relic cannot find Jasync-MySQL operation

Hello I'm currently using Jasync-MySQL 2.0.9 to my Spring Boot Webflux project, the result is really great, but when I open Databases Monitoring in New Relic, they said if they couldn't find database operations, do you have any suggestion the Jasync-MySQL version that I need to use?

image

<dependency>
    <groupId>com.github.jasync-sql</groupId>
    <artifactId>jasync-r2dbc-mysql</artifactId>
    <version>2.0.9</version>
</dependency>

other dependencies

Java: 11
Spring Boot: 2.4.4
New Relic Agent: 7.11

thank you โค๏ธ

[Bug] LEAK: ByteBuf.release() was not called before it's garbage-collected.

Describe the bug
I checked the memory leak error after changing from jasync r2dbc mysql to asyncer. Come to think of it, I remember that I tested using the mirromutth r2dbc library before and confirmed the same memory leak, and when I changed it to jasync, there was no memory leak. If this project were to use mirromutth as it is, it probably still has the same problem.

Environment

  • Spring Boot
  • Kotlin 1.8.22
  • R2dbc spi 1.0.0
  • R2dbc pool 1.0.0

Error Log(Sentry)

LEAK: ByteBuf.release() was not called before it's garbage-collected. See https://netty.io/wiki/reference-counted-objects.html for more information.
Recent access records: 
Created at:
	io.netty.buffer.PooledByteBufAllocator.newDirectBuffer(PooledByteBufAllocator.java:407)
	io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:188)
	io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:179)
	io.netty.buffer.AbstractByteBufAllocator.ioBuffer(AbstractByteBufAllocator.java:140)
	io.netty.channel.DefaultMaxMessagesRecvByteBufAllocator$MaxMessageHandle.allocate(DefaultMaxMessagesRecvByteBufAllocator.java:120)
	io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:150)
	io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788)
	io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)
	io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)
	io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
	io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
	io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	java.base/java.lang.Thread.run(Thread.java:833)

[feature] Simplify build jobs using a matrix

Is your feature request related to a problem? Please describe.

The current build&unit test jobs(./github/workflows/unit-tests.yml) in the GitHub Actions workflow have significant duplication, with the only difference being the java-version used. This makes the workflow harder to maintain and update when changes are required.

Describe the solution you'd like

I suggest using a matrix to reduce duplication in the GitHub Actions workflow. By utilizing a matrix, we can define a single build job that iterates over the different java-version values, making the workflow more concise and easier to maintain.

Additional context

reported by #80

Handling int<lenenc> values greater than 2^63-1 in MySQL OKPackets and related packets

Issue Description

It has come to our attention that MySQL's OKPackets and other packets containing int<lenenc> types may potentially have values greater than 2^63-1. As per the MySQL documentation, int<lenenc> supports such values.

Current Implementation

Our current implementation does not take this into account, and we need to address this issue to ensure proper handling of int<lenenc> values exceeding 2^63-1.

Impact on Real-world Usage

It is worth noting that this issue does not have a significant impact on real-world usage. Nonetheless, when converting the value to a string representation, it might be presented as a negative number.

Proposed Solution

To enhance the accuracy and reliability of our implementation, we need to implement a patch that properly handles int<lenenc> values exceeding 2^63-1.

[bug]Github Actions on PR from fork are failing.

Describe the bug
Github Actions on PR from fork are failing.

To Reproduce
Steps to reproduce the behavior:

  1. Create PR using account which is not member of asyncer-io.
  2. Run github actions
  3. Errors.

Expected behavior
A clear and concise description of what you expected to happen.

  1. Github actions run without an issue.

Screenshots
If applicable, add screenshots to help explain your problem.

Additional context
Add any other context about the problem here.

Unknown system variable 'innodb_lock_wait_timeout'

Summary

use s2dbc-mysql connect to doris(version 1.2.6)
The following exception occurred, how to fix it
Unknown system variable 'innodb_lock_wait_timeout'

Detailed description

Relevant context

Your environment

Additional information

Checklist

  • I have searched the existing issues to make sure my question has not been asked before
  • I have provided all the necessary information and context to help answer my question
  • I have read the documentation and/or README for this project (if applicable)

Unable to load ApplicationContext after upgrading to asyncer

Summary

Am unable to run tests and get the following error, more information here: https://stackoverflow.com/questions/76684680/upgraded-from-miku-to-asyncer-r2dbc-facing-autoconfigure-error-when-compiling

Detailed description

In my test, I have @SpringBootTest @AutoConfigureTestDatabase, and am getting the following error

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.r2dbc.core.DatabaseClient' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

I updated my maven pom.xml, and updated my ConnectionFactory to the asyncer programmatic implementation

Old

@Configuration
@EnableR2dbcRepositories
public class MySqlConnectionFactories extends AbstractR2dbcConfiguration {
  
  @Value("${spring.datasource.host}")
  public String host;
  
  @Value("${spring.datasource.db}")
  public String db;
  
  @Value("${spring.datasource.username}")
  public String userName;

  @Value("${spring.datasource.password}")
  public String password;

  @Override
  @Bean
  public ConnectionFactory connectionFactory() {
    return MySqlConnectionFactory.from(
      MySqlConnectionConfiguration.builder()
        .host(host)
        .database(db)
        .username(userName)
        .password(password)
        .sslMode(SslMode.VERIFY_IDENTITY)
        .tlsVersion(TlsVersions.TLS1_2)
        .port(3306)
        .tcpKeepAlive(true)
        .tcpNoDelay(true)
        .build());
  }
}

New

@Configuration
@EnableR2dbcRepositories
public class MySqlConnectionFactories extends AbstractR2dbcConfiguration {
  
  @Value("${spring.datasource.host}")
  public String host;
  
  @Value("${spring.datasource.db}")
  public String db;
  
  @Value("${spring.datasource.username}")
  public String userName;

  @Value("${spring.datasource.password}")
  public String password;

  @Override
  @Bean
  public ConnectionFactory connectionFactory() {
    ConnectionFactoryOptions options = ConnectionFactoryOptions.builder()
        .option(ConnectionFactoryOptions.DRIVER, "mysql")
        .option(ConnectionFactoryOptions.HOST, host)
        .option(ConnectionFactoryOptions.USER, userName)
        .option(ConnectionFactoryOptions.PORT, 3306)
        .option(ConnectionFactoryOptions.PASSWORD, password)
        .option(ConnectionFactoryOptions.DATABASE, db)
        .option(Option.valueOf("sslMode"), SslMode.VERIFY_IDENTITY)
        .option(Option.valueOf("tlsVersion"), TlsVersions.TLS1_2)
        .option(Option.valueOf("tcpKeepAlive"), true) // optional, default false
        .option(Option.valueOf("tcpNoDelay"), true) // optional, default false
        .build();
    return ConnectionFactories.get(options);
  }
}

Relevant context

Checklist

  • [ Yes ] I have searched the existing issues to make sure my question has not been asked before
  • [ Yes] I have provided all the necessary information and context to help answer my question
  • [ Yes ] I have read the documentation and/or README for this project (if applicable)

This MySQL driver may cause my request to wait at least 20 seconds

Describe the bug

Recently, I was trying to integrate R2DBC MySQL driver io.asyncer:r2dbc-mysql, but I found the problem about pending some requests randomly and at least 20 seconds.

This only happened after replacing another R2DBC MySQL driver com.github.jasync-sql:jasync-r2dbc-mysql. It was the first time I saw the weird behavior. I had no idea what happened.

To Reproduce

  1. Please checkout PR halo-dev/halo#3918.

  2. After starting the application, please open browser devtools, and try to make some requests and view the networks. You will see some pending requests.

Expected behavior

All requests should be respond quickly instead of stalling 20s.

Screenshots

image image

Not Able to access Id (auto generated field) post save operation

return ordersRepository.save(orders)
.flatMap(savedOrder -> {
// Access the saved entity with the populated id
Long orderId = savedOrder.getId();
log.info("OrderId.....{}", orderId); // Getting null here..

      // Perform operations on the id if needed
      // ...

      return Mono.just("Insert Successful"); // Return a success message
    })
    .doOnSuccess(successMessage -> log.info("Successfully Inserted"))
    .doOnError(error -> log.error("Failed to Insert", error));

}

@id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@column(name = "id", nullable = false)
private Long id;

mysql: id bigint NOT NULL AUTO_INCREMENT,
The field is getting persisted correctly in database, but I am not able to access it.

Support opitonal Closeable interface for other stateful objects

While Connection already implements Closeable as a mandatory part of R2DBC, other stateful objects such as ConnectionFactory could benefit from providing a way to release their resources through implementing the Closeable interface.

This is an optional feature, so it is not mandatory to implement it according to the R2DBC specification.

However, it would be useful for those who need to manually close their resources without blocking the caller.

refer: https://r2dbc.io/spec/1.0.0.RELEASE/spec/html/#closeable

[Bug] Request queue is full

Describe the bug
An asynchronous call was used in a Kotlin Coroutine and a Request queue is full error was detected.

How can i solve this problem ?

Should we increase the settings below?

-Dreactor.bufferSize.small=4096

Error Log
{"timestamp":"2023-07-28T08:01:14.679Z","level":"ERROR","thread":"reactor-tcp-nio-4","mdc":{"trace_id":"0f649e308d0dd6030daffe80bf7cd9fd","trace_flags":"01","span_id":"714f910c35cf72c5"},"logger":"com.hpcnt.paymentplatform.advice.ExceptionHandler$Companion","message":"Internal Server Error : java.lang.IllegalStateException: Request queue is full\n\tat io.asyncer.r2dbc.mysql.client.RequestQueue.submit(RequestQueue.java:110)\n\tSuppressed: The stacktrace has been enhanced by Reactor, refer to additional information below: \nError has been observed at the following site(s):\n\t*__checkpoint โ‡ข SQL \"INSERT INTO gateway_identifier_payment_context (application_id, type, gateway_id, payment_id, created_at) VALUES (?, ?, ?, ?, ?)\" [DatabaseClient]\n\t*__checkpoint โ‡ข Handler com.hpcnt.paymentplatform.gatewayevent.GooglePlayClientEventController#create(UUID, GooglePlayClientEventRequest, Continuation) [DispatcherHandler]\nOriginal Stack Trace:\n\t\tat io.asyncer.r2dbc.mysql.client.RequestQueue.submit(RequestQueue.java:110)\n\t\tat io.asyncer.r2dbc.mysql.client.ReactorNettyClient.lambda$exchange$9(ReactorNettyClient.java:189)\n\t\tat reactor.core.publisher.MonoCreate.subscribe(MonoCreate.java:58)\n\t\tat reactor.core.publisher.InternalFluxOperator.subscribe(InternalFluxOperator.java:62)\n\t\tat reactor.core.publisher.FluxDefer.subscribe(FluxDefer.java:54)\n\t\tat reactor.core.publisher.InternalFluxOperator.subscribe(InternalFluxOperator.java:62)\n\t\tat reactor.core.publisher.FluxDefer.subscribe(FluxDefer.java:54)\n\t\tat reactor.core.publisher.Flux.subscribe(Flux.java:8773)\n\t\tat reactor.core.publisher.FluxUsingWhen$ResourceSubscriber.onNext(FluxUsingWhen.java:195)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onNext$1(TracingSubscriber.java:62)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onNext(TracingSubscriber.java:62)\n\t\tat reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onNext$1(TracingSubscriber.java:62)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onNext(TracingSubscriber.java:62)\n\t\tat reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onNext$1(TracingSubscriber.java:62)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onNext(TracingSubscriber.java:62)\n\t\tat reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onNext$1(TracingSubscriber.java:62)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onNext(TracingSubscriber.java:62)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.secondComplete(MonoFlatMap.java:245)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:305)\n\t\tat reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2545)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapInner.onSubscribe(MonoFlatMap.java:291)\n\t\tat reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55)\n\t\tat reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onNext$1(TracingSubscriber.java:62)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onNext(TracingSubscriber.java:62)\n\t\tat reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onNext$1(TracingSubscriber.java:62)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onNext(TracingSubscriber.java:62)\n\t\tat reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2545)\n\t\tat reactor.core.publisher.FluxMap$MapSubscriber.request(FluxMap.java:164)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)\n\t\tat reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2341)\n\t\tat reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onSubscribe(FluxOnErrorResume.java:74)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onSubscribe$0(TracingSubscriber.java:57)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onSubscribe(TracingSubscriber.java:57)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onSubscribe$0(TracingSubscriber.java:57)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onSubscribe(TracingSubscriber.java:57)\n\t\tat reactor.core.publisher.FluxMap$MapSubscriber.onSubscribe(FluxMap.java:92)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onSubscribe$0(TracingSubscriber.java:57)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onSubscribe(TracingSubscriber.java:57)\n\t\tat reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55)\n\t\tat reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)\n\t\tat reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55)\n\t\tat reactor.core.publisher.Mono.subscribe(Mono.java:4495)\n\t\tat reactor.core.publisher.FluxUsingWhen.subscribe(FluxUsingWhen.java:104)\n\t\tat reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165)\n\t\tat reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2545)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapInner.onSubscribe(MonoFlatMap.java:291)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onSubscribe$0(TracingSubscriber.java:57)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onSubscribe(TracingSubscriber.java:57)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117)\n\t\tat reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55)\n\t\tat reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165)\n\t\tat reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2545)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)\n\t\tat reactor.core.publisher.FluxHide$SuppressFuseableSubscriber.request(FluxHide.java:152)\n\t\tat reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.request(FluxContextWrite.java:136)\n\t\tat reactor.core.publisher.StrictSubscriber.onSubscribe(StrictSubscriber.java:77)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onSubscribe$0(TracingSubscriber.java:57)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onSubscribe(TracingSubscriber.java:57)\n\t\tat reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onSubscribe(FluxContextWrite.java:101)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onSubscribe$0(TracingSubscriber.java:57)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onSubscribe(TracingSubscriber.java:57)\n\t\tat reactor.core.publisher.FluxHide$SuppressFuseableSubscriber.onSubscribe(FluxHide.java:122)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117)\n\t\tat reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55)\n\t\tat reactor.core.publisher.Mono.subscribe(Mono.java:4495)\n\t\tat kotlinx.coroutines.reactive.AwaitKt.awaitOne(Await.kt:190)\n\t\tat kotlinx.coroutines.reactive.AwaitKt.awaitOne$default(Await.kt:183)\n\t\tat kotlinx.coroutines.reactive.AwaitKt.awaitSingle(Await.kt:81)\n\t\tat org.springframework.data.r2dbc.core.ReactiveInsertOperationExtensionsKt.usingAndAwait(ReactiveInsertOperationExtensions.kt:38)\n\t\tat com.hpcnt.paymentplatform.gatewayidentifierpaymentcontext.GatewayIdentifierPaymentContextRepositoryImpl$insert$2$1.invokeSuspend(GatewayIdentifierPaymentContextRepositoryImpl.kt:40)\n\t\tat com.hpcnt.paymentplatform.gatewayidentifierpaymentcontext.GatewayIdentifierPaymentContextRepositoryImpl$insert$2$1.invoke(GatewayIdentifierPaymentContextRepositoryImpl.kt)\n\t\tat com.hpcnt.paymentplatform.gatewayidentifierpaymentcontext.GatewayIdentifierPaymentContextRepositoryImpl$insert$2$1.invoke(GatewayIdentifierPaymentContextRepositoryImpl.kt)\n\t\tat com.hpcnt.paymentplatform.mysql.config.R2dbcExceptionHandler.handle(R2dbcExceptionHandler.kt:11)\n\t\tat com.hpcnt.paymentplatform.gatewayidentifierpaymentcontext.GatewayIdentifierPaymentContextRepositoryImpl$insert$2.invokeSuspend(GatewayIdentifierPaymentContextRepositoryImpl.kt:38)\n\t\tat com.hpcnt.paymentplatform.gatewayidentifierpaymentcontext.GatewayIdentifierPaymentContextRepositoryImpl$insert$2.invoke(GatewayIdentifierPaymentContextRepositoryImpl.kt)\n\t\tat com.hpcnt.paymentplatform.gatewayidentifierpaymentcontext.GatewayIdentifierPaymentContextRepositoryImpl$insert$2.invoke(GatewayIdentifierPaymentContextRepositoryImpl.kt)\n\t\tat kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:89)\n\t\tat kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:169)\n\t\tat kotlinx.coroutines.BuildersKt.withContext(Unknown Source)\n\t\tat com.hpcnt.paymentplatform.gatewayidentifierpaymentcontext.GatewayIdentifierPaymentContextRepositoryImpl.insert$suspendImpl(GatewayIdentifierPaymentContextRepositoryImpl.kt:37)\n\t\tat com.hpcnt.paymentplatform.gatewayidentifierpaymentcontext.GatewayIdentifierPaymentContextRepositoryImpl.insert(GatewayIdentifierPaymentContextRepositoryImpl.kt)\n\t\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n\t\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)\n\t\tat java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n\t\tat java.base/java.lang.reflect.Method.invoke(Method.java:568)\n\t\tat org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)\n\t\tat org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)\n\t\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)\n\t\tat org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:756)\n\t\tat org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)\n\t\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)\n\t\tat org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:756)\n\t\tat org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708)\n\t\tat com.hpcnt.paymentplatform.gatewayidentifierpaymentcontext.GatewayIdentifierPaymentContextRepositoryImpl$$SpringCGLIB$$0.insert(<generated>)\n\t\tat com.hpcnt.paymentplatform.gatewayidentifierpaymentcontext.GatewayIdentifierPaymentContext.create(GatewayIdentifierPaymentContext.kt:50)\n\t\tat com.hpcnt.paymentplatform.gatewayevent.AbstractClientEventHandler.create(AbstractClientEventHandler.kt:63)\n\t\tat com.hpcnt.paymentplatform.gatewayevent.GooglePlayClientEventHandler.createGatewayIdentifierPaymentContext(GooglePlayClientEventHandler.kt:171)\n\t\tat com.hpcnt.paymentplatform.gatewayevent.GooglePlayClientEventHandler.access$createGatewayIdentifierPaymentContext(GooglePlayClientEventHandler.kt:36)\n\t\tat com.hpcnt.paymentplatform.gatewayevent.GooglePlayClientEventHandler$handle$2$deferredCreateGatewayIdentifierPaymentContext$1.invokeSuspend(GooglePlayClientEventHandler.kt:70)\n\t\tat kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)\n\t\tat kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)\n\t\tat kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)\n\t\tat kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)\n\t\tat kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)\n\t\tat kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)\n\t\tat kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)\n\t\tat kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)\n","context":"default","exception":"java.lang.IllegalStateException: Request queue is full\n\tat io.asyncer.r2dbc.mysql.client.RequestQueue.submit(RequestQueue.java:110)\n\tSuppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: \nError has been observed at the following site(s):\n\t*__checkpoint โ‡ข SQL \"INSERT INTO gateway_identifier_payment_context (application_id, type, gateway_id, payment_id, created_at) VALUES (?, ?, ?, ?, ?)\" [DatabaseClient]\n\t*__checkpoint โ‡ข Handler com.hpcnt.paymentplatform.gatewayevent.GooglePlayClientEventController#create(UUID, GooglePlayClientEventRequest, Continuation) [DispatcherHandler]\nOriginal Stack Trace:\n\t\tat io.asyncer.r2dbc.mysql.client.RequestQueue.submit(RequestQueue.java:110)\n\t\tat io.asyncer.r2dbc.mysql.client.ReactorNettyClient.lambda$exchange$9(ReactorNettyClient.java:189)\n\t\tat reactor.core.publisher.MonoCreate.subscribe(MonoCreate.java:58)\n\t\tat reactor.core.publisher.InternalFluxOperator.subscribe(InternalFluxOperator.java:62)\n\t\tat reactor.core.publisher.FluxDefer.subscribe(FluxDefer.java:54)\n\t\tat reactor.core.publisher.InternalFluxOperator.subscribe(InternalFluxOperator.java:62)\n\t\tat reactor.core.publisher.FluxDefer.subscribe(FluxDefer.java:54)\n\t\tat reactor.core.publisher.Flux.subscribe(Flux.java:8773)\n\t\tat reactor.core.publisher.FluxUsingWhen$ResourceSubscriber.onNext(FluxUsingWhen.java:195)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onNext$1(TracingSubscriber.java:62)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onNext(TracingSubscriber.java:62)\n\t\tat reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onNext$1(TracingSubscriber.java:62)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onNext(TracingSubscriber.java:62)\n\t\tat reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onNext$1(TracingSubscriber.java:62)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onNext(TracingSubscriber.java:62)\n\t\tat reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onNext$1(TracingSubscriber.java:62)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onNext(TracingSubscriber.java:62)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.secondComplete(MonoFlatMap.java:245)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:305)\n\t\tat reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2545)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapInner.onSubscribe(MonoFlatMap.java:291)\n\t\tat reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55)\n\t\tat reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onNext$1(TracingSubscriber.java:62)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onNext(TracingSubscriber.java:62)\n\t\tat reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onNext$1(TracingSubscriber.java:62)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onNext(TracingSubscriber.java:62)\n\t\tat reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2545)\n\t\tat reactor.core.publisher.FluxMap$MapSubscriber.request(FluxMap.java:164)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)\n\t\tat reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2341)\n\t\tat reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onSubscribe(FluxOnErrorResume.java:74)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onSubscribe$0(TracingSubscriber.java:57)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onSubscribe(TracingSubscriber.java:57)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onSubscribe$0(TracingSubscriber.java:57)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onSubscribe(TracingSubscriber.java:57)\n\t\tat reactor.core.publisher.FluxMap$MapSubscriber.onSubscribe(FluxMap.java:92)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onSubscribe$0(TracingSubscriber.java:57)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onSubscribe(TracingSubscriber.java:57)\n\t\tat reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55)\n\t\tat reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)\n\t\tat reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55)\n\t\tat reactor.core.publisher.Mono.subscribe(Mono.java:4495)\n\t\tat reactor.core.publisher.FluxUsingWhen.subscribe(FluxUsingWhen.java:104)\n\t\tat reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165)\n\t\tat reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2545)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapInner.onSubscribe(MonoFlatMap.java:291)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onSubscribe$0(TracingSubscriber.java:57)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onSubscribe(TracingSubscriber.java:57)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117)\n\t\tat reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55)\n\t\tat reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165)\n\t\tat reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2545)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)\n\t\tat reactor.core.publisher.FluxHide$SuppressFuseableSubscriber.request(FluxHide.java:152)\n\t\tat reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.request(FluxContextWrite.java:136)\n\t\tat reactor.core.publisher.StrictSubscriber.onSubscribe(StrictSubscriber.java:77)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onSubscribe$0(TracingSubscriber.java:57)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onSubscribe(TracingSubscriber.java:57)\n\t\tat reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onSubscribe(FluxContextWrite.java:101)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.lambda$onSubscribe$0(TracingSubscriber.java:57)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.withActiveSpan(TracingSubscriber.java:83)\n\t\tat io.opentelemetry.javaagent.shaded.instrumentation.reactor.v3_1.TracingSubscriber.onSubscribe(TracingSubscriber.java:57)\n\t\tat reactor.core.publisher.FluxHide$SuppressFuseableSubscriber.onSubscribe(FluxHide.java:122)\n\t\tat reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117)\n\t\tat reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55)\n\t\tat reactor.core.publisher.Mono.subscribe(Mono.java:4495)\n\t\tat kotlinx.coroutines.reactive.AwaitKt.awaitOne(Await.kt:190)\n\t\tat kotlinx.coroutines.reactive.AwaitKt.awaitOne$default(Await.kt:183)\n\t\tat kotlinx.coroutines.reactive.AwaitKt.awaitSingle(Await.kt:81)\n\t\tat org.springframework.data.r2dbc.core.ReactiveInsertOperationExtensionsKt.usingAndAwait(ReactiveInsertOperationExtensions.kt:38)\n\t\tat com.hpcnt.paymentplatform.gatewayidentifierpaymentcontext.GatewayIdentifierPaymentContextRepositoryImpl$insert$2$1.invokeSuspend(GatewayIdentifierPaymentContextRepositoryImpl.kt:40)\n\t\tat com.hpcnt.paymentplatform.gatewayidentifierpaymentcontext.GatewayIdentifierPaymentContextRepositoryImpl$insert$2$1.invoke(GatewayIdentifierPaymentContextRepositoryImpl.kt)\n\t\tat com.hpcnt.paymentplatform.gatewayidentifierpaymentcontext.GatewayIdentifierPaymentContextRepositoryImpl$insert$2$1.invoke(GatewayIdentifierPaymentContextRepositoryImpl.kt)\n\t\tat com.hpcnt.paymentplatform.mysql.config.R2dbcExceptionHandler.handle(R2dbcExceptionHandler.kt:11)\n\t\tat com.hpcnt.paymentplatform.gatewayidentifierpaymentcontext.GatewayIdentifierPaymentContextRepositoryImpl$insert$2.invokeSuspend(GatewayIdentifierPaymentContextRepositoryImpl.kt:38)\n\t\tat com.hpcnt.paymentplatform.gatewayidentifierpaymentcontext.GatewayIdentifierPaymentContextRepositoryImpl$insert$2.invoke(GatewayIdentifierPaymentContextRepositoryImpl.kt)\n\t\tat com.hpcnt.paymentplatform.gatewayidentifierpaymentcontext.GatewayIdentifierPaymentContextRepositoryImpl$insert$2.invoke(GatewayIdentifierPaymentContextRepositoryImpl.kt)\n\t\tat kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:89)\n\t\tat kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:169)\n\t\tat kotlinx.coroutines.BuildersKt.withContext(Unknown Source)\n\t\tat com.hpcnt.paymentplatform.gatewayidentifierpaymentcontext.GatewayIdentifierPaymentContextRepositoryImpl.insert$suspendImpl(GatewayIdentifierPaymentContextRepositoryImpl.kt:37)\n\t\tat com.hpcnt.paymentplatform.gatewayidentifierpaymentcontext.GatewayIdentifierPaymentContextRepositoryImpl.insert(GatewayIdentifierPaymentContextRepositoryImpl.kt)\n\t\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n\t\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)\n\t\tat java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n\t\tat java.base/java.lang.reflect.Method.invoke(Method.java:568)\n\t\tat org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)\n\t\tat org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)\n\t\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)\n\t\tat org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:756)\n\t\tat org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)\n\t\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)\n\t\tat org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:756)\n\t\tat org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708)\n\t\tat com.hpcnt.paymentplatform.gatewayidentifierpaymentcontext.GatewayIdentifierPaymentContextRepositoryImpl$$SpringCGLIB$$0.insert(<generated>)\n\t\tat com.hpcnt.paymentplatform.gatewayidentifierpaymentcontext.GatewayIdentifierPaymentContext.create(GatewayIdentifierPaymentContext.kt:50)\n\t\tat com.hpcnt.paymentplatform.gatewayevent.AbstractClientEventHandler.create(AbstractClientEventHandler.kt:63)\n\t\tat com.hpcnt.paymentplatform.gatewayevent.GooglePlayClientEventHandler.createGatewayIdentifierPaymentContext(GooglePlayClientEventHandler.kt:171)\n\t\tat com.hpcnt.paymentplatform.gatewayevent.GooglePlayClientEventHandler.access$createGatewayIdentifierPaymentContext(GooglePlayClientEventHandler.kt:36)\n\t\tat com.hpcnt.paymentplatform.gatewayevent.GooglePlayClientEventHandler$handle$2$deferredCreateGatewayIdentifierPaymentContext$1.invokeSuspend(GooglePlayClientEventHandler.kt:70)\n\t\tat kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)\n\t\tat kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)\n\t\tat kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)\n\t\tat kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)\n\t\tat kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)\n\t\tat kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)\n\t\tat kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)\n\t\tat

[bug] JSON type breaks when UNION query

Describe the bug

  • when UNION query is used mysql JSON type breaks into BLOB
  • conversion to a String breaks
java.lang.IllegalArgumentException: Cannot decode class java.lang.String for BLOB

	at io.asyncer.r2dbc.mysql.codec.DefaultCodecs.decodeNormal(DefaultCodecs.java:226)
	at io.asyncer.r2dbc.mysql.codec.DefaultCodecs.decode(DefaultCodecs.java:110)
	at io.asyncer.r2dbc.mysql.MySqlRow.get(MySqlRow.java:69)
	at com.infrastructure.db.R2dbcMysqlIT.lambda$errorWhenUnionQuery$2(R2dbcMysqlIT.java:86)
	at io.asyncer.r2dbc.mysql.MySqlResult.lambda$map$2(MySqlResult.java:113)
	at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.onNext(FluxHandleFuseable.java:178)
	at com.sdk.context.logging.MdcContextLifter.onNext(MdcContextLifter.java:30)
	at reactor.core.publisher.FluxHide$SuppressFuseableSubscriber.onNext(FluxHide.java:137)
	at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.onNext(FluxHandleFuseable.java:193)
	at com.sdk.context.logging.MdcContextLifter.onNext(MdcContextLifter.java:30)
	at reactor.core.publisher.FluxHide$SuppressFuseableSubscriber.onNext(FluxHide.java:137)
	at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107)
	at io.asyncer.r2dbc.mysql.internal.util.DiscardOnCancelSubscriber.onNext(DiscardOnCancelSubscriber.java:66)
	at reactor.core.publisher.FluxWindowPredicate$WindowFlux.drainRegular(FluxWindowPredicate.java:670)
	at reactor.core.publisher.FluxWindowPredicate$WindowFlux.drain(FluxWindowPredicate.java:748)
	at reactor.core.publisher.FluxWindowPredicate$WindowFlux.onNext(FluxWindowPredicate.java:790)
	at reactor.core.publisher.FluxWindowPredicate$WindowPredicateMain.onNext(FluxWindowPredicate.java:268)
	at com.sdk.context.logging.MdcContextLifter.onNext(MdcContextLifter.java:30)
	at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:200)
	at com.sdk.context.logging.MdcContextLifter.onNext(MdcContextLifter.java:30)
	at reactor.core.publisher.MonoFlatMapMany$FlatMapManyInner.onNext(MonoFlatMapMany.java:250)
	at com.sdk.context.logging.MdcContextLifter.onNext(MdcContextLifter.java:30)
	at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107)
	at io.asyncer.r2dbc.mysql.internal.util.DiscardOnCancelSubscriber.onNext(DiscardOnCancelSubscriber.java:66)
	at com.sdk.context.logging.MdcContextLifter.onNext(MdcContextLifter.java:30)
	at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:200)
	at com.sdk.context.logging.MdcContextLifter.onNext(MdcContextLifter.java:30)
	at reactor.core.publisher.FluxHandle$HandleSubscriber.onNext(FluxHandle.java:128)
	at com.sdk.context.logging.MdcContextLifter.onNext(MdcContextLifter.java:30)
	at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:200)
	at reactor.core.publisher.EmitterProcessor.drain(EmitterProcessor.java:537)
	at reactor.core.publisher.EmitterProcessor.tryEmitNext(EmitterProcessor.java:343)
	at reactor.core.publisher.InternalManySink.emitNext(InternalManySink.java:27)
	at reactor.core.publisher.EmitterProcessor.onNext(EmitterProcessor.java:309)
	at io.asyncer.r2dbc.mysql.client.ReactorNettyClient$ResponseSink.next(ReactorNettyClient.java:355)
	at io.asyncer.r2dbc.mysql.client.ReactorNettyClient.lambda$new$0(ReactorNettyClient.java:113)
	at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:185)
	at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:294)
	at reactor.netty.channel.FluxReceive.onInboundNext(FluxReceive.java:403)
	at reactor.netty.channel.ChannelOperations.onInboundNext(ChannelOperations.java:411)
	at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:113)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
	at io.asyncer.r2dbc.mysql.client.MessageDuplexCodec.handleDecoded(MessageDuplexCodec.java:178)
	at io.asyncer.r2dbc.mysql.client.MessageDuplexCodec.channelRead(MessageDuplexCodec.java:81)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346)
	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:333)
	at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:454)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:290)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
	at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1373)
	at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1236)
	at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1285)
	at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:529)
	at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:468)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:290)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:1589)

To Reproduce

package com.infrastructure.db;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.r2dbc.core.DatabaseClient;

import java.util.List;

import static java.util.Objects.requireNonNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertIterableEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

@SpringBootTest
public class R2dbcMysqlIT {

  @Autowired
  private DatabaseClient databaseClient;

  @BeforeEach
  void setUp() {
    var initDb = """
        create schema r2dbc_mysql_test;
        use r2dbc_mysql_test;
        create table phone_call (id int not null, agents json not null);
        insert into phone_call values(1, '[{"id" : "1", "name": "agent_1"}, {"id" : "2", "name": "agent_2"}]');
        insert into phone_call values(2, '[{"id" : "3", "name": "agent_3"}]');
        """;
    databaseClient.sql(initDb)
        .then()
        .block();
  }

  @AfterEach
  void tearDown() {
    var cleanDb = "drop schema r2dbc_mysql_test;";
    databaseClient.sql(cleanDb)
        .then()
        .block();
  }

  @Test
  void noErrorWhenSimpleQuery() {
    var expected = List.of(
        new Agent(1, "agent_1"),
        new Agent(2, "agent_2"),
        new Agent(3, "agent_3"));
    var query = "select * from r2dbc_mysql_test.phone_call;";
    var agentListType = new TypeToken<List<Agent>>(){}.getType();
    List<PhoneCall> phoneCalls = databaseClient.sql(query)
        .map(row -> new PhoneCall(
            requireNonNull(row.get("id", Integer.class)),
            new Gson().fromJson(row.get("agents", String.class), agentListType)))
        .all()
        .collectList()
        .block();
    assertNotNull(phoneCalls);
    assertEquals(2, phoneCalls.size());
    assertIterableEquals(expected, phoneCalls.stream().flatMap(p -> p.agents.stream()).toList());
  }

  @Test
  void errorWhenUnionQuery() {
    var expected = List.of(
        new Agent(1, "agent_1"),
        new Agent(2, "agent_2"),
        new Agent(3, "agent_3"));
    var query = """
        (select * from r2dbc_mysql_test.phone_call
        where id = 1)
        union
        (select * from r2dbc_mysql_test.phone_call
        where id = 2);
        """;
    var agentListType = new TypeToken<List<Agent>>(){}.getType();
    List<PhoneCall> phoneCalls = databaseClient.sql(query)
        .map(row -> new PhoneCall(
            requireNonNull(row.get("id", Integer.class)),
            new Gson().fromJson(row.get("agents", String.class), agentListType)))
        .all()
        .collectList()
        .block();
    assertNotNull(phoneCalls);
    assertEquals(2, phoneCalls.size());
    assertIterableEquals(expected, phoneCalls.stream().flatMap(p -> p.agents.stream()).toList());
  }

  private static class PhoneCall {
    int id;
    List<Agent> agents;

    PhoneCall(int id, List<Agent> agents) {
      this.id = id;
      this.agents = agents;
    }
  }

  private static class Agent {
    int id;
    String name;

    Agent(int id, String name) {
      this.id = id;
      this.name = name;
    }

    @Override
    public boolean equals(Object o) {
      if (this == o) return true;
      if (!(o instanceof Agent agent)) return false;

      if (id != agent.id) return false;
      return name.equals(agent.name);
    }

    @Override
    public int hashCode() {
      int result = id;
      result = 31 * result + name.hashCode();
      return result;
    }
  }
}

Expected behavior
Conversion from JSON mysql type to String java type works with UNION queries.

Screenshots
asyncer_simple_query
asyncer_simple_query_string_codec
asyncer_union_query
asyncer_union_query_string_codec
miku_union_query
miku_union_query_string_codec
tested versions
mysql_version
io.asyncer:r2dbc-mysql:1.0.0
dev.miku:r2dbc-mysql:0.8.2.RELEASE

Additional context
It seems that the implementation of StringCodec has changed. Conversion works fine for dev.miku:r2dbc-mysql:0.8.2.RELEASE. Also conversion works as well for org.mariadb:r2dbc-mariadb:1.1.4.

[feature] Support Logging Query Parameters

Is your feature request related to a problem? Please describe.
Currently, r2dbc-mysql supports logging the query sentence but does not include query parameters in the logs. This limitation makes debugging more challenging when dealing with parameterized queries.

Describe the solution you'd like
I would like to request support for logging query parameters in r2dbc-mysql. When executing parameterized queries, the query parameters should be included in the logs alongside the query sentence. This addition would greatly aid developers in debugging and understanding the exact parameter values used during query execution.

Additional context
As a developer, having access to the logged query parameters would be immensely helpful in troubleshooting issues related to database interactions. It would provide a comprehensive view of the queries being executed and the corresponding parameter values. This feature would significantly enhance the usability and debugging capabilities of r2dbc-mysql.

For instance, with the incorporation of this feature, resolving this issue would become effortless: #129

[bug] owasp dependency check fails

Describe the bug
When running a dependency check on a project that depends on this project, the dependency check fails.

To Reproduce
Add the dependency to the pom:

        <dependency>
            <groupId>io.asyncer</groupId>
            <artifactId>r2dbc-mysql</artifactId>
            <version>1.0.3</version>
        </dependency>

Add owasp dependency check to the pom's build plugins section:

            <plugin>
                <groupId>org.owasp</groupId>
                <artifactId>dependency-check-maven</artifactId>
                <version>8.4.0</version>
                <configuration>
                    <failBuildOnCVSS>4</failBuildOnCVSS>
                    <assemblyAnalyzerEnabled>false</assemblyAnalyzerEnabled>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>check</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

Run: mvn dependency-check:check

Expected behavior
There should not be any security issues raised.

Current result:
r2dbc-mysql-1.0.3.jar (pkg:maven/io.asyncer/[email protected], cpe:2.3:a:mysql:mysql:1.0.3:*:*:*:*:*:*:*) : CVE-2017-15945, CVE-2009-4028, CVE-2010-1621, CVE-2007-2691, CVE-2015-2575, CVE-2007-5925, CVE-2009-0819, CVE-2010-3677, CVE-2010-3682, CVE-2010-1626, CVE-2007-1420

[feature] Start a plan for Support MariaDB

Is your feature request related to a problem? Please describe.
Currently, the r2dbc-mysql project does not support MariaDB, which limits its usability for users who are using MariaDB as their preferred database. Although MariaDB and MySQL share a similar protocol, the existing r2dbc-mysql implementation does not have the necessary logic to handle the differences between the two database systems. Therefore, I would like to request the addition of support for MariaDB in the r2dbc-mysql project.

Describe the solution you'd like
I would like to propose adding support for MariaDB in the r2dbc-mysql project. Since MariaDB and MySQL share a similar protocol, it should be possible to extend the existing implementation to accommodate MariaDB with some additional logic. This would involve introducing branching in the code to handle specific behaviors or features that are unique to MariaDB.

Additional context
Supporting MariaDB in the r2dbc-mysql project would provide users with more options and flexibility when choosing their preferred database. It would leverage the similarities between MariaDB and MySQL, making it possible to reuse much of the existing codebase. However, it is important to carefully address any differences between the two database systems to ensure correct behavior.

Adding integration tests is crucial to guarantee that the implementation works as expected with MariaDB. These tests should cover various scenarios and edge cases to validate the compatibility and functionality of r2dbc-mysql with MariaDB.

I believe that by implementing this feature, the r2dbc-mysql project will become a more comprehensive and inclusive solution for developers working with both MySQL and MariaDB databases.

get nothing if there is @Data annotation on the entity class

Describe the bug

  • If an entity class has annotation @Data from lombok library, we get nothing from database.
  • It still not works when we put @NoArgsConstructor on the entity class.
  • If we remove all annotations from lombok library and generate all getter and setter, it works.

I'm not sure if it's an issue here or should we report it to spring r2dbc, just create an issue here for tracking.

To Reproduce
db schema:

create table user (
    id bigint auto_increment primary key ,
    name varchar(20) not null ,
    age tinyint not null
) engine = InnoDB;

entity class:

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;

@Data
@Table("user")
public class User {
    @Id
    private Long id;
    private String name;
    private Integer age;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.