Re: Support UPDATE table SET(*)=...

From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: Atri Sharma <atri(dot)jiit(at)gmail(dot)com>
Cc: Michael Paquier <michael(dot)paquier(at)gmail(dot)com>, Marko Tiikkaja <marko(at)joh(dot)to>, Pg Hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: Support UPDATE table SET(*)=...
Date: 2015-04-07 16:53:44
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

Atri Sharma <atri(dot)jiit(at)gmail(dot)com> writes:
> Please find attached latest version of UPDATE (*) patch.The patch
> implements review comments and Tom's gripe about touching
> transformTargetList is addressed now. I have added regression tests and
> simplified parser representation a bit.

I spent a fair amount of time cleaning this patch up to get it into
committable shape, but as I was working on the documentation I started
to lose enthusiasm for it, because I was having a hard time coming up
with compelling examples. The originally proposed motivation was

>> It solves the problem of doing UPDATE from a record variable of the same
>> type as the table e.g. update foo set (*) = (select foorec.*) where ...;

but it feels to me that this is not actually a very good solution to that
problem --- even granting that the problem needs to be solved, a claim
that still requires some justification IMO. Here is a possible use-case:

regression=# create table src (f1 int, f2 text, f3 real);
regression=# create table dst (f1 int, f2 text, f3 real);
regression=# create rule r1 as on update to src do instead
regression-# update dst set (*) = (new.*) where dst.f1 = old.f1;
ERROR: number of columns does not match number of values
LINE 2: update dst set (*) = (new.*) where dst.f1 = old.f1;

So that's annoying. You can work around it with this very unobvious
(and undocumented) syntax hack:

regression=# create rule r1 as on update to src do instead
regression-# update dst set (*) = (select new.*) where dst.f1 = old.f1;

But what happens if dst has no matching row? Your data goes into the
bit bucket, that's what. What you really wanted here was some kind of
UPSERT. There's certainly a possible use-case for a notation like this
in UPSERT, when we get around to implementing that; but I'm less than
convinced that we need it in plain UPDATE.

What's much worse though is that the rule that actually gets stored is:

regression=# \d+ src
Table "public.src"
Column | Type | Modifiers | Storage | Stats target | Description
f1 | integer | | plain | |
f2 | text | | extended | |
f3 | real | | plain | |
r1 AS
ON UPDATE TO src DO INSTEAD UPDATE dst SET (f1, f2, f3) = ( SELECT new.f1,
WHERE dst.f1 = old.f1

That is, you don't actually have any protection at all against future
additions of columns, which seems like it would be most of the point
of using a notation like this.

We could possibly address that by postponing expansion of the *-notation
to rule rewrite time, but that seems like it'd be a complete disaster in
terms of modularity, or even usability (since column-mismatch errors
wouldn't get raised till then either). And it'd certainly be a far more
invasive and complex patch than this.

So I'm feeling that this may not be a good idea, or at least not a good
implementation of the idea. I'm inclined to reject the patch rather than
lock us into something that is not standard and doesn't really do what
people would be likely to want.

Attached is the updated patch that I had before arriving at this
discouraging conclusion.

regards, tom lane

Attachment Content-Type Size
updatestar_v3.patch text/x-diff 20.3 KB

In response to


Browse pgsql-hackers by date

  From Date Subject
Next Message Sawada Masahiko 2015-04-07 16:57:35 Re: Proposal : REINDEX xxx VERBOSE
Previous Message Fabrízio de Royes Mello 2015-04-07 16:11:35 Re: Proposal : REINDEX xxx VERBOSE