diff --git a/docker/thirdparties/docker-compose/postgresql/init/02-create-table.sql b/docker/thirdparties/docker-compose/postgresql/init/02-create-table.sql index 6ace3b20cb..738582a7cb 100644 --- a/docker/thirdparties/docker-compose/postgresql/init/02-create-table.sql +++ b/docker/thirdparties/docker-compose/postgresql/init/02-create-table.sql @@ -156,3 +156,8 @@ CREATE TABLE catalog_pg_test.test_insert ( name varchar(128), age int ); + +CREATE TABLE catalog_pg_test.wkb_test ( + id SERIAL PRIMARY KEY, + location bytea +); \ No newline at end of file diff --git a/docker/thirdparties/docker-compose/postgresql/init/03-insert.sql b/docker/thirdparties/docker-compose/postgresql/init/03-insert.sql index c5c0f565f1..6211db298b 100644 --- a/docker/thirdparties/docker-compose/postgresql/init/03-insert.sql +++ b/docker/thirdparties/docker-compose/postgresql/init/03-insert.sql @@ -2655,3 +2655,5 @@ insert into catalog_pg_test.test12 values (1, '980dd890-f7fe-4fff-999d-873516108b2e'); insert into catalog_pg_test.test12 values (2, '980dd890-f7fe-4fff-999d-873516108b2e'); + +INSERT INTO catalog_pg_test.wkb_test (location) SELECT ST_AsBinary(ST_GeomFromText('POLYGON((0 0,0 1,1 1,1 0,0 0))',4326)); \ No newline at end of file diff --git a/fe/fe-core/src/main/java/org/apache/doris/external/jdbc/JdbcClient.java b/fe/fe-core/src/main/java/org/apache/doris/external/jdbc/JdbcClient.java index 837690f37f..15cb5846af 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/external/jdbc/JdbcClient.java +++ b/fe/fe-core/src/main/java/org/apache/doris/external/jdbc/JdbcClient.java @@ -586,6 +586,7 @@ public class JdbcClient { case "varbit": case "jsonb": case "uuid": + case "bytea": return ScalarType.createStringType(); default: return Type.UNSUPPORTED; diff --git a/fe/java-udf/src/main/java/org/apache/doris/udf/JdbcExecutor.java b/fe/java-udf/src/main/java/org/apache/doris/udf/JdbcExecutor.java index 84b2a7d893..4380f9505d 100644 --- a/fe/java-udf/src/main/java/org/apache/doris/udf/JdbcExecutor.java +++ b/fe/java-udf/src/main/java/org/apache/doris/udf/JdbcExecutor.java @@ -1164,6 +1164,49 @@ public class JdbcExecutor { UdfUtils.copyMemory(bytes, UdfUtils.BYTE_ARRAY_OFFSET, null, bytesAddr, offsets[numRows - 1]); } + private void byteaPutToHexString(Object[] column, boolean isNullable, int numRows, long nullMapAddr, + long offsetsAddr, long charsAddr) { + int[] offsets = new int[numRows]; + byte[][] byteRes = new byte[numRows][]; + int offset = 0; + if (isNullable) { + for (int i = 0; i < numRows; i++) { + if (column[i] == null) { + byteRes[i] = emptyBytes; + UdfUtils.UNSAFE.putByte(nullMapAddr + i, (byte) 1); + } else { + byteRes[i] = byteArrayToHexString((byte[]) column[i]).getBytes(StandardCharsets.UTF_8); + } + offset += byteRes[i].length; + offsets[i] = offset; + } + } else { + for (int i = 0; i < numRows; i++) { + byteRes[i] = byteArrayToHexString((byte[]) column[i]).getBytes(StandardCharsets.UTF_8); + offset += byteRes[i].length; + offsets[i] = offset; + } + } + byte[] bytes = new byte[offsets[numRows - 1]]; + long bytesAddr = JNINativeMethod.resizeStringColumn(charsAddr, offsets[numRows - 1]); + int dst = 0; + for (int i = 0; i < numRows; i++) { + for (int j = 0; j < byteRes[i].length; j++) { + bytes[dst++] = byteRes[i][j]; + } + } + UdfUtils.copyMemory(offsets, UdfUtils.INT_ARRAY_OFFSET, null, offsetsAddr, numRows * 4L); + UdfUtils.copyMemory(bytes, UdfUtils.BYTE_ARRAY_OFFSET, null, bytesAddr, offsets[numRows - 1]); + } + + private static String byteArrayToHexString(byte[] bytes) { + StringBuilder hexString = new StringBuilder("\\x"); + for (byte b : bytes) { + hexString.append(String.format("%02x", b & 0xff)); + } + return hexString.toString(); + } + public void copyBatchStringResult(Object columnObj, boolean isNullable, int numRows, long nullMapAddr, long offsetsAddr, long charsAddr) { Object[] column = (Object[]) columnObj; @@ -1176,6 +1219,9 @@ public class JdbcExecutor { } if (column[firstNotNullIndex] instanceof String) { stringPutToString(column, isNullable, numRows, nullMapAddr, offsetsAddr, charsAddr); + } else if (column[firstNotNullIndex] instanceof byte[]) { + // for postgresql bytea type + byteaPutToHexString(column, isNullable, numRows, nullMapAddr, offsetsAddr, charsAddr); } else { // object like in pg type point, polygon, jsonb..... get object is // org.postgresql.util.PGobject..... diff --git a/regression-test/data/jdbc_catalog_p0/test_pg_jdbc_catalog.out b/regression-test/data/jdbc_catalog_p0/test_pg_jdbc_catalog.out index 2c8073daff..6986a6b289 100644 --- a/regression-test/data/jdbc_catalog_p0/test_pg_jdbc_catalog.out +++ b/regression-test/data/jdbc_catalog_p0/test_pg_jdbc_catalog.out @@ -2136,6 +2136,9 @@ true abc def 2022-10-11 1.234 1 2 99 2022-10-22T10:59:59 34.123 1 980dd890-f7fe-4fff-999d-873516108b2e 2 980dd890-f7fe-4fff-999d-873516108b2e +-- !wkb_test -- +1 \\x01030000000100000005000000000000000000000000000000000000000000000000000000000000000000f03f000000000000f03f000000000000f03f000000000000f03f000000000000000000000000000000000000000000000000 + -- !test_insert1 -- doris1 18 diff --git a/regression-test/suites/jdbc_catalog_p0/test_pg_jdbc_catalog.groovy b/regression-test/suites/jdbc_catalog_p0/test_pg_jdbc_catalog.groovy index d0b3c76d7c..8416fa2fef 100644 --- a/regression-test/suites/jdbc_catalog_p0/test_pg_jdbc_catalog.groovy +++ b/regression-test/suites/jdbc_catalog_p0/test_pg_jdbc_catalog.groovy @@ -73,6 +73,7 @@ suite("test_pg_jdbc_catalog", "p0") { order_qt_test12 """ select * from test10 order by id; """ order_qt_test13 """ select * from test11 order by id; """ order_qt_test14 """ select * from test12 order by id; """ + order_qt_wkb_test """ select * from wkb_test order by id; """ // test insert String uuid1 = UUID.randomUUID().toString();