aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/copy.c2
-rw-r--r--src/backend/commands/createas.c2
-rw-r--r--src/backend/commands/explain.c2
-rw-r--r--src/backend/commands/extension.c2
-rw-r--r--src/backend/commands/matview.c2
-rw-r--r--src/backend/commands/portalcmds.c2
-rw-r--r--src/backend/commands/prepare.c2
-rw-r--r--src/backend/executor/execMain.c38
-rw-r--r--src/backend/executor/execParallel.c2
-rw-r--r--src/backend/executor/functions.c2
-rw-r--r--src/backend/executor/spi.c2
-rw-r--r--src/backend/tcop/postgres.c2
-rw-r--r--src/backend/tcop/pquery.c20
-rw-r--r--src/include/executor/execdesc.h3
-rw-r--r--src/include/executor/executor.h7
-rw-r--r--src/include/tcop/pquery.h2
-rw-r--r--src/include/utils/portal.h1
17 files changed, 63 insertions, 30 deletions
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index b0fd09f458a..ab59be84552 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -2074,7 +2074,7 @@ CopyTo(CopyState cstate)
else
{
/* run the plan --- the dest receiver will send tuples */
- ExecutorRun(cstate->queryDesc, ForwardScanDirection, 0L);
+ ExecutorRun(cstate->queryDesc, ForwardScanDirection, 0L, true);
processed = ((DR_copy *) cstate->queryDesc->dest)->processed;
}
diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c
index 646a88409f2..3daffc894a1 100644
--- a/src/backend/commands/createas.c
+++ b/src/backend/commands/createas.c
@@ -347,7 +347,7 @@ ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString,
ExecutorStart(queryDesc, GetIntoRelEFlags(into));
/* run the plan to completion */
- ExecutorRun(queryDesc, ForwardScanDirection, 0L);
+ ExecutorRun(queryDesc, ForwardScanDirection, 0L, true);
/* save the rowcount if we're given a completionTag to fill */
if (completionTag)
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index c9b55ead3dc..b4c7466666b 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -530,7 +530,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es,
dir = ForwardScanDirection;
/* run the plan */
- ExecutorRun(queryDesc, dir, 0L);
+ ExecutorRun(queryDesc, dir, 0L, true);
/* run cleanup too */
ExecutorFinish(queryDesc);
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 86a84ee2346..5a84bedf467 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -742,7 +742,7 @@ execute_sql_string(const char *sql, const char *filename)
dest, NULL, 0);
ExecutorStart(qdesc, 0);
- ExecutorRun(qdesc, ForwardScanDirection, 0);
+ ExecutorRun(qdesc, ForwardScanDirection, 0, true);
ExecutorFinish(qdesc);
ExecutorEnd(qdesc);
diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c
index 8df3d1d81dd..9d41ad8fad2 100644
--- a/src/backend/commands/matview.c
+++ b/src/backend/commands/matview.c
@@ -424,7 +424,7 @@ refresh_matview_datafill(DestReceiver *dest, Query *query,
ExecutorStart(queryDesc, EXEC_FLAG_WITHOUT_OIDS);
/* run the plan */
- ExecutorRun(queryDesc, ForwardScanDirection, 0L);
+ ExecutorRun(queryDesc, ForwardScanDirection, 0L, true);
processed = queryDesc->estate->es_processed;
diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c
index 29d0430dd87..f57cf87e8c3 100644
--- a/src/backend/commands/portalcmds.c
+++ b/src/backend/commands/portalcmds.c
@@ -395,7 +395,7 @@ PersistHoldablePortal(Portal portal)
true);
/* Fetch the result set into the tuplestore */
- ExecutorRun(queryDesc, ForwardScanDirection, 0L);
+ ExecutorRun(queryDesc, ForwardScanDirection, 0L, false);
(*queryDesc->dest->rDestroy) (queryDesc->dest);
queryDesc->dest = NULL;
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index 1cf0d2b971a..992ba1c9a2e 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -301,7 +301,7 @@ ExecuteQuery(ExecuteStmt *stmt, IntoClause *intoClause,
*/
PortalStart(portal, paramLI, eflags, GetActiveSnapshot());
- (void) PortalRun(portal, count, false, dest, dest, completionTag);
+ (void) PortalRun(portal, count, false, true, dest, dest, completionTag);
PortalDrop(portal, false);
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 023ea0081a0..c28cf9c8eab 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -85,7 +85,8 @@ 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,
@@ -288,17 +289,18 @@ standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
*/
void
ExecutorRun(QueryDesc *queryDesc,
- ScanDirection direction, uint64 count)
+ ScanDirection direction, uint64 count,
+ bool execute_once)
{
if (ExecutorRun_hook)
- (*ExecutorRun_hook) (queryDesc, direction, count);
+ (*ExecutorRun_hook) (queryDesc, direction, count, execute_once);
else
- standard_ExecutorRun(queryDesc, direction, count);
+ standard_ExecutorRun(queryDesc, direction, count, execute_once);
}
void
standard_ExecutorRun(QueryDesc *queryDesc,
- ScanDirection direction, uint64 count)
+ ScanDirection direction, uint64 count, bool execute_once)
{
EState *estate;
CmdType operation;
@@ -345,6 +347,11 @@ standard_ExecutorRun(QueryDesc *queryDesc,
* run plan
*/
if (!ScanDirectionIsNoMovement(direction))
+ {
+ if (execute_once && queryDesc->already_executed)
+ elog(ERROR, "can't re-execute query flagged for single execution");
+ queryDesc->already_executed = true;
+
ExecutePlan(estate,
queryDesc->planstate,
queryDesc->plannedstmt->parallelModeNeeded,
@@ -352,7 +359,9 @@ standard_ExecutorRun(QueryDesc *queryDesc,
sendTuples,
count,
direction,
- dest);
+ dest,
+ execute_once);
+ }
/*
* shutdown tuple receiver, if we started it
@@ -1595,7 +1604,8 @@ ExecutePlan(EState *estate,
bool sendTuples,
uint64 numberTuples,
ScanDirection direction,
- DestReceiver *dest)
+ DestReceiver *dest,
+ bool execute_once)
{
TupleTableSlot *slot;
uint64 current_tuple_count;
@@ -1611,12 +1621,12 @@ ExecutePlan(EState *estate,
estate->es_direction = direction;
/*
- * 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.
+ * If the plan might potentially be executed multiple times, we must force
+ * it 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.
*/
- if (numberTuples || dest->mydest == DestIntoRel)
+ if (!execute_once || dest->mydest == DestIntoRel)
use_parallel_mode = false;
if (use_parallel_mode)
@@ -1687,7 +1697,11 @@ ExecutePlan(EState *estate,
*/
current_tuple_count++;
if (numberTuples && numberTuples == current_tuple_count)
+ {
+ /* Allow nodes to release or shut down resources. */
+ (void) ExecShutdownNode(planstate);
break;
+ }
}
if (use_parallel_mode)
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index 86db73be431..b91b663c46f 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -853,7 +853,7 @@ ParallelQueryMain(dsm_segment *seg, shm_toc *toc)
ExecParallelInitializeWorker(queryDesc->planstate, toc);
/* Run the plan */
- ExecutorRun(queryDesc, ForwardScanDirection, 0L);
+ ExecutorRun(queryDesc, ForwardScanDirection, 0L, true);
/* Shut down the executor */
ExecutorFinish(queryDesc);
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 2d49a656502..12214f8a150 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -855,7 +855,7 @@ postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache)
/* Run regular commands to completion unless lazyEval */
uint64 count = (es->lazyEval) ? 1 : 0;
- ExecutorRun(es->qd, ForwardScanDirection, count);
+ ExecutorRun(es->qd, ForwardScanDirection, count, !fcache->returnsSet || !es->lazyEval);
/*
* If we requested run to completion OR there was no tuple returned,
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 55f97b14e6e..72c7b4d0689 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -2305,7 +2305,7 @@ _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, uint64 tcount)
ExecutorStart(queryDesc, eflags);
- ExecutorRun(queryDesc, ForwardScanDirection, tcount);
+ ExecutorRun(queryDesc, ForwardScanDirection, tcount, true);
_SPI_current->processed = queryDesc->estate->es_processed;
_SPI_current->lastoid = queryDesc->estate->es_lastoid;
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index ba41f907126..6258a14c390 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -1101,6 +1101,7 @@ exec_simple_query(const char *query_string)
(void) PortalRun(portal,
FETCH_ALL,
isTopLevel,
+ true,
receiver,
receiver,
completionTag);
@@ -1985,6 +1986,7 @@ exec_execute_message(const char *portal_name, long max_rows)
completed = PortalRun(portal,
max_rows,
true, /* always top level */
+ !execute_is_fetch && max_rows == FETCH_ALL,
receiver,
receiver,
completionTag);
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index 371d7350b7a..f538b7787c3 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -90,6 +90,9 @@ CreateQueryDesc(PlannedStmt *plannedstmt,
qd->planstate = NULL;
qd->totaltime = NULL;
+ /* not yet executed */
+ qd->already_executed = false;
+
return qd;
}
@@ -152,7 +155,7 @@ ProcessQuery(PlannedStmt *plan,
/*
* Run the plan to completion.
*/
- ExecutorRun(queryDesc, ForwardScanDirection, 0L);
+ ExecutorRun(queryDesc, ForwardScanDirection, 0L, true);
/*
* Build command completion status string, if caller wants one.
@@ -679,7 +682,7 @@ PortalSetResultFormat(Portal portal, int nFormats, int16 *formats)
* suspended due to exhaustion of the count parameter.
*/
bool
-PortalRun(Portal portal, long count, bool isTopLevel,
+PortalRun(Portal portal, long count, bool isTopLevel, bool run_once,
DestReceiver *dest, DestReceiver *altdest,
char *completionTag)
{
@@ -712,6 +715,10 @@ PortalRun(Portal portal, long count, bool isTopLevel,
*/
MarkPortalActive(portal);
+ /* Set run_once flag. Shouldn't be clear if previously set. */
+ Assert(!portal->run_once || run_once);
+ portal->run_once = run_once;
+
/*
* Set up global portal context pointers.
*
@@ -918,7 +925,8 @@ PortalRunSelect(Portal portal,
else
{
PushActiveSnapshot(queryDesc->snapshot);
- ExecutorRun(queryDesc, direction, (uint64) count);
+ ExecutorRun(queryDesc, direction, (uint64) count,
+ portal->run_once);
nprocessed = queryDesc->estate->es_processed;
PopActiveSnapshot();
}
@@ -957,7 +965,8 @@ PortalRunSelect(Portal portal,
else
{
PushActiveSnapshot(queryDesc->snapshot);
- ExecutorRun(queryDesc, direction, (uint64) count);
+ ExecutorRun(queryDesc, direction, (uint64) count,
+ portal->run_once);
nprocessed = queryDesc->estate->es_processed;
PopActiveSnapshot();
}
@@ -1394,6 +1403,9 @@ PortalRunFetch(Portal portal,
*/
MarkPortalActive(portal);
+ /* If supporting FETCH, portal can't be run-once. */
+ Assert(!portal->run_once);
+
/*
* Set up global portal context pointers.
*/
diff --git a/src/include/executor/execdesc.h b/src/include/executor/execdesc.h
index c99ea818158..87e7ca85082 100644
--- a/src/include/executor/execdesc.h
+++ b/src/include/executor/execdesc.h
@@ -47,6 +47,9 @@ typedef struct QueryDesc
EState *estate; /* executor's query-wide state */
PlanState *planstate; /* tree of per-plan-node state */
+ /* This field is set by ExecutorRun */
+ bool already_executed; /* true if previously executed */
+
/* This is always set NULL by the core system, but plugins can change it */
struct Instrumentation *totaltime; /* total time spent in ExecutorRun */
} QueryDesc;
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index e64d6fb93fe..a5c75e771f0 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -81,7 +81,8 @@ extern PGDLLIMPORT ExecutorStart_hook_type ExecutorStart_hook;
/* Hook for plugins to get control in ExecutorRun() */
typedef void (*ExecutorRun_hook_type) (QueryDesc *queryDesc,
ScanDirection direction,
- uint64 count);
+ uint64 count,
+ bool execute_once);
extern PGDLLIMPORT ExecutorRun_hook_type ExecutorRun_hook;
/* Hook for plugins to get control in ExecutorFinish() */
@@ -176,9 +177,9 @@ extern TupleTableSlot *ExecFilterJunk(JunkFilter *junkfilter,
extern void ExecutorStart(QueryDesc *queryDesc, int eflags);
extern void standard_ExecutorStart(QueryDesc *queryDesc, int eflags);
extern void ExecutorRun(QueryDesc *queryDesc,
- ScanDirection direction, uint64 count);
+ ScanDirection direction, uint64 count, bool execute_once);
extern void standard_ExecutorRun(QueryDesc *queryDesc,
- ScanDirection direction, uint64 count);
+ ScanDirection direction, uint64 count, bool execute_once);
extern void ExecutorFinish(QueryDesc *queryDesc);
extern void standard_ExecutorFinish(QueryDesc *queryDesc);
extern void ExecutorEnd(QueryDesc *queryDesc);
diff --git a/src/include/tcop/pquery.h b/src/include/tcop/pquery.h
index 61c0b3447e5..12ff4588c61 100644
--- a/src/include/tcop/pquery.h
+++ b/src/include/tcop/pquery.h
@@ -34,7 +34,7 @@ extern void PortalSetResultFormat(Portal portal, int nFormats,
int16 *formats);
extern bool PortalRun(Portal portal, long count, bool isTopLevel,
- DestReceiver *dest, DestReceiver *altdest,
+ bool run_once, DestReceiver *dest, DestReceiver *altdest,
char *completionTag);
extern uint64 PortalRunFetch(Portal portal,
diff --git a/src/include/utils/portal.h b/src/include/utils/portal.h
index dc76acd0a42..e7c5a8bd091 100644
--- a/src/include/utils/portal.h
+++ b/src/include/utils/portal.h
@@ -141,6 +141,7 @@ typedef struct PortalData
/* Features/options */
PortalStrategy strategy; /* see above */
int cursorOptions; /* DECLARE CURSOR option bits */
+ bool run_once; /* portal will only be run once */
/* Status data */
PortalStatus status; /* see above */