fix-AfterTriggerExecute-2.patch

application/octet-stream

Filename: fix-AfterTriggerExecute-2.patch
Type: application/octet-stream
Part: 0
Message: Re: BUG #16139: Assertion fails on INSERT into a postgres_fdw' table with two AFTER INSERT triggers

Patch

Format: context
File+
contrib/postgres_fdw/expected/postgres_fdw.out 30 0
contrib/postgres_fdw/sql/postgres_fdw.sql 16 0
doc/src/sgml/trigger.sgml 8 0
src/backend/commands/trigger.c 19 0
*** a/contrib/postgres_fdw/expected/postgres_fdw.out
--- b/contrib/postgres_fdw/expected/postgres_fdw.out
***************
*** 6459,6464 **** DROP TRIGGER trig_row_after ON rem1;
--- 6459,6493 ----
  DROP TRIGGER trig_stmt_before ON rem1;
  DROP TRIGGER trig_stmt_after ON rem1;
  DELETE from rem1;
+ CREATE TRIGGER trig_row_after1
+ AFTER INSERT OR UPDATE OR DELETE ON rem1
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ CREATE TRIGGER trig_row_after2
+ AFTER INSERT OR UPDATE OR DELETE ON rem1
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ insert into rem1 values(1,'insert');
+ NOTICE:  trig_row_after1(23, skidoo) AFTER ROW INSERT ON rem1
+ NOTICE:  NEW: (1,insert)
+ NOTICE:  trig_row_after2(23, skidoo) AFTER ROW INSERT ON rem1
+ NOTICE:  NEW: (1,insert)
+ update rem1 set f2  = 'update' where f1 = 1;
+ NOTICE:  trig_row_after1(23, skidoo) AFTER ROW UPDATE ON rem1
+ NOTICE:  OLD: (1,insert),NEW: (1,update)
+ NOTICE:  trig_row_after2(23, skidoo) AFTER ROW UPDATE ON rem1
+ NOTICE:  OLD: (1,insert),NEW: (1,update)
+ update rem1 set f2 = f2 || f2;
+ NOTICE:  trig_row_after1(23, skidoo) AFTER ROW UPDATE ON rem1
+ NOTICE:  OLD: (1,update),NEW: (1,updateupdate)
+ NOTICE:  trig_row_after2(23, skidoo) AFTER ROW UPDATE ON rem1
+ NOTICE:  OLD: (1,update),NEW: (1,updateupdate)
+ delete from rem1;
+ NOTICE:  trig_row_after1(23, skidoo) AFTER ROW DELETE ON rem1
+ NOTICE:  OLD: (1,updateupdate)
+ NOTICE:  trig_row_after2(23, skidoo) AFTER ROW DELETE ON rem1
+ NOTICE:  OLD: (1,updateupdate)
+ -- cleanup
+ DROP TRIGGER trig_row_after1 ON rem1;
+ DROP TRIGGER trig_row_after2 ON rem1;
  -- Test WHEN conditions
  CREATE TRIGGER trig_row_before_insupd
  BEFORE INSERT OR UPDATE ON rem1
***************
*** 6689,6695 **** NOTICE:  trig_row_after(23, skidoo) AFTER ROW INSERT ON rem1
  NOTICE:  NEW: (13,"test triggered !")
    ctid  
  --------
!  (0,29)
  (1 row)
  
  -- cleanup
--- 6718,6724 ----
  NOTICE:  NEW: (13,"test triggered !")
    ctid  
  --------
!  (0,32)
  (1 row)
  
  -- cleanup
*** a/contrib/postgres_fdw/sql/postgres_fdw.sql
--- b/contrib/postgres_fdw/sql/postgres_fdw.sql
***************
*** 1485,1490 **** DROP TRIGGER trig_stmt_after ON rem1;
--- 1485,1506 ----
  
  DELETE from rem1;
  
+ CREATE TRIGGER trig_row_after1
+ AFTER INSERT OR UPDATE OR DELETE ON rem1
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ 
+ CREATE TRIGGER trig_row_after2
+ AFTER INSERT OR UPDATE OR DELETE ON rem1
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ 
+ insert into rem1 values(1,'insert');
+ update rem1 set f2  = 'update' where f1 = 1;
+ update rem1 set f2 = f2 || f2;
+ delete from rem1;
+ 
+ -- cleanup
+ DROP TRIGGER trig_row_after1 ON rem1;
+ DROP TRIGGER trig_row_after2 ON rem1;
  
  -- Test WHEN conditions
  
*** a/doc/src/sgml/trigger.sgml
--- b/doc/src/sgml/trigger.sgml
***************
*** 511,518 **** typedef struct TriggerData
      HeapTuple        tg_trigtuple;
      HeapTuple        tg_newtuple;
      Trigger         *tg_trigger;
!     Buffer           tg_trigtuplebuf;
!     Buffer           tg_newtuplebuf;
      Tuplestorestate *tg_oldtable;
      Tuplestorestate *tg_newtable;
  } TriggerData;
--- 511,518 ----
      HeapTuple        tg_trigtuple;
      HeapTuple        tg_newtuple;
      Trigger         *tg_trigger;
!     TupleTableSlot  *tg_trigslot;
!     TupleTableSlot  *tg_newslot;
      Tuplestorestate *tg_oldtable;
      Tuplestorestate *tg_newtable;
  } TriggerData;
***************
*** 714,734 **** typedef struct Trigger
       </varlistentry>
  
       <varlistentry>
!       <term><structfield>tg_trigtuplebuf</structfield></term>
        <listitem>
         <para>
!         The buffer containing <structfield>tg_trigtuple</structfield>, or <symbol>InvalidBuffer</symbol> if there
!         is no such tuple or it is not stored in a disk buffer.
         </para>
        </listitem>
       </varlistentry>
  
       <varlistentry>
!       <term><structfield>tg_newtuplebuf</structfield></term>
        <listitem>
         <para>
!         The buffer containing <structfield>tg_newtuple</structfield>, or <symbol>InvalidBuffer</symbol> if there
!         is no such tuple or it is not stored in a disk buffer.
         </para>
        </listitem>
       </varlistentry>
--- 714,734 ----
       </varlistentry>
  
       <varlistentry>
!       <term><structfield>tg_trigslot</structfield></term>
        <listitem>
         <para>
!         The slot containing <structfield>tg_trigtuple</structfield>,
!         or a <symbol>NULL</symbol> pointer if there is no such tuple.
         </para>
        </listitem>
       </varlistentry>
  
       <varlistentry>
!       <term><structfield>tg_newslot</structfield></term>
        <listitem>
         <para>
!         The slot containing <structfield>tg_newtuple</structfield>,
!         or a <symbol>NULL</symbol> pointer if there is no such tuple.
         </para>
        </listitem>
       </varlistentry>
*** a/src/backend/commands/trigger.c
--- b/src/backend/commands/trigger.c
***************
*** 4255,4266 **** AfterTriggerExecute(EState *estate,
  			LocTriggerData.tg_trigtuple =
  				ExecFetchSlotHeapTuple(trig_tuple_slot1, true, &should_free_trig);
  
! 			LocTriggerData.tg_newslot = trig_tuple_slot2;
! 			LocTriggerData.tg_newtuple =
! 				((evtshared->ats_event & TRIGGER_EVENT_OPMASK) ==
! 				 TRIGGER_EVENT_UPDATE) ?
! 				ExecFetchSlotHeapTuple(trig_tuple_slot2, true, &should_free_new) : NULL;
! 
  			break;
  
  		default:
--- 4255,4271 ----
  			LocTriggerData.tg_trigtuple =
  				ExecFetchSlotHeapTuple(trig_tuple_slot1, true, &should_free_trig);
  
! 			if ((evtshared->ats_event & TRIGGER_EVENT_OPMASK) ==
! 				TRIGGER_EVENT_UPDATE)
! 			{
! 				LocTriggerData.tg_newslot = trig_tuple_slot2;
! 				LocTriggerData.tg_newtuple =
! 					ExecFetchSlotHeapTuple(trig_tuple_slot2, true, &should_free_new);
! 			}
! 			else
! 			{
! 				LocTriggerData.tg_newtuple = NULL;
! 			}
  			break;
  
  		default:
***************
*** 4355,4364 **** AfterTriggerExecute(EState *estate,
  	if (should_free_new)
  		heap_freetuple(LocTriggerData.tg_newtuple);
  
! 	if (LocTriggerData.tg_trigslot)
! 		ExecClearTuple(LocTriggerData.tg_trigslot);
! 	if (LocTriggerData.tg_newslot)
! 		ExecClearTuple(LocTriggerData.tg_newslot);
  
  	/*
  	 * If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count
--- 4360,4373 ----
  	if (should_free_new)
  		heap_freetuple(LocTriggerData.tg_newtuple);
  
! 	/* don't clear slots' contents if foreign table */
! 	if (trig_tuple_slot1 == NULL)
! 	{
! 		if (LocTriggerData.tg_trigslot)
! 			ExecClearTuple(LocTriggerData.tg_trigslot);
! 		if (LocTriggerData.tg_newslot)
! 			ExecClearTuple(LocTriggerData.tg_newslot);
! 	}
  
  	/*
  	 * If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count