*** postgresql-snapshot/src/backend/parser/gram.y	2007-03-27 02:58:39.000000000 +1000
--- pgbase2103/src/backend/parser/gram.y	2007-03-31 18:16:28.982287848 +1000
***************
*** 296,302 ****
  %type <node>	columnDef
  %type <defelt>	def_elem old_aggr_elem
  %type <node>	def_arg columnElem where_clause
! 				a_expr b_expr c_expr func_expr AexprConst indirection_el
  				columnref in_expr having_clause func_table array_expr
  %type <list>	row type_list array_expr_list
  %type <node>	case_expr case_arg when_clause case_default
--- 296,302 ----
  %type <node>	columnDef
  %type <defelt>	def_elem old_aggr_elem
  %type <node>	def_arg columnElem where_clause
! 				a_expr b_expr c_expr func_expr AexprConst indirection_el where_current_clause
  				columnref in_expr having_clause func_table array_expr
  %type <list>	row type_list array_expr_list
  %type <node>	case_expr case_arg when_clause case_default
***************
*** 376,382 ****
  	CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
  	COMMITTED CONCURRENTLY CONNECTION CONSTRAINT CONSTRAINTS
  	CONTENT_P CONVERSION_P CONVERT COPY COST CREATE CREATEDB
! 	CREATEROLE CREATEUSER CROSS CSV CURRENT_DATE CURRENT_ROLE CURRENT_TIME
  	CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
  
  	DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
--- 376,382 ----
  	CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
  	COMMITTED CONCURRENTLY CONNECTION CONSTRAINT CONSTRAINTS
  	CONTENT_P CONVERSION_P CONVERT COPY COST CREATE CREATEDB
! 	CREATEROLE CREATEUSER CROSS CSV CURRENT CURRENT_DATE CURRENT_ROLE CURRENT_TIME
  	CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
  
  	DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
***************
*** 5635,5641 ****
   *****************************************************************************/
  
  DeleteStmt: DELETE_P FROM relation_expr_opt_alias
! 			using_clause where_clause returning_clause
  				{
  					DeleteStmt *n = makeNode(DeleteStmt);
  					n->relation = $3;
--- 5627,5633 ----
   *****************************************************************************/
  
  DeleteStmt: DELETE_P FROM relation_expr_opt_alias
! 			using_clause where_current_clause returning_clause
  				{
  					DeleteStmt *n = makeNode(DeleteStmt);
  					n->relation = $3;
***************
*** 5691,5697 ****
  UpdateStmt: UPDATE relation_expr_opt_alias
  			SET set_clause_list
  			from_clause
! 			where_clause
  			returning_clause
  				{
  					UpdateStmt *n = makeNode(UpdateStmt);
--- 5683,5689 ----
  UpdateStmt: UPDATE relation_expr_opt_alias
  			SET set_clause_list
  			from_clause
! 			where_current_clause
  			returning_clause
  				{
  					UpdateStmt *n = makeNode(UpdateStmt);
***************
*** 5780,5788 ****
  					n->query = $7;
  					if ($5)
  						n->options |= CURSOR_OPT_HOLD;
  					$$ = (Node *)n;
  				}
! 		;
  
  cursor_options: /*EMPTY*/					{ $$ = 0; }
  			| cursor_options NO SCROLL		{ $$ = $1 | CURSOR_OPT_NO_SCROLL; }
--- 5772,5783 ----
  					n->query = $7;
  					if ($5)
  						n->options |= CURSOR_OPT_HOLD;
+ 					if($7 && ((SelectStmt *)$7)->lockingClause)
+ 						if (((LockingClause *)((SelectStmt *)$7)->lockingClause)->forUpdate)
+ 							n->options |= CURSOR_OPT_FORUPDATE;
  					$$ = (Node *)n;
  				}
! 		; 
  
  cursor_options: /*EMPTY*/					{ $$ = 0; }
  			| cursor_options NO SCROLL		{ $$ = $1 | CURSOR_OPT_NO_SCROLL; }
***************
*** 6483,6488 ****
--- 6478,6491 ----
  			| /*EMPTY*/								{ $$ = NULL; }
  		;
  
+ where_current_clause:
+ 			WHERE a_expr							{ $$ = $2; }
+ 			| WHERE CURRENT OF param_name
+ 				{
+ 					$$ = (Node *) makeString($4);
+ 				}
+ 			| /*EMPTY*/								{ $$ = NULL; }
+ 		;
  
  TableFuncElementList:
  			TableFuncElement
***************
*** 9038,9043 ****
--- 9041,9047 ----
  			| COLUMN
  			| CONSTRAINT
  			| CREATE
+ 			| CURRENT
  			| CURRENT_DATE
  			| CURRENT_ROLE
  			| CURRENT_TIME
*** postgresql-snapshot/src/backend/parser/keywords.c	2007-03-20 10:38:29.000000000 +1100
--- pgbase2103/src/backend/parser/keywords.c	2007-03-28 22:44:35.000000000 +1000
***************
*** 101,106 ****
--- 101,107 ----
  	{"createuser", CREATEUSER},
  	{"cross", CROSS},
  	{"csv", CSV},
+ 	{"current", CURRENT},
  	{"current_date", CURRENT_DATE},
  	{"current_role", CURRENT_ROLE},
  	{"current_time", CURRENT_TIME},
*** postgresql-snapshot/src/backend/parser/analyze.c	2007-03-13 11:33:41.000000000 +1100
--- pgbase2103/src/backend/parser/analyze.c	2007-03-31 17:52:33.184562280 +1000
***************
*** 393,399 ****
  transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
  {
  	Query	   *qry = makeNode(Query);
! 	Node	   *qual;
  
  	qry->commandType = CMD_DELETE;
  
--- 393,399 ----
  transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
  {
  	Query	   *qry = makeNode(Query);
! 	Node	   *qual = NULL;
  
  	qry->commandType = CMD_DELETE;
  
***************
*** 413,419 ****
  	 */
  	transformFromClause(pstate, stmt->usingClause);
  
! 	qual = transformWhereClause(pstate, stmt->whereClause, "WHERE");
  
  	qry->returningList = transformReturningList(pstate, stmt->returningList);
  
--- 413,428 ----
  	 */
  	transformFromClause(pstate, stmt->usingClause);
  
! 	if (stmt->whereClause != NULL)
! 	{
! 		/* WHERE a_expr clause */
! 		if (IsA(stmt->whereClause, A_Expr))
! 			qual = transformWhereClause(pstate, stmt->whereClause, "WHERE");
! 
! 		/* WHERE CURRENT OF cursorname clause */
! 		if (IsA(stmt->whereClause, String))
! 			qry->cursorName = pstrdup(strVal(stmt->whereClause));
! 	}
  
  	qry->returningList = transformReturningList(pstate, stmt->returningList);
  
***************
*** 2781,2787 ****
  transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
  {
  	Query	   *qry = makeNode(Query);
! 	Node	   *qual;
  	ListCell   *origTargetList;
  	ListCell   *tl;
  
--- 2790,2796 ----
  transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
  {
  	Query	   *qry = makeNode(Query);
! 	Node	   *qual = NULL;
  	ListCell   *origTargetList;
  	ListCell   *tl;
  
***************
*** 2801,2807 ****
  
  	qry->targetList = transformTargetList(pstate, stmt->targetList);
  
! 	qual = transformWhereClause(pstate, stmt->whereClause, "WHERE");
  
  	qry->returningList = transformReturningList(pstate, stmt->returningList);
  
--- 2810,2825 ----
  
  	qry->targetList = transformTargetList(pstate, stmt->targetList);
  
! 	if (stmt->whereClause != NULL)
! 	{
! 		/* WHERE a_expr clause */
! 		if (IsA(stmt->whereClause, A_Expr))
! 			qual = transformWhereClause(pstate, stmt->whereClause, "WHERE");
! 
! 		/* WHERE CURRENT OF cursorname clause */
! 		if (IsA(stmt->whereClause, String))
! 			qry->cursorName = pstrdup(strVal(stmt->whereClause));
! 	}
  
  	qry->returningList = transformReturningList(pstate, stmt->returningList);
  
*** postgresql-snapshot/src/backend/optimizer/plan/planner.c	2007-02-27 12:11:25.000000000 +1100
--- pgbase2103/src/backend/optimizer/plan/planner.c	2007-03-31 17:55:33.463155768 +1000
***************
*** 164,169 ****
--- 164,178 ----
  	result->rowMarks = parse->rowMarks;
  	result->nParamExec = list_length(glob->paramlist);
  
+ 	/* If the command is an update or delete on cursor
+ 	 * we need the cursor name.
+ 	 */
+ 	if ((parse->commandType == CMD_DELETE ||
+ 	     parse->commandType == CMD_UPDATE) &&
+ 	     parse->cursorName != NULL)
+ 		/* pass the portal name into the PlannedStmt structure */
+ 		result->cursorName = pstrdup(parse->cursorName); 
+ 
  	return result;
  }
  
*** postgresql-snapshot/src/backend/tcop/pquery.c	2007-03-13 11:33:42.000000000 +1100
--- pgbase2103/src/backend/tcop/pquery.c	2007-03-28 18:17:16.000000000 +1000
***************
*** 936,941 ****
--- 936,945 ----
  		else
  		{
  			ActiveSnapshot = queryDesc->snapshot;
+ 
+ 			if (portal->cursorOptions & CURSOR_OPT_FORUPDATE)
+ 				queryDesc->estate->es_store_uctuple = true;
+ 
  			ExecutorRun(queryDesc, direction, count);
  			nprocessed = queryDesc->estate->es_processed;
  		}
***************
*** 978,983 ****
--- 982,991 ----
  		else
  		{
  			ActiveSnapshot = queryDesc->snapshot;
+ 
+ 			if (portal->cursorOptions & CURSOR_OPT_FORUPDATE)
+ 				queryDesc->estate->es_store_uctuple = true;
+ 
  			ExecutorRun(queryDesc, direction, count);
  			nprocessed = queryDesc->estate->es_processed;
  		}
*** postgresql-snapshot/src/backend/executor/execMain.c	2007-03-29 10:15:38.000000000 +1000
--- pgbase2103/src/backend/executor/execMain.c	2007-03-31 17:57:39.199041008 +1000
***************
*** 26,32 ****
   *
   *
   * IDENTIFICATION
!  *	  $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.292 2007/03/29 00:15:38 tgl Exp $
   *
   *-------------------------------------------------------------------------
   */
--- 26,32 ----
   *
   *
   * IDENTIFICATION
!  *	  $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.290 2007/03/06 02:06:13 momjian Exp $
   *
   *-------------------------------------------------------------------------
   */
***************
*** 52,58 ****
  #include "utils/acl.h"
  #include "utils/lsyscache.h"
  #include "utils/memutils.h"
! 
  
  typedef struct evalPlanQual
  {
--- 52,58 ----
  #include "utils/acl.h"
  #include "utils/lsyscache.h"
  #include "utils/memutils.h"
! #include "commands/portalcmds.h"
  
  typedef struct evalPlanQual
  {
***************
*** 234,239 ****
--- 234,246 ----
  	if (sendTuples)
  		(*dest->rStartup) (dest, operation, queryDesc->tupDesc);
  
+ 	if ( ((operation == CMD_DELETE) || (operation == CMD_UPDATE)) &&
+ 		queryDesc->plannedstmt->cursorName )
+ 	{
+ 		estate->es_useUcPlan = true;
+ 		estate->cursorName = pstrdup(queryDesc->plannedstmt->cursorName);
+ 	}
+ 
  	/*
  	 * run plan
  	 */
***************
*** 1104,1110 ****
  		 * Execute the plan and obtain a tuple
  		 */
  lnext:	;
! 		if (estate->es_useEvalPlan)
  		{
  			planSlot = EvalPlanQualNext(estate);
  			if (TupIsNull(planSlot))
--- 1111,1122 ----
  		 * Execute the plan and obtain a tuple
  		 */
  lnext:	;
! 		if (estate->es_useUcPlan)
! 		{
! 			planSlot = GetCursorSlot(estate, planstate);
! 			numberTuples = 1; 
! 		}
! 		else if (estate->es_useEvalPlan)
  		{
  			planSlot = EvalPlanQualNext(estate);
  			if (TupIsNull(planSlot))
*** postgresql-snapshot/src/backend/executor/execScan.c	2007-02-02 11:07:03.000000000 +1100
--- pgbase2103/src/backend/executor/execScan.c	2007-03-31 17:34:02.026483984 +1000
***************
*** 65,71 ****
  	 * all the overhead and return the raw scan tuple.
  	 */
  	if (!qual && !projInfo)
! 		return (*accessMtd) (node);
  
  	/*
  	 * Check to see if we're still projecting out tuples from a previous scan
--- 65,80 ----
  	 * all the overhead and return the raw scan tuple.
  	 */
  	if (!qual && !projInfo)
! 	{
! 		resultSlot = (*accessMtd) (node);
! 		
! 		/* place the current tuple in estate if we are scanning for
! 		 * updateable cursors */
! 		if (node->ps.state->es_store_uctuple)
! 			node->ps.state->es_uctuple_slot = resultSlot;
! 
! 		return resultSlot;
! 	}
  
  	/*
  	 * Check to see if we're still projecting out tuples from a previous scan
***************
*** 121,126 ****
--- 130,139 ----
  		 */
  		econtext->ecxt_scantuple = slot;
  
+ 		/* place the current tuple also in estate. */
+ 		if (node->ps.state->es_store_uctuple)
+ 			node->ps.state->es_uctuple_slot = slot;
+ 
  		/*
  		 * check that the current tuple satisfies the qual-clause
  		 *
*** postgresql-snapshot/src/backend/utils/mmgr/portalmem.c	2007-03-13 11:33:42.000000000 +1100
--- pgbase2103/src/backend/utils/mmgr/portalmem.c	2007-03-29 11:44:19.000000000 +1000
***************
*** 866,872 ****
  		 * build tupdesc for result tuples. This must match the definition of
  		 * the pg_cursors view in system_views.sql
  		 */
! 		tupdesc = CreateTemplateTupleDesc(6, false);
  		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
  						   TEXTOID, -1, 0);
  		TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement",
--- 866,872 ----
  		 * build tupdesc for result tuples. This must match the definition of
  		 * the pg_cursors view in system_views.sql
  		 */
! 		tupdesc = CreateTemplateTupleDesc(7, false);
  		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
  						   TEXTOID, -1, 0);
  		TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement",
***************
*** 877,883 ****
  						   BOOLOID, -1, 0);
  		TupleDescInitEntry(tupdesc, (AttrNumber) 5, "is_scrollable",
  						   BOOLOID, -1, 0);
! 		TupleDescInitEntry(tupdesc, (AttrNumber) 6, "creation_time",
  						   TIMESTAMPTZOID, -1, 0);
  
  		funcctx->tuple_desc = BlessTupleDesc(tupdesc);
--- 877,885 ----
  						   BOOLOID, -1, 0);
  		TupleDescInitEntry(tupdesc, (AttrNumber) 5, "is_scrollable",
  						   BOOLOID, -1, 0);
! 		TupleDescInitEntry(tupdesc, (AttrNumber) 6, "is_updateable",
! 						   BOOLOID, -1, 0);
! 		TupleDescInitEntry(tupdesc, (AttrNumber) 7, "creation_time",
  						   TIMESTAMPTZOID, -1, 0);
  
  		funcctx->tuple_desc = BlessTupleDesc(tupdesc);
***************
*** 904,911 ****
  		Portal		portal;
  		Datum		result;
  		HeapTuple	tuple;
! 		Datum		values[6];
! 		bool		nulls[6];
  
  		portal = hentry->portal;
  		MemSet(nulls, 0, sizeof(nulls));
--- 906,913 ----
  		Portal		portal;
  		Datum		result;
  		HeapTuple	tuple;
! 		Datum		values[7];
! 		bool		nulls[7];
  
  		portal = hentry->portal;
  		MemSet(nulls, 0, sizeof(nulls));
***************
*** 915,925 ****
  			nulls[1] = true;
  		else
  			values[1] = DirectFunctionCall1(textin,
! 										CStringGetDatum(portal->sourceText));
  		values[2] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_HOLD);
  		values[3] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_BINARY);
  		values[4] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_SCROLL);
! 		values[5] = TimestampTzGetDatum(portal->creation_time);
  
  		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
  		result = HeapTupleGetDatum(tuple);
--- 917,928 ----
  			nulls[1] = true;
  		else
  			values[1] = DirectFunctionCall1(textin,
! 								CStringGetDatum(portal->sourceText));
  		values[2] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_HOLD);
  		values[3] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_BINARY);
  		values[4] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_SCROLL);
! 		values[5] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_FORUPDATE);
! 		values[6] = TimestampTzGetDatum(portal->creation_time);
  
  		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
  		result = HeapTupleGetDatum(tuple);
*** postgresql-snapshot/src/backend/commands/portalcmds.c	2007-03-13 11:33:39.000000000 +1100
--- pgbase2103/src/backend/commands/portalcmds.c	2007-03-29 12:25:54.000000000 +1000
***************
*** 31,37 ****
  #include "tcop/pquery.h"
  #include "tcop/tcopprot.h"
  #include "utils/memutils.h"
! 
  
  /*
   * PerformCursorOpen
--- 31,38 ----
  #include "tcop/pquery.h"
  #include "tcop/tcopprot.h"
  #include "utils/memutils.h"
! #include "executor/tuptable.h"
! #include "nodes/execnodes.h"
  
  /*
   * PerformCursorOpen
***************
*** 48,53 ****
--- 49,55 ----
  	PlannedStmt *plan;
  	Portal		portal;
  	MemoryContext oldContext;
+ 	ListCell        *rm;
  
  	/*
  	 * Disallow empty-string cursor name (conflicts with protocol-level
***************
*** 59,64 ****
--- 61,74 ----
  				 errmsg("invalid cursor name: must not be empty")));
  
  	/*
+ 	 * We don't allow an updateable WITH HOLD cursor. We don't support 
+ 	 * this feature yet.*/
+ 	if ( (stmt->options & CURSOR_OPT_HOLD) && (stmt->options & CURSOR_OPT_FORUPDATE) )
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				errmsg("Holdable cursors cannot be Updated")));
+ 
+ 	/*
  	 * If this is a non-holdable cursor, we require that this statement has
  	 * been executed inside a transaction block (or else, it would have no
  	 * user-visible effect).
***************
*** 105,114 ****
  				 errmsg("DECLARE CURSOR cannot specify INTO")));
  
  	if (query->rowMarks != NIL)
! 		ereport(ERROR,
! 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! 			  errmsg("DECLARE CURSOR ... FOR UPDATE/SHARE is not supported"),
! 				 errdetail("Cursors must be READ ONLY.")));
  
  	/* plan the query */
  	plan = planner(query, true, stmt->options, params);
--- 115,137 ----
  				 errmsg("DECLARE CURSOR cannot specify INTO")));
  
  	if (query->rowMarks != NIL)
! 	{
! 		foreach(rm, query->rowMarks)
! 		{
! 			RowMarkClause	*rmc = (RowMarkClause *) lfirst(rm);
! 
! 			if (rmc->forUpdate == FALSE)
! 			       ereport(ERROR,
! 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! 					errmsg("DECLARE CURSOR ... FOR SHARE is not supported"),
! 					errdetail("Cursors must not be FOR SHARE.")));
! 		}
! 		if ((stmt->options & CURSOR_OPT_FORUPDATE) && (list_length(query->rowMarks) != 1)) 
! 			ereport(ERROR,
! 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! 			errmsg("Only one target table can be specified for updateable cursors")));
! 	}
! 
  
  	/* plan the query */
  	plan = planner(query, true, stmt->options, params);
***************
*** 469,471 ****
--- 492,564 ----
  	 */
  	MemoryContextDeleteChildren(PortalGetHeapMemory(portal));
  }
+ 
+ /*
+  * GetCursorSlot
+  *	Returns the tupleslot at which the cursor is currently positioned
+  *
+  *	estate: estate of the current command
+  *	planstate: The current planstate
+  */
+ TupleTableSlot *
+ GetCursorSlot(EState *estate, PlanState *planstate)
+ {
+ 	TupleTableSlot *slot = NULL;
+ 	QueryDesc *queryDesc;
+ 	Portal portal;
+ 	ExprContext *econtext;
+ 	ExprDoneCond isDone;
+ 
+ 	/*
+ 	 * Disallow empty-string cursor name (conflicts with protocol-level
+ 	 * unnamed portal).
+ 	 */
+ 	if (!estate->cursorName || estate->cursorName[0] == '\0')
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INVALID_CURSOR_NAME),
+ 				 errmsg("invalid cursor name: must not be empty")));
+ 
+ 	/* get the portal from the portal name */
+ 	portal = GetPortalByName(estate->cursorName);
+ 
+ 	if (!PortalIsValid(portal))
+ 	{
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_UNDEFINED_CURSOR),
+ 				 errmsg("cursor \"%s\" does not exist", estate->cursorName)));
+ 	}
+ 	else if (!(portal->cursorOptions & CURSOR_OPT_FORUPDATE))
+ 	{
+ 		/* Positioned deletes only allowed for updateable cursors. */
+ 		ereport(ERROR,
+ 		 		(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ 				 errmsg("cursor is not updateable")));
+ 	}
+ 
+ 	queryDesc = PortalGetQueryDesc(portal);
+ 
+ 	if (queryDesc && PointerIsValid(queryDesc))
+ 		slot = queryDesc->estate->es_uctuple_slot;
+ 
+ 	if ( (!slot) || (! PointerIsValid(slot)) )
+ 	{
+ 		/* Either the tuple was already deleted or the user
+ 		 * is trying to sneak in even before giving a fetch.
+ 		 */
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ 				errmsg("Invalid cursor position"), 
+ 					errdetail("Use Fetch or Move to position the cursor")));
+ 	}
+ 
+ 	/* Project the tuple */
+ 	if (planstate->ps_ProjInfo)
+ 	{
+ 		econtext = planstate->ps_ExprContext;
+ 		ResetExprContext(econtext);
+ 		econtext->ecxt_scantuple = slot;
+ 		slot = ExecProject(planstate->ps_ProjInfo, &isDone);
+ 		ResetExprContext(econtext);
+ 	}
+ 	return slot;
+ }
*** postgresql-snapshot/src/include/nodes/plannodes.h	2007-02-27 12:11:26.000000000 +1100
--- pgbase2103/src/include/nodes/plannodes.h	2007-03-28 19:08:17.000000000 +1000
***************
*** 52,57 ****
--- 52,59 ----
  
  	Bitmapset  *rewindPlanIDs;	/* indices of subplans that require REWIND */
  
+ 	char		*cursorName;	/* The updateable cursor name for the current query */
+ 
  	/*
  	 * If the query has a returningList then the planner will store a list of
  	 * processed targetlists (one per result relation) here.  We must have a
*** postgresql-snapshot/src/include/nodes/parsenodes.h	2007-03-20 10:38:32.000000000 +1100
--- pgbase2103/src/include/nodes/parsenodes.h	2007-03-31 15:58:14.735205064 +1000
***************
*** 107,112 ****
--- 107,114 ----
  	bool		hasAggs;		/* has aggregates in tlist or havingQual */
  	bool		hasSubLinks;	/* has subquery SubLink */
  
+ 	char		*cursorName;	/* The updateable cursor name for the current query */
+ 
  	List	   *rtable;			/* list of range table entries */
  	FromExpr   *jointree;		/* table join tree (FROM and WHERE clauses) */
  
***************
*** 686,691 ****
--- 688,694 ----
  	List	   *usingClause;	/* optional using clause for more tables */
  	Node	   *whereClause;	/* qualifications */
  	List	   *returningList;	/* list of expressions to return */
+ 	
  } DeleteStmt;
  
  /* ----------------------
***************
*** 1434,1439 ****
--- 1437,1443 ----
  #define CURSOR_OPT_NO_SCROLL	0x0004
  #define CURSOR_OPT_INSENSITIVE	0x0008
  #define CURSOR_OPT_HOLD			0x0010
+ #define CURSOR_OPT_FORUPDATE	0x0020
  
  typedef struct DeclareCursorStmt
  {
*** postgresql-snapshot/src/include/commands/portalcmds.h	2007-03-13 11:33:43.000000000 +1100
--- pgbase2103/src/include/commands/portalcmds.h	2007-03-29 00:16:54.000000000 +1000
***************
*** 16,21 ****
--- 16,23 ----
  
  #include "nodes/parsenodes.h"
  #include "utils/portal.h"
+ #include "executor/tuptable.h"
+ #include "nodes/execnodes.h"
  
  
  extern void PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params,
***************
*** 30,33 ****
--- 32,37 ----
  
  extern void PersistHoldablePortal(Portal portal);
  
+ extern TupleTableSlot *GetCursorSlot(EState *estate, PlanState *planstate);
+ 
  #endif   /* PORTALCMDS_H */
*** postgresql-snapshot/src/include/nodes/execnodes.h	2007-03-28 09:21:12.000000000 +1000
--- pgbase2103/src/include/nodes/execnodes.h	2007-03-28 22:54:20.000000000 +1000
***************
*** 7,13 ****
   * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
   * Portions Copyright (c) 1994, Regents of the University of California
   *
!  * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.171 2007/03/27 23:21:12 tgl Exp $
   *
   *-------------------------------------------------------------------------
   */
--- 7,13 ----
   * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
   * Portions Copyright (c) 1994, Regents of the University of California
   *
!  * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.170 2007/02/27 01:11:26 tgl Exp $
   *
   *-------------------------------------------------------------------------
   */
***************
*** 312,317 ****
--- 312,322 ----
  
  	TupleTableSlot *es_trig_tuple_slot; /* for trigger output tuples */
  
+ 	bool		es_store_uctuple;
+ 	bool		es_useUcPlan;
+ 	char		*cursorName;
+ 	TupleTableSlot *es_uctuple_slot; /* for updateable cursor tuple */
+ 
  	Relation	es_into_relation_descriptor;	/* for SELECT INTO */
  	bool		es_into_relation_use_wal;
  
*** head_210307/src/test/regress/expected/portals.out	2007-03-21 09:30:33.000000000 +1100
--- head_300307/src/test/regress/expected/portals.out	2007-03-30 15:39:23.000000000 +1000
***************
*** 869,871 ****
--- 869,1009 ----
   c2   | declare c2 cursor with hold for select count_tt1_v(), count_tt1_s(); | t           | f         | f
  (1 row)
  
+ -- Create an updatable cursor and show that delete at position works
+ CREATE TABLE t4(i int, j text);
+ INSERT INTO t4 VALUES(1, 'one');
+ INSERT INTO t4 VALUES(2, 'two');
+ INSERT INTO t4 VALUES(3, 'three');
+ INSERT INTO t4 VALUES(4, 'four');
+ INSERT INTO t4 VALUES(5, 'five');
+ INSERT INTO t4 VALUES(6, 'six');
+ INSERT INTO t4 VALUES(7, 'seven');
+ INSERT INTO t4 VALUES(8, 'eight');
+ INSERT INTO t4 VALUES(9, 'nine');
+ SELECT * FROM t4;
+  i |   j   
+ ---+-------
+  1 | one
+  2 | two
+  3 | three
+  4 | four
+  5 | five
+  6 | six
+  7 | seven
+  8 | eight
+  9 | nine
+ (9 rows)
+ 
+ BEGIN;
+ DECLARE c1 CURSOR FOR SELECT * FROM t4 FOR UPDATE;
+ FETCH c1;
+  i |  j  
+ ---+-----
+  1 | one
+ (1 row)
+ 
+ DELETE FROM t4 WHERE CURRENT OF c1;
+ FETCH ALL FROM c1;
+  i |   j   
+ ---+-------
+  2 | two
+  3 | three
+  4 | four
+  5 | five
+  6 | six
+  7 | seven
+  8 | eight
+  9 | nine
+ (8 rows)
+ 
+ SELECT * FROM t4;
+  i |   j   
+ ---+-------
+  2 | two
+  3 | three
+  4 | four
+  5 | five
+  6 | six
+  7 | seven
+  8 | eight
+  9 | nine
+ (8 rows)
+ 
+ CLOSE c1;
+ COMMIT;
+ -- Create an updatable cursor and show that update at position works
+ SELECT * FROM t4;
+  i |   j   
+ ---+-------
+  2 | two
+  3 | three
+  4 | four
+  5 | five
+  6 | six
+  7 | seven
+  8 | eight
+  9 | nine
+ (8 rows)
+ 
+ BEGIN;
+ DECLARE c1 CURSOR FOR SELECT * FROM t4 FOR UPDATE;
+ FETCH c1;
+  i |  j  
+ ---+-----
+  2 | two
+ (1 row)
+ 
+ UPDATE t4 SET i = 8 WHERE CURRENT OF c1;
+ SELECT * FROM t4;
+  i |   j   
+ ---+-------
+  3 | three
+  4 | four
+  5 | five
+  6 | six
+  7 | seven
+  8 | eight
+  9 | nine
+  8 | two
+ (8 rows)
+ 
+ CLOSE c1;
+ COMMIT;
+ -- Updatable cursor combined with MOVE
+ BEGIN;
+ DECLARE c1 CURSOR FOR SELECT * FROM t4 FOR UPDATE;
+ FETCH c1;
+  i |   j   
+ ---+-------
+  3 | three
+ (1 row)
+ 
+ UPDATE t4 SET i = 10 WHERE CURRENT OF c1;
+ MOVE 5 IN c1;
+ FETCH c1;
+  i |  j   
+ ---+------
+  9 | nine
+ (1 row)
+ 
+ UPDATE t4 SET i = 12 WHERE CURRENT OF c1;
+ CLOSE c1;
+ COMMIT;
+ -- Update on j, ordering on i
+ BEGIN;
+ DECLARE c1 CURSOR FOR SELECT j FROM t4 ORDER BY i FOR UPDATE OF i;
+ ERROR:  relation "i" in FOR UPDATE/SHARE clause not found in FROM clause
+ ROLLBACK;
+ -- Attempt a DELETE WHERE CURRENT OF prior to FETCHing a row, should fail
+ BEGIN;
+ DECLARE c1 CURSOR FOR SELECT * FROM t4 FOR UPDATE;
+ -- should fail
+ DELETE FROM t4 WHERE CURRENT OF c1;
+ ERROR:  Invalid cursor position.
+ ROLLBACK;
+ --Attempt to use a WITH HOLD updatable cursor, should fail
+ BEGIN;
+ DECLARE c1 CURSOR WITH HOLD FOR SELECT * FROM t4 FOR UPDATE;
+ ERROR:  Holdable cursors cannot be Updated
+ ROLLBACK;
+ DROP TABLE t4;
*** head_210307/src/test/regress/sql/portals.sql	2007-03-21 09:30:33.000000000 +1100
--- head_300307/src/test/regress/sql/portals.sql	2007-03-30 15:29:49.000000000 +1000
***************
*** 303,305 ****
--- 303,366 ----
  PREPARE cprep AS
    SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors;
  EXECUTE cprep;
+ 
+ 
+ -- Create an updatable cursor and show that delete at position works
+ CREATE TABLE t4(i int, j text);
+ INSERT INTO t4 VALUES(1, 'one');
+ INSERT INTO t4 VALUES(2, 'two');
+ INSERT INTO t4 VALUES(3, 'three');
+ INSERT INTO t4 VALUES(4, 'four');
+ INSERT INTO t4 VALUES(5, 'five');
+ INSERT INTO t4 VALUES(6, 'six');
+ INSERT INTO t4 VALUES(7, 'seven');
+ INSERT INTO t4 VALUES(8, 'eight');
+ INSERT INTO t4 VALUES(9, 'nine');
+ 
+ SELECT * FROM t4;
+ BEGIN;
+ DECLARE c1 CURSOR FOR SELECT * FROM t4 FOR UPDATE;
+ FETCH c1;
+ DELETE FROM t4 WHERE CURRENT OF c1;
+ FETCH ALL FROM c1;
+ SELECT * FROM t4;
+ CLOSE c1;
+ COMMIT;
+ 
+ -- Create an updatable cursor and show that update at position works
+ SELECT * FROM t4;
+ BEGIN;
+ DECLARE c1 CURSOR FOR SELECT * FROM t4 FOR UPDATE;
+ FETCH c1;
+ UPDATE t4 SET i = 8 WHERE CURRENT OF c1;
+ SELECT * FROM t4;
+ CLOSE c1;
+ COMMIT;
+ 
+ -- Updatable cursor combined with MOVE
+ BEGIN;
+ DECLARE c1 CURSOR FOR SELECT * FROM t4 FOR UPDATE;
+ FETCH c1;
+ UPDATE t4 SET i = 10 WHERE CURRENT OF c1;
+ MOVE 5 IN c1;
+ FETCH c1;
+ UPDATE t4 SET i = 12 WHERE CURRENT OF c1;
+ CLOSE c1;
+ COMMIT;
+ -- Update on j, ordering on i
+ BEGIN;
+ DECLARE c1 CURSOR FOR SELECT j FROM t4 ORDER BY i FOR UPDATE OF i;
+ ROLLBACK;
+ 
+ -- Attempt a DELETE WHERE CURRENT OF prior to FETCHing a row, should fail
+ BEGIN;
+ DECLARE c1 CURSOR FOR SELECT * FROM t4 FOR UPDATE;
+ -- should fail
+ DELETE FROM t4 WHERE CURRENT OF c1;
+ ROLLBACK;
+ 
+ --Attempt to use a WITH HOLD updatable cursor, should fail
+ BEGIN;
+ DECLARE c1 CURSOR WITH HOLD FOR SELECT * FROM t4 FOR UPDATE;
+ ROLLBACK;
+ DROP TABLE t4;
*** postgresql-snapshot/src/backend/catalog/system_views.sql	2007-03-17 04:57:36.000000000 +1100
--- pgbase2103/src/backend/catalog/system_views.sql	2007-03-29 11:09:24.000000000 +1000
***************
*** 150,159 ****
  
  CREATE VIEW pg_cursors AS
      SELECT C.name, C.statement, C.is_holdable, C.is_binary,
!            C.is_scrollable, C.creation_time
      FROM pg_cursor() AS C
           (name text, statement text, is_holdable boolean, is_binary boolean,
!           is_scrollable boolean, creation_time timestamptz);
  
  CREATE VIEW pg_prepared_xacts AS
      SELECT P.transaction, P.gid, P.prepared,
--- 150,159 ----
  
  CREATE VIEW pg_cursors AS
      SELECT C.name, C.statement, C.is_holdable, C.is_binary,
!            C.is_scrollable, C.is_updateable, C.creation_time
      FROM pg_cursor() AS C
           (name text, statement text, is_holdable boolean, is_binary boolean,
!           is_scrollable boolean, is_updateable boolean, creation_time timestamptz);
  
  CREATE VIEW pg_prepared_xacts AS
      SELECT P.transaction, P.gid, P.prepared,

*** org/doc/src/sgml/ref/delete.sgml	Fri Mar 30 20:01:32 2007
--- pgsql/doc/src/sgml/ref/delete.sgml	Fri Mar 30 18:44:02 2007
***************
*** 22,28 ****
  <synopsis>
  DELETE FROM [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ [ AS ] <replaceable class="parameter">alias</replaceable> ]
      [ USING <replaceable class="PARAMETER">usinglist</replaceable> ]
!     [ WHERE <replaceable class="PARAMETER">condition</replaceable> ]
      [ RETURNING * | <replaceable class="parameter">output_expression</replaceable> [ AS <replaceable class="parameter">output_name</replaceable> ] [, ...] ]
  </synopsis>
   </refsynopsisdiv>
--- 22,28 ----
  <synopsis>
  DELETE FROM [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ [ AS ] <replaceable class="parameter">alias</replaceable> ]
      [ USING <replaceable class="PARAMETER">usinglist</replaceable> ]
!     [ [ WHERE <replaceable class="PARAMETER">condition</replaceable> ] | [ WHERE CURRENT OF <replaceable class="PARAMETER">cursor_name</replaceable> ] ]
      [ RETURNING * | <replaceable class="parameter">output_expression</replaceable> [ AS <replaceable class="parameter">output_name</replaceable> ] [, ...] ]
  </synopsis>
   </refsynopsisdiv>
***************
*** 162,167 ****
--- 162,176 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="PARAMETER">cursor_name</replaceable></term>
+     <listitem>
+      <para>
+       The name of the cursor to use with <command>WHERE CURRENT OF</> condition.
+      </para>
+     </listitem>
+    </varlistentry>
    </variablelist>
   </refsect1>
  
***************
*** 236,241 ****
--- 245,257 ----
     Delete completed tasks, returning full details of the deleted rows:
  <programlisting>
  DELETE FROM tasks WHERE status = 'DONE' RETURNING *;
+ </programlisting>      
+   </para>
+ 
+    <para>
+    Delete the task, on which the cursor c_tasks is pointing currently:
+ <programlisting>
+ DELETE FROM tasks WHERE CURRENT OF c_tasks;
  </programlisting>      
    </para>
   </refsect1>
*** org/doc/src/sgml/ref/declare.sgml	Fri Mar 30 20:02:04 2007
--- pgsql/doc/src/sgml/ref/declare.sgml	Fri Mar 30 18:26:35 2007
***************
*** 171,181 ****
       <para>
        <literal>FOR READ ONLY</literal> indicates that the cursor will
        be used in a read-only mode.  <literal>FOR UPDATE</literal>
!       indicates that the cursor will be used to update tables.  Since
!       cursor updates are not currently supported in
!       <productname>PostgreSQL</productname>, specifying <literal>FOR
!       UPDATE</literal> will cause an error message and specifying
!       <literal>FOR READ ONLY</literal> has no effect.
       </para>
      </listitem>
     </varlistentry>
--- 171,177 ----
       <para>
        <literal>FOR READ ONLY</literal> indicates that the cursor will
        be used in a read-only mode.  <literal>FOR UPDATE</literal>
!       indicates that the cursor will be used to update tables.
       </para>
      </listitem>
     </varlistentry>
***************
*** 184,191 ****
      <term><replaceable class="parameter">column</replaceable></term>
      <listitem>
       <para>
!       Column(s) to be updated by the cursor.  Since cursor updates are
!       not currently supported in
        <productname>PostgreSQL</productname>, the <literal>FOR
        UPDATE</literal> clause provokes an error message.
       </para>
--- 180,187 ----
      <term><replaceable class="parameter">column</replaceable></term>
      <listitem>
       <para>
!       Column(s) to be updated by the cursor.  Since cursor updates on column(s)
!       are not currently supported in
        <productname>PostgreSQL</productname>, the <literal>FOR
        UPDATE</literal> clause provokes an error message.
       </para>
***************
*** 283,293 ****
     The SQL standard allows cursors only in embedded
     <acronym>SQL</acronym> and in modules. <productname>PostgreSQL</>
     permits cursors to be used interactively.
-   </para>
- 
-   <para>
-    The SQL standard allows cursors to update table data. All
-    <productname>PostgreSQL</> cursors are read only.
    </para>
  
    <para>
--- 279,284 ----
*** org/doc/src/sgml/ref/update.sgml	Fri Mar 30 20:00:48 2007
--- pgsql/doc/src/sgml/ref/update.sgml	Fri Mar 30 19:37:28 2007
***************
*** 24,30 ****
      SET { <replaceable class="PARAMETER">column</replaceable> = { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } |
            ( <replaceable class="PARAMETER">column</replaceable> [, ...] ) = ( { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } [, ...] ) } [, ...]
      [ FROM <replaceable class="PARAMETER">fromlist</replaceable> ]
!     [ WHERE <replaceable class="PARAMETER">condition</replaceable> ]
      [ RETURNING * | <replaceable class="parameter">output_expression</replaceable> [ AS <replaceable class="parameter">output_name</replaceable> ] [, ...] ]
  </synopsis>
   </refsynopsisdiv>
--- 24,30 ----
      SET { <replaceable class="PARAMETER">column</replaceable> = { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } |
            ( <replaceable class="PARAMETER">column</replaceable> [, ...] ) = ( { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } [, ...] ) } [, ...]
      [ FROM <replaceable class="PARAMETER">fromlist</replaceable> ]
!     [ [ WHERE <replaceable class="PARAMETER">condition</replaceable> ] | [ WHERE CURRENT OF <replaceable class="PARAMETER">cursor_name</replaceable> ] ]
      [ RETURNING * | <replaceable class="parameter">output_expression</replaceable> [ AS <replaceable class="parameter">output_name</replaceable> ] [, ...] ]
  </synopsis>
   </refsynopsisdiv>
***************
*** 181,186 ****
--- 181,195 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="PARAMETER">cursor_name</replaceable></term>
+     <listitem>
+      <para>
+       The name of the cursor to use with <command>WHERE CURRENT OF</> condition.
+      </para>
+     </listitem>
+    </varlistentry>
    </variablelist>
   </refsect1>
  
***************
*** 244,249 ****
--- 253,269 ----
  </programlisting>
    </para>
  
+    <para>
+    Change the word to <literal>Dramatic</> in the
+    column <structfield>kind</> of the table <structname>films</structname>,
+    on the row on which the cursor c_tasks is positioned currently:
+ 
+ <programlisting>
+ UPDATE films SET kind = 'Dramatic' WHERE CURRENT OF c_tasks;
+ </programlisting>      
+   </para>
+ 
+ 
    <para>
     Adjust temperature entries and reset precipitation to its default
     value in one row of the table <structname>weather</structname>:
***************
*** 309,314 ****
--- 329,335 ----
  COMMIT;
  </programlisting>
    </para>
+ 
   </refsect1>
  
   <refsect1>
*** org/doc/src/sgml/config.sgml	Fri Mar 30 18:04:47 2007
--- pgsql/doc/src/sgml/config.sgml	Fri Mar 30 17:45:03 2007
***************
*** 1,5 ****
  <!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.118 2007/03/26 01:41:57 tgl Exp $ -->
! 
  <chapter Id="runtime-config">
    <title>Server Configuration</title>
  
--- 1,5 ----
  <!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.118 2007/03/26 01:41:57 tgl Exp $ -->
! <!DOCTYPE Book PUBLIC "-//OASIS//DTD DocBook V4.2//EN">
  <chapter Id="runtime-config">
    <title>Server Configuration</title>
  
***************
*** 2229,2235 ****
         <para>
          <productname>PostgreSQL</productname> supports several methods
           for logging server messages, including
!          <systemitem>stderr</systemitem> and
           <systemitem>syslog</systemitem>. On Windows, 
           <systemitem>eventlog</systemitem> is also supported. Set this
           parameter to a list of desired log destinations separated by
--- 2229,2235 ----
         <para>
          <productname>PostgreSQL</productname> supports several methods
           for logging server messages, including
!          <systemitem>stderr</systemitem>, <systemitem>sqllog</systemitem> and
           <systemitem>syslog</systemitem>. On Windows, 
           <systemitem>eventlog</systemitem> is also supported. Set this
           parameter to a list of desired log destinations separated by
***************
*** 2267,2274 ****
        </indexterm>
        <listitem>
         <para>
!         When <varname>redirect_stderr</> is enabled, this parameter
!         determines the directory in which log files will be created.
          It can be specified as an absolute path, or relative to the
          cluster data directory.
          This parameter can only be set in the <filename>postgresql.conf</>
--- 2267,2274 ----
        </indexterm>
        <listitem>
         <para>
!         When <varname>redirect_stderr</> is enabled or <varname>log_destination</> is set to <systemitem>sqllog</systemitem>, 
!         this parameter determines the directory in which log files will be created.
          It can be specified as an absolute path, or relative to the
          cluster data directory.
          This parameter can only be set in the <filename>postgresql.conf</>
***************
*** 2284,2291 ****
        </indexterm>
        <listitem>
         <para>
!         When <varname>redirect_stderr</varname> is enabled, this parameter
!         sets the file names of the created log files.  The value
          is treated as a <systemitem>strftime</systemitem> pattern,
          so <literal>%</literal>-escapes
          can be used to specify time-varying file names.
--- 2284,2291 ----
        </indexterm>
        <listitem>
         <para>
!         When <varname>redirect_stderr</varname> is enabled or <varname>log_destination</> is set to <systemitem>sqllog</systemitem>,
! 	this parameter sets the file names of the created log files.  The value
          is treated as a <systemitem>strftime</systemitem> pattern,
          so <literal>%</literal>-escapes
          can be used to specify time-varying file names.
***************
*** 2308,2315 ****
        </indexterm>
        <listitem>
         <para>
!         When <varname>redirect_stderr</varname> is enabled, this parameter
!         determines the maximum lifetime of an individual log file.
          After this many minutes have elapsed, a new log file will
          be created.  Set to zero to disable time-based creation of
          new log files.
--- 2308,2315 ----
        </indexterm>
        <listitem>
         <para>
!         When <varname>redirect_stderr</varname> is enabled or <varname>log_destination</> is set to <systemitem>sqllog</systemitem>,
! 	this parameter determines the maximum lifetime of an individual log file.
          After this many minutes have elapsed, a new log file will
          be created.  Set to zero to disable time-based creation of
          new log files.
***************
*** 2326,2333 ****
        </indexterm>
        <listitem>
         <para>
!         When <varname>redirect_stderr</varname> is enabled, this parameter
!         determines the maximum size of an individual log file.
          After this many kilobytes have been emitted into a log file,
          a new log file will be created.  Set to zero to disable size-based
          creation of new log files.
--- 2326,2333 ----
        </indexterm>
        <listitem>
         <para>
!         When <varname>redirect_stderr</varname> is enabled or <varname>log_destination</> is set to <systemitem>sqllog</systemitem>,
! 	this parameter determines the maximum size of an individual log file.
          After this many kilobytes have been emitted into a log file,
          a new log file will be created.  Set to zero to disable size-based
          creation of new log files.
***************
*** 2344,2351 ****
        </indexterm>
        <listitem>
         <para>
!         When <varname>redirect_stderr</varname> is enabled, this parameter will cause
!         <productname>PostgreSQL</productname> to truncate (overwrite),
          rather than append to, any existing log file of the same name.
          However, truncation will occur only when a new file is being opened
          due to time-based rotation, not during server startup or size-based
--- 2344,2351 ----
        </indexterm>
        <listitem>
         <para>
!         When <varname>redirect_stderr</varname> is enabled or <varname>log_destination</> is set to <systemitem>sqllog</systemitem>,
! 	this parameter will cause <productname>PostgreSQL</productname> to truncate (overwrite),
          rather than append to, any existing log file of the same name.
          However, truncation will occur only when a new file is being opened
          due to time-based rotation, not during server startup or size-based
***************
*** 2386,2393 ****
        </indexterm>
        <listitem>
         <para>
!         When logging to <application>syslog</> is enabled, this parameter
!         determines the <application>syslog</application>
          <quote>facility</quote> to be used.  You can choose
          from <literal>LOCAL0</>, <literal>LOCAL1</>,
          <literal>LOCAL2</>, <literal>LOCAL3</>, <literal>LOCAL4</>,
--- 2386,2393 ----
        </indexterm>
        <listitem>
         <para>
!         When logging to <application>syslog</> is enabled or <varname>log_destination</> is set to <application>sqllog</application>,
! 	this parameter determines the <application>syslog</application>
          <quote>facility</quote> to be used.  You can choose
          from <literal>LOCAL0</>, <literal>LOCAL1</>,
          <literal>LOCAL2</>, <literal>LOCAL3</>, <literal>LOCAL4</>,
***************
*** 2408,2415 ****
        </indexterm>
         <listitem>
          <para>
!          When logging to <application>syslog</> is enabled, this parameter
!          determines the program name used to identify
           <productname>PostgreSQL</productname> messages in
           <application>syslog</application> logs. The default is
           <literal>postgres</literal>.
--- 2408,2415 ----
        </indexterm>
         <listitem>
          <para>
!          When logging to <application>syslog</> is enabled or <varname>log_destination</> is set to <application>sqllog</application>,
! 	 this parameter determines the program name used to identify
           <productname>PostgreSQL</productname> messages in
           <application>syslog</application> logs. The default is
           <literal>postgres</literal>.
