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

Support the PostgreSQL domain #532

Merged
merged 11 commits into from
Feb 24, 2025
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;