Обсуждение: fast default vs triggers
Tomas Vondra has pointed out to me that there's an issue with triggers not getting expanded tuples for columns with fast defaults. Here is an example that shows the issue: andrew=# create table blurfl (id int); CREATE TABLE andrew=# insert into blurfl select x from generate_series(1,5) x; INSERT 0 5 andrew=# alter table blurfl add column x int default 100; ALTER TABLE andrew=# create or replace function showmej() returns trigger language plpgsql as $$ declare j json; begin j := to_json(old); raise notice 'old x: %', j->>'x'; return new; end; $$; CREATE FUNCTION andrew=# create trigger show_x before update on blurfl for each row execute procedure showmej(); CREATE TRIGGER andrew=# update blurfl set id = id where id = 1; NOTICE: old x: <NULL> UPDATE 1 andrew=# update blurfl set id = id where id = 1; NOTICE: old x: 100 UPDATE 1 andrew=# The error is fixed with this patch: diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 2436692..f34a72a 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -3396,7 +3396,11 @@ ltrmark:; LockBuffer(buffer, BUFFER_LOCK_UNLOCK); } - result = heap_copytuple(&tuple); + if (HeapTupleHeaderGetNatts(tuple.t_data) < relation->rd_att->natts) + result = heap_expand_tuple(&tuple, relation->rd_att); + else + result = heap_copytuple(&tuple); + ReleaseBuffer(buffer); return result; I'm going to re-check the various places that this might have been missed. I guess it belongs on the open items list. cheers andrew -- Andrew Dunstan https://www.2ndQuadrant.com PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
On 09/18/2018 03:36 PM, Andrew Dunstan wrote: > > > Tomas Vondra has pointed out to me that there's an issue with triggers > not getting expanded tuples for columns with fast defaults. Here is an > example that shows the issue: > > > andrew=# create table blurfl (id int); > CREATE TABLE > andrew=# insert into blurfl select x from generate_series(1,5) x; > INSERT 0 5 > andrew=# alter table blurfl add column x int default 100; > ALTER TABLE > andrew=# create or replace function showmej() returns trigger > language plpgsql as $$ declare j json; begin j := to_json(old); > raise notice 'old x: %', j->>'x'; return new; end; $$; > CREATE FUNCTION > andrew=# create trigger show_x before update on blurfl for each row > execute procedure showmej(); > CREATE TRIGGER > andrew=# update blurfl set id = id where id = 1; > NOTICE: old x: <NULL> > UPDATE 1 > andrew=# update blurfl set id = id where id = 1; > NOTICE: old x: 100 > UPDATE 1 > andrew=# > > > The error is fixed with this patch: > > > diff --git a/src/backend/commands/trigger.c > b/src/backend/commands/trigger.c > index 2436692..f34a72a 100644 > --- a/src/backend/commands/trigger.c > +++ b/src/backend/commands/trigger.c > @@ -3396,7 +3396,11 @@ ltrmark:; > LockBuffer(buffer, BUFFER_LOCK_UNLOCK); > } > - result = heap_copytuple(&tuple); > + if (HeapTupleHeaderGetNatts(tuple.t_data) < > relation->rd_att->natts) > + result = heap_expand_tuple(&tuple, relation->rd_att); > + else > + result = heap_copytuple(&tuple); > + > ReleaseBuffer(buffer); > return result; > > I'm going to re-check the various places that this might have been > missed. I guess it belongs on the open items list. > > > I haven't found anything further that is misbehaving. I paid particular attention to indexes and index-only scans. I propose to commit this along with an appropriate regression test. cheers andrew -- Andrew Dunstan https://www.2ndQuadrant.com PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
On 09/19/2018 10:35 PM, Andrew Dunstan wrote: > > > On 09/18/2018 03:36 PM, Andrew Dunstan wrote: >> >> >> Tomas Vondra has pointed out to me that there's an issue with triggers >> not getting expanded tuples for columns with fast defaults. Here is an >> example that shows the issue: >> >> >> andrew=# create table blurfl (id int); >> CREATE TABLE >> andrew=# insert into blurfl select x from generate_series(1,5) x; >> INSERT 0 5 >> andrew=# alter table blurfl add column x int default 100; >> ALTER TABLE >> andrew=# create or replace function showmej() returns trigger >> language plpgsql as $$ declare j json; begin j := to_json(old); >> raise notice 'old x: %', j->>'x'; return new; end; $$; >> CREATE FUNCTION >> andrew=# create trigger show_x before update on blurfl for each row >> execute procedure showmej(); >> CREATE TRIGGER >> andrew=# update blurfl set id = id where id = 1; >> NOTICE: old x: <NULL> >> UPDATE 1 >> andrew=# update blurfl set id = id where id = 1; >> NOTICE: old x: 100 >> UPDATE 1 >> andrew=# >> >> >> The error is fixed with this patch: >> >> >> diff --git a/src/backend/commands/trigger.c >> b/src/backend/commands/trigger.c >> index 2436692..f34a72a 100644 >> --- a/src/backend/commands/trigger.c >> +++ b/src/backend/commands/trigger.c >> @@ -3396,7 +3396,11 @@ ltrmark:; >> LockBuffer(buffer, BUFFER_LOCK_UNLOCK); >> } >> - result = heap_copytuple(&tuple); >> + if (HeapTupleHeaderGetNatts(tuple.t_data) < >> relation->rd_att->natts) >> + result = heap_expand_tuple(&tuple, relation->rd_att); >> + else >> + result = heap_copytuple(&tuple); >> + >> ReleaseBuffer(buffer); >> return result; >> >> I'm going to re-check the various places that this might have been >> missed. I guess it belongs on the open items list. >> >> >> > > > > I haven't found anything further that is misbehaving. I paid particular > attention to indexes and index-only scans. > > I propose to commit this along with an appropriate regression test. > Seems reasonable to me. regards -- Tomas Vondra http://www.2ndQuadrant.com PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
On 09/20/2018 09:04 AM, Tomas Vondra wrote: > > > On 09/19/2018 10:35 PM, Andrew Dunstan wrote: >> >> >> On 09/18/2018 03:36 PM, Andrew Dunstan wrote: >>> >>> >>> Tomas Vondra has pointed out to me that there's an issue with >>> triggers not getting expanded tuples for columns with fast defaults. >>> Here is an example that shows the issue: >>> >>> >>> andrew=# create table blurfl (id int); >>> CREATE TABLE >>> andrew=# insert into blurfl select x from generate_series(1,5) x; >>> INSERT 0 5 >>> andrew=# alter table blurfl add column x int default 100; >>> ALTER TABLE >>> andrew=# create or replace function showmej() returns trigger >>> language plpgsql as $$ declare j json; begin j := to_json(old); >>> raise notice 'old x: %', j->>'x'; return new; end; $$; >>> CREATE FUNCTION >>> andrew=# create trigger show_x before update on blurfl for each row >>> execute procedure showmej(); >>> CREATE TRIGGER >>> andrew=# update blurfl set id = id where id = 1; >>> NOTICE: old x: <NULL> >>> UPDATE 1 >>> andrew=# update blurfl set id = id where id = 1; >>> NOTICE: old x: 100 >>> UPDATE 1 >>> andrew=# >>> >>> >>> The error is fixed with this patch: >>> >>> >>> diff --git a/src/backend/commands/trigger.c >>> b/src/backend/commands/trigger.c >>> index 2436692..f34a72a 100644 >>> --- a/src/backend/commands/trigger.c >>> +++ b/src/backend/commands/trigger.c >>> @@ -3396,7 +3396,11 @@ ltrmark:; >>> LockBuffer(buffer, BUFFER_LOCK_UNLOCK); >>> } >>> - result = heap_copytuple(&tuple); >>> + if (HeapTupleHeaderGetNatts(tuple.t_data) < >>> relation->rd_att->natts) >>> + result = heap_expand_tuple(&tuple, relation->rd_att); >>> + else >>> + result = heap_copytuple(&tuple); >>> + >>> ReleaseBuffer(buffer); >>> return result; >>> >>> I'm going to re-check the various places that this might have been >>> missed. I guess it belongs on the open items list. >>> >>> >>> >> >> >> >> I haven't found anything further that is misbehaving. I paid >> particular attention to indexes and index-only scans. >> >> I propose to commit this along with an appropriate regression test. >> > > Seems reasonable to me. > This exposed a further issue with nulls in certain positions. A fix for both issues, and some regression tests, has been committed. Thanks to Tomas for his help. cheers andrew -- Andrew Dunstan https://www.2ndQuadrant.com PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services