Skip to content

Commit

Permalink
support array domain
Browse files Browse the repository at this point in the history
  • Loading branch information
Leo-XM-Zeng committed Jan 1, 2025
1 parent eafdeee commit 1fe2582
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 20 deletions.
25 changes: 25 additions & 0 deletions src/pg/relations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ extern "C" {
#include "postgres.h"
#include "access/htup_details.h" // GETSTRUCT
#include "access/relation.h" // relation_open and relation_close
#include "access/tupdesc.h" // TupleDescAttr
#include "catalog/namespace.h" // makeRangeVarFromNameList, RangeVarGetRelid
#include "catalog/pg_type.h" // Form_pg_type
#include "optimizer/plancat.h" // estimate_rel_size
#include "utils/rel.h"
#include "utils/resowner.h" // CurrentResourceOwner and TopTransactionResourceOwner
#include "utils/syscache.h" // RELOID
#include "utils/lsyscache.h" // getBaseType
}

namespace pgduckdb {
Expand Down Expand Up @@ -48,6 +51,28 @@ OpenRelation(Oid relationId) {
ResourceOwner saveResourceOwner = CurrentResourceOwner;
CurrentResourceOwner = TopTransactionResourceOwner;
auto rel = PostgresFunctionGuard(relation_open, relationId, AccessShareLock);
TupleDesc tupleDesc = rel->rd_att;
for (int i = 0; i < tupleDesc->natts; i++) {
Oid type_id= InvalidOid;
Form_pg_attribute thisatt = TupleDescAttr(tupleDesc, i);
if (type_is_array_domain(thisatt->atttypid) && thisatt->attndims == 0) {
HeapTuple typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(thisatt->atttypid));
thisatt->attndims = ((Form_pg_type) GETSTRUCT(typeTuple))->typndims;
ReleaseSysCache(typeTuple);

/* If it's a domain, look at the base type instead */
type_id = getBaseType(thisatt->atttypid);
} else if (type_is_array(thisatt->atttypid)) {
/* if an array type, assume domain attribute */
type_id = get_array_type(getBaseType(get_base_element_type(thisatt->atttypid)));
} else {
/* If it's a domain, look at the base type instead */
type_id = getBaseType(thisatt->atttypid);
}

thisatt->atttypid = type_id;
}

CurrentResourceOwner = saveResourceOwner;
return rel;
}
Expand Down
6 changes: 2 additions & 4 deletions src/pgduckdb_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -808,9 +808,7 @@ numeric_typmod_scale(int32 typmod) {

duckdb::LogicalType
ConvertPostgresToBaseDuckColumnType(Form_pg_attribute &attribute) {
/* If it's a domain, look at the base type instead */
auto type_id = getBaseType(attribute->atttypid);
switch (type_id) {
switch (attribute->atttypid) {
case BOOLOID:
case BOOLARRAYOID:
return duckdb::LogicalTypeId::BOOLEAN;
Expand Down Expand Up @@ -869,7 +867,7 @@ ConvertPostgresToBaseDuckColumnType(Form_pg_attribute &attribute) {
case REGCLASSARRAYOID:
return duckdb::LogicalTypeId::UINTEGER;
default:
return duckdb::LogicalType::USER("UnsupportedPostgresType (Oid=" + std::to_string(type_id) + ")");
return duckdb::LogicalType::USER("UnsupportedPostgresType (Oid=" + std::to_string(attribute->atttypid) + ")");
}
}

Expand Down
79 changes: 67 additions & 12 deletions test/regression/expected/domain.out
Original file line number Diff line number Diff line change
@@ -1,31 +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'); -- Good
INSERT INTO basictest values ('88', 'haha', 'short text'); -- Bad varchar
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 ('888', 'haha', 'short');
INSERT INTO basictest values ('88', 'haha', 'short', '123.1212'); -- Truncate numeric
select * from basictest;
testint4 | testtext | testvarchar
----------+----------+-------------
88 | haha | short
888 | haha | short
testint4 | testtext | testvarchar | testnumeric
----------+----------+-------------+-------------
88 | haha | short | 123.12
88 | haha | short | 123.12
(2 rows)

select testtext || testvarchar as concat, testint4 + 12 as sum
select testtext || testvarchar as concat, testnumeric + 42 as sum
from basictest;
concat | sum
-----------+-----
hahashort | 100
hahashort | 900
concat | sum
-----------+--------
hahashort | 165.12
hahashort | 165.12
(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;
38 changes: 34 additions & 4 deletions test/regression/sql/domain.sql
Original file line number Diff line number Diff line change
@@ -1,23 +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'); -- Good
INSERT INTO basictest values ('88', 'haha', 'short text'); -- Bad varchar
INSERT INTO basictest values ('888', 'haha', 'short');
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, testint4 + 12 as sum
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 1fe2582

Please sign in to comment.