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

Reply via email to