Attaching patch... :-/

On Tue, Oct 31, 2017 at 4:27 PM, Rob McColl <r...@robmccoll.com> wrote:

> Between 9.6.5 and 10, the handling of parenthesized single-column UPDATE
> statements changed. In 9.6.5, they were treated identically to
> unparenthesized single-column UPDATES. In 10, they are treated as
> multiple-column updates.  This results in this being valid in Postgres
> 9.6.5, but an error in Postgres 10:
>
> CREATE TABLE test (id INT PRIMARY KEY, data INT);
> INSERT INTO test VALUES (1, 1);
> UPDATE test SET (data) = (2) WHERE id = 1;
>
> In 10 and the current master, this produces the error:
>
> errmsg("source for a multiple-column UPDATE item must be a sub-SELECT or
> ROW() expression")
>
> I believe that this is not an intended change or behavior, but is instead
> an unintentional side effect of 906bfcad7ba7cb3863fe0e2a7810be8e3cd84fbd
> Improve handling of "UPDATE ... SET (column_list) = row_constructor". (
> https://github.com/postgres/postgres/commit/906bfcad7ba7cb3
> 863fe0e2a7810be8e3cd84fbd).
>
> This is a small patch to the grammar that restores the previous behavior
> by adding a rule to the set_clause rule and modifying the final rule of the
> set_clause rule to only match lists of more then one element.  I'm not sure
> if there are more elegant or preferred ways to address this.
>
> Compiled and tested on Ubuntu 17.04 Linux 4.10.0-33-generic x86_64.
>
> Regression test added under the update test to cover the parenthesized
> single-column case.
>
> I see no reason this would affect performance.
>
> Thanks,
> -rob
>
> --
> Rob McColl
> @robmccoll
> r...@robmccoll.com
> 205.422.0909 <(205)%20422-0909>
>
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
new file mode 100644
index 4c83a63..b5f4ccf
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
*************** set_clause:
*** 10694,10712 ****
  					$1->val = (Node *) $3;
  					$$ = list_make1($1);
  				}
! 			| '(' set_target_list ')' '=' a_expr
  				{
! 					int ncolumns = list_length($2);
  					int i = 1;
  					ListCell *col_cell;
  
  					/* Create a MultiAssignRef source for each target */
  					foreach(col_cell, $2)
  					{
  						ResTarget *res_col = (ResTarget *) lfirst(col_cell);
  						MultiAssignRef *r = makeNode(MultiAssignRef);
  
! 						r->source = (Node *) $5;
  						r->colno = i;
  						r->ncolumns = ncolumns;
  						res_col->val = (Node *) r;
--- 10694,10720 ----
  					$1->val = (Node *) $3;
  					$$ = list_make1($1);
  				}
! 			| '(' set_target ')' '=' a_expr
  				{
! 					$2->val = (Node *) $5;
! 					$$ = list_make1($2);
! 				}
! 			| '(' set_target_list ',' set_target ')' '=' a_expr
! 				{
! 					int ncolumns;
  					int i = 1;
  					ListCell *col_cell;
  
+ 					$2 = lappend($2,$4);
+ 					ncolumns = list_length($2);
+ 
  					/* Create a MultiAssignRef source for each target */
  					foreach(col_cell, $2)
  					{
  						ResTarget *res_col = (ResTarget *) lfirst(col_cell);
  						MultiAssignRef *r = makeNode(MultiAssignRef);
  
! 						r->source = (Node *) $7;
  						r->colno = i;
  						r->ncolumns = ncolumns;
  						res_col->val = (Node *) r;
diff --git a/src/test/regress/expected/update.out b/src/test/regress/expected/update.out
new file mode 100644
index cef70b1..90d33ad
*** a/src/test/regress/expected/update.out
--- b/src/test/regress/expected/update.out
*************** SELECT * FROM update_test;
*** 76,82 ****
   100 | 21 | 
  (4 rows)
  
! UPDATE update_test SET (c,b,a) = ('bugle', b+11, DEFAULT) WHERE c = 'foo';
  SELECT * FROM update_test;
    a  | b  |   c   
  -----+----+-------
--- 76,93 ----
   100 | 21 | 
  (4 rows)
  
! -- parenthesized single column should be valid
! UPDATE update_test SET (c) = ('bungle') WHERE c = 'foo';
! SELECT * FROM update_test;
!   a  | b  |   c    
! -----+----+--------
!  100 | 20 | 
!  100 | 21 | 
!  100 | 20 | bungle
!  100 | 21 | bungle
! (4 rows)
! 
! UPDATE update_test SET (c,b,a) = ('bugle', b+11, DEFAULT) WHERE c = 'bungle';
  SELECT * FROM update_test;
    a  | b  |   c   
  -----+----+-------
diff --git a/src/test/regress/sql/update.sql b/src/test/regress/sql/update.sql
new file mode 100644
index 66d1fec..0ed5f6a
*** a/src/test/regress/sql/update.sql
--- b/src/test/regress/sql/update.sql
*************** UPDATE update_test SET a = v.* FROM (VAL
*** 51,57 ****
  INSERT INTO update_test SELECT a,b+1,c FROM update_test;
  SELECT * FROM update_test;
  
! UPDATE update_test SET (c,b,a) = ('bugle', b+11, DEFAULT) WHERE c = 'foo';
  SELECT * FROM update_test;
  UPDATE update_test SET (c,b) = ('car', a+b), a = a + 1 WHERE a = 10;
  SELECT * FROM update_test;
--- 51,60 ----
  INSERT INTO update_test SELECT a,b+1,c FROM update_test;
  SELECT * FROM update_test;
  
! -- parenthesized single column should be valid
! UPDATE update_test SET (c) = ('bungle') WHERE c = 'foo';
! SELECT * FROM update_test;
! UPDATE update_test SET (c,b,a) = ('bugle', b+11, DEFAULT) WHERE c = 'bungle';
  SELECT * FROM update_test;
  UPDATE update_test SET (c,b) = ('car', a+b), a = a + 1 WHERE a = 10;
  SELECT * FROM update_test;
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to