The cause of bug #5716 is that preprocess_targetlist is trying to get away with creating a whole-row variable marked with type RECORDOID, even in cases where a specific composite type is known for the referenced RTE. This fails because now we might have non-equal Vars representing the same RTE attribute in different places in the same query.
I think the best fix for this is to have one and only one function generating whole-row Vars, which means pulling out the guts of the parser's transformWholeRowRef() function into a function that looks like the attached. Now I'm wondering where to put it. I'm tempted to put it into makefuncs.c next to makeVar(), and it fits there without needing to add any new #includes; but it looks a tad more complicated than most other functions in makefuncs.c. Does anyone think this is a bad place for it, and if so where would you put it instead? regards, tom lane /* * makeWholeRowVar - * creates a Var node representing a whole row from the specified RTE */ Var * makeWholeRowVar(RangeTblEntry *rte, Index varno, Index varlevelsup) { Var *result; Oid toid; switch (rte->rtekind) { case RTE_RELATION: /* relation: the rowtype is a named composite type */ toid = get_rel_type_id(rte->relid); if (!OidIsValid(toid)) elog(ERROR, "could not find type OID for relation %u", rte->relid); result = makeVar(varno, InvalidAttrNumber, toid, -1, varlevelsup); break; case RTE_FUNCTION: toid = exprType(rte->funcexpr); if (type_is_rowtype(toid)) { /* func returns composite; same as relation case */ result = makeVar(varno, InvalidAttrNumber, toid, -1, varlevelsup); } else { /* * func returns scalar; instead of making a whole-row Var, * just reference the function's scalar output. (XXX this * seems a tad inconsistent, especially if "f.*" was * explicitly written ...) */ result = makeVar(varno, 1, toid, -1, varlevelsup); } break; case RTE_VALUES: toid = RECORDOID; /* returns composite; same as relation case */ result = makeVar(varno, InvalidAttrNumber, toid, -1, varlevelsup); break; default: /* * RTE is a join or subselect. We represent this as a whole-row * Var of RECORD type. (Note that in most cases the Var will be * expanded to a RowExpr during planning, but that is not our * concern here.) */ result = makeVar(varno, InvalidAttrNumber, RECORDOID, -1, varlevelsup); break; } return result; } -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers