diff -cr pgsql/src/backend/access/common/printtup.c pgsql-iudret/src/backend/access/common/printtup.c
*** pgsql/src/backend/access/common/printtup.c	2005-11-03 12:11:30.000000000 -0500
--- pgsql-iudret/src/backend/access/common/printtup.c	2006-03-02 12:07:43.000000000 -0500
***************
*** 19,24 ****
--- 19,25 ----
  #include "access/printtup.h"
  #include "libpq/libpq.h"
  #include "libpq/pqformat.h"
+ #include "executor/executor.h"
  #include "tcop/pquery.h"
  #include "utils/lsyscache.h"
  #include "utils/portal.h"
***************
*** 112,117 ****
--- 113,120 ----
  {
  	DR_printtup *myState = (DR_printtup *) self;
  	Portal		portal = myState->portal;
+ 	List 		*returning = ((Query *) linitial(portal->parseTrees))->returning;
+ 	bool		withReturning = (returning != NIL);
  
  	if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
  	{
***************
*** 136,142 ****
  		SendRowDescriptionMessage(typeinfo,
  								  FetchPortalTargetList(portal),
  								  portal->formats);
! 
  	/* ----------------
  	 * We could set up the derived attr info at this time, but we postpone it
  	 * until the first call of printtup, for 2 reasons:
--- 139,149 ----
  		SendRowDescriptionMessage(typeinfo,
  								  FetchPortalTargetList(portal),
  								  portal->formats);
! 	else if (withReturning)
! 		SendRowDescriptionMessage(ExecTypeFromTL(returning, false),
! 								  returning,
! 								  portal->formats);
! 		
  	/* ----------------
  	 * We could set up the derived attr info at this time, but we postpone it
  	 * until the first call of printtup, for 2 reasons:
***************
*** 305,311 ****
  	/*
  	 * send the attributes of this tuple
  	 */
! 	for (i = 0; i < natts; ++i)
  	{
  		PrinttupAttrInfo *thisState = myState->myinfo + i;
  		Datum		origattr = slot->tts_values[i],
--- 312,318 ----
  	/*
  	 * send the attributes of this tuple
  	 */
! 	for (i = 0; i < natts; i++)
  	{
  		PrinttupAttrInfo *thisState = myState->myinfo + i;
  		Datum		origattr = slot->tts_values[i],
diff -cr pgsql/src/backend/executor/execMain.c pgsql-iudret/src/backend/executor/execMain.c
*** pgsql/src/backend/executor/execMain.c	2006-02-27 23:10:27.000000000 -0500
--- pgsql-iudret/src/backend/executor/execMain.c	2006-03-02 12:07:43.000000000 -0500
***************
*** 77,88 ****
  static void ExecSelect(TupleTableSlot *slot,
  		   DestReceiver *dest,
  		   EState *estate);
! static void ExecInsert(TupleTableSlot *slot, ItemPointer tupleid,
! 		   EState *estate);
! static void ExecDelete(TupleTableSlot *slot, ItemPointer tupleid,
! 		   EState *estate);
! static void ExecUpdate(TupleTableSlot *slot, ItemPointer tupleid,
! 		   EState *estate);
  static TupleTableSlot *EvalPlanQualNext(EState *estate);
  static void EndEvalPlanQual(EState *estate);
  static void ExecCheckRTEPerms(RangeTblEntry *rte);
--- 77,88 ----
  static void ExecSelect(TupleTableSlot *slot,
  		   DestReceiver *dest,
  		   EState *estate);
! static void ExecInsert(TupleTableSlot *slot, DestReceiver *dest, 
!            ItemPointer tupleid, EState *estate);
! static void ExecDelete(TupleTableSlot *slot, DestReceiver *dest,
! 		   ItemPointer tupleid, EState *estate);
! static void ExecUpdate(TupleTableSlot *slot, DestReceiver *dest,
! 		   ItemPointer tupleid, EState *estate);
  static TupleTableSlot *EvalPlanQualNext(EState *estate);
  static void EndEvalPlanQual(EState *estate);
  static void ExecCheckRTEPerms(RangeTblEntry *rte);
***************
*** 151,156 ****
--- 151,159 ----
  	estate->es_snapshot = queryDesc->snapshot;
  	estate->es_crosscheck_snapshot = queryDesc->crosscheck_snapshot;
  	estate->es_instrument = queryDesc->doInstrument;
+ 	estate->es_returning = 
+ 		ExecTransformReturning(queryDesc->parsetree->returning,
+ 							   estate);
  
  	/*
  	 * Initialize the plan state tree
***************
*** 1299,1315 ****
  				break;
  
  			case CMD_INSERT:
! 				ExecInsert(slot, tupleid, estate);
  				result = NULL;
  				break;
  
  			case CMD_DELETE:
! 				ExecDelete(slot, tupleid, estate);
  				result = NULL;
  				break;
  
  			case CMD_UPDATE:
! 				ExecUpdate(slot, tupleid, estate);
  				result = NULL;
  				break;
  
--- 1302,1318 ----
  				break;
  
  			case CMD_INSERT:
! 				ExecInsert(slot, dest, tupleid, estate);
  				result = NULL;
  				break;
  
  			case CMD_DELETE:
! 				ExecDelete(slot, dest, tupleid, estate);
  				result = NULL;
  				break;
  
  			case CMD_UPDATE:
! 				ExecUpdate(slot, dest, tupleid, estate);
  				result = NULL;
  				break;
  
***************
*** 1408,1413 ****
--- 1411,1417 ----
   */
  static void
  ExecInsert(TupleTableSlot *slot,
+ 		   DestReceiver *dest,
  		   ItemPointer tupleid,
  		   EState *estate)
  {
***************
*** 1475,1480 ****
--- 1479,1494 ----
  						estate->es_snapshot->curcid,
  						true, true);
  
+ 	if (estate->es_returning != NULL)
+ 	{
+ 		TupleTableSlot *retSlot = ExecReturning(slot, estate);
+ 		/*
+ 		 * send the tuple to the destination
+ 		 */
+ 		(*dest->receiveSlot) (retSlot, dest);
+ 		ExecClearTuple(retSlot);
+ 	}
+ 
  	IncrAppended();
  	(estate->es_processed)++;
  	estate->es_lastoid = newId;
***************
*** 1499,1504 ****
--- 1513,1519 ----
   */
  static void
  ExecDelete(TupleTableSlot *slot,
+ 		   DestReceiver *dest,
  		   ItemPointer tupleid,
  		   EState *estate)
  {
***************
*** 1578,1583 ****
--- 1593,1613 ----
  			return;
  	}
  
+ 	if (estate->es_returning != NULL)
+ 	{
+ 		TupleTableSlot *deletedSlot;
+ 		TupleTableSlot *retSlot;
+ 		
+ 		deletedSlot = ExecGetDeletedSlot(tupleid, estate);
+ 		retSlot = ExecReturning(deletedSlot, estate);
+ 		/*
+ 		 * send the tuple to the destination
+ 		 */
+ 		(*dest->receiveSlot) (retSlot, dest);
+ 		ExecClearTuple(retSlot);
+ 		ExecClearTuple(deletedSlot);
+ 	}
+ 
  	IncrDeleted();
  	(estate->es_processed)++;
  
***************
*** 1607,1612 ****
--- 1637,1643 ----
   */
  static void
  ExecUpdate(TupleTableSlot *slot,
+ 		   DestReceiver *dest,
  		   ItemPointer tupleid,
  		   EState *estate)
  {
***************
*** 1733,1738 ****
--- 1764,1779 ----
  			return;
  	}
  
+ 	if (estate->es_returning != NULL)
+ 	{
+ 		TupleTableSlot *retSlot = ExecReturning(slot, estate);
+ 		/*
+ 		 * send the tuple to the destination
+ 		 */
+ 		(*dest->receiveSlot) (retSlot, dest);
+ 		ExecClearTuple(retSlot);
+ 	}
+ 
  	IncrReplaced();
  	(estate->es_processed)++;
  
diff -cr pgsql/src/backend/executor/execUtils.c pgsql-iudret/src/backend/executor/execUtils.c
*** pgsql/src/backend/executor/execUtils.c	2006-01-14 17:03:35.000000000 -0500
--- pgsql-iudret/src/backend/executor/execUtils.c	2006-03-02 12:07:43.000000000 -0500
***************
*** 1158,1160 ****
--- 1158,1245 ----
  
  	MemoryContextSwitchTo(oldcontext);
  }
+ 
+ TupleTableSlot *
+ ExecReturning(TupleTableSlot *slot,
+ 			  EState *estate)
+ {
+ 	TupleTableSlot	*retSlot,
+ 					*scanTupleSave;
+ 	ExprContext		*returningExprContext;
+ 	ProjectionInfo	*retProject;
+ 
+ 	returningExprContext = (ExprContext *) linitial(estate->es_exprcontexts);
+ 
+ 	scanTupleSave = returningExprContext->ecxt_scantuple;
+ 	returningExprContext->ecxt_scantuple = slot;
+ 
+ 	retProject = ExecBuildProjectionInfo(estate->es_returning->retExprs,
+ 										 returningExprContext,
+ 										 estate->es_returning->retSlot);
+ 
+ 	retSlot = ExecProject(retProject, NULL);
+ 	returningExprContext->ecxt_scantuple = scanTupleSave;
+ 	return retSlot;
+ }
+ 
+ ReturningState *
+ ExecTransformReturning(List *returning,
+ 					   EState *estate)
+ {
+ 	ReturningState	*retState;
+ 	List			*retExprs = NIL;
+ 	ListCell		*retElem;
+ 	int				 i = 1;
+ 
+ 	if (returning == NIL)
+ 		return NULL;
+ 	
+ 	retState = palloc(1 * sizeof(ReturningState));
+ 
+ 	foreach (retElem, returning)
+ 	{
+ 		TargetEntry		 *tle;
+ 		GenericExprState *gstate;
+ 
+ 		tle = (TargetEntry *) lfirst(retElem);
+ 		tle->resno = i++;
+ 		gstate = makeNode(GenericExprState);
+ 		gstate->xprstate.expr = (Expr *) tle;
+ 		gstate->xprstate.evalfunc = NULL;
+ 		gstate->arg = ExecPrepareExpr(tle->expr, estate);
+ 
+ 		retExprs = lappend(retExprs, gstate);
+ 	}
+ 
+ 	retState->retTupleDesc = ExecTypeFromTL(returning, false);
+ 	retState->retExprs = retExprs;
+ 	retState->retSlot = MakeSingleTupleTableSlot(retState->retTupleDesc);
+ 
+ 	return retState;
+ }
+ 
+ TupleTableSlot *
+ ExecGetDeletedSlot(ItemPointer tupleid,
+ 				   EState *estate)
+ {
+ 	TupleTableSlot *retSlot = NULL;
+ 	HeapTupleData	retTuple;
+ 	Buffer			buffer;
+ 
+ 	retTuple.t_self = *tupleid;
+ 
+ 	if (heap_fetch(estate->es_result_relation_info->ri_RelationDesc,
+ 				   SnapshotNow,
+ 				   &retTuple,
+ 				   &buffer,
+ 				   false,
+ 				   NULL))
+ 	{
+ 		retSlot = MakeSingleTupleTableSlot(estate->es_result_relation_info->ri_RelationDesc->rd_att);
+ 		ExecStoreTuple(&retTuple, retSlot, InvalidBuffer, false);
+ 		slot_getallattrs(retSlot);
+ 		ReleaseBuffer(buffer);
+ 	} 
+ 
+ 	return retSlot;
+ }
diff -cr pgsql/src/backend/nodes/copyfuncs.c pgsql-iudret/src/backend/nodes/copyfuncs.c
*** pgsql/src/backend/nodes/copyfuncs.c	2006-02-18 19:04:26.000000000 -0500
--- pgsql-iudret/src/backend/nodes/copyfuncs.c	2006-03-02 12:07:43.000000000 -0500
***************
*** 1672,1677 ****
--- 1672,1678 ----
  	COPY_SCALAR_FIELD(forUpdate);
  	COPY_SCALAR_FIELD(rowNoWait);
  	COPY_NODE_FIELD(targetList);
+ 	COPY_NODE_FIELD(returning);
  	COPY_NODE_FIELD(groupClause);
  	COPY_NODE_FIELD(havingQual);
  	COPY_NODE_FIELD(distinctClause);
***************
*** 1693,1698 ****
--- 1694,1700 ----
  	COPY_NODE_FIELD(cols);
  	COPY_NODE_FIELD(targetList);
  	COPY_NODE_FIELD(selectStmt);
+ 	COPY_NODE_FIELD(returning);
  
  	return newnode;
  }
***************
*** 1705,1710 ****
--- 1707,1713 ----
  	COPY_NODE_FIELD(relation);
  	COPY_NODE_FIELD(whereClause);
  	COPY_NODE_FIELD(usingClause);
+ 	COPY_NODE_FIELD(returning);
  
  	return newnode;
  }
***************
*** 1718,1723 ****
--- 1721,1727 ----
  	COPY_NODE_FIELD(targetList);
  	COPY_NODE_FIELD(whereClause);
  	COPY_NODE_FIELD(fromClause);
+ 	COPY_NODE_FIELD(returning);
  
  	return newnode;
  }
diff -cr pgsql/src/backend/nodes/equalfuncs.c pgsql-iudret/src/backend/nodes/equalfuncs.c
*** pgsql/src/backend/nodes/equalfuncs.c	2006-02-18 19:04:26.000000000 -0500
--- pgsql-iudret/src/backend/nodes/equalfuncs.c	2006-03-02 12:07:43.000000000 -0500
***************
*** 683,688 ****
--- 683,689 ----
  	COMPARE_SCALAR_FIELD(forUpdate);
  	COMPARE_SCALAR_FIELD(rowNoWait);
  	COMPARE_NODE_FIELD(targetList);
+ 	COMPARE_NODE_FIELD(returning);
  	COMPARE_NODE_FIELD(groupClause);
  	COMPARE_NODE_FIELD(havingQual);
  	COMPARE_NODE_FIELD(distinctClause);
***************
*** 702,707 ****
--- 703,709 ----
  	COMPARE_NODE_FIELD(cols);
  	COMPARE_NODE_FIELD(targetList);
  	COMPARE_NODE_FIELD(selectStmt);
+ 	COMPARE_NODE_FIELD(returning);
  
  	return true;
  }
***************
*** 712,717 ****
--- 714,720 ----
  	COMPARE_NODE_FIELD(relation);
  	COMPARE_NODE_FIELD(whereClause);
  	COMPARE_NODE_FIELD(usingClause);
+ 	COMPARE_NODE_FIELD(returning);
  
  	return true;
  }
***************
*** 723,728 ****
--- 726,732 ----
  	COMPARE_NODE_FIELD(targetList);
  	COMPARE_NODE_FIELD(whereClause);
  	COMPARE_NODE_FIELD(fromClause);
+ 	COMPARE_NODE_FIELD(returning);
  
  	return true;
  }
diff -cr pgsql/src/backend/nodes/outfuncs.c pgsql-iudret/src/backend/nodes/outfuncs.c
*** pgsql/src/backend/nodes/outfuncs.c	2006-02-18 19:04:26.000000000 -0500
--- pgsql-iudret/src/backend/nodes/outfuncs.c	2006-03-02 12:07:43.000000000 -0500
***************
*** 1517,1522 ****
--- 1517,1523 ----
  	WRITE_BOOL_FIELD(forUpdate);
  	WRITE_BOOL_FIELD(rowNoWait);
  	WRITE_NODE_FIELD(targetList);
+ 	WRITE_NODE_FIELD(returning);
  	WRITE_NODE_FIELD(groupClause);
  	WRITE_NODE_FIELD(havingQual);
  	WRITE_NODE_FIELD(distinctClause);
diff -cr pgsql/src/backend/nodes/readfuncs.c pgsql-iudret/src/backend/nodes/readfuncs.c
*** pgsql/src/backend/nodes/readfuncs.c	2006-02-18 19:04:26.000000000 -0500
--- pgsql-iudret/src/backend/nodes/readfuncs.c	2006-03-02 12:07:43.000000000 -0500
***************
*** 151,156 ****
--- 151,157 ----
  	READ_BOOL_FIELD(forUpdate);
  	READ_BOOL_FIELD(rowNoWait);
  	READ_NODE_FIELD(targetList);
+ 	READ_NODE_FIELD(returning);
  	READ_NODE_FIELD(groupClause);
  	READ_NODE_FIELD(havingQual);
  	READ_NODE_FIELD(distinctClause);
diff -cr pgsql/src/backend/parser/analyze.c pgsql-iudret/src/backend/parser/analyze.c
*** pgsql/src/backend/parser/analyze.c	2006-02-18 19:04:26.000000000 -0500
--- pgsql-iudret/src/backend/parser/analyze.c	2006-03-02 12:07:43.000000000 -0500
***************
*** 102,107 ****
--- 102,109 ----
  static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
  static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
  					List **extras_before, List **extras_after);
+ static List *transformReturningList(ParseState *pstate, RangeVar *relation, List *returning);
+ 
  static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt);
  static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt,
  				  List **extras_before, List **extras_after);
***************
*** 486,491 ****
--- 488,500 ----
  	/* fix where clause */
  	qual = transformWhereClause(pstate, stmt->whereClause, "WHERE");
  
+ 	/*
+ 	 * Transform any RETURNING values to form a targetlist.
+ 	 */
+ 
+ 	qry->returning = transformReturningList(pstate, stmt->relation, 
+ 											stmt->returning);
+ 
  	/* done building the range table and jointree */
  	qry->rtable = pstate->p_rtable;
  	qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
***************
*** 662,667 ****
--- 671,683 ----
  	}
  
  	/*
+ 	 * Transform any RETURNING values to form a targetlist.
+ 	 */
+ 
+ 	qry->returning = transformReturningList(pstate, stmt->relation, 
+ 											stmt->returning);
+ 
+ 	/*
  	 * Now we are done with SELECT-like processing, and can get on with
  	 * transforming the target list to match the INSERT target columns.
  	 */
***************
*** 721,726 ****
--- 737,769 ----
  	return qry;
  }
  
+ static List *
+ transformReturningList(ParseState *pstate, RangeVar *relation, List *returning)
+ {
+ 	List *ret = NIL;
+ 	RangeTblEntry *retrte;
+ 
+ 	if (returning != NIL)
+ 	{
+ 		/*
+ 		 * Add the RTE to the pstate if we don't have any already.
+ 		 * This will usually happen for INSERT.
+ 		 */
+ 		if (pstate->p_varnamespace == NIL)
+ 		{
+ 			retrte = addRangeTableEntry(pstate, relation, 
+ 										makeAlias("*RETURNING*", NIL),
+ 										false, false);
+ 			addRTEtoQuery(pstate, retrte, false, true, true);
+ 		}
+ 
+ 		ret = transformTargetList(pstate, returning);
+ 		if (ret != NIL)
+ 			markTargetListOrigins(pstate, ret);
+ 	}
+ 	return ret;
+ }
+ 
  /*
   * transformCreateStmt -
   *	  transforms the "create table" statement
***************
*** 2329,2334 ****
--- 2372,2384 ----
  
  	qry->targetList = transformTargetList(pstate, stmt->targetList);
  
+ 	/*
+ 	 * Transform any RETURNING values to form a targetlist.
+ 	 */
+ 
+ 	qry->returning = transformReturningList(pstate, stmt->relation, 
+ 											stmt->returning);
+ 
  	qual = transformWhereClause(pstate, stmt->whereClause, "WHERE");
  
  	qry->rtable = pstate->p_rtable;
diff -cr pgsql/src/backend/parser/gram.y pgsql-iudret/src/backend/parser/gram.y
*** pgsql/src/backend/parser/gram.y	2006-02-28 17:37:26.000000000 -0500
--- pgsql-iudret/src/backend/parser/gram.y	2006-03-02 12:07:43.000000000 -0500
***************
*** 257,262 ****
--- 257,263 ----
  %type <boolean> index_opt_unique opt_verbose opt_full
  %type <boolean> opt_freeze opt_default opt_recheck
  %type <defelt>	opt_binary opt_oids copy_delimiter
+ %type <list>	opt_returning_list
  
  %type <boolean> copy_from opt_hold
  
***************
*** 393,399 ****
  	QUOTE
  
  	READ REAL REASSIGN RECHECK REFERENCES REINDEX RELATIVE_P RELEASE RENAME
! 	REPEATABLE REPLACE RESET RESTART RESTRICT RETURNS REVOKE RIGHT
  	ROLE ROLLBACK ROW ROWS RULE
  
  	SAVEPOINT SCHEMA SCROLL SECOND_P SECURITY SELECT SEQUENCE
--- 394,400 ----
  	QUOTE
  
  	READ REAL REASSIGN RECHECK REFERENCES REINDEX RELATIVE_P RELEASE RENAME
! 	REPEATABLE REPLACE RESET RESTART RESTRICT RETURNING RETURNS REVOKE RIGHT
  	ROLE ROLLBACK ROW ROWS RULE
  
  	SAVEPOINT SCHEMA SCROLL SECOND_P SECURITY SELECT SEQUENCE
***************
*** 5120,5128 ****
   *****************************************************************************/
  
  InsertStmt:
! 			INSERT INTO qualified_name insert_rest
  				{
  					$4->relation = $3;
  					$$ = (Node *) $4;
  				}
  		;
--- 5121,5130 ----
   *****************************************************************************/
  
  InsertStmt:
! 			INSERT INTO qualified_name insert_rest opt_returning_list
  				{
  					$4->relation = $3;
+ 					$4->returning = $5;
  					$$ = (Node *) $4;
  				}
  		;
***************
*** 5182,5187 ****
--- 5184,5192 ----
  				}
  		;
  
+ opt_returning_list:
+ 				RETURNING target_list { $$ = $2; }
+ 				| /*EMPTY*/			  { $$ = NIL; }
  
  /*****************************************************************************
   *
***************
*** 5191,5202 ****
   *****************************************************************************/
  
  DeleteStmt: DELETE_P FROM relation_expr_opt_alias
! 			using_clause where_clause
  				{
  					DeleteStmt *n = makeNode(DeleteStmt);
  					n->relation = $3;
  					n->usingClause = $4;
  					n->whereClause = $5;
  					$$ = (Node *)n;
  				}
  		;
--- 5196,5208 ----
   *****************************************************************************/
  
  DeleteStmt: DELETE_P FROM relation_expr_opt_alias
! 			using_clause where_clause opt_returning_list
  				{
  					DeleteStmt *n = makeNode(DeleteStmt);
  					n->relation = $3;
  					n->usingClause = $4;
  					n->whereClause = $5;
+ 					n->returning = $6;
  					$$ = (Node *)n;
  				}
  		;
***************
*** 5247,5258 ****
--- 5253,5266 ----
  			SET update_target_list
  			from_clause
  			where_clause
+ 			opt_returning_list
  				{
  					UpdateStmt *n = makeNode(UpdateStmt);
  					n->relation = $2;
  					n->targetList = $4;
  					n->fromClause = $5;
  					n->whereClause = $6;
+ 					n->returning = $7;
  					$$ = (Node *)n;
  				}
  		;
***************
*** 7946,7952 ****
  				}
  		;
  
- 
  /*****************************************************************************
   *
   *	Names and constants
--- 7954,7959 ----
***************
*** 8561,8566 ****
--- 8568,8574 ----
  			| PLACING
  			| PRIMARY
  			| REFERENCES
+ 			| RETURNING
  			| SELECT
  			| SESSION_USER
  			| SOME
diff -cr pgsql/src/backend/parser/keywords.c pgsql-iudret/src/backend/parser/keywords.c
*** pgsql/src/backend/parser/keywords.c	2005-12-26 23:00:07.000000000 -0500
--- pgsql-iudret/src/backend/parser/keywords.c	2006-03-02 12:07:43.000000000 -0500
***************
*** 282,287 ****
--- 282,288 ----
  	{"reset", RESET},
  	{"restart", RESTART},
  	{"restrict", RESTRICT},
+ 	{"returning", RETURNING},
  	{"returns", RETURNS},
  	{"revoke", REVOKE},
  	{"right", RIGHT},
diff -cr pgsql/src/include/executor/executor.h pgsql-iudret/src/include/executor/executor.h
*** pgsql/src/include/executor/executor.h	2006-02-27 23:10:28.000000000 -0500
--- pgsql-iudret/src/include/executor/executor.h	2006-03-02 12:07:43.000000000 -0500
***************
*** 280,283 ****
--- 280,290 ----
  							  ExprContextCallbackFunction function,
  							  Datum arg);
  
+ extern TupleTableSlot *ExecReturning(TupleTableSlot *slot, 
+ 									 EState *estate);
+ extern ReturningState *ExecTransformReturning(List *returning,
+ 											  EState *estate);
+ extern TupleTableSlot *ExecGetDeletedSlot(ItemPointer tupleid,
+ 										  EState *estate);
+ 
  #endif   /* EXECUTOR_H  */
diff -cr pgsql/src/include/nodes/execnodes.h pgsql-iudret/src/include/nodes/execnodes.h
*** pgsql/src/include/nodes/execnodes.h	2006-02-28 00:48:44.000000000 -0500
--- pgsql-iudret/src/include/nodes/execnodes.h	2006-03-02 12:07:43.000000000 -0500
***************
*** 282,287 ****
--- 282,294 ----
  	JunkFilter *ri_junkFilter;
  } ResultRelInfo;
  
+ typedef struct ReturningState
+ {
+     TupleDesc		 retTupleDesc;
+     List			*retExprs;
+ 	TupleTableSlot	*retSlot;
+ } ReturningState;
+ 
  /* ----------------
   *	  EState information
   *
***************
*** 327,332 ****
--- 334,340 ----
  	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 */
+ 	ReturningState *es_returning;	/* list of expressions to return */
  
  	List	   *es_exprcontexts;	/* List of ExprContexts within EState */
  
diff -cr pgsql/src/include/nodes/parsenodes.h pgsql-iudret/src/include/nodes/parsenodes.h
*** pgsql/src/include/nodes/parsenodes.h	2006-02-18 19:04:27.000000000 -0500
--- pgsql-iudret/src/include/nodes/parsenodes.h	2006-03-02 12:07:43.000000000 -0500
***************
*** 110,115 ****
--- 110,117 ----
  
  	List	   *targetList;		/* target list (of TargetEntry) */
  
+ 	List	   *returning;		/* the list of columns to return */
+ 
  	List	   *groupClause;	/* a list of GroupClause's */
  
  	Node	   *havingQual;		/* qualifications applied to groups */
***************
*** 622,627 ****
--- 624,630 ----
  	 */
  	List	   *targetList;		/* the target list (of ResTarget) */
  	Node	   *selectStmt;		/* the source SELECT */
+ 	List	   *returning;		/* the list of columns to return */
  } InsertStmt;
  
  /* ----------------------
***************
*** 634,639 ****
--- 637,643 ----
  	RangeVar   *relation;		/* relation to delete from */
  	Node	   *whereClause;	/* qualifications */
  	List	   *usingClause;	/* optional using clause for more tables */
+ 	List	   *returning;		/* the list of columns to return */
  } DeleteStmt;
  
  /* ----------------------
***************
*** 647,652 ****
--- 651,657 ----
  	List	   *targetList;		/* the target list (of ResTarget) */
  	Node	   *whereClause;	/* qualifications */
  	List	   *fromClause;		/* optional from clause for more tables */
+ 	List	   *returning;		/* the list of columns to return */
  } UpdateStmt;
  
  /* ----------------------
diff -cr pgsql/src/test/regress/expected/insert.out pgsql-iudret/src/test/regress/expected/insert.out
*** pgsql/src/test/regress/expected/insert.out	2003-09-25 02:58:06.000000000 -0400
--- pgsql-iudret/src/test/regress/expected/insert.out	2006-03-02 12:07:43.000000000 -0500
***************
*** 8,13 ****
--- 8,19 ----
  insert into inserttest (col1, col2, col3) values (DEFAULT, 5, DEFAULT);
  insert into inserttest values (DEFAULT, 5, 'test');
  insert into inserttest values (DEFAULT, 7);
+ insert into inserttest (col2, col3) values (3, DEFAULT) returning col3, col1, col2, col2 * 5, least(col2, col2 * 5);
+   col3   | col1 | col2 | ?column? | least 
+ ---------+------+------+----------+-------
+  testing |      |    3 |       15 |     3
+ (1 row)
+ 
  select * from inserttest;
   col1 | col2 |  col3   
  ------+------+---------
***************
*** 15,21 ****
        |    5 | testing
        |    5 | test
        |    7 | testing
! (4 rows)
  
  --
  -- insert with similar expression / target_list values (all fail)
--- 21,28 ----
        |    5 | testing
        |    5 | test
        |    7 | testing
!       |    3 | testing
! (5 rows)
  
  --
  -- insert with similar expression / target_list values (all fail)
***************
*** 35,40 ****
        |    5 | testing
        |    5 | test
        |    7 | testing
! (4 rows)
  
  drop table inserttest;
--- 42,48 ----
        |    5 | testing
        |    5 | test
        |    7 | testing
!       |    3 | testing
! (5 rows)
  
  drop table inserttest;
diff -cr pgsql/src/test/regress/expected/join.out pgsql-iudret/src/test/regress/expected/join.out
*** pgsql/src/test/regress/expected/join.out	2005-07-22 15:12:02.000000000 -0400
--- pgsql-iudret/src/test/regress/expected/join.out	2006-03-02 12:07:43.000000000 -0500
***************
*** 2184,2186 ****
--- 2184,2204 ----
  ---+---
  (0 rows)
  
+ INSERT INTO t3 VALUES (5, 20);
+ INSERT INTO t3 VALUES (6, 7);
+ INSERT INTO t3 VALUES (7, 8);
+ INSERT INTO t3 VALUES (500, 100);
+ DELETE FROM t3 USING t3 t3_other WHERE t3.x = t3_other.x AND t3.y = t3_other.y RETURNING t3.y, t3.x, t3.y + t3_other.x AS sum;
+   y  |  x  | sum 
+ -----+-----+-----
+    7 |   6 |  13
+    8 |   7 |  15
+   20 |   5 |  25
+  100 | 500 | 600
+ (4 rows)
+ 
+ SELECT * FROM t3;
+  x | y 
+ ---+---
+ (0 rows)
+ 
diff -cr pgsql/src/test/regress/expected/update.out pgsql-iudret/src/test/regress/expected/update.out
*** pgsql/src/test/regress/expected/update.out	2006-01-22 00:20:35.000000000 -0500
--- pgsql-iudret/src/test/regress/expected/update.out	2006-03-02 12:07:43.000000000 -0500
***************
*** 47,50 ****
--- 47,66 ----
  ERROR:  invalid reference to FROM-clause entry for table "update_test"
  HINT:  Perhaps you meant to reference the table alias "t".
  ROLLBACK;
+ 
+ -- Test UPDATE RETURNING
+ UPDATE update_test SET a = 5, b = 10 RETURNING b, a, a * 2 + b, greatest(a, b);
+  b  | a | ?column? | greatest 
+ ----+---+----------+----------
+  10 | 5 |       20 |       10
+  10 | 5 |       20 |       10
+ (2 rows)
+ 
+ SELECT * FROM update_test;
+  a | b  
+ ---+----
+  5 | 10
+  5 | 10
+ (2 rows)
+ 
  DROP TABLE update_test;
diff -cr pgsql/src/test/regress/sql/insert.sql pgsql-iudret/src/test/regress/sql/insert.sql
*** pgsql/src/test/regress/sql/insert.sql	2002-04-23 22:22:54.000000000 -0400
--- pgsql-iudret/src/test/regress/sql/insert.sql	2006-03-02 12:07:43.000000000 -0500
***************
*** 7,12 ****
--- 7,13 ----
  insert into inserttest (col1, col2, col3) values (DEFAULT, 5, DEFAULT);
  insert into inserttest values (DEFAULT, 5, 'test');
  insert into inserttest values (DEFAULT, 7);
+ insert into inserttest (col2, col3) values (3, DEFAULT) returning col3, col1, col2, col2 * 5, least(col2, col2 * 5);
  
  select * from inserttest;
  
diff -cr pgsql/src/test/regress/sql/join.sql pgsql-iudret/src/test/regress/sql/join.sql
*** pgsql/src/test/regress/sql/join.sql	2005-04-07 11:23:06.000000000 -0400
--- pgsql-iudret/src/test/regress/sql/join.sql	2006-03-02 12:07:43.000000000 -0500
***************
*** 373,375 ****
--- 373,383 ----
  SELECT * FROM t3;
  DELETE FROM t3 USING t3 t3_other WHERE t3.x = t3_other.x AND t3.y = t3_other.y;
  SELECT * FROM t3;
+ 
+ INSERT INTO t3 VALUES (5, 20);
+ INSERT INTO t3 VALUES (6, 7);
+ INSERT INTO t3 VALUES (7, 8);
+ INSERT INTO t3 VALUES (500, 100);
+ 
+ DELETE FROM t3 USING t3 t3_other WHERE t3.x = t3_other.x AND t3.y = t3_other.y RETURNING t3.y, t3.x, t3.y + t3_other.x AS sum;
+ SELECT * FROM t3;
diff -cr pgsql/src/test/regress/sql/update.sql pgsql-iudret/src/test/regress/sql/update.sql
*** pgsql/src/test/regress/sql/update.sql	2006-01-22 00:20:35.000000000 -0500
--- pgsql-iudret/src/test/regress/sql/update.sql	2006-03-02 12:07:43.000000000 -0500
***************
*** 32,35 ****
--- 32,40 ----
  UPDATE update_test AS t SET b = update_test.b + 10 WHERE t.a = 10;
  ROLLBACK;
  
+ -- Test UPDATE RETURNING
+ UPDATE update_test SET a = 5, b = 10 RETURNING b, a, a * 2 + b, greatest(a, b);
+ 
+ SELECT * FROM update_test;
+ 
  DROP TABLE update_test;

