aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execMain.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/execMain.c')
-rw-r--r--src/backend/executor/execMain.c30
1 files changed, 25 insertions, 5 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index df4da3faa97..26793eecf48 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -147,8 +147,20 @@ standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
/*
* If the transaction is read-only, we need to check if any writes are
* planned to non-temporary tables. EXPLAIN is considered read-only.
+ *
+ * Don't allow writes in parallel mode. Supporting UPDATE and DELETE would
+ * require (a) storing the combocid hash in shared memory, rather than
+ * synchronizing it just once at the start of parallelism, and (b) an
+ * alternative to heap_update()'s reliance on xmax for mutual exclusion.
+ * INSERT may have no such troubles, but we forbid it to simplify the
+ * checks.
+ *
+ * We have lower-level defenses in CommandCounterIncrement and elsewhere
+ * against performing unsafe operations in parallel mode, but this gives
+ * a more user-friendly error message.
*/
- if (XactReadOnly && !(eflags & EXEC_FLAG_EXPLAIN_ONLY))
+ if ((XactReadOnly || IsInParallelMode()) &&
+ !(eflags & EXEC_FLAG_EXPLAIN_ONLY))
ExecCheckXactReadOnly(queryDesc->plannedstmt);
/*
@@ -691,18 +703,23 @@ ExecCheckRTEPerms(RangeTblEntry *rte)
}
/*
- * Check that the query does not imply any writes to non-temp tables.
+ * Check that the query does not imply any writes to non-temp tables;
+ * unless we're in parallel mode, in which case don't even allow writes
+ * to temp tables.
*
* Note: in a Hot Standby slave this would need to reject writes to temp
- * tables as well; but an HS slave can't have created any temp tables
- * in the first place, so no need to check that.
+ * tables just as we do in parallel mode; but an HS slave can't have created
+ * any temp tables in the first place, so no need to check that.
*/
static void
ExecCheckXactReadOnly(PlannedStmt *plannedstmt)
{
ListCell *l;
- /* Fail if write permissions are requested on any non-temp table */
+ /*
+ * Fail if write permissions are requested in parallel mode for
+ * table (temp or non-temp), otherwise fail for any non-temp table.
+ */
foreach(l, plannedstmt->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
@@ -718,6 +735,9 @@ ExecCheckXactReadOnly(PlannedStmt *plannedstmt)
PreventCommandIfReadOnly(CreateCommandTag((Node *) plannedstmt));
}
+
+ if (plannedstmt->commandType != CMD_SELECT || plannedstmt->hasModifyingCTE)
+ PreventCommandIfParallelMode(CreateCommandTag((Node *) plannedstmt));
}