@@ -10,7 +10,14 @@ index ea04300..38672a9 100644
1010 class PostgresSchemaEntry;
1111 class PostgresTransaction;
1212
13- @@ -64,7 +65,8 @@ public:
13+ @@ -21,5 +22,6 @@ struct PostgresTypeData {
14+ int64_t type_modifier = 0;
15+ string type_name;
16+ + int64_t type_oid = 0;
17+ idx_t array_dimensions = 0;
18+ };
19+
20+ @@ -64,7 +66,8 @@ public:
1421 static LogicalType ToPostgresType(const LogicalType &input);
1522 static LogicalType TypeToLogicalType(optional_ptr<PostgresTransaction> transaction,
1623 optional_ptr<PostgresSchemaEntry> schema, const PostgresTypeData &input,
@@ -60,32 +67,39 @@ index 2d9f5d9..6f2a3f2 100644
6067 auto &pgtypename = type_info.type_name;
6168
6269 // postgres array types start with an _
63- @@ -113,7 +115,7 @@ LogicalType PostgresUtils::TypeToLogicalType(optional_ptr<PostgresTransaction> t
70+ @@ -113,7 +115,14 @@ LogicalType PostgresUtils::TypeToLogicalType(optional_ptr<PostgresTransaction> t
6471 child_type_info.type_name = pgtypename.substr(1);
6572 child_type_info.type_modifier = type_info.type_modifier;
73+ + if (connection) {
74+ + D_ASSERT(type_info.type_oid != 0);
75+ + auto elem_result = connection->Query(StringUtil::Format(
76+ + "SELECT typelem FROM pg_type WHERE oid = %d", type_info.type_oid));
77+ + D_ASSERT(elem_result->Count() > 0);
78+ + child_type_info.type_oid = elem_result->GetInt64(0, 0);
79+ + }
6680 PostgresType child_pg_type;
6781- auto child_type = PostgresUtils::TypeToLogicalType(transaction, schema, child_type_info, child_pg_type);
6882+ auto child_type = PostgresUtils::TypeToLogicalType(transaction, schema, child_type_info, child_pg_type, connection);
6983 // construct the child type based on the number of dimensions
7084 for (idx_t i = 1; i < dimensions; i++) {
7185 PostgresType new_pg_type;
72- @@ -201,7 +203,51 @@ LogicalType PostgresUtils::TypeToLogicalType(optional_ptr<PostgresTransaction> t
86+ @@ -201,7 +203,52 @@ LogicalType PostgresUtils::TypeToLogicalType(optional_ptr<PostgresTransaction> t
7387 return LogicalType::LIST(LogicalType::DOUBLE);
7488 } else {
7589 if (!transaction) {
7690- // unsupported so fallback to varchar
7791+ if (connection) {
78- + // try composite type
92+ + D_ASSERT(type_info.type_oid != 0);
7993+ auto query = StringUtil::Format(
80- + "SELECT a.attname, t.typname, a.atttypmod "
94+ + "SELECT a.attname, t.typname, a.atttypmod, a.atttypid "
8195+ "FROM pg_type ct "
8296+ "JOIN pg_class c ON c.oid = ct.typrelid "
8397+ "JOIN pg_attribute a ON a.attrelid = ct.typrelid "
8498+ "JOIN pg_type t ON t.oid = a.atttypid "
85- + "WHERE ct.typname = %s AND ct.typtype = 'c' "
99+ + "WHERE ct.oid = %d AND ct.typtype = 'c' "
86100+ "AND a.attnum > 0 AND NOT a.attisdropped "
87101+ "ORDER BY a.attnum",
88- + KeywordHelper::WriteQuoted(pgtypename).c_str() );
102+ + type_info.type_oid );
89103+ auto result = connection->Query(query);
90104+ auto rows = result->Count();
91105+ if (rows > 0) {
@@ -95,6 +109,7 @@ index 2d9f5d9..6f2a3f2 100644
95109+ PostgresTypeData field_type_info;
96110+ field_type_info.type_name = result->GetString(row, 1);
97111+ field_type_info.type_modifier = result->GetInt64(row, 2);
112+ + field_type_info.type_oid = result->GetInt64(row, 3);
98113+ PostgresType child_pg_type;
99114+ auto field_type = TypeToLogicalType(nullptr, nullptr, field_type_info,
100115+ child_pg_type, connection);
@@ -103,18 +118,18 @@ index 2d9f5d9..6f2a3f2 100644
103118+ }
104119+ return LogicalType::STRUCT(std::move(child_types));
105120+ }
106- + // try domain type — resolve to base type
107121+ auto domain_query = StringUtil::Format(
108- + "SELECT bt.typname, t.typtypmod "
122+ + "SELECT bt.typname, t.typtypmod, bt.oid "
109123+ "FROM pg_type t "
110124+ "JOIN pg_type bt ON bt.oid = t.typbasetype "
111- + "WHERE t.typname = %s AND t.typtype = 'd'",
112- + KeywordHelper::WriteQuoted(pgtypename).c_str() );
125+ + "WHERE t.oid = %d AND t.typtype = 'd'",
126+ + type_info.type_oid );
113127+ auto domain_result = connection->Query(domain_query);
114128+ if (domain_result->Count() > 0) {
115129+ PostgresTypeData base_type_info;
116130+ base_type_info.type_name = domain_result->GetString(0, 0);
117131+ base_type_info.type_modifier = domain_result->GetInt64(0, 1);
132+ + base_type_info.type_oid = domain_result->GetInt64(0, 2);
118133+ return TypeToLogicalType(nullptr, nullptr, base_type_info,
119134+ postgres_type, connection);
120135+ }
@@ -126,7 +141,27 @@ diff --git a/src/storage/postgres_table_set.cpp b/src/storage/postgres_table_set
126141index efe37a1..07d3ee6 100644
127142--- a/src/storage/postgres_table_set.cpp
128143+++ b/src/storage/postgres_table_set.cpp
129- @@ -53,7 +53,7 @@ ORDER BY namespace_id, relname, attnum, constraint_id;
144+ @@ -24,16 +24,16 @@ SELECT pg_namespace.oid AS namespace_id, relname, relpages, attname,
145+ - pg_type.typname type_name, atttypmod type_modifier, pg_attribute.attndims ndim,
146+ - attnum, pg_attribute.attnotnull AS notnull, NULL constraint_id,
147+ + pg_type.typname type_name, atttypmod type_modifier, pg_attribute.attndims ndim,
148+ + atttypid type_oid, attnum, pg_attribute.attnotnull AS notnull, NULL constraint_id,
149+ NULL constraint_type, NULL constraint_key
150+ FROM pg_class
151+ JOIN pg_namespace ON relnamespace = pg_namespace.oid
152+ JOIN pg_attribute ON pg_class.oid=pg_attribute.attrelid
153+ JOIN pg_type ON atttypid=pg_type.oid
154+ WHERE attnum > 0 AND relkind IN ('r', 'v', 'm', 'f', 'p') ${CONDITION}
155+ UNION ALL
156+ SELECT pg_namespace.oid AS namespace_id, relname, NULL relpages, NULL attname, NULL type_name,
157+ - NULL type_modifier, NULL ndim, NULL attnum, NULL AS notnull,
158+ + NULL type_modifier, NULL ndim, NULL type_oid, NULL attnum, NULL AS notnull,
159+ pg_constraint.oid AS constraint_id, contype AS constraint_type,
160+ conkey AS constraint_key
161+ FROM pg_class
162+ JOIN pg_namespace ON relnamespace = pg_namespace.oid
163+ JOIN pg_constraint ON (pg_class.oid=pg_constraint.conrelid)
164+ @@ -53,18 +53,19 @@ ORDER BY namespace_id, relname, attnum, constraint_id;
130165
131166 void PostgresTableSet::AddColumn(optional_ptr<PostgresTransaction> transaction,
132167 optional_ptr<PostgresSchemaEntry> schema, PostgresResult &result, idx_t row,
@@ -135,7 +170,12 @@ index efe37a1..07d3ee6 100644
135170 PostgresTypeData type_info;
136171 idx_t column_index = 3;
137172 auto column_name = result.GetString(row, column_index);
138- @@ -64,7 +64,7 @@ void PostgresTableSet::AddColumn(optional_ptr<PostgresTransaction> transaction,
173+ type_info.type_name = result.GetString(row, column_index + 1);
174+ type_info.type_modifier = result.GetInt64(row, column_index + 2);
175+ type_info.array_dimensions = result.GetInt64(row, column_index + 3);
176+ + type_info.type_oid = result.GetInt64(row, column_index + 4);
177+ - bool is_not_null = result.GetBool(row, column_index + 5);
178+ + bool is_not_null = result.GetBool(row, column_index + 6);
139179 string default_value;
140180
141181 PostgresType postgres_type;
@@ -144,6 +184,11 @@ index efe37a1..07d3ee6 100644
144184 table_info.postgres_types.push_back(std::move(postgres_type));
145185 table_info.postgres_names.push_back(column_name);
146186 ColumnDefinition column(std::move(column_name), std::move(column_type));
187+ @@ -87,3 +87,3 @@ void PostgresTableSet::AddConstraint(PostgresResult &result, idx_t row, Postgres
188+ void PostgresTableSet::AddConstraint(PostgresResult &result, idx_t row, PostgresTableInfo &table_info) {
189+ - idx_t column_index = 9;
190+ + idx_t column_index = 10;
191+ auto constraint_type = result.GetString(row, column_index + 1);
147192@@ -109,12 +109,13 @@ void PostgresTableSet::AddConstraint(PostgresResult &result, idx_t row, Postgres
148193
149194 void PostgresTableSet::AddColumnOrConstraint(optional_ptr<PostgresTransaction> transaction,
0 commit comments