diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index a8a1fe6..38037f9 100644
--- a/src/backend/executor/nodeGroup.c
+++ b/src/backend/executor/nodeGroup.c
@@ -110,7 +110,10 @@ ExecGroup(GroupState *node)
 			TupleTableSlot *result;
 			ExprDoneCond isDone;
 
-			result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
+			if (node->ss.ps.ps_ProjInfo)
+				result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
+			else  /* Assign outertuple for identity projection */
+				result = econtext->ecxt_outertuple;
 
 			if (isDone != ExprEndResult)
 			{
@@ -173,7 +176,10 @@ ExecGroup(GroupState *node)
 			TupleTableSlot *result;
 			ExprDoneCond isDone;
 
-			result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
+			if (node->ss.ps.ps_ProjInfo)
+				result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
+			else  /* Assign outertuple for identity projection */
+				result = econtext->ecxt_outertuple;
 
 			if (isDone != ExprEndResult)
 			{
@@ -244,7 +250,10 @@ ExecInitGroup(Group *node, EState *estate, int eflags)
 	 * Initialize result tuple type and projection info.
 	 */
 	ExecAssignResultTypeFromTL(&grpstate->ss.ps);
-	ExecAssignProjectionInfo(&grpstate->ss.ps, NULL);
+	if (node->plan.tlist_lower_congruent)
+		grpstate->ss.ps.ps_ProjInfo = NULL;
+	else
+		ExecAssignProjectionInfo(&grpstate->ss.ps, NULL);
 
 	grpstate->ss.ps.ps_TupFromTlist = false;
 
diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c
index b51efd8..4a129d6 100644
--- a/src/backend/executor/nodeResult.c
+++ b/src/backend/executor/nodeResult.c
@@ -152,7 +152,10 @@ ExecResult(ResultState *node)
 		 * the projection produces an empty set, in which case we must loop
 		 * back to see if there are more outerPlan tuples.
 		 */
-		resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
+		if (node->ps.ps_ProjInfo)
+			resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
+		else  /* Assign outertuple for identity projection */
+			resultSlot = econtext->ecxt_outertuple;
 
 		if (isDone != ExprEndResult)
 		{
@@ -261,7 +264,10 @@ ExecInitResult(Result *node, EState *estate, int eflags)
 	 * initialize tuple type and projection info
 	 */
 	ExecAssignResultTypeFromTL(&resstate->ps);
-	ExecAssignProjectionInfo(&resstate->ps, NULL);
+	if (node->plan.tlist_lower_congruent)
+		resstate->ps.ps_ProjInfo = NULL;
+	else
+		ExecAssignProjectionInfo(&resstate->ps, NULL);
 
 	return resstate;
 }
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index ade9b57..d34c45a 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -1373,7 +1373,10 @@ restart:
 	 * evaluated with respect to that row.
 	 */
 	econtext->ecxt_outertuple = winstate->ss.ss_ScanTupleSlot;
-	result = ExecProject(winstate->ss.ps.ps_ProjInfo, &isDone);
+	if (winstate->ss.ps.ps_ProjInfo)
+		result = ExecProject(winstate->ss.ps.ps_ProjInfo, &isDone);
+	else  /* Assign outertuple for identity projection */
+		result = econtext->ecxt_outertuple;
 
 	if (isDone == ExprEndResult)
 	{
@@ -1490,7 +1493,10 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
 	 * Initialize result tuple type and projection info.
 	 */
 	ExecAssignResultTypeFromTL(&winstate->ss.ps);
-	ExecAssignProjectionInfo(&winstate->ss.ps, NULL);
+	if (node->plan.tlist_lower_congruent)
+		winstate->ss.ps.ps_ProjInfo = NULL;
+	else
+		ExecAssignProjectionInfo(&winstate->ss.ps, NULL);
 
 	winstate->ss.ps.ps_TupFromTlist = false;
 
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index ccd69fc..39d54ce 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -1184,6 +1184,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 +1215,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/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;
