diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 792ba56d75..c15b1b979c 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -4893,6 +4893,16 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode) table_slot_callbacks(oldrel)); newslot = MakeSingleTupleTableSlot(newTupDesc, table_slot_callbacks(newrel)); + + /* + * Set all columns in the new slot to NULL initially, to ensure + * columns added as part of the rewrite are initialized to + * NULL. That is necessary as tab->newvals will not contain an + * expression for columns with a NULL default, e.g. when adding a + * column without a default together with a column with a default + * requiring an actual rewrite. + */ + ExecStoreAllNullTuple(newslot); } else { diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index c97ff48b75..aa7f664782 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -2436,6 +2436,53 @@ select * from at_view_2; drop view at_view_2; drop view at_view_1; drop table at_base_table; +-- check adding a column not iself requiring a rewrite, together with +-- a column requiring a default (bug #16038) +-- ensure that rewrites aren't silently optimized away, removing the +-- value of the test +CREATE OR REPLACE FUNCTION evtrig_rewrite_log() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN + RAISE WARNING 'rewriting table %', + pg_event_trigger_table_rewrite_oid()::regclass; +END; +$$; +CREATE EVENT TRIGGER evtrig_rewrite_log ON table_rewrite + EXECUTE PROCEDURE evtrig_rewrite_log(); +CREATE TABLE rewrite_test(col text); +INSERT INTO rewrite_test VALUES ('something'); +INSERT INTO rewrite_test VALUES (NULL); +-- empty[12] doesn't need rewrite, but notempty[12]_rewrite will force one +ALTER TABLE rewrite_test + ADD COLUMN empty1 text, + ADD COLUMN notempty1_rewrite serial; +WARNING: rewriting table rewrite_test +ALTER TABLE rewrite_test + ADD COLUMN notempty2_rewrite serial, + ADD COLUMN empty2 text; +WARNING: rewriting table rewrite_test +-- also check that fast defaults cause no problem, first without rewrite +ALTER TABLE rewrite_test + ADD COLUMN empty3 text, + ADD COLUMN notempty3_norewrite int default 42; +ALTER TABLE rewrite_test + ADD COLUMN notempty4_norewrite int default 42, + ADD COLUMN empty4 text; +-- then with rewrite +ALTER TABLE rewrite_test + ADD COLUMN empty5 text, + ADD COLUMN notempty5_norewrite int default 42, + ADD COLUMN notempty5_rewrite serial; +WARNING: rewriting table rewrite_test +ALTER TABLE rewrite_test + ADD COLUMN notempty6_rewrite serial, + ADD COLUMN empty6 text, + ADD COLUMN notempty6_norewrite int default 42; +WARNING: rewriting table rewrite_test +-- cleanup +drop event trigger evtrig_rewrite_log; +drop function evtrig_rewrite_log(); +DROP TABLE rewrite_test; -- -- lock levels -- diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 8016f8a823..0c8c181a73 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -1550,6 +1550,54 @@ drop view at_view_2; drop view at_view_1; drop table at_base_table; +-- check adding a column not iself requiring a rewrite, together with +-- a column requiring a default (bug #16038) + +-- ensure that rewrites aren't silently optimized away, removing the +-- value of the test +CREATE OR REPLACE FUNCTION evtrig_rewrite_log() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN + RAISE WARNING 'rewriting table %', + pg_event_trigger_table_rewrite_oid()::regclass; +END; +$$; +CREATE EVENT TRIGGER evtrig_rewrite_log ON table_rewrite + EXECUTE PROCEDURE evtrig_rewrite_log(); + +CREATE TABLE rewrite_test(col text); +INSERT INTO rewrite_test VALUES ('something'); +INSERT INTO rewrite_test VALUES (NULL); + +-- empty[12] doesn't need rewrite, but notempty[12]_rewrite will force one +ALTER TABLE rewrite_test + ADD COLUMN empty1 text, + ADD COLUMN notempty1_rewrite serial; +ALTER TABLE rewrite_test + ADD COLUMN notempty2_rewrite serial, + ADD COLUMN empty2 text; +-- also check that fast defaults cause no problem, first without rewrite +ALTER TABLE rewrite_test + ADD COLUMN empty3 text, + ADD COLUMN notempty3_norewrite int default 42; +ALTER TABLE rewrite_test + ADD COLUMN notempty4_norewrite int default 42, + ADD COLUMN empty4 text; +-- then with rewrite +ALTER TABLE rewrite_test + ADD COLUMN empty5 text, + ADD COLUMN notempty5_norewrite int default 42, + ADD COLUMN notempty5_rewrite serial; +ALTER TABLE rewrite_test + ADD COLUMN notempty6_rewrite serial, + ADD COLUMN empty6 text, + ADD COLUMN notempty6_norewrite int default 42; + +-- cleanup +drop event trigger evtrig_rewrite_log; +drop function evtrig_rewrite_log(); +DROP TABLE rewrite_test; + -- -- lock levels --