Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit906bfca

Browse files
committed
Improve handling of "UPDATE ... SET (column_list) = row_constructor".
Previously, the right-hand side of a multiple-column assignment, if itwasn't a sub-SELECT, had to be a simple parenthesized expression list,because gram.y was responsible for "bursting" the construct intoindependent column assignments. This had the minor defect that youcouldn't write ROW (though you should be able to, since the standard saysthis is a row constructor), and the rather larger defect that unlike otheruses of row constructors, we would not expand a "foo.*" item into multiplecolumns.Fix that by changing the RHS to be just "a_expr" in the grammar, leavingit to transformMultiAssignRef to separate the elements of a RowExpr;which it will do only after performing standard transformation of theRowExpr, so that "foo.*" behaves as expected.The key reason we didn't do that before was the hard-wired handling ofDEFAULT tokens (SetToDefault nodes). This patch deals with that issue byallowing DEFAULT in any a_expr and having parse analysis throw an errorif SetToDefault is found in an unexpected place. That's an improvementanyway since the error can be more specific than just "syntax error".The SQL standard suggests that the RHS could be any a_expr yielding asuitable row value. This patch doesn't really move the goal posts in thatrespect --- you're still limited to RowExpr or a sub-SELECT --- but it doesfix the grammar restriction, so it provides some tangible progress towardsa full implementation. And the limitation is now documented by an expliciterror message rather than an unhelpful "syntax error".Discussion: <8542.1479742008@sss.pgh.pa.us>
1 parente8ac886 commit906bfca

File tree

8 files changed

+230
-182
lines changed

8 files changed

+230
-182
lines changed

‎doc/src/sgml/ref/update.sgml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ PostgreSQL documentation
2424
[ WITH [ RECURSIVE ] <replaceable class="parameter">with_query</replaceable> [, ...] ]
2525
UPDATE [ ONLY ] <replaceable class="PARAMETER">table_name</replaceable> [ * ] [ [ AS ] <replaceable class="parameter">alias</replaceable> ]
2626
SET { <replaceable class="PARAMETER">column_name</replaceable> = { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } |
27-
( <replaceable class="PARAMETER">column_name</replaceable> [, ...] ) = ( { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } [, ...] ) |
27+
( <replaceable class="PARAMETER">column_name</replaceable> [, ...] ) =[ ROW ]( { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } [, ...] ) |
2828
( <replaceable class="PARAMETER">column_name</replaceable> [, ...] ) = ( <replaceable class="PARAMETER">sub-SELECT</replaceable> )
2929
} [, ...]
3030
[ FROM <replaceable class="PARAMETER">from_list</replaceable> ]
@@ -420,12 +420,12 @@ UPDATE films SET kind = 'Dramatic' WHERE CURRENT OF c_films;
420420

421421
<para>
422422
According to the standard, the source value for a parenthesized sub-list of
423-
column names can be any row-valued expression yielding the correct number
424-
of columns. <productname>PostgreSQL</productname> only allows the source
425-
value to be aparenthesized list of expressions (arow constructor) or a
426-
sub-<literal>SELECT</>. An individual column's updated value can be
427-
specified as <literal>DEFAULT</> in the row-constructor case, but not
428-
inside a sub-<literal>SELECT</>.
423+
targetcolumn names can be any row-valued expression yielding the correct
424+
numberof columns. <productname>PostgreSQL</productname> only allows the
425+
sourcevalue to be a<link linkend="sql-syntax-row-constructors">row
426+
constructor</link> or asub-<literal>SELECT</>. An individual column's
427+
updated value can bespecified as <literal>DEFAULT</> in the
428+
row-constructor case, but notinside a sub-<literal>SELECT</>.
429429
</para>
430430
</refsect1>
431431
</refentry>

‎src/backend/parser/analyze.c

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -644,8 +644,12 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
644644
{
645645
List*sublist= (List*)lfirst(lc);
646646

647-
/* Do basic expression transformation (same as a ROW() expr) */
648-
sublist=transformExpressionList(pstate,sublist,EXPR_KIND_VALUES);
647+
/*
648+
* Do basic expression transformation (same as a ROW() expr, but
649+
* allow SetToDefault at top level)
650+
*/
651+
sublist=transformExpressionList(pstate,sublist,
652+
EXPR_KIND_VALUES, true);
649653

650654
/*
651655
* All the sublists must be the same length, *after*
@@ -752,10 +756,14 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
752756
Assert(list_length(valuesLists)==1);
753757
Assert(selectStmt->intoClause==NULL);
754758

755-
/* Do basic expression transformation (same as a ROW() expr) */
759+
/*
760+
* Do basic expression transformation (same as a ROW() expr, but allow
761+
* SetToDefault at top level)
762+
*/
756763
exprList=transformExpressionList(pstate,
757764
(List*)linitial(valuesLists),
758-
EXPR_KIND_VALUES);
765+
EXPR_KIND_VALUES,
766+
true);
759767

760768
/* Prepare row for assignment to target table */
761769
exprList=transformInsertRow(pstate,exprList,
@@ -1293,9 +1301,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
12931301
}
12941302

12951303
/*
1296-
* For each row of VALUES, transform the raw expressions. This is also a
1297-
* handy place to reject DEFAULT nodes, which the grammar allows for
1298-
* simplicity.
1304+
* For each row of VALUES, transform the raw expressions.
12991305
*
13001306
* Note that the intermediate representation we build is column-organized
13011307
* not row-organized. That simplifies the type and collation processing
@@ -1305,8 +1311,12 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
13051311
{
13061312
List*sublist= (List*)lfirst(lc);
13071313

1308-
/* Do basic expression transformation (same as a ROW() expr) */
1309-
sublist=transformExpressionList(pstate,sublist,EXPR_KIND_VALUES);
1314+
/*
1315+
* Do basic expression transformation (same as a ROW() expr, but here
1316+
* we disallow SetToDefault)
1317+
*/
1318+
sublist=transformExpressionList(pstate,sublist,
1319+
EXPR_KIND_VALUES, false);
13101320

13111321
/*
13121322
* All the sublists must be the same length, *after* transformation
@@ -1329,17 +1339,12 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
13291339
exprLocation((Node*)sublist))));
13301340
}
13311341

1332-
/*Check for DEFAULT and build per-column expression lists */
1342+
/*Build per-column expression lists */
13331343
i=0;
13341344
foreach(lc2,sublist)
13351345
{
13361346
Node*col= (Node*)lfirst(lc2);
13371347

1338-
if (IsA(col,SetToDefault))
1339-
ereport(ERROR,
1340-
(errcode(ERRCODE_SYNTAX_ERROR),
1341-
errmsg("DEFAULT can only appear in a VALUES list within INSERT"),
1342-
parser_errposition(pstate,exprLocation(col))));
13431348
colexprs[i]=lappend(colexprs[i],col);
13441349
i++;
13451350
}

‎src/backend/parser/gram.y

Lines changed: 31 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -365,8 +365,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
365365
qualified_name_listany_nameany_name_listtype_name_list
366366
any_operatorexpr_listattrs
367367
target_listopt_target_listinsert_column_listset_target_list
368-
set_clause_listset_clausemultiple_set_clause
369-
ctext_expr_listctext_rowdef_listoperator_def_listindirectionopt_indirection
368+
set_clause_listset_clause
369+
def_listoperator_def_listindirectionopt_indirection
370370
reloption_listgroup_clauseTriggerFuncArgsselect_limit
371371
opt_select_limitopclass_item_listopclass_drop_list
372372
opclass_purposeopt_opfamilytransaction_mode_list_or_empty
@@ -454,7 +454,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
454454
%type<node>case_exprcase_argwhen_clausecase_default
455455
%type<list>when_clause_list
456456
%type<ival>sub_type
457-
%type<node>ctext_expr
458457
%type<value>NumericOnly
459458
%type<list>NumericOnly_list
460459
%type<alias>alias_clauseopt_alias_clause
@@ -466,7 +465,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
466465
%type<range>relation_expr
467466
%type<range>relation_expr_opt_alias
468467
%type<node>tablesample_clauseopt_repeatable_clause
469-
%type<target>target_elsingle_set_clauseset_targetinsert_column_item
468+
%type<target>target_elset_targetinsert_column_item
470469

471470
%type<str>generic_option_name
472471
%type<node>generic_option_arg
@@ -9914,75 +9913,24 @@ set_clause_list:
99149913
;
99159914

99169915
set_clause:
9917-
single_set_clause{$$ = list_make1($1); }
9918-
|multiple_set_clause{$$ =$1; }
9919-
;
9920-
9921-
single_set_clause:
9922-
set_target'='ctext_expr
9923-
{
9924-
$$ =$1;
9925-
$$->val = (Node *)$3;
9926-
}
9927-
;
9928-
9929-
/*
9930-
* Ideally, we'd accept any row-valued a_expr as RHS of a multiple_set_clause.
9931-
* However, per SQL spec the row-constructor case must allow DEFAULT as a row
9932-
* member, and it's pretty unclear how to do that (unless perhaps we allow
9933-
* DEFAULT in any a_expr and let parse analysis sort it out later?). For the
9934-
* moment, the planner/executor only support a subquery as a multiassignment
9935-
* source anyhow, so we need only accept ctext_row and subqueries here.
9936-
*/
9937-
multiple_set_clause:
9938-
'('set_target_list')''='ctext_row
9916+
set_target'='a_expr
99399917
{
9940-
ListCell *col_cell;
9941-
ListCell *val_cell;
9942-
9943-
/*
9944-
* Break the ctext_row apart, merge individual expressions
9945-
* into the destination ResTargets. This is semantically
9946-
* equivalent to, and much cheaper to process than, the
9947-
* general case.
9948-
*/
9949-
if (list_length($2) != list_length($5))
9950-
ereport(ERROR,
9951-
(errcode(ERRCODE_SYNTAX_ERROR),
9952-
errmsg("number of columns does not match number of values"),
9953-
parser_errposition(@5)));
9954-
forboth(col_cell, $2, val_cell, $5)
9955-
{
9956-
ResTarget *res_col = (ResTarget *)lfirst(col_cell);
9957-
Node *res_val = (Node *)lfirst(val_cell);
9958-
9959-
res_col->val = res_val;
9960-
}
9961-
9962-
$$ =$2;
9918+
$1->val = (Node *)$3;
9919+
$$ = list_make1($1);
99639920
}
9964-
|'('set_target_list')''='select_with_parens
9921+
|'('set_target_list')''='a_expr
99659922
{
9966-
SubLink *sl = makeNode(SubLink);
99679923
int ncolumns = list_length($2);
99689924
int i =1;
99699925
ListCell *col_cell;
99709926

9971-
/* First, convert bare SelectStmt into a SubLink*/
9972-
sl->subLinkType = MULTIEXPR_SUBLINK;
9973-
sl->subLinkId =0;/* will be assigned later*/
9974-
sl->testexpr =NULL;
9975-
sl->operName = NIL;
9976-
sl->subselect =$5;
9977-
sl->location =@5;
9978-
99799927
/* Create a MultiAssignRef source for each target*/
99809928
foreach(col_cell, $2)
99819929
{
99829930
ResTarget *res_col = (ResTarget *)lfirst(col_cell);
99839931
MultiAssignRef *r =makeNode(MultiAssignRef);
99849932

9985-
r->source = (Node *)sl;
9933+
r->source = (Node *)$5;
99869934
r->colno = i;
99879935
r->ncolumns = ncolumns;
99889936
res_col->val = (Node *) r;
@@ -10641,17 +10589,22 @@ locked_rels_list:
1064110589
;
1064210590

1064310591

10592+
/*
10593+
* We should allow ROW '(' expr_list ')' too, but that seems to require
10594+
* making VALUES a fully reserved word, which will probably break more apps
10595+
* than allowing the noise-word is worth.
10596+
*/
1064410597
values_clause:
10645-
VALUESctext_row
10598+
VALUES'('expr_list')'
1064610599
{
1064710600
SelectStmt *n = makeNode(SelectStmt);
10648-
n->valuesLists = list_make1($2);
10601+
n->valuesLists = list_make1($3);
1064910602
$$ = (Node *) n;
1065010603
}
10651-
|values_clause','ctext_row
10604+
|values_clause',''('expr_list')'
1065210605
{
1065310606
SelectStmt *n = (SelectStmt *)$1;
10654-
n->valuesLists = lappend(n->valuesLists,$3);
10607+
n->valuesLists = lappend(n->valuesLists,$4);
1065510608
$$ = (Node *) n;
1065610609
}
1065710610
;
@@ -12042,6 +11995,20 @@ a_expr:c_expr{ $$ = $1; }
1204211995
list_make1($1), @2),
1204311996
@2);
1204411997
}
11998+
|DEFAULT
11999+
{
12000+
/*
12001+
* The SQL spec only allows DEFAULT in "contextually typed
12002+
* expressions", but for us, it's easier to allow it in
12003+
* any a_expr and then throw error during parse analysis
12004+
* if it's in an inappropriate context. This way also
12005+
* lets us say something smarter than "syntax error".
12006+
*/
12007+
SetToDefault *n = makeNode(SetToDefault);
12008+
/* parse analysis will fill in the rest*/
12009+
n->location =@1;
12010+
$$ = (Node *)n;
12011+
}
1204512012
;
1204612013

1204712014
/*
@@ -13297,36 +13264,6 @@ opt_asymmetric: ASYMMETRIC
1329713264
|/*EMPTY*/
1329813265
;
1329913266

13300-
/*
13301-
* The SQL spec defines "contextually typed value expressions" and
13302-
* "contextually typed row value constructors", which for our purposes
13303-
* are the same as "a_expr" and "row" except that DEFAULT can appear at
13304-
* the top level.
13305-
*/
13306-
13307-
ctext_expr:
13308-
a_expr{ $$ = (Node *) $1; }
13309-
| DEFAULT
13310-
{
13311-
SetToDefault *n =makeNode(SetToDefault);
13312-
n->location = @1;
13313-
$$ = (Node *) n;
13314-
}
13315-
;
13316-
13317-
ctext_expr_list:
13318-
ctext_expr{ $$ =list_make1($1); }
13319-
| ctext_expr_list',' ctext_expr{ $$ =lappend($1, $3); }
13320-
;
13321-
13322-
/*
13323-
* We should allow ROW '(' ctext_expr_list ')' too, but that seems to require
13324-
* making VALUES a fully reserved word, which will probably break more apps
13325-
* than allowing the noise-word is worth.
13326-
*/
13327-
ctext_row:'(' ctext_expr_list')'{ $$ = $2; }
13328-
;
13329-
1333013267

1333113268
/*****************************************************************************
1333213269
*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp