diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 3b23de9..0deaf8f 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -664,6 +664,10 @@ ExecCreateScanSlotFromOuterPlan(EState *estate, * * Detect whether a relation (identified by rangetable index) * is one of the target relations of the query. + * + * Note: This is currently no longer used in core. We keep it + * around to allow FDWs to use it in order to determine if the foreign + * table is the target of an UPDATE/DELETE. * ---------------------------------------------------------------- */ bool diff --git a/src/backend/executor/nodeBitmapIndexscan.c b/src/backend/executor/nodeBitmapIndexscan.c index bd837d3..604f4f1 100644 --- a/src/backend/executor/nodeBitmapIndexscan.c +++ b/src/backend/executor/nodeBitmapIndexscan.c @@ -211,7 +211,7 @@ BitmapIndexScanState * ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags) { BitmapIndexScanState *indexstate; - bool relistarget; + LOCKMODE lockmode; /* check for unsupported flags */ Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); @@ -260,16 +260,9 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags) if (eflags & EXEC_FLAG_EXPLAIN_ONLY) return indexstate; - /* - * Open the index relation. - * - * If the parent table is one of the target relations of the query, then - * InitPlan already opened and write-locked the index, so we can avoid - * taking another lock here. Otherwise we need a normal reader's lock. - */ - relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid); - indexstate->biss_RelationDesc = index_open(node->indexid, - relistarget ? NoLock : AccessShareLock); + /* Open the index relation. */ + lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode; + indexstate->biss_RelationDesc = index_open(node->indexid, lockmode); /* * Initialize index-specific scan state diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c index 2d954b7..7711728 100644 --- a/src/backend/executor/nodeIndexonlyscan.c +++ b/src/backend/executor/nodeIndexonlyscan.c @@ -493,7 +493,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags) { IndexOnlyScanState *indexstate; Relation currentRelation; - bool relistarget; + LOCKMODE lockmode; TupleDesc tupDesc; /* @@ -556,16 +556,9 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags) if (eflags & EXEC_FLAG_EXPLAIN_ONLY) return indexstate; - /* - * Open the index relation. - * - * If the parent table is one of the target relations of the query, then - * InitPlan already opened and write-locked the index, so we can avoid - * taking another lock here. Otherwise we need a normal reader's lock. - */ - relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid); - indexstate->ioss_RelationDesc = index_open(node->indexid, - relistarget ? NoLock : AccessShareLock); + /* Open the index relation. */ + lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode; + indexstate->ioss_RelationDesc = index_open(node->indexid, lockmode); /* * Initialize index-specific scan state diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index 8f39cc2..399ac01 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -901,7 +901,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags) { IndexScanState *indexstate; Relation currentRelation; - bool relistarget; + LOCKMODE lockmode; /* * create state structure @@ -964,16 +964,9 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags) if (eflags & EXEC_FLAG_EXPLAIN_ONLY) return indexstate; - /* - * Open the index relation. - * - * If the parent table is one of the target relations of the query, then - * InitPlan already opened and write-locked the index, so we can avoid - * taking another lock here. Otherwise we need a normal reader's lock. - */ - relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid); - indexstate->iss_RelationDesc = index_open(node->indexid, - relistarget ? NoLock : AccessShareLock); + /* Open the index relation. */ + lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode; + indexstate->iss_RelationDesc = index_open(node->indexid, lockmode); /* * Initialize index-specific scan state diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index c430189..15fe132 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -6285,6 +6285,7 @@ plan_create_index_workers(Oid tableOid, Oid indexOid) /* Build RelOptInfo */ rel = build_simple_rel(root, 1, NULL); + /* Already locked by the caller */ heap = table_open(tableOid, NoLock); index = index_open(indexOid, NoLock); diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 31a3784..c01dbb8 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -161,25 +161,13 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, if (hasindex) { + RangeTblEntry *rte; List *indexoidlist; ListCell *l; - LOCKMODE lmode; + rte = root->simple_rte_array[varno]; indexoidlist = RelationGetIndexList(relation); - /* - * For each index, we get the same type of lock that the executor will - * need, and do not release it. This saves a couple of trips to the - * shared lock manager while not creating any real loss of - * concurrency, because no schema changes could be happening on the - * index while we hold lock on the parent rel, and neither lock type - * blocks any other kind of index operation. - */ - if (rel->relid == root->parse->resultRelation) - lmode = RowExclusiveLock; - else - lmode = AccessShareLock; - foreach(l, indexoidlist) { Oid indexoid = lfirst_oid(l); @@ -194,7 +182,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, /* * Extract info from the relation descriptor for the index. */ - indexRelation = index_open(indexoid, lmode); + indexRelation = index_open(indexoid, rte->rellockmode); index = indexRelation->rd_index; /* @@ -592,8 +580,8 @@ infer_arbiter_indexes(PlannerInfo *root) OnConflictExpr *onconflict = root->parse->onConflict; /* Iteration state */ + RangeTblEntry *rte; Relation relation; - Oid relationObjectId; Oid indexOidFromConstraint = InvalidOid; List *indexList; ListCell *l; @@ -620,10 +608,9 @@ infer_arbiter_indexes(PlannerInfo *root) * the rewriter or when expand_inherited_rtentry() added it to the query's * rangetable. */ - relationObjectId = rt_fetch(root->parse->resultRelation, - root->parse->rtable)->relid; + rte = rt_fetch(root->parse->resultRelation, root->parse->rtable); - relation = table_open(relationObjectId, NoLock); + relation = table_open(rte->relid, NoLock); /* * Build normalized/BMS representation of plain indexed attributes, as @@ -695,7 +682,8 @@ infer_arbiter_indexes(PlannerInfo *root) * enforcement needs to occur there anyway when an inference clause is * omitted. */ - idxRel = index_open(indexoid, RowExclusiveLock); + Assert(rte->rellockmode >= RowExclusiveLock); + idxRel = index_open(indexoid, rte->rellockmode); idxForm = idxRel->rd_index; if (!idxForm->indisvalid) diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index ecffffb..23bfb71 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -5187,11 +5187,11 @@ get_actual_variable_range(PlannerInfo *root, VariableStatData *vardata, /* * Open the table and index so we can read from them. We should - * already have at least AccessShareLock on the table, but not - * necessarily on the index. + * already have at least AccessShareLock on the table. The index + * should have been locked in get_relation_info. */ heapRel = table_open(rte->relid, NoLock); - indexRel = index_open(index->indexoid, AccessShareLock); + indexRel = index_open(index->indexoid, NoLock); /* extract index key information from the index's pg_index info */ indexInfo = BuildIndexInfo(indexRel); @@ -5305,7 +5305,7 @@ get_actual_variable_range(PlannerInfo *root, VariableStatData *vardata, /* Clean everything up */ ExecDropSingleTupleTableSlot(slot); - index_close(indexRel, AccessShareLock); + index_close(indexRel, NoLock); table_close(heapRel, NoLock); MemoryContextSwitchTo(oldcontext); @@ -6472,9 +6472,10 @@ gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count, */ if (!index->hypothetical) { - indexRel = index_open(index->indexoid, AccessShareLock); + /* Lock should have already been obtained in get_relation_info */ + indexRel = index_open(index->indexoid, NoLock); ginGetStats(indexRel, &ginStats); - index_close(indexRel, AccessShareLock); + index_close(indexRel, NoLock); } else { @@ -6781,11 +6782,12 @@ brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count, &spc_seq_page_cost); /* - * Obtain some data from the index itself. + * Obtain some data from the index itself. A lock should have already + * been obtained on the index during get_relation_info. */ - indexRel = index_open(index->indexoid, AccessShareLock); + indexRel = index_open(index->indexoid, NoLock); brinGetStats(indexRel, &statsData); - index_close(indexRel, AccessShareLock); + index_close(indexRel, NoLock); /* * Compute index correlation