Found while working #11161 (which repaired the error contract of this method, not its query). Not fixed there: the bounded in-place-fix exemption did not apply — this is a scoping defect, a different class from the swallowed-error defect that card owns. #11161 remains open on its own subject; this issue is not addressed by that PR.
What
packages/drivers/driver-sql/src/sql-driver.ts, SqlDriver.introspectForeignKeys, Postgres arm. The query filters:
WHEREtc.constraint_type='FOREIGN KEY'ANDtc.table_name= ?
with no table_schema predicate on tc at all. information_schema.table_constraints spans every schema the user can read, so for a table name that exists in more than one schema, the result merges foreign keys from all of them — including schemas the session's search_path never reaches.
Why this is a real hazard here, not a theoretical one
Suggested shape
Add AND tc.table_schema = ANY (current_schemas(false)) — the same pin introspectSchema's table listing and introspectUniqueConstraints use, keeping one resolution rule across the four arms. (MySQL's arm already pins TABLE_SCHEMA = DATABASE(); SQLite has no schemas.)
Not measured here
Whether any in-tree consumer currently hits the collision (the live suite's per-file tables mostly have per-file names). The defect is the unscoped read, which returns a wrong answer the moment names collide.
Found while working #11161 (which repaired the error contract of this method, not its query). Not fixed there: the bounded in-place-fix exemption did not apply — this is a scoping defect, a different class from the swallowed-error defect that card owns. #11161 remains open on its own subject; this issue is not addressed by that PR.
What
packages/drivers/driver-sql/src/sql-driver.ts,SqlDriver.introspectForeignKeys, Postgres arm. The query filters:with no
table_schemapredicate ontcat all.information_schema.table_constraintsspans every schema the user can read, so for a table name that exists in more than one schema, the result merges foreign keys from all of them — including schemas the session'ssearch_pathnever reaches.Why this is a real hazard here, not a theoretical one
introspectIndexesresolves byto_regclass(?)(session resolution),introspectSchemaliststable_schema = ANY (current_schemas(false)), and driver-sql: introspectPrimaryKeys / ForeignKeys / UniqueConstraints still swallow every error and report ABSENCE — the #7332 ruling was applied to introspectIndexes only #11161 just applied thecurrent_schemas(false)pin tointrospectUniqueConstraintswhen its (previously always-failing) query was repaired.introspectForeignKeysis now the only introspection arm still unscoped.Suggested shape
Add
AND tc.table_schema = ANY (current_schemas(false))— the same pinintrospectSchema's table listing andintrospectUniqueConstraintsuse, keeping one resolution rule across the four arms. (MySQL's arm already pinsTABLE_SCHEMA = DATABASE(); SQLite has no schemas.)Not measured here
Whether any in-tree consumer currently hits the collision (the live suite's per-file tables mostly have per-file names). The defect is the unscoped read, which returns a wrong answer the moment names collide.