This is an automated email from the ASF dual-hosted git repository. zhaojinchao 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 034c7bde9c0 Fix raw bytes corrupted when decoding FIELD_TYPE_STRING in MySQL protocol (#28236) 034c7bde9c0 is described below commit 034c7bde9c0d84a35275374e7faeca14c18fa059 Author: 吴伟杰 <wuwei...@apache.org> AuthorDate: Wed Aug 23 17:52:18 2023 +0800 Fix raw bytes corrupted when decoding FIELD_TYPE_STRING in MySQL protocol (#28236) * Fix raw bytes corrupted when decoding FIELD_TYPE_STRING in MySQL protocol * Apply spotless --- .../protocol/MySQLBinaryProtocolValueFactory.java | 15 ++++--- .../MySQLByteLenencBinaryProtocolValue.java | 40 +++++++++++++++++ .../MySQLBinaryProtocolValueFactoryTest.java | 10 ++--- .../MySQLByteLenencBinaryProtocolValueTest.java | 52 ++++++++++++++++++++++ 4 files changed, 107 insertions(+), 10 deletions(-) diff --git a/db-protocol/mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLBinaryProtocolValueFactory.java b/db-protocol/mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLBinaryProtocolValueFactory.java index 60e6aa885ea..d27b28ba46a 100644 --- a/db-protocol/mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLBinaryProtocolValueFactory.java +++ b/db-protocol/mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLBinaryProtocolValueFactory.java @@ -36,6 +36,7 @@ public final class MySQLBinaryProtocolValueFactory { static { setStringLenencBinaryProtocolValue(); + setByteLenencBinaryProtocolValue(); setInt8BinaryProtocolValue(); setInt4BinaryProtocolValue(); setInt2BinaryProtocolValue(); @@ -49,21 +50,25 @@ public final class MySQLBinaryProtocolValueFactory { private static void setStringLenencBinaryProtocolValue() { MySQLStringLenencBinaryProtocolValue binaryProtocolValue = new MySQLStringLenencBinaryProtocolValue(); - BINARY_PROTOCOL_VALUES.put(MySQLBinaryColumnType.STRING, binaryProtocolValue); BINARY_PROTOCOL_VALUES.put(MySQLBinaryColumnType.VARCHAR, binaryProtocolValue); BINARY_PROTOCOL_VALUES.put(MySQLBinaryColumnType.VAR_STRING, binaryProtocolValue); BINARY_PROTOCOL_VALUES.put(MySQLBinaryColumnType.ENUM, binaryProtocolValue); BINARY_PROTOCOL_VALUES.put(MySQLBinaryColumnType.SET, binaryProtocolValue); - BINARY_PROTOCOL_VALUES.put(MySQLBinaryColumnType.LONG_BLOB, binaryProtocolValue); - BINARY_PROTOCOL_VALUES.put(MySQLBinaryColumnType.MEDIUM_BLOB, binaryProtocolValue); - BINARY_PROTOCOL_VALUES.put(MySQLBinaryColumnType.BLOB, binaryProtocolValue); - BINARY_PROTOCOL_VALUES.put(MySQLBinaryColumnType.TINY_BLOB, binaryProtocolValue); BINARY_PROTOCOL_VALUES.put(MySQLBinaryColumnType.GEOMETRY, binaryProtocolValue); BINARY_PROTOCOL_VALUES.put(MySQLBinaryColumnType.BIT, binaryProtocolValue); BINARY_PROTOCOL_VALUES.put(MySQLBinaryColumnType.DECIMAL, binaryProtocolValue); BINARY_PROTOCOL_VALUES.put(MySQLBinaryColumnType.NEWDECIMAL, binaryProtocolValue); } + private static void setByteLenencBinaryProtocolValue() { + MySQLByteLenencBinaryProtocolValue binaryProtocolValue = new MySQLByteLenencBinaryProtocolValue(); + BINARY_PROTOCOL_VALUES.put(MySQLBinaryColumnType.STRING, binaryProtocolValue); + BINARY_PROTOCOL_VALUES.put(MySQLBinaryColumnType.LONG_BLOB, binaryProtocolValue); + BINARY_PROTOCOL_VALUES.put(MySQLBinaryColumnType.MEDIUM_BLOB, binaryProtocolValue); + BINARY_PROTOCOL_VALUES.put(MySQLBinaryColumnType.BLOB, binaryProtocolValue); + BINARY_PROTOCOL_VALUES.put(MySQLBinaryColumnType.TINY_BLOB, binaryProtocolValue); + } + private static void setInt8BinaryProtocolValue() { MySQLInt8BinaryProtocolValue binaryProtocolValue = new MySQLInt8BinaryProtocolValue(); BINARY_PROTOCOL_VALUES.put(MySQLBinaryColumnType.LONGLONG, binaryProtocolValue); diff --git a/db-protocol/mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLByteLenencBinaryProtocolValue.java b/db-protocol/mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLByteLenencBinaryProtocolValue.java new file mode 100644 index 00000000000..84003a99d92 --- /dev/null +++ b/db-protocol/mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLByteLenencBinaryProtocolValue.java @@ -0,0 +1,40 @@ +/* + * 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.mysql.packet.command.query.binary.execute.protocol; + +import org.apache.shardingsphere.db.protocol.mysql.payload.MySQLPacketPayload; + +/** + * Binary protocol value for byte lenenc for MySQL. Actually this is string lenenc, but converting to {@link String} may corrupt the raw bytes. + */ +public final class MySQLByteLenencBinaryProtocolValue implements MySQLBinaryProtocolValue { + + @Override + public Object read(final MySQLPacketPayload payload, final boolean unsigned) { + return payload.readStringLenencByBytes(); + } + + @Override + public void write(final MySQLPacketPayload payload, final Object value) { + if (value instanceof byte[]) { + payload.writeBytesLenenc((byte[]) value); + } else { + payload.writeStringLenenc(value.toString()); + } + } +} diff --git a/db-protocol/mysql/src/test/java/org/apache/shardingsphere/db/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLBinaryProtocolValueFactoryTest.java b/db-protocol/mysql/src/test/java/org/apache/shardingsphere/db/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLBinaryProtocolValueFactoryTest.java index fb4801aa44e..1ddf0b8fade 100644 --- a/db-protocol/mysql/src/test/java/org/apache/shardingsphere/db/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLBinaryProtocolValueFactoryTest.java +++ b/db-protocol/mysql/src/test/java/org/apache/shardingsphere/db/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLBinaryProtocolValueFactoryTest.java @@ -29,7 +29,7 @@ class MySQLBinaryProtocolValueFactoryTest { @Test void assertGetBinaryProtocolValueWithMySQLTypeString() { - assertThat(MySQLBinaryProtocolValueFactory.getBinaryProtocolValue(MySQLBinaryColumnType.STRING), instanceOf(MySQLStringLenencBinaryProtocolValue.class)); + assertThat(MySQLBinaryProtocolValueFactory.getBinaryProtocolValue(MySQLBinaryColumnType.STRING), instanceOf(MySQLByteLenencBinaryProtocolValue.class)); } @Test @@ -54,22 +54,22 @@ class MySQLBinaryProtocolValueFactoryTest { @Test void assertGetBinaryProtocolValueWithMySQLTypeLongBlob() { - assertThat(MySQLBinaryProtocolValueFactory.getBinaryProtocolValue(MySQLBinaryColumnType.LONG_BLOB), instanceOf(MySQLStringLenencBinaryProtocolValue.class)); + assertThat(MySQLBinaryProtocolValueFactory.getBinaryProtocolValue(MySQLBinaryColumnType.LONG_BLOB), instanceOf(MySQLByteLenencBinaryProtocolValue.class)); } @Test void assertGetBinaryProtocolValueWithMySQLTypeMediumBlob() { - assertThat(MySQLBinaryProtocolValueFactory.getBinaryProtocolValue(MySQLBinaryColumnType.MEDIUM_BLOB), instanceOf(MySQLStringLenencBinaryProtocolValue.class)); + assertThat(MySQLBinaryProtocolValueFactory.getBinaryProtocolValue(MySQLBinaryColumnType.MEDIUM_BLOB), instanceOf(MySQLByteLenencBinaryProtocolValue.class)); } @Test void assertGetBinaryProtocolValueWithMySQLTypeBlob() { - assertThat(MySQLBinaryProtocolValueFactory.getBinaryProtocolValue(MySQLBinaryColumnType.BLOB), instanceOf(MySQLStringLenencBinaryProtocolValue.class)); + assertThat(MySQLBinaryProtocolValueFactory.getBinaryProtocolValue(MySQLBinaryColumnType.BLOB), instanceOf(MySQLByteLenencBinaryProtocolValue.class)); } @Test void assertGetBinaryProtocolValueWithMySQLTypeTinyBlob() { - assertThat(MySQLBinaryProtocolValueFactory.getBinaryProtocolValue(MySQLBinaryColumnType.TINY_BLOB), instanceOf(MySQLStringLenencBinaryProtocolValue.class)); + assertThat(MySQLBinaryProtocolValueFactory.getBinaryProtocolValue(MySQLBinaryColumnType.TINY_BLOB), instanceOf(MySQLByteLenencBinaryProtocolValue.class)); } @Test diff --git a/db-protocol/mysql/src/test/java/org/apache/shardingsphere/db/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLByteLenencBinaryProtocolValueTest.java b/db-protocol/mysql/src/test/java/org/apache/shardingsphere/db/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLByteLenencBinaryProtocolValueTest.java new file mode 100644 index 00000000000..6ee5d588ebf --- /dev/null +++ b/db-protocol/mysql/src/test/java/org/apache/shardingsphere/db/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLByteLenencBinaryProtocolValueTest.java @@ -0,0 +1,52 @@ +/* + * 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.mysql.packet.command.query.binary.execute.protocol; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import org.apache.shardingsphere.db.protocol.mysql.payload.MySQLPacketPayload; +import org.junit.jupiter.api.Test; + +import java.nio.charset.StandardCharsets; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +class MySQLByteLenencBinaryProtocolValueTest { + + @Test + void assertRead() { + byte[] input = {0x0d, 0x0a, 0x33, 0x18, 0x01, 0x4a, 0x08, 0x0a, (byte) 0x9a, 0x01, 0x18, 0x01, 0x4a, 0x6f}; + byte[] expected = {0x0a, 0x33, 0x18, 0x01, 0x4a, 0x08, 0x0a, (byte) 0x9a, 0x01, 0x18, 0x01, 0x4a, 0x6f}; + ByteBuf byteBuf = Unpooled.wrappedBuffer(input); + MySQLPacketPayload payload = new MySQLPacketPayload(byteBuf, StandardCharsets.UTF_8); + byte[] actual = (byte[]) new MySQLByteLenencBinaryProtocolValue().read(payload, false); + assertThat(actual, is(expected)); + } + + @Test + void assertWrite() { + byte[] input = {0x0a, 0x33, 0x18, 0x01, 0x4a, 0x08, 0x0a, (byte) 0x9a, 0x01, 0x18, 0x01, 0x4a, 0x6f}; + byte[] expected = {0x0d, 0x0a, 0x33, 0x18, 0x01, 0x4a, 0x08, 0x0a, (byte) 0x9a, 0x01, 0x18, 0x01, 0x4a, 0x6f}; + ByteBuf actual = Unpooled.wrappedBuffer(new byte[expected.length]).writerIndex(0); + MySQLPacketPayload payload = new MySQLPacketPayload(actual, StandardCharsets.UTF_8); + new MySQLByteLenencBinaryProtocolValue().write(payload, input); + assertThat(ByteBufUtil.getBytes(actual), is(expected)); + } +}