This is an automated email from the ASF dual-hosted git repository.

RaigorJiang 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 5f28295f952 Fix MySQL STRING parameter decoding for numeric columns 
(#40232)
5f28295f952 is described below

commit 5f28295f952d446f86694ed3967e41cec3b870ed
Author: Raigor <[email protected]>
AuthorDate: Mon Oct 19 11:16:52 2026 +0800

    Fix MySQL STRING parameter decoding for numeric columns (#40232)
---
 .../binary/execute/MySQLComStmtExecutePacket.java  | 27 ++++--
 .../execute/MySQLComStmtExecutePacketTest.java     | 98 ++++++++++++++++++----
 2 files changed, 103 insertions(+), 22 deletions(-)

diff --git 
a/database/protocol/dialect/mysql/src/main/java/org/apache/shardingsphere/database/protocol/mysql/packet/command/query/binary/execute/MySQLComStmtExecutePacket.java
 
b/database/protocol/dialect/mysql/src/main/java/org/apache/shardingsphere/database/protocol/mysql/packet/command/query/binary/execute/MySQLComStmtExecutePacket.java
index ae6ac371c1d..07e08c6696e 100644
--- 
a/database/protocol/dialect/mysql/src/main/java/org/apache/shardingsphere/database/protocol/mysql/packet/command/query/binary/execute/MySQLComStmtExecutePacket.java
+++ 
b/database/protocol/dialect/mysql/src/main/java/org/apache/shardingsphere/database/protocol/mysql/packet/command/query/binary/execute/MySQLComStmtExecutePacket.java
@@ -149,17 +149,34 @@ public final class MySQLComStmtExecutePacket extends 
MySQLCommandPacket {
     }
     
     private Object decodeStringParameterValue(final 
List<MySQLBinaryColumnType> parameterColumnTypes, final int paramIndex, final 
MySQLBinaryColumnType parameterType, final Object value) {
-        if (!(value instanceof byte[]) || MySQLBinaryColumnType.STRING != 
parameterType || !isCharacterColumnType(parameterColumnTypes, paramIndex)) {
+        if (!(value instanceof byte[]) || MySQLBinaryColumnType.STRING != 
parameterType || !isCharacterOrNumericColumnType(parameterColumnTypes, 
paramIndex)) {
             return value;
         }
         return new String((byte[]) value, payload.getCharset());
     }
     
-    private boolean isCharacterColumnType(final List<MySQLBinaryColumnType> 
parameterColumnTypes, final int paramIndex) {
-        if (paramIndex >= parameterColumnTypes.size()) {
+    private boolean isCharacterOrNumericColumnType(final 
List<MySQLBinaryColumnType> parameterColumnTypes, final int paramIndex) {
+        MySQLBinaryColumnType columnType = 
getParameterColumnType(parameterColumnTypes, paramIndex);
+        if (null == columnType) {
             return false;
         }
-        MySQLBinaryColumnType columnType = 
parameterColumnTypes.get(paramIndex);
-        return MySQLBinaryColumnType.STRING == columnType || 
MySQLBinaryColumnType.VAR_STRING == columnType || MySQLBinaryColumnType.VARCHAR 
== columnType;
+        switch (columnType) {
+            case STRING:
+            case VAR_STRING:
+            case VARCHAR:
+                return true;
+            case TINY:
+            case SHORT:
+            case LONG:
+            case LONGLONG:
+            case INT24:
+            case FLOAT:
+            case DOUBLE:
+            case DECIMAL:
+            case NEWDECIMAL:
+                return true;
+            default:
+                return false;
+        }
     }
 }
diff --git 
a/database/protocol/dialect/mysql/src/test/java/org/apache/shardingsphere/database/protocol/mysql/packet/command/query/binary/execute/MySQLComStmtExecutePacketTest.java
 
b/database/protocol/dialect/mysql/src/test/java/org/apache/shardingsphere/database/protocol/mysql/packet/command/query/binary/execute/MySQLComStmtExecutePacketTest.java
index ca174473977..029e4baef3a 100644
--- 
a/database/protocol/dialect/mysql/src/test/java/org/apache/shardingsphere/database/protocol/mysql/packet/command/query/binary/execute/MySQLComStmtExecutePacketTest.java
+++ 
b/database/protocol/dialect/mysql/src/test/java/org/apache/shardingsphere/database/protocol/mysql/packet/command/query/binary/execute/MySQLComStmtExecutePacketTest.java
@@ -17,6 +17,7 @@
 
 package 
org.apache.shardingsphere.database.protocol.mysql.packet.command.query.binary.execute;
 
+import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
 import 
org.apache.shardingsphere.database.protocol.mysql.constant.MySQLBinaryColumnType;
 import 
org.apache.shardingsphere.database.protocol.mysql.constant.MySQLNewParametersBoundFlag;
@@ -28,6 +29,7 @@ import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
 
+import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.sql.Date;
 import java.sql.SQLException;
@@ -160,28 +162,90 @@ class MySQLComStmtExecutePacketTest {
     @DisplayName("assertReadParametersWithStringDecoding")
     @ParameterizedTest(name = "{0}")
     @MethodSource("stringDecodingArguments")
-    void assertReadParametersWithStringDecoding(final String name, final 
MySQLBinaryColumnType parameterType,
-                                                final 
List<MySQLBinaryColumnType> parameterColumnTypes, final boolean expectedString) 
throws SQLException {
-        byte[] data = createPacketData(parameterType, new byte[]{0x61});
-        MySQLPacketPayload payload = new 
MySQLPacketPayload(Unpooled.wrappedBuffer(data), StandardCharsets.UTF_8);
-        MySQLComStmtExecutePacket actual = new 
MySQLComStmtExecutePacket(payload, 1);
-        List<MySQLPreparedStatementParameterType> parameterTypes = 
actual.getNewParameterTypes();
-        Object actualValue = actual.readParameters(parameterTypes, 
Collections.emptySet(), parameterColumnTypes).get(0);
-        assertThat(actualValue instanceof String, is(expectedString));
-        if (expectedString) {
-            assertThat(actualValue, is("a"));
-            return;
+    void assertReadParametersWithStringDecoding(final String name, final 
MySQLBinaryColumnType columnType, final String expected, final Charset charset) 
throws SQLException {
+        ByteBuf buffer = 
Unpooled.wrappedBuffer(createPacketData(MySQLBinaryColumnType.STRING, 
expected.getBytes(charset)));
+        try {
+            MySQLComStmtExecutePacket packet = new 
MySQLComStmtExecutePacket(new MySQLPacketPayload(buffer, charset), 1);
+            Object actual = 
packet.readParameters(packet.getNewParameterTypes(), Collections.emptySet(), 
Collections.singletonList(columnType)).get(0);
+            assertThat(actual, isA(String.class));
+            assertThat(actual, is(expected));
+        } finally {
+            buffer.release();
         }
-        assertThat((byte[]) actualValue, is(new byte[]{0x61}));
     }
     
     private static Stream<Arguments> stringDecodingArguments() {
         return Stream.of(
-                Arguments.of("string-column", MySQLBinaryColumnType.STRING, 
Collections.singletonList(MySQLBinaryColumnType.STRING), true),
-                Arguments.of("var-string-column", 
MySQLBinaryColumnType.STRING, 
Collections.singletonList(MySQLBinaryColumnType.VAR_STRING), true),
-                Arguments.of("varchar-column", MySQLBinaryColumnType.STRING, 
Collections.singletonList(MySQLBinaryColumnType.VARCHAR), true),
-                Arguments.of("missing-column-type", 
MySQLBinaryColumnType.STRING, Collections.emptyList(), false),
-                Arguments.of("blob-parameter-type", 
MySQLBinaryColumnType.BLOB, 
Collections.singletonList(MySQLBinaryColumnType.VAR_STRING), false));
+                Arguments.of("string-column", MySQLBinaryColumnType.STRING, 
"0", StandardCharsets.UTF_8),
+                Arguments.of("var-string-column", 
MySQLBinaryColumnType.VAR_STRING, "0", StandardCharsets.UTF_8),
+                Arguments.of("varchar-column", MySQLBinaryColumnType.VARCHAR, 
"0", StandardCharsets.UTF_8),
+                Arguments.of("tiny-column", MySQLBinaryColumnType.TINY, "48", 
StandardCharsets.UTF_8),
+                Arguments.of("short-column", MySQLBinaryColumnType.SHORT, 
"48", StandardCharsets.UTF_8),
+                Arguments.of("long-column", MySQLBinaryColumnType.LONG, "48", 
StandardCharsets.UTF_8),
+                Arguments.of("longlong-column", 
MySQLBinaryColumnType.LONGLONG, "48", StandardCharsets.UTF_8),
+                Arguments.of("int24-column", MySQLBinaryColumnType.INT24, 
"48", StandardCharsets.UTF_8),
+                Arguments.of("float-column", MySQLBinaryColumnType.FLOAT, 
"48", StandardCharsets.UTF_8),
+                Arguments.of("double-column", MySQLBinaryColumnType.DOUBLE, 
"48", StandardCharsets.UTF_8),
+                Arguments.of("decimal-column", MySQLBinaryColumnType.DECIMAL, 
"48", StandardCharsets.UTF_8),
+                Arguments.of("newdecimal-column", 
MySQLBinaryColumnType.NEWDECIMAL, "48", StandardCharsets.UTF_8),
+                Arguments.of("negative-number", 
MySQLBinaryColumnType.LONGLONG, "-48", StandardCharsets.UTF_8),
+                Arguments.of("fractional-number", 
MySQLBinaryColumnType.NEWDECIMAL, "48.123456", StandardCharsets.UTF_8),
+                Arguments.of("unsigned-bigint-boundary", 
MySQLBinaryColumnType.LONGLONG, "18446744073709551615", StandardCharsets.UTF_8),
+                Arguments.of("invalid-number", MySQLBinaryColumnType.LONGLONG, 
"foo_invalid", StandardCharsets.UTF_8),
+                Arguments.of("empty-string", MySQLBinaryColumnType.LONG, "", 
StandardCharsets.UTF_8),
+                Arguments.of("numeric-column-charset", 
MySQLBinaryColumnType.LONGLONG, "é", StandardCharsets.ISO_8859_1),
+                Arguments.of("character-column-charset", 
MySQLBinaryColumnType.VAR_STRING, "foo_中文", StandardCharsets.UTF_8));
+    }
+    
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("withoutStringDecodingArguments")
+    void assertReadParametersWithoutStringDecoding(final String name, final 
MySQLBinaryColumnType paramType, final List<MySQLBinaryColumnType> columnTypes) 
throws SQLException {
+        byte[] expected = {0x34, 0x38};
+        ByteBuf buffer = Unpooled.wrappedBuffer(createPacketData(paramType, 
expected));
+        try {
+            MySQLComStmtExecutePacket packet = new 
MySQLComStmtExecutePacket(new MySQLPacketPayload(buffer, 
StandardCharsets.UTF_8), 1);
+            Object actual = 
packet.readParameters(packet.getNewParameterTypes(), Collections.emptySet(), 
columnTypes).get(0);
+            assertThat(actual, isA(byte[].class));
+            assertThat((byte[]) actual, is(expected));
+        } finally {
+            buffer.release();
+        }
+    }
+    
+    private static Stream<Arguments> withoutStringDecodingArguments() {
+        return Stream.of(
+                Arguments.of("missing-column-type", 
MySQLBinaryColumnType.STRING, Collections.emptyList()),
+                Arguments.of("unknown-column-type", 
MySQLBinaryColumnType.STRING, 
Collections.singletonList(MySQLBinaryColumnType.NULL)),
+                Arguments.of("date-column", MySQLBinaryColumnType.STRING, 
Collections.singletonList(MySQLBinaryColumnType.DATE)),
+                Arguments.of("blob-parameter-character-column", 
MySQLBinaryColumnType.BLOB, 
Collections.singletonList(MySQLBinaryColumnType.VAR_STRING)),
+                Arguments.of("blob-parameter-numeric-column", 
MySQLBinaryColumnType.BLOB, 
Collections.singletonList(MySQLBinaryColumnType.LONGLONG)));
+    }
+    
+    @Test
+    void assertReadParametersWithNullStringBoundToNumericColumn() throws 
SQLException {
+        byte[] data = {1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, (byte) 0xfe, 0};
+        ByteBuf buffer = Unpooled.wrappedBuffer(data);
+        try {
+            MySQLComStmtExecutePacket packet = new 
MySQLComStmtExecutePacket(new MySQLPacketPayload(buffer, 
StandardCharsets.UTF_8), 1);
+            assertNull(packet.readParameters(packet.getNewParameterTypes(), 
Collections.emptySet(), 
Collections.singletonList(MySQLBinaryColumnType.LONGLONG)).get(0));
+        } finally {
+            buffer.release();
+        }
+    }
+    
+    @Test
+    void assertReadParametersWithReusedStringTypeBoundToNumericColumn() throws 
SQLException {
+        byte[] data = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0x34, 0x38};
+        ByteBuf buffer = Unpooled.wrappedBuffer(data);
+        try {
+            MySQLComStmtExecutePacket packet = new 
MySQLComStmtExecutePacket(new MySQLPacketPayload(buffer, 
StandardCharsets.UTF_8), 1);
+            List<MySQLPreparedStatementParameterType> paramTypes = 
Collections.singletonList(new 
MySQLPreparedStatementParameterType(MySQLBinaryColumnType.STRING, 0));
+            Object actual = packet.readParameters(paramTypes, 
Collections.emptySet(), 
Collections.singletonList(MySQLBinaryColumnType.LONGLONG)).get(0);
+            assertThat(actual, isA(String.class));
+            assertThat(actual, is("48"));
+        } finally {
+            buffer.release();
+        }
     }
     
     private static Stream<Arguments> withoutParameterArguments() {

Reply via email to