Skip to content

Commit

Permalink
fix bytea in array parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
stepansergeevitch committed Dec 23, 2024
1 parent 1a43081 commit 52e7669
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,19 @@ void nullableBiDimensionalArray() throws SQLException {
}
}

@Test
void byteaArray() throws SQLException {
try (Connection connection = createConnection(); Statement statement = connection.createStatement()) {
try (ResultSet rs = statement.executeQuery("select [E'\\x61\\x62\\x63']::array(bytea), [[E'\\x61\\x62\\x63']]::array(array(bytea))")) {
rs.next();
validateArrayUsingGetObject(rs, 1, new byte[][] {new byte[] {0x61, 0x62, 0x63}});
validateArrayUsingGetArray(rs, 1, Types.BINARY, "bytea", new byte[][] {new byte[] {0x61, 0x62, 0x63}});
validateArrayUsingGetObject(rs, 2, new byte[][][] {new byte[][] {new byte[] {0x61, 0x62, 0x63}}});
validateArrayUsingGetArray(rs, 2, Types.BINARY, "bytea", new byte[][][] {new byte[][] {new byte[] {0x61, 0x62, 0x63}}});
}
}
}

private <T> void validateArrayUsingGetObject(ResultSet rs, int index, T[] expected) throws SQLException {
assertSqlArray(rs.getObject(index), expected);
}
Expand Down
11 changes: 3 additions & 8 deletions src/main/java/com/firebolt/jdbc/type/BaseType.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import java.util.regex.Pattern;

import static com.firebolt.jdbc.exception.ExceptionType.TYPE_TRANSFORMATION_ERROR;
import static com.firebolt.jdbc.type.array.SqlArrayUtil.BYTE_ARRAY_PREFIX;
import static com.firebolt.jdbc.type.array.SqlArrayUtil.hexStringToByteArray;

/** This class contains the java types the Firebolt data types are mapped to */
Expand Down Expand Up @@ -89,13 +88,9 @@ public enum BaseType {
if (s == null || s.isEmpty()) {
return new byte[] {};
}
if (s.startsWith(BYTE_ARRAY_PREFIX)) {
byte[] bytes = hexStringToByteArray(s);
int limit = conversion.getMaxFieldSize();
return limit > 0 && limit <= bytes.length ? Arrays.copyOf(bytes, limit) : bytes;
}
// Cannot convert from other formats (such as 'Escape') for the moment
throw new FireboltException("Cannot convert binary string in non-hex format to byte array");
byte[] bytes = hexStringToByteArray(s);
int limit = conversion.getMaxFieldSize();
return limit > 0 && limit <= bytes.length ? Arrays.copyOf(bytes, limit) : bytes;
});

// this class is needed to prevent back reference because the constant is used from the enum constructor
Expand Down
12 changes: 7 additions & 5 deletions src/main/java/com/firebolt/jdbc/type/array/SqlArrayUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ public class SqlArrayUtil {
);
private final ColumnType columnType;
private final Markers markers;
public static final String BYTE_ARRAY_PREFIX = "\\x";
public static final String BYTEA_PREFIX = "\\x";
public static final String BYTEA_IN_ARRAY_PREFIX = "\\\\x"; // In CSV arrays bytea prefix has two backslashes

private static final class Markers {
private final char leftArrayBracket;
Expand Down Expand Up @@ -269,19 +270,20 @@ public static String byteArrayToHexString(@Nullable byte[] bytes, boolean separa
return null;
}
ByteBuffer buffer = ByteBuffer.wrap(bytes);
String separator = separateEachByte ? BYTE_ARRAY_PREFIX : "";
return Stream.generate(buffer::get).limit(buffer.capacity()).map(i -> format("%02x", i)).collect(joining(separator, BYTE_ARRAY_PREFIX, ""));
String separator = separateEachByte ? BYTEA_PREFIX : "";
return Stream.generate(buffer::get).limit(buffer.capacity()).map(i -> format("%02x", i)).collect(joining(separator, BYTEA_PREFIX, ""));
}

@SuppressWarnings("java:S1168") // we have to return null here
public static byte[] hexStringToByteArray(String str) {
if (str == null) {
return null;
}
if (!str.startsWith(BYTE_ARRAY_PREFIX)) {
if (!str.startsWith(BYTEA_PREFIX) && !str.startsWith(BYTEA_IN_ARRAY_PREFIX)) {
return str.getBytes(UTF_8);
}
char[] chars = str.substring(2).toCharArray();
int prefixLength = str.startsWith(BYTEA_PREFIX) ? BYTEA_PREFIX.length() : BYTEA_IN_ARRAY_PREFIX.length();
char[] chars = str.substring(prefixLength).toCharArray();
byte[] bytes = new byte[chars.length / 2];
for (int i = 0; i < chars.length; i += 2) {
bytes[i / 2] = (byte) ((hexDigit(chars[i]) << 4) + hexDigit(chars[i + 1]));
Expand Down

0 comments on commit 52e7669

Please sign in to comment.