diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 56b106a..da1113f 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -5360,6 +5360,11 @@ ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone)
 	if (isDone)
 		*isDone = ExprSingleResult;
 
+	/* Simply return outer tuple for identity projection */
+	if (projInfo->pi_identity)
+		return econtext->ecxt_outertuple;
+
+
 	/*
 	 * Clear any former contents of the result slot.  This makes it safe for
 	 * us to use the slot's Datum/isnull arrays as workspace. (Also, we can
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 0bbd0d4..38d259a 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -485,6 +485,9 @@ ExecGetResultType(PlanState *planstate)
  * ensured that tuple slot has a descriptor matching the tlist!)  Note that
  * the given tlist should be a list of ExprState nodes, not Expr nodes.
  *
+ * This ProjectionInfo is marked as identity projection and passes through the
+ * outer tupleslot in ExecProject() when lower_congruent is true.
+ *
  * inputDesc can be NULL, but if it is not, we check to see whether simple
  * Vars in the tlist match the descriptor.	It is important to provide
  * inputDesc for relation-scan plan nodes, as a cross check that the relation
@@ -494,6 +497,7 @@ ExecGetResultType(PlanState *planstate)
  */
 ProjectionInfo *
 ExecBuildProjectionInfo(List *targetList,
+						bool lower_congruent,
 						ExprContext *econtext,
 						TupleTableSlot *slot,
 						TupleDesc inputDesc)
@@ -511,6 +515,12 @@ ExecBuildProjectionInfo(List *targetList,
 
 	projInfo->pi_exprContext = econtext;
 	projInfo->pi_slot = slot;
+	projInfo->pi_identity = lower_congruent;
+
+	/* identity projection does not need further fields */
+	if (lower_congruent)
+		return projInfo;
+	
 	/* since these are all int arrays, we need do just one palloc */
 	workspace = (int *) palloc(len * 3 * sizeof(int));
 	projInfo->pi_varSlotOffsets = varSlotOffsets = workspace;
@@ -676,6 +686,7 @@ ExecAssignProjectionInfo(PlanState *planstate,
 {
 	planstate->ps_ProjInfo =
 		ExecBuildProjectionInfo(planstate->targetlist,
+								planstate->tlist_lower_congruent,
 								planstate->ps_ExprContext,
 								planstate->ps_ResultTupleSlot,
 								inputDesc);
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 38c7141..6e84aa7 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -1449,6 +1449,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
 	aggstate->ss.ps.qual = (List *)
 		ExecInitExpr((Expr *) node->plan.qual,
 					 (PlanState *) aggstate);
+	aggstate->ss.ps.tlist_lower_congruent = node->plan.tlist_lower_congruent;
 
 	/*
 	 * initialize child nodes
@@ -1748,6 +1749,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
 
 		/* Set up projection info for evaluation */
 		peraggstate->evalproj = ExecBuildProjectionInfo(aggrefstate->args,
+														false,
 														aggstate->tmpcontext,
 														peraggstate->evalslot,
 														NULL);
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index a8a1fe6..048c265 100644
--- a/src/backend/executor/nodeGroup.c
+++ b/src/backend/executor/nodeGroup.c
@@ -229,6 +229,7 @@ ExecInitGroup(Group *node, EState *estate, int eflags)
 	grpstate->ss.ps.qual = (List *)
 		ExecInitExpr((Expr *) node->plan.qual,
 					 (PlanState *) grpstate);
+	grpstate->ss.ps.tlist_lower_congruent = node->plan.tlist_lower_congruent;
 
 	/*
 	 * initialize child nodes
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 26a59d0..aa95004 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1006,7 +1006,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
 
 			rliststate = (List *) ExecInitExpr((Expr *) rlist, &mtstate->ps);
 			resultRelInfo->ri_projectReturning =
-				ExecBuildProjectionInfo(rliststate, econtext, slot,
+				ExecBuildProjectionInfo(rliststate, false, econtext, slot,
 									 resultRelInfo->ri_RelationDesc->rd_att);
 			resultRelInfo++;
 		}
diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c
index b51efd8..cd6c8f2 100644
--- a/src/backend/executor/nodeResult.c
+++ b/src/backend/executor/nodeResult.c
@@ -246,6 +246,7 @@ ExecInitResult(Result *node, EState *estate, int eflags)
 					 (PlanState *) resstate);
 	resstate->resconstantqual = ExecInitExpr((Expr *) node->resconstantqual,
 											 (PlanState *) resstate);
+	resstate->ps.tlist_lower_congruent = node->plan.tlist_lower_congruent;
 
 	/*
 	 * initialize child nodes
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index d615b78..5612e93 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -866,6 +866,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
 		slot = ExecInitExtraTupleSlot(estate);
 		ExecSetSlotDescriptor(slot, tupDesc);
 		sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
+												   false,
 												   NULL,
 												   slot,
 												   NULL);
@@ -874,6 +875,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
 		slot = ExecInitExtraTupleSlot(estate);
 		ExecSetSlotDescriptor(slot, tupDesc);
 		sstate->projRight = ExecBuildProjectionInfo(righttlist,
+													false,
 													sstate->innerecontext,
 													slot,
 													NULL);
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index ade9b57..dd557a8 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -1457,6 +1457,7 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
 	winstate->ss.ps.targetlist = (List *)
 		ExecInitExpr((Expr *) node->plan.targetlist,
 					 (PlanState *) winstate);
+	winstate->ss.ps.tlist_lower_congruent = node->plan.tlist_lower_congruent;
 
 	/*
 	 * WindowAgg nodes never have quals, since they can only occur at the
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index ccd69fc..776ce64 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -26,7 +26,6 @@
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
-
 typedef struct
 {
 	Index		varno;			/* RT index of Var */
@@ -1184,6 +1183,7 @@ set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset)
 	indexed_tlist *subplan_itlist;
 	List	   *output_targetlist;
 	ListCell   *l;
+	int         nmatch = 0;
 
 	subplan_itlist = build_tlist_index(subplan->targetlist);
 
@@ -1214,12 +1214,25 @@ set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset)
 									 subplan_itlist,
 									 OUTER_VAR,
 									 rtoffset);
+		
+		if (IsA(newexpr, Var) && ((Var*)newexpr)->varattno == nmatch + 1)
+			nmatch++;
+
 		tle = flatCopyTargetEntry(tle);
 		tle->expr = (Expr *) newexpr;
 		output_targetlist = lappend(output_targetlist, tle);
 	}
-	plan->targetlist = output_targetlist;
 
+	/*
+	 * Directly refer to the lower tuple slot on projection if the all elements
+	 * in target list exactly correspond to the ones in the lower tlist.
+	 */
+	plan->tlist_lower_congruent  =
+		(nmatch == list_length(plan->targetlist) &&
+		 nmatch == list_length(subplan->targetlist));
+
+	plan->targetlist = output_targetlist;
+ 
 	plan->qual = (List *)
 		fix_upper_expr(root,
 					   (Node *) plan->qual,
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 075bbe8..f705262 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -328,6 +328,7 @@ extern void ExecAssignResultType(PlanState *planstate, TupleDesc tupDesc);
 extern void ExecAssignResultTypeFromTL(PlanState *planstate);
 extern TupleDesc ExecGetResultType(PlanState *planstate);
 extern ProjectionInfo *ExecBuildProjectionInfo(List *targetList,
+						bool tlist_lower_congruent,
 						ExprContext *econtext,
 						TupleTableSlot *slot,
 						TupleDesc inputDesc);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index fec07b8..d3b0bc6 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -220,6 +220,7 @@ typedef struct ReturnSetInfo
  *		slot			slot to place projection result in
  *		itemIsDone		workspace array for ExecProject
  *		directMap		true if varOutputCols[] is an identity map
+ *		identity        true if this is an identity projection
  *		numSimpleVars	number of simple Vars found in original tlist
  *		varSlotOffsets	array indicating which slot each simple Var is from
  *		varNumbers		array containing input attr numbers of simple Vars
@@ -237,6 +238,7 @@ typedef struct ProjectionInfo
 	TupleTableSlot *pi_slot;
 	ExprDoneCond *pi_itemIsDone;
 	bool		pi_directMap;
+	bool        pi_identity;
 	int			pi_numSimpleVars;
 	int		   *pi_varSlotOffsets;
 	int		   *pi_varNumbers;
@@ -987,6 +989,7 @@ typedef struct PlanState
 	 * subPlan list, which does not exist in the plan tree).
 	 */
 	List	   *targetlist;		/* target list to be computed at this node */
+	bool        tlist_lower_congruent; /* target list is lower-congruent   */
 	List	   *qual;			/* implicitly-ANDed qual conditions */
 	struct PlanState *lefttree; /* input plan tree(s) */
 	struct PlanState *righttree;
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index fb9a863..9e7729c 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -106,6 +106,7 @@ typedef struct Plan
 	 * Common structural data for all Plan types.
 	 */
 	List	   *targetlist;		/* target list to be computed at this node */
+	bool        tlist_lower_congruent; /* target list is lower-congruent */
 	List	   *qual;			/* implicitly-ANDed qual conditions */
 	struct Plan *lefttree;		/* input plan tree(s) */
 	struct Plan *righttree;
