Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: bytea in array parsing #491

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading