diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 6e21b4b708..03933cf694 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -78,6 +78,7 @@ struct ParallelAppendState
 };
 
 #define INVALID_SUBPLAN_INDEX		-1
+#define NO_MATCHING_SUBPLANS		-2
 
 static TupleTableSlot *ExecAppend(PlanState *pstate);
 static bool choose_next_subplan_locally(AppendState *node);
@@ -122,7 +123,9 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
 	appendstate->ps.plan = (Plan *) node;
 	appendstate->ps.state = estate;
 	appendstate->ps.ExecProcNode = ExecAppend;
-	appendstate->as_noopscan = false;
+
+	/* Let choose_next_subplan_* function handle setting the first subplan */
+	appendstate->as_whichplan = INVALID_SUBPLAN_INDEX;
 
 	/* If run-time partition pruning is enabled, then setup that up now */
 	if (node->part_prune_infos != NIL)
@@ -150,12 +153,12 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
 			 * explain.c requires an Append to have at least one subplan in
 			 * order for it to properly determine the Vars in that subplan's
 			 * targetlist.  We sidestep this issue by just initializing the
-			 * first subplan, but we set a noop flag so that we never actually
-			 * bother scanning it.
+			 * first subplan, but set as_whichplan to a special value which
+			 * indicates that no plans match.
 			 */
 			if (bms_is_empty(validsubplans))
 			{
-				appendstate->as_noopscan = true;
+				appendstate->as_whichplan = NO_MATCHING_SUBPLANS;
 
 				/* Mark the first as valid so that it's initialized below */
 				validsubplans = bms_make_singleton(0);
@@ -226,9 +229,6 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
 
 	appendstate->ps.ps_ProjInfo = NULL;
 
-	/* Let choose_next_subplan_* function handle setting the first subplan */
-	appendstate->as_whichplan = INVALID_SUBPLAN_INDEX;
-
 	/* For parallel query, this will be overridden later. */
 	appendstate->choose_next_subplan = choose_next_subplan_locally;
 
@@ -245,11 +245,22 @@ static TupleTableSlot *
 ExecAppend(PlanState *pstate)
 {
 	AppendState *node = castNode(AppendState, pstate);
+	int			whichplan = node->as_whichplan;
 
-	/* If no subplan has been chosen, we must choose one before proceeding. */
-	if (node->as_whichplan == INVALID_SUBPLAN_INDEX &&
-		!node->choose_next_subplan(node))
-		return ExecClearTuple(node->ps.ps_ResultTupleSlot);
+	if (whichplan < 0)
+	{
+		/*
+		 * If no subplan has been chosen, we must choose one before
+		 * proceeding.
+		 */
+		if (whichplan == INVALID_SUBPLAN_INDEX &&
+			!node->choose_next_subplan(node))
+			return ExecClearTuple(node->ps.ps_ResultTupleSlot);
+
+		/* Nothing to do if there are no matching subplans */
+		else if (whichplan == NO_MATCHING_SUBPLANS)
+			return ExecClearTuple(node->ps.ps_ResultTupleSlot);
+	}
 
 	for (;;)
 	{
@@ -442,9 +453,8 @@ choose_next_subplan_locally(AppendState *node)
 	int			whichplan = node->as_whichplan;
 	int			nextplan;
 
-	/* Handle the case for when all subplans were pruned */
-	if (node->as_noopscan)
-		return false;
+	/* We should never be called when there are no subplans */
+	Assert(whichplan != NO_MATCHING_SUBPLANS);
 
 	/*
 	 * If first call then have the bms member function choose the first valid
@@ -495,6 +505,9 @@ choose_next_subplan_for_leader(AppendState *node)
 	/* Backward scan is not supported by parallel-aware plans */
 	Assert(ScanDirectionIsForward(node->ps.state->es_direction));
 
+	/* We should never be called when there are no subplans */
+	Assert(node->as_whichplan != NO_MATCHING_SUBPLANS);
+
 	LWLockAcquire(&pstate->pa_lock, LW_EXCLUSIVE);
 
 	if (node->as_whichplan != INVALID_SUBPLAN_INDEX)
@@ -502,12 +515,6 @@ choose_next_subplan_for_leader(AppendState *node)
 		/* Mark just-completed subplan as finished. */
 		node->as_pstate->pa_finished[node->as_whichplan] = true;
 	}
-	else if (node->as_noopscan)
-	{
-		/* Handle the case for when all subplans were pruned */
-		LWLockRelease(&pstate->pa_lock);
-		return false;
-	}
 	else
 	{
 		/* Start with last subplan. */
@@ -575,19 +582,15 @@ choose_next_subplan_for_worker(AppendState *node)
 	/* Backward scan is not supported by parallel-aware plans */
 	Assert(ScanDirectionIsForward(node->ps.state->es_direction));
 
+	/* We should never be called when there are no subplans */
+	Assert(node->as_whichplan != NO_MATCHING_SUBPLANS);
+
 	LWLockAcquire(&pstate->pa_lock, LW_EXCLUSIVE);
 
 	/* Mark just-completed subplan as finished. */
 	if (node->as_whichplan != INVALID_SUBPLAN_INDEX)
 		node->as_pstate->pa_finished[node->as_whichplan] = true;
 
-	else if (node->as_noopscan)
-	{
-		/* Handle the case for when all subplans were pruned */
-		LWLockRelease(&pstate->pa_lock);
-		return false;
-	}
-
 	/*
 	 * If we've yet to determine the valid subplans for these parameters then
 	 * do so now.  If run-time pruning is disabled then the valid subplans
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 1986abaa9c..fccc38cbe7 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1115,14 +1115,12 @@ typedef struct ModifyTableState
  *	 AppendState information
  *
  *		nplans				how many plans are in the array
- *		whichplan			which plan is being executed (0 .. n-1)
+ *		whichplan			which plan is being executed (0 .. n-1), or a
+ *							special negative value. See nodeAppend.c.
  *		partition_pruning	details required to allow partitions to be
  *							eliminated from the scan, or NULL if not possible.
  *		valid_subplans		for runtime pruning, valid appendplans indexes to
  *							scan.
- *		noopscan			true if partition pruning proved that none of the
- *							appendplans can contain a record to satisfy this
- *							query.
  * ----------------
  */
 
@@ -1143,7 +1141,6 @@ struct AppendState
 	struct PartitionPruning *partition_pruning;
 	Bitmapset  *as_valid_subplans;
 	bool		(*choose_next_subplan) (AppendState *);
-	bool		as_noopscan;	/* true if no subplans need scanned */
 };
 
 /* ----------------
