aboutsummaryrefslogtreecommitdiff
path: root/src/backend/nodes/makefuncs.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2010-10-19 15:08:37 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2010-10-19 15:09:23 -0400
commit6e74a91b2bf0e0032ccd60dd99d6cf47c190c428 (patch)
treeab3b16a1b02b566a71da14e298090f4d8c707dda /src/backend/nodes/makefuncs.c
parent722d5beeb266ae83f548fc3953df700a71f30134 (diff)
downloadpostgresql-6e74a91b2bf0e0032ccd60dd99d6cf47c190c428.tar.gz
postgresql-6e74a91b2bf0e0032ccd60dd99d6cf47c190c428.zip
Fix incorrect generation of whole-row variables in planner.
A couple of places in the planner need to generate whole-row Vars, and were cutting corners by setting vartype = RECORDOID in the Vars, even in cases where there's an identifiable named composite type for the RTE being referenced. While we mostly got away with this, it failed when there was also a parser-generated whole-row reference to the same RTE, because the two Vars weren't equal() due to the difference in vartype. Fix by providing a subroutine the planner can call to generate whole-row Vars the same way the parser does. Per bug #5716 from Andrew Tipton. Back-patch to 9.0 where one of the bogus calls was introduced (the other one is new in HEAD).
Diffstat (limited to 'src/backend/nodes/makefuncs.c')
-rw-r--r--src/backend/nodes/makefuncs.c87
1 files changed, 87 insertions, 0 deletions
diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c
index ee15695b914..4b268f3c6b3 100644
--- a/src/backend/nodes/makefuncs.c
+++ b/src/backend/nodes/makefuncs.c
@@ -108,6 +108,93 @@ makeVarFromTargetEntry(Index varno,
}
/*
+ * makeWholeRowVar -
+ * creates a Var node representing a whole row of the specified RTE
+ *
+ * A whole-row reference is a Var with varno set to the correct range
+ * table entry, and varattno == 0 to signal that it references the whole
+ * tuple. (Use of zero here is unclean, since it could easily be confused
+ * with error cases, but it's not worth changing now.) The vartype indicates
+ * a rowtype; either a named composite type, or RECORD. This function
+ * encapsulates the logic for determining the correct rowtype OID to use.
+ */
+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;
+}
+
+/*
* makeTargetEntry -
* creates a TargetEntry node
*/