Revised Patch to allow multiple table locks in "Unison"

Поиск
Список
Период
Сортировка
Искать
От
Neil Padgett
Тема
Revised Patch to allow multiple table locks in "Unison"
Дата
Msg-id
3B5F6407.81923B6A@redhat.com
Список
Дерево обсуждения
Re: Revised Patch to allow multiple table locks in "Unison" Neil Padgett <npadgett@redhat.com>
Re: Revised Patch to allow multiple table locks in "Unison" Bruce Momjian <pgman@candle.pha.pa.us>
Re: Revised Patch to allow multiple table locks in "Unison" Bruce Momjian <pgman@candle.pha.pa.us>
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 по дате отправления
От: Neil Padgett
Дата:
От: Jason Tishler
Дата:
Сообщение: Re: libpq.dll (resend)
FAQ