You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by wu...@apache.org on 2022/02/15 05:27:36 UTC
[shardingsphere] branch master updated: Numeric type supported for PostgreSQL (#15366)
This is an automated email from the ASF dual-hosted git repository.
wuweijie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new a9d4987 Numeric type supported for PostgreSQL (#15366)
a9d4987 is described below
commit a9d49873dded90fd0e264ea25e37beb2266506f6
Author: gin <ja...@163.com>
AuthorDate: Tue Feb 15 13:26:19 2022 +0800
Numeric type supported for PostgreSQL (#15366)
* Numeric type supported for PostgreSQL
* Optimize PostgreSQL byte converter
* Fix PostgreSQL byte converter test
* Fix PostgreSQL byte converter test to byte array
---
.../bind/protocol/PostgreSQLByteConverter.java | 418 +++++++++++++++++++++
.../PostgreSQLNumericBinaryProtocolValue.java | 3 +-
.../bind/protocol/PostgreSQLByteConverterTest.java | 55 +++
.../PostgreSQLNumericBinaryProtocolValueTest.java | 10 +-
.../shadow/postgresql/pro_insert_order_value.xml | 2 +-
.../postgresql/pro_update_order_by_user_id.xml | 4 +-
.../postgresql/shadow_insert_order_value.xml | 2 +-
.../postgresql/shadow_update_order_by_user_id.xml | 4 +-
.../cases/dml/dml-integration-test-cases.xml | 16 +-
.../env/shadow/init-sql/postgresql/init.sql | 4 +-
10 files changed, 494 insertions(+), 24 deletions(-)
diff --git a/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/main/java/org/apache/shardingsphere/db/protocol/postgresql/packet/command/query/extended/bind/protocol/PostgreSQLByteConverter.java b/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/main/java/org/apache/shardingsphere/db/protocol/postgresql/packet/command/query/extended/bind/protocol/PostgreSQLByteConverter.java
new file mode 100644
index 0000000..a43d86b
--- /dev/null
+++ b/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/main/java/org/apache/shardingsphere/db/protocol/postgresql/packet/command/query/extended/bind/protocol/PostgreSQLByteConverter.java
@@ -0,0 +1,418 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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 org.apache.shardingsphere.db.protocol.postgresql.packet.command.query.extended.bind.protocol;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Arrays;
+
+/**
+ * Refer to
+ * <a href="https://github.com/pgjdbc/pgjdbc/blob/REL42.3.2/pgjdbc/src/main/java/org/postgresql/util/ByteConverter.java" >
+ * org.postgresql.util.ByteConverter
+ * </a>.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class PostgreSQLByteConverter {
+
+ private static final short NUMERIC_POS = 0x0000;
+
+ private static final short NUMERIC_NEG = 0x4000;
+
+ private static final short NUMERIC_NAN = (short) 0xC000;
+
+ private static final int[] INT_TEN_POWERS = new int[6];
+
+ private static final BigInteger[] BI_TEN_POWERS = new BigInteger[32];
+
+ private static final BigInteger BI_TEN_THOUSAND = BigInteger.valueOf(10000);
+
+ static {
+ for (int i = 0; i < INT_TEN_POWERS.length; ++i) {
+ INT_TEN_POWERS[i] = (int) Math.pow(10, i);
+ }
+ for (int i = 0; i < BI_TEN_POWERS.length; ++i) {
+ BI_TEN_POWERS[i] = BigInteger.TEN.pow(i);
+ }
+ }
+
+ /**
+ * Convert a variable length array of bytes to an number.
+ *
+ * @param bytes array of bytes that can be decoded as an integer
+ * @return number
+ */
+ public static Number numeric(final byte[] bytes) {
+ return numeric(bytes, 0);
+ }
+
+ /**
+ * Convert a variable length array of bytes to an number.
+ *
+ * @param bytes array of bytes that can be decoded as an integer
+ * @param pos index of the start position of the bytes array for number
+ * @return number
+ */
+ public static Number numeric(final byte[] bytes, final int pos) {
+ short sign = readShort2(bytes, pos + 4);
+ short scale = readShort2(bytes, pos + 6);
+ validator(sign, scale);
+ if (sign == NUMERIC_NAN) {
+ return Double.NaN;
+ }
+ short len = readShort2(bytes, pos);
+ if (len == 0) {
+ return new BigDecimal(BigInteger.ZERO, scale);
+ }
+ short weight = readShort2(bytes, pos + 2);
+ if (weight < 0) {
+ ++weight;
+ return initBigDecimalNoneWeight(bytes, pos, len, weight, sign, scale);
+ } else if (scale == 0) {
+ return initBigDecimalNoneScale(bytes, pos, len, weight, sign);
+ } else {
+ return initBigDecimal(bytes, pos, len, weight, sign, scale);
+ }
+ }
+
+ /**
+ * Converts a non-null {@link BigDecimal} to binary.
+ *
+ * @param number number to represent in binary.
+ * @return The binary representation of <i>input</i>.
+ */
+ public static byte[] numeric(final BigDecimal number) {
+ BigInteger unscaled = number.unscaledValue().abs();
+ int scale = number.scale();
+ if (BigInteger.ZERO.equals(unscaled)) {
+ return initBytesZeroCase(scale);
+ }
+ final PositiveShortStack shortStacks = new PositiveShortStack();
+ int weight = -1;
+ if (scale < 0) {
+ scale = Math.abs(scale);
+ weight += scale / 4;
+ int mod = scale % 4;
+ unscaled = unscaled.multiply(tenPower(mod));
+ scale = 0;
+ }
+ if (scale == 0) {
+ weight = initShortValuesNoneScaled(shortStacks, unscaled, weight);
+ } else {
+ weight = initShortValuesScaled(shortStacks, unscaled, scale);
+ }
+ return initBytes(number, shortStacks, scale, weight);
+ }
+
+ private static byte[] initBytesZeroCase(final int scale) {
+ final byte[] bytes = new byte[] {0, 0, -1, -1, 0, 0, 0, 0};
+ int2(bytes, 6, Math.max(0, scale));
+ return bytes;
+ }
+
+ private static int initShortValuesNoneScaled(final PositiveShortStack shortStacks, final BigInteger unscaled, final int weight) {
+ int result = weight;
+ BigInteger tempUnscaled = unscaled;
+ BigInteger maxInteger = BigInteger.valueOf(Long.MAX_VALUE);
+ while (unscaled.compareTo(maxInteger) > 0) {
+ final BigInteger[] pair = unscaled.divideAndRemainder(BI_TEN_THOUSAND);
+ tempUnscaled = pair[0];
+ shortStacks.push(pair[1].shortValue());
+ ++result;
+ }
+ long unscaledLong = tempUnscaled.longValueExact();
+ do {
+ shortStacks.push((short) (unscaledLong % 10000));
+ unscaledLong = unscaledLong / 10000L;
+ ++result;
+ } while (unscaledLong != 0);
+ return result;
+ }
+
+ private static int initShortValuesScaled(final PositiveShortStack shortStacks, final BigInteger unscaled, final int scale) {
+ int weight = -1;
+ final BigInteger[] split = unscaled.divideAndRemainder(tenPower(scale));
+ BigInteger decimal = split[1];
+ BigInteger wholes = split[0];
+ if (!BigInteger.ZERO.equals(decimal)) {
+ int mod = scale % 4;
+ int segments = scale / 4;
+ if (mod != 0) {
+ decimal = decimal.multiply(tenPower(4 - mod));
+ ++segments;
+ }
+ do {
+ final BigInteger[] pair = decimal.divideAndRemainder(BI_TEN_THOUSAND);
+ decimal = pair[0];
+ shortStacks.push(pair[1].shortValue());
+ --segments;
+ } while (!BigInteger.ZERO.equals(decimal));
+ if (BigInteger.ZERO.equals(wholes)) {
+ weight -= segments;
+ } else {
+ for (int i = 0; i < segments; ++i) {
+ shortStacks.push((short) 0);
+ }
+ }
+ }
+ while (!BigInteger.ZERO.equals(wholes)) {
+ ++weight;
+ final BigInteger[] pair = wholes.divideAndRemainder(BI_TEN_THOUSAND);
+ wholes = pair[0];
+ shortStacks.push(pair[1].shortValue());
+ }
+ return weight;
+ }
+
+ private static byte[] initBytes(final BigDecimal number, final PositiveShortStack shortStacks, final int scale, final int weight) {
+ final byte[] result = new byte[8 + (2 * shortStacks.size())];
+ int idx = 0;
+ int2(result, idx, shortStacks.size());
+ idx += 2;
+ int2(result, idx, weight);
+ idx += 2;
+ int2(result, idx, number.signum() == -1 ? NUMERIC_NEG : NUMERIC_POS);
+ idx += 2;
+ int2(result, idx, Math.max(0, scale));
+ idx += 2;
+ short s;
+ while ((s = shortStacks.pop()) != -1) {
+ int2(result, idx, s);
+ idx += 2;
+ }
+ return result;
+ }
+
+ private static void int2(final byte[] target, final int idx, final int value) {
+ target[idx] = (byte) (value >>> 8);
+ target[idx + 1] = (byte) value;
+ }
+
+ private static Number initBigDecimalNoneWeight(final byte[] bytes, final int pos, final short len, final short weight, final short sign, final short scale) {
+ int idx = pos + 8;
+ short d = readShort2(bytes, idx);
+ assert scale > 0;
+ int effectiveScale = scale;
+ if (weight < 0) {
+ effectiveScale += 4 * weight;
+ }
+ for (int i = 1; i < len && d == 0; ++i) {
+ effectiveScale -= 4;
+ idx += 2;
+ d = readShort2(bytes, idx);
+ }
+ assert effectiveScale > 0;
+ if (effectiveScale >= 4) {
+ effectiveScale -= 4;
+ } else {
+ d = (short) (d / INT_TEN_POWERS[4 - effectiveScale]);
+ effectiveScale = 0;
+ }
+ BigInteger unscaledBI = null;
+ long unscaledInt = d;
+ for (int i = 1; i < len; ++i) {
+ if (i == 4 && effectiveScale > 2) {
+ unscaledBI = BigInteger.valueOf(unscaledInt);
+ }
+ idx += 2;
+ d = readShort2(bytes, idx);
+ if (effectiveScale >= 4) {
+ if (unscaledBI == null) {
+ unscaledInt *= 10000;
+ } else {
+ unscaledBI = unscaledBI.multiply(BI_TEN_THOUSAND);
+ }
+ effectiveScale -= 4;
+ } else {
+ if (unscaledBI == null) {
+ unscaledInt *= INT_TEN_POWERS[effectiveScale];
+ } else {
+ unscaledBI = unscaledBI.multiply(tenPower(effectiveScale));
+ }
+ d = (short) (d / INT_TEN_POWERS[4 - effectiveScale]);
+ effectiveScale = 0;
+ }
+ if (unscaledBI == null) {
+ unscaledInt += d;
+ } else {
+ if (d != 0) {
+ unscaledBI = unscaledBI.add(BigInteger.valueOf(d));
+ }
+ }
+ }
+ if (unscaledBI == null) {
+ unscaledBI = BigInteger.valueOf(unscaledInt);
+ }
+ if (effectiveScale > 0) {
+ unscaledBI = unscaledBI.multiply(tenPower(effectiveScale));
+ }
+ if (sign == NUMERIC_NEG) {
+ unscaledBI = unscaledBI.negate();
+ }
+ return new BigDecimal(unscaledBI, scale);
+ }
+
+ private static Number initBigDecimalNoneScale(final byte[] bytes, final int pos, final short len, final short weight, final short sign) {
+ int idx = pos + 8;
+ short d = readShort2(bytes, idx);
+ BigInteger unscaledBI = null;
+ long unscaledInt = d;
+ for (int i = 1; i < len; ++i) {
+ if (i == 4) {
+ unscaledBI = BigInteger.valueOf(unscaledInt);
+ }
+ idx += 2;
+ d = readShort2(bytes, idx);
+ if (unscaledBI == null) {
+ unscaledInt *= 10000;
+ unscaledInt += d;
+ } else {
+ unscaledBI = unscaledBI.multiply(BI_TEN_THOUSAND);
+ if (d != 0) {
+ unscaledBI = unscaledBI.add(BigInteger.valueOf(d));
+ }
+ }
+ }
+ if (unscaledBI == null) {
+ unscaledBI = BigInteger.valueOf(unscaledInt);
+ }
+ if (sign == NUMERIC_NEG) {
+ unscaledBI = unscaledBI.negate();
+ }
+ final int bigDecScale = (len - (weight + 1)) * 4;
+ return bigDecScale == 0 ? new BigDecimal(unscaledBI) : new BigDecimal(unscaledBI, bigDecScale);
+ }
+
+ private static Number initBigDecimal(final byte[] bytes, final int pos, final short len, final short weight, final short sign, final short scale) {
+ int idx = pos + 8;
+ short d = readShort2(bytes, idx);
+ BigInteger unscaledBI = null;
+ long unscaledInt = d;
+ int effectiveWeight = weight;
+ int effectiveScale = scale;
+ for (int i = 1; i < len; ++i) {
+ if (i == 4) {
+ unscaledBI = BigInteger.valueOf(unscaledInt);
+ }
+ idx += 2;
+ d = readShort2(bytes, idx);
+ if (effectiveWeight > 0) {
+ --effectiveWeight;
+ if (unscaledBI == null) {
+ unscaledInt *= 10000;
+ } else {
+ unscaledBI = unscaledBI.multiply(BI_TEN_THOUSAND);
+ }
+ } else if (effectiveScale >= 4) {
+ effectiveScale -= 4;
+ if (unscaledBI == null) {
+ unscaledInt *= 10000;
+ } else {
+ unscaledBI = unscaledBI.multiply(BI_TEN_THOUSAND);
+ }
+ } else {
+ if (unscaledBI == null) {
+ unscaledInt *= INT_TEN_POWERS[effectiveScale];
+ } else {
+ unscaledBI = unscaledBI.multiply(tenPower(effectiveScale));
+ }
+ d = (short) (d / INT_TEN_POWERS[4 - effectiveScale]);
+ effectiveScale = 0;
+ }
+ if (unscaledBI == null) {
+ unscaledInt += d;
+ } else {
+ if (d != 0) {
+ unscaledBI = unscaledBI.add(BigInteger.valueOf(d));
+ }
+ }
+ }
+ if (unscaledBI == null) {
+ unscaledBI = BigInteger.valueOf(unscaledInt);
+ }
+ if (effectiveWeight > 0) {
+ unscaledBI = unscaledBI.multiply(tenPower(effectiveWeight * 4));
+ }
+ if (effectiveScale > 0) {
+ unscaledBI = unscaledBI.multiply(tenPower(effectiveScale));
+ }
+ if (sign == NUMERIC_NEG) {
+ unscaledBI = unscaledBI.negate();
+ }
+ return new BigDecimal(unscaledBI, scale);
+ }
+
+ private static void validator(final short sign, final short scale) {
+ if (!(sign == 0x0000 || NUMERIC_NEG == sign || NUMERIC_NAN == sign)) {
+ throw new IllegalArgumentException("invalid sign in \"numeric\" value");
+ }
+ if ((scale & 0x00003FFF) != scale) {
+ throw new IllegalArgumentException("invalid scale in \"numeric\" value");
+ }
+ }
+
+ private static BigInteger tenPower(final int exponent) {
+ return BI_TEN_POWERS.length > exponent ? BI_TEN_POWERS[exponent] : BigInteger.TEN.pow(exponent);
+ }
+
+ private static short readShort2(final byte[] bytes, final int index) {
+ return (short) (((bytes[index] & 255) << 8) + ((bytes[index + 1] & 255)));
+ }
+
+ /**
+ * Simple stack structure for non-negative {@code short} values.
+ */
+ private static final class PositiveShortStack {
+
+ private short[] shorts = new short[8];
+
+ private int index;
+
+ public void push(final short value) {
+ if (value != 0 || index != 0) {
+ if (value < 0) {
+ throw new IllegalArgumentException("only non-negative values accepted: " + value);
+ }
+ if (index == shorts.length) {
+ grow();
+ }
+ shorts[index++] = value;
+ }
+ }
+
+ public int size() {
+ return index;
+ }
+
+ public boolean isEmpty() {
+ return index == 0;
+ }
+
+ public short pop() {
+ return index > 0 ? shorts[--index] : -1;
+ }
+
+ private void grow() {
+ final int newSize = shorts.length <= 1024 ? shorts.length << 1 : (int) (shorts.length * 1.5);
+ shorts = Arrays.copyOf(shorts, newSize);
+ }
+ }
+}
diff --git a/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/main/java/org/apache/shardingsphere/db/protocol/postgresql/packet/command/query/extended/bind/protocol/PostgreSQLNumericBinaryProtocolValue.java b/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/main/java/org/apache/shardingsphere/db/protocol/postgresql/packet/command/query/extended/bind/protocol/PostgreSQLNumericBinaryProtocolValue.java
index a8ef6b9..001bd8c 100644
--- a/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/main/java/org/apache/shardingsphere/db/protocol/postgresql/packet/command/query/extended/bind/protocol/PostgreSQLNumericBinaryProtocolValue.java
+++ b/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/main/java/org/apache/shardingsphere/db/protocol/postgresql/packet/command/query/extended/bind/protocol/PostgreSQLNumericBinaryProtocolValue.java
@@ -19,7 +19,6 @@ package org.apache.shardingsphere.db.protocol.postgresql.packet.command.query.ex
import org.apache.shardingsphere.db.protocol.postgresql.payload.PostgreSQLPacketPayload;
-import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
/**
@@ -36,7 +35,7 @@ public final class PostgreSQLNumericBinaryProtocolValue implements PostgreSQLBin
public Object read(final PostgreSQLPacketPayload payload, final int parameterValueLength) {
byte[] bytes = new byte[parameterValueLength];
payload.getByteBuf().readBytes(bytes);
- return new BigDecimal(new String(bytes));
+ return PostgreSQLByteConverter.numeric(bytes);
}
@Override
diff --git a/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/test/java/org/apache/shardingsphere/db/protocol/postgresql/packet/command/query/extended/bind/protocol/PostgreSQLByteConverterTest.java b/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/test/java/org/apache/shardingsphere/db/protocol/postgresql/packet/command/query/extended/bind/protocol/PostgreSQLByteConverterTest.java
new file mode 100644
index 0000000..a91d1e0
--- /dev/null
+++ b/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/test/java/org/apache/shardingsphere/db/protocol/postgresql/packet/command/query/extended/bind/protocol/PostgreSQLByteConverterTest.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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 org.apache.shardingsphere.db.protocol.postgresql.packet.command.query.extended.bind.protocol;
+
+import lombok.RequiredArgsConstructor;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.math.BigDecimal;
+import java.util.Arrays;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+@RunWith(Parameterized.class)
+@RequiredArgsConstructor
+public final class PostgreSQLByteConverterTest {
+
+ private final BigDecimal input;
+
+ private final byte[] expected;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static Iterable<Object[]> textValues() {
+ return Arrays.asList(
+ new Object[]{new BigDecimal("0"), new byte[] {0, 0, -1, -1, 0, 0, 0, 0}},
+ new Object[]{new BigDecimal("0.00"), new byte[] {0, 0, -1, -1, 0, 0, 0, 2}},
+ new Object[]{new BigDecimal("0.0001"), new byte[] {0, 1, -1, -1, 0, 0, 0, 4, 0, 1}},
+ new Object[]{new BigDecimal("9999"), new byte[] {0, 1, 0, 0, 0, 0, 0, 0, 39, 15}},
+ new Object[]{new BigDecimal("9999.0"), new byte[] {0, 1, 0, 0, 0, 0, 0, 1, 39, 15}},
+ new Object[]{new BigDecimal("9999.9999"), new byte[] {0, 2, 0, 0, 0, 0, 0, 4, 39, 15, 39, 15}}
+ );
+ }
+
+ @Test
+ public void assertNumeric() {
+ assertThat(PostgreSQLByteConverter.numeric(input), is(expected));
+ }
+}
diff --git a/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/test/java/org/apache/shardingsphere/db/protocol/postgresql/packet/command/query/extended/bind/protocol/PostgreSQLNumericBinaryProtocolValueTest.java b/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/test/java/org/apache/shardingsphere/db/protocol/postgresql/packet/command/query/extended/bind/protocol/PostgreSQLNumericBinaryProtocolValueTest.java
index edf0e8f..f01d3d9 100644
--- a/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/test/java/org/apache/shardingsphere/db/protocol/postgresql/packet/command/query/extended/bind/protocol/PostgreSQLNumericBinaryProtocolValueTest.java
+++ b/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/test/java/org/apache/shardingsphere/db/protocol/postgresql/packet/command/query/extended/bind/protocol/PostgreSQLNumericBinaryProtocolValueTest.java
@@ -44,14 +44,12 @@ public final class PostgreSQLNumericBinaryProtocolValueTest {
PostgreSQLNumericBinaryProtocolValue binaryProtocolValue = new PostgreSQLNumericBinaryProtocolValue();
String decimalText = "1234567890.12";
BigDecimal expectedDecimal = new BigDecimal(decimalText);
- int columnLength = binaryProtocolValue.getColumnLength(expectedDecimal);
- int expectedLength = 4 + columnLength;
+ byte[] numericBytes = PostgreSQLByteConverter.numeric(expectedDecimal);
+ int expectedLength = numericBytes.length;
ByteBuf byteBuf = ByteBufTestUtils.createByteBuf(expectedLength);
- byteBuf.writeInt(columnLength);
- byteBuf.writeBytes(decimalText.getBytes(StandardCharsets.UTF_8));
- byteBuf.readInt();
+ byteBuf.writeBytes(numericBytes);
PostgreSQLPacketPayload payload = new PostgreSQLPacketPayload(byteBuf, StandardCharsets.UTF_8);
- Object result = binaryProtocolValue.read(payload, columnLength);
+ Object result = binaryProtocolValue.read(payload, expectedLength);
assertNotNull(result);
assertTrue(result instanceof BigDecimal);
assertThat(result, is(expectedDecimal));
diff --git a/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dml/dataset/shadow/postgresql/pro_insert_order_value.xml b/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dml/dataset/shadow/postgresql/pro_insert_order_value.xml
index 668e724..4a315c5 100644
--- a/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dml/dataset/shadow/postgresql/pro_insert_order_value.xml
+++ b/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dml/dataset/shadow/postgresql/pro_insert_order_value.xml
@@ -34,5 +34,5 @@
<row data-node="db.t_order" values="3, 1, pro_order, S, true, 5, summer, 10.00, 2017-08-08, 18:30:30, 2017-08-08 18:30:30.0" />
<row data-node="db.t_order" values="4, 1, pro_order, S, true, 5, summer, 10.00, 2017-08-08, 18:30:30, 2017-08-08 18:30:30.0" />
<row data-node="db.t_order" values="5, 1, pro_order, S, true, 5, summer, 10.00, 2017-08-08, 18:30:30, 2017-08-08 18:30:30.0" />
- <row data-node="db.t_order" values="6, 1, pro_order, S, true, 50, summer, 100.00, 2021-01-01, 12:30:30, 2021-01-01 12:30:30.0" />
+ <row data-node="db.t_order" values="6, 1, pro_order, S, true, 50, summer, 120.00, 2021-01-01, 12:30:30, 2021-01-01 12:30:30.0" />
</dataset>
diff --git a/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dml/dataset/shadow/postgresql/pro_update_order_by_user_id.xml b/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dml/dataset/shadow/postgresql/pro_update_order_by_user_id.xml
index 477b8ac..9be10b1 100644
--- a/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dml/dataset/shadow/postgresql/pro_update_order_by_user_id.xml
+++ b/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dml/dataset/shadow/postgresql/pro_update_order_by_user_id.xml
@@ -29,8 +29,8 @@
<column name="type_time" type="time" />
<column name="type_timestamp" type="timestamp"/>
</metadata>
- <row data-node="db.t_order" values="1, 1, pro_order_update, F, false, 60, spring, 10.00, 2017-08-08, 18:30:30, 2017-08-08 18:30:30.0" />
- <row data-node="db.t_order" values="2, 1, pro_order_update, F, false, 60, spring, 10.00, 2017-08-08, 18:30:30, 2017-08-08 18:30:30.0" />
+ <row data-node="db.t_order" values="1, 1, pro_order_update, F, false, 60, spring, 120.00, 2017-08-08, 18:30:30, 2017-08-08 18:30:30.0" />
+ <row data-node="db.t_order" values="2, 1, pro_order_update, F, false, 60, spring, 120.00, 2017-08-08, 18:30:30, 2017-08-08 18:30:30.0" />
<row data-node="db.t_order" values="3, 1, pro_order, S, true, 5, summer, 10.00, 2017-08-08, 18:30:30, 2017-08-08 18:30:30.0" />
<row data-node="db.t_order" values="4, 1, pro_order, S, true, 5, summer, 10.00, 2017-08-08, 18:30:30, 2017-08-08 18:30:30.0" />
<row data-node="db.t_order" values="5, 1, pro_order, S, true, 5, summer, 10.00, 2017-08-08, 18:30:30, 2017-08-08 18:30:30.0" />
diff --git a/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dml/dataset/shadow/postgresql/shadow_insert_order_value.xml b/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dml/dataset/shadow/postgresql/shadow_insert_order_value.xml
index 248c76c..80985e1 100644
--- a/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dml/dataset/shadow/postgresql/shadow_insert_order_value.xml
+++ b/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dml/dataset/shadow/postgresql/shadow_insert_order_value.xml
@@ -34,5 +34,5 @@
<row data-node="shadow_db.t_order" values="3, 0, shadow_order, S, true, 5, summer, 10.00, 2017-08-08, 18:30:30, 2017-08-08 18:30:30.0" />
<row data-node="shadow_db.t_order" values="4, 0, shadow_order, S, true, 5, summer, 10.00, 2017-08-08, 18:30:30, 2017-08-08 18:30:30.0" />
<row data-node="shadow_db.t_order" values="5, 0, shadow_order, S, true, 5, summer, 10.00, 2017-08-08, 18:30:30, 2017-08-08 18:30:30.0" />
- <row data-node="shadow_db.t_order" values="6, 0, shadow_order, S, true, 50, summer, 100.00, 2021-01-01, 12:30:30, 2021-01-01 12:30:30.0" />
+ <row data-node="shadow_db.t_order" values="6, 0, shadow_order, S, true, 50, summer, 120.00, 2021-01-01, 12:30:30, 2021-01-01 12:30:30.0" />
</dataset>
diff --git a/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dml/dataset/shadow/postgresql/shadow_update_order_by_user_id.xml b/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dml/dataset/shadow/postgresql/shadow_update_order_by_user_id.xml
index e5f8ff5..b5d4e320 100644
--- a/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dml/dataset/shadow/postgresql/shadow_update_order_by_user_id.xml
+++ b/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dml/dataset/shadow/postgresql/shadow_update_order_by_user_id.xml
@@ -29,8 +29,8 @@
<column name="type_time" type="time" />
<column name="type_timestamp" type="timestamp"/>
</metadata>
- <row data-node="shadow_db.t_order" values="1, 0, shadow_order_update, F, false, 60, spring, 10.00, 2017-08-08, 18:30:30, 2017-08-08 18:30:30.0" />
- <row data-node="shadow_db.t_order" values="2, 0, shadow_order_update, F, false, 60, spring, 10.00, 2017-08-08, 18:30:30, 2017-08-08 18:30:30.0" />
+ <row data-node="shadow_db.t_order" values="1, 0, shadow_order_update, F, false, 60, spring, 120.00, 2017-08-08, 18:30:30, 2017-08-08 18:30:30.0" />
+ <row data-node="shadow_db.t_order" values="2, 0, shadow_order_update, F, false, 60, spring, 120.00, 2017-08-08, 18:30:30, 2017-08-08 18:30:30.0" />
<row data-node="shadow_db.t_order" values="3, 0, shadow_order, S, true, 5, summer, 10.00, 2017-08-08, 18:30:30, 2017-08-08 18:30:30.0" />
<row data-node="shadow_db.t_order" values="4, 0, shadow_order, S, true, 5, summer, 10.00, 2017-08-08, 18:30:30, 2017-08-08 18:30:30.0" />
<row data-node="shadow_db.t_order" values="5, 0, shadow_order, S, true, 5, summer, 10.00, 2017-08-08, 18:30:30, 2017-08-08 18:30:30.0" />
diff --git a/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dml/dml-integration-test-cases.xml b/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dml/dml-integration-test-cases.xml
index 9180d08..bea5abb 100644
--- a/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dml/dml-integration-test-cases.xml
+++ b/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dml/dml-integration-test-cases.xml
@@ -253,20 +253,20 @@
<assertion parameters="0:int, 4:long, 5:long" expected-data-file="shadow_delete_order_by_user_id.xml" />
</test-case>
- <!-- FIXME Support decimal, enum types for PostgreSQL -->
- <test-case sql="INSERT INTO t_order (order_id, user_id, order_name, type_char, type_boolean, type_smallint, type_date, type_time, type_timestamp)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);" db-types="PostgreSQL" scenario-types="shadow">
- <assertion parameters="6:long, 1:int, pro_order:String, S:char, true:boolean, 50:smallint, 2021-01-01:Date, 12:30:30:time, 2021-01-01 12:30:30:timestamp"
+ <!-- FIXME Support enum types for PostgreSQL -->
+ <test-case sql="INSERT INTO t_order (order_id, user_id, order_name, type_char, type_boolean, type_smallint, type_decimal, type_date, type_time, type_timestamp)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);" db-types="PostgreSQL" scenario-types="shadow">
+ <assertion parameters="6:long, 1:int, pro_order:String, S:char, true:boolean, 50:smallint, 120.00:decimal, 2021-01-01:Date, 12:30:30:time, 2021-01-01 12:30:30:timestamp"
expected-data-file="pro_insert_order_value.xml" />
- <assertion parameters="6:long, 0:int, shadow_order:String, S:char, true:boolean, 50:smallint, 2021-01-01:Date, 12:30:30:time, 2021-01-01 12:30:30:timestamp"
+ <assertion parameters="6:long, 0:int, shadow_order:String, S:char, true:boolean, 50:smallint, 120.00:decimal, 2021-01-01:Date, 12:30:30:time, 2021-01-01 12:30:30:timestamp"
expected-data-file="shadow_insert_order_value.xml" />
</test-case>
- <test-case sql="UPDATE t_order SET order_name = ?, type_char = ?, type_boolean = ?, type_smallint = ?, type_enum = ?::season
+ <test-case sql="UPDATE t_order SET order_name = ?, type_char = ?, type_boolean = ?, type_smallint = ?, type_decimal = ?, type_enum = ?::season
WHERE user_id = ? and order_id in (?, ?)" db-types="PostgreSQL" scenario-types="shadow">
- <assertion parameters="pro_order_update:String, F:char, false:boolean, 60:smallint, spring:enum#season, 1:int, 1:long, 2:long"
+ <assertion parameters="pro_order_update:String, F:char, false:boolean, 60:smallint, 120.00:decimal, spring:enum#season, 1:int, 1:long, 2:long"
expected-data-file="pro_update_order_by_user_id.xml" />
- <assertion parameters="shadow_order_update:String, F:char, false:boolean, 60:smallint, spring:enum#season, 0:int, 1:long, 2:long"
+ <assertion parameters="shadow_order_update:String, F:char, false:boolean, 60:smallint, 120.00:decimal, spring:enum#season, 0:int, 1:long, 2:long"
expected-data-file="shadow_update_order_by_user_id.xml" />
</test-case>
diff --git a/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/env/shadow/init-sql/postgresql/init.sql b/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/env/shadow/init-sql/postgresql/init.sql
index 0fc7eec..ec42c1a 100644
--- a/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/env/shadow/init-sql/postgresql/init.sql
+++ b/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/env/shadow/init-sql/postgresql/init.sql
@@ -28,7 +28,7 @@ DROP TABLE IF EXISTS t_order;
CREATE TYPE season AS ENUM ('spring', 'summer', 'autumn', 'winter');
CREATE TABLE t_order (order_id BIGINT NOT NULL, user_id INT NOT NULL, order_name VARCHAR(32) NOT NULL, type_char CHAR(1) NOT NULL, type_boolean BOOLEAN NOT NULL, type_smallint SMALLINT NOT NULL,
- type_enum season DEFAULT 'summer', type_decimal NUMERIC(18,2) DEFAULT '100.00', type_date DATE DEFAULT NULL, type_time TIME DEFAULT NULL, type_timestamp TIMESTAMP DEFAULT NULL,
+ type_enum season DEFAULT 'summer', type_decimal NUMERIC(18,2) DEFAULT NULL, type_date DATE DEFAULT NULL, type_time TIME DEFAULT NULL, type_timestamp TIMESTAMP DEFAULT NULL,
PRIMARY KEY (order_id));
\c shadow_db
@@ -38,5 +38,5 @@ DROP TABLE IF EXISTS t_order;
CREATE TYPE season AS ENUM ('spring', 'summer', 'autumn', 'winter');
CREATE TABLE t_order (order_id BIGINT NOT NULL, user_id INT NOT NULL, order_name VARCHAR(32) NOT NULL, type_char CHAR(1) NOT NULL, type_boolean BOOLEAN NOT NULL, type_smallint SMALLINT NOT NULL,
- type_enum season DEFAULT 'summer', type_decimal NUMERIC(18,2) DEFAULT '100.00', type_date DATE DEFAULT NULL, type_time TIME DEFAULT NULL, type_timestamp TIMESTAMP DEFAULT NULL,
+ type_enum season DEFAULT 'summer', type_decimal NUMERIC(18,2) DEFAULT NULL, type_date DATE DEFAULT NULL, type_time TIME DEFAULT NULL, type_timestamp TIMESTAMP DEFAULT NULL,
PRIMARY KEY (order_id));