Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[R2DBC-76] MEDIUM value decoding leave resultset in a bad shape : MED…
…IUM are encoded on 3 bytes server side, but protocol send them in 4 bytes in exchange when using binary protocol.

This remaining byte is not read, losing resultset next read on the same row.
  • Loading branch information
rusher committed Jan 5, 2023
1 parent 2ef16dc commit 08b3e06
Show file tree
Hide file tree
Showing 12 changed files with 76 additions and 28 deletions.
Expand Up @@ -109,10 +109,10 @@ public BigDecimal decodeBinary(
return BigDecimal.valueOf((int) buf.readShortLE());

case MEDIUMINT:
if (!column.isSigned()) {
return BigDecimal.valueOf((buf.readUnsignedMediumLE()));
}
return BigDecimal.valueOf(buf.readMediumLE());
BigDecimal v =
BigDecimal.valueOf(column.isSigned() ? buf.readMediumLE() : buf.readUnsignedMediumLE());
buf.readByte(); // needed since binary protocol exchange for medium are on 4 bytes
return v;

case INTEGER:
if (!column.isSigned()) {
Expand Down
Expand Up @@ -120,10 +120,10 @@ public BigInteger decodeBinary(
return BigInteger.valueOf((int) buf.readShortLE());

case MEDIUMINT:
if (!column.isSigned()) {
return BigInteger.valueOf((buf.readUnsignedMediumLE()));
}
return BigInteger.valueOf(buf.readMediumLE());
BigInteger v =
BigInteger.valueOf(column.isSigned() ? buf.readMediumLE() : buf.readUnsignedMediumLE());
buf.readByte(); // needed since binary protocol exchange for medium are on 4 bytes
return v;

case INTEGER:
if (!column.isSigned()) {
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/org/mariadb/r2dbc/codec/list/BooleanCodec.java
Expand Up @@ -109,7 +109,10 @@ public Boolean decodeBinary(
return buf.readShortLE() != 0;

case MEDIUMINT:
return buf.readMediumLE() != 0;
boolean b = buf.readMediumLE() != 0;
buf.readByte(); // needed since binary protocol exchange for medium are on 4 bytes
return b;

case INTEGER:
return buf.readIntLE() != 0;
case BIGINT:
Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/mariadb/r2dbc/codec/list/ByteCodec.java
Expand Up @@ -139,6 +139,7 @@ public Byte decodeBinary(

case MEDIUMINT:
result = column.isSigned() ? buf.readMediumLE() : buf.readUnsignedMediumLE();
buf.readByte(); // needed since binary protocol exchange for medium are on 4 bytes
break;

case INTEGER:
Expand Down
7 changes: 3 additions & 4 deletions src/main/java/org/mariadb/r2dbc/codec/list/DoubleCodec.java
Expand Up @@ -101,10 +101,9 @@ public Double decodeBinary(
return (double) buf.readShortLE();

case MEDIUMINT:
if (!column.isSigned()) {
return (double) buf.readUnsignedMediumLE();
}
return (double) buf.readMediumLE();
double v = column.isSigned() ? buf.readMediumLE() : buf.readUnsignedMediumLE();
buf.readByte(); // needed since binary protocol exchange for medium are on 4 bytes
return v;

case INTEGER:
if (!column.isSigned()) {
Expand Down
7 changes: 3 additions & 4 deletions src/main/java/org/mariadb/r2dbc/codec/list/FloatCodec.java
Expand Up @@ -102,10 +102,9 @@ public Float decodeBinary(
return (float) buf.readShortLE();

case MEDIUMINT:
if (!column.isSigned()) {
return (float) buf.readUnsignedMediumLE();
}
return (float) buf.readMediumLE();
float v = column.isSigned() ? buf.readMediumLE() : buf.readUnsignedMediumLE();
buf.readByte(); // needed since binary protocol exchange for medium are on 4 bytes
return v;

case INTEGER:
if (!column.isSigned()) {
Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/mariadb/r2dbc/codec/list/IntCodec.java
Expand Up @@ -123,6 +123,7 @@ public Integer decodeBinary(

case MEDIUMINT:
result = column.isSigned() ? buf.readMediumLE() : buf.readUnsignedMediumLE();
buf.readByte(); // needed since binary protocol exchange for medium are on 4 bytes
break;

case BIGINT:
Expand Down
7 changes: 3 additions & 4 deletions src/main/java/org/mariadb/r2dbc/codec/list/LongCodec.java
Expand Up @@ -179,10 +179,9 @@ public Long decodeBinary(
return (long) buf.readShortLE();

case MEDIUMINT:
if (!column.isSigned()) {
return (long) buf.readUnsignedMediumLE();
}
return (long) buf.readMediumLE();
long v = column.isSigned() ? buf.readMediumLE() : buf.readUnsignedMediumLE();
buf.readByte(); // needed since binary protocol exchange for medium are on 4 bytes
return v;

case INTEGER:
if (!column.isSigned()) {
Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/mariadb/r2dbc/codec/list/ShortCodec.java
Expand Up @@ -112,6 +112,7 @@ public Short decodeBinary(

case MEDIUMINT:
result = column.isSigned() ? buf.readMediumLE() : buf.readUnsignedMediumLE();
buf.readByte(); // needed since binary protocol exchange for medium are on 4 bytes
break;

case INTEGER:
Expand Down
Expand Up @@ -82,10 +82,17 @@ void localDateValuePrepare() {

private void localDateValue(MariadbConnection connection) {
connection
.createStatement("SELECT t1 FROM DateTable WHERE 1 = ?")
.createStatement("SELECT t1,t2 FROM DateTable WHERE 1 = ?")
.bind(0, 1)
.execute()
.flatMap(r -> r.map((row, metadata) -> Optional.ofNullable(row.get(0, LocalDate.class))))
.flatMap(
r ->
r.map(
(row, metadata) -> {
row.get(0, LocalDate.class);
row.get(1);
return Optional.ofNullable(row.get(0, LocalDate.class));
}))
.as(StepVerifier::create)
.expectNext(
Optional.of(LocalDate.parse("2010-01-12")),
Expand Down
Expand Up @@ -9,6 +9,7 @@
import java.math.BigInteger;
import java.util.Optional;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.mariadb.r2dbc.BaseConnectionTest;
Expand Down Expand Up @@ -440,6 +441,42 @@ private void decimalValue(MariadbConnection connection) {
Optional.of(BigDecimal.valueOf(-1)),
Optional.empty())
.verifyComplete();

connection
.createStatement("SELECT t1, t2 FROM MediumIntTable WHERE 1 = ?")
.bind(0, 1)
.execute()
.flatMap(
r ->
r.map(
(row, metadata) -> {
return new BigDecimal[] {
row.get(0, BigDecimal.class), row.get(1, BigDecimal.class)
};
}))
.as(StepVerifier::create)
.assertNext(
r -> {
Assertions.assertEquals(0, r[0].intValue());
Assertions.assertEquals(0, r[1].intValue());
})
.assertNext(
r -> {
Assertions.assertEquals(1, r[0].intValue());
Assertions.assertEquals(10, r[1].intValue());
})
.assertNext(
r -> {
Assertions.assertEquals(-1, r[0].intValue());
Assertions.assertEquals(100, r[1].intValue());
})
.assertNext(
r -> {
Assertions.assertNull(r[0]);
Assertions.assertNull(r[1]);
})
.verifyComplete();

connection
.createStatement("SELECT t1 FROM MediumIntUnsignedTable WHERE 1 = ?")
.bind(0, 1)
Expand Down
Expand Up @@ -123,25 +123,26 @@ private void defaultValue(MariadbConnection connection) {
.verifyComplete();
}


@Test
void tt() {
String b = "0xFFBF0F23485930303054686520636C69656E742077617320646973636F6E6E656374656420627920746865207365727665722062656361757365206F6620696E61637469766974792E2053656520776169745F74696D656F757420616E6420696E7465726163746976655F74696D656F757420666F7220636F6E6669677572696E672074686973206265686176696F722E";
String b =
"0xFFBF0F23485930303054686520636C69656E742077617320646973636F6E6E656374656420627920746865207365727665722062656361757365206F6620696E61637469766974792E2053656520776169745F74696D656F757420616E6420696E7465726163746976655F74696D656F757420666F7220636F6E6669677572696E672074686973206265686176696F722E";
byte[] bytes = hexStringToByteArray(b);
String st = new String(bytes, StandardCharsets.UTF_8);
System.out.println(st);

}

public static byte[] hexStringToByteArray(String hex) {
int l = hex.length();
byte[] data = new byte[l / 2];
for (int i = 0; i < l; i += 2) {
data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
+ Character.digit(hex.charAt(i + 1), 16));
data[i / 2] =
(byte)
((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16));
}
return data;
}

@Test
void defaultValueBinary() {
defaultValueBinary(sharedConn);
Expand Down

0 comments on commit 08b3e06

Please sign in to comment.