Skip to content

Commit

Permalink
Support the PostgreSQL domain
Browse files Browse the repository at this point in the history
  • Loading branch information
Leo-XM-Zeng committed Jan 14, 2025
1 parent cc4a2d6 commit 6076683
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 3 deletions.
36 changes: 33 additions & 3 deletions src/pgduckdb_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -917,10 +917,40 @@ ConvertPostgresToBaseDuckColumnType(Form_pg_attribute &attribute) {

duckdb::LogicalType
ConvertPostgresToDuckColumnType(Form_pg_attribute &attribute) {
int dimensions = -1;
Oid save_typoid = InvalidOid;

if (get_typtype(attribute->atttypid) == TYPTYPE_DOMAIN) {
/* If the domain is an array type, you need to obtain the corresponding array dimension information */
if (type_is_array_domain(attribute->atttypid)) {
HeapTuple typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(attribute->atttypid));
dimensions = ((Form_pg_type) GETSTRUCT(typeTuple))->typndims;
ReleaseSysCache(typeTuple);
}

save_typoid = attribute->atttypid;
/* It is a domain type that needs to be reduced to its base type */
attribute->atttypid = getBaseType(attribute->atttypid);
} else if (type_is_array(attribute->atttypid)) {
Oid elem_type = get_base_element_type(attribute->atttypid);
if (OidIsValid(elem_type) && get_typtype(elem_type) == TYPTYPE_DOMAIN) {
save_typoid = attribute->atttypid;
/* When the member type of an array is domain, you need to build a base array type */
attribute->atttypid = get_array_type(getBaseType(elem_type));
}
}

auto base_type = ConvertPostgresToBaseDuckColumnType(attribute);
auto dimensions = attribute->attndims;
if (dimensions == 0) {
return base_type;

if (save_typoid != InvalidOid) {
attribute->atttypid = save_typoid;
}

if (dimensions == -1) {
dimensions = attribute->attndims;
if (dimensions == 0) {
return base_type;
}
}

for (int i = 0; i < dimensions; i++) {
Expand Down
86 changes: 86 additions & 0 deletions test/regression/expected/domain.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
create domain domainvarchar varchar(5);
create domain domainnumeric numeric(8,2);
create domain domainint4 int4;
create domain domaintext text;
-- Test tables using domains
create table basictest
( testint4 domainint4
, testtext domaintext
, testvarchar domainvarchar
, testnumeric domainnumeric
);
INSERT INTO basictest values ('88', 'haha', 'short', '123.12'); -- Good
INSERT INTO basictest values ('88', 'haha', 'short text', '123.12'); -- Bad varchar
ERROR: value too long for type character varying(5)
INSERT INTO basictest values ('88', 'haha', 'short', '123.1212'); -- Truncate numeric
select * from basictest;
testint4 | testtext | testvarchar | testnumeric
----------+----------+-------------+-------------
88 | haha | short | 123.12
88 | haha | short | 123.12
(2 rows)

select testtext || testvarchar as concat, testnumeric + 42 as sum
from basictest;
concat | sum
-----------+---------
hahashort | 165.120
hahashort | 165.120
(2 rows)

select * from basictest where testtext = 'haha';
testint4 | testtext | testvarchar | testnumeric
----------+----------+-------------+-------------
88 | haha | short | 123.12
88 | haha | short | 123.12
(2 rows)

select * from basictest where testvarchar = 'short';
testint4 | testtext | testvarchar | testnumeric
----------+----------+-------------+-------------
88 | haha | short | 123.12
88 | haha | short | 123.12
(2 rows)

-- array_domain
create domain domain_int_array as INT[];
CREATE TABLE domain_int_array_1d(a domain_int_array);
INSERT INTO domain_int_array_1d SELECT CAST(a as domain_int_array) FROM (VALUES
('{1, 2, 3}'),
(NULL),
('{4, 5, NULL, 7}'),
('{}')
) t(a);
SELECT * FROM domain_int_array_1d;
a
--------------
{1,2,3}

{4,5,NULL,7}
{}
(4 rows)

CREATE TABLE domain_int_array_2d(a domainint4[]);
INSERT INTO domain_int_array_2d SELECT CAST(a as domain_int_array) FROM (VALUES
('{1, 2, 3}'),
(NULL),
('{4, 5, NULL, 7}'),
('{}')
) t(a);
SELECT * FROM domain_int_array_2d;
a
--------------
{1,2,3}

{4,5,NULL,7}
{}
(4 rows)

drop table domain_int_array_2d;
drop table domain_int_array_1d;
drop domain domain_int_array;
drop table basictest;
drop domain domainvarchar restrict;
drop domain domainnumeric restrict;
drop domain domainint4 restrict;
drop domain domaintext;
1 change: 1 addition & 0 deletions test/regression/schedule
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ test: hugeint_conversion
test: read_functions
test: duckdb_only_functions
test: duckdb_recycle
test: domain
test: cte
test: create_schema
test: create_table_as
Expand Down
53 changes: 53 additions & 0 deletions test/regression/sql/domain.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
create domain domainvarchar varchar(5);
create domain domainnumeric numeric(8,2);
create domain domainint4 int4;
create domain domaintext text;

-- Test tables using domains
create table basictest
( testint4 domainint4
, testtext domaintext
, testvarchar domainvarchar
, testnumeric domainnumeric
);

INSERT INTO basictest values ('88', 'haha', 'short', '123.12'); -- Good
INSERT INTO basictest values ('88', 'haha', 'short text', '123.12'); -- Bad varchar
INSERT INTO basictest values ('88', 'haha', 'short', '123.1212'); -- Truncate numeric

select * from basictest;

select testtext || testvarchar as concat, testnumeric + 42 as sum
from basictest;

select * from basictest where testtext = 'haha';
select * from basictest where testvarchar = 'short';

-- array_domain
create domain domain_int_array as INT[];
CREATE TABLE domain_int_array_1d(a domain_int_array);
INSERT INTO domain_int_array_1d SELECT CAST(a as domain_int_array) FROM (VALUES
('{1, 2, 3}'),
(NULL),
('{4, 5, NULL, 7}'),
('{}')
) t(a);
SELECT * FROM domain_int_array_1d;

CREATE TABLE domain_int_array_2d(a domainint4[]);
INSERT INTO domain_int_array_2d SELECT CAST(a as domain_int_array) FROM (VALUES
('{1, 2, 3}'),
(NULL),
('{4, 5, NULL, 7}'),
('{}')
) t(a);
SELECT * FROM domain_int_array_2d;

drop table domain_int_array_2d;
drop table domain_int_array_1d;
drop domain domain_int_array;
drop table basictest;
drop domain domainvarchar restrict;
drop domain domainnumeric restrict;
drop domain domainint4 restrict;
drop domain domaintext;

0 comments on commit 6076683

Please sign in to comment.