mirror of
https://github.com/postgres/postgres.git
synced 2025-07-15 19:21:59 +03:00
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))".
This commit is contained in:
contrib/pg_stat_statements
doc/src/sgml
src
backend
executor
nodes
optimizer
parser
rewrite
utils
adt
include
catalog
nodes
optimizer
parser
test
regress
@ -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;
|
||||
|
Reference in New Issue
Block a user