diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index b3113f3..40f512f 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -363,7 +363,12 @@ ExecDelete(ItemPointer tupleid,
 		   TupleTableSlot *planSlot,
 		   EPQState *epqstate,
 		   EState *estate,
+#ifndef PGXC
 		   bool canSetTag)
+#else
+		   bool canSetTag,
+		   TupleTableSlot *pslot)
+#endif
 {
 	ResultRelInfo *resultRelInfo;
 	Relation	resultRelationDesc;
@@ -455,7 +460,18 @@ ldelete:;
 #ifdef PGXC
 		if (IS_PGXC_COORDINATOR && resultRemoteRel)
 		{
-			slot = ExecProcNodeDMLInXC(estate, planSlot, NULL);
+			/*
+			 * Pass in the source plan slot, we may attributes other than ctid
+			 * in case delete is based on primay key or other unique column.
+			 * planSlot can't be passed in place of pslot here because of the
+			 * following test case failure
+			 * create table t2(a int, b int) distribute by replication;
+			 * insert into t2 values(1,2), (3,4), (5,6);
+			 * set enable_fast_query_shipping=false;
+			 * delete from t2 where a = 1;
+			 * ERROR:  operator does not exist: tid = integer
+			 */
+			slot = ExecProcNodeDMLInXC(estate, planSlot, pslot);
 		}
 		else
 		{
@@ -1007,10 +1023,11 @@ ExecModifyTable(ModifyTableState *node)
 	ResultRelInfo *saved_resultRelInfo;
 	ResultRelInfo *resultRelInfo;
 	PlanState  *subplanstate;
-#ifdef PGXC	
+#ifdef PGXC
 	PlanState  *remoterelstate;
 	PlanState  *saved_resultRemoteRel;
-#endif	
+	RemoteQuery		*step = NULL;
+#endif
 	JunkFilter *junkfilter;
 	TupleTableSlot *slot;
 	TupleTableSlot *planSlot;
@@ -1054,6 +1071,8 @@ ExecModifyTable(ModifyTableState *node)
 #ifdef PGXC
 	/* Initialize remote plan state */
 	remoterelstate = node->mt_remoterels[node->mt_whichplan];
+	if (!IS_PGXC_DATANODE && remoterelstate != NULL)
+		step = (RemoteQuery *)((RemoteQueryState *)remoterelstate)->ss.ps.plan;
 #endif
 	junkfilter = resultRelInfo->ri_junkFilter;
 
@@ -1177,8 +1196,14 @@ ExecModifyTable(ModifyTableState *node)
 			/*
 			 * apply the junkfilter if needed.
 			 */
+#ifndef PGXC
 			if (operation != CMD_DELETE)
+#else
+			if (operation != CMD_DELETE ||
+				(!IS_PGXC_DATANODE && step != NULL &&
+					!step->rq_use_pk_for_rep_change))
 				slot = ExecFilterJunk(junkfilter, slot);
+#endif
 		}
 #ifdef PGXC
 		estate->es_result_remoterel = remoterelstate;
@@ -1194,7 +1219,11 @@ ExecModifyTable(ModifyTableState *node)
 				break;
 			case CMD_DELETE:
 				slot = ExecDelete(tupleid, oldtuple, planSlot,
+#ifndef PGXC
 								&node->mt_epqstate, estate, node->canSetTag);
+#else
+								&node->mt_epqstate, estate, node->canSetTag, slot);
+#endif
 				break;
 			default:
 				elog(ERROR, "unknown operation");
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 99564d5..0f58759 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -1048,6 +1048,7 @@ _copyRemoteQuery(const RemoteQuery *from)
 	COPY_SCALAR_FIELD(has_row_marks);
 	COPY_SCALAR_FIELD(rq_save_command_id);
 	COPY_SCALAR_FIELD(rq_params_internal);
+	COPY_SCALAR_FIELD(rq_save_command_id);
 
 	return newnode;
 }
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index c0f6c19..31b65f6 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -492,6 +492,7 @@ _outRemoteQuery(StringInfo str, const RemoteQuery *node)
 	WRITE_NODE_FIELD(query_var_tlist);
 	WRITE_BOOL_FIELD(rq_save_command_id);
 	WRITE_BOOL_FIELD(rq_params_internal);
+	WRITE_BOOL_FIELD(rq_save_command_id);
 }
 
 static void
diff --git a/src/backend/optimizer/plan/pgxcplan.c b/src/backend/optimizer/plan/pgxcplan.c
index 049d50f..ab94a89 100644
--- a/src/backend/optimizer/plan/pgxcplan.c
+++ b/src/backend/optimizer/plan/pgxcplan.c
@@ -48,6 +48,7 @@
 #include "pgxc/pgxcnode.h"
 #include "pgxc/execRemote.h"
 #include "rewrite/rewriteManip.h"
+#include "rewrite/rewriteHandler.h"
 #include "utils/builtins.h"
 #include "utils/rel.h"
 #include "utils/lsyscache.h"
@@ -1067,6 +1068,9 @@ pgxc_build_dml_statement(PlannerInfo *root, CmdType cmdtype,
 	int				col_att = 0;
 	int				ctid_param_num;
 	ListCell		*lc;
+	bool			can_use_pk_for_rep_change = false;
+	int16			*indexed_col_numbers = NULL;
+	int				index_col_count = 0;
 
 	/* Make sure we are dealing with DMLs */
 	if (cmdtype != CMD_UPDATE &&
@@ -1128,6 +1132,28 @@ pgxc_build_dml_statement(PlannerInfo *root, CmdType cmdtype,
 
 	query_to_deparse->jointree = makeNode(FromExpr);
 
+	can_use_pk_for_rep_change = (cmdtype == CMD_UPDATE || cmdtype == CMD_DELETE) &&
+				IsRelationReplicated(GetRelationLocInfo(res_rel->relid));
+
+	if (can_use_pk_for_rep_change)
+	{
+		index_col_count = pgxc_find_unique_index(res_rel->relid,
+												&indexed_col_numbers);
+		if (index_col_count <= 0)
+			can_use_pk_for_rep_change = false;
+
+		if (can_use_pk_for_rep_change)
+		{
+			if (is_pk_being_changed(root->parse, indexed_col_numbers,
+									index_col_count))
+			{
+				can_use_pk_for_rep_change = false;
+			}
+		}
+	}
+
+	rqplan->rq_use_pk_for_rep_change = can_use_pk_for_rep_change;
+
 	/*
 	 * Prepare a param list for INSERT queries
 	 * While doing so note the position of ctid, xc_node_id in source data
@@ -1140,7 +1166,8 @@ pgxc_build_dml_statement(PlannerInfo *root, CmdType cmdtype,
 		col_att++;
 
 		/* The position of ctid/xc_node_id is not required for INSERT */
-		if (tle->resjunk && (cmdtype == CMD_UPDATE || cmdtype == CMD_DELETE))
+		if (!can_use_pk_for_rep_change && tle->resjunk &&
+			(cmdtype == CMD_UPDATE || cmdtype == CMD_DELETE))
 		{
 			Var *v = (Var *)tle->expr;
 
@@ -1226,42 +1253,89 @@ pgxc_build_dml_statement(PlannerInfo *root, CmdType cmdtype,
 		 * the n table attributes, followed by ctid and optionally node_id. So
 		 * we know that the ctid has to be n + 1.
 		 */
-		ctid_param_num = natts + 1;
+		if (!can_use_pk_for_rep_change)
+		{
+			ctid_param_num = natts + 1;
+		}
 	}
-	else if (cmdtype == CMD_DELETE)
+	if (cmdtype == CMD_DELETE)
 	{
-		/*
-		 * Since there is no data to update, the first param is going to be
-		 * ctid.
-		 */
-		ctid_param_num = 1;
+		if (!can_use_pk_for_rep_change)
+		{
+			/*
+			 * Since there is no data to update, the first param is going to be
+			 * ctid.
+			 */
+			ctid_param_num = 1;
+		}
 	}
 
 	/* Add quals like ctid = $4 AND xc_node_id = $6 to the UPDATE/DELETE query */
 	if (cmdtype == CMD_UPDATE || cmdtype == CMD_DELETE)
 	{
-		if (!ctid_found)
-			elog(ERROR, "Source data plan's target list does not contain ctid colum");
-
 		/*
-		 * Beware, the ordering of ctid and node_id is important ! ctid should
-		 * be followed by node_id, not vice-versa, so as to be consistent with
-		 * the data row to be generated while binding the parameters for the
-		 * update statement.
+		 * If it is not replicated, we can use CTID, otherwise we need
+		 * to use a defined primary key
 		 */
-		pgxc_dml_add_qual_to_query(query_to_deparse, ctid_param_num,
-						SelfItemPointerAttributeNumber, resultRelationIndex);
+		if (!can_use_pk_for_rep_change)
+		{
+			if (!ctid_found)
+				elog(ERROR, "Source data plan's target list does not contain ctid colum");
 
-		if (node_id_found)
+			/*
+			 * Beware, the ordering of ctid and node_id is important ! ctid should
+			 * be followed by node_id, not vice-versa, so as to be consistent with
+			 * the data row to be generated while binding the parameters for the
+			 * update statement.
+			 */
+			pgxc_dml_add_qual_to_query(query_to_deparse, ctid_param_num,
+							SelfItemPointerAttributeNumber, resultRelationIndex);
+
+			if (node_id_found)
+			{
+				pgxc_dml_add_qual_to_query(query_to_deparse, ctid_param_num + 1,
+								XC_NodeIdAttributeNumber, resultRelationIndex);
+			}
+		}
+		else
 		{
-			pgxc_dml_add_qual_to_query(query_to_deparse, ctid_param_num + 1,
-							XC_NodeIdAttributeNumber, resultRelationIndex);
+			/*
+			 * Add all the columns of the primary key or unique index
+			 * in the where clause of update / delete on the replicated table
+			 */
+			int i;
+			for (i = 0; i < index_col_count; i++)
+			{
+				int			pkattno = indexed_col_numbers[i];
 
-			query_to_deparse->jointree->quals = (Node *)make_andclause(
-								(List *)query_to_deparse->jointree->quals);
+				col_att = 0;
+				foreach(elt, sourceTargetList)
+				{
+					TargetEntry	*tle = lfirst(elt);
+					Var *v;
+			
+					col_att++;
+			
+					v = (Var *)tle->expr;
+		
+					if (v->varno == resultRelationIndex &&
+						v->varattno == pkattno)
+					{
+						break;
+					}
+				}
+
+				pgxc_dml_add_qual_to_query(query_to_deparse, col_att,
+							pkattno, resultRelationIndex);
+			}
 		}
+		query_to_deparse->jointree->quals = (Node *)make_andclause(
+						(List *)query_to_deparse->jointree->quals);
 	}
 
+	if (indexed_col_numbers != NULL)
+		pfree(indexed_col_numbers);
+
 	/* pgxc_add_returning_list copied returning list in base_tlist */
 	if (rqplan->base_tlist)
 		query_to_deparse->returningList = list_copy(rqplan->base_tlist);
diff --git a/src/backend/pgxc/pool/execRemote.c b/src/backend/pgxc/pool/execRemote.c
index 97a8fe5..800ff2e 100644
--- a/src/backend/pgxc/pool/execRemote.c
+++ b/src/backend/pgxc/pool/execRemote.c
@@ -4934,7 +4934,6 @@ void AtEOXact_DBCleanup(bool isCommit)
  * and the ctid/nodeid values to be supplied for the WHERE clause of the
  * query. The data values are present in dataSlot whereas the ctid/nodeid
  * are available in sourceSlot as junk attributes.
- * For DELETEs, the dataSlot is NULL.
  * sourceSlot is used only to retrieve ctid/nodeid, so it does not get
  * used for INSERTs, although it will never be NULL.
  * The slots themselves are undisturbed.
@@ -5032,10 +5031,6 @@ SetDataRowForIntParams(JunkFilter *junkfilter,
 		appendBinaryStringInfo(&buf, (char *) &params_nbo, sizeof(params_nbo));
 	}
 
-	/*
-	 * The data attributes would not be present for DELETE. In such case,
-	 * dataSlot will be NULL.
-	 */
 	if (dataSlot)
 	{
 		TupleDesc	 	tdesc = dataSlot->tts_tupleDescriptor;
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index d23ea40..3849fd0 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -39,6 +39,8 @@
 #include "optimizer/var.h"
 #include "tcop/tcopprot.h"
 #include "tcop/utility.h"
+#include "utils/syscache.h"
+#include "access/htup_details.h"
 #endif
 
 
@@ -1256,6 +1258,9 @@ rewriteTargetListUD(Query *parsetree, RangeTblEntry *target_rte,
 #ifdef PGXC
 	List *var_list = NIL;
 	ListCell *elt;
+	bool can_use_pk_for_rep_change = false;
+	int16 *indexed_col_numbers = NULL;
+	int index_col_count = 0;
 
 	/*
 	 * In Postgres-XC, we need to evaluate quals of the parse tree and determine
@@ -1290,6 +1295,86 @@ rewriteTargetListUD(Query *parsetree, RangeTblEntry *target_rte,
 
 		parsetree->targetList = lappend(parsetree->targetList, tle);
 	}
+
+	if (IS_PGXC_COORDINATOR && RelationGetLocInfo(target_relation) != NULL
+		&& target_relation->rd_rel->relkind == RELKIND_RELATION)
+	{
+		can_use_pk_for_rep_change = IsRelationReplicated(RelationGetLocInfo(
+															target_relation));
+		if (can_use_pk_for_rep_change)
+		{
+			index_col_count = pgxc_find_unique_index(target_relation->rd_id,
+													&indexed_col_numbers);
+			if (index_col_count <= 0)
+				can_use_pk_for_rep_change = false;
+
+			if (can_use_pk_for_rep_change)
+			{
+				if (is_pk_being_changed(parsetree, indexed_col_numbers,
+										index_col_count))
+				{
+					can_use_pk_for_rep_change = false;
+				}
+			}
+		}
+
+		if (can_use_pk_for_rep_change)
+		{
+			int i;
+
+			for (i = 0; i < index_col_count; i++)
+			{
+				int			pkattno = indexed_col_numbers[i];
+				bool		found = false;
+				TargetEntry	*qtle;
+				char		*pkattname = get_attname(target_rte->relid, pkattno);
+
+				/*
+				 * Is it so that the primary key is already in the target list?
+				 */
+				foreach(elt, parsetree->targetList)
+				{
+					qtle = lfirst(elt);
+
+					if (qtle->resname == NULL)
+						continue;
+
+					if (!strcmp(qtle->resname, pkattname))
+					{
+						found = true;
+						break;
+					}
+				}
+
+				/*
+				 * Add all the primary key columns to the target list of the
+				 * query if one is not already there.
+				 */
+				if (!found)
+				{
+					TargetEntry		*tle;
+					Var				*var;
+					Oid				var_type;
+					int32			var_typmod;
+					Oid				var_collid;
+
+					get_rte_attribute_type(target_rte, pkattno, &var_type,
+							&var_typmod, &var_collid);
+
+					var = makeVar(parsetree->resultRelation, pkattno, var_type,
+									var_typmod, var_collid, 0);
+
+					tle = makeTargetEntry((Expr *) var,
+										list_length(parsetree->targetList) + 1,
+										pkattname, true);
+
+					parsetree->targetList = lappend(parsetree->targetList, tle);
+				}
+			}
+		}
+	}
+	if (indexed_col_numbers != NULL)
+		pfree(indexed_col_numbers);
 #endif
 
 	if (target_relation->rd_rel->relkind == RELKIND_RELATION ||
@@ -3503,6 +3588,139 @@ QueryRewriteCTAS(Query *parsetree)
 	return pg_analyze_and_rewrite(linitial(raw_parsetree_list), cquery.data,
 			NULL, 0);
 }
-#endif
 
+/*
+ * pgxc_find_unique_index finds either primary key or unique index
+ * defined for the passed relation.
+ * Returns the number of columns in the primary key or unique index
+ * ZERO means no primary key or unique index is defined.
+ * The column attributes of the primary key or unique index are returned
+ * in the passed indexed_col_numbers.
+ * The function allocates space for indexed_col_numbers, the caller is
+ * supposed to free it after use.
+ */
+int
+pgxc_find_unique_index(Oid relid, int16 **indexed_col_numbers)
+{
+	HeapTuple		indexTuple = NULL;
+	HeapTuple		indexUnique = NULL;
+	Form_pg_index	indexStruct;
+	ListCell		*item;
+	int				i;
+
+	/* Get necessary information about relation */
+	Relation rel = relation_open(relid, AccessShareLock);
+
+	foreach(item, RelationGetIndexList(rel))
+	{
+		Oid			indexoid = lfirst_oid(item);
+
+		indexTuple = SearchSysCache1(INDEXRELID,
+									ObjectIdGetDatum(indexoid));
+		if (!HeapTupleIsValid(indexTuple))
+			elog(ERROR, "cache lookup failed for index %u", indexoid);
+
+		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
+
+		if (indexStruct->indisprimary)
+		{
+			indexUnique = indexTuple;
+			ReleaseSysCache(indexTuple);
+			break;
+		}
+
+		/* In case we do not have a primary key, use a unique index */
+		if (indexStruct->indisunique)
+		{
+			indexUnique = indexTuple;
+		}
+
+		ReleaseSysCache(indexTuple);
+	}
+	relation_close(rel, AccessShareLock);
+
+	if (!indexUnique)
+		return 0;
+
+	indexStruct = (Form_pg_index) GETSTRUCT(indexUnique);
+
+	*indexed_col_numbers = palloc0(indexStruct->indnatts * sizeof(int16));
+
+	/*
+	 * Now get the list of PK attributes from the indkey definition (we
+	 * assume a primary key cannot have expressional elements)
+	 */
+	for (i = 0; i < indexStruct->indnatts; i++)
+	{
+		(*indexed_col_numbers)[i] = indexStruct->indkey.values[i];
+	}
+	return indexStruct->indnatts;
+}
+
+/*
+ * is_pk_being_changed determines whether the query is changing primary key
+ * or unique index.
+ * The attributes of the primary key / unique index and their count is
+ * passed to the function along with the query
+ * Returns true if the query is changing the primary key / unique index
+ * The function takes care of the fact that just having the primary key
+ * in set caluse does not mean that it is being changed unless the RHS
+ * is different that the LHS of the set caluse i.e. set pk = pk
+ * is taken as no change to the column
+ */
+bool
+is_pk_being_changed(const Query *query, int16 *indexed_col_numbers, int count)
+{
+	ListCell *lc;
+	int i;
+
+	if (query == NULL || query->rtable == NULL || indexed_col_numbers == NULL)
+		return false;
+
+	if (query->commandType != CMD_UPDATE)
+		return false;
+
+	for (i = 0; i < count; i++)
+	{
+		foreach(lc, query->targetList)
+		{
+			TargetEntry *tle = (TargetEntry *) lfirst(lc);
+
+			/* Nothing to do for a junk entry */
+			if (tle->resjunk)
+				continue;
+
+			/*
+			 * The TargetEntry::resno is the same as the attribute number
+			 * of the column being updated, if the attribute number of the
+			 * column being updated and the attribute of the primary key of
+			 * the table is same means this set clause entry is updating the
+			 * primary key column of the target table.
+			 */
+			if (indexed_col_numbers[i] == tle->resno)
+			{
+				Var *v;
+				/*
+				 * Although the set caluse contains pk column, but if it is
+				 * not being modified, we can use pk for updating the row
+				 */
+				if (!IsA(tle->expr, Var))
+					return true;
 
+				v = (Var *)tle->expr;
+				if (v->varno == query->resultRelation &&
+					v->varattno == tle->resno)
+				{
+					return false;
+				}
+				else
+				{
+					return true;
+				}
+			}
+		}
+	}
+	return false;
+}
+
+#endif
diff --git a/src/include/optimizer/pgxcplan.h b/src/include/optimizer/pgxcplan.h
index ba3fb0b..069273b 100644
--- a/src/include/optimizer/pgxcplan.h
+++ b/src/include/optimizer/pgxcplan.h
@@ -121,6 +121,11 @@ typedef struct
 	bool			has_row_marks;		/* Did SELECT had FOR UPDATE/SHARE? */
 	bool			rq_save_command_id;	/* Save the command ID to be used in
 										 * some special cases */
+	bool			rq_use_pk_for_rep_change;	/* Are we using primary key or
+												 * unique index defined on
+												 * the replicated table to
+												 * perform update/delete?
+												 */
 } RemoteQuery;
 
 extern PlannedStmt *pgxc_planner(Query *query, int cursorOptions,
diff --git a/src/include/rewrite/rewriteHandler.h b/src/include/rewrite/rewriteHandler.h
index 4efbf4a..91db6bc 100644
--- a/src/include/rewrite/rewriteHandler.h
+++ b/src/include/rewrite/rewriteHandler.h
@@ -25,6 +25,9 @@ extern int	relation_is_updatable(Oid reloid, bool include_triggers);
 
 #ifdef PGXC
 extern List *QueryRewriteCTAS(Query *parsetree);
+extern int pgxc_find_unique_index(Oid relid, int16 **indexed_col_numbers);
+extern bool is_pk_being_changed(const Query *query, int16 *indexed_col_numbers,
+								int count);
 #endif
 
 #endif   /* REWRITEHANDLER_H */
diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out
index 630d374..53af7f7 100644
--- a/src/test/regress/expected/updatable_views.out
+++ b/src/test/regress/expected/updatable_views.out
@@ -283,7 +283,7 @@ EXPLAIN (verbose true, costs off, nodes false) UPDATE rw_view1 SET a=6 WHERE a=5
                                           QUERY PLAN                                           
 -----------------------------------------------------------------------------------------------
  Update on public.base_tbl
-   Remote query: UPDATE ONLY public.base_tbl SET a = $1, b = $2 WHERE (base_tbl.ctid = $3)
+   Remote query: UPDATE ONLY public.base_tbl SET a = $1, b = $2 WHERE ((base_tbl.ctid = $3))
    ->  Data Node Scan on base_tbl "_REMOTE_TABLE_QUERY_"
          Output: 6, base_tbl.b, base_tbl.a, base_tbl.a, base_tbl.a, base_tbl.ctid
          Remote query: SELECT b, a, ctid FROM ONLY public.base_tbl WHERE ((a > 0) AND (a = 5))
@@ -293,7 +293,7 @@ EXPLAIN (verbose true, costs off, nodes false) DELETE FROM rw_view1 WHERE a=5;
                                          QUERY PLAN                                         
 --------------------------------------------------------------------------------------------
  Delete on public.base_tbl
-   Remote query: DELETE FROM ONLY public.base_tbl WHERE (base_tbl.ctid = $1)
+   Remote query: DELETE FROM ONLY public.base_tbl WHERE ((base_tbl.a = $1))
    ->  Data Node Scan on base_tbl "_REMOTE_TABLE_QUERY_"
          Output: base_tbl.a, base_tbl.a, base_tbl.a, base_tbl.ctid
          Remote query: SELECT a, ctid FROM ONLY public.base_tbl WHERE ((a > 0) AND (a = 5))
diff --git a/src/test/regress/expected/updatable_views_1.out b/src/test/regress/expected/updatable_views_1.out
index ea66300..65fbb88 100644
--- a/src/test/regress/expected/updatable_views_1.out
+++ b/src/test/regress/expected/updatable_views_1.out
@@ -283,7 +283,7 @@ EXPLAIN (verbose true, costs off, nodes false) UPDATE rw_view1 SET a=6 WHERE a=5
                                           QUERY PLAN                                           
 -----------------------------------------------------------------------------------------------
  Update on public.base_tbl
-   Remote query: UPDATE ONLY public.base_tbl SET a = $1, b = $2 WHERE (base_tbl.ctid = $3)
+   Remote query: UPDATE ONLY public.base_tbl SET a = $1, b = $2 WHERE ((base_tbl.ctid = $3))
    ->  Data Node Scan on base_tbl "_REMOTE_TABLE_QUERY_"
          Output: 6, base_tbl.b, base_tbl.a, base_tbl.a, base_tbl.a, base_tbl.ctid
          Remote query: SELECT b, a, ctid FROM ONLY public.base_tbl WHERE ((a > 0) AND (a = 5))
@@ -293,7 +293,7 @@ EXPLAIN (verbose true, costs off, nodes false) DELETE FROM rw_view1 WHERE a=5;
                                          QUERY PLAN                                         
 --------------------------------------------------------------------------------------------
  Delete on public.base_tbl
-   Remote query: DELETE FROM ONLY public.base_tbl WHERE (base_tbl.ctid = $1)
+   Remote query: DELETE FROM ONLY public.base_tbl WHERE ((base_tbl.a = $1))
    ->  Data Node Scan on base_tbl "_REMOTE_TABLE_QUERY_"
          Output: base_tbl.a, base_tbl.a, base_tbl.a, base_tbl.ctid
          Remote query: SELECT a, ctid FROM ONLY public.base_tbl WHERE ((a > 0) AND (a = 5))
diff --git a/src/test/regress/expected/xc_FQS_join.out b/src/test/regress/expected/xc_FQS_join.out
index 0a81cef..6b23767 100644
--- a/src/test/regress/expected/xc_FQS_join.out
+++ b/src/test/regress/expected/xc_FQS_join.out
@@ -827,10 +827,10 @@ explain (costs off, verbose on, nodes off) delete from tab1_mod using tab2_mod
 
 explain (costs off, verbose on, nodes off) update tab1_rep set val2 = 1000 from tab2_rep
 		where tab1_rep.val = tab2_rep.val and tab1_rep.val2 = tab2_rep.val2;
-                                           QUERY PLAN                                           
-------------------------------------------------------------------------------------------------
+                                            QUERY PLAN                                            
+--------------------------------------------------------------------------------------------------
  Update on public.tab1_rep
-   Remote query: UPDATE ONLY public.tab1_rep SET val = $1, val2 = $2 WHERE (tab1_rep.ctid = $3)
+   Remote query: UPDATE ONLY public.tab1_rep SET val = $1, val2 = $2 WHERE ((tab1_rep.ctid = $3))
    ->  Hash Join
          Output: tab1_rep.val, 1000, tab1_rep.val, tab1_rep.val2, tab1_rep.ctid, ctid
          Hash Cond: ((tab1_rep.val = val) AND (tab1_rep.val2 = val2))
@@ -849,7 +849,7 @@ explain (costs off, verbose on, nodes off) delete from tab1_rep using tab2_rep
                                           QUERY PLAN                                           
 -----------------------------------------------------------------------------------------------
  Delete on public.tab1_rep
-   Remote query: DELETE FROM ONLY public.tab1_rep WHERE (tab1_rep.ctid = $1)
+   Remote query: DELETE FROM ONLY public.tab1_rep WHERE ((tab1_rep.ctid = $1))
    ->  Hash Join
          Output: tab1_rep.val, tab1_rep.val2, tab1_rep.ctid, ctid
          Hash Cond: ((tab1_rep.val = val) AND (tab1_rep.val2 = val2))
diff --git a/src/test/regress/expected/xc_alter_table.out b/src/test/regress/expected/xc_alter_table.out
index 5934088..1715b19 100644
--- a/src/test/regress/expected/xc_alter_table.out
+++ b/src/test/regress/expected/xc_alter_table.out
@@ -147,7 +147,7 @@ EXPLAIN (VERBOSE true, COSTS false, NODES false) UPDATE xc_alter_table_2 SET b =
                                                                    QUERY PLAN                                                                    
 -------------------------------------------------------------------------------------------------------------------------------------------------
  Update on public.xc_alter_table_2
-   Remote query: UPDATE ONLY public.xc_alter_table_2 SET b = $2, c = $3 WHERE (xc_alter_table_2.ctid = $6)
+   Remote query: UPDATE ONLY public.xc_alter_table_2 SET b = $2, c = $3 WHERE ((xc_alter_table_2.ctid = $6))
    ->  Data Node Scan on xc_alter_table_2 "_REMOTE_TABLE_QUERY_"
          Output: NULL::integer, 'Morphee'::character varying(20), false, NULL::integer, NULL::integer, xc_alter_table_2.b, xc_alter_table_2.ctid
          Remote query: SELECT b, ctid FROM ONLY public.xc_alter_table_2 WHERE ((b)::text = 'Neo'::text)
@@ -192,7 +192,7 @@ EXPLAIN (VERBOSE true, COSTS false, NODES false) UPDATE xc_alter_table_2 SET a =
                                                                                     QUERY PLAN                                                                                     
 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  Update on public.xc_alter_table_2
-   Remote query: UPDATE ONLY public.xc_alter_table_2 SET b = $2, c = $3, a = $6, a2 = $7 WHERE (xc_alter_table_2.ctid = $8)
+   Remote query: UPDATE ONLY public.xc_alter_table_2 SET b = $2, c = $3, a = $6, a2 = $7 WHERE ((xc_alter_table_2.ctid = $8))
    ->  Data Node Scan on xc_alter_table_2 "_REMOTE_TABLE_QUERY_"
          Output: NULL::integer, xc_alter_table_2.b, xc_alter_table_2.c, NULL::integer, NULL::integer, 200, 'CTO'::character varying(20), xc_alter_table_2.b, xc_alter_table_2.ctid
          Remote query: SELECT b, c, ctid FROM ONLY public.xc_alter_table_2 WHERE ((b)::text = 'John'::text)
diff --git a/src/test/regress/expected/xc_misc.out b/src/test/regress/expected/xc_misc.out
index 76fd835..d94ef76 100644
--- a/src/test/regress/expected/xc_misc.out
+++ b/src/test/regress/expected/xc_misc.out
@@ -556,3 +556,189 @@ UPDATE pcu_base_tbl set a = pcu_base_tbl.a, b=pcu_base_tbl2.b from pcu_base_tbl2
 drop table pcu_base_tbl cascade;
 NOTICE:  drop cascades to view rw_view1
 drop table pcu_base_tbl2 cascade;
+------------------------------------------------------------------------------
+-- Check that the updates / deletes are using primary key when appropriate
+-- to perfomr the operation
+------------------------------------------------------------------------------
+create table xc_t41(a int, b int) distribute by replication;
+create table xc_t42(a int primary key, b int) distribute by replication;
+create table xc_t43(a int, b int primary key) distribute by replication;
+create table xc_t44(a int, b int, constraint pk PRIMARY KEY (a,b)) distribute by replication;
+insert into xc_t41 values(1,2);
+insert into xc_t41 values(3,4);
+insert into xc_t41 values(5,6);
+insert into xc_t42 values(1,2);
+insert into xc_t42 values(3,4);
+insert into xc_t42 values(5,6);
+insert into xc_t43 values(1,2);
+insert into xc_t43 values(3,4);
+insert into xc_t43 values(5,6);
+insert into xc_t44 values(1,2);
+insert into xc_t44 values(3,4);
+insert into xc_t44 values(5,6);
+set enable_fast_query_shipping=false;
+EXPLAIN (verbose true, costs off, nodes false) delete from xc_t41 where a = 1;
+                                 QUERY PLAN                                 
+----------------------------------------------------------------------------
+ Delete on public.xc_t41
+   Remote query: DELETE FROM ONLY public.xc_t41 WHERE ((xc_t41.ctid = $1))
+   ->  Data Node Scan on xc_t41 "_REMOTE_TABLE_QUERY_"
+         Output: xc_t41.a, xc_t41.ctid
+         Remote query: SELECT a, ctid FROM ONLY public.xc_t41 WHERE (a = 1)
+(5 rows)
+
+EXPLAIN (verbose true, costs off, nodes false) delete from xc_t42 where a = 1;
+                                 QUERY PLAN                                 
+----------------------------------------------------------------------------
+ Delete on public.xc_t42
+   Remote query: DELETE FROM ONLY public.xc_t42 WHERE ((xc_t42.a = $1))
+   ->  Data Node Scan on xc_t42 "_REMOTE_TABLE_QUERY_"
+         Output: xc_t42.a, xc_t42.ctid
+         Remote query: SELECT a, ctid FROM ONLY public.xc_t42 WHERE (a = 1)
+(5 rows)
+
+EXPLAIN (verbose true, costs off, nodes false) delete from xc_t43 where a = 1;
+                                  QUERY PLAN                                   
+-------------------------------------------------------------------------------
+ Delete on public.xc_t43
+   Remote query: DELETE FROM ONLY public.xc_t43 WHERE ((xc_t43.b = $2))
+   ->  Data Node Scan on xc_t43 "_REMOTE_TABLE_QUERY_"
+         Output: xc_t43.a, xc_t43.b, xc_t43.ctid
+         Remote query: SELECT a, b, ctid FROM ONLY public.xc_t43 WHERE (a = 1)
+(5 rows)
+
+EXPLAIN (verbose true, costs off, nodes false) delete from xc_t44 where a = 1;
+                                         QUERY PLAN                                         
+--------------------------------------------------------------------------------------------
+ Delete on public.xc_t44
+   Remote query: DELETE FROM ONLY public.xc_t44 WHERE ((xc_t44.a = $1) AND (xc_t44.b = $2))
+   ->  Data Node Scan on xc_t44 "_REMOTE_TABLE_QUERY_"
+         Output: xc_t44.a, xc_t44.b, xc_t44.ctid
+         Remote query: SELECT a, b, ctid FROM ONLY public.xc_t44 WHERE (a = 1)
+(5 rows)
+
+delete from xc_t41 where a = 1;
+delete from xc_t42 where a = 1;
+delete from xc_t43 where a = 1;
+delete from xc_t44 where a = 1;
+EXPLAIN (verbose true, costs off, nodes false) update xc_t41 set b = b + 1 where a = 3;
+                                       QUERY PLAN                                        
+-----------------------------------------------------------------------------------------
+ Update on public.xc_t41
+   Remote query: UPDATE ONLY public.xc_t41 SET a = $1, b = $2 WHERE ((xc_t41.ctid = $3))
+   ->  Data Node Scan on xc_t41 "_REMOTE_TABLE_QUERY_"
+         Output: xc_t41.a, (xc_t41.b + 1), xc_t41.a, xc_t41.ctid
+         Remote query: SELECT a, b, ctid FROM ONLY public.xc_t41 WHERE (a = 3)
+(5 rows)
+
+EXPLAIN (verbose true, costs off, nodes false) update xc_t42 set b = b + 1 where a = 3;
+                                      QUERY PLAN                                      
+--------------------------------------------------------------------------------------
+ Update on public.xc_t42
+   Remote query: UPDATE ONLY public.xc_t42 SET a = $1, b = $2 WHERE ((xc_t42.a = $1))
+   ->  Data Node Scan on xc_t42 "_REMOTE_TABLE_QUERY_"
+         Output: xc_t42.a, (xc_t42.b + 1), xc_t42.a, xc_t42.ctid
+         Remote query: SELECT a, b, ctid FROM ONLY public.xc_t42 WHERE (a = 3)
+(5 rows)
+
+EXPLAIN (verbose true, costs off, nodes false) update xc_t43 set b = b + 1 where a = 3;
+                                       QUERY PLAN                                        
+-----------------------------------------------------------------------------------------
+ Update on public.xc_t43
+   Remote query: UPDATE ONLY public.xc_t43 SET a = $1, b = $2 WHERE ((xc_t43.ctid = $3))
+   ->  Data Node Scan on xc_t43 "_REMOTE_TABLE_QUERY_"
+         Output: xc_t43.a, (xc_t43.b + 1), xc_t43.a, xc_t43.ctid
+         Remote query: SELECT a, b, ctid FROM ONLY public.xc_t43 WHERE (a = 3)
+(5 rows)
+
+EXPLAIN (verbose true, costs off, nodes false) update xc_t44 set b = b + 1 where a = 3;
+                                       QUERY PLAN                                        
+-----------------------------------------------------------------------------------------
+ Update on public.xc_t44
+   Remote query: UPDATE ONLY public.xc_t44 SET a = $1, b = $2 WHERE ((xc_t44.ctid = $3))
+   ->  Data Node Scan on xc_t44 "_REMOTE_TABLE_QUERY_"
+         Output: xc_t44.a, (xc_t44.b + 1), xc_t44.a, xc_t44.ctid
+         Remote query: SELECT a, b, ctid FROM ONLY public.xc_t44 WHERE (a = 3)
+(5 rows)
+
+update xc_t41 set b = b + 1 where a = 3;
+update xc_t42 set b = b + 1 where a = 3;
+update xc_t43 set b = b + 1 where a = 3;
+update xc_t44 set b = b + 1 where a = 3;
+EXPLAIN (verbose true, costs off, nodes false) update xc_t41 set a = a + 1 where b = 6;
+                                       QUERY PLAN                                        
+-----------------------------------------------------------------------------------------
+ Update on public.xc_t41
+   Remote query: UPDATE ONLY public.xc_t41 SET a = $1, b = $2 WHERE ((xc_t41.ctid = $3))
+   ->  Data Node Scan on xc_t41 "_REMOTE_TABLE_QUERY_"
+         Output: (xc_t41.a + 1), xc_t41.b, xc_t41.b, xc_t41.ctid
+         Remote query: SELECT a, b, ctid FROM ONLY public.xc_t41 WHERE (b = 6)
+(5 rows)
+
+EXPLAIN (verbose true, costs off, nodes false) update xc_t42 set a = a + 1 where b = 6;
+                                       QUERY PLAN                                        
+-----------------------------------------------------------------------------------------
+ Update on public.xc_t42
+   Remote query: UPDATE ONLY public.xc_t42 SET a = $1, b = $2 WHERE ((xc_t42.ctid = $3))
+   ->  Data Node Scan on xc_t42 "_REMOTE_TABLE_QUERY_"
+         Output: (xc_t42.a + 1), xc_t42.b, xc_t42.b, xc_t42.ctid
+         Remote query: SELECT a, b, ctid FROM ONLY public.xc_t42 WHERE (b = 6)
+(5 rows)
+
+EXPLAIN (verbose true, costs off, nodes false) update xc_t43 set a = a + 1 where b = 6;
+                                      QUERY PLAN                                      
+--------------------------------------------------------------------------------------
+ Update on public.xc_t43
+   Remote query: UPDATE ONLY public.xc_t43 SET a = $1, b = $2 WHERE ((xc_t43.b = $2))
+   ->  Data Node Scan on xc_t43 "_REMOTE_TABLE_QUERY_"
+         Output: (xc_t43.a + 1), xc_t43.b, xc_t43.b, xc_t43.ctid
+         Remote query: SELECT a, b, ctid FROM ONLY public.xc_t43 WHERE (b = 6)
+(5 rows)
+
+EXPLAIN (verbose true, costs off, nodes false) update xc_t44 set a = a + 1 where b = 6;
+                                       QUERY PLAN                                        
+-----------------------------------------------------------------------------------------
+ Update on public.xc_t44
+   Remote query: UPDATE ONLY public.xc_t44 SET a = $1, b = $2 WHERE ((xc_t44.ctid = $3))
+   ->  Data Node Scan on xc_t44 "_REMOTE_TABLE_QUERY_"
+         Output: (xc_t44.a + 1), xc_t44.b, xc_t44.b, xc_t44.ctid
+         Remote query: SELECT a, b, ctid FROM ONLY public.xc_t44 WHERE (b = 6)
+(5 rows)
+
+update xc_t41 set a = a + 1 where b = 6;
+update xc_t42 set a = a + 1 where b = 6;
+update xc_t43 set a = a + 1 where b = 6;
+update xc_t44 set a = a + 1 where b = 6;
+select * from xc_t41 order by 1, 2;
+ a | b 
+---+---
+ 3 | 5
+ 6 | 6
+(2 rows)
+
+select * from xc_t42 order by 1, 2;
+ a | b 
+---+---
+ 3 | 5
+ 6 | 6
+(2 rows)
+
+select * from xc_t43 order by 1, 2;
+ a | b 
+---+---
+ 3 | 5
+ 6 | 6
+(2 rows)
+
+select * from xc_t44 order by 1, 2;
+ a | b 
+---+---
+ 3 | 5
+ 6 | 6
+(2 rows)
+
+set enable_fast_query_shipping=true;
+drop table xc_t41;
+drop table xc_t42;
+drop table xc_t43;
+drop table xc_t44;
diff --git a/src/test/regress/expected/xc_trigship.out b/src/test/regress/expected/xc_trigship.out
index 1fe0e4c..7a01e4d 100644
--- a/src/test/regress/expected/xc_trigship.out
+++ b/src/test/regress/expected/xc_trigship.out
@@ -644,7 +644,7 @@ INSERT 0 6
                                                                                         QUERY PLAN                                                                                        
 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  Update on xc_trigship.xctrigemp1
-   Remote query: UPDATE ONLY xc_trigship.xctrigemp1 SET id = $1, empname = $2, empsal = $3, empadd = $4, trigop = $5 WHERE (xctrigemp1.ctid = $6)
+   Remote query: UPDATE ONLY xc_trigship.xctrigemp1 SET id = $1, empname = $2, empsal = $3, empadd = $4, trigop = $5 WHERE ((xctrigemp1.empname = $2))
    ->  Data Node Scan on xctrigemp1 "_REMOTE_TABLE_QUERY_"
          Output: xctrigemp1.id, xctrigemp1.empname, (xctrigemp1.empsal + 1000::double precision), xctrigemp1.empadd, xctrigemp1.trigop, xctrigemp1.empname, xctrigemp1.ctid, xctrigemp1.*
          Remote query: SELECT id, empname, empsal, empadd, trigop, ctid, xctrigemp1.*::xc_trigship.xctrigemp1 FROM ONLY xc_trigship.xctrigemp1 WHERE ((empname)::text <> 'Dummy'::text)
diff --git a/src/test/regress/sql/xc_misc.sql b/src/test/regress/sql/xc_misc.sql
index cccd388..e67aee8 100644
--- a/src/test/regress/sql/xc_misc.sql
+++ b/src/test/regress/sql/xc_misc.sql
@@ -337,3 +337,76 @@ UPDATE pcu_base_tbl set a = pcu_base_tbl.a, b=pcu_base_tbl2.b from pcu_base_tbl2
 
 drop table pcu_base_tbl cascade;
 drop table pcu_base_tbl2 cascade;
+
+
+------------------------------------------------------------------------------
+-- Check that the updates / deletes are using primary key when appropriate
+-- to perfomr the operation
+------------------------------------------------------------------------------
+
+create table xc_t41(a int, b int) distribute by replication;
+create table xc_t42(a int primary key, b int) distribute by replication;
+create table xc_t43(a int, b int primary key) distribute by replication;
+create table xc_t44(a int, b int, constraint pk PRIMARY KEY (a,b)) distribute by replication;
+
+insert into xc_t41 values(1,2);
+insert into xc_t41 values(3,4);
+insert into xc_t41 values(5,6);
+
+insert into xc_t42 values(1,2);
+insert into xc_t42 values(3,4);
+insert into xc_t42 values(5,6);
+
+insert into xc_t43 values(1,2);
+insert into xc_t43 values(3,4);
+insert into xc_t43 values(5,6);
+
+insert into xc_t44 values(1,2);
+insert into xc_t44 values(3,4);
+insert into xc_t44 values(5,6);
+
+set enable_fast_query_shipping=false;
+
+EXPLAIN (verbose true, costs off, nodes false) delete from xc_t41 where a = 1;
+EXPLAIN (verbose true, costs off, nodes false) delete from xc_t42 where a = 1;
+EXPLAIN (verbose true, costs off, nodes false) delete from xc_t43 where a = 1;
+EXPLAIN (verbose true, costs off, nodes false) delete from xc_t44 where a = 1;
+
+delete from xc_t41 where a = 1;
+delete from xc_t42 where a = 1;
+delete from xc_t43 where a = 1;
+delete from xc_t44 where a = 1;
+
+EXPLAIN (verbose true, costs off, nodes false) update xc_t41 set b = b + 1 where a = 3;
+EXPLAIN (verbose true, costs off, nodes false) update xc_t42 set b = b + 1 where a = 3;
+EXPLAIN (verbose true, costs off, nodes false) update xc_t43 set b = b + 1 where a = 3;
+EXPLAIN (verbose true, costs off, nodes false) update xc_t44 set b = b + 1 where a = 3;
+
+update xc_t41 set b = b + 1 where a = 3;
+update xc_t42 set b = b + 1 where a = 3;
+update xc_t43 set b = b + 1 where a = 3;
+update xc_t44 set b = b + 1 where a = 3;
+
+
+EXPLAIN (verbose true, costs off, nodes false) update xc_t41 set a = a + 1 where b = 6;
+EXPLAIN (verbose true, costs off, nodes false) update xc_t42 set a = a + 1 where b = 6;
+EXPLAIN (verbose true, costs off, nodes false) update xc_t43 set a = a + 1 where b = 6;
+EXPLAIN (verbose true, costs off, nodes false) update xc_t44 set a = a + 1 where b = 6;
+
+update xc_t41 set a = a + 1 where b = 6;
+update xc_t42 set a = a + 1 where b = 6;
+update xc_t43 set a = a + 1 where b = 6;
+update xc_t44 set a = a + 1 where b = 6;
+
+select * from xc_t41 order by 1, 2;
+select * from xc_t42 order by 1, 2;
+select * from xc_t43 order by 1, 2;
+select * from xc_t44 order by 1, 2;
+
+set enable_fast_query_shipping=true;
+
+drop table xc_t41;
+drop table xc_t42;
+drop table xc_t43;
+drop table xc_t44;
+