Обсуждение: BUG #16038: Alter table - SegFault
The following bug has been logged on the website: Bug reference: 16038 Logged by: death lock Email address: deathlock13@gmail.com PostgreSQL version: 12.0 Operating system: WinXP (VisualStudio 2013) , Debian11 gcc9 Description: create schema if not exists test ; drop table test.testa; CREATE TABLE test.testa ( code character varying(2) NOT NULL, namez character varying(255) NOT NULL, descr character varying(1024), wersja numeric(1,0), modt timestamp without time zone, crtt timestamp without time zone, crt integer, mod integer, -- ida numeric(10,0) DEFAULT nextval(('test.sq_testa'::text)::regclass) NOT NULL, -- fk_tmp character varying(20), CONSTRAINT test_pk PRIMARY KEY (code) ); INSERT INTO test.testa VALUES ('0', 'AA', NULL, NULL, '2018-02-19 09:40:38.776875', '2008-05-20 10:06:28.171', 1001, 1001 /*, 1, 'DUMMYA' */); -- INSERT INTO test.testa VALUES ('1', 'BB', NULL, NULL, '2018-02-19 09:40:38.776875', '2008-05-20 10:06:28.171', 1001, 1001 /*, 2, 'DUMMYB' */); drop sequence if exists test.sq_testb; create SEQUENCE test.sq_testb; alter table test.testa add column idb numeric(10,0) NOT NULL DEFAULT nextval('test.sq_testb'), add column fk_tmpb varchar(20); server process (PID 21884) was terminated by signal 11: Segmentation fault - empty table - alter goes ok , split alter into 2 add col - works too
On 2019-Oct-04, PG Bug reporting form wrote: > alter table test.testa > add column idb numeric(10,0) NOT NULL DEFAULT nextval('test.sq_testb'), > add column fk_tmpb varchar(20); > > server process (PID 21884) was terminated by signal 11: Segmentation fault > - empty table - alter goes ok , split alter into 2 add col - works too Hmm, confirmed, here's the stack trace: #0 0x0000561459590e9f in heap_compute_data_size (tupleDesc=tupleDesc@entry=0x7faa37b16618, values=values@entry=0x56145b26ba30, isnull=isnull@entry=0x56145b26ba80) at /pgsql/source/REL_12_STABLE/src/backend/access/common/heaptuple.c:138 #1 0x000056145959232b in heap_form_tuple (tupleDescriptor=0x7faa37b16618, values=0x56145b26ba30, isnull=0x56145b26ba80) at /pgsql/source/REL_12_STABLE/src/backend/access/common/heaptuple.c:1061 #2 0x000056145975f881 in tts_buffer_heap_materialize (slot=0x56145b26b9c0) at /pgsql/source/REL_12_STABLE/src/backend/executor/execTuples.c:713 #3 0x0000561459761083 in ExecFetchSlotHeapTuple (slot=0x56145b26b9c0, materialize=<optimized out>, shouldFree=0x7ffffc491bbf) at /pgsql/source/REL_12_STABLE/src/backend/executor/execTuples.c:1618 #4 0x00005614595e09c4 in heapam_tuple_insert (relation=0x7faa37b159e0, slot=0x56145b26b9c0, cid=8, options=2, bistate=0x56145b26bd68) at /pgsql/source/REL_12_STABLE/src/backend/access/heap/heapam_handler.c:250 #5 0x0000561459715614 in table_tuple_insert (bistate=0x56145b26bd68, options=2, cid=8, slot=0x56145b26b9c0, rel=0x7faa37b159e0) at /pgsql/source/REL_12_STABLE/src/include/access/tableam.h:1126 #6 ATRewriteTable (tab=tab@entry=0x56145b25b5d8, OIDNewHeap=OIDNewHeap@entry=16396, lockmode=lockmode@entry=8) at /pgsql/source/REL_12_STABLE/src/backend/commands/tablecmds.c:5039 #7 0x000056145972a9b8 in ATRewriteTables (lockmode=8, wqueue=0x7ffffc491d08, parsetree=0x56145b24d7c0) at /pgsql/source/REL_12_STABLE/src/backend/commands/tablecmds.c:4641 #8 ATController (parsetree=parsetree@entry=0x56145b24d7c0, rel=<optimized out>, cmds=<optimized out>, recurse=<optimized out>, lockmode=lockmode@entry=8) at /pgsql/source/REL_12_STABLE/src/backend/commands/tablecmds.c:3848 -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Hi, On 2019-10-04 11:43:52 -0300, Alvaro Herrera wrote: > On 2019-Oct-04, PG Bug reporting form wrote: > > > alter table test.testa > > add column idb numeric(10,0) NOT NULL DEFAULT nextval('test.sq_testb'), > > add column fk_tmpb varchar(20); > > > > server process (PID 21884) was terminated by signal 11: Segmentation fault > > - empty table - alter goes ok , split alter into 2 add col - works too > > Hmm, confirmed, here's the stack trace: The trailing attributes in the new slot in AtRewriteTable() aren't necessarily set to isnull=true. So to trigger the problem, one needs a rewrite triggered by *another* column (otherwise we'll not hit this path), combined with a new column that doesn't have a default value. I think that's probably my bug. This seems to fix the problem: diff --git i/src/backend/commands/tablecmds.c w/src/backend/commands/tablecmds.c index 05593f33162..6f72b08a87d 100644 --- i/src/backend/commands/tablecmds.c +++ w/src/backend/commands/tablecmds.c @@ -4890,6 +4890,14 @@ 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's necessary as tab->newvals will not contain an + * expression for columns with a NULL default. + */ + ExecStoreAllNullTuple(newslot); } else { Greetings, Andres Freund
Hi, On 2019-10-04 08:26:24 -0700, Andres Freund wrote: > On 2019-10-04 11:43:52 -0300, Alvaro Herrera wrote: > > On 2019-Oct-04, PG Bug reporting form wrote: > > > > > alter table test.testa > > > add column idb numeric(10,0) NOT NULL DEFAULT nextval('test.sq_testb'), > > > add column fk_tmpb varchar(20); > > > > > > server process (PID 21884) was terminated by signal 11: Segmentation fault > > > - empty table - alter goes ok , split alter into 2 add col - works too Thanks for the bug report! I've pushed a fix, which will be included in the next minor release. If you need a workaround until then, you can avoid the crash by only adding one column add a time. > > Hmm, confirmed, here's the stack trace: > > The trailing attributes in the new slot in AtRewriteTable() aren't > necessarily set to isnull=true. So to trigger the problem, one needs a > rewrite triggered by *another* column (otherwise we'll not hit this > path), combined with a new column that doesn't have a default value. I > think that's probably my bug. > > This seems to fix the problem: > > diff --git i/src/backend/commands/tablecmds.c w/src/backend/commands/tablecmds.c > index 05593f33162..6f72b08a87d 100644 > --- i/src/backend/commands/tablecmds.c > +++ w/src/backend/commands/tablecmds.c > @@ -4890,6 +4890,14 @@ 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's necessary as tab->newvals will not contain an > + * expression for columns with a NULL default. > + */ > + ExecStoreAllNullTuple(newslot); > } Pushed, after adding some tests. Greetings, Andres Freund