summaryrefslogtreecommitdiff
path: root/src/backend/nodes
diff options
context:
space:
mode:
authorTom Lane2014-06-18 17:22:25 +0000
committerTom Lane2014-06-18 17:22:34 +0000
commit8f889b1083f38f4f5b3bd3512008a3f60e939244 (patch)
tree68c2e242c88245ea0d3b9329e1e27c78a8e70eaf /src/backend/nodes
parent230ba02d855de7fac31bfb6af25ebd4ae052640b (diff)
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/nodes')
-rw-r--r--src/backend/nodes/copyfuncs.c16
-rw-r--r--src/backend/nodes/equalfuncs.c14
-rw-r--r--src/backend/nodes/list.c2
-rw-r--r--src/backend/nodes/nodeFuncs.c28
-rw-r--r--src/backend/nodes/outfuncs.c15
-rw-r--r--src/backend/nodes/readfuncs.c1
6 files changed, 67 insertions, 9 deletions
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 43530aa24a8..8d3d5a7c734 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -1327,6 +1327,7 @@ _copySubLink(const SubLink *from)
SubLink *newnode = makeNode(SubLink);
COPY_SCALAR_FIELD(subLinkType);
+ COPY_SCALAR_FIELD(subLinkId);
COPY_NODE_FIELD(testexpr);
COPY_NODE_FIELD(operName);
COPY_NODE_FIELD(subselect);
@@ -2247,6 +2248,18 @@ _copyResTarget(const ResTarget *from)
return newnode;
}
+static MultiAssignRef *
+_copyMultiAssignRef(const MultiAssignRef *from)
+{
+ MultiAssignRef *newnode = makeNode(MultiAssignRef);
+
+ COPY_NODE_FIELD(source);
+ COPY_SCALAR_FIELD(colno);
+ COPY_SCALAR_FIELD(ncolumns);
+
+ return newnode;
+}
+
static TypeName *
_copyTypeName(const TypeName *from)
{
@@ -4561,6 +4574,9 @@ copyObject(const void *from)
case T_ResTarget:
retval = _copyResTarget(from);
break;
+ case T_MultiAssignRef:
+ retval = _copyMultiAssignRef(from);
+ break;
case T_TypeCast:
retval = _copyTypeCast(from);
break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 2407cb73a38..e7b49f680cf 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -382,6 +382,7 @@ static bool
_equalSubLink(const SubLink *a, const SubLink *b)
{
COMPARE_SCALAR_FIELD(subLinkType);
+ COMPARE_SCALAR_FIELD(subLinkId);
COMPARE_NODE_FIELD(testexpr);
COMPARE_NODE_FIELD(operName);
COMPARE_NODE_FIELD(subselect);
@@ -2095,6 +2096,16 @@ _equalResTarget(const ResTarget *a, const ResTarget *b)
}
static bool
+_equalMultiAssignRef(const MultiAssignRef *a, const MultiAssignRef *b)
+{
+ COMPARE_NODE_FIELD(source);
+ COMPARE_SCALAR_FIELD(colno);
+ COMPARE_SCALAR_FIELD(ncolumns);
+
+ return true;
+}
+
+static bool
_equalTypeName(const TypeName *a, const TypeName *b)
{
COMPARE_NODE_FIELD(names);
@@ -3029,6 +3040,9 @@ equal(const void *a, const void *b)
case T_ResTarget:
retval = _equalResTarget(a, b);
break;
+ case T_MultiAssignRef:
+ retval = _equalMultiAssignRef(a, b);
+ break;
case T_TypeCast:
retval = _equalTypeCast(a, b);
break;
diff --git a/src/backend/nodes/list.c b/src/backend/nodes/list.c
index f32124bedff..5c09d2f1081 100644
--- a/src/backend/nodes/list.c
+++ b/src/backend/nodes/list.c
@@ -385,7 +385,7 @@ list_truncate(List *list, int new_size)
* Locate the n'th cell (counting from 0) of the list. It is an assertion
* failure if there is no such cell.
*/
-static ListCell *
+ListCell *
list_nth_cell(const List *list, int n)
{
ListCell *match;
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index f4999c5be03..41e973b1236 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -116,6 +116,11 @@ exprType(const Node *expr)
format_type_be(exprType((Node *) tent->expr)))));
}
}
+ else if (sublink->subLinkType == MULTIEXPR_SUBLINK)
+ {
+ /* MULTIEXPR is always considered to return RECORD */
+ type = RECORDOID;
+ }
else
{
/* for all other sublink types, result is boolean */
@@ -142,6 +147,11 @@ exprType(const Node *expr)
format_type_be(subplan->firstColType))));
}
}
+ else if (subplan->subLinkType == MULTIEXPR_SUBLINK)
+ {
+ /* MULTIEXPR is always considered to return RECORD */
+ type = RECORDOID;
+ }
else
{
/* for all other subplan types, result is boolean */
@@ -299,6 +309,7 @@ exprTypmod(const Node *expr)
return exprTypmod((Node *) tent->expr);
/* note we don't need to care if it's an array */
}
+ /* otherwise, result is RECORD or BOOLEAN, typmod is -1 */
}
break;
case T_SubPlan:
@@ -312,11 +323,7 @@ exprTypmod(const Node *expr)
/* note we don't need to care if it's an array */
return subplan->firstColTypmod;
}
- else
- {
- /* for all other subplan types, result is boolean */
- return -1;
- }
+ /* otherwise, result is RECORD or BOOLEAN, typmod is -1 */
}
break;
case T_AlternativeSubPlan:
@@ -784,7 +791,7 @@ exprCollation(const Node *expr)
}
else
{
- /* for all other sublink types, result is boolean */
+ /* otherwise, result is RECORD or BOOLEAN */
coll = InvalidOid;
}
}
@@ -802,7 +809,7 @@ exprCollation(const Node *expr)
}
else
{
- /* for all other subplan types, result is boolean */
+ /* otherwise, result is RECORD or BOOLEAN */
coll = InvalidOid;
}
}
@@ -1017,7 +1024,7 @@ exprSetCollation(Node *expr, Oid collation)
}
else
{
- /* for all other sublink types, result is boolean */
+ /* otherwise, result is RECORD or BOOLEAN */
Assert(!OidIsValid(collation));
}
}
@@ -1420,6 +1427,9 @@ exprLocation(const Node *expr)
/* we need not examine the contained expression (if any) */
loc = ((const ResTarget *) expr)->location;
break;
+ case T_MultiAssignRef:
+ loc = exprLocation(((const MultiAssignRef *) expr)->source);
+ break;
case T_TypeCast:
{
const TypeCast *tc = (const TypeCast *) expr;
@@ -3107,6 +3117,8 @@ raw_expression_tree_walker(Node *node,
return true;
}
break;
+ case T_MultiAssignRef:
+ return walker(((MultiAssignRef *) node)->source, context);
case T_TypeCast:
{
TypeCast *tc = (TypeCast *) node;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index deff33f6f71..c182212e62f 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1115,6 +1115,7 @@ _outSubLink(StringInfo str, const SubLink *node)
WRITE_NODE_TYPE("SUBLINK");
WRITE_ENUM_FIELD(subLinkType, SubLinkType);
+ WRITE_INT_FIELD(subLinkId);
WRITE_NODE_FIELD(testexpr);
WRITE_NODE_FIELD(operName);
WRITE_NODE_FIELD(subselect);
@@ -1701,6 +1702,7 @@ _outPlannerInfo(StringInfo str, const PlannerInfo *node)
WRITE_INT_FIELD(join_cur_level);
WRITE_NODE_FIELD(init_plans);
WRITE_NODE_FIELD(cte_plan_ids);
+ WRITE_NODE_FIELD(multiexpr_params);
WRITE_NODE_FIELD(eq_classes);
WRITE_NODE_FIELD(canon_pathkeys);
WRITE_NODE_FIELD(left_join_clauses);
@@ -2581,6 +2583,16 @@ _outResTarget(StringInfo str, const ResTarget *node)
}
static void
+_outMultiAssignRef(StringInfo str, const MultiAssignRef *node)
+{
+ WRITE_NODE_TYPE("MULTIASSIGNREF");
+
+ WRITE_NODE_FIELD(source);
+ WRITE_INT_FIELD(colno);
+ WRITE_INT_FIELD(ncolumns);
+}
+
+static void
_outSortBy(StringInfo str, const SortBy *node)
{
WRITE_NODE_TYPE("SORTBY");
@@ -3191,6 +3203,9 @@ _outNode(StringInfo str, const void *obj)
case T_ResTarget:
_outResTarget(str, obj);
break;
+ case T_MultiAssignRef:
+ _outMultiAssignRef(str, obj);
+ break;
case T_SortBy:
_outSortBy(str, obj);
break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 1ec4f3c6956..69d99894849 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -744,6 +744,7 @@ _readSubLink(void)
READ_LOCALS(SubLink);
READ_ENUM_FIELD(subLinkType, SubLinkType);
+ READ_INT_FIELD(subLinkId);
READ_NODE_FIELD(testexpr);
READ_NODE_FIELD(operName);
READ_NODE_FIELD(subselect);