AW: AW: UPDATE myTable SET (myTable.*) = json_populate_record(...) ?

From: Färber, Franz-Josef (StMUK) <Franz-Josef(dot)Faerber(at)stmuk(dot)bayern(dot)de>
To: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, Adrian Klaver <adrian(dot)klaver(at)aklaver(dot)com>
Cc: "pgsql-general(at)lists(dot)postgresql(dot)org" <pgsql-general(at)lists(dot)postgresql(dot)org>
Subject: AW: AW: UPDATE myTable SET (myTable.*) = json_populate_record(...) ?
Date: 2026-08-03 18:26:57
Message-ID: b412205b5aa1415190ab1111c4647ebf@stmuk.bayern.de
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-general

Thank you for your thoughts on it. What I was really doing was:

1) I have an audit table that gets filled with JSON objects. The Trigger Procedure does in essence:

INSERT INTO audit_log
(timestamp, tg_relid, tg_op, old, new)
VALUES
(now(), TG_RELID, TG_OP, to_json(OLD), to_json(NEW));

2) I thought about un-doing these operations in reverse order. Time-Travel, so to say. For example to un-do an UPDATE statement, I would have

UPDATE %1$s
SET (%2$s) = (SELECT * FROM json_populate_record(NULL::%1$s, $1))
WHERE json_populate_record(NULL::%1$s, $2) = (%1$s.*)

(dynamic SQL, constructed with EXECUTE format(...) USING old, new ; where "old" and "new" are JSON values from the audit_log table.)

Here you see:
* The WHERE condition can be written quite compact, using equality on row types.
* But the SET clause can't: Does not support a row type on the left hand, and does not support a row type returning function on the right hand.
(Yes I know the SET assigment is a semantically different thing to the WHERE equality comparison operator.)

THAT is the thing that occured to me as somehow inconsequent.

-----Ursprüngliche Nachricht-----
Von: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Gesendet: Montag, 3. August 2026 18:49
An: Adrian Klaver <adrian(dot)klaver(at)aklaver(dot)com>
Cc: Färber, Franz-Josef (StMUK) <Franz-Josef(dot)Faerber(at)stmuk(dot)bayern(dot)de>; pgsql-general(at)lists(dot)postgresql(dot)org
Betreff: Re: AW: UPDATE myTable SET (myTable.*) = json_populate_record(...) ?

Adrian Klaver <adrian(dot)klaver(at)aklaver(dot)com> writes:
> On 8/3/26 8:17 AM, Färber, Franz-Josef (StMUK) wrote:
>> But what about my other item... what about somehow preventing to write all column names, i. e. changing ...
>> SET (col1, col2, ...)
>> ... to something like ...
>> SET (myTable.*)

> Best bet is you are seeing the effect of, from here:
> https://www.postgresql.org/docs/18/sql-update.html

The SQL standard does not allow writing "*" there, and that's a restriction I agree with. If you write "SELECT *" and the output has more or fewer columns, or columns in a different order, than you expected, no great harm is done to your database.
If we allowed "UPDATE SET (*) = blah, blah" and the same type of confusion occurred, you might completely destroy your table.
Writing out the target columns explicitly is a small price to reduce the odds of mistakes.

(I'm too lazy to search for the exact quote, but there's something in Brooks' classic "The Mythical Man-month" to the effect that, if a fairy came to a programmer and offered to make all his code bug-free if he'd agree to type it in three times, any programmer in the world would instantly take that bargain.)

Having said that, the error checks in transformMultiAssignRef could probably be ordered better. For instance:

postgres=# create table tab (a int, b int); CREATE TABLE

postgres=# update tab set (*) = row(1,2);
ERROR: syntax error at or near "*"
LINE 1: update tab set (*) = row(1,2);
^

postgres=# update tab set (tab.*) = row(1,2);
ERROR: number of columns does not match number of values LINE 1: update tab set (tab.*) = row(1,2);
^

postgres=# update tab set (tab.*) = row(1);
ERROR: column "tab" of relation "tab" does not exist LINE 1: update tab set (tab.*) = row(1);
^
HINT: SET target columns cannot be qualified with the relation name.

We ought to be complaining that the SET target is inherently invalid before we start thinking about whether it matches the source value.

regards, tom lane

In response to

Browse pgsql-general by date

  From Date Subject
Next Message Merlin Moncure 2026-08-03 20:21:51 Re: UPDATE myTable SET (myTable.*) = json_populate_record(...) ?
Previous Message Tom Lane 2026-08-03 16:48:56 Re: AW: UPDATE myTable SET (myTable.*) = json_populate_record(...) ?