Hackers,

This patch adds subtransaction support into the storage manager.  Files
created or dropped inside a subtransaction are correctly dealt with at
subtransaction commit or abort.

This works:
create table foo (a int);
create table foo2 (a int);
begin;
        begin;
                create table bar (a int);
                select relfilenode, relname from pg_class where relname in ('foo', 
'bar');
                drop table foo2;
        rollback;
        drop table foo;
        create table baz (a int);
        select relfilenode, relname from pg_class where relname='baz';
commit;

At this point, the files for "bar" and "foo" have disappeared, while
"foo2" and "baz" remain.  (Note however that the catalog entries are not
correct -- this is because we don't have correctly recorded results in
pg_clog.)

While making this I realized I had made a mistake regarding portal
memory, so I also correct it with this patch.  As a side effect, the
following works;

begin;
        begin;
                declare foo cursor for select 1;
        commit;
        begin;
                declare bar cursor for select 1;
        rollback;
        fetch all from foo;             -- returns 1 row
        fetch all from bar;             -- no such cursor
rollback;

(This patch will only apply cleanly with the previous patch applied.)



Still missing:

- support for prepared statements, async notifies.  Easy.
- support for on commit actions.  Not sure.
- support for deferred triggers.  Not so easy, maybe hard.
- correct LWLock handling.  Should be easy (release them all on abort)
- correct regular lock handling.  Not so easy.
- pg_clog/pg_subtrans.  Need a solution.


PS: somehow I managed to get tired of the phrase "nested transactions"
and I'm using the term "subtransactions" instead.  In my head they are
the same thing ...

-- 
Alvaro Herrera (<alvherre[a]dcc.uchile.cl>)
Hi! I'm a .signature virus!
cp me into your .signature file to help me spread!
diff -cr --exclude-from=diff-ignore 08simple/src/backend/access/transam/xact.c 
10smgr/src/backend/access/transam/xact.c
*** 08simple/src/backend/access/transam/xact.c  2004-04-20 01:25:52.000000000 -0400
--- 10smgr/src/backend/access/transam/xact.c    2004-04-25 13:34:13.376961237 -0400
***************
*** 202,207 ****
--- 202,208 ----
  
  static void AtSubStart_Memory(void);
  static void AtSubCommit_Memory(void);
+ static void AtSubAbort_Memory(void);
  static void AtSubCleanup_Memory(void);
  
  #else /* SUBTRANSACTIONS */
***************
*** 382,387 ****
--- 383,434 ----
  
  
  /*
+  * TransactionGetPendingDeletes
+  */
+ List *
+ TransactionGetPendingDeletes(void)
+ {
+       TransactionState s = CurrentTransactionState;
+ 
+       return s->pendingDeletes;
+ }
+ 
+ /*
+  * TransactionSetPendingDeletes
+  */
+ void
+ TransactionSetPendingDeletes(List *pending)
+ {
+       TransactionState s = CurrentTransactionState;
+ 
+       s->pendingDeletes = pending;
+ }
+ 
+ /*
+  * TransactionGetParentPendingDeletes
+  */
+ List *
+ TransactionGetParentPendingDeletes(void)
+ {
+       TransactionState s = CurrentTransactionState;
+ 
+       Assert(s->parent != NULL);
+       return s->parent->pendingDeletes;
+ }
+ 
+ /*
+  * TransactionSetParentPendingDeletes
+  */
+ void
+ TransactionSetParentPendingDeletes(List *pending)
+ {
+       TransactionState s = CurrentTransactionState;
+ 
+       Assert(s->parent != NULL);
+       s->parent->pendingDeletes = pending;
+ }
+ 
+ /*
   *    TransactionIdIsCurrentTransactionId
   *
   *    During bootstrap, we cheat and say "it's not my transaction ID" even though
***************
*** 479,484 ****
--- 526,533 ----
  static void
  AtStart_Memory(void)
  {
+       TransactionState s = CurrentTransactionState;
+ 
        /*
         * We shouldn't have a transaction context already.
         */
***************
*** 507,512 ****
--- 556,563 ----
                                                                                  
ALLOCSET_DEFAULT_MINSIZE,
                                                                                  
ALLOCSET_DEFAULT_INITSIZE,
                                                                                  
ALLOCSET_DEFAULT_MAXSIZE);
+ 
+       s->commitContext = CommitContext;
  }
  
  #ifdef SUBTRANSACTIONS
***************
*** 537,542 ****
--- 588,595 ----
                                                                                  
ALLOCSET_DEFAULT_MINSIZE,
                                                                                  
ALLOCSET_DEFAULT_INITSIZE,
                                                                                  
ALLOCSET_DEFAULT_MAXSIZE);
+ 
+       s->commitContext = CommitContext;
  }
  #endif /* SUBTRANSACTIONS */
  
***************
*** 884,889 ****
--- 937,954 ----
                MemoryContextSwitchTo(TopMemoryContext);
  }
  
+ #ifdef SUBTRANSACTIONS
+ /*
+  * AtSubAbort_Memory
+  */
+ static void
+ AtSubAbort_Memory(void)
+ {
+       Assert(TopTransactionContext != NULL);
+ 
+       MemoryContextSwitchTo(TopTransactionContext);
+ }
+ #endif
  
  /* ----------------------------------------------------------------
   *                                            CleanupTransaction stuff
***************
*** 1002,1007 ****
--- 1067,1073 ----
         * progress"
         */
        s->state = TRANS_INPROGRESS;
+       ShowTransactionState("StartTransaction");
  
  }
  
***************
*** 1013,1018 ****
--- 1079,1086 ----
  {
        TransactionState s = CurrentTransactionState;
  
+       ShowTransactionState("CommitTransaction");
+ 
        /*
         * check the current transaction state
         */
***************
*** 1267,1274 ****
  {
        TransactionState s = CurrentTransactionState;
  
-       ShowTransactionState("StartTransactionCommand");
- 
        switch (s->blockState)
        {
                        /*
--- 1335,1340 ----
***************
*** 1321,1327 ****
         */
        Assert(TopTransactionContext != NULL);
        MemoryContextSwitchTo(TopTransactionContext);
-       ShowTransactionState("End StartTransactionCommand");
  }
  
  /*
--- 1387,1392 ----
***************
*** 1331,1337 ****
  CommitTransactionCommand(void)
  {
        TransactionState s = CurrentTransactionState;
-       ShowTransactionState("CommitTransactionCommand");
  
        switch (s->blockState)
        {
--- 1396,1401 ----
***************
*** 1471,1477 ****
                        }
                        break;
        }
-       ShowTransactionState("End CommitTransactionCommand");
  }
  
  /*
--- 1535,1540 ----
***************
*** 1482,1489 ****
  {
        TransactionState s = CurrentTransactionState;
  
-       ShowTransactionState("AbortCurrentTransaction");
- 
        switch (s->blockState)
        {
                /*
--- 1545,1550 ----
***************
*** 1599,1605 ****
                                AbortTransaction();
                        break;
        }
-       ShowTransactionState("End AbortCurrentTransaction");
  }
  
  /*
--- 1660,1665 ----
***************
*** 2134,2144 ****
  void
  StartSubTransaction(void)
  {
!       ShowTransactionState("StartSubTransaction");
        
        /* Initialize the memory subsystem */
        AtSubStart_Memory();
  
  }
  
  /*
--- 2194,2212 ----
  void
  StartSubTransaction(void)
  {
!       TransactionState s = CurrentTransactionState;
! 
!       /*
!        * generate a new transaction id
!        */
!       s->transactionIdData = GetNewTransactionId();
! 
!       CommandCounterIncrement();
        
        /* Initialize the memory subsystem */
        AtSubStart_Memory();
  
+       ShowTransactionState("StartSubTransaction");
  }
  
  /*
***************
*** 2147,2154 ****
--- 2215,2230 ----
  void
  CommitSubTransaction(void)
  {
+       TransactionState s = CurrentTransactionState;
        ShowTransactionState("CommitSubTransaction");
  
+       CommandCounterIncrement();
+ 
+       Assert(s->parent != NULL);
+ 
+       smgrCommitSubTransaction();
+ 
+       AtSubCommit_Portals(s->parent->transactionIdData);
        AtSubCommit_Memory();
  }
  
***************
*** 2159,2164 ****
--- 2235,2248 ----
  AbortSubTransaction(void)
  {
        ShowTransactionState("AbortSubTransaction");
+ 
+       AtSubAbort_Portals();
+       AtSubAbort_Memory();
+ 
+       /* I'm not sure this is needed. */
+       CommandCounterIncrement();
+ 
+       smgrAbortSubTransaction();
  }
  
  /*
***************
*** 2169,2174 ****
--- 2253,2259 ----
  {
        ShowTransactionState("CleanupSubTransaction");
  
+       AtSubCleanup_Portals();
        AtSubCleanup_Memory();
  }
  
***************
*** 2186,2201 ****
         * Make sure the transaction state node is in a long-lived context
         */
        old_cxt = MemoryContextSwitchTo(TopMemoryContext);
-       parent = (TransactionState) palloc(sizeof(TransactionStateData));
-       MemoryContextSwitchTo(old_cxt);
  
        memcpy(parent, s, sizeof(TransactionStateData));
  
-       parent->commitContext = CommitContext;
        s->parent = parent;
        s->nestingLevel = s->parent->nestingLevel + 1;
        s->commandId = s->parent->commandId;
!       CommandCounterIncrement();
  }
  
  /*
--- 2271,2285 ----
         * Make sure the transaction state node is in a long-lived context
         */
        old_cxt = MemoryContextSwitchTo(TopMemoryContext);
  
+       parent = (TransactionState) palloc(sizeof(TransactionStateData));
        memcpy(parent, s, sizeof(TransactionStateData));
  
        s->parent = parent;
        s->nestingLevel = s->parent->nestingLevel + 1;
        s->commandId = s->parent->commandId;
! 
!       MemoryContextSwitchTo(old_cxt);
  }
  
  /*
***************
*** 2215,2221 ****
  
        memcpy(s, p, sizeof(TransactionStateData));
        CommitContext = s->commitContext;
-       CommandCounterIncrement();
  
        /* Free the old parent structure */
        pfree(p);
--- 2299,2304 ----
***************
*** 2227,2234 ****
  void
  ShowTransactionState(char *str)
  {
        elog(DEBUG2, "%s", str);
!     ShowTransactionStateRec(CurrentTransactionState, 0);
  }
  
  /*
--- 2310,2319 ----
  void
  ShowTransactionState(char *str)
  {
+       TransactionState s = CurrentTransactionState;
+ 
        elog(DEBUG2, "%s", str);
!     ShowTransactionStateRec(CurrentTransactionState, 2 * s->nestingLevel);
  }
  
  /*
***************
*** 2237,2262 ****
  void
  ShowTransactionStateRec(TransactionState s, int indent)
  {
!       char *i;
!       char *blockState = BlockStateAsString(s->blockState);
!       char *state      = TransStateAsString(s->state);
! 
!       i = (char *)malloc(sizeof(char) * indent + 1);
!       memset(i, ' ', indent);
!       memset(i + indent, '\0', 1);
  
!       elog(DEBUG1, "%sblockState: %s; state: %s, tid/cid: %u/%u, nestlvl: %d",
!                       i,
                        blockState,
                        state,
                        (unsigned int)s->transactionIdData,
!                       (unsigned int)s->commandId ,
                        s->nestingLevel);
!       free(i);
        pfree(blockState);
        pfree(state);
-       if (s->parent)
-               ShowTransactionStateRec(s->parent, indent + 1);
  }
  
  #endif /* SUBTRANSACTIONS */
--- 2322,2348 ----
  void
  ShowTransactionStateRec(TransactionState s, int indent)
  {
!       char   *blockState = BlockStateAsString(s->blockState);
!       char   *state      = TransStateAsString(s->state);
!       char   *tmp;
!       
!       if (s->parent)
!               ShowTransactionStateRec(s->parent, indent - 2);
  
!       tmp = (char *)malloc(sizeof(char) * indent + 1);
!       memset(tmp, ' ', indent);
!       memset(tmp + indent, '\0', 1);
! 
!       elog(DEBUG2, "%sblockState: %s; state: %s, xid/cid: %u/%u, nestlvl: %d",
!                       tmp,
                        blockState,
                        state,
                        (unsigned int)s->transactionIdData,
!                       (unsigned int)s->commandId,
                        s->nestingLevel);
!       free(tmp);
        pfree(blockState);
        pfree(state);
  }
  
  #endif /* SUBTRANSACTIONS */
diff -cr --exclude-from=diff-ignore 08simple/src/backend/storage/smgr/smgr.c 
10smgr/src/backend/storage/smgr/smgr.c
*** 08simple/src/backend/storage/smgr/smgr.c    2004-04-19 17:10:12.000000000 -0400
--- 10smgr/src/backend/storage/smgr/smgr.c      2004-04-25 12:37:32.247548626 -0400
***************
*** 17,22 ****
--- 17,23 ----
   */
  #include "postgres.h"
  
+ #include "access/xact.h"
  #include "storage/bufmgr.h"
  #include "storage/freespace.h"
  #include "storage/ipc.h"
***************
*** 77,98 ****
   * executed immediately, but is just entered in the list.  When and if
   * the transaction commits, we can delete the physical file.
   *
!  * NOTE: the list is kept in TopMemoryContext to be sure it won't disappear
!  * unbetimes.  It'd probably be OK to keep it in TopTransactionContext,
!  * but I'm being paranoid.
   */
  
! typedef struct PendingRelDelete
  {
        RelFileNode relnode;            /* relation that may need to be deleted */
        int                     which;                  /* which storage manager? */
        bool            isTemp;                 /* is it a temporary relation? */
        bool            atCommit;               /* T=delete at commit; F=delete at 
abort */
!       struct PendingRelDelete *next;          /* linked-list link */
! } PendingRelDelete;
! 
! static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
  
  
  /*
   * Declarations for smgr-related XLOG records
--- 78,95 ----
   * executed immediately, but is just entered in the list.  When and if
   * the transaction commits, we can delete the physical file.
   *
!  * The list is kept in CommitContext.
   */
  
! typedef struct PendingRelDeleteData
  {
        RelFileNode relnode;            /* relation that may need to be deleted */
        int                     which;                  /* which storage manager? */
        bool            isTemp;                 /* is it a temporary relation? */
        bool            atCommit;               /* T=delete at commit; F=delete at 
abort */
! } PendingRelDeleteData;
  
+ typedef PendingRelDeleteData *PendingRelDelete;
  
  /*
   * Declarations for smgr-related XLOG records
***************
*** 300,306 ****
        XLogRecPtr              lsn;
        XLogRecData             rdata;
        xl_smgr_create  xlrec;
!       PendingRelDelete *pending;
  
        if (! (*(smgrsw[reln->smgr_which].smgr_create)) (reln, isRedo))
                ereport(ERROR,
--- 297,304 ----
        XLogRecPtr              lsn;
        XLogRecData             rdata;
        xl_smgr_create  xlrec;
!       PendingRelDelete pending;
!       MemoryContext   old_cxt;
  
        if (! (*(smgrsw[reln->smgr_which].smgr_create)) (reln, isRedo))
                ereport(ERROR,
***************
*** 326,340 ****
  
        lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE | XLOG_NO_TRAN, &rdata);
  
        /* Add the relation to the list of stuff to delete at abort */
!       pending = (PendingRelDelete *)
!               MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
        pending->relnode = reln->smgr_rnode;
        pending->which = reln->smgr_which;
        pending->isTemp = isTemp;
        pending->atCommit = false;      /* delete if abort */
!       pending->next = pendingDeletes;
!       pendingDeletes = pending;
  }
  
  /*
--- 324,342 ----
  
        lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE | XLOG_NO_TRAN, &rdata);
  
+       old_cxt = MemoryContextSwitchTo(CommitContext);
+ 
        /* Add the relation to the list of stuff to delete at abort */
!       pending = (PendingRelDelete) palloc(sizeof(PendingRelDeleteData));
        pending->relnode = reln->smgr_rnode;
        pending->which = reln->smgr_which;
        pending->isTemp = isTemp;
        pending->atCommit = false;      /* delete if abort */
! 
!       TransactionSetPendingDeletes(lcons(pending,
!                               TransactionGetPendingDeletes()));
! 
!       MemoryContextSwitchTo(old_cxt);
  }
  
  /*
***************
*** 348,364 ****
  void
  smgrscheduleunlink(SMgrRelation reln, bool isTemp)
  {
!       PendingRelDelete *pending;
  
        /* Add the relation to the list of stuff to delete at commit */
!       pending = (PendingRelDelete *)
!               MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
        pending->relnode = reln->smgr_rnode;
        pending->which = reln->smgr_which;
        pending->isTemp = isTemp;
        pending->atCommit = true;       /* delete if commit */
!       pending->next = pendingDeletes;
!       pendingDeletes = pending;
  
        /*
         * NOTE: if the relation was created in this transaction, it will now
--- 350,369 ----
  void
  smgrscheduleunlink(SMgrRelation reln, bool isTemp)
  {
!       PendingRelDelete pending;
!       MemoryContext    old_cxt;
! 
!       old_cxt = MemoryContextSwitchTo(CommitContext);
  
        /* Add the relation to the list of stuff to delete at commit */
!       pending = (PendingRelDelete) palloc(sizeof(PendingRelDeleteData));
        pending->relnode = reln->smgr_rnode;
        pending->which = reln->smgr_which;
        pending->isTemp = isTemp;
        pending->atCommit = true;       /* delete if commit */
! 
!       TransactionSetPendingDeletes(lcons(pending,
!                               TransactionGetPendingDeletes()));
  
        /*
         * NOTE: if the relation was created in this transaction, it will now
***************
*** 372,377 ****
--- 377,384 ----
  
        /* Now close the file and throw away the hashtable entry */
        smgrclose(reln);
+ 
+       MemoryContextSwitchTo(old_cxt);
  }
  
  /*
***************
*** 573,590 ****
  void
  smgrDoPendingDeletes(bool isCommit)
  {
!       while (pendingDeletes != NULL)
        {
!               PendingRelDelete *pending = pendingDeletes;
  
-               pendingDeletes = pending->next;
                if (pending->atCommit == isCommit)
                        smgr_internal_unlink(pending->relnode,
                                                                 pending->which,
                                                                 pending->isTemp,
                                                                 false);
-               pfree(pending);
        }
  }
  
  /*
--- 580,640 ----
  void
  smgrDoPendingDeletes(bool isCommit)
  {
!       List *p;
! 
!       foreach (p, TransactionGetPendingDeletes())
        {
!               PendingRelDelete pending = lfirst(p);
  
                if (pending->atCommit == isCommit)
                        smgr_internal_unlink(pending->relnode,
                                                                 pending->which,
                                                                 pending->isTemp,
                                                                 false);
        }
+ 
+       TransactionSetPendingDeletes(NIL);
+ }
+ 
+ /*
+  * smgrAbortSubTransaction() --- Take care of subtransaction abort.
+  *
+  * Delete created relations and forget about deleted relations.
+  * We don't care about these operations anymore because we know this
+  * subtransaction will not commit.
+  */
+ void
+ smgrAbortSubTransaction(void)
+ {
+       List *p;
+ 
+       foreach (p, TransactionGetPendingDeletes())
+       {
+               PendingRelDelete pending = lfirst(p);
+ 
+               if (pending->atCommit == false)
+                       smgr_internal_unlink(pending->relnode,
+                                                                pending->which,
+                                                                pending->isTemp,
+                                                                false);
+       }
+ }
+ 
+ /*
+  * smgrCommitSubTransaction() --- Take care of subtransaction commit.
+  *
+  * Reassign all items in the pending deletes list to the parent transaction.
+  */
+ void
+ smgrCommitSubTransaction(void)
+ {
+       List *pending,
+            *parentPending;
+ 
+       pending = TransactionGetPendingDeletes();
+       parentPending = TransactionGetParentPendingDeletes();
+ 
+       TransactionSetParentPendingDeletes(nconc(parentPending, pending));
  }
  
  /*
***************
*** 599,609 ****
  {
        int                     nrels;
        RelFileNode *rptr;
!       PendingRelDelete *pending;
  
        nrels = 0;
!       for (pending = pendingDeletes; pending != NULL; pending = pending->next)
        {
                if (pending->atCommit == forCommit)
                        nrels++;
        }
--- 649,661 ----
  {
        int                     nrels;
        RelFileNode *rptr;
!       List            *p;
  
        nrels = 0;
!       foreach (p, TransactionGetPendingDeletes())
        {
+               PendingRelDelete pending = lfirst(p);
+ 
                if (pending->atCommit == forCommit)
                        nrels++;
        }
***************
*** 614,621 ****
        }
        rptr = (RelFileNode *) palloc(nrels * sizeof(RelFileNode));
        *ptr = rptr;
!       for (pending = pendingDeletes; pending != NULL; pending = pending->next)
        {
                if (pending->atCommit == forCommit)
                        *rptr++ = pending->relnode;
        }
--- 666,675 ----
        }
        rptr = (RelFileNode *) palloc(nrels * sizeof(RelFileNode));
        *ptr = rptr;
!       foreach (p, TransactionGetPendingDeletes())
        {
+               PendingRelDelete pending = lfirst(p);
+ 
                if (pending->atCommit == forCommit)
                        *rptr++ = pending->relnode;
        }
diff -cr --exclude-from=diff-ignore 08simple/src/backend/utils/mmgr/portalmem.c 
10smgr/src/backend/utils/mmgr/portalmem.c
*** 08simple/src/backend/utils/mmgr/portalmem.c 2004-04-19 17:10:12.000000000 -0400
--- 10smgr/src/backend/utils/mmgr/portalmem.c   2004-04-25 12:47:46.014641484 -0400
***************
*** 511,513 ****
--- 511,603 ----
                PortalDrop(portal, true);
        }
  }
+ 
+ #ifdef SUBTRANSACTIONS
+ /*
+  * Subtransaction commit handling for portals.
+  *
+  * Reassign all portals created by the current subtransaction to the
+  * parent transaction.
+  */
+ void
+ AtSubCommit_Portals(TransactionId parentXid)
+ {
+       HASH_SEQ_STATUS status;
+       PortalHashEnt *hentry;
+       TransactionId curXid = GetCurrentTransactionId();
+ 
+       hash_seq_init(&status, PortalHashTable);
+ 
+       while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
+       {
+               Portal  portal = hentry->portal;
+ 
+               if (portal->createXact == curXid)
+                       portal->createXact = parentXid;
+       }
+ }
+ 
+ /*
+  * Subtransaction abort handling for portals.
+  *
+  * Deactivate all portals created during to the finishing subtransaction.
+  * Note that per AtSubCommit_Portals, this will catch portals created
+  * in descendents of the finishing subtransaction too.
+  */
+ void
+ AtSubAbort_Portals(void)
+ {
+       HASH_SEQ_STATUS status;
+       PortalHashEnt *hentry;
+       TransactionId curXid = GetCurrentTransactionId();
+ 
+       hash_seq_init(&status, PortalHashTable);
+ 
+       while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
+       {
+               Portal  portal = hentry->portal;
+ 
+               if (portal->createXact != curXid)
+                       continue;
+ 
+               portal->portalActive = false;
+               if (PointerIsValid(portal->cleanup))
+               {
+                       (*portal->cleanup) (portal, true);
+                       portal->cleanup = NULL;
+               }
+       }
+ }
+ 
+ /*
+  * Subtransaction cleanup handling for portals.
+  *
+  * Drop all portals created in the aborting subtransaction and all
+  * its descendents.
+  */
+ void
+ AtSubCleanup_Portals(void)
+ {
+       HASH_SEQ_STATUS status;
+       PortalHashEnt *hentry;
+       TransactionId curXid = GetCurrentTransactionId();
+ 
+       hash_seq_init(&status, PortalHashTable);
+ 
+       while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
+       {
+               Portal          portal = hentry->portal;
+ 
+               if (portal->createXact != curXid)
+                       continue;
+ 
+               /*
+                * Let's just make sure no one's active...
+                */
+               portal->portalActive = false;
+ 
+               /* Zap it with prejudice. */
+               PortalDrop(portal, true);
+       }
+ }
+ #endif /* SUBTRANSACTIONS */
diff -cr --exclude-from=diff-ignore 08simple/src/include/access/xact.h 
10smgr/src/include/access/xact.h
*** 08simple/src/include/access/xact.h  2004-04-20 01:22:20.000000000 -0400
--- 10smgr/src/include/access/xact.h    2004-04-25 12:45:54.782938704 -0400
***************
*** 149,154 ****
--- 149,158 ----
  extern CommandId GetCurrentCommandId(void);
  extern AbsoluteTime GetCurrentTransactionStartTime(void);
  extern AbsoluteTime GetCurrentTransactionStartTimeUsec(int *usec);
+ extern List *TransactionGetPendingDeletes(void);
+ extern void TransactionSetPendingDeletes(List *);
+ extern List *TransactionGetParentPendingDeletes(void);
+ extern void TransactionSetParentPendingDeletes(List *);
  extern bool TransactionIdIsCurrentTransactionId(TransactionId xid);
  extern bool CommandIdIsCurrentCommandId(CommandId cid);
  extern void CommandCounterIncrement(void);
diff -cr --exclude-from=diff-ignore 08simple/src/include/storage/smgr.h 
10smgr/src/include/storage/smgr.h
*** 08simple/src/include/storage/smgr.h 2004-04-19 17:10:13.000000000 -0400
--- 10smgr/src/include/storage/smgr.h   2004-04-25 12:37:33.222659985 -0400
***************
*** 61,66 ****
--- 61,68 ----
  extern BlockNumber smgrnblocks(SMgrRelation reln);
  extern BlockNumber smgrtruncate(SMgrRelation reln, BlockNumber nblocks);
  extern void smgrDoPendingDeletes(bool isCommit);
+ extern void smgrAbortSubTransaction(void);
+ extern void smgrCommitSubTransaction(void);
  extern int    smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr);
  extern void smgrcommit(void);
  extern void smgrabort(void);
diff -cr --exclude-from=diff-ignore 08simple/src/include/utils/portal.h 
10smgr/src/include/utils/portal.h
*** 08simple/src/include/utils/portal.h 2004-04-19 17:10:13.000000000 -0400
--- 10smgr/src/include/utils/portal.h   2004-04-25 12:47:06.368113808 -0400
***************
*** 167,172 ****
--- 167,177 ----
  extern void AtCommit_Portals(void);
  extern void AtAbort_Portals(void);
  extern void AtCleanup_Portals(void);
+ #ifdef SUBTRANSACTIONS
+ extern void AtSubCommit_Portals(TransactionId);
+ extern void AtSubAbort_Portals(void);
+ extern void AtSubCleanup_Portals(void);
+ #endif /* SUBTRANSACTIONS */
  extern Portal CreatePortal(const char *name, bool allowDup, bool dupSilent);
  extern Portal CreateNewPortal(void);
  extern void PortalDrop(Portal portal, bool isError);
---------------------------(end of broadcast)---------------------------
TIP 7: don't forget to increase your free space map settings

Reply via email to