fix(pg-meta): pair composite FK columns positionally to avoid cartesi…#317
fix(pg-meta): pair composite FK columns positionally to avoid cartesi…#317anp0429 wants to merge 1 commit into
Conversation
…an product The foreign-key subquery in tables.sql joined source and target columns independently (attnum = any(conkey) with attnum = any(confkey)), producing the cartesian product of a composite key's columns. An N-column foreign key yielded N^2 relationship rows, reporting column pairings that do not exist in the schema. This surfaces in list_tables (verbose) foreign_key_constraints. Pair the columns positionally with unnest(conkey, confkey) with ordinality so column i maps only to column i. Adds a regression test.
|
Hi @gregnr : no rush on this, but I wanted to check whether you see this as a real issue before it goes further. The short version: for composite foreign keys, list_tables (verbose) returns the cartesian product of columns (N² pairings instead of N), so it reports column relationships that don't exist in the schema , which an AI agent could silently trust. There's a minimal repro in the PR. I might be missing context on why it works this way, so I'd genuinely value your read: is this a bug worth fixing, or intended behavior? Happy to adjust or close if I've misunderstood something. |
There was a problem hiding this comment.
@anp0429 thanks for the PR and the ping! I just tried this and repro'd the bug on my end - nice find. The fix looks good, though one thing I noticed - for a composite FK, foreign_key_constraints is outputting one row per column pair vs a single row that represents captures both columns. If we keep it as is, nothing really signals that 2 rows belong to one atomic constraint vs 2 independent FKs.
I think we'll likely want to group within a single constraint instead - something like:
{
"name": "child_parent_fk",
"source_columns": ["a", "b"],
"target_table": "public.parent",
"target_columns": ["a", "b"]
}so that the composite is explicit. What do you think?
What kind of change does this PR introduce?
Bug fix : data-integrity issue in
list_tables(verbose) foreign-key output.What is the current behavior?
For any composite (multi-column) foreign key,
list_tables(verbose) returns the cartesian product of the source and target columns. An N-column FK produces N²foreign_key_constraintsentries instead of N - reporting column pairings that do not exist in the schema.Repro:
list_tableswithverbose: truereturns 4 constraints forchild_parent_fk:Only
a=>aandb=>bare real. Because this tool exists so an AI agent can reason about database structure, the fabricated relationships are silently trusted - an agent could infer key relationships that don't exist.Root cause is in
pg-meta/tables.sql. The FK subquery joins source and target columns independently:any(conkey)againstany(confkey)cross-joins every source column with every target column, instead of pairing them positionally.What is the new behavior?
The two arrays are walked in lockstep with
unnest(conkey, confkey) with ordinality, so column i pairs only with column i. The example above now returns exactly the two real pairs. Adds a regression test asserting the exact set of column pairs for a composite FK.Additional context
The same
pg-metaquery backs the schema-docs work in #278, so this fix helps that path as well.