aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/access/heap/heapam.c16
-rw-r--r--src/backend/commands/createas.c4
-rw-r--r--src/backend/commands/explain.c4
-rw-r--r--src/backend/executor/execMain.c6
-rw-r--r--src/backend/optimizer/plan/planner.c10
5 files changed, 24 insertions, 16 deletions
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index c435482cd21..0c0f640f640 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2598,15 +2598,17 @@ heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
CommandId cid, int options)
{
/*
- * For now, parallel operations are required to be strictly read-only.
- * Unlike heap_update() and heap_delete(), an insert should never create a
- * combo CID, so it might be possible to relax this restriction, but not
- * without more thought and testing.
- */
- if (IsInParallelMode())
+ * Parallel operations are required to be strictly read-only in a parallel
+ * worker. Parallel inserts are not safe even in the leader in the
+ * general case, because group locking means that heavyweight locks for
+ * relation extension or GIN page locks will not conflict between members
+ * of a lock group, but we don't prohibit that case here because there are
+ * useful special cases that we can safely allow, such as CREATE TABLE AS.
+ */
+ if (IsParallelWorker())
ereport(ERROR,
(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
- errmsg("cannot insert tuples during a parallel operation")));
+ errmsg("cannot insert tuples in a parallel worker")));
if (relation->rd_rel->relhasoids)
{
diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c
index e60210cb24b..4d77411a682 100644
--- a/src/backend/commands/createas.c
+++ b/src/backend/commands/createas.c
@@ -326,8 +326,8 @@ ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString,
query = linitial_node(Query, rewritten);
Assert(query->commandType == CMD_SELECT);
- /* plan the query --- note we disallow parallelism */
- plan = pg_plan_query(query, 0, params);
+ /* plan the query */
+ plan = pg_plan_query(query, CURSOR_OPT_PARALLEL_OK, params);
/*
* Use a snapshot with an updated command ID to ensure this query sees
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index c1602c59cca..8f7062cd6ea 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -396,8 +396,6 @@ ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es,
* We have to rewrite the contained SELECT and then pass it back to
* ExplainOneQuery. It's probably not really necessary to copy the
* contained parsetree another time, but let's be safe.
- *
- * Like ExecCreateTableAs, disallow parallelism in the plan.
*/
CreateTableAsStmt *ctas = (CreateTableAsStmt *) utilityStmt;
List *rewritten;
@@ -405,7 +403,7 @@ ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es,
rewritten = QueryRewrite(castNode(Query, copyObject(ctas->query)));
Assert(list_length(rewritten) == 1);
ExplainOneQuery(linitial_node(Query, rewritten),
- 0, ctas->into, es,
+ CURSOR_OPT_PARALLEL_OK, ctas->into, es,
queryString, params, queryEnv);
}
else if (IsA(utilityStmt, DeclareCursorStmt))
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 62fb05efac6..384ad70f2d9 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -1697,11 +1697,9 @@ ExecutePlan(EState *estate,
/*
* 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.
+ * it to run without parallelism, because we might exit early.
*/
- if (!execute_once || dest->mydest == DestIntoRel)
+ if (!execute_once)
use_parallel_mode = false;
if (use_parallel_mode)
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 7f146d670cb..e7ac11e9bb7 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -257,6 +257,16 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
* to values that don't permit parallelism, or if parallel-unsafe
* functions are present in the query tree.
*
+ * (Note that we do allow CREATE TABLE AS, SELECT INTO, and CREATE
+ * MATERIALIZED VIEW to use parallel plans, but this is safe only because
+ * the command is writing into a completely new table which workers won't
+ * be able to see. If the workers could see the table, the fact that
+ * group locking would cause them to ignore the leader's heavyweight
+ * relation extension lock and GIN page locks would make this unsafe.
+ * We'll have to fix that somehow if we want to allow parallel inserts in
+ * general; updates and deletes have additional problems especially around
+ * combo CIDs.)
+ *
* For now, we don't try to use parallel mode if we're running inside a
* parallel worker. We might eventually be able to relax this
* restriction, but for now it seems best not to have parallel workers