From c89a0b53040d680eefe4e7178e67a2fe878a24f1 Mon Sep 17 00:00:00 2001 From: amit 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