@@ -9,24 +9,24 @@ import (
99func initPgCatalog (db * sql.DB ) error {
1010 // Create our own pg_database view that has all the columns psql expects
1111 // We put it in main schema and rewrite queries to use it
12+ // Include template databases for PostgreSQL compatibility
13+ // Note: We use 'testdb' as the user database name to match the test PostgreSQL container
1214 pgDatabaseSQL := `
1315 CREATE OR REPLACE VIEW pg_database AS
14- SELECT
15- 1::INTEGER AS oid,
16- current_database() AS datname,
17- 0::INTEGER AS datdba,
18- 6::INTEGER AS encoding,
19- 'en_US.UTF-8' AS datcollate,
20- 'en_US.UTF-8' AS datctype,
21- false AS datistemplate,
22- true AS datallowconn,
23- -1::INTEGER AS datconnlimit,
24- NULL AS datacl
16+ SELECT * FROM (
17+ VALUES
18+ (1::INTEGER, 'postgres', 10::INTEGER, 6::INTEGER, 'en_US.UTF-8', 'en_US.UTF-8', false, true, -1::INTEGER, NULL),
19+ (2::INTEGER, 'template0', 10::INTEGER, 6::INTEGER, 'en_US.UTF-8', 'en_US.UTF-8', true, false, -1::INTEGER, NULL),
20+ (3::INTEGER, 'template1', 10::INTEGER, 6::INTEGER, 'en_US.UTF-8', 'en_US.UTF-8', true, true, -1::INTEGER, NULL),
21+ (4::INTEGER, 'testdb', 10::INTEGER, 6::INTEGER, 'en_US.UTF-8', 'en_US.UTF-8', false, true, -1::INTEGER, NULL)
22+ ) AS t(oid, datname, datdba, encoding, datcollate, datctype, datistemplate, datallowconn, datconnlimit, datacl)
2523 `
2624 db .Exec (pgDatabaseSQL )
2725
2826 // Create pg_class wrapper that adds missing columns psql expects
2927 // DuckDB's pg_catalog.pg_class is missing relforcerowsecurity
28+ // Also filter out internal duckgres views so they don't appear in \dt output
29+ // Note: We use an explicit list of internal view names to filter
3030 pgClassSQL := `
3131 CREATE OR REPLACE VIEW pg_class_full AS
3232 SELECT
@@ -67,6 +67,13 @@ func initPgCatalog(db *sql.DB) error {
6767 reloptions,
6868 relpartbound
6969 FROM pg_catalog.pg_class
70+ WHERE relname NOT IN (
71+ 'pg_database', 'pg_class_full', 'pg_collation', 'pg_policy', 'pg_roles',
72+ 'pg_statistic_ext', 'pg_publication_tables', 'pg_rules', 'pg_publication',
73+ 'pg_publication_rel', 'pg_inherits', 'pg_namespace',
74+ 'information_schema_columns_compat', 'information_schema_tables_compat',
75+ 'information_schema_schemata_compat', '__duckgres_column_metadata'
76+ )
7077 `
7178 db .Exec (pgClassSQL )
7279
@@ -203,6 +210,21 @@ func initPgCatalog(db *sql.DB) error {
203210 `
204211 db .Exec (pgInheritsSQL )
205212
213+ // Create pg_namespace wrapper that maps 'main' to 'public' for PostgreSQL compatibility
214+ // Also set owner to match PostgreSQL conventions:
215+ // - public (main) is owned by pg_database_owner (OID 6171)
216+ // - other schemas are owned by postgres (OID 10)
217+ pgNamespaceSQL := `
218+ CREATE OR REPLACE VIEW pg_namespace AS
219+ SELECT
220+ oid,
221+ CASE WHEN nspname = 'main' THEN 'public' ELSE nspname END AS nspname,
222+ CASE WHEN nspname = 'main' THEN 6171::BIGINT ELSE 10::BIGINT END AS nspowner,
223+ nspacl
224+ FROM pg_catalog.pg_namespace
225+ `
226+ db .Exec (pgNamespaceSQL )
227+
206228 // Create helper macros/functions that psql expects but DuckDB doesn't have
207229 // These need to be created without schema prefix so DuckDB finds them
208230 //
@@ -211,7 +233,13 @@ func initPgCatalog(db *sql.DB) error {
211233 // in DuckLake mode. Otherwise, the macros won't be found when DuckLake is attached.
212234 functions := []string {
213235 // pg_get_userbyid - returns username for a role OID
214- `CREATE OR REPLACE MACRO pg_get_userbyid(id) AS 'duckdb'` ,
236+ // Map common PostgreSQL role OIDs to their names
237+ `CREATE OR REPLACE MACRO pg_get_userbyid(id) AS
238+ CASE id
239+ WHEN 10 THEN 'postgres'
240+ WHEN 6171 THEN 'pg_database_owner'
241+ ELSE 'postgres'
242+ END` ,
215243 // pg_table_is_visible - checks if table is in search path
216244 `CREATE OR REPLACE MACRO pg_table_is_visible(oid) AS true` ,
217245 // has_schema_privilege - check schema access
0 commit comments