Skip to content

Commit 1f34f4e

Browse files
committed
Numeric casting
[pgjdbc#378]
1 parent 07666b1 commit 1f34f4e

13 files changed

+235
-113
lines changed

src/main/java/io/r2dbc/postgresql/codec/AbstractNumericCodec.java

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,20 @@
1717
package io.r2dbc.postgresql.codec;
1818

1919
import io.netty.buffer.ByteBuf;
20+
import io.netty.buffer.ByteBufAllocator;
2021
import io.r2dbc.postgresql.client.EncodedParameter;
2122
import io.r2dbc.postgresql.message.Format;
2223
import io.r2dbc.postgresql.type.PostgresqlObjectId;
2324
import io.r2dbc.postgresql.util.Assert;
25+
import io.r2dbc.postgresql.util.ByteBufUtils;
2426
import reactor.util.annotation.Nullable;
2527

2628
import java.util.EnumSet;
2729
import java.util.Set;
2830
import java.util.function.Function;
2931

3032
import static io.r2dbc.postgresql.message.Format.FORMAT_BINARY;
33+
import static io.r2dbc.postgresql.message.Format.FORMAT_TEXT;
3134
import static io.r2dbc.postgresql.type.PostgresqlObjectId.FLOAT4;
3235
import static io.r2dbc.postgresql.type.PostgresqlObjectId.FLOAT8;
3336
import static io.r2dbc.postgresql.type.PostgresqlObjectId.INT2;
@@ -45,13 +48,11 @@ abstract class AbstractNumericCodec<T extends Number> extends AbstractCodec<T> {
4548

4649
private static final Set<PostgresqlObjectId> SUPPORTED_TYPES = EnumSet.of(INT2, INT4, INT8, FLOAT4, FLOAT8, NUMERIC, OID);
4750

48-
/**
49-
* Create a new {@link AbstractCodec}.
50-
*
51-
* @param type the type handled by this codec
52-
*/
53-
AbstractNumericCodec(Class<T> type) {
51+
private final ByteBufAllocator byteBufAllocator;
52+
53+
AbstractNumericCodec(Class<T> type, ByteBufAllocator byteBufAllocator) {
5454
super(type);
55+
this.byteBufAllocator = Assert.requireNonNull(byteBufAllocator, "byteBufAllocator must not be null");
5556
}
5657

5758
@Override
@@ -81,6 +82,40 @@ EncodedParameter doEncode(T value) {
8182
return doEncode(value, getDefaultType());
8283
}
8384

85+
EncodedParameter doEncode(T value, PostgresqlObjectId dataType) {
86+
Assert.requireNonNull(value, "value must not be null");
87+
88+
if (dataType == NUMERIC) {
89+
return create(FORMAT_TEXT, dataType, () -> ByteBufUtils.encode(this.byteBufAllocator, value.toString()));
90+
}
91+
92+
return create(FORMAT_BINARY, dataType, () -> doEncodeNumber(value, dataType));
93+
}
94+
95+
private ByteBuf doEncodeNumber(Number value, PostgresqlObjectId dataType) {
96+
97+
switch (dataType) {
98+
99+
case FLOAT8:
100+
return this.byteBufAllocator.buffer(8).writeDouble(value.doubleValue());
101+
102+
case FLOAT4:
103+
return this.byteBufAllocator.buffer(4).writeFloat(value.floatValue());
104+
105+
case INT8:
106+
return this.byteBufAllocator.buffer(8).writeLong(value.longValue());
107+
108+
case INT4:
109+
return this.byteBufAllocator.buffer(4).writeInt(value.intValue());
110+
111+
case INT2:
112+
return this.byteBufAllocator.buffer(4).writeShort(value.shortValue());
113+
}
114+
115+
throw new IllegalArgumentException(String.format("Cannot encode %s to %s", value, dataType));
116+
117+
}
118+
84119
/**
85120
* Decode {@code buffer} to {@link Number} and potentially convert it to {@link Class expectedType} using {@link Function converter} if the decoded type does not match {@code expectedType}.
86121
*

src/main/java/io/r2dbc/postgresql/codec/BigDecimalCodec.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ final class BigDecimalCodec extends AbstractNumericCodec<BigDecimal> {
3535
private final ByteBufAllocator byteBufAllocator;
3636

3737
BigDecimalCodec(ByteBufAllocator byteBufAllocator) {
38-
super(BigDecimal.class);
38+
super(BigDecimal.class, byteBufAllocator);
3939
this.byteBufAllocator = Assert.requireNonNull(byteBufAllocator, "byteBufAllocator must not be null");
4040
}
4141

src/main/java/io/r2dbc/postgresql/codec/BigIntegerCodec.java

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,20 @@
1818

1919
import io.netty.buffer.ByteBuf;
2020
import io.netty.buffer.ByteBufAllocator;
21-
import io.r2dbc.postgresql.client.EncodedParameter;
2221
import io.r2dbc.postgresql.message.Format;
2322
import io.r2dbc.postgresql.type.PostgresqlObjectId;
2423
import io.r2dbc.postgresql.util.Assert;
25-
import io.r2dbc.postgresql.util.ByteBufUtils;
2624
import reactor.util.annotation.Nullable;
2725

2826
import java.math.BigDecimal;
2927
import java.math.BigInteger;
3028

31-
import static io.r2dbc.postgresql.message.Format.FORMAT_TEXT;
3229
import static io.r2dbc.postgresql.type.PostgresqlObjectId.NUMERIC;
3330

3431
final class BigIntegerCodec extends AbstractNumericCodec<BigInteger> {
3532

36-
private final ByteBufAllocator byteBufAllocator;
37-
3833
public BigIntegerCodec(ByteBufAllocator byteBufAllocator) {
39-
super(BigInteger.class);
40-
this.byteBufAllocator = Assert.requireNonNull(byteBufAllocator, "byteBufAllocator must not be null");
34+
super(BigInteger.class, byteBufAllocator);
4135
}
4236

4337
@Override
@@ -49,13 +43,6 @@ BigInteger doDecode(ByteBuf buffer, PostgresqlObjectId dataType, @Nullable Forma
4943
});
5044
}
5145

52-
@Override
53-
EncodedParameter doEncode(BigInteger value, PostgresqlObjectId dataType) {
54-
Assert.requireNonNull(value, "value must not be null");
55-
56-
return create(FORMAT_TEXT, dataType, () -> ByteBufUtils.encode(this.byteBufAllocator, value.toString()));
57-
}
58-
5946
@Override
6047
PostgresqlObjectId getDefaultType() {
6148
return NUMERIC;

src/main/java/io/r2dbc/postgresql/codec/DefaultCodecs.java

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import io.netty.buffer.ByteBufAllocator;
2121
import io.r2dbc.postgresql.client.EncodedParameter;
2222
import io.r2dbc.postgresql.message.Format;
23+
import io.r2dbc.postgresql.type.PostgresTypeIdentifier;
2324
import io.r2dbc.postgresql.type.PostgresqlObjectId;
2425
import io.r2dbc.postgresql.util.Assert;
2526
import io.r2dbc.spi.Parameter;
@@ -175,24 +176,30 @@ public EncodedParameter encode(Object value) {
175176
Parameter parameter = (Parameter) value;
176177
parameterValue = parameter.getValue();
177178

178-
if (parameter.getType() instanceof Type.InferredType) {
179-
180-
if (parameterValue == null) {
181-
throw new IllegalArgumentException("Cannot encode null values using type inference");
182-
}
179+
if (parameter.getType() instanceof Type.InferredType && parameterValue == null) {
180+
return encodeNull(parameter.getType().getJavaType());
181+
}
183182

184-
} else if (parameter.getType() instanceof R2dbcTypes) {
183+
if (parameter.getType() instanceof R2dbcTypes) {
185184

186185
PostgresqlObjectId targetType = PostgresqlObjectId.valueOf((R2dbcTypes) parameter.getType());
187186
dataType = targetType.getObjectId();
188187
}
188+
189+
if (parameter.getType() instanceof PostgresTypeIdentifier) {
190+
dataType = ((PostgresTypeIdentifier) parameter.getType()).getObjectId();
191+
}
189192
}
190193

191194
if (dataType == -1) {
192195

196+
if (parameterValue == null) {
197+
throw new IllegalArgumentException(String.format("Cannot encode null value %s using type inference", value));
198+
}
199+
193200
for (Codec<?> codec : this.codecs) {
194-
if (codec.canEncode(value)) {
195-
return codec.encode(value);
201+
if (codec.canEncode(parameterValue)) {
202+
return codec.encode(parameterValue);
196203
}
197204
}
198205
} else {
@@ -203,14 +210,14 @@ public EncodedParameter encode(Object value) {
203210

204211
for (Codec<?> codec : this.codecs) {
205212

206-
if (codec.canEncode(value)) {
207-
return codec.encode(value, dataType);
213+
if (codec.canEncode(parameterValue)) {
214+
return codec.encode(parameterValue, dataType);
208215
}
209216
}
210217
}
211218
}
212219

213-
throw new IllegalArgumentException(String.format("Cannot encode parameter of type %s", value.getClass().getName()));
220+
throw new IllegalArgumentException(String.format("Cannot encode parameter of type %s (%s)", value.getClass().getName(), parameterValue));
214221
}
215222

216223
@Override

src/main/java/io/r2dbc/postgresql/codec/DoubleCodec.java

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,17 @@
1818

1919
import io.netty.buffer.ByteBuf;
2020
import io.netty.buffer.ByteBufAllocator;
21-
import io.r2dbc.postgresql.client.EncodedParameter;
2221
import io.r2dbc.postgresql.message.Format;
2322
import io.r2dbc.postgresql.type.PostgresqlObjectId;
2423
import io.r2dbc.postgresql.util.Assert;
2524
import reactor.util.annotation.Nullable;
2625

27-
import static io.r2dbc.postgresql.message.Format.FORMAT_BINARY;
2826
import static io.r2dbc.postgresql.type.PostgresqlObjectId.FLOAT8;
2927

3028
final class DoubleCodec extends AbstractNumericCodec<Double> {
3129

32-
private final ByteBufAllocator byteBufAllocator;
33-
3430
DoubleCodec(ByteBufAllocator byteBufAllocator) {
35-
super(Double.class);
36-
this.byteBufAllocator = Assert.requireNonNull(byteBufAllocator, "byteBufAllocator must not be null");
31+
super(Double.class, byteBufAllocator);
3732
}
3833

3934
@Override
@@ -44,11 +39,6 @@ Double doDecode(ByteBuf buffer, PostgresqlObjectId dataType, Format format, @Nul
4439
return decodeNumber(buffer, dataType, format, Double.class, Number::doubleValue);
4540
}
4641

47-
@Override
48-
EncodedParameter doEncode(Double value, PostgresqlObjectId dataType) {
49-
return create(FORMAT_BINARY, dataType, () -> this.byteBufAllocator.buffer(8).writeDouble(value));
50-
}
51-
5242
@Override
5343
PostgresqlObjectId getDefaultType() {
5444
return FLOAT8;

src/main/java/io/r2dbc/postgresql/codec/FloatCodec.java

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,17 @@
1818

1919
import io.netty.buffer.ByteBuf;
2020
import io.netty.buffer.ByteBufAllocator;
21-
import io.r2dbc.postgresql.client.EncodedParameter;
2221
import io.r2dbc.postgresql.message.Format;
2322
import io.r2dbc.postgresql.type.PostgresqlObjectId;
2423
import io.r2dbc.postgresql.util.Assert;
2524
import reactor.util.annotation.Nullable;
2625

27-
import static io.r2dbc.postgresql.message.Format.FORMAT_BINARY;
2826
import static io.r2dbc.postgresql.type.PostgresqlObjectId.FLOAT4;
2927

3028
final class FloatCodec extends AbstractNumericCodec<Float> {
3129

32-
private final ByteBufAllocator byteBufAllocator;
33-
3430
FloatCodec(ByteBufAllocator byteBufAllocator) {
35-
super(Float.class);
36-
this.byteBufAllocator = Assert.requireNonNull(byteBufAllocator, "byteBufAllocator must not be null");
31+
super(Float.class, byteBufAllocator);
3732
}
3833

3934
@Override
@@ -44,11 +39,6 @@ Float doDecode(ByteBuf buffer, PostgresqlObjectId dataType, Format format, @Null
4439
return decodeNumber(buffer, dataType, format, Float.class, Number::floatValue);
4540
}
4641

47-
@Override
48-
EncodedParameter doEncode(Float value, PostgresqlObjectId dataType) {
49-
return create(FORMAT_BINARY, dataType, () -> this.byteBufAllocator.buffer(4).writeFloat(value));
50-
}
51-
5242
@Override
5343
PostgresqlObjectId getDefaultType() {
5444
return FLOAT4;

src/main/java/io/r2dbc/postgresql/codec/IntegerCodec.java

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,17 @@
1818

1919
import io.netty.buffer.ByteBuf;
2020
import io.netty.buffer.ByteBufAllocator;
21-
import io.r2dbc.postgresql.client.EncodedParameter;
2221
import io.r2dbc.postgresql.message.Format;
2322
import io.r2dbc.postgresql.type.PostgresqlObjectId;
2423
import io.r2dbc.postgresql.util.Assert;
2524
import reactor.util.annotation.Nullable;
2625

27-
import static io.r2dbc.postgresql.message.Format.FORMAT_BINARY;
2826
import static io.r2dbc.postgresql.type.PostgresqlObjectId.INT4;
2927

3028
final class IntegerCodec extends AbstractNumericCodec<Integer> {
3129

32-
private final ByteBufAllocator byteBufAllocator;
33-
3430
IntegerCodec(ByteBufAllocator byteBufAllocator) {
35-
super(Integer.class);
36-
this.byteBufAllocator = Assert.requireNonNull(byteBufAllocator, "byteBufAllocator must not be null");
31+
super(Integer.class, byteBufAllocator);
3732
}
3833

3934
@Override
@@ -44,11 +39,6 @@ Integer doDecode(ByteBuf buffer, PostgresqlObjectId dataType, @Nullable Format f
4439
return decodeNumber(buffer, dataType, format, Integer.class, Number::intValue);
4540
}
4641

47-
@Override
48-
EncodedParameter doEncode(Integer value, PostgresqlObjectId dataType) {
49-
return create(FORMAT_BINARY, dataType, () -> this.byteBufAllocator.buffer(4).writeInt(value));
50-
}
51-
5242
@Override
5343
PostgresqlObjectId getDefaultType() {
5444
return INT4;

src/main/java/io/r2dbc/postgresql/codec/LongCodec.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,18 @@
1818

1919
import io.netty.buffer.ByteBuf;
2020
import io.netty.buffer.ByteBufAllocator;
21-
import io.r2dbc.postgresql.client.EncodedParameter;
2221
import io.r2dbc.postgresql.message.Format;
2322
import io.r2dbc.postgresql.type.PostgresqlObjectId;
2423
import io.r2dbc.postgresql.util.Assert;
2524
import reactor.util.annotation.Nullable;
2625

27-
import static io.r2dbc.postgresql.message.Format.FORMAT_BINARY;
2826
import static io.r2dbc.postgresql.type.PostgresqlObjectId.INT8;
2927

3028
final class LongCodec extends AbstractNumericCodec<Long> {
3129

32-
private final ByteBufAllocator byteBufAllocator;
3330

3431
LongCodec(ByteBufAllocator byteBufAllocator) {
35-
super(Long.class);
36-
this.byteBufAllocator = Assert.requireNonNull(byteBufAllocator, "byteBufAllocator must not be null");
32+
super(Long.class, byteBufAllocator);
3733
}
3834

3935
@Override
@@ -44,11 +40,6 @@ Long doDecode(ByteBuf buffer, PostgresqlObjectId dataType, Format format, @Nulla
4440
return decodeNumber(buffer, dataType, format, Long.class, Number::longValue);
4541
}
4642

47-
@Override
48-
EncodedParameter doEncode(Long value, PostgresqlObjectId dataType) {
49-
return create(FORMAT_BINARY, dataType, () -> this.byteBufAllocator.buffer(8).writeLong(value));
50-
}
51-
5243
@Override
5344
PostgresqlObjectId getDefaultType() {
5445
return INT8;

src/main/java/io/r2dbc/postgresql/codec/PostgresTypes.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package io.r2dbc.postgresql.codec;
1818

1919
import io.r2dbc.postgresql.api.PostgresqlConnection;
20+
import io.r2dbc.postgresql.type.PostgresTypeIdentifier;
2021
import io.r2dbc.postgresql.util.Assert;
2122
import reactor.core.publisher.Flux;
2223
import reactor.core.publisher.Mono;
@@ -96,7 +97,7 @@ public Flux<PostgresType> lookupTypes(Iterable<String> typeNames) {
9697

9798
}
9899

99-
public static class PostgresType {
100+
public static class PostgresType implements PostgresTypeIdentifier {
100101

101102
private final int oid;
102103

@@ -110,10 +111,21 @@ public PostgresType(int oid, String name, String category) {
110111
this.category = category;
111112
}
112113

114+
@Override
115+
public int getObjectId() {
116+
return getOid();
117+
}
118+
113119
public int getOid() {
114120
return this.oid;
115121
}
116122

123+
@Override
124+
public Class<?> getJavaType() {
125+
return Object.class;
126+
}
127+
128+
@Override
117129
public String getName() {
118130
return this.name;
119131
}

0 commit comments

Comments
 (0)