diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 3dd1bab2a2..d20c75367c 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -2050,7 +2050,7 @@ postgresBeginForeignInsert(ModifyTableState *mtstate, * Vars contained in those expressions. */ if (plan && plan->operation == CMD_UPDATE && - resultRelation == plan->nominalRelation) + resultRelation == plan->targetRelation) resultRelation = mtstate->resultRelInfo[0].ri_RangeTableIndex; } diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 2be2d340ca..57efb20d20 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -837,7 +837,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt, List *attnums; ListCell *cur; RangeTblEntry *rte; - int lockmode = is_from ? RowExclusiveLock : AccessShareLock; + LOCKMODE lockmode = is_from ? RowExclusiveLock : AccessShareLock; Assert(!stmt->query); diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index ed6afe79a9..5ca7f69830 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -929,7 +929,7 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used) break; case T_ModifyTable: *rels_used = bms_add_member(*rels_used, - ((ModifyTable *) plan)->nominalRelation); + ((ModifyTable *) plan)->targetRelation); if (((ModifyTable *) plan)->exclRelRTI) *rels_used = bms_add_member(*rels_used, ((ModifyTable *) plan)->exclRelRTI); @@ -2924,7 +2924,7 @@ ExplainScanTarget(Scan *plan, ExplainState *es) static void ExplainModifyTarget(ModifyTable *plan, ExplainState *es) { - ExplainTargetRel((Plan *) plan, plan->nominalRelation, es); + ExplainTargetRel((Plan *) plan, plan->targetRelation, es); } /* @@ -3088,7 +3088,7 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors, /* Should we explicitly label target relations? */ labeltargets = (mtstate->mt_nplans > 1 || (mtstate->mt_nplans == 1 && - mtstate->resultRelInfo->ri_RangeTableIndex != node->nominalRelation)); + mtstate->resultRelInfo->ri_RangeTableIndex != node->targetRelation)); if (labeltargets) ExplainOpenGroup("Target Tables", "Target Tables", false, es); diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c index 09a6a7f9d3..2949b4e6d7 100644 --- a/src/backend/commands/policy.c +++ b/src/backend/commands/policy.c @@ -568,7 +568,7 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id) /* Add this rel to the parsestate's rangetable, for dependencies */ addRangeTableEntryForRelation(qual_pstate, rel, NULL, false, false, - NoLock); + AccessExclusiveLock); qual_parse_rtable = qual_pstate->p_rtable; free_parsestate(qual_pstate); @@ -591,7 +591,7 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id) /* Add this rel to the parsestate's rangetable, for dependencies */ addRangeTableEntryForRelation(with_check_pstate, rel, NULL, false, - false, NoLock); + false, AccessExclusiveLock); with_check_parse_rtable = with_check_pstate->p_rtable; free_parsestate(with_check_pstate); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index f5b9d768e8..5afa54389a 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -13632,7 +13632,8 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy) * rangetable entry. We need a ParseState for transformExpr. */ pstate = make_parsestate(NULL); - rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true, NoLock); + rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true, + NoLock); addRTEtoQuery(pstate, rte, true, true, true); /* take care of any partition expressions */ diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index f673029ed1..f0d45844c1 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -579,11 +579,13 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, */ rte = addRangeTableEntryForRelation(pstate, rel, makeAlias("old", NIL), - false, false, NoLock); + false, false, + ShareRowExclusiveLock); addRTEtoQuery(pstate, rte, false, true, true); rte = addRangeTableEntryForRelation(pstate, rel, makeAlias("new", NIL), - false, false, NoLock); + false, false, + ShareRowExclusiveLock); addRTEtoQuery(pstate, rte, false, true, true); /* Transform expression. Copy to be sure we don't modify original */ diff --git a/src/backend/executor/README b/src/backend/executor/README index 0d7cd552eb..30df410e0e 100644 --- a/src/backend/executor/README +++ b/src/backend/executor/README @@ -267,8 +267,8 @@ This is a sketch of control flow for full query processing: Per above comments, it's not really critical for ExecEndNode to free any memory; it'll all go away in FreeExecutorState anyway. However, we do need to -be careful to close relations, drop buffer pins, etc, so we do need to scan -the plan state tree to find these sorts of resources. +be careful to drop buffer pins, etc, so we do need to scan the plan state tree +to find these sorts of resources. The executor can also be used to evaluate simple expressions without any Plan diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 1be4dabb53..2ca25d857d 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -837,25 +837,22 @@ InitPlan(QueryDesc *queryDesc, int eflags) */ ExecCheckRTPerms(rangeTable, true); - /* - * initialize the node's execution state - */ ExecInitRangeTable(estate, rangeTable); /* - * Just initialize 0-filled array of Relation pointers. Actual values are - * filled later as the plan is initialized. + * Allocate an array to store open Relations of each rangeTable item. We + * 0 fill this for now. The Relations are only opened and stored here the + * first time they're required during node initialization. */ estate->es_relations = (Relation *) palloc0(estate->es_range_table_size * sizeof(Relation)); - estate->es_plannedstmt = plannedstmt; - /* - * initialize result relation stuff, and open/lock the result rels. - * - * We must do this before initializing the plan tree, else we might try to - * do a lock upgrade if a result rel is also a source rel. + * initialize the node's execution state */ + estate->es_range_table = rangeTable; + estate->es_plannedstmt = plannedstmt; + + /* Allocate memory required for result relations */ if (plannedstmt->resultRelations) { int numResultRelations = list_length(plannedstmt->resultRelations); @@ -1496,8 +1493,10 @@ ExecEndPlan(PlanState *planstate, EState *estate) /* Close range table relations. */ for (i = 0; i < estate->es_range_table_size; i++) + { if (estate->es_relations[i]) heap_close(estate->es_relations[i], NoLock); + } /* * shut down the node-type-specific query processing @@ -2270,7 +2269,11 @@ ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo) } /* - * ExecBuildRowMark -- create ExecRowMark struct for given PlanRowMark + * ExecBuildRowMark -- create and return an ExecRowMark struct for the given + * PlanRowMark. + * + * The created ExecRowMark is also added to the list of rowmarks in the given + * EState. */ ExecRowMark * ExecBuildRowMark(EState *estate, PlanRowMark *rc) diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index 7e224b23fe..7fb34d2173 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -379,7 +379,7 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, leaf_part_rri = makeNode(ResultRelInfo); InitResultRelInfo(leaf_part_rri, partrel, - node ? node->nominalRelation : 1, + node ? node->targetRelation : 1, rootrel, estate->es_instrument); @@ -1417,9 +1417,6 @@ adjust_partition_tlist(List *tlist, TupleConversionMap *map) * functions. Details stored include how to map the partition index * returned by the partition pruning code into subplan indexes. * - * ExecDestroyPartitionPruneState: - * Deletes a PartitionPruneState. Must be called during executor shutdown. - * * ExecFindInitialMatchingSubPlans: * Returns indexes of matching subplans. Partition pruning is attempted * without any evaluation of expressions containing PARAM_EXEC Params. diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index abee92ee59..ab46fd425d 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -25,7 +25,6 @@ * etc * * ExecOpenScanRelation Common code for scan node init routines. - * ExecCloseScanRelation * * executor_errposition Report syntactic position of an error. * @@ -35,6 +34,8 @@ * GetAttributeByName Runtime extraction of columns from tuples. * GetAttributeByNum * + * ExecInitRangeTable Build an array from the range table list to + * allow faster lookups by relid. * NOTES * This file has traditionally been the place to stick misc. * executor support stuff that doesn't really go anyplace else. @@ -997,10 +998,10 @@ ExecInitRangeTable(EState *estate, List *rangeTable) * meaning the upstream code already acquired the needed locks. */ Assert(rte->lockmode != NoLock); - if (LockRelationOid(rte->relid, rte->lockmode) && - !IsParallelWorker()) - elog(NOTICE, "InitPlan: lock on \"%s\" not already taken", - get_rel_name(rte->relid)); + if (!IsParallelWorker() && + !CheckRelationLockedByUs(rte->relid, rte->lockmode)) + elog(WARNING, "InitPlan: lock on \"%s\" not already taken", + get_rel_name(rte->relid)); } } #endif diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c index 9e7c5e94cf..ff9606342b 100644 --- a/src/backend/executor/nodeLockRows.c +++ b/src/backend/executor/nodeLockRows.c @@ -424,7 +424,7 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags) /* safety check on size of lr_curtuples array */ Assert(rc->rti > 0 && rc->rti <= lrstate->lr_ntables); - /* find ExecRowMark and build ExecAuxRowMark */ + /* build the ExecRowMark and ExecAuxRowMark */ erm = ExecBuildRowMark(estate, rc); aerm = ExecBuildAuxRowMark(erm, outerPlan->targetlist); diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 082666c76c..c837d36a87 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -2260,11 +2260,10 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) node->rootResultRelIndex; Assert(node->partitionedTarget); - /* nominalRelation is the index of the target partitioned table. */ - rel = ExecRangeTableRelation(estate, node->nominalRelation); + rel = ExecRangeTableRelation(estate, node->targetRelation); InitResultRelInfo(mtstate->rootResultRelInfo, rel, - node->nominalRelation, + node->targetRelation, NULL, estate->es_instrument); } @@ -2554,7 +2553,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) if (rc->isParent) continue; - /* find ExecRowMark (same for all subplans) */ + /* build the ExecRowMark (same for all subplans) */ erm = ExecBuildRowMark(estate, rc); /* build ExecAuxRowMark for each subplan */ @@ -2711,9 +2710,7 @@ ExecEndModifyTable(ModifyTableState *node) { int i; - /* - * close the result relation(s) if any, but hold locks until xact commit. - */ + /* Perform cleanup. */ for (i = 0; i < node->mt_nplans; i++) { ResultRelInfo *resultRelInfo = node->resultRelInfo + i; @@ -2725,9 +2722,11 @@ ExecEndModifyTable(ModifyTableState *node) resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state, resultRelInfo); - /* Close indices and then the relation itself */ + /* + * Close the ResultRelInfo's indexes. The relation itself + * is handled by the executor cleanup code. + */ ExecCloseIndices(resultRelInfo); - resultRelInfo++; } /* Close all the partitioned tables, leaf partitions, and their indices */ diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index cde0cd7c16..dd76284676 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -202,7 +202,7 @@ _copyModifyTable(const ModifyTable *from) */ COPY_SCALAR_FIELD(operation); COPY_SCALAR_FIELD(canSetTag); - COPY_SCALAR_FIELD(nominalRelation); + COPY_SCALAR_FIELD(targetRelation); COPY_SCALAR_FIELD(partitionedTarget); COPY_SCALAR_FIELD(partColsUpdated); COPY_NODE_FIELD(resultRelations); diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 683a7ba94e..6aefdd8bc4 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -374,7 +374,7 @@ _outModifyTable(StringInfo str, const ModifyTable *node) WRITE_ENUM_FIELD(operation, CmdType); WRITE_BOOL_FIELD(canSetTag); - WRITE_UINT_FIELD(nominalRelation); + WRITE_UINT_FIELD(targetRelation); WRITE_BOOL_FIELD(partitionedTarget); WRITE_BOOL_FIELD(partColsUpdated); WRITE_NODE_FIELD(resultRelations); @@ -2175,7 +2175,7 @@ _outModifyTablePath(StringInfo str, const ModifyTablePath *node) WRITE_ENUM_FIELD(operation, CmdType); WRITE_BOOL_FIELD(canSetTag); - WRITE_UINT_FIELD(nominalRelation); + WRITE_UINT_FIELD(targetRelation); WRITE_BOOL_FIELD(partitionedTarget); WRITE_BOOL_FIELD(partColsUpdated); WRITE_NODE_FIELD(resultRelations); diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 342b271ea5..30609c96e6 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -1596,7 +1596,7 @@ _readModifyTable(void) READ_ENUM_FIELD(operation, CmdType); READ_BOOL_FIELD(canSetTag); - READ_UINT_FIELD(nominalRelation); + READ_UINT_FIELD(targetRelation); READ_BOOL_FIELD(partitionedTarget); READ_BOOL_FIELD(partColsUpdated); READ_NODE_FIELD(resultRelations); diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index becc5ef75d..8f20e54d9e 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -278,7 +278,7 @@ static Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan); static ProjectSet *make_project_set(List *tlist, Plan *subplan); static ModifyTable *make_modifytable(PlannerInfo *root, CmdType operation, bool canSetTag, - Index nominalRelation, bool partitionedTarget, + Index targetRelation, bool partitionedTarget, bool partColsUpdated, List *resultRelations, List *subplans, List *subroots, List *withCheckOptionLists, List *returningLists, @@ -2405,7 +2405,7 @@ create_modifytable_plan(PlannerInfo *root, ModifyTablePath *best_path) plan = make_modifytable(root, best_path->operation, best_path->canSetTag, - best_path->nominalRelation, + best_path->targetRelation, best_path->partitionedTarget, best_path->partColsUpdated, best_path->resultRelations, @@ -6481,7 +6481,7 @@ make_project_set(List *tlist, static ModifyTable * make_modifytable(PlannerInfo *root, CmdType operation, bool canSetTag, - Index nominalRelation, bool partitionedTarget, + Index targetRelation, bool partitionedTarget, bool partColsUpdated, List *resultRelations, List *subplans, List *subroots, List *withCheckOptionLists, List *returningLists, @@ -6509,7 +6509,7 @@ make_modifytable(PlannerInfo *root, node->operation = operation; node->canSetTag = canSetTag; - node->nominalRelation = nominalRelation; + node->targetRelation = targetRelation; node->partitionedTarget = partitionedTarget; node->partColsUpdated = partColsUpdated; node->resultRelations = resultRelations; diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index cd46849f26..074ec9bf55 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -248,7 +248,7 @@ static bool group_by_has_partkey(RelOptInfo *input_rel, List *targetList, List *groupClause); static int common_prefix_cmp(const void *a, const void *b); -static List *get_unpruned_rowmarks(PlannerInfo *root); +static List *get_nondummy_rowmarks(PlannerInfo *root); /***************************************************************************** * @@ -1167,7 +1167,7 @@ inheritance_planner(PlannerInfo *root) int top_parentRTindex = parse->resultRelation; Bitmapset *subqueryRTindexes; Bitmapset *modifiableARIindexes; - int nominalRelation = -1; + int targetRelation = -1; List *final_rtable = NIL; int save_rel_array_size = 0; RelOptInfo **save_rel_array = NULL; @@ -1245,19 +1245,13 @@ inheritance_planner(PlannerInfo *root) } /* - * If the parent RTE is a partitioned table, we should use that as the - * nominal relation, because the RTEs added for partitioned tables - * (including the root parent) as child members of the inheritance set do - * not appear anywhere else in the plan. The situation is exactly the - * opposite in the case of non-partitioned inheritance parent as described - * below. For the same reason, collect the list of descendant partitioned - * tables to be saved in ModifyTable node, so that executor can lock those - * as well. + * If the parent RTE is a partitioned table, set that as the target + * relation and mark that we're working with a partitioned target. */ parent_rte = rt_fetch(top_parentRTindex, root->parse->rtable); if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE) { - nominalRelation = top_parentRTindex; + targetRelation = top_parentRTindex; partitionedTarget = true; } @@ -1355,17 +1349,17 @@ inheritance_planner(PlannerInfo *root) } /* - * Set the nominal target relation of the ModifyTable node if not - * already done. We use the inheritance parent RTE as the nominal - * target relation if it's a partitioned table (see just above this - * loop). In the non-partitioned parent case, we'll use the first - * child relation (even if it's excluded) as the nominal target - * relation. Because of the way expand_inherited_rtentry works, the - * latter should be the RTE representing the parent table in its role - * as a simple member of the inheritance set. + * Set the target relation of the ModifyTable node if not already + * done. We use the inheritance parent RTE as the target relation + * if it's a partitioned table (see just above this loop). In the + * non-partitioned parent case, we'll use the first child relation + * (even if it's excluded) as the target relation. Because of the way + * expand_inherited_rtentry works, the latter should be the RTE + * representing the parent table in its role as a simple member of + * the inheritance set. * * It would be logically cleaner to *always* use the inheritance - * parent RTE as the nominal relation; but that RTE is not otherwise + * parent RTE as the target relation; but that RTE is not otherwise * referenced in the plan in the non-partitioned inheritance case. * Instead the duplicate child RTE created by expand_inherited_rtentry * is used elsewhere in the plan, so using the original parent RTE @@ -1375,8 +1369,8 @@ inheritance_planner(PlannerInfo *root) * duplicate child RTE added for the parent does not appear anywhere * else in the plan tree. */ - if (nominalRelation < 0) - nominalRelation = appinfo->child_relid; + if (targetRelation < 0) + targetRelation = appinfo->child_relid; /* * The rowMarks list might contain references to subquery RTEs, so @@ -1601,14 +1595,14 @@ inheritance_planner(PlannerInfo *root) if (parse->rowMarks) rowMarks = NIL; else - rowMarks = get_unpruned_rowmarks(root); + rowMarks = get_nondummy_rowmarks(root); /* Create Path representing a ModifyTable to do the UPDATE/DELETE work */ add_path(final_rel, (Path *) create_modifytable_path(root, final_rel, parse->commandType, parse->canSetTag, - nominalRelation, + targetRelation, partitionedTarget, root->partColsUpdated, resultRelations, @@ -2131,7 +2125,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, */ if (parse->rowMarks) path = (Path *) create_lockrows_path(root, final_rel, path, - get_unpruned_rowmarks(root), + get_nondummy_rowmarks(root), SS_assign_special_param(root)); /* @@ -2177,14 +2171,14 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, if (parse->rowMarks) rowMarks = NIL; else - rowMarks = get_unpruned_rowmarks(root); + rowMarks = get_nondummy_rowmarks(root); path = (Path *) create_modifytable_path(root, final_rel, parse->commandType, parse->canSetTag, parse->resultRelation, - 0, + false, false, list_make1_int(parse->resultRelation), list_make1(path), @@ -7225,11 +7219,11 @@ group_by_has_partkey(RelOptInfo *input_rel, } /* - * get_unpruned_rowmarks - * Return a list of PlanRowMark's that reference unpruned relations + * get_nondummy_rowmarks + * Return a list of PlanRowMark's that reference non-dummy relations */ static List * -get_unpruned_rowmarks(PlannerInfo *root) +get_nondummy_rowmarks(PlannerInfo *root) { List *rowMarks = NIL; ListCell *lc; diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 72ad161e57..ee01ef82d2 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -827,7 +827,7 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) fix_scan_list(root, splan->exclRelTlist, rtoffset); } - splan->nominalRelation += rtoffset; + splan->targetRelation += rtoffset; splan->exclRelRTI += rtoffset; foreach(l, splan->resultRelations) @@ -870,7 +870,7 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) list_length(root->glob->rootResultRelations); root->glob->rootResultRelations = lappend_int(root->glob->rootResultRelations, - splan->nominalRelation); + splan->targetRelation); } } break; diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 28f90a2a04..73eca1d4d0 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -3291,8 +3291,8 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel, * 'rel' is the parent relation associated with the result * 'operation' is the operation type * 'canSetTag' is true if we set the command tag/es_processed - * 'nominalRelation' is the parent RT index for use of EXPLAIN - * 'rootRelation' is the RT index of the root partitioned table + * 'targetRelation' is the target table's RT index + * 'partitionedTarget' true if 'targetRelation' is a partitioned table * 'partColsUpdated' is true if any partitioning columns are being updated, * either from the target relation or a descendent partitioned table. * 'resultRelations' is an integer list of actual RT indexes of target rel(s) @@ -3307,7 +3307,7 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel, ModifyTablePath * create_modifytable_path(PlannerInfo *root, RelOptInfo *rel, CmdType operation, bool canSetTag, - Index nominalRelation, bool partitionedTarget, + Index targetRelation, bool partitionedTarget, bool partColsUpdated, List *resultRelations, List *subpaths, List *subroots, @@ -3374,7 +3374,7 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel, pathnode->operation = operation; pathnode->canSetTag = canSetTag; - pathnode->nominalRelation = nominalRelation; + pathnode->targetRelation = targetRelation; pathnode->partitionedTarget = partitionedTarget; pathnode->partColsUpdated = partColsUpdated; pathnode->resultRelations = resultRelations; diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index 53b2832215..a9cfd1f67b 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -28,6 +28,7 @@ #include "parser/parse_enr.h" #include "parser/parse_relation.h" #include "parser/parse_type.h" +#include "storage/lmgr.h" #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/rel.h" @@ -1281,6 +1282,11 @@ addRangeTableEntryForRelation(ParseState *pstate, Assert(pstate != NULL); +#ifdef USE_ASSERT_CHECKING + if (lockmode != NoLock && !CheckRelationLockedByUs(RelationGetRelid(rel), lockmode)) + elog(WARNING, "lock on \"%s\" is not held", RelationGetRelationName(rel)); +#endif + rte->rtekind = RTE_RELATION; rte->alias = alias; rte->relid = RelationGetRelid(rel); diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index 14adac8312..5df0348f1c 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -2638,11 +2638,11 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString, oldrte = addRangeTableEntryForRelation(pstate, rel, makeAlias("old", NIL), false, false, - AccessShareLock); + AccessExclusiveLock); newrte = addRangeTableEntryForRelation(pstate, rel, makeAlias("new", NIL), false, false, - AccessShareLock); + AccessExclusiveLock); /* Must override addRangeTableEntry's default access-check flags */ oldrte->requiredPerms = 0; newrte->requiredPerms = 0; @@ -2738,11 +2738,11 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString, oldrte = addRangeTableEntryForRelation(sub_pstate, rel, makeAlias("old", NIL), false, false, - AccessShareLock); + AccessExclusiveLock); newrte = addRangeTableEntryForRelation(sub_pstate, rel, makeAlias("new", NIL), false, false, - AccessShareLock); + AccessExclusiveLock); oldrte->requiredPerms = 0; newrte->requiredPerms = 0; addRTEtoQuery(sub_pstate, oldrte, false, true, false); diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c index b22d2d1457..2d8eae62e6 100644 --- a/src/backend/storage/lmgr/lmgr.c +++ b/src/backend/storage/lmgr/lmgr.c @@ -100,9 +100,8 @@ SetLocktagRelationOid(LOCKTAG *tag, Oid relid) * * Lock a relation given only its OID. This should generally be used * before attempting to open the relation's relcache entry. - * Return true if we acquired a new lock, false if already held. */ -bool +void LockRelationOid(Oid relid, LOCKMODE lockmode) { LOCKTAG tag; @@ -133,10 +132,22 @@ LockRelationOid(Oid relid, LOCKMODE lockmode) { AcceptInvalidationMessages(); MarkLockClear(locallock); - return true; } +} + +/* + * CheckRelationLockedByUs + * + * Returns true we hold a lock on 'relid' with 'lockmode'. + */ +bool +CheckRelationLockedByUs(Oid relid, LOCKMODE lockmode) +{ + LOCKTAG tag; + + SetLocktagRelationOid(&tag, relid); - return res == LOCKACQUIRE_ALREADY_HELD; + return LocalLockExists(&tag, lockmode); } /* diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index 831ae62525..8c140fe4b0 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -563,6 +563,30 @@ DoLockModesConflict(LOCKMODE mode1, LOCKMODE mode2) return false; } +/* + * LocalLockExists -- check if a log with 'locktag' is held locally with + * 'lockmode' + */ +bool +LocalLockExists(const LOCKTAG *locktag, LOCKMODE lockmode) +{ + LOCALLOCKTAG localtag; + bool found; + + MemSet(&localtag, 0, sizeof(localtag)); /* must clear padding */ + localtag.lock = *locktag; + localtag.mode = lockmode; + + /* + * Find the LOCALLOCK entry for this lock and lockmode + */ + (void) hash_search(LockMethodLocalHash, + (void *) &localtag, + HASH_FIND, &found); + + return found; +} + /* * LockHasWaiters -- look up 'locktag' and check if releasing this * lock would wake up other processes waiting for it. diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 93259a4ffa..b03d8c591f 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -580,8 +580,8 @@ ExecRangeTableRelation(EState *estate, Index rti) RangeTblEntry *rte = exec_rt_fetch(rti, estate->es_range_table_array); /* - * No need to lock the relation lock, because upstream code - * must hold the lock already. + * No need to lock the relation. Locks were already + * obtained by the upstream code. */ rel = estate->es_relations[rti - 1] = heap_open(rte->relid, NoLock); } diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index b2ab3fd2b6..639235d622 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -482,7 +482,8 @@ typedef struct EState List *es_range_table; /* List of RangeTblEntry */ struct RangeTblEntry **es_range_table_array; /* 0-based range table */ int es_range_table_size; /* size of the range table array */ - Relation *es_relations; /* 0-based array of Relation pointers */ + Relation *es_relations; /* 0-based array of Relations + * es_range_table_size elements in length. */ PlannedStmt *es_plannedstmt; /* link to top of plan tree */ const char *es_sourceText; /* Source text from QueryDesc */ @@ -590,7 +591,7 @@ typedef struct EState */ #define exec_rt_fetch(rangetblidx, rangetbl) rangetbl[(rangetblidx) - 1] -/* XXX moved from parsetree.h. okay?? +/* * getrelid * * Given the range index of a relation, return the corresponding diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 2743e1ea81..d844e323f0 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -977,8 +977,7 @@ typedef struct RangeTblEntry */ Oid relid; /* OID of the relation */ char relkind; /* relation kind (see pg_class.relkind) */ - LOCKMODE lockmode; /* lock level to obtain on the relation, or - * 0 if no lock required */ + LOCKMODE lockmode; /* lock level to obtain on the relation */ struct TableSampleClause *tablesample; /* sampling info, or NULL */ /* diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 59dd26b04e..452627dd03 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -212,8 +212,9 @@ typedef struct ModifyTable Plan plan; CmdType operation; /* INSERT, UPDATE, or DELETE */ bool canSetTag; /* do we set the command tag/es_processed? */ - Index nominalRelation; /* RT index of the target table specified - * in the command */ + Index targetRelation; /* RT index of the target table specified in + * the command or first child for inheritance + * tables */ bool partitionedTarget; /* is the target table partitioned? */ bool partColsUpdated; /* some part key in hierarchy updated */ List *resultRelations; /* integer list of RT indexes */ @@ -1092,7 +1093,7 @@ typedef struct PartitionPruneInfo typedef struct PartitionedRelPruneInfo { NodeTag type; - Index rtindex; /* Table's RT index */ + Index rtindex; /* Partition table's RT index */ List *pruning_steps; /* List of PartitionPruneStep, see below */ Bitmapset *present_parts; /* Indexes of all partitions which subplans or * subparts are present for. */ diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index c9f288c24d..bcc2ba6db5 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -1713,8 +1713,9 @@ typedef struct ModifyTablePath Path path; CmdType operation; /* INSERT, UPDATE, or DELETE */ bool canSetTag; /* do we set the command tag/es_processed? */ - Index nominalRelation; /* RT index of the target table specified - * in the command */ + Index targetRelation; /* RT index of the target table specified in + * the command or first child for inheritance + * tables */ bool partitionedTarget; /* is the target table partitioned? */ bool partColsUpdated; /* some part key in hierarchy updated */ List *resultRelations; /* integer list of RT indexes */ diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h index d826e3cc55..a45c2407d0 100644 --- a/src/include/optimizer/pathnode.h +++ b/src/include/optimizer/pathnode.h @@ -238,7 +238,7 @@ extern LockRowsPath *create_lockrows_path(PlannerInfo *root, RelOptInfo *rel, extern ModifyTablePath *create_modifytable_path(PlannerInfo *root, RelOptInfo *rel, CmdType operation, bool canSetTag, - Index nominalRelation, bool partitionedTarget, + Index targetRelation, bool partitionedTarget, bool partColsUpdated, List *resultRelations, List *subpaths, List *subroots, diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h index 69e6f7ffd6..abfafe5e40 100644 --- a/src/include/storage/lmgr.h +++ b/src/include/storage/lmgr.h @@ -37,7 +37,8 @@ typedef enum XLTW_Oper extern void RelationInitLockInfo(Relation relation); /* Lock a relation */ -extern bool LockRelationOid(Oid relid, LOCKMODE lockmode); +extern void LockRelationOid(Oid relid, LOCKMODE lockmode); +extern bool CheckRelationLockedByUs(Oid relid, LOCKMODE lockmode); extern bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode); extern void UnlockRelationId(LockRelId *relid, LOCKMODE lockmode); extern void UnlockRelationOid(Oid relid, LOCKMODE lockmode); diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h index ff4df7fec5..b4a71ced0b 100644 --- a/src/include/storage/lock.h +++ b/src/include/storage/lock.h @@ -540,6 +540,7 @@ extern void LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks); extern void LockReleaseSession(LOCKMETHODID lockmethodid); extern void LockReleaseCurrentOwner(LOCALLOCK **locallocks, int nlocks); extern void LockReassignCurrentOwner(LOCALLOCK **locallocks, int nlocks); +extern bool LocalLockExists(const LOCKTAG *locktag, LOCKMODE lockmode); extern bool LockHasWaiters(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock); extern VirtualTransactionId *GetLockConflicts(const LOCKTAG *locktag,