Skip to content

Commit 25c06a1

Browse files
committed
Don't mess up pstate->p_next_resno in transformOnConflictClause().
transformOnConflictClause incremented p_next_resno while generating the phony targetlist for the EXCLUDED pseudo-rel. Then that field got incremented some more during transformTargetList, possibly leading to free_parsestate concluding that we'd overrun the allowed length of a tlist, as reported by Justin Pryzby. We could fix this by resetting p_next_resno to 1 after using it for the EXCLUDED pseudo-rel tlist, but it seems easier and less coupled to other places if we just don't use that field at all in this loop. (Note that this doesn't change anything about the resnos that end up appearing in the main target list, because those are all replaced with target-column numbers by updateTargetListEntry.) In passing, fix incorrect type OID assigned to the whole-row Var for "EXCLUDED.*" (somehow this escaped having any bad consequences so far, but it's certainly wrong); remove useless assignment to var->location; pstrdup the column names in case of a relcache flush; and improve nearby comments. Back-patch to 9.5 where ON CONFLICT was introduced. Report: https://postgr.es/m/20161204163237.GA8030@telsasoft.com
1 parent 5ab4b2e commit 25c06a1

File tree

1 file changed

+12
-15
lines changed

1 file changed

+12
-15
lines changed

src/backend/parser/analyze.c

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -915,11 +915,10 @@ transformOnConflictClause(ParseState *pstate,
915915
exclRelIndex = list_length(pstate->p_rtable);
916916

917917
/*
918-
* Build a targetlist for the EXCLUDED pseudo relation. Have to be
919-
* careful to use resnos that correspond to attnos of the underlying
920-
* relation.
918+
* Build a targetlist representing the columns of the EXCLUDED pseudo
919+
* relation. Have to be careful to use resnos that correspond to
920+
* attnos of the underlying relation.
921921
*/
922-
Assert(pstate->p_next_resno == 1);
923922
for (attno = 0; attno < targetrel->rd_rel->relnatts; attno++)
924923
{
925924
Form_pg_attribute attr = targetrel->rd_att->attrs[attno];
@@ -940,14 +939,11 @@ transformOnConflictClause(ParseState *pstate,
940939
attr->atttypid, attr->atttypmod,
941940
attr->attcollation,
942941
0);
943-
var->location = -1;
944-
945-
name = NameStr(attr->attname);
942+
name = pstrdup(NameStr(attr->attname));
946943
}
947944

948-
Assert(pstate->p_next_resno == attno + 1);
949945
te = makeTargetEntry((Expr *) var,
950-
pstate->p_next_resno++,
946+
attno + 1,
951947
name,
952948
false);
953949

@@ -956,15 +952,16 @@ transformOnConflictClause(ParseState *pstate,
956952
}
957953

958954
/*
959-
* Additionally add a whole row tlist entry for EXCLUDED. That's
960-
* really only needed for ruleutils' benefit, which expects to find
961-
* corresponding entries in child tlists. Alternatively we could do
962-
* this only when required, but that doesn't seem worth the trouble.
955+
* Add a whole-row-Var entry to support references to "EXCLUDED.*".
956+
* Like the other entries in exclRelTlist, its resno must match the
957+
* Var's varattno, else the wrong things happen while resolving
958+
* references in setrefs.c. This is against normal conventions for
959+
* targetlists, but it's okay since we don't use this as a real tlist.
963960
*/
964961
var = makeVar(exclRelIndex, InvalidAttrNumber,
965-
RelationGetRelid(targetrel),
962+
targetrel->rd_rel->reltype,
966963
-1, InvalidOid, 0);
967-
te = makeTargetEntry((Expr *) var, 0, NULL, true);
964+
te = makeTargetEntry((Expr *) var, InvalidAttrNumber, NULL, true);
968965
exclRelTlist = lappend(exclRelTlist, te);
969966

970967
/*

0 commit comments

Comments
 (0)