v12-0002-Introduce-an-array-of-RangeTblEntry-pointers-in-.patch

text/plain

Filename: v12-0002-Introduce-an-array-of-RangeTblEntry-pointers-in-.patch
Type: text/plain
Part: 1
Message: Re: executor relation handling

Patch

Format: format-patch
Series: patch v12-0002
Subject: Introduce an array of RangeTblEntry pointers in EState
File+
contrib/postgres_fdw/postgres_fdw.c 6 6
src/backend/commands/copy.c 1 1
src/backend/commands/trigger.c 2 1
src/backend/executor/execExprInterp.c 4 3
src/backend/executor/execMain.c 11 8
src/backend/executor/execUtils.c 23 1
src/backend/executor/nodeLockRows.c 1 1
src/backend/replication/logical/worker.c 2 0
src/include/executor/executor.h 1 0
src/include/nodes/execnodes.h 19 0
src/include/parser/parsetree.h 0 10
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