diff -rc head_260207/src/backend/commands/portalcmds.c head_260207_jb/src/backend/commands/portalcmds.c
*** head_260207/src/backend/commands/portalcmds.c	2007-02-26 17:12:37.000000000 +1100
--- head_260207_jb/src/backend/commands/portalcmds.c	2007-02-26 16:26:44.000000000 +1100
***************
*** 90,99 ****
  				(errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
  				 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 = planner(query, true, stmt->options, params);
  
--- 90,100 ----
  				(errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
  				 errmsg("DECLARE CURSOR cannot specify INTO")));
  	if (query->rowMarks != NIL)
! 		if (query->forUpdate == FALSE)
! 		       ereport(ERROR,
!                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! 			 errmsg("DECLARE CURSOR ... FOR SHARE is not supported"),
!                                 errdetail("Cursors must not be FOR SHARE.")));
  
  	plan = planner(query, true, stmt->options, params);
  
/*-------------------------------------------------
 * 
 * ctidListStore.c
 * 	Contains the processing relating to the storage of the list of ctids
 *	required for Updatable Cursor.
 *
 *	The details to be handled here include:
 *	
 *	use of shared memory to hold basic list
 *	format and use of file for permanent storage of list
 *	functions to access and search the shared memory, ie use the list
 *	functions to access and build the list
 *	functions to initialise and empty the list
 *	functions to initialise and remove the file associated with the list
 *	functions to populate shared memory from existing ctid files during 
 *	database startup.
 *
 * INTERFACE ROUTINES
 *
 * saveCtids(ItemPointer ctid)
 */


#include "backend/executor/ctidListStore.h"

/*
 * Directory where CTID list files reside within PGDATA
 */

#define CTID_DIR	"pg_ctids"

static List *ctidList;      /* list of ctids for updatable cursor */ 

static void RegisterCtidRecord();
static void ReadCtidFile();
static void ProcessCtidRecords();

int max_ctids_in_list = 1000;	/* This is for performance reasons */
typedef struct CtidData
{
	/*
	 * Number of Ctid records in the list
	 */
	int	CtidCount;

	ItemPointer	ctidArray[1];	/* VARIABLE LENGTH ARRAY */	
} CtidData; /* VARIABLE LENGTH STRUCT */

static void CtidShmemSize()
{

        Size            size;

        /* Need the fixed struct and the  ctid */
        size = offsetof(CtidData, ctidArray);
        size = add_size(size, sizeof(ItemPointer));
        size = MAXALIGN(size);

        return size;
}


static void CtidShmemInit()
{

	bool found;
	CtidState =  ShmemInitStruct("Current Tuple Id Table",
                                     CtidShmemSize(),
                                     &found);
}


/************************************************************************/
/* State file support                                                                                                   */
/************************************************************************/

#define CtidListFilePath(path, ) \
        snprintf(path, MAXPGPATH, CTIDLIST_DIR "/%08X", xid)

/*
 * CtidList state file format:
 *
 *      1. CtidListFileHeader
 *      5. CtidRecordOnDisk
 *      6. ...
 *      7. CtidRecordOnDisk (end sentinel, rmid == CTIDLIST_RM_END_ID)
 *      8. CRC32
 *
 * Each segment except the final CRC32 is MAXALIGN'd.
 */
/*
 * Header for a CtidList file
 */
#define CTIDLIST_MAGIC  ????????              /* format identifier HOW IS THIS DEFINED */

typedef struct CtidListFileHeader
{
        uint32          magic;                  /* format identifier */
        uint32          total_len;              /* actual file length */
        TransactionId xid;                      /* original transaction XID */
        Oid                     database;               /* OID of database it was in */
        Oid                     owner;                  /* user running the transaction */
        char            gid[GIDSIZE];   /* GID for transaction */
} CtidListFileHeader;
/*
 * Header for each record in a state file
 *
 * NOTE: len counts only the rmgr data, not the TwoPhaseRecordOnDisk header.
 * The rmgr data will be stored starting on a MAXALIGN boundary.
 */
typedef struct CtidRecordOnDisk
{
        uint32          len;                    /* length of rmgr data */
        CtidListRmgrId rmid;            /* resource manager for this record */
        uint16          info;                   /* flag bits for use by rmgr */
} CtidRecordOnDisk;

/* WILL CTID LIST BE WRITTEN TO WAL???
 * During prepare, the state file is assembled in memory before writing it
 * to WAL and the actual state file.  We use a chain of XLogRecData blocks
 * so that we will be able to pass the state file contents directly to
 * XLogInsert.
 */
static struct xllist
{
        XLogRecData *head;                      /* first data block in the chain */
        XLogRecData *tail;                      /* last block in chain */
        uint32          bytes_free;             /* free bytes left in tail block */
        uint32          total_len;              /* total data bytes in chain */
}       records;


static void StartCtidPrepare()
{
}
static void EndCtidPrepare()
{
}
static void RemoveCtidFile()
{
}

static void 
saveCtid(ItemPointer ctid)
{

	if (ctidList != NIL)
 		lappend(ctidList,ctid);
}

static ItemPointer findCtidInList(ItemPointer ctid)
{
	if (ctidList == NILL)
		return;
	while(

}

/*
 * ctidListStore.h
 *
 * Header file to expose the interface for ctid shared memory and file 
 * processing
 */

static void saveCtid(ItemPointer ctid);
static ItemPointer findCtidInList(ItemPointer ctid);
static void CtidShmemSize();
static void CtidShmemInit();
static void StartCtidPrepare();
static void EndCtidPrepare();
static void RemoveCtidFile();

diff -rc head_260207/src/backend/executor/execMain.c head_260207_jb/src/backend/executor/execMain.c
*** head_260207/src/backend/executor/execMain.c	2007-02-26 17:21:03.000000000 +1100
--- head_260207_jb/src/backend/executor/execMain.c	2007-02-26 16:29:08.000000000 +1100
***************
*** 41,46 ****
--- 41,47 ----
  #include "catalog/toasting.h"
  #include "commands/tablespace.h"
  #include "commands/trigger.h"
+ #include "executor/ctidListStore.h"
  #include "executor/execdebug.h"
  #include "executor/instrument.h"
  #include "executor/nodeSubplan.h"
***************
*** 70,76 ****
  				  List *rangeTable,
  				  CmdType operation,
  				  bool doInstrument);
! static TupleTableSlot *ExecutePlan(EState *estate, PlanState *planstate,
  			CmdType operation,
  			long numberTuples,
  			ScanDirection direction,
--- 71,77 ----
  				  List *rangeTable,
  				  CmdType operation,
  				  bool doInstrument);
! static TupleTableSlot *ExecutePlan(EState *estate, QueryDesc *queryDesc,
  			CmdType operation,
  			long numberTuples,
  			ScanDirection direction,
***************
*** 240,246 ****
  		result = NULL;
  	else
  		result = ExecutePlan(estate,
! 							 queryDesc->planstate,
  							 operation,
  							 count,
  							 direction,
--- 241,247 ----
  		result = NULL;
  	else
  		result = ExecutePlan(estate,
! 							 queryDesc,
  							 operation,
  							 count,
  							 direction,
***************
*** 1009,1022 ****
   */
  static TupleTableSlot *
  ExecutePlan(EState *estate,
! 			PlanState *planstate,
  			CmdType operation,
  			long numberTuples,
  			ScanDirection direction,
  			DestReceiver *dest)
  {
  	JunkFilter *junkfilter;
  	TupleTableSlot *planSlot;
  	TupleTableSlot *slot;
  	ItemPointer tupleid = NULL;
  	ItemPointerData tuple_ctid;
--- 1010,1025 ----
   */
  static TupleTableSlot *
  ExecutePlan(EState *estate,
! 			QueryDesc *queryDesc,
  			CmdType operation,
  			long numberTuples,
  			ScanDirection direction,
  			DestReceiver *dest)
  {
  	JunkFilter *junkfilter;
+ 	PlanState *planstate = queryDesc->planstate;
  	TupleTableSlot *planSlot;
+ 	TupleTaplanstatebleSlot *planSlot;
  	TupleTableSlot *slot;
  	ItemPointer tupleid = NULL;
  	ItemPointerData tuple_ctid;
***************
*** 1103,1110 ****
--- 1106,1116 ----
  
  			/*
  			 * extract the 'ctid' junk attribute.
+ 			 * The third condition here relates to updatable cursor, when
+ 			 * the ctid must always be extracted.
  			 */
  			if (operation == CMD_UPDATE || operation == CMD_DELETE)
+ 			    queryDesc->parsetree->portal != NULL))
  			{
  				datum = ExecGetJunkAttribute(slot, junkfilter->jf_junkAttNo,
  											 &isNull);
***************
*** 1115,1120 ****
--- 1121,1154 ----
  				tupleid = (ItemPointer) DatumGetPointer(datum);
  				tuple_ctid = *tupleid;	/* make sure we don't free the ctid!! */
  				tupleid = &tuple_ctid;
+  
+ 				/*
+ 				 * Save the ctid in portal for updatable cursor during Fetch
+ 				 * request
+ 				 */
+ 				if (((FetchStmt *)queryDesc->parsetree->utilityStmt)->type == T_FetchStmt)
+ 				{
+ 					/*
+ 					 * Save the ctid and tuple in the portal for
+ 					 * updatable cursor during a Fetch request.
+ 					 */
+ 					queryDesc->parsetree->portal->ctid = tupleid;
+ 					queryDesc->parsetree->portal->tuple = slot;
+ 				}
+ 				else if ((queryDesc->parsetree->commandType == CMD_UPDATE ||
+ 					queryDesc->parsetree->commandType == CMD_DELETE) &&
+ 					queryDesc->parsetree->portal != NULL &&
+ 					NodeTag(planstate) == TidScanState &&
+ 					ctidList == NULL)
+ 				{
+ 					/*
+ 					 * Update or Delete statement with updatable cursor
+ 					 * executing the TidScan node for the first time in
+ 				  	 * this query so save the tupleid into a hash table
+ 					 * and store to disk.
+ 					 */
+ 					saveCtid(tupleid);
+ 				}
  			}
  
  			/*
diff -rc head_260207/src/backend/optimizer/path/tidpath.c head_260207_jb/src/backend/optimizer/path/tidpath.c
*** head_260207/src/backend/optimizer/path/tidpath.c	2007-02-26 15:12:00.000000000 +1100
--- head_260207_jb/src/backend/optimizer/path/tidpath.c	2007-02-26 16:30:47.000000000 +1100
***************
*** 41,46 ****
--- 41,47 ----
  
  static bool IsTidEqualClause(OpExpr *node, int varno);
  static bool IsTidEqualAnyClause(ScalarArrayOpExpr *node, int varno);
+ /* static List *build_tidqual(); */
  static List *TidQualFromExpr(Node *expr, int varno);
  static List *TidQualFromRestrictinfo(List *restrictinfo, int varno);
  
***************
*** 140,145 ****
--- 141,192 ----
  
  	return false;
  }
+ /*
+  * build_tid_qual	
+  * 
+  * 	Create a tid qual to represent CTID = ANY and insert it into the tidqual
+  * 	list to be returned. As this tid qual is required only to force a TidScan to
+  *	occur, it is only necessary to populate those fields required to satisfy 
+  * 	the conditions required to force a TidScan path to be created in the plan.
+  *	CTID is not a string it is data stored in a tuple. Need to obtain it from 
+  *	somewhere for use here...
+  *
+  *	This function has been commented out as it may not be needed to implement updatable 
+  *	cursor functionality.
+  *	
+ 
+ static List *
+ build_tidqual()
+ {
+ 	List *qualList;
+ 	ScalarArrayOpExpr *qual;
+ 	Var		*arg1;
+ 	Node		*arg2;
+ 
+ 	qual->xpr = ; 
+ 	qual->opno = TIDEqualOperator; 
+ 	qual->useOr = TRUE;
+ 
+ 	 * Define arguments 1 and 2. arg1 is a Var, arg2 is a const.
+ 	 * varattno is just assigned the value here to satisfy tidqual conditions
+ 	 * It means nothing outside this area.
+ 	arg1->varattno = SelfItemPointerAttributeNumber; 
+ 	arg1->vartype = TIDOID;
+ 	arg1->varlevelsup = 0;
+ 	arg1->xpr = 
+ 	arg1->vartypmod = 
+ 	arg1->varnoold = 
+ 	arg1->varoattno = 
+ 
+ 	* Add first and second arguments into argument list
+ 
+ 	qual->args = lappend(qual->args, arg1);
+ 	qual->args = lappend(qual->args, arg2);
+        
+ 	qualList = lappend(qualList, qual);
+ 	return qualList;
+ }
+ */
  
  /*
   *	Extract a set of CTID conditions from the given qual expression
***************
*** 239,246 ****
  {
  	List	   *tidquals;
  
! 	tidquals = TidQualFromRestrictinfo(rel->baserestrictinfo, rel->relid);
  
! 	if (tidquals)
! 		add_path(rel, (Path *) create_tidscan_path(root, rel, tidquals));
  }
--- 286,307 ----
  {
  	List	   *tidquals;
  
! 	if (root->parse->portal == NULL)
! 	{
! 		tidquals = TidQualFromRestrictinfo(rel->baserestrictinfo, rel->relid);
  
! 		if (tidquals)
! 			add_path(rel, (Path *) create_tidscan_path(root, rel, tidquals));
! 	}
! 	else
! 	{
! 		/*
! 		 * Updatable cursor case: According to the Executor, tid quals are
! 		 * not required for a TidScan to be processed. So pass tidquals of NULL
! 		 */
! 
! 		/* tidquals = build_tidqual(); may not be needed */
! 		if (tidquals)
! 			add_path(rel, (Path *) create_tidscan_path(root, rel, NULL));
! 	}
  }
diff -rc head_260207/src/backend/parser/analyze.c head_260207_jb/src/backend/parser/analyze.c
*** head_260207/src/backend/parser/analyze.c	2007-02-26 15:01:03.000000000 +1100
--- head_260207_jb/src/backend/parser/analyze.c	2007-02-26 16:36:20.000000000 +1100
***************
*** 508,514 ****
  	 */
  	transformFromClause(pstate, stmt->usingClause);
  
! 	qual = transformWhereClause(pstate, stmt->whereClause, "WHERE");
  
  	qry->returningList = transformReturningList(pstate, stmt->returningList);
  
--- 508,536 ----
  	 */
  	transformFromClause(pstate, stmt->usingClause);
  
! 	if (stmt->cursorName == NULL)
! 	{
! 		/* Only transform WHERE clause if not a WHERE CURRENT OF clause */
! 		qual = transformWhereClause(pstate, stmt->whereClause, "WHERE");
! 	}
! 	else
! 	{
! 		/*
! 		 * In WHERE CURRENT OF clause obtain Portal from cursor name and save in 
! 		 * Query structure. The test condition below ensures that a combined WHERE 
! 		 * and WHERE CURRENT OF clause is not possible in a single query.
! 		 */
! 		if (stmt->whereClause != NULL)
! 			ereport(ERROR,
! 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! 					errmsg("Cannot have WHERE and WHERE CURRENT OF in same query"),
! 					errdetail("Only WHERE or WHERE CURRENT OF may be used in query"));
! 		qry->portal = GetPortalByName(stmt->cursorName);
! 	}
! 
! 	qry->returningList = transformReturningList(pstate, stmt->returningList);
! 		qry->portal = GetPortalByName(stmt->cursorName);
! 	}
  
  	qry->returningList = transformReturningList(pstate, stmt->returningList);
  
***************
*** 2836,2841 ****
--- 2858,2864 ----
  transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
  {
  	Query	   *qry = makeNode(Query);
+ 	Portal	   *portal;
  	Node	   *qual;
  	ListCell   *origTargetList;
  	ListCell   *tl;
***************
*** 2855,2862 ****
  	transformFromClause(pstate, stmt->fromClause);
  
  	qry->targetList = transformTargetList(pstate, stmt->targetList);
  
! 	qual = transformWhereClause(pstate, stmt->whereClause, "WHERE");
  
  	qry->returningList = transformReturningList(pstate, stmt->returningList);
  
--- 2878,2907 ----
  	transformFromClause(pstate, stmt->fromClause);
  
  	qry->targetList = transformTargetList(pstate, stmt->targetList);
+ 	
+ 	if (stmt->cursorName == NULL)
+ 	{
+ 		/*
+ 		 * Only call if it is not a WHERE CURRENT OF clause 
+ 		 */	
+ 		qual = transformWhereClause(pstate, stmt->whereClause, "WHERE");
+ 	}
+ 	else
+ 	{
+ 		/* 
+ 		 * In WHERE CURRENT OF cursor name, get Portal from cursor name 
+ 		 * and save in Query structure. The test condition below ensures that 
+ 		 * a combined WHERE and WHERE CURRENT OF clause is not possible
+ 		 * in a single query.
+ 		 */
  
! 		if (stmt->whereClause != NULL)
! 			ereport(ERROR,
! 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! 					errmsg("Cannot have WHERE and WHERE CURRENT OF in same query"),
! 					errdetail("Only WHERE or WHERE CURRENT OF may be used in query"));
! 		qry->portal = GetPortalByName(stmt->cursorName);
! 	}
  
  	qry->returningList = transformReturningList(pstate, stmt->returningList);
  
diff -rc head_260207/src/backend/parser/gram.y head_260207_jb/src/backend/parser/gram.y
*** head_260207/src/backend/parser/gram.y	2007-02-26 15:05:24.000000000 +1100
--- head_260207_jb/src/backend/parser/gram.y	2007-02-26 16:47:59.000000000 +1100
***************
*** 249,255 ****
  				prep_type_clause
  				execute_param_clause using_clause returning_clause
  
! %type <range>	OptTempTableName
  %type <into>	into_clause create_as_target
  
  %type <defelt>	createfunc_opt_item common_func_opt_item
--- 249,255 ----
  				prep_type_clause
  				execute_param_clause using_clause returning_clause
  
! %type <range>   OptTempTableName
  %type <into>	into_clause create_as_target
  
  %type <defelt>	createfunc_opt_item common_func_opt_item
***************
*** 375,382 ****
  	CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
  	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
--- 375,382 ----
  	CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
  	CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
  	COMMITTED CONCURRENTLY CONNECTION CONSTRAINT CONSTRAINTS
+ 	CREATEROLE CREATEUSER CROSS CSV CURRENT CURRENT_DATE CURRENT_ROLE CURRENT_TIME
  	CONTENT_P CONVERSION_P CONVERT COPY COST CREATE CREATEDB
  	CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
  
  	DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
***************
*** 5584,5590 ****
  					DeleteStmt *n = makeNode(DeleteStmt);
  					n->relation = $3;
  					n->usingClause = $4;
! 					n->whereClause = $5;
  					n->returningList = $6;
  					$$ = (Node *)n;
  				}
--- 5584,5593 ----
  					DeleteStmt *n = makeNode(DeleteStmt);
  					n->relation = $3;
  					n->usingClause = $4;
! 					if ( (Node *)$5->type == T_A_Expr )
! 						n->whereClause = $5;
! 					else
! 						n->cursorName = $5;
  					n->returningList = $6;
  					$$ = (Node *)n;
  				}
***************
*** 5642,5648 ****
  					n->relation = $2;
  					n->targetList = $4;
  					n->fromClause = $5;
! 					n->whereClause = $6;
  					n->returningList = $7;
  					$$ = (Node *)n;
  				}
--- 5645,5654 ----
  					n->relation = $2;
  					n->targetList = $4;
  					n->fromClause = $5;
! 					if ( (Node *)$6->type == T_A_Expr )
! 						n->whereClause = $6;
! 					else
! 						n->cursorName = $6;
  					n->returningList = $7;
  					$$ = (Node *)n;
  				}
***************
*** 5709,5715 ****
  			| set_target_list ',' set_target		{ $$ = lappend($1,$3); }
  		;
  
- 
  /*****************************************************************************
   *
   *		QUERY:
--- 5715,5720 ----
***************
*** 6440,6445 ****
--- 6445,6451 ----
  
  where_clause:
  			WHERE a_expr							{ $$ = $2; }
+ 			| WHERE CURRENT OF name					{$$ = $4; }
  			| /*EMPTY*/								{ $$ = NULL; }
  		;
  
***************
*** 8996,9001 ****
--- 9002,9008 ----
  			| COLUMN
  			| CONSTRAINT
  			| CREATE
+ 			| CURRENT
  			| CURRENT_DATE
  			| CURRENT_ROLE
  			| CURRENT_TIME
diff -rc head_260207/src/backend/parser/keywords.c head_260207_jb/src/backend/parser/keywords.c
*** head_260207/src/backend/parser/keywords.c	2007-02-26 15:05:35.000000000 +1100
--- head_260207_jb/src/backend/parser/keywords.c	2007-02-26 16:39:02.000000000 +1100
***************
*** 100,105 ****
--- 100,106 ----
  	{"createuser", CREATEUSER},
  	{"cross", CROSS},
  	{"csv", CSV},
+ 	{"current", CURRENT},
  	{"current_date", CURRENT_DATE},
  	{"current_role", CURRENT_ROLE},
  	{"current_time", CURRENT_TIME},
diff -rc head_260207/src/include/executor/execdesc.h head_260207_jb/src/include/executor/execdesc.h
*** head_260207/src/include/executor/execdesc.h	2007-02-26 15:05:14.000000000 +1100
--- head_260207_jb/src/include/executor/execdesc.h	2007-02-26 17:18:30.000000000 +1100
***************
*** 47,52 ****
--- 47,56 ----
  	TupleDesc	tupDesc;		/* descriptor for result tuples */
  	EState	   *estate;			/* executor's query-wide state */
  	PlanState  *planstate;		/* tree of per-plan-node state */
+ 	/* These fields are set by ExecutorRun ??? */
+ 	TupleId		tupleId;	/* Tuple id retrieved on cursor FETCH */
+ 	TupleTableSlot	tuple;		/* Tuple relating to tuple id */
+ 	RelationId	relationId;	/* Relation Id retrieved on cursor FETCH */ 
  } QueryDesc;
  
  /* in pquery.c */
diff -rc head_260207/src/include/nodes/parsenodes.h head_260207_jb/src/include/nodes/parsenodes.h
*** head_260207/src/include/nodes/parsenodes.h	2007-02-26 15:06:09.000000000 +1100
--- head_260207_jb/src/include/nodes/parsenodes.h	2007-02-26 17:13:08.000000000 +1100
***************
*** 109,114 ****
--- 109,115 ----
  
  	List	   *rtable;			/* list of range table entries */
  	FromExpr   *jointree;		/* table join tree (FROM and WHERE clauses) */
+ 	Portal	   *portal;		/* Portal relating to updatable cursor */
  
  	List	   *targetList;		/* target list (of TargetEntry) */
  
***************
*** 685,690 ****
--- 686,692 ----
  	RangeVar   *relation;		/* relation to delete from */
  	List	   *usingClause;	/* optional using clause for more tables */
  	Node	   *whereClause;	/* qualifications */
+ 	char	   *cursorName;		/* Cursor name in WHERE CURRENT OF */
  	List	   *returningList;	/* list of expressions to return */
  } DeleteStmt;
  
***************
*** 698,703 ****
--- 700,706 ----
  	RangeVar   *relation;		/* relation to update */
  	List	   *targetList;		/* the target list (of ResTarget) */
  	Node	   *whereClause;	/* qualifications */
+ 	char	   *cursorName;		/* Cursor name in WHERE CURRENT OF */
  	List	   *fromClause;		/* optional from clause for more tables */
  	List	   *returningList;	/* list of expressions to return */
  } UpdateStmt;
diff -rc head_260207/src/include/utils/portal.h head_260207_jb/src/include/utils/portal.h
*** head_260207/src/include/utils/portal.h	2007-02-26 15:06:20.000000000 +1100
--- head_260207_jb/src/include/utils/portal.h	2007-02-26 17:16:23.000000000 +1100
***************
*** 161,166 ****
--- 161,172 ----
  	MemoryContext holdContext;	/* memory containing holdStore */
  
  	/*
+ 	 * Updatable Cursor change. Here the current tuple id (ctid) is
+ 	 * stored.
+ 	 */
+ 	 ItemPointer ctid;	/* updatable cursor current tuple id */
+ 	 TupleTableSlot tuple; 	/* tuple related to ctid */
+ 	/*
  	 * atStart, atEnd and portalPos indicate the current cursor position.
  	 * portalPos is zero before the first row, N after fetching N'th row of
  	 * query.  After we run off the end, portalPos = # of rows in query, and
