Skip to content

Commit 29b7d6e

Browse files
committed
Support spatial extension types
This change adds support for the following types from the spatial extension: - `POINT_2D`: as `STRUCT{x: DOUBLE, y: DOUBLE}` - `POINT_3D`: as `STRUCT{x: DOUBLE, y: DOUBLE, z: DOUBLE}` - `POINT_4D`: as `STRUCT{x: DOUBLE, y: DOUBLE, z: DOUBLE, m: DOUBLE}` - `LINESTRING_2D`: as `LIST[STRUCT{x: DOUBLE, y: DOUBLE}]` - `POLYGON_2D`: as `LIST[LIST[STRUCT{x: DOUBLE, y: DOUBLE}]]` - `BOX_2D`: as `STRUCT{min_x: DOUBLE, max_x: DOUBLE, min_y: DOUBLE, max_y: DOUBLE}` - `BOX_2DF`: as `STRUCT{min_x: FLOAT, max_x: FLOAT, min_y: FLOAT, max_y: FLOAT}` - `GEOMETRY`: as `BLOB` - `WKB_BLOB`: as `BLOB` No new Java APIs are added for these types. Instead `java.sql.Array`, `java.sql.Struct` and `java.sql.Blob` need to be used to read them from a result set or to pass them as bind parameters. Testing: new test added to cover all spatial types in bind parameters and in result set. Fixes: duckdb#37
1 parent 887b5f5 commit 29b7d6e

File tree

8 files changed

+366
-5
lines changed

8 files changed

+366
-5
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ add_library(duckdb_java SHARED
155155
src/jni/duckdb_java.cpp
156156
src/jni/functions.cpp
157157
src/jni/refs.cpp
158+
src/jni/types.cpp
158159
src/jni/util.cpp
159160
${DUCKDB_SRC_FILES})
160161
target_compile_definitions(duckdb_java PRIVATE -DDUCKDB_STATIC_BUILD)

src/jni/duckdb_java.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "duckdb/parser/parsed_data/create_type_info.hpp"
1515
#include "functions.hpp"
1616
#include "refs.hpp"
17+
#include "types.hpp"
1718
#include "util.hpp"
1819

1920
#include <cstdint>
@@ -515,6 +516,7 @@ jobjectArray _duckdb_jdbc_fetch(JNIEnv *env, jclass, jobject res_ref_buf, jobjec
515516

516517
return vec_array;
517518
}
519+
518520
jobject ProcessVector(JNIEnv *env, Connection *conn_ref, Vector &vec, idx_t row_count) {
519521
auto type_str = env->NewStringUTF(type_to_jduckdb_type(vec.GetType()).c_str());
520522
// construct nullmask
@@ -532,7 +534,7 @@ jobject ProcessVector(JNIEnv *env, Connection *conn_ref, Vector &vec, idx_t row_
532534

533535
// this allows us to treat aliased (usually extension) types as strings
534536
auto type = vec.GetType();
535-
auto type_id = type.HasAlias() ? LogicalTypeId::UNKNOWN : type.id();
537+
auto type_id = type_id_from_type(type);
536538

537539
switch (type_id) {
538540
case LogicalTypeId::BOOLEAN:

src/jni/types.cpp

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
#include "types.hpp"
3+
4+
#include "util.hpp"
5+
6+
#include <string>
7+
#include <vector>
8+
9+
static const std::vector<std::string> SPATIAL_STRUCT_TYPES = {"POINT_2D", "POINT_3D", "POINT_4D", "BOX_2D", "BOX_2DF"};
10+
static const std::vector<std::string> SPATIAL_LIST_TYPES = {"LINESTRING_2D", "POLYGON_2D"};
11+
static const std::vector<std::string> SPATIAL_BLOB_TYPES = {"GEOMETRY", "WKB_BLOB"};
12+
13+
duckdb::LogicalTypeId type_id_from_type(const duckdb::LogicalType &type) {
14+
if (!type.HasAlias()) {
15+
return type.id();
16+
}
17+
18+
std::string alias = type.GetAlias();
19+
20+
if (vector_contains(SPATIAL_STRUCT_TYPES, alias)) {
21+
return duckdb::LogicalTypeId::STRUCT;
22+
}
23+
24+
if (vector_contains(SPATIAL_LIST_TYPES, alias)) {
25+
return duckdb::LogicalTypeId::LIST;
26+
}
27+
28+
if (vector_contains(SPATIAL_BLOB_TYPES, alias)) {
29+
return duckdb::LogicalTypeId::BLOB;
30+
}
31+
32+
return duckdb::LogicalTypeId::UNKNOWN;
33+
}

src/jni/types.hpp

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
#pragma once
3+
4+
#include "duckdb.hpp"
5+
6+
duckdb::LogicalTypeId type_id_from_type(const duckdb::LogicalType &type);

src/jni/util.hpp

+8
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
#include "duckdb.hpp"
44

5+
#include <algorithm>
56
#include <jni.h>
67
#include <string>
8+
#include <vector>
79

810
void check_java_exception_and_rethrow(JNIEnv *env);
911

@@ -14,3 +16,9 @@ std::string jstring_to_string(JNIEnv *env, jstring string_j);
1416
jobject decode_charbuffer_to_jstring(JNIEnv *env, const char *d_str, idx_t d_str_len);
1517

1618
duckdb::Value create_value_from_bigdecimal(JNIEnv *env, jobject decimal);
19+
20+
template <typename T>
21+
bool vector_contains(const std::vector<T> &vec, const T &value) {
22+
auto found = std::find(vec.begin(), vec.end(), value);
23+
return found != vec.end();
24+
}

src/main/java/org/duckdb/DuckDBColumnType.java

+12-1
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,16 @@ public enum DuckDBColumnType {
3535
MAP,
3636
ARRAY,
3737
UNKNOWN,
38-
UNION;
38+
UNION,
39+
40+
// spatial extension types
41+
POINT_2D,
42+
POINT_3D,
43+
POINT_4D,
44+
LINESTRING_2D,
45+
POLYGON_2D,
46+
BOX_2D,
47+
BOX_2DF,
48+
GEOMETRY,
49+
WKB_BLOB;
3950
}

src/main/java/org/duckdb/DuckDBVector.java

+18-3
Original file line numberDiff line numberDiff line change
@@ -109,15 +109,24 @@ Object getObject(int idx) throws SQLException {
109109
case JSON:
110110
return getJsonObject(idx);
111111
case BLOB:
112+
case GEOMETRY:
113+
case WKB_BLOB:
112114
return getBlob(idx);
113115
case UUID:
114116
return getUuid(idx);
115117
case MAP:
116118
return getMap(idx);
117119
case LIST:
118120
case ARRAY:
121+
case LINESTRING_2D:
122+
case POLYGON_2D:
119123
return getArray(idx);
120124
case STRUCT:
125+
case POINT_2D:
126+
case POINT_3D:
127+
case POINT_4D:
128+
case BOX_2D:
129+
case BOX_2DF:
121130
return getStruct(idx);
122131
case UNION:
123132
return getUnion(idx);
@@ -249,7 +258,11 @@ Array getArray(int idx) throws SQLException {
249258
if (check_and_null(idx)) {
250259
return null;
251260
}
252-
if (isType(DuckDBColumnType.LIST) || isType(DuckDBColumnType.ARRAY)) {
261+
switch (duckdb_type) {
262+
case LIST:
263+
case ARRAY:
264+
case LINESTRING_2D:
265+
case POLYGON_2D:
253266
return (Array) varlen_data[idx];
254267
}
255268
throw new SQLFeatureNotSupportedException("getArray");
@@ -278,10 +291,12 @@ Blob getBlob(int idx) throws SQLException {
278291
if (check_and_null(idx)) {
279292
return null;
280293
}
281-
if (isType(DuckDBColumnType.BLOB)) {
294+
switch (duckdb_type) {
295+
case BLOB:
296+
case GEOMETRY:
297+
case WKB_BLOB:
282298
return new DuckDBResultSet.DuckDBBlobResult(ByteBuffer.wrap((byte[]) varlen_data[idx]));
283299
}
284-
285300
throw new SQLFeatureNotSupportedException("getBlob");
286301
}
287302

0 commit comments

Comments
 (0)