diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 3f76a407d7..098b14d227 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -84,7 +84,7 @@ static void ExecutePlan(EState *estate, PlanState *planstate,
 			bool sendTuples,
 			uint64 numberTuples,
 			ScanDirection direction,
-			DestReceiver *dest);
+			DestReceiver *dest, bool execute_once);
 static bool ExecCheckRTEPerms(RangeTblEntry *rte);
 static bool ExecCheckRTEPermsModified(Oid relOid, Oid userid,
 						  Bitmapset *modifiedCols,
@@ -97,7 +97,6 @@ static char *ExecBuildSlotValueDescription(Oid reloid,
 							  int maxfieldlen);
 static void EvalPlanQualStart(EPQState *epqstate, EState *parentestate,
 				  Plan *planTree);
-
 /*
  * Note that GetUpdatedColumns() also exists in commands/trigger.c.  There does
  * not appear to be any good header to put it into, given the structures that
@@ -340,6 +339,12 @@ standard_ExecutorRun(QueryDesc *queryDesc,
 	 * run plan
 	 */
 	if (!ScanDirectionIsNoMovement(direction))
+	{
+		if (queryDesc->execute_once)
+			elog(ERROR, "query is called more than once for the same query-descriptor %s", queryDesc->sourceText);
+		if (dest->mydest == DestSPI || dest->mydest == DestSQLFunction || count == 0)
+			queryDesc->execute_once = true;
+
 		ExecutePlan(estate,
 					queryDesc->planstate,
 					queryDesc->plannedstmt->parallelModeNeeded,
@@ -347,7 +352,9 @@ standard_ExecutorRun(QueryDesc *queryDesc,
 					sendTuples,
 					count,
 					direction,
-					dest);
+					dest,
+					queryDesc->execute_once);
+	}
 
 	/*
 	 * shutdown tuple receiver, if we started it
@@ -1570,7 +1577,8 @@ ExecutePlan(EState *estate,
 			bool sendTuples,
 			uint64 numberTuples,
 			ScanDirection direction,
-			DestReceiver *dest)
+			DestReceiver *dest,
+			bool execute_once)
 {
 	TupleTableSlot *slot;
 	uint64		current_tuple_count;
@@ -1589,9 +1597,11 @@ ExecutePlan(EState *estate,
 	 * If a tuple count was supplied, we must force the plan to run without
 	 * parallelism, because we might exit early.  Also disable parallelism
 	 * when writing into a relation, because no database changes are allowed
-	 * in parallel mode.
+	 * in parallel mode. To enable parallelism for queries coming from SQL
+	 * or other PL functions, allow parallelism if the planner considers
+	 * it safe and those are coming from queryDesc which will execute only once.
 	 */
-	if (numberTuples || dest->mydest == DestIntoRel)
+	if (!execute_once || dest->mydest == DestIntoRel)
 		use_parallel_mode = false;
 
 	if (use_parallel_mode)
@@ -1662,7 +1672,16 @@ ExecutePlan(EState *estate,
 		 */
 		current_tuple_count++;
 		if (numberTuples && numberTuples == current_tuple_count)
+		{
+			/*
+			 * For the queries coming from SQL or PL functions, this condition
+			 * will be satisfied for the first tuple and since we enabled
+			 * parallel workers for it, a proper shutdown of the workers would
+			 * be required.
+			 */
+			(void) ExecShutdownNode(planstate);
 			break;
+		}
 	}
 
 	if (use_parallel_mode)
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index e64ea2ed76..7737bf5041 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -87,6 +87,7 @@ CreateQueryDesc(PlannedStmt *plannedstmt,
 	qd->estate = NULL;
 	qd->planstate = NULL;
 	qd->totaltime = NULL;
+	qd->execute_once = false;
 
 	return qd;
 }
diff --git a/src/include/executor/execdesc.h b/src/include/executor/execdesc.h
index c99ea81815..062f47fb76 100644
--- a/src/include/executor/execdesc.h
+++ b/src/include/executor/execdesc.h
@@ -49,6 +49,7 @@ typedef struct QueryDesc
 
 	/* This is always set NULL by the core system, but plugins can change it */
 	struct Instrumentation *totaltime;	/* total time spent in ExecutorRun */
+	bool		execute_once;
 } QueryDesc;
 
 /* in pquery.c */
