Common R2DBC Resources
This repository contains common resources for R2DBC projects. These are in particular:
R2DBC Driver for Microsoft SQL Server using TDS (Tabular Data Stream) Protocol
License: Apache License 2.0
We already provide support for ZonedDateTime
. We should add a simplified variant supporting OffsetDateTime
Hi all. I'm trying to write a basic example of the Spring R2DBC using a SQL Server database.
Whenever I try to query it, I get the following exception: java.lang.IllegalStateException: Collation not available.
Here are my classes:
My ConnectionFactoryConfiguration:
@Configuration
class ConnectionFactoryConfiguration {
@Bean
DatabaseClient databaseClient() {
return DatabaseClient.create(connectionFactory());
}
@Bean
public ConnectionFactory connectionFactory() {
MssqlConnectionConfiguration config = MssqlConnectionConfiguration.builder() //
.host("localhost")
.port(1434)
.database("pizza")
.username("test")
.password("test")
.build();
return new MssqlConnectionFactory(config);
}
}
My repository (I'm not using Spring Data, though):
@Repository
public class ManualPizzaRepository {
private final ConnectionFactory connectionFactory;
public ManualPizzaRepository(ConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
Mono<Void> deleteById(Integer id) {
return this.connection()
.flatMapMany(c -> c.createStatement("delete from pizza where id = $1")
.bind("$1", id)
.execute())
.then();
}
Flux<Pizza> findAll() {
return this.connection()
.flatMapMany(connection ->
Flux.from(connection.createStatement("select * from pizza").execute())
.flatMap(r ->
r.map((row, rowMetadata) ->
new Pizza(row.get("id", Integer.class), row.get("flavor", String.class)))));
}
Flux<Pizza> save(Pizza pizza) {
Flux<? extends Result> flux = this.connection().flatMapMany(conn -> conn.createStatement("insert into pizza (flavor) values ($1)")
.bind("$1", pizza.getFlavor())
.add()
.execute());
return flux.switchMap(x -> Flux.just(new Pizza(pizza.getId(), pizza.getFlavor())));
}
private Mono<Connection> connection() {
return Mono.from(this.connectionFactory.create());
}
}
My model class:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Pizza {
@Id
private Integer id;
private String flavor;
}
My test class (where I perform the call that's throwing the exception):
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {ConnectionFactoryConfiguration.class, ManualPizzaRepository.class})
public class ReactiveSqlSqlserverApplicationTests {
@Autowired
ManualPizzaRepository pizzas;
@Autowired
DatabaseClient databaseClient;
@Test
public void testAllManual() {
Flux<Void> deleteAll = this.pizzas.findAll().flatMap(pizza -> this.pizzas.deleteById(pizza.getId()));
StepVerifier.create(deleteAll).expectNextCount(0).verifyComplete();
Flux<Pizza> savePizzas = Flux.just("Mozzarella", "Pepperoni", "Margherita")
.map(flavor -> new Pizza(null, flavor))
.flatMap(pizza -> this.pizzas.save(pizza));
StepVerifier.create(savePizzas).expectNextCount(3).verifyComplete();
Flux<Pizza> findAll = this.pizzas.findAll();
StepVerifier.create(findAll).expectNextCount(3).verifyComplete();
}
}
Stack trace of the exception:
2019-03-15 13:31:34.058 WARN 8292 --- [actor-tcp-nio-1] i.r2dbc.mssql.client.ReactorNettyClient : Failed onEnvironmentChange() in io.r2dbc.mssql.client.ReactorNettyClient$CollationListener@1680fe48
io.r2dbc.mssql.message.tds.ProtocolException: null
at io.r2dbc.mssql.message.type.Collation.decode(Collation.java:127) ~[r2dbc-mssql-1.0.0.M7.jar:1.0.0.M7]
at io.r2dbc.mssql.client.ReactorNettyClient$CollationListener.onEnvironmentChange(ReactorNettyClient.java:429) ~[r2dbc-mssql-1.0.0.M7.jar:1.0.0.M7]
at io.r2dbc.mssql.client.ReactorNettyClient.lambda$new$1(ReactorNettyClient.java:106) ~[r2dbc-mssql-1.0.0.M7.jar:1.0.0.M7]
at io.r2dbc.mssql.client.ReactorNettyClient.lambda$handleMessage$19(ReactorNettyClient.java:363) ~[r2dbc-mssql-1.0.0.M7.jar:1.0.0.M7]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:177) ~[reactor-core-3.2.6.RELEASE.jar:3.2.6.RELEASE]
at reactor.core.publisher.FluxHandle$HandleSubscriber.onNext(FluxHandle.java:113) ~[reactor-core-3.2.6.RELEASE.jar:3.2.6.RELEASE]
at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:826) ~[reactor-core-3.2.6.RELEASE.jar:3.2.6.RELEASE]
at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:826) ~[reactor-core-3.2.6.RELEASE.jar:3.2.6.RELEASE]
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.innerNext(FluxConcatMap.java:275) ~[reactor-core-3.2.6.RELEASE.jar:3.2.6.RELEASE]
at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:849) ~[reactor-core-3.2.6.RELEASE.jar:3.2.6.RELEASE]
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.drainSync(FluxFlattenIterable.java:564) ~[reactor-core-3.2.6.RELEASE.jar:3.2.6.RELEASE]
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.drain(FluxFlattenIterable.java:635) ~[reactor-core-3.2.6.RELEASE.jar:3.2.6.RELEASE]
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.request(FluxFlattenIterable.java:266) ~[reactor-core-3.2.6.RELEASE.jar:3.2.6.RELEASE]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:1878) ~[reactor-core-3.2.6.RELEASE.jar:3.2.6.RELEASE]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:1752) ~[reactor-core-3.2.6.RELEASE.jar:3.2.6.RELEASE]
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.onSubscribe(FluxFlattenIterable.java:208) ~[reactor-core-3.2.6.RELEASE.jar:3.2.6.RELEASE]
at reactor.core.publisher.FluxGenerate.subscribe(FluxGenerate.java:83) ~[reactor-core-3.2.6.RELEASE.jar:3.2.6.RELEASE]
at reactor.core.publisher.FluxFlattenIterable.subscribe(FluxFlattenIterable.java:109) ~[reactor-core-3.2.6.RELEASE.jar:3.2.6.RELEASE]
at reactor.core.publisher.Flux.subscribe(Flux.java:7777) ~[reactor-core-3.2.6.RELEASE.jar:3.2.6.RELEASE]
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:442) ~[reactor-core-3.2.6.RELEASE.jar:3.2.6.RELEASE]
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onNext(FluxConcatMap.java:244) ~[reactor-core-3.2.6.RELEASE.jar:3.2.6.RELEASE]
at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:205) ~[reactor-netty-0.8.5.RELEASE.jar:0.8.5.RELEASE]
at reactor.netty.channel.FluxReceive.onInboundNext(FluxReceive.java:321) ~[reactor-netty-0.8.5.RELEASE.jar:0.8.5.RELEASE]
at reactor.netty.channel.ChannelOperations.onInboundNext(ChannelOperations.java:319) ~[reactor-netty-0.8.5.RELEASE.jar:0.8.5.RELEASE]
at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:141) ~[reactor-netty-0.8.5.RELEASE.jar:0.8.5.RELEASE]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.r2dbc.mssql.client.ssl.TdsSslHandler.channelRead(TdsSslHandler.java:374) ~[r2dbc-mssql-1.0.0.M7.jar:1.0.0.M7]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1408) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:677) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:612) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:529) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:491) ~[netty-transport-4.1.33.Final.jar:4.1.33.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:905) ~[netty-common-4.1.33.Final.jar:4.1.33.Final]
at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_201]
Caused by: java.io.UnsupportedEncodingException: Windows collation not supported: D000
at io.r2dbc.mssql.message.type.Collation.getEncodingFromLCID(Collation.java:226) ~[r2dbc-mssql-1.0.0.M7.jar:1.0.0.M7]
at io.r2dbc.mssql.message.type.Collation.<init>(Collation.java:89) ~[r2dbc-mssql-1.0.0.M7.jar:1.0.0.M7]
at io.r2dbc.mssql.message.type.Collation.decode(Collation.java:125) ~[r2dbc-mssql-1.0.0.M7.jar:1.0.0.M7]
... 51 common frames omitted
java.lang.AssertionError: expectation "expectComplete" failed (expected: onComplete(); actual: onError(java.lang.IllegalStateException: Collation not available))
at reactor.test.ErrorFormatter.assertionError(ErrorFormatter.java:105)
at reactor.test.ErrorFormatter.failPrefix(ErrorFormatter.java:94)
at reactor.test.ErrorFormatter.fail(ErrorFormatter.java:64)
at reactor.test.ErrorFormatter.failOptional(ErrorFormatter.java:79)
at reactor.test.DefaultStepVerifierBuilder.lambda$expectComplete$4(DefaultStepVerifierBuilder.java:323)
at reactor.test.DefaultStepVerifierBuilder$SignalEvent.test(DefaultStepVerifierBuilder.java:2112)
at reactor.test.DefaultStepVerifierBuilder$DefaultVerifySubscriber.onSignal(DefaultStepVerifierBuilder.java:1408)
at reactor.test.DefaultStepVerifierBuilder$DefaultVerifySubscriber.onExpectation(DefaultStepVerifierBuilder.java:1356)
at reactor.test.DefaultStepVerifierBuilder$DefaultVerifySubscriber.onError(DefaultStepVerifierBuilder.java:1030)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.checkTerminated(FluxFlatMap.java:790)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.drainLoop(FluxFlatMap.java:560)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.drain(FluxFlatMap.java:540)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onError(FluxFlatMap.java:412)
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyInner.onError(MonoFlatMapMany.java:243)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.checkTerminated(FluxFlatMap.java:790)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.drainLoop(FluxFlatMap.java:560)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.drain(FluxFlatMap.java:540)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onError(FluxFlatMap.java:412)
at reactor.core.publisher.Operators.error(Operators.java:181)
at reactor.core.publisher.FluxDefer.subscribe(FluxDefer.java:50)
at reactor.core.publisher.FluxFlatMap.subscribe(FluxFlatMap.java:97)
at reactor.core.publisher.Flux.subscribe(Flux.java:7777)
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyMain.onNext(MonoFlatMapMany.java:184)
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:114)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1505)
at reactor.core.publisher.MonoDelayUntil$DelayUntilCoordinator.signal(MonoDelayUntil.java:211)
at reactor.core.publisher.MonoDelayUntil$DelayUntilTrigger.onComplete(MonoDelayUntil.java:290)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:252)
at reactor.core.publisher.FluxHandle$HandleSubscriber.onComplete(FluxHandle.java:207)
at reactor.core.publisher.FluxHandle$HandleSubscriber.onNext(FluxHandle.java:128)
at reactor.core.publisher.FluxFilter$FilterConditionalSubscriber.onNext(FluxFilter.java:240)
at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:826)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.drainLoop(FluxFlatMap.java:664)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.drain(FluxFlatMap.java:540)
at reactor.core.publisher.FluxFlatMap$FlatMapInner.onNext(FluxFlatMap.java:940)
at reactor.core.publisher.FluxReplay$UnboundedReplayBuffer.replayFused(FluxReplay.java:626)
at reactor.core.publisher.FluxReplay$UnboundedReplayBuffer.replay(FluxReplay.java:656)
at reactor.core.publisher.FluxReplay$ReplaySubscriber.onNext(FluxReplay.java:1161)
at reactor.core.publisher.FluxWindowPredicate$WindowFlux.drainRegular(FluxWindowPredicate.java:636)
at reactor.core.publisher.FluxWindowPredicate$WindowFlux.drain(FluxWindowPredicate.java:714)
at reactor.core.publisher.FluxWindowPredicate$WindowFlux.onNext(FluxWindowPredicate.java:756)
at reactor.core.publisher.FluxWindowPredicate$WindowPredicateMain.onNext(FluxWindowPredicate.java:227)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:192)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:192)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:192)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:192)
at reactor.core.publisher.FluxHandle$HandleSubscriber.onNext(FluxHandle.java:113)
at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:826)
at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:826)
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.innerNext(FluxConcatMap.java:275)
at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:849)
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.drainSync(FluxFlattenIterable.java:564)
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.drain(FluxFlattenIterable.java:635)
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.request(FluxFlattenIterable.java:266)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:1878)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:1752)
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.onSubscribe(FluxFlattenIterable.java:208)
at reactor.core.publisher.FluxGenerate.subscribe(FluxGenerate.java:83)
at reactor.core.publisher.FluxFlattenIterable.subscribe(FluxFlattenIterable.java:109)
at reactor.core.publisher.Flux.subscribe(Flux.java:7777)
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:442)
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onNext(FluxConcatMap.java:244)
at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:205)
at reactor.netty.channel.FluxReceive.onInboundNext(FluxReceive.java:321)
at reactor.netty.channel.ChannelOperations.onInboundNext(ChannelOperations.java:319)
at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:141)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
at io.r2dbc.mssql.client.ssl.TdsSslHandler.channelRead(TdsSslHandler.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1408)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:677)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:612)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:529)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:491)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:905)
at java.lang.Thread.run(Thread.java:748)
Suppressed: java.lang.IllegalStateException: Collation not available
at io.r2dbc.mssql.client.Client.lambda$getRequiredCollation$0(Client.java:85)
at java.util.Optional.orElseThrow(Optional.java:290)
at io.r2dbc.mssql.client.Client.getRequiredCollation(Client.java:85)
at io.r2dbc.mssql.CursoredQueryMessageFlow.exchange(CursoredQueryMessageFlow.java:112)
at io.r2dbc.mssql.SimpleCursoredMssqlStatement.lambda$execute$1(SimpleCursoredMssqlStatement.java:58)
at reactor.core.publisher.FluxDefer.subscribe(FluxDefer.java:46)
... 73 more
UPDATE: Forgot to add my POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>reactive-sql-sqlserver</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>reactive-sql-sqlserver</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-r2dbc</artifactId>
<version>1.0.0.M1</version>
</dependency>
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-mssql</artifactId>
<version>1.0.0.M7</version>
</dependency>
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-spi</artifactId>
<version>1.0.0.M7</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Thanks in advance for your help.
See r2dbc/r2dbc-spi#23.
Decoding exceptions are not propagated to the resulting Publisher
but bubbled up to the netty handler pipeline. Decode exceptions should be propagated down to the receiver and should also close the connection as decoding issues typically destroy the connection state.
Example:
16:14:19.862 reactor-tcp-nio-1 reactor.core.publisher.Operators Operator called default onErrorDropped
reactor.core.Exceptions$BubblingException: java.lang.IllegalArgumentException: minimumReadableBytes: -1 (expected: >= 0)
at reactor.core.Exceptions.bubble(Exceptions.java:154)
at reactor.core.publisher.FluxGenerate$GenerateSubscription.poll(FluxGenerate.java:364)
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.poll(FluxOnAssembly.java:470)
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.drainSync(FluxFlattenIterable.java:498)
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.drain(FluxFlattenIterable.java:635)
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.request(FluxFlattenIterable.java:266)
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.request(FluxOnAssembly.java:458)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:1849)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:1723)
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onSubscribe(FluxOnAssembly.java:442)
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.onSubscribe(FluxFlattenIterable.java:208)
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onSubscribe(FluxOnAssembly.java:442)
at reactor.core.publisher.FluxGenerate.subscribe(FluxGenerate.java:83)
at reactor.core.publisher.FluxOnAssembly.subscribe(FluxOnAssembly.java:164)
at reactor.core.publisher.FluxFlattenIterable.subscribe(FluxFlattenIterable.java:109)
at reactor.core.publisher.FluxOnAssembly.subscribe(FluxOnAssembly.java:164)
at reactor.core.publisher.Flux.subscribe(Flux.java:7734)
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:442)
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onNext(FluxConcatMap.java:244)
at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:211)
at reactor.netty.channel.FluxReceive.onInboundNext(FluxReceive.java:327)
at reactor.netty.channel.ChannelOperations.onInboundNext(ChannelOperations.java:310)
at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:141)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
at io.r2dbc.mssql.client.ssl.TdsSslHandler.channelRead(TdsSslHandler.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:648)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:583)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:500)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:462)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897)
at java.lang.Thread.run(Thread.java:748)
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Assembly trace from producer [reactor.core.publisher.FluxFlattenIterable] :
reactor.core.publisher.Flux.flatMapIterable(Flux.java:4853)
reactor.core.publisher.Flux.flatMapIterable(Flux.java:4828)
io.r2dbc.mssql.client.StreamDecoder.decode(StreamDecoder.java:123)
io.r2dbc.mssql.client.ReactorNettyClient.lambda$new$4(ReactorNettyClient.java:177)
reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:368)
reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onNext(FluxConcatMap.java:244)
reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:211)
reactor.netty.channel.FluxReceive.onInboundNext(FluxReceive.java:327)
reactor.netty.channel.ChannelOperations.onInboundNext(ChannelOperations.java:310)
reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:141)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
io.r2dbc.mssql.client.ssl.TdsSslHandler.channelRead(TdsSslHandler.java:374)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965)
io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:648)
io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:583)
io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:500)
io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:462)
io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897)
Error has been observed by the following operator(s):
|_ Flux.flatMapIterable ⇢ io.r2dbc.mssql.client.StreamDecoder.decode(StreamDecoder.java:123)
Caused by: java.lang.IllegalArgumentException: minimumReadableBytes: -1 (expected: >= 0)
at io.netty.buffer.AbstractByteBuf.checkReadableBytes(AbstractByteBuf.java:1418)
at io.netty.buffer.AbstractByteBuf.skipBytes(AbstractByteBuf.java:971)
at io.r2dbc.mssql.message.token.RowToken.canDecodeColumn(RowToken.java:125)
at io.r2dbc.mssql.message.token.RowToken.canDecode(RowToken.java:95)
at io.r2dbc.mssql.message.token.Tabular.lambda$decodeFunction$0(Tabular.java:184)
at io.r2dbc.mssql.message.token.Tabular$TabularDecoder.decode(Tabular.java:372)
at io.r2dbc.mssql.client.ConnectionState$4.lambda$decoder$1(ConnectionState.java:194)
at io.r2dbc.mssql.client.StreamDecoder.lambda$decode$1(StreamDecoder.java:94)
at reactor.core.publisher.FluxGenerate$GenerateSubscription.poll(FluxGenerate.java:347)
... 48 common frames omitted
16:14:19.863 reactor-tcp-nio-1 io.netty.channel.AbstractChannelHandlerContext An exception '{}' [enable DEBUG level for full stacktrace] was thrown by a user handler's exceptionCaught() method while handling the following exception:
reactor.core.Exceptions$BubblingException: java.lang.IllegalArgumentException: minimumReadableBytes: -1 (expected: >= 0)
at reactor.core.Exceptions.bubble(Exceptions.java:154)
at reactor.core.publisher.FluxGenerate$GenerateSubscription.poll(FluxGenerate.java:364)
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.poll(FluxOnAssembly.java:470)
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.drainSync(FluxFlattenIterable.java:498)
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.drain(FluxFlattenIterable.java:635)
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.request(FluxFlattenIterable.java:266)
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.request(FluxOnAssembly.java:458)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:1849)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:1723)
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onSubscribe(FluxOnAssembly.java:442)
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.onSubscribe(FluxFlattenIterable.java:208)
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onSubscribe(FluxOnAssembly.java:442)
at reactor.core.publisher.FluxGenerate.subscribe(FluxGenerate.java:83)
at reactor.core.publisher.FluxOnAssembly.subscribe(FluxOnAssembly.java:164)
at reactor.core.publisher.FluxFlattenIterable.subscribe(FluxFlattenIterable.java:109)
at reactor.core.publisher.FluxOnAssembly.subscribe(FluxOnAssembly.java:164)
at reactor.core.publisher.Flux.subscribe(Flux.java:7734)
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:442)
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onNext(FluxConcatMap.java:244)
at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:211)
at reactor.netty.channel.FluxReceive.onInboundNext(FluxReceive.java:327)
at reactor.netty.channel.ChannelOperations.onInboundNext(ChannelOperations.java:310)
at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:141)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
at io.r2dbc.mssql.client.ssl.TdsSslHandler.channelRead(TdsSslHandler.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:648)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:583)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:500)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:462)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897)
at java.lang.Thread.run(Thread.java:748)
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Assembly trace from producer [reactor.core.publisher.FluxFlattenIterable] :
reactor.core.publisher.Flux.flatMapIterable(Flux.java:4853)
reactor.core.publisher.Flux.flatMapIterable(Flux.java:4828)
io.r2dbc.mssql.client.StreamDecoder.decode(StreamDecoder.java:123)
io.r2dbc.mssql.client.ReactorNettyClient.lambda$new$4(ReactorNettyClient.java:177)
reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:368)
reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onNext(FluxConcatMap.java:244)
reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:211)
reactor.netty.channel.FluxReceive.onInboundNext(FluxReceive.java:327)
reactor.netty.channel.ChannelOperations.onInboundNext(ChannelOperations.java:310)
reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:141)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
io.r2dbc.mssql.client.ssl.TdsSslHandler.channelRead(TdsSslHandler.java:374)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965)
io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:648)
io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:583)
io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:500)
io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:462)
io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897)
Error has been observed by the following operator(s):
|_ Flux.flatMapIterable ⇢ io.r2dbc.mssql.client.StreamDecoder.decode(StreamDecoder.java:123)
Caused by: java.lang.IllegalArgumentException: minimumReadableBytes: -1 (expected: >= 0)
at io.netty.buffer.AbstractByteBuf.checkReadableBytes(AbstractByteBuf.java:1418)
at io.netty.buffer.AbstractByteBuf.skipBytes(AbstractByteBuf.java:971)
at io.r2dbc.mssql.message.token.RowToken.canDecodeColumn(RowToken.java:125)
at io.r2dbc.mssql.message.token.RowToken.canDecode(RowToken.java:95)
at io.r2dbc.mssql.message.token.Tabular.lambda$decodeFunction$0(Tabular.java:184)
at io.r2dbc.mssql.message.token.Tabular$TabularDecoder.decode(Tabular.java:372)
at io.r2dbc.mssql.client.ConnectionState$4.lambda$decoder$1(ConnectionState.java:194)
at io.r2dbc.mssql.client.StreamDecoder.lambda$decode$1(StreamDecoder.java:94)
at reactor.core.publisher.FluxGenerate$GenerateSubscription.poll(FluxGenerate.java:347)
... 48 common frames omitted
We should consider caching for Length
and lazily create row consumers instead of pre-preparing row count and row data sequences.
We need a Flux
operator that allows discarding data signals (except terminal signals) when a downstream Subscriber
cancels the subscription. A typical example is:
result.map((row, metadata)-> …).next();
Canceling the subscription can leave data signals non-consumed so the protocol state gets mixed up:
FluxDiscardOnCancel
would behave ideally:
request(Long.MAX_VALUE)
The example
ConnectionFactory connectionFactory = ConnectionFactories.get(ConnectionFactoryOptions.builder()
...
.build());
Mono<Connection> connection = connectionFactory.create();
does not work because ConnectionFactory
returns Publisher<…>
and not Mono<…>
.
ORDER token is used to indicate by which column data is ordered.
It's contained in TDS when a query contains an ORDER BY
clause.
varchar(max)
and nvarchar(max)
are PLP (Partially Length-Prefixed) Data Types and they are not supported by the driver yet.
Using a varchar(max)
column typically results in a decoding exception:
java.lang.IllegalArgumentException: minimumReadableBytes: -1 (expected: >= 0)
at io.netty.buffer.AbstractByteBuf.checkReadableBytes(AbstractByteBuf.java:1418)
at io.netty.buffer.AbstractByteBuf.skipBytes(AbstractByteBuf.java:971)
at io.r2dbc.mssql.message.token.RowToken.canDecodeColumn(RowToken.java:125)
at io.r2dbc.mssql.message.token.RowToken.canDecode(RowToken.java:95)
at io.r2dbc.mssql.message.token.Tabular.lambda$decodeFunction$0(Tabular.java:184)
at io.r2dbc.mssql.message.token.Tabular$TabularDecoder.decode(Tabular.java:372)
Reusing a parametrized statement (multiple subscriptions) fails because bound values (ref-counted) are attempted to be released.
We should either reject the execution early or allow execution multiple times.
Statement.add()
allows the creation of multiple bindings for a prepared statement and so execution of the prepared statements with various bindings ("Prepared Statement Batch"). We should add support for this mode of execution.
The difficulty is to consume/retain protocol state to make sure the next batch is sent when the previous one's response is fully consumed.
We should add support for VARBINARY
to support ByteBuffer
/byte[]
representations of binary data.
Executing a Tabular
decode retains previous column metadata (ColumnMetadataToken
) token and does not replace it when receiving a subsequent token. This leads to decoding errors of row metadata.
We need to check after metadata decoding whether the token is qualified to replate a potential previous metadata token.
We should cache the ParsedQuery
result in the PreparedStatementCache
to allow reuse of parameter information.
We should allow the configuration of fetchSize
on Statement
level to supply a fetch size for cursored execution and to override the cursored execution preference. Setting fetch size to zero enforces direct execution, setting it to a non-negative non-zero value enforces cursored execution.
Spec Update
Currently, this project depends on reactor-extra
, Spring Boot JDBC starter, and transitively on netty-codec-http
(1+2), and netty-handler-proxy
.
We should eliminate dead dependencies.
We should provide a suite of benchmarks to measure the performance and throughput of the driver. Metrics that we should gather:
ParsedQuery
)SQLBATCH
and RPC (Non-parametrized Cursored, Parametrized Direct, Parametrized Cursored)When issuing a query, downstream subscribers of query flows remain subscribed. This causes duplication of signals and a lot of dropped notifications. We should unsubscribe from the message exchange after completing a query execution.
See r2dbc/r2dbc-spi#51 for details.
We should use a cached instance of RowMetadata
(implemented by MssqlRowMetadata
) to not create new instances per row. Metadata does not depend on a particular row, it's bound to a result and it is used to describe that result (see ColumnMetadataToken
).
there is a typo error in readme.
driver: mysql instead of driver: mssql
Server configurations such as Azure require full transport-level support (e.g. Encryption = required). We should add support for full TLS support.
We should be able to interact with sql_variant typed-columns
We sporadically observed test failures caused by remote disconnects. We traced the issue down to protocol frames that remained unconsumed while sending subsequent commands. GeneratedValues.reduceToSingleCountDoneToken(…)
issued a completion signal when it received another count message.
Unconsumed stack frames eventually piled up and SQL server terminated the connection.
When trying to save an object that contains an enum
value, I got the following error:
java.lang.IllegalArgumentException: Cannot encode [MY_VALUE] parameter of type [com.mycompany.MyEnum]
at io.r2dbc.mssql.codec.DefaultCodecs.encode(DefaultCodecs.java:92) ~[r2dbc-mssql-1.0.0.M7.jar:1.0.0.M7]
at io.r2dbc.mssql.PreparedMssqlStatement.bind(PreparedMssqlStatement.java:155) ~[r2dbc-mssql-1.0.0.M7.jar:1.0.0.M7]
at io.r2dbc.mssql.PreparedMssqlStatement.bind(PreparedMssqlStatement.java:57) ~[r2dbc-mssql-1.0.0.M7.jar:1.0.0.M7]
at org.springframework.data.r2dbc.dialect.NamedBindMarkers$NamedBindMarker.bind(NamedBindMarkers.java:105) ~[spring-data-r2dbc-1.0.0.M1.jar:1.0.0.M1]
at org.springframework.data.r2dbc.function.DefaultReactiveDataAccessStrategy$DefaultBindableInsert.bind(DefaultReactiveDataAccessStrategy.java:465) ~[spring-data-r2dbc-1.0.0.M1.jar:1.0.0.M1]
at org.springframework.data.r2dbc.function.BindableOperation.bind(BindableOperation.java:53) ~[spring-data-r2dbc-1.0.0.M1.jar:1.0.0.M1]
at org.springframework.data.r2dbc.function.DefaultDatabaseClient$DefaultTypedInsertSpec.lambda$exchange$2(DefaultDatabaseClient.java:996) ~[spring-data-r2dbc-1.0.0.M1.jar:1.0.0.M1]
at org.springframework.data.r2dbc.function.DefaultDatabaseClient$DefaultTypedInsertSpec.lambda$exchange$3(DefaultDatabaseClient.java:1002) ~[spring-data-r2dbc-1.0.0.M1.jar:1.0.0.M1]
at org.springframework.data.r2dbc.function.DefaultSqlResult$2.apply(DefaultSqlResult.java:81) ~[spring-data-r2dbc-1.0.0.M1.jar:1.0.0.M1]
at org.springframework.data.r2dbc.function.DefaultSqlResult$2.apply(DefaultSqlResult.java:78) ~[spring-data-r2dbc-1.0.0.M1.jar:1.0.0.M1]
at org.springframework.data.r2dbc.function.DefaultDatabaseClient.doInConnectionMany(DefaultDatabaseClient.java:1018) ~[spring-data-r2dbc-1.0.0.M1.jar:1.0.0.M1]
at org.springframework.data.r2dbc.function.DefaultDatabaseClient.lambda$inConnectionMany$2(DefaultDatabaseClient.java:159) ~[spring-data-r2dbc-1.0.0.M1.jar:1.0.0.M1]
There is no EnumCodec yet, but once implemented it should look like the one from postgresql: https://github.com/r2dbc/r2dbc-postgresql/blob/master/src/main/java/io/r2dbc/postgresql/codec/EnumCodec.java
Interestingly decoding of varchar
to an enum
value works. It is decoded to a String
and Springs ConversionService
turns it into an enum
value.
I would have added a codec by myself, but there is no easy way to add a custom codec to DefaultCodecs
.
Evaluate the changes in r2dbc/r2dbc-spi#42 for updates in this implementation.
Executing an insert and returning generated keys returns a duplicate row count via Result.getRowsUpdated(). This is because
DoneInProcTokens are returned for the
INSERT` statement and for the tabular result.
Not sure this affects parametrized queries only, maybe simple queries are affected as well.
Related to #14, we should add support to configure the connectTimeout
option (ConnectionFactoryOptions.CONNECT_TIMEOUT
)
See r2dbc/r2dbc-spi#22.
SQL Server statements can be executed using various execution methods:
We should introduce a Predicate<String>
(or a similar type) and a preference flag whether to prefer direct (cursor-less) or cursored execution. The predicate would allow controlling the preference regarding cursored/non-cursored execution.
Cursored execution has a factor 4 overhead in contrast to direct execution:
SELECT foo FROM bar
)SELECT foo FROM bar
)Parameter binding is not working at all on the latest snapshot or 1.0.0.M7.
Depending on what you do it says
Binding parameters is not supported for the statement [SELECT TOP $1 * FROM metadata
Binding parameters is not supported for the statement [SELECT TOP :size * FROM metadata
executeMany; uncategorized R2dbcException for SQL [SELECT TOP @size * FROM metadata]; Incorrect syntax near '@size'.; nested exception is R2dbcException{errorCode=102, sqlState='S0001'} io.r2dbc.mssql.MssqlException: Incorrect syntax near '@size'.
A prepared statement is recognized when it contains an @
but parameters which such a character cannot be bound. The documentation says named parameters start with :
and indexed with $
.
Error signals in MssqlResult
are emitted directly and this causes cancellation of the upstream subscription. Frames may remain on the upstream source and this breaks downstream/next consumers.
We should defer error emission until receiving a done token and emit the error signal if an error was recorded.
SimpleMssqlStatement
creates a message flow eagerly (i.e. not lazily) and thus it uses the transactional state at the assembly time and not the transactional state on materialization time.
StreamDecoder
attempts to de-chunk a single segment and does not consider multiple chunks/header sequences in its aggregated body. This leaves not decoded segments in the aggregator buffer and protocol sequence does not advance.
This is a blocker for chunks greater 16k.
Related to #58.
Hi, this is a first-timers-only
issue. This means we've worked to make it more legible to folks who either haven't contributed to our codebase before or even folks who haven't contributed to open source before.
If that's you, we're interested in helping you take the first step and can answer questions and help you out as you do. Note that we're especially interested in contributions from people from groups underrepresented in free and open source software!
If you have contributed before, consider leaving this one for someone new, and looking through our general ideal-for-contribution
issues. Thanks!
We should document which SQL Server data types are currently supported by this driver to document features/limitations. Any non-documented data type is not supported.
Right now, it's not obvious which data types can be used and to which Java types SQL Server types map to.
Supported data types can be found by checking for Codec
implementations in the io.r2dbc.mssql.codec
package. Supported data types can be a table (matrix) between the SQL Server data type (e.g. VARCHAR
) and to which Java type it maps to (e.g. java.lang.String
, based on StringCodec
.
The table with the type mapping should be added to our README.md
.
README.md
containing a section which SQL Server data types are currently supported by this driver.This method allows parameter usage with less overhead and less roundtrips.
We currently do not release ReturnValue
s in the cursored RPC flow which leaves byte buffers not released.
Add Statement.returnGeneratedValues(String...)
Ideally, we interchange SQLXML as Clob type. We should also provide a utility to retrieve SQLXML for document parsing and to provide Clob data from a Document.
This driver implementation should implement ConnectionFactory
discovery.
Hi, this is a first-timers-only
issue. This means we've worked to make it more legible to folks who either haven't contributed to our codebase before or even folks who haven't contributed to open source before.
If that's you, we're interested in helping you take the first step and can answer questions and help you out as you do. Note that we're especially interested in contributions from people from groups underrepresented in free and open source software!
If you have contributed before, consider leaving this one for someone new, and looking through our general ideal-for-contribution
issues. Thanks!
SQL server supports more isolation levels than specified in R2DBC SPI.
We would like to support SNAPSHOT
isolation in this driver. R2DBC defines isolation levels in an enum
which makes extension impossible.
R2DBC SPI declares the following levels:
READ_COMMITTED
READ_UNCOMMITTED
REPEATABLE_READ
SERIALIZABLE
SQL Server supports additionally the SNAPSHOT
level.
We need a driver-specific enum that contains all SQL server isolation levels (modelled along the lines of R2DBC's IsolationLevel
enum).
We also need another setTransactionIsolationLevel
method that allows to set the isolation level through the new enumeration.
MssqlIsolationLevel
enum.io.r2dbc.mssql.MssqlConnection
by adding a setTransactionIsolationLevel(MssqlIsolationLevel)
method.MssqlConnectionUnitTests
.We should add support for SQL Server geometry/geography types that serialize and deserialize from/to Well-Known-Text/Well-Known-Binary representations and expose geometry/geography properties according to SQL Server specs.
See also:
I am using UUID
/ uniqueidentifier
primary keys.
CREATE TABLE test (
id UNIQUEIDENTIFIER DEFAULT NEWID(),
text VARCHAR(255)
)
When inserting a new object, I dont get the generated id. GENERATED_KEYS
is empty.
INSERT INTO test (text) VALUES('test') select SCOPE_IDENTITY() AS GENERATED_KEYS;
Will return NULL
.
That is an issue of SQL Server but the workaround would be to use the OUTPUT
syntax:
INSERT INTO test (text) OUTPUT inserted.id VALUES('test');
That will actually return something like | id | B5BA707B-872E-4BFC-8A96-97A1D789E74C |
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.