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

JSONB support #513

Merged
merged 15 commits into from
Jan 13, 2025
Merged
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
19 changes: 18 additions & 1 deletion src/pgduckdb_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -900,6 +901,8 @@ ConvertPostgresToBaseDuckColumnType(Form_pg_attribute &attribute) {
return duckdb::LogicalTypeId::UUID;
case JSONOID:
case JSONARRAYOID:
case JSONBOID:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also support jsonb insida a postgres array:

Suggested change
case JSONBOID:
case JSONBOID:
case JSONBARRAYOID:

This would need some tests in array_type_support.sql

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

case JSONBARRAYOID:
return duckdb::LogicalType::JSON();
case REGCLASSOID:
case REGCLASSARRAYOID:
Expand Down Expand Up @@ -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<duckdb::string_t>(result);
data[offset] = duckdb::StringVector::AddString(result, str);
}

template <class T, class OP = DecimalConversionInteger>
T
ConvertDecimal(const NumericVar &numeric) {
Expand Down Expand Up @@ -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:
Expand Down
26 changes: 24 additions & 2 deletions test/regression/expected/array_type_support.out
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
21 changes: 21 additions & 0 deletions test/regression/expected/type_support.out
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
19 changes: 17 additions & 2 deletions test/regression/sql/array_type_support.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
12 changes: 12 additions & 0 deletions test/regression/sql/type_support.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;