diff --git a/src/pgduckdb_types.cpp b/src/pgduckdb_types.cpp index b90375a6..d8041272 100644 --- a/src/pgduckdb_types.cpp +++ b/src/pgduckdb_types.cpp @@ -27,6 +27,7 @@ extern "C" { #include "utils/syscache.h" #include "utils/date.h" #include "utils/timestamp.h" +#include "utils/jsonb.h" } #include "pgduckdb/pgduckdb_filter.hpp" @@ -900,6 +901,8 @@ ConvertPostgresToBaseDuckColumnType(Form_pg_attribute &attribute) { return duckdb::LogicalTypeId::UUID; case JSONOID: case JSONARRAYOID: + case JSONBOID: + case JSONBARRAYOID: return duckdb::LogicalType::JSON(); case REGCLASSOID: case REGCLASSARRAYOID: @@ -1059,6 +1062,15 @@ AppendString(duckdb::Vector &result, Datum value, idx_t offset, bool is_bpchar) data[offset] = duckdb::StringVector::AddString(result, str); } +static void +AppendJsonb(duckdb::Vector &result, Datum value, idx_t offset) { + auto jsonb = DatumGetJsonbP(value); + auto jsonb_str = JsonbToCString(NULL, &jsonb->root, VARSIZE(jsonb)); + duckdb::string_t str(jsonb_str); + auto data = duckdb::FlatVector::GetData(result); + data[offset] = duckdb::StringVector::AddString(result, str); +} + template T ConvertDecimal(const NumericVar &numeric) { @@ -1200,7 +1212,12 @@ ConvertPostgresToDuckValue(Oid attr_type, Datum value, duckdb::Vector &result, i break; case duckdb::LogicalTypeId::VARCHAR: { // NOTE: This also handles JSON - AppendString(result, value, offset, attr_type == BPCHAROID); + if (attr_type == JSONBOID) { + AppendJsonb(result, value, offset); + break; + } else { + AppendString(result, value, offset, attr_type == BPCHAROID); + } break; } case duckdb::LogicalTypeId::DATE: diff --git a/test/regression/expected/array_type_support.out b/test/regression/expected/array_type_support.out index e229f4c6..ac0c629e 100644 --- a/test/regression/expected/array_type_support.out +++ b/test/regression/expected/array_type_support.out @@ -248,6 +248,27 @@ SELECT * FROM json_array_1d; {} (4 rows) +-- JSONB (single dimension) +CREATE TABLE jsonb_array_1d(a JSONB[]); +INSERT INTO jsonb_array_1d VALUES + (ARRAY['{"key": "value"}', '{"array": [1, 2, 3]}']::JSONB[]), + (ARRAY[ + '{"key1": "value1"}'::jsonb, + '{"key2": "value2"}'::jsonb + ]), + (NULL), + (ARRAY['{"object": {"nested": "value"}}', NULL, '{"number": 42}']::JSONB[]), + (ARRAY[]::JSONB[]); +SELECT * FROM jsonb_array_1d; + a +------------------------------------------------------------------- + {"{\"key\": \"value\"}","{\"array\": [1, 2, 3]}"} + {"{\"key1\": \"value1\"}","{\"key2\": \"value2\"}"} + + {"{\"object\": {\"nested\": \"value\"}}",NULL,"{\"number\": 42}"} + {} +(5 rows) + -- REGCLASS (single dimension) CREATE TABLE regclass_array_1d(a REGCLASS[]); INSERT INTO regclass_array_1d VALUES @@ -320,8 +341,8 @@ SELECT * FROM varchar_array_2d; -- BYTEA (single dimension) CREATE TABLE bytea_array_1d (a bytea[]); -INSERT INTO bytea_array_1d (a) -VALUES +INSERT INTO bytea_array_1d (a) +VALUES (ARRAY[decode('01020304', 'hex'), decode('aabbccdd', 'hex')]), (ARRAY[decode('11223344', 'hex'), decode('55667788', 'hex')]); SELECT * FROM bytea_array_1d; @@ -454,6 +475,7 @@ DROP TABLE float8_array_1d; DROP TABLE numeric_array_1d; DROP TABLE uuid_array_1d; DROP TABLE json_array_1d; +DROP TABLE jsonb_array_1d; DROP TABLE regclass_array_1d; DROP TABLE char_array_2d; DROP TABLE smallint_array_2d; diff --git a/test/regression/expected/type_support.out b/test/regression/expected/type_support.out index 4d509658..c4a42c26 100644 --- a/test/regression/expected/type_support.out +++ b/test/regression/expected/type_support.out @@ -308,6 +308,26 @@ SELECT * FROM json_tbl; {} (4 rows) +-- JSONB +CREATE TABLE jsonb_tbl(a JSONB); +INSERT INTO jsonb_tbl (a) VALUES +('{"a": 1, "b": {"c": 2, "d": [3, 4]}, "e": "hello"}'), +('{"f": 10, "g": {"h": 20, "i": 30}, "j": [40, 50, 60]}'), +('{"k": true, "l": null, "m": {"n": "world", "o": [7, 8, 9]}}'), +('[1, 2, 3]'), +('["a", "b", "c"]'), +('[{"key": "value"}, {"key": "another"}]'); +SELECT * FROM jsonb_tbl; + a +------------------------------------------------------------- + {"a": 1, "b": {"c": 2, "d": [3, 4]}, "e": "hello"} + {"f": 10, "g": {"h": 20, "i": 30}, "j": [40, 50, 60]} + {"k": true, "l": null, "m": {"n": "world", "o": [7, 8, 9]}} + [1, 2, 3] + ["a", "b", "c"] + [{"key": "value"}, {"key": "another"}] +(6 rows) + -- BLOB CREATE TABLE blob_tbl(a bytea); INSERT INTO blob_tbl SELECT CAST(a as bytea) FROM (VALUES @@ -364,5 +384,6 @@ DROP TABLE bigint_numeric; DROP TABLE hugeint_numeric; DROP TABLE uuid_tbl; DROP TABLE json_tbl; +DROP TABLE jsonb_tbl; DROP TABLE blob_tbl; DROP TABLE regclass_tbl; diff --git a/test/regression/sql/array_type_support.sql b/test/regression/sql/array_type_support.sql index aec79467..2633e8bd 100644 --- a/test/regression/sql/array_type_support.sql +++ b/test/regression/sql/array_type_support.sql @@ -153,6 +153,20 @@ INSERT INTO json_array_1d VALUES (ARRAY[]::JSON[]); SELECT * FROM json_array_1d; + +-- JSONB (single dimension) +CREATE TABLE jsonb_array_1d(a JSONB[]); +INSERT INTO jsonb_array_1d VALUES + (ARRAY['{"key": "value"}', '{"array": [1, 2, 3]}']::JSONB[]), + (ARRAY[ + '{"key1": "value1"}'::jsonb, + '{"key2": "value2"}'::jsonb + ]), + (NULL), + (ARRAY['{"object": {"nested": "value"}}', NULL, '{"number": 42}']::JSONB[]), + (ARRAY[]::JSONB[]); +SELECT * FROM jsonb_array_1d; + -- REGCLASS (single dimension) CREATE TABLE regclass_array_1d(a REGCLASS[]); INSERT INTO regclass_array_1d VALUES @@ -198,8 +212,8 @@ SELECT * FROM varchar_array_2d; -- BYTEA (single dimension) CREATE TABLE bytea_array_1d (a bytea[]); -INSERT INTO bytea_array_1d (a) -VALUES +INSERT INTO bytea_array_1d (a) +VALUES (ARRAY[decode('01020304', 'hex'), decode('aabbccdd', 'hex')]), (ARRAY[decode('11223344', 'hex'), decode('55667788', 'hex')]); SELECT * FROM bytea_array_1d; @@ -279,6 +293,7 @@ DROP TABLE float8_array_1d; DROP TABLE numeric_array_1d; DROP TABLE uuid_array_1d; DROP TABLE json_array_1d; +DROP TABLE jsonb_array_1d; DROP TABLE regclass_array_1d; DROP TABLE char_array_2d; DROP TABLE smallint_array_2d; diff --git a/test/regression/sql/type_support.sql b/test/regression/sql/type_support.sql index b42a9eb3..64f1e20c 100644 --- a/test/regression/sql/type_support.sql +++ b/test/regression/sql/type_support.sql @@ -154,6 +154,17 @@ INSERT INTO json_tbl SELECT CAST(a as JSON) FROM (VALUES ) t(a); SELECT * FROM json_tbl; +-- JSONB +CREATE TABLE jsonb_tbl(a JSONB); +INSERT INTO jsonb_tbl (a) VALUES +('{"a": 1, "b": {"c": 2, "d": [3, 4]}, "e": "hello"}'), +('{"f": 10, "g": {"h": 20, "i": 30}, "j": [40, 50, 60]}'), +('{"k": true, "l": null, "m": {"n": "world", "o": [7, 8, 9]}}'), +('[1, 2, 3]'), +('["a", "b", "c"]'), +('[{"key": "value"}, {"key": "another"}]'); +SELECT * FROM jsonb_tbl; + -- BLOB CREATE TABLE blob_tbl(a bytea); INSERT INTO blob_tbl SELECT CAST(a as bytea) FROM (VALUES @@ -191,5 +202,6 @@ DROP TABLE bigint_numeric; DROP TABLE hugeint_numeric; DROP TABLE uuid_tbl; DROP TABLE json_tbl; +DROP TABLE jsonb_tbl; DROP TABLE blob_tbl; DROP TABLE regclass_tbl;