fix: typecheck false positive for SQL function args of table row type#770
Open
mvanhorn wants to merge 1 commit into
Open
fix: typecheck false positive for SQL function args of table row type#770mvanhorn wants to merge 1 commit into
mvanhorn wants to merge 1 commit into
Conversation
pg typecheck raised a false-positive "missing FROM-clause entry" when a SQL function argument's type is a table's row (composite) type, e.g. `get_tbl_name(row_arg public.tbl) ... SELECT row_arg.name`. The schema-cache types query only loaded standalone composites (relkind 'c') and skipped relation row types, so resolve_type returned None and the field reference was left unreplaced. Load row types for tables, partitioned tables, views, materialized views and foreign tables (all relkinds that expose a composite row type) along with their user column attributes, restricting the attribute join to `attnum > 0` so system columns like ctid/xmin are not mistaken for real fields. The prepared .sqlx offline cache is regenerated to match. Fixes supabase-community#705
2 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
pg typecheckreported a false-positivemissing FROM-clause entry for table "row_arg"when a SQL function argument's type is a table's row (composite) type, for example:This is valid in Postgres because the argument resolves to the row, but the language server flagged
row_arg.nameas an error.Why this matters
Passing a table's row type as a function argument is a documented, common Postgres pattern. Reporting it as an error is a false positive: it flags correct code, which undermines trust in
pg typecheckand can hide the real diagnostics a user cares about. This was reported in #705 with a minimal reproduction and confirmed by a maintainer.Cause
To type-check a SQL function body,
apply_identifiersreplacesfn.arg[.field]references with default literals, resolving the argument type through the schema cache'stypeslist. The query that populates that list (crates/pgls_schema_cache/src/queries/types.sql) only admitted base/enum types and standalone composites created withCREATE TYPE ... AS (...)(relkind = 'c'). A table's implicit row type hasrelkind = 'r'(or'p'for a partitioned table), so it was never loaded.resolve_typethen returnedNone, therow_arg.namereference was left unreplaced, and Postgrespreparereported the missing-FROM error.Fix
Extend
types.sqlto also load the composite row types exposed by relations (ordinary tables, partitioned tables, views, materialized views, and foreign tables) along with their column attributes, admittingrelkind IN ('c', 'r', 'p', 'v', 'm', 'f')in both the attributes sub-select and the outer type filter. The attribute join is restricted toattnum > 0so relation system columns such asctid/xminare not mistaken for real fields. With the row type present in the cache, the existing composite-field-access branch inresolve_typemocksrow_arg.namewith the column's default literal, so the body type-checks cleanly. This completes the existing composite-type mocking path rather than depending on a separate type checker. The prepared.sqlxoffline query cache is regenerated to match the updated query.Tests
crates/pgls_typecheck/tests/diagnostics.rs): the reported MRE (select row_arg.namewithrow_arg public.tbl) now produces no diagnostic; a view-typed argument is covered as well.crates/pgls_typecheck/src/typed_identifier.rs): a table-backed row-type argument has its.idand.namefield references replaced with the columns' default literals, and a system-column reference (row_arg.ctid) is deliberately left unresolved so it still surfaces downstream.Known limitations
Field access on row-type arguments uses the same identifier-substitution mocking as other function parameters, so it inherits that mechanism's existing limitations: a parameter name that also shadows a
FROMalias, or an unqualified row-type name that is ambiguous across schemas under a custom search path, can still be substituted where Postgres would resolve differently. Addressing those cases belongs to the dedicated type checker discussed in #692 rather than to this query change.Fixes #705
AI was used for assistance.