Build whole-row Vars the same way during parsing and planning.
authorTom Lane <[email protected]>
Wed, 12 Mar 2025 15:47:19 +0000 (11:47 -0400)
committerTom Lane <[email protected]>
Wed, 12 Mar 2025 15:47:19 +0000 (11:47 -0400)
commitd3a29ae6a60cba3d971cd184d477af8d17f157ee
tree63e95ed0718c39f19c701dda369c120ad73bfcde
parent584f17a9063ee63aa472705bfac1bed95e3e2194
Build whole-row Vars the same way during parsing and planning.

makeWholeRowVar() has different rules for constructing a
whole-row Var depending on the kind of RTE it's representing.
This turns out to be problematic because the rewriter and planner
can convert view RTEs and set-returning-function RTEs into
subquery RTEs; so a whole-row Var made during planning might
look different from one made by the parser.  In isolation this
doesn't cause any problem, but if a query contains Vars made
both ways for the same varno, there are cross-checks in the
executor that will complain.  This manifests for UPDATE, DELETE,
and MERGE queries that use whole-row table references.

To fix, we need makeWholeRowVar() to produce the same result
from an inlined RTE as it would have for the original.  For
an inlined view, we can use RangeTblEntry.relid to detect
that this had been a view RTE.  For inlined SRFs, make a
data structure definition change akin to commit 47bb9db75,
and say that we won't clear RangeTblEntry.functions until
the end of planning.  That allows makeWholeRowVar() to
repeat what it would have done with the unmodified RTE.

Reported-by: Duncan Sands <[email protected]>
Reported-by: Dean Rasheed <[email protected]>
Diagnosed-by: Tender Wang <[email protected]>
Author: Tom Lane <[email protected]>
Reviewed-by: Dean Rasheed <[email protected]>
Discussion: https://postgr.es/m/3518c50a-ab18-482f-b916-a37263622501@deepbluecap.com
Backpatch-through: 13
src/backend/nodes/makefuncs.c
src/backend/optimizer/prep/prepjointree.c
src/test/regress/expected/returning.out
src/test/regress/sql/returning.sql