I wrote:
> I think what we're seeing here is evidence that it really doesn't work.
> Possibly there's some hack in array_set that overwrites the source
> data (which it shouldn't be doing, in any case!) when the data length
> doesn't need to change. Needs more digging to understand in detail...
Indeed, it looks like that's exactly what's happening. Try this on
for size:
regression=# select * from t1;
a
----------------
{"foo1","bar"}
(1 row)
regression=# begin;
BEGIN
regression=# update t1 set a[1] = 'foot';
UPDATE 1
regression=# abort;
ROLLBACK
regression=# select * from t1;
a
----------------
{"foot","bar"}
(1 row)
<Dana Carvey> My, isn't *that* special ... </Dana Carvey>
Evidently, array_set scribbles on its source object when the size
of the object isn't changed by the element assignment. This is why
it's possible for more than one element assignment to appear to work;
when the later assignments are executed with the same old source
datum, they see the other fields as updated. Too bad scribbling on
disk buffers is verboten.
I have to hack on the array support soon for TOAST anyway, and I'll
make sure that this idiocy goes away then. That will mean that
in fact you don't get more than one array update per UPDATE. Don't
see any easy way around that, unless we want to hack on the parser
to convert
UPDATE table SET a[1] = foo, a[2] = bar
into
UPDATE table SET a = array_set(array_set(a, 1, foo), 2, bar)
That might not be totally impractical but it looks ugly... Thomas,
what do you think about it?
regards, tom lane