Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 091fe03

Browse files
committed
Code review for UPDATE SET (columnlist) patch. Make it handle as much
of the syntax as this fundamentally dead-end approach can, in particular combinations of single and multi column assignments. Improve rather inadequate documentation and provide some regression tests.
1 parent 676d1b4 commit 091fe03

File tree

4 files changed

+195
-141
lines changed

4 files changed

+195
-141
lines changed

doc/src/sgml/ref/update.sgml

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/ref/update.sgml,v 1.39 2006/09/02 20:34:47 momjian Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/ref/update.sgml,v 1.40 2006/09/03 22:37:05 tgl Exp $
33
PostgreSQL documentation
44
-->
55

@@ -21,8 +21,8 @@ PostgreSQL documentation
2121
<refsynopsisdiv>
2222
<synopsis>
2323
UPDATE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ [ AS ] <replaceable class="parameter">alias</replaceable> ]
24-
[ SET <replaceable class="PARAMETER">column</replaceable> = { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } [, ...] |
25-
SET ( <replaceable class="PARAMETER">column</replaceable> [, ...] ) = ( { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } [, ...] ) [, ...] ]
24+
SET { <replaceable class="PARAMETER">column</replaceable> = { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } |
25+
( <replaceable class="PARAMETER">column</replaceable> [, ...] ) = ( { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } [, ...] ) } [, ...]
2626
[ FROM <replaceable class="PARAMETER">fromlist</replaceable> ]
2727
[ WHERE <replaceable class="PARAMETER">condition</replaceable> ]
2828
[ RETURNING * | <replaceable class="parameter">output_expression</replaceable> [ AS <replaceable class="parameter">output_name</replaceable> ] [, ...] ]
@@ -251,10 +251,6 @@ UPDATE films SET kind = 'Dramatic' WHERE kind = 'Drama';
251251
<programlisting>
252252
UPDATE weather SET temp_lo = temp_lo+1, temp_hi = temp_lo+15, prcp = DEFAULT
253253
WHERE city = 'San Francisco' AND date = '2003-07-03';
254-
</programlisting>
255-
<programlisting>
256-
UPDATE weather SET (temp_lo, temp_hi, prcp) = (temp_lo+1, temp_lo+15, DEFAULT)
257-
WHERE city = 'San Francisco' AND date = '2003-07-03';
258254
</programlisting>
259255
</para>
260256

@@ -268,6 +264,14 @@ UPDATE weather SET temp_lo = temp_lo+1, temp_hi = temp_lo+15, prcp = DEFAULT
268264
</programlisting>
269265
</para>
270266

267+
<para>
268+
Use the alternative column-list syntax to do the same update:
269+
<programlisting>
270+
UPDATE weather SET (temp_lo, temp_hi, prcp) = (temp_lo+1, temp_lo+15, DEFAULT)
271+
WHERE city = 'San Francisco' AND date = '2003-07-03';
272+
</programlisting>
273+
</para>
274+
271275
<para>
272276
Increment the sales count of the salesperson who manages the
273277
account for Acme Corporation, using the <literal>FROM</literal>
@@ -316,6 +320,19 @@ COMMIT;
316320
are <productname>PostgreSQL</productname> extensions.
317321
</para>
318322

323+
<para>
324+
According to the standard, the column-list syntax should allow a list
325+
of columns to be assigned from a single row-valued expression, such
326+
as a sub-select:
327+
<programlisting>
328+
UPDATE accounts SET (contact_last_name, contact_first_name) =
329+
(SELECT last_name, first_name FROM salesmen
330+
WHERE salesmen.id = accounts.sales_id);
331+
</programlisting>
332+
This is not currently implemented &mdash; the source must be a list
333+
of independent expressions.
334+
</para>
335+
319336
<para>
320337
Some other database systems offer a <literal>FROM</> option in which
321338
the target table is supposed to be listed again within <literal>FROM</>.

src/backend/parser/gram.y

Lines changed: 96 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.564 2006/09/03 03:19:44 momjian Exp $
14+
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.565 2006/09/03 22:37:05 tgl Exp $
1515
*
1616
* HISTORY
1717
* AUTHOR DATE MAJOR EVENT
@@ -236,9 +236,9 @@ static void doNegateFloat(Value *v);
236236
name_list from_clause from_list opt_array_bounds
237237
qualified_name_list any_name any_name_list
238238
any_operator expr_list attrs
239-
target_list update_col_list update_target_list
240-
update_value_list set_opt insert_column_list
241-
values_list def_list indirection opt_indirection
239+
target_list insert_column_list set_target_list
240+
set_clause_list set_clause multiple_set_clause
241+
ctext_expr_list ctext_row def_list indirection opt_indirection
242242
group_clause TriggerFuncArgs select_limit
243243
opt_select_limit opclass_item_list
244244
transaction_mode_list_or_empty
@@ -299,7 +299,7 @@ static void doNegateFloat(Value *v);
299299
%type <list> when_clause_list
300300
%type <ival> sub_type
301301
%type <list> OptCreateAs CreateAsList
302-
%type <node> CreateAsElement values_item
302+
%type <node> CreateAsElement ctext_expr
303303
%type <value> NumericOnly FloatOnly IntegerOnly
304304
%type <alias> alias_clause
305305
%type <sortby> sortby
@@ -308,8 +308,7 @@ static void doNegateFloat(Value *v);
308308
%type <jexpr> joined_table
309309
%type <range> relation_expr
310310
%type <range> relation_expr_opt_alias
311-
%type <target> target_el update_target_el update_col_list_el insert_column_item
312-
%type <list> update_target_lists_list update_target_lists_el
311+
%type <target> target_el single_set_clause set_target insert_column_item
313312

314313
%type <typnam> Typename SimpleTypename ConstTypename
315314
GenericType Numeric opt_float
@@ -5488,7 +5487,7 @@ opt_nowait: NOWAIT { $$ = TRUE; }
54885487
*****************************************************************************/
54895488

54905489
UpdateStmt: UPDATE relation_expr_opt_alias
5491-
SET set_opt
5490+
SET set_clause_list
54925491
from_clause
54935492
where_clause
54945493
returning_clause
@@ -5503,9 +5502,65 @@ UpdateStmt: UPDATE relation_expr_opt_alias
55035502
}
55045503
;
55055504

5506-
set_opt:
5507-
update_target_list { $$ = $1; }
5508-
| update_target_lists_list { $$ = $1; }
5505+
set_clause_list:
5506+
set_clause { $$ = $1; }
5507+
| set_clause_list ',' set_clause { $$ = list_concat($1,$3); }
5508+
;
5509+
5510+
set_clause:
5511+
single_set_clause { $$ = list_make1($1); }
5512+
| multiple_set_clause { $$ = $1; }
5513+
;
5514+
5515+
single_set_clause:
5516+
set_target '=' ctext_expr
5517+
{
5518+
$$ = $1;
5519+
$$->val = (Node *) $3;
5520+
}
5521+
;
5522+
5523+
multiple_set_clause:
5524+
'(' set_target_list ')' '=' ctext_row
5525+
{
5526+
ListCell *col_cell;
5527+
ListCell *val_cell;
5528+
5529+
/*
5530+
* Break the ctext_row apart, merge individual expressions
5531+
* into the destination ResTargets. XXX this approach
5532+
* cannot work for general row expressions as sources.
5533+
*/
5534+
if (list_length($2) != list_length($5))
5535+
ereport(ERROR,
5536+
(errcode(ERRCODE_SYNTAX_ERROR),
5537+
errmsg("number of columns does not match number of values")));
5538+
forboth(col_cell, $2, val_cell, $5)
5539+
{
5540+
ResTarget *res_col = (ResTarget *) lfirst(col_cell);
5541+
Node *res_val = (Node *) lfirst(val_cell);
5542+
5543+
res_col->val = res_val;
5544+
}
5545+
5546+
$$ = $2;
5547+
}
5548+
;
5549+
5550+
set_target:
5551+
ColId opt_indirection
5552+
{
5553+
$$ = makeNode(ResTarget);
5554+
$$->name = $1;
5555+
$$->indirection = $2;
5556+
$$->val = NULL; /* upper production sets this */
5557+
$$->location = @1;
5558+
}
5559+
;
5560+
5561+
set_target_list:
5562+
set_target { $$ = list_make1($1); }
5563+
| set_target_list ',' set_target { $$ = lappend($1,$3); }
55095564
;
55105565

55115566

@@ -5887,83 +5942,20 @@ locked_rels_list:
58875942

58885943

58895944
values_clause:
5890-
VALUES '(' values_list ')'
5945+
VALUES ctext_row
58915946
{
58925947
SelectStmt *n = makeNode(SelectStmt);
5893-
n->valuesLists = list_make1($3);
5948+
n->valuesLists = list_make1($2);
58945949
$$ = (Node *) n;
58955950
}
5896-
| values_clause ',' '(' values_list ')'
5951+
| values_clause ',' ctext_row
58975952
{
58985953
SelectStmt *n = (SelectStmt *) $1;
5899-
n->valuesLists = lappend(n->valuesLists, $4);
5954+
n->valuesLists = lappend(n->valuesLists, $3);
59005955
$$ = (Node *) n;
59015956
}
59025957
;
59035958

5904-
values_list: values_item { $$ = list_make1($1); }
5905-
| values_list ',' values_item { $$ = lappend($1, $3); }
5906-
;
5907-
5908-
values_item:
5909-
a_expr { $$ = (Node *) $1; }
5910-
| DEFAULT { $$ = (Node *) makeNode(SetToDefault); }
5911-
;
5912-
5913-
update_target_lists_list:
5914-
update_target_lists_el { $$ = $1; }
5915-
| update_target_lists_list ',' update_target_lists_el { $$ = list_concat($1, $3); }
5916-
;
5917-
5918-
update_target_lists_el:
5919-
'(' update_col_list ')' '=' '(' update_value_list ')'
5920-
{
5921-
ListCell *col_cell;
5922-
ListCell *val_cell;
5923-
5924-
if (list_length($2) != list_length($6))
5925-
{
5926-
ereport(ERROR,
5927-
(errcode(ERRCODE_SYNTAX_ERROR),
5928-
errmsg("number of columns does not match to number of values")));
5929-
}
5930-
5931-
for (col_cell = list_head($2), val_cell = list_head($6);
5932-
col_cell != NULL && val_cell != NULL;
5933-
col_cell = lnext(col_cell), val_cell = lnext(val_cell))
5934-
{
5935-
/* merge update_value_list with update_col_list */
5936-
ResTarget *res_col = (ResTarget *) lfirst(col_cell);
5937-
Node *res_val = (Node *) lfirst(val_cell);
5938-
5939-
res_col->val = res_val;
5940-
}
5941-
5942-
$$ = $2;
5943-
}
5944-
;
5945-
5946-
update_col_list:
5947-
update_col_list_el { $$ = list_make1($1); }
5948-
| update_col_list ',' update_col_list_el { $$ = lappend($1, $3); }
5949-
;
5950-
5951-
update_col_list_el:
5952-
ColId opt_indirection
5953-
{
5954-
$$ = makeNode(ResTarget);
5955-
$$->name = $1;
5956-
$$->indirection = $2;
5957-
$$->val = NULL;
5958-
$$->location = @1;
5959-
}
5960-
;
5961-
5962-
update_value_list:
5963-
values_item { $$ = list_make1($1); }
5964-
| update_value_list ',' values_item { $$ = lappend($1, $3); }
5965-
;
5966-
59675959

59685960
/*****************************************************************************
59695961
*
@@ -8232,10 +8224,35 @@ opt_asymmetric: ASYMMETRIC
82328224
| /*EMPTY*/
82338225
;
82348226

8227+
/*
8228+
* The SQL spec defines "contextually typed value expressions" and
8229+
* "contextually typed row value constructors", which for our purposes
8230+
* are the same as "a_expr" and "row" except that DEFAULT can appear at
8231+
* the top level.
8232+
*/
8233+
8234+
ctext_expr:
8235+
a_expr { $$ = (Node *) $1; }
8236+
| DEFAULT { $$ = (Node *) makeNode(SetToDefault); }
8237+
;
8238+
8239+
ctext_expr_list:
8240+
ctext_expr { $$ = list_make1($1); }
8241+
| ctext_expr_list ',' ctext_expr { $$ = lappend($1, $3); }
8242+
;
8243+
8244+
/*
8245+
* We should allow ROW '(' ctext_expr_list ')' too, but that seems to require
8246+
* making VALUES a fully reserved word, which will probably break more apps
8247+
* than allowing the noise-word is worth.
8248+
*/
8249+
ctext_row: '(' ctext_expr_list ')' { $$ = $2; }
8250+
;
8251+
82358252

82368253
/*****************************************************************************
82378254
*
8238-
* target lists for SELECT, UPDATE, INSERT
8255+
* target list for SELECT
82398256
*
82408257
*****************************************************************************/
82418258

@@ -8275,31 +8292,6 @@ target_el: a_expr AS ColLabel
82758292
}
82768293
;
82778294

8278-
update_target_list:
8279-
update_target_el { $$ = list_make1($1); }
8280-
| update_target_list ',' update_target_el { $$ = lappend($1,$3); }
8281-
;
8282-
8283-
update_target_el:
8284-
ColId opt_indirection '=' a_expr
8285-
{
8286-
$$ = makeNode(ResTarget);
8287-
$$->name = $1;
8288-
$$->indirection = $2;
8289-
$$->val = (Node *) $4;
8290-
$$->location = @1;
8291-
}
8292-
| ColId opt_indirection '=' DEFAULT
8293-
{
8294-
$$ = makeNode(ResTarget);
8295-
$$->name = $1;
8296-
$$->indirection = $2;
8297-
$$->val = (Node *) makeNode(SetToDefault);
8298-
$$->location = @1;
8299-
}
8300-
8301-
;
8302-
83038295

83048296
/*****************************************************************************
83058297
*

0 commit comments

Comments
 (0)