diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index f3aae45ce2a0dfd53075f837150d9e0be215582d..186c0f0313ef145e066d27d3397e3974f6872301 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -48,7 +48,7 @@ static void _SPI_fetch(FetchStmt * stmt);
 #endif
 static int
 _SPI_execute_plan(_SPI_plan * plan,
-				  Datum *Values, char *Nulls, int tcount);
+				  Datum * Values, char *Nulls, int tcount);
 
 #define _SPI_CPLAN_CURCXT	0
 #define _SPI_CPLAN_PROCXT	1
@@ -199,7 +199,7 @@ SPI_exec(char *src, int tcount)
 }
 
 int
-SPI_execp(void *plan, Datum *Values, char *Nulls, int tcount)
+SPI_execp(void *plan, Datum * Values, char *Nulls, int tcount)
 {
 	int			res;
 
@@ -278,11 +278,108 @@ SPI_saveplan(void *plan)
 
 }
 
+HeapTuple
+SPI_copytuple(HeapTuple tuple)
+{
+	MemoryContext oldcxt = NULL;
+	HeapTuple	ctuple;
+
+	if (tuple == NULL)
+	{
+		SPI_result = SPI_ERROR_ARGUMENT;
+		return (NULL);
+	}
+
+	if (_SPI_curid + 1 == _SPI_connected)		/* connected */
+	{
+		if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
+			elog(FATAL, "SPI: stack corrupted");
+		oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
+	}
+
+	ctuple = heap_copytuple(tuple);
+
+	if (oldcxt)
+		MemoryContextSwitchTo(oldcxt);
+
+	return (ctuple);
+}
+
+HeapTuple
+SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
+				Datum * Values, char *Nulls)
+{
+	MemoryContext oldcxt = NULL;
+	HeapTuple	mtuple;
+	int			numberOfAttributes;
+	uint8		infomask;
+	Datum	   *v;
+	char	   *n;
+	bool		isnull;
+	int			i;
+
+	if (rel == NULL || tuple == NULL || natts <= 0 || attnum == NULL || Values == NULL)
+	{
+		SPI_result = SPI_ERROR_ARGUMENT;
+		return (NULL);
+	}
+
+	if (_SPI_curid + 1 == _SPI_connected)		/* connected */
+	{
+		if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
+			elog(FATAL, "SPI: stack corrupted");
+		oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
+	}
+	SPI_result = 0;
+	numberOfAttributes = rel->rd_att->natts;
+	v = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
+	n = (char *) palloc(numberOfAttributes * sizeof(char));
+
+	/* fetch old values and nulls */
+	for (i = 0; i < numberOfAttributes; i++)
+	{
+		v[i] = heap_getattr(tuple, InvalidBuffer, i + 1, rel->rd_att, &isnull);
+		n[i] = (isnull) ? 'n' : ' ';
+	}
+
+	/* replace values and nulls */
+	for (i = 0; i < natts; i++)
+	{
+		if (attnum[i] <= 0 || attnum[i] > numberOfAttributes)
+			break;
+		v[attnum[i] - 1] = Values[i];
+		n[attnum[i] - 1] = (Nulls && Nulls[i] == 'n') ? 'n' : ' ';
+	}
+
+	if (i == natts)				/* no errors in attnum[] */
+	{
+		mtuple = heap_formtuple(rel->rd_att, v, n);
+		infomask = mtuple->t_infomask;
+		memmove(&(mtuple->t_ctid), &(tuple->t_ctid),
+				((char *) &(tuple->t_hoff) - (char *) &(tuple->t_ctid)));
+		mtuple->t_infomask = infomask;
+		mtuple->t_natts = numberOfAttributes;
+	}
+	else
+	{
+		mtuple = NULL;
+		SPI_result = SPI_ERROR_NOATTRIBUTE;
+	}
+
+	pfree(v);
+	pfree(n);
+
+	if (oldcxt)
+		MemoryContextSwitchTo(oldcxt);
+
+	return (mtuple);
+}
+
 int
 SPI_fnumber(TupleDesc tupdesc, char *fname)
 {
 	int			res;
-	
+
 	for (res = 0; res < tupdesc->natts; res++)
 	{
 		if (strcasecmp(tupdesc->attrs[res]->attname.data, fname) == 0)
@@ -333,7 +430,7 @@ SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
 Datum
 SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool * isnull)
 {
-	Datum	val;
+	Datum		val;
 
 	*isnull = true;
 	SPI_result = 0;
@@ -539,7 +636,7 @@ _SPI_execute(char *src, int tcount, _SPI_plan * plan)
 }
 
 static int
-_SPI_execute_plan(_SPI_plan * plan, Datum *Values, char *Nulls, int tcount)
+_SPI_execute_plan(_SPI_plan * plan, Datum * Values, char *Nulls, int tcount)
 {
 	QueryTreeList *queryTree_list = plan->qtlist;
 	List	   *planTree_list = plan->ptlist;
@@ -591,7 +688,7 @@ _SPI_execute_plan(_SPI_plan * plan, Datum *Values, char *Nulls, int tcount)
 				{
 					paramLI->kind = PARAM_NUM;
 					paramLI->id = k + 1;
-					paramLI->isnull = (Nulls != NULL && Nulls[k] != 'n');
+					paramLI->isnull = (Nulls && Nulls[k] == 'n');
 					paramLI->value = Values[k];
 				}
 				paramLI->kind = PARAM_INVALID;
diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h
index 6eab4b8544fce19073a92d4a217cf1c92d17f997..58346be4921786f171254237fec69e0fbb46b73f 100644
--- a/src/include/executor/spi.h
+++ b/src/include/executor/spi.h
@@ -73,10 +73,14 @@ extern int	SPI_result;
 extern int	SPI_connect(void);
 extern int	SPI_finish(void);
 extern int	SPI_exec(char *src, int tcount);
-extern int	SPI_execp(void *plan, Datum *values, char *Nulls, int tcount);
+extern int	SPI_execp(void *plan, Datum * values, char *Nulls, int tcount);
 extern void *SPI_prepare(char *src, int nargs, Oid * argtypes);
 extern void *SPI_saveplan(void *plan);
 
+extern HeapTuple SPI_copytuple(HeapTuple tuple);
+extern HeapTuple
+SPI_modifytuple(Relation rel, HeapTuple tuple, int natts,
+				int *attnum, Datum * Values, char *Nulls);
 extern int	SPI_fnumber(TupleDesc tupdesc, char *fname);
 extern char *SPI_fname(TupleDesc tupdesc, int fnumber);
 extern char *SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber);