Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmit Kapila2021-03-24 05:40:12 +0000
committerAmit Kapila2021-03-24 05:59:15 +0000
commit26acb54a1368bf3706294400abca85b15c9233a6 (patch)
tree435436137df934ae0d011d271ab73a4710b4c893 /src/backend
parent84007043fc1b1be68dad5d0a78269347c12094b6 (diff)
Revert "Enable parallel SELECT for "INSERT INTO ... SELECT ..."."
To allow inserts in parallel-mode this feature has to ensure that all the constraints, triggers, etc. are parallel-safe for the partition hierarchy which is costly and we need to find a better way to do that. Additionally, we could have used existing cached information in some cases like indexes, domains, etc. to determine the parallel-safety. List of commits reverted, in reverse chronological order: ed62d3737c Doc: Update description for parallel insert reloption. c8f78b6161 Add a new GUC and a reloption to enable inserts in parallel-mode. c5be48f092 Improve FK trigger parallel-safety check added by 05c8482f7f. e2cda3c20a Fix use of relcache TriggerDesc field introduced by commit 05c8482f7f. e4e87a32cc Fix valgrind issue in commit 05c8482f7f. 05c8482f7f Enable parallel SELECT for "INSERT INTO ... SELECT ...". Discussion: https://postgr.es/m/E1lMiB9-0001c3-SY@gemulon.postgresql.org
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/access/common/reloptions.c25
-rw-r--r--src/backend/access/transam/xact.c26
-rw-r--r--src/backend/executor/execMain.c3
-rw-r--r--src/backend/nodes/copyfuncs.c1
-rw-r--r--src/backend/nodes/outfuncs.c2
-rw-r--r--src/backend/nodes/readfuncs.c1
-rw-r--r--src/backend/optimizer/path/costsize.c2
-rw-r--r--src/backend/optimizer/plan/planner.c37
-rw-r--r--src/backend/optimizer/util/clauses.c571
-rw-r--r--src/backend/utils/cache/plancache.c33
-rw-r--r--src/backend/utils/misc/guc.c10
-rw-r--r--src/backend/utils/misc/postgresql.conf.sample1
12 files changed, 25 insertions, 687 deletions
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 5a0ae99750f..d897bbec2ba 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -168,15 +168,6 @@ static relopt_bool boolRelOpts[] =
},
true
},
- {
- {
- "parallel_insert_enabled",
- "Enables \"parallel insert\" feature for this table",
- RELOPT_KIND_HEAP | RELOPT_KIND_PARTITIONED,
- ShareUpdateExclusiveLock
- },
- true
- },
/* list terminator */
{{NULL}}
};
@@ -1868,9 +1859,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
{"vacuum_index_cleanup", RELOPT_TYPE_BOOL,
offsetof(StdRdOptions, vacuum_index_cleanup)},
{"vacuum_truncate", RELOPT_TYPE_BOOL,
- offsetof(StdRdOptions, vacuum_truncate)},
- {"parallel_insert_enabled", RELOPT_TYPE_BOOL,
- offsetof(StdRdOptions, parallel_insert_enabled)}
+ offsetof(StdRdOptions, vacuum_truncate)}
};
return (bytea *) build_reloptions(reloptions, validate, kind,
@@ -1972,15 +1961,13 @@ build_local_reloptions(local_relopts *relopts, Datum options, bool validate)
bytea *
partitioned_table_reloptions(Datum reloptions, bool validate)
{
- static const relopt_parse_elt tab[] = {
- {"parallel_insert_enabled", RELOPT_TYPE_BOOL,
- offsetof(PartitionedTableRdOptions, parallel_insert_enabled)}
- };
-
+ /*
+ * There are no options for partitioned tables yet, but this is able to do
+ * some validation.
+ */
return (bytea *) build_reloptions(reloptions, validate,
RELOPT_KIND_PARTITIONED,
- sizeof(PartitionedTableRdOptions),
- tab, lengthof(tab));
+ 0, NULL, 0);
}
/*
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 6395a9b2408..c83aa16f2ce 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -1015,32 +1015,6 @@ IsInParallelMode(void)
}
/*
- * PrepareParallelModePlanExec
- *
- * Prepare for entering parallel mode plan execution, based on command-type.
- */
-void
-PrepareParallelModePlanExec(CmdType commandType)
-{
- if (IsModifySupportedInParallelMode(commandType))
- {
- Assert(!IsInParallelMode());
-
- /*
- * Prepare for entering parallel mode by assigning a TransactionId.
- * Failure to do this now would result in heap_insert() subsequently
- * attempting to assign a TransactionId whilst in parallel-mode, which
- * is not allowed.
- *
- * This approach has a disadvantage in that if the underlying SELECT
- * does not return any rows, then the TransactionId is not used,
- * however that shouldn't happen in practice in many cases.
- */
- (void) GetCurrentTransactionId();
- }
-}
-
-/*
* CommandCounterIncrement
*/
void
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 0648dd82ba0..c74ce36ffba 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -1512,10 +1512,7 @@ ExecutePlan(EState *estate,
estate->es_use_parallel_mode = use_parallel_mode;
if (use_parallel_mode)
- {
- PrepareParallelModePlanExec(estate->es_plannedstmt->commandType);
EnterParallelMode();
- }
/*
* Loop until we've processed the proper number of tuples from the plan.
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 2c20541e92a..82d7cce5d57 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -96,7 +96,6 @@ _copyPlannedStmt(const PlannedStmt *from)
COPY_BITMAPSET_FIELD(rewindPlanIDs);
COPY_NODE_FIELD(rowMarks);
COPY_NODE_FIELD(relationOids);
- COPY_NODE_FIELD(partitionOids);
COPY_NODE_FIELD(invalItems);
COPY_NODE_FIELD(paramExecTypes);
COPY_NODE_FIELD(utilityStmt);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 305311d4a7a..9f7918c7e90 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -314,7 +314,6 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node)
WRITE_BITMAPSET_FIELD(rewindPlanIDs);
WRITE_NODE_FIELD(rowMarks);
WRITE_NODE_FIELD(relationOids);
- WRITE_NODE_FIELD(partitionOids);
WRITE_NODE_FIELD(invalItems);
WRITE_NODE_FIELD(paramExecTypes);
WRITE_NODE_FIELD(utilityStmt);
@@ -2222,7 +2221,6 @@ _outPlannerGlobal(StringInfo str, const PlannerGlobal *node)
WRITE_NODE_FIELD(resultRelations);
WRITE_NODE_FIELD(appendRelations);
WRITE_NODE_FIELD(relationOids);
- WRITE_NODE_FIELD(partitionOids);
WRITE_NODE_FIELD(invalItems);
WRITE_NODE_FIELD(paramExecTypes);
WRITE_UINT_FIELD(lastPHId);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 9b8f81c5231..377185f7c67 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1591,7 +1591,6 @@ _readPlannedStmt(void)
READ_BITMAPSET_FIELD(rewindPlanIDs);
READ_NODE_FIELD(rowMarks);
READ_NODE_FIELD(relationOids);
- READ_NODE_FIELD(partitionOids);
READ_NODE_FIELD(invalItems);
READ_NODE_FIELD(paramExecTypes);
READ_NODE_FIELD(utilityStmt);
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index c81e2cf2447..a25b674a192 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -129,8 +129,6 @@ Cost disable_cost = 1.0e10;
int max_parallel_workers_per_gather = 2;
-bool enable_parallel_insert = true;
-
bool enable_seqscan = true;
bool enable_indexscan = true;
bool enable_indexonlyscan = true;
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 28b40dd905b..f529d107d29 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -305,7 +305,6 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
glob->resultRelations = NIL;
glob->appendRelations = NIL;
glob->relationOids = NIL;
- glob->partitionOids = NIL;
glob->invalItems = NIL;
glob->paramExecTypes = NIL;
glob->lastPHId = 0;
@@ -317,16 +316,16 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
/*
* Assess whether it's feasible to use parallel mode for this query. We
* can't do this in a standalone backend, or if the command will try to
- * modify any data (except for Insert), or if this is a cursor operation,
- * or if GUCs are set to values that don't permit parallelism, or if
- * parallel-unsafe functions are present in the query tree.
+ * modify any data, or if this is a cursor operation, or if GUCs are set
+ * 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, INSERT INTO...SELECT, SELECT
- * INTO, and CREATE MATERIALIZED VIEW to use parallel plans. However, as
- * of now, only the leader backend writes into a completely new table. In
- * the future, we can extend it to allow workers to write into the table.
- * However, to allow parallel updates and deletes, we have to solve other
- * problems, especially around combo CIDs.)
+ * (Note that we do allow CREATE TABLE AS, SELECT INTO, and CREATE
+ * MATERIALIZED VIEW to use parallel plans, but as of now, only the leader
+ * backend writes into a completely new table. In the future, we can
+ * extend it to allow workers to write into the table. However, to allow
+ * parallel updates and deletes, we have to solve other 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
@@ -335,14 +334,13 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
*/
if ((cursorOptions & CURSOR_OPT_PARALLEL_OK) != 0 &&
IsUnderPostmaster &&
- (parse->commandType == CMD_SELECT ||
- is_parallel_allowed_for_modify(parse)) &&
+ parse->commandType == CMD_SELECT &&
!parse->hasModifyingCTE &&
max_parallel_workers_per_gather > 0 &&
!IsParallelWorker())
{
/* all the cheap tests pass, so scan the query tree */
- glob->maxParallelHazard = max_parallel_hazard(parse, glob);
+ glob->maxParallelHazard = max_parallel_hazard(parse);
glob->parallelModeOK = (glob->maxParallelHazard != PROPARALLEL_UNSAFE);
}
else
@@ -523,19 +521,6 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
result->rewindPlanIDs = glob->rewindPlanIDs;
result->rowMarks = glob->finalrowmarks;
result->relationOids = glob->relationOids;
-
- /*
- * Register the Oids of parallel-safety-checked partitions as plan
- * dependencies. This is only really needed in the case of a parallel plan
- * so that if parallel-unsafe properties are subsequently defined on the
- * partitions, the cached parallel plan will be invalidated, and a
- * non-parallel plan will be generated.
- *
- * We also use this list to acquire locks on partitions before executing
- * cached plan. See AcquireExecutorLocks().
- */
- if (glob->partitionOids != NIL && glob->parallelModeNeeded)
- result->partitionOids = glob->partitionOids;
result->invalItems = glob->invalItems;
result->paramExecTypes = glob->paramExecTypes;
/* utilityStmt should be null, but we might as well copy it */
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index c6be4f87c2d..f3786dd2b63 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -19,18 +19,13 @@
#include "postgres.h"
-#include "access/genam.h"
#include "access/htup_details.h"
-#include "access/table.h"
-#include "access/xact.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_class.h"
-#include "catalog/pg_constraint.h"
#include "catalog/pg_language.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
-#include "commands/trigger.h"
#include "executor/executor.h"
#include "executor/functions.h"
#include "funcapi.h"
@@ -48,8 +43,6 @@
#include "parser/parse_agg.h"
#include "parser/parse_coerce.h"
#include "parser/parse_func.h"
-#include "parser/parsetree.h"
-#include "partitioning/partdesc.h"
#include "rewrite/rewriteManip.h"
#include "tcop/tcopprot.h"
#include "utils/acl.h"
@@ -58,8 +51,6 @@
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
-#include "utils/partcache.h"
-#include "utils/rel.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
@@ -97,9 +88,6 @@ typedef struct
char max_hazard; /* worst proparallel hazard found so far */
char max_interesting; /* worst proparallel hazard of interest */
List *safe_param_ids; /* PARAM_EXEC Param IDs to treat as safe */
- RangeTblEntry *target_rte; /* query's target relation if any */
- CmdType command_type; /* query's command type */
- PlannerGlobal *planner_global; /* global info for planner invocation */
} max_parallel_hazard_context;
static bool contain_agg_clause_walker(Node *node, void *context);
@@ -110,20 +98,6 @@ static bool contain_volatile_functions_walker(Node *node, void *context);
static bool contain_volatile_functions_not_nextval_walker(Node *node, void *context);
static bool max_parallel_hazard_walker(Node *node,
max_parallel_hazard_context *context);
-static bool target_rel_max_parallel_hazard(max_parallel_hazard_context *context);
-static bool target_rel_max_parallel_hazard_recurse(Relation relation,
- CmdType command_type,
- max_parallel_hazard_context *context);
-static bool target_rel_trigger_max_parallel_hazard(Relation rel,
- max_parallel_hazard_context *context);
-static bool target_rel_index_max_parallel_hazard(Relation rel,
- max_parallel_hazard_context *context);
-static bool target_rel_domain_max_parallel_hazard(Oid typid,
- max_parallel_hazard_context *context);
-static bool target_rel_partitions_max_parallel_hazard(Relation rel,
- max_parallel_hazard_context *context);
-static bool target_rel_chk_constr_max_parallel_hazard(Relation rel,
- max_parallel_hazard_context *context);
static bool contain_nonstrict_functions_walker(Node *node, void *context);
static bool contain_exec_param_walker(Node *node, List *param_ids);
static bool contain_context_dependent_node(Node *clause);
@@ -571,19 +545,14 @@ contain_volatile_functions_not_nextval_walker(Node *node, void *context)
* later, in the common case where everything is SAFE.
*/
char
-max_parallel_hazard(Query *parse, PlannerGlobal *glob)
+max_parallel_hazard(Query *parse)
{
max_parallel_hazard_context context;
context.max_hazard = PROPARALLEL_SAFE;
context.max_interesting = PROPARALLEL_UNSAFE;
context.safe_param_ids = NIL;
- context.target_rte = parse->resultRelation > 0 ?
- rt_fetch(parse->resultRelation, parse->rtable) : NULL;
- context.command_type = parse->commandType;
- context.planner_global = glob;
(void) max_parallel_hazard_walker((Node *) parse, &context);
-
return context.max_hazard;
}
@@ -614,10 +583,6 @@ is_parallel_safe(PlannerInfo *root, Node *node)
context.max_hazard = PROPARALLEL_SAFE;
context.max_interesting = PROPARALLEL_RESTRICTED;
context.safe_param_ids = NIL;
- /* We don't need to evaluate target relation's parallel-safety here. */
- context.target_rte = NULL;
- context.command_type = CMD_UNKNOWN;
- context.planner_global = NULL;
/*
* The params that refer to the same or parent query level are considered
@@ -690,20 +655,14 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
* opclass support functions are generally parallel-safe. XmlExpr is a
* bit more dubious but we can probably get away with it. We err on the
* side of caution by treating CoerceToDomain as parallel-restricted.
- * However, for table modification statements, we check the parallel
- * safety of domain constraints as that could contain a parallel-unsafe
- * function, and executing that in parallel mode will lead to error.
- * SQLValueFunction should be safe in all cases. NextValueExpr is
- * parallel-unsafe.
+ * (Note: in principle that's wrong because a domain constraint could
+ * contain a parallel-unsafe function; but useful constraints probably
+ * never would have such, and assuming they do would cripple use of
+ * parallel query in the presence of domain types.) SQLValueFunction
+ * should be safe in all cases. NextValueExpr is parallel-unsafe.
*/
if (IsA(node, CoerceToDomain))
{
- if (context->target_rte != NULL)
- {
- if (target_rel_domain_max_parallel_hazard(((CoerceToDomain *) node)->resulttype, context))
- return true;
- }
-
if (max_parallel_hazard_test(PROPARALLEL_RESTRICTED, context))
return true;
}
@@ -729,27 +688,6 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
}
/*
- * ModifyingCTE expressions are treated as parallel-unsafe.
- *
- * XXX Normally, if the Query has a modifying CTE, the hasModifyingCTE
- * flag is set in the Query tree, and the query will be regarded as
- * parallel-usafe. However, in some cases, a re-written query with a
- * modifying CTE does not have that flag set, due to a bug in the query
- * rewriter.
- */
- else if (IsA(node, CommonTableExpr))
- {
- CommonTableExpr *cte = (CommonTableExpr *) node;
- Query *ctequery = castNode(Query, cte->ctequery);
-
- if (ctequery->commandType != CMD_SELECT)
- {
- context->max_hazard = PROPARALLEL_UNSAFE;
- return true;
- }
- }
-
- /*
* As a notational convenience for callers, look through RestrictInfo.
*/
else if (IsA(node, RestrictInfo))
@@ -819,19 +757,6 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
}
return false; /* nothing to recurse to */
}
- else if (IsA(node, RangeTblEntry))
- {
- RangeTblEntry *rte = (RangeTblEntry *) node;
-
- /* Nothing interesting to check for SELECTs */
- if (context->target_rte == NULL)
- return false;
-
- if (rte == context->target_rte)
- return target_rel_max_parallel_hazard(context);
-
- return false;
- }
/*
* When we're first invoked on a completely unplanned tree, we must
@@ -852,9 +777,7 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
/* Recurse into subselects */
return query_tree_walker(query,
max_parallel_hazard_walker,
- context,
- context->target_rte != NULL ?
- QTW_EXAMINE_RTES_BEFORE : 0);
+ context, 0);
}
/* Recurse to check arguments */
@@ -863,486 +786,6 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
context);
}
-/*
- * target_rel_max_parallel_hazard
- *
- * Determines the maximum parallel-mode hazard level for modification
- * of a specified relation.
- */
-static bool
-target_rel_max_parallel_hazard(max_parallel_hazard_context *context)
-{
- bool max_hazard_found;
-
- Relation targetRel;
-
- /*
- * The target table is already locked by the caller (this is done in the
- * parse/analyze phase), and remains locked until end-of-transaction.
- */
- targetRel = table_open(context->target_rte->relid, NoLock);
- max_hazard_found = target_rel_max_parallel_hazard_recurse(targetRel,
- context->command_type,
- context);
- table_close(targetRel, NoLock);
-
- return max_hazard_found;
-}
-
-static bool
-target_rel_max_parallel_hazard_recurse(Relation rel,
- CmdType command_type,
- max_parallel_hazard_context *context)
-{
- /* Currently only CMD_INSERT is supported */
- Assert(command_type == CMD_INSERT);
-
- /*
- * We can't support table modification in a parallel worker if it's a
- * foreign table/partition (no FDW API for supporting parallel access) or
- * a temporary table.
- */
- if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
- RelationUsesLocalBuffers(rel))
- {
- if (max_parallel_hazard_test(PROPARALLEL_RESTRICTED, context))
- return true;
- }
-
- /*
- * If a partitioned table, check that each partition is safe for
- * modification in parallel-mode.
- */
- if (target_rel_partitions_max_parallel_hazard(rel, context))
- return true;
-
- /*
- * If there are any index expressions or index predicate, check that they
- * are parallel-mode safe.
- */
- if (target_rel_index_max_parallel_hazard(rel, context))
- return true;
-
- /*
- * If any triggers exist, check that they are parallel-safe.
- */
- if (target_rel_trigger_max_parallel_hazard(rel, context))
- return true;
-
- /*
- * Column default expressions are only applicable to INSERT and UPDATE.
- * For columns in the target-list, these are already being checked for
- * parallel-safety in the max_parallel_hazard() scan of the query tree in
- * standard_planner(), so there's no need to do it here. Note that even
- * though column defaults may be specified separately for each partition
- * in a partitioned table, a partition's default value is not applied when
- * inserting a tuple through a partitioned table.
- */
-
- /*
- * CHECK constraints are only applicable to INSERT and UPDATE. If any
- * CHECK constraints exist, determine if they are parallel-safe.
- */
- if (target_rel_chk_constr_max_parallel_hazard(rel, context))
- return true;
-
- return false;
-}
-
-/*
- * target_rel_trigger_max_parallel_hazard
- *
- * Finds the maximum parallel-mode hazard level for the specified relation's
- * trigger data.
- */
-static bool
-target_rel_trigger_max_parallel_hazard(Relation rel,
- max_parallel_hazard_context *context)
-{
- int i;
-
- if (rel->trigdesc == NULL)
- return false;
-
- /*
- * Care is needed here to avoid using the same relcache TriggerDesc field
- * across other cache accesses, because relcache doesn't guarantee that it
- * won't move.
- */
- for (i = 0; i < rel->trigdesc->numtriggers; i++)
- {
- Oid tgfoid = rel->trigdesc->triggers[i].tgfoid;
-
- if (max_parallel_hazard_test(func_parallel(tgfoid), context))
- return true;
- }
-
- return false;
-}
-
-/*
- * target_rel_index_max_parallel_hazard
- *
- * Finds the maximum parallel-mode hazard level for any existing index
- * expressions or index predicate of a specified relation.
- */
-static bool
-target_rel_index_max_parallel_hazard(Relation rel,
- max_parallel_hazard_context *context)
-{
- List *index_oid_list;
- ListCell *lc;
- bool found_max_hazard = false;
- LOCKMODE lockmode = AccessShareLock;
-
- index_oid_list = RelationGetIndexList(rel);
- foreach(lc, index_oid_list)
- {
- Relation index_rel;
- Form_pg_index indexStruct;
- List *ii_Expressions;
- List *ii_Predicate;
- Oid index_oid = lfirst_oid(lc);
-
- index_rel = index_open(index_oid, lockmode);
-
- indexStruct = index_rel->rd_index;
- ii_Expressions = RelationGetIndexExpressions(index_rel);
-
- if (ii_Expressions != NIL)
- {
- int i;
- ListCell *index_expr_item = list_head(ii_Expressions);
-
- for (i = 0; i < indexStruct->indnatts; i++)
- {
- int keycol = indexStruct->indkey.values[i];
-
- if (keycol == 0)
- {
- /* Found an index expression */
-
- Node *index_expr;
-
- Assert(index_expr_item != NULL);
- if (index_expr_item == NULL) /* shouldn't happen */
- {
- elog(WARNING, "too few entries in indexprs list");
- context->max_hazard = PROPARALLEL_UNSAFE;
- found_max_hazard = true;
- break;
- }
-
- index_expr = (Node *) lfirst(index_expr_item);
-
- if (max_parallel_hazard_walker(index_expr, context))
- {
- found_max_hazard = true;
- break;
- }
-
- index_expr_item = lnext(ii_Expressions, index_expr_item);
- }
- }
- }
-
- if (!found_max_hazard)
- {
- ii_Predicate = RelationGetIndexPredicate(index_rel);
- if (ii_Predicate != NIL)
- {
- if (max_parallel_hazard_walker((Node *) ii_Predicate, context))
- found_max_hazard = true;
- }
- }
-
- /*
- * XXX We don't need to retain lock on index as index expressions
- * can't be changed later.
- */
- index_close(index_rel, lockmode);
- }
- list_free(index_oid_list);
-
- return found_max_hazard;
-}
-
-/*
- * target_rel_domain_max_parallel_hazard
- *
- * Finds the maximum parallel-mode hazard level for the specified DOMAIN type.
- * Only any CHECK expressions are examined for parallel-safety.
- */
-static bool
-target_rel_domain_max_parallel_hazard(Oid typid, max_parallel_hazard_context *context)
-{
- Relation con_rel;
- ScanKeyData key[1];
- SysScanDesc scan;
- HeapTuple tup;
- bool found_max_hazard = false;
-
- LOCKMODE lockmode = AccessShareLock;
-
- con_rel = table_open(ConstraintRelationId, lockmode);
-
- ScanKeyInit(&key[0],
- Anum_pg_constraint_contypid, BTEqualStrategyNumber,
- F_OIDEQ, ObjectIdGetDatum(typid));
- scan = systable_beginscan(con_rel, ConstraintTypidIndexId, true,
- NULL, 1, key);
-
- while (HeapTupleIsValid((tup = systable_getnext(scan))))
- {
- Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
-
- if (con->contype == CONSTRAINT_CHECK)
- {
- char *conbin;
- Datum val;
- bool isnull;
- Expr *check_expr;
-
- val = SysCacheGetAttr(CONSTROID, tup,
- Anum_pg_constraint_conbin, &isnull);
- Assert(!isnull);
- if (isnull)
- {
- /*
- * This shouldn't ever happen, but if it does, log a WARNING
- * and return UNSAFE, rather than erroring out.
- */
- elog(WARNING, "null conbin for constraint %u", con->oid);
- context->max_hazard = PROPARALLEL_UNSAFE;
- found_max_hazard = true;
- break;
- }
- conbin = TextDatumGetCString(val);
- check_expr = stringToNode(conbin);
- pfree(conbin);
- if (max_parallel_hazard_walker((Node *) check_expr, context))
- {
- found_max_hazard = true;
- break;
- }
- }
- }
-
- systable_endscan(scan);
- table_close(con_rel, lockmode);
- return found_max_hazard;
-}
-
-/*
- * target_rel_partitions_max_parallel_hazard
- *
- * Finds the maximum parallel-mode hazard level for any partitions of a
- * of a specified relation.
- */
-static bool
-target_rel_partitions_max_parallel_hazard(Relation rel,
- max_parallel_hazard_context *context)
-{
- int i;
- PartitionDesc pdesc;
- PartitionKey pkey;
- ListCell *partexprs_item;
- int partnatts;
- List *partexprs;
- PlannerGlobal *glob;
-
-
- if (rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
- return false;
-
- pkey = RelationGetPartitionKey(rel);
-
- partnatts = get_partition_natts(pkey);
- partexprs = get_partition_exprs(pkey);
-
- partexprs_item = list_head(partexprs);
- for (i = 0; i < partnatts; i++)
- {
- /* Check parallel-safety of partition key support functions */
- if (OidIsValid(pkey->partsupfunc[i].fn_oid))
- {
- if (max_parallel_hazard_test(func_parallel(pkey->partsupfunc[i].fn_oid), context))
- return true;
- }
-
- /* Check parallel-safety of any expressions in the partition key */
- if (get_partition_col_attnum(pkey, i) == 0)
- {
- Node *check_expr = (Node *) lfirst(partexprs_item);
-
- if (max_parallel_hazard_walker(check_expr, context))
- return true;
-
- partexprs_item = lnext(partexprs, partexprs_item);
- }
- }
-
- /* Recursively check each partition ... */
-
- /* Create the PartitionDirectory infrastructure if we didn't already */
- glob = context->planner_global;
- if (glob->partition_directory == NULL)
- glob->partition_directory =
- CreatePartitionDirectory(CurrentMemoryContext);
-
- pdesc = PartitionDirectoryLookup(glob->partition_directory, rel);
-
- for (i = 0; i < pdesc->nparts; i++)
- {
- bool max_hazard_found;
- Relation part_rel;
-
- /*
- * The partition needs to be locked, and remain locked until
- * end-of-transaction to ensure its parallel-safety state is not
- * hereafter altered.
- */
- part_rel = table_open(pdesc->oids[i], context->target_rte->rellockmode);
- max_hazard_found = target_rel_max_parallel_hazard_recurse(part_rel,
- context->command_type,
- context);
- table_close(part_rel, NoLock);
-
- /*
- * Remember partitionOids to record the partition as a potential plan
- * dependency.
- */
- glob->partitionOids = lappend_oid(glob->partitionOids, pdesc->oids[i]);
-
- if (max_hazard_found)
- return true;
- }
-
- return false;
-}
-
-/*
- * target_rel_chk_constr_max_parallel_hazard
- *
- * Finds the maximum parallel-mode hazard level for any CHECK expressions or
- * CHECK constraints related to the specified relation.
- */
-static bool
-target_rel_chk_constr_max_parallel_hazard(Relation rel,
- max_parallel_hazard_context *context)
-{
- TupleDesc tupdesc;
-
- tupdesc = RelationGetDescr(rel);
-
- /*
- * Determine if there are any CHECK constraints which are not
- * parallel-safe.
- */
- if (tupdesc->constr != NULL && tupdesc->constr->num_check > 0)
- {
- int i;
-
- ConstrCheck *check = tupdesc->constr->check;
-
- for (i = 0; i < tupdesc->constr->num_check; i++)
- {
- Expr *check_expr = stringToNode(check->ccbin);
-
- if (max_parallel_hazard_walker((Node *) check_expr, context))
- return true;
- }
- }
-
- return false;
-}
-
-/*
- * is_parallel_allowed_for_modify
- *
- * Check at a high-level if parallel mode is able to be used for the specified
- * table-modification statement. Currently, we support only Inserts.
- *
- * It's not possible in the following cases:
- *
- * 1) enable_parallel_insert is off
- * 2) INSERT...ON CONFLICT...DO UPDATE
- * 3) INSERT without SELECT
- * 4) the reloption parallel_insert_enabled is set to off
- *
- * (Note: we don't do in-depth parallel-safety checks here, we do only the
- * cheaper tests that can quickly exclude obvious cases for which
- * parallelism isn't supported, to avoid having to do further parallel-safety
- * checks for these)
- */
-bool
-is_parallel_allowed_for_modify(Query *parse)
-{
- bool hasSubQuery;
- bool parallel_enabled;
- RangeTblEntry *rte;
- ListCell *lc;
- Relation rel;
-
- if (!IsModifySupportedInParallelMode(parse->commandType))
- return false;
-
- if (!enable_parallel_insert)
- return false;
-
- /*
- * UPDATE is not currently supported in parallel-mode, so prohibit
- * INSERT...ON CONFLICT...DO UPDATE...
- *
- * In order to support update, even if only in the leader, some further
- * work would need to be done. A mechanism would be needed for sharing
- * combo-cids between leader and workers during parallel-mode, since for
- * example, the leader might generate a combo-cid and it needs to be
- * propagated to the workers.
- */
- if (parse->commandType == CMD_INSERT &&
- parse->onConflict != NULL &&
- parse->onConflict->action == ONCONFLICT_UPDATE)
- return false;
-
- /*
- * If there is no underlying SELECT, a parallel insert operation is not
- * desirable.
- */
- hasSubQuery = false;
- foreach(lc, parse->rtable)
- {
- rte = lfirst_node(RangeTblEntry, lc);
- if (rte->rtekind == RTE_SUBQUERY)
- {
- hasSubQuery = true;
- break;
- }
- }
-
- if (!hasSubQuery)
- return false;
-
- /*
- * Check if parallel_insert_enabled is enabled for the target table, if
- * not, skip the safety checks.
- *
- * (Note: if the target table is partitioned, the parallel_insert_enabled
- * option setting of the partitions are ignored).
- */
- rte = rt_fetch(parse->resultRelation, parse->rtable);
-
- /*
- * The target table is already locked by the caller (this is done in the
- * parse/analyze phase), and remains locked until end-of-transaction.
- */
- rel = table_open(rte->relid, NoLock);
-
- parallel_enabled = RelationGetParallelInsert(rel, true);
- table_close(rel, NoLock);
-
- return parallel_enabled;
-}
/*****************************************************************************
* Check clauses for nonstrict functions
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index c1f4128445b..1a0950489d7 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -1735,23 +1735,6 @@ QueryListGetPrimaryStmt(List *stmts)
return NULL;
}
-static void
-AcquireExecutorLocksOnPartitions(List *partitionOids, int lockmode,
- bool acquire)
-{
- ListCell *lc;
-
- foreach(lc, partitionOids)
- {
- Oid partOid = lfirst_oid(lc);
-
- if (acquire)
- LockRelationOid(partOid, lockmode);
- else
- UnlockRelationOid(partOid, lockmode);
- }
-}
-
/*
* AcquireExecutorLocks: acquire locks needed for execution of a cached plan;
* or release them if acquire is false.
@@ -1765,8 +1748,6 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
{
PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
ListCell *lc2;
- Index rti,
- resultRelation = 0;
if (plannedstmt->commandType == CMD_UTILITY)
{
@@ -1784,9 +1765,6 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
continue;
}
- rti = 1;
- if (plannedstmt->resultRelations)
- resultRelation = linitial_int(plannedstmt->resultRelations);
foreach(lc2, plannedstmt->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
@@ -1804,14 +1782,6 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
LockRelationOid(rte->relid, rte->rellockmode);
else
UnlockRelationOid(rte->relid, rte->rellockmode);
-
- /* Lock partitions ahead of modifying them in parallel mode. */
- if (rti == resultRelation &&
- plannedstmt->partitionOids != NIL)
- AcquireExecutorLocksOnPartitions(plannedstmt->partitionOids,
- rte->rellockmode, acquire);
-
- rti++;
}
}
}
@@ -2020,8 +1990,7 @@ PlanCacheRelCallback(Datum arg, Oid relid)
if (plannedstmt->commandType == CMD_UTILITY)
continue; /* Ignore utility statements */
if ((relid == InvalidOid) ? plannedstmt->relationOids != NIL :
- (list_member_oid(plannedstmt->relationOids, relid) ||
- list_member_oid(plannedstmt->partitionOids, relid)))
+ list_member_oid(plannedstmt->relationOids, relid))
{
/* Invalidate the generic plan only */
plansource->gplan->is_valid = false;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 3b36a31a475..8bfaa535411 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -1132,16 +1132,6 @@ static struct config_bool ConfigureNamesBool[] =
NULL, NULL, NULL
},
{
- {"enable_parallel_insert", PGC_USERSET, QUERY_TUNING_METHOD,
- gettext_noop("Enables the planner's use of parallel plans for INSERT commands."),
- NULL,
- GUC_EXPLAIN
- },
- &enable_parallel_insert,
- true,
- NULL, NULL, NULL
- },
- {
/* Not for general use --- used by SET SESSION AUTHORIZATION */
{"is_superuser", PGC_INTERNAL, UNGROUPED,
gettext_noop("Shows whether the current user is a superuser."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 86425965d0d..74b416b74a8 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -371,7 +371,6 @@
#enable_partitionwise_aggregate = off
#enable_parallel_hash = on
#enable_partition_pruning = on
-#enable_parallel_insert = on
# - Planner Cost Constants -