aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_target.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2014-06-18 13:22:25 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2014-06-18 13:22:34 -0400
commit8f889b1083f38f4f5b3bd3512008a3f60e939244 (patch)
tree68c2e242c88245ea0d3b9329e1e27c78a8e70eaf /src/backend/parser/parse_target.c
parent230ba02d855de7fac31bfb6af25ebd4ae052640b (diff)
downloadpostgresql-8f889b1083f38f4f5b3bd3512008a3f60e939244.tar.gz
postgresql-8f889b1083f38f4f5b3bd3512008a3f60e939244.zip
Implement UPDATE tab SET (col1,col2,...) = (SELECT ...), ...
This SQL-standard feature allows a sub-SELECT yielding multiple columns (but only one row) to be used to compute the new values of several columns to be updated. While the same results can be had with an independent sub-SELECT per column, such a workaround can require a great deal of duplicated computation. The standard actually says that the source for a multi-column assignment could be any row-valued expression. The implementation used here is tightly tied to our existing sub-SELECT support and can't handle other cases; the Bison grammar would have some issues with them too. However, I don't feel too bad about this since other cases can be converted into sub-SELECTs. For instance, "SET (a,b,c) = row_valued_function(x)" could be written "SET (a,b,c) = (SELECT * FROM row_valued_function(x))".
Diffstat (limited to 'src/backend/parser/parse_target.c')
-rw-r--r--src/backend/parser/parse_target.c26
1 files changed, 23 insertions, 3 deletions
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 2ee1270ec5d..328e0c67aca 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -113,9 +113,9 @@ transformTargetEntry(ParseState *pstate,
* transformTargetList()
* Turns a list of ResTarget's into a list of TargetEntry's.
*
- * At this point, we don't care whether we are doing SELECT, UPDATE,
- * or RETURNING; we just transform the given expressions (the "val" fields).
- * However, our subroutines care, so we need the exprKind parameter.
+ * This code acts mostly the same for SELECT, UPDATE, or RETURNING lists;
+ * the main thing is to transform the given expressions (the "val" fields).
+ * The exprKind parameter distinguishes these cases when necesssary.
*/
List *
transformTargetList(ParseState *pstate, List *targetlist,
@@ -124,6 +124,9 @@ transformTargetList(ParseState *pstate, List *targetlist,
List *p_target = NIL;
ListCell *o_target;
+ /* Shouldn't have any leftover multiassign items at start */
+ Assert(pstate->p_multiassign_exprs == NIL);
+
foreach(o_target, targetlist)
{
ResTarget *res = (ResTarget *) lfirst(o_target);
@@ -172,6 +175,19 @@ transformTargetList(ParseState *pstate, List *targetlist,
false));
}
+ /*
+ * If any multiassign resjunk items were created, attach them to the end
+ * of the targetlist. This should only happen in an UPDATE tlist. We
+ * don't need to worry about numbering of these items; transformUpdateStmt
+ * will set their resnos.
+ */
+ if (pstate->p_multiassign_exprs)
+ {
+ Assert(exprKind == EXPR_KIND_UPDATE_SOURCE);
+ p_target = list_concat(p_target, pstate->p_multiassign_exprs);
+ pstate->p_multiassign_exprs = NIL;
+ }
+
return p_target;
}
@@ -234,6 +250,9 @@ transformExpressionList(ParseState *pstate, List *exprlist,
transformExpr(pstate, e, exprKind));
}
+ /* Shouldn't have any multiassign items here */
+ Assert(pstate->p_multiassign_exprs == NIL);
+
return result;
}
@@ -1691,6 +1710,7 @@ FigureColnameInternal(Node *node, char **name)
}
break;
/* As with other operator-like nodes, these have no names */
+ case MULTIEXPR_SUBLINK:
case ALL_SUBLINK:
case ANY_SUBLINK:
case ROWCOMPARE_SUBLINK: