Skip to content

Commit 25033f4

Browse files
authored
Fix bytea text encoding in PostgreSQL data rows (#37772)
1 parent a6318c4 commit 25033f4

2 files changed

Lines changed: 34 additions & 4 deletions

File tree

database/protocol/dialect/postgresql/src/main/java/org/apache/shardingsphere/database/protocol/postgresql/packet/command/query/PostgreSQLDataRowPacket.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.apache.shardingsphere.database.protocol.postgresql.packet.identifier.PostgreSQLMessagePacketType;
2828
import org.apache.shardingsphere.database.protocol.postgresql.payload.PostgreSQLPacketPayload;
2929

30+
import java.nio.charset.StandardCharsets;
3031
import java.sql.SQLException;
3132
import java.sql.SQLXML;
3233
import java.util.Collection;
@@ -38,6 +39,8 @@
3839
@Getter
3940
public final class PostgreSQLDataRowPacket extends PostgreSQLIdentifierPacket {
4041

42+
private static final byte[] HEX_DIGITS = "0123456789abcdef".getBytes(StandardCharsets.US_ASCII);
43+
4144
private final Collection<Object> data;
4245

4346
@Override
@@ -67,8 +70,9 @@ private void writeTextValue(final PostgreSQLPacketPayload payload, final Object
6770
if (null == each) {
6871
payload.writeInt4(0xFFFFFFFF);
6972
} else if (each instanceof byte[]) {
70-
payload.writeInt4(((byte[]) each).length);
71-
payload.writeBytes((byte[]) each);
73+
byte[] columnData = encodeByteaText((byte[]) each);
74+
payload.writeInt4(columnData.length);
75+
payload.writeBytes(columnData);
7276
} else if (each instanceof SQLXML) {
7377
writeSQLXMLData(payload, each);
7478
} else if (each instanceof Boolean) {
@@ -82,6 +86,18 @@ private void writeTextValue(final PostgreSQLPacketPayload payload, final Object
8286
}
8387
}
8488

89+
private byte[] encodeByteaText(final byte[] value) {
90+
byte[] result = new byte[value.length * 2 + 2];
91+
result[0] = '\\';
92+
result[1] = 'x';
93+
for (int i = 0; i < value.length; i++) {
94+
int unsignedByte = value[i] & 0xFF;
95+
result[2 + i * 2] = HEX_DIGITS[unsignedByte >>> 4];
96+
result[3 + i * 2] = HEX_DIGITS[unsignedByte & 0x0F];
97+
}
98+
return result;
99+
}
100+
85101
private void writeSQLXMLData(final PostgreSQLPacketPayload payload, final Object data) {
86102
try {
87103
byte[] dataBytes = ((SQLXML) data).getString().getBytes(payload.getCharset());

database/protocol/dialect/postgresql/src/test/java/org/apache/shardingsphere/database/protocol/postgresql/packet/command/query/PostgreSQLDataRowPacketTest.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,9 @@ void assertWriteWithNull() {
6868
void assertWriteWithBytes() {
6969
PostgreSQLDataRowPacket actual = new PostgreSQLDataRowPacket(Collections.singleton(new byte[]{'a'}));
7070
actual.write(payload);
71-
verify(payload).writeInt4(new byte[]{'a'}.length);
72-
verify(payload).writeBytes(new byte[]{'a'});
71+
byte[] expectedBytes = buildExpectedByteaText(new byte[]{'a'});
72+
verify(payload).writeInt4(expectedBytes.length);
73+
verify(payload).writeBytes(expectedBytes);
7374
}
7475

7576
@Test
@@ -122,4 +123,17 @@ void assertWriteBinaryInt4() {
122123
void assertGetIdentifier() {
123124
assertThat(new PostgreSQLDataRowPacket(Collections.emptyList()).getIdentifier(), is(PostgreSQLMessagePacketType.DATA_ROW));
124125
}
126+
127+
private byte[] buildExpectedByteaText(final byte[] value) {
128+
byte[] result = new byte[value.length * 2 + 2];
129+
result[0] = '\\';
130+
result[1] = 'x';
131+
byte[] hexDigits = "0123456789abcdef".getBytes(StandardCharsets.US_ASCII);
132+
for (int i = 0; i < value.length; i++) {
133+
int unsignedByte = value[i] & 0xFF;
134+
result[2 + i * 2] = hexDigits[unsignedByte >>> 4];
135+
result[3 + i * 2] = hexDigits[unsignedByte & 0x0F];
136+
}
137+
return result;
138+
}
125139
}

0 commit comments

Comments
 (0)