On 2018/08/16 17:22, Amit Langote wrote: > 0004-Revise-executor-range-table-relation-opening-closing.patch > > This adds two arrays to EState indexed by RT indexes, one for > RangeTblEntry's and another for Relation pointers. The former reduces the > cost of fetching RangeTblEntry by RT index. The latter is used by a newly > introduced function ExecRangeTableRelation(), which replaces heap_open for > relations that are contained in the range table. If a given RTE's > relation is opened by multiple times, only the first call of > ExecRangeTableRelation will go to relcache.
David Rowely recently, independently [1], proposed one of the ideas mentioned above (store RangeTblEntry's in an array in EState). As I mentioned in reply to his email, I think his implementation of the idea is better than mine, so I've merged his patch in the above patch, except one part: instead of removing the es_range_table list altogether, I decided to keep it around so that ExecSerializePlan doesn't have to build one all over again from the array like his patch did. Updated patches attached; 0001-0003 are same as v1. Thanks, Amit [1] Make executor's Range Table an array instead of a List https://postgr.es/m/CAKJS1f9EypD_=xG6ACFdF=1cbjz+z9hihhsd-rqljor+qya...@mail.gmail.com
From e46911bd7bb621b66c8d693132d4aeb3202d73df Mon Sep 17 00:00:00 2001 From: amit <amitlangot...@gmail.com> Date: Thu, 19 Jul 2018 16:14:51 +0900 Subject: [PATCH v2 1/4] Don't lock range table relations in the executor As noted in https://postgre.es/m/4114.1531674142%40sss.pgh.pa.us, taking relation locks inside the executor proper is redundant, because appropriate locks should've been taken by the upstream code, that is, during the parse/rewrite/plan pipeline when adding the relations to range table or by the AcquireExecutorLocks if using a cached plan. Also, InitPlan would do certain initiaization steps, such as creating result rels, ExecRowMarks, etc. only because of the concerns about locking order, which it needs not to do anymore, because we've eliminated executor locking at all. Instead create result rels and ExecRowMarks, etc. in the ExecInit* routines of the respective nodes. To indicate which lock was taken on a relation before creating a RTE_RELATION range table entry for it, add a 'lockmode' field to RangeTblEntry. It's set when the relation is opened for the first time in the parse/rewrite/plan pipeline and its range table entry created. --- src/backend/commands/view.c | 2 + src/backend/executor/execMain.c | 269 ++++++++++++--------------------- src/backend/executor/execPartition.c | 4 +- src/backend/executor/execUtils.c | 24 +-- src/backend/executor/nodeLockRows.c | 2 +- src/backend/executor/nodeModifyTable.c | 39 ++++- src/backend/nodes/copyfuncs.c | 1 + src/backend/nodes/equalfuncs.c | 1 + src/backend/nodes/outfuncs.c | 1 + src/backend/nodes/readfuncs.c | 1 + src/backend/parser/analyze.c | 1 + src/backend/parser/parse_clause.c | 1 + src/backend/parser/parse_relation.c | 1 + src/backend/parser/parse_utilcmd.c | 4 + src/backend/rewrite/rewriteHandler.c | 18 +-- src/backend/storage/lmgr/lmgr.c | 7 +- src/backend/utils/cache/plancache.c | 26 +--- src/include/executor/executor.h | 2 +- src/include/nodes/parsenodes.h | 1 + src/include/storage/lmgr.h | 2 +- 20 files changed, 166 insertions(+), 241 deletions(-) diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c index ffb71c0ea7..818557d796 100644 --- a/src/backend/commands/view.c +++ b/src/backend/commands/view.c @@ -388,9 +388,11 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse) rt_entry1 = addRangeTableEntryForRelation(pstate, viewRel, makeAlias("old", NIL), false, false); + rt_entry1->lockmode = AccessShareLock; rt_entry2 = addRangeTableEntryForRelation(pstate, viewRel, makeAlias("new", NIL), false, false); + rt_entry2->lockmode = AccessShareLock; /* Must override addRangeTableEntry's default access-check flags */ rt_entry1->requiredPerms = 0; rt_entry2->requiredPerms = 0; diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index c583e020a0..298bf43fce 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -50,10 +50,12 @@ #include "mb/pg_wchar.h" #include "miscadmin.h" #include "optimizer/clauses.h" +#include "optimizer/prep.h" #include "parser/parsetree.h" #include "rewrite/rewriteManip.h" #include "storage/bufmgr.h" #include "storage/lmgr.h" +#include "storage/lockdefs.h" #include "tcop/utility.h" #include "utils/acl.h" #include "utils/lsyscache.h" @@ -818,6 +820,26 @@ InitPlan(QueryDesc *queryDesc, int eflags) */ ExecCheckRTPerms(rangeTable, true); +#ifdef USE_ASSERT_CHECKING + foreach(l, rangeTable) + { + RangeTblEntry *rte = lfirst(l); + + if (rte->rtekind == RTE_RELATION && OidIsValid(rte->relid)) + { + /* + * The following asserts that no new lock needed to be taken, + * 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)); + } + } +#endif + /* * initialize the node's execution state */ @@ -832,85 +854,19 @@ InitPlan(QueryDesc *queryDesc, int eflags) */ if (plannedstmt->resultRelations) { - List *resultRelations = plannedstmt->resultRelations; - int numResultRelations = list_length(resultRelations); - ResultRelInfo *resultRelInfos; - ResultRelInfo *resultRelInfo; + int numResultRelations = list_length(plannedstmt->resultRelations); + int num_roots = list_length(plannedstmt->rootResultRelations); - resultRelInfos = (ResultRelInfo *) - palloc(numResultRelations * sizeof(ResultRelInfo)); - resultRelInfo = resultRelInfos; - foreach(l, resultRelations) - { - Index resultRelationIndex = lfirst_int(l); - Oid resultRelationOid; - Relation resultRelation; - - resultRelationOid = getrelid(resultRelationIndex, rangeTable); - resultRelation = heap_open(resultRelationOid, RowExclusiveLock); - - InitResultRelInfo(resultRelInfo, - resultRelation, - resultRelationIndex, - NULL, - estate->es_instrument); - resultRelInfo++; - } - estate->es_result_relations = resultRelInfos; + estate->es_result_relations = (ResultRelInfo *) + palloc(numResultRelations * sizeof(ResultRelInfo)); estate->es_num_result_relations = numResultRelations; /* es_result_relation_info is NULL except when within ModifyTable */ estate->es_result_relation_info = NULL; - /* - * In the partitioned result relation case, lock the non-leaf result - * relations too. A subset of these are the roots of respective - * partitioned tables, for which we also allocate ResultRelInfos. - */ - estate->es_root_result_relations = NULL; - estate->es_num_root_result_relations = 0; - if (plannedstmt->nonleafResultRelations) - { - int num_roots = list_length(plannedstmt->rootResultRelations); - - /* - * Firstly, build ResultRelInfos for all the partitioned table - * roots, because we will need them to fire the statement-level - * triggers, if any. - */ - resultRelInfos = (ResultRelInfo *) + /* For partitioned tables that are roots of their partition trees. */ + estate->es_root_result_relations = (ResultRelInfo *) palloc(num_roots * sizeof(ResultRelInfo)); - resultRelInfo = resultRelInfos; - foreach(l, plannedstmt->rootResultRelations) - { - Index resultRelIndex = lfirst_int(l); - Oid resultRelOid; - Relation resultRelDesc; - - resultRelOid = getrelid(resultRelIndex, rangeTable); - resultRelDesc = heap_open(resultRelOid, RowExclusiveLock); - InitResultRelInfo(resultRelInfo, - resultRelDesc, - lfirst_int(l), - NULL, - estate->es_instrument); - resultRelInfo++; - } - - estate->es_root_result_relations = resultRelInfos; - estate->es_num_root_result_relations = num_roots; - - /* Simply lock the rest of them. */ - foreach(l, plannedstmt->nonleafResultRelations) - { - Index resultRelIndex = lfirst_int(l); - - /* We locked the roots above. */ - if (!list_member_int(plannedstmt->rootResultRelations, - resultRelIndex)) - LockRelationOid(getrelid(resultRelIndex, rangeTable), - RowExclusiveLock); - } - } + estate->es_num_root_result_relations = num_roots; } else { @@ -924,73 +880,7 @@ InitPlan(QueryDesc *queryDesc, int eflags) estate->es_num_root_result_relations = 0; } - /* - * Similarly, we have to lock relations selected FOR [KEY] UPDATE/SHARE - * before we initialize the plan tree, else we'd be risking lock upgrades. - * While we are at it, build the ExecRowMark list. Any partitioned child - * tables are ignored here (because isParent=true) and will be locked by - * the first Append or MergeAppend node that references them. (Note that - * the RowMarks corresponding to partitioned child tables are present in - * the same list as the rest, i.e., plannedstmt->rowMarks.) - */ estate->es_rowMarks = NIL; - foreach(l, plannedstmt->rowMarks) - { - PlanRowMark *rc = (PlanRowMark *) lfirst(l); - Oid relid; - Relation relation; - ExecRowMark *erm; - - /* ignore "parent" rowmarks; they are irrelevant at runtime */ - if (rc->isParent) - continue; - - /* get relation's OID (will produce InvalidOid if subquery) */ - relid = getrelid(rc->rti, rangeTable); - - /* - * If you change the conditions under which rel locks are acquired - * here, be sure to adjust ExecOpenScanRelation to match. - */ - switch (rc->markType) - { - case ROW_MARK_EXCLUSIVE: - case ROW_MARK_NOKEYEXCLUSIVE: - case ROW_MARK_SHARE: - case ROW_MARK_KEYSHARE: - relation = heap_open(relid, RowShareLock); - break; - case ROW_MARK_REFERENCE: - relation = heap_open(relid, AccessShareLock); - break; - case ROW_MARK_COPY: - /* no physical table access is required */ - relation = NULL; - break; - default: - elog(ERROR, "unrecognized markType: %d", rc->markType); - relation = NULL; /* keep compiler quiet */ - break; - } - - /* Check that relation is a legal target for marking */ - if (relation) - CheckValidRowMarkRel(relation, rc->markType); - - erm = (ExecRowMark *) palloc(sizeof(ExecRowMark)); - erm->relation = relation; - erm->relid = relid; - erm->rti = rc->rti; - erm->prti = rc->prti; - erm->rowmarkId = rc->rowmarkId; - erm->markType = rc->markType; - erm->strength = rc->strength; - erm->waitPolicy = rc->waitPolicy; - erm->ermActive = false; - ItemPointerSetInvalid(&(erm->curCtid)); - erm->ermExtra = NULL; - estate->es_rowMarks = lappend(estate->es_rowMarks, erm); - } /* * Initialize the executor's tuple table to empty. @@ -1597,8 +1487,6 @@ ExecPostprocessPlan(EState *estate) static void ExecEndPlan(PlanState *planstate, EState *estate) { - ResultRelInfo *resultRelInfo; - int i; ListCell *l; /* @@ -1624,26 +1512,6 @@ ExecEndPlan(PlanState *planstate, EState *estate) */ ExecResetTupleTable(estate->es_tupleTable, false); - /* - * close the result relation(s) if any, but hold locks until xact commit. - */ - resultRelInfo = estate->es_result_relations; - for (i = estate->es_num_result_relations; i > 0; i--) - { - /* Close indices and then the relation itself */ - ExecCloseIndices(resultRelInfo); - heap_close(resultRelInfo->ri_RelationDesc, NoLock); - resultRelInfo++; - } - - /* Close the root target relation(s). */ - resultRelInfo = estate->es_root_result_relations; - for (i = estate->es_num_root_result_relations; i > 0; i--) - { - heap_close(resultRelInfo->ri_RelationDesc, NoLock); - resultRelInfo++; - } - /* likewise close any trigger target relations */ ExecCleanUpTriggerState(estate); @@ -2404,25 +2272,64 @@ ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo) } /* - * ExecFindRowMark -- find the ExecRowMark struct for given rangetable index - * - * If no such struct, either return NULL or throw error depending on missing_ok + * ExecBuildRowMark -- create ExecRowMark struct for given PlanRowMark */ ExecRowMark * -ExecFindRowMark(EState *estate, Index rti, bool missing_ok) +ExecBuildRowMark(EState *estate, PlanRowMark *rc) { - ListCell *lc; + ExecRowMark *erm; + Oid relid; + Relation relation; - foreach(lc, estate->es_rowMarks) + Assert(!rc->isParent); + + /* get relation's OID (will produce InvalidOid if subquery) */ + relid = getrelid(rc->rti, estate->es_range_table); + + /* + * If you change the conditions under which rel locks are acquired + * here, be sure to adjust ExecOpenScanRelation to match. + */ + switch (rc->markType) { - ExecRowMark *erm = (ExecRowMark *) lfirst(lc); - - if (erm->rti == rti) - return erm; + case ROW_MARK_EXCLUSIVE: + case ROW_MARK_NOKEYEXCLUSIVE: + case ROW_MARK_SHARE: + case ROW_MARK_KEYSHARE: + relation = heap_open(relid, NoLock); + break; + case ROW_MARK_REFERENCE: + relation = heap_open(relid, NoLock); + break; + case ROW_MARK_COPY: + /* no physical table access is required */ + relation = NULL; + break; + default: + elog(ERROR, "unrecognized markType: %d", rc->markType); + relation = NULL; /* keep compiler quiet */ + break; } - if (!missing_ok) - elog(ERROR, "failed to find ExecRowMark for rangetable index %u", rti); - return NULL; + + /* Check that relation is a legal target for marking */ + if (relation) + CheckValidRowMarkRel(relation, rc->markType); + + erm = (ExecRowMark *) palloc(sizeof(ExecRowMark)); + erm->relation = relation; + erm->relid = relid; + erm->rti = rc->rti; + erm->prti = rc->prti; + erm->rowmarkId = rc->rowmarkId; + erm->markType = rc->markType; + erm->strength = rc->strength; + erm->waitPolicy = rc->waitPolicy; + erm->ermActive = false; + ItemPointerSetInvalid(&(erm->curCtid)); + erm->ermExtra = NULL; + estate->es_rowMarks = lappend(estate->es_rowMarks, erm); + + return erm; } /* @@ -3154,7 +3061,7 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree) } /* es_result_relation_info must NOT be copied */ /* es_trig_target_relations must NOT be copied */ - estate->es_rowMarks = parentestate->es_rowMarks; + /* es_rowMarks must NOT be copied */ estate->es_top_eflags = parentestate->es_top_eflags; estate->es_instrument = parentestate->es_instrument; /* es_auxmodifytables must NOT be copied */ @@ -3267,6 +3174,18 @@ EvalPlanQualEnd(EPQState *epqstate) ExecEndNode(subplanstate); } + /* + * close any relations selected FOR [KEY] UPDATE/SHARE, again keeping + * locks + */ + foreach(l, estate->es_rowMarks) + { + ExecRowMark *erm = (ExecRowMark *) lfirst(l); + + if (erm->relation) + heap_close(erm->relation, NoLock); + } + /* throw away the per-estate tuple table */ ExecResetTupleTable(estate->es_tupleTable, false); diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index 1a9943c3aa..81c2f5cedc 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -1510,9 +1510,7 @@ ExecCreatePartitionPruneState(PlanState *planstate, /* * We need to hold a pin on the partitioned table's relcache entry * so that we can rely on its copies of the table's partition key - * and partition descriptor. We need not get a lock though; one - * should have been acquired already by InitPlan or - * ExecLockNonLeafAppendTables. + * and partition descriptor. */ context->partrel = relation_open(pinfo->reloid, NoLock); diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 5b3eaec80b..09942b34fb 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -42,6 +42,7 @@ #include "postgres.h" +#include "access/parallel.h" #include "access/relscan.h" #include "access/transam.h" #include "executor/executor.h" @@ -51,6 +52,7 @@ #include "parser/parsetree.h" #include "storage/lmgr.h" #include "utils/builtins.h" +#include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/rel.h" #include "utils/typcache.h" @@ -652,28 +654,10 @@ ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags) { Relation rel; Oid reloid; - LOCKMODE lockmode; - /* - * Determine the lock type we need. First, scan to see if target relation - * is a result relation. If not, check if it's a FOR UPDATE/FOR SHARE - * relation. In either of those cases, we got the lock already. - */ - lockmode = AccessShareLock; - if (ExecRelationIsTargetRelation(estate, scanrelid)) - lockmode = NoLock; - else - { - /* Keep this check in sync with InitPlan! */ - ExecRowMark *erm = ExecFindRowMark(estate, scanrelid, true); - - if (erm != NULL && erm->relation != NULL) - lockmode = NoLock; - } - - /* Open the relation and acquire lock as needed */ + /* Open the relation. */ reloid = getrelid(scanrelid, estate->es_range_table); - rel = heap_open(reloid, lockmode); + rel = heap_open(reloid, NoLock); /* * Complain if we're attempting a scan of an unscannable relation, except diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c index 30de8a95ab..8c80291a53 100644 --- a/src/backend/executor/nodeLockRows.c +++ b/src/backend/executor/nodeLockRows.c @@ -425,7 +425,7 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags) Assert(rc->rti > 0 && rc->rti <= lrstate->lr_ntables); /* find ExecRowMark and build ExecAuxRowMark */ - erm = ExecFindRowMark(estate, rc->rti, false); + erm = ExecBuildRowMark(estate, rc); aerm = ExecBuildAuxRowMark(erm, outerPlan->targetlist); /* diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index d8d89c7983..93e5bf7af6 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -46,6 +46,7 @@ #include "foreign/fdwapi.h" #include "miscadmin.h" #include "nodes/nodeFuncs.h" +#include "parser/parsetree.h" #include "storage/bufmgr.h" #include "storage/lmgr.h" #include "utils/builtins.h" @@ -2238,12 +2239,36 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) mtstate->mt_plans = (PlanState **) palloc0(sizeof(PlanState *) * nplans); mtstate->resultRelInfo = estate->es_result_relations + node->resultRelIndex; + resultRelInfo = mtstate->resultRelInfo; + foreach(l, node->resultRelations) + { + Index resultRelationIndex = lfirst_int(l); + RangeTblEntry *rte = rt_fetch(resultRelationIndex, + estate->es_range_table); + Relation rel = heap_open(rte->relid, NoLock); + + InitResultRelInfo(resultRelInfo, rel, resultRelationIndex, NULL, + estate->es_instrument); + resultRelInfo++; + } /* If modifying a partitioned table, initialize the root table info */ if (node->rootResultRelIndex >= 0) + { + Index root_rt_index = linitial_int(node->partitioned_rels); + RangeTblEntry *rte; + Relation rel; + mtstate->rootResultRelInfo = estate->es_root_result_relations + node->rootResultRelIndex; + Assert(root_rt_index > 0); + rte = rt_fetch(root_rt_index, estate->es_range_table); + rel = heap_open(rte->relid, NoLock); + InitResultRelInfo(mtstate->rootResultRelInfo, rel, root_rt_index, + NULL, estate->es_instrument); + } + mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans); mtstate->mt_nplans = nplans; @@ -2530,7 +2555,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) continue; /* find ExecRowMark (same for all subplans) */ - erm = ExecFindRowMark(estate, rc->rti, false); + erm = ExecBuildRowMark(estate, rc); /* build ExecAuxRowMark for each subplan */ for (i = 0; i < nplans; i++) @@ -2687,19 +2712,29 @@ ExecEndModifyTable(ModifyTableState *node) int i; /* - * Allow any FDWs to shut down + * close the result relation(s) if any, but hold locks until xact commit. */ for (i = 0; i < node->mt_nplans; i++) { ResultRelInfo *resultRelInfo = node->resultRelInfo + i; + /* Allow any FDWs to shut down. */ if (!resultRelInfo->ri_usesFdwDirectModify && resultRelInfo->ri_FdwRoutine != NULL && resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL) resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state, resultRelInfo); + + /* Close indices and then the relation itself */ + ExecCloseIndices(resultRelInfo); + heap_close(resultRelInfo->ri_RelationDesc, NoLock); + resultRelInfo++; } + /* Close the root partitioned table, if any. */ + if (node->rootResultRelInfo) + heap_close(node->rootResultRelInfo->ri_RelationDesc, NoLock); + /* Close all the partitioned tables, leaf partitions, and their indices */ if (node->mt_partition_tuple_routing) ExecCleanupTupleRouting(node, node->mt_partition_tuple_routing); diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 7c8220cf65..6d685db0ea 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -2356,6 +2356,7 @@ _copyRangeTblEntry(const RangeTblEntry *from) COPY_SCALAR_FIELD(rtekind); COPY_SCALAR_FIELD(relid); COPY_SCALAR_FIELD(relkind); + COPY_SCALAR_FIELD(lockmode); COPY_NODE_FIELD(tablesample); COPY_NODE_FIELD(subquery); COPY_SCALAR_FIELD(security_barrier); diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 378f2facb8..488fddb255 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -2630,6 +2630,7 @@ _equalRangeTblEntry(const RangeTblEntry *a, const RangeTblEntry *b) COMPARE_SCALAR_FIELD(rtekind); COMPARE_SCALAR_FIELD(relid); COMPARE_SCALAR_FIELD(relkind); + COMPARE_SCALAR_FIELD(lockmode); COMPARE_NODE_FIELD(tablesample); COMPARE_NODE_FIELD(subquery); COMPARE_SCALAR_FIELD(security_barrier); diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index b5af904c18..53f209e170 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -3127,6 +3127,7 @@ _outRangeTblEntry(StringInfo str, const RangeTblEntry *node) case RTE_RELATION: WRITE_OID_FIELD(relid); WRITE_CHAR_FIELD(relkind); + WRITE_INT_FIELD(lockmode); WRITE_NODE_FIELD(tablesample); break; case RTE_SUBQUERY: diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 3254524223..7a1e839ef4 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -1350,6 +1350,7 @@ _readRangeTblEntry(void) case RTE_RELATION: READ_OID_FIELD(relid); READ_CHAR_FIELD(relkind); + READ_INT_FIELD(lockmode); READ_NODE_FIELD(tablesample); break; case RTE_SUBQUERY: diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index c601b6d40d..f70597cbd3 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -1040,6 +1040,7 @@ transformOnConflictClause(ParseState *pstate, makeAlias("excluded", NIL), false, false); exclRte->relkind = RELKIND_COMPOSITE_TYPE; + exclRte->lockmode = RowExclusiveLock; exclRte->requiredPerms = 0; /* other permissions fields in exclRte are already empty */ diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index cfd4b91897..b6a1b60d1e 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -218,6 +218,7 @@ setTargetTable(ParseState *pstate, RangeVar *relation, */ rte = addRangeTableEntryForRelation(pstate, pstate->p_target_relation, relation->alias, inh, false); + rte->lockmode = RowExclusiveLock; pstate->p_target_rangetblentry = rte; /* assume new rte is at end */ diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index bf5df26009..3fd91bdbb3 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -1217,6 +1217,7 @@ addRangeTableEntry(ParseState *pstate, rel = parserOpenTable(pstate, relation, lockmode); rte->relid = RelationGetRelid(rel); rte->relkind = rel->rd_rel->relkind; + rte->lockmode = lockmode; /* * Build the list of effective column names using user-supplied aliases diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index 656b1b5f1b..54c6b1e082 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -2636,9 +2636,11 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString, oldrte = addRangeTableEntryForRelation(pstate, rel, makeAlias("old", NIL), false, false); + oldrte->lockmode = AccessShareLock; newrte = addRangeTableEntryForRelation(pstate, rel, makeAlias("new", NIL), false, false); + newrte->lockmode = AccessShareLock; /* Must override addRangeTableEntry's default access-check flags */ oldrte->requiredPerms = 0; newrte->requiredPerms = 0; @@ -2734,9 +2736,11 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString, oldrte = addRangeTableEntryForRelation(sub_pstate, rel, makeAlias("old", NIL), false, false); + oldrte->lockmode = AccessShareLock; newrte = addRangeTableEntryForRelation(sub_pstate, rel, makeAlias("new", NIL), false, false); + newrte->lockmode = AccessShareLock; oldrte->requiredPerms = 0; newrte->requiredPerms = 0; addRTEtoQuery(sub_pstate, oldrte, false, true, false); diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index d830569641..f99c15bfcd 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -147,7 +147,6 @@ AcquireRewriteLocks(Query *parsetree, { RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); Relation rel; - LOCKMODE lockmode; List *newaliasvars; Index curinputvarno; RangeTblEntry *curinputrte; @@ -162,21 +161,8 @@ AcquireRewriteLocks(Query *parsetree, * Grab the appropriate lock type for the relation, and do not * release it until end of transaction. This protects the * rewriter and planner against schema changes mid-query. - * - * Assuming forExecute is true, this logic must match what the - * executor will do, else we risk lock-upgrade deadlocks. */ - if (!forExecute) - lockmode = AccessShareLock; - else if (rt_index == parsetree->resultRelation) - lockmode = RowExclusiveLock; - else if (forUpdatePushedDown || - get_parse_rowmark(parsetree, rt_index) != NULL) - lockmode = RowShareLock; - else - lockmode = AccessShareLock; - - rel = heap_open(rte->relid, lockmode); + rel = heap_open(rte->relid, rte->lockmode); /* * While we have the relation open, update the RTE's relkind, @@ -2895,6 +2881,7 @@ rewriteTargetView(Query *parsetree, Relation view) * it changed since this view was made (cf. AcquireRewriteLocks). */ base_rte->relkind = base_rel->rd_rel->relkind; + base_rte->lockmode = RowExclusiveLock; /* * If the view query contains any sublink subqueries then we need to also @@ -3102,6 +3089,7 @@ rewriteTargetView(Query *parsetree, Relation view) NIL), false, false); new_exclRte->relkind = RELKIND_COMPOSITE_TYPE; + new_exclRte->lockmode = RowExclusiveLock; new_exclRte->requiredPerms = 0; /* other permissions fields in new_exclRte are already empty */ diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c index 7b2dcb6c60..a1ebf647de 100644 --- a/src/backend/storage/lmgr/lmgr.c +++ b/src/backend/storage/lmgr/lmgr.c @@ -100,8 +100,9 @@ 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. */ -void +bool LockRelationOid(Oid relid, LOCKMODE lockmode) { LOCKTAG tag; @@ -122,7 +123,11 @@ LockRelationOid(Oid relid, LOCKMODE lockmode) * CommandCounterIncrement, not here.) */ if (res != LOCKACQUIRE_ALREADY_HELD) + { AcceptInvalidationMessages(); + return true; + } + return false; } /* diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c index 7271b5880b..b57e4d81ad 100644 --- a/src/backend/utils/cache/plancache.c +++ b/src/backend/utils/cache/plancache.c @@ -1516,8 +1516,6 @@ AcquireExecutorLocks(List *stmt_list, bool acquire) foreach(lc2, plannedstmt->rtable) { RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2); - LOCKMODE lockmode; - PlanRowMark *rc; rt_index++; @@ -1530,19 +1528,10 @@ AcquireExecutorLocks(List *stmt_list, bool acquire) * fail if it's been dropped entirely --- we'll just transiently * acquire a non-conflicting lock. */ - if (list_member_int(plannedstmt->resultRelations, rt_index) || - list_member_int(plannedstmt->nonleafResultRelations, rt_index)) - lockmode = RowExclusiveLock; - else if ((rc = get_plan_rowmark(plannedstmt->rowMarks, rt_index)) != NULL && - RowMarkRequiresRowShareLock(rc->markType)) - lockmode = RowShareLock; - else - lockmode = AccessShareLock; - if (acquire) - LockRelationOid(rte->relid, lockmode); + LockRelationOid(rte->relid, rte->lockmode); else - UnlockRelationOid(rte->relid, lockmode); + UnlockRelationOid(rte->relid, rte->lockmode); } } } @@ -1596,23 +1585,16 @@ ScanQueryForLocks(Query *parsetree, bool acquire) foreach(lc, parsetree->rtable) { RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc); - LOCKMODE lockmode; rt_index++; switch (rte->rtekind) { case RTE_RELATION: /* Acquire or release the appropriate type of lock */ - if (rt_index == parsetree->resultRelation) - lockmode = RowExclusiveLock; - else if (get_parse_rowmark(parsetree, rt_index) != NULL) - lockmode = RowShareLock; - else - lockmode = AccessShareLock; if (acquire) - LockRelationOid(rte->relid, lockmode); + LockRelationOid(rte->relid, rte->lockmode); else - UnlockRelationOid(rte->relid, lockmode); + UnlockRelationOid(rte->relid, rte->lockmode); break; case RTE_SUBQUERY: diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index f82b51667f..4425b978f9 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -188,7 +188,7 @@ extern void ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo, extern void ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate); extern LockTupleMode ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo); -extern ExecRowMark *ExecFindRowMark(EState *estate, Index rti, bool missing_ok); +extern ExecRowMark *ExecBuildRowMark(EState *estate, PlanRowMark *rc); extern ExecAuxRowMark *ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist); extern TupleTableSlot *EvalPlanQual(EState *estate, EPQState *epqstate, Relation relation, Index rti, int lockmode, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 07ab1a3dde..e8ac2459d1 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -977,6 +977,7 @@ typedef struct RangeTblEntry */ Oid relid; /* OID of the relation */ char relkind; /* relation kind (see pg_class.relkind) */ + int lockmode; /* lock taken on the relation or 0 */ struct TableSampleClause *tablesample; /* sampling info, or NULL */ /* diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h index a217de9716..69e6f7ffd6 100644 --- a/src/include/storage/lmgr.h +++ b/src/include/storage/lmgr.h @@ -37,7 +37,7 @@ typedef enum XLTW_Oper extern void RelationInitLockInfo(Relation relation); /* Lock a relation */ -extern void LockRelationOid(Oid relid, LOCKMODE lockmode); +extern bool LockRelationOid(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); -- 2.11.0
From 2c9a0f7d81f69bb5faafbe1d552aeb0cad6be8d5 Mon Sep 17 00:00:00 2001 From: amit <amitlangot...@gmail.com> Date: Mon, 13 Aug 2018 16:10:19 +0900 Subject: [PATCH v2 2/4] Remove useless fields from planner nodes They were added so that executor could identify range table entries entries to lock them or to impose order on locking during executor initialization, but turns out that executor doesn't take any locks of its own on the relations, so these fields are redundant. Following fields are removed: * 'partitioned_rels' from Append, MergeAppend, and ModifyTable. Actually, in ModifyTable, it is replaced by a single Index field called 'rootRelation', because we still need to refer to root partitioned table for constructing a ResultRelInfo needed for processing its statement triggers. * 'nonleafResultRelations' from PlannedStmt and PlannerGlobal. * 'rowMarks' from PlannedStmt and 'finalrowmarks' from PlannerGlobal. In PlannedStmt, it is replaced by a bool hasRowMarks that stores if query->rowMarks != NIL. --- src/backend/commands/portalcmds.c | 2 +- src/backend/executor/execMain.c | 2 +- src/backend/executor/execParallel.c | 3 +- src/backend/executor/execUtils.c | 55 --------------------------------- src/backend/executor/nodeAppend.c | 6 ---- src/backend/executor/nodeMergeAppend.c | 6 ---- src/backend/executor/nodeModifyTable.c | 7 ++--- src/backend/executor/spi.c | 4 +-- src/backend/nodes/copyfuncs.c | 7 ++--- src/backend/nodes/outfuncs.c | 11 ++----- src/backend/nodes/readfuncs.c | 7 ++--- src/backend/optimizer/plan/createplan.c | 42 +++++-------------------- src/backend/optimizer/plan/planner.c | 39 +++-------------------- src/backend/optimizer/plan/setrefs.c | 49 ++++------------------------- src/backend/optimizer/util/pathnode.c | 8 ++--- src/backend/tcop/utility.c | 15 +++++++-- src/include/executor/executor.h | 2 -- src/include/nodes/plannodes.h | 26 ++++------------ src/include/nodes/relation.h | 6 +--- src/include/optimizer/pathnode.h | 2 +- 20 files changed, 56 insertions(+), 243 deletions(-) diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c index 568499761f..4b213a8db7 100644 --- a/src/backend/commands/portalcmds.c +++ b/src/backend/commands/portalcmds.c @@ -133,7 +133,7 @@ PerformCursorOpen(DeclareCursorStmt *cstmt, ParamListInfo params, portal->cursorOptions = cstmt->options; if (!(portal->cursorOptions & (CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL))) { - if (plan->rowMarks == NIL && + if (!plan->hasRowMarks && ExecSupportsBackwardScan(plan->planTree)) portal->cursorOptions |= CURSOR_OPT_SCROLL; else diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 298bf43fce..5e0c2b8e67 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -217,7 +217,7 @@ standard_ExecutorStart(QueryDesc *queryDesc, int eflags) * SELECT FOR [KEY] UPDATE/SHARE and modifying CTEs need to mark * tuples */ - if (queryDesc->plannedstmt->rowMarks != NIL || + if (queryDesc->plannedstmt->hasRowMarks || queryDesc->plannedstmt->hasModifyingCTE) estate->es_output_cid = GetCurrentCommandId(true); diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c index ee0f07a81e..7afcd5b6c0 100644 --- a/src/backend/executor/execParallel.c +++ b/src/backend/executor/execParallel.c @@ -174,6 +174,7 @@ ExecSerializePlan(Plan *plan, EState *estate) pstmt->queryId = UINT64CONST(0); pstmt->hasReturning = false; pstmt->hasModifyingCTE = false; + pstmt->hasRowMarks = false; pstmt->canSetTag = true; pstmt->transientPlan = false; pstmt->dependsOnRole = false; @@ -181,7 +182,6 @@ ExecSerializePlan(Plan *plan, EState *estate) pstmt->planTree = plan; pstmt->rtable = estate->es_range_table; pstmt->resultRelations = NIL; - pstmt->nonleafResultRelations = NIL; /* * Transfer only parallel-safe subplans, leaving a NULL "hole" in the list @@ -201,7 +201,6 @@ ExecSerializePlan(Plan *plan, EState *estate) } pstmt->rewindPlanIDs = NULL; - pstmt->rowMarks = NIL; pstmt->relationOids = NIL; pstmt->invalItems = NIL; /* workers can't replan anyway... */ pstmt->paramExecTypes = estate->es_plannedstmt->paramExecTypes; diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 09942b34fb..d32796aac3 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -848,61 +848,6 @@ ShutdownExprContext(ExprContext *econtext, bool isCommit) } /* - * ExecLockNonLeafAppendTables - * - * Locks, if necessary, the tables indicated by the RT indexes contained in - * the partitioned_rels list. These are the non-leaf tables in the partition - * tree controlled by a given Append or MergeAppend node. - */ -void -ExecLockNonLeafAppendTables(List *partitioned_rels, EState *estate) -{ - PlannedStmt *stmt = estate->es_plannedstmt; - ListCell *lc; - - foreach(lc, partitioned_rels) - { - ListCell *l; - Index rti = lfirst_int(lc); - bool is_result_rel = false; - Oid relid = getrelid(rti, estate->es_range_table); - - /* If this is a result relation, already locked in InitPlan */ - foreach(l, stmt->nonleafResultRelations) - { - if (rti == lfirst_int(l)) - { - is_result_rel = true; - break; - } - } - - /* - * Not a result relation; check if there is a RowMark that requires - * taking a RowShareLock on this rel. - */ - if (!is_result_rel) - { - PlanRowMark *rc = NULL; - - foreach(l, stmt->rowMarks) - { - if (((PlanRowMark *) lfirst(l))->rti == rti) - { - rc = lfirst(l); - break; - } - } - - if (rc && RowMarkRequiresRowShareLock(rc->markType)) - LockRelationOid(relid, RowShareLock); - else - LockRelationOid(relid, AccessShareLock); - } - } -} - -/* * GetAttributeByName * GetAttributeByNum * diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c index f08dfcbcf0..eb587be221 100644 --- a/src/backend/executor/nodeAppend.c +++ b/src/backend/executor/nodeAppend.c @@ -113,12 +113,6 @@ ExecInitAppend(Append *node, EState *estate, int eflags) Assert(!(eflags & EXEC_FLAG_MARK)); /* - * Lock the non-leaf tables in the partition tree controlled by this node. - * It's a no-op for non-partitioned parent tables. - */ - ExecLockNonLeafAppendTables(node->partitioned_rels, estate); - - /* * create new AppendState for our append node */ appendstate->ps.plan = (Plan *) node; diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c index 9a72d3a0ac..d8e0978966 100644 --- a/src/backend/executor/nodeMergeAppend.c +++ b/src/backend/executor/nodeMergeAppend.c @@ -76,12 +76,6 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags) Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); /* - * Lock the non-leaf tables in the partition tree controlled by this node. - * It's a no-op for non-partitioned parent tables. - */ - ExecLockNonLeafAppendTables(node->partitioned_rels, estate); - - /* * create new MergeAppendState for our node */ mergestate->ps.plan = (Plan *) node; diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 93e5bf7af6..fd3966d489 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -2255,17 +2255,16 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) /* If modifying a partitioned table, initialize the root table info */ if (node->rootResultRelIndex >= 0) { - Index root_rt_index = linitial_int(node->partitioned_rels); RangeTblEntry *rte; Relation rel; mtstate->rootResultRelInfo = estate->es_root_result_relations + node->rootResultRelIndex; - Assert(root_rt_index > 0); - rte = rt_fetch(root_rt_index, estate->es_range_table); + Assert(node->rootRelation > 0); + rte = rt_fetch(node->rootRelation, estate->es_range_table); rel = heap_open(rte->relid, NoLock); - InitResultRelInfo(mtstate->rootResultRelInfo, rel, root_rt_index, + InitResultRelInfo(mtstate->rootResultRelInfo, rel, node->rootRelation, NULL, estate->es_instrument); } diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 5756365c8f..b3664e2f3f 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -1334,7 +1334,7 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, { if (list_length(stmt_list) == 1 && linitial_node(PlannedStmt, stmt_list)->commandType != CMD_UTILITY && - linitial_node(PlannedStmt, stmt_list)->rowMarks == NIL && + !linitial_node(PlannedStmt, stmt_list)->hasRowMarks && ExecSupportsBackwardScan(linitial_node(PlannedStmt, stmt_list)->planTree)) portal->cursorOptions |= CURSOR_OPT_SCROLL; else @@ -1350,7 +1350,7 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, { if (list_length(stmt_list) == 1 && linitial_node(PlannedStmt, stmt_list)->commandType != CMD_UTILITY && - linitial_node(PlannedStmt, stmt_list)->rowMarks != NIL) + linitial_node(PlannedStmt, stmt_list)->hasRowMarks) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("DECLARE SCROLL CURSOR ... FOR UPDATE/SHARE is not supported"), diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 6d685db0ea..29abe56b70 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -83,6 +83,7 @@ _copyPlannedStmt(const PlannedStmt *from) COPY_SCALAR_FIELD(queryId); COPY_SCALAR_FIELD(hasReturning); COPY_SCALAR_FIELD(hasModifyingCTE); + COPY_SCALAR_FIELD(hasRowMarks); COPY_SCALAR_FIELD(canSetTag); COPY_SCALAR_FIELD(transientPlan); COPY_SCALAR_FIELD(dependsOnRole); @@ -91,11 +92,9 @@ _copyPlannedStmt(const PlannedStmt *from) COPY_NODE_FIELD(planTree); COPY_NODE_FIELD(rtable); COPY_NODE_FIELD(resultRelations); - COPY_NODE_FIELD(nonleafResultRelations); COPY_NODE_FIELD(rootResultRelations); COPY_NODE_FIELD(subplans); COPY_BITMAPSET_FIELD(rewindPlanIDs); - COPY_NODE_FIELD(rowMarks); COPY_NODE_FIELD(relationOids); COPY_NODE_FIELD(invalItems); COPY_NODE_FIELD(paramExecTypes); @@ -204,7 +203,7 @@ _copyModifyTable(const ModifyTable *from) COPY_SCALAR_FIELD(operation); COPY_SCALAR_FIELD(canSetTag); COPY_SCALAR_FIELD(nominalRelation); - COPY_NODE_FIELD(partitioned_rels); + COPY_SCALAR_FIELD(rootRelation); COPY_SCALAR_FIELD(partColsUpdated); COPY_NODE_FIELD(resultRelations); COPY_SCALAR_FIELD(resultRelIndex); @@ -244,7 +243,6 @@ _copyAppend(const Append *from) */ COPY_NODE_FIELD(appendplans); COPY_SCALAR_FIELD(first_partial_plan); - COPY_NODE_FIELD(partitioned_rels); COPY_NODE_FIELD(part_prune_info); return newnode; @@ -266,7 +264,6 @@ _copyMergeAppend(const MergeAppend *from) /* * copy remainder of node */ - COPY_NODE_FIELD(partitioned_rels); COPY_NODE_FIELD(mergeplans); COPY_SCALAR_FIELD(numCols); COPY_POINTER_FIELD(sortColIdx, from->numCols * sizeof(AttrNumber)); diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 53f209e170..ac1e434ce5 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -268,6 +268,7 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node) WRITE_UINT64_FIELD(queryId); WRITE_BOOL_FIELD(hasReturning); WRITE_BOOL_FIELD(hasModifyingCTE); + WRITE_BOOL_FIELD(hasRowMarks); WRITE_BOOL_FIELD(canSetTag); WRITE_BOOL_FIELD(transientPlan); WRITE_BOOL_FIELD(dependsOnRole); @@ -276,11 +277,9 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node) WRITE_NODE_FIELD(planTree); WRITE_NODE_FIELD(rtable); WRITE_NODE_FIELD(resultRelations); - WRITE_NODE_FIELD(nonleafResultRelations); WRITE_NODE_FIELD(rootResultRelations); WRITE_NODE_FIELD(subplans); WRITE_BITMAPSET_FIELD(rewindPlanIDs); - WRITE_NODE_FIELD(rowMarks); WRITE_NODE_FIELD(relationOids); WRITE_NODE_FIELD(invalItems); WRITE_NODE_FIELD(paramExecTypes); @@ -372,7 +371,7 @@ _outModifyTable(StringInfo str, const ModifyTable *node) WRITE_ENUM_FIELD(operation, CmdType); WRITE_BOOL_FIELD(canSetTag); WRITE_UINT_FIELD(nominalRelation); - WRITE_NODE_FIELD(partitioned_rels); + WRITE_UINT_FIELD(rootRelation); WRITE_BOOL_FIELD(partColsUpdated); WRITE_NODE_FIELD(resultRelations); WRITE_INT_FIELD(resultRelIndex); @@ -401,7 +400,6 @@ _outAppend(StringInfo str, const Append *node) WRITE_NODE_FIELD(appendplans); WRITE_INT_FIELD(first_partial_plan); - WRITE_NODE_FIELD(partitioned_rels); WRITE_NODE_FIELD(part_prune_info); } @@ -414,7 +412,6 @@ _outMergeAppend(StringInfo str, const MergeAppend *node) _outPlanInfo(str, (const Plan *) node); - WRITE_NODE_FIELD(partitioned_rels); WRITE_NODE_FIELD(mergeplans); WRITE_INT_FIELD(numCols); @@ -2175,7 +2172,7 @@ _outModifyTablePath(StringInfo str, const ModifyTablePath *node) WRITE_ENUM_FIELD(operation, CmdType); WRITE_BOOL_FIELD(canSetTag); WRITE_UINT_FIELD(nominalRelation); - WRITE_NODE_FIELD(partitioned_rels); + WRITE_UINT_FIELD(rootRelation); WRITE_BOOL_FIELD(partColsUpdated); WRITE_NODE_FIELD(resultRelations); WRITE_NODE_FIELD(subpaths); @@ -2253,9 +2250,7 @@ _outPlannerGlobal(StringInfo str, const PlannerGlobal *node) WRITE_NODE_FIELD(subplans); WRITE_BITMAPSET_FIELD(rewindPlanIDs); WRITE_NODE_FIELD(finalrtable); - WRITE_NODE_FIELD(finalrowmarks); WRITE_NODE_FIELD(resultRelations); - WRITE_NODE_FIELD(nonleafResultRelations); WRITE_NODE_FIELD(rootResultRelations); WRITE_NODE_FIELD(relationOids); WRITE_NODE_FIELD(invalItems); diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 7a1e839ef4..780d261edf 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -1476,6 +1476,7 @@ _readPlannedStmt(void) READ_UINT64_FIELD(queryId); READ_BOOL_FIELD(hasReturning); READ_BOOL_FIELD(hasModifyingCTE); + READ_BOOL_FIELD(hasRowMarks); READ_BOOL_FIELD(canSetTag); READ_BOOL_FIELD(transientPlan); READ_BOOL_FIELD(dependsOnRole); @@ -1484,11 +1485,9 @@ _readPlannedStmt(void) READ_NODE_FIELD(planTree); READ_NODE_FIELD(rtable); READ_NODE_FIELD(resultRelations); - READ_NODE_FIELD(nonleafResultRelations); READ_NODE_FIELD(rootResultRelations); READ_NODE_FIELD(subplans); READ_BITMAPSET_FIELD(rewindPlanIDs); - READ_NODE_FIELD(rowMarks); READ_NODE_FIELD(relationOids); READ_NODE_FIELD(invalItems); READ_NODE_FIELD(paramExecTypes); @@ -1578,7 +1577,7 @@ _readModifyTable(void) READ_ENUM_FIELD(operation, CmdType); READ_BOOL_FIELD(canSetTag); READ_UINT_FIELD(nominalRelation); - READ_NODE_FIELD(partitioned_rels); + READ_UINT_FIELD(rootRelation); READ_BOOL_FIELD(partColsUpdated); READ_NODE_FIELD(resultRelations); READ_INT_FIELD(resultRelIndex); @@ -1612,7 +1611,6 @@ _readAppend(void) READ_NODE_FIELD(appendplans); READ_INT_FIELD(first_partial_plan); - READ_NODE_FIELD(partitioned_rels); READ_NODE_FIELD(part_prune_info); READ_DONE(); @@ -1628,7 +1626,6 @@ _readMergeAppend(void) ReadCommonPlan(&local_node->plan); - READ_NODE_FIELD(partitioned_rels); READ_NODE_FIELD(mergeplans); READ_INT_FIELD(numCols); READ_ATTRNUMBER_ARRAY(sortColIdx, local_node->numCols); diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index ae41c9efa0..ae46b0140e 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -124,7 +124,6 @@ static BitmapHeapScan *create_bitmap_scan_plan(PlannerInfo *root, static Plan *create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual, List **qual, List **indexqual, List **indexECs); static void bitmap_subplan_mark_shared(Plan *plan); -static List *flatten_partitioned_rels(List *partitioned_rels); static TidScan *create_tidscan_plan(PlannerInfo *root, TidPath *best_path, List *tlist, List *scan_clauses); static SubqueryScan *create_subqueryscan_plan(PlannerInfo *root, @@ -203,8 +202,7 @@ static NamedTuplestoreScan *make_namedtuplestorescan(List *qptlist, List *qpqual static WorkTableScan *make_worktablescan(List *qptlist, List *qpqual, Index scanrelid, int wtParam); static Append *make_append(List *appendplans, int first_partial_plan, - List *tlist, List *partitioned_rels, - PartitionPruneInfo *partpruneinfo); + List *tlist, PartitionPruneInfo *partpruneinfo); static RecursiveUnion *make_recursive_union(List *tlist, Plan *lefttree, Plan *righttree, @@ -280,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, List *partitioned_rels, + Index nominalRelation, Index rootRelation, bool partColsUpdated, List *resultRelations, List *subplans, List *subroots, List *withCheckOptionLists, List *returningLists, @@ -1110,8 +1108,7 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path) */ plan = make_append(subplans, best_path->first_partial_path, - tlist, best_path->partitioned_rels, - partpruneinfo); + tlist, partpruneinfo); copy_generic_path_info(&plan->plan, (Path *) best_path); @@ -1253,8 +1250,6 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path) prunequal); } - node->partitioned_rels = - flatten_partitioned_rels(best_path->partitioned_rels); node->mergeplans = subplans; node->part_prune_info = partpruneinfo; @@ -2411,7 +2406,7 @@ create_modifytable_plan(PlannerInfo *root, ModifyTablePath *best_path) best_path->operation, best_path->canSetTag, best_path->nominalRelation, - best_path->partitioned_rels, + best_path->rootRelation, best_path->partColsUpdated, best_path->resultRelations, subplans, @@ -5005,27 +5000,6 @@ bitmap_subplan_mark_shared(Plan *plan) elog(ERROR, "unrecognized node type: %d", nodeTag(plan)); } -/* - * flatten_partitioned_rels - * Convert List of Lists into a single List with all elements from the - * sub-lists. - */ -static List * -flatten_partitioned_rels(List *partitioned_rels) -{ - List *newlist = NIL; - ListCell *lc; - - foreach(lc, partitioned_rels) - { - List *sublist = lfirst(lc); - - newlist = list_concat(newlist, list_copy(sublist)); - } - - return newlist; -} - /***************************************************************************** * * PLAN NODE BUILDING ROUTINES @@ -5368,8 +5342,7 @@ make_foreignscan(List *qptlist, static Append * make_append(List *appendplans, int first_partial_plan, - List *tlist, List *partitioned_rels, - PartitionPruneInfo *partpruneinfo) + List *tlist, PartitionPruneInfo *partpruneinfo) { Append *node = makeNode(Append); Plan *plan = &node->plan; @@ -5380,7 +5353,6 @@ make_append(List *appendplans, int first_partial_plan, plan->righttree = NULL; node->appendplans = appendplans; node->first_partial_plan = first_partial_plan; - node->partitioned_rels = flatten_partitioned_rels(partitioned_rels); node->part_prune_info = partpruneinfo; return node; } @@ -6509,7 +6481,7 @@ make_project_set(List *tlist, static ModifyTable * make_modifytable(PlannerInfo *root, CmdType operation, bool canSetTag, - Index nominalRelation, List *partitioned_rels, + Index nominalRelation, Index rootRelation, bool partColsUpdated, List *resultRelations, List *subplans, List *subroots, List *withCheckOptionLists, List *returningLists, @@ -6538,7 +6510,7 @@ make_modifytable(PlannerInfo *root, node->operation = operation; node->canSetTag = canSetTag; node->nominalRelation = nominalRelation; - node->partitioned_rels = flatten_partitioned_rels(partitioned_rels); + node->rootRelation = rootRelation; node->partColsUpdated = partColsUpdated; node->resultRelations = resultRelations; node->resultRelIndex = -1; /* will be set correctly in setrefs.c */ diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 96bf0601a8..34fbc37702 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -290,9 +290,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) glob->subroots = NIL; glob->rewindPlanIDs = NULL; glob->finalrtable = NIL; - glob->finalrowmarks = NIL; glob->resultRelations = NIL; - glob->nonleafResultRelations = NIL; glob->rootResultRelations = NIL; glob->relationOids = NIL; glob->invalItems = NIL; @@ -490,9 +488,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) /* final cleanup of the plan */ Assert(glob->finalrtable == NIL); - Assert(glob->finalrowmarks == NIL); Assert(glob->resultRelations == NIL); - Assert(glob->nonleafResultRelations == NIL); Assert(glob->rootResultRelations == NIL); top_plan = set_plan_references(root, top_plan); /* ... and the subplans (both regular subplans and initplans) */ @@ -512,6 +508,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) result->queryId = parse->queryId; result->hasReturning = (parse->returningList != NIL); result->hasModifyingCTE = parse->hasModifyingCTE; + result->hasRowMarks = (parse->rowMarks != NIL); result->canSetTag = parse->canSetTag; result->transientPlan = glob->transientPlan; result->dependsOnRole = glob->dependsOnRole; @@ -519,11 +516,9 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) result->planTree = top_plan; result->rtable = glob->finalrtable; result->resultRelations = glob->resultRelations; - result->nonleafResultRelations = glob->nonleafResultRelations; result->rootResultRelations = glob->rootResultRelations; result->subplans = glob->subplans; result->rewindPlanIDs = glob->rewindPlanIDs; - result->rowMarks = glob->finalrowmarks; result->relationOids = glob->relationOids; result->invalItems = glob->invalItems; result->paramExecTypes = glob->paramExecTypes; @@ -1174,7 +1169,7 @@ inheritance_planner(PlannerInfo *root) Index rti; RangeTblEntry *parent_rte; Relids partitioned_relids = NULL; - List *partitioned_rels = NIL; + Index rootRelation = 0; PlannerInfo *parent_root; Query *parent_parse; Bitmapset *parent_relids = bms_make_singleton(top_parentRTindex); @@ -1248,15 +1243,7 @@ inheritance_planner(PlannerInfo *root) */ parent_rte = rt_fetch(top_parentRTindex, root->parse->rtable); if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE) - { - nominalRelation = top_parentRTindex; - - /* - * Root parent's RT index is always present in the partitioned_rels of - * the ModifyTable node, if one is needed at all. - */ - partitioned_relids = bms_make_singleton(top_parentRTindex); - } + nominalRelation = rootRelation = top_parentRTindex; /* * The PlannerInfo for each child is obtained by translating the relevant @@ -1609,29 +1596,13 @@ inheritance_planner(PlannerInfo *root) else rowMarks = root->rowMarks; - if (partitioned_relids) - { - int i; - - i = -1; - while ((i = bms_next_member(partitioned_relids, i)) >= 0) - partitioned_rels = lappend_int(partitioned_rels, i); - - /* - * If we're going to create ModifyTable at all, the list should - * contain at least one member, that is, the root parent's index. - */ - Assert(list_length(partitioned_rels) >= 1); - partitioned_rels = list_make1(partitioned_rels); - } - /* 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, - partitioned_rels, + rootRelation, root->partColsUpdated, resultRelations, subpaths, @@ -2208,7 +2179,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, parse->commandType, parse->canSetTag, parse->resultRelation, - NIL, + 0, false, list_make1_int(parse->resultRelation), list_make1(path), diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index f66f39d8c6..f516b3a85c 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -211,7 +211,6 @@ set_plan_references(PlannerInfo *root, Plan *plan) { PlannerGlobal *glob = root->glob; int rtoffset = list_length(glob->finalrtable); - ListCell *lc; /* * Add all the query's RTEs to the flattened rangetable. The live ones @@ -220,25 +219,6 @@ set_plan_references(PlannerInfo *root, Plan *plan) */ add_rtes_to_flat_rtable(root, false); - /* - * Adjust RT indexes of PlanRowMarks and add to final rowmarks list - */ - foreach(lc, root->rowMarks) - { - PlanRowMark *rc = lfirst_node(PlanRowMark, lc); - PlanRowMark *newrc; - - /* flat copy is enough since all fields are scalars */ - newrc = (PlanRowMark *) palloc(sizeof(PlanRowMark)); - memcpy(newrc, rc, sizeof(PlanRowMark)); - - /* adjust indexes ... but *not* the rowmarkId */ - newrc->rti += rtoffset; - newrc->prti += rtoffset; - - glob->finalrowmarks = lappend(glob->finalrowmarks, newrc); - } - /* Now fix the Plan tree */ return set_plan_refs(root, plan, rtoffset); } @@ -848,12 +828,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) } splan->nominalRelation += rtoffset; + if (splan->rootRelation > 0) + splan->rootRelation += rtoffset; splan->exclRelRTI += rtoffset; - foreach(l, splan->partitioned_rels) - { - lfirst_int(l) += rtoffset; - } foreach(l, splan->resultRelations) { lfirst_int(l) += rtoffset; @@ -884,24 +862,17 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) list_copy(splan->resultRelations)); /* - * If the main target relation is a partitioned table, the - * following list contains the RT indexes of partitioned child - * relations including the root, which are not included in the - * above list. We also keep RT indexes of the roots - * separately to be identified as such during the executor - * initialization. + * If the main target relation is a partitioned table, remember + * the root table's RT index. */ - if (splan->partitioned_rels != NIL) + if (splan->rootRelation > 0) { - root->glob->nonleafResultRelations = - list_concat(root->glob->nonleafResultRelations, - list_copy(splan->partitioned_rels)); /* Remember where this root will be in the global list. */ splan->rootResultRelIndex = list_length(root->glob->rootResultRelations); root->glob->rootResultRelations = lappend_int(root->glob->rootResultRelations, - linitial_int(splan->partitioned_rels)); + splan->rootRelation); } } break; @@ -915,10 +886,6 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) */ set_dummy_tlist_references(plan, rtoffset); Assert(splan->plan.qual == NIL); - foreach(l, splan->partitioned_rels) - { - lfirst_int(l) += rtoffset; - } foreach(l, splan->appendplans) { lfirst(l) = set_plan_refs(root, @@ -937,10 +904,6 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) */ set_dummy_tlist_references(plan, rtoffset); Assert(splan->plan.qual == NIL); - foreach(l, splan->partitioned_rels) - { - lfirst_int(l) += rtoffset; - } foreach(l, splan->mergeplans) { lfirst(l) = set_plan_refs(root, diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index c5aaaf5c22..4983e500ac 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -3292,9 +3292,7 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel, * '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 - * 'partitioned_rels' is an integer list of RT indexes of non-leaf tables in - * the partition tree, if this is an UPDATE/DELETE to a partitioned table. - * Otherwise NIL. + * 'rootRelation' is the RT index of the root 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) @@ -3309,7 +3307,7 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel, ModifyTablePath * create_modifytable_path(PlannerInfo *root, RelOptInfo *rel, CmdType operation, bool canSetTag, - Index nominalRelation, List *partitioned_rels, + Index nominalRelation, Index rootRelation, bool partColsUpdated, List *resultRelations, List *subpaths, List *subroots, @@ -3377,7 +3375,7 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel, pathnode->operation = operation; pathnode->canSetTag = canSetTag; pathnode->nominalRelation = nominalRelation; - pathnode->partitioned_rels = list_copy(partitioned_rels); + pathnode->rootRelation = rootRelation; pathnode->partColsUpdated = partColsUpdated; pathnode->resultRelations = resultRelations; pathnode->subpaths = subpaths; diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index b5804f64ad..72cf99c79e 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -103,7 +103,7 @@ CommandIsReadOnly(PlannedStmt *pstmt) switch (pstmt->commandType) { case CMD_SELECT: - if (pstmt->rowMarks != NIL) + if (pstmt->hasRowMarks) return false; /* SELECT FOR [KEY] UPDATE/SHARE */ else if (pstmt->hasModifyingCTE) return false; /* data-modifying CTE */ @@ -2809,10 +2809,19 @@ CreateCommandTag(Node *parsetree) * will be useful for complaints about read-only * statements */ - if (stmt->rowMarks != NIL) + if (stmt->hasRowMarks) { + List *rowMarks; + + /* Top-level Plan must be LockRows or ModifyTable */ + Assert(IsA(stmt->planTree, LockRows) || + IsA(stmt->planTree, ModifyTable)); + if (IsA(stmt->planTree, LockRows)) + rowMarks = ((LockRows *) stmt->planTree)->rowMarks; + else if (IsA(stmt->planTree, ModifyTable)) + rowMarks = ((ModifyTable *) stmt->planTree)->rowMarks; /* not 100% but probably close enough */ - switch (((PlanRowMark *) linitial(stmt->rowMarks))->strength) + switch (((PlanRowMark *) linitial(rowMarks))->strength) { case LCS_FORKEYSHARE: tag = "SELECT FOR KEY SHARE"; diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 4425b978f9..1d2b48fe09 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -524,8 +524,6 @@ extern void UnregisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg); -extern void ExecLockNonLeafAppendTables(List *partitioned_rels, EState *estate); - extern Datum GetAttributeByName(HeapTupleHeader tuple, const char *attname, bool *isNull); extern Datum GetAttributeByNum(HeapTupleHeader tuple, AttrNumber attrno, diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 7c2abbd03a..a342edf49c 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -51,6 +51,8 @@ typedef struct PlannedStmt bool hasModifyingCTE; /* has insert|update|delete in WITH? */ + bool hasRowMarks; /* has FOR UPDATE/SHARE? */ + bool canSetTag; /* do I set the command result tag? */ bool transientPlan; /* redo plan when TransactionXmin changes? */ @@ -69,15 +71,8 @@ typedef struct PlannedStmt List *resultRelations; /* integer list of RT indexes, or NIL */ /* - * rtable indexes of non-leaf target relations for UPDATE/DELETE on all - * the partitioned tables mentioned in the query. - */ - List *nonleafResultRelations; - - /* - * rtable indexes of root target relations for UPDATE/DELETE; this list - * maintains a subset of the RT indexes in nonleafResultRelations, - * indicating the roots of the respective partition hierarchies. + * rtable indexes of root partitioned tables that are UPDATE/DELETE + * targets */ List *rootResultRelations; @@ -86,8 +81,6 @@ typedef struct PlannedStmt Bitmapset *rewindPlanIDs; /* indices of subplans that require REWIND */ - List *rowMarks; /* a list of PlanRowMark's */ - List *relationOids; /* OIDs of relations the plan depends on */ List *invalItems; /* other dependencies, as PlanInvalItems */ @@ -220,8 +213,7 @@ typedef struct ModifyTable CmdType operation; /* INSERT, UPDATE, or DELETE */ bool canSetTag; /* do we set the command tag/es_processed? */ Index nominalRelation; /* Parent RT index for use of EXPLAIN */ - /* RT indexes of non-leaf tables in a partition tree */ - List *partitioned_rels; + Index rootRelation; /* RT index of root partitioned table */ bool partColsUpdated; /* some part key in hierarchy updated */ List *resultRelations; /* integer list of RT indexes */ int resultRelIndex; /* index of first resultRel in plan's list */ @@ -259,9 +251,6 @@ typedef struct Append */ int first_partial_plan; - /* RT indexes of non-leaf tables in a partition tree */ - List *partitioned_rels; - /* Info for run-time subplan pruning; NULL if we're not doing that */ struct PartitionPruneInfo *part_prune_info; } Append; @@ -274,8 +263,6 @@ typedef struct Append typedef struct MergeAppend { Plan plan; - /* RT indexes of non-leaf tables in a partition tree */ - List *partitioned_rels; List *mergeplans; /* remaining fields are just like the sort-key info in struct Sort */ int numCols; /* number of sort-key columns */ @@ -927,8 +914,7 @@ typedef struct SetOp /* ---------------- * lock-rows node * - * rowMarks identifies the rels to be locked by this node; it should be - * a subset of the rowMarks listed in the top-level PlannedStmt. + * rowMarks identifies the rels to be locked by this node. * epqParam is a Param that all scan nodes below this one must depend on. * It is used to force re-evaluation of the plan during EvalPlanQual. * ---------------- diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index adb4265047..f9d23305fb 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -117,11 +117,8 @@ typedef struct PlannerGlobal List *finalrtable; /* "flat" rangetable for executor */ - List *finalrowmarks; /* "flat" list of PlanRowMarks */ - List *resultRelations; /* "flat" list of integer RT indexes */ - List *nonleafResultRelations; /* "flat" list of integer RT indexes */ List *rootResultRelations; /* "flat" list of integer RT indexes */ List *relationOids; /* OIDs of relations the plan depends on */ @@ -1717,8 +1714,7 @@ typedef struct ModifyTablePath CmdType operation; /* INSERT, UPDATE, or DELETE */ bool canSetTag; /* do we set the command tag/es_processed? */ Index nominalRelation; /* Parent RT index for use of EXPLAIN */ - /* RT indexes of non-leaf tables in a partition tree */ - List *partitioned_rels; + Index rootRelation; /* RT index of root partitioned table */ bool partColsUpdated; /* some part key in hierarchy updated */ List *resultRelations; /* integer list of RT indexes */ List *subpaths; /* Path(s) producing source data */ diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h index 7c5ff22650..81abcf53a8 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, List *partitioned_rels, + Index nominalRelation, Index rootRelation, bool partColsUpdated, List *resultRelations, List *subpaths, List *subroots, -- 2.11.0
From a2aab818dd94db0d78c73ecfda4134a80dbed043 Mon Sep 17 00:00:00 2001 From: amit <amitlangot...@gmail.com> Date: Tue, 14 Aug 2018 10:35:47 +0900 Subject: [PATCH v2 3/4] Prune PlanRowMark of relations that are pruned from a plan --- src/backend/optimizer/plan/planner.c | 47 +++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 34fbc37702..3cca02c4a2 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -1594,7 +1594,19 @@ inheritance_planner(PlannerInfo *root) if (parse->rowMarks) rowMarks = NIL; else - rowMarks = root->rowMarks; + { + rowMarks = NIL; + foreach(lc, root->rowMarks) + { + PlanRowMark *rc = lfirst(lc); + + if (root->simple_rel_array[rc->rti] != NULL && + IS_DUMMY_REL(root->simple_rel_array[rc->rti])) + continue; + + rowMarks = lappend(rowMarks, rc); + } + } /* Create Path representing a ModifyTable to do the UPDATE/DELETE work */ add_path(final_rel, (Path *) @@ -2124,8 +2136,23 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, */ if (parse->rowMarks) { + ListCell *lc2; + List *rowMarks; + + rowMarks = NIL; + foreach(lc2, root->rowMarks) + { + PlanRowMark *rc = lfirst(lc2); + + if (root->simple_rel_array[rc->rti] != NULL && + IS_DUMMY_REL(root->simple_rel_array[rc->rti])) + continue; + + rowMarks = lappend(rowMarks, rc); + } + path = (Path *) create_lockrows_path(root, final_rel, path, - root->rowMarks, + rowMarks, SS_assign_special_param(root)); } @@ -2172,7 +2199,21 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, if (parse->rowMarks) rowMarks = NIL; else - rowMarks = root->rowMarks; + { + ListCell *lc2; + + rowMarks = NIL; + foreach(lc2, root->rowMarks) + { + PlanRowMark *rc = lfirst(lc2); + + if (root->simple_rel_array[rc->rti] != NULL && + IS_DUMMY_REL(root->simple_rel_array[rc->rti])) + continue; + + rowMarks = lappend(rowMarks, rc); + } + } path = (Path *) create_modifytable_path(root, final_rel, -- 2.11.0
From 36e2b0b58e0c7b1a1445a46be147881fe416a2dc Mon Sep 17 00:00:00 2001 From: amit <amitlangot...@gmail.com> Date: Thu, 19 Jul 2018 13:01:43 +0900 Subject: [PATCH v2 4/4] Revise executor range table relation opening/closing All requests to open range table relations in the executor now go through ExecRangeTableRelation(), which consults an array of Relation pointers indexed by RT index. To speed up retrieving range table entries at arbitrary points within the executor, this introduceds an array of RangeTblEntry pointers in EState. InitPlan builds it from the es_range_table list. This also revises PartitionedRelPruneInfo node to contain the partitioned table's RT index instead of OID. With that change, ExecCreatePartitionPruneState can use ExecRangeTableRelation described above. Authors: Amit Langote, David Rowley --- contrib/postgres_fdw/postgres_fdw.c | 12 ++++++------ src/backend/commands/copy.c | 12 +++++++++++- src/backend/commands/trigger.c | 3 ++- src/backend/executor/execExprInterp.c | 7 ++++--- src/backend/executor/execMain.c | 33 ++++++++++++++++++++------------ src/backend/executor/execPartition.c | 12 ++++++------ src/backend/executor/execUtils.c | 4 +--- src/backend/executor/nodeLockRows.c | 2 +- src/backend/executor/nodeModifyTable.c | 9 +++------ src/backend/nodes/copyfuncs.c | 2 +- src/backend/nodes/outfuncs.c | 2 +- src/backend/nodes/readfuncs.c | 2 +- src/backend/optimizer/plan/setrefs.c | 30 +++++++++++++++++++++++++++++ src/backend/partitioning/partprune.c | 5 +---- src/backend/replication/logical/worker.c | 3 ++- src/include/executor/executor.h | 28 +++++++++++++++++++++++++++ src/include/nodes/execnodes.h | 22 ++++++++++++++++++++- src/include/nodes/plannodes.h | 2 +- src/include/parser/parsetree.h | 10 ---------- 19 files changed, 141 insertions(+), 59 deletions(-) diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index e4e330397e..604e480d93 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -1345,7 +1345,7 @@ postgresBeginForeignScan(ForeignScanState *node, int eflags) rtindex = fsplan->scan.scanrelid; else rtindex = bms_next_member(fsplan->fs_relids, -1); - rte = rt_fetch(rtindex, estate->es_range_table); + rte = exec_rt_fetch(rtindex, estate->es_range_table_array); userid = rte->checkAsUser ? rte->checkAsUser : GetUserId(); /* Get info about foreign table. */ @@ -1732,8 +1732,8 @@ postgresBeginForeignModify(ModifyTableState *mtstate, FdwModifyPrivateRetrievedAttrs); /* Find RTE. */ - rte = rt_fetch(resultRelInfo->ri_RangeTableIndex, - mtstate->ps.state->es_range_table); + rte = exec_rt_fetch(resultRelInfo->ri_RangeTableIndex, + mtstate->ps.state->es_range_table_array); /* Construct an execution state. */ fmstate = create_foreign_modify(mtstate->ps.state, @@ -2037,7 +2037,7 @@ postgresBeginForeignInsert(ModifyTableState *mtstate, * correspond to this partition if it is one of the UPDATE subplan target * rels; in that case, we can just use the existing RTE as-is. */ - rte = list_nth(estate->es_range_table, resultRelation - 1); + rte = exec_rt_fetch(resultRelation, estate->es_range_table_array); if (rte->relid != RelationGetRelid(rel)) { rte = copyObject(rte); @@ -2397,7 +2397,7 @@ postgresBeginDirectModify(ForeignScanState *node, int eflags) * ExecCheckRTEPerms() does. */ rtindex = estate->es_result_relation_info->ri_RangeTableIndex; - rte = rt_fetch(rtindex, estate->es_range_table); + rte = exec_rt_fetch(rtindex, estate->es_range_table_array); userid = rte->checkAsUser ? rte->checkAsUser : GetUserId(); /* Get info about foreign table. */ @@ -5757,7 +5757,7 @@ conversion_error_callback(void *arg) RangeTblEntry *rte; Var *var = (Var *) tle->expr; - rte = rt_fetch(var->varno, estate->es_range_table); + rte = exec_rt_fetch(var->varno, estate->es_range_table_array); if (var->varattno == 0) is_wholerow = true; diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 9bc67ce60f..3dce6e7359 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -2333,6 +2333,8 @@ CopyFrom(CopyState cstate) bool has_before_insert_row_trig; bool has_instead_insert_row_trig; bool leafpart_use_multi_insert = false; + int i; + ListCell *lc; #define MAX_BUFFERED_TUPLES 1000 #define RECHECK_MULTI_INSERT_THRESHOLD 1000 @@ -2482,7 +2484,15 @@ CopyFrom(CopyState cstate) estate->es_result_relations = resultRelInfo; estate->es_num_result_relations = 1; estate->es_result_relation_info = resultRelInfo; - estate->es_range_table = cstate->range_table; + + estate->es_range_table_size = list_length(cstate->range_table); + estate->es_range_table_array = (RangeTblEntry **) + palloc(sizeof(RangeTblEntry *) * + estate->es_range_table_size); + /* Populate the range table array */ + i = 0; + foreach(lc, cstate->range_table) + estate->es_range_table_array[i++] = lfirst_node(RangeTblEntry, lc); /* Set up a tuple slot too */ myslot = ExecInitExtraTupleSlot(estate, tupDesc); diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 2436692eb8..e60fd5f1d7 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -75,7 +75,8 @@ static int MyTriggerDepth = 0; * to be changed, however. */ #define GetUpdatedColumns(relinfo, estate) \ - (rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->updatedCols) + (exec_rt_fetch((relinfo)->ri_RangeTableIndex,\ + (estate)->es_range_table_array)->updatedCols) /* Local function prototypes */ static void ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid); diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index 9d6e25aae5..5de1d01a94 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -3961,10 +3961,11 @@ ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext) * perhaps other places.) */ if (econtext->ecxt_estate && - variable->varno <= list_length(econtext->ecxt_estate->es_range_table)) + variable->varno <= econtext->ecxt_estate->es_range_table_size) { - RangeTblEntry *rte = rt_fetch(variable->varno, - econtext->ecxt_estate->es_range_table); + RangeTblEntry *rte = + exec_rt_fetch(variable->varno, + econtext->ecxt_estate->es_range_table_array); if (rte->eref) ExecTypeSetColNames(output_tupdesc, rte->eref->colnames); diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 5e0c2b8e67..a219a87483 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -109,9 +109,9 @@ static void EvalPlanQualStart(EPQState *epqstate, EState *parentestate, * to be changed, however. */ #define GetInsertedColumns(relinfo, estate) \ - (rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->insertedCols) + (exec_rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table_array)->insertedCols) #define GetUpdatedColumns(relinfo, estate) \ - (rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->updatedCols) + (exec_rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table_array)->updatedCols) /* end of local decls */ @@ -814,6 +814,7 @@ InitPlan(QueryDesc *queryDesc, int eflags) TupleDesc tupType; ListCell *l; int i; + int rti; /* * Do permissions checks @@ -844,6 +845,17 @@ InitPlan(QueryDesc *queryDesc, int eflags) * initialize the node's execution state */ estate->es_range_table = rangeTable; + estate->es_range_table_size = list_length(rangeTable); + estate->es_range_table_array = (RangeTblEntry **) + palloc(estate->es_range_table_size * + sizeof(RangeTblEntry *)); + estate->es_relations = (Relation *) palloc0(estate->es_range_table_size * + sizeof(Relation)); + /* Fill the RTEs, Relations array will be filled later. */ + rti = 0; + foreach(l, rangeTable) + estate->es_range_table_array[rti++] = lfirst_node(RangeTblEntry, l); + estate->es_plannedstmt = plannedstmt; /* @@ -2278,14 +2290,10 @@ ExecRowMark * ExecBuildRowMark(EState *estate, PlanRowMark *rc) { ExecRowMark *erm; - Oid relid; Relation relation; Assert(!rc->isParent); - /* get relation's OID (will produce InvalidOid if subquery) */ - relid = getrelid(rc->rti, estate->es_range_table); - /* * If you change the conditions under which rel locks are acquired * here, be sure to adjust ExecOpenScanRelation to match. @@ -2296,10 +2304,10 @@ ExecBuildRowMark(EState *estate, PlanRowMark *rc) case ROW_MARK_NOKEYEXCLUSIVE: case ROW_MARK_SHARE: case ROW_MARK_KEYSHARE: - relation = heap_open(relid, NoLock); + relation = ExecRangeTableRelation(estate, rc->rti); break; case ROW_MARK_REFERENCE: - relation = heap_open(relid, NoLock); + relation = ExecRangeTableRelation(estate, rc->rti); break; case ROW_MARK_COPY: /* no physical table access is required */ @@ -2317,7 +2325,7 @@ ExecBuildRowMark(EState *estate, PlanRowMark *rc) erm = (ExecRowMark *) palloc(sizeof(ExecRowMark)); erm->relation = relation; - erm->relid = relid; + erm->relid = exec_rt_fetch(rc->rti, estate->es_range_table_array)->relid; erm->rti = rc->rti; erm->prti = rc->prti; erm->rowmarkId = rc->rowmarkId; @@ -2975,7 +2983,7 @@ EvalPlanQualBegin(EPQState *epqstate, EState *parentestate) /* * We already have a suitable child EPQ tree, so just reset it. */ - int rtsize = list_length(parentestate->es_range_table); + int rtsize = parentestate->es_range_table_size; PlanState *planstate = epqstate->planstate; MemSet(estate->es_epqScanDone, 0, rtsize * sizeof(bool)); @@ -3020,7 +3028,7 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree) MemoryContext oldcontext; ListCell *l; - rtsize = list_length(parentestate->es_range_table); + rtsize = parentestate->es_range_table_size; epqstate->estate = estate = CreateExecutorState(); @@ -3043,7 +3051,8 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree) estate->es_direction = ForwardScanDirection; estate->es_snapshot = parentestate->es_snapshot; estate->es_crosscheck_snapshot = parentestate->es_crosscheck_snapshot; - estate->es_range_table = parentestate->es_range_table; + estate->es_range_table_array = parentestate->es_range_table_array; + estate->es_relations = parentestate->es_relations; estate->es_plannedstmt = parentestate->es_plannedstmt; estate->es_junkFilter = parentestate->es_junkFilter; estate->es_output_cid = parentestate->es_output_cid; diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index 81c2f5cedc..e56f090a2c 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -831,11 +831,10 @@ ExecCleanupTupleRouting(ModifyTableState *mtstate, int subplan_index = 0; /* - * Remember, proute->partition_dispatch_info[0] corresponds to the root - * partitioned table, which we must not try to close, because it is the - * main target table of the query that will be closed by callers such as - * ExecEndPlan() or DoCopy(). Also, tupslot is NULL for the root - * partitioned table. + * proute->partition_dispatch_info[0] corresponds to the root partitioned + * table, which is the main target table of the query, so it is closed by + * ExecEndModifyTable() or DoCopy(). Also, tupslot is NULL for the root + * partitioned table, so nothing to do here for the root table. */ for (i = 1; i < proute->num_dispatch; i++) { @@ -1432,6 +1431,7 @@ PartitionPruneState * ExecCreatePartitionPruneState(PlanState *planstate, PartitionPruneInfo *partitionpruneinfo) { + EState *estate = planstate->state; PartitionPruneState *prunestate; int n_part_hierarchies; ListCell *lc; @@ -1512,7 +1512,7 @@ ExecCreatePartitionPruneState(PlanState *planstate, * so that we can rely on its copies of the table's partition key * and partition descriptor. */ - context->partrel = relation_open(pinfo->reloid, NoLock); + context->partrel = ExecRangeTableRelation(estate, pinfo->rtindex); partkey = RelationGetPartitionKey(context->partrel); partdesc = RelationGetPartitionDesc(context->partrel); diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index d32796aac3..94acea245a 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -653,11 +653,9 @@ Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags) { Relation rel; - Oid reloid; /* Open the relation. */ - reloid = getrelid(scanrelid, estate->es_range_table); - rel = heap_open(reloid, NoLock); + rel = ExecRangeTableRelation(estate, scanrelid); /* * Complain if we're attempting a scan of an unscannable relation, except diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c index 8c80291a53..9e7c5e94cf 100644 --- a/src/backend/executor/nodeLockRows.c +++ b/src/backend/executor/nodeLockRows.c @@ -400,7 +400,7 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags) /* * Create workspace in which we can remember per-RTE locked tuples */ - lrstate->lr_ntables = list_length(estate->es_range_table); + lrstate->lr_ntables = estate->es_range_table_size; lrstate->lr_curtuples = (HeapTuple *) palloc0(lrstate->lr_ntables * sizeof(HeapTuple)); diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index fd3966d489..8c6c26d7d6 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -2243,10 +2243,9 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) foreach(l, node->resultRelations) { Index resultRelationIndex = lfirst_int(l); - RangeTblEntry *rte = rt_fetch(resultRelationIndex, - estate->es_range_table); - Relation rel = heap_open(rte->relid, NoLock); + Relation rel; + rel = ExecRangeTableRelation(estate, resultRelationIndex); InitResultRelInfo(resultRelInfo, rel, resultRelationIndex, NULL, estate->es_instrument); resultRelInfo++; @@ -2255,15 +2254,13 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) /* If modifying a partitioned table, initialize the root table info */ if (node->rootResultRelIndex >= 0) { - RangeTblEntry *rte; Relation rel; mtstate->rootResultRelInfo = estate->es_root_result_relations + node->rootResultRelIndex; Assert(node->rootRelation > 0); - rte = rt_fetch(node->rootRelation, estate->es_range_table); - rel = heap_open(rte->relid, NoLock); + rel = ExecRangeTableRelation(estate, node->rootRelation); InitResultRelInfo(mtstate->rootResultRelInfo, rel, node->rootRelation, NULL, estate->es_instrument); } diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 29abe56b70..478cd711cf 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -1190,7 +1190,7 @@ _copyPartitionedRelPruneInfo(const PartitionedRelPruneInfo *from) { PartitionedRelPruneInfo *newnode = makeNode(PartitionedRelPruneInfo); - COPY_SCALAR_FIELD(reloid); + COPY_SCALAR_FIELD(rtindex); COPY_NODE_FIELD(pruning_steps); COPY_BITMAPSET_FIELD(present_parts); COPY_SCALAR_FIELD(nparts); diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index ac1e434ce5..7589299c97 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -1025,7 +1025,7 @@ _outPartitionedRelPruneInfo(StringInfo str, const PartitionedRelPruneInfo *node) WRITE_NODE_TYPE("PARTITIONEDRELPRUNEINFO"); - WRITE_OID_FIELD(reloid); + WRITE_UINT_FIELD(rtindex); WRITE_NODE_FIELD(pruning_steps); WRITE_BITMAPSET_FIELD(present_parts); WRITE_INT_FIELD(nparts); diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 780d261edf..df80a31cc1 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -2338,7 +2338,7 @@ _readPartitionedRelPruneInfo(void) { READ_LOCALS(PartitionedRelPruneInfo); - READ_OID_FIELD(reloid); + READ_UINT_FIELD(rtindex); READ_NODE_FIELD(pruning_steps); READ_BITMAPSET_FIELD(present_parts); READ_INT_FIELD(nparts); diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index f516b3a85c..9990cc4155 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -892,6 +892,21 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) (Plan *) lfirst(l), rtoffset); } + if (splan->part_prune_info) + { + foreach(l, splan->part_prune_info->prune_infos) + { + List *prune_infos = lfirst(l); + ListCell *l2; + + foreach(l2, prune_infos) + { + PartitionedRelPruneInfo *pinfo = lfirst(l2); + + pinfo->rtindex += rtoffset; + } + } + } } break; case T_MergeAppend: @@ -910,6 +925,21 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) (Plan *) lfirst(l), rtoffset); } + if (splan->part_prune_info) + { + foreach(l, splan->part_prune_info->prune_infos) + { + List *prune_infos = lfirst(l); + ListCell *l2; + + foreach(l2, prune_infos) + { + PartitionedRelPruneInfo *pinfo = lfirst(l2); + + pinfo->rtindex += rtoffset; + } + } + } } break; case T_RecursiveUnion: diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index b5c1c7d4dd..c46b8166a6 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -357,7 +357,6 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, Index rti = lfirst_int(lc); RelOptInfo *subpart = find_base_rel(root, rti); PartitionedRelPruneInfo *pinfo; - RangeTblEntry *rte; Bitmapset *present_parts; int nparts = subpart->nparts; int partnatts = subpart->part_scheme->partnatts; @@ -459,10 +458,8 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, present_parts = bms_add_member(present_parts, i); } - rte = root->simple_rte_array[subpart->relid]; - pinfo = makeNode(PartitionedRelPruneInfo); - pinfo->reloid = rte->relid; + pinfo->rtindex = rti; pinfo->pruning_steps = pruning_steps; pinfo->present_parts = present_parts; pinfo->nparts = nparts; diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c index 2054abe653..5e7aa7c6c5 100644 --- a/src/backend/replication/logical/worker.c +++ b/src/backend/replication/logical/worker.c @@ -199,7 +199,8 @@ create_estate_for_relation(LogicalRepRelMapEntry *rel) rte->rtekind = RTE_RELATION; rte->relid = RelationGetRelid(rel->localrel); rte->relkind = rel->localrel->rd_rel->relkind; - estate->es_range_table = list_make1(rte); + estate->es_range_table_array = &rte; + estate->es_range_table_size = 1; resultRelInfo = makeNode(ResultRelInfo); InitResultRelInfo(resultRelInfo, rel->localrel, 1, NULL, 0); diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 1d2b48fe09..4752dcc9c7 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -17,6 +17,7 @@ #include "executor/execdesc.h" #include "nodes/parsenodes.h" #include "utils/memutils.h" +#include "utils/rel.h" /* @@ -568,4 +569,31 @@ extern void CheckCmdReplicaIdentity(Relation rel, CmdType cmd); extern void CheckSubscriptionRelkind(char relkind, const char *nspname, const char *relname); +#ifndef FRONTEND +static inline Relation +ExecRangeTableRelation(EState *estate, Index rti) +{ + RangeTblEntry *rte; + Relation rel; + + if (estate->es_relations[rti - 1] != NULL) + { + RelationIncrementReferenceCount(estate->es_relations[rti - 1]); + rel = estate->es_relations[rti - 1]; + } + else + { + 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. + */ + rel = estate->es_relations[rti - 1] = heap_open(rte->relid, NoLock); + } + + return rel; +} +#endif + #endif /* EXECUTOR_H */ diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index c830f141b1..966e2f3b62 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -20,6 +20,7 @@ #include "executor/instrument.h" #include "lib/pairingheap.h" #include "nodes/params.h" +#include "nodes/parsenodes.h" #include "nodes/plannodes.h" #include "utils/hsearch.h" #include "utils/queryenvironment.h" @@ -478,7 +479,10 @@ typedef struct EState ScanDirection es_direction; /* current scan direction */ Snapshot es_snapshot; /* time qual to use */ Snapshot es_crosscheck_snapshot; /* crosscheck time qual for RI */ - List *es_range_table; /* List of RangeTblEntry */ + 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 */ PlannedStmt *es_plannedstmt; /* link to top of plan tree */ const char *es_sourceText; /* Source text from QueryDesc */ @@ -573,7 +577,23 @@ typedef struct EState int es_jit_flags; struct JitContext *es_jit; } EState; + +/* + * exec_rt_fetch + * + * NB: this will crash and burn if handed an out-of-range RT index + */ +#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 + * relation OID. Note that InvalidOid will be returned if the + * RTE is for a non-relation-type RTE. + */ +#define getrelid(rangeindex,rangetable) \ + (exec_rt_fetch(rangeindex, rangetable)->relid) /* * ExecRowMark - diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index a342edf49c..34f7de1f9d 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -1091,7 +1091,7 @@ typedef struct PartitionPruneInfo typedef struct PartitionedRelPruneInfo { NodeTag type; - Oid reloid; /* OID of partition rel for this level */ + Index rtindex; /* 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/parser/parsetree.h b/src/include/parser/parsetree.h index dd9ae658ac..fe16d7d1fa 100644 --- a/src/include/parser/parsetree.h +++ b/src/include/parser/parsetree.h @@ -32,16 +32,6 @@ ((RangeTblEntry *) list_nth(rangetable, (rangetable_index)-1)) /* - * getrelid - * - * Given the range index of a relation, return the corresponding - * relation OID. Note that InvalidOid will be returned if the - * RTE is for a non-relation-type RTE. - */ -#define getrelid(rangeindex,rangetable) \ - (rt_fetch(rangeindex, rangetable)->relid) - -/* * Given an RTE and an attribute number, return the appropriate * variable name or alias for that attribute of that RTE. */ -- 2.11.0