else if (node && IsA(node, Var) &&
((Var *) node)->varattno == InvalidAttrNumber)
{
- int rtindex = ((Var *) node)->varno;
- int sublevels_up = ((Var *) node)->varlevelsup;
- int vlocation = ((Var *) node)->location;
+ Var *var = (Var *) node;
ParseNamespaceItem *nsitem;
- nsitem = GetNSItemByRangeTablePosn(pstate, rtindex, sublevels_up);
- args = expandNSItemVars(pstate, nsitem, sublevels_up, vlocation, NULL);
+ nsitem = GetNSItemByVar(pstate, var);
+ args = expandNSItemVars(pstate, nsitem, var->varlevelsup,
+ var->location, NULL);
}
else
ereport(ERROR,
{
ParseNamespaceItem *nsitem;
- nsitem = GetNSItemByRangeTablePosn(pstate,
- ((Var *) first_arg)->varno,
- ((Var *) first_arg)->varlevelsup);
+ nsitem = GetNSItemByVar(pstate, (Var *) first_arg);
/* Return a Var if funcname matches a column, else NULL */
return scanNSItemForColumn(pstate, nsitem,
((Var *) first_arg)->varlevelsup,
/*
* Given an RT index and nesting depth, find the corresponding
* ParseNamespaceItem (there must be one).
+ *
+ * NB: Callers starting from a Var should consider using GetNSItemByVar()
+ * instead, to find the namespace item with matching varreturningtype.
*/
ParseNamespaceItem *
GetNSItemByRangeTablePosn(ParseState *pstate,
return NULL; /* keep compiler quiet */
}
+/*
+ * Given a Var, find the corresponding ParseNamespaceItem (there must be one).
+ *
+ * Like GetNSItemByRangeTablePosn(), but uses the Var's varreturningtype in
+ * addition to its varno and varlevelsup to find the namespace item.
+ */
+ParseNamespaceItem *
+GetNSItemByVar(ParseState *pstate, Var *var)
+{
+ int sublevels_up = var->varlevelsup;
+ ListCell *lc;
+
+ while (sublevels_up-- > 0)
+ {
+ pstate = pstate->parentParseState;
+ Assert(pstate != NULL);
+ }
+ foreach(lc, pstate->p_namespace)
+ {
+ ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(lc);
+
+ if (nsitem->p_rtindex == var->varno &&
+ nsitem->p_returning_type == var->varreturningtype)
+ return nsitem;
+ }
+ elog(ERROR, "nsitem not found (internal error)");
+ return NULL; /* keep compiler quiet */
+}
+
/*
* Given an RT index and nesting depth, find the corresponding RTE.
* (Note that the RTE need not be in the query's namespace.)
Var *var = (Var *) expr;
ParseNamespaceItem *nsitem;
- nsitem = GetNSItemByRangeTablePosn(pstate, var->varno, var->varlevelsup);
+ nsitem = GetNSItemByVar(pstate, var);
return ExpandSingleTable(pstate, nsitem, var->varlevelsup, var->location, make_target_entry);
}
extern ParseNamespaceItem *GetNSItemByRangeTablePosn(ParseState *pstate,
int varno,
int sublevels_up);
+extern ParseNamespaceItem *GetNSItemByVar(ParseState *pstate, Var *var);
extern RangeTblEntry *GetRTEByRangeTablePosn(ParseState *pstate,
int varno,
int sublevels_up);
foo | (0,7) | 5 | ok | 42 | 100 | | | | | | | 5 | ok | 42 | 100
(1 row)
+-- Parenthesized OLD and NEW
+INSERT INTO foo VALUES (6, 'paren-test', 60, 600)
+ RETURNING old, (old).f4, (old).*,
+ new, (new).f4, (new).*;
+ old | f4 | f1 | f2 | f3 | f4 | new | f4 | f1 | f2 | f3 | f4
+-----+----+----+----+----+----+-----------------------+-----+----+------------+----+-----
+ | | | | | | (6,paren-test,60,600) | 600 | 6 | paren-test | 60 | 600
+(1 row)
+
+UPDATE foo SET f4 = 700 WHERE f1 = 6
+ RETURNING old, (old).f4, (old).*,
+ new, (new).f4, (new).*;
+ old | f4 | f1 | f2 | f3 | f4 | new | f4 | f1 | f2 | f3 | f4
+-----------------------+-----+----+------------+----+-----+-----------------------+-----+----+------------+----+-----
+ (6,paren-test,60,600) | 600 | 6 | paren-test | 60 | 600 | (6,paren-test,60,700) | 700 | 6 | paren-test | 60 | 700
+(1 row)
+
+DELETE FROM foo WHERE f1 = 6
+ RETURNING old, (old).f4, (old).*,
+ new, (new).f4, (new).*;
+ old | f4 | f1 | f2 | f3 | f4 | new | f4 | f1 | f2 | f3 | f4
+-----------------------+-----+----+------------+----+-----+-----+----+----+----+----+----
+ (6,paren-test,60,700) | 700 | 6 | paren-test | 60 | 700 | | | | | |
+(1 row)
+
-- RETURNING OLD and NEW from subquery
EXPLAIN (verbose, costs off)
INSERT INTO foo VALUES (5, 'subquery test')
RETURNING old.tableoid::regclass, old.ctid, old.*,
new.tableoid::regclass, new.ctid, new.*, *;
+-- Parenthesized OLD and NEW
+INSERT INTO foo VALUES (6, 'paren-test', 60, 600)
+ RETURNING old, (old).f4, (old).*,
+ new, (new).f4, (new).*;
+UPDATE foo SET f4 = 700 WHERE f1 = 6
+ RETURNING old, (old).f4, (old).*,
+ new, (new).f4, (new).*;
+DELETE FROM foo WHERE f1 = 6
+ RETURNING old, (old).f4, (old).*,
+ new, (new).f4, (new).*;
+
-- RETURNING OLD and NEW from subquery
EXPLAIN (verbose, costs off)
INSERT INTO foo VALUES (5, 'subquery test')