executor relation handling
This is the continuation of the discussion at:
/messages/by-id/7500.1531920772@sss.pgh.pa.us
Actually, for more background on what I've written below, reading this
email in the same discussion would help:
/messages/by-id/4114.1531674142@sss.pgh.pa.us
Attached find a series of patches, the first of which tries to implement
the main topic discussed in the above email, which is to eliminate
execution-time locking of relations in PlannedStmt.rtable. One of the
other patches removes the plan node fields that are obsoleted by
eliminating execution-time locking of relations. Those fields served no
purpose beside telling the executor which relations to lock, or more
precisely which relations to lock before initializing the plan tree so
that we don't end up upgrading lock strength due to same relation being
both a source relation and target relation.
When working on that, I noticed that planner fails to remove PlanRowMarks
of relations that won't be scanned by a given plan, which results in
executor redundantly locking relations that the planner already deemed
unnecessary to scan. The locking would be gone with one of the proposed
patches, but there are still a couple of overheads during executor
initialization of having all those PlanRowMarks. For example,
ExecInitLockRows or ExecInitModifyTable calling ExecFindRowMark would end
up going over PlanRowMarks that won't ever be used, which especially grows
worse with many partitions.
Short description of each patch follows:
0001-Don-t-lock-range-table-relations-in-the-executor.patch
This removes all instances of heap_open(relid, <not-NoLock>) in the
executor code with heap_open(relid, NoLock). To verify that an
appropriate lock is already taken on a relation by the time we get into
executor, this also installs an assert-build-only check that confirms that
lmgr indeed holds the lock. To remember which lock was taken when
creating a given RTE_RELATION range table entry, this adds a lockmode
field to RangeTblEntry. Finally, because we don't lock in the executor
and hence there are no concerns about lock strength upgrade hazard,
InitPlan doesn't need toinitialize ResultRelInfos and ExecRowMarks, in
favor of doing that in the ExecInit* routines of respective nodes which
need those ResultRelInfos and ExecLockRows.
(This doesn't touch index relations though, as they don't have a range
table entry.)
0002-Remove-useless-fields-from-planner-nodes.patch
This removes some fields from PlannedStmt whose only purpose currently is
to help InitPlan do certain things that it no longer does, as mentioned
above. Also, some fields in Append, MergeAppend, ModifyTable, whose only
purpose currently is to propagate partitioned table RT indexes so that
executor could lock them, are removed. Removing them also means that the
planner doesn't have to spend cycles initializing them.
0003-Prune-PlanRowMark-of-relations-that-are-pruned-from-.patch
This prevents PlanRowMarks corresponding to relations that won't be
scanned by a given plan from appearing in the rowMarks field of LockRows
or ModifyTable nodes. This results in removing significant overhead from
the executor initialization of those nodes, especially for partitioned
tables with many partitions.
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.
Although improving executor's performance is not the main goal of these
patches, the fact that we're getting rid of redundant processing means
there would be at least some speedup, especially with large number of
relations in the range table, such as with partitioned tables with many
partitions.
* Benchmark script used:
$ cat /tmp/select-lt.sql
select * from lt where b = 999;
'lt' above is a list-partitioned table with 1000 partitions, with one
partition for each value in the range 1..1000.
$ for i in 1 2;
do
pgbench -n -Mprepared -T 60 -f /tmp/select-lt.sql
done
master
tps = 768.172129 (excluding connections establishing)
tps = 764.180834 (excluding connections establishing)
patch 0001 (no locking in the executor)
tps = 775.060323 (excluding connections establishing)
tps = 778.772917 (excluding connections establishing)
patch 0002 (remove useless planner node fields)
tps = 782.165436 (excluding connections establishing)
tps = 759.417411 (excluding connections establishing
patch 0003 (prune PlanRowMarks)
tps = 783.558539 (excluding connections establishing)
tps = 776.106055 (excluding connections establishing)
patch 0004 (executor range table Relation open)
tps = 778.924649 (excluding connections establishing)
tps = 769.093431 (excluding connections establishing)
Speedup is more pronounced with a benchmark that needs RowMarks, because
one of the patches (0003) removes overhead around handling them.
$ cat /tmp/select-lt-for-share.sql
select * from lt where b = 999 for share;
master
tps = 94.095985 (excluding connections establishing)
tps = 93.955702 (excluding connections establishing)
patch 0001 (no locking in the executor)
tps = 199.030555 (excluding connections establishing)
tps = 197.630424 (excluding connections establishing)
patch 0002 (remove useless planner node fields)
tps = 194.384994 (excluding connections establishing)
tps = 195.821362 (excluding connections establishing)
patch 0003 (prune PlanRowMarks)
tps = 712.544029 (excluding connections establishing)
tps = 717.540052 (excluding connections establishing)
patch 0004 (executor range table Relation open)
tps = 725.189715 (excluding connections establishing)
tps = 727.344683 (excluding connections establishing)
Will add this to next CF.
Thanks,
Amit
Attachments:
v1-0001-Don-t-lock-range-table-relations-in-the-executor.patchtext/plain; charset=UTF-8; name=v1-0001-Don-t-lock-range-table-relations-in-the-executor.patchDownload
From 14f9d6e7d443e7f9c0601210aab59d5cf3c6b249 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Thu, 19 Jul 2018 16:14:51 +0900
Subject: [PATCH v1 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 7d4511c585..2a021a028b 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 d13be4145f..3db0b99aa6 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 6269f474d2..b4d2a4aa4c 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -3126,6 +3126,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 3123ee274d..5b12e3c80c 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,
@@ -2886,6 +2872,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
@@ -3093,6 +3080,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
v1-0002-Remove-useless-fields-from-planner-nodes.patchtext/plain; charset=UTF-8; name=v1-0002-Remove-useless-fields-from-planner-nodes.patchDownload
From 6b934cf39c05fc0f3720bb8817e0489cf7e0c339 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Mon, 13 Aug 2018 16:10:19 +0900
Subject: [PATCH v1 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 b4d2a4aa4c..f5fd9e6345 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 69dd327f0c..7db9d0f1d4 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -215,7 +215,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
@@ -224,25 +223,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);
}
@@ -852,12 +832,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;
@@ -888,24 +866,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;
@@ -919,10 +890,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,
@@ -941,10 +908,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 41caf873fb..10d9327b8b 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 */
@@ -1713,8 +1710,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
v1-0003-Prune-PlanRowMark-of-relations-that-are-pruned-fr.patchtext/plain; charset=UTF-8; name=v1-0003-Prune-PlanRowMark-of-relations-that-are-pruned-fr.patchDownload
From 8ca856147b53d806d597101a73b4cdeff429c7ff Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 14 Aug 2018 10:35:47 +0900
Subject: [PATCH v1 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
v1-0004-Revise-executor-range-table-relation-opening-clos.patchtext/plain; charset=UTF-8; name=v1-0004-Revise-executor-range-table-relation-opening-clos.patchDownload
From e519b5c78ce6c21df524a609eb9acf582f49cb79 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Thu, 19 Jul 2018 13:01:43 +0900
Subject: [PATCH v1 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.
---
src/backend/executor/execExprInterp.c | 6 ++++--
src/backend/executor/execMain.c | 34 +++++++++++++++++++++++++---------
src/backend/executor/execPartition.c | 12 ++++++------
src/backend/executor/execUtils.c | 4 +---
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/include/executor/executor.h | 30 ++++++++++++++++++++++++++++++
src/include/nodes/execnodes.h | 7 +++++++
src/include/nodes/plannodes.h | 2 +-
13 files changed, 111 insertions(+), 34 deletions(-)
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 9d6e25aae5..af8c636d94 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3963,8 +3963,10 @@ ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
if (econtext->ecxt_estate &&
variable->varno <= list_length(econtext->ecxt_estate->es_range_table))
{
- RangeTblEntry *rte = rt_fetch(variable->varno,
- econtext->ecxt_estate->es_range_table);
+ RangeTblEntry *rte = econtext->ecxt_estate->es_rtable_array ?
+ econtext->ecxt_estate->es_rtable_array[variable->varno] :
+ rt_fetch(variable->varno,
+ econtext->ecxt_estate->es_range_table);
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..c3899d9068 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -109,9 +109,13 @@ 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)
+ ((estate)->es_rtable_array != NULL ?\
+ (estate)->es_rtable_array[(relinfo)->ri_RangeTableIndex]->insertedCols :\
+ rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->insertedCols)
#define GetUpdatedColumns(relinfo, estate) \
- (rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->updatedCols)
+ ((estate)->es_rtable_array != NULL ?\
+ (estate)->es_rtable_array[(relinfo)->ri_RangeTableIndex]->updatedCols :\
+ rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->updatedCols)
/* end of local decls */
@@ -814,6 +818,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
TupleDesc tupType;
ListCell *l;
int i;
+ int rti;
/*
* Do permissions checks
@@ -844,6 +849,17 @@ InitPlan(QueryDesc *queryDesc, int eflags)
* initialize the node's execution state
*/
estate->es_range_table = rangeTable;
+
+ /* allocate space for Relation pointer and initialize with 0s. */
+ estate->es_relations = (Relation *)
+ palloc0((list_length(rangeTable) + 1) * sizeof(Relation));
+ estate->es_rtable_array = (RangeTblEntry **)
+ palloc((list_length(rangeTable) + 1) *
+ sizeof(RangeTblEntry *));
+ rti = 1;
+ foreach(l, rangeTable)
+ estate->es_rtable_array[rti++] = lfirst(l);
+
estate->es_plannedstmt = plannedstmt;
/*
@@ -2278,14 +2294,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 +2308,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 +2329,7 @@ ExecBuildRowMark(EState *estate, PlanRowMark *rc)
erm = (ExecRowMark *) palloc(sizeof(ExecRowMark));
erm->relation = relation;
- erm->relid = relid;
+ erm->relid = estate->es_rtable_array[rc->rti]->relid;
erm->rti = rc->rti;
erm->prti = rc->prti;
erm->rowmarkId = rc->rowmarkId;
@@ -3114,6 +3126,10 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree)
*/
estate->es_tupleTable = NIL;
+ /* OK to use these as is from the parent. */
+ estate->es_rtable_array = parentestate->es_rtable_array;
+ estate->es_relations = parentestate->es_relations;
+
/*
* Initialize private state information for each SubPlan. We must do this
* before running ExecInitNode on the main query tree, since
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index 3db0b99aa6..cf4b569d5c 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/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 f5fd9e6345..dd53ef3115 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 7db9d0f1d4..0e53981834 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -896,6 +896,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:
@@ -914,6 +929,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 0dd55ac1ba..58d8ad6f24 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/include/executor/executor.h b/src/include/executor/executor.h
index 1d2b48fe09..97d86788ba 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,33 @@ 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] != NULL)
+ {
+ RelationIncrementReferenceCount(estate->es_relations[rti]);
+ rel = estate->es_relations[rti];
+ }
+ else
+ {
+ Assert(estate->es_rtable_array != NULL &&
+ estate->es_rtable_array[rti] != NULL);
+ rte = estate->es_rtable_array[rti];
+
+ /*
+ * No need to lock the relation lock, because upstream code
+ * must hold the lock already.
+ */
+ rel = estate->es_relations[rti] = 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 41fa2052a2..127153b3be 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"
@@ -486,6 +487,12 @@ typedef struct EState
/* If query can insert/delete tuples, the command ID to mark them with */
CommandId es_output_cid;
+ /* Array of RT entries indexed by their RT indexes. */
+ RangeTblEntry **es_rtable_array;
+
+ /* Relation pointers for all relations in es_range_table. */
+ Relation *es_relations;
+
/* Info about target table(s) for insert/update/delete queries: */
ResultRelInfo *es_result_relations; /* array of ResultRelInfos */
int es_num_result_relations; /* length of array */
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. */
--
2.11.0
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]Make executor's Range Table an array instead of a List /messages/by-id/CAKJS1f9EypD_=xG6ACFdF=1cBjz+Z9hiHHSd-RqLjor+QyA-nw@mail.gmail.com, 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 /messages/by-id/CAKJS1f9EypD_=xG6ACFdF=1cBjz+Z9hiHHSd-RqLjor+QyA-nw@mail.gmail.com
/messages/by-id/CAKJS1f9EypD_=xG6ACFdF=1cBjz+Z9hiHHSd-RqLjor+QyA-nw@mail.gmail.com
Attachments:
v2-0001-Don-t-lock-range-table-relations-in-the-executor.patchtext/plain; charset=UTF-8; name=v2-0001-Don-t-lock-range-table-relations-in-the-executor.patchDownload
From e46911bd7bb621b66c8d693132d4aeb3202d73df Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@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
v2-0002-Remove-useless-fields-from-planner-nodes.patchtext/plain; charset=UTF-8; name=v2-0002-Remove-useless-fields-from-planner-nodes.patchDownload
From 2c9a0f7d81f69bb5faafbe1d552aeb0cad6be8d5 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@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
v2-0003-Prune-PlanRowMark-of-relations-that-are-pruned-fr.patchtext/plain; charset=UTF-8; name=v2-0003-Prune-PlanRowMark-of-relations-that-are-pruned-fr.patchDownload
From a2aab818dd94db0d78c73ecfda4134a80dbed043 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@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
v2-0004-Revise-executor-range-table-relation-opening-clos.patchtext/plain; charset=UTF-8; name=v2-0004-Revise-executor-range-table-relation-opening-clos.patchDownload
From 36e2b0b58e0c7b1a1445a46be147881fe416a2dc Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@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
On 4 September 2018 at 20:53, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
Updated patches attached; 0001-0003 are same as v1.
I've looked at these. Here's my review so far:
0001:
1. The following does not seem to be true any longer:
+ /*
+ * If you change the conditions under which rel locks are acquired
+ * here, be sure to adjust ExecOpenScanRelation to match.
+ */
per:
@@ -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;
- }
-
2. Should addRangeTableEntryForRelation() initialize lockmode, or
maybe take it as a parameter?
3. Don't think there's a need to capitalise true and false in:
+ * Return TRUE if we acquired a new lock, FALSE if already held.
4. The comment probably should read "lock level to obtain, or 0 if no
lock is required" in:
+ int lockmode; /* lock taken on the relation or 0 */
The field should likely also be LOCKMODE, not int.
5. AcquireExecutorLocks() does not need the local variable named rt_index
0002:
6. I don't think "rootRelation" is a good name for this field. I think
"root" is being confused with "target". Nothing is it say the target
is the same as the root.
+ Index rootRelation; /* RT index of root partitioned table */
Perhaps "partitionedTarget" is a better name?
7. Should use "else" instead of "else if" in:
+ /* 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;
or you'll likely get a compiler warning on non-Assert enabled builds.
0003:
8. The following code seems repeated enough to warrant a static function:
+ 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);
+ }
Also, why not reverse the condition and do the lappend inside the if?
Save two lines.
9. The following code appears in copy.c, which is pretty much the same
as the code in execMain.c:
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);
Would it not be better to invent a function with the signature:
void
setup_range_table_array(EState *estate, List *rangeTable)
and use it in both locations?
10. In create_estate_for_relation() I don't think you should remove
the line that sets es_range_table.
@@ -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);
If you're keeping es_range_table then I think it needs to always be
set properly to help prevent future bugs in that area.
11. ExecRangeTableRelation should look more like:
ExecRangeTableRelation(EState *estate, Index rti)
{
Relation rel = estate->es_relations[rti - 1];
if (rel != NULL)
RelationIncrementReferenceCount(rel);
else
{
RangeTblEntry *rte = exec_rt_fetch(rti, estate->es_range_table_array);
/*
* No need to lock the relation lock, because upstream code
* must hold the lock already.
*/
rel = estate->es_relations[rti - 1] = heap_open(rte->relid, NoLock);
}
return rel;
}
12. I think this should read: /* Fill in RTEs. es_relations will be
populated later. */
+ /* Fill the RTEs, Relations array will be filled later. */
13. I also notice that you're still cleaning up Relations with
heap_close or relation_close. Did you consider not doing that and just
having a function that's run at the end of execution which closes all
non-NULL es_relations? This way you'd not need to perform
RelationIncrementReferenceCount inside ExecRangeTableRelation.
--
David Rowley http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
Thank you for reviewing.
On 2018/09/10 13:36, David Rowley wrote:
On 4 September 2018 at 20:53, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:Updated patches attached; 0001-0003 are same as v1.
I've looked at these. Here's my review so far:
0001:
1. The following does not seem to be true any longer:
+ /* + * If you change the conditions under which rel locks are acquired + * here, be sure to adjust ExecOpenScanRelation to match. + */per:
@@ -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;
- }
-
Yeah, removed that comment in ExecBuildRowMark.
2. Should addRangeTableEntryForRelation() initialize lockmode, or
maybe take it as a parameter?
Hmm, that sounds like a good idea. Looking at the various places it's
called from though, it's not clear in many instances which lock was taken
on the relation that's passed to it, because the lock itself seems to be
taken several stack frames removed from the call site.
That said, at least for the cases that we care about, that is, the cases
in which the RTE being built will be passed to the executor by the way of
being in a PlannedStmt, it's clear which lock is taken. So, we can add
the lockmode parameter to addRangeTableEntryForRelation as you suggest and
pass the actual lockmode value only in the cases we care about, mentioning
the fact in the function's header comment that callers may pass NoLock
arbitrarily if it's clear the RTE won't be passed to the executor.
I've modified patch that way. Thoughts?
3. Don't think there's a need to capitalise true and false in:
+ * Return TRUE if we acquired a new lock, FALSE if already held.
OK, fixed.
4. The comment probably should read "lock level to obtain, or 0 if no
lock is required" in:+ int lockmode; /* lock taken on the relation or 0 */
OK.
The field should likely also be LOCKMODE, not int.
OK.
5. AcquireExecutorLocks() does not need the local variable named rt_index
Good catch, removed.
0002:
6. I don't think "rootRelation" is a good name for this field. I think
"root" is being confused with "target". Nothing is it say the target
is the same as the root.+ Index rootRelation; /* RT index of root partitioned table */
Perhaps "partitionedTarget" is a better name?
I realized that we don't need a new Index field here. nominalRelation
serves the purpose that rootRelation is meant for, so it seems silly to
have two fields of the same value. Instead, let's have a bool
partitionedTarget which is set to true if the target (whose RT index is
nominalRelation) is a partitioned tables.
7. Should use "else" instead of "else if" in:
+ /* 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;or you'll likely get a compiler warning on non-Assert enabled builds.
Yep, fixed.
0003:
8. The following code seems repeated enough to warrant a static function:
+ 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); + }Also, why not reverse the condition and do the lappend inside the if?
Save two lines.
OK, made this change and added a static function called
get_unpruned_rowmarks(PlannerInfo *root).
9. The following code appears in copy.c, which is pretty much the same
as the code in execMain.c: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);Would it not be better to invent a function with the signature:
void
setup_range_table_array(EState *estate, List *rangeTable)and use it in both locations?
Agreed, but I named it ExecInitRangeTable.
10. In create_estate_for_relation() I don't think you should remove
the line that sets es_range_table.@@ -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);If you're keeping es_range_table then I think it needs to always be
set properly to help prevent future bugs in that area.
My bad, fixed.
11. ExecRangeTableRelation should look more like:
ExecRangeTableRelation(EState *estate, Index rti)
{
Relation rel = estate->es_relations[rti - 1];if (rel != NULL)
RelationIncrementReferenceCount(rel);
else
{
RangeTblEntry *rte = exec_rt_fetch(rti, estate->es_range_table_array);/*
* No need to lock the relation lock, because upstream code
* must hold the lock already.
*/
rel = estate->es_relations[rti - 1] = heap_open(rte->relid, NoLock);
}return rel;
}
Much better, done.
12. I think this should read: /* Fill in RTEs. es_relations will be
populated later. */+ /* Fill the RTEs, Relations array will be filled later. */
I've rewritten the comment.
13. I also notice that you're still cleaning up Relations with
heap_close or relation_close. Did you consider not doing that and just
having a function that's run at the end of execution which closes all
non-NULL es_relations? This way you'd not need to perform
RelationIncrementReferenceCount inside ExecRangeTableRelation.
Agreed, done. I'd be slightly hesitant to remove ExecCloseScanRelation,
ExecDestroyPartitionPruneState et al if they weren't just a wrapper around
heap_close.
Please find attached revised patches.
Thanks,
Amit
Attachments:
v3-0001-Don-t-lock-range-table-relations-in-the-executor.patchtext/plain; charset=UTF-8; name=v3-0001-Don-t-lock-range-table-relations-in-the-executor.patchDownload
From 1651c36689dc4ead28b13b5e6e075e3b5799137b Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Thu, 19 Jul 2018 16:14:51 +0900
Subject: [PATCH v3 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/catalog/heap.c | 3 +-
src/backend/commands/copy.c | 7 +-
src/backend/commands/policy.c | 17 +-
src/backend/commands/tablecmds.c | 2 +-
src/backend/commands/trigger.c | 4 +-
src/backend/commands/view.c | 6 +-
src/backend/executor/execMain.c | 265 ++++++++---------------
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 | 3 +-
src/backend/parser/parse_clause.c | 3 +-
src/backend/parser/parse_relation.c | 9 +-
src/backend/parser/parse_utilcmd.c | 18 +-
src/backend/replication/logical/tablesync.c | 2 +-
src/backend/rewrite/rewriteHandler.c | 20 +-
src/backend/storage/lmgr/lmgr.c | 6 +-
src/backend/utils/cache/plancache.c | 30 +--
src/include/executor/executor.h | 2 +-
src/include/nodes/parsenodes.h | 3 +
src/include/parser/parse_relation.h | 4 +-
src/include/storage/lmgr.h | 2 +-
src/test/modules/test_rls_hooks/test_rls_hooks.c | 4 +-
28 files changed, 207 insertions(+), 276 deletions(-)
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 9176f6280b..19b530ac94 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -2551,7 +2551,8 @@ AddRelationNewConstraints(Relation rel,
rel,
NULL,
false,
- true);
+ true,
+ NoLock);
addRTEtoQuery(pstate, rte, true, true, true);
/*
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 9bc67ce60f..0f8be85303 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -837,16 +837,17 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
List *attnums;
ListCell *cur;
RangeTblEntry *rte;
+ int lockmode = is_from ? RowExclusiveLock : AccessShareLock;
Assert(!stmt->query);
/* Open and lock the relation, using the appropriate lock type. */
- rel = heap_openrv(stmt->relation,
- (is_from ? RowExclusiveLock : AccessShareLock));
+ rel = heap_openrv(stmt->relation, lockmode);
relid = RelationGetRelid(rel);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, false);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, false,
+ lockmode);
rte->requiredPerms = (is_from ? ACL_INSERT : ACL_SELECT);
tupDesc = RelationGetDescr(rel);
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index cee0ef915b..09a6a7f9d3 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -567,7 +567,8 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
qual_expr = stringToNode(qual_value);
/* Add this rel to the parsestate's rangetable, for dependencies */
- addRangeTableEntryForRelation(qual_pstate, rel, NULL, false, false);
+ addRangeTableEntryForRelation(qual_pstate, rel, NULL, false, false,
+ NoLock);
qual_parse_rtable = qual_pstate->p_rtable;
free_parsestate(qual_pstate);
@@ -590,7 +591,7 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(with_check_pstate, rel, NULL, false,
- false);
+ false, NoLock);
with_check_parse_rtable = with_check_pstate->p_rtable;
free_parsestate(with_check_pstate);
@@ -752,12 +753,12 @@ CreatePolicy(CreatePolicyStmt *stmt)
/* Add for the regular security quals */
rte = addRangeTableEntryForRelation(qual_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
/* Add for the with-check quals */
rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(with_check_pstate, rte, false, true, true);
qual = transformWhereClause(qual_pstate,
@@ -928,7 +929,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
ParseState *qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
@@ -950,7 +951,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
ParseState *with_check_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(with_check_pstate, rte, false, true, true);
@@ -1097,7 +1098,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(qual_pstate, target_table, NULL,
- false, false);
+ false, false, NoLock);
qual_parse_rtable = qual_pstate->p_rtable;
free_parsestate(qual_pstate);
@@ -1138,7 +1139,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(with_check_pstate, target_table, NULL,
- false, false);
+ false, false, NoLock);
with_check_parse_rtable = with_check_pstate->p_rtable;
free_parsestate(with_check_pstate);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index e96512e051..dbdbbde9e8 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -13659,7 +13659,7 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
* rangetable entry. We need a ParseState for transformExpr.
*/
pstate = make_parsestate(NULL);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true, NoLock);
addRTEtoQuery(pstate, rte, true, true, true);
/* take care of any partition expressions */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 2436692eb8..ce9acef1c2 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -578,11 +578,11 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
*/
rte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false, NoLock);
addRTEtoQuery(pstate, rte, false, true, true);
rte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false, NoLock);
addRTEtoQuery(pstate, rte, false, true, true);
/* Transform expression. Copy to be sure we don't modify original */
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index ffb71c0ea7..4c379fd83b 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -387,10 +387,12 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
*/
rt_entry1 = addRangeTableEntryForRelation(pstate, viewRel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessShareLock);
rt_entry2 = addRangeTableEntryForRelation(pstate, viewRel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ 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..f797cdfe7c 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,60 @@ 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);
+
+ 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 +3057,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 +3170,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..d2f90c2de6 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -1038,7 +1038,8 @@ transformOnConflictClause(ParseState *pstate,
exclRte = addRangeTableEntryForRelation(pstate,
targetrel,
makeAlias("excluded", NIL),
- false, false);
+ false, false,
+ RowExclusiveLock);
exclRte->relkind = RELKIND_COMPOSITE_TYPE;
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..5358042f89 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -217,7 +217,8 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
* Now build an RTE.
*/
rte = addRangeTableEntryForRelation(pstate, pstate->p_target_relation,
- relation->alias, inh, false);
+ relation->alias, inh, false,
+ 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..37b4c79126 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
@@ -1262,13 +1263,18 @@ addRangeTableEntry(ParseState *pstate,
*
* This is just like addRangeTableEntry() except that it makes an RTE
* given an already-open relation instead of a RangeVar reference.
+ *
+ * 'lockmode' is the lock taken on 'rel'. The caller may pass NoLock if the
+ * RTE won't be passed to the executor, that is, won't be part of a
+ * PlannedStmt.
*/
RangeTblEntry *
addRangeTableEntryForRelation(ParseState *pstate,
Relation rel,
Alias *alias,
bool inh,
- bool inFromCl)
+ bool inFromCl,
+ LOCKMODE lockmode)
{
RangeTblEntry *rte = makeNode(RangeTblEntry);
char *refname = alias ? alias->aliasname : RelationGetRelationName(rel);
@@ -1279,6 +1285,7 @@ addRangeTableEntryForRelation(ParseState *pstate,
rte->alias = alias;
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 f5c1e2a0d7..14adac8312 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -2526,7 +2526,8 @@ transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
* relation, but we still need to open it.
*/
rel = relation_open(relid, NoLock);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true,
+ NoLock);
/* no to join list, yes to namespaces */
addRTEtoQuery(pstate, rte, false, true, true);
@@ -2636,10 +2637,12 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
*/
oldrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessShareLock);
newrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ AccessShareLock);
/* Must override addRangeTableEntry's default access-check flags */
oldrte->requiredPerms = 0;
newrte->requiredPerms = 0;
@@ -2734,10 +2737,12 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
*/
oldrte = addRangeTableEntryForRelation(sub_pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessShareLock);
newrte = addRangeTableEntryForRelation(sub_pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ AccessShareLock);
oldrte->requiredPerms = 0;
newrte->requiredPerms = 0;
addRTEtoQuery(sub_pstate, oldrte, false, true, false);
@@ -2940,7 +2945,8 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
rel,
NULL,
false,
- true);
+ true,
+ NoLock);
addRTEtoQuery(pstate, rte, false, true, true);
/* Set up CreateStmtContext */
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index acc6498567..905a983074 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -795,7 +795,7 @@ copy_table(Relation rel)
copybuf = makeStringInfo();
pstate = make_parsestate(NULL);
- addRangeTableEntryForRelation(pstate, rel, NULL, false, false);
+ addRangeTableEntryForRelation(pstate, rel, NULL, false, false, NoLock);
attnamelist = make_copy_attnamelist(relmapentry);
cstate = BeginCopyFrom(pstate, rel, NULL, false, copy_read_data, attnamelist, NIL);
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index d830569641..d5a928671e 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
@@ -3100,7 +3087,8 @@ rewriteTargetView(Query *parsetree, Relation view)
base_rel,
makeAlias("excluded",
NIL),
- false, false);
+ false, false,
+ RowExclusiveLock);
new_exclRte->relkind = RELKIND_COMPOSITE_TYPE;
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 dc0a439638..b22d2d1457 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;
@@ -132,7 +133,10 @@ LockRelationOid(Oid relid, LOCKMODE lockmode)
{
AcceptInvalidationMessages();
MarkLockClear(locallock);
+ return true;
}
+
+ return res == LOCKACQUIRE_ALREADY_HELD;
}
/*
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 7271b5880b..1876345de5 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -1493,7 +1493,6 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
foreach(lc1, stmt_list)
{
PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
- int rt_index;
ListCell *lc2;
if (plannedstmt->commandType == CMD_UTILITY)
@@ -1512,14 +1511,9 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
continue;
}
- rt_index = 0;
foreach(lc2, plannedstmt->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
- LOCKMODE lockmode;
- PlanRowMark *rc;
-
- rt_index++;
if (rte->rtekind != RTE_RELATION)
continue;
@@ -1530,19 +1524,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 +1581,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..a0ce4109e2 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -27,6 +27,7 @@
#include "nodes/primnodes.h"
#include "nodes/value.h"
#include "partitioning/partdefs.h"
+#include "storage/lockdefs.h"
typedef enum OverridingKind
@@ -977,6 +978,8 @@ typedef struct RangeTblEntry
*/
Oid relid; /* OID of the relation */
char relkind; /* relation kind (see pg_class.relkind) */
+ LOCKMODE lockmode; /* lock level to obtain on the relation, or
+ * 0 if no lock required */
struct TableSampleClause *tablesample; /* sampling info, or NULL */
/*
diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h
index b9792acdae..99d1b4135c 100644
--- a/src/include/parser/parse_relation.h
+++ b/src/include/parser/parse_relation.h
@@ -15,6 +15,7 @@
#define PARSE_RELATION_H
#include "parser/parse_node.h"
+#include "storage/lockdefs.h"
/*
@@ -71,7 +72,8 @@ extern RangeTblEntry *addRangeTableEntryForRelation(ParseState *pstate,
Relation rel,
Alias *alias,
bool inh,
- bool inFromCl);
+ bool inFromCl,
+ LOCKMODE lockmode);
extern RangeTblEntry *addRangeTableEntryForSubquery(ParseState *pstate,
Query *subquery,
Alias *alias,
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);
diff --git a/src/test/modules/test_rls_hooks/test_rls_hooks.c b/src/test/modules/test_rls_hooks/test_rls_hooks.c
index cab67a60aa..d455c97ef6 100644
--- a/src/test/modules/test_rls_hooks/test_rls_hooks.c
+++ b/src/test/modules/test_rls_hooks/test_rls_hooks.c
@@ -81,7 +81,7 @@ test_rls_hooks_permissive(CmdType cmdtype, Relation relation)
qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, relation, NULL, false,
- false);
+ false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
@@ -144,7 +144,7 @@ test_rls_hooks_restrictive(CmdType cmdtype, Relation relation)
qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, relation, NULL, false,
- false);
+ false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
--
2.11.0
v3-0002-Remove-useless-fields-from-planner-nodes.patchtext/plain; charset=UTF-8; name=v3-0002-Remove-useless-fields-from-planner-nodes.patchDownload
From 1369aa80c1abf1bd0131f7625ec9523c05cd1777 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Mon, 13 Aug 2018 16:10:19 +0900
Subject: [PATCH v3 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 bool field called
'partitionedTarget', which is set if the target is a partitioned
table. The table itself is identified by nominalRelation.
* '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 | 10 +++---
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 | 48 ++++------------------------
src/backend/optimizer/plan/setrefs.c | 47 +++-------------------------
src/backend/optimizer/util/pathnode.c | 8 ++---
src/backend/tcop/utility.c | 15 +++++++--
src/include/executor/executor.h | 2 --
src/include/nodes/plannodes.h | 29 +++++------------
src/include/nodes/relation.h | 9 ++----
src/include/optimizer/pathnode.h | 2 +-
20 files changed, 61 insertions(+), 254 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 f797cdfe7c..e84ebe0c87 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..ab4ec575fc 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2255,18 +2255,18 @@ 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->partitionedTarget);
+ /* nominalRelation is the index of the target partitioned table. */
+ rte = rt_fetch(node->nominalRelation, estate->es_range_table);
rel = heap_open(rte->relid, NoLock);
- InitResultRelInfo(mtstate->rootResultRelInfo, rel, root_rt_index,
- NULL, estate->es_instrument);
+ InitResultRelInfo(mtstate->rootResultRelInfo, rel,
+ node->nominalRelation, NULL, estate->es_instrument);
}
mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 11ca800e4c..1bee240e72 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -1358,7 +1358,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
@@ -1374,7 +1374,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..b0193a94a9 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(partitionedTarget);
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..36d46f5d8f 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_BOOL_FIELD(partitionedTarget);
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_BOOL_FIELD(partitionedTarget);
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..4d1317e339 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_BOOL_FIELD(partitionedTarget);
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..becc5ef75d 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, bool partitionedTarget,
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->partitionedTarget,
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, bool partitionedTarget,
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->partitionedTarget = partitionedTarget;
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..bc4f02fbf6 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;
@@ -1173,8 +1168,7 @@ inheritance_planner(PlannerInfo *root)
ListCell *lc;
Index rti;
RangeTblEntry *parent_rte;
- Relids partitioned_relids = NULL;
- List *partitioned_rels = NIL;
+ bool partitionedTarget = false;
PlannerInfo *parent_root;
Query *parent_parse;
Bitmapset *parent_relids = bms_make_singleton(top_parentRTindex);
@@ -1250,12 +1244,7 @@ inheritance_planner(PlannerInfo *root)
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);
+ partitionedTarget = true;
}
/*
@@ -1327,7 +1316,7 @@ inheritance_planner(PlannerInfo *root)
* inheritance parent.
*/
subroot->inhTargetKind =
- partitioned_relids ? INHKIND_PARTITIONED : INHKIND_INHERITED;
+ partitionedTarget ? INHKIND_PARTITIONED : INHKIND_INHERITED;
/*
* If this child is further partitioned, remember it as a parent.
@@ -1498,15 +1487,6 @@ inheritance_planner(PlannerInfo *root)
continue;
/*
- * Add the current parent's RT index to the partitioned_relids set if
- * we're creating the ModifyTable path for a partitioned root table.
- * (We only care about parents of non-excluded children.)
- */
- if (partitioned_relids)
- partitioned_relids = bms_add_member(partitioned_relids,
- appinfo->parent_relid);
-
- /*
* If this is the first non-excluded child, its post-planning rtable
* becomes the initial contents of final_rtable; otherwise, append
* just its modified subquery RTEs to final_rtable.
@@ -1609,29 +1589,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,
+ partitionedTarget,
root->partColsUpdated,
resultRelations,
subpaths,
@@ -2208,7 +2172,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..a8ec0be83a 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);
}
@@ -850,10 +830,6 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
splan->nominalRelation += rtoffset;
splan->exclRelRTI += rtoffset;
- foreach(l, splan->partitioned_rels)
- {
- lfirst_int(l) += rtoffset;
- }
foreach(l, splan->resultRelations)
{
lfirst_int(l) += rtoffset;
@@ -884,24 +860,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->partitionedTarget)
{
- 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->nominalRelation);
}
}
break;
@@ -915,10 +884,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 +902,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..28f90a2a04 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, bool partitionedTarget,
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->partitionedTarget = partitionedTarget;
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..d0427c64ba 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
+ 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..ceec266a21 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 */
@@ -219,9 +212,9 @@ typedef struct ModifyTable
Plan plan;
CmdType operation; /* INSERT, UPDATE, or DELETE */
bool canSetTag; /* do we set the command tag/es_processed? */
- Index nominalRelation; /* Parent RT index for use of EXPLAIN */
- /* RT indexes of non-leaf tables in a partition tree */
- List *partitioned_rels;
+ Index nominalRelation; /* RT index of the target table specified
+ * in the command */
+ bool partitionedTarget; /* is the target table partitioned? */
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 +252,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 +264,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 +915,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..c9f288c24d 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 */
@@ -1716,9 +1713,9 @@ typedef struct ModifyTablePath
Path path;
CmdType operation; /* INSERT, UPDATE, or DELETE */
bool canSetTag; /* do we set the command tag/es_processed? */
- Index nominalRelation; /* Parent RT index for use of EXPLAIN */
- /* RT indexes of non-leaf tables in a partition tree */
- List *partitioned_rels;
+ Index nominalRelation; /* RT index of the target table specified
+ * in the command */
+ bool partitionedTarget; /* is the target table partitioned? */
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..d826e3cc55 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, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subpaths,
List *subroots,
--
2.11.0
v3-0003-Prune-PlanRowMark-of-relations-that-are-pruned-fr.patchtext/plain; charset=UTF-8; name=v3-0003-Prune-PlanRowMark-of-relations-that-are-pruned-fr.patchDownload
From 8e9f0d3422453bd19b897d4212498f62855f6304 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 14 Aug 2018 10:35:47 +0900
Subject: [PATCH v3 3/4] Prune PlanRowMark of relations that are pruned from a
plan
---
src/backend/optimizer/plan/planner.c | 31 ++++++++++++++++++++++++++-----
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index bc4f02fbf6..4cd3b9b902 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -237,6 +237,7 @@ static void create_partitionwise_grouping_paths(PlannerInfo *root,
static bool group_by_has_partkey(RelOptInfo *input_rel,
List *targetList,
List *groupClause);
+static List *get_unpruned_rowmarks(PlannerInfo *root);
/*****************************************************************************
@@ -1587,7 +1588,7 @@ inheritance_planner(PlannerInfo *root)
if (parse->rowMarks)
rowMarks = NIL;
else
- rowMarks = root->rowMarks;
+ rowMarks = get_unpruned_rowmarks(root);
/* Create Path representing a ModifyTable to do the UPDATE/DELETE work */
add_path(final_rel, (Path *)
@@ -2116,11 +2117,9 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
* is what goes into the LockRows node.)
*/
if (parse->rowMarks)
- {
path = (Path *) create_lockrows_path(root, final_rel, path,
- root->rowMarks,
+ get_unpruned_rowmarks(root),
SS_assign_special_param(root));
- }
/*
* If there is a LIMIT/OFFSET clause, add the LIMIT node.
@@ -2165,7 +2164,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
if (parse->rowMarks)
rowMarks = NIL;
else
- rowMarks = root->rowMarks;
+ rowMarks = get_unpruned_rowmarks(root);
path = (Path *)
create_modifytable_path(root, final_rel,
@@ -7159,3 +7158,25 @@ group_by_has_partkey(RelOptInfo *input_rel,
return true;
}
+
+/*
+ * get_unpruned_rowmarks
+ * Return a list of PlanRowMark's that reference unpruned relations
+ */
+static List *
+get_unpruned_rowmarks(PlannerInfo *root)
+{
+ List *rowMarks = NIL;
+ ListCell *lc;
+
+ 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]))
+ rowMarks = lappend(rowMarks, rc);
+ }
+
+ return rowMarks;
+}
--
2.11.0
v3-0004-Revise-executor-range-table-relation-opening-clos.patchtext/plain; charset=UTF-8; name=v3-0004-Revise-executor-range-table-relation-opening-clos.patchDownload
From b3a8f055c5f4a33c96c073b3749ca6938358a5dc Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Thu, 19 Jul 2018 13:01:43 +0900
Subject: [PATCH v3 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 | 16 +++-----
src/backend/commands/copy.c | 3 +-
src/backend/commands/trigger.c | 3 +-
src/backend/executor/execExprInterp.c | 7 ++--
src/backend/executor/execMain.c | 68 +++++++++++--------------------
src/backend/executor/execPartition.c | 36 +++-------------
src/backend/executor/execUtils.c | 64 ++++++++++++++++++-----------
src/backend/executor/nodeAppend.c | 6 ---
src/backend/executor/nodeBitmapHeapscan.c | 5 ---
src/backend/executor/nodeCustom.c | 4 --
src/backend/executor/nodeForeignscan.c | 4 --
src/backend/executor/nodeIndexonlyscan.c | 5 ---
src/backend/executor/nodeIndexscan.c | 5 ---
src/backend/executor/nodeLockRows.c | 2 +-
src/backend/executor/nodeMergeAppend.c | 6 ---
src/backend/executor/nodeModifyTable.c | 21 ++++------
src/backend/executor/nodeSamplescan.c | 5 ---
src/backend/executor/nodeSeqscan.c | 5 ---
src/backend/executor/nodeTidscan.c | 5 ---
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 | 2 +
src/include/executor/execPartition.h | 1 -
src/include/executor/executor.h | 24 ++++++++++-
src/include/nodes/execnodes.h | 22 +++++++++-
src/include/nodes/plannodes.h | 2 +-
src/include/parser/parsetree.h | 10 -----
30 files changed, 174 insertions(+), 198 deletions(-)
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index e4e330397e..4d2f5e448e 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. */
@@ -2547,10 +2547,6 @@ postgresEndDirectModify(ForeignScanState *node)
ReleaseConnection(dmstate->conn);
dmstate->conn = NULL;
- /* close the target relation. */
- if (dmstate->resultRel)
- ExecCloseScanRelation(dmstate->resultRel);
-
/* MemoryContext will be deleted automatically. */
}
@@ -5757,7 +5753,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 0f8be85303..b3d34307f6 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -2483,7 +2483,8 @@ 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;
+
+ ExecInitRangeTable(estate, cstate->range_table);
/* 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 ce9acef1c2..afbb6311af 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 e84ebe0c87..33b12d330a 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 */
@@ -820,30 +820,17 @@ 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
*/
- estate->es_range_table = rangeTable;
+ ExecInitRangeTable(estate, rangeTable);
+
+ /*
+ * Just initialize 0-filled array of Relation pointers. Actual values are
+ * filled later as the plan is initialized.
+ */
+ estate->es_relations = (Relation *) palloc0(estate->es_range_table_size *
+ sizeof(Relation));
estate->es_plannedstmt = plannedstmt;
/*
@@ -1488,6 +1475,12 @@ static void
ExecEndPlan(PlanState *planstate, EState *estate)
{
ListCell *l;
+ int i;
+
+ /* Close range table relations. */
+ for (i = 0; i < estate->es_range_table_size; i++)
+ if (estate->es_relations[i])
+ heap_close(estate->es_relations[i], NoLock);
/*
* shut down the node-type-specific query processing
@@ -1514,18 +1507,6 @@ ExecEndPlan(PlanState *planstate, EState *estate)
/* likewise close any trigger target relations */
ExecCleanUpTriggerState(estate);
-
- /*
- * 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);
- }
}
/* ----------------------------------------------------------------
@@ -2278,24 +2259,20 @@ 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);
-
switch (rc->markType)
{
case ROW_MARK_EXCLUSIVE:
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 */
@@ -2313,7 +2290,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;
@@ -2971,7 +2948,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));
@@ -3016,7 +2993,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();
@@ -3039,7 +3016,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..197175f106 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);
@@ -1593,30 +1593,6 @@ ExecCreatePartitionPruneState(PlanState *planstate,
}
/*
- * ExecDestroyPartitionPruneState
- * Release resources at plan shutdown.
- *
- * We don't bother to free any memory here, since the whole executor context
- * will be going away shortly. We do need to release our relcache pins.
- */
-void
-ExecDestroyPartitionPruneState(PartitionPruneState *prunestate)
-{
- PartitionPruningData **partprunedata = prunestate->partprunedata;
- int i;
-
- for (i = 0; i < prunestate->num_partprunedata; i++)
- {
- PartitionPruningData *prunedata = partprunedata[i];
- PartitionedRelPruningData *pprune = prunedata->partrelprunedata;
- int j;
-
- for (j = 0; j < prunedata->num_partrelprunedata; j++)
- relation_close(pprune[j].context.partrel, NoLock);
- }
-}
-
-/*
* ExecFindInitialMatchingSubPlans
* Identify the set of subplans that cannot be eliminated by initial
* pruning (disregarding any pruning constraints involving PARAM_EXEC
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index d32796aac3..abee92ee59 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
@@ -675,26 +673,6 @@ ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
return rel;
}
-/* ----------------------------------------------------------------
- * ExecCloseScanRelation
- *
- * Close the heap relation scanned by a base-level scan plan node.
- * This should be called during the node's ExecEnd routine.
- *
- * Currently, we do not release the lock acquired by ExecOpenScanRelation.
- * This lock should be held till end of transaction. (There is a faction
- * that considers this too much locking, however.)
- *
- * If we did want to release the lock, we'd have to repeat the logic in
- * ExecOpenScanRelation in order to figure out what to release.
- * ----------------------------------------------------------------
- */
-void
-ExecCloseScanRelation(Relation scanrel)
-{
- heap_close(scanrel, NoLock);
-}
-
/*
* UpdateChangedParamSet
* Add changed parameters to a plan node's chgParam set
@@ -997,3 +975,43 @@ ExecCleanTargetListLength(List *targetlist)
}
return len;
}
+
+/*
+ * Initialize executor's range table array
+ */
+void
+ExecInitRangeTable(EState *estate, List *rangeTable)
+{
+ int rti;
+ ListCell *l;
+
+#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
+
+ Assert(estate != NULL);
+ 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 *));
+ rti = 0;
+ foreach(l, rangeTable)
+ estate->es_range_table_array[rti++] = lfirst_node(RangeTblEntry, l);
+}
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index eb587be221..a16b6da474 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -329,12 +329,6 @@ ExecEndAppend(AppendState *node)
*/
for (i = 0; i < nplans; i++)
ExecEndNode(appendplans[i]);
-
- /*
- * release any resources associated with run-time pruning
- */
- if (node->as_prune_state)
- ExecDestroyPartitionPruneState(node->as_prune_state);
}
void
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index 3e1c9e0714..884f02b924 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -833,11 +833,6 @@ ExecEndBitmapHeapScan(BitmapHeapScanState *node)
* close heap scan
*/
heap_endscan(scanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index b816e0b31d..9a33eda688 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -126,10 +126,6 @@ ExecEndCustomScan(CustomScanState *node)
/* Clean out the tuple table */
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /* Close the heap relation */
- if (node->ss.ss_currentRelation)
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
void
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index a2a28b7ec2..cf7df72d8c 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -258,10 +258,6 @@ ExecEndForeignScan(ForeignScanState *node)
/* clean out the tuple table */
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /* close the relation. */
- if (node->ss.ss_currentRelation)
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 8c32a74d39..1588dbfb14 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -411,11 +411,6 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node)
index_endscan(indexScanDesc);
if (indexRelationDesc)
index_close(indexRelationDesc, NoLock);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 10891bc3f4..a77d731c81 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -835,11 +835,6 @@ ExecEndIndexScan(IndexScanState *node)
index_endscan(indexScanDesc);
if (indexRelationDesc)
index_close(indexRelationDesc, NoLock);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
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/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index d8e0978966..5d0dbb8146 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -363,12 +363,6 @@ ExecEndMergeAppend(MergeAppendState *node)
*/
for (i = 0; i < nplans; i++)
ExecEndNode(mergeplans[i]);
-
- /*
- * release any resources associated with run-time pruning
- */
- if (node->ms_prune_state)
- ExecDestroyPartitionPruneState(node->ms_prune_state);
}
void
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index ab4ec575fc..ccbf4c0f73 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,7 +2254,6 @@ 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 +
@@ -2263,10 +2261,12 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
Assert(node->partitionedTarget);
/* nominalRelation is the index of the target partitioned table. */
- rte = rt_fetch(node->nominalRelation, estate->es_range_table);
- rel = heap_open(rte->relid, NoLock);
- InitResultRelInfo(mtstate->rootResultRelInfo, rel,
- node->nominalRelation, NULL, estate->es_instrument);
+ rel = ExecRangeTableRelation(estate, node->nominalRelation);
+ InitResultRelInfo(mtstate->rootResultRelInfo,
+ rel,
+ node->nominalRelation,
+ NULL,
+ estate->es_instrument);
}
mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
@@ -2727,14 +2727,9 @@ ExecEndModifyTable(ModifyTableState *node)
/* 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/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index 15177dbed7..491f8d48fd 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -223,11 +223,6 @@ ExecEndSampleScan(SampleScanState *node)
*/
if (node->ss.ss_currentScanDesc)
heap_endscan(node->ss.ss_currentScanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index c7849de6bc..3c8f0ad615 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -227,11 +227,6 @@ ExecEndSeqScan(SeqScanState *node)
*/
if (scanDesc != NULL)
heap_endscan(scanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index e207b1ffb5..a3e62e4c9f 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -491,11 +491,6 @@ ExecEndTidScan(TidScanState *node)
*/
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index b0193a94a9..cde0cd7c16 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 36d46f5d8f..aba0c6bbd1 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 4d1317e339..1d9810dbfd 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 a8ec0be83a..72ad161e57 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -890,6 +890,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:
@@ -908,6 +923,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 e1ce8b4ddc..1763dd67a3 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..e61544199b 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -200,6 +200,8 @@ create_estate_for_relation(LogicalRepRelMapEntry *rel)
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/execPartition.h b/src/include/executor/execPartition.h
index f6cd842cc9..48d4997661 100644
--- a/src/include/executor/execPartition.h
+++ b/src/include/executor/execPartition.h
@@ -225,7 +225,6 @@ extern void ExecCleanupTupleRouting(ModifyTableState *mtstate,
PartitionTupleRouting *proute);
extern PartitionPruneState *ExecCreatePartitionPruneState(PlanState *planstate,
PartitionPruneInfo *partitionpruneinfo);
-extern void ExecDestroyPartitionPruneState(PartitionPruneState *prunestate);
extern Bitmapset *ExecFindMatchingSubPlans(PartitionPruneState *prunestate);
extern Bitmapset *ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate,
int nsubplans);
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 1d2b48fe09..93259a4ffa 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"
/*
@@ -478,6 +479,7 @@ extern ExprContext *CreateExprContext(EState *estate);
extern ExprContext *CreateStandaloneExprContext(void);
extern void FreeExprContext(ExprContext *econtext, bool isCommit);
extern void ReScanExprContext(ExprContext *econtext);
+extern void ExecInitRangeTable(EState *estate, List *rangeTable);
#define ResetExprContext(econtext) \
MemoryContextReset((econtext)->ecxt_per_tuple_memory)
@@ -513,7 +515,6 @@ extern void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate
extern bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid);
extern Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags);
-extern void ExecCloseScanRelation(Relation scanrel);
extern int executor_errposition(EState *estate, int location);
@@ -568,4 +569,25 @@ 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)
+{
+ Relation rel = estate->es_relations[rti - 1];
+
+ if (rel == NULL)
+ {
+ RangeTblEntry *rte = exec_rt_fetch(rti, estate->es_range_table_array);
+
+ /*
+ * No need to lock the relation lock, because upstream code
+ * must hold the lock already.
+ */
+ 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..d669a3fada 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 */
@@ -574,6 +578,22 @@ typedef struct EState
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 ceec266a21..59dd26b04e 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -1092,7 +1092,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
Hi Amit,
On 9/12/18 1:23 AM, Amit Langote wrote:
Please find attached revised patches.
After applying 0004 I'm getting a crash in 'eval-plan-qual' during
check-world using
export CFLAGS="-DCOPY_PARSE_PLAN_TREES -O0 -fno-omit-frame-pointer" &&
./configure --enable-dtrace --with-openssl --with-gssapi --with-libxml
--with-llvm --enable-debug --enable-depend --enable-tap-tests
--enable-cassert
Confirmed by CFBot in [1]https://travis-ci.org/postgresql-cfbot/postgresql/builds/427530296.
[1]: https://travis-ci.org/postgresql-cfbot/postgresql/builds/427530296
Best regards,
Jesper
On Wed, Sep 12, 2018 at 9:23 PM, Jesper Pedersen
<jesper.pedersen@redhat.com> wrote:
Hi Amit,
On 9/12/18 1:23 AM, Amit Langote wrote:
Please find attached revised patches.
After applying 0004 I'm getting a crash in 'eval-plan-qual' during
check-world usingexport CFLAGS="-DCOPY_PARSE_PLAN_TREES -O0 -fno-omit-frame-pointer" &&
./configure --enable-dtrace --with-openssl --with-gssapi --with-libxml
--with-llvm --enable-debug --enable-depend --enable-tap-tests
--enable-cassertConfirmed by CFBot in [1].
[1] https://travis-ci.org/postgresql-cfbot/postgresql/builds/427530296
Thanks Jesper. Will look into it first thing tomorrow morning.
Thanks,
Amit
On 2018/09/13 0:23, Amit Langote wrote:
On Wed, Sep 12, 2018 at 9:23 PM, Jesper Pedersen
<jesper.pedersen@redhat.com> wrote:Hi Amit,
On 9/12/18 1:23 AM, Amit Langote wrote:
Please find attached revised patches.
After applying 0004 I'm getting a crash in 'eval-plan-qual' during
check-world usingexport CFLAGS="-DCOPY_PARSE_PLAN_TREES -O0 -fno-omit-frame-pointer" &&
./configure --enable-dtrace --with-openssl --with-gssapi --with-libxml
--with-llvm --enable-debug --enable-depend --enable-tap-tests
--enable-cassertConfirmed by CFBot in [1].
[1] https://travis-ci.org/postgresql-cfbot/postgresql/builds/427530296
Thanks Jesper. Will look into it first thing tomorrow morning.
Attached updated patches.
Beside the issue that caused eval-plan-qual isolation test to crash, I
also spotted and fixed an oversight in the 0002 patch which would lead to
EState.es_output_cid being set to wrong value and causing unexpected error
during tuple locking as result of that.
Thanks,
Amit
Attachments:
v4-0001-Don-t-lock-range-table-relations-in-the-executor.patchtext/plain; charset=UTF-8; name=v4-0001-Don-t-lock-range-table-relations-in-the-executor.patchDownload
From 531a872b4b016fe90b439e88d2698ce2a4cea87b Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Thu, 19 Jul 2018 16:14:51 +0900
Subject: [PATCH v4 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/catalog/heap.c | 3 +-
src/backend/commands/copy.c | 7 +-
src/backend/commands/policy.c | 17 +-
src/backend/commands/tablecmds.c | 2 +-
src/backend/commands/trigger.c | 4 +-
src/backend/commands/view.c | 6 +-
src/backend/executor/execMain.c | 265 ++++++++---------------
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 | 3 +-
src/backend/parser/parse_clause.c | 3 +-
src/backend/parser/parse_relation.c | 9 +-
src/backend/parser/parse_utilcmd.c | 18 +-
src/backend/replication/logical/tablesync.c | 2 +-
src/backend/rewrite/rewriteHandler.c | 20 +-
src/backend/storage/lmgr/lmgr.c | 6 +-
src/backend/utils/cache/plancache.c | 30 +--
src/include/executor/executor.h | 2 +-
src/include/nodes/parsenodes.h | 3 +
src/include/parser/parse_relation.h | 4 +-
src/include/storage/lmgr.h | 2 +-
src/test/modules/test_rls_hooks/test_rls_hooks.c | 4 +-
28 files changed, 207 insertions(+), 276 deletions(-)
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 9176f6280b..19b530ac94 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -2551,7 +2551,8 @@ AddRelationNewConstraints(Relation rel,
rel,
NULL,
false,
- true);
+ true,
+ NoLock);
addRTEtoQuery(pstate, rte, true, true, true);
/*
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 9bc67ce60f..0f8be85303 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -837,16 +837,17 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
List *attnums;
ListCell *cur;
RangeTblEntry *rte;
+ int lockmode = is_from ? RowExclusiveLock : AccessShareLock;
Assert(!stmt->query);
/* Open and lock the relation, using the appropriate lock type. */
- rel = heap_openrv(stmt->relation,
- (is_from ? RowExclusiveLock : AccessShareLock));
+ rel = heap_openrv(stmt->relation, lockmode);
relid = RelationGetRelid(rel);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, false);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, false,
+ lockmode);
rte->requiredPerms = (is_from ? ACL_INSERT : ACL_SELECT);
tupDesc = RelationGetDescr(rel);
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index cee0ef915b..09a6a7f9d3 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -567,7 +567,8 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
qual_expr = stringToNode(qual_value);
/* Add this rel to the parsestate's rangetable, for dependencies */
- addRangeTableEntryForRelation(qual_pstate, rel, NULL, false, false);
+ addRangeTableEntryForRelation(qual_pstate, rel, NULL, false, false,
+ NoLock);
qual_parse_rtable = qual_pstate->p_rtable;
free_parsestate(qual_pstate);
@@ -590,7 +591,7 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(with_check_pstate, rel, NULL, false,
- false);
+ false, NoLock);
with_check_parse_rtable = with_check_pstate->p_rtable;
free_parsestate(with_check_pstate);
@@ -752,12 +753,12 @@ CreatePolicy(CreatePolicyStmt *stmt)
/* Add for the regular security quals */
rte = addRangeTableEntryForRelation(qual_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
/* Add for the with-check quals */
rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(with_check_pstate, rte, false, true, true);
qual = transformWhereClause(qual_pstate,
@@ -928,7 +929,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
ParseState *qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
@@ -950,7 +951,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
ParseState *with_check_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(with_check_pstate, rte, false, true, true);
@@ -1097,7 +1098,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(qual_pstate, target_table, NULL,
- false, false);
+ false, false, NoLock);
qual_parse_rtable = qual_pstate->p_rtable;
free_parsestate(qual_pstate);
@@ -1138,7 +1139,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(with_check_pstate, target_table, NULL,
- false, false);
+ false, false, NoLock);
with_check_parse_rtable = with_check_pstate->p_rtable;
free_parsestate(with_check_pstate);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index e96512e051..dbdbbde9e8 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -13659,7 +13659,7 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
* rangetable entry. We need a ParseState for transformExpr.
*/
pstate = make_parsestate(NULL);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true, NoLock);
addRTEtoQuery(pstate, rte, true, true, true);
/* take care of any partition expressions */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 2436692eb8..ce9acef1c2 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -578,11 +578,11 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
*/
rte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false, NoLock);
addRTEtoQuery(pstate, rte, false, true, true);
rte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false, NoLock);
addRTEtoQuery(pstate, rte, false, true, true);
/* Transform expression. Copy to be sure we don't modify original */
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index ffb71c0ea7..4c379fd83b 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -387,10 +387,12 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
*/
rt_entry1 = addRangeTableEntryForRelation(pstate, viewRel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessShareLock);
rt_entry2 = addRangeTableEntryForRelation(pstate, viewRel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ 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..f797cdfe7c 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,60 @@ 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);
+
+ 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 +3057,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 +3170,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..d2f90c2de6 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -1038,7 +1038,8 @@ transformOnConflictClause(ParseState *pstate,
exclRte = addRangeTableEntryForRelation(pstate,
targetrel,
makeAlias("excluded", NIL),
- false, false);
+ false, false,
+ RowExclusiveLock);
exclRte->relkind = RELKIND_COMPOSITE_TYPE;
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..5358042f89 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -217,7 +217,8 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
* Now build an RTE.
*/
rte = addRangeTableEntryForRelation(pstate, pstate->p_target_relation,
- relation->alias, inh, false);
+ relation->alias, inh, false,
+ 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..37b4c79126 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
@@ -1262,13 +1263,18 @@ addRangeTableEntry(ParseState *pstate,
*
* This is just like addRangeTableEntry() except that it makes an RTE
* given an already-open relation instead of a RangeVar reference.
+ *
+ * 'lockmode' is the lock taken on 'rel'. The caller may pass NoLock if the
+ * RTE won't be passed to the executor, that is, won't be part of a
+ * PlannedStmt.
*/
RangeTblEntry *
addRangeTableEntryForRelation(ParseState *pstate,
Relation rel,
Alias *alias,
bool inh,
- bool inFromCl)
+ bool inFromCl,
+ LOCKMODE lockmode)
{
RangeTblEntry *rte = makeNode(RangeTblEntry);
char *refname = alias ? alias->aliasname : RelationGetRelationName(rel);
@@ -1279,6 +1285,7 @@ addRangeTableEntryForRelation(ParseState *pstate,
rte->alias = alias;
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 f5c1e2a0d7..14adac8312 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -2526,7 +2526,8 @@ transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
* relation, but we still need to open it.
*/
rel = relation_open(relid, NoLock);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true,
+ NoLock);
/* no to join list, yes to namespaces */
addRTEtoQuery(pstate, rte, false, true, true);
@@ -2636,10 +2637,12 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
*/
oldrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessShareLock);
newrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ AccessShareLock);
/* Must override addRangeTableEntry's default access-check flags */
oldrte->requiredPerms = 0;
newrte->requiredPerms = 0;
@@ -2734,10 +2737,12 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
*/
oldrte = addRangeTableEntryForRelation(sub_pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessShareLock);
newrte = addRangeTableEntryForRelation(sub_pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ AccessShareLock);
oldrte->requiredPerms = 0;
newrte->requiredPerms = 0;
addRTEtoQuery(sub_pstate, oldrte, false, true, false);
@@ -2940,7 +2945,8 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
rel,
NULL,
false,
- true);
+ true,
+ NoLock);
addRTEtoQuery(pstate, rte, false, true, true);
/* Set up CreateStmtContext */
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index acc6498567..905a983074 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -795,7 +795,7 @@ copy_table(Relation rel)
copybuf = makeStringInfo();
pstate = make_parsestate(NULL);
- addRangeTableEntryForRelation(pstate, rel, NULL, false, false);
+ addRangeTableEntryForRelation(pstate, rel, NULL, false, false, NoLock);
attnamelist = make_copy_attnamelist(relmapentry);
cstate = BeginCopyFrom(pstate, rel, NULL, false, copy_read_data, attnamelist, NIL);
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index d830569641..d5a928671e 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
@@ -3100,7 +3087,8 @@ rewriteTargetView(Query *parsetree, Relation view)
base_rel,
makeAlias("excluded",
NIL),
- false, false);
+ false, false,
+ RowExclusiveLock);
new_exclRte->relkind = RELKIND_COMPOSITE_TYPE;
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 dc0a439638..b22d2d1457 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;
@@ -132,7 +133,10 @@ LockRelationOid(Oid relid, LOCKMODE lockmode)
{
AcceptInvalidationMessages();
MarkLockClear(locallock);
+ return true;
}
+
+ return res == LOCKACQUIRE_ALREADY_HELD;
}
/*
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 7271b5880b..1876345de5 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -1493,7 +1493,6 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
foreach(lc1, stmt_list)
{
PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
- int rt_index;
ListCell *lc2;
if (plannedstmt->commandType == CMD_UTILITY)
@@ -1512,14 +1511,9 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
continue;
}
- rt_index = 0;
foreach(lc2, plannedstmt->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
- LOCKMODE lockmode;
- PlanRowMark *rc;
-
- rt_index++;
if (rte->rtekind != RTE_RELATION)
continue;
@@ -1530,19 +1524,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 +1581,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..a0ce4109e2 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -27,6 +27,7 @@
#include "nodes/primnodes.h"
#include "nodes/value.h"
#include "partitioning/partdefs.h"
+#include "storage/lockdefs.h"
typedef enum OverridingKind
@@ -977,6 +978,8 @@ typedef struct RangeTblEntry
*/
Oid relid; /* OID of the relation */
char relkind; /* relation kind (see pg_class.relkind) */
+ LOCKMODE lockmode; /* lock level to obtain on the relation, or
+ * 0 if no lock required */
struct TableSampleClause *tablesample; /* sampling info, or NULL */
/*
diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h
index b9792acdae..99d1b4135c 100644
--- a/src/include/parser/parse_relation.h
+++ b/src/include/parser/parse_relation.h
@@ -15,6 +15,7 @@
#define PARSE_RELATION_H
#include "parser/parse_node.h"
+#include "storage/lockdefs.h"
/*
@@ -71,7 +72,8 @@ extern RangeTblEntry *addRangeTableEntryForRelation(ParseState *pstate,
Relation rel,
Alias *alias,
bool inh,
- bool inFromCl);
+ bool inFromCl,
+ LOCKMODE lockmode);
extern RangeTblEntry *addRangeTableEntryForSubquery(ParseState *pstate,
Query *subquery,
Alias *alias,
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);
diff --git a/src/test/modules/test_rls_hooks/test_rls_hooks.c b/src/test/modules/test_rls_hooks/test_rls_hooks.c
index cab67a60aa..d455c97ef6 100644
--- a/src/test/modules/test_rls_hooks/test_rls_hooks.c
+++ b/src/test/modules/test_rls_hooks/test_rls_hooks.c
@@ -81,7 +81,7 @@ test_rls_hooks_permissive(CmdType cmdtype, Relation relation)
qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, relation, NULL, false,
- false);
+ false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
@@ -144,7 +144,7 @@ test_rls_hooks_restrictive(CmdType cmdtype, Relation relation)
qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, relation, NULL, false,
- false);
+ false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
--
2.11.0
v4-0002-Remove-useless-fields-from-planner-nodes.patchtext/plain; charset=UTF-8; name=v4-0002-Remove-useless-fields-from-planner-nodes.patchDownload
From 5fef352b9ce73c9ffbfa4b49e5c7e425c2e4da75 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Mon, 13 Aug 2018 16:10:19 +0900
Subject: [PATCH v4 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 bool field called
'partitionedTarget', which is set if the target is a partitioned
table. The table itself is identified by nominalRelation.
* '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 | 10 +++---
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 | 51 ++++++------------------------
src/backend/optimizer/plan/setrefs.c | 47 +++-------------------------
src/backend/optimizer/util/pathnode.c | 8 ++---
src/backend/tcop/utility.c | 15 +++++++--
src/include/executor/executor.h | 2 --
src/include/nodes/plannodes.h | 29 +++++------------
src/include/nodes/relation.h | 9 ++----
src/include/optimizer/pathnode.h | 2 +-
20 files changed, 64 insertions(+), 254 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 f797cdfe7c..e84ebe0c87 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..ab4ec575fc 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2255,18 +2255,18 @@ 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->partitionedTarget);
+ /* nominalRelation is the index of the target partitioned table. */
+ rte = rt_fetch(node->nominalRelation, estate->es_range_table);
rel = heap_open(rte->relid, NoLock);
- InitResultRelInfo(mtstate->rootResultRelInfo, rel, root_rt_index,
- NULL, estate->es_instrument);
+ InitResultRelInfo(mtstate->rootResultRelInfo, rel,
+ node->nominalRelation, NULL, estate->es_instrument);
}
mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 11ca800e4c..1bee240e72 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -1358,7 +1358,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
@@ -1374,7 +1374,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..b0193a94a9 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(partitionedTarget);
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..36d46f5d8f 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_BOOL_FIELD(partitionedTarget);
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_BOOL_FIELD(partitionedTarget);
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..4d1317e339 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_BOOL_FIELD(partitionedTarget);
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..becc5ef75d 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, bool partitionedTarget,
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->partitionedTarget,
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, bool partitionedTarget,
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->partitionedTarget = partitionedTarget;
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..44884c29c6 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -276,6 +276,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
Plan *top_plan;
ListCell *lp,
*lr;
+ bool hasRowMarks = (parse->rowMarks != NIL);
/*
* Set up global state for this planner invocation. This data is needed
@@ -290,9 +291,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 +489,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) */
@@ -503,6 +500,8 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
PlannerInfo *subroot = lfirst_node(PlannerInfo, lr);
lfirst(lp) = set_plan_references(subroot, subplan);
+ if (subroot->rowMarks != NIL)
+ hasRowMarks = true;
}
/* build the PlannedStmt result */
@@ -512,6 +511,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
result->queryId = parse->queryId;
result->hasReturning = (parse->returningList != NIL);
result->hasModifyingCTE = parse->hasModifyingCTE;
+ result->hasRowMarks = hasRowMarks;
result->canSetTag = parse->canSetTag;
result->transientPlan = glob->transientPlan;
result->dependsOnRole = glob->dependsOnRole;
@@ -519,11 +519,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;
@@ -1173,8 +1171,7 @@ inheritance_planner(PlannerInfo *root)
ListCell *lc;
Index rti;
RangeTblEntry *parent_rte;
- Relids partitioned_relids = NULL;
- List *partitioned_rels = NIL;
+ bool partitionedTarget = false;
PlannerInfo *parent_root;
Query *parent_parse;
Bitmapset *parent_relids = bms_make_singleton(top_parentRTindex);
@@ -1250,12 +1247,7 @@ inheritance_planner(PlannerInfo *root)
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);
+ partitionedTarget = true;
}
/*
@@ -1327,7 +1319,7 @@ inheritance_planner(PlannerInfo *root)
* inheritance parent.
*/
subroot->inhTargetKind =
- partitioned_relids ? INHKIND_PARTITIONED : INHKIND_INHERITED;
+ partitionedTarget ? INHKIND_PARTITIONED : INHKIND_INHERITED;
/*
* If this child is further partitioned, remember it as a parent.
@@ -1498,15 +1490,6 @@ inheritance_planner(PlannerInfo *root)
continue;
/*
- * Add the current parent's RT index to the partitioned_relids set if
- * we're creating the ModifyTable path for a partitioned root table.
- * (We only care about parents of non-excluded children.)
- */
- if (partitioned_relids)
- partitioned_relids = bms_add_member(partitioned_relids,
- appinfo->parent_relid);
-
- /*
* If this is the first non-excluded child, its post-planning rtable
* becomes the initial contents of final_rtable; otherwise, append
* just its modified subquery RTEs to final_rtable.
@@ -1609,29 +1592,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,
+ partitionedTarget,
root->partColsUpdated,
resultRelations,
subpaths,
@@ -2208,7 +2175,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..a8ec0be83a 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);
}
@@ -850,10 +830,6 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
splan->nominalRelation += rtoffset;
splan->exclRelRTI += rtoffset;
- foreach(l, splan->partitioned_rels)
- {
- lfirst_int(l) += rtoffset;
- }
foreach(l, splan->resultRelations)
{
lfirst_int(l) += rtoffset;
@@ -884,24 +860,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->partitionedTarget)
{
- 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->nominalRelation);
}
}
break;
@@ -915,10 +884,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 +902,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..28f90a2a04 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, bool partitionedTarget,
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->partitionedTarget = partitionedTarget;
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..d0427c64ba 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
+ 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..ceec266a21 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 */
@@ -219,9 +212,9 @@ typedef struct ModifyTable
Plan plan;
CmdType operation; /* INSERT, UPDATE, or DELETE */
bool canSetTag; /* do we set the command tag/es_processed? */
- Index nominalRelation; /* Parent RT index for use of EXPLAIN */
- /* RT indexes of non-leaf tables in a partition tree */
- List *partitioned_rels;
+ Index nominalRelation; /* RT index of the target table specified
+ * in the command */
+ bool partitionedTarget; /* is the target table partitioned? */
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 +252,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 +264,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 +915,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..c9f288c24d 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 */
@@ -1716,9 +1713,9 @@ typedef struct ModifyTablePath
Path path;
CmdType operation; /* INSERT, UPDATE, or DELETE */
bool canSetTag; /* do we set the command tag/es_processed? */
- Index nominalRelation; /* Parent RT index for use of EXPLAIN */
- /* RT indexes of non-leaf tables in a partition tree */
- List *partitioned_rels;
+ Index nominalRelation; /* RT index of the target table specified
+ * in the command */
+ bool partitionedTarget; /* is the target table partitioned? */
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..d826e3cc55 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, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subpaths,
List *subroots,
--
2.11.0
v4-0003-Prune-PlanRowMark-of-relations-that-are-pruned-fr.patchtext/plain; charset=UTF-8; name=v4-0003-Prune-PlanRowMark-of-relations-that-are-pruned-fr.patchDownload
From f05920a67c272b0c8464b09cccaac3e921a2c8d7 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 14 Aug 2018 10:35:47 +0900
Subject: [PATCH v4 3/4] Prune PlanRowMark of relations that are pruned from a
plan
---
src/backend/optimizer/plan/planner.c | 31 ++++++++++++++++++++++++++-----
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 44884c29c6..b03cdb13c7 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -237,6 +237,7 @@ static void create_partitionwise_grouping_paths(PlannerInfo *root,
static bool group_by_has_partkey(RelOptInfo *input_rel,
List *targetList,
List *groupClause);
+static List *get_unpruned_rowmarks(PlannerInfo *root);
/*****************************************************************************
@@ -1590,7 +1591,7 @@ inheritance_planner(PlannerInfo *root)
if (parse->rowMarks)
rowMarks = NIL;
else
- rowMarks = root->rowMarks;
+ rowMarks = get_unpruned_rowmarks(root);
/* Create Path representing a ModifyTable to do the UPDATE/DELETE work */
add_path(final_rel, (Path *)
@@ -2119,11 +2120,9 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
* is what goes into the LockRows node.)
*/
if (parse->rowMarks)
- {
path = (Path *) create_lockrows_path(root, final_rel, path,
- root->rowMarks,
+ get_unpruned_rowmarks(root),
SS_assign_special_param(root));
- }
/*
* If there is a LIMIT/OFFSET clause, add the LIMIT node.
@@ -2168,7 +2167,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
if (parse->rowMarks)
rowMarks = NIL;
else
- rowMarks = root->rowMarks;
+ rowMarks = get_unpruned_rowmarks(root);
path = (Path *)
create_modifytable_path(root, final_rel,
@@ -7162,3 +7161,25 @@ group_by_has_partkey(RelOptInfo *input_rel,
return true;
}
+
+/*
+ * get_unpruned_rowmarks
+ * Return a list of PlanRowMark's that reference unpruned relations
+ */
+static List *
+get_unpruned_rowmarks(PlannerInfo *root)
+{
+ List *rowMarks = NIL;
+ ListCell *lc;
+
+ 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]))
+ rowMarks = lappend(rowMarks, rc);
+ }
+
+ return rowMarks;
+}
--
2.11.0
v4-0004-Revise-executor-range-table-relation-opening-clos.patchtext/plain; charset=UTF-8; name=v4-0004-Revise-executor-range-table-relation-opening-clos.patchDownload
From 7eadf4055cfaee9a0f26514a5cd172c4f9e51955 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Thu, 19 Jul 2018 13:01:43 +0900
Subject: [PATCH v4 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, an arrangement which allows the executor
to have to heap_open any given range table relation only once.
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 | 16 +++----
src/backend/commands/copy.c | 3 +-
src/backend/commands/trigger.c | 3 +-
src/backend/executor/execExprInterp.c | 7 +--
src/backend/executor/execMain.c | 80 ++++++++++---------------------
src/backend/executor/execPartition.c | 36 +++-----------
src/backend/executor/execUtils.c | 64 ++++++++++++++++---------
src/backend/executor/nodeAppend.c | 6 ---
src/backend/executor/nodeBitmapHeapscan.c | 7 ---
src/backend/executor/nodeCustom.c | 4 --
src/backend/executor/nodeForeignscan.c | 4 --
src/backend/executor/nodeIndexonlyscan.c | 7 ---
src/backend/executor/nodeIndexscan.c | 7 ---
src/backend/executor/nodeLockRows.c | 2 +-
src/backend/executor/nodeMergeAppend.c | 6 ---
src/backend/executor/nodeModifyTable.c | 21 ++++----
src/backend/executor/nodeSamplescan.c | 5 --
src/backend/executor/nodeSeqscan.c | 7 ---
src/backend/executor/nodeTidscan.c | 5 --
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 | 2 +
src/include/executor/execPartition.h | 1 -
src/include/executor/executor.h | 24 +++++++++-
src/include/nodes/execnodes.h | 22 ++++++++-
src/include/nodes/plannodes.h | 2 +-
src/include/parser/parsetree.h | 10 ----
30 files changed, 175 insertions(+), 217 deletions(-)
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index e4e330397e..4d2f5e448e 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. */
@@ -2547,10 +2547,6 @@ postgresEndDirectModify(ForeignScanState *node)
ReleaseConnection(dmstate->conn);
dmstate->conn = NULL;
- /* close the target relation. */
- if (dmstate->resultRel)
- ExecCloseScanRelation(dmstate->resultRel);
-
/* MemoryContext will be deleted automatically. */
}
@@ -5757,7 +5753,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 0f8be85303..b3d34307f6 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -2483,7 +2483,8 @@ 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;
+
+ ExecInitRangeTable(estate, cstate->range_table);
/* 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 ce9acef1c2..afbb6311af 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 e84ebe0c87..dbba4e9e81 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 */
@@ -820,30 +820,17 @@ 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
*/
- estate->es_range_table = rangeTable;
+ ExecInitRangeTable(estate, rangeTable);
+
+ /*
+ * Just initialize 0-filled array of Relation pointers. Actual values are
+ * filled later as the plan is initialized.
+ */
+ estate->es_relations = (Relation *) palloc0(estate->es_range_table_size *
+ sizeof(Relation));
estate->es_plannedstmt = plannedstmt;
/*
@@ -1488,6 +1475,12 @@ static void
ExecEndPlan(PlanState *planstate, EState *estate)
{
ListCell *l;
+ int i;
+
+ /* Close range table relations. */
+ for (i = 0; i < estate->es_range_table_size; i++)
+ if (estate->es_relations[i])
+ heap_close(estate->es_relations[i], NoLock);
/*
* shut down the node-type-specific query processing
@@ -1514,18 +1507,6 @@ ExecEndPlan(PlanState *planstate, EState *estate)
/* likewise close any trigger target relations */
ExecCleanUpTriggerState(estate);
-
- /*
- * 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);
- }
}
/* ----------------------------------------------------------------
@@ -2278,24 +2259,20 @@ 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);
-
switch (rc->markType)
{
case ROW_MARK_EXCLUSIVE:
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 */
@@ -2313,7 +2290,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;
@@ -2971,7 +2948,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));
@@ -3016,7 +2993,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();
@@ -3040,6 +3017,9 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree)
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_range_table_size = parentestate->es_range_table_size;
+ 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;
@@ -3170,18 +3150,6 @@ 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 81c2f5cedc..197175f106 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);
@@ -1593,30 +1593,6 @@ ExecCreatePartitionPruneState(PlanState *planstate,
}
/*
- * ExecDestroyPartitionPruneState
- * Release resources at plan shutdown.
- *
- * We don't bother to free any memory here, since the whole executor context
- * will be going away shortly. We do need to release our relcache pins.
- */
-void
-ExecDestroyPartitionPruneState(PartitionPruneState *prunestate)
-{
- PartitionPruningData **partprunedata = prunestate->partprunedata;
- int i;
-
- for (i = 0; i < prunestate->num_partprunedata; i++)
- {
- PartitionPruningData *prunedata = partprunedata[i];
- PartitionedRelPruningData *pprune = prunedata->partrelprunedata;
- int j;
-
- for (j = 0; j < prunedata->num_partrelprunedata; j++)
- relation_close(pprune[j].context.partrel, NoLock);
- }
-}
-
-/*
* ExecFindInitialMatchingSubPlans
* Identify the set of subplans that cannot be eliminated by initial
* pruning (disregarding any pruning constraints involving PARAM_EXEC
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index d32796aac3..abee92ee59 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
@@ -675,26 +673,6 @@ ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
return rel;
}
-/* ----------------------------------------------------------------
- * ExecCloseScanRelation
- *
- * Close the heap relation scanned by a base-level scan plan node.
- * This should be called during the node's ExecEnd routine.
- *
- * Currently, we do not release the lock acquired by ExecOpenScanRelation.
- * This lock should be held till end of transaction. (There is a faction
- * that considers this too much locking, however.)
- *
- * If we did want to release the lock, we'd have to repeat the logic in
- * ExecOpenScanRelation in order to figure out what to release.
- * ----------------------------------------------------------------
- */
-void
-ExecCloseScanRelation(Relation scanrel)
-{
- heap_close(scanrel, NoLock);
-}
-
/*
* UpdateChangedParamSet
* Add changed parameters to a plan node's chgParam set
@@ -997,3 +975,43 @@ ExecCleanTargetListLength(List *targetlist)
}
return len;
}
+
+/*
+ * Initialize executor's range table array
+ */
+void
+ExecInitRangeTable(EState *estate, List *rangeTable)
+{
+ int rti;
+ ListCell *l;
+
+#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
+
+ Assert(estate != NULL);
+ 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 *));
+ rti = 0;
+ foreach(l, rangeTable)
+ estate->es_range_table_array[rti++] = lfirst_node(RangeTblEntry, l);
+}
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index eb587be221..a16b6da474 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -329,12 +329,6 @@ ExecEndAppend(AppendState *node)
*/
for (i = 0; i < nplans; i++)
ExecEndNode(appendplans[i]);
-
- /*
- * release any resources associated with run-time pruning
- */
- if (node->as_prune_state)
- ExecDestroyPartitionPruneState(node->as_prune_state);
}
void
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index 3e1c9e0714..2c4d67898e 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -786,13 +786,11 @@ ExecReScanBitmapHeapScan(BitmapHeapScanState *node)
void
ExecEndBitmapHeapScan(BitmapHeapScanState *node)
{
- Relation relation;
HeapScanDesc scanDesc;
/*
* extract information from the node
*/
- relation = node->ss.ss_currentRelation;
scanDesc = node->ss.ss_currentScanDesc;
/*
@@ -833,11 +831,6 @@ ExecEndBitmapHeapScan(BitmapHeapScanState *node)
* close heap scan
*/
heap_endscan(scanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index b816e0b31d..9a33eda688 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -126,10 +126,6 @@ ExecEndCustomScan(CustomScanState *node)
/* Clean out the tuple table */
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /* Close the heap relation */
- if (node->ss.ss_currentRelation)
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
void
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index a2a28b7ec2..cf7df72d8c 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -258,10 +258,6 @@ ExecEndForeignScan(ForeignScanState *node)
/* clean out the tuple table */
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /* close the relation. */
- if (node->ss.ss_currentRelation)
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 8c32a74d39..4a2b41d255 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -373,14 +373,12 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node)
{
Relation indexRelationDesc;
IndexScanDesc indexScanDesc;
- Relation relation;
/*
* extract information from the node
*/
indexRelationDesc = node->ioss_RelationDesc;
indexScanDesc = node->ioss_ScanDesc;
- relation = node->ss.ss_currentRelation;
/* Release VM buffer pin, if any. */
if (node->ioss_VMBuffer != InvalidBuffer)
@@ -411,11 +409,6 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node)
index_endscan(indexScanDesc);
if (indexRelationDesc)
index_close(indexRelationDesc, NoLock);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 10891bc3f4..bf528465ce 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -804,14 +804,12 @@ ExecEndIndexScan(IndexScanState *node)
{
Relation indexRelationDesc;
IndexScanDesc indexScanDesc;
- Relation relation;
/*
* extract information from the node
*/
indexRelationDesc = node->iss_RelationDesc;
indexScanDesc = node->iss_ScanDesc;
- relation = node->ss.ss_currentRelation;
/*
* Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
@@ -835,11 +833,6 @@ ExecEndIndexScan(IndexScanState *node)
index_endscan(indexScanDesc);
if (indexRelationDesc)
index_close(indexRelationDesc, NoLock);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
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/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index d8e0978966..5d0dbb8146 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -363,12 +363,6 @@ ExecEndMergeAppend(MergeAppendState *node)
*/
for (i = 0; i < nplans; i++)
ExecEndNode(mergeplans[i]);
-
- /*
- * release any resources associated with run-time pruning
- */
- if (node->ms_prune_state)
- ExecDestroyPartitionPruneState(node->ms_prune_state);
}
void
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index ab4ec575fc..ccbf4c0f73 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,7 +2254,6 @@ 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 +
@@ -2263,10 +2261,12 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
Assert(node->partitionedTarget);
/* nominalRelation is the index of the target partitioned table. */
- rte = rt_fetch(node->nominalRelation, estate->es_range_table);
- rel = heap_open(rte->relid, NoLock);
- InitResultRelInfo(mtstate->rootResultRelInfo, rel,
- node->nominalRelation, NULL, estate->es_instrument);
+ rel = ExecRangeTableRelation(estate, node->nominalRelation);
+ InitResultRelInfo(mtstate->rootResultRelInfo,
+ rel,
+ node->nominalRelation,
+ NULL,
+ estate->es_instrument);
}
mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
@@ -2727,14 +2727,9 @@ ExecEndModifyTable(ModifyTableState *node)
/* 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/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index 15177dbed7..491f8d48fd 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -223,11 +223,6 @@ ExecEndSampleScan(SampleScanState *node)
*/
if (node->ss.ss_currentScanDesc)
heap_endscan(node->ss.ss_currentScanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index c7849de6bc..2f43989e85 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -202,13 +202,11 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
void
ExecEndSeqScan(SeqScanState *node)
{
- Relation relation;
HeapScanDesc scanDesc;
/*
* get information from node
*/
- relation = node->ss.ss_currentRelation;
scanDesc = node->ss.ss_currentScanDesc;
/*
@@ -227,11 +225,6 @@ ExecEndSeqScan(SeqScanState *node)
*/
if (scanDesc != NULL)
heap_endscan(scanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index e207b1ffb5..a3e62e4c9f 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -491,11 +491,6 @@ ExecEndTidScan(TidScanState *node)
*/
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index b0193a94a9..cde0cd7c16 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 36d46f5d8f..aba0c6bbd1 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 4d1317e339..1d9810dbfd 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 a8ec0be83a..72ad161e57 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -890,6 +890,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:
@@ -908,6 +923,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 e1ce8b4ddc..1763dd67a3 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..e61544199b 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -200,6 +200,8 @@ create_estate_for_relation(LogicalRepRelMapEntry *rel)
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/execPartition.h b/src/include/executor/execPartition.h
index f6cd842cc9..48d4997661 100644
--- a/src/include/executor/execPartition.h
+++ b/src/include/executor/execPartition.h
@@ -225,7 +225,6 @@ extern void ExecCleanupTupleRouting(ModifyTableState *mtstate,
PartitionTupleRouting *proute);
extern PartitionPruneState *ExecCreatePartitionPruneState(PlanState *planstate,
PartitionPruneInfo *partitionpruneinfo);
-extern void ExecDestroyPartitionPruneState(PartitionPruneState *prunestate);
extern Bitmapset *ExecFindMatchingSubPlans(PartitionPruneState *prunestate);
extern Bitmapset *ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate,
int nsubplans);
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 1d2b48fe09..93259a4ffa 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"
/*
@@ -478,6 +479,7 @@ extern ExprContext *CreateExprContext(EState *estate);
extern ExprContext *CreateStandaloneExprContext(void);
extern void FreeExprContext(ExprContext *econtext, bool isCommit);
extern void ReScanExprContext(ExprContext *econtext);
+extern void ExecInitRangeTable(EState *estate, List *rangeTable);
#define ResetExprContext(econtext) \
MemoryContextReset((econtext)->ecxt_per_tuple_memory)
@@ -513,7 +515,6 @@ extern void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate
extern bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid);
extern Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags);
-extern void ExecCloseScanRelation(Relation scanrel);
extern int executor_errposition(EState *estate, int location);
@@ -568,4 +569,25 @@ 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)
+{
+ Relation rel = estate->es_relations[rti - 1];
+
+ if (rel == NULL)
+ {
+ RangeTblEntry *rte = exec_rt_fetch(rti, estate->es_range_table_array);
+
+ /*
+ * No need to lock the relation lock, because upstream code
+ * must hold the lock already.
+ */
+ 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..d669a3fada 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 */
@@ -574,6 +578,22 @@ typedef struct EState
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 ceec266a21..59dd26b04e 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -1092,7 +1092,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
Hi Amit,
On 9/13/18 12:58 AM, Amit Langote wrote:
Attached updated patches.
Beside the issue that caused eval-plan-qual isolation test to crash, I
also spotted and fixed an oversight in the 0002 patch which would lead to
EState.es_output_cid being set to wrong value and causing unexpected error
during tuple locking as result of that.
Thanks for the update.
However, the subscription TAP test
(src/test/subscription/t/001_rep_changes.pl) is still failing.
CFBot has the same log
https://travis-ci.org/postgresql-cfbot/postgresql/builds/427999969
as locally.
Best regards,
Jesper
Thanks again, Jesper.
On 2018/09/13 20:27, Jesper Pedersen wrote:
Hi Amit,
On 9/13/18 12:58 AM, Amit Langote wrote:
Attached updated patches.
Beside the issue that caused eval-plan-qual isolation test to crash, I
also spotted and fixed an oversight in the 0002 patch which would lead to
EState.es_output_cid being set to wrong value and causing unexpected error
during tuple locking as result of that.Thanks for the update.
However, the subscription TAP test
(src/test/subscription/t/001_rep_changes.pl) is still failing.CFBot has the same log
https://travis-ci.org/postgresql-cfbot/postgresql/builds/427999969
as locally.
My bad. I missed that logical replication code depends on the affected
executor code.
Fixed patches attached.
Thanks,
Amit
Attachments:
v5-0001-Don-t-lock-range-table-relations-in-the-executor.patchtext/plain; charset=UTF-8; name=v5-0001-Don-t-lock-range-table-relations-in-the-executor.patchDownload
From 52c004bd2be0b4541080b013828c2b55bd7c860b Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Thu, 19 Jul 2018 16:14:51 +0900
Subject: [PATCH v5 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/catalog/heap.c | 3 +-
src/backend/commands/copy.c | 7 +-
src/backend/commands/policy.c | 17 +-
src/backend/commands/tablecmds.c | 2 +-
src/backend/commands/trigger.c | 4 +-
src/backend/commands/view.c | 6 +-
src/backend/executor/execMain.c | 265 ++++++++---------------
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 | 3 +-
src/backend/parser/parse_clause.c | 3 +-
src/backend/parser/parse_relation.c | 9 +-
src/backend/parser/parse_utilcmd.c | 18 +-
src/backend/replication/logical/tablesync.c | 2 +-
src/backend/rewrite/rewriteHandler.c | 20 +-
src/backend/storage/lmgr/lmgr.c | 6 +-
src/backend/utils/cache/plancache.c | 30 +--
src/include/executor/executor.h | 2 +-
src/include/nodes/parsenodes.h | 3 +
src/include/parser/parse_relation.h | 4 +-
src/include/storage/lmgr.h | 2 +-
src/test/modules/test_rls_hooks/test_rls_hooks.c | 4 +-
28 files changed, 207 insertions(+), 276 deletions(-)
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 9176f6280b..19b530ac94 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -2551,7 +2551,8 @@ AddRelationNewConstraints(Relation rel,
rel,
NULL,
false,
- true);
+ true,
+ NoLock);
addRTEtoQuery(pstate, rte, true, true, true);
/*
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 9bc67ce60f..0f8be85303 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -837,16 +837,17 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
List *attnums;
ListCell *cur;
RangeTblEntry *rte;
+ int lockmode = is_from ? RowExclusiveLock : AccessShareLock;
Assert(!stmt->query);
/* Open and lock the relation, using the appropriate lock type. */
- rel = heap_openrv(stmt->relation,
- (is_from ? RowExclusiveLock : AccessShareLock));
+ rel = heap_openrv(stmt->relation, lockmode);
relid = RelationGetRelid(rel);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, false);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, false,
+ lockmode);
rte->requiredPerms = (is_from ? ACL_INSERT : ACL_SELECT);
tupDesc = RelationGetDescr(rel);
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index cee0ef915b..09a6a7f9d3 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -567,7 +567,8 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
qual_expr = stringToNode(qual_value);
/* Add this rel to the parsestate's rangetable, for dependencies */
- addRangeTableEntryForRelation(qual_pstate, rel, NULL, false, false);
+ addRangeTableEntryForRelation(qual_pstate, rel, NULL, false, false,
+ NoLock);
qual_parse_rtable = qual_pstate->p_rtable;
free_parsestate(qual_pstate);
@@ -590,7 +591,7 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(with_check_pstate, rel, NULL, false,
- false);
+ false, NoLock);
with_check_parse_rtable = with_check_pstate->p_rtable;
free_parsestate(with_check_pstate);
@@ -752,12 +753,12 @@ CreatePolicy(CreatePolicyStmt *stmt)
/* Add for the regular security quals */
rte = addRangeTableEntryForRelation(qual_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
/* Add for the with-check quals */
rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(with_check_pstate, rte, false, true, true);
qual = transformWhereClause(qual_pstate,
@@ -928,7 +929,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
ParseState *qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
@@ -950,7 +951,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
ParseState *with_check_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(with_check_pstate, rte, false, true, true);
@@ -1097,7 +1098,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(qual_pstate, target_table, NULL,
- false, false);
+ false, false, NoLock);
qual_parse_rtable = qual_pstate->p_rtable;
free_parsestate(qual_pstate);
@@ -1138,7 +1139,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(with_check_pstate, target_table, NULL,
- false, false);
+ false, false, NoLock);
with_check_parse_rtable = with_check_pstate->p_rtable;
free_parsestate(with_check_pstate);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index e96512e051..dbdbbde9e8 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -13659,7 +13659,7 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
* rangetable entry. We need a ParseState for transformExpr.
*/
pstate = make_parsestate(NULL);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true, NoLock);
addRTEtoQuery(pstate, rte, true, true, true);
/* take care of any partition expressions */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 2436692eb8..ce9acef1c2 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -578,11 +578,11 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
*/
rte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false, NoLock);
addRTEtoQuery(pstate, rte, false, true, true);
rte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false, NoLock);
addRTEtoQuery(pstate, rte, false, true, true);
/* Transform expression. Copy to be sure we don't modify original */
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index ffb71c0ea7..4c379fd83b 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -387,10 +387,12 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
*/
rt_entry1 = addRangeTableEntryForRelation(pstate, viewRel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessShareLock);
rt_entry2 = addRangeTableEntryForRelation(pstate, viewRel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ 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..f797cdfe7c 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,60 @@ 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);
+
+ 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 +3057,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 +3170,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..d2f90c2de6 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -1038,7 +1038,8 @@ transformOnConflictClause(ParseState *pstate,
exclRte = addRangeTableEntryForRelation(pstate,
targetrel,
makeAlias("excluded", NIL),
- false, false);
+ false, false,
+ RowExclusiveLock);
exclRte->relkind = RELKIND_COMPOSITE_TYPE;
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..5358042f89 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -217,7 +217,8 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
* Now build an RTE.
*/
rte = addRangeTableEntryForRelation(pstate, pstate->p_target_relation,
- relation->alias, inh, false);
+ relation->alias, inh, false,
+ 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..37b4c79126 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
@@ -1262,13 +1263,18 @@ addRangeTableEntry(ParseState *pstate,
*
* This is just like addRangeTableEntry() except that it makes an RTE
* given an already-open relation instead of a RangeVar reference.
+ *
+ * 'lockmode' is the lock taken on 'rel'. The caller may pass NoLock if the
+ * RTE won't be passed to the executor, that is, won't be part of a
+ * PlannedStmt.
*/
RangeTblEntry *
addRangeTableEntryForRelation(ParseState *pstate,
Relation rel,
Alias *alias,
bool inh,
- bool inFromCl)
+ bool inFromCl,
+ LOCKMODE lockmode)
{
RangeTblEntry *rte = makeNode(RangeTblEntry);
char *refname = alias ? alias->aliasname : RelationGetRelationName(rel);
@@ -1279,6 +1285,7 @@ addRangeTableEntryForRelation(ParseState *pstate,
rte->alias = alias;
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 f5c1e2a0d7..14adac8312 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -2526,7 +2526,8 @@ transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
* relation, but we still need to open it.
*/
rel = relation_open(relid, NoLock);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true,
+ NoLock);
/* no to join list, yes to namespaces */
addRTEtoQuery(pstate, rte, false, true, true);
@@ -2636,10 +2637,12 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
*/
oldrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessShareLock);
newrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ AccessShareLock);
/* Must override addRangeTableEntry's default access-check flags */
oldrte->requiredPerms = 0;
newrte->requiredPerms = 0;
@@ -2734,10 +2737,12 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
*/
oldrte = addRangeTableEntryForRelation(sub_pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessShareLock);
newrte = addRangeTableEntryForRelation(sub_pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ AccessShareLock);
oldrte->requiredPerms = 0;
newrte->requiredPerms = 0;
addRTEtoQuery(sub_pstate, oldrte, false, true, false);
@@ -2940,7 +2945,8 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
rel,
NULL,
false,
- true);
+ true,
+ NoLock);
addRTEtoQuery(pstate, rte, false, true, true);
/* Set up CreateStmtContext */
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index acc6498567..905a983074 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -795,7 +795,7 @@ copy_table(Relation rel)
copybuf = makeStringInfo();
pstate = make_parsestate(NULL);
- addRangeTableEntryForRelation(pstate, rel, NULL, false, false);
+ addRangeTableEntryForRelation(pstate, rel, NULL, false, false, NoLock);
attnamelist = make_copy_attnamelist(relmapentry);
cstate = BeginCopyFrom(pstate, rel, NULL, false, copy_read_data, attnamelist, NIL);
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index d830569641..d5a928671e 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
@@ -3100,7 +3087,8 @@ rewriteTargetView(Query *parsetree, Relation view)
base_rel,
makeAlias("excluded",
NIL),
- false, false);
+ false, false,
+ RowExclusiveLock);
new_exclRte->relkind = RELKIND_COMPOSITE_TYPE;
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 dc0a439638..b22d2d1457 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;
@@ -132,7 +133,10 @@ LockRelationOid(Oid relid, LOCKMODE lockmode)
{
AcceptInvalidationMessages();
MarkLockClear(locallock);
+ return true;
}
+
+ return res == LOCKACQUIRE_ALREADY_HELD;
}
/*
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 7271b5880b..1876345de5 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -1493,7 +1493,6 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
foreach(lc1, stmt_list)
{
PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
- int rt_index;
ListCell *lc2;
if (plannedstmt->commandType == CMD_UTILITY)
@@ -1512,14 +1511,9 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
continue;
}
- rt_index = 0;
foreach(lc2, plannedstmt->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
- LOCKMODE lockmode;
- PlanRowMark *rc;
-
- rt_index++;
if (rte->rtekind != RTE_RELATION)
continue;
@@ -1530,19 +1524,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 +1581,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..a0ce4109e2 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -27,6 +27,7 @@
#include "nodes/primnodes.h"
#include "nodes/value.h"
#include "partitioning/partdefs.h"
+#include "storage/lockdefs.h"
typedef enum OverridingKind
@@ -977,6 +978,8 @@ typedef struct RangeTblEntry
*/
Oid relid; /* OID of the relation */
char relkind; /* relation kind (see pg_class.relkind) */
+ LOCKMODE lockmode; /* lock level to obtain on the relation, or
+ * 0 if no lock required */
struct TableSampleClause *tablesample; /* sampling info, or NULL */
/*
diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h
index b9792acdae..99d1b4135c 100644
--- a/src/include/parser/parse_relation.h
+++ b/src/include/parser/parse_relation.h
@@ -15,6 +15,7 @@
#define PARSE_RELATION_H
#include "parser/parse_node.h"
+#include "storage/lockdefs.h"
/*
@@ -71,7 +72,8 @@ extern RangeTblEntry *addRangeTableEntryForRelation(ParseState *pstate,
Relation rel,
Alias *alias,
bool inh,
- bool inFromCl);
+ bool inFromCl,
+ LOCKMODE lockmode);
extern RangeTblEntry *addRangeTableEntryForSubquery(ParseState *pstate,
Query *subquery,
Alias *alias,
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);
diff --git a/src/test/modules/test_rls_hooks/test_rls_hooks.c b/src/test/modules/test_rls_hooks/test_rls_hooks.c
index cab67a60aa..d455c97ef6 100644
--- a/src/test/modules/test_rls_hooks/test_rls_hooks.c
+++ b/src/test/modules/test_rls_hooks/test_rls_hooks.c
@@ -81,7 +81,7 @@ test_rls_hooks_permissive(CmdType cmdtype, Relation relation)
qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, relation, NULL, false,
- false);
+ false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
@@ -144,7 +144,7 @@ test_rls_hooks_restrictive(CmdType cmdtype, Relation relation)
qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, relation, NULL, false,
- false);
+ false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
--
2.11.0
v5-0002-Remove-useless-fields-from-planner-nodes.patchtext/plain; charset=UTF-8; name=v5-0002-Remove-useless-fields-from-planner-nodes.patchDownload
From 9041a1cd68c3c1d48e99ea4cbbf724c44fb0085d Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Mon, 13 Aug 2018 16:10:19 +0900
Subject: [PATCH v5 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 bool field called
'partitionedTarget', which is set if the target is a partitioned
table. The table itself is identified by nominalRelation.
* '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 | 10 +++---
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 | 51 ++++++------------------------
src/backend/optimizer/plan/setrefs.c | 47 +++-------------------------
src/backend/optimizer/util/pathnode.c | 8 ++---
src/backend/tcop/utility.c | 15 +++++++--
src/include/executor/executor.h | 2 --
src/include/nodes/plannodes.h | 29 +++++------------
src/include/nodes/relation.h | 9 ++----
src/include/optimizer/pathnode.h | 2 +-
20 files changed, 64 insertions(+), 254 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 f797cdfe7c..e84ebe0c87 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..ab4ec575fc 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2255,18 +2255,18 @@ 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->partitionedTarget);
+ /* nominalRelation is the index of the target partitioned table. */
+ rte = rt_fetch(node->nominalRelation, estate->es_range_table);
rel = heap_open(rte->relid, NoLock);
- InitResultRelInfo(mtstate->rootResultRelInfo, rel, root_rt_index,
- NULL, estate->es_instrument);
+ InitResultRelInfo(mtstate->rootResultRelInfo, rel,
+ node->nominalRelation, NULL, estate->es_instrument);
}
mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 11ca800e4c..1bee240e72 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -1358,7 +1358,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
@@ -1374,7 +1374,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..b0193a94a9 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(partitionedTarget);
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..36d46f5d8f 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_BOOL_FIELD(partitionedTarget);
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_BOOL_FIELD(partitionedTarget);
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..4d1317e339 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_BOOL_FIELD(partitionedTarget);
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..becc5ef75d 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, bool partitionedTarget,
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->partitionedTarget,
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, bool partitionedTarget,
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->partitionedTarget = partitionedTarget;
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..44884c29c6 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -276,6 +276,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
Plan *top_plan;
ListCell *lp,
*lr;
+ bool hasRowMarks = (parse->rowMarks != NIL);
/*
* Set up global state for this planner invocation. This data is needed
@@ -290,9 +291,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 +489,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) */
@@ -503,6 +500,8 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
PlannerInfo *subroot = lfirst_node(PlannerInfo, lr);
lfirst(lp) = set_plan_references(subroot, subplan);
+ if (subroot->rowMarks != NIL)
+ hasRowMarks = true;
}
/* build the PlannedStmt result */
@@ -512,6 +511,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
result->queryId = parse->queryId;
result->hasReturning = (parse->returningList != NIL);
result->hasModifyingCTE = parse->hasModifyingCTE;
+ result->hasRowMarks = hasRowMarks;
result->canSetTag = parse->canSetTag;
result->transientPlan = glob->transientPlan;
result->dependsOnRole = glob->dependsOnRole;
@@ -519,11 +519,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;
@@ -1173,8 +1171,7 @@ inheritance_planner(PlannerInfo *root)
ListCell *lc;
Index rti;
RangeTblEntry *parent_rte;
- Relids partitioned_relids = NULL;
- List *partitioned_rels = NIL;
+ bool partitionedTarget = false;
PlannerInfo *parent_root;
Query *parent_parse;
Bitmapset *parent_relids = bms_make_singleton(top_parentRTindex);
@@ -1250,12 +1247,7 @@ inheritance_planner(PlannerInfo *root)
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);
+ partitionedTarget = true;
}
/*
@@ -1327,7 +1319,7 @@ inheritance_planner(PlannerInfo *root)
* inheritance parent.
*/
subroot->inhTargetKind =
- partitioned_relids ? INHKIND_PARTITIONED : INHKIND_INHERITED;
+ partitionedTarget ? INHKIND_PARTITIONED : INHKIND_INHERITED;
/*
* If this child is further partitioned, remember it as a parent.
@@ -1498,15 +1490,6 @@ inheritance_planner(PlannerInfo *root)
continue;
/*
- * Add the current parent's RT index to the partitioned_relids set if
- * we're creating the ModifyTable path for a partitioned root table.
- * (We only care about parents of non-excluded children.)
- */
- if (partitioned_relids)
- partitioned_relids = bms_add_member(partitioned_relids,
- appinfo->parent_relid);
-
- /*
* If this is the first non-excluded child, its post-planning rtable
* becomes the initial contents of final_rtable; otherwise, append
* just its modified subquery RTEs to final_rtable.
@@ -1609,29 +1592,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,
+ partitionedTarget,
root->partColsUpdated,
resultRelations,
subpaths,
@@ -2208,7 +2175,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..a8ec0be83a 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);
}
@@ -850,10 +830,6 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
splan->nominalRelation += rtoffset;
splan->exclRelRTI += rtoffset;
- foreach(l, splan->partitioned_rels)
- {
- lfirst_int(l) += rtoffset;
- }
foreach(l, splan->resultRelations)
{
lfirst_int(l) += rtoffset;
@@ -884,24 +860,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->partitionedTarget)
{
- 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->nominalRelation);
}
}
break;
@@ -915,10 +884,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 +902,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..28f90a2a04 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, bool partitionedTarget,
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->partitionedTarget = partitionedTarget;
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..d0427c64ba 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
+ 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..ceec266a21 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 */
@@ -219,9 +212,9 @@ typedef struct ModifyTable
Plan plan;
CmdType operation; /* INSERT, UPDATE, or DELETE */
bool canSetTag; /* do we set the command tag/es_processed? */
- Index nominalRelation; /* Parent RT index for use of EXPLAIN */
- /* RT indexes of non-leaf tables in a partition tree */
- List *partitioned_rels;
+ Index nominalRelation; /* RT index of the target table specified
+ * in the command */
+ bool partitionedTarget; /* is the target table partitioned? */
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 +252,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 +264,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 +915,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..c9f288c24d 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 */
@@ -1716,9 +1713,9 @@ typedef struct ModifyTablePath
Path path;
CmdType operation; /* INSERT, UPDATE, or DELETE */
bool canSetTag; /* do we set the command tag/es_processed? */
- Index nominalRelation; /* Parent RT index for use of EXPLAIN */
- /* RT indexes of non-leaf tables in a partition tree */
- List *partitioned_rels;
+ Index nominalRelation; /* RT index of the target table specified
+ * in the command */
+ bool partitionedTarget; /* is the target table partitioned? */
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..d826e3cc55 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, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subpaths,
List *subroots,
--
2.11.0
v5-0003-Prune-PlanRowMark-of-relations-that-are-pruned-fr.patchtext/plain; charset=UTF-8; name=v5-0003-Prune-PlanRowMark-of-relations-that-are-pruned-fr.patchDownload
From 8b6568be8e9837e5bca2f712a6774542226df8fa Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 14 Aug 2018 10:35:47 +0900
Subject: [PATCH v5 3/4] Prune PlanRowMark of relations that are pruned from a
plan
---
src/backend/optimizer/plan/planner.c | 31 ++++++++++++++++++++++++++-----
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 44884c29c6..b03cdb13c7 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -237,6 +237,7 @@ static void create_partitionwise_grouping_paths(PlannerInfo *root,
static bool group_by_has_partkey(RelOptInfo *input_rel,
List *targetList,
List *groupClause);
+static List *get_unpruned_rowmarks(PlannerInfo *root);
/*****************************************************************************
@@ -1590,7 +1591,7 @@ inheritance_planner(PlannerInfo *root)
if (parse->rowMarks)
rowMarks = NIL;
else
- rowMarks = root->rowMarks;
+ rowMarks = get_unpruned_rowmarks(root);
/* Create Path representing a ModifyTable to do the UPDATE/DELETE work */
add_path(final_rel, (Path *)
@@ -2119,11 +2120,9 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
* is what goes into the LockRows node.)
*/
if (parse->rowMarks)
- {
path = (Path *) create_lockrows_path(root, final_rel, path,
- root->rowMarks,
+ get_unpruned_rowmarks(root),
SS_assign_special_param(root));
- }
/*
* If there is a LIMIT/OFFSET clause, add the LIMIT node.
@@ -2168,7 +2167,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
if (parse->rowMarks)
rowMarks = NIL;
else
- rowMarks = root->rowMarks;
+ rowMarks = get_unpruned_rowmarks(root);
path = (Path *)
create_modifytable_path(root, final_rel,
@@ -7162,3 +7161,25 @@ group_by_has_partkey(RelOptInfo *input_rel,
return true;
}
+
+/*
+ * get_unpruned_rowmarks
+ * Return a list of PlanRowMark's that reference unpruned relations
+ */
+static List *
+get_unpruned_rowmarks(PlannerInfo *root)
+{
+ List *rowMarks = NIL;
+ ListCell *lc;
+
+ 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]))
+ rowMarks = lappend(rowMarks, rc);
+ }
+
+ return rowMarks;
+}
--
2.11.0
v5-0004-Revise-executor-range-table-relation-opening-clos.patchtext/plain; charset=UTF-8; name=v5-0004-Revise-executor-range-table-relation-opening-clos.patchDownload
From 0205a84fc78341d0beb12def246f0408946baadf Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Thu, 19 Jul 2018 13:01:43 +0900
Subject: [PATCH v5 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, an arrangement which allows the executor
to have to heap_open any given range table relation only once.
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 | 16 +++---
src/backend/commands/copy.c | 3 +-
src/backend/commands/trigger.c | 3 +-
src/backend/executor/execExprInterp.c | 7 +--
src/backend/executor/execMain.c | 80 +++++++++--------------------
src/backend/executor/execPartition.c | 36 +++----------
src/backend/executor/execUtils.c | 64 ++++++++++++++---------
src/backend/executor/nodeAppend.c | 6 ---
src/backend/executor/nodeBitmapHeapscan.c | 7 ---
src/backend/executor/nodeCustom.c | 4 --
src/backend/executor/nodeForeignscan.c | 4 --
src/backend/executor/nodeIndexonlyscan.c | 7 ---
src/backend/executor/nodeIndexscan.c | 7 ---
src/backend/executor/nodeLockRows.c | 2 +-
src/backend/executor/nodeMergeAppend.c | 6 ---
src/backend/executor/nodeModifyTable.c | 21 +++-----
src/backend/executor/nodeSamplescan.c | 5 --
src/backend/executor/nodeSeqscan.c | 7 ---
src/backend/executor/nodeTidscan.c | 5 --
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/tablesync.c | 9 +++-
src/backend/replication/logical/worker.c | 2 +
src/include/executor/execPartition.h | 1 -
src/include/executor/executor.h | 24 ++++++++-
src/include/nodes/execnodes.h | 22 +++++++-
src/include/nodes/plannodes.h | 2 +-
src/include/parser/parsetree.h | 10 ----
31 files changed, 183 insertions(+), 218 deletions(-)
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index e4e330397e..4d2f5e448e 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. */
@@ -2547,10 +2547,6 @@ postgresEndDirectModify(ForeignScanState *node)
ReleaseConnection(dmstate->conn);
dmstate->conn = NULL;
- /* close the target relation. */
- if (dmstate->resultRel)
- ExecCloseScanRelation(dmstate->resultRel);
-
/* MemoryContext will be deleted automatically. */
}
@@ -5757,7 +5753,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 0f8be85303..b3d34307f6 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -2483,7 +2483,8 @@ 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;
+
+ ExecInitRangeTable(estate, cstate->range_table);
/* 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 ce9acef1c2..afbb6311af 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 e84ebe0c87..dbba4e9e81 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 */
@@ -820,30 +820,17 @@ 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
*/
- estate->es_range_table = rangeTable;
+ ExecInitRangeTable(estate, rangeTable);
+
+ /*
+ * Just initialize 0-filled array of Relation pointers. Actual values are
+ * filled later as the plan is initialized.
+ */
+ estate->es_relations = (Relation *) palloc0(estate->es_range_table_size *
+ sizeof(Relation));
estate->es_plannedstmt = plannedstmt;
/*
@@ -1488,6 +1475,12 @@ static void
ExecEndPlan(PlanState *planstate, EState *estate)
{
ListCell *l;
+ int i;
+
+ /* Close range table relations. */
+ for (i = 0; i < estate->es_range_table_size; i++)
+ if (estate->es_relations[i])
+ heap_close(estate->es_relations[i], NoLock);
/*
* shut down the node-type-specific query processing
@@ -1514,18 +1507,6 @@ ExecEndPlan(PlanState *planstate, EState *estate)
/* likewise close any trigger target relations */
ExecCleanUpTriggerState(estate);
-
- /*
- * 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);
- }
}
/* ----------------------------------------------------------------
@@ -2278,24 +2259,20 @@ 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);
-
switch (rc->markType)
{
case ROW_MARK_EXCLUSIVE:
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 */
@@ -2313,7 +2290,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;
@@ -2971,7 +2948,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));
@@ -3016,7 +2993,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();
@@ -3040,6 +3017,9 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree)
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_range_table_size = parentestate->es_range_table_size;
+ 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;
@@ -3170,18 +3150,6 @@ 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 81c2f5cedc..197175f106 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);
@@ -1593,30 +1593,6 @@ ExecCreatePartitionPruneState(PlanState *planstate,
}
/*
- * ExecDestroyPartitionPruneState
- * Release resources at plan shutdown.
- *
- * We don't bother to free any memory here, since the whole executor context
- * will be going away shortly. We do need to release our relcache pins.
- */
-void
-ExecDestroyPartitionPruneState(PartitionPruneState *prunestate)
-{
- PartitionPruningData **partprunedata = prunestate->partprunedata;
- int i;
-
- for (i = 0; i < prunestate->num_partprunedata; i++)
- {
- PartitionPruningData *prunedata = partprunedata[i];
- PartitionedRelPruningData *pprune = prunedata->partrelprunedata;
- int j;
-
- for (j = 0; j < prunedata->num_partrelprunedata; j++)
- relation_close(pprune[j].context.partrel, NoLock);
- }
-}
-
-/*
* ExecFindInitialMatchingSubPlans
* Identify the set of subplans that cannot be eliminated by initial
* pruning (disregarding any pruning constraints involving PARAM_EXEC
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index d32796aac3..abee92ee59 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
@@ -675,26 +673,6 @@ ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
return rel;
}
-/* ----------------------------------------------------------------
- * ExecCloseScanRelation
- *
- * Close the heap relation scanned by a base-level scan plan node.
- * This should be called during the node's ExecEnd routine.
- *
- * Currently, we do not release the lock acquired by ExecOpenScanRelation.
- * This lock should be held till end of transaction. (There is a faction
- * that considers this too much locking, however.)
- *
- * If we did want to release the lock, we'd have to repeat the logic in
- * ExecOpenScanRelation in order to figure out what to release.
- * ----------------------------------------------------------------
- */
-void
-ExecCloseScanRelation(Relation scanrel)
-{
- heap_close(scanrel, NoLock);
-}
-
/*
* UpdateChangedParamSet
* Add changed parameters to a plan node's chgParam set
@@ -997,3 +975,43 @@ ExecCleanTargetListLength(List *targetlist)
}
return len;
}
+
+/*
+ * Initialize executor's range table array
+ */
+void
+ExecInitRangeTable(EState *estate, List *rangeTable)
+{
+ int rti;
+ ListCell *l;
+
+#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
+
+ Assert(estate != NULL);
+ 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 *));
+ rti = 0;
+ foreach(l, rangeTable)
+ estate->es_range_table_array[rti++] = lfirst_node(RangeTblEntry, l);
+}
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index eb587be221..a16b6da474 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -329,12 +329,6 @@ ExecEndAppend(AppendState *node)
*/
for (i = 0; i < nplans; i++)
ExecEndNode(appendplans[i]);
-
- /*
- * release any resources associated with run-time pruning
- */
- if (node->as_prune_state)
- ExecDestroyPartitionPruneState(node->as_prune_state);
}
void
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index 3e1c9e0714..2c4d67898e 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -786,13 +786,11 @@ ExecReScanBitmapHeapScan(BitmapHeapScanState *node)
void
ExecEndBitmapHeapScan(BitmapHeapScanState *node)
{
- Relation relation;
HeapScanDesc scanDesc;
/*
* extract information from the node
*/
- relation = node->ss.ss_currentRelation;
scanDesc = node->ss.ss_currentScanDesc;
/*
@@ -833,11 +831,6 @@ ExecEndBitmapHeapScan(BitmapHeapScanState *node)
* close heap scan
*/
heap_endscan(scanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index b816e0b31d..9a33eda688 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -126,10 +126,6 @@ ExecEndCustomScan(CustomScanState *node)
/* Clean out the tuple table */
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /* Close the heap relation */
- if (node->ss.ss_currentRelation)
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
void
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index a2a28b7ec2..cf7df72d8c 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -258,10 +258,6 @@ ExecEndForeignScan(ForeignScanState *node)
/* clean out the tuple table */
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /* close the relation. */
- if (node->ss.ss_currentRelation)
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 8c32a74d39..4a2b41d255 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -373,14 +373,12 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node)
{
Relation indexRelationDesc;
IndexScanDesc indexScanDesc;
- Relation relation;
/*
* extract information from the node
*/
indexRelationDesc = node->ioss_RelationDesc;
indexScanDesc = node->ioss_ScanDesc;
- relation = node->ss.ss_currentRelation;
/* Release VM buffer pin, if any. */
if (node->ioss_VMBuffer != InvalidBuffer)
@@ -411,11 +409,6 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node)
index_endscan(indexScanDesc);
if (indexRelationDesc)
index_close(indexRelationDesc, NoLock);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 10891bc3f4..bf528465ce 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -804,14 +804,12 @@ ExecEndIndexScan(IndexScanState *node)
{
Relation indexRelationDesc;
IndexScanDesc indexScanDesc;
- Relation relation;
/*
* extract information from the node
*/
indexRelationDesc = node->iss_RelationDesc;
indexScanDesc = node->iss_ScanDesc;
- relation = node->ss.ss_currentRelation;
/*
* Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
@@ -835,11 +833,6 @@ ExecEndIndexScan(IndexScanState *node)
index_endscan(indexScanDesc);
if (indexRelationDesc)
index_close(indexRelationDesc, NoLock);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
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/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index d8e0978966..5d0dbb8146 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -363,12 +363,6 @@ ExecEndMergeAppend(MergeAppendState *node)
*/
for (i = 0; i < nplans; i++)
ExecEndNode(mergeplans[i]);
-
- /*
- * release any resources associated with run-time pruning
- */
- if (node->ms_prune_state)
- ExecDestroyPartitionPruneState(node->ms_prune_state);
}
void
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index ab4ec575fc..ccbf4c0f73 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,7 +2254,6 @@ 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 +
@@ -2263,10 +2261,12 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
Assert(node->partitionedTarget);
/* nominalRelation is the index of the target partitioned table. */
- rte = rt_fetch(node->nominalRelation, estate->es_range_table);
- rel = heap_open(rte->relid, NoLock);
- InitResultRelInfo(mtstate->rootResultRelInfo, rel,
- node->nominalRelation, NULL, estate->es_instrument);
+ rel = ExecRangeTableRelation(estate, node->nominalRelation);
+ InitResultRelInfo(mtstate->rootResultRelInfo,
+ rel,
+ node->nominalRelation,
+ NULL,
+ estate->es_instrument);
}
mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
@@ -2727,14 +2727,9 @@ ExecEndModifyTable(ModifyTableState *node)
/* 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/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index 15177dbed7..491f8d48fd 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -223,11 +223,6 @@ ExecEndSampleScan(SampleScanState *node)
*/
if (node->ss.ss_currentScanDesc)
heap_endscan(node->ss.ss_currentScanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index c7849de6bc..2f43989e85 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -202,13 +202,11 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
void
ExecEndSeqScan(SeqScanState *node)
{
- Relation relation;
HeapScanDesc scanDesc;
/*
* get information from node
*/
- relation = node->ss.ss_currentRelation;
scanDesc = node->ss.ss_currentScanDesc;
/*
@@ -227,11 +225,6 @@ ExecEndSeqScan(SeqScanState *node)
*/
if (scanDesc != NULL)
heap_endscan(scanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index e207b1ffb5..a3e62e4c9f 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -491,11 +491,6 @@ ExecEndTidScan(TidScanState *node)
*/
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index b0193a94a9..cde0cd7c16 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 36d46f5d8f..aba0c6bbd1 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 4d1317e339..1d9810dbfd 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 a8ec0be83a..72ad161e57 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -890,6 +890,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:
@@ -908,6 +923,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 e1ce8b4ddc..1763dd67a3 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/tablesync.c b/src/backend/replication/logical/tablesync.c
index 905a983074..d72f6a1b4f 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -795,7 +795,14 @@ copy_table(Relation rel)
copybuf = makeStringInfo();
pstate = make_parsestate(NULL);
- addRangeTableEntryForRelation(pstate, rel, NULL, false, false, NoLock);
+
+ /*
+ * Caller LogicalRepSyncTableStart took RowExclusiveLock, which we must
+ * record in the RTE being built, because executor initialization invoked
+ * by copy.c expects it.
+ */
+ addRangeTableEntryForRelation(pstate, rel, NULL, false, false,
+ RowExclusiveLock);
attnamelist = make_copy_attnamelist(relmapentry);
cstate = BeginCopyFrom(pstate, rel, NULL, false, copy_read_data, attnamelist, NIL);
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 2054abe653..e61544199b 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -200,6 +200,8 @@ create_estate_for_relation(LogicalRepRelMapEntry *rel)
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/execPartition.h b/src/include/executor/execPartition.h
index f6cd842cc9..48d4997661 100644
--- a/src/include/executor/execPartition.h
+++ b/src/include/executor/execPartition.h
@@ -225,7 +225,6 @@ extern void ExecCleanupTupleRouting(ModifyTableState *mtstate,
PartitionTupleRouting *proute);
extern PartitionPruneState *ExecCreatePartitionPruneState(PlanState *planstate,
PartitionPruneInfo *partitionpruneinfo);
-extern void ExecDestroyPartitionPruneState(PartitionPruneState *prunestate);
extern Bitmapset *ExecFindMatchingSubPlans(PartitionPruneState *prunestate);
extern Bitmapset *ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate,
int nsubplans);
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 1d2b48fe09..93259a4ffa 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"
/*
@@ -478,6 +479,7 @@ extern ExprContext *CreateExprContext(EState *estate);
extern ExprContext *CreateStandaloneExprContext(void);
extern void FreeExprContext(ExprContext *econtext, bool isCommit);
extern void ReScanExprContext(ExprContext *econtext);
+extern void ExecInitRangeTable(EState *estate, List *rangeTable);
#define ResetExprContext(econtext) \
MemoryContextReset((econtext)->ecxt_per_tuple_memory)
@@ -513,7 +515,6 @@ extern void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate
extern bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid);
extern Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags);
-extern void ExecCloseScanRelation(Relation scanrel);
extern int executor_errposition(EState *estate, int location);
@@ -568,4 +569,25 @@ 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)
+{
+ Relation rel = estate->es_relations[rti - 1];
+
+ if (rel == NULL)
+ {
+ RangeTblEntry *rte = exec_rt_fetch(rti, estate->es_range_table_array);
+
+ /*
+ * No need to lock the relation lock, because upstream code
+ * must hold the lock already.
+ */
+ 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..d669a3fada 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 */
@@ -574,6 +578,22 @@ typedef struct EState
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 ceec266a21..59dd26b04e 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -1092,7 +1092,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
I've just completed a review of the v5 patch set. I ended up just
making the changes myself since Amit mentioned he was on leave for a
few weeks.
Summary of changes:
1. Changed the way we verify the lock already exists with debug
builds. I reverted some incorrect code added to LockRelationOid that
seems to have gotten broken after being rebased on f868a8143a9. I've
just added some functions that verify the lock is in the
LockMethodLocalHash hashtable.
2. Fixed some incorrect lock types being passed into
addRangeTableEntryForRelation()
3. Added code in addRangeTableEntryForRelation to verify we actually
hold the lock that the parameter claims we do. (This found all the
errors I fixed in #2)
4. Updated various comments outdated by the patches
5. Updated executor README's mention that we close relations when
calling the end node function. This is now handled at the end of
execution.
6. Renamed nominalRelation to targetRelation. I think this fits
better since we're overloading the variable.
7. Use LOCKMODE instead of int in some places.
8. Changed warning about relation not locked to WARNING instead of NOTICE.
9. Renamed get_unpruned_rowmarks() to get_nondummy_rowmarks(). Pruning
makes me think of partition pruning but the function checks for dummy
rels. These could be dummy for reasons other than partition pruning.
I've attached a diff showing the changes I made along with the full
patches which I tagged as v6.
--
David Rowley http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
Attachments:
v5_to_v6_changes.diffapplication/octet-stream; name=v5_to_v6_changes.diffDownload
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 3dd1bab2a2..d20c75367c 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -2050,7 +2050,7 @@ postgresBeginForeignInsert(ModifyTableState *mtstate,
* Vars contained in those expressions.
*/
if (plan && plan->operation == CMD_UPDATE &&
- resultRelation == plan->nominalRelation)
+ resultRelation == plan->targetRelation)
resultRelation = mtstate->resultRelInfo[0].ri_RangeTableIndex;
}
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 2be2d340ca..57efb20d20 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -837,7 +837,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
List *attnums;
ListCell *cur;
RangeTblEntry *rte;
- int lockmode = is_from ? RowExclusiveLock : AccessShareLock;
+ LOCKMODE lockmode = is_from ? RowExclusiveLock : AccessShareLock;
Assert(!stmt->query);
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index ed6afe79a9..5ca7f69830 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -929,7 +929,7 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
break;
case T_ModifyTable:
*rels_used = bms_add_member(*rels_used,
- ((ModifyTable *) plan)->nominalRelation);
+ ((ModifyTable *) plan)->targetRelation);
if (((ModifyTable *) plan)->exclRelRTI)
*rels_used = bms_add_member(*rels_used,
((ModifyTable *) plan)->exclRelRTI);
@@ -2924,7 +2924,7 @@ ExplainScanTarget(Scan *plan, ExplainState *es)
static void
ExplainModifyTarget(ModifyTable *plan, ExplainState *es)
{
- ExplainTargetRel((Plan *) plan, plan->nominalRelation, es);
+ ExplainTargetRel((Plan *) plan, plan->targetRelation, es);
}
/*
@@ -3088,7 +3088,7 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors,
/* Should we explicitly label target relations? */
labeltargets = (mtstate->mt_nplans > 1 ||
(mtstate->mt_nplans == 1 &&
- mtstate->resultRelInfo->ri_RangeTableIndex != node->nominalRelation));
+ mtstate->resultRelInfo->ri_RangeTableIndex != node->targetRelation));
if (labeltargets)
ExplainOpenGroup("Target Tables", "Target Tables", false, es);
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index 09a6a7f9d3..2949b4e6d7 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -568,7 +568,7 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(qual_pstate, rel, NULL, false, false,
- NoLock);
+ AccessExclusiveLock);
qual_parse_rtable = qual_pstate->p_rtable;
free_parsestate(qual_pstate);
@@ -591,7 +591,7 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(with_check_pstate, rel, NULL, false,
- false, NoLock);
+ false, AccessExclusiveLock);
with_check_parse_rtable = with_check_pstate->p_rtable;
free_parsestate(with_check_pstate);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index f5b9d768e8..5afa54389a 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -13632,7 +13632,8 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
* rangetable entry. We need a ParseState for transformExpr.
*/
pstate = make_parsestate(NULL);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true, NoLock);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true,
+ NoLock);
addRTEtoQuery(pstate, rte, true, true, true);
/* take care of any partition expressions */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index f673029ed1..f0d45844c1 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -579,11 +579,13 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
*/
rte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("old", NIL),
- false, false, NoLock);
+ false, false,
+ ShareRowExclusiveLock);
addRTEtoQuery(pstate, rte, false, true, true);
rte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("new", NIL),
- false, false, NoLock);
+ false, false,
+ ShareRowExclusiveLock);
addRTEtoQuery(pstate, rte, false, true, true);
/* Transform expression. Copy to be sure we don't modify original */
diff --git a/src/backend/executor/README b/src/backend/executor/README
index 0d7cd552eb..30df410e0e 100644
--- a/src/backend/executor/README
+++ b/src/backend/executor/README
@@ -267,8 +267,8 @@ This is a sketch of control flow for full query processing:
Per above comments, it's not really critical for ExecEndNode to free any
memory; it'll all go away in FreeExecutorState anyway. However, we do need to
-be careful to close relations, drop buffer pins, etc, so we do need to scan
-the plan state tree to find these sorts of resources.
+be careful to drop buffer pins, etc, so we do need to scan the plan state tree
+to find these sorts of resources.
The executor can also be used to evaluate simple expressions without any Plan
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 1be4dabb53..2ca25d857d 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -837,25 +837,22 @@ InitPlan(QueryDesc *queryDesc, int eflags)
*/
ExecCheckRTPerms(rangeTable, true);
- /*
- * initialize the node's execution state
- */
ExecInitRangeTable(estate, rangeTable);
/*
- * Just initialize 0-filled array of Relation pointers. Actual values are
- * filled later as the plan is initialized.
+ * Allocate an array to store open Relations of each rangeTable item. We
+ * 0 fill this for now. The Relations are only opened and stored here the
+ * first time they're required during node initialization.
*/
estate->es_relations = (Relation *) palloc0(estate->es_range_table_size *
sizeof(Relation));
- estate->es_plannedstmt = plannedstmt;
-
/*
- * initialize result relation stuff, and open/lock the result rels.
- *
- * We must do this before initializing the plan tree, else we might try to
- * do a lock upgrade if a result rel is also a source rel.
+ * initialize the node's execution state
*/
+ estate->es_range_table = rangeTable;
+ estate->es_plannedstmt = plannedstmt;
+
+ /* Allocate memory required for result relations */
if (plannedstmt->resultRelations)
{
int numResultRelations = list_length(plannedstmt->resultRelations);
@@ -1496,8 +1493,10 @@ ExecEndPlan(PlanState *planstate, EState *estate)
/* Close range table relations. */
for (i = 0; i < estate->es_range_table_size; i++)
+ {
if (estate->es_relations[i])
heap_close(estate->es_relations[i], NoLock);
+ }
/*
* shut down the node-type-specific query processing
@@ -2270,7 +2269,11 @@ ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
}
/*
- * ExecBuildRowMark -- create ExecRowMark struct for given PlanRowMark
+ * ExecBuildRowMark -- create and return an ExecRowMark struct for the given
+ * PlanRowMark.
+ *
+ * The created ExecRowMark is also added to the list of rowmarks in the given
+ * EState.
*/
ExecRowMark *
ExecBuildRowMark(EState *estate, PlanRowMark *rc)
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index 7e224b23fe..7fb34d2173 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -379,7 +379,7 @@ ExecInitPartitionInfo(ModifyTableState *mtstate,
leaf_part_rri = makeNode(ResultRelInfo);
InitResultRelInfo(leaf_part_rri,
partrel,
- node ? node->nominalRelation : 1,
+ node ? node->targetRelation : 1,
rootrel,
estate->es_instrument);
@@ -1417,9 +1417,6 @@ adjust_partition_tlist(List *tlist, TupleConversionMap *map)
* functions. Details stored include how to map the partition index
* returned by the partition pruning code into subplan indexes.
*
- * ExecDestroyPartitionPruneState:
- * Deletes a PartitionPruneState. Must be called during executor shutdown.
- *
* ExecFindInitialMatchingSubPlans:
* Returns indexes of matching subplans. Partition pruning is attempted
* without any evaluation of expressions containing PARAM_EXEC Params.
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index abee92ee59..ab46fd425d 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -25,7 +25,6 @@
* etc
*
* ExecOpenScanRelation Common code for scan node init routines.
- * ExecCloseScanRelation
*
* executor_errposition Report syntactic position of an error.
*
@@ -35,6 +34,8 @@
* GetAttributeByName Runtime extraction of columns from tuples.
* GetAttributeByNum
*
+ * ExecInitRangeTable Build an array from the range table list to
+ * allow faster lookups by relid.
* NOTES
* This file has traditionally been the place to stick misc.
* executor support stuff that doesn't really go anyplace else.
@@ -997,10 +998,10 @@ ExecInitRangeTable(EState *estate, List *rangeTable)
* meaning the upstream code already acquired the needed locks.
*/
Assert(rte->lockmode != NoLock);
- if (LockRelationOid(rte->relid, rte->lockmode) &&
- !IsParallelWorker())
- elog(NOTICE, "InitPlan: lock on \"%s\" not already taken",
- get_rel_name(rte->relid));
+ if (!IsParallelWorker() &&
+ !CheckRelationLockedByUs(rte->relid, rte->lockmode))
+ elog(WARNING, "InitPlan: lock on \"%s\" not already taken",
+ get_rel_name(rte->relid));
}
}
#endif
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index 9e7c5e94cf..ff9606342b 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -424,7 +424,7 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
/* safety check on size of lr_curtuples array */
Assert(rc->rti > 0 && rc->rti <= lrstate->lr_ntables);
- /* find ExecRowMark and build ExecAuxRowMark */
+ /* build the ExecRowMark and ExecAuxRowMark */
erm = ExecBuildRowMark(estate, rc);
aerm = ExecBuildAuxRowMark(erm, outerPlan->targetlist);
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 082666c76c..c837d36a87 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2260,11 +2260,10 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
node->rootResultRelIndex;
Assert(node->partitionedTarget);
- /* nominalRelation is the index of the target partitioned table. */
- rel = ExecRangeTableRelation(estate, node->nominalRelation);
+ rel = ExecRangeTableRelation(estate, node->targetRelation);
InitResultRelInfo(mtstate->rootResultRelInfo,
rel,
- node->nominalRelation,
+ node->targetRelation,
NULL,
estate->es_instrument);
}
@@ -2554,7 +2553,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
if (rc->isParent)
continue;
- /* find ExecRowMark (same for all subplans) */
+ /* build the ExecRowMark (same for all subplans) */
erm = ExecBuildRowMark(estate, rc);
/* build ExecAuxRowMark for each subplan */
@@ -2711,9 +2710,7 @@ ExecEndModifyTable(ModifyTableState *node)
{
int i;
- /*
- * close the result relation(s) if any, but hold locks until xact commit.
- */
+ /* Perform cleanup. */
for (i = 0; i < node->mt_nplans; i++)
{
ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
@@ -2725,9 +2722,11 @@ ExecEndModifyTable(ModifyTableState *node)
resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
resultRelInfo);
- /* Close indices and then the relation itself */
+ /*
+ * Close the ResultRelInfo's indexes. The relation itself
+ * is handled by the executor cleanup code.
+ */
ExecCloseIndices(resultRelInfo);
- resultRelInfo++;
}
/* Close all the partitioned tables, leaf partitions, and their indices */
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index cde0cd7c16..dd76284676 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -202,7 +202,7 @@ _copyModifyTable(const ModifyTable *from)
*/
COPY_SCALAR_FIELD(operation);
COPY_SCALAR_FIELD(canSetTag);
- COPY_SCALAR_FIELD(nominalRelation);
+ COPY_SCALAR_FIELD(targetRelation);
COPY_SCALAR_FIELD(partitionedTarget);
COPY_SCALAR_FIELD(partColsUpdated);
COPY_NODE_FIELD(resultRelations);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 683a7ba94e..6aefdd8bc4 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -374,7 +374,7 @@ _outModifyTable(StringInfo str, const ModifyTable *node)
WRITE_ENUM_FIELD(operation, CmdType);
WRITE_BOOL_FIELD(canSetTag);
- WRITE_UINT_FIELD(nominalRelation);
+ WRITE_UINT_FIELD(targetRelation);
WRITE_BOOL_FIELD(partitionedTarget);
WRITE_BOOL_FIELD(partColsUpdated);
WRITE_NODE_FIELD(resultRelations);
@@ -2175,7 +2175,7 @@ _outModifyTablePath(StringInfo str, const ModifyTablePath *node)
WRITE_ENUM_FIELD(operation, CmdType);
WRITE_BOOL_FIELD(canSetTag);
- WRITE_UINT_FIELD(nominalRelation);
+ WRITE_UINT_FIELD(targetRelation);
WRITE_BOOL_FIELD(partitionedTarget);
WRITE_BOOL_FIELD(partColsUpdated);
WRITE_NODE_FIELD(resultRelations);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 342b271ea5..30609c96e6 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1596,7 +1596,7 @@ _readModifyTable(void)
READ_ENUM_FIELD(operation, CmdType);
READ_BOOL_FIELD(canSetTag);
- READ_UINT_FIELD(nominalRelation);
+ READ_UINT_FIELD(targetRelation);
READ_BOOL_FIELD(partitionedTarget);
READ_BOOL_FIELD(partColsUpdated);
READ_NODE_FIELD(resultRelations);
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index becc5ef75d..8f20e54d9e 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -278,7 +278,7 @@ static Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
static ProjectSet *make_project_set(List *tlist, Plan *subplan);
static ModifyTable *make_modifytable(PlannerInfo *root,
CmdType operation, bool canSetTag,
- Index nominalRelation, bool partitionedTarget,
+ Index targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subplans, List *subroots,
List *withCheckOptionLists, List *returningLists,
@@ -2405,7 +2405,7 @@ create_modifytable_plan(PlannerInfo *root, ModifyTablePath *best_path)
plan = make_modifytable(root,
best_path->operation,
best_path->canSetTag,
- best_path->nominalRelation,
+ best_path->targetRelation,
best_path->partitionedTarget,
best_path->partColsUpdated,
best_path->resultRelations,
@@ -6481,7 +6481,7 @@ make_project_set(List *tlist,
static ModifyTable *
make_modifytable(PlannerInfo *root,
CmdType operation, bool canSetTag,
- Index nominalRelation, bool partitionedTarget,
+ Index targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subplans, List *subroots,
List *withCheckOptionLists, List *returningLists,
@@ -6509,7 +6509,7 @@ make_modifytable(PlannerInfo *root,
node->operation = operation;
node->canSetTag = canSetTag;
- node->nominalRelation = nominalRelation;
+ node->targetRelation = targetRelation;
node->partitionedTarget = partitionedTarget;
node->partColsUpdated = partColsUpdated;
node->resultRelations = resultRelations;
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index cd46849f26..074ec9bf55 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -248,7 +248,7 @@ static bool group_by_has_partkey(RelOptInfo *input_rel,
List *targetList,
List *groupClause);
static int common_prefix_cmp(const void *a, const void *b);
-static List *get_unpruned_rowmarks(PlannerInfo *root);
+static List *get_nondummy_rowmarks(PlannerInfo *root);
/*****************************************************************************
*
@@ -1167,7 +1167,7 @@ inheritance_planner(PlannerInfo *root)
int top_parentRTindex = parse->resultRelation;
Bitmapset *subqueryRTindexes;
Bitmapset *modifiableARIindexes;
- int nominalRelation = -1;
+ int targetRelation = -1;
List *final_rtable = NIL;
int save_rel_array_size = 0;
RelOptInfo **save_rel_array = NULL;
@@ -1245,19 +1245,13 @@ inheritance_planner(PlannerInfo *root)
}
/*
- * If the parent RTE is a partitioned table, we should use that as the
- * nominal relation, because the RTEs added for partitioned tables
- * (including the root parent) as child members of the inheritance set do
- * not appear anywhere else in the plan. The situation is exactly the
- * opposite in the case of non-partitioned inheritance parent as described
- * below. For the same reason, collect the list of descendant partitioned
- * tables to be saved in ModifyTable node, so that executor can lock those
- * as well.
+ * If the parent RTE is a partitioned table, set that as the target
+ * relation and mark that we're working with a partitioned target.
*/
parent_rte = rt_fetch(top_parentRTindex, root->parse->rtable);
if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
{
- nominalRelation = top_parentRTindex;
+ targetRelation = top_parentRTindex;
partitionedTarget = true;
}
@@ -1355,17 +1349,17 @@ inheritance_planner(PlannerInfo *root)
}
/*
- * Set the nominal target relation of the ModifyTable node if not
- * already done. We use the inheritance parent RTE as the nominal
- * target relation if it's a partitioned table (see just above this
- * loop). In the non-partitioned parent case, we'll use the first
- * child relation (even if it's excluded) as the nominal target
- * relation. Because of the way expand_inherited_rtentry works, the
- * latter should be the RTE representing the parent table in its role
- * as a simple member of the inheritance set.
+ * Set the target relation of the ModifyTable node if not already
+ * done. We use the inheritance parent RTE as the target relation
+ * if it's a partitioned table (see just above this loop). In the
+ * non-partitioned parent case, we'll use the first child relation
+ * (even if it's excluded) as the target relation. Because of the way
+ * expand_inherited_rtentry works, the latter should be the RTE
+ * representing the parent table in its role as a simple member of
+ * the inheritance set.
*
* It would be logically cleaner to *always* use the inheritance
- * parent RTE as the nominal relation; but that RTE is not otherwise
+ * parent RTE as the target relation; but that RTE is not otherwise
* referenced in the plan in the non-partitioned inheritance case.
* Instead the duplicate child RTE created by expand_inherited_rtentry
* is used elsewhere in the plan, so using the original parent RTE
@@ -1375,8 +1369,8 @@ inheritance_planner(PlannerInfo *root)
* duplicate child RTE added for the parent does not appear anywhere
* else in the plan tree.
*/
- if (nominalRelation < 0)
- nominalRelation = appinfo->child_relid;
+ if (targetRelation < 0)
+ targetRelation = appinfo->child_relid;
/*
* The rowMarks list might contain references to subquery RTEs, so
@@ -1601,14 +1595,14 @@ inheritance_planner(PlannerInfo *root)
if (parse->rowMarks)
rowMarks = NIL;
else
- rowMarks = get_unpruned_rowmarks(root);
+ rowMarks = get_nondummy_rowmarks(root);
/* Create Path representing a ModifyTable to do the UPDATE/DELETE work */
add_path(final_rel, (Path *)
create_modifytable_path(root, final_rel,
parse->commandType,
parse->canSetTag,
- nominalRelation,
+ targetRelation,
partitionedTarget,
root->partColsUpdated,
resultRelations,
@@ -2131,7 +2125,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
*/
if (parse->rowMarks)
path = (Path *) create_lockrows_path(root, final_rel, path,
- get_unpruned_rowmarks(root),
+ get_nondummy_rowmarks(root),
SS_assign_special_param(root));
/*
@@ -2177,14 +2171,14 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
if (parse->rowMarks)
rowMarks = NIL;
else
- rowMarks = get_unpruned_rowmarks(root);
+ rowMarks = get_nondummy_rowmarks(root);
path = (Path *)
create_modifytable_path(root, final_rel,
parse->commandType,
parse->canSetTag,
parse->resultRelation,
- 0,
+ false,
false,
list_make1_int(parse->resultRelation),
list_make1(path),
@@ -7225,11 +7219,11 @@ group_by_has_partkey(RelOptInfo *input_rel,
}
/*
- * get_unpruned_rowmarks
- * Return a list of PlanRowMark's that reference unpruned relations
+ * get_nondummy_rowmarks
+ * Return a list of PlanRowMark's that reference non-dummy relations
*/
static List *
-get_unpruned_rowmarks(PlannerInfo *root)
+get_nondummy_rowmarks(PlannerInfo *root)
{
List *rowMarks = NIL;
ListCell *lc;
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 72ad161e57..ee01ef82d2 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -827,7 +827,7 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
fix_scan_list(root, splan->exclRelTlist, rtoffset);
}
- splan->nominalRelation += rtoffset;
+ splan->targetRelation += rtoffset;
splan->exclRelRTI += rtoffset;
foreach(l, splan->resultRelations)
@@ -870,7 +870,7 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
list_length(root->glob->rootResultRelations);
root->glob->rootResultRelations =
lappend_int(root->glob->rootResultRelations,
- splan->nominalRelation);
+ splan->targetRelation);
}
}
break;
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 28f90a2a04..73eca1d4d0 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -3291,8 +3291,8 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
* 'rel' is the parent relation associated with the result
* 'operation' is the operation type
* 'canSetTag' is true if we set the command tag/es_processed
- * 'nominalRelation' is the parent RT index for use of EXPLAIN
- * 'rootRelation' is the RT index of the root partitioned table
+ * 'targetRelation' is the target table's RT index
+ * 'partitionedTarget' true if 'targetRelation' is a partitioned table
* 'partColsUpdated' is true if any partitioning columns are being updated,
* either from the target relation or a descendent partitioned table.
* 'resultRelations' is an integer list of actual RT indexes of target rel(s)
@@ -3307,7 +3307,7 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
ModifyTablePath *
create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
CmdType operation, bool canSetTag,
- Index nominalRelation, bool partitionedTarget,
+ Index targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subpaths,
List *subroots,
@@ -3374,7 +3374,7 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
pathnode->operation = operation;
pathnode->canSetTag = canSetTag;
- pathnode->nominalRelation = nominalRelation;
+ pathnode->targetRelation = targetRelation;
pathnode->partitionedTarget = partitionedTarget;
pathnode->partColsUpdated = partColsUpdated;
pathnode->resultRelations = resultRelations;
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 53b2832215..a9cfd1f67b 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -28,6 +28,7 @@
#include "parser/parse_enr.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
+#include "storage/lmgr.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
@@ -1281,6 +1282,11 @@ addRangeTableEntryForRelation(ParseState *pstate,
Assert(pstate != NULL);
+#ifdef USE_ASSERT_CHECKING
+ if (lockmode != NoLock && !CheckRelationLockedByUs(RelationGetRelid(rel), lockmode))
+ elog(WARNING, "lock on \"%s\" is not held", RelationGetRelationName(rel));
+#endif
+
rte->rtekind = RTE_RELATION;
rte->alias = alias;
rte->relid = RelationGetRelid(rel);
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 14adac8312..5df0348f1c 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -2638,11 +2638,11 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
oldrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("old", NIL),
false, false,
- AccessShareLock);
+ AccessExclusiveLock);
newrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("new", NIL),
false, false,
- AccessShareLock);
+ AccessExclusiveLock);
/* Must override addRangeTableEntry's default access-check flags */
oldrte->requiredPerms = 0;
newrte->requiredPerms = 0;
@@ -2738,11 +2738,11 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
oldrte = addRangeTableEntryForRelation(sub_pstate, rel,
makeAlias("old", NIL),
false, false,
- AccessShareLock);
+ AccessExclusiveLock);
newrte = addRangeTableEntryForRelation(sub_pstate, rel,
makeAlias("new", NIL),
false, false,
- AccessShareLock);
+ AccessExclusiveLock);
oldrte->requiredPerms = 0;
newrte->requiredPerms = 0;
addRTEtoQuery(sub_pstate, oldrte, false, true, false);
diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c
index b22d2d1457..2d8eae62e6 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -100,9 +100,8 @@ SetLocktagRelationOid(LOCKTAG *tag, Oid relid)
*
* Lock a relation given only its OID. This should generally be used
* before attempting to open the relation's relcache entry.
- * Return true if we acquired a new lock, false if already held.
*/
-bool
+void
LockRelationOid(Oid relid, LOCKMODE lockmode)
{
LOCKTAG tag;
@@ -133,10 +132,22 @@ LockRelationOid(Oid relid, LOCKMODE lockmode)
{
AcceptInvalidationMessages();
MarkLockClear(locallock);
- return true;
}
+}
+
+/*
+ * CheckRelationLockedByUs
+ *
+ * Returns true we hold a lock on 'relid' with 'lockmode'.
+ */
+bool
+CheckRelationLockedByUs(Oid relid, LOCKMODE lockmode)
+{
+ LOCKTAG tag;
+
+ SetLocktagRelationOid(&tag, relid);
- return res == LOCKACQUIRE_ALREADY_HELD;
+ return LocalLockExists(&tag, lockmode);
}
/*
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 831ae62525..8c140fe4b0 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -563,6 +563,30 @@ DoLockModesConflict(LOCKMODE mode1, LOCKMODE mode2)
return false;
}
+/*
+ * LocalLockExists -- check if a log with 'locktag' is held locally with
+ * 'lockmode'
+ */
+bool
+LocalLockExists(const LOCKTAG *locktag, LOCKMODE lockmode)
+{
+ LOCALLOCKTAG localtag;
+ bool found;
+
+ MemSet(&localtag, 0, sizeof(localtag)); /* must clear padding */
+ localtag.lock = *locktag;
+ localtag.mode = lockmode;
+
+ /*
+ * Find the LOCALLOCK entry for this lock and lockmode
+ */
+ (void) hash_search(LockMethodLocalHash,
+ (void *) &localtag,
+ HASH_FIND, &found);
+
+ return found;
+}
+
/*
* LockHasWaiters -- look up 'locktag' and check if releasing this
* lock would wake up other processes waiting for it.
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 93259a4ffa..b03d8c591f 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -580,8 +580,8 @@ ExecRangeTableRelation(EState *estate, Index rti)
RangeTblEntry *rte = exec_rt_fetch(rti, estate->es_range_table_array);
/*
- * No need to lock the relation lock, because upstream code
- * must hold the lock already.
+ * No need to lock the relation. Locks were already
+ * obtained by the upstream code.
*/
rel = estate->es_relations[rti - 1] = heap_open(rte->relid, NoLock);
}
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index b2ab3fd2b6..639235d622 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -482,7 +482,8 @@ typedef struct EState
List *es_range_table; /* List of RangeTblEntry */
struct RangeTblEntry **es_range_table_array; /* 0-based range table */
int es_range_table_size; /* size of the range table array */
- Relation *es_relations; /* 0-based array of Relation pointers */
+ Relation *es_relations; /* 0-based array of Relations
+ * es_range_table_size elements in length. */
PlannedStmt *es_plannedstmt; /* link to top of plan tree */
const char *es_sourceText; /* Source text from QueryDesc */
@@ -590,7 +591,7 @@ typedef struct EState
*/
#define exec_rt_fetch(rangetblidx, rangetbl) rangetbl[(rangetblidx) - 1]
-/* XXX moved from parsetree.h. okay??
+/*
* getrelid
*
* Given the range index of a relation, return the corresponding
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 2743e1ea81..d844e323f0 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -977,8 +977,7 @@ typedef struct RangeTblEntry
*/
Oid relid; /* OID of the relation */
char relkind; /* relation kind (see pg_class.relkind) */
- LOCKMODE lockmode; /* lock level to obtain on the relation, or
- * 0 if no lock required */
+ LOCKMODE lockmode; /* lock level to obtain on the relation */
struct TableSampleClause *tablesample; /* sampling info, or NULL */
/*
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 59dd26b04e..452627dd03 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -212,8 +212,9 @@ typedef struct ModifyTable
Plan plan;
CmdType operation; /* INSERT, UPDATE, or DELETE */
bool canSetTag; /* do we set the command tag/es_processed? */
- Index nominalRelation; /* RT index of the target table specified
- * in the command */
+ Index targetRelation; /* RT index of the target table specified in
+ * the command or first child for inheritance
+ * tables */
bool partitionedTarget; /* is the target table partitioned? */
bool partColsUpdated; /* some part key in hierarchy updated */
List *resultRelations; /* integer list of RT indexes */
@@ -1092,7 +1093,7 @@ typedef struct PartitionPruneInfo
typedef struct PartitionedRelPruneInfo
{
NodeTag type;
- Index rtindex; /* Table's RT index */
+ Index rtindex; /* Partition table's RT index */
List *pruning_steps; /* List of PartitionPruneStep, see below */
Bitmapset *present_parts; /* Indexes of all partitions which subplans or
* subparts are present for. */
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index c9f288c24d..bcc2ba6db5 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -1713,8 +1713,9 @@ typedef struct ModifyTablePath
Path path;
CmdType operation; /* INSERT, UPDATE, or DELETE */
bool canSetTag; /* do we set the command tag/es_processed? */
- Index nominalRelation; /* RT index of the target table specified
- * in the command */
+ Index targetRelation; /* RT index of the target table specified in
+ * the command or first child for inheritance
+ * tables */
bool partitionedTarget; /* is the target table partitioned? */
bool partColsUpdated; /* some part key in hierarchy updated */
List *resultRelations; /* integer list of RT indexes */
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index d826e3cc55..a45c2407d0 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -238,7 +238,7 @@ extern LockRowsPath *create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
extern ModifyTablePath *create_modifytable_path(PlannerInfo *root,
RelOptInfo *rel,
CmdType operation, bool canSetTag,
- Index nominalRelation, bool partitionedTarget,
+ Index targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subpaths,
List *subroots,
diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h
index 69e6f7ffd6..abfafe5e40 100644
--- a/src/include/storage/lmgr.h
+++ b/src/include/storage/lmgr.h
@@ -37,7 +37,8 @@ typedef enum XLTW_Oper
extern void RelationInitLockInfo(Relation relation);
/* Lock a relation */
-extern bool LockRelationOid(Oid relid, LOCKMODE lockmode);
+extern void LockRelationOid(Oid relid, LOCKMODE lockmode);
+extern bool CheckRelationLockedByUs(Oid relid, LOCKMODE lockmode);
extern bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode);
extern void UnlockRelationId(LockRelId *relid, LOCKMODE lockmode);
extern void UnlockRelationOid(Oid relid, LOCKMODE lockmode);
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index ff4df7fec5..b4a71ced0b 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -540,6 +540,7 @@ extern void LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks);
extern void LockReleaseSession(LOCKMETHODID lockmethodid);
extern void LockReleaseCurrentOwner(LOCALLOCK **locallocks, int nlocks);
extern void LockReassignCurrentOwner(LOCALLOCK **locallocks, int nlocks);
+extern bool LocalLockExists(const LOCKTAG *locktag, LOCKMODE lockmode);
extern bool LockHasWaiters(const LOCKTAG *locktag,
LOCKMODE lockmode, bool sessionLock);
extern VirtualTransactionId *GetLockConflicts(const LOCKTAG *locktag,
v6-0001-Don-t-lock-range-table-relations-in-the-executor.patchapplication/octet-stream; name=v6-0001-Don-t-lock-range-table-relations-in-the-executor.patchDownload
From dd0be26bf4f4269020bd71b8b1aba77e1795b87f Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Thu, 19 Jul 2018 16:14:51 +0900
Subject: [PATCH v6 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/catalog/heap.c | 3 +-
src/backend/commands/copy.c | 7 +-
src/backend/commands/policy.c | 17 +-
src/backend/commands/tablecmds.c | 3 +-
src/backend/commands/trigger.c | 6 +-
src/backend/commands/view.c | 6 +-
src/backend/executor/execMain.c | 274 ++++++++---------------
src/backend/executor/execPartition.c | 4 +-
src/backend/executor/execUtils.c | 24 +-
src/backend/executor/nodeLockRows.c | 4 +-
src/backend/executor/nodeModifyTable.c | 42 +++-
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 | 3 +-
src/backend/parser/parse_clause.c | 3 +-
src/backend/parser/parse_relation.c | 15 +-
src/backend/parser/parse_utilcmd.c | 18 +-
src/backend/replication/logical/tablesync.c | 2 +-
src/backend/rewrite/rewriteHandler.c | 20 +-
src/backend/storage/lmgr/lmgr.c | 15 ++
src/backend/storage/lmgr/lock.c | 24 ++
src/backend/utils/cache/plancache.c | 30 +--
src/include/executor/executor.h | 2 +-
src/include/nodes/parsenodes.h | 2 +
src/include/parser/parse_relation.h | 4 +-
src/include/storage/lmgr.h | 1 +
src/include/storage/lock.h | 1 +
src/test/modules/test_rls_hooks/test_rls_hooks.c | 4 +-
30 files changed, 255 insertions(+), 283 deletions(-)
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 9176f6280b..19b530ac94 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -2551,7 +2551,8 @@ AddRelationNewConstraints(Relation rel,
rel,
NULL,
false,
- true);
+ true,
+ NoLock);
addRTEtoQuery(pstate, rte, true, true, true);
/*
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index d06662bd32..0c4a7b6f4f 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -837,16 +837,17 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
List *attnums;
ListCell *cur;
RangeTblEntry *rte;
+ LOCKMODE lockmode = is_from ? RowExclusiveLock : AccessShareLock;
Assert(!stmt->query);
/* Open and lock the relation, using the appropriate lock type. */
- rel = heap_openrv(stmt->relation,
- (is_from ? RowExclusiveLock : AccessShareLock));
+ rel = heap_openrv(stmt->relation, lockmode);
relid = RelationGetRelid(rel);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, false);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, false,
+ lockmode);
rte->requiredPerms = (is_from ? ACL_INSERT : ACL_SELECT);
tupDesc = RelationGetDescr(rel);
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index cee0ef915b..2949b4e6d7 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -567,7 +567,8 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
qual_expr = stringToNode(qual_value);
/* Add this rel to the parsestate's rangetable, for dependencies */
- addRangeTableEntryForRelation(qual_pstate, rel, NULL, false, false);
+ addRangeTableEntryForRelation(qual_pstate, rel, NULL, false, false,
+ AccessExclusiveLock);
qual_parse_rtable = qual_pstate->p_rtable;
free_parsestate(qual_pstate);
@@ -590,7 +591,7 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(with_check_pstate, rel, NULL, false,
- false);
+ false, AccessExclusiveLock);
with_check_parse_rtable = with_check_pstate->p_rtable;
free_parsestate(with_check_pstate);
@@ -752,12 +753,12 @@ CreatePolicy(CreatePolicyStmt *stmt)
/* Add for the regular security quals */
rte = addRangeTableEntryForRelation(qual_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
/* Add for the with-check quals */
rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(with_check_pstate, rte, false, true, true);
qual = transformWhereClause(qual_pstate,
@@ -928,7 +929,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
ParseState *qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
@@ -950,7 +951,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
ParseState *with_check_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(with_check_pstate, rte, false, true, true);
@@ -1097,7 +1098,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(qual_pstate, target_table, NULL,
- false, false);
+ false, false, NoLock);
qual_parse_rtable = qual_pstate->p_rtable;
free_parsestate(qual_pstate);
@@ -1138,7 +1139,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(with_check_pstate, target_table, NULL,
- false, false);
+ false, false, NoLock);
with_check_parse_rtable = with_check_pstate->p_rtable;
free_parsestate(with_check_pstate);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 29d8353779..5afa54389a 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -13632,7 +13632,8 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
* rangetable entry. We need a ParseState for transformExpr.
*/
pstate = make_parsestate(NULL);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true,
+ NoLock);
addRTEtoQuery(pstate, rte, true, true, true);
/* take care of any partition expressions */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 36778b6f4d..34f9db93d5 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -578,11 +578,13 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
*/
rte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ ShareRowExclusiveLock);
addRTEtoQuery(pstate, rte, false, true, true);
rte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ ShareRowExclusiveLock);
addRTEtoQuery(pstate, rte, false, true, true);
/* Transform expression. Copy to be sure we don't modify original */
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index ffb71c0ea7..4c379fd83b 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -387,10 +387,12 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
*/
rt_entry1 = addRangeTableEntryForRelation(pstate, viewRel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessShareLock);
rt_entry2 = addRangeTableEntryForRelation(pstate, viewRel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ 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 5443cbf67d..6f46aa5436 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -52,10 +52,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"
@@ -835,99 +837,48 @@ 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 (!IsParallelWorker() &&
+ !CheckRelationLockedByUs(rte->relid, rte->lockmode))
+ elog(WARNING, "InitPlan: lock on \"%s\" not already taken",
+ get_rel_name(rte->relid));
+ }
+ }
+#endif
+
/*
* initialize the node's execution state
*/
estate->es_range_table = rangeTable;
estate->es_plannedstmt = plannedstmt;
- /*
- * initialize result relation stuff, and open/lock the result rels.
- *
- * We must do this before initializing the plan tree, else we might try to
- * do a lock upgrade if a result rel is also a source rel.
- */
+ /* Allocate memory required for result relations */
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
{
@@ -941,73 +892,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.
@@ -1614,8 +1499,6 @@ ExecPostprocessPlan(EState *estate)
static void
ExecEndPlan(PlanState *planstate, EState *estate)
{
- ResultRelInfo *resultRelInfo;
- int i;
ListCell *l;
/*
@@ -1641,26 +1524,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);
@@ -2421,25 +2284,64 @@ ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
}
/*
- * ExecFindRowMark -- find the ExecRowMark struct for given rangetable index
+ * ExecBuildRowMark -- create and return an ExecRowMark struct for the given
+ * PlanRowMark.
*
- * If no such struct, either return NULL or throw error depending on missing_ok
+ * The created ExecRowMark is also added to the list of rowmarks in the given
+ * EState.
*/
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)
- {
- ExecRowMark *erm = (ExecRowMark *) lfirst(lc);
+ Assert(!rc->isParent);
- if (erm->rti == rti)
- return erm;
+ /* get relation's OID (will produce InvalidOid if subquery) */
+ relid = getrelid(rc->rti, estate->es_range_table);
+
+ switch (rc->markType)
+ {
+ 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;
}
/*
@@ -3179,7 +3081,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 */
@@ -3315,6 +3217,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 ec7a5267c3..3be794b97d 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -1540,9 +1540,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..efbf4bd18a 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -424,8 +424,8 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
/* safety check on size of lr_curtuples array */
Assert(rc->rti > 0 && rc->rti <= lrstate->lr_ntables);
- /* find ExecRowMark and build ExecAuxRowMark */
- erm = ExecFindRowMark(estate, rc->rti, false);
+ /* build the ExecRowMark and ExecAuxRowMark */
+ erm = ExecBuildRowMark(estate, rc);
aerm = ExecBuildAuxRowMark(erm, outerPlan->targetlist);
/*
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index bf0d5e8edb..f81769ea85 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;
@@ -2529,8 +2554,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
if (rc->isParent)
continue;
- /* find ExecRowMark (same for all subplans) */
- erm = ExecFindRowMark(estate, rc->rti, false);
+ /* build the ExecRowMark (same for all subplans) */
+ erm = ExecBuildRowMark(estate, rc);
/* build ExecAuxRowMark for each subplan */
for (i = 0; i < nplans; i++)
@@ -2686,20 +2711,27 @@ ExecEndModifyTable(ModifyTableState *node)
{
int i;
- /*
- * Allow any FDWs to shut down
- */
+ /* Perform cleanup. */
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);
}
+ /* 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 93f1e2c4eb..03d84aa0cd 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -3131,6 +3131,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 519deab63a..fc006e2830 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1361,6 +1361,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 c020600955..ce0262d170 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -1038,7 +1038,8 @@ transformOnConflictClause(ParseState *pstate,
exclRte = addRangeTableEntryForRelation(pstate,
targetrel,
makeAlias("excluded", NIL),
- false, false);
+ false, false,
+ RowExclusiveLock);
exclRte->relkind = RELKIND_COMPOSITE_TYPE;
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 d6b93f55df..689ac72c3f 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -217,7 +217,8 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
* Now build an RTE.
*/
rte = addRangeTableEntryForRelation(pstate, pstate->p_target_relation,
- relation->alias, inh, false);
+ relation->alias, inh, false,
+ 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 60b8de0f95..a9cfd1f67b 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -28,6 +28,7 @@
#include "parser/parse_enr.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
+#include "storage/lmgr.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
@@ -1217,6 +1218,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
@@ -1262,23 +1264,34 @@ addRangeTableEntry(ParseState *pstate,
*
* This is just like addRangeTableEntry() except that it makes an RTE
* given an already-open relation instead of a RangeVar reference.
+ *
+ * 'lockmode' is the lock taken on 'rel'. The caller may pass NoLock if the
+ * RTE won't be passed to the executor, that is, won't be part of a
+ * PlannedStmt.
*/
RangeTblEntry *
addRangeTableEntryForRelation(ParseState *pstate,
Relation rel,
Alias *alias,
bool inh,
- bool inFromCl)
+ bool inFromCl,
+ LOCKMODE lockmode)
{
RangeTblEntry *rte = makeNode(RangeTblEntry);
char *refname = alias ? alias->aliasname : RelationGetRelationName(rel);
Assert(pstate != NULL);
+#ifdef USE_ASSERT_CHECKING
+ if (lockmode != NoLock && !CheckRelationLockedByUs(RelationGetRelid(rel), lockmode))
+ elog(WARNING, "lock on \"%s\" is not held", RelationGetRelationName(rel));
+#endif
+
rte->rtekind = RTE_RELATION;
rte->alias = alias;
rte->relid = RelationGetRelid(rel);
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 f5c1e2a0d7..5df0348f1c 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -2526,7 +2526,8 @@ transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
* relation, but we still need to open it.
*/
rel = relation_open(relid, NoLock);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true,
+ NoLock);
/* no to join list, yes to namespaces */
addRTEtoQuery(pstate, rte, false, true, true);
@@ -2636,10 +2637,12 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
*/
oldrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessExclusiveLock);
newrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ AccessExclusiveLock);
/* Must override addRangeTableEntry's default access-check flags */
oldrte->requiredPerms = 0;
newrte->requiredPerms = 0;
@@ -2734,10 +2737,12 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
*/
oldrte = addRangeTableEntryForRelation(sub_pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessExclusiveLock);
newrte = addRangeTableEntryForRelation(sub_pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ AccessExclusiveLock);
oldrte->requiredPerms = 0;
newrte->requiredPerms = 0;
addRTEtoQuery(sub_pstate, oldrte, false, true, false);
@@ -2940,7 +2945,8 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
rel,
NULL,
false,
- true);
+ true,
+ NoLock);
addRTEtoQuery(pstate, rte, false, true, true);
/* Set up CreateStmtContext */
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index acc6498567..905a983074 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -795,7 +795,7 @@ copy_table(Relation rel)
copybuf = makeStringInfo();
pstate = make_parsestate(NULL);
- addRangeTableEntryForRelation(pstate, rel, NULL, false, false);
+ addRangeTableEntryForRelation(pstate, rel, NULL, false, false, NoLock);
attnamelist = make_copy_attnamelist(relmapentry);
cstate = BeginCopyFrom(pstate, rel, NULL, false, copy_read_data, attnamelist, NIL);
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 327e5c33d7..6562ac60b1 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,
@@ -2898,6 +2884,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
@@ -3103,7 +3090,8 @@ rewriteTargetView(Query *parsetree, Relation view)
base_rel,
makeAlias("excluded",
NIL),
- false, false);
+ false, false,
+ RowExclusiveLock);
new_exclRte->relkind = RELKIND_COMPOSITE_TYPE;
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 dc0a439638..2d8eae62e6 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -135,6 +135,21 @@ LockRelationOid(Oid relid, LOCKMODE lockmode)
}
}
+/*
+ * CheckRelationLockedByUs
+ *
+ * Returns true we hold a lock on 'relid' with 'lockmode'.
+ */
+bool
+CheckRelationLockedByUs(Oid relid, LOCKMODE lockmode)
+{
+ LOCKTAG tag;
+
+ SetLocktagRelationOid(&tag, relid);
+
+ return LocalLockExists(&tag, lockmode);
+}
+
/*
* ConditionalLockRelationOid
*
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 831ae62525..8c140fe4b0 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -563,6 +563,30 @@ DoLockModesConflict(LOCKMODE mode1, LOCKMODE mode2)
return false;
}
+/*
+ * LocalLockExists -- check if a log with 'locktag' is held locally with
+ * 'lockmode'
+ */
+bool
+LocalLockExists(const LOCKTAG *locktag, LOCKMODE lockmode)
+{
+ LOCALLOCKTAG localtag;
+ bool found;
+
+ MemSet(&localtag, 0, sizeof(localtag)); /* must clear padding */
+ localtag.lock = *locktag;
+ localtag.mode = lockmode;
+
+ /*
+ * Find the LOCALLOCK entry for this lock and lockmode
+ */
+ (void) hash_search(LockMethodLocalHash,
+ (void *) &localtag,
+ HASH_FIND, &found);
+
+ return found;
+}
+
/*
* LockHasWaiters -- look up 'locktag' and check if releasing this
* lock would wake up other processes waiting for it.
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 7271b5880b..1876345de5 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -1493,7 +1493,6 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
foreach(lc1, stmt_list)
{
PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
- int rt_index;
ListCell *lc2;
if (plannedstmt->commandType == CMD_UTILITY)
@@ -1512,14 +1511,9 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
continue;
}
- rt_index = 0;
foreach(lc2, plannedstmt->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
- LOCKMODE lockmode;
- PlanRowMark *rc;
-
- rt_index++;
if (rte->rtekind != RTE_RELATION)
continue;
@@ -1530,19 +1524,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 +1581,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 62209a8f10..d844e323f0 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -27,6 +27,7 @@
#include "nodes/primnodes.h"
#include "nodes/value.h"
#include "partitioning/partdefs.h"
+#include "storage/lockdefs.h"
typedef enum OverridingKind
@@ -976,6 +977,7 @@ typedef struct RangeTblEntry
*/
Oid relid; /* OID of the relation */
char relkind; /* relation kind (see pg_class.relkind) */
+ LOCKMODE lockmode; /* lock level to obtain on the relation */
struct TableSampleClause *tablesample; /* sampling info, or NULL */
/*
diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h
index b9792acdae..99d1b4135c 100644
--- a/src/include/parser/parse_relation.h
+++ b/src/include/parser/parse_relation.h
@@ -15,6 +15,7 @@
#define PARSE_RELATION_H
#include "parser/parse_node.h"
+#include "storage/lockdefs.h"
/*
@@ -71,7 +72,8 @@ extern RangeTblEntry *addRangeTableEntryForRelation(ParseState *pstate,
Relation rel,
Alias *alias,
bool inh,
- bool inFromCl);
+ bool inFromCl,
+ LOCKMODE lockmode);
extern RangeTblEntry *addRangeTableEntryForSubquery(ParseState *pstate,
Query *subquery,
Alias *alias,
diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h
index a217de9716..abfafe5e40 100644
--- a/src/include/storage/lmgr.h
+++ b/src/include/storage/lmgr.h
@@ -38,6 +38,7 @@ extern void RelationInitLockInfo(Relation relation);
/* Lock a relation */
extern void LockRelationOid(Oid relid, LOCKMODE lockmode);
+extern bool CheckRelationLockedByUs(Oid relid, LOCKMODE lockmode);
extern bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode);
extern void UnlockRelationId(LockRelId *relid, LOCKMODE lockmode);
extern void UnlockRelationOid(Oid relid, LOCKMODE lockmode);
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index ff4df7fec5..b4a71ced0b 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -540,6 +540,7 @@ extern void LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks);
extern void LockReleaseSession(LOCKMETHODID lockmethodid);
extern void LockReleaseCurrentOwner(LOCALLOCK **locallocks, int nlocks);
extern void LockReassignCurrentOwner(LOCALLOCK **locallocks, int nlocks);
+extern bool LocalLockExists(const LOCKTAG *locktag, LOCKMODE lockmode);
extern bool LockHasWaiters(const LOCKTAG *locktag,
LOCKMODE lockmode, bool sessionLock);
extern VirtualTransactionId *GetLockConflicts(const LOCKTAG *locktag,
diff --git a/src/test/modules/test_rls_hooks/test_rls_hooks.c b/src/test/modules/test_rls_hooks/test_rls_hooks.c
index cab67a60aa..d455c97ef6 100644
--- a/src/test/modules/test_rls_hooks/test_rls_hooks.c
+++ b/src/test/modules/test_rls_hooks/test_rls_hooks.c
@@ -81,7 +81,7 @@ test_rls_hooks_permissive(CmdType cmdtype, Relation relation)
qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, relation, NULL, false,
- false);
+ false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
@@ -144,7 +144,7 @@ test_rls_hooks_restrictive(CmdType cmdtype, Relation relation)
qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, relation, NULL, false,
- false);
+ false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
--
2.16.2.windows.1
v6-0002-Remove-useless-fields-from-planner-nodes.patchapplication/octet-stream; name=v6-0002-Remove-useless-fields-from-planner-nodes.patchDownload
From 81e6d2406dfc25847f2952c5dc62813d5c2bb1a3 Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Thu, 27 Sep 2018 13:27:24 +1200
Subject: [PATCH v6 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 bool field called
'partitionedTarget', which is set if the target is a partitioned
table. The table itself is identified by targetRelation which
replaces nominalRelation.
* '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.
---
contrib/postgres_fdw/postgres_fdw.c | 2 +-
src/backend/commands/explain.c | 6 +--
src/backend/commands/portalcmds.c | 2 +-
src/backend/executor/execMain.c | 2 +-
src/backend/executor/execParallel.c | 3 +-
src/backend/executor/execPartition.c | 2 +-
src/backend/executor/execUtils.c | 55 --------------------
src/backend/executor/nodeAppend.c | 6 ---
src/backend/executor/nodeMergeAppend.c | 6 ---
src/backend/executor/nodeModifyTable.c | 9 ++--
src/backend/executor/spi.c | 4 +-
src/backend/nodes/copyfuncs.c | 9 ++--
src/backend/nodes/outfuncs.c | 15 ++----
src/backend/nodes/readfuncs.c | 9 ++--
src/backend/optimizer/plan/createplan.c | 46 ++++-------------
src/backend/optimizer/plan/planner.c | 89 +++++++++------------------------
src/backend/optimizer/plan/setrefs.c | 49 ++----------------
src/backend/optimizer/util/pathnode.c | 12 ++---
src/backend/tcop/utility.c | 15 ++++--
src/include/executor/executor.h | 2 -
src/include/nodes/plannodes.h | 30 ++++-------
src/include/nodes/relation.h | 10 ++--
src/include/optimizer/pathnode.h | 2 +-
23 files changed, 95 insertions(+), 290 deletions(-)
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 6cbba97c22..eeb053d5d8 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -2050,7 +2050,7 @@ postgresBeginForeignInsert(ModifyTableState *mtstate,
* Vars contained in those expressions.
*/
if (plan && plan->operation == CMD_UPDATE &&
- resultRelation == plan->nominalRelation)
+ resultRelation == plan->targetRelation)
resultRelation = mtstate->resultRelInfo[0].ri_RangeTableIndex;
}
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index ed6afe79a9..5ca7f69830 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -929,7 +929,7 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
break;
case T_ModifyTable:
*rels_used = bms_add_member(*rels_used,
- ((ModifyTable *) plan)->nominalRelation);
+ ((ModifyTable *) plan)->targetRelation);
if (((ModifyTable *) plan)->exclRelRTI)
*rels_used = bms_add_member(*rels_used,
((ModifyTable *) plan)->exclRelRTI);
@@ -2924,7 +2924,7 @@ ExplainScanTarget(Scan *plan, ExplainState *es)
static void
ExplainModifyTarget(ModifyTable *plan, ExplainState *es)
{
- ExplainTargetRel((Plan *) plan, plan->nominalRelation, es);
+ ExplainTargetRel((Plan *) plan, plan->targetRelation, es);
}
/*
@@ -3088,7 +3088,7 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors,
/* Should we explicitly label target relations? */
labeltargets = (mtstate->mt_nplans > 1 ||
(mtstate->mt_nplans == 1 &&
- mtstate->resultRelInfo->ri_RangeTableIndex != node->nominalRelation));
+ mtstate->resultRelInfo->ri_RangeTableIndex != node->targetRelation));
if (labeltargets)
ExplainOpenGroup("Target Tables", "Target Tables", false, es);
diff --git a/src/backend/commands/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 6f46aa5436..fe2bbd6b5d 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -219,7 +219,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 7d8bd01994..15d8fcc352 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -176,6 +176,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;
@@ -183,7 +184,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
@@ -203,7 +203,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/execPartition.c b/src/backend/executor/execPartition.c
index 3be794b97d..1d2b3620ee 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -379,7 +379,7 @@ ExecInitPartitionInfo(ModifyTableState *mtstate,
leaf_part_rri = makeNode(ResultRelInfo);
InitResultRelInfo(leaf_part_rri,
partrel,
- node ? node->nominalRelation : 1,
+ node ? node->targetRelation : 1,
rootrel,
estate->es_instrument);
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
@@ -847,61 +847,6 @@ ShutdownExprContext(ExprContext *econtext, bool isCommit)
MemoryContextSwitchTo(oldcontext);
}
-/*
- * 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
@@ -112,12 +112,6 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
/* check for unsupported flags */
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
*/
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
@@ -75,12 +75,6 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
/* check for unsupported flags */
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
*/
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index f81769ea85..b18f9e3164 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2255,18 +2255,17 @@ 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->partitionedTarget);
+ rte = rt_fetch(node->targetRelation, estate->es_range_table);
rel = heap_open(rte->relid, NoLock);
- InitResultRelInfo(mtstate->rootResultRelInfo, rel, root_rt_index,
- NULL, estate->es_instrument);
+ InitResultRelInfo(mtstate->rootResultRelInfo, rel,
+ node->targetRelation, NULL, estate->es_instrument);
}
mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 11ca800e4c..1bee240e72 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -1358,7 +1358,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
@@ -1374,7 +1374,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..da02b8961c 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);
@@ -203,8 +202,8 @@ _copyModifyTable(const ModifyTable *from)
*/
COPY_SCALAR_FIELD(operation);
COPY_SCALAR_FIELD(canSetTag);
- COPY_SCALAR_FIELD(nominalRelation);
- COPY_NODE_FIELD(partitioned_rels);
+ COPY_SCALAR_FIELD(targetRelation);
+ COPY_SCALAR_FIELD(partitionedTarget);
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 03d84aa0cd..2e6a5a1b42 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -272,6 +272,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);
@@ -280,11 +281,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);
@@ -375,8 +374,8 @@ _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(targetRelation);
+ WRITE_BOOL_FIELD(partitionedTarget);
WRITE_BOOL_FIELD(partColsUpdated);
WRITE_NODE_FIELD(resultRelations);
WRITE_INT_FIELD(resultRelIndex);
@@ -405,7 +404,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);
}
@@ -418,7 +416,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);
@@ -2178,8 +2175,8 @@ _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(targetRelation);
+ WRITE_BOOL_FIELD(partitionedTarget);
WRITE_BOOL_FIELD(partColsUpdated);
WRITE_NODE_FIELD(resultRelations);
WRITE_NODE_FIELD(subpaths);
@@ -2257,9 +2254,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 fc006e2830..aea5b0abc4 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1496,6 +1496,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);
@@ -1504,11 +1505,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);
@@ -1597,8 +1596,8 @@ _readModifyTable(void)
READ_ENUM_FIELD(operation, CmdType);
READ_BOOL_FIELD(canSetTag);
- READ_UINT_FIELD(nominalRelation);
- READ_NODE_FIELD(partitioned_rels);
+ READ_UINT_FIELD(targetRelation);
+ READ_BOOL_FIELD(partitionedTarget);
READ_BOOL_FIELD(partColsUpdated);
READ_NODE_FIELD(resultRelations);
READ_INT_FIELD(resultRelIndex);
@@ -1632,7 +1631,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();
@@ -1648,7 +1646,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..8f20e54d9e 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 targetRelation, bool partitionedTarget,
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;
@@ -2410,8 +2405,8 @@ create_modifytable_plan(PlannerInfo *root, ModifyTablePath *best_path)
plan = make_modifytable(root,
best_path->operation,
best_path->canSetTag,
- best_path->nominalRelation,
- best_path->partitioned_rels,
+ best_path->targetRelation,
+ best_path->partitionedTarget,
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 targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subplans, List *subroots,
List *withCheckOptionLists, List *returningLists,
@@ -6537,8 +6509,8 @@ make_modifytable(PlannerInfo *root,
node->operation = operation;
node->canSetTag = canSetTag;
- node->nominalRelation = nominalRelation;
- node->partitioned_rels = flatten_partitioned_rels(partitioned_rels);
+ node->targetRelation = targetRelation;
+ node->partitionedTarget = partitionedTarget;
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 22c010c19e..a927c0a1db 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -287,6 +287,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
Plan *top_plan;
ListCell *lp,
*lr;
+ bool hasRowMarks = (parse->rowMarks != NIL);
/*
* Set up global state for this planner invocation. This data is needed
@@ -301,9 +302,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;
@@ -501,9 +500,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) */
@@ -514,6 +511,8 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
PlannerInfo *subroot = lfirst_node(PlannerInfo, lr);
lfirst(lp) = set_plan_references(subroot, subplan);
+ if (subroot->rowMarks != NIL)
+ hasRowMarks = true;
}
/* build the PlannedStmt result */
@@ -523,6 +522,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
result->queryId = parse->queryId;
result->hasReturning = (parse->returningList != NIL);
result->hasModifyingCTE = parse->hasModifyingCTE;
+ result->hasRowMarks = hasRowMarks;
result->canSetTag = parse->canSetTag;
result->transientPlan = glob->transientPlan;
result->dependsOnRole = glob->dependsOnRole;
@@ -530,11 +530,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;
@@ -1169,7 +1167,7 @@ inheritance_planner(PlannerInfo *root)
int top_parentRTindex = parse->resultRelation;
Bitmapset *subqueryRTindexes;
Bitmapset *modifiableARIindexes;
- int nominalRelation = -1;
+ int targetRelation = -1;
List *final_rtable = NIL;
int save_rel_array_size = 0;
RelOptInfo **save_rel_array = NULL;
@@ -1184,8 +1182,7 @@ inheritance_planner(PlannerInfo *root)
ListCell *lc;
Index rti;
RangeTblEntry *parent_rte;
- Relids partitioned_relids = NULL;
- List *partitioned_rels = NIL;
+ bool partitionedTarget = false;
PlannerInfo *parent_root;
Query *parent_parse;
Bitmapset *parent_relids = bms_make_singleton(top_parentRTindex);
@@ -1248,25 +1245,14 @@ inheritance_planner(PlannerInfo *root)
}
/*
- * If the parent RTE is a partitioned table, we should use that as the
- * nominal relation, because the RTEs added for partitioned tables
- * (including the root parent) as child members of the inheritance set do
- * not appear anywhere else in the plan. The situation is exactly the
- * opposite in the case of non-partitioned inheritance parent as described
- * below. For the same reason, collect the list of descendant partitioned
- * tables to be saved in ModifyTable node, so that executor can lock those
- * as well.
+ * If the parent RTE is a partitioned table, set that as the target
+ * relation and mark that we're working with a partitioned target.
*/
parent_rte = rt_fetch(top_parentRTindex, root->parse->rtable);
if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
{
- nominalRelation = top_parentRTindex;
-
- /*
- * 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);
+ targetRelation = top_parentRTindex;
+ partitionedTarget = true;
}
/*
@@ -1338,7 +1324,7 @@ inheritance_planner(PlannerInfo *root)
* inheritance parent.
*/
subroot->inhTargetKind =
- partitioned_relids ? INHKIND_PARTITIONED : INHKIND_INHERITED;
+ partitionedTarget ? INHKIND_PARTITIONED : INHKIND_INHERITED;
/*
* If this child is further partitioned, remember it as a parent.
@@ -1363,17 +1349,17 @@ inheritance_planner(PlannerInfo *root)
}
/*
- * Set the nominal target relation of the ModifyTable node if not
- * already done. We use the inheritance parent RTE as the nominal
- * target relation if it's a partitioned table (see just above this
- * loop). In the non-partitioned parent case, we'll use the first
- * child relation (even if it's excluded) as the nominal target
- * relation. Because of the way expand_inherited_rtentry works, the
- * latter should be the RTE representing the parent table in its role
- * as a simple member of the inheritance set.
+ * Set the target relation of the ModifyTable node if not already
+ * done. We use the inheritance parent RTE as the target relation
+ * if it's a partitioned table (see just above this loop). In the
+ * non-partitioned parent case, we'll use the first child relation
+ * (even if it's excluded) as the target relation. Because of the way
+ * expand_inherited_rtentry works, the latter should be the RTE
+ * representing the parent table in its role as a simple member of
+ * the inheritance set.
*
* It would be logically cleaner to *always* use the inheritance
- * parent RTE as the nominal relation; but that RTE is not otherwise
+ * parent RTE as the target relation; but that RTE is not otherwise
* referenced in the plan in the non-partitioned inheritance case.
* Instead the duplicate child RTE created by expand_inherited_rtentry
* is used elsewhere in the plan, so using the original parent RTE
@@ -1383,8 +1369,8 @@ inheritance_planner(PlannerInfo *root)
* duplicate child RTE added for the parent does not appear anywhere
* else in the plan tree.
*/
- if (nominalRelation < 0)
- nominalRelation = appinfo->child_relid;
+ if (targetRelation < 0)
+ targetRelation = appinfo->child_relid;
/*
* The rowMarks list might contain references to subquery RTEs, so
@@ -1508,15 +1494,6 @@ inheritance_planner(PlannerInfo *root)
if (IS_DUMMY_PATH(subpath))
continue;
- /*
- * Add the current parent's RT index to the partitioned_relids set if
- * we're creating the ModifyTable path for a partitioned root table.
- * (We only care about parents of non-excluded children.)
- */
- if (partitioned_relids)
- partitioned_relids = bms_add_member(partitioned_relids,
- appinfo->parent_relid);
-
/*
* If this is the first non-excluded child, its post-planning rtable
* becomes the initial contents of final_rtable; otherwise, append
@@ -1620,29 +1597,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,
+ targetRelation,
+ partitionedTarget,
root->partColsUpdated,
resultRelations,
subpaths,
@@ -2219,7 +2180,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
parse->commandType,
parse->canSetTag,
parse->resultRelation,
- NIL,
+ false,
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..17d53f356c 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);
}
@@ -847,13 +827,9 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
fix_scan_list(root, splan->exclRelTlist, rtoffset);
}
- splan->nominalRelation += rtoffset;
+ splan->targetRelation += rtoffset;
splan->exclRelRTI += rtoffset;
- foreach(l, splan->partitioned_rels)
- {
- lfirst_int(l) += rtoffset;
- }
foreach(l, splan->resultRelations)
{
lfirst_int(l) += rtoffset;
@@ -884,24 +860,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->partitionedTarget)
{
- 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->targetRelation);
}
}
break;
@@ -915,10 +884,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 +902,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..73eca1d4d0 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -3291,10 +3291,8 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
* 'rel' is the parent relation associated with the result
* 'operation' is the operation type
* 'canSetTag' is true if we set the command tag/es_processed
- * 'nominalRelation' is the parent RT index for use of EXPLAIN
- * '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.
+ * 'targetRelation' is the target table's RT index
+ * 'partitionedTarget' true if 'targetRelation' is a partitioned table
* 'partColsUpdated' is true if any partitioning columns are being updated,
* either from the target relation or a descendent partitioned table.
* 'resultRelations' is an integer list of actual RT indexes of target rel(s)
@@ -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 targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subpaths,
List *subroots,
@@ -3376,8 +3374,8 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
pathnode->operation = operation;
pathnode->canSetTag = canSetTag;
- pathnode->nominalRelation = nominalRelation;
- pathnode->partitioned_rels = list_copy(partitioned_rels);
+ pathnode->targetRelation = targetRelation;
+ pathnode->partitionedTarget = partitionedTarget;
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..d0427c64ba 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
+ 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..27ae73e3d4 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 */
@@ -219,9 +212,10 @@ typedef struct ModifyTable
Plan plan;
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 targetRelation; /* RT index of the target table specified in
+ * the command or first child for inheritance
+ * tables */
+ bool partitionedTarget; /* is the target table partitioned? */
bool partColsUpdated; /* some part key in hierarchy updated */
List *resultRelations; /* integer list of RT indexes */
int resultRelIndex; /* index of first resultRel in plan's list */
@@ -259,9 +253,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 +265,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 +916,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..bcc2ba6db5 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 */
@@ -1716,9 +1713,10 @@ typedef struct ModifyTablePath
Path path;
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 targetRelation; /* RT index of the target table specified in
+ * the command or first child for inheritance
+ * tables */
+ bool partitionedTarget; /* is the target table partitioned? */
bool partColsUpdated; /* some part key in hierarchy updated */
List *resultRelations; /* integer list of RT indexes */
List *subpaths; /* Path(s) producing source data */
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 7c5ff22650..a45c2407d0 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -238,7 +238,7 @@ extern LockRowsPath *create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
extern ModifyTablePath *create_modifytable_path(PlannerInfo *root,
RelOptInfo *rel,
CmdType operation, bool canSetTag,
- Index nominalRelation, List *partitioned_rels,
+ Index targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subpaths,
List *subroots,
--
2.16.2.windows.1
v6-0003-Prune-PlanRowMark-of-relations-that-are-pruned-fr.patchapplication/octet-stream; name=v6-0003-Prune-PlanRowMark-of-relations-that-are-pruned-fr.patchDownload
From 70e95ddc6481681fd7f92f1beee67d3ed14a0a3e Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Thu, 27 Sep 2018 13:31:11 +1200
Subject: [PATCH v6 3/4] Prune PlanRowMark of relations that are pruned from a
plan
---
src/backend/optimizer/plan/planner.c | 32 ++++++++++++++++++++++++++------
1 file changed, 26 insertions(+), 6 deletions(-)
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index a927c0a1db..074ec9bf55 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -248,7 +248,7 @@ static bool group_by_has_partkey(RelOptInfo *input_rel,
List *targetList,
List *groupClause);
static int common_prefix_cmp(const void *a, const void *b);
-
+static List *get_nondummy_rowmarks(PlannerInfo *root);
/*****************************************************************************
*
@@ -1595,7 +1595,7 @@ inheritance_planner(PlannerInfo *root)
if (parse->rowMarks)
rowMarks = NIL;
else
- rowMarks = root->rowMarks;
+ rowMarks = get_nondummy_rowmarks(root);
/* Create Path representing a ModifyTable to do the UPDATE/DELETE work */
add_path(final_rel, (Path *)
@@ -2124,11 +2124,9 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
* is what goes into the LockRows node.)
*/
if (parse->rowMarks)
- {
path = (Path *) create_lockrows_path(root, final_rel, path,
- root->rowMarks,
+ get_nondummy_rowmarks(root),
SS_assign_special_param(root));
- }
/*
* If there is a LIMIT/OFFSET clause, add the LIMIT node.
@@ -2173,7 +2171,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
if (parse->rowMarks)
rowMarks = NIL;
else
- rowMarks = root->rowMarks;
+ rowMarks = get_nondummy_rowmarks(root);
path = (Path *)
create_modifytable_path(root, final_rel,
@@ -7219,3 +7217,25 @@ group_by_has_partkey(RelOptInfo *input_rel,
return true;
}
+
+/*
+ * get_nondummy_rowmarks
+ * Return a list of PlanRowMark's that reference non-dummy relations
+ */
+static List *
+get_nondummy_rowmarks(PlannerInfo *root)
+{
+ List *rowMarks = NIL;
+ ListCell *lc;
+
+ 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]))
+ rowMarks = lappend(rowMarks, rc);
+ }
+
+ return rowMarks;
+}
--
2.16.2.windows.1
v6-0004-Revise-executor-range-table-relation-opening-clos.patchapplication/octet-stream; name=v6-0004-Revise-executor-range-table-relation-opening-clos.patchDownload
From bc70b782794935dabc76c02409c3b17d36df0a01 Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Thu, 27 Sep 2018 16:14:41 +1200
Subject: [PATCH v6 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, an arrangement which allows the executor
to have to heap_open any given range table relation only once.
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.
Accessed Relations are now also closed during ExecEndPlan(). Callers of
ExecRangeTableRelation() have no need to consider how their Relation
objects are cleaned up.
Authors: Amit Langote, David Rowley
---
contrib/postgres_fdw/postgres_fdw.c | 16 +++---
src/backend/commands/copy.c | 3 +-
src/backend/commands/trigger.c | 3 +-
src/backend/executor/README | 4 +-
src/backend/executor/execExprInterp.c | 7 +--
src/backend/executor/execMain.c | 80 ++++++++++-------------------
src/backend/executor/execPartition.c | 39 +++-----------
src/backend/executor/execUtils.c | 67 +++++++++++++++---------
src/backend/executor/nodeAppend.c | 6 ---
src/backend/executor/nodeBitmapHeapscan.c | 7 ---
src/backend/executor/nodeCustom.c | 4 --
src/backend/executor/nodeForeignscan.c | 4 --
src/backend/executor/nodeIndexonlyscan.c | 7 ---
src/backend/executor/nodeIndexscan.c | 7 ---
src/backend/executor/nodeLockRows.c | 2 +-
src/backend/executor/nodeMergeAppend.c | 6 ---
src/backend/executor/nodeModifyTable.c | 26 +++++-----
src/backend/executor/nodeSamplescan.c | 5 --
src/backend/executor/nodeSeqscan.c | 7 ---
src/backend/executor/nodeTidscan.c | 5 --
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/tablesync.c | 9 +++-
src/backend/replication/logical/worker.c | 2 +
src/include/executor/execPartition.h | 1 -
src/include/executor/executor.h | 24 ++++++++-
src/include/nodes/execnodes.h | 23 ++++++++-
src/include/nodes/plannodes.h | 2 +-
src/include/parser/parsetree.h | 10 ----
32 files changed, 194 insertions(+), 223 deletions(-)
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index eeb053d5d8..d20c75367c 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. */
@@ -1731,8 +1731,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,
@@ -2036,7 +2036,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);
@@ -2396,7 +2396,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. */
@@ -2546,10 +2546,6 @@ postgresEndDirectModify(ForeignScanState *node)
ReleaseConnection(dmstate->conn);
dmstate->conn = NULL;
- /* close the target relation. */
- if (dmstate->resultRel)
- ExecCloseScanRelation(dmstate->resultRel);
-
/* MemoryContext will be deleted automatically. */
}
@@ -5756,7 +5752,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 0c4a7b6f4f..57efb20d20 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -2483,7 +2483,8 @@ 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;
+
+ ExecInitRangeTable(estate, cstate->range_table);
/* 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 34f9db93d5..f0d45844c1 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/README b/src/backend/executor/README
index 0d7cd552eb..30df410e0e 100644
--- a/src/backend/executor/README
+++ b/src/backend/executor/README
@@ -267,8 +267,8 @@ This is a sketch of control flow for full query processing:
Per above comments, it's not really critical for ExecEndNode to free any
memory; it'll all go away in FreeExecutorState anyway. However, we do need to
-be careful to close relations, drop buffer pins, etc, so we do need to scan
-the plan state tree to find these sorts of resources.
+be careful to drop buffer pins, etc, so we do need to scan the plan state tree
+to find these sorts of resources.
The executor can also be used to evaluate simple expressions without any Plan
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index f597363eb1..f8ca60ae5a 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3934,10 +3934,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 fe2bbd6b5d..2ca25d857d 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -111,9 +111,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 */
@@ -837,26 +837,15 @@ 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 (!IsParallelWorker() &&
- !CheckRelationLockedByUs(rte->relid, rte->lockmode))
- elog(WARNING, "InitPlan: lock on \"%s\" not already taken",
- get_rel_name(rte->relid));
- }
- }
-#endif
+ ExecInitRangeTable(estate, rangeTable);
+ /*
+ * Allocate an array to store open Relations of each rangeTable item. We
+ * 0 fill this for now. The Relations are only opened and stored here the
+ * first time they're required during node initialization.
+ */
+ estate->es_relations = (Relation *) palloc0(estate->es_range_table_size *
+ sizeof(Relation));
/*
* initialize the node's execution state
*/
@@ -1500,6 +1489,14 @@ static void
ExecEndPlan(PlanState *planstate, EState *estate)
{
ListCell *l;
+ int i;
+
+ /* Close range table relations. */
+ for (i = 0; i < estate->es_range_table_size; i++)
+ {
+ if (estate->es_relations[i])
+ heap_close(estate->es_relations[i], NoLock);
+ }
/*
* shut down the node-type-specific query processing
@@ -1526,18 +1523,6 @@ ExecEndPlan(PlanState *planstate, EState *estate)
/* likewise close any trigger target relations */
ExecCleanUpTriggerState(estate);
-
- /*
- * 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);
- }
}
/* ----------------------------------------------------------------
@@ -2294,24 +2279,20 @@ 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);
-
switch (rc->markType)
{
case ROW_MARK_EXCLUSIVE:
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 */
@@ -2329,7 +2310,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;
@@ -2987,7 +2968,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));
@@ -3040,7 +3021,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();
@@ -3064,6 +3045,9 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree)
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_range_table_size = parentestate->es_range_table_size;
+ 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;
@@ -3217,18 +3201,6 @@ 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 1d2b3620ee..7fb34d2173 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -861,11 +861,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++)
{
@@ -1418,9 +1417,6 @@ adjust_partition_tlist(List *tlist, TupleConversionMap *map)
* functions. Details stored include how to map the partition index
* returned by the partition pruning code into subplan indexes.
*
- * ExecDestroyPartitionPruneState:
- * Deletes a PartitionPruneState. Must be called during executor shutdown.
- *
* ExecFindInitialMatchingSubPlans:
* Returns indexes of matching subplans. Partition pruning is attempted
* without any evaluation of expressions containing PARAM_EXEC Params.
@@ -1462,6 +1458,7 @@ PartitionPruneState *
ExecCreatePartitionPruneState(PlanState *planstate,
PartitionPruneInfo *partitionpruneinfo)
{
+ EState *estate = planstate->state;
PartitionPruneState *prunestate;
int n_part_hierarchies;
ListCell *lc;
@@ -1542,7 +1539,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);
@@ -1622,30 +1619,6 @@ ExecCreatePartitionPruneState(PlanState *planstate,
return prunestate;
}
-/*
- * ExecDestroyPartitionPruneState
- * Release resources at plan shutdown.
- *
- * We don't bother to free any memory here, since the whole executor context
- * will be going away shortly. We do need to release our relcache pins.
- */
-void
-ExecDestroyPartitionPruneState(PartitionPruneState *prunestate)
-{
- PartitionPruningData **partprunedata = prunestate->partprunedata;
- int i;
-
- for (i = 0; i < prunestate->num_partprunedata; i++)
- {
- PartitionPruningData *prunedata = partprunedata[i];
- PartitionedRelPruningData *pprune = prunedata->partrelprunedata;
- int j;
-
- for (j = 0; j < prunedata->num_partrelprunedata; j++)
- relation_close(pprune[j].context.partrel, NoLock);
- }
-}
-
/*
* ExecFindInitialMatchingSubPlans
* Identify the set of subplans that cannot be eliminated by initial
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index d32796aac3..ab46fd425d 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -25,7 +25,6 @@
* etc
*
* ExecOpenScanRelation Common code for scan node init routines.
- * ExecCloseScanRelation
*
* executor_errposition Report syntactic position of an error.
*
@@ -35,6 +34,8 @@
* GetAttributeByName Runtime extraction of columns from tuples.
* GetAttributeByNum
*
+ * ExecInitRangeTable Build an array from the range table list to
+ * allow faster lookups by relid.
* NOTES
* This file has traditionally been the place to stick misc.
* executor support stuff that doesn't really go anyplace else.
@@ -653,11 +654,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
@@ -675,26 +674,6 @@ ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
return rel;
}
-/* ----------------------------------------------------------------
- * ExecCloseScanRelation
- *
- * Close the heap relation scanned by a base-level scan plan node.
- * This should be called during the node's ExecEnd routine.
- *
- * Currently, we do not release the lock acquired by ExecOpenScanRelation.
- * This lock should be held till end of transaction. (There is a faction
- * that considers this too much locking, however.)
- *
- * If we did want to release the lock, we'd have to repeat the logic in
- * ExecOpenScanRelation in order to figure out what to release.
- * ----------------------------------------------------------------
- */
-void
-ExecCloseScanRelation(Relation scanrel)
-{
- heap_close(scanrel, NoLock);
-}
-
/*
* UpdateChangedParamSet
* Add changed parameters to a plan node's chgParam set
@@ -997,3 +976,43 @@ ExecCleanTargetListLength(List *targetlist)
}
return len;
}
+
+/*
+ * Initialize executor's range table array
+ */
+void
+ExecInitRangeTable(EState *estate, List *rangeTable)
+{
+ int rti;
+ ListCell *l;
+
+#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 (!IsParallelWorker() &&
+ !CheckRelationLockedByUs(rte->relid, rte->lockmode))
+ elog(WARNING, "InitPlan: lock on \"%s\" not already taken",
+ get_rel_name(rte->relid));
+ }
+ }
+#endif
+
+ Assert(estate != NULL);
+ 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 *));
+ rti = 0;
+ foreach(l, rangeTable)
+ estate->es_range_table_array[rti++] = lfirst_node(RangeTblEntry, l);
+}
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index eb587be221..a16b6da474 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -329,12 +329,6 @@ ExecEndAppend(AppendState *node)
*/
for (i = 0; i < nplans; i++)
ExecEndNode(appendplans[i]);
-
- /*
- * release any resources associated with run-time pruning
- */
- if (node->as_prune_state)
- ExecDestroyPartitionPruneState(node->as_prune_state);
}
void
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index baffae27e3..5307cd1b87 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -785,13 +785,11 @@ ExecReScanBitmapHeapScan(BitmapHeapScanState *node)
void
ExecEndBitmapHeapScan(BitmapHeapScanState *node)
{
- Relation relation;
HeapScanDesc scanDesc;
/*
* extract information from the node
*/
- relation = node->ss.ss_currentRelation;
scanDesc = node->ss.ss_currentScanDesc;
/*
@@ -832,11 +830,6 @@ ExecEndBitmapHeapScan(BitmapHeapScanState *node)
* close heap scan
*/
heap_endscan(scanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index b816e0b31d..9a33eda688 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -126,10 +126,6 @@ ExecEndCustomScan(CustomScanState *node)
/* Clean out the tuple table */
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /* Close the heap relation */
- if (node->ss.ss_currentRelation)
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
void
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index a2a28b7ec2..cf7df72d8c 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -258,10 +258,6 @@ ExecEndForeignScan(ForeignScanState *node)
/* clean out the tuple table */
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /* close the relation. */
- if (node->ss.ss_currentRelation)
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 4b6d531810..1b530cea40 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -373,14 +373,12 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node)
{
Relation indexRelationDesc;
IndexScanDesc indexScanDesc;
- Relation relation;
/*
* extract information from the node
*/
indexRelationDesc = node->ioss_RelationDesc;
indexScanDesc = node->ioss_ScanDesc;
- relation = node->ss.ss_currentRelation;
/* Release VM buffer pin, if any. */
if (node->ioss_VMBuffer != InvalidBuffer)
@@ -411,11 +409,6 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node)
index_endscan(indexScanDesc);
if (indexRelationDesc)
index_close(indexRelationDesc, NoLock);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 6285a2114e..786e7ac25c 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -802,14 +802,12 @@ ExecEndIndexScan(IndexScanState *node)
{
Relation indexRelationDesc;
IndexScanDesc indexScanDesc;
- Relation relation;
/*
* extract information from the node
*/
indexRelationDesc = node->iss_RelationDesc;
indexScanDesc = node->iss_ScanDesc;
- relation = node->ss.ss_currentRelation;
/*
* Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
@@ -833,11 +831,6 @@ ExecEndIndexScan(IndexScanState *node)
index_endscan(indexScanDesc);
if (indexRelationDesc)
index_close(indexRelationDesc, NoLock);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index efbf4bd18a..ff9606342b 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/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index d8e0978966..5d0dbb8146 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -363,12 +363,6 @@ ExecEndMergeAppend(MergeAppendState *node)
*/
for (i = 0; i < nplans; i++)
ExecEndNode(mergeplans[i]);
-
- /*
- * release any resources associated with run-time pruning
- */
- if (node->ms_prune_state)
- ExecDestroyPartitionPruneState(node->ms_prune_state);
}
void
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index b18f9e3164..c837d36a87 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,17 +2254,18 @@ 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->partitionedTarget);
- rte = rt_fetch(node->targetRelation, estate->es_range_table);
- rel = heap_open(rte->relid, NoLock);
- InitResultRelInfo(mtstate->rootResultRelInfo, rel,
- node->targetRelation, NULL, estate->es_instrument);
+ rel = ExecRangeTableRelation(estate, node->targetRelation);
+ InitResultRelInfo(mtstate->rootResultRelInfo,
+ rel,
+ node->targetRelation,
+ NULL,
+ estate->es_instrument);
}
mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
@@ -2722,15 +2722,13 @@ ExecEndModifyTable(ModifyTableState *node)
resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
resultRelInfo);
- /* Close indices and then the relation itself */
+ /*
+ * Close the ResultRelInfo's indexes. The relation itself
+ * is handled by the executor cleanup code.
+ */
ExecCloseIndices(resultRelInfo);
- heap_close(resultRelInfo->ri_RelationDesc, NoLock);
}
- /* 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/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index 99528be84a..92ff68a764 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -222,11 +222,6 @@ ExecEndSampleScan(SampleScanState *node)
*/
if (node->ss.ss_currentScanDesc)
heap_endscan(node->ss.ss_currentScanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index cd53491be0..92ff1e50ed 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -201,13 +201,11 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
void
ExecEndSeqScan(SeqScanState *node)
{
- Relation relation;
HeapScanDesc scanDesc;
/*
* get information from node
*/
- relation = node->ss.ss_currentRelation;
scanDesc = node->ss.ss_currentScanDesc;
/*
@@ -226,11 +224,6 @@ ExecEndSeqScan(SeqScanState *node)
*/
if (scanDesc != NULL)
heap_endscan(scanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index 0cb1946a3e..8cae56f48c 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -489,11 +489,6 @@ ExecEndTidScan(TidScanState *node)
*/
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index da02b8961c..dd76284676 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 2e6a5a1b42..6aefdd8bc4 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1029,7 +1029,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 aea5b0abc4..30609c96e6 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -2373,7 +2373,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 17d53f356c..ee01ef82d2 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -890,6 +890,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:
@@ -908,6 +923,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 e1ce8b4ddc..1763dd67a3 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/tablesync.c b/src/backend/replication/logical/tablesync.c
index 905a983074..d72f6a1b4f 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -795,7 +795,14 @@ copy_table(Relation rel)
copybuf = makeStringInfo();
pstate = make_parsestate(NULL);
- addRangeTableEntryForRelation(pstate, rel, NULL, false, false, NoLock);
+
+ /*
+ * Caller LogicalRepSyncTableStart took RowExclusiveLock, which we must
+ * record in the RTE being built, because executor initialization invoked
+ * by copy.c expects it.
+ */
+ addRangeTableEntryForRelation(pstate, rel, NULL, false, false,
+ RowExclusiveLock);
attnamelist = make_copy_attnamelist(relmapentry);
cstate = BeginCopyFrom(pstate, rel, NULL, false, copy_read_data, attnamelist, NIL);
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 42345f94d3..c63de66857 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -200,6 +200,8 @@ create_estate_for_relation(LogicalRepRelMapEntry *rel)
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/execPartition.h b/src/include/executor/execPartition.h
index 89ce53815c..04847d639d 100644
--- a/src/include/executor/execPartition.h
+++ b/src/include/executor/execPartition.h
@@ -197,7 +197,6 @@ extern void ExecCleanupTupleRouting(ModifyTableState *mtstate,
PartitionTupleRouting *proute);
extern PartitionPruneState *ExecCreatePartitionPruneState(PlanState *planstate,
PartitionPruneInfo *partitionpruneinfo);
-extern void ExecDestroyPartitionPruneState(PartitionPruneState *prunestate);
extern Bitmapset *ExecFindMatchingSubPlans(PartitionPruneState *prunestate);
extern Bitmapset *ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate,
int nsubplans);
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 1d2b48fe09..b03d8c591f 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"
/*
@@ -478,6 +479,7 @@ extern ExprContext *CreateExprContext(EState *estate);
extern ExprContext *CreateStandaloneExprContext(void);
extern void FreeExprContext(ExprContext *econtext, bool isCommit);
extern void ReScanExprContext(ExprContext *econtext);
+extern void ExecInitRangeTable(EState *estate, List *rangeTable);
#define ResetExprContext(econtext) \
MemoryContextReset((econtext)->ecxt_per_tuple_memory)
@@ -513,7 +515,6 @@ extern void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate
extern bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid);
extern Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags);
-extern void ExecCloseScanRelation(Relation scanrel);
extern int executor_errposition(EState *estate, int location);
@@ -568,4 +569,25 @@ 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)
+{
+ Relation rel = estate->es_relations[rti - 1];
+
+ if (rel == NULL)
+ {
+ RangeTblEntry *rte = exec_rt_fetch(rti, estate->es_range_table_array);
+
+ /*
+ * No need to lock the relation. Locks were already
+ * obtained by the upstream code.
+ */
+ rel = estate->es_relations[rti - 1] = heap_open(rte->relid, NoLock);
+ }
+
+ return rel;
+}
+#endif
+
#endif /* EXECUTOR_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 03ad516976..639235d622 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,11 @@ 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 Relations
+ * es_range_table_size elements in length. */
PlannedStmt *es_plannedstmt; /* link to top of plan tree */
const char *es_sourceText; /* Source text from QueryDesc */
@@ -579,6 +584,22 @@ typedef struct EState
struct JitInstrumentation *es_jit_combined_instr;
} 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]
+
+/*
+ * 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 27ae73e3d4..452627dd03 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -1093,7 +1093,7 @@ typedef struct PartitionPruneInfo
typedef struct PartitionedRelPruneInfo
{
NodeTag type;
- Oid reloid; /* OID of partition rel for this level */
+ Index rtindex; /* Partition table's RT index */
List *pruning_steps; /* List of PartitionPruneStep, see below */
Bitmapset *present_parts; /* Indexes of all partitions which subplans or
* subparts are present for. */
diff --git a/src/include/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
@@ -31,16 +31,6 @@
#define rt_fetch(rangetable_index, rangetable) \
((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.16.2.windows.1
On 2018/09/27 18:15, David Rowley wrote:
I've just completed a review of the v5 patch set. I ended up just
making the changes myself since Amit mentioned he was on leave for a
few weeks.
Thanks David. I'm back today and will look at the updated patches tomorrow.
Regards,
Amit
Hi,
On 9/27/18 5:15 AM, David Rowley wrote:
I've just completed a review of the v5 patch set. I ended up just
making the changes myself since Amit mentioned he was on leave for a
few weeks.Summary of changes:
1. Changed the way we verify the lock already exists with debug
builds. I reverted some incorrect code added to LockRelationOid that
seems to have gotten broken after being rebased on f868a8143a9. I've
just added some functions that verify the lock is in the
LockMethodLocalHash hashtable.
2. Fixed some incorrect lock types being passed into
addRangeTableEntryForRelation()
3. Added code in addRangeTableEntryForRelation to verify we actually
hold the lock that the parameter claims we do. (This found all the
errors I fixed in #2)
4. Updated various comments outdated by the patches
5. Updated executor README's mention that we close relations when
calling the end node function. This is now handled at the end of
execution.
6. Renamed nominalRelation to targetRelation. I think this fits
better since we're overloading the variable.
7. Use LOCKMODE instead of int in some places.
8. Changed warning about relation not locked to WARNING instead of NOTICE.
9. Renamed get_unpruned_rowmarks() to get_nondummy_rowmarks(). Pruning
makes me think of partition pruning but the function checks for dummy
rels. These could be dummy for reasons other than partition pruning.I've attached a diff showing the changes I made along with the full
patches which I tagged as v6.
Thanks David and Amit -- this version passes check-world. I'll also take
a deeper look.
Best regards,
Jesper
On 2018/09/27 18:15, David Rowley wrote:
I've just completed a review of the v5 patch set. I ended up just
making the changes myself since Amit mentioned he was on leave for a
few weeks.Summary of changes:
1. Changed the way we verify the lock already exists with debug
builds. I reverted some incorrect code added to LockRelationOid that
seems to have gotten broken after being rebased on f868a8143a9. I've
just added some functions that verify the lock is in the
LockMethodLocalHash hashtable.
Thanks. I guess I wasn't terribly happy with my job of rebasing on top of
f868a8143a9, because that commit had made the result of
LockAcquireExtended a bit ambiguous for me.
I like the new CheckRelationLockedByUs() and LocalLockExists() functions
that you added to lock manager.
2. Fixed some incorrect lock types being passed into
addRangeTableEntryForRelation()3. Added code in addRangeTableEntryForRelation to verify we actually
hold the lock that the parameter claims we do. (This found all the
errors I fixed in #2)
I see that I'd falsely copy-pasted AccessShareLock in transformRuleStmt,
which you've corrected to AccessExclusiveLock. I was not sure about other
cases where you've replaced NoLock by something else, because they won't
be checked or asserted, but perhaps that's fine.
4. Updated various comments outdated by the patches
5. Updated executor README's mention that we close relations when
calling the end node function. This is now handled at the end of
execution.
Thank you. I see that you also fixed some useless code that I had left
lying around as result of code movement such as the following dead code:
@@ -2711,9 +2711,7 @@ ExecEndModifyTable(ModifyTableState *node)
{
int i;
- /*
- * close the result relation(s) if any, but hold locks until xact commit.
- */
+ /* Perform cleanup. */
for (i = 0; i < node->mt_nplans; i++)
{
ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
@@ -2728,7 +2726,6 @@ ExecEndModifyTable(ModifyTableState *node)
/* Close indices and then the relation itself */
ExecCloseIndices(resultRelInfo);
heap_close(resultRelInfo->ri_RelationDesc, NoLock);
- resultRelInfo++;
}
6. Renamed nominalRelation to targetRelation. I think this fits
better since we're overloading the variable.
That makes sense to me.
7. Use LOCKMODE instead of int in some places.
8. Changed warning about relation not locked to WARNING instead of NOTICE.
Oops, think I'd forgotten to do that myself.
9. Renamed get_unpruned_rowmarks() to get_nondummy_rowmarks(). Pruning
makes me think of partition pruning but the function checks for dummy
rels. These could be dummy for reasons other than partition pruning.
Makes sense too.
I've attached a diff showing the changes I made along with the full
patches which I tagged as v6.
Thanks a lot for working on that. I've made minor tweaks, which find in
the attached updated patches (a .diff file containing changes from v6 to
v7 is also attached).
Regards,
Amit
Attachments:
v6_to_v7_changes.difftext/plain; charset=UTF-8; name=v6_to_v7_changes.diffDownload
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 2ca25d857d..d895ed29d1 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -841,8 +841,8 @@ InitPlan(QueryDesc *queryDesc, int eflags)
/*
* Allocate an array to store open Relations of each rangeTable item. We
- * 0 fill this for now. The Relations are only opened and stored here the
- * first time they're required during node initialization.
+ * zero-fill this for now. The Relations are only opened and stored here
+ * the first time they're required during node initialization.
*/
estate->es_relations = (Relation *) palloc0(estate->es_range_table_size *
sizeof(Relation));
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index ab46fd425d..bd306d0389 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -994,8 +994,9 @@ ExecInitRangeTable(EState *estate, List *rangeTable)
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.
+ * The following asserts that the necessary lock on the relation
+ * has already been taken. That can only however be true in the
+ * parallel leader.
*/
Assert(rte->lockmode != NoLock);
if (!IsParallelWorker() &&
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index a9cfd1f67b..cbee07aeb8 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -1283,8 +1283,10 @@ addRangeTableEntryForRelation(ParseState *pstate,
Assert(pstate != NULL);
#ifdef USE_ASSERT_CHECKING
- if (lockmode != NoLock && !CheckRelationLockedByUs(RelationGetRelid(rel), lockmode))
- elog(WARNING, "lock on \"%s\" is not held", RelationGetRelationName(rel));
+ if (lockmode != NoLock &&
+ !CheckRelationLockedByUs(RelationGetRelid(rel), lockmode))
+ elog(WARNING, "lock on \"%s\" is not held",
+ RelationGetRelationName(rel));
#endif
rte->rtekind = RTE_RELATION;
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index d844e323f0..2a265d591d 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -977,7 +977,10 @@ typedef struct RangeTblEntry
*/
Oid relid; /* OID of the relation */
char relkind; /* relation kind (see pg_class.relkind) */
- LOCKMODE lockmode; /* lock level to obtain on the relation */
+ LOCKMODE lockmode; /* lock level to obtain on the relation; must
+ * be non-zero for all plain relation RTEs
+ * that will be passed to the executor via
+ * PlannedStmt. */
struct TableSampleClause *tablesample; /* sampling info, or NULL */
/*
v7-0001-Don-t-lock-range-table-relations-in-the-executor.patchtext/plain; charset=UTF-8; name=v7-0001-Don-t-lock-range-table-relations-in-the-executor.patchDownload
From a8a2d82d15991968d921339e6e7d63030cf61bce Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Thu, 19 Jul 2018 16:14:51 +0900
Subject: [PATCH v7 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/catalog/heap.c | 3 +-
src/backend/commands/copy.c | 7 +-
src/backend/commands/policy.c | 17 +-
src/backend/commands/tablecmds.c | 3 +-
src/backend/commands/trigger.c | 6 +-
src/backend/commands/view.c | 6 +-
src/backend/executor/execMain.c | 275 ++++++++---------------
src/backend/executor/execPartition.c | 4 +-
src/backend/executor/execUtils.c | 24 +-
src/backend/executor/nodeLockRows.c | 4 +-
src/backend/executor/nodeModifyTable.c | 42 +++-
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 | 3 +-
src/backend/parser/parse_clause.c | 3 +-
src/backend/parser/parse_relation.c | 17 +-
src/backend/parser/parse_utilcmd.c | 18 +-
src/backend/replication/logical/tablesync.c | 2 +-
src/backend/rewrite/rewriteHandler.c | 20 +-
src/backend/storage/lmgr/lmgr.c | 15 ++
src/backend/storage/lmgr/lock.c | 24 ++
src/backend/utils/cache/plancache.c | 30 +--
src/include/executor/executor.h | 2 +-
src/include/nodes/parsenodes.h | 5 +
src/include/parser/parse_relation.h | 4 +-
src/include/storage/lmgr.h | 1 +
src/include/storage/lock.h | 1 +
src/test/modules/test_rls_hooks/test_rls_hooks.c | 4 +-
30 files changed, 261 insertions(+), 283 deletions(-)
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 9176f6280b..19b530ac94 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -2551,7 +2551,8 @@ AddRelationNewConstraints(Relation rel,
rel,
NULL,
false,
- true);
+ true,
+ NoLock);
addRTEtoQuery(pstate, rte, true, true, true);
/*
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index d06662bd32..0c4a7b6f4f 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -837,16 +837,17 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
List *attnums;
ListCell *cur;
RangeTblEntry *rte;
+ LOCKMODE lockmode = is_from ? RowExclusiveLock : AccessShareLock;
Assert(!stmt->query);
/* Open and lock the relation, using the appropriate lock type. */
- rel = heap_openrv(stmt->relation,
- (is_from ? RowExclusiveLock : AccessShareLock));
+ rel = heap_openrv(stmt->relation, lockmode);
relid = RelationGetRelid(rel);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, false);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, false,
+ lockmode);
rte->requiredPerms = (is_from ? ACL_INSERT : ACL_SELECT);
tupDesc = RelationGetDescr(rel);
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index cee0ef915b..2949b4e6d7 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -567,7 +567,8 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
qual_expr = stringToNode(qual_value);
/* Add this rel to the parsestate's rangetable, for dependencies */
- addRangeTableEntryForRelation(qual_pstate, rel, NULL, false, false);
+ addRangeTableEntryForRelation(qual_pstate, rel, NULL, false, false,
+ AccessExclusiveLock);
qual_parse_rtable = qual_pstate->p_rtable;
free_parsestate(qual_pstate);
@@ -590,7 +591,7 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(with_check_pstate, rel, NULL, false,
- false);
+ false, AccessExclusiveLock);
with_check_parse_rtable = with_check_pstate->p_rtable;
free_parsestate(with_check_pstate);
@@ -752,12 +753,12 @@ CreatePolicy(CreatePolicyStmt *stmt)
/* Add for the regular security quals */
rte = addRangeTableEntryForRelation(qual_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
/* Add for the with-check quals */
rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(with_check_pstate, rte, false, true, true);
qual = transformWhereClause(qual_pstate,
@@ -928,7 +929,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
ParseState *qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
@@ -950,7 +951,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
ParseState *with_check_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(with_check_pstate, rte, false, true, true);
@@ -1097,7 +1098,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(qual_pstate, target_table, NULL,
- false, false);
+ false, false, NoLock);
qual_parse_rtable = qual_pstate->p_rtable;
free_parsestate(qual_pstate);
@@ -1138,7 +1139,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(with_check_pstate, target_table, NULL,
- false, false);
+ false, false, NoLock);
with_check_parse_rtable = with_check_pstate->p_rtable;
free_parsestate(with_check_pstate);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 29d8353779..5afa54389a 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -13632,7 +13632,8 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
* rangetable entry. We need a ParseState for transformExpr.
*/
pstate = make_parsestate(NULL);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true,
+ NoLock);
addRTEtoQuery(pstate, rte, true, true, true);
/* take care of any partition expressions */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 36778b6f4d..34f9db93d5 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -578,11 +578,13 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
*/
rte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ ShareRowExclusiveLock);
addRTEtoQuery(pstate, rte, false, true, true);
rte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ ShareRowExclusiveLock);
addRTEtoQuery(pstate, rte, false, true, true);
/* Transform expression. Copy to be sure we don't modify original */
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index ffb71c0ea7..4c379fd83b 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -387,10 +387,12 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
*/
rt_entry1 = addRangeTableEntryForRelation(pstate, viewRel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessShareLock);
rt_entry2 = addRangeTableEntryForRelation(pstate, viewRel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ 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 5443cbf67d..a9edc90a52 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -52,10 +52,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"
@@ -835,99 +837,49 @@ 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 the necessary lock on the relation
+ * has already been taken. That can only however be true in the
+ * parallel leader.
+ */
+ Assert(rte->lockmode != NoLock);
+ if (!IsParallelWorker() &&
+ !CheckRelationLockedByUs(rte->relid, rte->lockmode))
+ elog(WARNING, "InitPlan: lock on \"%s\" not already taken",
+ get_rel_name(rte->relid));
+ }
+ }
+#endif
+
/*
* initialize the node's execution state
*/
estate->es_range_table = rangeTable;
estate->es_plannedstmt = plannedstmt;
- /*
- * initialize result relation stuff, and open/lock the result rels.
- *
- * We must do this before initializing the plan tree, else we might try to
- * do a lock upgrade if a result rel is also a source rel.
- */
+ /* Allocate memory required for result relations */
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
{
@@ -941,73 +893,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.
@@ -1614,8 +1500,6 @@ ExecPostprocessPlan(EState *estate)
static void
ExecEndPlan(PlanState *planstate, EState *estate)
{
- ResultRelInfo *resultRelInfo;
- int i;
ListCell *l;
/*
@@ -1641,26 +1525,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);
@@ -2421,25 +2285,64 @@ ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
}
/*
- * ExecFindRowMark -- find the ExecRowMark struct for given rangetable index
+ * ExecBuildRowMark -- create and return an ExecRowMark struct for the given
+ * PlanRowMark.
*
- * If no such struct, either return NULL or throw error depending on missing_ok
+ * The created ExecRowMark is also added to the list of rowmarks in the given
+ * EState.
*/
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);
+
+ 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;
}
/*
@@ -3179,7 +3082,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 */
@@ -3315,6 +3218,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 ec7a5267c3..3be794b97d 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -1540,9 +1540,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..efbf4bd18a 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -424,8 +424,8 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
/* safety check on size of lr_curtuples array */
Assert(rc->rti > 0 && rc->rti <= lrstate->lr_ntables);
- /* find ExecRowMark and build ExecAuxRowMark */
- erm = ExecFindRowMark(estate, rc->rti, false);
+ /* build the ExecRowMark and ExecAuxRowMark */
+ erm = ExecBuildRowMark(estate, rc);
aerm = ExecBuildAuxRowMark(erm, outerPlan->targetlist);
/*
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index bf0d5e8edb..f81769ea85 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;
@@ -2529,8 +2554,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
if (rc->isParent)
continue;
- /* find ExecRowMark (same for all subplans) */
- erm = ExecFindRowMark(estate, rc->rti, false);
+ /* build the ExecRowMark (same for all subplans) */
+ erm = ExecBuildRowMark(estate, rc);
/* build ExecAuxRowMark for each subplan */
for (i = 0; i < nplans; i++)
@@ -2686,20 +2711,27 @@ ExecEndModifyTable(ModifyTableState *node)
{
int i;
- /*
- * Allow any FDWs to shut down
- */
+ /* Perform cleanup. */
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);
}
+ /* 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 93f1e2c4eb..03d84aa0cd 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -3131,6 +3131,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 519deab63a..fc006e2830 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1361,6 +1361,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 c020600955..ce0262d170 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -1038,7 +1038,8 @@ transformOnConflictClause(ParseState *pstate,
exclRte = addRangeTableEntryForRelation(pstate,
targetrel,
makeAlias("excluded", NIL),
- false, false);
+ false, false,
+ RowExclusiveLock);
exclRte->relkind = RELKIND_COMPOSITE_TYPE;
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 d6b93f55df..689ac72c3f 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -217,7 +217,8 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
* Now build an RTE.
*/
rte = addRangeTableEntryForRelation(pstate, pstate->p_target_relation,
- relation->alias, inh, false);
+ relation->alias, inh, false,
+ 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 60b8de0f95..cbee07aeb8 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -28,6 +28,7 @@
#include "parser/parse_enr.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
+#include "storage/lmgr.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
@@ -1217,6 +1218,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
@@ -1262,23 +1264,36 @@ addRangeTableEntry(ParseState *pstate,
*
* This is just like addRangeTableEntry() except that it makes an RTE
* given an already-open relation instead of a RangeVar reference.
+ *
+ * 'lockmode' is the lock taken on 'rel'. The caller may pass NoLock if the
+ * RTE won't be passed to the executor, that is, won't be part of a
+ * PlannedStmt.
*/
RangeTblEntry *
addRangeTableEntryForRelation(ParseState *pstate,
Relation rel,
Alias *alias,
bool inh,
- bool inFromCl)
+ bool inFromCl,
+ LOCKMODE lockmode)
{
RangeTblEntry *rte = makeNode(RangeTblEntry);
char *refname = alias ? alias->aliasname : RelationGetRelationName(rel);
Assert(pstate != NULL);
+#ifdef USE_ASSERT_CHECKING
+ if (lockmode != NoLock &&
+ !CheckRelationLockedByUs(RelationGetRelid(rel), lockmode))
+ elog(WARNING, "lock on \"%s\" is not held",
+ RelationGetRelationName(rel));
+#endif
+
rte->rtekind = RTE_RELATION;
rte->alias = alias;
rte->relid = RelationGetRelid(rel);
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 f5c1e2a0d7..5df0348f1c 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -2526,7 +2526,8 @@ transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
* relation, but we still need to open it.
*/
rel = relation_open(relid, NoLock);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true,
+ NoLock);
/* no to join list, yes to namespaces */
addRTEtoQuery(pstate, rte, false, true, true);
@@ -2636,10 +2637,12 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
*/
oldrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessExclusiveLock);
newrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ AccessExclusiveLock);
/* Must override addRangeTableEntry's default access-check flags */
oldrte->requiredPerms = 0;
newrte->requiredPerms = 0;
@@ -2734,10 +2737,12 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
*/
oldrte = addRangeTableEntryForRelation(sub_pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessExclusiveLock);
newrte = addRangeTableEntryForRelation(sub_pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ AccessExclusiveLock);
oldrte->requiredPerms = 0;
newrte->requiredPerms = 0;
addRTEtoQuery(sub_pstate, oldrte, false, true, false);
@@ -2940,7 +2945,8 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
rel,
NULL,
false,
- true);
+ true,
+ NoLock);
addRTEtoQuery(pstate, rte, false, true, true);
/* Set up CreateStmtContext */
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index acc6498567..905a983074 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -795,7 +795,7 @@ copy_table(Relation rel)
copybuf = makeStringInfo();
pstate = make_parsestate(NULL);
- addRangeTableEntryForRelation(pstate, rel, NULL, false, false);
+ addRangeTableEntryForRelation(pstate, rel, NULL, false, false, NoLock);
attnamelist = make_copy_attnamelist(relmapentry);
cstate = BeginCopyFrom(pstate, rel, NULL, false, copy_read_data, attnamelist, NIL);
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 327e5c33d7..6562ac60b1 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,
@@ -2898,6 +2884,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
@@ -3103,7 +3090,8 @@ rewriteTargetView(Query *parsetree, Relation view)
base_rel,
makeAlias("excluded",
NIL),
- false, false);
+ false, false,
+ RowExclusiveLock);
new_exclRte->relkind = RELKIND_COMPOSITE_TYPE;
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 dc0a439638..2d8eae62e6 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -136,6 +136,21 @@ LockRelationOid(Oid relid, LOCKMODE lockmode)
}
/*
+ * CheckRelationLockedByUs
+ *
+ * Returns true we hold a lock on 'relid' with 'lockmode'.
+ */
+bool
+CheckRelationLockedByUs(Oid relid, LOCKMODE lockmode)
+{
+ LOCKTAG tag;
+
+ SetLocktagRelationOid(&tag, relid);
+
+ return LocalLockExists(&tag, lockmode);
+}
+
+/*
* ConditionalLockRelationOid
*
* As above, but only lock if we can get the lock without blocking.
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 831ae62525..8c140fe4b0 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -564,6 +564,30 @@ DoLockModesConflict(LOCKMODE mode1, LOCKMODE mode2)
}
/*
+ * LocalLockExists -- check if a log with 'locktag' is held locally with
+ * 'lockmode'
+ */
+bool
+LocalLockExists(const LOCKTAG *locktag, LOCKMODE lockmode)
+{
+ LOCALLOCKTAG localtag;
+ bool found;
+
+ MemSet(&localtag, 0, sizeof(localtag)); /* must clear padding */
+ localtag.lock = *locktag;
+ localtag.mode = lockmode;
+
+ /*
+ * Find the LOCALLOCK entry for this lock and lockmode
+ */
+ (void) hash_search(LockMethodLocalHash,
+ (void *) &localtag,
+ HASH_FIND, &found);
+
+ return found;
+}
+
+/*
* LockHasWaiters -- look up 'locktag' and check if releasing this
* lock would wake up other processes waiting for it.
*/
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 7271b5880b..1876345de5 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -1493,7 +1493,6 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
foreach(lc1, stmt_list)
{
PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
- int rt_index;
ListCell *lc2;
if (plannedstmt->commandType == CMD_UTILITY)
@@ -1512,14 +1511,9 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
continue;
}
- rt_index = 0;
foreach(lc2, plannedstmt->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
- LOCKMODE lockmode;
- PlanRowMark *rc;
-
- rt_index++;
if (rte->rtekind != RTE_RELATION)
continue;
@@ -1530,19 +1524,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 +1581,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 62209a8f10..2a265d591d 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -27,6 +27,7 @@
#include "nodes/primnodes.h"
#include "nodes/value.h"
#include "partitioning/partdefs.h"
+#include "storage/lockdefs.h"
typedef enum OverridingKind
@@ -976,6 +977,10 @@ typedef struct RangeTblEntry
*/
Oid relid; /* OID of the relation */
char relkind; /* relation kind (see pg_class.relkind) */
+ LOCKMODE lockmode; /* lock level to obtain on the relation; must
+ * be non-zero for all plain relation RTEs
+ * that will be passed to the executor via
+ * PlannedStmt. */
struct TableSampleClause *tablesample; /* sampling info, or NULL */
/*
diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h
index b9792acdae..99d1b4135c 100644
--- a/src/include/parser/parse_relation.h
+++ b/src/include/parser/parse_relation.h
@@ -15,6 +15,7 @@
#define PARSE_RELATION_H
#include "parser/parse_node.h"
+#include "storage/lockdefs.h"
/*
@@ -71,7 +72,8 @@ extern RangeTblEntry *addRangeTableEntryForRelation(ParseState *pstate,
Relation rel,
Alias *alias,
bool inh,
- bool inFromCl);
+ bool inFromCl,
+ LOCKMODE lockmode);
extern RangeTblEntry *addRangeTableEntryForSubquery(ParseState *pstate,
Query *subquery,
Alias *alias,
diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h
index a217de9716..abfafe5e40 100644
--- a/src/include/storage/lmgr.h
+++ b/src/include/storage/lmgr.h
@@ -38,6 +38,7 @@ extern void RelationInitLockInfo(Relation relation);
/* Lock a relation */
extern void LockRelationOid(Oid relid, LOCKMODE lockmode);
+extern bool CheckRelationLockedByUs(Oid relid, LOCKMODE lockmode);
extern bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode);
extern void UnlockRelationId(LockRelId *relid, LOCKMODE lockmode);
extern void UnlockRelationOid(Oid relid, LOCKMODE lockmode);
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index ff4df7fec5..b4a71ced0b 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -540,6 +540,7 @@ extern void LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks);
extern void LockReleaseSession(LOCKMETHODID lockmethodid);
extern void LockReleaseCurrentOwner(LOCALLOCK **locallocks, int nlocks);
extern void LockReassignCurrentOwner(LOCALLOCK **locallocks, int nlocks);
+extern bool LocalLockExists(const LOCKTAG *locktag, LOCKMODE lockmode);
extern bool LockHasWaiters(const LOCKTAG *locktag,
LOCKMODE lockmode, bool sessionLock);
extern VirtualTransactionId *GetLockConflicts(const LOCKTAG *locktag,
diff --git a/src/test/modules/test_rls_hooks/test_rls_hooks.c b/src/test/modules/test_rls_hooks/test_rls_hooks.c
index cab67a60aa..d455c97ef6 100644
--- a/src/test/modules/test_rls_hooks/test_rls_hooks.c
+++ b/src/test/modules/test_rls_hooks/test_rls_hooks.c
@@ -81,7 +81,7 @@ test_rls_hooks_permissive(CmdType cmdtype, Relation relation)
qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, relation, NULL, false,
- false);
+ false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
@@ -144,7 +144,7 @@ test_rls_hooks_restrictive(CmdType cmdtype, Relation relation)
qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, relation, NULL, false,
- false);
+ false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
--
2.11.0
v7-0002-Remove-useless-fields-from-planner-nodes.patchtext/plain; charset=UTF-8; name=v7-0002-Remove-useless-fields-from-planner-nodes.patchDownload
From 4ad70348d8fa0ef95052451aec88aa9e2076567e Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Thu, 27 Sep 2018 13:27:24 +1200
Subject: [PATCH v7 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 bool field called
'partitionedTarget', which is set if the target is a partitioned
table. The table itself is identified by targetRelation which
replaces nominalRelation.
* '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.
---
contrib/postgres_fdw/postgres_fdw.c | 2 +-
src/backend/commands/explain.c | 6 +--
src/backend/commands/portalcmds.c | 2 +-
src/backend/executor/execMain.c | 2 +-
src/backend/executor/execParallel.c | 3 +-
src/backend/executor/execPartition.c | 2 +-
src/backend/executor/execUtils.c | 55 --------------------
src/backend/executor/nodeAppend.c | 6 ---
src/backend/executor/nodeMergeAppend.c | 6 ---
src/backend/executor/nodeModifyTable.c | 9 ++--
src/backend/executor/spi.c | 4 +-
src/backend/nodes/copyfuncs.c | 9 ++--
src/backend/nodes/outfuncs.c | 15 ++----
src/backend/nodes/readfuncs.c | 9 ++--
src/backend/optimizer/plan/createplan.c | 46 ++++-------------
src/backend/optimizer/plan/planner.c | 89 +++++++++------------------------
src/backend/optimizer/plan/setrefs.c | 49 ++----------------
src/backend/optimizer/util/pathnode.c | 12 ++---
src/backend/tcop/utility.c | 15 ++++--
src/include/executor/executor.h | 2 -
src/include/nodes/plannodes.h | 30 ++++-------
src/include/nodes/relation.h | 10 ++--
src/include/optimizer/pathnode.h | 2 +-
23 files changed, 95 insertions(+), 290 deletions(-)
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 6cbba97c22..eeb053d5d8 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -2050,7 +2050,7 @@ postgresBeginForeignInsert(ModifyTableState *mtstate,
* Vars contained in those expressions.
*/
if (plan && plan->operation == CMD_UPDATE &&
- resultRelation == plan->nominalRelation)
+ resultRelation == plan->targetRelation)
resultRelation = mtstate->resultRelInfo[0].ri_RangeTableIndex;
}
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index ed6afe79a9..5ca7f69830 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -929,7 +929,7 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
break;
case T_ModifyTable:
*rels_used = bms_add_member(*rels_used,
- ((ModifyTable *) plan)->nominalRelation);
+ ((ModifyTable *) plan)->targetRelation);
if (((ModifyTable *) plan)->exclRelRTI)
*rels_used = bms_add_member(*rels_used,
((ModifyTable *) plan)->exclRelRTI);
@@ -2924,7 +2924,7 @@ ExplainScanTarget(Scan *plan, ExplainState *es)
static void
ExplainModifyTarget(ModifyTable *plan, ExplainState *es)
{
- ExplainTargetRel((Plan *) plan, plan->nominalRelation, es);
+ ExplainTargetRel((Plan *) plan, plan->targetRelation, es);
}
/*
@@ -3088,7 +3088,7 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors,
/* Should we explicitly label target relations? */
labeltargets = (mtstate->mt_nplans > 1 ||
(mtstate->mt_nplans == 1 &&
- mtstate->resultRelInfo->ri_RangeTableIndex != node->nominalRelation));
+ mtstate->resultRelInfo->ri_RangeTableIndex != node->targetRelation));
if (labeltargets)
ExplainOpenGroup("Target Tables", "Target Tables", false, es);
diff --git a/src/backend/commands/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 a9edc90a52..3c197c55f4 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -219,7 +219,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 7d8bd01994..15d8fcc352 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -176,6 +176,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;
@@ -183,7 +184,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
@@ -203,7 +203,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/execPartition.c b/src/backend/executor/execPartition.c
index 3be794b97d..1d2b3620ee 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -379,7 +379,7 @@ ExecInitPartitionInfo(ModifyTableState *mtstate,
leaf_part_rri = makeNode(ResultRelInfo);
InitResultRelInfo(leaf_part_rri,
partrel,
- node ? node->nominalRelation : 1,
+ node ? node->targetRelation : 1,
rootrel,
estate->es_instrument);
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 f81769ea85..b18f9e3164 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2255,18 +2255,17 @@ 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->partitionedTarget);
+ rte = rt_fetch(node->targetRelation, estate->es_range_table);
rel = heap_open(rte->relid, NoLock);
- InitResultRelInfo(mtstate->rootResultRelInfo, rel, root_rt_index,
- NULL, estate->es_instrument);
+ InitResultRelInfo(mtstate->rootResultRelInfo, rel,
+ node->targetRelation, NULL, estate->es_instrument);
}
mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 11ca800e4c..1bee240e72 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -1358,7 +1358,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
@@ -1374,7 +1374,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..da02b8961c 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);
@@ -203,8 +202,8 @@ _copyModifyTable(const ModifyTable *from)
*/
COPY_SCALAR_FIELD(operation);
COPY_SCALAR_FIELD(canSetTag);
- COPY_SCALAR_FIELD(nominalRelation);
- COPY_NODE_FIELD(partitioned_rels);
+ COPY_SCALAR_FIELD(targetRelation);
+ COPY_SCALAR_FIELD(partitionedTarget);
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 03d84aa0cd..2e6a5a1b42 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -272,6 +272,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);
@@ -280,11 +281,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);
@@ -375,8 +374,8 @@ _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(targetRelation);
+ WRITE_BOOL_FIELD(partitionedTarget);
WRITE_BOOL_FIELD(partColsUpdated);
WRITE_NODE_FIELD(resultRelations);
WRITE_INT_FIELD(resultRelIndex);
@@ -405,7 +404,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);
}
@@ -418,7 +416,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);
@@ -2178,8 +2175,8 @@ _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(targetRelation);
+ WRITE_BOOL_FIELD(partitionedTarget);
WRITE_BOOL_FIELD(partColsUpdated);
WRITE_NODE_FIELD(resultRelations);
WRITE_NODE_FIELD(subpaths);
@@ -2257,9 +2254,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 fc006e2830..aea5b0abc4 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1496,6 +1496,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);
@@ -1504,11 +1505,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);
@@ -1597,8 +1596,8 @@ _readModifyTable(void)
READ_ENUM_FIELD(operation, CmdType);
READ_BOOL_FIELD(canSetTag);
- READ_UINT_FIELD(nominalRelation);
- READ_NODE_FIELD(partitioned_rels);
+ READ_UINT_FIELD(targetRelation);
+ READ_BOOL_FIELD(partitionedTarget);
READ_BOOL_FIELD(partColsUpdated);
READ_NODE_FIELD(resultRelations);
READ_INT_FIELD(resultRelIndex);
@@ -1632,7 +1631,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();
@@ -1648,7 +1646,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..8f20e54d9e 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 targetRelation, bool partitionedTarget,
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;
@@ -2410,8 +2405,8 @@ create_modifytable_plan(PlannerInfo *root, ModifyTablePath *best_path)
plan = make_modifytable(root,
best_path->operation,
best_path->canSetTag,
- best_path->nominalRelation,
- best_path->partitioned_rels,
+ best_path->targetRelation,
+ best_path->partitionedTarget,
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 targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subplans, List *subroots,
List *withCheckOptionLists, List *returningLists,
@@ -6537,8 +6509,8 @@ make_modifytable(PlannerInfo *root,
node->operation = operation;
node->canSetTag = canSetTag;
- node->nominalRelation = nominalRelation;
- node->partitioned_rels = flatten_partitioned_rels(partitioned_rels);
+ node->targetRelation = targetRelation;
+ node->partitionedTarget = partitionedTarget;
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 22c010c19e..a927c0a1db 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -287,6 +287,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
Plan *top_plan;
ListCell *lp,
*lr;
+ bool hasRowMarks = (parse->rowMarks != NIL);
/*
* Set up global state for this planner invocation. This data is needed
@@ -301,9 +302,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;
@@ -501,9 +500,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) */
@@ -514,6 +511,8 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
PlannerInfo *subroot = lfirst_node(PlannerInfo, lr);
lfirst(lp) = set_plan_references(subroot, subplan);
+ if (subroot->rowMarks != NIL)
+ hasRowMarks = true;
}
/* build the PlannedStmt result */
@@ -523,6 +522,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
result->queryId = parse->queryId;
result->hasReturning = (parse->returningList != NIL);
result->hasModifyingCTE = parse->hasModifyingCTE;
+ result->hasRowMarks = hasRowMarks;
result->canSetTag = parse->canSetTag;
result->transientPlan = glob->transientPlan;
result->dependsOnRole = glob->dependsOnRole;
@@ -530,11 +530,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;
@@ -1169,7 +1167,7 @@ inheritance_planner(PlannerInfo *root)
int top_parentRTindex = parse->resultRelation;
Bitmapset *subqueryRTindexes;
Bitmapset *modifiableARIindexes;
- int nominalRelation = -1;
+ int targetRelation = -1;
List *final_rtable = NIL;
int save_rel_array_size = 0;
RelOptInfo **save_rel_array = NULL;
@@ -1184,8 +1182,7 @@ inheritance_planner(PlannerInfo *root)
ListCell *lc;
Index rti;
RangeTblEntry *parent_rte;
- Relids partitioned_relids = NULL;
- List *partitioned_rels = NIL;
+ bool partitionedTarget = false;
PlannerInfo *parent_root;
Query *parent_parse;
Bitmapset *parent_relids = bms_make_singleton(top_parentRTindex);
@@ -1248,25 +1245,14 @@ inheritance_planner(PlannerInfo *root)
}
/*
- * If the parent RTE is a partitioned table, we should use that as the
- * nominal relation, because the RTEs added for partitioned tables
- * (including the root parent) as child members of the inheritance set do
- * not appear anywhere else in the plan. The situation is exactly the
- * opposite in the case of non-partitioned inheritance parent as described
- * below. For the same reason, collect the list of descendant partitioned
- * tables to be saved in ModifyTable node, so that executor can lock those
- * as well.
+ * If the parent RTE is a partitioned table, set that as the target
+ * relation and mark that we're working with a partitioned target.
*/
parent_rte = rt_fetch(top_parentRTindex, root->parse->rtable);
if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
{
- nominalRelation = top_parentRTindex;
-
- /*
- * 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);
+ targetRelation = top_parentRTindex;
+ partitionedTarget = true;
}
/*
@@ -1338,7 +1324,7 @@ inheritance_planner(PlannerInfo *root)
* inheritance parent.
*/
subroot->inhTargetKind =
- partitioned_relids ? INHKIND_PARTITIONED : INHKIND_INHERITED;
+ partitionedTarget ? INHKIND_PARTITIONED : INHKIND_INHERITED;
/*
* If this child is further partitioned, remember it as a parent.
@@ -1363,17 +1349,17 @@ inheritance_planner(PlannerInfo *root)
}
/*
- * Set the nominal target relation of the ModifyTable node if not
- * already done. We use the inheritance parent RTE as the nominal
- * target relation if it's a partitioned table (see just above this
- * loop). In the non-partitioned parent case, we'll use the first
- * child relation (even if it's excluded) as the nominal target
- * relation. Because of the way expand_inherited_rtentry works, the
- * latter should be the RTE representing the parent table in its role
- * as a simple member of the inheritance set.
+ * Set the target relation of the ModifyTable node if not already
+ * done. We use the inheritance parent RTE as the target relation
+ * if it's a partitioned table (see just above this loop). In the
+ * non-partitioned parent case, we'll use the first child relation
+ * (even if it's excluded) as the target relation. Because of the way
+ * expand_inherited_rtentry works, the latter should be the RTE
+ * representing the parent table in its role as a simple member of
+ * the inheritance set.
*
* It would be logically cleaner to *always* use the inheritance
- * parent RTE as the nominal relation; but that RTE is not otherwise
+ * parent RTE as the target relation; but that RTE is not otherwise
* referenced in the plan in the non-partitioned inheritance case.
* Instead the duplicate child RTE created by expand_inherited_rtentry
* is used elsewhere in the plan, so using the original parent RTE
@@ -1383,8 +1369,8 @@ inheritance_planner(PlannerInfo *root)
* duplicate child RTE added for the parent does not appear anywhere
* else in the plan tree.
*/
- if (nominalRelation < 0)
- nominalRelation = appinfo->child_relid;
+ if (targetRelation < 0)
+ targetRelation = appinfo->child_relid;
/*
* The rowMarks list might contain references to subquery RTEs, so
@@ -1509,15 +1495,6 @@ inheritance_planner(PlannerInfo *root)
continue;
/*
- * Add the current parent's RT index to the partitioned_relids set if
- * we're creating the ModifyTable path for a partitioned root table.
- * (We only care about parents of non-excluded children.)
- */
- if (partitioned_relids)
- partitioned_relids = bms_add_member(partitioned_relids,
- appinfo->parent_relid);
-
- /*
* If this is the first non-excluded child, its post-planning rtable
* becomes the initial contents of final_rtable; otherwise, append
* just its modified subquery RTEs to final_rtable.
@@ -1620,29 +1597,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,
+ targetRelation,
+ partitionedTarget,
root->partColsUpdated,
resultRelations,
subpaths,
@@ -2219,7 +2180,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
parse->commandType,
parse->canSetTag,
parse->resultRelation,
- NIL,
+ false,
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..17d53f356c 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);
}
@@ -847,13 +827,9 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
fix_scan_list(root, splan->exclRelTlist, rtoffset);
}
- splan->nominalRelation += rtoffset;
+ splan->targetRelation += rtoffset;
splan->exclRelRTI += rtoffset;
- foreach(l, splan->partitioned_rels)
- {
- lfirst_int(l) += rtoffset;
- }
foreach(l, splan->resultRelations)
{
lfirst_int(l) += rtoffset;
@@ -884,24 +860,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->partitionedTarget)
{
- 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->targetRelation);
}
}
break;
@@ -915,10 +884,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 +902,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..73eca1d4d0 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -3291,10 +3291,8 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
* 'rel' is the parent relation associated with the result
* 'operation' is the operation type
* 'canSetTag' is true if we set the command tag/es_processed
- * 'nominalRelation' is the parent RT index for use of EXPLAIN
- * '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.
+ * 'targetRelation' is the target table's RT index
+ * 'partitionedTarget' true if 'targetRelation' is a partitioned table
* 'partColsUpdated' is true if any partitioning columns are being updated,
* either from the target relation or a descendent partitioned table.
* 'resultRelations' is an integer list of actual RT indexes of target rel(s)
@@ -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 targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subpaths,
List *subroots,
@@ -3376,8 +3374,8 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
pathnode->operation = operation;
pathnode->canSetTag = canSetTag;
- pathnode->nominalRelation = nominalRelation;
- pathnode->partitioned_rels = list_copy(partitioned_rels);
+ pathnode->targetRelation = targetRelation;
+ pathnode->partitionedTarget = partitionedTarget;
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..d0427c64ba 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
+ 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..27ae73e3d4 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 */
@@ -219,9 +212,10 @@ typedef struct ModifyTable
Plan plan;
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 targetRelation; /* RT index of the target table specified in
+ * the command or first child for inheritance
+ * tables */
+ bool partitionedTarget; /* is the target table partitioned? */
bool partColsUpdated; /* some part key in hierarchy updated */
List *resultRelations; /* integer list of RT indexes */
int resultRelIndex; /* index of first resultRel in plan's list */
@@ -259,9 +253,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 +265,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 +916,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..bcc2ba6db5 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 */
@@ -1716,9 +1713,10 @@ typedef struct ModifyTablePath
Path path;
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 targetRelation; /* RT index of the target table specified in
+ * the command or first child for inheritance
+ * tables */
+ bool partitionedTarget; /* is the target table partitioned? */
bool partColsUpdated; /* some part key in hierarchy updated */
List *resultRelations; /* integer list of RT indexes */
List *subpaths; /* Path(s) producing source data */
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 7c5ff22650..a45c2407d0 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -238,7 +238,7 @@ extern LockRowsPath *create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
extern ModifyTablePath *create_modifytable_path(PlannerInfo *root,
RelOptInfo *rel,
CmdType operation, bool canSetTag,
- Index nominalRelation, List *partitioned_rels,
+ Index targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subpaths,
List *subroots,
--
2.11.0
v7-0003-Prune-PlanRowMark-of-relations-that-are-pruned-fr.patchtext/plain; charset=UTF-8; name=v7-0003-Prune-PlanRowMark-of-relations-that-are-pruned-fr.patchDownload
From 67f72dc024244bd4c36d865bb0b5dd350c7f1c82 Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Thu, 27 Sep 2018 13:31:11 +1200
Subject: [PATCH v7 3/4] Prune PlanRowMark of relations that are pruned from a
plan
---
src/backend/optimizer/plan/planner.c | 32 ++++++++++++++++++++++++++------
1 file changed, 26 insertions(+), 6 deletions(-)
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index a927c0a1db..074ec9bf55 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -248,7 +248,7 @@ static bool group_by_has_partkey(RelOptInfo *input_rel,
List *targetList,
List *groupClause);
static int common_prefix_cmp(const void *a, const void *b);
-
+static List *get_nondummy_rowmarks(PlannerInfo *root);
/*****************************************************************************
*
@@ -1595,7 +1595,7 @@ inheritance_planner(PlannerInfo *root)
if (parse->rowMarks)
rowMarks = NIL;
else
- rowMarks = root->rowMarks;
+ rowMarks = get_nondummy_rowmarks(root);
/* Create Path representing a ModifyTable to do the UPDATE/DELETE work */
add_path(final_rel, (Path *)
@@ -2124,11 +2124,9 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
* is what goes into the LockRows node.)
*/
if (parse->rowMarks)
- {
path = (Path *) create_lockrows_path(root, final_rel, path,
- root->rowMarks,
+ get_nondummy_rowmarks(root),
SS_assign_special_param(root));
- }
/*
* If there is a LIMIT/OFFSET clause, add the LIMIT node.
@@ -2173,7 +2171,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
if (parse->rowMarks)
rowMarks = NIL;
else
- rowMarks = root->rowMarks;
+ rowMarks = get_nondummy_rowmarks(root);
path = (Path *)
create_modifytable_path(root, final_rel,
@@ -7219,3 +7217,25 @@ group_by_has_partkey(RelOptInfo *input_rel,
return true;
}
+
+/*
+ * get_nondummy_rowmarks
+ * Return a list of PlanRowMark's that reference non-dummy relations
+ */
+static List *
+get_nondummy_rowmarks(PlannerInfo *root)
+{
+ List *rowMarks = NIL;
+ ListCell *lc;
+
+ 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]))
+ rowMarks = lappend(rowMarks, rc);
+ }
+
+ return rowMarks;
+}
--
2.11.0
v7-0004-Revise-executor-range-table-relation-opening-clos.patchtext/plain; charset=UTF-8; name=v7-0004-Revise-executor-range-table-relation-opening-clos.patchDownload
From d0e15553d15964d1722485417d6ae5799d43b790 Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Thu, 27 Sep 2018 16:14:41 +1200
Subject: [PATCH v7 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, an arrangement which allows the executor
to have to heap_open any given range table relation only once.
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.
Accessed Relations are now also closed during ExecEndPlan(). Callers of
ExecRangeTableRelation() have no need to consider how their Relation
objects are cleaned up.
Authors: Amit Langote, David Rowley
---
contrib/postgres_fdw/postgres_fdw.c | 16 +++---
src/backend/commands/copy.c | 3 +-
src/backend/commands/trigger.c | 3 +-
src/backend/executor/README | 4 +-
src/backend/executor/execExprInterp.c | 7 +--
src/backend/executor/execMain.c | 81 +++++++++--------------------
src/backend/executor/execPartition.c | 39 +++-----------
src/backend/executor/execUtils.c | 68 +++++++++++++++---------
src/backend/executor/nodeAppend.c | 6 ---
src/backend/executor/nodeBitmapHeapscan.c | 7 ---
src/backend/executor/nodeCustom.c | 4 --
src/backend/executor/nodeForeignscan.c | 4 --
src/backend/executor/nodeIndexonlyscan.c | 7 ---
src/backend/executor/nodeIndexscan.c | 7 ---
src/backend/executor/nodeLockRows.c | 2 +-
src/backend/executor/nodeMergeAppend.c | 6 ---
src/backend/executor/nodeModifyTable.c | 26 +++++----
src/backend/executor/nodeSamplescan.c | 5 --
src/backend/executor/nodeSeqscan.c | 7 ---
src/backend/executor/nodeTidscan.c | 5 --
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/tablesync.c | 9 +++-
src/backend/replication/logical/worker.c | 2 +
src/include/executor/execPartition.h | 1 -
src/include/executor/executor.h | 24 ++++++++-
src/include/nodes/execnodes.h | 23 +++++++-
src/include/nodes/plannodes.h | 2 +-
src/include/parser/parsetree.h | 10 ----
32 files changed, 195 insertions(+), 224 deletions(-)
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index eeb053d5d8..d20c75367c 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. */
@@ -1731,8 +1731,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,
@@ -2036,7 +2036,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);
@@ -2396,7 +2396,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. */
@@ -2546,10 +2546,6 @@ postgresEndDirectModify(ForeignScanState *node)
ReleaseConnection(dmstate->conn);
dmstate->conn = NULL;
- /* close the target relation. */
- if (dmstate->resultRel)
- ExecCloseScanRelation(dmstate->resultRel);
-
/* MemoryContext will be deleted automatically. */
}
@@ -5756,7 +5752,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 0c4a7b6f4f..57efb20d20 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -2483,7 +2483,8 @@ 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;
+
+ ExecInitRangeTable(estate, cstate->range_table);
/* 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 34f9db93d5..f0d45844c1 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/README b/src/backend/executor/README
index 0d7cd552eb..30df410e0e 100644
--- a/src/backend/executor/README
+++ b/src/backend/executor/README
@@ -267,8 +267,8 @@ This is a sketch of control flow for full query processing:
Per above comments, it's not really critical for ExecEndNode to free any
memory; it'll all go away in FreeExecutorState anyway. However, we do need to
-be careful to close relations, drop buffer pins, etc, so we do need to scan
-the plan state tree to find these sorts of resources.
+be careful to drop buffer pins, etc, so we do need to scan the plan state tree
+to find these sorts of resources.
The executor can also be used to evaluate simple expressions without any Plan
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index f597363eb1..f8ca60ae5a 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3934,10 +3934,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 3c197c55f4..d895ed29d1 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -111,9 +111,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 */
@@ -837,28 +837,16 @@ 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 the necessary lock on the relation
- * has already been taken. That can only however be true in the
- * parallel leader.
- */
- Assert(rte->lockmode != NoLock);
- if (!IsParallelWorker() &&
- !CheckRelationLockedByUs(rte->relid, rte->lockmode))
- elog(WARNING, "InitPlan: lock on \"%s\" not already taken",
- get_rel_name(rte->relid));
- }
- }
-#endif
+ ExecInitRangeTable(estate, rangeTable);
/*
+ * Allocate an array to store open Relations of each rangeTable item. We
+ * zero-fill this for now. The Relations are only opened and stored here
+ * the first time they're required during node initialization.
+ */
+ estate->es_relations = (Relation *) palloc0(estate->es_range_table_size *
+ sizeof(Relation));
+ /*
* initialize the node's execution state
*/
estate->es_range_table = rangeTable;
@@ -1501,6 +1489,14 @@ static void
ExecEndPlan(PlanState *planstate, EState *estate)
{
ListCell *l;
+ int i;
+
+ /* Close range table relations. */
+ for (i = 0; i < estate->es_range_table_size; i++)
+ {
+ if (estate->es_relations[i])
+ heap_close(estate->es_relations[i], NoLock);
+ }
/*
* shut down the node-type-specific query processing
@@ -1527,18 +1523,6 @@ ExecEndPlan(PlanState *planstate, EState *estate)
/* likewise close any trigger target relations */
ExecCleanUpTriggerState(estate);
-
- /*
- * 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);
- }
}
/* ----------------------------------------------------------------
@@ -2295,24 +2279,20 @@ 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);
-
switch (rc->markType)
{
case ROW_MARK_EXCLUSIVE:
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 */
@@ -2330,7 +2310,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;
@@ -2988,7 +2968,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));
@@ -3041,7 +3021,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();
@@ -3065,6 +3045,9 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree)
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_range_table_size = parentestate->es_range_table_size;
+ 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;
@@ -3218,18 +3201,6 @@ 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 1d2b3620ee..7fb34d2173 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -861,11 +861,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++)
{
@@ -1418,9 +1417,6 @@ adjust_partition_tlist(List *tlist, TupleConversionMap *map)
* functions. Details stored include how to map the partition index
* returned by the partition pruning code into subplan indexes.
*
- * ExecDestroyPartitionPruneState:
- * Deletes a PartitionPruneState. Must be called during executor shutdown.
- *
* ExecFindInitialMatchingSubPlans:
* Returns indexes of matching subplans. Partition pruning is attempted
* without any evaluation of expressions containing PARAM_EXEC Params.
@@ -1462,6 +1458,7 @@ PartitionPruneState *
ExecCreatePartitionPruneState(PlanState *planstate,
PartitionPruneInfo *partitionpruneinfo)
{
+ EState *estate = planstate->state;
PartitionPruneState *prunestate;
int n_part_hierarchies;
ListCell *lc;
@@ -1542,7 +1539,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);
@@ -1623,30 +1620,6 @@ ExecCreatePartitionPruneState(PlanState *planstate,
}
/*
- * ExecDestroyPartitionPruneState
- * Release resources at plan shutdown.
- *
- * We don't bother to free any memory here, since the whole executor context
- * will be going away shortly. We do need to release our relcache pins.
- */
-void
-ExecDestroyPartitionPruneState(PartitionPruneState *prunestate)
-{
- PartitionPruningData **partprunedata = prunestate->partprunedata;
- int i;
-
- for (i = 0; i < prunestate->num_partprunedata; i++)
- {
- PartitionPruningData *prunedata = partprunedata[i];
- PartitionedRelPruningData *pprune = prunedata->partrelprunedata;
- int j;
-
- for (j = 0; j < prunedata->num_partrelprunedata; j++)
- relation_close(pprune[j].context.partrel, NoLock);
- }
-}
-
-/*
* ExecFindInitialMatchingSubPlans
* Identify the set of subplans that cannot be eliminated by initial
* pruning (disregarding any pruning constraints involving PARAM_EXEC
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index d32796aac3..bd306d0389 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -25,7 +25,6 @@
* etc
*
* ExecOpenScanRelation Common code for scan node init routines.
- * ExecCloseScanRelation
*
* executor_errposition Report syntactic position of an error.
*
@@ -35,6 +34,8 @@
* GetAttributeByName Runtime extraction of columns from tuples.
* GetAttributeByNum
*
+ * ExecInitRangeTable Build an array from the range table list to
+ * allow faster lookups by relid.
* NOTES
* This file has traditionally been the place to stick misc.
* executor support stuff that doesn't really go anyplace else.
@@ -653,11 +654,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
@@ -675,26 +674,6 @@ ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
return rel;
}
-/* ----------------------------------------------------------------
- * ExecCloseScanRelation
- *
- * Close the heap relation scanned by a base-level scan plan node.
- * This should be called during the node's ExecEnd routine.
- *
- * Currently, we do not release the lock acquired by ExecOpenScanRelation.
- * This lock should be held till end of transaction. (There is a faction
- * that considers this too much locking, however.)
- *
- * If we did want to release the lock, we'd have to repeat the logic in
- * ExecOpenScanRelation in order to figure out what to release.
- * ----------------------------------------------------------------
- */
-void
-ExecCloseScanRelation(Relation scanrel)
-{
- heap_close(scanrel, NoLock);
-}
-
/*
* UpdateChangedParamSet
* Add changed parameters to a plan node's chgParam set
@@ -997,3 +976,44 @@ ExecCleanTargetListLength(List *targetlist)
}
return len;
}
+
+/*
+ * Initialize executor's range table array
+ */
+void
+ExecInitRangeTable(EState *estate, List *rangeTable)
+{
+ int rti;
+ ListCell *l;
+
+#ifdef USE_ASSERT_CHECKING
+ foreach(l, rangeTable)
+ {
+ RangeTblEntry *rte = lfirst(l);
+
+ if (rte->rtekind == RTE_RELATION && OidIsValid(rte->relid))
+ {
+ /*
+ * The following asserts that the necessary lock on the relation
+ * has already been taken. That can only however be true in the
+ * parallel leader.
+ */
+ Assert(rte->lockmode != NoLock);
+ if (!IsParallelWorker() &&
+ !CheckRelationLockedByUs(rte->relid, rte->lockmode))
+ elog(WARNING, "InitPlan: lock on \"%s\" not already taken",
+ get_rel_name(rte->relid));
+ }
+ }
+#endif
+
+ Assert(estate != NULL);
+ 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 *));
+ rti = 0;
+ foreach(l, rangeTable)
+ estate->es_range_table_array[rti++] = lfirst_node(RangeTblEntry, l);
+}
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index eb587be221..a16b6da474 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -329,12 +329,6 @@ ExecEndAppend(AppendState *node)
*/
for (i = 0; i < nplans; i++)
ExecEndNode(appendplans[i]);
-
- /*
- * release any resources associated with run-time pruning
- */
- if (node->as_prune_state)
- ExecDestroyPartitionPruneState(node->as_prune_state);
}
void
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index baffae27e3..5307cd1b87 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -785,13 +785,11 @@ ExecReScanBitmapHeapScan(BitmapHeapScanState *node)
void
ExecEndBitmapHeapScan(BitmapHeapScanState *node)
{
- Relation relation;
HeapScanDesc scanDesc;
/*
* extract information from the node
*/
- relation = node->ss.ss_currentRelation;
scanDesc = node->ss.ss_currentScanDesc;
/*
@@ -832,11 +830,6 @@ ExecEndBitmapHeapScan(BitmapHeapScanState *node)
* close heap scan
*/
heap_endscan(scanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index b816e0b31d..9a33eda688 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -126,10 +126,6 @@ ExecEndCustomScan(CustomScanState *node)
/* Clean out the tuple table */
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /* Close the heap relation */
- if (node->ss.ss_currentRelation)
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
void
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index a2a28b7ec2..cf7df72d8c 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -258,10 +258,6 @@ ExecEndForeignScan(ForeignScanState *node)
/* clean out the tuple table */
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /* close the relation. */
- if (node->ss.ss_currentRelation)
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 4b6d531810..1b530cea40 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -373,14 +373,12 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node)
{
Relation indexRelationDesc;
IndexScanDesc indexScanDesc;
- Relation relation;
/*
* extract information from the node
*/
indexRelationDesc = node->ioss_RelationDesc;
indexScanDesc = node->ioss_ScanDesc;
- relation = node->ss.ss_currentRelation;
/* Release VM buffer pin, if any. */
if (node->ioss_VMBuffer != InvalidBuffer)
@@ -411,11 +409,6 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node)
index_endscan(indexScanDesc);
if (indexRelationDesc)
index_close(indexRelationDesc, NoLock);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 6285a2114e..786e7ac25c 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -802,14 +802,12 @@ ExecEndIndexScan(IndexScanState *node)
{
Relation indexRelationDesc;
IndexScanDesc indexScanDesc;
- Relation relation;
/*
* extract information from the node
*/
indexRelationDesc = node->iss_RelationDesc;
indexScanDesc = node->iss_ScanDesc;
- relation = node->ss.ss_currentRelation;
/*
* Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
@@ -833,11 +831,6 @@ ExecEndIndexScan(IndexScanState *node)
index_endscan(indexScanDesc);
if (indexRelationDesc)
index_close(indexRelationDesc, NoLock);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index efbf4bd18a..ff9606342b 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/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index d8e0978966..5d0dbb8146 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -363,12 +363,6 @@ ExecEndMergeAppend(MergeAppendState *node)
*/
for (i = 0; i < nplans; i++)
ExecEndNode(mergeplans[i]);
-
- /*
- * release any resources associated with run-time pruning
- */
- if (node->ms_prune_state)
- ExecDestroyPartitionPruneState(node->ms_prune_state);
}
void
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index b18f9e3164..c837d36a87 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,17 +2254,18 @@ 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->partitionedTarget);
- rte = rt_fetch(node->targetRelation, estate->es_range_table);
- rel = heap_open(rte->relid, NoLock);
- InitResultRelInfo(mtstate->rootResultRelInfo, rel,
- node->targetRelation, NULL, estate->es_instrument);
+ rel = ExecRangeTableRelation(estate, node->targetRelation);
+ InitResultRelInfo(mtstate->rootResultRelInfo,
+ rel,
+ node->targetRelation,
+ NULL,
+ estate->es_instrument);
}
mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
@@ -2722,15 +2722,13 @@ ExecEndModifyTable(ModifyTableState *node)
resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
resultRelInfo);
- /* Close indices and then the relation itself */
+ /*
+ * Close the ResultRelInfo's indexes. The relation itself
+ * is handled by the executor cleanup code.
+ */
ExecCloseIndices(resultRelInfo);
- heap_close(resultRelInfo->ri_RelationDesc, NoLock);
}
- /* 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/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index 99528be84a..92ff68a764 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -222,11 +222,6 @@ ExecEndSampleScan(SampleScanState *node)
*/
if (node->ss.ss_currentScanDesc)
heap_endscan(node->ss.ss_currentScanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index cd53491be0..92ff1e50ed 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -201,13 +201,11 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
void
ExecEndSeqScan(SeqScanState *node)
{
- Relation relation;
HeapScanDesc scanDesc;
/*
* get information from node
*/
- relation = node->ss.ss_currentRelation;
scanDesc = node->ss.ss_currentScanDesc;
/*
@@ -226,11 +224,6 @@ ExecEndSeqScan(SeqScanState *node)
*/
if (scanDesc != NULL)
heap_endscan(scanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index 0cb1946a3e..8cae56f48c 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -489,11 +489,6 @@ ExecEndTidScan(TidScanState *node)
*/
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index da02b8961c..dd76284676 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 2e6a5a1b42..6aefdd8bc4 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1029,7 +1029,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 aea5b0abc4..30609c96e6 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -2373,7 +2373,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 17d53f356c..ee01ef82d2 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -890,6 +890,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:
@@ -908,6 +923,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 e1ce8b4ddc..1763dd67a3 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/tablesync.c b/src/backend/replication/logical/tablesync.c
index 905a983074..d72f6a1b4f 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -795,7 +795,14 @@ copy_table(Relation rel)
copybuf = makeStringInfo();
pstate = make_parsestate(NULL);
- addRangeTableEntryForRelation(pstate, rel, NULL, false, false, NoLock);
+
+ /*
+ * Caller LogicalRepSyncTableStart took RowExclusiveLock, which we must
+ * record in the RTE being built, because executor initialization invoked
+ * by copy.c expects it.
+ */
+ addRangeTableEntryForRelation(pstate, rel, NULL, false, false,
+ RowExclusiveLock);
attnamelist = make_copy_attnamelist(relmapentry);
cstate = BeginCopyFrom(pstate, rel, NULL, false, copy_read_data, attnamelist, NIL);
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 42345f94d3..c63de66857 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -200,6 +200,8 @@ create_estate_for_relation(LogicalRepRelMapEntry *rel)
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/execPartition.h b/src/include/executor/execPartition.h
index 89ce53815c..04847d639d 100644
--- a/src/include/executor/execPartition.h
+++ b/src/include/executor/execPartition.h
@@ -197,7 +197,6 @@ extern void ExecCleanupTupleRouting(ModifyTableState *mtstate,
PartitionTupleRouting *proute);
extern PartitionPruneState *ExecCreatePartitionPruneState(PlanState *planstate,
PartitionPruneInfo *partitionpruneinfo);
-extern void ExecDestroyPartitionPruneState(PartitionPruneState *prunestate);
extern Bitmapset *ExecFindMatchingSubPlans(PartitionPruneState *prunestate);
extern Bitmapset *ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate,
int nsubplans);
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 1d2b48fe09..b03d8c591f 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"
/*
@@ -478,6 +479,7 @@ extern ExprContext *CreateExprContext(EState *estate);
extern ExprContext *CreateStandaloneExprContext(void);
extern void FreeExprContext(ExprContext *econtext, bool isCommit);
extern void ReScanExprContext(ExprContext *econtext);
+extern void ExecInitRangeTable(EState *estate, List *rangeTable);
#define ResetExprContext(econtext) \
MemoryContextReset((econtext)->ecxt_per_tuple_memory)
@@ -513,7 +515,6 @@ extern void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate
extern bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid);
extern Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags);
-extern void ExecCloseScanRelation(Relation scanrel);
extern int executor_errposition(EState *estate, int location);
@@ -568,4 +569,25 @@ 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)
+{
+ Relation rel = estate->es_relations[rti - 1];
+
+ if (rel == NULL)
+ {
+ RangeTblEntry *rte = exec_rt_fetch(rti, estate->es_range_table_array);
+
+ /*
+ * No need to lock the relation. Locks were already
+ * obtained by the upstream code.
+ */
+ rel = estate->es_relations[rti - 1] = heap_open(rte->relid, NoLock);
+ }
+
+ return rel;
+}
+#endif
+
#endif /* EXECUTOR_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 03ad516976..639235d622 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,11 @@ 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 Relations
+ * es_range_table_size elements in length. */
PlannedStmt *es_plannedstmt; /* link to top of plan tree */
const char *es_sourceText; /* Source text from QueryDesc */
@@ -579,6 +584,22 @@ typedef struct EState
struct JitInstrumentation *es_jit_combined_instr;
} 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]
+
+/*
+ * 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 27ae73e3d4..452627dd03 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -1093,7 +1093,7 @@ typedef struct PartitionPruneInfo
typedef struct PartitionedRelPruneInfo
{
NodeTag type;
- Oid reloid; /* OID of partition rel for this level */
+ Index rtindex; /* Partition table's RT index */
List *pruning_steps; /* List of PartitionPruneStep, see below */
Bitmapset *present_parts; /* Indexes of all partitions which subplans or
* subparts are present for. */
diff --git a/src/include/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
On 28 September 2018 at 20:00, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
I've made minor tweaks, which find in
the attached updated patches (a .diff file containing changes from v6 to
v7 is also attached).
Thanks for looking over the changes.
I've looked at the v6 to v7 diff and it seems all good, apart from:
+ * The following asserts that the necessary lock on the relation
I think we maybe should switch the word "assert" for "verifies". The
Assert is just checking we didn't get a NoLock and I don't think
you're using "assert" meaning the Assert() marco, so likely should be
changed to avoid confusion.
Apart from that, I see nothing wrong with the patches, so I think we
should get someone else to look. I'm marking it as ready for
committer.
--
David Rowley http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
On 2018/09/28 17:21, David Rowley wrote:
On 28 September 2018 at 20:00, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:I've made minor tweaks, which find in
the attached updated patches (a .diff file containing changes from v6 to
v7 is also attached).Thanks for looking over the changes.
I've looked at the v6 to v7 diff and it seems all good, apart from:
+ * The following asserts that the necessary lock on the relation
I think we maybe should switch the word "assert" for "verifies". The
Assert is just checking we didn't get a NoLock and I don't think
you're using "assert" meaning the Assert() marco, so likely should be
changed to avoid confusion.
Okay, I've revised the text in the attached updated patch.
Apart from that, I see nothing wrong with the patches, so I think we
should get someone else to look. I'm marking it as ready for
committer.
Thanks for your time reviewing the patches.
Regards,
Amit
Attachments:
v8-0001-Don-t-lock-range-table-relations-in-the-executor.patchtext/plain; charset=UTF-8; name=v8-0001-Don-t-lock-range-table-relations-in-the-executor.patchDownload
From a8a2d82d15991968d921339e6e7d63030cf61bce Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Thu, 19 Jul 2018 16:14:51 +0900
Subject: [PATCH v8 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/catalog/heap.c | 3 +-
src/backend/commands/copy.c | 7 +-
src/backend/commands/policy.c | 17 +-
src/backend/commands/tablecmds.c | 3 +-
src/backend/commands/trigger.c | 6 +-
src/backend/commands/view.c | 6 +-
src/backend/executor/execMain.c | 275 ++++++++---------------
src/backend/executor/execPartition.c | 4 +-
src/backend/executor/execUtils.c | 24 +-
src/backend/executor/nodeLockRows.c | 4 +-
src/backend/executor/nodeModifyTable.c | 42 +++-
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 | 3 +-
src/backend/parser/parse_clause.c | 3 +-
src/backend/parser/parse_relation.c | 17 +-
src/backend/parser/parse_utilcmd.c | 18 +-
src/backend/replication/logical/tablesync.c | 2 +-
src/backend/rewrite/rewriteHandler.c | 20 +-
src/backend/storage/lmgr/lmgr.c | 15 ++
src/backend/storage/lmgr/lock.c | 24 ++
src/backend/utils/cache/plancache.c | 30 +--
src/include/executor/executor.h | 2 +-
src/include/nodes/parsenodes.h | 5 +
src/include/parser/parse_relation.h | 4 +-
src/include/storage/lmgr.h | 1 +
src/include/storage/lock.h | 1 +
src/test/modules/test_rls_hooks/test_rls_hooks.c | 4 +-
30 files changed, 261 insertions(+), 283 deletions(-)
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 9176f6280b..19b530ac94 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -2551,7 +2551,8 @@ AddRelationNewConstraints(Relation rel,
rel,
NULL,
false,
- true);
+ true,
+ NoLock);
addRTEtoQuery(pstate, rte, true, true, true);
/*
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index d06662bd32..0c4a7b6f4f 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -837,16 +837,17 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
List *attnums;
ListCell *cur;
RangeTblEntry *rte;
+ LOCKMODE lockmode = is_from ? RowExclusiveLock : AccessShareLock;
Assert(!stmt->query);
/* Open and lock the relation, using the appropriate lock type. */
- rel = heap_openrv(stmt->relation,
- (is_from ? RowExclusiveLock : AccessShareLock));
+ rel = heap_openrv(stmt->relation, lockmode);
relid = RelationGetRelid(rel);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, false);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, false,
+ lockmode);
rte->requiredPerms = (is_from ? ACL_INSERT : ACL_SELECT);
tupDesc = RelationGetDescr(rel);
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index cee0ef915b..2949b4e6d7 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -567,7 +567,8 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
qual_expr = stringToNode(qual_value);
/* Add this rel to the parsestate's rangetable, for dependencies */
- addRangeTableEntryForRelation(qual_pstate, rel, NULL, false, false);
+ addRangeTableEntryForRelation(qual_pstate, rel, NULL, false, false,
+ AccessExclusiveLock);
qual_parse_rtable = qual_pstate->p_rtable;
free_parsestate(qual_pstate);
@@ -590,7 +591,7 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(with_check_pstate, rel, NULL, false,
- false);
+ false, AccessExclusiveLock);
with_check_parse_rtable = with_check_pstate->p_rtable;
free_parsestate(with_check_pstate);
@@ -752,12 +753,12 @@ CreatePolicy(CreatePolicyStmt *stmt)
/* Add for the regular security quals */
rte = addRangeTableEntryForRelation(qual_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
/* Add for the with-check quals */
rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(with_check_pstate, rte, false, true, true);
qual = transformWhereClause(qual_pstate,
@@ -928,7 +929,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
ParseState *qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
@@ -950,7 +951,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
ParseState *with_check_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(with_check_pstate, rte, false, true, true);
@@ -1097,7 +1098,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(qual_pstate, target_table, NULL,
- false, false);
+ false, false, NoLock);
qual_parse_rtable = qual_pstate->p_rtable;
free_parsestate(qual_pstate);
@@ -1138,7 +1139,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(with_check_pstate, target_table, NULL,
- false, false);
+ false, false, NoLock);
with_check_parse_rtable = with_check_pstate->p_rtable;
free_parsestate(with_check_pstate);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 29d8353779..5afa54389a 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -13632,7 +13632,8 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
* rangetable entry. We need a ParseState for transformExpr.
*/
pstate = make_parsestate(NULL);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true,
+ NoLock);
addRTEtoQuery(pstate, rte, true, true, true);
/* take care of any partition expressions */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 36778b6f4d..34f9db93d5 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -578,11 +578,13 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
*/
rte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ ShareRowExclusiveLock);
addRTEtoQuery(pstate, rte, false, true, true);
rte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ ShareRowExclusiveLock);
addRTEtoQuery(pstate, rte, false, true, true);
/* Transform expression. Copy to be sure we don't modify original */
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index ffb71c0ea7..4c379fd83b 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -387,10 +387,12 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
*/
rt_entry1 = addRangeTableEntryForRelation(pstate, viewRel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessShareLock);
rt_entry2 = addRangeTableEntryForRelation(pstate, viewRel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ 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 5443cbf67d..a9edc90a52 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -52,10 +52,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"
@@ -835,99 +837,49 @@ 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 the necessary lock on the relation
+ * has already been taken. That can only however be true in the
+ * parallel leader.
+ */
+ Assert(rte->lockmode != NoLock);
+ if (!IsParallelWorker() &&
+ !CheckRelationLockedByUs(rte->relid, rte->lockmode))
+ elog(WARNING, "InitPlan: lock on \"%s\" not already taken",
+ get_rel_name(rte->relid));
+ }
+ }
+#endif
+
/*
* initialize the node's execution state
*/
estate->es_range_table = rangeTable;
estate->es_plannedstmt = plannedstmt;
- /*
- * initialize result relation stuff, and open/lock the result rels.
- *
- * We must do this before initializing the plan tree, else we might try to
- * do a lock upgrade if a result rel is also a source rel.
- */
+ /* Allocate memory required for result relations */
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
{
@@ -941,73 +893,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.
@@ -1614,8 +1500,6 @@ ExecPostprocessPlan(EState *estate)
static void
ExecEndPlan(PlanState *planstate, EState *estate)
{
- ResultRelInfo *resultRelInfo;
- int i;
ListCell *l;
/*
@@ -1641,26 +1525,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);
@@ -2421,25 +2285,64 @@ ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
}
/*
- * ExecFindRowMark -- find the ExecRowMark struct for given rangetable index
+ * ExecBuildRowMark -- create and return an ExecRowMark struct for the given
+ * PlanRowMark.
*
- * If no such struct, either return NULL or throw error depending on missing_ok
+ * The created ExecRowMark is also added to the list of rowmarks in the given
+ * EState.
*/
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);
+
+ 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;
}
/*
@@ -3179,7 +3082,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 */
@@ -3315,6 +3218,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 ec7a5267c3..3be794b97d 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -1540,9 +1540,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..efbf4bd18a 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -424,8 +424,8 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
/* safety check on size of lr_curtuples array */
Assert(rc->rti > 0 && rc->rti <= lrstate->lr_ntables);
- /* find ExecRowMark and build ExecAuxRowMark */
- erm = ExecFindRowMark(estate, rc->rti, false);
+ /* build the ExecRowMark and ExecAuxRowMark */
+ erm = ExecBuildRowMark(estate, rc);
aerm = ExecBuildAuxRowMark(erm, outerPlan->targetlist);
/*
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index bf0d5e8edb..f81769ea85 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;
@@ -2529,8 +2554,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
if (rc->isParent)
continue;
- /* find ExecRowMark (same for all subplans) */
- erm = ExecFindRowMark(estate, rc->rti, false);
+ /* build the ExecRowMark (same for all subplans) */
+ erm = ExecBuildRowMark(estate, rc);
/* build ExecAuxRowMark for each subplan */
for (i = 0; i < nplans; i++)
@@ -2686,20 +2711,27 @@ ExecEndModifyTable(ModifyTableState *node)
{
int i;
- /*
- * Allow any FDWs to shut down
- */
+ /* Perform cleanup. */
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);
}
+ /* 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 93f1e2c4eb..03d84aa0cd 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -3131,6 +3131,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 519deab63a..fc006e2830 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1361,6 +1361,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 c020600955..ce0262d170 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -1038,7 +1038,8 @@ transformOnConflictClause(ParseState *pstate,
exclRte = addRangeTableEntryForRelation(pstate,
targetrel,
makeAlias("excluded", NIL),
- false, false);
+ false, false,
+ RowExclusiveLock);
exclRte->relkind = RELKIND_COMPOSITE_TYPE;
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 d6b93f55df..689ac72c3f 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -217,7 +217,8 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
* Now build an RTE.
*/
rte = addRangeTableEntryForRelation(pstate, pstate->p_target_relation,
- relation->alias, inh, false);
+ relation->alias, inh, false,
+ 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 60b8de0f95..cbee07aeb8 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -28,6 +28,7 @@
#include "parser/parse_enr.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
+#include "storage/lmgr.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
@@ -1217,6 +1218,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
@@ -1262,23 +1264,36 @@ addRangeTableEntry(ParseState *pstate,
*
* This is just like addRangeTableEntry() except that it makes an RTE
* given an already-open relation instead of a RangeVar reference.
+ *
+ * 'lockmode' is the lock taken on 'rel'. The caller may pass NoLock if the
+ * RTE won't be passed to the executor, that is, won't be part of a
+ * PlannedStmt.
*/
RangeTblEntry *
addRangeTableEntryForRelation(ParseState *pstate,
Relation rel,
Alias *alias,
bool inh,
- bool inFromCl)
+ bool inFromCl,
+ LOCKMODE lockmode)
{
RangeTblEntry *rte = makeNode(RangeTblEntry);
char *refname = alias ? alias->aliasname : RelationGetRelationName(rel);
Assert(pstate != NULL);
+#ifdef USE_ASSERT_CHECKING
+ if (lockmode != NoLock &&
+ !CheckRelationLockedByUs(RelationGetRelid(rel), lockmode))
+ elog(WARNING, "lock on \"%s\" is not held",
+ RelationGetRelationName(rel));
+#endif
+
rte->rtekind = RTE_RELATION;
rte->alias = alias;
rte->relid = RelationGetRelid(rel);
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 f5c1e2a0d7..5df0348f1c 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -2526,7 +2526,8 @@ transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
* relation, but we still need to open it.
*/
rel = relation_open(relid, NoLock);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true,
+ NoLock);
/* no to join list, yes to namespaces */
addRTEtoQuery(pstate, rte, false, true, true);
@@ -2636,10 +2637,12 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
*/
oldrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessExclusiveLock);
newrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ AccessExclusiveLock);
/* Must override addRangeTableEntry's default access-check flags */
oldrte->requiredPerms = 0;
newrte->requiredPerms = 0;
@@ -2734,10 +2737,12 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
*/
oldrte = addRangeTableEntryForRelation(sub_pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessExclusiveLock);
newrte = addRangeTableEntryForRelation(sub_pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ AccessExclusiveLock);
oldrte->requiredPerms = 0;
newrte->requiredPerms = 0;
addRTEtoQuery(sub_pstate, oldrte, false, true, false);
@@ -2940,7 +2945,8 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
rel,
NULL,
false,
- true);
+ true,
+ NoLock);
addRTEtoQuery(pstate, rte, false, true, true);
/* Set up CreateStmtContext */
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index acc6498567..905a983074 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -795,7 +795,7 @@ copy_table(Relation rel)
copybuf = makeStringInfo();
pstate = make_parsestate(NULL);
- addRangeTableEntryForRelation(pstate, rel, NULL, false, false);
+ addRangeTableEntryForRelation(pstate, rel, NULL, false, false, NoLock);
attnamelist = make_copy_attnamelist(relmapentry);
cstate = BeginCopyFrom(pstate, rel, NULL, false, copy_read_data, attnamelist, NIL);
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 327e5c33d7..6562ac60b1 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,
@@ -2898,6 +2884,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
@@ -3103,7 +3090,8 @@ rewriteTargetView(Query *parsetree, Relation view)
base_rel,
makeAlias("excluded",
NIL),
- false, false);
+ false, false,
+ RowExclusiveLock);
new_exclRte->relkind = RELKIND_COMPOSITE_TYPE;
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 dc0a439638..2d8eae62e6 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -136,6 +136,21 @@ LockRelationOid(Oid relid, LOCKMODE lockmode)
}
/*
+ * CheckRelationLockedByUs
+ *
+ * Returns true we hold a lock on 'relid' with 'lockmode'.
+ */
+bool
+CheckRelationLockedByUs(Oid relid, LOCKMODE lockmode)
+{
+ LOCKTAG tag;
+
+ SetLocktagRelationOid(&tag, relid);
+
+ return LocalLockExists(&tag, lockmode);
+}
+
+/*
* ConditionalLockRelationOid
*
* As above, but only lock if we can get the lock without blocking.
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 831ae62525..8c140fe4b0 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -564,6 +564,30 @@ DoLockModesConflict(LOCKMODE mode1, LOCKMODE mode2)
}
/*
+ * LocalLockExists -- check if a log with 'locktag' is held locally with
+ * 'lockmode'
+ */
+bool
+LocalLockExists(const LOCKTAG *locktag, LOCKMODE lockmode)
+{
+ LOCALLOCKTAG localtag;
+ bool found;
+
+ MemSet(&localtag, 0, sizeof(localtag)); /* must clear padding */
+ localtag.lock = *locktag;
+ localtag.mode = lockmode;
+
+ /*
+ * Find the LOCALLOCK entry for this lock and lockmode
+ */
+ (void) hash_search(LockMethodLocalHash,
+ (void *) &localtag,
+ HASH_FIND, &found);
+
+ return found;
+}
+
+/*
* LockHasWaiters -- look up 'locktag' and check if releasing this
* lock would wake up other processes waiting for it.
*/
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 7271b5880b..1876345de5 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -1493,7 +1493,6 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
foreach(lc1, stmt_list)
{
PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
- int rt_index;
ListCell *lc2;
if (plannedstmt->commandType == CMD_UTILITY)
@@ -1512,14 +1511,9 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
continue;
}
- rt_index = 0;
foreach(lc2, plannedstmt->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
- LOCKMODE lockmode;
- PlanRowMark *rc;
-
- rt_index++;
if (rte->rtekind != RTE_RELATION)
continue;
@@ -1530,19 +1524,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 +1581,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 62209a8f10..2a265d591d 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -27,6 +27,7 @@
#include "nodes/primnodes.h"
#include "nodes/value.h"
#include "partitioning/partdefs.h"
+#include "storage/lockdefs.h"
typedef enum OverridingKind
@@ -976,6 +977,10 @@ typedef struct RangeTblEntry
*/
Oid relid; /* OID of the relation */
char relkind; /* relation kind (see pg_class.relkind) */
+ LOCKMODE lockmode; /* lock level to obtain on the relation; must
+ * be non-zero for all plain relation RTEs
+ * that will be passed to the executor via
+ * PlannedStmt. */
struct TableSampleClause *tablesample; /* sampling info, or NULL */
/*
diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h
index b9792acdae..99d1b4135c 100644
--- a/src/include/parser/parse_relation.h
+++ b/src/include/parser/parse_relation.h
@@ -15,6 +15,7 @@
#define PARSE_RELATION_H
#include "parser/parse_node.h"
+#include "storage/lockdefs.h"
/*
@@ -71,7 +72,8 @@ extern RangeTblEntry *addRangeTableEntryForRelation(ParseState *pstate,
Relation rel,
Alias *alias,
bool inh,
- bool inFromCl);
+ bool inFromCl,
+ LOCKMODE lockmode);
extern RangeTblEntry *addRangeTableEntryForSubquery(ParseState *pstate,
Query *subquery,
Alias *alias,
diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h
index a217de9716..abfafe5e40 100644
--- a/src/include/storage/lmgr.h
+++ b/src/include/storage/lmgr.h
@@ -38,6 +38,7 @@ extern void RelationInitLockInfo(Relation relation);
/* Lock a relation */
extern void LockRelationOid(Oid relid, LOCKMODE lockmode);
+extern bool CheckRelationLockedByUs(Oid relid, LOCKMODE lockmode);
extern bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode);
extern void UnlockRelationId(LockRelId *relid, LOCKMODE lockmode);
extern void UnlockRelationOid(Oid relid, LOCKMODE lockmode);
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index ff4df7fec5..b4a71ced0b 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -540,6 +540,7 @@ extern void LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks);
extern void LockReleaseSession(LOCKMETHODID lockmethodid);
extern void LockReleaseCurrentOwner(LOCALLOCK **locallocks, int nlocks);
extern void LockReassignCurrentOwner(LOCALLOCK **locallocks, int nlocks);
+extern bool LocalLockExists(const LOCKTAG *locktag, LOCKMODE lockmode);
extern bool LockHasWaiters(const LOCKTAG *locktag,
LOCKMODE lockmode, bool sessionLock);
extern VirtualTransactionId *GetLockConflicts(const LOCKTAG *locktag,
diff --git a/src/test/modules/test_rls_hooks/test_rls_hooks.c b/src/test/modules/test_rls_hooks/test_rls_hooks.c
index cab67a60aa..d455c97ef6 100644
--- a/src/test/modules/test_rls_hooks/test_rls_hooks.c
+++ b/src/test/modules/test_rls_hooks/test_rls_hooks.c
@@ -81,7 +81,7 @@ test_rls_hooks_permissive(CmdType cmdtype, Relation relation)
qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, relation, NULL, false,
- false);
+ false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
@@ -144,7 +144,7 @@ test_rls_hooks_restrictive(CmdType cmdtype, Relation relation)
qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, relation, NULL, false,
- false);
+ false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
--
2.11.0
v8-0002-Remove-useless-fields-from-planner-nodes.patchtext/plain; charset=UTF-8; name=v8-0002-Remove-useless-fields-from-planner-nodes.patchDownload
From 4ad70348d8fa0ef95052451aec88aa9e2076567e Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Thu, 27 Sep 2018 13:27:24 +1200
Subject: [PATCH v8 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 bool field called
'partitionedTarget', which is set if the target is a partitioned
table. The table itself is identified by targetRelation which
replaces nominalRelation.
* '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.
---
contrib/postgres_fdw/postgres_fdw.c | 2 +-
src/backend/commands/explain.c | 6 +--
src/backend/commands/portalcmds.c | 2 +-
src/backend/executor/execMain.c | 2 +-
src/backend/executor/execParallel.c | 3 +-
src/backend/executor/execPartition.c | 2 +-
src/backend/executor/execUtils.c | 55 --------------------
src/backend/executor/nodeAppend.c | 6 ---
src/backend/executor/nodeMergeAppend.c | 6 ---
src/backend/executor/nodeModifyTable.c | 9 ++--
src/backend/executor/spi.c | 4 +-
src/backend/nodes/copyfuncs.c | 9 ++--
src/backend/nodes/outfuncs.c | 15 ++----
src/backend/nodes/readfuncs.c | 9 ++--
src/backend/optimizer/plan/createplan.c | 46 ++++-------------
src/backend/optimizer/plan/planner.c | 89 +++++++++------------------------
src/backend/optimizer/plan/setrefs.c | 49 ++----------------
src/backend/optimizer/util/pathnode.c | 12 ++---
src/backend/tcop/utility.c | 15 ++++--
src/include/executor/executor.h | 2 -
src/include/nodes/plannodes.h | 30 ++++-------
src/include/nodes/relation.h | 10 ++--
src/include/optimizer/pathnode.h | 2 +-
23 files changed, 95 insertions(+), 290 deletions(-)
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 6cbba97c22..eeb053d5d8 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -2050,7 +2050,7 @@ postgresBeginForeignInsert(ModifyTableState *mtstate,
* Vars contained in those expressions.
*/
if (plan && plan->operation == CMD_UPDATE &&
- resultRelation == plan->nominalRelation)
+ resultRelation == plan->targetRelation)
resultRelation = mtstate->resultRelInfo[0].ri_RangeTableIndex;
}
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index ed6afe79a9..5ca7f69830 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -929,7 +929,7 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
break;
case T_ModifyTable:
*rels_used = bms_add_member(*rels_used,
- ((ModifyTable *) plan)->nominalRelation);
+ ((ModifyTable *) plan)->targetRelation);
if (((ModifyTable *) plan)->exclRelRTI)
*rels_used = bms_add_member(*rels_used,
((ModifyTable *) plan)->exclRelRTI);
@@ -2924,7 +2924,7 @@ ExplainScanTarget(Scan *plan, ExplainState *es)
static void
ExplainModifyTarget(ModifyTable *plan, ExplainState *es)
{
- ExplainTargetRel((Plan *) plan, plan->nominalRelation, es);
+ ExplainTargetRel((Plan *) plan, plan->targetRelation, es);
}
/*
@@ -3088,7 +3088,7 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors,
/* Should we explicitly label target relations? */
labeltargets = (mtstate->mt_nplans > 1 ||
(mtstate->mt_nplans == 1 &&
- mtstate->resultRelInfo->ri_RangeTableIndex != node->nominalRelation));
+ mtstate->resultRelInfo->ri_RangeTableIndex != node->targetRelation));
if (labeltargets)
ExplainOpenGroup("Target Tables", "Target Tables", false, es);
diff --git a/src/backend/commands/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 a9edc90a52..3c197c55f4 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -219,7 +219,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 7d8bd01994..15d8fcc352 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -176,6 +176,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;
@@ -183,7 +184,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
@@ -203,7 +203,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/execPartition.c b/src/backend/executor/execPartition.c
index 3be794b97d..1d2b3620ee 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -379,7 +379,7 @@ ExecInitPartitionInfo(ModifyTableState *mtstate,
leaf_part_rri = makeNode(ResultRelInfo);
InitResultRelInfo(leaf_part_rri,
partrel,
- node ? node->nominalRelation : 1,
+ node ? node->targetRelation : 1,
rootrel,
estate->es_instrument);
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 f81769ea85..b18f9e3164 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2255,18 +2255,17 @@ 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->partitionedTarget);
+ rte = rt_fetch(node->targetRelation, estate->es_range_table);
rel = heap_open(rte->relid, NoLock);
- InitResultRelInfo(mtstate->rootResultRelInfo, rel, root_rt_index,
- NULL, estate->es_instrument);
+ InitResultRelInfo(mtstate->rootResultRelInfo, rel,
+ node->targetRelation, NULL, estate->es_instrument);
}
mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 11ca800e4c..1bee240e72 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -1358,7 +1358,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
@@ -1374,7 +1374,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..da02b8961c 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);
@@ -203,8 +202,8 @@ _copyModifyTable(const ModifyTable *from)
*/
COPY_SCALAR_FIELD(operation);
COPY_SCALAR_FIELD(canSetTag);
- COPY_SCALAR_FIELD(nominalRelation);
- COPY_NODE_FIELD(partitioned_rels);
+ COPY_SCALAR_FIELD(targetRelation);
+ COPY_SCALAR_FIELD(partitionedTarget);
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 03d84aa0cd..2e6a5a1b42 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -272,6 +272,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);
@@ -280,11 +281,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);
@@ -375,8 +374,8 @@ _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(targetRelation);
+ WRITE_BOOL_FIELD(partitionedTarget);
WRITE_BOOL_FIELD(partColsUpdated);
WRITE_NODE_FIELD(resultRelations);
WRITE_INT_FIELD(resultRelIndex);
@@ -405,7 +404,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);
}
@@ -418,7 +416,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);
@@ -2178,8 +2175,8 @@ _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(targetRelation);
+ WRITE_BOOL_FIELD(partitionedTarget);
WRITE_BOOL_FIELD(partColsUpdated);
WRITE_NODE_FIELD(resultRelations);
WRITE_NODE_FIELD(subpaths);
@@ -2257,9 +2254,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 fc006e2830..aea5b0abc4 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1496,6 +1496,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);
@@ -1504,11 +1505,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);
@@ -1597,8 +1596,8 @@ _readModifyTable(void)
READ_ENUM_FIELD(operation, CmdType);
READ_BOOL_FIELD(canSetTag);
- READ_UINT_FIELD(nominalRelation);
- READ_NODE_FIELD(partitioned_rels);
+ READ_UINT_FIELD(targetRelation);
+ READ_BOOL_FIELD(partitionedTarget);
READ_BOOL_FIELD(partColsUpdated);
READ_NODE_FIELD(resultRelations);
READ_INT_FIELD(resultRelIndex);
@@ -1632,7 +1631,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();
@@ -1648,7 +1646,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..8f20e54d9e 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 targetRelation, bool partitionedTarget,
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;
@@ -2410,8 +2405,8 @@ create_modifytable_plan(PlannerInfo *root, ModifyTablePath *best_path)
plan = make_modifytable(root,
best_path->operation,
best_path->canSetTag,
- best_path->nominalRelation,
- best_path->partitioned_rels,
+ best_path->targetRelation,
+ best_path->partitionedTarget,
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 targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subplans, List *subroots,
List *withCheckOptionLists, List *returningLists,
@@ -6537,8 +6509,8 @@ make_modifytable(PlannerInfo *root,
node->operation = operation;
node->canSetTag = canSetTag;
- node->nominalRelation = nominalRelation;
- node->partitioned_rels = flatten_partitioned_rels(partitioned_rels);
+ node->targetRelation = targetRelation;
+ node->partitionedTarget = partitionedTarget;
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 22c010c19e..a927c0a1db 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -287,6 +287,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
Plan *top_plan;
ListCell *lp,
*lr;
+ bool hasRowMarks = (parse->rowMarks != NIL);
/*
* Set up global state for this planner invocation. This data is needed
@@ -301,9 +302,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;
@@ -501,9 +500,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) */
@@ -514,6 +511,8 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
PlannerInfo *subroot = lfirst_node(PlannerInfo, lr);
lfirst(lp) = set_plan_references(subroot, subplan);
+ if (subroot->rowMarks != NIL)
+ hasRowMarks = true;
}
/* build the PlannedStmt result */
@@ -523,6 +522,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
result->queryId = parse->queryId;
result->hasReturning = (parse->returningList != NIL);
result->hasModifyingCTE = parse->hasModifyingCTE;
+ result->hasRowMarks = hasRowMarks;
result->canSetTag = parse->canSetTag;
result->transientPlan = glob->transientPlan;
result->dependsOnRole = glob->dependsOnRole;
@@ -530,11 +530,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;
@@ -1169,7 +1167,7 @@ inheritance_planner(PlannerInfo *root)
int top_parentRTindex = parse->resultRelation;
Bitmapset *subqueryRTindexes;
Bitmapset *modifiableARIindexes;
- int nominalRelation = -1;
+ int targetRelation = -1;
List *final_rtable = NIL;
int save_rel_array_size = 0;
RelOptInfo **save_rel_array = NULL;
@@ -1184,8 +1182,7 @@ inheritance_planner(PlannerInfo *root)
ListCell *lc;
Index rti;
RangeTblEntry *parent_rte;
- Relids partitioned_relids = NULL;
- List *partitioned_rels = NIL;
+ bool partitionedTarget = false;
PlannerInfo *parent_root;
Query *parent_parse;
Bitmapset *parent_relids = bms_make_singleton(top_parentRTindex);
@@ -1248,25 +1245,14 @@ inheritance_planner(PlannerInfo *root)
}
/*
- * If the parent RTE is a partitioned table, we should use that as the
- * nominal relation, because the RTEs added for partitioned tables
- * (including the root parent) as child members of the inheritance set do
- * not appear anywhere else in the plan. The situation is exactly the
- * opposite in the case of non-partitioned inheritance parent as described
- * below. For the same reason, collect the list of descendant partitioned
- * tables to be saved in ModifyTable node, so that executor can lock those
- * as well.
+ * If the parent RTE is a partitioned table, set that as the target
+ * relation and mark that we're working with a partitioned target.
*/
parent_rte = rt_fetch(top_parentRTindex, root->parse->rtable);
if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
{
- nominalRelation = top_parentRTindex;
-
- /*
- * 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);
+ targetRelation = top_parentRTindex;
+ partitionedTarget = true;
}
/*
@@ -1338,7 +1324,7 @@ inheritance_planner(PlannerInfo *root)
* inheritance parent.
*/
subroot->inhTargetKind =
- partitioned_relids ? INHKIND_PARTITIONED : INHKIND_INHERITED;
+ partitionedTarget ? INHKIND_PARTITIONED : INHKIND_INHERITED;
/*
* If this child is further partitioned, remember it as a parent.
@@ -1363,17 +1349,17 @@ inheritance_planner(PlannerInfo *root)
}
/*
- * Set the nominal target relation of the ModifyTable node if not
- * already done. We use the inheritance parent RTE as the nominal
- * target relation if it's a partitioned table (see just above this
- * loop). In the non-partitioned parent case, we'll use the first
- * child relation (even if it's excluded) as the nominal target
- * relation. Because of the way expand_inherited_rtentry works, the
- * latter should be the RTE representing the parent table in its role
- * as a simple member of the inheritance set.
+ * Set the target relation of the ModifyTable node if not already
+ * done. We use the inheritance parent RTE as the target relation
+ * if it's a partitioned table (see just above this loop). In the
+ * non-partitioned parent case, we'll use the first child relation
+ * (even if it's excluded) as the target relation. Because of the way
+ * expand_inherited_rtentry works, the latter should be the RTE
+ * representing the parent table in its role as a simple member of
+ * the inheritance set.
*
* It would be logically cleaner to *always* use the inheritance
- * parent RTE as the nominal relation; but that RTE is not otherwise
+ * parent RTE as the target relation; but that RTE is not otherwise
* referenced in the plan in the non-partitioned inheritance case.
* Instead the duplicate child RTE created by expand_inherited_rtentry
* is used elsewhere in the plan, so using the original parent RTE
@@ -1383,8 +1369,8 @@ inheritance_planner(PlannerInfo *root)
* duplicate child RTE added for the parent does not appear anywhere
* else in the plan tree.
*/
- if (nominalRelation < 0)
- nominalRelation = appinfo->child_relid;
+ if (targetRelation < 0)
+ targetRelation = appinfo->child_relid;
/*
* The rowMarks list might contain references to subquery RTEs, so
@@ -1509,15 +1495,6 @@ inheritance_planner(PlannerInfo *root)
continue;
/*
- * Add the current parent's RT index to the partitioned_relids set if
- * we're creating the ModifyTable path for a partitioned root table.
- * (We only care about parents of non-excluded children.)
- */
- if (partitioned_relids)
- partitioned_relids = bms_add_member(partitioned_relids,
- appinfo->parent_relid);
-
- /*
* If this is the first non-excluded child, its post-planning rtable
* becomes the initial contents of final_rtable; otherwise, append
* just its modified subquery RTEs to final_rtable.
@@ -1620,29 +1597,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,
+ targetRelation,
+ partitionedTarget,
root->partColsUpdated,
resultRelations,
subpaths,
@@ -2219,7 +2180,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
parse->commandType,
parse->canSetTag,
parse->resultRelation,
- NIL,
+ false,
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..17d53f356c 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);
}
@@ -847,13 +827,9 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
fix_scan_list(root, splan->exclRelTlist, rtoffset);
}
- splan->nominalRelation += rtoffset;
+ splan->targetRelation += rtoffset;
splan->exclRelRTI += rtoffset;
- foreach(l, splan->partitioned_rels)
- {
- lfirst_int(l) += rtoffset;
- }
foreach(l, splan->resultRelations)
{
lfirst_int(l) += rtoffset;
@@ -884,24 +860,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->partitionedTarget)
{
- 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->targetRelation);
}
}
break;
@@ -915,10 +884,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 +902,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..73eca1d4d0 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -3291,10 +3291,8 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
* 'rel' is the parent relation associated with the result
* 'operation' is the operation type
* 'canSetTag' is true if we set the command tag/es_processed
- * 'nominalRelation' is the parent RT index for use of EXPLAIN
- * '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.
+ * 'targetRelation' is the target table's RT index
+ * 'partitionedTarget' true if 'targetRelation' is a partitioned table
* 'partColsUpdated' is true if any partitioning columns are being updated,
* either from the target relation or a descendent partitioned table.
* 'resultRelations' is an integer list of actual RT indexes of target rel(s)
@@ -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 targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subpaths,
List *subroots,
@@ -3376,8 +3374,8 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
pathnode->operation = operation;
pathnode->canSetTag = canSetTag;
- pathnode->nominalRelation = nominalRelation;
- pathnode->partitioned_rels = list_copy(partitioned_rels);
+ pathnode->targetRelation = targetRelation;
+ pathnode->partitionedTarget = partitionedTarget;
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..d0427c64ba 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
+ 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..27ae73e3d4 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 */
@@ -219,9 +212,10 @@ typedef struct ModifyTable
Plan plan;
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 targetRelation; /* RT index of the target table specified in
+ * the command or first child for inheritance
+ * tables */
+ bool partitionedTarget; /* is the target table partitioned? */
bool partColsUpdated; /* some part key in hierarchy updated */
List *resultRelations; /* integer list of RT indexes */
int resultRelIndex; /* index of first resultRel in plan's list */
@@ -259,9 +253,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 +265,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 +916,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..bcc2ba6db5 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 */
@@ -1716,9 +1713,10 @@ typedef struct ModifyTablePath
Path path;
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 targetRelation; /* RT index of the target table specified in
+ * the command or first child for inheritance
+ * tables */
+ bool partitionedTarget; /* is the target table partitioned? */
bool partColsUpdated; /* some part key in hierarchy updated */
List *resultRelations; /* integer list of RT indexes */
List *subpaths; /* Path(s) producing source data */
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 7c5ff22650..a45c2407d0 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -238,7 +238,7 @@ extern LockRowsPath *create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
extern ModifyTablePath *create_modifytable_path(PlannerInfo *root,
RelOptInfo *rel,
CmdType operation, bool canSetTag,
- Index nominalRelation, List *partitioned_rels,
+ Index targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subpaths,
List *subroots,
--
2.11.0
v8-0003-Prune-PlanRowMark-of-relations-that-are-pruned-fr.patchtext/plain; charset=UTF-8; name=v8-0003-Prune-PlanRowMark-of-relations-that-are-pruned-fr.patchDownload
From 67f72dc024244bd4c36d865bb0b5dd350c7f1c82 Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Thu, 27 Sep 2018 13:31:11 +1200
Subject: [PATCH v8 3/4] Prune PlanRowMark of relations that are pruned from a
plan
---
src/backend/optimizer/plan/planner.c | 32 ++++++++++++++++++++++++++------
1 file changed, 26 insertions(+), 6 deletions(-)
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index a927c0a1db..074ec9bf55 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -248,7 +248,7 @@ static bool group_by_has_partkey(RelOptInfo *input_rel,
List *targetList,
List *groupClause);
static int common_prefix_cmp(const void *a, const void *b);
-
+static List *get_nondummy_rowmarks(PlannerInfo *root);
/*****************************************************************************
*
@@ -1595,7 +1595,7 @@ inheritance_planner(PlannerInfo *root)
if (parse->rowMarks)
rowMarks = NIL;
else
- rowMarks = root->rowMarks;
+ rowMarks = get_nondummy_rowmarks(root);
/* Create Path representing a ModifyTable to do the UPDATE/DELETE work */
add_path(final_rel, (Path *)
@@ -2124,11 +2124,9 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
* is what goes into the LockRows node.)
*/
if (parse->rowMarks)
- {
path = (Path *) create_lockrows_path(root, final_rel, path,
- root->rowMarks,
+ get_nondummy_rowmarks(root),
SS_assign_special_param(root));
- }
/*
* If there is a LIMIT/OFFSET clause, add the LIMIT node.
@@ -2173,7 +2171,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
if (parse->rowMarks)
rowMarks = NIL;
else
- rowMarks = root->rowMarks;
+ rowMarks = get_nondummy_rowmarks(root);
path = (Path *)
create_modifytable_path(root, final_rel,
@@ -7219,3 +7217,25 @@ group_by_has_partkey(RelOptInfo *input_rel,
return true;
}
+
+/*
+ * get_nondummy_rowmarks
+ * Return a list of PlanRowMark's that reference non-dummy relations
+ */
+static List *
+get_nondummy_rowmarks(PlannerInfo *root)
+{
+ List *rowMarks = NIL;
+ ListCell *lc;
+
+ 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]))
+ rowMarks = lappend(rowMarks, rc);
+ }
+
+ return rowMarks;
+}
--
2.11.0
v8-0004-Revise-executor-range-table-relation-opening-clos.patchtext/plain; charset=UTF-8; name=v8-0004-Revise-executor-range-table-relation-opening-clos.patchDownload
From edfb20fd3fa6c0360c10d6f9a5fd6c5379f6a2c7 Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Thu, 27 Sep 2018 16:14:41 +1200
Subject: [PATCH v8 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, an arrangement which allows the executor
to have to heap_open any given range table relation only once.
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.
Accessed Relations are now also closed during ExecEndPlan(). Callers of
ExecRangeTableRelation() have no need to consider how their Relation
objects are cleaned up.
Authors: Amit Langote, David Rowley
---
contrib/postgres_fdw/postgres_fdw.c | 16 +++---
src/backend/commands/copy.c | 3 +-
src/backend/commands/trigger.c | 3 +-
src/backend/executor/README | 4 +-
src/backend/executor/execExprInterp.c | 7 +--
src/backend/executor/execMain.c | 81 +++++++++--------------------
src/backend/executor/execPartition.c | 39 +++-----------
src/backend/executor/execUtils.c | 68 +++++++++++++++---------
src/backend/executor/nodeAppend.c | 6 ---
src/backend/executor/nodeBitmapHeapscan.c | 7 ---
src/backend/executor/nodeCustom.c | 4 --
src/backend/executor/nodeForeignscan.c | 4 --
src/backend/executor/nodeIndexonlyscan.c | 7 ---
src/backend/executor/nodeIndexscan.c | 7 ---
src/backend/executor/nodeLockRows.c | 2 +-
src/backend/executor/nodeMergeAppend.c | 6 ---
src/backend/executor/nodeModifyTable.c | 26 +++++----
src/backend/executor/nodeSamplescan.c | 5 --
src/backend/executor/nodeSeqscan.c | 7 ---
src/backend/executor/nodeTidscan.c | 5 --
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/tablesync.c | 9 +++-
src/backend/replication/logical/worker.c | 2 +
src/include/executor/execPartition.h | 1 -
src/include/executor/executor.h | 24 ++++++++-
src/include/nodes/execnodes.h | 23 +++++++-
src/include/nodes/plannodes.h | 2 +-
src/include/parser/parsetree.h | 10 ----
32 files changed, 195 insertions(+), 224 deletions(-)
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index eeb053d5d8..d20c75367c 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. */
@@ -1731,8 +1731,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,
@@ -2036,7 +2036,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);
@@ -2396,7 +2396,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. */
@@ -2546,10 +2546,6 @@ postgresEndDirectModify(ForeignScanState *node)
ReleaseConnection(dmstate->conn);
dmstate->conn = NULL;
- /* close the target relation. */
- if (dmstate->resultRel)
- ExecCloseScanRelation(dmstate->resultRel);
-
/* MemoryContext will be deleted automatically. */
}
@@ -5756,7 +5752,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 0c4a7b6f4f..57efb20d20 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -2483,7 +2483,8 @@ 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;
+
+ ExecInitRangeTable(estate, cstate->range_table);
/* 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 34f9db93d5..f0d45844c1 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/README b/src/backend/executor/README
index 0d7cd552eb..30df410e0e 100644
--- a/src/backend/executor/README
+++ b/src/backend/executor/README
@@ -267,8 +267,8 @@ This is a sketch of control flow for full query processing:
Per above comments, it's not really critical for ExecEndNode to free any
memory; it'll all go away in FreeExecutorState anyway. However, we do need to
-be careful to close relations, drop buffer pins, etc, so we do need to scan
-the plan state tree to find these sorts of resources.
+be careful to drop buffer pins, etc, so we do need to scan the plan state tree
+to find these sorts of resources.
The executor can also be used to evaluate simple expressions without any Plan
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index f597363eb1..f8ca60ae5a 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3934,10 +3934,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 3c197c55f4..d895ed29d1 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -111,9 +111,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 */
@@ -837,28 +837,16 @@ 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 the necessary lock on the relation
- * has already been taken. That can only however be true in the
- * parallel leader.
- */
- Assert(rte->lockmode != NoLock);
- if (!IsParallelWorker() &&
- !CheckRelationLockedByUs(rte->relid, rte->lockmode))
- elog(WARNING, "InitPlan: lock on \"%s\" not already taken",
- get_rel_name(rte->relid));
- }
- }
-#endif
+ ExecInitRangeTable(estate, rangeTable);
/*
+ * Allocate an array to store open Relations of each rangeTable item. We
+ * zero-fill this for now. The Relations are only opened and stored here
+ * the first time they're required during node initialization.
+ */
+ estate->es_relations = (Relation *) palloc0(estate->es_range_table_size *
+ sizeof(Relation));
+ /*
* initialize the node's execution state
*/
estate->es_range_table = rangeTable;
@@ -1501,6 +1489,14 @@ static void
ExecEndPlan(PlanState *planstate, EState *estate)
{
ListCell *l;
+ int i;
+
+ /* Close range table relations. */
+ for (i = 0; i < estate->es_range_table_size; i++)
+ {
+ if (estate->es_relations[i])
+ heap_close(estate->es_relations[i], NoLock);
+ }
/*
* shut down the node-type-specific query processing
@@ -1527,18 +1523,6 @@ ExecEndPlan(PlanState *planstate, EState *estate)
/* likewise close any trigger target relations */
ExecCleanUpTriggerState(estate);
-
- /*
- * 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);
- }
}
/* ----------------------------------------------------------------
@@ -2295,24 +2279,20 @@ 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);
-
switch (rc->markType)
{
case ROW_MARK_EXCLUSIVE:
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 */
@@ -2330,7 +2310,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;
@@ -2988,7 +2968,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));
@@ -3041,7 +3021,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();
@@ -3065,6 +3045,9 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree)
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_range_table_size = parentestate->es_range_table_size;
+ 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;
@@ -3218,18 +3201,6 @@ 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 1d2b3620ee..7fb34d2173 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -861,11 +861,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++)
{
@@ -1418,9 +1417,6 @@ adjust_partition_tlist(List *tlist, TupleConversionMap *map)
* functions. Details stored include how to map the partition index
* returned by the partition pruning code into subplan indexes.
*
- * ExecDestroyPartitionPruneState:
- * Deletes a PartitionPruneState. Must be called during executor shutdown.
- *
* ExecFindInitialMatchingSubPlans:
* Returns indexes of matching subplans. Partition pruning is attempted
* without any evaluation of expressions containing PARAM_EXEC Params.
@@ -1462,6 +1458,7 @@ PartitionPruneState *
ExecCreatePartitionPruneState(PlanState *planstate,
PartitionPruneInfo *partitionpruneinfo)
{
+ EState *estate = planstate->state;
PartitionPruneState *prunestate;
int n_part_hierarchies;
ListCell *lc;
@@ -1542,7 +1539,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);
@@ -1623,30 +1620,6 @@ ExecCreatePartitionPruneState(PlanState *planstate,
}
/*
- * ExecDestroyPartitionPruneState
- * Release resources at plan shutdown.
- *
- * We don't bother to free any memory here, since the whole executor context
- * will be going away shortly. We do need to release our relcache pins.
- */
-void
-ExecDestroyPartitionPruneState(PartitionPruneState *prunestate)
-{
- PartitionPruningData **partprunedata = prunestate->partprunedata;
- int i;
-
- for (i = 0; i < prunestate->num_partprunedata; i++)
- {
- PartitionPruningData *prunedata = partprunedata[i];
- PartitionedRelPruningData *pprune = prunedata->partrelprunedata;
- int j;
-
- for (j = 0; j < prunedata->num_partrelprunedata; j++)
- relation_close(pprune[j].context.partrel, NoLock);
- }
-}
-
-/*
* ExecFindInitialMatchingSubPlans
* Identify the set of subplans that cannot be eliminated by initial
* pruning (disregarding any pruning constraints involving PARAM_EXEC
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index d32796aac3..d841e5e675 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -25,7 +25,6 @@
* etc
*
* ExecOpenScanRelation Common code for scan node init routines.
- * ExecCloseScanRelation
*
* executor_errposition Report syntactic position of an error.
*
@@ -35,6 +34,8 @@
* GetAttributeByName Runtime extraction of columns from tuples.
* GetAttributeByNum
*
+ * ExecInitRangeTable Build an array from the range table list to
+ * allow faster lookups by relid.
* NOTES
* This file has traditionally been the place to stick misc.
* executor support stuff that doesn't really go anyplace else.
@@ -653,11 +654,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
@@ -675,26 +674,6 @@ ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
return rel;
}
-/* ----------------------------------------------------------------
- * ExecCloseScanRelation
- *
- * Close the heap relation scanned by a base-level scan plan node.
- * This should be called during the node's ExecEnd routine.
- *
- * Currently, we do not release the lock acquired by ExecOpenScanRelation.
- * This lock should be held till end of transaction. (There is a faction
- * that considers this too much locking, however.)
- *
- * If we did want to release the lock, we'd have to repeat the logic in
- * ExecOpenScanRelation in order to figure out what to release.
- * ----------------------------------------------------------------
- */
-void
-ExecCloseScanRelation(Relation scanrel)
-{
- heap_close(scanrel, NoLock);
-}
-
/*
* UpdateChangedParamSet
* Add changed parameters to a plan node's chgParam set
@@ -997,3 +976,44 @@ ExecCleanTargetListLength(List *targetlist)
}
return len;
}
+
+/*
+ * Initialize executor's range table array
+ */
+void
+ExecInitRangeTable(EState *estate, List *rangeTable)
+{
+ int rti;
+ ListCell *l;
+
+#ifdef USE_ASSERT_CHECKING
+ foreach(l, rangeTable)
+ {
+ RangeTblEntry *rte = lfirst(l);
+
+ if (rte->rtekind == RTE_RELATION && OidIsValid(rte->relid))
+ {
+ /*
+ * The following verifies that the necessary lock on the relation
+ * has already been taken. That can only however be true in the
+ * parallel leader.
+ */
+ Assert(rte->lockmode != NoLock);
+ if (!IsParallelWorker() &&
+ !CheckRelationLockedByUs(rte->relid, rte->lockmode))
+ elog(WARNING, "InitPlan: lock on \"%s\" not already taken",
+ get_rel_name(rte->relid));
+ }
+ }
+#endif
+
+ Assert(estate != NULL);
+ 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 *));
+ rti = 0;
+ foreach(l, rangeTable)
+ estate->es_range_table_array[rti++] = lfirst_node(RangeTblEntry, l);
+}
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index eb587be221..a16b6da474 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -329,12 +329,6 @@ ExecEndAppend(AppendState *node)
*/
for (i = 0; i < nplans; i++)
ExecEndNode(appendplans[i]);
-
- /*
- * release any resources associated with run-time pruning
- */
- if (node->as_prune_state)
- ExecDestroyPartitionPruneState(node->as_prune_state);
}
void
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index baffae27e3..5307cd1b87 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -785,13 +785,11 @@ ExecReScanBitmapHeapScan(BitmapHeapScanState *node)
void
ExecEndBitmapHeapScan(BitmapHeapScanState *node)
{
- Relation relation;
HeapScanDesc scanDesc;
/*
* extract information from the node
*/
- relation = node->ss.ss_currentRelation;
scanDesc = node->ss.ss_currentScanDesc;
/*
@@ -832,11 +830,6 @@ ExecEndBitmapHeapScan(BitmapHeapScanState *node)
* close heap scan
*/
heap_endscan(scanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index b816e0b31d..9a33eda688 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -126,10 +126,6 @@ ExecEndCustomScan(CustomScanState *node)
/* Clean out the tuple table */
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /* Close the heap relation */
- if (node->ss.ss_currentRelation)
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
void
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index a2a28b7ec2..cf7df72d8c 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -258,10 +258,6 @@ ExecEndForeignScan(ForeignScanState *node)
/* clean out the tuple table */
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /* close the relation. */
- if (node->ss.ss_currentRelation)
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 4b6d531810..1b530cea40 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -373,14 +373,12 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node)
{
Relation indexRelationDesc;
IndexScanDesc indexScanDesc;
- Relation relation;
/*
* extract information from the node
*/
indexRelationDesc = node->ioss_RelationDesc;
indexScanDesc = node->ioss_ScanDesc;
- relation = node->ss.ss_currentRelation;
/* Release VM buffer pin, if any. */
if (node->ioss_VMBuffer != InvalidBuffer)
@@ -411,11 +409,6 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node)
index_endscan(indexScanDesc);
if (indexRelationDesc)
index_close(indexRelationDesc, NoLock);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 6285a2114e..786e7ac25c 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -802,14 +802,12 @@ ExecEndIndexScan(IndexScanState *node)
{
Relation indexRelationDesc;
IndexScanDesc indexScanDesc;
- Relation relation;
/*
* extract information from the node
*/
indexRelationDesc = node->iss_RelationDesc;
indexScanDesc = node->iss_ScanDesc;
- relation = node->ss.ss_currentRelation;
/*
* Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
@@ -833,11 +831,6 @@ ExecEndIndexScan(IndexScanState *node)
index_endscan(indexScanDesc);
if (indexRelationDesc)
index_close(indexRelationDesc, NoLock);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index efbf4bd18a..ff9606342b 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/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index d8e0978966..5d0dbb8146 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -363,12 +363,6 @@ ExecEndMergeAppend(MergeAppendState *node)
*/
for (i = 0; i < nplans; i++)
ExecEndNode(mergeplans[i]);
-
- /*
- * release any resources associated with run-time pruning
- */
- if (node->ms_prune_state)
- ExecDestroyPartitionPruneState(node->ms_prune_state);
}
void
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index b18f9e3164..c837d36a87 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,17 +2254,18 @@ 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->partitionedTarget);
- rte = rt_fetch(node->targetRelation, estate->es_range_table);
- rel = heap_open(rte->relid, NoLock);
- InitResultRelInfo(mtstate->rootResultRelInfo, rel,
- node->targetRelation, NULL, estate->es_instrument);
+ rel = ExecRangeTableRelation(estate, node->targetRelation);
+ InitResultRelInfo(mtstate->rootResultRelInfo,
+ rel,
+ node->targetRelation,
+ NULL,
+ estate->es_instrument);
}
mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
@@ -2722,15 +2722,13 @@ ExecEndModifyTable(ModifyTableState *node)
resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
resultRelInfo);
- /* Close indices and then the relation itself */
+ /*
+ * Close the ResultRelInfo's indexes. The relation itself
+ * is handled by the executor cleanup code.
+ */
ExecCloseIndices(resultRelInfo);
- heap_close(resultRelInfo->ri_RelationDesc, NoLock);
}
- /* 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/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index 99528be84a..92ff68a764 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -222,11 +222,6 @@ ExecEndSampleScan(SampleScanState *node)
*/
if (node->ss.ss_currentScanDesc)
heap_endscan(node->ss.ss_currentScanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index cd53491be0..92ff1e50ed 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -201,13 +201,11 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
void
ExecEndSeqScan(SeqScanState *node)
{
- Relation relation;
HeapScanDesc scanDesc;
/*
* get information from node
*/
- relation = node->ss.ss_currentRelation;
scanDesc = node->ss.ss_currentScanDesc;
/*
@@ -226,11 +224,6 @@ ExecEndSeqScan(SeqScanState *node)
*/
if (scanDesc != NULL)
heap_endscan(scanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index 0cb1946a3e..8cae56f48c 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -489,11 +489,6 @@ ExecEndTidScan(TidScanState *node)
*/
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index da02b8961c..dd76284676 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 2e6a5a1b42..6aefdd8bc4 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1029,7 +1029,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 aea5b0abc4..30609c96e6 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -2373,7 +2373,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 17d53f356c..ee01ef82d2 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -890,6 +890,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:
@@ -908,6 +923,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 e1ce8b4ddc..1763dd67a3 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/tablesync.c b/src/backend/replication/logical/tablesync.c
index 905a983074..d72f6a1b4f 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -795,7 +795,14 @@ copy_table(Relation rel)
copybuf = makeStringInfo();
pstate = make_parsestate(NULL);
- addRangeTableEntryForRelation(pstate, rel, NULL, false, false, NoLock);
+
+ /*
+ * Caller LogicalRepSyncTableStart took RowExclusiveLock, which we must
+ * record in the RTE being built, because executor initialization invoked
+ * by copy.c expects it.
+ */
+ addRangeTableEntryForRelation(pstate, rel, NULL, false, false,
+ RowExclusiveLock);
attnamelist = make_copy_attnamelist(relmapentry);
cstate = BeginCopyFrom(pstate, rel, NULL, false, copy_read_data, attnamelist, NIL);
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 42345f94d3..c63de66857 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -200,6 +200,8 @@ create_estate_for_relation(LogicalRepRelMapEntry *rel)
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/execPartition.h b/src/include/executor/execPartition.h
index 89ce53815c..04847d639d 100644
--- a/src/include/executor/execPartition.h
+++ b/src/include/executor/execPartition.h
@@ -197,7 +197,6 @@ extern void ExecCleanupTupleRouting(ModifyTableState *mtstate,
PartitionTupleRouting *proute);
extern PartitionPruneState *ExecCreatePartitionPruneState(PlanState *planstate,
PartitionPruneInfo *partitionpruneinfo);
-extern void ExecDestroyPartitionPruneState(PartitionPruneState *prunestate);
extern Bitmapset *ExecFindMatchingSubPlans(PartitionPruneState *prunestate);
extern Bitmapset *ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate,
int nsubplans);
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 1d2b48fe09..b03d8c591f 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"
/*
@@ -478,6 +479,7 @@ extern ExprContext *CreateExprContext(EState *estate);
extern ExprContext *CreateStandaloneExprContext(void);
extern void FreeExprContext(ExprContext *econtext, bool isCommit);
extern void ReScanExprContext(ExprContext *econtext);
+extern void ExecInitRangeTable(EState *estate, List *rangeTable);
#define ResetExprContext(econtext) \
MemoryContextReset((econtext)->ecxt_per_tuple_memory)
@@ -513,7 +515,6 @@ extern void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate
extern bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid);
extern Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags);
-extern void ExecCloseScanRelation(Relation scanrel);
extern int executor_errposition(EState *estate, int location);
@@ -568,4 +569,25 @@ 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)
+{
+ Relation rel = estate->es_relations[rti - 1];
+
+ if (rel == NULL)
+ {
+ RangeTblEntry *rte = exec_rt_fetch(rti, estate->es_range_table_array);
+
+ /*
+ * No need to lock the relation. Locks were already
+ * obtained by the upstream code.
+ */
+ rel = estate->es_relations[rti - 1] = heap_open(rte->relid, NoLock);
+ }
+
+ return rel;
+}
+#endif
+
#endif /* EXECUTOR_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 03ad516976..639235d622 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,11 @@ 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 Relations
+ * es_range_table_size elements in length. */
PlannedStmt *es_plannedstmt; /* link to top of plan tree */
const char *es_sourceText; /* Source text from QueryDesc */
@@ -579,6 +584,22 @@ typedef struct EState
struct JitInstrumentation *es_jit_combined_instr;
} 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]
+
+/*
+ * 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 27ae73e3d4..452627dd03 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -1093,7 +1093,7 @@ typedef struct PartitionPruneInfo
typedef struct PartitionedRelPruneInfo
{
NodeTag type;
- Oid reloid; /* OID of partition rel for this level */
+ Index rtindex; /* Partition table's RT index */
List *pruning_steps; /* List of PartitionPruneStep, see below */
Bitmapset *present_parts; /* Indexes of all partitions which subplans or
* subparts are present for. */
diff --git a/src/include/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
On 28 September 2018 at 20:28, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
On 2018/09/28 17:21, David Rowley wrote:
I think we maybe should switch the word "assert" for "verifies". The
Assert is just checking we didn't get a NoLock and I don't think
you're using "assert" meaning the Assert() marco, so likely should be
changed to avoid confusion.Okay, I've revised the text in the attached updated patch.
Meh, I just noticed that the WARNING text claims "InitPlan" is the
function name. I think it's best to get rid of that. It's pretty much
redundant anyway if you do: \set VERBOSITY verbose
--
David Rowley http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
On 2018/09/28 17:48, David Rowley wrote:
On 28 September 2018 at 20:28, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:On 2018/09/28 17:21, David Rowley wrote:
I think we maybe should switch the word "assert" for "verifies". The
Assert is just checking we didn't get a NoLock and I don't think
you're using "assert" meaning the Assert() marco, so likely should be
changed to avoid confusion.Okay, I've revised the text in the attached updated patch.
Meh, I just noticed that the WARNING text claims "InitPlan" is the
function name. I think it's best to get rid of that. It's pretty much
redundant anyway if you do: \set VERBOSITY verbose
Oops, good catch that one. Removed "InitPlan: " from the message in the
attached.
Thanks,
Amit
Attachments:
v9-0001-Don-t-lock-range-table-relations-in-the-executor.patchtext/plain; charset=UTF-8; name=v9-0001-Don-t-lock-range-table-relations-in-the-executor.patchDownload
From a8a2d82d15991968d921339e6e7d63030cf61bce Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Thu, 19 Jul 2018 16:14:51 +0900
Subject: [PATCH v9 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/catalog/heap.c | 3 +-
src/backend/commands/copy.c | 7 +-
src/backend/commands/policy.c | 17 +-
src/backend/commands/tablecmds.c | 3 +-
src/backend/commands/trigger.c | 6 +-
src/backend/commands/view.c | 6 +-
src/backend/executor/execMain.c | 275 ++++++++---------------
src/backend/executor/execPartition.c | 4 +-
src/backend/executor/execUtils.c | 24 +-
src/backend/executor/nodeLockRows.c | 4 +-
src/backend/executor/nodeModifyTable.c | 42 +++-
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 | 3 +-
src/backend/parser/parse_clause.c | 3 +-
src/backend/parser/parse_relation.c | 17 +-
src/backend/parser/parse_utilcmd.c | 18 +-
src/backend/replication/logical/tablesync.c | 2 +-
src/backend/rewrite/rewriteHandler.c | 20 +-
src/backend/storage/lmgr/lmgr.c | 15 ++
src/backend/storage/lmgr/lock.c | 24 ++
src/backend/utils/cache/plancache.c | 30 +--
src/include/executor/executor.h | 2 +-
src/include/nodes/parsenodes.h | 5 +
src/include/parser/parse_relation.h | 4 +-
src/include/storage/lmgr.h | 1 +
src/include/storage/lock.h | 1 +
src/test/modules/test_rls_hooks/test_rls_hooks.c | 4 +-
30 files changed, 261 insertions(+), 283 deletions(-)
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 9176f6280b..19b530ac94 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -2551,7 +2551,8 @@ AddRelationNewConstraints(Relation rel,
rel,
NULL,
false,
- true);
+ true,
+ NoLock);
addRTEtoQuery(pstate, rte, true, true, true);
/*
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index d06662bd32..0c4a7b6f4f 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -837,16 +837,17 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
List *attnums;
ListCell *cur;
RangeTblEntry *rte;
+ LOCKMODE lockmode = is_from ? RowExclusiveLock : AccessShareLock;
Assert(!stmt->query);
/* Open and lock the relation, using the appropriate lock type. */
- rel = heap_openrv(stmt->relation,
- (is_from ? RowExclusiveLock : AccessShareLock));
+ rel = heap_openrv(stmt->relation, lockmode);
relid = RelationGetRelid(rel);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, false);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, false,
+ lockmode);
rte->requiredPerms = (is_from ? ACL_INSERT : ACL_SELECT);
tupDesc = RelationGetDescr(rel);
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index cee0ef915b..2949b4e6d7 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -567,7 +567,8 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
qual_expr = stringToNode(qual_value);
/* Add this rel to the parsestate's rangetable, for dependencies */
- addRangeTableEntryForRelation(qual_pstate, rel, NULL, false, false);
+ addRangeTableEntryForRelation(qual_pstate, rel, NULL, false, false,
+ AccessExclusiveLock);
qual_parse_rtable = qual_pstate->p_rtable;
free_parsestate(qual_pstate);
@@ -590,7 +591,7 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(with_check_pstate, rel, NULL, false,
- false);
+ false, AccessExclusiveLock);
with_check_parse_rtable = with_check_pstate->p_rtable;
free_parsestate(with_check_pstate);
@@ -752,12 +753,12 @@ CreatePolicy(CreatePolicyStmt *stmt)
/* Add for the regular security quals */
rte = addRangeTableEntryForRelation(qual_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
/* Add for the with-check quals */
rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(with_check_pstate, rte, false, true, true);
qual = transformWhereClause(qual_pstate,
@@ -928,7 +929,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
ParseState *qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
@@ -950,7 +951,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
ParseState *with_check_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(with_check_pstate, rte, false, true, true);
@@ -1097,7 +1098,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(qual_pstate, target_table, NULL,
- false, false);
+ false, false, NoLock);
qual_parse_rtable = qual_pstate->p_rtable;
free_parsestate(qual_pstate);
@@ -1138,7 +1139,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(with_check_pstate, target_table, NULL,
- false, false);
+ false, false, NoLock);
with_check_parse_rtable = with_check_pstate->p_rtable;
free_parsestate(with_check_pstate);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 29d8353779..5afa54389a 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -13632,7 +13632,8 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
* rangetable entry. We need a ParseState for transformExpr.
*/
pstate = make_parsestate(NULL);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true,
+ NoLock);
addRTEtoQuery(pstate, rte, true, true, true);
/* take care of any partition expressions */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 36778b6f4d..34f9db93d5 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -578,11 +578,13 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
*/
rte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ ShareRowExclusiveLock);
addRTEtoQuery(pstate, rte, false, true, true);
rte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ ShareRowExclusiveLock);
addRTEtoQuery(pstate, rte, false, true, true);
/* Transform expression. Copy to be sure we don't modify original */
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index ffb71c0ea7..4c379fd83b 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -387,10 +387,12 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
*/
rt_entry1 = addRangeTableEntryForRelation(pstate, viewRel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessShareLock);
rt_entry2 = addRangeTableEntryForRelation(pstate, viewRel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ 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 5443cbf67d..a9edc90a52 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -52,10 +52,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"
@@ -835,99 +837,49 @@ 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 the necessary lock on the relation
+ * has already been taken. That can only however be true in the
+ * parallel leader.
+ */
+ Assert(rte->lockmode != NoLock);
+ if (!IsParallelWorker() &&
+ !CheckRelationLockedByUs(rte->relid, rte->lockmode))
+ elog(WARNING, "InitPlan: lock on \"%s\" not already taken",
+ get_rel_name(rte->relid));
+ }
+ }
+#endif
+
/*
* initialize the node's execution state
*/
estate->es_range_table = rangeTable;
estate->es_plannedstmt = plannedstmt;
- /*
- * initialize result relation stuff, and open/lock the result rels.
- *
- * We must do this before initializing the plan tree, else we might try to
- * do a lock upgrade if a result rel is also a source rel.
- */
+ /* Allocate memory required for result relations */
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
{
@@ -941,73 +893,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.
@@ -1614,8 +1500,6 @@ ExecPostprocessPlan(EState *estate)
static void
ExecEndPlan(PlanState *planstate, EState *estate)
{
- ResultRelInfo *resultRelInfo;
- int i;
ListCell *l;
/*
@@ -1641,26 +1525,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);
@@ -2421,25 +2285,64 @@ ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
}
/*
- * ExecFindRowMark -- find the ExecRowMark struct for given rangetable index
+ * ExecBuildRowMark -- create and return an ExecRowMark struct for the given
+ * PlanRowMark.
*
- * If no such struct, either return NULL or throw error depending on missing_ok
+ * The created ExecRowMark is also added to the list of rowmarks in the given
+ * EState.
*/
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);
+
+ 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;
}
/*
@@ -3179,7 +3082,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 */
@@ -3315,6 +3218,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 ec7a5267c3..3be794b97d 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -1540,9 +1540,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..efbf4bd18a 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -424,8 +424,8 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
/* safety check on size of lr_curtuples array */
Assert(rc->rti > 0 && rc->rti <= lrstate->lr_ntables);
- /* find ExecRowMark and build ExecAuxRowMark */
- erm = ExecFindRowMark(estate, rc->rti, false);
+ /* build the ExecRowMark and ExecAuxRowMark */
+ erm = ExecBuildRowMark(estate, rc);
aerm = ExecBuildAuxRowMark(erm, outerPlan->targetlist);
/*
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index bf0d5e8edb..f81769ea85 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;
@@ -2529,8 +2554,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
if (rc->isParent)
continue;
- /* find ExecRowMark (same for all subplans) */
- erm = ExecFindRowMark(estate, rc->rti, false);
+ /* build the ExecRowMark (same for all subplans) */
+ erm = ExecBuildRowMark(estate, rc);
/* build ExecAuxRowMark for each subplan */
for (i = 0; i < nplans; i++)
@@ -2686,20 +2711,27 @@ ExecEndModifyTable(ModifyTableState *node)
{
int i;
- /*
- * Allow any FDWs to shut down
- */
+ /* Perform cleanup. */
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);
}
+ /* 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 93f1e2c4eb..03d84aa0cd 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -3131,6 +3131,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 519deab63a..fc006e2830 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1361,6 +1361,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 c020600955..ce0262d170 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -1038,7 +1038,8 @@ transformOnConflictClause(ParseState *pstate,
exclRte = addRangeTableEntryForRelation(pstate,
targetrel,
makeAlias("excluded", NIL),
- false, false);
+ false, false,
+ RowExclusiveLock);
exclRte->relkind = RELKIND_COMPOSITE_TYPE;
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 d6b93f55df..689ac72c3f 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -217,7 +217,8 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
* Now build an RTE.
*/
rte = addRangeTableEntryForRelation(pstate, pstate->p_target_relation,
- relation->alias, inh, false);
+ relation->alias, inh, false,
+ 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 60b8de0f95..cbee07aeb8 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -28,6 +28,7 @@
#include "parser/parse_enr.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
+#include "storage/lmgr.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
@@ -1217,6 +1218,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
@@ -1262,23 +1264,36 @@ addRangeTableEntry(ParseState *pstate,
*
* This is just like addRangeTableEntry() except that it makes an RTE
* given an already-open relation instead of a RangeVar reference.
+ *
+ * 'lockmode' is the lock taken on 'rel'. The caller may pass NoLock if the
+ * RTE won't be passed to the executor, that is, won't be part of a
+ * PlannedStmt.
*/
RangeTblEntry *
addRangeTableEntryForRelation(ParseState *pstate,
Relation rel,
Alias *alias,
bool inh,
- bool inFromCl)
+ bool inFromCl,
+ LOCKMODE lockmode)
{
RangeTblEntry *rte = makeNode(RangeTblEntry);
char *refname = alias ? alias->aliasname : RelationGetRelationName(rel);
Assert(pstate != NULL);
+#ifdef USE_ASSERT_CHECKING
+ if (lockmode != NoLock &&
+ !CheckRelationLockedByUs(RelationGetRelid(rel), lockmode))
+ elog(WARNING, "lock on \"%s\" is not held",
+ RelationGetRelationName(rel));
+#endif
+
rte->rtekind = RTE_RELATION;
rte->alias = alias;
rte->relid = RelationGetRelid(rel);
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 f5c1e2a0d7..5df0348f1c 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -2526,7 +2526,8 @@ transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
* relation, but we still need to open it.
*/
rel = relation_open(relid, NoLock);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true,
+ NoLock);
/* no to join list, yes to namespaces */
addRTEtoQuery(pstate, rte, false, true, true);
@@ -2636,10 +2637,12 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
*/
oldrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessExclusiveLock);
newrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ AccessExclusiveLock);
/* Must override addRangeTableEntry's default access-check flags */
oldrte->requiredPerms = 0;
newrte->requiredPerms = 0;
@@ -2734,10 +2737,12 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
*/
oldrte = addRangeTableEntryForRelation(sub_pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessExclusiveLock);
newrte = addRangeTableEntryForRelation(sub_pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ AccessExclusiveLock);
oldrte->requiredPerms = 0;
newrte->requiredPerms = 0;
addRTEtoQuery(sub_pstate, oldrte, false, true, false);
@@ -2940,7 +2945,8 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
rel,
NULL,
false,
- true);
+ true,
+ NoLock);
addRTEtoQuery(pstate, rte, false, true, true);
/* Set up CreateStmtContext */
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index acc6498567..905a983074 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -795,7 +795,7 @@ copy_table(Relation rel)
copybuf = makeStringInfo();
pstate = make_parsestate(NULL);
- addRangeTableEntryForRelation(pstate, rel, NULL, false, false);
+ addRangeTableEntryForRelation(pstate, rel, NULL, false, false, NoLock);
attnamelist = make_copy_attnamelist(relmapentry);
cstate = BeginCopyFrom(pstate, rel, NULL, false, copy_read_data, attnamelist, NIL);
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 327e5c33d7..6562ac60b1 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,
@@ -2898,6 +2884,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
@@ -3103,7 +3090,8 @@ rewriteTargetView(Query *parsetree, Relation view)
base_rel,
makeAlias("excluded",
NIL),
- false, false);
+ false, false,
+ RowExclusiveLock);
new_exclRte->relkind = RELKIND_COMPOSITE_TYPE;
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 dc0a439638..2d8eae62e6 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -136,6 +136,21 @@ LockRelationOid(Oid relid, LOCKMODE lockmode)
}
/*
+ * CheckRelationLockedByUs
+ *
+ * Returns true we hold a lock on 'relid' with 'lockmode'.
+ */
+bool
+CheckRelationLockedByUs(Oid relid, LOCKMODE lockmode)
+{
+ LOCKTAG tag;
+
+ SetLocktagRelationOid(&tag, relid);
+
+ return LocalLockExists(&tag, lockmode);
+}
+
+/*
* ConditionalLockRelationOid
*
* As above, but only lock if we can get the lock without blocking.
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 831ae62525..8c140fe4b0 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -564,6 +564,30 @@ DoLockModesConflict(LOCKMODE mode1, LOCKMODE mode2)
}
/*
+ * LocalLockExists -- check if a log with 'locktag' is held locally with
+ * 'lockmode'
+ */
+bool
+LocalLockExists(const LOCKTAG *locktag, LOCKMODE lockmode)
+{
+ LOCALLOCKTAG localtag;
+ bool found;
+
+ MemSet(&localtag, 0, sizeof(localtag)); /* must clear padding */
+ localtag.lock = *locktag;
+ localtag.mode = lockmode;
+
+ /*
+ * Find the LOCALLOCK entry for this lock and lockmode
+ */
+ (void) hash_search(LockMethodLocalHash,
+ (void *) &localtag,
+ HASH_FIND, &found);
+
+ return found;
+}
+
+/*
* LockHasWaiters -- look up 'locktag' and check if releasing this
* lock would wake up other processes waiting for it.
*/
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 7271b5880b..1876345de5 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -1493,7 +1493,6 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
foreach(lc1, stmt_list)
{
PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
- int rt_index;
ListCell *lc2;
if (plannedstmt->commandType == CMD_UTILITY)
@@ -1512,14 +1511,9 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
continue;
}
- rt_index = 0;
foreach(lc2, plannedstmt->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
- LOCKMODE lockmode;
- PlanRowMark *rc;
-
- rt_index++;
if (rte->rtekind != RTE_RELATION)
continue;
@@ -1530,19 +1524,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 +1581,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 62209a8f10..2a265d591d 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -27,6 +27,7 @@
#include "nodes/primnodes.h"
#include "nodes/value.h"
#include "partitioning/partdefs.h"
+#include "storage/lockdefs.h"
typedef enum OverridingKind
@@ -976,6 +977,10 @@ typedef struct RangeTblEntry
*/
Oid relid; /* OID of the relation */
char relkind; /* relation kind (see pg_class.relkind) */
+ LOCKMODE lockmode; /* lock level to obtain on the relation; must
+ * be non-zero for all plain relation RTEs
+ * that will be passed to the executor via
+ * PlannedStmt. */
struct TableSampleClause *tablesample; /* sampling info, or NULL */
/*
diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h
index b9792acdae..99d1b4135c 100644
--- a/src/include/parser/parse_relation.h
+++ b/src/include/parser/parse_relation.h
@@ -15,6 +15,7 @@
#define PARSE_RELATION_H
#include "parser/parse_node.h"
+#include "storage/lockdefs.h"
/*
@@ -71,7 +72,8 @@ extern RangeTblEntry *addRangeTableEntryForRelation(ParseState *pstate,
Relation rel,
Alias *alias,
bool inh,
- bool inFromCl);
+ bool inFromCl,
+ LOCKMODE lockmode);
extern RangeTblEntry *addRangeTableEntryForSubquery(ParseState *pstate,
Query *subquery,
Alias *alias,
diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h
index a217de9716..abfafe5e40 100644
--- a/src/include/storage/lmgr.h
+++ b/src/include/storage/lmgr.h
@@ -38,6 +38,7 @@ extern void RelationInitLockInfo(Relation relation);
/* Lock a relation */
extern void LockRelationOid(Oid relid, LOCKMODE lockmode);
+extern bool CheckRelationLockedByUs(Oid relid, LOCKMODE lockmode);
extern bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode);
extern void UnlockRelationId(LockRelId *relid, LOCKMODE lockmode);
extern void UnlockRelationOid(Oid relid, LOCKMODE lockmode);
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index ff4df7fec5..b4a71ced0b 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -540,6 +540,7 @@ extern void LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks);
extern void LockReleaseSession(LOCKMETHODID lockmethodid);
extern void LockReleaseCurrentOwner(LOCALLOCK **locallocks, int nlocks);
extern void LockReassignCurrentOwner(LOCALLOCK **locallocks, int nlocks);
+extern bool LocalLockExists(const LOCKTAG *locktag, LOCKMODE lockmode);
extern bool LockHasWaiters(const LOCKTAG *locktag,
LOCKMODE lockmode, bool sessionLock);
extern VirtualTransactionId *GetLockConflicts(const LOCKTAG *locktag,
diff --git a/src/test/modules/test_rls_hooks/test_rls_hooks.c b/src/test/modules/test_rls_hooks/test_rls_hooks.c
index cab67a60aa..d455c97ef6 100644
--- a/src/test/modules/test_rls_hooks/test_rls_hooks.c
+++ b/src/test/modules/test_rls_hooks/test_rls_hooks.c
@@ -81,7 +81,7 @@ test_rls_hooks_permissive(CmdType cmdtype, Relation relation)
qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, relation, NULL, false,
- false);
+ false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
@@ -144,7 +144,7 @@ test_rls_hooks_restrictive(CmdType cmdtype, Relation relation)
qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, relation, NULL, false,
- false);
+ false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
--
2.11.0
v9-0002-Remove-useless-fields-from-planner-nodes.patchtext/plain; charset=UTF-8; name=v9-0002-Remove-useless-fields-from-planner-nodes.patchDownload
From 4ad70348d8fa0ef95052451aec88aa9e2076567e Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Thu, 27 Sep 2018 13:27:24 +1200
Subject: [PATCH v9 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 bool field called
'partitionedTarget', which is set if the target is a partitioned
table. The table itself is identified by targetRelation which
replaces nominalRelation.
* '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.
---
contrib/postgres_fdw/postgres_fdw.c | 2 +-
src/backend/commands/explain.c | 6 +--
src/backend/commands/portalcmds.c | 2 +-
src/backend/executor/execMain.c | 2 +-
src/backend/executor/execParallel.c | 3 +-
src/backend/executor/execPartition.c | 2 +-
src/backend/executor/execUtils.c | 55 --------------------
src/backend/executor/nodeAppend.c | 6 ---
src/backend/executor/nodeMergeAppend.c | 6 ---
src/backend/executor/nodeModifyTable.c | 9 ++--
src/backend/executor/spi.c | 4 +-
src/backend/nodes/copyfuncs.c | 9 ++--
src/backend/nodes/outfuncs.c | 15 ++----
src/backend/nodes/readfuncs.c | 9 ++--
src/backend/optimizer/plan/createplan.c | 46 ++++-------------
src/backend/optimizer/plan/planner.c | 89 +++++++++------------------------
src/backend/optimizer/plan/setrefs.c | 49 ++----------------
src/backend/optimizer/util/pathnode.c | 12 ++---
src/backend/tcop/utility.c | 15 ++++--
src/include/executor/executor.h | 2 -
src/include/nodes/plannodes.h | 30 ++++-------
src/include/nodes/relation.h | 10 ++--
src/include/optimizer/pathnode.h | 2 +-
23 files changed, 95 insertions(+), 290 deletions(-)
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 6cbba97c22..eeb053d5d8 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -2050,7 +2050,7 @@ postgresBeginForeignInsert(ModifyTableState *mtstate,
* Vars contained in those expressions.
*/
if (plan && plan->operation == CMD_UPDATE &&
- resultRelation == plan->nominalRelation)
+ resultRelation == plan->targetRelation)
resultRelation = mtstate->resultRelInfo[0].ri_RangeTableIndex;
}
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index ed6afe79a9..5ca7f69830 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -929,7 +929,7 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
break;
case T_ModifyTable:
*rels_used = bms_add_member(*rels_used,
- ((ModifyTable *) plan)->nominalRelation);
+ ((ModifyTable *) plan)->targetRelation);
if (((ModifyTable *) plan)->exclRelRTI)
*rels_used = bms_add_member(*rels_used,
((ModifyTable *) plan)->exclRelRTI);
@@ -2924,7 +2924,7 @@ ExplainScanTarget(Scan *plan, ExplainState *es)
static void
ExplainModifyTarget(ModifyTable *plan, ExplainState *es)
{
- ExplainTargetRel((Plan *) plan, plan->nominalRelation, es);
+ ExplainTargetRel((Plan *) plan, plan->targetRelation, es);
}
/*
@@ -3088,7 +3088,7 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors,
/* Should we explicitly label target relations? */
labeltargets = (mtstate->mt_nplans > 1 ||
(mtstate->mt_nplans == 1 &&
- mtstate->resultRelInfo->ri_RangeTableIndex != node->nominalRelation));
+ mtstate->resultRelInfo->ri_RangeTableIndex != node->targetRelation));
if (labeltargets)
ExplainOpenGroup("Target Tables", "Target Tables", false, es);
diff --git a/src/backend/commands/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 a9edc90a52..3c197c55f4 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -219,7 +219,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 7d8bd01994..15d8fcc352 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -176,6 +176,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;
@@ -183,7 +184,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
@@ -203,7 +203,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/execPartition.c b/src/backend/executor/execPartition.c
index 3be794b97d..1d2b3620ee 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -379,7 +379,7 @@ ExecInitPartitionInfo(ModifyTableState *mtstate,
leaf_part_rri = makeNode(ResultRelInfo);
InitResultRelInfo(leaf_part_rri,
partrel,
- node ? node->nominalRelation : 1,
+ node ? node->targetRelation : 1,
rootrel,
estate->es_instrument);
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 f81769ea85..b18f9e3164 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2255,18 +2255,17 @@ 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->partitionedTarget);
+ rte = rt_fetch(node->targetRelation, estate->es_range_table);
rel = heap_open(rte->relid, NoLock);
- InitResultRelInfo(mtstate->rootResultRelInfo, rel, root_rt_index,
- NULL, estate->es_instrument);
+ InitResultRelInfo(mtstate->rootResultRelInfo, rel,
+ node->targetRelation, NULL, estate->es_instrument);
}
mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 11ca800e4c..1bee240e72 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -1358,7 +1358,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
@@ -1374,7 +1374,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..da02b8961c 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);
@@ -203,8 +202,8 @@ _copyModifyTable(const ModifyTable *from)
*/
COPY_SCALAR_FIELD(operation);
COPY_SCALAR_FIELD(canSetTag);
- COPY_SCALAR_FIELD(nominalRelation);
- COPY_NODE_FIELD(partitioned_rels);
+ COPY_SCALAR_FIELD(targetRelation);
+ COPY_SCALAR_FIELD(partitionedTarget);
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 03d84aa0cd..2e6a5a1b42 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -272,6 +272,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);
@@ -280,11 +281,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);
@@ -375,8 +374,8 @@ _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(targetRelation);
+ WRITE_BOOL_FIELD(partitionedTarget);
WRITE_BOOL_FIELD(partColsUpdated);
WRITE_NODE_FIELD(resultRelations);
WRITE_INT_FIELD(resultRelIndex);
@@ -405,7 +404,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);
}
@@ -418,7 +416,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);
@@ -2178,8 +2175,8 @@ _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(targetRelation);
+ WRITE_BOOL_FIELD(partitionedTarget);
WRITE_BOOL_FIELD(partColsUpdated);
WRITE_NODE_FIELD(resultRelations);
WRITE_NODE_FIELD(subpaths);
@@ -2257,9 +2254,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 fc006e2830..aea5b0abc4 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1496,6 +1496,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);
@@ -1504,11 +1505,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);
@@ -1597,8 +1596,8 @@ _readModifyTable(void)
READ_ENUM_FIELD(operation, CmdType);
READ_BOOL_FIELD(canSetTag);
- READ_UINT_FIELD(nominalRelation);
- READ_NODE_FIELD(partitioned_rels);
+ READ_UINT_FIELD(targetRelation);
+ READ_BOOL_FIELD(partitionedTarget);
READ_BOOL_FIELD(partColsUpdated);
READ_NODE_FIELD(resultRelations);
READ_INT_FIELD(resultRelIndex);
@@ -1632,7 +1631,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();
@@ -1648,7 +1646,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..8f20e54d9e 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 targetRelation, bool partitionedTarget,
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;
@@ -2410,8 +2405,8 @@ create_modifytable_plan(PlannerInfo *root, ModifyTablePath *best_path)
plan = make_modifytable(root,
best_path->operation,
best_path->canSetTag,
- best_path->nominalRelation,
- best_path->partitioned_rels,
+ best_path->targetRelation,
+ best_path->partitionedTarget,
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 targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subplans, List *subroots,
List *withCheckOptionLists, List *returningLists,
@@ -6537,8 +6509,8 @@ make_modifytable(PlannerInfo *root,
node->operation = operation;
node->canSetTag = canSetTag;
- node->nominalRelation = nominalRelation;
- node->partitioned_rels = flatten_partitioned_rels(partitioned_rels);
+ node->targetRelation = targetRelation;
+ node->partitionedTarget = partitionedTarget;
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 22c010c19e..a927c0a1db 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -287,6 +287,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
Plan *top_plan;
ListCell *lp,
*lr;
+ bool hasRowMarks = (parse->rowMarks != NIL);
/*
* Set up global state for this planner invocation. This data is needed
@@ -301,9 +302,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;
@@ -501,9 +500,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) */
@@ -514,6 +511,8 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
PlannerInfo *subroot = lfirst_node(PlannerInfo, lr);
lfirst(lp) = set_plan_references(subroot, subplan);
+ if (subroot->rowMarks != NIL)
+ hasRowMarks = true;
}
/* build the PlannedStmt result */
@@ -523,6 +522,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
result->queryId = parse->queryId;
result->hasReturning = (parse->returningList != NIL);
result->hasModifyingCTE = parse->hasModifyingCTE;
+ result->hasRowMarks = hasRowMarks;
result->canSetTag = parse->canSetTag;
result->transientPlan = glob->transientPlan;
result->dependsOnRole = glob->dependsOnRole;
@@ -530,11 +530,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;
@@ -1169,7 +1167,7 @@ inheritance_planner(PlannerInfo *root)
int top_parentRTindex = parse->resultRelation;
Bitmapset *subqueryRTindexes;
Bitmapset *modifiableARIindexes;
- int nominalRelation = -1;
+ int targetRelation = -1;
List *final_rtable = NIL;
int save_rel_array_size = 0;
RelOptInfo **save_rel_array = NULL;
@@ -1184,8 +1182,7 @@ inheritance_planner(PlannerInfo *root)
ListCell *lc;
Index rti;
RangeTblEntry *parent_rte;
- Relids partitioned_relids = NULL;
- List *partitioned_rels = NIL;
+ bool partitionedTarget = false;
PlannerInfo *parent_root;
Query *parent_parse;
Bitmapset *parent_relids = bms_make_singleton(top_parentRTindex);
@@ -1248,25 +1245,14 @@ inheritance_planner(PlannerInfo *root)
}
/*
- * If the parent RTE is a partitioned table, we should use that as the
- * nominal relation, because the RTEs added for partitioned tables
- * (including the root parent) as child members of the inheritance set do
- * not appear anywhere else in the plan. The situation is exactly the
- * opposite in the case of non-partitioned inheritance parent as described
- * below. For the same reason, collect the list of descendant partitioned
- * tables to be saved in ModifyTable node, so that executor can lock those
- * as well.
+ * If the parent RTE is a partitioned table, set that as the target
+ * relation and mark that we're working with a partitioned target.
*/
parent_rte = rt_fetch(top_parentRTindex, root->parse->rtable);
if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
{
- nominalRelation = top_parentRTindex;
-
- /*
- * 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);
+ targetRelation = top_parentRTindex;
+ partitionedTarget = true;
}
/*
@@ -1338,7 +1324,7 @@ inheritance_planner(PlannerInfo *root)
* inheritance parent.
*/
subroot->inhTargetKind =
- partitioned_relids ? INHKIND_PARTITIONED : INHKIND_INHERITED;
+ partitionedTarget ? INHKIND_PARTITIONED : INHKIND_INHERITED;
/*
* If this child is further partitioned, remember it as a parent.
@@ -1363,17 +1349,17 @@ inheritance_planner(PlannerInfo *root)
}
/*
- * Set the nominal target relation of the ModifyTable node if not
- * already done. We use the inheritance parent RTE as the nominal
- * target relation if it's a partitioned table (see just above this
- * loop). In the non-partitioned parent case, we'll use the first
- * child relation (even if it's excluded) as the nominal target
- * relation. Because of the way expand_inherited_rtentry works, the
- * latter should be the RTE representing the parent table in its role
- * as a simple member of the inheritance set.
+ * Set the target relation of the ModifyTable node if not already
+ * done. We use the inheritance parent RTE as the target relation
+ * if it's a partitioned table (see just above this loop). In the
+ * non-partitioned parent case, we'll use the first child relation
+ * (even if it's excluded) as the target relation. Because of the way
+ * expand_inherited_rtentry works, the latter should be the RTE
+ * representing the parent table in its role as a simple member of
+ * the inheritance set.
*
* It would be logically cleaner to *always* use the inheritance
- * parent RTE as the nominal relation; but that RTE is not otherwise
+ * parent RTE as the target relation; but that RTE is not otherwise
* referenced in the plan in the non-partitioned inheritance case.
* Instead the duplicate child RTE created by expand_inherited_rtentry
* is used elsewhere in the plan, so using the original parent RTE
@@ -1383,8 +1369,8 @@ inheritance_planner(PlannerInfo *root)
* duplicate child RTE added for the parent does not appear anywhere
* else in the plan tree.
*/
- if (nominalRelation < 0)
- nominalRelation = appinfo->child_relid;
+ if (targetRelation < 0)
+ targetRelation = appinfo->child_relid;
/*
* The rowMarks list might contain references to subquery RTEs, so
@@ -1509,15 +1495,6 @@ inheritance_planner(PlannerInfo *root)
continue;
/*
- * Add the current parent's RT index to the partitioned_relids set if
- * we're creating the ModifyTable path for a partitioned root table.
- * (We only care about parents of non-excluded children.)
- */
- if (partitioned_relids)
- partitioned_relids = bms_add_member(partitioned_relids,
- appinfo->parent_relid);
-
- /*
* If this is the first non-excluded child, its post-planning rtable
* becomes the initial contents of final_rtable; otherwise, append
* just its modified subquery RTEs to final_rtable.
@@ -1620,29 +1597,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,
+ targetRelation,
+ partitionedTarget,
root->partColsUpdated,
resultRelations,
subpaths,
@@ -2219,7 +2180,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
parse->commandType,
parse->canSetTag,
parse->resultRelation,
- NIL,
+ false,
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..17d53f356c 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);
}
@@ -847,13 +827,9 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
fix_scan_list(root, splan->exclRelTlist, rtoffset);
}
- splan->nominalRelation += rtoffset;
+ splan->targetRelation += rtoffset;
splan->exclRelRTI += rtoffset;
- foreach(l, splan->partitioned_rels)
- {
- lfirst_int(l) += rtoffset;
- }
foreach(l, splan->resultRelations)
{
lfirst_int(l) += rtoffset;
@@ -884,24 +860,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->partitionedTarget)
{
- 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->targetRelation);
}
}
break;
@@ -915,10 +884,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 +902,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..73eca1d4d0 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -3291,10 +3291,8 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
* 'rel' is the parent relation associated with the result
* 'operation' is the operation type
* 'canSetTag' is true if we set the command tag/es_processed
- * 'nominalRelation' is the parent RT index for use of EXPLAIN
- * '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.
+ * 'targetRelation' is the target table's RT index
+ * 'partitionedTarget' true if 'targetRelation' is a partitioned table
* 'partColsUpdated' is true if any partitioning columns are being updated,
* either from the target relation or a descendent partitioned table.
* 'resultRelations' is an integer list of actual RT indexes of target rel(s)
@@ -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 targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subpaths,
List *subroots,
@@ -3376,8 +3374,8 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
pathnode->operation = operation;
pathnode->canSetTag = canSetTag;
- pathnode->nominalRelation = nominalRelation;
- pathnode->partitioned_rels = list_copy(partitioned_rels);
+ pathnode->targetRelation = targetRelation;
+ pathnode->partitionedTarget = partitionedTarget;
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..d0427c64ba 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
+ 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..27ae73e3d4 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 */
@@ -219,9 +212,10 @@ typedef struct ModifyTable
Plan plan;
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 targetRelation; /* RT index of the target table specified in
+ * the command or first child for inheritance
+ * tables */
+ bool partitionedTarget; /* is the target table partitioned? */
bool partColsUpdated; /* some part key in hierarchy updated */
List *resultRelations; /* integer list of RT indexes */
int resultRelIndex; /* index of first resultRel in plan's list */
@@ -259,9 +253,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 +265,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 +916,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..bcc2ba6db5 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 */
@@ -1716,9 +1713,10 @@ typedef struct ModifyTablePath
Path path;
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 targetRelation; /* RT index of the target table specified in
+ * the command or first child for inheritance
+ * tables */
+ bool partitionedTarget; /* is the target table partitioned? */
bool partColsUpdated; /* some part key in hierarchy updated */
List *resultRelations; /* integer list of RT indexes */
List *subpaths; /* Path(s) producing source data */
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 7c5ff22650..a45c2407d0 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -238,7 +238,7 @@ extern LockRowsPath *create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
extern ModifyTablePath *create_modifytable_path(PlannerInfo *root,
RelOptInfo *rel,
CmdType operation, bool canSetTag,
- Index nominalRelation, List *partitioned_rels,
+ Index targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subpaths,
List *subroots,
--
2.11.0
v9-0003-Prune-PlanRowMark-of-relations-that-are-pruned-fr.patchtext/plain; charset=UTF-8; name=v9-0003-Prune-PlanRowMark-of-relations-that-are-pruned-fr.patchDownload
From 67f72dc024244bd4c36d865bb0b5dd350c7f1c82 Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Thu, 27 Sep 2018 13:31:11 +1200
Subject: [PATCH v9 3/4] Prune PlanRowMark of relations that are pruned from a
plan
---
src/backend/optimizer/plan/planner.c | 32 ++++++++++++++++++++++++++------
1 file changed, 26 insertions(+), 6 deletions(-)
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index a927c0a1db..074ec9bf55 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -248,7 +248,7 @@ static bool group_by_has_partkey(RelOptInfo *input_rel,
List *targetList,
List *groupClause);
static int common_prefix_cmp(const void *a, const void *b);
-
+static List *get_nondummy_rowmarks(PlannerInfo *root);
/*****************************************************************************
*
@@ -1595,7 +1595,7 @@ inheritance_planner(PlannerInfo *root)
if (parse->rowMarks)
rowMarks = NIL;
else
- rowMarks = root->rowMarks;
+ rowMarks = get_nondummy_rowmarks(root);
/* Create Path representing a ModifyTable to do the UPDATE/DELETE work */
add_path(final_rel, (Path *)
@@ -2124,11 +2124,9 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
* is what goes into the LockRows node.)
*/
if (parse->rowMarks)
- {
path = (Path *) create_lockrows_path(root, final_rel, path,
- root->rowMarks,
+ get_nondummy_rowmarks(root),
SS_assign_special_param(root));
- }
/*
* If there is a LIMIT/OFFSET clause, add the LIMIT node.
@@ -2173,7 +2171,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
if (parse->rowMarks)
rowMarks = NIL;
else
- rowMarks = root->rowMarks;
+ rowMarks = get_nondummy_rowmarks(root);
path = (Path *)
create_modifytable_path(root, final_rel,
@@ -7219,3 +7217,25 @@ group_by_has_partkey(RelOptInfo *input_rel,
return true;
}
+
+/*
+ * get_nondummy_rowmarks
+ * Return a list of PlanRowMark's that reference non-dummy relations
+ */
+static List *
+get_nondummy_rowmarks(PlannerInfo *root)
+{
+ List *rowMarks = NIL;
+ ListCell *lc;
+
+ 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]))
+ rowMarks = lappend(rowMarks, rc);
+ }
+
+ return rowMarks;
+}
--
2.11.0
v9-0004-Revise-executor-range-table-relation-opening-clos.patchtext/plain; charset=UTF-8; name=v9-0004-Revise-executor-range-table-relation-opening-clos.patchDownload
From 944e715ff2aac4dcb1331679aea4dbfaf18c4b95 Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Thu, 27 Sep 2018 16:14:41 +1200
Subject: [PATCH v9 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, an arrangement which allows the executor
to have to heap_open any given range table relation only once.
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.
Accessed Relations are now also closed during ExecEndPlan(). Callers of
ExecRangeTableRelation() have no need to consider how their Relation
objects are cleaned up.
Authors: Amit Langote, David Rowley
---
contrib/postgres_fdw/postgres_fdw.c | 16 +++---
src/backend/commands/copy.c | 3 +-
src/backend/commands/trigger.c | 3 +-
src/backend/executor/README | 4 +-
src/backend/executor/execExprInterp.c | 7 +--
src/backend/executor/execMain.c | 81 +++++++++--------------------
src/backend/executor/execPartition.c | 39 +++-----------
src/backend/executor/execUtils.c | 68 +++++++++++++++---------
src/backend/executor/nodeAppend.c | 6 ---
src/backend/executor/nodeBitmapHeapscan.c | 7 ---
src/backend/executor/nodeCustom.c | 4 --
src/backend/executor/nodeForeignscan.c | 4 --
src/backend/executor/nodeIndexonlyscan.c | 7 ---
src/backend/executor/nodeIndexscan.c | 7 ---
src/backend/executor/nodeLockRows.c | 2 +-
src/backend/executor/nodeMergeAppend.c | 6 ---
src/backend/executor/nodeModifyTable.c | 26 +++++----
src/backend/executor/nodeSamplescan.c | 5 --
src/backend/executor/nodeSeqscan.c | 7 ---
src/backend/executor/nodeTidscan.c | 5 --
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/tablesync.c | 9 +++-
src/backend/replication/logical/worker.c | 2 +
src/include/executor/execPartition.h | 1 -
src/include/executor/executor.h | 24 ++++++++-
src/include/nodes/execnodes.h | 23 +++++++-
src/include/nodes/plannodes.h | 2 +-
src/include/parser/parsetree.h | 10 ----
32 files changed, 195 insertions(+), 224 deletions(-)
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index eeb053d5d8..d20c75367c 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. */
@@ -1731,8 +1731,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,
@@ -2036,7 +2036,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);
@@ -2396,7 +2396,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. */
@@ -2546,10 +2546,6 @@ postgresEndDirectModify(ForeignScanState *node)
ReleaseConnection(dmstate->conn);
dmstate->conn = NULL;
- /* close the target relation. */
- if (dmstate->resultRel)
- ExecCloseScanRelation(dmstate->resultRel);
-
/* MemoryContext will be deleted automatically. */
}
@@ -5756,7 +5752,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 0c4a7b6f4f..57efb20d20 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -2483,7 +2483,8 @@ 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;
+
+ ExecInitRangeTable(estate, cstate->range_table);
/* 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 34f9db93d5..f0d45844c1 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/README b/src/backend/executor/README
index 0d7cd552eb..30df410e0e 100644
--- a/src/backend/executor/README
+++ b/src/backend/executor/README
@@ -267,8 +267,8 @@ This is a sketch of control flow for full query processing:
Per above comments, it's not really critical for ExecEndNode to free any
memory; it'll all go away in FreeExecutorState anyway. However, we do need to
-be careful to close relations, drop buffer pins, etc, so we do need to scan
-the plan state tree to find these sorts of resources.
+be careful to drop buffer pins, etc, so we do need to scan the plan state tree
+to find these sorts of resources.
The executor can also be used to evaluate simple expressions without any Plan
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index f597363eb1..f8ca60ae5a 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3934,10 +3934,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 3c197c55f4..d895ed29d1 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -111,9 +111,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 */
@@ -837,28 +837,16 @@ 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 the necessary lock on the relation
- * has already been taken. That can only however be true in the
- * parallel leader.
- */
- Assert(rte->lockmode != NoLock);
- if (!IsParallelWorker() &&
- !CheckRelationLockedByUs(rte->relid, rte->lockmode))
- elog(WARNING, "InitPlan: lock on \"%s\" not already taken",
- get_rel_name(rte->relid));
- }
- }
-#endif
+ ExecInitRangeTable(estate, rangeTable);
/*
+ * Allocate an array to store open Relations of each rangeTable item. We
+ * zero-fill this for now. The Relations are only opened and stored here
+ * the first time they're required during node initialization.
+ */
+ estate->es_relations = (Relation *) palloc0(estate->es_range_table_size *
+ sizeof(Relation));
+ /*
* initialize the node's execution state
*/
estate->es_range_table = rangeTable;
@@ -1501,6 +1489,14 @@ static void
ExecEndPlan(PlanState *planstate, EState *estate)
{
ListCell *l;
+ int i;
+
+ /* Close range table relations. */
+ for (i = 0; i < estate->es_range_table_size; i++)
+ {
+ if (estate->es_relations[i])
+ heap_close(estate->es_relations[i], NoLock);
+ }
/*
* shut down the node-type-specific query processing
@@ -1527,18 +1523,6 @@ ExecEndPlan(PlanState *planstate, EState *estate)
/* likewise close any trigger target relations */
ExecCleanUpTriggerState(estate);
-
- /*
- * 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);
- }
}
/* ----------------------------------------------------------------
@@ -2295,24 +2279,20 @@ 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);
-
switch (rc->markType)
{
case ROW_MARK_EXCLUSIVE:
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 */
@@ -2330,7 +2310,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;
@@ -2988,7 +2968,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));
@@ -3041,7 +3021,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();
@@ -3065,6 +3045,9 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree)
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_range_table_size = parentestate->es_range_table_size;
+ 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;
@@ -3218,18 +3201,6 @@ 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 1d2b3620ee..7fb34d2173 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -861,11 +861,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++)
{
@@ -1418,9 +1417,6 @@ adjust_partition_tlist(List *tlist, TupleConversionMap *map)
* functions. Details stored include how to map the partition index
* returned by the partition pruning code into subplan indexes.
*
- * ExecDestroyPartitionPruneState:
- * Deletes a PartitionPruneState. Must be called during executor shutdown.
- *
* ExecFindInitialMatchingSubPlans:
* Returns indexes of matching subplans. Partition pruning is attempted
* without any evaluation of expressions containing PARAM_EXEC Params.
@@ -1462,6 +1458,7 @@ PartitionPruneState *
ExecCreatePartitionPruneState(PlanState *planstate,
PartitionPruneInfo *partitionpruneinfo)
{
+ EState *estate = planstate->state;
PartitionPruneState *prunestate;
int n_part_hierarchies;
ListCell *lc;
@@ -1542,7 +1539,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);
@@ -1623,30 +1620,6 @@ ExecCreatePartitionPruneState(PlanState *planstate,
}
/*
- * ExecDestroyPartitionPruneState
- * Release resources at plan shutdown.
- *
- * We don't bother to free any memory here, since the whole executor context
- * will be going away shortly. We do need to release our relcache pins.
- */
-void
-ExecDestroyPartitionPruneState(PartitionPruneState *prunestate)
-{
- PartitionPruningData **partprunedata = prunestate->partprunedata;
- int i;
-
- for (i = 0; i < prunestate->num_partprunedata; i++)
- {
- PartitionPruningData *prunedata = partprunedata[i];
- PartitionedRelPruningData *pprune = prunedata->partrelprunedata;
- int j;
-
- for (j = 0; j < prunedata->num_partrelprunedata; j++)
- relation_close(pprune[j].context.partrel, NoLock);
- }
-}
-
-/*
* ExecFindInitialMatchingSubPlans
* Identify the set of subplans that cannot be eliminated by initial
* pruning (disregarding any pruning constraints involving PARAM_EXEC
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index d32796aac3..c7f82c83a3 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -25,7 +25,6 @@
* etc
*
* ExecOpenScanRelation Common code for scan node init routines.
- * ExecCloseScanRelation
*
* executor_errposition Report syntactic position of an error.
*
@@ -35,6 +34,8 @@
* GetAttributeByName Runtime extraction of columns from tuples.
* GetAttributeByNum
*
+ * ExecInitRangeTable Build an array from the range table list to
+ * allow faster lookups by relid.
* NOTES
* This file has traditionally been the place to stick misc.
* executor support stuff that doesn't really go anyplace else.
@@ -653,11 +654,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
@@ -675,26 +674,6 @@ ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
return rel;
}
-/* ----------------------------------------------------------------
- * ExecCloseScanRelation
- *
- * Close the heap relation scanned by a base-level scan plan node.
- * This should be called during the node's ExecEnd routine.
- *
- * Currently, we do not release the lock acquired by ExecOpenScanRelation.
- * This lock should be held till end of transaction. (There is a faction
- * that considers this too much locking, however.)
- *
- * If we did want to release the lock, we'd have to repeat the logic in
- * ExecOpenScanRelation in order to figure out what to release.
- * ----------------------------------------------------------------
- */
-void
-ExecCloseScanRelation(Relation scanrel)
-{
- heap_close(scanrel, NoLock);
-}
-
/*
* UpdateChangedParamSet
* Add changed parameters to a plan node's chgParam set
@@ -997,3 +976,44 @@ ExecCleanTargetListLength(List *targetlist)
}
return len;
}
+
+/*
+ * Initialize executor's range table array
+ */
+void
+ExecInitRangeTable(EState *estate, List *rangeTable)
+{
+ int rti;
+ ListCell *l;
+
+#ifdef USE_ASSERT_CHECKING
+ foreach(l, rangeTable)
+ {
+ RangeTblEntry *rte = lfirst(l);
+
+ if (rte->rtekind == RTE_RELATION && OidIsValid(rte->relid))
+ {
+ /*
+ * The following verifies that the necessary lock on the relation
+ * has already been taken. That can only however be true in the
+ * parallel leader.
+ */
+ Assert(rte->lockmode != NoLock);
+ if (!IsParallelWorker() &&
+ !CheckRelationLockedByUs(rte->relid, rte->lockmode))
+ elog(WARNING, "lock on \"%s\" not already taken",
+ get_rel_name(rte->relid));
+ }
+ }
+#endif
+
+ Assert(estate != NULL);
+ 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 *));
+ rti = 0;
+ foreach(l, rangeTable)
+ estate->es_range_table_array[rti++] = lfirst_node(RangeTblEntry, l);
+}
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index eb587be221..a16b6da474 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -329,12 +329,6 @@ ExecEndAppend(AppendState *node)
*/
for (i = 0; i < nplans; i++)
ExecEndNode(appendplans[i]);
-
- /*
- * release any resources associated with run-time pruning
- */
- if (node->as_prune_state)
- ExecDestroyPartitionPruneState(node->as_prune_state);
}
void
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index baffae27e3..5307cd1b87 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -785,13 +785,11 @@ ExecReScanBitmapHeapScan(BitmapHeapScanState *node)
void
ExecEndBitmapHeapScan(BitmapHeapScanState *node)
{
- Relation relation;
HeapScanDesc scanDesc;
/*
* extract information from the node
*/
- relation = node->ss.ss_currentRelation;
scanDesc = node->ss.ss_currentScanDesc;
/*
@@ -832,11 +830,6 @@ ExecEndBitmapHeapScan(BitmapHeapScanState *node)
* close heap scan
*/
heap_endscan(scanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index b816e0b31d..9a33eda688 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -126,10 +126,6 @@ ExecEndCustomScan(CustomScanState *node)
/* Clean out the tuple table */
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /* Close the heap relation */
- if (node->ss.ss_currentRelation)
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
void
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index a2a28b7ec2..cf7df72d8c 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -258,10 +258,6 @@ ExecEndForeignScan(ForeignScanState *node)
/* clean out the tuple table */
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /* close the relation. */
- if (node->ss.ss_currentRelation)
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 4b6d531810..1b530cea40 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -373,14 +373,12 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node)
{
Relation indexRelationDesc;
IndexScanDesc indexScanDesc;
- Relation relation;
/*
* extract information from the node
*/
indexRelationDesc = node->ioss_RelationDesc;
indexScanDesc = node->ioss_ScanDesc;
- relation = node->ss.ss_currentRelation;
/* Release VM buffer pin, if any. */
if (node->ioss_VMBuffer != InvalidBuffer)
@@ -411,11 +409,6 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node)
index_endscan(indexScanDesc);
if (indexRelationDesc)
index_close(indexRelationDesc, NoLock);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 6285a2114e..786e7ac25c 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -802,14 +802,12 @@ ExecEndIndexScan(IndexScanState *node)
{
Relation indexRelationDesc;
IndexScanDesc indexScanDesc;
- Relation relation;
/*
* extract information from the node
*/
indexRelationDesc = node->iss_RelationDesc;
indexScanDesc = node->iss_ScanDesc;
- relation = node->ss.ss_currentRelation;
/*
* Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
@@ -833,11 +831,6 @@ ExecEndIndexScan(IndexScanState *node)
index_endscan(indexScanDesc);
if (indexRelationDesc)
index_close(indexRelationDesc, NoLock);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index efbf4bd18a..ff9606342b 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/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index d8e0978966..5d0dbb8146 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -363,12 +363,6 @@ ExecEndMergeAppend(MergeAppendState *node)
*/
for (i = 0; i < nplans; i++)
ExecEndNode(mergeplans[i]);
-
- /*
- * release any resources associated with run-time pruning
- */
- if (node->ms_prune_state)
- ExecDestroyPartitionPruneState(node->ms_prune_state);
}
void
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index b18f9e3164..c837d36a87 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,17 +2254,18 @@ 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->partitionedTarget);
- rte = rt_fetch(node->targetRelation, estate->es_range_table);
- rel = heap_open(rte->relid, NoLock);
- InitResultRelInfo(mtstate->rootResultRelInfo, rel,
- node->targetRelation, NULL, estate->es_instrument);
+ rel = ExecRangeTableRelation(estate, node->targetRelation);
+ InitResultRelInfo(mtstate->rootResultRelInfo,
+ rel,
+ node->targetRelation,
+ NULL,
+ estate->es_instrument);
}
mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
@@ -2722,15 +2722,13 @@ ExecEndModifyTable(ModifyTableState *node)
resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
resultRelInfo);
- /* Close indices and then the relation itself */
+ /*
+ * Close the ResultRelInfo's indexes. The relation itself
+ * is handled by the executor cleanup code.
+ */
ExecCloseIndices(resultRelInfo);
- heap_close(resultRelInfo->ri_RelationDesc, NoLock);
}
- /* 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/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index 99528be84a..92ff68a764 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -222,11 +222,6 @@ ExecEndSampleScan(SampleScanState *node)
*/
if (node->ss.ss_currentScanDesc)
heap_endscan(node->ss.ss_currentScanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index cd53491be0..92ff1e50ed 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -201,13 +201,11 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
void
ExecEndSeqScan(SeqScanState *node)
{
- Relation relation;
HeapScanDesc scanDesc;
/*
* get information from node
*/
- relation = node->ss.ss_currentRelation;
scanDesc = node->ss.ss_currentScanDesc;
/*
@@ -226,11 +224,6 @@ ExecEndSeqScan(SeqScanState *node)
*/
if (scanDesc != NULL)
heap_endscan(scanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index 0cb1946a3e..8cae56f48c 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -489,11 +489,6 @@ ExecEndTidScan(TidScanState *node)
*/
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index da02b8961c..dd76284676 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 2e6a5a1b42..6aefdd8bc4 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1029,7 +1029,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 aea5b0abc4..30609c96e6 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -2373,7 +2373,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 17d53f356c..ee01ef82d2 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -890,6 +890,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:
@@ -908,6 +923,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 e1ce8b4ddc..1763dd67a3 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/tablesync.c b/src/backend/replication/logical/tablesync.c
index 905a983074..d72f6a1b4f 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -795,7 +795,14 @@ copy_table(Relation rel)
copybuf = makeStringInfo();
pstate = make_parsestate(NULL);
- addRangeTableEntryForRelation(pstate, rel, NULL, false, false, NoLock);
+
+ /*
+ * Caller LogicalRepSyncTableStart took RowExclusiveLock, which we must
+ * record in the RTE being built, because executor initialization invoked
+ * by copy.c expects it.
+ */
+ addRangeTableEntryForRelation(pstate, rel, NULL, false, false,
+ RowExclusiveLock);
attnamelist = make_copy_attnamelist(relmapentry);
cstate = BeginCopyFrom(pstate, rel, NULL, false, copy_read_data, attnamelist, NIL);
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 42345f94d3..c63de66857 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -200,6 +200,8 @@ create_estate_for_relation(LogicalRepRelMapEntry *rel)
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/execPartition.h b/src/include/executor/execPartition.h
index 89ce53815c..04847d639d 100644
--- a/src/include/executor/execPartition.h
+++ b/src/include/executor/execPartition.h
@@ -197,7 +197,6 @@ extern void ExecCleanupTupleRouting(ModifyTableState *mtstate,
PartitionTupleRouting *proute);
extern PartitionPruneState *ExecCreatePartitionPruneState(PlanState *planstate,
PartitionPruneInfo *partitionpruneinfo);
-extern void ExecDestroyPartitionPruneState(PartitionPruneState *prunestate);
extern Bitmapset *ExecFindMatchingSubPlans(PartitionPruneState *prunestate);
extern Bitmapset *ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate,
int nsubplans);
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 1d2b48fe09..b03d8c591f 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"
/*
@@ -478,6 +479,7 @@ extern ExprContext *CreateExprContext(EState *estate);
extern ExprContext *CreateStandaloneExprContext(void);
extern void FreeExprContext(ExprContext *econtext, bool isCommit);
extern void ReScanExprContext(ExprContext *econtext);
+extern void ExecInitRangeTable(EState *estate, List *rangeTable);
#define ResetExprContext(econtext) \
MemoryContextReset((econtext)->ecxt_per_tuple_memory)
@@ -513,7 +515,6 @@ extern void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate
extern bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid);
extern Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags);
-extern void ExecCloseScanRelation(Relation scanrel);
extern int executor_errposition(EState *estate, int location);
@@ -568,4 +569,25 @@ 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)
+{
+ Relation rel = estate->es_relations[rti - 1];
+
+ if (rel == NULL)
+ {
+ RangeTblEntry *rte = exec_rt_fetch(rti, estate->es_range_table_array);
+
+ /*
+ * No need to lock the relation. Locks were already
+ * obtained by the upstream code.
+ */
+ rel = estate->es_relations[rti - 1] = heap_open(rte->relid, NoLock);
+ }
+
+ return rel;
+}
+#endif
+
#endif /* EXECUTOR_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 03ad516976..639235d622 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,11 @@ 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 Relations
+ * es_range_table_size elements in length. */
PlannedStmt *es_plannedstmt; /* link to top of plan tree */
const char *es_sourceText; /* Source text from QueryDesc */
@@ -579,6 +584,22 @@ typedef struct EState
struct JitInstrumentation *es_jit_combined_instr;
} 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]
+
+/*
+ * 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 27ae73e3d4..452627dd03 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -1093,7 +1093,7 @@ typedef struct PartitionPruneInfo
typedef struct PartitionedRelPruneInfo
{
NodeTag type;
- Oid reloid; /* OID of partition rel for this level */
+ Index rtindex; /* Partition table's RT index */
List *pruning_steps; /* List of PartitionPruneStep, see below */
Bitmapset *present_parts; /* Indexes of all partitions which subplans or
* subparts are present for. */
diff --git a/src/include/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
Hi,
On 9/28/18 4:58 AM, Amit Langote wrote:
Okay, I've revised the text in the attached updated patch.
Meh, I just noticed that the WARNING text claims "InitPlan" is the
function name. I think it's best to get rid of that. It's pretty much
redundant anyway if you do: \set VERBOSITY verboseOops, good catch that one. Removed "InitPlan: " from the message in the
attached.
I have looked at the patch (v9), and have no further comments. I can
confirm a speedup in the SELECT FOR SHARE case.
Thanks for working on this !
Best regards,
Jesper
On 2018-Sep-28, Amit Langote wrote:
On 2018/09/28 17:48, David Rowley wrote:
Meh, I just noticed that the WARNING text claims "InitPlan" is the
function name. I think it's best to get rid of that. It's pretty much
redundant anyway if you do: \set VERBOSITY verboseOops, good catch that one. Removed "InitPlan: " from the message in the
attached.
Were there two cases of that? Because one still remains.
--
�lvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
On 29 September 2018 at 03:49, Alvaro Herrera <alvherre@2ndquadrant.com> wrote:
On 2018-Sep-28, Amit Langote wrote:
On 2018/09/28 17:48, David Rowley wrote:
Meh, I just noticed that the WARNING text claims "InitPlan" is the
function name. I think it's best to get rid of that. It's pretty much
redundant anyway if you do: \set VERBOSITY verboseOops, good catch that one. Removed "InitPlan: " from the message in the
attached.Were there two cases of that? Because one still remains.
Yeah, 0001 added it and 0004 removed it again replacing it with the
corrected version.
I've attached v10 which fixes this and aligns the WARNING text in
ExecInitRangeTable() and addRangeTableEntryForRelation().
--
David Rowley http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
Attachments:
v10-0001-Don-t-lock-range-table-relations-in-the-executor.patchapplication/octet-stream; name=v10-0001-Don-t-lock-range-table-relations-in-the-executor.patchDownload
From f20a0155ce0787d1620ace0dd30771ec5bcf9192 Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Sat, 29 Sep 2018 12:30:40 +1200
Subject: [PATCH v10 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/catalog/heap.c | 3 +-
src/backend/commands/copy.c | 7 +-
src/backend/commands/policy.c | 17 +-
src/backend/commands/tablecmds.c | 3 +-
src/backend/commands/trigger.c | 6 +-
src/backend/commands/view.c | 6 +-
src/backend/executor/execMain.c | 275 ++++++++---------------
src/backend/executor/execPartition.c | 4 +-
src/backend/executor/execUtils.c | 24 +-
src/backend/executor/nodeLockRows.c | 4 +-
src/backend/executor/nodeModifyTable.c | 42 +++-
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 | 3 +-
src/backend/parser/parse_clause.c | 3 +-
src/backend/parser/parse_relation.c | 17 +-
src/backend/parser/parse_utilcmd.c | 18 +-
src/backend/replication/logical/tablesync.c | 2 +-
src/backend/rewrite/rewriteHandler.c | 20 +-
src/backend/storage/lmgr/lmgr.c | 15 ++
src/backend/storage/lmgr/lock.c | 24 ++
src/backend/utils/cache/plancache.c | 30 +--
src/include/executor/executor.h | 2 +-
src/include/nodes/parsenodes.h | 5 +
src/include/parser/parse_relation.h | 4 +-
src/include/storage/lmgr.h | 1 +
src/include/storage/lock.h | 1 +
src/test/modules/test_rls_hooks/test_rls_hooks.c | 4 +-
30 files changed, 261 insertions(+), 283 deletions(-)
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 9176f6280b..19b530ac94 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -2551,7 +2551,8 @@ AddRelationNewConstraints(Relation rel,
rel,
NULL,
false,
- true);
+ true,
+ NoLock);
addRTEtoQuery(pstate, rte, true, true, true);
/*
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index d06662bd32..0c4a7b6f4f 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -837,16 +837,17 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
List *attnums;
ListCell *cur;
RangeTblEntry *rte;
+ LOCKMODE lockmode = is_from ? RowExclusiveLock : AccessShareLock;
Assert(!stmt->query);
/* Open and lock the relation, using the appropriate lock type. */
- rel = heap_openrv(stmt->relation,
- (is_from ? RowExclusiveLock : AccessShareLock));
+ rel = heap_openrv(stmt->relation, lockmode);
relid = RelationGetRelid(rel);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, false);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, false,
+ lockmode);
rte->requiredPerms = (is_from ? ACL_INSERT : ACL_SELECT);
tupDesc = RelationGetDescr(rel);
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index cee0ef915b..2949b4e6d7 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -567,7 +567,8 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
qual_expr = stringToNode(qual_value);
/* Add this rel to the parsestate's rangetable, for dependencies */
- addRangeTableEntryForRelation(qual_pstate, rel, NULL, false, false);
+ addRangeTableEntryForRelation(qual_pstate, rel, NULL, false, false,
+ AccessExclusiveLock);
qual_parse_rtable = qual_pstate->p_rtable;
free_parsestate(qual_pstate);
@@ -590,7 +591,7 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(with_check_pstate, rel, NULL, false,
- false);
+ false, AccessExclusiveLock);
with_check_parse_rtable = with_check_pstate->p_rtable;
free_parsestate(with_check_pstate);
@@ -752,12 +753,12 @@ CreatePolicy(CreatePolicyStmt *stmt)
/* Add for the regular security quals */
rte = addRangeTableEntryForRelation(qual_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
/* Add for the with-check quals */
rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(with_check_pstate, rte, false, true, true);
qual = transformWhereClause(qual_pstate,
@@ -928,7 +929,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
ParseState *qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
@@ -950,7 +951,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
ParseState *with_check_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
- NULL, false, false);
+ NULL, false, false, NoLock);
addRTEtoQuery(with_check_pstate, rte, false, true, true);
@@ -1097,7 +1098,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(qual_pstate, target_table, NULL,
- false, false);
+ false, false, NoLock);
qual_parse_rtable = qual_pstate->p_rtable;
free_parsestate(qual_pstate);
@@ -1138,7 +1139,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
/* Add this rel to the parsestate's rangetable, for dependencies */
addRangeTableEntryForRelation(with_check_pstate, target_table, NULL,
- false, false);
+ false, false, NoLock);
with_check_parse_rtable = with_check_pstate->p_rtable;
free_parsestate(with_check_pstate);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 29d8353779..5afa54389a 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -13632,7 +13632,8 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
* rangetable entry. We need a ParseState for transformExpr.
*/
pstate = make_parsestate(NULL);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true,
+ NoLock);
addRTEtoQuery(pstate, rte, true, true, true);
/* take care of any partition expressions */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 36778b6f4d..34f9db93d5 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -578,11 +578,13 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
*/
rte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ ShareRowExclusiveLock);
addRTEtoQuery(pstate, rte, false, true, true);
rte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ ShareRowExclusiveLock);
addRTEtoQuery(pstate, rte, false, true, true);
/* Transform expression. Copy to be sure we don't modify original */
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index ffb71c0ea7..4c379fd83b 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -387,10 +387,12 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
*/
rt_entry1 = addRangeTableEntryForRelation(pstate, viewRel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessShareLock);
rt_entry2 = addRangeTableEntryForRelation(pstate, viewRel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ 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 5443cbf67d..e5612c4707 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -52,10 +52,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"
@@ -835,99 +837,49 @@ 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 the necessary lock on the relation
+ * has already been taken. That can only however be true in the
+ * parallel leader.
+ */
+ Assert(rte->lockmode != NoLock);
+ if (!IsParallelWorker() &&
+ !CheckRelationLockedByUs(rte->relid, rte->lockmode))
+ elog(WARNING, "lock is not held on relation \"%s\"",
+ get_rel_name(rte->relid));
+ }
+ }
+#endif
+
/*
* initialize the node's execution state
*/
estate->es_range_table = rangeTable;
estate->es_plannedstmt = plannedstmt;
- /*
- * initialize result relation stuff, and open/lock the result rels.
- *
- * We must do this before initializing the plan tree, else we might try to
- * do a lock upgrade if a result rel is also a source rel.
- */
+ /* Allocate memory required for result relations */
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
{
@@ -941,73 +893,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.
@@ -1614,8 +1500,6 @@ ExecPostprocessPlan(EState *estate)
static void
ExecEndPlan(PlanState *planstate, EState *estate)
{
- ResultRelInfo *resultRelInfo;
- int i;
ListCell *l;
/*
@@ -1641,26 +1525,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);
@@ -2421,25 +2285,64 @@ ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
}
/*
- * ExecFindRowMark -- find the ExecRowMark struct for given rangetable index
+ * ExecBuildRowMark -- create and return an ExecRowMark struct for the given
+ * PlanRowMark.
*
- * If no such struct, either return NULL or throw error depending on missing_ok
+ * The created ExecRowMark is also added to the list of rowmarks in the given
+ * EState.
*/
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)
- {
- ExecRowMark *erm = (ExecRowMark *) lfirst(lc);
+ Assert(!rc->isParent);
- if (erm->rti == rti)
- return erm;
+ /* get relation's OID (will produce InvalidOid if subquery) */
+ relid = getrelid(rc->rti, estate->es_range_table);
+
+ switch (rc->markType)
+ {
+ 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;
}
/*
@@ -3179,7 +3082,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 */
@@ -3315,6 +3218,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 ec7a5267c3..3be794b97d 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -1540,9 +1540,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..efbf4bd18a 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -424,8 +424,8 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
/* safety check on size of lr_curtuples array */
Assert(rc->rti > 0 && rc->rti <= lrstate->lr_ntables);
- /* find ExecRowMark and build ExecAuxRowMark */
- erm = ExecFindRowMark(estate, rc->rti, false);
+ /* build the ExecRowMark and ExecAuxRowMark */
+ erm = ExecBuildRowMark(estate, rc);
aerm = ExecBuildAuxRowMark(erm, outerPlan->targetlist);
/*
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index bf0d5e8edb..f81769ea85 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;
@@ -2529,8 +2554,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
if (rc->isParent)
continue;
- /* find ExecRowMark (same for all subplans) */
- erm = ExecFindRowMark(estate, rc->rti, false);
+ /* build the ExecRowMark (same for all subplans) */
+ erm = ExecBuildRowMark(estate, rc);
/* build ExecAuxRowMark for each subplan */
for (i = 0; i < nplans; i++)
@@ -2686,20 +2711,27 @@ ExecEndModifyTable(ModifyTableState *node)
{
int i;
- /*
- * Allow any FDWs to shut down
- */
+ /* Perform cleanup. */
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);
}
+ /* 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 93f1e2c4eb..03d84aa0cd 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -3131,6 +3131,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 519deab63a..fc006e2830 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1361,6 +1361,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 c020600955..ce0262d170 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -1038,7 +1038,8 @@ transformOnConflictClause(ParseState *pstate,
exclRte = addRangeTableEntryForRelation(pstate,
targetrel,
makeAlias("excluded", NIL),
- false, false);
+ false, false,
+ RowExclusiveLock);
exclRte->relkind = RELKIND_COMPOSITE_TYPE;
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 d6b93f55df..689ac72c3f 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -217,7 +217,8 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
* Now build an RTE.
*/
rte = addRangeTableEntryForRelation(pstate, pstate->p_target_relation,
- relation->alias, inh, false);
+ relation->alias, inh, false,
+ 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 60b8de0f95..a41f1620b1 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -28,6 +28,7 @@
#include "parser/parse_enr.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
+#include "storage/lmgr.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
@@ -1217,6 +1218,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
@@ -1262,23 +1264,36 @@ addRangeTableEntry(ParseState *pstate,
*
* This is just like addRangeTableEntry() except that it makes an RTE
* given an already-open relation instead of a RangeVar reference.
+ *
+ * 'lockmode' is the lock taken on 'rel'. The caller may pass NoLock if the
+ * RTE won't be passed to the executor, that is, won't be part of a
+ * PlannedStmt.
*/
RangeTblEntry *
addRangeTableEntryForRelation(ParseState *pstate,
Relation rel,
Alias *alias,
bool inh,
- bool inFromCl)
+ bool inFromCl,
+ LOCKMODE lockmode)
{
RangeTblEntry *rte = makeNode(RangeTblEntry);
char *refname = alias ? alias->aliasname : RelationGetRelationName(rel);
Assert(pstate != NULL);
+#ifdef USE_ASSERT_CHECKING
+ if (lockmode != NoLock &&
+ !CheckRelationLockedByUs(RelationGetRelid(rel), lockmode))
+ elog(WARNING, "lock is not held on relation \"%s\"",
+ RelationGetRelationName(rel));
+#endif
+
rte->rtekind = RTE_RELATION;
rte->alias = alias;
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 f5c1e2a0d7..5df0348f1c 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -2526,7 +2526,8 @@ transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
* relation, but we still need to open it.
*/
rel = relation_open(relid, NoLock);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
+ rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true,
+ NoLock);
/* no to join list, yes to namespaces */
addRTEtoQuery(pstate, rte, false, true, true);
@@ -2636,10 +2637,12 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
*/
oldrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessExclusiveLock);
newrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ AccessExclusiveLock);
/* Must override addRangeTableEntry's default access-check flags */
oldrte->requiredPerms = 0;
newrte->requiredPerms = 0;
@@ -2734,10 +2737,12 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
*/
oldrte = addRangeTableEntryForRelation(sub_pstate, rel,
makeAlias("old", NIL),
- false, false);
+ false, false,
+ AccessExclusiveLock);
newrte = addRangeTableEntryForRelation(sub_pstate, rel,
makeAlias("new", NIL),
- false, false);
+ false, false,
+ AccessExclusiveLock);
oldrte->requiredPerms = 0;
newrte->requiredPerms = 0;
addRTEtoQuery(sub_pstate, oldrte, false, true, false);
@@ -2940,7 +2945,8 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
rel,
NULL,
false,
- true);
+ true,
+ NoLock);
addRTEtoQuery(pstate, rte, false, true, true);
/* Set up CreateStmtContext */
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index acc6498567..905a983074 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -795,7 +795,7 @@ copy_table(Relation rel)
copybuf = makeStringInfo();
pstate = make_parsestate(NULL);
- addRangeTableEntryForRelation(pstate, rel, NULL, false, false);
+ addRangeTableEntryForRelation(pstate, rel, NULL, false, false, NoLock);
attnamelist = make_copy_attnamelist(relmapentry);
cstate = BeginCopyFrom(pstate, rel, NULL, false, copy_read_data, attnamelist, NIL);
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 327e5c33d7..6562ac60b1 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,
@@ -2898,6 +2884,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
@@ -3103,7 +3090,8 @@ rewriteTargetView(Query *parsetree, Relation view)
base_rel,
makeAlias("excluded",
NIL),
- false, false);
+ false, false,
+ RowExclusiveLock);
new_exclRte->relkind = RELKIND_COMPOSITE_TYPE;
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 dc0a439638..2d8eae62e6 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -135,6 +135,21 @@ LockRelationOid(Oid relid, LOCKMODE lockmode)
}
}
+/*
+ * CheckRelationLockedByUs
+ *
+ * Returns true we hold a lock on 'relid' with 'lockmode'.
+ */
+bool
+CheckRelationLockedByUs(Oid relid, LOCKMODE lockmode)
+{
+ LOCKTAG tag;
+
+ SetLocktagRelationOid(&tag, relid);
+
+ return LocalLockExists(&tag, lockmode);
+}
+
/*
* ConditionalLockRelationOid
*
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 831ae62525..8c140fe4b0 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -563,6 +563,30 @@ DoLockModesConflict(LOCKMODE mode1, LOCKMODE mode2)
return false;
}
+/*
+ * LocalLockExists -- check if a log with 'locktag' is held locally with
+ * 'lockmode'
+ */
+bool
+LocalLockExists(const LOCKTAG *locktag, LOCKMODE lockmode)
+{
+ LOCALLOCKTAG localtag;
+ bool found;
+
+ MemSet(&localtag, 0, sizeof(localtag)); /* must clear padding */
+ localtag.lock = *locktag;
+ localtag.mode = lockmode;
+
+ /*
+ * Find the LOCALLOCK entry for this lock and lockmode
+ */
+ (void) hash_search(LockMethodLocalHash,
+ (void *) &localtag,
+ HASH_FIND, &found);
+
+ return found;
+}
+
/*
* LockHasWaiters -- look up 'locktag' and check if releasing this
* lock would wake up other processes waiting for it.
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 7271b5880b..1876345de5 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -1493,7 +1493,6 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
foreach(lc1, stmt_list)
{
PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
- int rt_index;
ListCell *lc2;
if (plannedstmt->commandType == CMD_UTILITY)
@@ -1512,14 +1511,9 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
continue;
}
- rt_index = 0;
foreach(lc2, plannedstmt->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
- LOCKMODE lockmode;
- PlanRowMark *rc;
-
- rt_index++;
if (rte->rtekind != RTE_RELATION)
continue;
@@ -1530,19 +1524,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 +1581,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 62209a8f10..2a265d591d 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -27,6 +27,7 @@
#include "nodes/primnodes.h"
#include "nodes/value.h"
#include "partitioning/partdefs.h"
+#include "storage/lockdefs.h"
typedef enum OverridingKind
@@ -976,6 +977,10 @@ typedef struct RangeTblEntry
*/
Oid relid; /* OID of the relation */
char relkind; /* relation kind (see pg_class.relkind) */
+ LOCKMODE lockmode; /* lock level to obtain on the relation; must
+ * be non-zero for all plain relation RTEs
+ * that will be passed to the executor via
+ * PlannedStmt. */
struct TableSampleClause *tablesample; /* sampling info, or NULL */
/*
diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h
index b9792acdae..99d1b4135c 100644
--- a/src/include/parser/parse_relation.h
+++ b/src/include/parser/parse_relation.h
@@ -15,6 +15,7 @@
#define PARSE_RELATION_H
#include "parser/parse_node.h"
+#include "storage/lockdefs.h"
/*
@@ -71,7 +72,8 @@ extern RangeTblEntry *addRangeTableEntryForRelation(ParseState *pstate,
Relation rel,
Alias *alias,
bool inh,
- bool inFromCl);
+ bool inFromCl,
+ LOCKMODE lockmode);
extern RangeTblEntry *addRangeTableEntryForSubquery(ParseState *pstate,
Query *subquery,
Alias *alias,
diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h
index a217de9716..abfafe5e40 100644
--- a/src/include/storage/lmgr.h
+++ b/src/include/storage/lmgr.h
@@ -38,6 +38,7 @@ extern void RelationInitLockInfo(Relation relation);
/* Lock a relation */
extern void LockRelationOid(Oid relid, LOCKMODE lockmode);
+extern bool CheckRelationLockedByUs(Oid relid, LOCKMODE lockmode);
extern bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode);
extern void UnlockRelationId(LockRelId *relid, LOCKMODE lockmode);
extern void UnlockRelationOid(Oid relid, LOCKMODE lockmode);
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index ff4df7fec5..b4a71ced0b 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -540,6 +540,7 @@ extern void LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks);
extern void LockReleaseSession(LOCKMETHODID lockmethodid);
extern void LockReleaseCurrentOwner(LOCALLOCK **locallocks, int nlocks);
extern void LockReassignCurrentOwner(LOCALLOCK **locallocks, int nlocks);
+extern bool LocalLockExists(const LOCKTAG *locktag, LOCKMODE lockmode);
extern bool LockHasWaiters(const LOCKTAG *locktag,
LOCKMODE lockmode, bool sessionLock);
extern VirtualTransactionId *GetLockConflicts(const LOCKTAG *locktag,
diff --git a/src/test/modules/test_rls_hooks/test_rls_hooks.c b/src/test/modules/test_rls_hooks/test_rls_hooks.c
index cab67a60aa..d455c97ef6 100644
--- a/src/test/modules/test_rls_hooks/test_rls_hooks.c
+++ b/src/test/modules/test_rls_hooks/test_rls_hooks.c
@@ -81,7 +81,7 @@ test_rls_hooks_permissive(CmdType cmdtype, Relation relation)
qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, relation, NULL, false,
- false);
+ false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
@@ -144,7 +144,7 @@ test_rls_hooks_restrictive(CmdType cmdtype, Relation relation)
qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, relation, NULL, false,
- false);
+ false, NoLock);
addRTEtoQuery(qual_pstate, rte, false, true, true);
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
--
2.16.2.windows.1
v10-0002-Remove-useless-fields-from-planner-nodes.patchapplication/octet-stream; name=v10-0002-Remove-useless-fields-from-planner-nodes.patchDownload
From 73eae2ad277c58932a209fb23acf9ba049092833 Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Sat, 29 Sep 2018 12:31:21 +1200
Subject: [PATCH v10 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 bool field called
'partitionedTarget', which is set if the target is a partitioned
table. The table itself is identified by targetRelation which
replaces nominalRelation.
* '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.
---
contrib/postgres_fdw/postgres_fdw.c | 2 +-
src/backend/commands/explain.c | 6 +--
src/backend/commands/portalcmds.c | 2 +-
src/backend/executor/execMain.c | 2 +-
src/backend/executor/execParallel.c | 3 +-
src/backend/executor/execPartition.c | 2 +-
src/backend/executor/execUtils.c | 55 --------------------
src/backend/executor/nodeAppend.c | 6 ---
src/backend/executor/nodeMergeAppend.c | 6 ---
src/backend/executor/nodeModifyTable.c | 9 ++--
src/backend/executor/spi.c | 4 +-
src/backend/nodes/copyfuncs.c | 9 ++--
src/backend/nodes/outfuncs.c | 15 ++----
src/backend/nodes/readfuncs.c | 9 ++--
src/backend/optimizer/plan/createplan.c | 46 ++++-------------
src/backend/optimizer/plan/planner.c | 89 +++++++++------------------------
src/backend/optimizer/plan/setrefs.c | 49 ++----------------
src/backend/optimizer/util/pathnode.c | 12 ++---
src/backend/tcop/utility.c | 15 ++++--
src/include/executor/executor.h | 2 -
src/include/nodes/plannodes.h | 30 ++++-------
src/include/nodes/relation.h | 10 ++--
src/include/optimizer/pathnode.h | 2 +-
23 files changed, 95 insertions(+), 290 deletions(-)
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 6cbba97c22..eeb053d5d8 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -2050,7 +2050,7 @@ postgresBeginForeignInsert(ModifyTableState *mtstate,
* Vars contained in those expressions.
*/
if (plan && plan->operation == CMD_UPDATE &&
- resultRelation == plan->nominalRelation)
+ resultRelation == plan->targetRelation)
resultRelation = mtstate->resultRelInfo[0].ri_RangeTableIndex;
}
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index ed6afe79a9..5ca7f69830 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -929,7 +929,7 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
break;
case T_ModifyTable:
*rels_used = bms_add_member(*rels_used,
- ((ModifyTable *) plan)->nominalRelation);
+ ((ModifyTable *) plan)->targetRelation);
if (((ModifyTable *) plan)->exclRelRTI)
*rels_used = bms_add_member(*rels_used,
((ModifyTable *) plan)->exclRelRTI);
@@ -2924,7 +2924,7 @@ ExplainScanTarget(Scan *plan, ExplainState *es)
static void
ExplainModifyTarget(ModifyTable *plan, ExplainState *es)
{
- ExplainTargetRel((Plan *) plan, plan->nominalRelation, es);
+ ExplainTargetRel((Plan *) plan, plan->targetRelation, es);
}
/*
@@ -3088,7 +3088,7 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors,
/* Should we explicitly label target relations? */
labeltargets = (mtstate->mt_nplans > 1 ||
(mtstate->mt_nplans == 1 &&
- mtstate->resultRelInfo->ri_RangeTableIndex != node->nominalRelation));
+ mtstate->resultRelInfo->ri_RangeTableIndex != node->targetRelation));
if (labeltargets)
ExplainOpenGroup("Target Tables", "Target Tables", false, es);
diff --git a/src/backend/commands/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 e5612c4707..118edea11c 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -219,7 +219,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 7d8bd01994..15d8fcc352 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -176,6 +176,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;
@@ -183,7 +184,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
@@ -203,7 +203,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/execPartition.c b/src/backend/executor/execPartition.c
index 3be794b97d..1d2b3620ee 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -379,7 +379,7 @@ ExecInitPartitionInfo(ModifyTableState *mtstate,
leaf_part_rri = makeNode(ResultRelInfo);
InitResultRelInfo(leaf_part_rri,
partrel,
- node ? node->nominalRelation : 1,
+ node ? node->targetRelation : 1,
rootrel,
estate->es_instrument);
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
@@ -847,61 +847,6 @@ ShutdownExprContext(ExprContext *econtext, bool isCommit)
MemoryContextSwitchTo(oldcontext);
}
-/*
- * 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
@@ -112,12 +112,6 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
/* check for unsupported flags */
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
*/
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
@@ -75,12 +75,6 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
/* check for unsupported flags */
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
*/
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index f81769ea85..b18f9e3164 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2255,18 +2255,17 @@ 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->partitionedTarget);
+ rte = rt_fetch(node->targetRelation, estate->es_range_table);
rel = heap_open(rte->relid, NoLock);
- InitResultRelInfo(mtstate->rootResultRelInfo, rel, root_rt_index,
- NULL, estate->es_instrument);
+ InitResultRelInfo(mtstate->rootResultRelInfo, rel,
+ node->targetRelation, NULL, estate->es_instrument);
}
mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 11ca800e4c..1bee240e72 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -1358,7 +1358,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
@@ -1374,7 +1374,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..da02b8961c 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);
@@ -203,8 +202,8 @@ _copyModifyTable(const ModifyTable *from)
*/
COPY_SCALAR_FIELD(operation);
COPY_SCALAR_FIELD(canSetTag);
- COPY_SCALAR_FIELD(nominalRelation);
- COPY_NODE_FIELD(partitioned_rels);
+ COPY_SCALAR_FIELD(targetRelation);
+ COPY_SCALAR_FIELD(partitionedTarget);
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 03d84aa0cd..2e6a5a1b42 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -272,6 +272,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);
@@ -280,11 +281,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);
@@ -375,8 +374,8 @@ _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(targetRelation);
+ WRITE_BOOL_FIELD(partitionedTarget);
WRITE_BOOL_FIELD(partColsUpdated);
WRITE_NODE_FIELD(resultRelations);
WRITE_INT_FIELD(resultRelIndex);
@@ -405,7 +404,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);
}
@@ -418,7 +416,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);
@@ -2178,8 +2175,8 @@ _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(targetRelation);
+ WRITE_BOOL_FIELD(partitionedTarget);
WRITE_BOOL_FIELD(partColsUpdated);
WRITE_NODE_FIELD(resultRelations);
WRITE_NODE_FIELD(subpaths);
@@ -2257,9 +2254,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 fc006e2830..aea5b0abc4 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1496,6 +1496,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);
@@ -1504,11 +1505,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);
@@ -1597,8 +1596,8 @@ _readModifyTable(void)
READ_ENUM_FIELD(operation, CmdType);
READ_BOOL_FIELD(canSetTag);
- READ_UINT_FIELD(nominalRelation);
- READ_NODE_FIELD(partitioned_rels);
+ READ_UINT_FIELD(targetRelation);
+ READ_BOOL_FIELD(partitionedTarget);
READ_BOOL_FIELD(partColsUpdated);
READ_NODE_FIELD(resultRelations);
READ_INT_FIELD(resultRelIndex);
@@ -1632,7 +1631,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();
@@ -1648,7 +1646,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..8f20e54d9e 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 targetRelation, bool partitionedTarget,
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;
@@ -2410,8 +2405,8 @@ create_modifytable_plan(PlannerInfo *root, ModifyTablePath *best_path)
plan = make_modifytable(root,
best_path->operation,
best_path->canSetTag,
- best_path->nominalRelation,
- best_path->partitioned_rels,
+ best_path->targetRelation,
+ best_path->partitionedTarget,
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 targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subplans, List *subroots,
List *withCheckOptionLists, List *returningLists,
@@ -6537,8 +6509,8 @@ make_modifytable(PlannerInfo *root,
node->operation = operation;
node->canSetTag = canSetTag;
- node->nominalRelation = nominalRelation;
- node->partitioned_rels = flatten_partitioned_rels(partitioned_rels);
+ node->targetRelation = targetRelation;
+ node->partitionedTarget = partitionedTarget;
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 22c010c19e..a927c0a1db 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -287,6 +287,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
Plan *top_plan;
ListCell *lp,
*lr;
+ bool hasRowMarks = (parse->rowMarks != NIL);
/*
* Set up global state for this planner invocation. This data is needed
@@ -301,9 +302,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;
@@ -501,9 +500,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) */
@@ -514,6 +511,8 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
PlannerInfo *subroot = lfirst_node(PlannerInfo, lr);
lfirst(lp) = set_plan_references(subroot, subplan);
+ if (subroot->rowMarks != NIL)
+ hasRowMarks = true;
}
/* build the PlannedStmt result */
@@ -523,6 +522,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
result->queryId = parse->queryId;
result->hasReturning = (parse->returningList != NIL);
result->hasModifyingCTE = parse->hasModifyingCTE;
+ result->hasRowMarks = hasRowMarks;
result->canSetTag = parse->canSetTag;
result->transientPlan = glob->transientPlan;
result->dependsOnRole = glob->dependsOnRole;
@@ -530,11 +530,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;
@@ -1169,7 +1167,7 @@ inheritance_planner(PlannerInfo *root)
int top_parentRTindex = parse->resultRelation;
Bitmapset *subqueryRTindexes;
Bitmapset *modifiableARIindexes;
- int nominalRelation = -1;
+ int targetRelation = -1;
List *final_rtable = NIL;
int save_rel_array_size = 0;
RelOptInfo **save_rel_array = NULL;
@@ -1184,8 +1182,7 @@ inheritance_planner(PlannerInfo *root)
ListCell *lc;
Index rti;
RangeTblEntry *parent_rte;
- Relids partitioned_relids = NULL;
- List *partitioned_rels = NIL;
+ bool partitionedTarget = false;
PlannerInfo *parent_root;
Query *parent_parse;
Bitmapset *parent_relids = bms_make_singleton(top_parentRTindex);
@@ -1248,25 +1245,14 @@ inheritance_planner(PlannerInfo *root)
}
/*
- * If the parent RTE is a partitioned table, we should use that as the
- * nominal relation, because the RTEs added for partitioned tables
- * (including the root parent) as child members of the inheritance set do
- * not appear anywhere else in the plan. The situation is exactly the
- * opposite in the case of non-partitioned inheritance parent as described
- * below. For the same reason, collect the list of descendant partitioned
- * tables to be saved in ModifyTable node, so that executor can lock those
- * as well.
+ * If the parent RTE is a partitioned table, set that as the target
+ * relation and mark that we're working with a partitioned target.
*/
parent_rte = rt_fetch(top_parentRTindex, root->parse->rtable);
if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
{
- nominalRelation = top_parentRTindex;
-
- /*
- * 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);
+ targetRelation = top_parentRTindex;
+ partitionedTarget = true;
}
/*
@@ -1338,7 +1324,7 @@ inheritance_planner(PlannerInfo *root)
* inheritance parent.
*/
subroot->inhTargetKind =
- partitioned_relids ? INHKIND_PARTITIONED : INHKIND_INHERITED;
+ partitionedTarget ? INHKIND_PARTITIONED : INHKIND_INHERITED;
/*
* If this child is further partitioned, remember it as a parent.
@@ -1363,17 +1349,17 @@ inheritance_planner(PlannerInfo *root)
}
/*
- * Set the nominal target relation of the ModifyTable node if not
- * already done. We use the inheritance parent RTE as the nominal
- * target relation if it's a partitioned table (see just above this
- * loop). In the non-partitioned parent case, we'll use the first
- * child relation (even if it's excluded) as the nominal target
- * relation. Because of the way expand_inherited_rtentry works, the
- * latter should be the RTE representing the parent table in its role
- * as a simple member of the inheritance set.
+ * Set the target relation of the ModifyTable node if not already
+ * done. We use the inheritance parent RTE as the target relation
+ * if it's a partitioned table (see just above this loop). In the
+ * non-partitioned parent case, we'll use the first child relation
+ * (even if it's excluded) as the target relation. Because of the way
+ * expand_inherited_rtentry works, the latter should be the RTE
+ * representing the parent table in its role as a simple member of
+ * the inheritance set.
*
* It would be logically cleaner to *always* use the inheritance
- * parent RTE as the nominal relation; but that RTE is not otherwise
+ * parent RTE as the target relation; but that RTE is not otherwise
* referenced in the plan in the non-partitioned inheritance case.
* Instead the duplicate child RTE created by expand_inherited_rtentry
* is used elsewhere in the plan, so using the original parent RTE
@@ -1383,8 +1369,8 @@ inheritance_planner(PlannerInfo *root)
* duplicate child RTE added for the parent does not appear anywhere
* else in the plan tree.
*/
- if (nominalRelation < 0)
- nominalRelation = appinfo->child_relid;
+ if (targetRelation < 0)
+ targetRelation = appinfo->child_relid;
/*
* The rowMarks list might contain references to subquery RTEs, so
@@ -1508,15 +1494,6 @@ inheritance_planner(PlannerInfo *root)
if (IS_DUMMY_PATH(subpath))
continue;
- /*
- * Add the current parent's RT index to the partitioned_relids set if
- * we're creating the ModifyTable path for a partitioned root table.
- * (We only care about parents of non-excluded children.)
- */
- if (partitioned_relids)
- partitioned_relids = bms_add_member(partitioned_relids,
- appinfo->parent_relid);
-
/*
* If this is the first non-excluded child, its post-planning rtable
* becomes the initial contents of final_rtable; otherwise, append
@@ -1620,29 +1597,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,
+ targetRelation,
+ partitionedTarget,
root->partColsUpdated,
resultRelations,
subpaths,
@@ -2219,7 +2180,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
parse->commandType,
parse->canSetTag,
parse->resultRelation,
- NIL,
+ false,
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..17d53f356c 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);
}
@@ -847,13 +827,9 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
fix_scan_list(root, splan->exclRelTlist, rtoffset);
}
- splan->nominalRelation += rtoffset;
+ splan->targetRelation += rtoffset;
splan->exclRelRTI += rtoffset;
- foreach(l, splan->partitioned_rels)
- {
- lfirst_int(l) += rtoffset;
- }
foreach(l, splan->resultRelations)
{
lfirst_int(l) += rtoffset;
@@ -884,24 +860,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->partitionedTarget)
{
- 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->targetRelation);
}
}
break;
@@ -915,10 +884,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 +902,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..73eca1d4d0 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -3291,10 +3291,8 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
* 'rel' is the parent relation associated with the result
* 'operation' is the operation type
* 'canSetTag' is true if we set the command tag/es_processed
- * 'nominalRelation' is the parent RT index for use of EXPLAIN
- * '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.
+ * 'targetRelation' is the target table's RT index
+ * 'partitionedTarget' true if 'targetRelation' is a partitioned table
* 'partColsUpdated' is true if any partitioning columns are being updated,
* either from the target relation or a descendent partitioned table.
* 'resultRelations' is an integer list of actual RT indexes of target rel(s)
@@ -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 targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subpaths,
List *subroots,
@@ -3376,8 +3374,8 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
pathnode->operation = operation;
pathnode->canSetTag = canSetTag;
- pathnode->nominalRelation = nominalRelation;
- pathnode->partitioned_rels = list_copy(partitioned_rels);
+ pathnode->targetRelation = targetRelation;
+ pathnode->partitionedTarget = partitionedTarget;
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..d0427c64ba 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
+ 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..27ae73e3d4 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 */
@@ -219,9 +212,10 @@ typedef struct ModifyTable
Plan plan;
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 targetRelation; /* RT index of the target table specified in
+ * the command or first child for inheritance
+ * tables */
+ bool partitionedTarget; /* is the target table partitioned? */
bool partColsUpdated; /* some part key in hierarchy updated */
List *resultRelations; /* integer list of RT indexes */
int resultRelIndex; /* index of first resultRel in plan's list */
@@ -259,9 +253,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 +265,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 +916,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..bcc2ba6db5 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 */
@@ -1716,9 +1713,10 @@ typedef struct ModifyTablePath
Path path;
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 targetRelation; /* RT index of the target table specified in
+ * the command or first child for inheritance
+ * tables */
+ bool partitionedTarget; /* is the target table partitioned? */
bool partColsUpdated; /* some part key in hierarchy updated */
List *resultRelations; /* integer list of RT indexes */
List *subpaths; /* Path(s) producing source data */
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 7c5ff22650..a45c2407d0 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -238,7 +238,7 @@ extern LockRowsPath *create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
extern ModifyTablePath *create_modifytable_path(PlannerInfo *root,
RelOptInfo *rel,
CmdType operation, bool canSetTag,
- Index nominalRelation, List *partitioned_rels,
+ Index targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subpaths,
List *subroots,
--
2.16.2.windows.1
v10-0003-Prune-PlanRowMark-of-relations-that-are-pruned-f.patchapplication/octet-stream; name=v10-0003-Prune-PlanRowMark-of-relations-that-are-pruned-f.patchDownload
From 02cb376608f7654aa331ab76a3b50287b45494be Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Sat, 29 Sep 2018 12:31:49 +1200
Subject: [PATCH v10 3/4] Prune PlanRowMark of relations that are pruned from a
plan
---
src/backend/optimizer/plan/planner.c | 32 ++++++++++++++++++++++++++------
1 file changed, 26 insertions(+), 6 deletions(-)
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index a927c0a1db..074ec9bf55 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -248,7 +248,7 @@ static bool group_by_has_partkey(RelOptInfo *input_rel,
List *targetList,
List *groupClause);
static int common_prefix_cmp(const void *a, const void *b);
-
+static List *get_nondummy_rowmarks(PlannerInfo *root);
/*****************************************************************************
*
@@ -1595,7 +1595,7 @@ inheritance_planner(PlannerInfo *root)
if (parse->rowMarks)
rowMarks = NIL;
else
- rowMarks = root->rowMarks;
+ rowMarks = get_nondummy_rowmarks(root);
/* Create Path representing a ModifyTable to do the UPDATE/DELETE work */
add_path(final_rel, (Path *)
@@ -2124,11 +2124,9 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
* is what goes into the LockRows node.)
*/
if (parse->rowMarks)
- {
path = (Path *) create_lockrows_path(root, final_rel, path,
- root->rowMarks,
+ get_nondummy_rowmarks(root),
SS_assign_special_param(root));
- }
/*
* If there is a LIMIT/OFFSET clause, add the LIMIT node.
@@ -2173,7 +2171,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
if (parse->rowMarks)
rowMarks = NIL;
else
- rowMarks = root->rowMarks;
+ rowMarks = get_nondummy_rowmarks(root);
path = (Path *)
create_modifytable_path(root, final_rel,
@@ -7219,3 +7217,25 @@ group_by_has_partkey(RelOptInfo *input_rel,
return true;
}
+
+/*
+ * get_nondummy_rowmarks
+ * Return a list of PlanRowMark's that reference non-dummy relations
+ */
+static List *
+get_nondummy_rowmarks(PlannerInfo *root)
+{
+ List *rowMarks = NIL;
+ ListCell *lc;
+
+ 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]))
+ rowMarks = lappend(rowMarks, rc);
+ }
+
+ return rowMarks;
+}
--
2.16.2.windows.1
v10-0004-Revise-executor-range-table-relation-opening-clo.patchapplication/octet-stream; name=v10-0004-Revise-executor-range-table-relation-opening-clo.patchDownload
From 812e2c54c72a143c4f4ae1a66a05b3982be29451 Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Sat, 29 Sep 2018 12:35:56 +1200
Subject: [PATCH v10 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, an arrangement which allows the executor
to have to heap_open any given range table relation only once.
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.
Accessed Relations are now also closed during ExecEndPlan(). Callers of
ExecRangeTableRelation() have no need to consider how their Relation
objects are cleaned up.
Authors: Amit Langote, David Rowley
---
contrib/postgres_fdw/postgres_fdw.c | 16 +++---
src/backend/commands/copy.c | 3 +-
src/backend/commands/trigger.c | 3 +-
src/backend/executor/README | 4 +-
src/backend/executor/execExprInterp.c | 7 +--
src/backend/executor/execMain.c | 80 ++++++++++-------------------
src/backend/executor/execPartition.c | 39 +++-----------
src/backend/executor/execUtils.c | 68 +++++++++++++++---------
src/backend/executor/nodeAppend.c | 6 ---
src/backend/executor/nodeBitmapHeapscan.c | 7 ---
src/backend/executor/nodeCustom.c | 4 --
src/backend/executor/nodeForeignscan.c | 4 --
src/backend/executor/nodeIndexonlyscan.c | 7 ---
src/backend/executor/nodeIndexscan.c | 7 ---
src/backend/executor/nodeLockRows.c | 2 +-
src/backend/executor/nodeMergeAppend.c | 6 ---
src/backend/executor/nodeModifyTable.c | 26 +++++-----
src/backend/executor/nodeSamplescan.c | 5 --
src/backend/executor/nodeSeqscan.c | 7 ---
src/backend/executor/nodeTidscan.c | 5 --
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/tablesync.c | 9 +++-
src/backend/replication/logical/worker.c | 2 +
src/include/executor/execPartition.h | 1 -
src/include/executor/executor.h | 24 ++++++++-
src/include/nodes/execnodes.h | 23 ++++++++-
src/include/nodes/plannodes.h | 2 +-
src/include/parser/parsetree.h | 10 ----
32 files changed, 195 insertions(+), 223 deletions(-)
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index eeb053d5d8..d20c75367c 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. */
@@ -1731,8 +1731,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,
@@ -2036,7 +2036,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);
@@ -2396,7 +2396,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. */
@@ -2546,10 +2546,6 @@ postgresEndDirectModify(ForeignScanState *node)
ReleaseConnection(dmstate->conn);
dmstate->conn = NULL;
- /* close the target relation. */
- if (dmstate->resultRel)
- ExecCloseScanRelation(dmstate->resultRel);
-
/* MemoryContext will be deleted automatically. */
}
@@ -5756,7 +5752,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 0c4a7b6f4f..57efb20d20 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -2483,7 +2483,8 @@ 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;
+
+ ExecInitRangeTable(estate, cstate->range_table);
/* 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 34f9db93d5..f0d45844c1 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/README b/src/backend/executor/README
index 0d7cd552eb..30df410e0e 100644
--- a/src/backend/executor/README
+++ b/src/backend/executor/README
@@ -267,8 +267,8 @@ This is a sketch of control flow for full query processing:
Per above comments, it's not really critical for ExecEndNode to free any
memory; it'll all go away in FreeExecutorState anyway. However, we do need to
-be careful to close relations, drop buffer pins, etc, so we do need to scan
-the plan state tree to find these sorts of resources.
+be careful to drop buffer pins, etc, so we do need to scan the plan state tree
+to find these sorts of resources.
The executor can also be used to evaluate simple expressions without any Plan
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index f597363eb1..f8ca60ae5a 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3934,10 +3934,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 118edea11c..e704c9150c 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -111,9 +111,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 */
@@ -837,26 +837,15 @@ InitPlan(QueryDesc *queryDesc, int eflags)
*/
ExecCheckRTPerms(rangeTable, true);
-#ifdef USE_ASSERT_CHECKING
- foreach(l, rangeTable)
- {
- RangeTblEntry *rte = lfirst(l);
+ ExecInitRangeTable(estate, rangeTable);
- if (rte->rtekind == RTE_RELATION && OidIsValid(rte->relid))
- {
- /*
- * The following asserts that the necessary lock on the relation
- * has already been taken. That can only however be true in the
- * parallel leader.
- */
- Assert(rte->lockmode != NoLock);
- if (!IsParallelWorker() &&
- !CheckRelationLockedByUs(rte->relid, rte->lockmode))
- elog(WARNING, "lock is not held on relation \"%s\"",
- get_rel_name(rte->relid));
- }
- }
-#endif
+ /*
+ * Allocate an array to store open Relations of each rangeTable item. We
+ * zero-fill this for now. The Relations are only opened and stored here
+ * the first time they're required during node initialization.
+ */
+ estate->es_relations = (Relation *) palloc0(estate->es_range_table_size *
+ sizeof(Relation));
/*
* initialize the node's execution state
@@ -1501,6 +1490,14 @@ static void
ExecEndPlan(PlanState *planstate, EState *estate)
{
ListCell *l;
+ int i;
+
+ /* Close range table relations. */
+ for (i = 0; i < estate->es_range_table_size; i++)
+ {
+ if (estate->es_relations[i])
+ heap_close(estate->es_relations[i], NoLock);
+ }
/*
* shut down the node-type-specific query processing
@@ -1527,18 +1524,6 @@ ExecEndPlan(PlanState *planstate, EState *estate)
/* likewise close any trigger target relations */
ExecCleanUpTriggerState(estate);
-
- /*
- * 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);
- }
}
/* ----------------------------------------------------------------
@@ -2295,24 +2280,20 @@ 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);
-
switch (rc->markType)
{
case ROW_MARK_EXCLUSIVE:
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 */
@@ -2330,7 +2311,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;
@@ -2988,7 +2969,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));
@@ -3041,7 +3022,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();
@@ -3065,6 +3046,9 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree)
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_range_table_size = parentestate->es_range_table_size;
+ 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;
@@ -3218,18 +3202,6 @@ 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 1d2b3620ee..7fb34d2173 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -861,11 +861,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++)
{
@@ -1418,9 +1417,6 @@ adjust_partition_tlist(List *tlist, TupleConversionMap *map)
* functions. Details stored include how to map the partition index
* returned by the partition pruning code into subplan indexes.
*
- * ExecDestroyPartitionPruneState:
- * Deletes a PartitionPruneState. Must be called during executor shutdown.
- *
* ExecFindInitialMatchingSubPlans:
* Returns indexes of matching subplans. Partition pruning is attempted
* without any evaluation of expressions containing PARAM_EXEC Params.
@@ -1462,6 +1458,7 @@ PartitionPruneState *
ExecCreatePartitionPruneState(PlanState *planstate,
PartitionPruneInfo *partitionpruneinfo)
{
+ EState *estate = planstate->state;
PartitionPruneState *prunestate;
int n_part_hierarchies;
ListCell *lc;
@@ -1542,7 +1539,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);
@@ -1622,30 +1619,6 @@ ExecCreatePartitionPruneState(PlanState *planstate,
return prunestate;
}
-/*
- * ExecDestroyPartitionPruneState
- * Release resources at plan shutdown.
- *
- * We don't bother to free any memory here, since the whole executor context
- * will be going away shortly. We do need to release our relcache pins.
- */
-void
-ExecDestroyPartitionPruneState(PartitionPruneState *prunestate)
-{
- PartitionPruningData **partprunedata = prunestate->partprunedata;
- int i;
-
- for (i = 0; i < prunestate->num_partprunedata; i++)
- {
- PartitionPruningData *prunedata = partprunedata[i];
- PartitionedRelPruningData *pprune = prunedata->partrelprunedata;
- int j;
-
- for (j = 0; j < prunedata->num_partrelprunedata; j++)
- relation_close(pprune[j].context.partrel, NoLock);
- }
-}
-
/*
* ExecFindInitialMatchingSubPlans
* Identify the set of subplans that cannot be eliminated by initial
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index d32796aac3..b77fc9e619 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -25,7 +25,6 @@
* etc
*
* ExecOpenScanRelation Common code for scan node init routines.
- * ExecCloseScanRelation
*
* executor_errposition Report syntactic position of an error.
*
@@ -35,6 +34,8 @@
* GetAttributeByName Runtime extraction of columns from tuples.
* GetAttributeByNum
*
+ * ExecInitRangeTable Build an array from the range table list to
+ * allow faster lookups by relid.
* NOTES
* This file has traditionally been the place to stick misc.
* executor support stuff that doesn't really go anyplace else.
@@ -653,11 +654,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
@@ -675,26 +674,6 @@ ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
return rel;
}
-/* ----------------------------------------------------------------
- * ExecCloseScanRelation
- *
- * Close the heap relation scanned by a base-level scan plan node.
- * This should be called during the node's ExecEnd routine.
- *
- * Currently, we do not release the lock acquired by ExecOpenScanRelation.
- * This lock should be held till end of transaction. (There is a faction
- * that considers this too much locking, however.)
- *
- * If we did want to release the lock, we'd have to repeat the logic in
- * ExecOpenScanRelation in order to figure out what to release.
- * ----------------------------------------------------------------
- */
-void
-ExecCloseScanRelation(Relation scanrel)
-{
- heap_close(scanrel, NoLock);
-}
-
/*
* UpdateChangedParamSet
* Add changed parameters to a plan node's chgParam set
@@ -997,3 +976,44 @@ ExecCleanTargetListLength(List *targetlist)
}
return len;
}
+
+/*
+ * Initialize executor's range table array
+ */
+void
+ExecInitRangeTable(EState *estate, List *rangeTable)
+{
+ int rti;
+ ListCell *l;
+
+#ifdef USE_ASSERT_CHECKING
+ foreach(l, rangeTable)
+ {
+ RangeTblEntry *rte = lfirst(l);
+
+ if (rte->rtekind == RTE_RELATION && OidIsValid(rte->relid))
+ {
+ /*
+ * The following verifies that the necessary lock on the relation
+ * has already been taken. That can only however be true in the
+ * parallel leader.
+ */
+ Assert(rte->lockmode != NoLock);
+ if (!IsParallelWorker() &&
+ !CheckRelationLockedByUs(rte->relid, rte->lockmode))
+ elog(WARNING, "lock is not held on relation \"%s\"",
+ get_rel_name(rte->relid));
+ }
+ }
+#endif
+
+ Assert(estate != NULL);
+ 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 *));
+ rti = 0;
+ foreach(l, rangeTable)
+ estate->es_range_table_array[rti++] = lfirst_node(RangeTblEntry, l);
+}
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index eb587be221..a16b6da474 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -329,12 +329,6 @@ ExecEndAppend(AppendState *node)
*/
for (i = 0; i < nplans; i++)
ExecEndNode(appendplans[i]);
-
- /*
- * release any resources associated with run-time pruning
- */
- if (node->as_prune_state)
- ExecDestroyPartitionPruneState(node->as_prune_state);
}
void
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index baffae27e3..5307cd1b87 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -785,13 +785,11 @@ ExecReScanBitmapHeapScan(BitmapHeapScanState *node)
void
ExecEndBitmapHeapScan(BitmapHeapScanState *node)
{
- Relation relation;
HeapScanDesc scanDesc;
/*
* extract information from the node
*/
- relation = node->ss.ss_currentRelation;
scanDesc = node->ss.ss_currentScanDesc;
/*
@@ -832,11 +830,6 @@ ExecEndBitmapHeapScan(BitmapHeapScanState *node)
* close heap scan
*/
heap_endscan(scanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index b816e0b31d..9a33eda688 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -126,10 +126,6 @@ ExecEndCustomScan(CustomScanState *node)
/* Clean out the tuple table */
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /* Close the heap relation */
- if (node->ss.ss_currentRelation)
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
void
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index a2a28b7ec2..cf7df72d8c 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -258,10 +258,6 @@ ExecEndForeignScan(ForeignScanState *node)
/* clean out the tuple table */
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /* close the relation. */
- if (node->ss.ss_currentRelation)
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 4b6d531810..1b530cea40 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -373,14 +373,12 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node)
{
Relation indexRelationDesc;
IndexScanDesc indexScanDesc;
- Relation relation;
/*
* extract information from the node
*/
indexRelationDesc = node->ioss_RelationDesc;
indexScanDesc = node->ioss_ScanDesc;
- relation = node->ss.ss_currentRelation;
/* Release VM buffer pin, if any. */
if (node->ioss_VMBuffer != InvalidBuffer)
@@ -411,11 +409,6 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node)
index_endscan(indexScanDesc);
if (indexRelationDesc)
index_close(indexRelationDesc, NoLock);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 6285a2114e..786e7ac25c 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -802,14 +802,12 @@ ExecEndIndexScan(IndexScanState *node)
{
Relation indexRelationDesc;
IndexScanDesc indexScanDesc;
- Relation relation;
/*
* extract information from the node
*/
indexRelationDesc = node->iss_RelationDesc;
indexScanDesc = node->iss_ScanDesc;
- relation = node->ss.ss_currentRelation;
/*
* Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
@@ -833,11 +831,6 @@ ExecEndIndexScan(IndexScanState *node)
index_endscan(indexScanDesc);
if (indexRelationDesc)
index_close(indexRelationDesc, NoLock);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index efbf4bd18a..ff9606342b 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/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index d8e0978966..5d0dbb8146 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -363,12 +363,6 @@ ExecEndMergeAppend(MergeAppendState *node)
*/
for (i = 0; i < nplans; i++)
ExecEndNode(mergeplans[i]);
-
- /*
- * release any resources associated with run-time pruning
- */
- if (node->ms_prune_state)
- ExecDestroyPartitionPruneState(node->ms_prune_state);
}
void
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index b18f9e3164..c837d36a87 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,17 +2254,18 @@ 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->partitionedTarget);
- rte = rt_fetch(node->targetRelation, estate->es_range_table);
- rel = heap_open(rte->relid, NoLock);
- InitResultRelInfo(mtstate->rootResultRelInfo, rel,
- node->targetRelation, NULL, estate->es_instrument);
+ rel = ExecRangeTableRelation(estate, node->targetRelation);
+ InitResultRelInfo(mtstate->rootResultRelInfo,
+ rel,
+ node->targetRelation,
+ NULL,
+ estate->es_instrument);
}
mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
@@ -2722,15 +2722,13 @@ ExecEndModifyTable(ModifyTableState *node)
resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
resultRelInfo);
- /* Close indices and then the relation itself */
+ /*
+ * Close the ResultRelInfo's indexes. The relation itself
+ * is handled by the executor cleanup code.
+ */
ExecCloseIndices(resultRelInfo);
- heap_close(resultRelInfo->ri_RelationDesc, NoLock);
}
- /* 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/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index 99528be84a..92ff68a764 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -222,11 +222,6 @@ ExecEndSampleScan(SampleScanState *node)
*/
if (node->ss.ss_currentScanDesc)
heap_endscan(node->ss.ss_currentScanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index cd53491be0..92ff1e50ed 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -201,13 +201,11 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
void
ExecEndSeqScan(SeqScanState *node)
{
- Relation relation;
HeapScanDesc scanDesc;
/*
* get information from node
*/
- relation = node->ss.ss_currentRelation;
scanDesc = node->ss.ss_currentScanDesc;
/*
@@ -226,11 +224,6 @@ ExecEndSeqScan(SeqScanState *node)
*/
if (scanDesc != NULL)
heap_endscan(scanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index 0cb1946a3e..8cae56f48c 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -489,11 +489,6 @@ ExecEndTidScan(TidScanState *node)
*/
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index da02b8961c..dd76284676 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 2e6a5a1b42..6aefdd8bc4 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1029,7 +1029,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 aea5b0abc4..30609c96e6 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -2373,7 +2373,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 17d53f356c..ee01ef82d2 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -890,6 +890,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:
@@ -908,6 +923,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 e1ce8b4ddc..1763dd67a3 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/tablesync.c b/src/backend/replication/logical/tablesync.c
index 905a983074..d72f6a1b4f 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -795,7 +795,14 @@ copy_table(Relation rel)
copybuf = makeStringInfo();
pstate = make_parsestate(NULL);
- addRangeTableEntryForRelation(pstate, rel, NULL, false, false, NoLock);
+
+ /*
+ * Caller LogicalRepSyncTableStart took RowExclusiveLock, which we must
+ * record in the RTE being built, because executor initialization invoked
+ * by copy.c expects it.
+ */
+ addRangeTableEntryForRelation(pstate, rel, NULL, false, false,
+ RowExclusiveLock);
attnamelist = make_copy_attnamelist(relmapentry);
cstate = BeginCopyFrom(pstate, rel, NULL, false, copy_read_data, attnamelist, NIL);
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 42345f94d3..c63de66857 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -200,6 +200,8 @@ create_estate_for_relation(LogicalRepRelMapEntry *rel)
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/execPartition.h b/src/include/executor/execPartition.h
index 89ce53815c..04847d639d 100644
--- a/src/include/executor/execPartition.h
+++ b/src/include/executor/execPartition.h
@@ -197,7 +197,6 @@ extern void ExecCleanupTupleRouting(ModifyTableState *mtstate,
PartitionTupleRouting *proute);
extern PartitionPruneState *ExecCreatePartitionPruneState(PlanState *planstate,
PartitionPruneInfo *partitionpruneinfo);
-extern void ExecDestroyPartitionPruneState(PartitionPruneState *prunestate);
extern Bitmapset *ExecFindMatchingSubPlans(PartitionPruneState *prunestate);
extern Bitmapset *ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate,
int nsubplans);
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 1d2b48fe09..b03d8c591f 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"
/*
@@ -478,6 +479,7 @@ extern ExprContext *CreateExprContext(EState *estate);
extern ExprContext *CreateStandaloneExprContext(void);
extern void FreeExprContext(ExprContext *econtext, bool isCommit);
extern void ReScanExprContext(ExprContext *econtext);
+extern void ExecInitRangeTable(EState *estate, List *rangeTable);
#define ResetExprContext(econtext) \
MemoryContextReset((econtext)->ecxt_per_tuple_memory)
@@ -513,7 +515,6 @@ extern void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate
extern bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid);
extern Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags);
-extern void ExecCloseScanRelation(Relation scanrel);
extern int executor_errposition(EState *estate, int location);
@@ -568,4 +569,25 @@ 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)
+{
+ Relation rel = estate->es_relations[rti - 1];
+
+ if (rel == NULL)
+ {
+ RangeTblEntry *rte = exec_rt_fetch(rti, estate->es_range_table_array);
+
+ /*
+ * No need to lock the relation. Locks were already
+ * obtained by the upstream code.
+ */
+ rel = estate->es_relations[rti - 1] = heap_open(rte->relid, NoLock);
+ }
+
+ return rel;
+}
+#endif
+
#endif /* EXECUTOR_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 03ad516976..639235d622 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,11 @@ 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 Relations
+ * es_range_table_size elements in length. */
PlannedStmt *es_plannedstmt; /* link to top of plan tree */
const char *es_sourceText; /* Source text from QueryDesc */
@@ -579,6 +584,22 @@ typedef struct EState
struct JitInstrumentation *es_jit_combined_instr;
} 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]
+
+/*
+ * 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 27ae73e3d4..452627dd03 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -1093,7 +1093,7 @@ typedef struct PartitionPruneInfo
typedef struct PartitionedRelPruneInfo
{
NodeTag type;
- Oid reloid; /* OID of partition rel for this level */
+ Index rtindex; /* Partition table's RT index */
List *pruning_steps; /* List of PartitionPruneStep, see below */
Bitmapset *present_parts; /* Indexes of all partitions which subplans or
* subparts are present for. */
diff --git a/src/include/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
@@ -31,16 +31,6 @@
#define rt_fetch(rangetable_index, rangetable) \
((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.16.2.windows.1
David Rowley <david.rowley@2ndquadrant.com> writes:
I've attached v10 which fixes this and aligns the WARNING text in
ExecInitRangeTable() and addRangeTableEntryForRelation().
I started poking at this. I thought that it would be a good cross-check
to apply just the "front half" of 0001 (i.e., creation and population of
the RTE lockmode field), and then to insert checks in each of the
"back half" places (executor, plancache, etc) that the lockmodes they
are computing today match what is in the RTE.
Those checks fell over many times in the regression tests.
There seem to be at least four distinct problems:
1. You set up transformRuleStmt to insert AccessExclusiveLock into
the "OLD" and "NEW" RTEs for a view. This is surely wrong; we do
not want to take exclusive lock on a view just to run a query using
the view. It should (usually, anyway) just be AccessShareLock.
However, because addRangeTableEntryForRelation insists that you
hold the requested lock type *now*, just changing the parameter
to AccessShareLock doesn't work.
I hacked around this for the moment by passing NoLock to
addRangeTableEntryForRelation and then changing rte->lockmode
after it returns, but man that's ugly. It makes me wonder whether
addRangeTableEntryForRelation should be checking the lockmode at all.
I'm inclined to think we should remove the check for current lockmode
in addRangeTableEntryForRelation, and instead just assert that the
passed lockmode must be one of AccessShareLock, RowShareLock, or
RowExclusiveLock depending on whether the RTE is meant to represent
a plain source table, a FOR UPDATE/SHARE source table, or a target
table. I don't think it's that helpful to be checking that the
caller got exactly the same lock, especially given the number of
places where the patch had to cheat already by using NoLock.
2. The "forUpdatePushedDown" override in AcquireRewriteLocks isn't
getting modeled in the RTE lockmode fields. In other words, if we
have something like
CREATE VIEW vv AS SELECT * FROM tab1;
SELECT * FROM vv FOR UPDATE OF vv;
the checks fall over, because the tab1 RTE in the view's rangetable
just has AccessShareLock, but we need RowShareLock. I fixed this
by having AcquireRewriteLocks actually modify the RTE if it is
promoting the lock level. This is kinda grotty, but we were already
assuming that AcquireRewriteLocks could scribble on the query tree,
so it seems safe enough.
3. There remain some cases where the RTE says RowExclusiveLock but
the executor calculation indicates we only need AccessShareLock.
AFAICT, this happens only when we have a DO ALSO rule that results
in an added query that merely scans the target table. The RTE used
for that purpose is just the original one, so it still has a lockmode
suitable for a target table.
We could probably hack the rewriter so that it changes the RTE lockmode
back down to AccessShareLock in these cases. However, I'm inclined to
think that that is something *not* to do, and that we should let the
higher lockmode be used instead, for two reasons:
(1) Asking for both AccessShareLock and RowExclusiveLock on the same
table requires an extra trip through the shared lock manager, for little
value that I can see.
(2) If the DO ALSO rule is run before the main one, we'd be acquiring
AccessShareLock before RowExclusiveLock, resulting in deadlock hazard
due to lock upgrade. (I think this may be a pre-existing bug, although
it could likely only manifest in corner cases such as where we're pulling
a plan tree out of plancache. In most cases the first thing we'd acquire
on a rule target table is RowExclusiveLock in the parser, before any
rule rewriting could happen.)
4. I also notice some cases (all in FDW tests) where ExecOpenScanRelation
is choosing AccessShareLock although the RTE has RowShareLock. These seem
to all be cases where we're implementing FOR UPDATE/SHARE via
ROW_MARK_COPY, so that this:
ExecRowMark *erm = ExecFindRowMark(estate, scanrelid, true);
if (erm != NULL && erm->relation != NULL)
lockmode = NoLock;
leaves lockmode as AccessShareLock because erm->relation is NULL.
Again, I think this is probably OK, and it'd be better to use
RowShareLock for consistency with other places that might open
the rel. It will be a change in externally-visible behavior though.
Thoughts?
regards, tom lane
I wrote:
I started poking at this. I thought that it would be a good cross-check
to apply just the "front half" of 0001 (i.e., creation and population of
the RTE lockmode field), and then to insert checks in each of the
"back half" places (executor, plancache, etc) that the lockmodes they
are computing today match what is in the RTE.
Those checks fell over many times in the regression tests.
Here's a version that doesn't fall over (for me), incorporating fixes
as I suggested for points 1 and 2, and weakening the back-half assertions
enough to let points 3 and 4 succeed. I'm inclined to commit this to see
if the buildfarm can find any problems I missed.
Some cosmetic changes:
* I renamed the RTE field to rellockmode in the name of greppability.
* I rearranged the order of the arguments for
addRangeTableEntryForRelation to make it more consistent with the
other addRangeTableEntryXXX functions.
regards, tom lane
Attachments:
v11-add-rte-rellockmode-field.patchtext/x-diff; charset=us-ascii; name=v11-add-rte-rellockmode-field.patchDownload
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 4f1d365..7dfa327 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -1415,6 +1415,7 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
rte.rtekind = RTE_RELATION;
rte.relid = relId;
rte.relkind = RELKIND_RELATION; /* no need for exactness here */
+ rte.rellockmode = AccessShareLock;
context.rtables = list_make1(list_make1(&rte));
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 9176f62..4ad5868 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -2549,6 +2549,7 @@ AddRelationNewConstraints(Relation rel,
pstate->p_sourcetext = queryString;
rte = addRangeTableEntryForRelation(pstate,
rel,
+ AccessShareLock,
NULL,
false,
true);
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index d06662b..2d5bc8a 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -833,20 +833,21 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
if (stmt->relation)
{
+ LOCKMODE lockmode = is_from ? RowExclusiveLock : AccessShareLock;
+ RangeTblEntry *rte;
TupleDesc tupDesc;
List *attnums;
ListCell *cur;
- RangeTblEntry *rte;
Assert(!stmt->query);
/* Open and lock the relation, using the appropriate lock type. */
- rel = heap_openrv(stmt->relation,
- (is_from ? RowExclusiveLock : AccessShareLock));
+ rel = heap_openrv(stmt->relation, lockmode);
relid = RelationGetRelid(rel);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, false);
+ rte = addRangeTableEntryForRelation(pstate, rel, lockmode,
+ NULL, false, false);
rte->requiredPerms = (is_from ? ACL_INSERT : ACL_SELECT);
tupDesc = RelationGetDescr(rel);
diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c
index 3d82edb..d5cb62d 100644
--- a/src/backend/commands/createas.c
+++ b/src/backend/commands/createas.c
@@ -528,6 +528,7 @@ intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
rte->rtekind = RTE_RELATION;
rte->relid = intoRelationAddr.objectId;
rte->relkind = relkind;
+ rte->rellockmode = RowExclusiveLock;
rte->requiredPerms = ACL_INSERT;
for (attnum = 1; attnum <= intoRelationDesc->rd_att->natts; attnum++)
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index cee0ef9..2fd17b2 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -567,7 +567,9 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
qual_expr = stringToNode(qual_value);
/* Add this rel to the parsestate's rangetable, for dependencies */
- addRangeTableEntryForRelation(qual_pstate, rel, NULL, false, false);
+ addRangeTableEntryForRelation(qual_pstate, rel,
+ AccessShareLock,
+ NULL, false, false);
qual_parse_rtable = qual_pstate->p_rtable;
free_parsestate(qual_pstate);
@@ -589,8 +591,9 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
with_check_qual = stringToNode(with_check_value);
/* Add this rel to the parsestate's rangetable, for dependencies */
- addRangeTableEntryForRelation(with_check_pstate, rel, NULL, false,
- false);
+ addRangeTableEntryForRelation(with_check_pstate, rel,
+ AccessShareLock,
+ NULL, false, false);
with_check_parse_rtable = with_check_pstate->p_rtable;
free_parsestate(with_check_pstate);
@@ -752,11 +755,13 @@ CreatePolicy(CreatePolicyStmt *stmt)
/* Add for the regular security quals */
rte = addRangeTableEntryForRelation(qual_pstate, target_table,
+ AccessShareLock,
NULL, false, false);
addRTEtoQuery(qual_pstate, rte, false, true, true);
/* Add for the with-check quals */
rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
+ AccessShareLock,
NULL, false, false);
addRTEtoQuery(with_check_pstate, rte, false, true, true);
@@ -928,6 +933,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
ParseState *qual_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(qual_pstate, target_table,
+ AccessShareLock,
NULL, false, false);
addRTEtoQuery(qual_pstate, rte, false, true, true);
@@ -950,6 +956,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
ParseState *with_check_pstate = make_parsestate(NULL);
rte = addRangeTableEntryForRelation(with_check_pstate, target_table,
+ AccessShareLock,
NULL, false, false);
addRTEtoQuery(with_check_pstate, rte, false, true, true);
@@ -1096,8 +1103,9 @@ AlterPolicy(AlterPolicyStmt *stmt)
qual = stringToNode(qual_value);
/* Add this rel to the parsestate's rangetable, for dependencies */
- addRangeTableEntryForRelation(qual_pstate, target_table, NULL,
- false, false);
+ addRangeTableEntryForRelation(qual_pstate, target_table,
+ AccessShareLock,
+ NULL, false, false);
qual_parse_rtable = qual_pstate->p_rtable;
free_parsestate(qual_pstate);
@@ -1137,8 +1145,9 @@ AlterPolicy(AlterPolicyStmt *stmt)
with_check_qual = stringToNode(with_check_value);
/* Add this rel to the parsestate's rangetable, for dependencies */
- addRangeTableEntryForRelation(with_check_pstate, target_table, NULL,
- false, false);
+ addRangeTableEntryForRelation(with_check_pstate, target_table,
+ AccessShareLock,
+ NULL, false, false);
with_check_parse_rtable = with_check_pstate->p_rtable;
free_parsestate(with_check_pstate);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 29d8353..9e60bb3 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -13632,7 +13632,8 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
* rangetable entry. We need a ParseState for transformExpr.
*/
pstate = make_parsestate(NULL);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
+ rte = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
+ NULL, false, true);
addRTEtoQuery(pstate, rte, true, true, true);
/* take care of any partition expressions */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 36778b6..b2de1cc 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -577,10 +577,12 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
* 'OLD' must always have varno equal to 1 and 'NEW' equal to 2.
*/
rte = addRangeTableEntryForRelation(pstate, rel,
+ AccessShareLock,
makeAlias("old", NIL),
false, false);
addRTEtoQuery(pstate, rte, false, true, true);
rte = addRangeTableEntryForRelation(pstate, rel,
+ AccessShareLock,
makeAlias("new", NIL),
false, false);
addRTEtoQuery(pstate, rte, false, true, true);
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index ffb71c0..e73f1d8 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -353,7 +353,7 @@ DefineViewRules(Oid viewOid, Query *viewParse, bool replace)
* by 2...
*
* These extra RT entries are not actually used in the query,
- * except for run-time permission checking.
+ * except for run-time locking and permission checking.
*---------------------------------------------------------------
*/
static Query *
@@ -386,9 +386,11 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
* OLD first, then NEW....
*/
rt_entry1 = addRangeTableEntryForRelation(pstate, viewRel,
+ AccessShareLock,
makeAlias("old", NIL),
false, false);
rt_entry2 = addRangeTableEntryForRelation(pstate, viewRel,
+ AccessShareLock,
makeAlias("new", NIL),
false, false);
/* Must override addRangeTableEntry's default access-check flags */
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 5443cbf..2b7cf26 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -864,6 +864,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
Relation resultRelation;
resultRelationOid = getrelid(resultRelationIndex, rangeTable);
+ Assert(rt_fetch(resultRelationIndex, rangeTable)->rellockmode == RowExclusiveLock);
resultRelation = heap_open(resultRelationOid, RowExclusiveLock);
InitResultRelInfo(resultRelInfo,
@@ -904,6 +905,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
Relation resultRelDesc;
resultRelOid = getrelid(resultRelIndex, rangeTable);
+ Assert(rt_fetch(resultRelIndex, rangeTable)->rellockmode == RowExclusiveLock);
resultRelDesc = heap_open(resultRelOid, RowExclusiveLock);
InitResultRelInfo(resultRelInfo,
resultRelDesc,
@@ -924,8 +926,11 @@ InitPlan(QueryDesc *queryDesc, int eflags)
/* We locked the roots above. */
if (!list_member_int(plannedstmt->rootResultRelations,
resultRelIndex))
+ {
+ Assert(rt_fetch(resultRelIndex, rangeTable)->rellockmode == RowExclusiveLock);
LockRelationOid(getrelid(resultRelIndex, rangeTable),
RowExclusiveLock);
+ }
}
}
}
@@ -955,6 +960,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
{
PlanRowMark *rc = (PlanRowMark *) lfirst(l);
Oid relid;
+ LOCKMODE rellockmode;
Relation relation;
ExecRowMark *erm;
@@ -964,6 +970,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
/* get relation's OID (will produce InvalidOid if subquery) */
relid = getrelid(rc->rti, rangeTable);
+ rellockmode = rt_fetch(rc->rti, rangeTable)->rellockmode;
/*
* If you change the conditions under which rel locks are acquired
@@ -975,9 +982,13 @@ InitPlan(QueryDesc *queryDesc, int eflags)
case ROW_MARK_NOKEYEXCLUSIVE:
case ROW_MARK_SHARE:
case ROW_MARK_KEYSHARE:
+ Assert(rellockmode == RowShareLock);
relation = heap_open(relid, RowShareLock);
break;
case ROW_MARK_REFERENCE:
+ /* RTE might be a query target table */
+ Assert(rellockmode == AccessShareLock ||
+ rellockmode == RowExclusiveLock);
relation = heap_open(relid, AccessShareLock);
break;
case ROW_MARK_COPY:
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 5b3eaec..da84d5d 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -657,20 +657,32 @@ ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
/*
* 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.
+ * relation.
+ *
+ * Note: we may have already gotten the desired lock type, but for now
+ * don't try to optimize; this logic is going away soon anyhow.
*/
lockmode = AccessShareLock;
if (ExecRelationIsTargetRelation(estate, scanrelid))
- lockmode = NoLock;
+ lockmode = RowExclusiveLock;
else
{
/* Keep this check in sync with InitPlan! */
ExecRowMark *erm = ExecFindRowMark(estate, scanrelid, true);
- if (erm != NULL && erm->relation != NULL)
- lockmode = NoLock;
+ if (erm != NULL)
+ {
+ if (erm->markType == ROW_MARK_REFERENCE ||
+ erm->markType == ROW_MARK_COPY)
+ lockmode = AccessShareLock;
+ else
+ lockmode = RowShareLock;
+ }
}
+ /* lockmode per above logic must not be more than we previously acquired */
+ Assert(lockmode <= rt_fetch(scanrelid, estate->es_range_table)->rellockmode);
+
/* Open the relation and acquire lock as needed */
reloid = getrelid(scanrelid, estate->es_range_table);
rel = heap_open(reloid, lockmode);
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 7c8220c..925cb8f 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(rellockmode);
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 378f2fa..3bb91c9 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(rellockmode);
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 93f1e2c..22dbae1 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -3131,6 +3131,7 @@ _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
case RTE_RELATION:
WRITE_OID_FIELD(relid);
WRITE_CHAR_FIELD(relkind);
+ WRITE_INT_FIELD(rellockmode);
WRITE_NODE_FIELD(tablesample);
break;
case RTE_SUBQUERY:
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 519deab..ce55658 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1361,6 +1361,7 @@ _readRangeTblEntry(void)
case RTE_RELATION:
READ_OID_FIELD(relid);
READ_CHAR_FIELD(relkind);
+ READ_INT_FIELD(rellockmode);
READ_NODE_FIELD(tablesample);
break;
case RTE_SUBQUERY:
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 22c010c..89625f4 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -6021,6 +6021,7 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
rte->rtekind = RTE_RELATION;
rte->relid = tableOid;
rte->relkind = RELKIND_RELATION; /* Don't be too picky. */
+ rte->rellockmode = AccessShareLock;
rte->lateral = false;
rte->inh = false;
rte->inFromCl = true;
@@ -6143,6 +6144,7 @@ plan_create_index_workers(Oid tableOid, Oid indexOid)
rte->rtekind = RTE_RELATION;
rte->relid = tableOid;
rte->relkind = RELKIND_RELATION; /* Don't be too picky. */
+ rte->rellockmode = AccessShareLock;
rte->lateral = false;
rte->inh = true;
rte->inFromCl = true;
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index c020600..226927b 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -1037,6 +1037,7 @@ transformOnConflictClause(ParseState *pstate,
*/
exclRte = addRangeTableEntryForRelation(pstate,
targetrel,
+ RowExclusiveLock,
makeAlias("excluded", NIL),
false, false);
exclRte->relkind = RELKIND_COMPOSITE_TYPE;
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index d6b93f5..660011a 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -217,6 +217,7 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
* Now build an RTE.
*/
rte = addRangeTableEntryForRelation(pstate, pstate->p_target_relation,
+ RowExclusiveLock,
relation->alias, inh, false);
pstate->p_target_rangetblentry = rte;
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 60b8de0..da600dc 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -1208,15 +1208,22 @@ addRangeTableEntry(ParseState *pstate,
rte->alias = alias;
/*
+ * Identify the type of lock we'll need on this relation. It's not the
+ * query's target table (that case is handled elsewhere), so we need
+ * either RowShareLock if it's locked by FOR UPDATE/SHARE, or plain
+ * AccessShareLock otherwise.
+ */
+ lockmode = isLockedRefname(pstate, refname) ? RowShareLock : AccessShareLock;
+
+ /*
* Get the rel's OID. This access also ensures that we have an up-to-date
* relcache entry for the rel. Since this is typically the first access
- * to a rel in a statement, be careful to get the right access level
- * depending on whether we're doing SELECT FOR UPDATE/SHARE.
+ * to a rel in a statement, we must open the rel with the proper lockmode.
*/
- lockmode = isLockedRefname(pstate, refname) ? RowShareLock : AccessShareLock;
rel = parserOpenTable(pstate, relation, lockmode);
rte->relid = RelationGetRelid(rel);
rte->relkind = rel->rd_rel->relkind;
+ rte->rellockmode = lockmode;
/*
* Build the list of effective column names using user-supplied aliases
@@ -1262,10 +1269,20 @@ addRangeTableEntry(ParseState *pstate,
*
* This is just like addRangeTableEntry() except that it makes an RTE
* given an already-open relation instead of a RangeVar reference.
+ *
+ * lockmode is the lock type required for query execution; it must be one
+ * of AccessShareLock, RowShareLock, or RowExclusiveLock depending on the
+ * RTE's role within the query. The caller should always hold that lock mode
+ * or a stronger one.
+ *
+ * Note: properly, lockmode should be declared LOCKMODE not int, but that
+ * would require importing storage/lock.h into parse_relation.h. Since
+ * LOCKMODE is typedef'd as int anyway, that seems like overkill.
*/
RangeTblEntry *
addRangeTableEntryForRelation(ParseState *pstate,
Relation rel,
+ int lockmode,
Alias *alias,
bool inh,
bool inFromCl)
@@ -1275,10 +1292,15 @@ addRangeTableEntryForRelation(ParseState *pstate,
Assert(pstate != NULL);
+ Assert(lockmode == AccessShareLock ||
+ lockmode == RowShareLock ||
+ lockmode == RowExclusiveLock);
+
rte->rtekind = RTE_RELATION;
rte->alias = alias;
rte->relid = RelationGetRelid(rel);
rte->relkind = rel->rd_rel->relkind;
+ rte->rellockmode = 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 f5c1e2a..42bf9bf 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -2526,7 +2526,9 @@ transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
* relation, but we still need to open it.
*/
rel = relation_open(relid, NoLock);
- rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
+ rte = addRangeTableEntryForRelation(pstate, rel,
+ AccessShareLock,
+ NULL, false, true);
/* no to join list, yes to namespaces */
addRTEtoQuery(pstate, rte, false, true, true);
@@ -2635,9 +2637,11 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
* qualification.
*/
oldrte = addRangeTableEntryForRelation(pstate, rel,
+ AccessShareLock,
makeAlias("old", NIL),
false, false);
newrte = addRangeTableEntryForRelation(pstate, rel,
+ AccessShareLock,
makeAlias("new", NIL),
false, false);
/* Must override addRangeTableEntry's default access-check flags */
@@ -2733,9 +2737,11 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
* them in the joinlist.
*/
oldrte = addRangeTableEntryForRelation(sub_pstate, rel,
+ AccessShareLock,
makeAlias("old", NIL),
false, false);
newrte = addRangeTableEntryForRelation(sub_pstate, rel,
+ AccessShareLock,
makeAlias("new", NIL),
false, false);
oldrte->requiredPerms = 0;
@@ -2938,6 +2944,7 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
pstate->p_sourcetext = queryString;
rte = addRangeTableEntryForRelation(pstate,
rel,
+ AccessShareLock,
NULL,
false,
true);
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index acc6498..6e420d8 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -795,7 +795,8 @@ copy_table(Relation rel)
copybuf = makeStringInfo();
pstate = make_parsestate(NULL);
- addRangeTableEntryForRelation(pstate, rel, NULL, false, false);
+ addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
+ NULL, false, false);
attnamelist = make_copy_attnamelist(relmapentry);
cstate = BeginCopyFrom(pstate, rel, NULL, false, copy_read_data, attnamelist, NIL);
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 42345f9..e247539 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -199,6 +199,7 @@ create_estate_for_relation(LogicalRepRelMapEntry *rel)
rte->rtekind = RTE_RELATION;
rte->relid = RelationGetRelid(rel->localrel);
rte->relkind = rel->localrel->rd_rel->relkind;
+ rte->rellockmode = AccessShareLock;
estate->es_range_table = list_make1(rte);
resultRelInfo = makeNode(ResultRelInfo);
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 327e5c3..50788fe 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -89,6 +89,10 @@ static Bitmapset *adjust_view_column_set(Bitmapset *cols, List *targetlist);
* These locks will ensure that the relation schemas don't change under us
* while we are rewriting and planning the query.
*
+ * Caution: this may modify the querytree, therefore caller should usually
+ * have done a copyObject() to make a writable copy of the querytree in the
+ * current memory context.
+ *
* forExecute indicates that the query is about to be executed.
* If so, we'll acquire RowExclusiveLock on the query's resultRelation,
* RowShareLock on any relation accessed FOR [KEY] UPDATE/SHARE, and
@@ -101,13 +105,11 @@ static Bitmapset *adjust_view_column_set(Bitmapset *cols, List *targetlist);
* forUpdatePushedDown indicates that a pushed-down FOR [KEY] UPDATE/SHARE
* applies to the current subquery, requiring all rels to be opened with at
* least RowShareLock. This should always be false at the top of the
- * recursion. This flag is ignored if forExecute is false.
+ * recursion. This flag is ignored if forExecute is false. If it is true,
+ * though, we adjust RTE rellockmode fields to reflect the higher lock level.
*
* A secondary purpose of this routine is to fix up JOIN RTE references to
- * dropped columns (see details below). Because the RTEs are modified in
- * place, it is generally appropriate for the caller of this routine to have
- * first done a copyObject() to make a writable copy of the querytree in the
- * current memory context.
+ * dropped columns (see details below). Such RTEs are modified in-place.
*
* This processing can, and for efficiency's sake should, be skipped when the
* querytree has just been built by the parser: parse analysis already got
@@ -170,12 +172,22 @@ AcquireRewriteLocks(Query *parsetree,
lockmode = AccessShareLock;
else if (rt_index == parsetree->resultRelation)
lockmode = RowExclusiveLock;
- else if (forUpdatePushedDown ||
- get_parse_rowmark(parsetree, rt_index) != NULL)
+ else if (forUpdatePushedDown)
+ {
+ lockmode = RowShareLock;
+ /* Upgrade RTE's lock mode to reflect pushed-down lock */
+ if (rte->rellockmode == AccessShareLock)
+ rte->rellockmode = RowShareLock;
+ }
+ else if (get_parse_rowmark(parsetree, rt_index) != NULL)
lockmode = RowShareLock;
else
lockmode = AccessShareLock;
+ Assert(!forExecute || lockmode == rte->rellockmode ||
+ (lockmode == AccessShareLock &&
+ rte->rellockmode == RowExclusiveLock));
+
rel = heap_open(rte->relid, lockmode);
/*
@@ -1593,6 +1605,7 @@ ApplyRetrieveRule(Query *parsetree,
/* Clear fields that should not be set in a subquery RTE */
rte->relid = InvalidOid;
rte->relkind = 0;
+ rte->rellockmode = 0;
rte->tablesample = NULL;
rte->inh = false; /* must not be set for a subquery */
@@ -2920,8 +2933,14 @@ rewriteTargetView(Query *parsetree, Relation view)
* very much like what the planner would do to "pull up" the view into the
* outer query. Perhaps someday we should refactor things enough so that
* we can share code with the planner.)
+ *
+ * Be sure to set rellockmode to the correct thing for the target table.
+ * Since we copied the whole viewquery above, we can just scribble on
+ * base_rte instead of copying it.
*/
- new_rte = (RangeTblEntry *) base_rte;
+ new_rte = base_rte;
+ new_rte->rellockmode = RowExclusiveLock;
+
parsetree->rtable = lappend(parsetree->rtable, new_rte);
new_rt_index = list_length(parsetree->rtable);
@@ -3101,8 +3120,8 @@ rewriteTargetView(Query *parsetree, Relation view)
new_exclRte = addRangeTableEntryForRelation(make_parsestate(NULL),
base_rel,
- makeAlias("excluded",
- NIL),
+ RowExclusiveLock,
+ makeAlias("excluded", NIL),
false, false);
new_exclRte->relkind = RELKIND_COMPOSITE_TYPE;
new_exclRte->requiredPerms = 0;
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index fc034ce..049b204 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -1878,12 +1878,14 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
pkrte->rtekind = RTE_RELATION;
pkrte->relid = RelationGetRelid(pk_rel);
pkrte->relkind = pk_rel->rd_rel->relkind;
+ pkrte->rellockmode = AccessShareLock;
pkrte->requiredPerms = ACL_SELECT;
fkrte = makeNode(RangeTblEntry);
fkrte->rtekind = RTE_RELATION;
fkrte->relid = RelationGetRelid(fk_rel);
fkrte->relkind = fk_rel->rd_rel->relkind;
+ fkrte->rellockmode = AccessShareLock;
fkrte->requiredPerms = ACL_SELECT;
for (i = 0; i < riinfo->nkeys; i++)
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index eecd64e..f6693ea 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -1000,6 +1000,7 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
oldrte->rtekind = RTE_RELATION;
oldrte->relid = trigrec->tgrelid;
oldrte->relkind = relkind;
+ oldrte->rellockmode = AccessShareLock;
oldrte->alias = makeAlias("old", NIL);
oldrte->eref = oldrte->alias;
oldrte->lateral = false;
@@ -1010,6 +1011,7 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
newrte->rtekind = RTE_RELATION;
newrte->relid = trigrec->tgrelid;
newrte->relkind = relkind;
+ newrte->rellockmode = AccessShareLock;
newrte->alias = makeAlias("new", NIL);
newrte->eref = newrte->alias;
newrte->lateral = false;
@@ -3206,6 +3208,7 @@ deparse_context_for(const char *aliasname, Oid relid)
rte->rtekind = RTE_RELATION;
rte->relid = relid;
rte->relkind = RELKIND_RELATION; /* no need for exactness here */
+ rte->rellockmode = AccessShareLock;
rte->alias = makeAlias(aliasname, NIL);
rte->eref = rte->alias;
rte->lateral = false;
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 7271b58..15df189 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -1539,6 +1539,8 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
else
lockmode = AccessShareLock;
+ Assert(lockmode == rte->rellockmode);
+
if (acquire)
LockRelationOid(rte->relid, lockmode);
else
@@ -1609,6 +1611,8 @@ ScanQueryForLocks(Query *parsetree, bool acquire)
lockmode = RowShareLock;
else
lockmode = AccessShareLock;
+ Assert(lockmode == rte->rellockmode ||
+ (lockmode == AccessShareLock && rte->rellockmode == RowExclusiveLock));
if (acquire)
LockRelationOid(rte->relid, lockmode);
else
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 07e0576..1e064d4 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201809241
+#define CATALOG_VERSION_NO 201809291
#endif
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 62209a8..3056819 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -973,9 +973,21 @@ typedef struct RangeTblEntry
* that the tuple format of the tuplestore is the same as the referenced
* relation. This allows plans referencing AFTER trigger transition
* tables to be invalidated if the underlying table is altered.
+ *
+ * rellockmode is really LOCKMODE, but it's declared int to avoid having
+ * to include lock-related headers here. It must be RowExclusiveLock if
+ * the RTE is an INSERT/UPDATE/DELETE target, else RowShareLock if the RTE
+ * is a SELECT FOR UPDATE/FOR SHARE source, else AccessShareLock.
+ *
+ * Note: in some cases, rule expansion may result in RTEs that are marked
+ * with RowExclusiveLock even though they are not the target of the
+ * current query; this happens if a DO ALSO rule simply scans the original
+ * target table. We leave such RTEs with their original lockmode so as to
+ * avoid getting an additional, lesser lock.
*/
Oid relid; /* OID of the relation */
char relkind; /* relation kind (see pg_class.relkind) */
+ int rellockmode; /* lock level that query requires on the rel */
struct TableSampleClause *tablesample; /* sampling info, or NULL */
/*
diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h
index b9792ac..687a7d7 100644
--- a/src/include/parser/parse_relation.h
+++ b/src/include/parser/parse_relation.h
@@ -69,6 +69,7 @@ extern RangeTblEntry *addRangeTableEntry(ParseState *pstate,
bool inFromCl);
extern RangeTblEntry *addRangeTableEntryForRelation(ParseState *pstate,
Relation rel,
+ int lockmode,
Alias *alias,
bool inh,
bool inFromCl);
diff --git a/src/test/modules/test_rls_hooks/test_rls_hooks.c b/src/test/modules/test_rls_hooks/test_rls_hooks.c
index cab67a6..d492697 100644
--- a/src/test/modules/test_rls_hooks/test_rls_hooks.c
+++ b/src/test/modules/test_rls_hooks/test_rls_hooks.c
@@ -80,8 +80,8 @@ test_rls_hooks_permissive(CmdType cmdtype, Relation relation)
qual_pstate = make_parsestate(NULL);
- rte = addRangeTableEntryForRelation(qual_pstate, relation, NULL, false,
- false);
+ rte = addRangeTableEntryForRelation(qual_pstate, relation, AccessShareLock,
+ NULL, false, false);
addRTEtoQuery(qual_pstate, rte, false, true, true);
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
@@ -143,8 +143,8 @@ test_rls_hooks_restrictive(CmdType cmdtype, Relation relation)
qual_pstate = make_parsestate(NULL);
- rte = addRangeTableEntryForRelation(qual_pstate, relation, NULL, false,
- false);
+ rte = addRangeTableEntryForRelation(qual_pstate, relation, AccessShareLock,
+ NULL, false, false);
addRTEtoQuery(qual_pstate, rte, false, true, true);
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
I wrote:
1. You set up transformRuleStmt to insert AccessExclusiveLock into
the "OLD" and "NEW" RTEs for a view. This is surely wrong; we do
not want to take exclusive lock on a view just to run a query using
the view. It should (usually, anyway) just be AccessShareLock.
However, because addRangeTableEntryForRelation insists that you
hold the requested lock type *now*, just changing the parameter
to AccessShareLock doesn't work.
I hacked around this for the moment by passing NoLock to
addRangeTableEntryForRelation and then changing rte->lockmode
after it returns, but man that's ugly. It makes me wonder whether
addRangeTableEntryForRelation should be checking the lockmode at all.
It occurred to me that it'd be reasonable to insist that the caller
holds a lock *at least as strong* as the one being recorded in the RTE,
and that there's also been discussions about verifying that some lock
is held when something like heap_open(foo, NoLock) is attempted.
So I dusted off the part of 0001 that did that, producing the
attached delta patch.
Unfortunately, I can't commit this, because it exposes at least two
pre-existing bugs :-(. So we'll need to fix those first, which seems
like it should be a separate thread. I'm just parking this here for
the moment.
I think that the call sites should ultimately look like
Assert(CheckRelationLockedByMe(...));
but for hunting down the places where the assertion currently fails,
it's more convenient if it's just an elog(WARNING).
regards, tom lane
Attachments:
check-relation-lock-held-1.patchtext/x-diff; charset=us-ascii; name=check-relation-lock-held-1.patchDownload
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 3395445..f8a55ee 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -1137,6 +1137,11 @@ relation_open(Oid relationId, LOCKMODE lockmode)
if (!RelationIsValid(r))
elog(ERROR, "could not open relation with OID %u", relationId);
+ if (lockmode == NoLock &&
+ !CheckRelationLockedByMe(r, AccessShareLock, true))
+ elog(WARNING, "relation_open: no lock held on %s",
+ RelationGetRelationName(r));
+
/* Make note that we've accessed a temporary relation */
if (RelationUsesLocalBuffers(r))
MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPREL;
@@ -1183,6 +1188,11 @@ try_relation_open(Oid relationId, LOCKMODE lockmode)
if (!RelationIsValid(r))
elog(ERROR, "could not open relation with OID %u", relationId);
+ if (lockmode == NoLock &&
+ !CheckRelationLockedByMe(r, AccessShareLock, true))
+ elog(WARNING, "try_relation_open: no lock held on %s",
+ RelationGetRelationName(r));
+
/* Make note that we've accessed a temporary relation */
if (RelationUsesLocalBuffers(r))
MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPREL;
@@ -8084,6 +8094,10 @@ ExtractReplicaIdentity(Relation relation, HeapTuple tp, bool key_changed, bool *
idx_rel = RelationIdGetRelation(replidindex);
+ if (!CheckRelationLockedByMe(idx_rel, AccessShareLock, true))
+ elog(WARNING, "ExtractReplicaIdentity: no lock held on %s",
+ RelationGetRelationName(idx_rel));
+
/* deform tuple, so we have fast access to columns */
heap_deform_tuple(tp, desc, values, nulls);
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index da600dc..aaf5544 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -28,6 +28,7 @@
#include "parser/parse_enr.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
+#include "storage/lmgr.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
@@ -1272,7 +1273,7 @@ addRangeTableEntry(ParseState *pstate,
*
* lockmode is the lock type required for query execution; it must be one
* of AccessShareLock, RowShareLock, or RowExclusiveLock depending on the
- * RTE's role within the query. The caller should always hold that lock mode
+ * RTE's role within the query. The caller must hold that lock mode
* or a stronger one.
*
* Note: properly, lockmode should be declared LOCKMODE not int, but that
@@ -1295,6 +1296,9 @@ addRangeTableEntryForRelation(ParseState *pstate,
Assert(lockmode == AccessShareLock ||
lockmode == RowShareLock ||
lockmode == RowExclusiveLock);
+ if (!CheckRelationLockedByMe(rel, lockmode, true))
+ elog(WARNING, "addRangeTableEntryForRelation: no lock held on %s",
+ RelationGetRelationName(rel));
rte->rtekind = RTE_RELATION;
rte->alias = alias;
diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c
index dc0a439..517ff8e 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -288,6 +288,51 @@ UnlockRelation(Relation relation, LOCKMODE lockmode)
}
/*
+ * CheckRelationLockedByMe
+ *
+ * Returns true if current transaction holds a lock on 'relation' of mode
+ * 'lockmode'. If 'orstronger' is true, a stronger lockmode is also OK.
+ * ("Stronger" is defined as "numerically higher", which is a bit
+ * semantically dubious but is OK for the purposes we use this for.)
+ */
+bool
+CheckRelationLockedByMe(Relation relation, LOCKMODE lockmode, bool orstronger)
+{
+ LOCKTAG tag;
+
+ SET_LOCKTAG_RELATION(tag,
+ relation->rd_lockInfo.lockRelId.dbId,
+ relation->rd_lockInfo.lockRelId.relId);
+
+ if (LockHeldByMe(&tag, lockmode))
+ return true;
+
+ if (orstronger)
+ {
+ LOCKMODE slockmode;
+
+ for (slockmode = lockmode + 1;
+ slockmode <= AccessExclusiveLock;
+ slockmode++)
+ {
+ if (LockHeldByMe(&tag, slockmode))
+ {
+#ifdef NOT_USED
+ /* Sometimes this might be useful for debugging purposes */
+ elog(WARNING, "lock mode %s substituted for %s on relation %s",
+ GetLockmodeName(tag.locktag_lockmethodid, slockmode),
+ GetLockmodeName(tag.locktag_lockmethodid, lockmode),
+ RelationGetRelationName(relation));
+#endif
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/*
* LockHasWaitersRelation
*
* This is a function to check whether someone else is waiting for a
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 831ae62..10f6f60 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -564,6 +564,30 @@ DoLockModesConflict(LOCKMODE mode1, LOCKMODE mode2)
}
/*
+ * LockHeldByMe -- test whether lock 'locktag' is held with mode 'lockmode'
+ * by the current transaction
+ */
+bool
+LockHeldByMe(const LOCKTAG *locktag, LOCKMODE lockmode)
+{
+ LOCALLOCKTAG localtag;
+ LOCALLOCK *locallock;
+
+ /*
+ * See if there is a LOCALLOCK entry for this lock and lockmode
+ */
+ MemSet(&localtag, 0, sizeof(localtag)); /* must clear padding */
+ localtag.lock = *locktag;
+ localtag.mode = lockmode;
+
+ locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash,
+ (void *) &localtag,
+ HASH_FIND, NULL);
+
+ return (locallock && locallock->nLocks > 0);
+}
+
+/*
* LockHasWaiters -- look up 'locktag' and check if releasing this
* lock would wake up other processes waiting for it.
*/
diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h
index a217de9..e5356b7 100644
--- a/src/include/storage/lmgr.h
+++ b/src/include/storage/lmgr.h
@@ -45,6 +45,8 @@ extern void UnlockRelationOid(Oid relid, LOCKMODE lockmode);
extern void LockRelation(Relation relation, LOCKMODE lockmode);
extern bool ConditionalLockRelation(Relation relation, LOCKMODE lockmode);
extern void UnlockRelation(Relation relation, LOCKMODE lockmode);
+extern bool CheckRelationLockedByMe(Relation relation, LOCKMODE lockmode,
+ bool orstronger);
extern bool LockHasWaitersRelation(Relation relation, LOCKMODE lockmode);
extern void LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode);
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index ff4df7f..a37fda7 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -540,6 +540,7 @@ extern void LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks);
extern void LockReleaseSession(LOCKMETHODID lockmethodid);
extern void LockReleaseCurrentOwner(LOCALLOCK **locallocks, int nlocks);
extern void LockReassignCurrentOwner(LOCALLOCK **locallocks, int nlocks);
+extern bool LockHeldByMe(const LOCKTAG *locktag, LOCKMODE lockmode);
extern bool LockHasWaiters(const LOCKTAG *locktag,
LOCKMODE lockmode, bool sessionLock);
extern VirtualTransactionId *GetLockConflicts(const LOCKTAG *locktag,
On 1 October 2018 at 06:18, Tom Lane <tgl@sss.pgh.pa.us> wrote:
It occurred to me that it'd be reasonable to insist that the caller
holds a lock *at least as strong* as the one being recorded in the RTE,
and that there's also been discussions about verifying that some lock
is held when something like heap_open(foo, NoLock) is attempted.
So I dusted off the part of 0001 that did that, producing the
attached delta patch.
My imagination struggles to think of a case, but perhaps one day in
the future we might have a lock manager that coordinates locks on
multiple nodes. If so, is there not a risk that one day we might have
a lock level greater than AccessExclusiveLock, meaning the following
would get broken:
+ for (slockmode = lockmode + 1;
+ slockmode <= AccessExclusiveLock;
+ slockmode++)
For index strategies we do:
#define BTGreaterStrategyNumber 5
#define BTMaxStrategyNumber 5
So would it not be better to add the following to lockdefs.h?
#define MaxLockLevel 8
then use that to terminate the loop.
--
David Rowley http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
David Rowley <david.rowley@2ndquadrant.com> writes:
On 1 October 2018 at 06:18, Tom Lane <tgl@sss.pgh.pa.us> wrote:
+ for (slockmode = lockmode + 1; + slockmode <= AccessExclusiveLock; + slockmode++)
So would it not be better to add the following to lockdefs.h?
#define MaxLockLevel 8
then use that to terminate the loop.
Good idea, will do.
regards, tom lane
On 2018/09/30 5:04, Tom Lane wrote:
David Rowley <david.rowley@2ndquadrant.com> writes:
I've attached v10 which fixes this and aligns the WARNING text in
ExecInitRangeTable() and addRangeTableEntryForRelation().I started poking at this.
Thanks a lot for looking at this.
I thought that it would be a good cross-check
to apply just the "front half" of 0001 (i.e., creation and population of
the RTE lockmode field), and then to insert checks in each of the
"back half" places (executor, plancache, etc) that the lockmodes they
are computing today match what is in the RTE.Those checks fell over many times in the regression tests.
There seem to be at least four distinct problems:
1. You set up transformRuleStmt to insert AccessExclusiveLock into
the "OLD" and "NEW" RTEs for a view. This is surely wrong; we do
not want to take exclusive lock on a view just to run a query using
the view. It should (usually, anyway) just be AccessShareLock.However, because addRangeTableEntryForRelation insists that you
hold the requested lock type *now*, just changing the parameter
to AccessShareLock doesn't work.I hacked around this for the moment by passing NoLock to
addRangeTableEntryForRelation and then changing rte->lockmode
after it returns, but man that's ugly. It makes me wonder whether
addRangeTableEntryForRelation should be checking the lockmode at all.I'm inclined to think we should remove the check for current lockmode
in addRangeTableEntryForRelation, and instead just assert that the
passed lockmode must be one of AccessShareLock, RowShareLock, or
RowExclusiveLock depending on whether the RTE is meant to represent
a plain source table, a FOR UPDATE/SHARE source table, or a target
table. I don't think it's that helpful to be checking that the
caller got exactly the same lock, especially given the number of
places where the patch had to cheat already by using NoLock.
Yeah, addRangeTableEntryForRelation should not insist on holding the
"exact" lock, but rather *at least* as strong as the passed in lock mode.
I see that the patch you posted downthread does that.
In the original patch, the lock mode used for handling the CREATE RULE
command was being conflated with the lock mode to require on NEW and OLD
RTEs that will be added to the rule's query.
2. The "forUpdatePushedDown" override in AcquireRewriteLocks isn't
getting modeled in the RTE lockmode fields. In other words, if we
have something likeCREATE VIEW vv AS SELECT * FROM tab1;
SELECT * FROM vv FOR UPDATE OF vv;the checks fall over, because the tab1 RTE in the view's rangetable
just has AccessShareLock, but we need RowShareLock. I fixed this
by having AcquireRewriteLocks actually modify the RTE if it is
promoting the lock level. This is kinda grotty, but we were already
assuming that AcquireRewriteLocks could scribble on the query tree,
so it seems safe enough.
Thanks for fixing that.
3. There remain some cases where the RTE says RowExclusiveLock but
the executor calculation indicates we only need AccessShareLock.
AFAICT, this happens only when we have a DO ALSO rule that results
in an added query that merely scans the target table.
I've seen something like that happen for ON CONFLICT's excluded
pseudo-relation RTE too, because the executor deems only the RTE fetched
with result relation RT index to require RowExclusiveLock.
The RTE used
for that purpose is just the original one, so it still has a lockmode
suitable for a target table.We could probably hack the rewriter so that it changes the RTE lockmode
back down to AccessShareLock in these cases.
Is the problematic RTE one coming from an action query? If so, isn't it
distinct from the original RTE and its rellockmode independently
determined based on whether the action is select or not?
I'm not sure if I understand why we'd need to change its lock mode.
However, I'm inclined to
think that that is something *not* to do, and that we should let the
higher lockmode be used instead, for two reasons:(1) Asking for both AccessShareLock and RowExclusiveLock on the same
table requires an extra trip through the shared lock manager, for little
value that I can see.(2) If the DO ALSO rule is run before the main one, we'd be acquiring
AccessShareLock before RowExclusiveLock, resulting in deadlock hazard
due to lock upgrade. (I think this may be a pre-existing bug, although
it could likely only manifest in corner cases such as where we're pulling
a plan tree out of plancache. In most cases the first thing we'd acquire
on a rule target table is RowExclusiveLock in the parser, before any
rule rewriting could happen.)4. I also notice some cases (all in FDW tests) where ExecOpenScanRelation
is choosing AccessShareLock although the RTE has RowShareLock. These seem
to all be cases where we're implementing FOR UPDATE/SHARE via
ROW_MARK_COPY, so that this:ExecRowMark *erm = ExecFindRowMark(estate, scanrelid, true);
if (erm != NULL && erm->relation != NULL)
lockmode = NoLock;leaves lockmode as AccessShareLock because erm->relation is NULL.
Again, I think this is probably OK, and it'd be better to use
RowShareLock for consistency with other places that might open
the rel. It will be a change in externally-visible behavior though.
For this and the other cases (AcquireRewriteLocks, AcquireExecutorLocks,
etc.), I wonder whether we couldn't just *not* recalculate the lock mode
based on inspecting the query tree to cross-check with rellockmode? Why
not just use rellockmode for locking? Maybe, okay to keep doing that in
debug builds though. Also, are the discrepancies like this to be
considered bugs of the existing logic?
Thanks,
Amit
On 2018/10/01 2:18, Tom Lane wrote:
I wrote:
1. You set up transformRuleStmt to insert AccessExclusiveLock into
the "OLD" and "NEW" RTEs for a view. This is surely wrong; we do
not want to take exclusive lock on a view just to run a query using
the view. It should (usually, anyway) just be AccessShareLock.
However, because addRangeTableEntryForRelation insists that you
hold the requested lock type *now*, just changing the parameter
to AccessShareLock doesn't work.
I hacked around this for the moment by passing NoLock to
addRangeTableEntryForRelation and then changing rte->lockmode
after it returns, but man that's ugly. It makes me wonder whether
addRangeTableEntryForRelation should be checking the lockmode at all.It occurred to me that it'd be reasonable to insist that the caller
holds a lock *at least as strong* as the one being recorded in the RTE,
and that there's also been discussions about verifying that some lock
is held when something like heap_open(foo, NoLock) is attempted.
So I dusted off the part of 0001 that did that, producing the
attached delta patch.Unfortunately, I can't commit this, because it exposes at least two
pre-existing bugs :-(. So we'll need to fix those first, which seems
like it should be a separate thread. I'm just parking this here for
the moment.I think that the call sites should ultimately look like
Assert(CheckRelationLockedByMe(...));
but for hunting down the places where the assertion currently fails,
it's more convenient if it's just an elog(WARNING).
Should this check that we're not in a parallel worker process?
Thanks,
Amit
Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> writes:
On 2018/09/30 5:04, Tom Lane wrote:
3. There remain some cases where the RTE says RowExclusiveLock but
the executor calculation indicates we only need AccessShareLock.
AFAICT, this happens only when we have a DO ALSO rule that results
in an added query that merely scans the target table.
I've seen something like that happen for ON CONFLICT's excluded
pseudo-relation RTE too, because the executor deems only the RTE fetched
with result relation RT index to require RowExclusiveLock.
OK, I had not carefully inspected every case.
For this and the other cases (AcquireRewriteLocks, AcquireExecutorLocks,
etc.), I wonder whether we couldn't just *not* recalculate the lock mode
based on inspecting the query tree to cross-check with rellockmode? Why
not just use rellockmode for locking?
Right, that's exactly where we want to end up. This intermediate state of
the patch is just an attempt to verify that we understand when and how
relying on rellockmode will change the behavior.
Also, are the discrepancies like this to be
considered bugs of the existing logic?
Mmm ... hard to say. In the DO ALSO case, it's possible that query
execution would take AccessShareLock and then RowExclusiveLock, which
at least in principle creates a lock-upgrade deadlock hazard. So I
think standardizing on taking the rellockmode will be an improvement,
but I don't know that I'd call the existing behavior a bug; I certainly
wouldn't risk trying to back-patch a change for it.
In the ROW_MARK_COPY case, it's conceivable that with the existing code
query re-execution would take only AccessShareLock on a FOR UPDATE target
table, where the parser had originally taken RowShareLock. Again, it
seems like making the behavior more consistent is an improvement, but
not something we'd try to back-patch.
regards, tom lane
Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> writes:
On 2018/10/01 2:18, Tom Lane wrote:
I think that the call sites should ultimately look like
Assert(CheckRelationLockedByMe(...));
but for hunting down the places where the assertion currently fails,
it's more convenient if it's just an elog(WARNING).
Should this check that we're not in a parallel worker process?
Hmm. I've not seen any failures in the parallel parts of the regular
regression tests, but maybe I'd better do a force_parallel_mode
run before committing.
In general, I'm not on board with the idea that parallel workers don't
need to get their own locks, so I don't really want to exclude parallel
workers from this check. But if it's not safe for that today, fixing it
is beyond the scope of this particular patch.
regards, tom lane
On 1 October 2018 at 19:39, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote:
For this and the other cases (AcquireRewriteLocks, AcquireExecutorLocks,
etc.), I wonder whether we couldn't just *not* recalculate the lock mode
based on inspecting the query tree to cross-check with rellockmode? Why
not just use rellockmode for locking? Maybe, okay to keep doing that in
debug builds though. Also, are the discrepancies like this to be
considered bugs of the existing logic?
I got the impression Tom was just leaving that in for a while to let
the buildfarm verify the new code is getting the same lock level as
the old code. Of course, I might be wrong.
--
David Rowley http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
David Rowley <david.rowley@2ndquadrant.com> writes:
On 1 October 2018 at 19:39, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote:
For this and the other cases (AcquireRewriteLocks, AcquireExecutorLocks,
etc.), I wonder whether we couldn't just *not* recalculate the lock mode
based on inspecting the query tree to cross-check with rellockmode? Why
not just use rellockmode for locking? Maybe, okay to keep doing that in
debug builds though. Also, are the discrepancies like this to be
considered bugs of the existing logic?
I got the impression Tom was just leaving that in for a while to let
the buildfarm verify the new code is getting the same lock level as
the old code. Of course, I might be wrong.
Yeah, exactly. My plan is to next switch to taking the locks based on
rellockmode, and then if that doesn't show any problems to switch the
executor to just Assert that there's already a suitable lock, and then
lastly to proceed with ripping out the no-longer-needed logic that
supports the downstream calculations of lockmode. So a bit more granular
than what Amit submitted, but we'll get to the same place in the end,
with more confidence that we didn't break anything.
regards, tom lane
I wrote:
Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> writes:
Should this check that we're not in a parallel worker process?
Hmm. I've not seen any failures in the parallel parts of the regular
regression tests, but maybe I'd better do a force_parallel_mode
run before committing.
In general, I'm not on board with the idea that parallel workers don't
need to get their own locks, so I don't really want to exclude parallel
workers from this check. But if it's not safe for that today, fixing it
is beyond the scope of this particular patch.
So the place where that came out in the wash is the commit I just made
(9a3cebeaa) to change the executor from taking table locks to asserting
that somebody else took them already. To make that work, I had to make
both ExecOpenScanRelation and relation_open skip checking for lock-held
if IsParallelWorker().
This makes me entirely uncomfortable with the idea that parallel workers
can be allowed to not take any locks of their own. There is no basis
for arguing that we have field proof that that's safe, because *up to
now, parallel workers in fact did take their own locks*. And it seems
unsafe on its face, because there's nothing that really guarantees that
the parent process won't go away while children are still running.
(elog(FATAL) seems like a counterexample, for instance.)
I think that we ought to adjust parallel query to insist that children
do take locks, and then revert the IsParallelWorker() exceptions I made
here. I plan to leave that point in abeyance till we've got the rest
of these changes in place, though. The easiest way to do it will
doubtless change once we've centralized the executor's table-opening
logic, so trying to code it right now seems like a waste of effort.
regards, tom lane
On 2018/10/04 5:16, Tom Lane wrote:
I wrote:
Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> writes:
Should this check that we're not in a parallel worker process?
Hmm. I've not seen any failures in the parallel parts of the regular
regression tests, but maybe I'd better do a force_parallel_mode
run before committing.
In general, I'm not on board with the idea that parallel workers don't
need to get their own locks, so I don't really want to exclude parallel
workers from this check. But if it's not safe for that today, fixing it
is beyond the scope of this particular patch.So the place where that came out in the wash is the commit I just made
(9a3cebeaa) to change the executor from taking table locks to asserting
that somebody else took them already.
Thanks for getting that done.
To make that work, I had to make
both ExecOpenScanRelation and relation_open skip checking for lock-held
if IsParallelWorker().
Yeah, I had to do that to when rebasing the remaining patches.
This makes me entirely uncomfortable with the idea that parallel workers
can be allowed to not take any locks of their own. There is no basis
for arguing that we have field proof that that's safe, because *up to
now, parallel workers in fact did take their own locks*. And it seems
unsafe on its face, because there's nothing that really guarantees that
the parent process won't go away while children are still running.
(elog(FATAL) seems like a counterexample, for instance.)I think that we ought to adjust parallel query to insist that children
do take locks, and then revert the IsParallelWorker() exceptions I made
here.
Maybe I'm missing something here, but isn't the necessary adjustment just
that the relations are opened with locks if inside a parallel worker?
I plan to leave that point in abeyance till we've got the rest
of these changes in place, though. The easiest way to do it will
doubtless change once we've centralized the executor's table-opening
logic, so trying to code it right now seems like a waste of effort.
Okay.
I've rebased the remaining patches. I broke down one of the patches into
2 and re-ordered the patches as follows:
0001: introduces a function that opens range table relations and maintains
them in an array indexes by RT index
0002: introduces a new field in EState that's an array of RangeTblEntry
pointers and revises macros used in the executor that access RTEs to
return them from the array (David Rowley co-authored this one)
0003: moves result relation and ExecRowMark initialization out of InitPlan
and into ExecInit* routines of respective nodes
0004: removes useless fields from certain planner nodes whose only purpose
has been to assist the executor lock relations in proper order
0005: teaches planner to remove PlanRowMarks corresponding to dummy relations
Thanks,
Amit
Attachments:
v12-0001-Revise-executor-range-table-relation-locking-and.patchtext/plain; charset=UTF-8; name=v12-0001-Revise-executor-range-table-relation-locking-and.patchDownload
From ebef0d923ea8a1d5e458c9a60845bad68904cb52 Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Thu, 27 Sep 2018 16:14:41 +1200
Subject: [PATCH v12 1/5] Revise executor range table relation locking and
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, an arrangement which allows the executor
to have to heap_open any given range table relation only once.
Relations are closed by ExecEndPlan() instead of ExecEndNode.
This needed revising PartitionedRelPruneInfo node to contain the
partitioned table's RT index instead of OID. With that change,
ExecCreatePartitionPruneState can use ExecRangeTableRelation described
above.
---
contrib/postgres_fdw/postgres_fdw.c | 4 --
src/backend/executor/README | 4 +-
src/backend/executor/execMain.c | 61 +++++++++++++------------------
src/backend/executor/execPartition.c | 34 ++---------------
src/backend/executor/execUtils.c | 60 +++++++++++++++---------------
src/backend/executor/nodeAppend.c | 6 ---
src/backend/executor/nodeBitmapHeapscan.c | 7 ----
src/backend/executor/nodeCustom.c | 4 --
src/backend/executor/nodeForeignscan.c | 4 --
src/backend/executor/nodeIndexonlyscan.c | 7 ----
src/backend/executor/nodeIndexscan.c | 7 ----
src/backend/executor/nodeMergeAppend.c | 6 ---
src/backend/executor/nodeModifyTable.c | 4 +-
src/backend/executor/nodeSamplescan.c | 5 ---
src/backend/executor/nodeSeqscan.c | 7 ----
src/backend/executor/nodeTidscan.c | 5 ---
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/include/executor/execPartition.h | 1 -
src/include/executor/executor.h | 2 +-
src/include/nodes/execnodes.h | 2 +
src/include/nodes/plannodes.h | 2 +-
25 files changed, 100 insertions(+), 173 deletions(-)
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 6cbba97c22..c02287a55c 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -2546,10 +2546,6 @@ postgresEndDirectModify(ForeignScanState *node)
ReleaseConnection(dmstate->conn);
dmstate->conn = NULL;
- /* close the target relation. */
- if (dmstate->resultRel)
- ExecCloseScanRelation(dmstate->resultRel);
-
/* MemoryContext will be deleted automatically. */
}
diff --git a/src/backend/executor/README b/src/backend/executor/README
index 0d7cd552eb..30df410e0e 100644
--- a/src/backend/executor/README
+++ b/src/backend/executor/README
@@ -267,8 +267,8 @@ This is a sketch of control flow for full query processing:
Per above comments, it's not really critical for ExecEndNode to free any
memory; it'll all go away in FreeExecutorState anyway. However, we do need to
-be careful to close relations, drop buffer pins, etc, so we do need to scan
-the plan state tree to find these sorts of resources.
+be careful to drop buffer pins, etc, so we do need to scan the plan state tree
+to find these sorts of resources.
The executor can also be used to evaluate simple expressions without any Plan
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 9569d2fa42..4ec47ac41e 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -824,6 +824,15 @@ InitPlan(QueryDesc *queryDesc, int eflags)
* initialize the node's execution state
*/
estate->es_range_table = rangeTable;
+
+ /*
+ * Allocate an array to store open Relations of each rangeTable item. We
+ * zero-fill this for now. The Relations are only opened and stored here
+ * the first time they're required during node initialization.
+ */
+ estate->es_relations = (Relation *) palloc0(list_length(rangeTable) *
+ sizeof(Relation));
+
estate->es_plannedstmt = plannedstmt;
/*
@@ -845,13 +854,10 @@ InitPlan(QueryDesc *queryDesc, int eflags)
foreach(l, resultRelations)
{
Index resultRelationIndex = lfirst_int(l);
- Oid resultRelationOid;
Relation resultRelation;
- resultRelationOid = getrelid(resultRelationIndex, rangeTable);
- resultRelation = heap_open(resultRelationOid, NoLock);
- Assert(CheckRelationLockedByMe(resultRelation, RowExclusiveLock, true));
-
+ Assert(rt_fetch(resultRelationIndex, rangeTable)->rellockmode == RowExclusiveLock);
+ resultRelation = ExecRangeTableRelation(estate, resultRelationIndex);
InitResultRelInfo(resultRelInfo,
resultRelation,
resultRelationIndex,
@@ -886,12 +892,10 @@ InitPlan(QueryDesc *queryDesc, int eflags)
foreach(l, plannedstmt->rootResultRelations)
{
Index resultRelIndex = lfirst_int(l);
- Oid resultRelOid;
Relation resultRelDesc;
- resultRelOid = getrelid(resultRelIndex, rangeTable);
- resultRelDesc = heap_open(resultRelOid, NoLock);
- Assert(CheckRelationLockedByMe(resultRelDesc, RowExclusiveLock, true));
+ Assert(rt_fetch(resultRelIndex, rangeTable)->rellockmode == RowExclusiveLock);
+ resultRelDesc = ExecRangeTableRelation(estate, resultRelIndex);
InitResultRelInfo(resultRelInfo,
resultRelDesc,
lfirst_int(l),
@@ -967,10 +971,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
case ROW_MARK_SHARE:
case ROW_MARK_KEYSHARE:
case ROW_MARK_REFERENCE:
- relation = heap_open(relid, NoLock);
- Assert(CheckRelationLockedByMe(relation,
- rt_fetch(rc->rti, rangeTable)->rellockmode,
- true));
+ relation = ExecRangeTableRelation(estate, rc->rti);
break;
case ROW_MARK_COPY:
/* no physical table access is required */
@@ -1606,10 +1607,18 @@ ExecPostprocessPlan(EState *estate)
static void
ExecEndPlan(PlanState *planstate, EState *estate)
{
+ int num_relations = list_length(estate->es_range_table);
ResultRelInfo *resultRelInfo;
int i;
ListCell *l;
+ /* Close range table relations. */
+ for (i = 0; i < num_relations; i++)
+ {
+ if (estate->es_relations[i])
+ heap_close(estate->es_relations[i], NoLock);
+ }
+
/*
* shut down the node-type-specific query processing
*/
@@ -1634,39 +1643,18 @@ ExecEndPlan(PlanState *planstate, EState *estate)
ExecResetTupleTable(estate->es_tupleTable, false);
/*
- * close the result relation(s) if any, but hold locks until xact commit.
+ * close indexes of result relation(s) if any
*/
resultRelInfo = estate->es_result_relations;
for (i = estate->es_num_result_relations; i > 0; i--)
{
- /* Close indices and then the relation itself */
+ /* Close indices; the relation itself already closed above */
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);
-
- /*
- * 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);
- }
}
/* ----------------------------------------------------------------
@@ -3161,6 +3149,7 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree)
estate->es_snapshot = parentestate->es_snapshot;
estate->es_crosscheck_snapshot = parentestate->es_crosscheck_snapshot;
estate->es_range_table = parentestate->es_range_table;
+ 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 832c79b41e..c082bb7632 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -1389,9 +1389,6 @@ adjust_partition_tlist(List *tlist, TupleConversionMap *map)
* functions. Details stored include how to map the partition index
* returned by the partition pruning code into subplan indexes.
*
- * ExecDestroyPartitionPruneState:
- * Deletes a PartitionPruneState. Must be called during executor shutdown.
- *
* ExecFindInitialMatchingSubPlans:
* Returns indexes of matching subplans. Partition pruning is attempted
* without any evaluation of expressions containing PARAM_EXEC Params.
@@ -1433,6 +1430,7 @@ PartitionPruneState *
ExecCreatePartitionPruneState(PlanState *planstate,
PartitionPruneInfo *partitionpruneinfo)
{
+ EState *estate = planstate->state;
PartitionPruneState *prunestate;
int n_part_hierarchies;
ListCell *lc;
@@ -1511,11 +1509,9 @@ 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);
+ context->partrel = ExecRangeTableRelation(estate, pinfo->rtindex);
partkey = RelationGetPartitionKey(context->partrel);
partdesc = RelationGetPartitionDesc(context->partrel);
@@ -1596,30 +1592,6 @@ ExecCreatePartitionPruneState(PlanState *planstate,
}
/*
- * ExecDestroyPartitionPruneState
- * Release resources at plan shutdown.
- *
- * We don't bother to free any memory here, since the whole executor context
- * will be going away shortly. We do need to release our relcache pins.
- */
-void
-ExecDestroyPartitionPruneState(PartitionPruneState *prunestate)
-{
- PartitionPruningData **partprunedata = prunestate->partprunedata;
- int i;
-
- for (i = 0; i < prunestate->num_partprunedata; i++)
- {
- PartitionPruningData *prunedata = partprunedata[i];
- PartitionedRelPruningData *pprune = prunedata->partrelprunedata;
- int j;
-
- for (j = 0; j < prunedata->num_partrelprunedata; j++)
- relation_close(pprune[j].context.partrel, NoLock);
- }
-}
-
-/*
* ExecFindInitialMatchingSubPlans
* Identify the set of subplans that cannot be eliminated by initial
* pruning (disregarding any pruning constraints involving PARAM_EXEC
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index ba93b40104..4825756a32 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -25,7 +25,6 @@
* etc
*
* ExecOpenScanRelation Common code for scan node init routines.
- * ExecCloseScanRelation
*
* executor_errposition Report syntactic position of an error.
*
@@ -648,15 +647,9 @@ Relation
ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
{
Relation rel;
- Oid reloid;
- /* Open the relation and verify lock was obtained upstream */
- reloid = getrelid(scanrelid, estate->es_range_table);
- rel = heap_open(reloid, NoLock);
- Assert(IsParallelWorker() ||
- CheckRelationLockedByMe(rel,
- rt_fetch(scanrelid, estate->es_range_table)->rellockmode,
- true));
+ /* Open the relation. */
+ rel = ExecRangeTableRelation(estate, scanrelid);
/*
* Complain if we're attempting a scan of an unscannable relation, except
@@ -674,26 +667,6 @@ ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
return rel;
}
-/* ----------------------------------------------------------------
- * ExecCloseScanRelation
- *
- * Close the heap relation scanned by a base-level scan plan node.
- * This should be called during the node's ExecEnd routine.
- *
- * Currently, we do not release the lock acquired by ExecOpenScanRelation.
- * This lock should be held till end of transaction. (There is a faction
- * that considers this too much locking, however.)
- *
- * If we did want to release the lock, we'd have to repeat the logic in
- * ExecOpenScanRelation in order to figure out what to release.
- * ----------------------------------------------------------------
- */
-void
-ExecCloseScanRelation(Relation scanrel)
-{
- heap_close(scanrel, NoLock);
-}
-
/*
* UpdateChangedParamSet
* Add changed parameters to a plan node's chgParam set
@@ -1056,3 +1029,32 @@ ExecCleanTargetListLength(List *targetlist)
}
return len;
}
+
+/*
+ * ExecRangeTableRelation
+ * Open and lock, if not already done, a range table relation
+ */
+Relation
+ExecRangeTableRelation(EState *estate, Index rti)
+{
+ Relation rel = estate->es_relations[rti - 1];
+
+ if (rel == NULL)
+ {
+ RangeTblEntry *rte = rt_fetch(rti, estate->es_range_table);
+
+ Assert(rte->rtekind == RTE_RELATION && rte->rellockmode != NoLock);
+
+ /* Open the relation and verify lock was obtained upstream */
+ rel = estate->es_relations[rti - 1] = heap_open(rte->relid, NoLock);
+
+ /*
+ * In the case of parallel query, only the leader would've obtained
+ * the lock.
+ */
+ Assert(IsParallelWorker() ||
+ CheckRelationLockedByMe(rel, rte->rellockmode, false));
+ }
+
+ return rel;
+}
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index f08dfcbcf0..d44befd44e 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -335,12 +335,6 @@ ExecEndAppend(AppendState *node)
*/
for (i = 0; i < nplans; i++)
ExecEndNode(appendplans[i]);
-
- /*
- * release any resources associated with run-time pruning
- */
- if (node->as_prune_state)
- ExecDestroyPartitionPruneState(node->as_prune_state);
}
void
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index baffae27e3..5307cd1b87 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -785,13 +785,11 @@ ExecReScanBitmapHeapScan(BitmapHeapScanState *node)
void
ExecEndBitmapHeapScan(BitmapHeapScanState *node)
{
- Relation relation;
HeapScanDesc scanDesc;
/*
* extract information from the node
*/
- relation = node->ss.ss_currentRelation;
scanDesc = node->ss.ss_currentScanDesc;
/*
@@ -832,11 +830,6 @@ ExecEndBitmapHeapScan(BitmapHeapScanState *node)
* close heap scan
*/
heap_endscan(scanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index b816e0b31d..9a33eda688 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -126,10 +126,6 @@ ExecEndCustomScan(CustomScanState *node)
/* Clean out the tuple table */
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /* Close the heap relation */
- if (node->ss.ss_currentRelation)
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
void
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index a2a28b7ec2..cf7df72d8c 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -258,10 +258,6 @@ ExecEndForeignScan(ForeignScanState *node)
/* clean out the tuple table */
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /* close the relation. */
- if (node->ss.ss_currentRelation)
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 4b6d531810..1b530cea40 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -373,14 +373,12 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node)
{
Relation indexRelationDesc;
IndexScanDesc indexScanDesc;
- Relation relation;
/*
* extract information from the node
*/
indexRelationDesc = node->ioss_RelationDesc;
indexScanDesc = node->ioss_ScanDesc;
- relation = node->ss.ss_currentRelation;
/* Release VM buffer pin, if any. */
if (node->ioss_VMBuffer != InvalidBuffer)
@@ -411,11 +409,6 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node)
index_endscan(indexScanDesc);
if (indexRelationDesc)
index_close(indexRelationDesc, NoLock);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 6285a2114e..786e7ac25c 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -802,14 +802,12 @@ ExecEndIndexScan(IndexScanState *node)
{
Relation indexRelationDesc;
IndexScanDesc indexScanDesc;
- Relation relation;
/*
* extract information from the node
*/
indexRelationDesc = node->iss_RelationDesc;
indexScanDesc = node->iss_ScanDesc;
- relation = node->ss.ss_currentRelation;
/*
* Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
@@ -833,11 +831,6 @@ ExecEndIndexScan(IndexScanState *node)
index_endscan(indexScanDesc);
if (indexRelationDesc)
index_close(indexRelationDesc, NoLock);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index 9a72d3a0ac..6daf60a454 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -369,12 +369,6 @@ ExecEndMergeAppend(MergeAppendState *node)
*/
for (i = 0; i < nplans; i++)
ExecEndNode(mergeplans[i]);
-
- /*
- * release any resources associated with run-time pruning
- */
- if (node->ms_prune_state)
- ExecDestroyPartitionPruneState(node->ms_prune_state);
}
void
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 24beb40435..07ac3de5e0 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2690,9 +2690,7 @@ ExecEndModifyTable(ModifyTableState *node)
{
int i;
- /*
- * Allow any FDWs to shut down
- */
+ /* Allow any FDWs to shut down */
for (i = 0; i < node->mt_nplans; i++)
{
ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index 99528be84a..92ff68a764 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -222,11 +222,6 @@ ExecEndSampleScan(SampleScanState *node)
*/
if (node->ss.ss_currentScanDesc)
heap_endscan(node->ss.ss_currentScanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index cd53491be0..92ff1e50ed 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -201,13 +201,11 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
void
ExecEndSeqScan(SeqScanState *node)
{
- Relation relation;
HeapScanDesc scanDesc;
/*
* get information from node
*/
- relation = node->ss.ss_currentRelation;
scanDesc = node->ss.ss_currentScanDesc;
/*
@@ -226,11 +224,6 @@ ExecEndSeqScan(SeqScanState *node)
*/
if (scanDesc != NULL)
heap_endscan(scanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index 0cb1946a3e..8cae56f48c 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -489,11 +489,6 @@ ExecEndTidScan(TidScanState *node)
*/
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 925cb8f380..3b690b55b3 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -1193,7 +1193,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 22dbae15d3..863d29cc57 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1032,7 +1032,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 ce556580a5..73ffa9714c 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -2376,7 +2376,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 f66f39d8c6..13ee458802 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -925,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_MergeAppend:
@@ -947,6 +962,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 e1ce8b4ddc..1763dd67a3 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/include/executor/execPartition.h b/src/include/executor/execPartition.h
index 8b4a9ca044..3e08104ea4 100644
--- a/src/include/executor/execPartition.h
+++ b/src/include/executor/execPartition.h
@@ -195,7 +195,6 @@ extern void ExecCleanupTupleRouting(ModifyTableState *mtstate,
PartitionTupleRouting *proute);
extern PartitionPruneState *ExecCreatePartitionPruneState(PlanState *planstate,
PartitionPruneInfo *partitionpruneinfo);
-extern void ExecDestroyPartitionPruneState(PartitionPruneState *prunestate);
extern Bitmapset *ExecFindMatchingSubPlans(PartitionPruneState *prunestate);
extern Bitmapset *ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate,
int nsubplans);
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index f82b51667f..f3df6408a9 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -513,7 +513,6 @@ extern void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate
extern bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid);
extern Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags);
-extern void ExecCloseScanRelation(Relation scanrel);
extern int executor_errposition(EState *estate, int location);
@@ -569,5 +568,6 @@ extern void CheckCmdReplicaIdentity(Relation rel, CmdType cmd);
extern void CheckSubscriptionRelkind(char relkind, const char *nspname,
const char *relname);
+extern Relation ExecRangeTableRelation(EState *estate, Index rti);
#endif /* EXECUTOR_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 020ecdcd40..7c47967494 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -479,6 +479,8 @@ typedef struct EState
Snapshot es_snapshot; /* time qual to use */
Snapshot es_crosscheck_snapshot; /* crosscheck time qual for RI */
List *es_range_table; /* List of RangeTblEntry */
+ Relation *es_relations; /* 0-based array of Relations
+ * es_range_table_size elements in length. */
PlannedStmt *es_plannedstmt; /* link to top of plan tree */
const char *es_sourceText; /* Source text from QueryDesc */
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 7c2abbd03a..fbbb278e79 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -1105,7 +1105,7 @@ typedef struct PartitionPruneInfo
typedef struct PartitionedRelPruneInfo
{
NodeTag type;
- Oid reloid; /* OID of partition rel for this level */
+ Index rtindex; /* Partition table's RT index */
List *pruning_steps; /* List of PartitionPruneStep, see below */
Bitmapset *present_parts; /* Indexes of all partitions which subplans or
* subparts are present for. */
--
2.11.0
v12-0002-Introduce-an-array-of-RangeTblEntry-pointers-in-.patchtext/plain; charset=UTF-8; name=v12-0002-Introduce-an-array-of-RangeTblEntry-pointers-in-.patchDownload
From c89a0b53040d680eefe4e7178e67a2fe878a24f1 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Wed, 3 Oct 2018 16:05:15 +0900
Subject: [PATCH v12 2/5] Introduce an array of RangeTblEntry pointers in
EState
Author: Amit Langote, David Rowley
---
contrib/postgres_fdw/postgres_fdw.c | 12 ++++++------
src/backend/commands/copy.c | 2 +-
src/backend/commands/trigger.c | 3 ++-
src/backend/executor/execExprInterp.c | 7 ++++---
src/backend/executor/execMain.c | 19 +++++++++++--------
src/backend/executor/execUtils.c | 24 +++++++++++++++++++++++-
src/backend/executor/nodeLockRows.c | 2 +-
src/backend/replication/logical/worker.c | 2 ++
src/include/executor/executor.h | 1 +
src/include/nodes/execnodes.h | 19 +++++++++++++++++++
src/include/parser/parsetree.h | 10 ----------
11 files changed, 70 insertions(+), 31 deletions(-)
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index c02287a55c..3dd1bab2a2 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. */
@@ -1731,8 +1731,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,
@@ -2036,7 +2036,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);
@@ -2396,7 +2396,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. */
@@ -5752,7 +5752,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 32706fad90..b2fededc9d 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -2484,7 +2484,7 @@ 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;
+ ExecInitRangeTable(estate, cstate->range_table);
/* 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 136f9f0627..5ce3720440 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 c549e3db5d..33cadf8e34 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3934,10 +3934,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 4ec47ac41e..d5227ae129 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 */
@@ -823,7 +823,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
/*
* initialize the node's execution state
*/
- estate->es_range_table = rangeTable;
+ ExecInitRangeTable(estate, rangeTable);
/*
* Allocate an array to store open Relations of each rangeTable item. We
@@ -918,9 +918,10 @@ InitPlan(QueryDesc *queryDesc, int eflags)
resultRelIndex))
{
Relation resultRelDesc;
+ Oid reloid = getrelid(resultRelIndex,
+ estate->es_range_table_array);
- resultRelDesc = heap_open(getrelid(resultRelIndex, rangeTable),
- NoLock);
+ resultRelDesc = heap_open(reloid, NoLock);
Assert(CheckRelationLockedByMe(resultRelDesc, RowExclusiveLock, true));
heap_close(resultRelDesc, NoLock);
}
@@ -962,7 +963,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
continue;
/* get relation's OID (will produce InvalidOid if subquery) */
- relid = getrelid(rc->rti, rangeTable);
+ relid = getrelid(rc->rti, estate->es_range_table_array);
switch (rc->markType)
{
@@ -3072,7 +3073,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));
@@ -3125,7 +3126,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();
@@ -3149,6 +3150,8 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree)
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_range_table_size = parentestate->es_range_table_size;
estate->es_relations = parentestate->es_relations;
estate->es_plannedstmt = parentestate->es_plannedstmt;
estate->es_junkFilter = parentestate->es_junkFilter;
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 4825756a32..2ff36ef364 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -34,6 +34,8 @@
* GetAttributeByName Runtime extraction of columns from tuples.
* GetAttributeByNum
*
+ * ExecInitRangeTable Build an array from the range table list to
+ * allow faster lookups by relid.
* NOTES
* This file has traditionally been the place to stick misc.
* executor support stuff that doesn't really go anyplace else.
@@ -837,7 +839,7 @@ ExecLockNonLeafAppendTables(List *partitioned_rels, EState *estate)
ListCell *l;
Index rti = lfirst_int(lc);
bool is_result_rel = false;
- Oid relid = getrelid(rti, estate->es_range_table);
+ Oid relid = getrelid(rti, estate->es_range_table_array);
/* If this is a result relation, already locked in InitPlan */
foreach(l, stmt->nonleafResultRelations)
@@ -1031,6 +1033,26 @@ ExecCleanTargetListLength(List *targetlist)
}
/*
+ * Initialize executor's range table array
+ */
+void
+ExecInitRangeTable(EState *estate, List *rangeTable)
+{
+ int rti;
+ ListCell *l;
+
+ Assert(estate != NULL);
+ 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 *));
+ rti = 0;
+ foreach(l, rangeTable)
+ estate->es_range_table_array[rti++] = lfirst_node(RangeTblEntry, l);
+}
+
+/*
* ExecRangeTableRelation
* Open and lock, if not already done, a range table relation
*/
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index 30de8a95ab..6db345ae7a 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/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index e247539d7b..b54e427be4 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -201,6 +201,8 @@ create_estate_for_relation(LogicalRepRelMapEntry *rel)
rte->relkind = rel->localrel->rd_rel->relkind;
rte->rellockmode = AccessShareLock;
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 f3df6408a9..fdfd48d897 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -478,6 +478,7 @@ extern ExprContext *CreateExprContext(EState *estate);
extern ExprContext *CreateStandaloneExprContext(void);
extern void FreeExprContext(ExprContext *econtext, bool isCommit);
extern void ReScanExprContext(ExprContext *econtext);
+extern void ExecInitRangeTable(EState *estate, List *rangeTable);
#define ResetExprContext(econtext) \
MemoryContextReset((econtext)->ecxt_per_tuple_memory)
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 7c47967494..fcdb7118a6 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"
@@ -479,6 +480,8 @@ typedef struct EState
Snapshot es_snapshot; /* time qual to use */
Snapshot es_crosscheck_snapshot; /* crosscheck time qual for RI */
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 Relations
* es_range_table_size elements in length. */
PlannedStmt *es_plannedstmt; /* link to top of plan tree */
@@ -581,6 +584,22 @@ typedef struct EState
struct JitInstrumentation *es_jit_worker_instr;
} 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]
+
+/*
+ * 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/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
v12-0003-Move-result-rel-and-ExecRowMark-initilization-to.patchtext/plain; charset=UTF-8; name=v12-0003-Move-result-rel-and-ExecRowMark-initilization-to.patchDownload
From fadc610644cfa352485e2ee8134640b7954f4cef Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Thu, 19 Jul 2018 16:14:51 +0900
Subject: [PATCH v12 3/5] Move result rel and ExecRowMark initilization to
ExecInitNode
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.
---
src/backend/executor/execMain.c | 238 +++++++++++----------------------
src/backend/executor/nodeLockRows.c | 4 +-
src/backend/executor/nodeModifyTable.c | 27 +++-
src/include/executor/executor.h | 2 +-
4 files changed, 103 insertions(+), 168 deletions(-)
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index d5227ae129..0e77c3b66f 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -836,98 +836,44 @@ InitPlan(QueryDesc *queryDesc, int eflags)
estate->es_plannedstmt = plannedstmt;
/*
- * initialize result relation stuff, and open/lock the result rels.
- *
- * We must do this before initializing the plan tree, else we might try to
- * do a lock upgrade if a result rel is also a source rel.
+ * Allocate memory required for result relations. ResultRelInfos
+ * themselves are initialized during ExecInitModifyTable of respective
+ * ModifyTable nodes.
*/
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);
- Relation resultRelation;
-
- Assert(rt_fetch(resultRelationIndex, rangeTable)->rellockmode == RowExclusiveLock);
- resultRelation = ExecRangeTableRelation(estate, resultRelationIndex);
- 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);
- Relation resultRelDesc;
+ estate->es_num_root_result_relations = num_roots;
- Assert(rt_fetch(resultRelIndex, rangeTable)->rellockmode == RowExclusiveLock);
- resultRelDesc = ExecRangeTableRelation(estate, resultRelIndex);
- 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 check the rest of them are locked. */
+ /*
+ * Since non-leaf tables of partition trees won't be processed by
+ * ExecInitModifyTable, so check here that the appropriate lock is
+ * held by upstream.
+ */
#ifdef USE_ASSERT_CHECKING
- foreach(l, plannedstmt->nonleafResultRelations)
- {
- Index resultRelIndex = lfirst_int(l);
+ foreach(l, plannedstmt->nonleafResultRelations)
+ {
+ Index resultRelIndex = lfirst_int(l);
+ Relation resultRelDesc;
+ Oid reloid = getrelid(resultRelIndex,
+ estate->es_range_table_array);
- /* We locked the roots above. */
- if (!list_member_int(plannedstmt->rootResultRelations,
- resultRelIndex))
- {
- Relation resultRelDesc;
- Oid reloid = getrelid(resultRelIndex,
- estate->es_range_table_array);
-
- resultRelDesc = heap_open(reloid, NoLock);
- Assert(CheckRelationLockedByMe(resultRelDesc, RowExclusiveLock, true));
- heap_close(resultRelDesc, NoLock);
- }
- }
-#endif
+ resultRelDesc = heap_open(reloid, NoLock);
+ Assert(CheckRelationLockedByMe(resultRelDesc, RowExclusiveLock, true));
+ heap_close(resultRelDesc, NoLock);
}
+#endif
}
else
{
@@ -941,67 +887,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, estate->es_range_table_array);
-
- switch (rc->markType)
- {
- case ROW_MARK_EXCLUSIVE:
- case ROW_MARK_NOKEYEXCLUSIVE:
- case ROW_MARK_SHARE:
- case ROW_MARK_KEYSHARE:
- case ROW_MARK_REFERENCE:
- relation = ExecRangeTableRelation(estate, rc->rti);
- 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.
@@ -1609,7 +1495,6 @@ static void
ExecEndPlan(PlanState *planstate, EState *estate)
{
int num_relations = list_length(estate->es_range_table);
- ResultRelInfo *resultRelInfo;
int i;
ListCell *l;
@@ -1643,17 +1528,6 @@ ExecEndPlan(PlanState *planstate, EState *estate)
*/
ExecResetTupleTable(estate->es_tupleTable, false);
- /*
- * close indexes of result relation(s) if any
- */
- resultRelInfo = estate->es_result_relations;
- for (i = estate->es_num_result_relations; i > 0; i--)
- {
- /* Close indices; the relation itself already closed above */
- ExecCloseIndices(resultRelInfo);
- resultRelInfo++;
- }
-
/* likewise close any trigger target relations */
ExecCleanUpTriggerState(estate);
}
@@ -2409,25 +2283,63 @@ ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
}
/*
- * ExecFindRowMark -- find the ExecRowMark struct for given rangetable index
+ * ExecBuildRowMark -- create and return an ExecRowMark struct for the given
+ * PlanRowMark.
*
- * If no such struct, either return NULL or throw error depending on missing_ok
+ * The created ExecRowMark is also added to the list of rowmarks in the given
+ * EState.
*/
ExecRowMark *
-ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
+ExecBuildRowMark(EState *estate, PlanRowMark *rc)
{
- ListCell *lc;
+ Oid relid;
+ ExecRowMark *erm;
+ Relation relation;
- foreach(lc, estate->es_rowMarks)
+ Assert(rc != NULL && rc->rti > 0);
+ Assert(!rc->isParent);
+ relid = getrelid(rc->rti, estate->es_range_table_array);
+
+ /* get relation's OID (will produce InvalidOid if subquery) */
+
+ 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:
+ case ROW_MARK_REFERENCE:
+ relation = ExecRangeTableRelation(estate, rc->rti);
+ 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;
}
/*
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index 6db345ae7a..ff9606342b 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -424,8 +424,8 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
/* safety check on size of lr_curtuples array */
Assert(rc->rti > 0 && rc->rti <= lrstate->lr_ntables);
- /* find ExecRowMark and build ExecAuxRowMark */
- erm = ExecFindRowMark(estate, rc->rti, false);
+ /* build the ExecRowMark and ExecAuxRowMark */
+ erm = ExecBuildRowMark(estate, rc);
aerm = ExecBuildAuxRowMark(erm, outerPlan->targetlist);
/*
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 07ac3de5e0..9b584097d7 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2242,12 +2242,33 @@ 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);
+ Relation rel;
+
+ rel = ExecRangeTableRelation(estate, resultRelationIndex);
+ 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);
+ Relation rel;
+
mtstate->rootResultRelInfo = estate->es_root_result_relations +
node->rootResultRelIndex;
+ Assert(root_rt_index > 0);
+ rel = ExecRangeTableRelation(estate, root_rt_index);
+ InitResultRelInfo(mtstate->rootResultRelInfo, rel, root_rt_index,
+ NULL, estate->es_instrument);
+ }
+
mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
mtstate->mt_nplans = nplans;
@@ -2533,8 +2554,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
if (rc->isParent)
continue;
- /* find ExecRowMark (same for all subplans) */
- erm = ExecFindRowMark(estate, rc->rti, false);
+ /* build the ExecRowMark (same for all subplans) */
+ erm = ExecBuildRowMark(estate, rc);
/* build ExecAuxRowMark for each subplan */
for (i = 0; i < nplans; i++)
@@ -2700,6 +2721,8 @@ ExecEndModifyTable(ModifyTableState *node)
resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
resultRelInfo);
+ /* closes indices */
+ ExecCloseIndices(resultRelInfo);
}
/* Close all the partitioned tables, leaf partitions, and their indices */
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index fdfd48d897..4c3a78b1a7 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,
--
2.11.0
v12-0004-Remove-useless-fields-from-planner-nodes.patchtext/plain; charset=UTF-8; name=v12-0004-Remove-useless-fields-from-planner-nodes.patchDownload
From d62e0b3e05dbb156b9d66254cd1279fdd5ed8e34 Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Thu, 27 Sep 2018 13:27:24 +1200
Subject: [PATCH v12 4/5] 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 bool field called
'partitionedTarget', which is set if the target is a partitioned
table. The table itself is identified by 'targetRelation' which
replaces 'nominalRelation'.
* 'nonleafResultRelations' from PlannedStmt and PlannerGlobal.
* 'rowMarks' from PlannedStmt and 'finalrowmarks' from PlannerGlobal.
In PlannedStmt, gets a new bool hasRowMarks that stores if
query->rowMarks != NIL.
---
contrib/postgres_fdw/postgres_fdw.c | 2 +-
src/backend/commands/explain.c | 6 +--
src/backend/commands/portalcmds.c | 2 +-
src/backend/executor/execMain.c | 21 +-------
src/backend/executor/execParallel.c | 3 +-
src/backend/executor/execPartition.c | 2 +-
src/backend/executor/execUtils.c | 60 ----------------------
src/backend/executor/nodeAppend.c | 6 ---
src/backend/executor/nodeMergeAppend.c | 6 ---
src/backend/executor/nodeModifyTable.c | 10 ++--
src/backend/executor/spi.c | 4 +-
src/backend/nodes/copyfuncs.c | 9 ++--
src/backend/nodes/outfuncs.c | 15 ++----
src/backend/nodes/readfuncs.c | 9 ++--
src/backend/optimizer/plan/createplan.c | 46 ++++-------------
src/backend/optimizer/plan/planner.c | 89 +++++++++------------------------
src/backend/optimizer/plan/setrefs.c | 49 ++----------------
src/backend/optimizer/util/pathnode.c | 12 ++---
src/backend/tcop/utility.c | 15 ++++--
src/include/executor/executor.h | 2 -
src/include/nodes/plannodes.h | 30 ++++-------
src/include/nodes/relation.h | 10 ++--
src/include/optimizer/pathnode.h | 2 +-
23 files changed, 96 insertions(+), 314 deletions(-)
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 3dd1bab2a2..d20c75367c 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -2050,7 +2050,7 @@ postgresBeginForeignInsert(ModifyTableState *mtstate,
* Vars contained in those expressions.
*/
if (plan && plan->operation == CMD_UPDATE &&
- resultRelation == plan->nominalRelation)
+ resultRelation == plan->targetRelation)
resultRelation = mtstate->resultRelInfo[0].ri_RangeTableIndex;
}
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 799a22e9d5..a7a851a405 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -954,7 +954,7 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
break;
case T_ModifyTable:
*rels_used = bms_add_member(*rels_used,
- ((ModifyTable *) plan)->nominalRelation);
+ ((ModifyTable *) plan)->targetRelation);
if (((ModifyTable *) plan)->exclRelRTI)
*rels_used = bms_add_member(*rels_used,
((ModifyTable *) plan)->exclRelRTI);
@@ -2949,7 +2949,7 @@ ExplainScanTarget(Scan *plan, ExplainState *es)
static void
ExplainModifyTarget(ModifyTable *plan, ExplainState *es)
{
- ExplainTargetRel((Plan *) plan, plan->nominalRelation, es);
+ ExplainTargetRel((Plan *) plan, plan->targetRelation, es);
}
/*
@@ -3113,7 +3113,7 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors,
/* Should we explicitly label target relations? */
labeltargets = (mtstate->mt_nplans > 1 ||
(mtstate->mt_nplans == 1 &&
- mtstate->resultRelInfo->ri_RangeTableIndex != node->nominalRelation));
+ mtstate->resultRelInfo->ri_RangeTableIndex != node->targetRelation));
if (labeltargets)
ExplainOpenGroup("Target Tables", "Target Tables", false, es);
diff --git a/src/backend/commands/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 0e77c3b66f..1288717b0a 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);
@@ -855,25 +855,6 @@ InitPlan(QueryDesc *queryDesc, int eflags)
estate->es_root_result_relations = (ResultRelInfo *)
palloc(num_roots * sizeof(ResultRelInfo));
estate->es_num_root_result_relations = num_roots;
-
- /*
- * Since non-leaf tables of partition trees won't be processed by
- * ExecInitModifyTable, so check here that the appropriate lock is
- * held by upstream.
- */
-#ifdef USE_ASSERT_CHECKING
- foreach(l, plannedstmt->nonleafResultRelations)
- {
- Index resultRelIndex = lfirst_int(l);
- Relation resultRelDesc;
- Oid reloid = getrelid(resultRelIndex,
- estate->es_range_table_array);
-
- resultRelDesc = heap_open(reloid, NoLock);
- Assert(CheckRelationLockedByMe(resultRelDesc, RowExclusiveLock, true));
- heap_close(resultRelDesc, NoLock);
- }
-#endif
}
else
{
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index 0fdbd119d9..aff14507e1 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -176,6 +176,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;
@@ -183,7 +184,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
@@ -203,7 +203,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/execPartition.c b/src/backend/executor/execPartition.c
index c082bb7632..5d9771c3a1 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -355,7 +355,7 @@ ExecInitPartitionInfo(ModifyTableState *mtstate,
leaf_part_rri = makeNode(ResultRelInfo);
InitResultRelInfo(leaf_part_rri,
partrel,
- node ? node->nominalRelation : 1,
+ node ? node->targetRelation : 1,
rootrel,
estate->es_instrument);
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 2ff36ef364..cc895ec5a1 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -822,66 +822,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_array);
-
- /* 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;
- LOCKMODE lockmode;
-
- foreach(l, stmt->rowMarks)
- {
- if (((PlanRowMark *) lfirst(l))->rti == rti)
- {
- rc = lfirst(l);
- break;
- }
- }
-
- if (rc && RowMarkRequiresRowShareLock(rc->markType))
- lockmode = RowShareLock;
- else
- lockmode = AccessShareLock;
-
- Assert(lockmode == rt_fetch(rti, estate->es_range_table)->rellockmode);
-
- LockRelationOid(relid, lockmode);
- }
- }
-}
-
-/*
* GetAttributeByName
* GetAttributeByNum
*
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index d44befd44e..a16b6da474 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 6daf60a454..5d0dbb8146 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 9b584097d7..60d4bea7b3 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2257,16 +2257,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);
Relation rel;
+ Assert(node->partitionedTarget);
+
mtstate->rootResultRelInfo = estate->es_root_result_relations +
node->rootResultRelIndex;
- Assert(root_rt_index > 0);
- rel = ExecRangeTableRelation(estate, root_rt_index);
- InitResultRelInfo(mtstate->rootResultRelInfo, rel, root_rt_index,
- NULL, estate->es_instrument);
+ rel = ExecRangeTableRelation(estate, node->targetRelation);
+ InitResultRelInfo(mtstate->rootResultRelInfo, rel,
+ node->targetRelation, NULL, estate->es_instrument);
}
mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 11ca800e4c..1bee240e72 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -1358,7 +1358,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
@@ -1374,7 +1374,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 3b690b55b3..da1820506a 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);
@@ -203,8 +202,8 @@ _copyModifyTable(const ModifyTable *from)
*/
COPY_SCALAR_FIELD(operation);
COPY_SCALAR_FIELD(canSetTag);
- COPY_SCALAR_FIELD(nominalRelation);
- COPY_NODE_FIELD(partitioned_rels);
+ COPY_SCALAR_FIELD(targetRelation);
+ COPY_SCALAR_FIELD(partitionedTarget);
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 863d29cc57..6d9ccd50d8 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -272,6 +272,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);
@@ -280,11 +281,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);
@@ -375,8 +374,8 @@ _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(targetRelation);
+ WRITE_BOOL_FIELD(partitionedTarget);
WRITE_BOOL_FIELD(partColsUpdated);
WRITE_NODE_FIELD(resultRelations);
WRITE_INT_FIELD(resultRelIndex);
@@ -405,7 +404,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);
}
@@ -418,7 +416,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);
@@ -2178,8 +2175,8 @@ _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(targetRelation);
+ WRITE_BOOL_FIELD(partitionedTarget);
WRITE_BOOL_FIELD(partColsUpdated);
WRITE_NODE_FIELD(resultRelations);
WRITE_NODE_FIELD(subpaths);
@@ -2257,9 +2254,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 73ffa9714c..e07f38538c 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1496,6 +1496,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);
@@ -1504,11 +1505,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);
@@ -1597,8 +1596,8 @@ _readModifyTable(void)
READ_ENUM_FIELD(operation, CmdType);
READ_BOOL_FIELD(canSetTag);
- READ_UINT_FIELD(nominalRelation);
- READ_NODE_FIELD(partitioned_rels);
+ READ_UINT_FIELD(targetRelation);
+ READ_BOOL_FIELD(partitionedTarget);
READ_BOOL_FIELD(partColsUpdated);
READ_NODE_FIELD(resultRelations);
READ_INT_FIELD(resultRelIndex);
@@ -1632,7 +1631,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();
@@ -1648,7 +1646,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..8f20e54d9e 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 targetRelation, bool partitionedTarget,
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;
@@ -2410,8 +2405,8 @@ create_modifytable_plan(PlannerInfo *root, ModifyTablePath *best_path)
plan = make_modifytable(root,
best_path->operation,
best_path->canSetTag,
- best_path->nominalRelation,
- best_path->partitioned_rels,
+ best_path->targetRelation,
+ best_path->partitionedTarget,
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 targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subplans, List *subroots,
List *withCheckOptionLists, List *returningLists,
@@ -6537,8 +6509,8 @@ make_modifytable(PlannerInfo *root,
node->operation = operation;
node->canSetTag = canSetTag;
- node->nominalRelation = nominalRelation;
- node->partitioned_rels = flatten_partitioned_rels(partitioned_rels);
+ node->targetRelation = targetRelation;
+ node->partitionedTarget = partitionedTarget;
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 89625f4f5b..6a5d2f9d99 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -287,6 +287,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
Plan *top_plan;
ListCell *lp,
*lr;
+ bool hasRowMarks = (parse->rowMarks != NIL);
/*
* Set up global state for this planner invocation. This data is needed
@@ -301,9 +302,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;
@@ -501,9 +500,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) */
@@ -514,6 +511,8 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
PlannerInfo *subroot = lfirst_node(PlannerInfo, lr);
lfirst(lp) = set_plan_references(subroot, subplan);
+ if (subroot->rowMarks != NIL)
+ hasRowMarks = true;
}
/* build the PlannedStmt result */
@@ -523,6 +522,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
result->queryId = parse->queryId;
result->hasReturning = (parse->returningList != NIL);
result->hasModifyingCTE = parse->hasModifyingCTE;
+ result->hasRowMarks = hasRowMarks;
result->canSetTag = parse->canSetTag;
result->transientPlan = glob->transientPlan;
result->dependsOnRole = glob->dependsOnRole;
@@ -530,11 +530,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;
@@ -1169,7 +1167,7 @@ inheritance_planner(PlannerInfo *root)
int top_parentRTindex = parse->resultRelation;
Bitmapset *subqueryRTindexes;
Bitmapset *modifiableARIindexes;
- int nominalRelation = -1;
+ int targetRelation = -1;
List *final_rtable = NIL;
int save_rel_array_size = 0;
RelOptInfo **save_rel_array = NULL;
@@ -1184,8 +1182,7 @@ inheritance_planner(PlannerInfo *root)
ListCell *lc;
Index rti;
RangeTblEntry *parent_rte;
- Relids partitioned_relids = NULL;
- List *partitioned_rels = NIL;
+ bool partitionedTarget = false;
PlannerInfo *parent_root;
Query *parent_parse;
Bitmapset *parent_relids = bms_make_singleton(top_parentRTindex);
@@ -1248,25 +1245,14 @@ inheritance_planner(PlannerInfo *root)
}
/*
- * If the parent RTE is a partitioned table, we should use that as the
- * nominal relation, because the RTEs added for partitioned tables
- * (including the root parent) as child members of the inheritance set do
- * not appear anywhere else in the plan. The situation is exactly the
- * opposite in the case of non-partitioned inheritance parent as described
- * below. For the same reason, collect the list of descendant partitioned
- * tables to be saved in ModifyTable node, so that executor can lock those
- * as well.
+ * If the parent RTE is a partitioned table, set that as the target
+ * relation and mark that we're working with a partitioned target.
*/
parent_rte = rt_fetch(top_parentRTindex, root->parse->rtable);
if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
{
- nominalRelation = top_parentRTindex;
-
- /*
- * 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);
+ targetRelation = top_parentRTindex;
+ partitionedTarget = true;
}
/*
@@ -1338,7 +1324,7 @@ inheritance_planner(PlannerInfo *root)
* inheritance parent.
*/
subroot->inhTargetKind =
- partitioned_relids ? INHKIND_PARTITIONED : INHKIND_INHERITED;
+ partitionedTarget ? INHKIND_PARTITIONED : INHKIND_INHERITED;
/*
* If this child is further partitioned, remember it as a parent.
@@ -1363,17 +1349,17 @@ inheritance_planner(PlannerInfo *root)
}
/*
- * Set the nominal target relation of the ModifyTable node if not
- * already done. We use the inheritance parent RTE as the nominal
- * target relation if it's a partitioned table (see just above this
- * loop). In the non-partitioned parent case, we'll use the first
- * child relation (even if it's excluded) as the nominal target
- * relation. Because of the way expand_inherited_rtentry works, the
- * latter should be the RTE representing the parent table in its role
- * as a simple member of the inheritance set.
+ * Set the target relation of the ModifyTable node if not already
+ * done. We use the inheritance parent RTE as the target relation
+ * if it's a partitioned table (see just above this loop). In the
+ * non-partitioned parent case, we'll use the first child relation
+ * (even if it's excluded) as the target relation. Because of the way
+ * expand_inherited_rtentry works, the latter should be the RTE
+ * representing the parent table in its role as a simple member of
+ * the inheritance set.
*
* It would be logically cleaner to *always* use the inheritance
- * parent RTE as the nominal relation; but that RTE is not otherwise
+ * parent RTE as the target relation; but that RTE is not otherwise
* referenced in the plan in the non-partitioned inheritance case.
* Instead the duplicate child RTE created by expand_inherited_rtentry
* is used elsewhere in the plan, so using the original parent RTE
@@ -1383,8 +1369,8 @@ inheritance_planner(PlannerInfo *root)
* duplicate child RTE added for the parent does not appear anywhere
* else in the plan tree.
*/
- if (nominalRelation < 0)
- nominalRelation = appinfo->child_relid;
+ if (targetRelation < 0)
+ targetRelation = appinfo->child_relid;
/*
* The rowMarks list might contain references to subquery RTEs, so
@@ -1509,15 +1495,6 @@ inheritance_planner(PlannerInfo *root)
continue;
/*
- * Add the current parent's RT index to the partitioned_relids set if
- * we're creating the ModifyTable path for a partitioned root table.
- * (We only care about parents of non-excluded children.)
- */
- if (partitioned_relids)
- partitioned_relids = bms_add_member(partitioned_relids,
- appinfo->parent_relid);
-
- /*
* If this is the first non-excluded child, its post-planning rtable
* becomes the initial contents of final_rtable; otherwise, append
* just its modified subquery RTEs to final_rtable.
@@ -1620,29 +1597,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,
+ targetRelation,
+ partitionedTarget,
root->partColsUpdated,
resultRelations,
subpaths,
@@ -2219,7 +2180,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
parse->commandType,
parse->canSetTag,
parse->resultRelation,
- NIL,
+ false,
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 13ee458802..ee01ef82d2 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);
}
@@ -847,13 +827,9 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
fix_scan_list(root, splan->exclRelTlist, rtoffset);
}
- splan->nominalRelation += rtoffset;
+ splan->targetRelation += rtoffset;
splan->exclRelRTI += rtoffset;
- foreach(l, splan->partitioned_rels)
- {
- lfirst_int(l) += rtoffset;
- }
foreach(l, splan->resultRelations)
{
lfirst_int(l) += rtoffset;
@@ -884,24 +860,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->partitionedTarget)
{
- 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->targetRelation);
}
}
break;
@@ -915,10 +884,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,
@@ -952,10 +917,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..73eca1d4d0 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -3291,10 +3291,8 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
* 'rel' is the parent relation associated with the result
* 'operation' is the operation type
* 'canSetTag' is true if we set the command tag/es_processed
- * 'nominalRelation' is the parent RT index for use of EXPLAIN
- * '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.
+ * 'targetRelation' is the target table's RT index
+ * 'partitionedTarget' true if 'targetRelation' is a partitioned table
* 'partColsUpdated' is true if any partitioning columns are being updated,
* either from the target relation or a descendent partitioned table.
* 'resultRelations' is an integer list of actual RT indexes of target rel(s)
@@ -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 targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subpaths,
List *subroots,
@@ -3376,8 +3374,8 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
pathnode->operation = operation;
pathnode->canSetTag = canSetTag;
- pathnode->nominalRelation = nominalRelation;
- pathnode->partitioned_rels = list_copy(partitioned_rels);
+ pathnode->targetRelation = targetRelation;
+ pathnode->partitionedTarget = partitionedTarget;
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..d0427c64ba 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
+ 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 4c3a78b1a7..4d3de18e07 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 fbbb278e79..452627dd03 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 */
@@ -219,9 +212,10 @@ typedef struct ModifyTable
Plan plan;
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 targetRelation; /* RT index of the target table specified in
+ * the command or first child for inheritance
+ * tables */
+ bool partitionedTarget; /* is the target table partitioned? */
bool partColsUpdated; /* some part key in hierarchy updated */
List *resultRelations; /* integer list of RT indexes */
int resultRelIndex; /* index of first resultRel in plan's list */
@@ -259,9 +253,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 +265,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 +916,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..bcc2ba6db5 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 */
@@ -1716,9 +1713,10 @@ typedef struct ModifyTablePath
Path path;
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 targetRelation; /* RT index of the target table specified in
+ * the command or first child for inheritance
+ * tables */
+ bool partitionedTarget; /* is the target table partitioned? */
bool partColsUpdated; /* some part key in hierarchy updated */
List *resultRelations; /* integer list of RT indexes */
List *subpaths; /* Path(s) producing source data */
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 7c5ff22650..a45c2407d0 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -238,7 +238,7 @@ extern LockRowsPath *create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
extern ModifyTablePath *create_modifytable_path(PlannerInfo *root,
RelOptInfo *rel,
CmdType operation, bool canSetTag,
- Index nominalRelation, List *partitioned_rels,
+ Index targetRelation, bool partitionedTarget,
bool partColsUpdated,
List *resultRelations, List *subpaths,
List *subroots,
--
2.11.0
v12-0005-Prune-PlanRowMark-of-relations-that-are-pruned-f.patchtext/plain; charset=UTF-8; name=v12-0005-Prune-PlanRowMark-of-relations-that-are-pruned-f.patchDownload
From f48e6b91cebe393da71d6412b07f00cc65758bc4 Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Thu, 27 Sep 2018 13:31:11 +1200
Subject: [PATCH v12 5/5] Prune PlanRowMark of relations that are pruned from a
plan
---
src/backend/optimizer/plan/planner.c | 31 ++++++++++++++++++++++++++-----
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 6a5d2f9d99..83e1021d12 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -248,6 +248,7 @@ static bool group_by_has_partkey(RelOptInfo *input_rel,
List *targetList,
List *groupClause);
static int common_prefix_cmp(const void *a, const void *b);
+static List *get_nondummy_rowmarks(PlannerInfo *root);
/*****************************************************************************
@@ -1595,7 +1596,7 @@ inheritance_planner(PlannerInfo *root)
if (parse->rowMarks)
rowMarks = NIL;
else
- rowMarks = root->rowMarks;
+ rowMarks = get_nondummy_rowmarks(root);
/* Create Path representing a ModifyTable to do the UPDATE/DELETE work */
add_path(final_rel, (Path *)
@@ -2124,11 +2125,9 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
* is what goes into the LockRows node.)
*/
if (parse->rowMarks)
- {
path = (Path *) create_lockrows_path(root, final_rel, path,
- root->rowMarks,
+ get_nondummy_rowmarks(root),
SS_assign_special_param(root));
- }
/*
* If there is a LIMIT/OFFSET clause, add the LIMIT node.
@@ -2173,7 +2172,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
if (parse->rowMarks)
rowMarks = NIL;
else
- rowMarks = root->rowMarks;
+ rowMarks = get_nondummy_rowmarks(root);
path = (Path *)
create_modifytable_path(root, final_rel,
@@ -7221,3 +7220,25 @@ group_by_has_partkey(RelOptInfo *input_rel,
return true;
}
+
+/*
+ * get_nondummy_rowmarks
+ * Return a list of PlanRowMark's that reference non-dummy relations
+ */
+static List *
+get_nondummy_rowmarks(PlannerInfo *root)
+{
+ List *rowMarks = NIL;
+ ListCell *lc;
+
+ 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]))
+ rowMarks = lappend(rowMarks, rc);
+ }
+
+ return rowMarks;
+}
--
2.11.0
Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> writes:
On 2018/10/04 5:16, Tom Lane wrote:
I think that we ought to adjust parallel query to insist that children
do take locks, and then revert the IsParallelWorker() exceptions I made
here.
Maybe I'm missing something here, but isn't the necessary adjustment just
that the relations are opened with locks if inside a parallel worker?
Yeah, that's one plausible way to fix it. I hadn't wanted to prejudge
the best way before we finish the other changes, though.
I've rebased the remaining patches. I broke down one of the patches into
2 and re-ordered the patches as follows:
Thanks, will start looking at these today.
regards, tom lane
Hi,
On 2018-10-03 16:16:11 -0400, Tom Lane wrote:
I wrote:
Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> writes:
Should this check that we're not in a parallel worker process?
Hmm. I've not seen any failures in the parallel parts of the regular
regression tests, but maybe I'd better do a force_parallel_mode
run before committing.
In general, I'm not on board with the idea that parallel workers don't
need to get their own locks, so I don't really want to exclude parallel
workers from this check. But if it's not safe for that today, fixing it
is beyond the scope of this particular patch.So the place where that came out in the wash is the commit I just made
(9a3cebeaa) to change the executor from taking table locks to asserting
that somebody else took them already. To make that work, I had to make
both ExecOpenScanRelation and relation_open skip checking for lock-held
if IsParallelWorker().This makes me entirely uncomfortable with the idea that parallel workers
can be allowed to not take any locks of their own. There is no basis
for arguing that we have field proof that that's safe, because *up to
now, parallel workers in fact did take their own locks*. And it seems
unsafe on its face, because there's nothing that really guarantees that
the parent process won't go away while children are still running.
(elog(FATAL) seems like a counterexample, for instance.)
I think that we ought to adjust parallel query to insist that children
do take locks, and then revert the IsParallelWorker() exceptions I made
here. I plan to leave that point in abeyance till we've got the rest
of these changes in place, though. The easiest way to do it will
doubtless change once we've centralized the executor's table-opening
logic, so trying to code it right now seems like a waste of effort.
I've not really followed this thread, and just caught up to here. It
seems entirely unacceptable to not acquire locks on workers to me.
Maybe I'm missing something, but why do/did the patches in this thread
require that / introduce that? We didn't have that kind of concept
before, no? The group locking stuff should rely / require that kind of
thing, no?
Greetings,
Andres Freund
Andres Freund <andres@anarazel.de> writes:
I've not really followed this thread, and just caught up to here. It
seems entirely unacceptable to not acquire locks on workers to me.
Maybe I'm missing something, but why do/did the patches in this thread
require that / introduce that? We didn't have that kind of concept
before, no? The group locking stuff should rely / require that kind of
thing, no?
I'm possibly confused, but I thought that the design of parallel query
involved an expectation that workers didn't need to get their own locks.
What we've determined so far in this thread is that workers *do* get
their own locks (or did before yesterday), but I'd been supposing that
that was accidental not intentional.
In any case, I definitely intend that they will be getting their own
locks again after the dust has settled. Panic not.
regards, tom lane
Hi,
On 2018-10-04 15:27:59 -0400, Tom Lane wrote:
Andres Freund <andres@anarazel.de> writes:
I've not really followed this thread, and just caught up to here. It
seems entirely unacceptable to not acquire locks on workers to me.
Maybe I'm missing something, but why do/did the patches in this thread
require that / introduce that? We didn't have that kind of concept
before, no? The group locking stuff should rely / require that kind of
thing, no?I'm possibly confused, but I thought that the design of parallel query
involved an expectation that workers didn't need to get their own
locks.
Not as far as I'm aware of - but I'm not exactly the expert
there. There's an exception that some lock classes don't conflict
between the leader and the workers - that's group locking
(a1c1af2a1f60). But the locks still have to be acquired, and I think
it's quite dangerous not to do so. The group locking logic is required
because otherwise it'd be trivial to get into deadlocks, and some of the
restrictions around parallel query are required to make that safe.
What we've determined so far in this thread is that workers *do* get
their own locks (or did before yesterday), but I'd been supposing that
that was accidental not intentional.
I don't think it was accidental.
Greetings,
Andres Freund
On 2018-10-04 12:34:44 -0700, Andres Freund wrote:
Hi,
On 2018-10-04 15:27:59 -0400, Tom Lane wrote:
Andres Freund <andres@anarazel.de> writes:
I've not really followed this thread, and just caught up to here. It
seems entirely unacceptable to not acquire locks on workers to me.
Maybe I'm missing something, but why do/did the patches in this thread
require that / introduce that? We didn't have that kind of concept
before, no? The group locking stuff should rely / require that kind of
thing, no?I'm possibly confused, but I thought that the design of parallel query
involved an expectation that workers didn't need to get their own
locks.Not as far as I'm aware of - but I'm not exactly the expert
there. There's an exception that some lock classes don't conflict
between the leader and the workers - that's group locking
(a1c1af2a1f60). But the locks still have to be acquired, and I think
it's quite dangerous not to do so. The group locking logic is required
because otherwise it'd be trivial to get into deadlocks, and some of the
restrictions around parallel query are required to make that safe.
Re-read docs + code just to make sure. Here's the relevant readme parts:
src/backend/access/transam/README.parallel
To prevent unprincipled deadlocks when running in parallel mode, this code
also arranges for the leader and all workers to participate in group
locking. See src/backend/storage/lmgr/README for more details.
src/backend/storage/lmgr/README:
Group Locking
-------------
As if all of that weren't already complicated enough, PostgreSQL now supports
parallelism (see src/backend/access/transam/README.parallel), which means that
we might need to resolve deadlocks that occur between gangs of related
processes rather than individual processes. This doesn't change the basic
deadlock detection algorithm very much, but it makes the bookkeeping more
complicated.
We choose to regard locks held by processes in the same parallel group as
non-conflicting. This means that two processes in a parallel group can hold a
self-exclusive lock on the same relation at the same time, or one process can
acquire an AccessShareLock while the other already holds AccessExclusiveLock.
This might seem dangerous and could be in some cases (more on that below), but
if we didn't do this then parallel query would be extremely prone to
self-deadlock. For example, a parallel query against a relation on which the
leader already had AccessExclusiveLock would hang, because the workers would
try to lock the same relation and be blocked by the leader; yet the leader
can't finish until it receives completion indications from all workers. An
undetected deadlock results. This is far from the only scenario where such a
problem happens. The same thing will occur if the leader holds only
AccessShareLock, the worker seeks AccessShareLock, but between the time the
leader attempts to acquire the lock and the time the worker attempts to
acquire it, some other process queues up waiting for an AccessExclusiveLock.
In this case, too, an indefinite hang results.
...
So yes, locks are expected to be acquired in workers.
Greetings,
Andres Freund
On Thu, Oct 4, 2018 at 3:28 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
I'm possibly confused, but I thought that the design of parallel query
involved an expectation that workers didn't need to get their own locks.
You are, indeed, confused. A heck of a lot of effort went into making
sure that the workers COULD take their own locks, and into trying to
make sure that didn't break anything. That effort may or may not have
been entirely successful, but I'm pretty sure that having them NOT
take locks is going to be a lot worse.
What we've determined so far in this thread is that workers *do* get
their own locks (or did before yesterday), but I'd been supposing that
that was accidental not intentional.
Nope, that was intentional.
In any case, I definitely intend that they will be getting their own
locks again after the dust has settled. Panic not.
/me unloads metaphorical bazooka.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Robert Haas <robertmhaas@gmail.com> writes:
On Thu, Oct 4, 2018 at 3:28 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
What we've determined so far in this thread is that workers *do* get
their own locks (or did before yesterday), but I'd been supposing that
that was accidental not intentional.
Nope, that was intentional.
Fair enough --- in which case, the patch series we're working on here
was broken to suppose that it could get away with removing that.
As I said, I'll make sure the locking is back before I finish with this.
regards, tom lane
Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> writes:
I've rebased the remaining patches. I broke down one of the patches into
2 and re-ordered the patches as follows:
0001: introduces a function that opens range table relations and maintains
them in an array indexes by RT index
0002: introduces a new field in EState that's an array of RangeTblEntry
pointers and revises macros used in the executor that access RTEs to
return them from the array (David Rowley co-authored this one)
I've pushed 0001 and 0002 with mostly cosmetic changes. One thing I
wanted to point out explicitly, though, is that I found this bit of 0002
to be a seriously bad idea:
--- 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"
Please do not add #includes of fundamental headers to other fundamental
headers without clearing it with somebody. There's little enough
structure to our header collection now. I don't want to end up in a
situation where effectively the entire header set gets pulled into
every .c file, or worse that we have actual reference loops in the
headers. (This is not an academic problem; somebody actually created
such a loop awhile back. Cleaning it up, by the time we'd recognized
the problem, was really painful.)
0003: moves result relation and ExecRowMark initialization out of InitPlan
and into ExecInit* routines of respective nodes
I am finding myself pretty unconvinced by this one; it seems like mostly
a random reallocation of responsibility with little advantage. The
particular thing that brought me to a screeching halt was seeing that
the patch removed ExecFindRowMark, despite the fact that that's part
of our advertised FDW API (see fdwhandler.sgml), and it didn't provide
any alternative way for an FDW to find out at runtime whether it's
subject to a row locking requirement.
I thought for a minute about just leaving the function in place, but
that wouldn't work because both nodeLockRows and nodeModifyTable are
written so that they find^H^H^Hbuild their rowmarks only after recursing
to initialize their child plan nodes; so a child node that tried to use
ExecFindRowMark during ExecInitNode would get the wrong answer. Of
course, we could consider changing the order of operations during
initialization of those node types, but I'm not really seeing a compelling
reason why we should whack things around that much.
So I'm inclined to just omit 0003. AFAICS this would only mean that
we couldn't drop the global PlanRowMarks list from PlannedStmt, which
does not bother me much.
0005: teaches planner to remove PlanRowMarks corresponding to dummy relations
I'm not entirely sold on the value of that either?
regards, tom lane
On 2018/10/05 5:59, Tom Lane wrote:
Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> writes:
I've rebased the remaining patches. I broke down one of the patches into
2 and re-ordered the patches as follows:0001: introduces a function that opens range table relations and maintains
them in an array indexes by RT index0002: introduces a new field in EState that's an array of RangeTblEntry
pointers and revises macros used in the executor that access RTEs to
return them from the array (David Rowley co-authored this one)I've pushed 0001 and 0002 with mostly cosmetic changes.
Thanks a lot.
One thing I
wanted to point out explicitly, though, is that I found this bit of 0002
to be a seriously bad idea:--- 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"Please do not add #includes of fundamental headers to other fundamental
headers without clearing it with somebody. There's little enough
structure to our header collection now. I don't want to end up in a
situation where effectively the entire header set gets pulled into
every .c file, or worse that we have actual reference loops in the
headers. (This is not an academic problem; somebody actually created
such a loop awhile back. Cleaning it up, by the time we'd recognized
the problem, was really painful.)
Okay, sorry about that. I was slightly nervous that I had to do it when
doing it, but forgot to mention that explicitly in the commit message or
the email.
0003: moves result relation and ExecRowMark initialization out of InitPlan
and into ExecInit* routines of respective nodesI am finding myself pretty unconvinced by this one; it seems like mostly
a random reallocation of responsibility with little advantage. The
particular thing that brought me to a screeching halt was seeing that
the patch removed ExecFindRowMark, despite the fact that that's part
of our advertised FDW API (see fdwhandler.sgml), and it didn't provide
any alternative way for an FDW to find out at runtime whether it's
subject to a row locking requirement.I thought for a minute about just leaving the function in place, but
that wouldn't work because both nodeLockRows and nodeModifyTable are
written so that they find^H^H^Hbuild their rowmarks only after recursing
to initialize their child plan nodes; so a child node that tried to use
ExecFindRowMark during ExecInitNode would get the wrong answer. Of
course, we could consider changing the order of operations during
initialization of those node types, but I'm not really seeing a compelling
reason why we should whack things around that much.So I'm inclined to just omit 0003. AFAICS this would only mean that
we couldn't drop the global PlanRowMarks list from PlannedStmt, which
does not bother me much.
To be honest, I too had begun to fail to see the point of this patch since
yesterday. In fact, getting this one to pass make check-world took a bit
of head-scratching due to its interaction with EvalPlanQuals EState
building, so I was almost to drop it from the series. But I felt that it
might still be a good idea to get rid of what was described as special
case code. Reading your argument against it based on how it messes up
some of the assumptions regarding ExecRowMark design, I'm willing to let
go of this one as more or less a cosmetic improvement.
0005: teaches planner to remove PlanRowMarks corresponding to dummy relations
I'm not entirely sold on the value of that either?
If you look at the first email on this thread, you can see that trimming
the PlanRowMarks list down to just the ones needed during execution
results in non-trivial improvement in SELECT FOR SHARE on partitioned
tables with large number of partitions:
<quote>
Speedup is more pronounced with a benchmark that needs RowMarks, because
one of the patches (0003) removes overhead around handling them.
$ cat /tmp/select-lt-for-share.sql
select * from lt where b = 999 for share;
master
tps = 94.095985 (excluding connections establishing)
tps = 93.955702 (excluding connections establishing)
<snip>
patch 0003 (prune PlanRowMarks)
tps = 712.544029 (excluding connections establishing)
tps = 717.540052 (excluding connections establishing)
</quote>
But on reflection, this seems more like adding special case code to the
planner just for this, rather than solving the more general problem of
initializing *any* partition information after pruning, being discussed
over at "speeding up planning with partitions" thread [1]/messages/by-id/9d7c5112-cb99-6a47-d3be-cf1ee6862a1d@lab.ntt.co.jp. So, I don't
mind dropping this one too.
So, that leaves us with only the patch that revises the plan node fields
in light of having relieved the executor of doing any locking of its own
in *some* cases. That patch's premise is that we don't need the fields
that the patch removes because they're only referenced for the locking
purposes. But, if those plan nodes support parallel execution and hence
will be passed to parallel workers for execution who will need to lock the
tables contained in the plan nodes, then they better contain all the
information needed for locking *every* affected tables, so we had better
not removed it. Plan nodes in question are Append, MergeAppend, and
ModifyTable, of which only the first two support parallel execution, but
maybe we should just leave all of them alone for now. IOW, I'm not sure
about that patch either. Thoughts?
Thanks,
Amit
[1]: /messages/by-id/9d7c5112-cb99-6a47-d3be-cf1ee6862a1d@lab.ntt.co.jp
/messages/by-id/9d7c5112-cb99-6a47-d3be-cf1ee6862a1d@lab.ntt.co.jp
Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> writes:
On 2018/10/05 5:59, Tom Lane wrote:
So I'm inclined to just omit 0003. AFAICS this would only mean that
we couldn't drop the global PlanRowMarks list from PlannedStmt, which
does not bother me much.
To be honest, I too had begun to fail to see the point of this patch since
yesterday. In fact, getting this one to pass make check-world took a bit
of head-scratching due to its interaction with EvalPlanQuals EState
building, so I was almost to drop it from the series. But I felt that it
might still be a good idea to get rid of what was described as special
case code. Reading your argument against it based on how it messes up
some of the assumptions regarding ExecRowMark design, I'm willing to let
go of this one as more or less a cosmetic improvement.
OK. We do need to fix the comments in InitPlan that talk about acquiring
locks and how that makes us need to do things in a particular order, but
I'll go take care of that.
So, that leaves us with only the patch that revises the plan node fields
in light of having relieved the executor of doing any locking of its own
in *some* cases. That patch's premise is that we don't need the fields
that the patch removes because they're only referenced for the locking
purposes. But, if those plan nodes support parallel execution and hence
will be passed to parallel workers for execution who will need to lock the
tables contained in the plan nodes, then they better contain all the
information needed for locking *every* affected tables, so we had better
not removed it.
No, I think this is unduly pessimistic. We need to make sure that a
parallel worker has lock on tables it's actually touching, but I don't
see why that should imply a requirement to hold lock on parent tables
it never touches.
The reasons why we need locks on tables not physically accessed by the
query are (a) to ensure that we've blocked, or received sinval messages
for, any DDL related to views or partition parent tables, in case that
would invalidate the plan; (b) to allow firing triggers safely, in
the case of partition parent tables. Neither of these issues apply to
a parallel worker -- the plan is already frozen before it can ever
start, and it isn't going to be firing any triggers either.
In particular, I think it's fine to get rid of
ExecLockNonLeafAppendTables. In the parent, that's clearly useless code
now: we have already locked *every* RTE_RELATION entry in the rangetable,
either when the parser/rewriter/planner added the RTE to the list to begin
with, or during AcquireExecutorLocks if the plan was retrieved from the
plancache. In a child it seems unnecessary as long as we're locking the
leaf rels we actually touch.
Possibly, we might fix the problem of inadequate locking in worker
processes by having them do the equivalent of AcquireExecutorLocks, ie
just run through the whole RT list and lock everything. I think we'd soon
end up doing that if we ever try to allow parallelization of non-read-only
queries; but that's a long way off AFAIK. For read-only queries it seems
like it'll be fine if we just rejigger ExecGetRangeTableRelation to take a
lock when IsParallelWorker.
regards, tom lane
Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> writes:
0004: removes useless fields from certain planner nodes whose only purpose
has been to assist the executor lock relations in proper order
I've pushed most of 0004 now; obviously, not the parts removing
PlannedStmt.rowMarks, since that's not possible without rearrangement
of the executor's RowMark handling.
I didn't like the idea of unifying ModifyTable.nominalRelation with
the partition root info. Those fields serve different masters ---
nominalRelation, at least in its original intent, is only meant for
use of EXPLAIN and might have nothing to do with what happens at
execution. So even though unifying them would work today, we might
regret it down the line. Instead I left that field alone and added
a separate rootRelation field to carry the partition root RT index,
which ends up being the same number of fields anyway since we don't
need a flag for is-the-nominal-relation-a-partition-root.
Still need to think a bit more about whether we want 0005 in
anything like its current form.
regards, tom lane
I wrote:
Still need to think a bit more about whether we want 0005 in
anything like its current form.
So I poked at that for a bit, and soon realized that the *main* problem
there is that ExecFindRowMark() eats O(N^2) time due to repeated searches
of the es_rowMarks list. While the patch as stated would improve that
for cases where most of the partitions can be pruned at plan time, it
does nothing much for cases where they can't. However, it's pretty
trivial to fix that: let's just use an array not a list. Patch 0001
attached does that.
A further improvement we could consider is to avoid opening the relcache
entries for pruned-away relations. I could not find a way to do that
that was less invasive than removing ExecRowMark.relation and requiring
callers to call a new function to get the relation if they need it.
Patch 0002 attached is a delta on top of 0001 that does that.
Replicating your select-lt-for-share test case as best I can (you never
actually specified it carefully), I find that the TPS rate on my
workstation goes from about 250 tps with HEAD to 920 tps with patch 0001
or 1130 tps with patch 0002. This compares to about 1600 tps for the
non-FOR-SHARE version of the query.
However, we should keep in mind that without partitioning overhead
(ie "select * from lt_999 where b = 999 for share"), the TPS rate
is over 25800 tps. Most of the overhead in the partitioned case seems
to be from acquiring locks on rangetable entries that we won't ever
use, and none of these patch variants are touching that problem.
So ISTM that the *real* win for this scenario is going to come from
teaching the system to prune unwanted relations from the query
altogether, not just from the PlanRowMark list.
Keeping that comparison in mind, I'm inclined to think that 0001
is the best thing to do for now. The incremental win from 0002
is not big enough to justify the API break it creates, while your
0005 is not really attacking the problem the right way.
regards, tom lane
Attachments:
0001-use-array-not-list-of-ExecRowMarks.patchtext/x-diff; charset=us-ascii; name=0001-use-array-not-list-of-ExecRowMarks.patchDownload
diff --git a/src/backend/executor/execCurrent.c b/src/backend/executor/execCurrent.c
index 7480cf5..aadf749 100644
--- a/src/backend/executor/execCurrent.c
+++ b/src/backend/executor/execCurrent.c
@@ -91,21 +91,22 @@ execCurrentOf(CurrentOfExpr *cexpr,
* the other code can't, while the non-FOR-UPDATE case allows use of WHERE
* CURRENT OF with an insensitive cursor.
*/
- if (queryDesc->estate->es_rowMarks)
+ if (queryDesc->estate->es_rowmarks)
{
ExecRowMark *erm;
- ListCell *lc;
+ Index i;
/*
* Here, the query must have exactly one FOR UPDATE/SHARE reference to
* the target table, and we dig the ctid info out of that.
*/
erm = NULL;
- foreach(lc, queryDesc->estate->es_rowMarks)
+ for (i = 0; i < queryDesc->estate->es_range_table_size; i++)
{
- ExecRowMark *thiserm = (ExecRowMark *) lfirst(lc);
+ ExecRowMark *thiserm = queryDesc->estate->es_rowmarks[i];
- if (!RowMarkRequiresRowShareLock(thiserm->markType))
+ if (thiserm == NULL ||
+ !RowMarkRequiresRowShareLock(thiserm->markType))
continue; /* ignore non-FOR UPDATE/SHARE items */
if (thiserm->relid == table_oid)
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index b6abad5..0a766ef 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -909,61 +909,68 @@ InitPlan(QueryDesc *queryDesc, int eflags)
}
/*
- * Next, build the ExecRowMark list from the PlanRowMark(s), if any.
+ * Next, build the ExecRowMark array from the PlanRowMark(s), if any.
*/
- estate->es_rowMarks = NIL;
- foreach(l, plannedstmt->rowMarks)
+ if (plannedstmt->rowMarks)
{
- PlanRowMark *rc = (PlanRowMark *) lfirst(l);
- Oid relid;
- Relation relation;
- ExecRowMark *erm;
+ estate->es_rowmarks = (ExecRowMark **)
+ palloc0(estate->es_range_table_size * sizeof(ExecRowMark *));
+ 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;
+ /* ignore "parent" rowmarks; they are irrelevant at runtime */
+ if (rc->isParent)
+ continue;
- /* get relation's OID (will produce InvalidOid if subquery) */
- relid = exec_rt_fetch(rc->rti, estate)->relid;
+ /* get relation's OID (will produce InvalidOid if subquery) */
+ relid = exec_rt_fetch(rc->rti, estate)->relid;
- /* open relation, if we need to access it for this mark type */
- switch (rc->markType)
- {
- case ROW_MARK_EXCLUSIVE:
- case ROW_MARK_NOKEYEXCLUSIVE:
- case ROW_MARK_SHARE:
- case ROW_MARK_KEYSHARE:
- case ROW_MARK_REFERENCE:
- relation = ExecGetRangeTableRelation(estate, rc->rti);
- 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;
- }
+ /* open relation, if we need to access it for this mark type */
+ switch (rc->markType)
+ {
+ case ROW_MARK_EXCLUSIVE:
+ case ROW_MARK_NOKEYEXCLUSIVE:
+ case ROW_MARK_SHARE:
+ case ROW_MARK_KEYSHARE:
+ case ROW_MARK_REFERENCE:
+ relation = ExecGetRangeTableRelation(estate, rc->rti);
+ 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);
+ /* 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;
+
+ Assert(erm->rti > 0 && erm->rti <= estate->es_range_table_size &&
+ estate->es_rowmarks[erm->rti - 1] == NULL);
+
+ estate->es_rowmarks[erm->rti - 1] = erm;
+ }
}
/*
@@ -2394,13 +2401,12 @@ ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
ExecRowMark *
ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
{
- ListCell *lc;
-
- foreach(lc, estate->es_rowMarks)
+ if (rti > 0 && rti <= estate->es_range_table_size &&
+ estate->es_rowmarks != NULL)
{
- ExecRowMark *erm = (ExecRowMark *) lfirst(lc);
+ ExecRowMark *erm = estate->es_rowmarks[rti - 1];
- if (erm->rti == rti)
+ if (erm)
return erm;
}
if (!missing_ok)
@@ -3131,6 +3137,7 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree)
estate->es_range_table_array = parentestate->es_range_table_array;
estate->es_range_table_size = parentestate->es_range_table_size;
estate->es_relations = parentestate->es_relations;
+ estate->es_rowmarks = parentestate->es_rowmarks;
estate->es_plannedstmt = parentestate->es_plannedstmt;
estate->es_junkFilter = parentestate->es_junkFilter;
estate->es_output_cid = parentestate->es_output_cid;
@@ -3148,7 +3155,6 @@ 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;
estate->es_top_eflags = parentestate->es_top_eflags;
estate->es_instrument = parentestate->es_instrument;
/* es_auxmodifytables must NOT be copied */
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index d98e90e..71c6b5d 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -113,6 +113,7 @@ CreateExecutorState(void)
estate->es_range_table_array = NULL;
estate->es_range_table_size = 0;
estate->es_relations = NULL;
+ estate->es_rowmarks = NULL;
estate->es_plannedstmt = NULL;
estate->es_junkFilter = NULL;
@@ -142,8 +143,6 @@ CreateExecutorState(void)
estate->es_tupleTable = NIL;
- estate->es_rowMarks = NIL;
-
estate->es_processed = 0;
estate->es_lastoid = InvalidOid;
@@ -709,6 +708,12 @@ ExecInitRangeTable(EState *estate, List *rangeTable)
*/
estate->es_relations = (Relation *)
palloc0(estate->es_range_table_size * sizeof(Relation));
+
+ /*
+ * es_rowmarks is also parallel to the es_range_table_array, but it's
+ * allocated only if needed.
+ */
+ estate->es_rowmarks = NULL;
}
/*
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 657b593..8347089 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -34,6 +34,7 @@
struct PlanState; /* forward references in this file */
struct ParallelHashJoinState;
+struct ExecRowMark;
struct ExprState;
struct ExprContext;
struct RangeTblEntry; /* avoid including parsenodes.h here */
@@ -491,6 +492,8 @@ typedef struct EState
Index es_range_table_size; /* size of the range table arrays */
Relation *es_relations; /* Array of per-range-table-entry Relation
* pointers, or NULL if not yet opened */
+ struct ExecRowMark **es_rowmarks; /* Array of per-range-table-entry
+ * ExecRowMarks, or NULL if none */
PlannedStmt *es_plannedstmt; /* link to top of plan tree */
const char *es_sourceText; /* Source text from QueryDesc */
@@ -537,8 +540,6 @@ typedef struct EState
List *es_tupleTable; /* List of TupleTableSlots */
- List *es_rowMarks; /* List of ExecRowMarks */
-
uint64 es_processed; /* # of tuples processed */
Oid es_lastoid; /* last oid processed (by INSERT) */
@@ -607,7 +608,9 @@ typedef struct EState
* node that sources the relation (e.g., for a foreign table the FDW can use
* ermExtra to hold information).
*
- * EState->es_rowMarks is a list of these structs.
+ * EState->es_rowmarks is an array of these structs, indexed by RT index,
+ * with NULLs for irrelevant RT indexes. es_rowmarks itself is NULL if
+ * there are no rowmarks.
*/
typedef struct ExecRowMark
{
@@ -629,7 +632,7 @@ typedef struct ExecRowMark
* additional runtime representation of FOR [KEY] UPDATE/SHARE clauses
*
* Each LockRows and ModifyTable node keeps a list of the rowmarks it needs to
- * deal with. In addition to a pointer to the related entry in es_rowMarks,
+ * deal with. In addition to a pointer to the related entry in es_rowmarks,
* this struct carries the column number(s) of the resjunk columns associated
* with the rowmark (see comments for PlanRowMark for more detail). In the
* case of ModifyTable, there has to be a separate ExecAuxRowMark list for
@@ -638,7 +641,7 @@ typedef struct ExecRowMark
*/
typedef struct ExecAuxRowMark
{
- ExecRowMark *rowmark; /* related entry in es_rowMarks */
+ ExecRowMark *rowmark; /* related entry in es_rowmarks */
AttrNumber ctidAttNo; /* resno of ctid junk attribute, if any */
AttrNumber toidAttNo; /* resno of tableoid junk attribute, if any */
AttrNumber wholeAttNo; /* resno of whole-row junk attribute, if any */
0002-postpone-rowmark-relation-access.patchtext/x-diff; charset=us-ascii; name=0002-postpone-rowmark-relation-access.patchDownload
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 0a766ef..1775e77 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -919,7 +919,6 @@ InitPlan(QueryDesc *queryDesc, int eflags)
{
PlanRowMark *rc = (PlanRowMark *) lfirst(l);
Oid relid;
- Relation relation;
ExecRowMark *erm;
/* ignore "parent" rowmarks; they are irrelevant at runtime */
@@ -929,32 +928,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
/* get relation's OID (will produce InvalidOid if subquery) */
relid = exec_rt_fetch(rc->rti, estate)->relid;
- /* open relation, if we need to access it for this mark type */
- switch (rc->markType)
- {
- case ROW_MARK_EXCLUSIVE:
- case ROW_MARK_NOKEYEXCLUSIVE:
- case ROW_MARK_SHARE:
- case ROW_MARK_KEYSHARE:
- case ROW_MARK_REFERENCE:
- relation = ExecGetRangeTableRelation(estate, rc->rti);
- 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;
@@ -963,6 +937,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
erm->strength = rc->strength;
erm->waitPolicy = rc->waitPolicy;
erm->ermActive = false;
+ erm->ermChecked = false;
ItemPointerSetInvalid(&(erm->curCtid));
erm->ermExtra = NULL;
@@ -2462,6 +2437,20 @@ ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
return aerm;
}
+Relation
+ExecRowMarkGetRelation(EState *estate, ExecRowMark *erm)
+{
+ Relation relation = ExecGetRangeTableRelation(estate, erm->rti);
+
+ /* Check that relation is a legal target for marking, if we haven't */
+ if (!erm->ermChecked)
+ {
+ CheckValidRowMarkRel(relation, erm->markType);
+ erm->ermChecked = true;
+ }
+ return relation;
+}
+
/*
* EvalPlanQual logic --- recheck modified tuple(s) to see if we want to
@@ -2935,10 +2924,9 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate)
if (erm->markType == ROW_MARK_REFERENCE)
{
+ Relation relation = ExecRowMarkGetRelation(epqstate->estate, erm);
HeapTuple copyTuple;
- Assert(erm->relation != NULL);
-
/* fetch the tuple's ctid */
datum = ExecGetJunkAttribute(epqstate->origslot,
aerm->ctidAttNo,
@@ -2948,18 +2936,18 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate)
continue;
/* fetch requests on foreign tables must be passed to their FDW */
- if (erm->relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+ if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
{
FdwRoutine *fdwroutine;
bool updated = false;
- fdwroutine = GetFdwRoutineForRelation(erm->relation, false);
+ fdwroutine = GetFdwRoutineForRelation(relation, false);
/* this should have been checked already, but let's be safe */
if (fdwroutine->RefetchForeignRow == NULL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot lock rows in foreign table \"%s\"",
- RelationGetRelationName(erm->relation))));
+ RelationGetRelationName(relation))));
copyTuple = fdwroutine->RefetchForeignRow(epqstate->estate,
erm,
datum,
@@ -2979,7 +2967,7 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate)
Buffer buffer;
tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
- if (!heap_fetch(erm->relation, SnapshotAny, &tuple, &buffer,
+ if (!heap_fetch(relation, SnapshotAny, &tuple, &buffer,
false, NULL))
elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index 6db345a..4e161c0 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -74,6 +74,7 @@ lnext:
{
ExecAuxRowMark *aerm = (ExecAuxRowMark *) lfirst(lc);
ExecRowMark *erm = aerm->rowmark;
+ Relation relation;
HeapTuple *testTuple;
Datum datum;
bool isNull;
@@ -122,19 +123,22 @@ lnext:
if (isNull)
elog(ERROR, "ctid is NULL");
+ /* access the tuple's relation */
+ relation = ExecRowMarkGetRelation(estate, erm);
+
/* requests for foreign tables must be passed to their FDW */
- if (erm->relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+ if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
{
FdwRoutine *fdwroutine;
bool updated = false;
- fdwroutine = GetFdwRoutineForRelation(erm->relation, false);
+ fdwroutine = GetFdwRoutineForRelation(relation, false);
/* this should have been checked already, but let's be safe */
if (fdwroutine->RefetchForeignRow == NULL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot lock rows in foreign table \"%s\"",
- RelationGetRelationName(erm->relation))));
+ RelationGetRelationName(relation))));
copyTuple = fdwroutine->RefetchForeignRow(estate,
erm,
datum,
@@ -180,7 +184,7 @@ lnext:
break;
}
- test = heap_lock_tuple(erm->relation, &tuple,
+ test = heap_lock_tuple(relation, &tuple,
estate->es_output_cid,
lockmode, erm->waitPolicy, true,
&buffer, &hufd);
@@ -230,7 +234,7 @@ lnext:
}
/* updated, so fetch and lock the updated version */
- copyTuple = EvalPlanQualFetch(estate, erm->relation,
+ copyTuple = EvalPlanQualFetch(estate, relation,
lockmode, erm->waitPolicy,
&hufd.ctid, hufd.xmax);
@@ -286,6 +290,7 @@ lnext:
{
ExecAuxRowMark *aerm = (ExecAuxRowMark *) lfirst(lc);
ExecRowMark *erm = aerm->rowmark;
+ Relation relation;
HeapTupleData tuple;
Buffer buffer;
@@ -309,13 +314,16 @@ lnext:
continue;
}
+ /* access the tuple's relation */
+ relation = ExecRowMarkGetRelation(estate, erm);
+
/* foreign tables should have been fetched above */
- Assert(erm->relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE);
+ Assert(relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE);
Assert(ItemPointerIsValid(&(erm->curCtid)));
/* okay, fetch the tuple */
tuple.t_self = erm->curCtid;
- if (!heap_fetch(erm->relation, SnapshotAny, &tuple, &buffer,
+ if (!heap_fetch(relation, SnapshotAny, &tuple, &buffer,
false, NULL))
elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index c9ed198..4dbbb3b 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -190,6 +190,7 @@ extern void ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
extern LockTupleMode ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo);
extern ExecRowMark *ExecFindRowMark(EState *estate, Index rti, bool missing_ok);
extern ExecAuxRowMark *ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist);
+extern Relation ExecRowMarkGetRelation(EState *estate, ExecRowMark *erm);
extern TupleTableSlot *EvalPlanQual(EState *estate, EPQState *epqstate,
Relation relation, Index rti, int lockmode,
ItemPointer tid, TransactionId priorXmax);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 8347089..e2cd7ea 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -597,16 +597,20 @@ typedef struct EState
* ExecRowMark -
* runtime representation of FOR [KEY] UPDATE/SHARE clauses
*
- * When doing UPDATE, DELETE, or SELECT FOR [KEY] UPDATE/SHARE, we will have an
- * ExecRowMark for each non-target relation in the query (except inheritance
- * parent RTEs, which can be ignored at runtime). Virtual relations such as
- * subqueries-in-FROM will have an ExecRowMark with relation == NULL. See
- * PlanRowMark for details about most of the fields. In addition to fields
- * directly derived from PlanRowMark, we store an activity flag (to denote
- * inactive children of inheritance trees), curCtid, which is used by the
- * WHERE CURRENT OF code, and ermExtra, which is available for use by the plan
- * node that sources the relation (e.g., for a foreign table the FDW can use
- * ermExtra to hold information).
+ * When doing UPDATE, DELETE, or SELECT FOR [KEY] UPDATE/SHARE, we will have
+ * an ExecRowMark for each non-target relation in the query (except
+ * inheritance parent RTEs, which can be ignored at runtime). See PlanRowMark
+ * for details about most of the fields. In addition to fields directly
+ * derived from PlanRowMark, we store an activity flag (to denote inactive
+ * children of inheritance trees); a "checked" flag (to denote whether we've
+ * verified the relation is of appropriate type to be marked); curCtid, which
+ * is used by the WHERE CURRENT OF code; and ermExtra, which is available for
+ * use by the plan node that sources the relation (e.g., for a foreign table
+ * the FDW can use ermExtra to hold information).
+ *
+ * For performance reasons, we don't open or verify the relkind of tables
+ * that are never accessed in a query; this is important in partitioned
+ * tables with many partitions. Use ExecRowMarkGetRelation to do that.
*
* EState->es_rowmarks is an array of these structs, indexed by RT index,
* with NULLs for irrelevant RT indexes. es_rowmarks itself is NULL if
@@ -614,8 +618,7 @@ typedef struct EState
*/
typedef struct ExecRowMark
{
- Relation relation; /* opened and suitably locked relation */
- Oid relid; /* its OID (or InvalidOid, if subquery) */
+ Oid relid; /* relation's OID (InvalidOid if subquery) */
Index rti; /* its range table index */
Index prti; /* parent range table index, if child */
Index rowmarkId; /* unique identifier for resjunk columns */
@@ -623,6 +626,7 @@ typedef struct ExecRowMark
LockClauseStrength strength; /* LockingClause's strength, or LCS_NONE */
LockWaitPolicy waitPolicy; /* NOWAIT and SKIP LOCKED */
bool ermActive; /* is this mark relevant for current tuple? */
+ bool ermChecked; /* have we verified relation's relkind? */
ItemPointerData curCtid; /* ctid of currently locked tuple, if any */
void *ermExtra; /* available for use by relation source node */
} ExecRowMark;
On 8 October 2018 at 12:18, Tom Lane <tgl@sss.pgh.pa.us> wrote:
However, we should keep in mind that without partitioning overhead
(ie "select * from lt_999 where b = 999 for share"), the TPS rate
is over 25800 tps. Most of the overhead in the partitioned case seems
to be from acquiring locks on rangetable entries that we won't ever
use, and none of these patch variants are touching that problem.
So ISTM that the *real* win for this scenario is going to come from
teaching the system to prune unwanted relations from the query
altogether, not just from the PlanRowMark list.
Idle thought: I wonder if we could add another field to the
RangeTblEntry; "delaylock". Set that to true in the planner for all
other_member rels that are partitions then not obtain locks on those
during AcquireExecutorLocks(). Instead, grab the lock in
ExecGetRangeTableRelation() the first time through.
We'd still obtain the lock for the table named in the query at the
normal time so cached plans could properly be invalidated. We'd need
to ensure that anything that could be changed in the partitions to
cause a plan to become invalid properly obtains a lock on the
partitioned table, all the way to the top of the hierarchy.
--
David Rowley http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
David Rowley <david.rowley@2ndquadrant.com> writes:
On 8 October 2018 at 12:18, Tom Lane <tgl@sss.pgh.pa.us> wrote:
So ISTM that the *real* win for this scenario is going to come from
teaching the system to prune unwanted relations from the query
altogether, not just from the PlanRowMark list.
Idle thought: I wonder if we could add another field to the
RangeTblEntry; "delaylock". Set that to true in the planner for all
other_member rels that are partitions then not obtain locks on those
during AcquireExecutorLocks(). Instead, grab the lock in
ExecGetRangeTableRelation() the first time through.
Hmm, I'm afraid that's not terribly safe, unless there are ALTER
TABLE restrictions on partitions that I'm not aware of. For instance,
a leaf partition might have an index it didn't inherit from the parent,
and the query plan might be intending to use that index. If you don't
take lock on the leaf, you might not know that the index has been dropped
so that a new plan is needed.
The idea I had in mind was to allow hard pruning of any leaf that's
been excluded *at plan time* based on partition constraints seen in
its parent rel(s). That should be safe enough as long as we take
locks on all the non-leaf rels --- then we'd know about any change
in the constraint situation.
Rather than coping with renumbering the RTEs, it might be easiest
to invent an "RTE_DUMMY" RTE type that a hard-pruned RTE could be
changed to.
regards, tom lane
On 8 October 2018 at 13:13, Tom Lane <tgl@sss.pgh.pa.us> wrote:
The idea I had in mind was to allow hard pruning of any leaf that's
been excluded *at plan time* based on partition constraints seen in
its parent rel(s). That should be safe enough as long as we take
locks on all the non-leaf rels --- then we'd know about any change
in the constraint situation.Rather than coping with renumbering the RTEs, it might be easiest
to invent an "RTE_DUMMY" RTE type that a hard-pruned RTE could be
changed to.
The problem with that is that, if we get [1]https://commitfest.postgresql.org/20/1778/ done in PG12, then the
RTE_DUMMYs would not exist, as we'd only have RTEs in the range table
for partitions that survived plan-time pruning.
It also leaves a problem to solve in the unneeded locks being taken on
partitions for PREPAREd queries using run-time pruning.
[1]: https://commitfest.postgresql.org/20/1778/
--
David Rowley http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
I wrote:
Keeping that comparison in mind, I'm inclined to think that 0001
is the best thing to do for now. The incremental win from 0002
is not big enough to justify the API break it creates, while your
0005 is not really attacking the problem the right way.
I've pushed 0001 now. I believe that closes out all the patches
discussed in this thread, so I've marked the CF entry committed.
Thanks for all the hard work!
regards, tom lane
On 2018/10/07 3:59, Tom Lane wrote:
Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> writes:
On 2018/10/05 5:59, Tom Lane wrote:
So I'm inclined to just omit 0003. AFAICS this would only mean that
we couldn't drop the global PlanRowMarks list from PlannedStmt, which
does not bother me much.To be honest, I too had begun to fail to see the point of this patch since
yesterday. In fact, getting this one to pass make check-world took a bit
of head-scratching due to its interaction with EvalPlanQuals EState
building, so I was almost to drop it from the series. But I felt that it
might still be a good idea to get rid of what was described as special
case code. Reading your argument against it based on how it messes up
some of the assumptions regarding ExecRowMark design, I'm willing to let
go of this one as more or less a cosmetic improvement.OK. We do need to fix the comments in InitPlan that talk about acquiring
locks and how that makes us need to do things in a particular order, but
I'll go take care of that.
Thanks for doing that.
So, that leaves us with only the patch that revises the plan node fields
in light of having relieved the executor of doing any locking of its own
in *some* cases. That patch's premise is that we don't need the fields
that the patch removes because they're only referenced for the locking
purposes. But, if those plan nodes support parallel execution and hence
will be passed to parallel workers for execution who will need to lock the
tables contained in the plan nodes, then they better contain all the
information needed for locking *every* affected tables, so we had better
not removed it.No, I think this is unduly pessimistic. We need to make sure that a
parallel worker has lock on tables it's actually touching, but I don't
see why that should imply a requirement to hold lock on parent tables
it never touches.The reasons why we need locks on tables not physically accessed by the
query are (a) to ensure that we've blocked, or received sinval messages
for, any DDL related to views or partition parent tables, in case that
would invalidate the plan; (b) to allow firing triggers safely, in
the case of partition parent tables. Neither of these issues apply to
a parallel worker -- the plan is already frozen before it can ever
start, and it isn't going to be firing any triggers either.In particular, I think it's fine to get rid of
ExecLockNonLeafAppendTables. In the parent, that's clearly useless code
now: we have already locked *every* RTE_RELATION entry in the rangetable,
either when the parser/rewriter/planner added the RTE to the list to begin
with, or during AcquireExecutorLocks if the plan was retrieved from the
plancache. In a child it seems unnecessary as long as we're locking the
leaf rels we actually touch.Possibly, we might fix the problem of inadequate locking in worker
processes by having them do the equivalent of AcquireExecutorLocks, ie
just run through the whole RT list and lock everything. I think we'd soon
end up doing that if we ever try to allow parallelization of non-read-only
queries; but that's a long way off AFAIK. For read-only queries it seems
like it'll be fine if we just rejigger ExecGetRangeTableRelation to take a
lock when IsParallelWorker.
Okay, thanks for the explanation. It's now clearer to me why parallel
workers don't really need to lock non-leaf relations.
Thanks,
Amit
On 2018/10/08 3:55, Tom Lane wrote:
I didn't like the idea of unifying ModifyTable.nominalRelation with
the partition root info. Those fields serve different masters ---
nominalRelation, at least in its original intent, is only meant for
use of EXPLAIN and might have nothing to do with what happens at
execution. So even though unifying them would work today, we might
regret it down the line. Instead I left that field alone and added
a separate rootRelation field to carry the partition root RT index,
which ends up being the same number of fields anyway since we don't
need a flag for is-the-nominal-relation-a-partition-root.
Thanks for pushing that. I'd also named it 'rootRelation' in my original
patch before David had objected to calling it that, because a command may
not specify the "actual" root of a partition tree; it could be a non-root
partitioned table. He'd suggested 'partitionedTarget' for the new field
[1]: /messages/by-id/CAKJS1f_M0jkgL-d=k-rf6TMzghATDmZ67nzja1tz4h3G=27e7Q@mail.gmail.com
confusing though.
Thanks,a
Amit
[1]: /messages/by-id/CAKJS1f_M0jkgL-d=k-rf6TMzghATDmZ67nzja1tz4h3G=27e7Q@mail.gmail.com
/messages/by-id/CAKJS1f_M0jkgL-d=k-rf6TMzghATDmZ67nzja1tz4h3G=27e7Q@mail.gmail.com
On 2018/10/09 0:38, Tom Lane wrote:
I wrote:
Keeping that comparison in mind, I'm inclined to think that 0001
is the best thing to do for now. The incremental win from 0002
is not big enough to justify the API break it creates, while your
0005 is not really attacking the problem the right way.I've pushed 0001 now. I believe that closes out all the patches
discussed in this thread, so I've marked the CF entry committed.
Thanks for all the hard work!
Thanks a lot for reviewing and committing.
Regards,
Amit
On 2018/10/08 9:29, David Rowley wrote:
On 8 October 2018 at 13:13, Tom Lane <tgl@sss.pgh.pa.us> wrote:
The idea I had in mind was to allow hard pruning of any leaf that's
been excluded *at plan time* based on partition constraints seen in
its parent rel(s). That should be safe enough as long as we take
locks on all the non-leaf rels --- then we'd know about any change
in the constraint situation.Rather than coping with renumbering the RTEs, it might be easiest
to invent an "RTE_DUMMY" RTE type that a hard-pruned RTE could be
changed to.The problem with that is that, if we get [1] done in PG12, then the
RTE_DUMMYs would not exist, as we'd only have RTEs in the range table
for partitions that survived plan-time pruning.
...
Yeah, the patch proposed at [1] postpones creating partition RTEs (hence
locking them) to a point after pruning, which also means we create only
the necessary RTEs. In fact, it's not just the RTEs, but child
PlanRowMarks, whose creation is postponed to after pruning. So, I
admitted upthread that my proposed patch here would only add code that
will become useless if we're able to get [1] in.
Thanks,
Amit
On 2018/10/08 8:18, Tom Lane wrote:
I wrote:
Still need to think a bit more about whether we want 0005 in
anything like its current form.So I poked at that for a bit, and soon realized that the *main* problem
there is that ExecFindRowMark() eats O(N^2) time due to repeated searches
of the es_rowMarks list.
Yeah, I proposed the patch only because of stumbling across O(N^2)
behavior, but went to solve it with the planner hack, which I agree is an
inferior solution overall.
While the patch as stated would improve that
for cases where most of the partitions can be pruned at plan time, it
does nothing much for cases where they can't. However, it's pretty
trivial to fix that: let's just use an array not a list. Patch 0001
attached does that.A further improvement we could consider is to avoid opening the relcache
entries for pruned-away relations. I could not find a way to do that
that was less invasive than removing ExecRowMark.relation and requiring
callers to call a new function to get the relation if they need it.
Patch 0002 attached is a delta on top of 0001 that does that.Replicating your select-lt-for-share test case as best I can (you never
actually specified it carefully), I find that the TPS rate on my
workstation goes from about 250 tps with HEAD to 920 tps with patch 0001
or 1130 tps with patch 0002. This compares to about 1600 tps for the
non-FOR-SHARE version of the query.However, we should keep in mind that without partitioning overhead
(ie "select * from lt_999 where b = 999 for share"), the TPS rate
is over 25800 tps. Most of the overhead in the partitioned case seems
to be from acquiring locks on rangetable entries that we won't ever
use, and none of these patch variants are touching that problem.
So ISTM that the *real* win for this scenario is going to come from
teaching the system to prune unwanted relations from the query
altogether, not just from the PlanRowMark list.
Agreed, which is why I mentioned the other patch [1]https://commitfest.postgresql.org/20/1778/, which gets us closer
to that goal.
Keeping that comparison in mind, I'm inclined to think that 0001
is the best thing to do for now. The incremental win from 0002
is not big enough to justify the API break it creates, while your
0005 is not really attacking the problem the right way.
I agree that 0002's improvement is only incremental and would lose its
appeal if we're able to solve the bigger problem of removing range table
and other overhead when planning with large number of partitions, but that
might take a while.
Thanks,
Amit
Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> writes:
On 2018/10/08 3:55, Tom Lane wrote:
I didn't like the idea of unifying ModifyTable.nominalRelation with
the partition root info. Those fields serve different masters ---
nominalRelation, at least in its original intent, is only meant for
use of EXPLAIN and might have nothing to do with what happens at
execution. So even though unifying them would work today, we might
regret it down the line. Instead I left that field alone and added
a separate rootRelation field to carry the partition root RT index,
which ends up being the same number of fields anyway since we don't
need a flag for is-the-nominal-relation-a-partition-root.
Thanks for pushing that. I'd also named it 'rootRelation' in my original
patch before David had objected to calling it that, because a command may
not specify the "actual" root of a partition tree; it could be a non-root
partitioned table. He'd suggested 'partitionedTarget' for the new field
[1], stressing the "target" part. Maybe, 'rootRelation' isn't too
confusing though.
Well, it's the root so far as the current query is concerned --- we do not
take any semantic account of partitioning levels that might exist above
the table named in the query, do we?
regards, tom lane
On Tue, Oct 9, 2018 at 11:07 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> writes:
On 2018/10/08 3:55, Tom Lane wrote:
I didn't like the idea of unifying ModifyTable.nominalRelation with
the partition root info. Those fields serve different masters ---
nominalRelation, at least in its original intent, is only meant for
use of EXPLAIN and might have nothing to do with what happens at
execution. So even though unifying them would work today, we might
regret it down the line. Instead I left that field alone and added
a separate rootRelation field to carry the partition root RT index,
which ends up being the same number of fields anyway since we don't
need a flag for is-the-nominal-relation-a-partition-root.Thanks for pushing that. I'd also named it 'rootRelation' in my original
patch before David had objected to calling it that, because a command may
not specify the "actual" root of a partition tree; it could be a non-root
partitioned table. He'd suggested 'partitionedTarget' for the new field
[1], stressing the "target" part. Maybe, 'rootRelation' isn't too
confusing though.Well, it's the root so far as the current query is concerned --- we do not
take any semantic account of partitioning levels that might exist above
the table named in the query, do we?
We don't, and I personally agree with the reasoning behind calling it
rootRelation.
Thanks,
Amit
On Sat, Oct 6, 2018 at 2:59 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
The reasons why we need locks on tables not physically accessed by the
query are (a) to ensure that we've blocked, or received sinval messages
for, any DDL related to views or partition parent tables, in case that
would invalidate the plan; (b) to allow firing triggers safely, in
the case of partition parent tables. Neither of these issues apply to
a parallel worker -- the plan is already frozen before it can ever
start, and it isn't going to be firing any triggers either.
That last part could *easily* change in a future release. We've
already started to allow CTAS with parallel query, and there have
already been multiple people wanting to allow more. It would be a
shame if we threw up additional obstacles in the way of that...
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Robert Haas <robertmhaas@gmail.com> writes:
On Sat, Oct 6, 2018 at 2:59 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
The reasons why we need locks on tables not physically accessed by the
query are (a) to ensure that we've blocked, or received sinval messages
for, any DDL related to views or partition parent tables, in case that
would invalidate the plan; (b) to allow firing triggers safely, in
the case of partition parent tables. Neither of these issues apply to
a parallel worker -- the plan is already frozen before it can ever
start, and it isn't going to be firing any triggers either.
That last part could *easily* change in a future release. We've
already started to allow CTAS with parallel query, and there have
already been multiple people wanting to allow more. It would be a
shame if we threw up additional obstacles in the way of that...
I hardly think that this is the most serious issue in the way of
doing non-read-only things in parallel workers.
In any case, a parallel worker would surely have to open any
relations it is going to fire triggers for. If it gets the correct
lock when it does that, all is well. If not, the Assert in
relation_open will complain.
regards, tom lane
On Tue, Oct 9, 2018 at 2:35 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
That last part could *easily* change in a future release. We've
already started to allow CTAS with parallel query, and there have
already been multiple people wanting to allow more. It would be a
shame if we threw up additional obstacles in the way of that...I hardly think that this is the most serious issue in the way of
doing non-read-only things in parallel workers.
My concern, as I said, is about adding new obstacles.
In any case, a parallel worker would surely have to open any
relations it is going to fire triggers for. If it gets the correct
lock when it does that, all is well. If not, the Assert in
relation_open will complain.
Well, in that case, no issues.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Hi,
On Sun, Sep 30, 2018 at 7:18 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
I think that the call sites should ultimately look like
Assert(CheckRelationLockedByMe(...));
but for hunting down the places where the assertion currently fails,
it's more convenient if it's just an elog(WARNING).
I just hit one of the asserts (in relation_open()) added in
b04aeb0a053. Here's a simple reproducer:
DROP TABLE IF EXISTS test;
CREATE TABLE test (id integer primary key);
PREPARE s AS DELETE FROM test WHERE id = 1;
EXECUTE s;
EXECUTE s;
This comes from ExecInitIndexScan() and ExecInitBitmapIndexScan(),
which open the index without lock if the parent table is a target
relation:
/*
* 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);
And digging into InitPlan() up to ExecInitModifyTable():
/*
* If there are indices on the result relation, open them and save
* descriptors in the result relation info, so that we can add new
* index entries for the tuples we add/update. We need not do this
* for a DELETE, however, since deletion doesn't affect indexes. Also,
* inside an EvalPlanQual operation, the indexes might be open
* already, since we share the resultrel state with the original
* query.
*/
if (resultRelInfo->ri_RelationDesc->rd_rel->relhasindex &&
operation != CMD_DELETE &&
resultRelInfo->ri_IndexRelationDescs == NULL)
ExecOpenIndices(resultRelInfo,
node->onConflictAction != ONCONFLICT_NONE);
So, this is problematic with a cached plan on a DELETE query since the
lock on the target relation's index will never be acquired (the lock
is acquired on the first execution in get_relation_info()). This
doesn't seem unsafe though, since DROP INDEX [CONCURRENTLY] will still
acquire lock on the index relation or query xid before dropping the
index.
I'm not sure of what's the best way to fix this problem. I wanted to
modify ExecInitIndexScan() and ExecInitBitmapIndexScan() to acquire
the lock for a DELETE on the target relation, however I don't think
that we have that information at this point. Maybe just
unconditionally acquire an AccessShareLock on the index in those
functions?
Julien Rouhaud <rjuju123@gmail.com> writes:
I just hit one of the asserts (in relation_open()) added in
b04aeb0a053. Here's a simple reproducer:
Yeah, I think this is the same issue being discussed in
/messages/by-id/19465.1541636036@sss.pgh.pa.us
I imagine the patch David recently posted in that thread will fix this,
but can you check, and/or review the patch?
regards, tom lane
On Sun, Feb 10, 2019 at 12:31 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:
Julien Rouhaud <rjuju123@gmail.com> writes:
I just hit one of the asserts (in relation_open()) added in
b04aeb0a053. Here's a simple reproducer:Yeah, I think this is the same issue being discussed in
Ah indeed, sorry I totally missed that thread.
I imagine the patch David recently posted in that thread will fix this,
but can you check, and/or review the patch?
I tried quickly and it does fix my test case. It's quite late here,
so I'll review the patch tomorrow.
Thanks.