aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Momjian <bruce@momjian.us>2006-09-02 20:34:47 +0000
committerBruce Momjian <bruce@momjian.us>2006-09-02 20:34:47 +0000
commit6e8596a146c9b16f2c053ea8c6e361a114c0b65c (patch)
treeff705971cafc03f720747aaea46ebc1923f45151
parent9e522d0816a93c6b574109b9b5251371ff6bcd64 (diff)
downloadpostgresql-6e8596a146c9b16f2c053ea8c6e361a114c0b65c.tar.gz
postgresql-6e8596a146c9b16f2c053ea8c6e361a114c0b65c.zip
Add UPDATE tab SET ROW (col, ...) = (val, ...) for updating
multiple columns Susanne Ebrecht
-rw-r--r--doc/src/sgml/ref/update.sgml9
-rw-r--r--src/backend/parser/gram.y78
2 files changed, 81 insertions, 6 deletions
diff --git a/doc/src/sgml/ref/update.sgml b/doc/src/sgml/ref/update.sgml
index 5d1265e945f..7b5d17a1fc8 100644
--- a/doc/src/sgml/ref/update.sgml
+++ b/doc/src/sgml/ref/update.sgml
@@ -1,5 +1,5 @@
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/update.sgml,v 1.38 2006/08/12 02:52:03 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/update.sgml,v 1.39 2006/09/02 20:34:47 momjian Exp $
PostgreSQL documentation
-->
@@ -21,7 +21,8 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
UPDATE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ [ AS ] <replaceable class="parameter">alias</replaceable> ]
- SET <replaceable class="PARAMETER">column</replaceable> = { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } [, ...]
+ [ SET <replaceable class="PARAMETER">column</replaceable> = { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } [, ...] |
+ SET ( <replaceable class="PARAMETER">column</replaceable> [, ...] ) = ( { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } [, ...] ) [, ...] ]
[ FROM <replaceable class="PARAMETER">fromlist</replaceable> ]
[ WHERE <replaceable class="PARAMETER">condition</replaceable> ]
[ RETURNING * | <replaceable class="parameter">output_expression</replaceable> [ AS <replaceable class="parameter">output_name</replaceable> ] [, ...] ]
@@ -251,6 +252,10 @@ UPDATE films SET kind = 'Dramatic' WHERE kind = 'Drama';
UPDATE weather SET temp_lo = temp_lo+1, temp_hi = temp_lo+15, prcp = DEFAULT
WHERE city = 'San Francisco' AND date = '2003-07-03';
</programlisting>
+<programlisting>
+UPDATE weather SET (temp_lo, temp_hi, prcp) = (temp_lo+1, temp_lo+15, DEFAULT)
+ WHERE city = 'San Francisco' AND date = '2003-07-03';
+</programlisting>
</para>
<para>
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index f53ba9ce60d..eab360bc774 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.560 2006/09/02 18:17:17 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.561 2006/09/02 20:34:47 momjian Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -237,7 +237,8 @@ static void doNegateFloat(Value *v);
name_list from_clause from_list opt_array_bounds
qualified_name_list any_name any_name_list
any_operator expr_list attrs
- target_list update_target_list insert_column_list
+ target_list update_col_list update_target_list
+ update_value_list insert_column_list
values_list def_list indirection opt_indirection
group_clause TriggerFuncArgs select_limit
opt_select_limit opclass_item_list
@@ -308,7 +309,8 @@ static void doNegateFloat(Value *v);
%type <jexpr> joined_table
%type <range> relation_expr
%type <range> relation_expr_opt_alias
-%type <target> target_el update_target_el insert_column_item
+%type <target> target_el update_target_el update_col_list_el insert_column_item
+%type <list> update_target_lists_list update_target_lists_el
%type <typnam> Typename SimpleTypename ConstTypename
GenericType Numeric opt_float
@@ -5537,6 +5539,20 @@ UpdateStmt: UPDATE relation_expr_opt_alias
n->returningList = $7;
$$ = (Node *)n;
}
+ | UPDATE relation_expr_opt_alias
+ SET update_target_lists_list
+ from_clause
+ where_clause
+ returning_clause
+ {
+ UpdateStmt *n = makeNode(UpdateStmt);
+ n->relation = $2;
+ n->targetList = $4;
+ n->fromClause = $5;
+ n->whereClause = $6;
+ n->returningList = $7;
+ $$ = (Node *)n;
+ }
;
@@ -5941,6 +5957,60 @@ values_item:
| DEFAULT { $$ = (Node *) makeNode(SetToDefault); }
;
+update_target_lists_list:
+ update_target_lists_el { $$ = $1; }
+ | update_target_lists_list ',' update_target_lists_el { $$ = list_concat($1, $3); }
+ ;
+
+update_target_lists_el:
+ '(' update_col_list ')' '=' '(' update_value_list ')'
+ {
+ ListCell *col_cell;
+ ListCell *val_cell;
+
+ if (list_length($2) != list_length($6))
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("number of columns does not match to number of values")));
+ }
+
+ for (col_cell = list_head($2), val_cell = list_head($6);
+ col_cell != NULL && val_cell != NULL;
+ col_cell = lnext(col_cell), val_cell = lnext(val_cell))
+ {
+ /* merge update_value_list with update_col_list */
+ ResTarget *res_col = (ResTarget *) lfirst(col_cell);
+ ResTarget *res_val = (ResTarget *) lfirst(val_cell);
+
+ res_col->val = (Node *)copyObject(res_val);
+ }
+
+ $$ = $2;
+ }
+ ;
+
+update_col_list:
+ update_col_list_el { $$ = list_make1($1); }
+ | update_col_list ',' update_col_list_el { $$ = lappend($1, $3); }
+ ;
+
+update_col_list_el:
+ ColId opt_indirection
+ {
+ $$ = makeNode(ResTarget);
+ $$->name = $1;
+ $$->indirection = $2;
+ $$->val = NULL;
+ $$->location = @1;
+ }
+ ;
+
+update_value_list:
+ values_item { $$ = list_make1($1); }
+ | update_value_list ',' values_item { $$ = lappend($1, $3); }
+ ;
+
/*****************************************************************************
*
@@ -8253,7 +8323,7 @@ target_el: a_expr AS ColLabel
;
update_target_list:
- update_target_el { $$ = list_make1($1); }
+ update_target_el { $$ = list_make1($1); }
| update_target_list ',' update_target_el { $$ = lappend($1,$3); }
;