1212/**
1313 * PostgreSQL implementation of IntrospectionProvider.
1414 * Uses pg_catalog and information_schema for schema introspection.
15+ *
16+ * <p>Every catalog query filters on {@code current_schema()} rather than a
17+ * hardcoded {@code 'public'}. Databases that keep their tables anywhere else —
18+ * a dbt warehouse in {@code marts}, a tenant schema, anything — were previously
19+ * invisible: introspection returned zero tables, so brain initialization
20+ * "COMPLETED" in about a second having learned nothing, and the schema snapshot
21+ * was persisted as an empty table list. Honouring the session search_path makes
22+ * the target schema a property of the connection (set it on the role, or via the
23+ * JDBC {@code currentSchema} parameter) instead of a compile-time constant.
24+ *
25+ * <p>{@link #getDefaultSchema()} deliberately still reports {@code public}: its
26+ * callers use it to decide whether a name needs qualifying, and reporting the
27+ * session schema there would strip the schema off exactly the names that need
28+ * it most ({@code marts.dim_person} → {@code dim_person}).
1529 */
1630@ Slf4j
1731@ Component
@@ -55,25 +69,27 @@ private List<DatabaseObject> getTablesAndViews(Connection connection) throws SQL
5569 JOIN pg_namespace n ON n.nspname = t.schemaname
5670 JOIN pg_class c ON c.relnamespace = n.oid AND c.relname = t.tablename
5771 LEFT JOIN pg_stat_all_tables s ON s.relid = c.oid
58- WHERE t.schemaname = 'public' AND c.relkind IN ('r', 'p')
72+ WHERE t.schemaname = current_schema() AND c.relkind IN ('r', 'p')
5973 UNION ALL
6074 SELECT v.viewname as name, 'view' as type, 0 as row_count
61- FROM pg_views v WHERE v.schemaname = 'public'
75+ FROM pg_views v WHERE v.schemaname = current_schema()
6276 ORDER BY type, name
6377 """ ;
6478
79+ String schema = resolveSchema (connection );
80+
6581 try (Statement stmt = connection .createStatement ();
6682 ResultSet rs = stmt .executeQuery (query )) {
6783 while (rs .next ()) {
6884 DatabaseObject obj = new DatabaseObject ();
6985 obj .setName (rs .getString ("name" ));
70- obj .setSchema (DEFAULT_SCHEMA );
86+ obj .setSchema (schema );
7187 obj .setType (rs .getString ("type" ));
7288 Long estimatedRowCount = getNullableLong (rs , "row_count" );
7389 obj .setRowCount ("table" .equals (obj .getType ())
74- ? resolveTableRowCount (connection , DEFAULT_SCHEMA , obj .getName (), estimatedRowCount )
90+ ? resolveTableRowCount (connection , schema , obj .getName (), estimatedRowCount )
7591 : estimatedRowCount );
76- obj .setColumns (getTableColumns (connection , DEFAULT_SCHEMA , obj .getName ()));
92+ obj .setColumns (getTableColumns (connection , schema , obj .getName ()));
7793 objects .add (obj );
7894 }
7995 }
@@ -87,16 +103,18 @@ private List<DatabaseObject> getFunctions(Connection connection) throws SQLExcep
87103 SELECT p.proname as name, pg_get_functiondef(p.oid) as definition
88104 FROM pg_proc p
89105 JOIN pg_namespace n ON p.pronamespace = n.oid
90- WHERE n.nspname = 'public' AND p.prokind = 'f'
106+ WHERE n.nspname = current_schema() AND p.prokind = 'f'
91107 ORDER BY p.proname
92108 """ ;
93109
110+ String schema = resolveSchema (connection );
111+
94112 try (Statement stmt = connection .createStatement ();
95113 ResultSet rs = stmt .executeQuery (query )) {
96114 while (rs .next ()) {
97115 DatabaseObject obj = new DatabaseObject ();
98116 obj .setName (rs .getString ("name" ));
99- obj .setSchema (DEFAULT_SCHEMA );
117+ obj .setSchema (schema );
100118 obj .setType ("function" );
101119 obj .setDefinition (rs .getString ("definition" ));
102120 objects .add (obj );
@@ -112,16 +130,18 @@ private List<DatabaseObject> getProcedures(Connection connection) throws SQLExce
112130 SELECT p.proname as name, pg_get_functiondef(p.oid) as definition
113131 FROM pg_proc p
114132 JOIN pg_namespace n ON p.pronamespace = n.oid
115- WHERE n.nspname = 'public' AND p.prokind = 'p'
133+ WHERE n.nspname = current_schema() AND p.prokind = 'p'
116134 ORDER BY p.proname
117135 """ ;
118136
137+ String schema = resolveSchema (connection );
138+
119139 try (Statement stmt = connection .createStatement ();
120140 ResultSet rs = stmt .executeQuery (query )) {
121141 while (rs .next ()) {
122142 DatabaseObject obj = new DatabaseObject ();
123143 obj .setName (rs .getString ("name" ));
124- obj .setSchema (DEFAULT_SCHEMA );
144+ obj .setSchema (schema );
125145 obj .setType ("procedure" );
126146 obj .setDefinition (rs .getString ("definition" ));
127147 objects .add (obj );
@@ -151,7 +171,7 @@ LEFT JOIN (
151171 try (PreparedStatement stmt = connection .prepareStatement (query )) {
152172 stmt .setString (1 , tableName );
153173 stmt .setString (2 , tableName );
154- stmt .setString (3 , DEFAULT_SCHEMA );
174+ stmt .setString (3 , resolveSchema ( connection ) );
155175 try (ResultSet rs = stmt .executeQuery ()) {
156176 while (rs .next ()) {
157177 ColumnInfo col = new ColumnInfo ();
@@ -257,11 +277,12 @@ WITH t AS (SELECT ?::regclass AS rel)
257277 stats .setIndexSize (rs .getLong ("index_bytes" ));
258278 stats .setSizeBytes (rs .getLong ("total_bytes" ));
259279 stats .setIndexSizeBytes (rs .getLong ("index_bytes" ));
280+ String schema = resolveSchema (connection );
260281 stats .setRowCount (resolveTableRowCount (
261282 connection ,
262- DEFAULT_SCHEMA ,
283+ schema ,
263284 tableName ,
264- getEstimatedTableRowCount (connection , DEFAULT_SCHEMA , tableName )
285+ getEstimatedTableRowCount (connection , schema , tableName )
265286 ));
266287 }
267288 }
@@ -288,27 +309,28 @@ public SchemaMetadata scanSchema(Connection connection, String database) throws
288309 "JOIN pg_namespace n ON n.nspname = t.schemaname " +
289310 "JOIN pg_class c ON c.relnamespace = n.oid AND c.relname = t.tablename " +
290311 "LEFT JOIN pg_stat_all_tables s ON s.relid = c.oid " +
291- "WHERE t.schemaname = 'public' AND c.relkind IN ('r', 'p') " +
312+ "WHERE t.schemaname = current_schema() AND c.relkind IN ('r', 'p') " +
292313 "UNION ALL " +
293314 "SELECT v.viewname as tablename, 'view' as type, 0 as size_bytes, 0 as row_count " +
294315 "FROM pg_views v " +
295- "WHERE v.schemaname = 'public' " +
316+ "WHERE v.schemaname = current_schema() " +
296317 "ORDER BY tablename" ;
297318
298319 Map <String , TableMetadata > tableMap = new HashMap <>();
320+ String schemaName = resolveSchema (connection );
299321
300322 try (Statement stmt = connection .createStatement ()) {
301323 applyStatementSettings (stmt );
302324 try (ResultSet rs = stmt .executeQuery (tablesQuery )) {
303325 while (rs .next ()) {
304326 TableMetadata table = new TableMetadata ();
305327 table .setName (rs .getString ("tablename" ));
306- table .setSchema (DEFAULT_SCHEMA );
328+ table .setSchema (schemaName );
307329 table .setType (rs .getString ("type" ));
308330 table .setSizeBytes (rs .getLong ("size_bytes" ));
309331 Long estimatedRowCount = getNullableLong (rs , "row_count" );
310332 table .setRowCount ("table" .equals (table .getType ())
311- ? resolveTableRowCount (connection , DEFAULT_SCHEMA , table .getName (), estimatedRowCount )
333+ ? resolveTableRowCount (connection , schemaName , table .getName (), estimatedRowCount )
312334 : estimatedRowCount );
313335 schema .getTables ().add (table );
314336 tableMap .put (table .getName (), table );
@@ -349,9 +371,9 @@ private void scanPostgreSQLColumnsBatch(Connection connection, Map<String, Table
349371 " FROM information_schema.table_constraints tc " +
350372 " JOIN information_schema.key_column_usage ku " +
351373 " ON tc.constraint_name = ku.constraint_name AND tc.table_name = ku.table_name " +
352- " WHERE tc.table_schema = 'public' AND tc.constraint_type = 'PRIMARY KEY' " +
374+ " WHERE tc.table_schema = current_schema() AND tc.constraint_type = 'PRIMARY KEY' " +
353375 ") pk ON c.table_name = pk.table_name AND c.column_name = pk.column_name " +
354- "WHERE c.table_schema = 'public' " +
376+ "WHERE c.table_schema = current_schema() " +
355377 "ORDER BY c.table_name, c.ordinal_position" ;
356378
357379 try (Statement stmt = connection .createStatement ()) {
@@ -386,10 +408,10 @@ private void scanPostgreSQLIndexesBatch(Connection connection, Map<String, Table
386408 "array_agg(a.attname ORDER BY array_position(ix.indkey, a.attnum)) as columns, " +
387409 "ix.indisunique " +
388410 "FROM pg_indexes i " +
389- "JOIN pg_class c ON c.relname = i.tablename AND c.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'public' ) " +
390- "JOIN pg_index ix ON ix.indexrelid = (SELECT oid FROM pg_class WHERE relname = i.indexname AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'public' )) " +
411+ "JOIN pg_class c ON c.relname = i.tablename AND c.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = current_schema() ) " +
412+ "JOIN pg_index ix ON ix.indexrelid = (SELECT oid FROM pg_class WHERE relname = i.indexname AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = current_schema() )) " +
391413 "JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum = ANY(ix.indkey) " +
392- "WHERE i.schemaname = 'public' " +
414+ "WHERE i.schemaname = current_schema() " +
393415 "GROUP BY i.tablename, i.indexname, i.indexdef, ix.indisunique " +
394416 "ORDER BY i.tablename, i.indexname" ;
395417
@@ -435,7 +457,7 @@ private void scanPostgreSQLForeignKeys(Connection connection, SchemaMetadata sch
435457 "ON tc.constraint_name = kcu.constraint_name " +
436458 "JOIN information_schema.constraint_column_usage AS ccu " +
437459 "ON ccu.constraint_name = tc.constraint_name " +
438- "WHERE tc.constraint_type = 'FOREIGN KEY' AND tc.table_schema = 'public' " +
460+ "WHERE tc.constraint_type = 'FOREIGN KEY' AND tc.table_schema = current_schema() " +
439461 "ORDER BY tc.table_name, tc.constraint_name" ;
440462
441463 try (Statement stmt = connection .createStatement ()) {
@@ -472,7 +494,7 @@ public List<RelationshipMetadata> getForeignKeys(Connection connection, String d
472494 JOIN information_schema.constraint_column_usage ccu
473495 ON tc.constraint_name = ccu.constraint_name
474496 WHERE tc.constraint_type = 'FOREIGN KEY'
475- AND tc.table_schema = 'public'
497+ AND tc.table_schema = current_schema()
476498 ORDER BY tc.table_name, tc.constraint_name
477499 """ ;
478500
@@ -502,7 +524,7 @@ public List<ColumnDetail> getColumnDetails(Connection connection, String databas
502524 data_type, character_maximum_length, numeric_precision, numeric_scale,
503525 udt_name
504526 FROM information_schema.columns
505- WHERE table_schema = 'public' AND table_name = ?
527+ WHERE table_schema = current_schema() AND table_name = ?
506528 ORDER BY ordinal_position
507529 """ ;
508530
@@ -547,7 +569,7 @@ public List<ConstraintDetail> getConstraintDetails(Connection connection, String
547569 LEFT JOIN information_schema.constraint_column_usage ccu
548570 ON tc.constraint_name = ccu.constraint_name
549571 AND tc.constraint_type = 'FOREIGN KEY'
550- WHERE tc.table_schema = 'public' AND tc.table_name = ?
572+ WHERE tc.table_schema = current_schema() AND tc.table_name = ?
551573 ORDER BY tc.constraint_name
552574 """ ;
553575
@@ -582,11 +604,12 @@ public List<ConstraintDetail> getConstraintDetails(Connection connection, String
582604
583605 @ Override
584606 public Long getTableRowCount (Connection connection , String database , String tableName ) throws SQLException {
607+ String schema = resolveSchema (connection );
585608 return resolveTableRowCount (
586609 connection ,
587- DEFAULT_SCHEMA ,
610+ schema ,
588611 tableName ,
589- getEstimatedTableRowCount (connection , DEFAULT_SCHEMA , tableName )
612+ getEstimatedTableRowCount (connection , schema , tableName )
590613 );
591614 }
592615
@@ -763,6 +786,28 @@ private Long getExactTableRowCount(Connection connection, String schemaName, Str
763786 return null ;
764787 }
765788
789+ /**
790+ * The schema this session's catalog queries resolve against — the first
791+ * existing entry in the search_path. Falls back to {@code public} so a
792+ * connection whose search_path names only missing schemas behaves exactly
793+ * as it did before, rather than tagging every object with a null schema.
794+ */
795+ private String resolveSchema (Connection connection ) {
796+ try (Statement stmt = connection .createStatement ();
797+ ResultSet rs = stmt .executeQuery ("SELECT current_schema()" )) {
798+ if (rs .next ()) {
799+ String schema = rs .getString (1 );
800+ if (schema != null && !schema .isBlank ()) {
801+ return schema ;
802+ }
803+ }
804+ } catch (SQLException e ) {
805+ log .debug ("Could not resolve current_schema(), falling back to {}: {}" ,
806+ DEFAULT_SCHEMA , e .getMessage ());
807+ }
808+ return DEFAULT_SCHEMA ;
809+ }
810+
766811 private String quoteIdentifier (String identifier ) {
767812 return "\" " + identifier .replace ("\" " , "\" \" " ) + "\" " ;
768813 }
@@ -802,7 +847,7 @@ public List<Map<String, Object>> getAllTablesWithMetadata(Connection connection,
802847 JOIN pg_namespace n ON n.nspname = t.schemaname
803848 JOIN pg_class c ON c.relnamespace = n.oid AND c.relname = t.tablename
804849 LEFT JOIN pg_stat_all_tables s ON s.relid = c.oid
805- WHERE t.schemaname = 'public' AND c.relkind IN ('r', 'p')
850+ WHERE t.schemaname = current_schema() AND c.relkind IN ('r', 'p')
806851 ORDER BY t.tablename
807852 """ ;
808853
0 commit comments