io.r2dbc.postgresql.codec.NumericDecodeUtils Maven / Gradle / Ivy
/*
* Copyright 2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.r2dbc.postgresql.codec;
import io.netty.buffer.ByteBuf;
import io.r2dbc.postgresql.message.Format;
import io.r2dbc.postgresql.util.Assert;
import io.r2dbc.postgresql.util.ByteBufUtils;
import reactor.util.annotation.Nullable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import static io.r2dbc.postgresql.message.Format.FORMAT_BINARY;
/**
* Utility methods to decode a numeric value.
*/
final class NumericDecodeUtils {
private NumericDecodeUtils() {
}
/**
* Decode {@code buffer} to {@link Number} according to {@link PostgresqlObjectId}.
*
* @param buffer the data buffer
* @param dataType the well-known {@link PostgresqlObjectId type OID}
* @param format the data type {@link Format}, text or binary
* @return the decoded number
*/
public static Number decodeNumber(ByteBuf buffer, PostgresqlObjectId dataType, @Nullable Format format) {
Assert.requireNonNull(buffer, "byteBuf must not be null");
switch (dataType) {
case NUMERIC:
case NUMERIC_ARRAY:
if (format == FORMAT_BINARY) {
return decodeBinary(buffer);
}
return new BigDecimal(ByteBufUtils.decode(buffer));
case INT2:
case INT2_ARRAY:
if (FORMAT_BINARY == format) {
return buffer.readShort();
}
return Short.parseShort(ByteBufUtils.decode(buffer));
case INT4:
case INT4_ARRAY:
if (FORMAT_BINARY == format) {
return buffer.readInt();
}
return Integer.parseInt(ByteBufUtils.decode(buffer));
case OID:
case OID_ARRAY:
if (FORMAT_BINARY == format) {
return buffer.readUnsignedInt();
}
return Long.parseLong(ByteBufUtils.decode(buffer));
case INT8:
case INT8_ARRAY:
if (FORMAT_BINARY == format) {
return buffer.readLong();
}
return Long.parseLong(ByteBufUtils.decode(buffer));
case FLOAT4:
case FLOAT4_ARRAY:
if (FORMAT_BINARY == format) {
return buffer.readFloat();
}
return Float.parseFloat(ByteBufUtils.decode(buffer));
case FLOAT8:
case FLOAT8_ARRAY:
if (FORMAT_BINARY == format) {
return buffer.readDouble();
}
return Double.parseDouble(ByteBufUtils.decode(buffer));
default:
throw new UnsupportedOperationException(String.format("Cannot decode value for type %s, format %s", dataType, format));
}
}
public static BigDecimal decodeBinary(ByteBuf byteBuf) {
// extract values
short numOfDigits = byteBuf.readShort();
if (numOfDigits == 0) {
return BigDecimal.ZERO;
}
short weight = byteBuf.readShort();
short sign = byteBuf.readShort();
short scale = byteBuf.readShort();
short[] digits = new short[numOfDigits];
for (short i = 0; i < numOfDigits; i++) {
digits[i] = byteBuf.readShort();
}
StringBuilder sb = new StringBuilder((sign != 0 ? 1 : 0) + 2 + (digits.length * 4));
if (sign != 0) {
sb.append("-");
}
sb.append("0.");
for (short digit : digits) {
String rendered = "" + digit;
int padded = rendered.length();
while (padded < 4) {
sb.append("0");
padded++;
}
sb.append(rendered);
}
return new BigDecimal(sb.toString()).movePointRight((weight + 1) * 4).setScale(scale, RoundingMode.DOWN);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy