diff -r -c postgresql-8.0.0rc2.orig/doc/src/sgml/ref/select.sgml postgresql-8.0.0rc2/doc/src/sgml/ref/select.sgml
*** postgresql-8.0.0rc2.orig/doc/src/sgml/ref/select.sgml	Sat Nov 27 22:27:07 2004
--- postgresql-8.0.0rc2/doc/src/sgml/ref/select.sgml	Mon Dec 27 10:57:05 2004
***************
*** 30,36 ****
      [ ORDER BY <replaceable class="parameter">expression</replaceable> [ ASC | DESC | USING <replaceable class="parameter">operator</replaceable> ] [, ...] ]
      [ LIMIT { <replaceable class="parameter">count</replaceable> | ALL } ]
      [ OFFSET <replaceable class="parameter">start</replaceable> ]
!     [ FOR UPDATE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] ]
  
  where <replaceable class="parameter">from_item</replaceable> can be one of:
  
--- 30,36 ----
      [ ORDER BY <replaceable class="parameter">expression</replaceable> [ ASC | DESC | USING <replaceable class="parameter">operator</replaceable> ] [, ...] ]
      [ LIMIT { <replaceable class="parameter">count</replaceable> | ALL } ]
      [ OFFSET <replaceable class="parameter">start</replaceable> ]
!     [ FOR UPDATE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] [NOWAIT] ]
  
  where <replaceable class="parameter">from_item</replaceable> can be one of:
  
***************
*** 772,778 ****
     <para>
      The <literal>FOR UPDATE</literal> clause has this form:
  <synopsis>
! FOR UPDATE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ]
  </synopsis>
     </para>
  
--- 772,778 ----
     <para>
      The <literal>FOR UPDATE</literal> clause has this form:
  <synopsis>
! FOR UPDATE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] [NOWAIT]
  </synopsis>
     </para>
  
***************
*** 789,796 ****
      has already locked a selected row or rows, <command>SELECT FOR
      UPDATE</command> will wait for the other transaction to complete,
      and will then lock and return the updated row (or no row, if the
!     row was deleted).  For further discussion see <xref
!     linkend="mvcc">.
     </para>
  
     <para>
--- 789,802 ----
      has already locked a selected row or rows, <command>SELECT FOR
      UPDATE</command> will wait for the other transaction to complete,
      and will then lock and return the updated row (or no row, if the
!     row was deleted).  If the current transaction is not supposed to
!     wait on other transactions to commit the NOWAIT option can be
!     used.  If <command>SELECT FOR UPDATE NOWAIT</command> finds out
!     that somebody else is holding a lock an error will be thrown.
!     This will only happen in case of row level locks - if somebody
!     holds a table lock <command>SELECT FOR UPDATE NOWAIT</command>
!     will still wait for concurrent transactions.  For further 
!     discussion see <xref linkend="mvcc">.
     </para>
  
     <para>
diff -r -c postgresql-8.0.0rc2.orig/doc/src/sgml/sql.sgml postgresql-8.0.0rc2/doc/src/sgml/sql.sgml
*** postgresql-8.0.0rc2.orig/doc/src/sgml/sql.sgml	Mon Nov 15 07:32:14 2004
--- postgresql-8.0.0rc2/doc/src/sgml/sql.sgml	Mon Dec 27 10:57:05 2004
***************
*** 866,872 ****
      [ ORDER BY <replaceable class="PARAMETER">expression</replaceable> [ ASC | DESC | USING <replaceable class="PARAMETER">operator</replaceable> ] [, ...] ]
      [ LIMIT { <replaceable class="PARAMETER">count</replaceable> | ALL } ]
      [ OFFSET <replaceable class="PARAMETER">start</replaceable> ]
!     [ FOR UPDATE [ OF <replaceable class="PARAMETER">class_name</replaceable> [, ...] ] ]
       </synopsis>
      </para>
  
--- 866,872 ----
      [ ORDER BY <replaceable class="PARAMETER">expression</replaceable> [ ASC | DESC | USING <replaceable class="PARAMETER">operator</replaceable> ] [, ...] ]
      [ LIMIT { <replaceable class="PARAMETER">count</replaceable> | ALL } ]
      [ OFFSET <replaceable class="PARAMETER">start</replaceable> ]
!     [ FOR UPDATE [ OF <replaceable class="PARAMETER">class_name</replaceable> [, ...] ] [NOWAIT] ]
       </synopsis>
      </para>
  
diff -r -c postgresql-8.0.0rc2.orig/src/backend/access/heap/heapam.c postgresql-8.0.0rc2/src/backend/access/heap/heapam.c
*** postgresql-8.0.0rc2.orig/src/backend/access/heap/heapam.c	Sun Nov 14 03:04:12 2004
--- postgresql-8.0.0rc2/src/backend/access/heap/heapam.c	Mon Dec 27 10:56:52 2004
***************
*** 16,21 ****
--- 16,22 ----
   *		relation_openrv - open any relation specified by a RangeVar
   *		relation_openr	- open a system relation by name
   *		relation_close	- close any relation
+  *		conditional_relation_open - open with option not to wait
   *		heap_open		- open a heap relation by relation OID
   *		heap_openrv		- open a heap relation specified by a RangeVar
   *		heap_openr		- open a system heap relation by name
***************
*** 1828,1834 ****
   */
  int
  heap_mark4update(Relation relation, HeapTuple tuple, Buffer *buffer,
! 				 CommandId cid)
  {
  	TransactionId xid = GetCurrentTransactionId();
  	ItemPointer tid = &(tuple->t_self);
--- 1829,1835 ----
   */
  int
  heap_mark4update(Relation relation, HeapTuple tuple, Buffer *buffer,
! 				 CommandId cid, bool nowait)
  {
  	TransactionId xid = GetCurrentTransactionId();
  	ItemPointer tid = &(tuple->t_self);
***************
*** 1858,1866 ****
  	{
  		TransactionId xwait = HeapTupleHeaderGetXmax(tuple->t_data);
  
- 		/* sleep until concurrent transaction ends */
  		LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
! 		XactLockTableWait(xwait);
  
  		LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
  		if (!TransactionIdDidCommit(xwait))
--- 1859,1881 ----
  	{
  		TransactionId xwait = HeapTupleHeaderGetXmax(tuple->t_data);
  
  		LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
! 
! 		if (nowait)
! 		{
! 			/* rather error than sleep until concurrent transaction ends */ 
! 			if (!ConditionalXactLockTableWait(xwait))
! 			{
! 				ReleaseBuffer(*buffer);
! 				ereport(ERROR,
! 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
! 					 errmsg("data in table \"%s\" was modify by concurrent trasaction.", 
! 						 RelationGetRelationName(relation))));
! 			}
! 		}
! 		else
! 			/* sleep until concurrent transaction ends */
! 			XactLockTableWait(xwait);
  
  		LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
  		if (!TransactionIdDidCommit(xwait))
diff -r -c postgresql-8.0.0rc2.orig/src/backend/commands/trigger.c postgresql-8.0.0rc2/src/backend/commands/trigger.c
*** postgresql-8.0.0rc2.orig/src/backend/commands/trigger.c	Tue Dec  7 00:57:17 2004
--- postgresql-8.0.0rc2/src/backend/commands/trigger.c	Mon Dec 27 10:56:52 2004
***************
*** 1574,1580 ****
  		*newSlot = NULL;
  		tuple.t_self = *tid;
  ltrmark:;
! 		test = heap_mark4update(relation, &tuple, &buffer, cid);
  		switch (test)
  		{
  			case HeapTupleSelfUpdated:
--- 1574,1580 ----
  		*newSlot = NULL;
  		tuple.t_self = *tid;
  ltrmark:;
! 		test = heap_mark4update(relation, &tuple, &buffer, cid, estate->es_nowait);
  		switch (test)
  		{
  			case HeapTupleSelfUpdated:
diff -r -c postgresql-8.0.0rc2.orig/src/backend/executor/execMain.c postgresql-8.0.0rc2/src/backend/executor/execMain.c
*** postgresql-8.0.0rc2.orig/src/backend/executor/execMain.c	Thu Oct  7 20:38:49 2004
--- postgresql-8.0.0rc2/src/backend/executor/execMain.c	Mon Dec 27 10:56:52 2004
***************
*** 558,563 ****
--- 558,564 ----
  	/*
  	 * Have to lock relations selected for update
  	 */
+ 	estate->es_nowait = parseTree->nowait;
  	estate->es_rowMark = NIL;
  	if (parseTree->rowMarks != NIL)
  	{
***************
*** 1133,1139 ****
  
  					tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
  					test = heap_mark4update(erm->relation, &tuple, &buffer,
! 											estate->es_snapshot->curcid);
  					ReleaseBuffer(buffer);
  					switch (test)
  					{
--- 1134,1140 ----
  
  					tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
  					test = heap_mark4update(erm->relation, &tuple, &buffer,
! 							estate->es_snapshot->curcid, estate->es_nowait);
  					ReleaseBuffer(buffer);
  					switch (test)
  					{
***************
*** 2082,2087 ****
--- 2083,2089 ----
  	epqstate->es_instrument = estate->es_instrument;
  	epqstate->es_select_into = estate->es_select_into;
  	epqstate->es_into_oids = estate->es_into_oids;
+ 	epqstate->es_nowait = estate->es_nowait;
  	epqstate->es_topPlan = estate->es_topPlan;
  
  	/*
diff -r -c postgresql-8.0.0rc2.orig/src/backend/executor/execUtils.c postgresql-8.0.0rc2/src/backend/executor/execUtils.c
*** postgresql-8.0.0rc2.orig/src/backend/executor/execUtils.c	Fri Oct  1 01:21:23 2004
--- postgresql-8.0.0rc2/src/backend/executor/execUtils.c	Mon Dec 27 10:56:52 2004
***************
*** 203,209 ****
  	estate->es_instrument = false;
  	estate->es_select_into = false;
  	estate->es_into_oids = false;
! 
  	estate->es_exprcontexts = NIL;
  
  	estate->es_per_tuple_exprcontext = NULL;
--- 203,210 ----
  	estate->es_instrument = false;
  	estate->es_select_into = false;
  	estate->es_into_oids = false;
! 	estate->es_nowait = false;
! 	
  	estate->es_exprcontexts = NIL;
  
  	estate->es_per_tuple_exprcontext = NULL;
diff -r -c postgresql-8.0.0rc2.orig/src/backend/nodes/copyfuncs.c postgresql-8.0.0rc2/src/backend/nodes/copyfuncs.c
*** postgresql-8.0.0rc2.orig/src/backend/nodes/copyfuncs.c	Sun Dec 12 00:26:33 2004
--- postgresql-8.0.0rc2/src/backend/nodes/copyfuncs.c	Mon Dec 27 10:56:52 2004
***************
*** 1426,1431 ****
--- 1426,1442 ----
  	return newnode;
  }
  
+ static ForUpdate *
+ _copyForUpdate(ForUpdate *from)
+ {
+ 	ForUpdate *newnode = makeNode(ForUpdate);
+ 
+ 	COPY_NODE_FIELD(update_list);
+ 	COPY_SCALAR_FIELD(nowait);
+ 
+ 	return newnode;
+ }
+ 
  static RangeSubselect *
  _copyRangeSubselect(RangeSubselect *from)
  {
***************
*** 1537,1542 ****
--- 1548,1554 ----
  	COPY_NODE_FIELD(groupClause);
  	COPY_NODE_FIELD(havingQual);
  	COPY_NODE_FIELD(distinctClause);
+ 	COPY_SCALAR_FIELD(nowait);
  	COPY_NODE_FIELD(sortClause);
  	COPY_NODE_FIELD(limitOffset);
  	COPY_NODE_FIELD(limitCount);
***************
*** 1611,1617 ****
  	COPY_NODE_FIELD(sortClause);
  	COPY_NODE_FIELD(limitOffset);
  	COPY_NODE_FIELD(limitCount);
! 	COPY_NODE_FIELD(forUpdate);
  	COPY_SCALAR_FIELD(op);
  	COPY_SCALAR_FIELD(all);
  	COPY_NODE_FIELD(larg);
--- 1623,1629 ----
  	COPY_NODE_FIELD(sortClause);
  	COPY_NODE_FIELD(limitOffset);
  	COPY_NODE_FIELD(limitCount);
! 	COPY_NODE_FIELD(forupdateClause);
  	COPY_SCALAR_FIELD(op);
  	COPY_SCALAR_FIELD(all);
  	COPY_NODE_FIELD(larg);
***************
*** 3065,3070 ****
--- 3077,3085 ----
  		case T_SortBy:
  			retval = _copySortBy(from);
  			break;
+ 		case T_ForUpdate:
+ 			retval = _copyForUpdate(from);
+ 			break;
  		case T_RangeSubselect:
  			retval = _copyRangeSubselect(from);
  			break;
diff -r -c postgresql-8.0.0rc2.orig/src/backend/nodes/equalfuncs.c postgresql-8.0.0rc2/src/backend/nodes/equalfuncs.c
*** postgresql-8.0.0rc2.orig/src/backend/nodes/equalfuncs.c	Sun Dec 12 00:26:33 2004
--- postgresql-8.0.0rc2/src/backend/nodes/equalfuncs.c	Mon Dec 27 10:56:52 2004
***************
*** 656,661 ****
--- 656,662 ----
  	COMPARE_NODE_FIELD(groupClause);
  	COMPARE_NODE_FIELD(havingQual);
  	COMPARE_NODE_FIELD(distinctClause);
+ 	COMPARE_SCALAR_FIELD(nowait);
  	COMPARE_NODE_FIELD(sortClause);
  	COMPARE_NODE_FIELD(limitOffset);
  	COMPARE_NODE_FIELD(limitCount);
***************
*** 719,725 ****
  	COMPARE_NODE_FIELD(sortClause);
  	COMPARE_NODE_FIELD(limitOffset);
  	COMPARE_NODE_FIELD(limitCount);
! 	COMPARE_NODE_FIELD(forUpdate);
  	COMPARE_SCALAR_FIELD(op);
  	COMPARE_SCALAR_FIELD(all);
  	COMPARE_NODE_FIELD(larg);
--- 720,726 ----
  	COMPARE_NODE_FIELD(sortClause);
  	COMPARE_NODE_FIELD(limitOffset);
  	COMPARE_NODE_FIELD(limitCount);
! 	COMPARE_NODE_FIELD(forupdateClause);
  	COMPARE_SCALAR_FIELD(op);
  	COMPARE_SCALAR_FIELD(all);
  	COMPARE_NODE_FIELD(larg);
***************
*** 1577,1582 ****
--- 1578,1592 ----
  }
  
  static bool
+ _equalForUpdate(ForUpdate *a, ForUpdate *b)
+ {
+ 	COMPARE_SCALAR_FIELD(nowait);
+ 	COMPARE_NODE_FIELD(update_list);
+ 
+ 	return true;
+ }
+ 
+ static bool
  _equalRangeSubselect(RangeSubselect *a, RangeSubselect *b)
  {
  	COMPARE_NODE_FIELD(subquery);
***************
*** 2202,2207 ****
--- 2212,2220 ----
  		case T_SortBy:
  			retval = _equalSortBy(a, b);
  			break;
+ 		case T_ForUpdate:
+ 			retval = _equalForUpdate(a, b);
+ 			break;
  		case T_RangeSubselect:
  			retval = _equalRangeSubselect(a, b);
  			break;
diff -r -c postgresql-8.0.0rc2.orig/src/backend/nodes/outfuncs.c postgresql-8.0.0rc2/src/backend/nodes/outfuncs.c
*** postgresql-8.0.0rc2.orig/src/backend/nodes/outfuncs.c	Sun Dec 12 00:26:33 2004
--- postgresql-8.0.0rc2/src/backend/nodes/outfuncs.c	Mon Dec 27 10:56:52 2004
***************
*** 1202,1208 ****
  	WRITE_NODE_FIELD(sortClause);
  	WRITE_NODE_FIELD(limitOffset);
  	WRITE_NODE_FIELD(limitCount);
! 	WRITE_NODE_FIELD(forUpdate);
  	WRITE_ENUM_FIELD(op, SetOperation);
  	WRITE_BOOL_FIELD(all);
  	WRITE_NODE_FIELD(larg);
--- 1202,1208 ----
  	WRITE_NODE_FIELD(sortClause);
  	WRITE_NODE_FIELD(limitOffset);
  	WRITE_NODE_FIELD(limitCount);
! 	WRITE_NODE_FIELD(forupdateClause);
  	WRITE_ENUM_FIELD(op, SetOperation);
  	WRITE_BOOL_FIELD(all);
  	WRITE_NODE_FIELD(larg);
***************
*** 1323,1328 ****
--- 1323,1329 ----
  	WRITE_NODE_FIELD(groupClause);
  	WRITE_NODE_FIELD(havingQual);
  	WRITE_NODE_FIELD(distinctClause);
+ 	WRITE_BOOL_FIELD(nowait);
  	WRITE_NODE_FIELD(sortClause);
  	WRITE_NODE_FIELD(limitOffset);
  	WRITE_NODE_FIELD(limitCount);
diff -r -c postgresql-8.0.0rc2.orig/src/backend/nodes/readfuncs.c postgresql-8.0.0rc2/src/backend/nodes/readfuncs.c
*** postgresql-8.0.0rc2.orig/src/backend/nodes/readfuncs.c	Sun Dec 12 00:26:34 2004
--- postgresql-8.0.0rc2/src/backend/nodes/readfuncs.c	Mon Dec 27 10:56:52 2004
***************
*** 149,154 ****
--- 149,155 ----
  	READ_NODE_FIELD(groupClause);
  	READ_NODE_FIELD(havingQual);
  	READ_NODE_FIELD(distinctClause);
+ 	READ_BOOL_FIELD(nowait);
  	READ_NODE_FIELD(sortClause);
  	READ_NODE_FIELD(limitOffset);
  	READ_NODE_FIELD(limitCount);
diff -r -c postgresql-8.0.0rc2.orig/src/backend/parser/analyze.c postgresql-8.0.0rc2/src/backend/parser/analyze.c
*** postgresql-8.0.0rc2.orig/src/backend/parser/analyze.c	Wed Nov 17 00:34:26 2004
--- postgresql-8.0.0rc2/src/backend/parser/analyze.c	Mon Dec 27 10:56:52 2004
***************
*** 135,141 ****
  					   bool isAddConstraint);
  static void applyColumnNames(List *dst, List *src);
  static List *getSetColTypes(ParseState *pstate, Node *node);
! static void transformForUpdate(Query *qry, List *forUpdate);
  static void transformConstraintAttrs(List *constraintList);
  static void transformColumnType(ParseState *pstate, ColumnDef *column);
  static void release_pstate_resources(ParseState *pstate);
--- 135,141 ----
  					   bool isAddConstraint);
  static void applyColumnNames(List *dst, List *src);
  static List *getSetColTypes(ParseState *pstate, Node *node);
! static void transformForUpdate(Query *qry, Node *forupdateClause);
  static void transformConstraintAttrs(List *constraintList);
  static void transformColumnType(ParseState *pstate, ColumnDef *column);
  static void release_pstate_resources(ParseState *pstate);
***************
*** 1804,1810 ****
  	qry->commandType = CMD_SELECT;
  
  	/* make FOR UPDATE clause available to addRangeTableEntry */
! 	pstate->p_forUpdate = stmt->forUpdate;
  
  	/* process the FROM clause */
  	transformFromClause(pstate, stmt->fromClause);
--- 1804,1810 ----
  	qry->commandType = CMD_SELECT;
  
  	/* make FOR UPDATE clause available to addRangeTableEntry */
! 	pstate->p_forUpdate = stmt->forupdateClause ? ((ForUpdate *)stmt->forupdateClause)->update_list : NIL;
  
  	/* process the FROM clause */
  	transformFromClause(pstate, stmt->fromClause);
***************
*** 1864,1871 ****
  	if (pstate->p_hasAggs || qry->groupClause)
  		parseCheckAggregates(pstate, qry);
  
! 	if (stmt->forUpdate != NIL)
! 		transformForUpdate(qry, stmt->forUpdate);
  
  	return qry;
  }
--- 1864,1871 ----
  	if (pstate->p_hasAggs || qry->groupClause)
  		parseCheckAggregates(pstate, qry);
  
! 	if (stmt->forupdateClause)
! 		transformForUpdate(qry, stmt->forupdateClause);
  
  	return qry;
  }
***************
*** 1893,1899 ****
  	List	   *sortClause;
  	Node	   *limitOffset;
  	Node	   *limitCount;
! 	List	   *forUpdate;
  	Node	   *node;
  	ListCell   *left_tlist,
  			   *dtlist;
--- 1893,1899 ----
  	List	   *sortClause;
  	Node	   *limitOffset;
  	Node	   *limitCount;
! 	Node	   *forUpdate;
  	Node	   *node;
  	ListCell   *left_tlist,
  			   *dtlist;
***************
*** 1931,1942 ****
  	sortClause = stmt->sortClause;
  	limitOffset = stmt->limitOffset;
  	limitCount = stmt->limitCount;
! 	forUpdate = stmt->forUpdate;
  
  	stmt->sortClause = NIL;
  	stmt->limitOffset = NULL;
  	stmt->limitCount = NULL;
! 	stmt->forUpdate = NIL;
  
  	/* We don't support forUpdate with set ops at the moment. */
  	if (forUpdate)
--- 1931,1942 ----
  	sortClause = stmt->sortClause;
  	limitOffset = stmt->limitOffset;
  	limitCount = stmt->limitCount;
! 	forUpdate = stmt->forupdateClause;
  
  	stmt->sortClause = NIL;
  	stmt->limitOffset = NULL;
  	stmt->limitCount = NULL;
! 	stmt->forupdateClause = NULL;
  
  	/* We don't support forUpdate with set ops at the moment. */
  	if (forUpdate)
***************
*** 2080,2086 ****
  	if (pstate->p_hasAggs || qry->groupClause)
  		parseCheckAggregates(pstate, qry);
  
! 	if (forUpdate != NIL)
  		transformForUpdate(qry, forUpdate);
  
  	return qry;
--- 2080,2086 ----
  	if (pstate->p_hasAggs || qry->groupClause)
  		parseCheckAggregates(pstate, qry);
  
! 	if (forUpdate)
  		transformForUpdate(qry, forUpdate);
  
  	return qry;
***************
*** 2105,2111 ****
  				(errcode(ERRCODE_SYNTAX_ERROR),
  				 errmsg("INTO is only allowed on first SELECT of UNION/INTERSECT/EXCEPT")));
  	/* We don't support forUpdate with set ops at the moment. */
! 	if (stmt->forUpdate)
  		ereport(ERROR,
  				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  				 errmsg("SELECT FOR UPDATE is not allowed with UNION/INTERSECT/EXCEPT")));
--- 2105,2111 ----
  				(errcode(ERRCODE_SYNTAX_ERROR),
  				 errmsg("INTO is only allowed on first SELECT of UNION/INTERSECT/EXCEPT")));
  	/* We don't support forUpdate with set ops at the moment. */
! 	if (stmt->forupdateClause)
  		ereport(ERROR,
  				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  				 errmsg("SELECT FOR UPDATE is not allowed with UNION/INTERSECT/EXCEPT")));
***************
*** 2125,2131 ****
  	{
  		Assert(stmt->larg != NULL && stmt->rarg != NULL);
  		if (stmt->sortClause || stmt->limitOffset || stmt->limitCount ||
! 			stmt->forUpdate)
  			isLeaf = true;
  		else
  			isLeaf = false;
--- 2125,2131 ----
  	{
  		Assert(stmt->larg != NULL && stmt->rarg != NULL);
  		if (stmt->sortClause || stmt->limitOffset || stmt->limitCount ||
! 			stmt->forupdateClause)
  			isLeaf = true;
  		else
  			isLeaf = false;
***************
*** 2737,2752 ****
   * in rewriteHandler.c.
   */
  static void
! transformForUpdate(Query *qry, List *forUpdate)
  {
  	List	   *rowMarks = qry->rowMarks;
  	ListCell   *l;
  	ListCell   *rt;
! 	Index		i;
  
  	CheckSelectForUpdate(qry);
  
! 	if (linitial(forUpdate) == NULL)
  	{
  		/* all regular tables used in query */
  		i = 0;
--- 2737,2761 ----
   * in rewriteHandler.c.
   */
  static void
! transformForUpdate(Query *qry, Node *forupdateClause)
  {
  	List	   *rowMarks = qry->rowMarks;
  	ListCell   *l;
  	ListCell   *rt;
! 	Index	   i;
! 	ForUpdate  *fu = (ForUpdate *) forupdateClause;
! 	ForUpdate  empty;
! 	List       *update_list;
  
  	CheckSelectForUpdate(qry);
  
! 	update_list = fu->update_list;
! 	qry->nowait = fu->nowait;
! 
! 	memset(&empty, 0, sizeof(ForUpdate));
! 	empty.nowait = FALSE;
! 	
! 	if (linitial(update_list) == NULL)
  	{
  		/* all regular tables used in query */
  		i = 0;
***************
*** 2768,2774 ****
  					 * FOR UPDATE of subquery is propagated to subquery's
  					 * rels
  					 */
! 					transformForUpdate(rte->subquery, list_make1(NULL));
  					break;
  				default:
  					/* ignore JOIN, SPECIAL, FUNCTION RTEs */
--- 2777,2785 ----
  					 * FOR UPDATE of subquery is propagated to subquery's
  					 * rels
  					 */
! 					empty.update_list = list_make1(NULL);
! 					transformForUpdate(rte->subquery, (Node *) &empty);
! 					empty.update_list = NIL;
  					break;
  				default:
  					/* ignore JOIN, SPECIAL, FUNCTION RTEs */
***************
*** 2779,2785 ****
  	else
  	{
  		/* just the named tables */
! 		foreach(l, forUpdate)
  		{
  			char	   *relname = strVal(lfirst(l));
  
--- 2790,2796 ----
  	else
  	{
  		/* just the named tables */
! 		foreach(l, update_list)
  		{
  			char	   *relname = strVal(lfirst(l));
  
***************
*** 2804,2810 ****
  							 * FOR UPDATE of subquery is propagated to
  							 * subquery's rels
  							 */
! 							transformForUpdate(rte->subquery, list_make1(NULL));
  							break;
  						case RTE_JOIN:
  							ereport(ERROR,
--- 2815,2823 ----
  							 * FOR UPDATE of subquery is propagated to
  							 * subquery's rels
  							 */
! 							empty.update_list = list_make1(NULL);
! 							transformForUpdate(rte->subquery, (Node *) &empty);
! 							empty.update_list = NULL;
  							break;
  						case RTE_JOIN:
  							ereport(ERROR,
diff -r -c postgresql-8.0.0rc2.orig/src/backend/parser/gram.y postgresql-8.0.0rc2/src/backend/parser/gram.y
*** postgresql-8.0.0rc2.orig/src/backend/parser/gram.y	Mon Nov  8 05:02:20 2004
--- postgresql-8.0.0rc2/src/backend/parser/gram.y	Mon Dec 27 10:56:52 2004
***************
*** 87,93 ****
  static List *extractArgTypes(List *parameters);
  static SelectStmt *findLeftmostSelect(SelectStmt *node);
  static void insertSelectOptions(SelectStmt *stmt,
! 								List *sortClause, List *forUpdate,
  								Node *limitOffset, Node *limitCount);
  static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
  static Node *doNegate(Node *n);
--- 87,93 ----
  static List *extractArgTypes(List *parameters);
  static SelectStmt *findLeftmostSelect(SelectStmt *node);
  static void insertSelectOptions(SelectStmt *stmt,
! 								List *sortClause, Node *forUpdate,
  								Node *limitOffset, Node *limitCount);
  static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
  static Node *doNegate(Node *n);
***************
*** 239,245 ****
  %type <oncommit> OnCommitOption
  %type <withoids> OptWithOids WithOidsAs
  
! %type <list>	for_update_clause opt_for_update_clause update_list
  %type <boolean>	opt_all
  
  %type <node>	join_outer join_qual
--- 239,247 ----
  %type <oncommit> OnCommitOption
  %type <withoids> OptWithOids WithOidsAs
  
! %type <node>	for_update_clause opt_for_update_clause
! %type <list>	update_list
! 
  %type <boolean>	opt_all
  
  %type <node>	join_outer join_qual
***************
*** 4801,4807 ****
  			simple_select						{ $$ = $1; }
  			| select_clause sort_clause
  				{
! 					insertSelectOptions((SelectStmt *) $1, $2, NIL,
  										NULL, NULL);
  					$$ = $1;
  				}
--- 4803,4809 ----
  			simple_select						{ $$ = $1; }
  			| select_clause sort_clause
  				{
! 					insertSelectOptions((SelectStmt *) $1, $2, NULL,
  										NULL, NULL);
  					$$ = $1;
  				}
***************
*** 4862,4867 ****
--- 4864,4870 ----
  					n->whereClause = $6;
  					n->groupClause = $7;
  					n->havingClause = $8;
+ 					n->forupdateClause = NULL;
  					$$ = (Node *)n;
  				}
  			| select_clause UNION opt_all select_clause
***************
*** 5053,5060 ****
  		;
  
  for_update_clause:
! 			FOR UPDATE update_list					{ $$ = $3; }
! 			| FOR READ ONLY							{ $$ = NULL; }
  		;
  
  opt_for_update_clause:
--- 5056,5069 ----
  		;
  
  for_update_clause:
! 			FOR UPDATE update_list opt_nowait	
! 				{ 
! 					ForUpdate *n = makeNode(ForUpdate);
! 					n->update_list = $3;
! 					n->nowait = $4;
! 					$$ = (Node *) n;
! 				}
! 			| FOR READ ONLY							{ $$ = NULL; }	
  		;
  
  opt_for_update_clause:
***************
*** 8284,8290 ****
   */
  static void
  insertSelectOptions(SelectStmt *stmt,
! 					List *sortClause, List *forUpdate,
  					Node *limitOffset, Node *limitCount)
  {
  	/*
--- 8293,8299 ----
   */
  static void
  insertSelectOptions(SelectStmt *stmt,
! 					List *sortClause, Node *forUpdate,
  					Node *limitOffset, Node *limitCount)
  {
  	/*
***************
*** 8301,8311 ****
  	}
  	if (forUpdate)
  	{
! 		if (stmt->forUpdate)
  			ereport(ERROR,
  					(errcode(ERRCODE_SYNTAX_ERROR),
  					 errmsg("multiple FOR UPDATE clauses not allowed")));
! 		stmt->forUpdate = forUpdate;
  	}
  	if (limitOffset)
  	{
--- 8310,8320 ----
  	}
  	if (forUpdate)
  	{
! 		if (stmt->forupdateClause)
  			ereport(ERROR,
  					(errcode(ERRCODE_SYNTAX_ERROR),
  					 errmsg("multiple FOR UPDATE clauses not allowed")));
! 		stmt->forupdateClause = forUpdate;
  	}
  	if (limitOffset)
  	{
diff -r -c postgresql-8.0.0rc2.orig/src/backend/parser/parse_type.c postgresql-8.0.0rc2/src/backend/parser/parse_type.c
*** postgresql-8.0.0rc2.orig/src/backend/parser/parse_type.c	Wed Dec 15 21:15:17 2004
--- postgresql-8.0.0rc2/src/backend/parser/parse_type.c	Mon Dec 27 10:56:52 2004
***************
*** 432,438 ****
  		stmt->sortClause != NIL ||
  		stmt->limitOffset != NULL ||
  		stmt->limitCount != NULL ||
! 		stmt->forUpdate != NIL ||
  		stmt->op != SETOP_NONE)
  		goto fail;
  	if (list_length(stmt->targetList) != 1)
--- 432,438 ----
  		stmt->sortClause != NIL ||
  		stmt->limitOffset != NULL ||
  		stmt->limitCount != NULL ||
! 		stmt->forupdateClause != NULL ||
  		stmt->op != SETOP_NONE)
  		goto fail;
  	if (list_length(stmt->targetList) != 1)
diff -r -c postgresql-8.0.0rc2.orig/src/backend/storage/lmgr/lmgr.c postgresql-8.0.0rc2/src/backend/storage/lmgr/lmgr.c
*** postgresql-8.0.0rc2.orig/src/backend/storage/lmgr/lmgr.c	Thu Sep 16 18:58:33 2004
--- postgresql-8.0.0rc2/src/backend/storage/lmgr/lmgr.c	Mon Dec 27 10:56:52 2004
***************
*** 393,395 ****
--- 393,435 ----
  	if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid))
  		TransactionIdAbort(xid);
  }
+ 
+ /*
+  * As above, but only lock if we can get the lock without blocking.
+  * Returns TRUE if the lock was acquired. 
+  */
+ bool
+ ConditionalXactLockTableWait(TransactionId xid)
+ {
+ 	LOCKTAG		tag;
+ 	TransactionId myxid = GetTopTransactionId();
+ 
+ 	for (;;)
+ 	{
+ 		Assert(TransactionIdIsValid(xid));
+ 		Assert(!TransactionIdEquals(xid, myxid));
+ 
+ 		MemSet(&tag, 0, sizeof(tag));
+ 		tag.relId = XactLockTableId;
+ 		tag.dbId = InvalidOid;
+ 		tag.objId.xid = xid;
+ 
+ 		if (!LockAcquire(LockTableId, &tag, myxid, ShareLock, true))
+ 			return FALSE;
+ 		LockRelease(LockTableId, &tag, myxid, ShareLock);
+ 
+ 		if (!TransactionIdIsInProgress(xid))
+ 			break;
+ 		xid = SubTransGetParent(xid);
+ 	}
+ 
+ 	/*
+ 	 * Transaction was committed/aborted/crashed - we have to update
+ 	 * pg_clog if transaction is still marked as running.
+ 	 */
+ 	if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid))
+ 		TransactionIdAbort(xid);
+ 	
+ 	return TRUE;
+ }
+ 
diff -r -c postgresql-8.0.0rc2.orig/src/bin/psql/sql_help.h postgresql-8.0.0rc2/src/bin/psql/sql_help.h
*** postgresql-8.0.0rc2.orig/src/bin/psql/sql_help.h	Tue Dec 21 05:22:44 2004
--- postgresql-8.0.0rc2/src/bin/psql/sql_help.h	Mon Dec 27 10:57:05 2004
***************
*** 383,393 ****
  
      { "SELECT",
        N_("retrieve rows from a table or view"),
!       N_("SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]\n    * | expression [ AS output_name ] [, ...]\n    [ FROM from_item [, ...] ]\n    [ WHERE condition ]\n    [ GROUP BY expression [, ...] ]\n    [ HAVING condition [, ...] ]\n    [ { UNION | INTERSECT | EXCEPT } [ ALL ] select ]\n    [ ORDER BY expression [ ASC | DESC | USING operator ] [, ...] ]\n    [ LIMIT { count | ALL } ]\n    [ OFFSET start ]\n    [ FOR UPDATE [ OF table_name [, ...] ] ]\n\nwhere from_item can be one of:\n\n    [ ONLY ] table_name [ * ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]\n    ( select ) [ AS ] alias [ ( column_alias [, ...] ) ]\n    function_name ( [ argument [, ...] ] ) [ AS ] alias [ ( column_alias [, ...] | column_definition [, ...] ) ]\n    function_name ( [ argument [, ...] ] ) AS ( column_definition [, ...] )\n    from_item [ NATURAL ] join_type from_item [ ON join_condition | USING ( join_column [, ...] ) ]") },
  
      { "SELECT INTO",
        N_("define a new table from the results of a query"),
!       N_("SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]\n    * | expression [ AS output_name ] [, ...]\n    INTO [ TEMPORARY | TEMP ] [ TABLE ] new_table\n    [ FROM from_item [, ...] ]\n    [ WHERE condition ]\n    [ GROUP BY expression [, ...] ]\n    [ HAVING condition [, ...] ]\n    [ { UNION | INTERSECT | EXCEPT } [ ALL ] select ]\n    [ ORDER BY expression [ ASC | DESC | USING operator ] [, ...] ]\n    [ LIMIT { count | ALL } ]\n    [ OFFSET start ]\n    [ FOR UPDATE [ OF tablename [, ...] ] ]") },
  
      { "SET",
        N_("change a run-time parameter"),
--- 383,393 ----
  
      { "SELECT",
        N_("retrieve rows from a table or view"),
!       N_("SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]\n    * | expression [ AS output_name ] [, ...]\n    [ FROM from_item [, ...] ]\n    [ WHERE condition ]\n    [ GROUP BY expression [, ...] ]\n    [ HAVING condition [, ...] ]\n    [ { UNION | INTERSECT | EXCEPT } [ ALL ] select ]\n    [ ORDER BY expression [ ASC | DESC | USING operator ] [, ...] ]\n    [ LIMIT { count | ALL } ]\n    [ OFFSET start ]\n    [ FOR UPDATE [ OF table_name [, ...] ] [NOWAIT] ]\n\nwhere from_item can be one of:\n\n    [ ONLY ] table_name [ * ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]\n    ( select ) [ AS ] alias [ ( column_alias [, ...] ) ]\n    function_name ( [ argument [, ...] ] ) [ AS ] alias [ ( column_alias [, ...] | column_definition [, ...] ) ]\n    function_name ( [ argument [, ...] ] ) AS ( column_definition [, ...] )\n    from_item [ NATURAL ] join_type from_item [ ON join_condition | USING ( join_column [, ...] ) ]") },
  
      { "SELECT INTO",
        N_("define a new table from the results of a query"),
!       N_("SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]\n    * | expression [ AS output_name ] [, ...]\n    INTO [ TEMPORARY | TEMP ] [ TABLE ] new_table\n    [ FROM from_item [, ...] ]\n    [ WHERE condition ]\n    [ GROUP BY expression [, ...] ]\n    [ HAVING condition [, ...] ]\n    [ { UNION | INTERSECT | EXCEPT } [ ALL ] select ]\n    [ ORDER BY expression [ ASC | DESC | USING operator ] [, ...] ]\n    [ LIMIT { count | ALL } ]\n    [ OFFSET start ]\n    [ FOR UPDATE [ OF tablename [, ...] ] [NOWAIT] ]") },
  
      { "SET",
        N_("change a run-time parameter"),
diff -r -c postgresql-8.0.0rc2.orig/src/include/access/heapam.h postgresql-8.0.0rc2/src/include/access/heapam.h
*** postgresql-8.0.0rc2.orig/src/include/access/heapam.h	Sun Aug 29 07:06:55 2004
--- postgresql-8.0.0rc2/src/include/access/heapam.h	Mon Dec 27 10:57:05 2004
***************
*** 164,170 ****
  extern int heap_update(Relation relation, ItemPointer otid, HeapTuple tup,
  		ItemPointer ctid, CommandId cid, Snapshot crosscheck, bool wait);
  extern int heap_mark4update(Relation relation, HeapTuple tup,
! 				 Buffer *userbuf, CommandId cid);
  
  extern Oid	simple_heap_insert(Relation relation, HeapTuple tup);
  extern void simple_heap_delete(Relation relation, ItemPointer tid);
--- 164,170 ----
  extern int heap_update(Relation relation, ItemPointer otid, HeapTuple tup,
  		ItemPointer ctid, CommandId cid, Snapshot crosscheck, bool wait);
  extern int heap_mark4update(Relation relation, HeapTuple tup,
! 				 Buffer *userbuf, CommandId cid, bool nowait);
  
  extern Oid	simple_heap_insert(Relation relation, HeapTuple tup);
  extern void simple_heap_delete(Relation relation, ItemPointer tid);
diff -r -c postgresql-8.0.0rc2.orig/src/include/nodes/execnodes.h postgresql-8.0.0rc2/src/include/nodes/execnodes.h
*** postgresql-8.0.0rc2.orig/src/include/nodes/execnodes.h	Sun Dec 12 00:26:49 2004
--- postgresql-8.0.0rc2/src/include/nodes/execnodes.h	Mon Dec 27 10:56:52 2004
***************
*** 308,313 ****
--- 308,314 ----
  	bool		es_instrument;	/* true requests runtime instrumentation */
  	bool		es_select_into; /* true if doing SELECT INTO */
  	bool		es_into_oids;	/* true to generate OIDs in SELECT INTO */
+ 	bool		es_nowait;	/* SELECT FOR UPDATE NOWAIT */
  
  	List	   *es_exprcontexts;	/* List of ExprContexts within EState */
  
diff -r -c postgresql-8.0.0rc2.orig/src/include/nodes/nodes.h postgresql-8.0.0rc2/src/include/nodes/nodes.h
*** postgresql-8.0.0rc2.orig/src/include/nodes/nodes.h	Sun Dec 12 00:26:49 2004
--- postgresql-8.0.0rc2/src/include/nodes/nodes.h	Mon Dec 27 10:56:52 2004
***************
*** 302,307 ****
--- 302,308 ----
  	T_CompositeTypeStmt,
  	T_InhRelation,
  	T_FunctionParameter,
+ 	T_ForUpdate,
  
  	/*
  	 * TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h)
diff -r -c postgresql-8.0.0rc2.orig/src/include/nodes/parsenodes.h postgresql-8.0.0rc2/src/include/nodes/parsenodes.h
*** postgresql-8.0.0rc2.orig/src/include/nodes/parsenodes.h	Fri Nov  5 20:16:38 2004
--- postgresql-8.0.0rc2/src/include/nodes/parsenodes.h	Mon Dec 27 10:56:52 2004
***************
*** 103,108 ****
--- 103,110 ----
  
  	List	   *sortClause;		/* a list of SortClause's */
  
+ 	bool	   nowait;		/* are we in NOWAIT mode? */
+ 
  	Node	   *limitOffset;	/* # of result tuples to skip */
  	Node	   *limitCount;		/* # of result tuples to return */
  
***************
*** 422,427 ****
--- 424,439 ----
  	Node	   *arg;			/* a (Value *) or a (TypeName *) */
  } DefElem;
  
+ /*
+  * ForUpdate -
+  *       used in raw parsetrees output only
+  */
+ typedef struct ForUpdate
+ {
+ 	NodeTag		type;
+ 	List		*update_list;	/* list of tables */
+ 	bool		nowait;		/* NOWAIT option */
+ } ForUpdate;
  
  /****************************************************************************
   *	Nodes for a Query tree
***************
*** 686,692 ****
  	List	   *sortClause;		/* sort clause (a list of SortBy's) */
  	Node	   *limitOffset;	/* # of result tuples to skip */
  	Node	   *limitCount;		/* # of result tuples to return */
! 	List	   *forUpdate;		/* FOR UPDATE clause */
  
  	/*
  	 * These fields are used only in upper-level SelectStmts.
--- 698,704 ----
  	List	   *sortClause;		/* sort clause (a list of SortBy's) */
  	Node	   *limitOffset;	/* # of result tuples to skip */
  	Node	   *limitCount;		/* # of result tuples to return */
! 	Node	   *forupdateClause;	/* FOR UPDATE clause (ForUpdate node) */
  
  	/*
  	 * These fields are used only in upper-level SelectStmts.
diff -r -c postgresql-8.0.0rc2.orig/src/include/storage/lmgr.h postgresql-8.0.0rc2/src/include/storage/lmgr.h
*** postgresql-8.0.0rc2.orig/src/include/storage/lmgr.h	Thu Sep 16 18:58:42 2004
--- postgresql-8.0.0rc2/src/include/storage/lmgr.h	Mon Dec 27 10:56:52 2004
***************
*** 60,64 ****
--- 60,65 ----
  extern void XactLockTableInsert(TransactionId xid);
  extern void XactLockTableDelete(TransactionId xid);
  extern void XactLockTableWait(TransactionId xid);
+ extern bool ConditionalXactLockTableWait(TransactionId xid);
  
  #endif   /* LMGR_H */
