Revised Patch to allow multiple table locks in "Unison" - Mailing list pgsql-patches

From Neil Padgett
Subject Revised Patch to allow multiple table locks in "Unison"
Date
Msg-id 3B5F6407.81923B6A@redhat.com
Whole thread Raw
Responses Re: Revised Patch to allow multiple table locks in "Unison"  (Bruce Momjian <pgman@candle.pha.pa.us>)
List pgsql-patches
Here is the revised patch to allow the syntax:

LOCK a,b,c;

It uses the method I described as the "new" method in a previous
message.

Neil

--
Neil Padgett
Red Hat Canada Ltd.                       E-Mail:  npadgett@redhat.com
2323 Yonge Street, Suite #300,
Toronto, ON  M4P 2C9

Index: src/backend/commands/command.c
===================================================================
RCS file:
/home/projects/pgsql/cvsroot/pgsql/src/backend/commands/command.c,v
retrieving revision 1.136
diff -c -p -r1.136 command.c
*** src/backend/commands/command.c    2001/07/16 05:06:57    1.136
--- src/backend/commands/command.c    2001/07/26 00:02:24
*************** needs_toast_table(Relation rel)
*** 1994,2019 ****
  void
  LockTableCommand(LockStmt *lockstmt)
  {
!     Relation    rel;
!     int            aclresult;

!     rel = heap_openr(lockstmt->relname, NoLock);

!     if (rel->rd_rel->relkind != RELKIND_RELATION)
!         elog(ERROR, "LOCK TABLE: %s is not a table", lockstmt->relname);

!     if (lockstmt->mode == AccessShareLock)
!         aclresult = pg_aclcheck(lockstmt->relname, GetUserId(), ACL_SELECT);
!     else
!         aclresult = pg_aclcheck(lockstmt->relname, GetUserId(),
!                                 ACL_UPDATE | ACL_DELETE);

!     if (aclresult != ACLCHECK_OK)
!         elog(ERROR, "LOCK TABLE: permission denied");

!     LockRelation(rel, lockstmt->mode);

!     heap_close(rel, NoLock);    /* close rel, keep lock */
  }


--- 1994,2170 ----
  void
  LockTableCommand(LockStmt *lockstmt)
  {
!     int         relCnt;

!     relCnt = length(lockstmt -> rellist);

!     /* Handle a single relation lock specially to avoid overhead on
likely the
!        most common case */

!     if(relCnt == 1)
!     {

!         /* Locking a single table */

!         Relation    rel;
!         int            aclresult;
!         char *relname;

!         relname = strVal(lfirst(lockstmt->rellist));
!
!         freeList(lockstmt->rellist);
!
!         rel = heap_openr(relname, NoLock);
!
!         if (rel->rd_rel->relkind != RELKIND_RELATION)
!             elog(ERROR, "LOCK TABLE: %s is not a table", relname);
!
!         if (lockstmt->mode == AccessShareLock)
!             aclresult = pg_aclcheck(relname, GetUserId(),
!                                     ACL_SELECT);
!         else
!             aclresult = pg_aclcheck(relname, GetUserId(),
!                                     ACL_UPDATE | ACL_DELETE);
!
!         if (aclresult != ACLCHECK_OK)
!             elog(ERROR, "LOCK TABLE: permission denied");
!
!         LockRelation(rel, lockstmt->mode);
!
!         pfree(relname);
!
!         heap_close(rel, NoLock);    /* close rel, keep lock */
!     }
!     else
!     {
!         List *p;
!         Relation *relationArray;
!         Relation *pRel;
!         Relation *blockingLockTarget;
!         bool allLocked = false;
!
!         /* Locking multiple tables */
!
!         /* Create an array of relations */
!
!         relationArray = palloc(relCnt * sizeof(Relation));
!         blockingLockTarget = relationArray;
!
!         pRel = relationArray;
!
!         /* Iterate over the list and populate the relation array */
!
!         foreach(p, lockstmt->rellist)
!         {
!             char *relname = strVal(lfirst(p));
!             int            aclresult;
!
!             *pRel = heap_openr(relname, NoLock);
!
!             if ((*pRel)->rd_rel->relkind != RELKIND_RELATION)
!                 elog(ERROR, "LOCK TABLE: %s is not a table",
!                      relname);
!
!             if (lockstmt->mode == AccessShareLock)
!                 aclresult = pg_aclcheck(relname, GetUserId(),
!                                         ACL_SELECT);
!             else
!                 aclresult = pg_aclcheck(relname, GetUserId(),
!                                         ACL_UPDATE | ACL_DELETE);
!
!             if (aclresult != ACLCHECK_OK)
!                 elog(ERROR, "LOCK TABLE: permission denied");
!
!             pRel++;
!             pfree(relname);
!         }
!
!         /* Now acquire locks on all the relations */
!
!         while(!allLocked)
!         {
!
!             allLocked = true;
!
!             /* Lock the blocking lock target (initially the first lock
!                in the user's list */
!
!             LockRelation(*blockingLockTarget, lockstmt->mode);
!
!             /* Lock is now obtained on the lock target, now grab locks in a
!                non-blocking way on the rest of the list */
!
!             for(pRel = blockingLockTarget + 1;
!                 pRel < relationArray + relCnt;
!                 pRel++)
!             {
!                 if(!ConditionalLockRelation(*pRel, lockstmt->mode))
!                 {
!                     Relation *pRelUnlock;
!
!                     /* Flag that all relations were not successfully
!                        locked */
!
!                     allLocked = false;
!
!                     /* A lock wasn't obtained, so unlock all others */
!
!                     for(pRelUnlock = blockingLockTarget;
!                         pRelUnlock < pRel;
!                         pRelUnlock++)
!                         UnlockRelation(*pRelUnlock, lockstmt->mode);
!
!                     /* Next time, do our blocking lock on the contended lock */
!
!                     blockingLockTarget = pRel;
!
!                     /* Now break out and try again */
!
!                     break;
!                 }
!             }
!
!             /* Now, lock anything before the blocking lock target in the lock
!                target array, if we were successful in getting locks on
!                everything after and including the blocking target */
!
!             if(allLocked)
!             {
!                 for(pRel = relationArray;
!                     pRel < blockingLockTarget;
!                     pRel++)
!                 {
!                     if(!ConditionalLockRelation(*pRel, lockstmt->mode))
!                     {
!                         Relation *pRelUnlock;
!
!                         /* Flag that all relations were not successfully
!                            locked */
!
!                         allLocked = false;
!
!                         /* Lock wasn't obtained, so unlock all others */
!
!                         for(pRelUnlock = relationArray;
!                             pRelUnlock < pRel;
!                             pRelUnlock++)
!                             UnlockRelation(*pRelUnlock, lockstmt->mode);
!
!                         /* Next time, do our blocking lock on the contended
!                            lock */
!
!                         blockingLockTarget = pRel;
!
!                         /* Now break out and try again */
!
!                         break;
!                     }
!                 }
!             }
!         }
!
!         pfree(relationArray);
!     }
  }


Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file:
/home/projects/pgsql/cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.148
diff -c -p -r1.148 copyfuncs.c
*** src/backend/nodes/copyfuncs.c    2001/07/16 19:07:37    1.148
--- src/backend/nodes/copyfuncs.c    2001/07/26 00:02:24
*************** _copyLockStmt(LockStmt *from)
*** 2425,2432 ****
  {
      LockStmt   *newnode = makeNode(LockStmt);

!     if (from->relname)
!         newnode->relname = pstrdup(from->relname);
      newnode->mode = from->mode;

      return newnode;
--- 2425,2432 ----
  {
      LockStmt   *newnode = makeNode(LockStmt);

!     Node_Copy(from, newnode, rellist);
!
      newnode->mode = from->mode;

      return newnode;
Index: src/backend/nodes/equalfuncs.c
===================================================================
RCS file:
/home/projects/pgsql/cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v
retrieving revision 1.96
diff -c -p -r1.96 equalfuncs.c
*** src/backend/nodes/equalfuncs.c    2001/07/16 19:07:38    1.96
--- src/backend/nodes/equalfuncs.c    2001/07/26 00:02:24
*************** _equalDropUserStmt(DropUserStmt *a, Drop
*** 1283,1289 ****
  static bool
  _equalLockStmt(LockStmt *a, LockStmt *b)
  {
!     if (!equalstr(a->relname, b->relname))
          return false;
      if (a->mode != b->mode)
          return false;
--- 1283,1289 ----
  static bool
  _equalLockStmt(LockStmt *a, LockStmt *b)
  {
!     if (!equal(a->rellist, b->rellist))
          return false;
      if (a->mode != b->mode)
          return false;
Index: src/backend/parser/gram.y
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.238
diff -c -p -r2.238 gram.y
*** src/backend/parser/gram.y    2001/07/16 19:07:40    2.238
--- src/backend/parser/gram.y    2001/07/26 00:02:25
*************** DeleteStmt:  DELETE FROM relation_expr w
*** 3280,3290 ****
                  }
          ;

! LockStmt:    LOCK_P opt_table relation_name opt_lock
                  {
                      LockStmt *n = makeNode(LockStmt);

!                     n->relname = $3;
                      n->mode = $4;
                      $$ = (Node *)n;
                  }
--- 3280,3290 ----
                  }
          ;

! LockStmt:    LOCK_P opt_table relation_name_list opt_lock
                  {
                      LockStmt *n = makeNode(LockStmt);

!                     n->rellist = $3;
                      n->mode = $4;
                      $$ = (Node *)n;
                  }
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file:
/home/projects/pgsql/cvsroot/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.136
diff -c -p -r1.136 parsenodes.h
*** src/include/nodes/parsenodes.h    2001/07/16 19:07:40    1.136
--- src/include/nodes/parsenodes.h    2001/07/26 00:02:26
*************** typedef struct VariableResetStmt
*** 760,766 ****
  typedef struct LockStmt
  {
      NodeTag        type;
!     char       *relname;        /* relation to lock */
      int            mode;            /* lock mode */
  } LockStmt;

--- 760,766 ----
  typedef struct LockStmt
  {
      NodeTag        type;
!     List       *rellist;        /* relation to lock */
      int            mode;            /* lock mode */
  } LockStmt;

Index: src/interfaces/ecpg/preproc/preproc.y
===================================================================
RCS file:
/home/projects/pgsql/cvsroot/pgsql/src/interfaces/ecpg/preproc/preproc.y,v
retrieving revision 1.146
diff -c -p -r1.146 preproc.y
*** src/interfaces/ecpg/preproc/preproc.y    2001/07/16 05:07:00    1.146
--- src/interfaces/ecpg/preproc/preproc.y    2001/07/26 00:02:27
*************** DeleteStmt:  DELETE FROM relation_expr w
*** 2421,2427 ****
                  }
          ;

! LockStmt:  LOCK_P opt_table relation_name opt_lock
                  {
                      $$ = cat_str(4, make_str("lock"), $2, $3, $4);
                  }
--- 2421,2427 ----
                  }
          ;

! LockStmt:  LOCK_P opt_table relation_name_list opt_lock
                  {
                      $$ = cat_str(4, make_str("lock"), $2, $3, $4);
                  }

pgsql-patches by date:

Previous
From: Neil Padgett
Date:
Subject: Re: Patch to allow multiple table locks in "Unison"
Next
From: Jason Tishler
Date:
Subject: Re: libpq.dll (resend)