diff --git a/src/pgduckdb_types.cpp b/src/pgduckdb_types.cpp index d8041272..ff8c479e 100644 --- a/src/pgduckdb_types.cpp +++ b/src/pgduckdb_types.cpp @@ -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++) { diff --git a/test/regression/expected/domain.out b/test/regression/expected/domain.out new file mode 100644 index 00000000..738363af --- /dev/null +++ b/test/regression/expected/domain.out @@ -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; diff --git a/test/regression/schedule b/test/regression/schedule index 18d43899..2383f220 100644 --- a/test/regression/schedule +++ b/test/regression/schedule @@ -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 diff --git a/test/regression/sql/domain.sql b/test/regression/sql/domain.sql new file mode 100644 index 00000000..cd7449cd --- /dev/null +++ b/test/regression/sql/domain.sql @@ -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;