该函数初始化索引扫描状态信息,创建扫描键,并打开表和索引的relation
测试表结构:
test=# \d poly100w
数据表 "sde.poly100w"
栏位 | 类型 | 校对规则 | 可空的 | 预设
-------------------+-----------------------+----------+----------+-------------------------------------------------------------
objectid | integer | | not null |
globalid | character varying(38) | | not null | '{00000000-0000-0000-0000-000000000000}'::character varying
gdb_geomattr_data | bytea | | |
shape | geometry | | |
索引:
"a2_ix1" gist (shape)
"r13_sde_rowid_uk" UNIQUE, btree (objectid) WITH (fillfactor='75')
"uuid_13" UNIQUE, btree (globalid) WITH (fillfactor='75')
检查约束限制
"enforce_srid_shape" CHECK (st_srid(shape) = 3857)
select length(st_astext(shape)) from poly100w where objectid=100;
代码段1
IndexScanState *
ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
{
IndexScanState *indexstate;
Relation currentRelation;
LOCKMODE lockmode;
/*
* create state structure
*/
/*
当前内存上下文为ExecutorState
*/
indexstate = makeNode(IndexScanState);
/*
p *(Plan *) node
$52 = {type = T_IndexScan, startup_cost = 0.42749999999999999, total_cost = 9.0724999999999998, plan_rows = 1, plan_width = 4, parallel_aware = false, parallel_safe = true,async_capable = false, plan_node_id = 0, targetlist = 0x25ee420, qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, extParam = 0x0, allParam = 0x0}
*/
indexstate->ss.ps.plan = (Plan *) node;
indexstate->ss.ps.state = estate;
/*
p indexstate->ss.ps.ExecProcNode
$56 = (ExecProcNodeMtd) 0x756c87 <ExecIndexScan>
*/
indexstate->ss.ps.ExecProcNode = ExecIndexScan;
/*
* Miscellaneous initialization
*
* create expression context for node
*/
/*创建ExprContext,并赋予planstate的ps_ExprContext变量
并在estate->es_query_cxt中创建ExprContext上下文,并赋予econtext->ecxt_per_tuple_memory,具体实现参考下面的代码段2
*/
ExecAssignExprContext(estate, &indexstate->ss.ps);
/*
* open the scan relation(表,poly100w)
具体看下面代码3部分
*/
currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
//赋予scanstatede ss_currentRelation
indexstate->ss.ss_currentRelation = currentRelation;
indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
/*
* get the scan type from the relation descriptor.
*/
//见下面的代码4部分
ExecInitScanTupleSlot(estate, &indexstate->ss,
RelationGetDescr(currentRelation),
table_slot_callbacks(currentRelation));
/*
* Initialize result type and projection.
*/
/*
void
ExecInitResultTypeTL(PlanState *planstate)
{
/*p *planstate->plan->targetlist
$69 = {type = T_List, length = 1, max_length = 5, elements = 0x25ee438, initial_elements = 0x25ee438}*/
//具体查看代码5
TupleDesc tupDesc = ExecTypeFromTL(planstate->plan->targetlist);
planstate->ps_ResultTupleDesc = tupDesc;
}
*/
ExecInitResultTypeTL(&indexstate->ss.ps);
//具体代码看https://blog.csdn.net/liufeng1980423/article/details/149253663?spm=1001.2014.3001.5501
ExecAssignScanProjectionInfo(&indexstate->ss);
/*
* initialize child expressions
*
* Note: we don't initialize all of the indexqual expression, only the
* sub-parts corresponding to runtime keys (see below). Likewise for
* indexorderby, if any. But the indexqualorig expression is always
* initialized even though it will only be used in some uncommon cases ---
* would be nice to improve that. (Problem is that any SubPlans present
* in the expression must be found now...)
*/
indexstate->ss.ps.qual =
ExecInitQual(node->scan.plan.qual, (PlanState *) indexstate);
indexstate->indexqualorig =
ExecInitQual(node->indexqualorig, (PlanState *) indexstate);
indexstate->indexorderbyorig =
ExecInitExprList(node->indexorderbyorig, (PlanState *) indexstate);
/*
* If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
* here. This allows an index-advisor plugin to EXPLAIN a plan containing
* references to nonexistent indexes.
*/
if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
return indexstate;
/* Open the index relation. */
lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode;
indexstate->iss_RelationDesc = index_open(node->indexid, lockmode);
/*
* Initialize index-specific scan state
*/
indexstate->iss_RuntimeKeysReady = false;
indexstate->iss_RuntimeKeys = NULL;
indexstate->iss_NumRuntimeKeys = 0;
/*
* build the index scan keys from the index qualification
*/
ExecIndexBuildScanKeys((PlanState *) indexstate,
indexstate->iss_RelationDesc,
node->indexqual,
false,
&indexstate->iss_ScanKeys,
&indexstate->iss_NumScanKeys,
&indexstate->iss_RuntimeKeys,
&indexstate->iss_NumRuntimeKeys,
NULL, /* no ArrayKeys */
NULL);
/*
* any ORDER BY exprs have to be turned into scankeys in the same way
*/
ExecIndexBuildScanKeys((PlanState *) indexstate,
indexstate->iss_RelationDesc,
node->indexorderby,
true,
&indexstate->iss_OrderByKeys,
&indexstate->iss_NumOrderByKeys,
&indexstate->iss_RuntimeKeys,
&indexstate->iss_NumRuntimeKeys,
NULL, /* no ArrayKeys */
NULL);
/* Initialize sort support, if we need to re-check ORDER BY exprs */
if (indexstate->iss_NumOrderByKeys > 0)
{
int numOrderByKeys = indexstate->iss_NumOrderByKeys;
int i;
ListCell *lco;
ListCell *lcx;
/*
* Prepare sort support, and look up the data type for each ORDER BY
* expression.
*/
Assert(numOrderByKeys == list_length(node->indexorderbyops));
Assert(numOrderByKeys == list_length(node->indexorderbyorig));
indexstate->iss_SortSupport = (SortSupportData *)
palloc0(numOrderByKeys * sizeof(SortSupportData));
indexstate->iss_OrderByTypByVals = (bool *)
palloc(numOrderByKeys * sizeof(bool));
indexstate->iss_OrderByTypLens = (int16 *)
palloc(numOrderByKeys * sizeof(int16));
i = 0;
forboth(lco, node->indexorderbyops, lcx, node->indexorderbyorig)
{
Oid orderbyop = lfirst_oid(lco);
Node *orderbyexpr = (Node *) lfirst(lcx);
Oid orderbyType = exprType(orderbyexpr);
Oid orderbyColl = exprCollation(orderbyexpr);
SortSupport orderbysort = &indexstate->iss_SortSupport[i];
/* Initialize sort support */
orderbysort->ssup_cxt = CurrentMemoryContext;
orderbysort->ssup_collation = orderbyColl;
/* See cmp_orderbyvals() comments on NULLS LAST */
orderbysort->ssup_nulls_first = false;
/* ssup_attno is unused here and elsewhere */
orderbysort->ssup_attno = 0;
/* No abbreviation */
orderbysort->abbreviate = false;
PrepareSortSupportFromOrderingOp(orderbyop, orderbysort);
get_typlenbyval(orderbyType,
&indexstate->iss_OrderByTypLens[i],
&indexstate->iss_OrderByTypByVals[i]);
i++;
}
/* allocate arrays to hold the re-calculated distances */
indexstate->iss_OrderByValues = (Datum *)
palloc(numOrderByKeys * sizeof(Datum));
indexstate->iss_OrderByNulls = (bool *)
palloc(numOrderByKeys * sizeof(bool));
/* and initialize the reorder queue */
indexstate->iss_ReorderQueue = pairingheap_allocate(reorderqueue_cmp,
indexstate);
}
/*
* If we have runtime keys, we need an ExprContext to evaluate them. The
* node's standard context won't do because we want to reset that context
* for every tuple. So, build another context just like the other one...
* -tgl 7/11/00
*/
if (indexstate->iss_NumRuntimeKeys != 0)
{
ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
ExecAssignExprContext(estate, &indexstate->ss.ps);
indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
indexstate->ss.ps.ps_ExprContext = stdecontext;
}
else
{
indexstate->iss_RuntimeContext = NULL;
}
/*
* all done.
*/
return indexstate;
}
代码段2
static ExprContext *
CreateExprContextInternal(EState *estate, Size minContextSize,
Size initBlockSize, Size maxBlockSize)
{
ExprContext *econtext;
MemoryContext oldcontext;
/*
当前内存上下文为ExecutorState
*/
/* Create the ExprContext node within the per-query memory context */
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
econtext = makeNode(ExprContext);
/* Initialize fields of ExprContext */
//单表的扫描tuple
econtext->ecxt_scantuple = NULL;
//关联内表的扫描tuple
econtext->ecxt_innertuple = NULL;
//关联外表的扫描tuple
econtext->ecxt_outertuple = NULL;
econtext->ecxt_per_query_memory = estate->es_query_cxt;
/*
* Create working memory for expression evaluation in this context.
*/
econtext->ecxt_per_tuple_memory =
AllocSetContextCreate(estate->es_query_cxt,
"ExprContext",
minContextSize,
initBlockSize,
maxBlockSize);
econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
econtext->ecxt_param_list_info = estate->es_param_list_info;
econtext->ecxt_aggvalues = NULL;
econtext->ecxt_aggnulls = NULL;
econtext->caseValue_datum = (Datum) 0;
econtext->caseValue_isNull = true;
econtext->domainValue_datum = (Datum) 0;
econtext->domainValue_isNull = true;
econtext->ecxt_estate = estate;
econtext->ecxt_callbacks = NULL;
/*
* Link the ExprContext into the EState to ensure it is shut down when the
* EState is freed. Because we use lcons(), shutdowns will occur in
* reverse order of creation, which may not be essential but can't hurt.
*/
/*estate->es_exprcontexts
$59 = {type = T_List, length = 1, max_length = 5, elements = 0x25e1418, initial_elements = 0x25e1418}*/
estate->es_exprcontexts = lcons(econtext, estate->es_exprcontexts);
MemoryContextSwitchTo(oldcontext);
return econtext;
}
代码段3:
Relation
ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
{
Relation rel;
/* Open the relation. */
rel = ExecGetRangeTableRelation(estate, scanrelid);
/*
* Complain if we're attempting a scan of an unscannable relation, except
* when the query won't actually be run. This is a slightly klugy place
* to do this, perhaps, but there is no better place.
*/
if ((eflags & (EXEC_FLAG_EXPLAIN_ONLY | EXEC_FLAG_WITH_NO_DATA)) == 0 &&
!RelationIsScannable(rel))
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("materialized view \"%s\" has not been populated",
RelationGetRelationName(rel)),
errhint("Use the REFRESH MATERIALIZED VIEW command.")));
return rel;
}
Relation
ExecGetRangeTableRelation(EState *estate, Index rti)
{
Relation rel;
Assert(rti > 0 && rti <= estate->es_range_table_size);
rel = estate->es_relations[rti - 1];
if (rel == NULL)
{
/* First time through, so open the relation */
/*static inline RangeTblEntry *
exec_rt_fetch(Index rti, EState *estate)
{
return (RangeTblEntry *) list_nth(estate->es_range_table, rti - 1);
}*/
RangeTblEntry *rte = exec_rt_fetch(rti, estate);
Assert(rte->rtekind == RTE_RELATION);
if (!IsParallelWorker())
{
/*
* In a normal query, we should already have the appropriate lock,
* but verify that through an Assert. Since there's already an
* Assert inside table_open that insists on holding some lock, it
* seems sufficient to check this only when rellockmode is higher
* than the minimum.
*/
rel = table_open(rte->relid, NoLock);
Assert(rte->rellockmode == AccessShareLock ||
CheckRelationLockedByMe(rel, rte->rellockmode, false));
}
else
{
/*
* If we are a parallel worker, we need to obtain our own local
* lock on the relation. This ensures sane behavior in case the
* parent process exits before we do.
*/
rel = table_open(rte->relid, rte->rellockmode);
}
estate->es_relations[rti - 1] = rel;
}
return rel;
}
代码段4
void
ExecInitScanTupleSlot(EState *estate, ScanState *scanstate,
TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
{
/*
p *tupledesc
$64 = {natts = 4, tdtypeid = 6789769, tdtypmod = -1, tdrefcount = 1, constr = 0x7f085fc8eea8, attrs = 0x7f085fc8ecb8}
*/
scanstate->ss_ScanTupleSlot = ExecAllocTableSlot(&estate->es_tupleTable,
tupledesc, tts_ops);
scanstate->ps.scandesc = tupledesc;
scanstate->ps.scanopsfixed = tupledesc != NULL;
scanstate->ps.scanops = tts_ops;
scanstate->ps.scanopsset = true;
}
TupleTableSlot *
ExecAllocTableSlot(List **tupleTable, TupleDesc desc,
const TupleTableSlotOps *tts_ops)
{
TupleTableSlot *slot = MakeTupleTableSlot(desc, tts_ops);
*tupleTable = lappend(*tupleTable, slot);
return slot;
}
/* --------------------------------
* MakeTupleTableSlot
*
* Basic routine to make an empty TupleTableSlot of given
* TupleTableSlotType. If tupleDesc is specified the slot's descriptor is
* fixed for its lifetime, gaining some efficiency. If that's
* undesirable, pass NULL.
* --------------------------------
*/
TupleTableSlot *
MakeTupleTableSlot(TupleDesc tupleDesc,
const TupleTableSlotOps *tts_ops)
{
Size basesz,
allocsz;
TupleTableSlot *slot;
basesz = tts_ops->base_slot_size;
/*
* When a fixed descriptor is specified, we can reduce overhead by
* allocating the entire slot in one go.
*/
if (tupleDesc)
allocsz = MAXALIGN(basesz) +
MAXALIGN(tupleDesc->natts * sizeof(Datum)) +
MAXALIGN(tupleDesc->natts * sizeof(bool));
else
allocsz = basesz;
//CurrentMemoryText: ExecutorState
slot = palloc0(allocsz);
/* const for optimization purposes, OK to modify at allocation time */
*((const TupleTableSlotOps **) &slot->tts_ops) = tts_ops;
slot->type = T_TupleTableSlot;
slot->tts_flags |= TTS_FLAG_EMPTY;
if (tupleDesc != NULL)
slot->tts_flags |= TTS_FLAG_FIXED;
slot->tts_tupleDescriptor = tupleDesc;
slot->tts_mcxt = CurrentMemoryContext;
slot->tts_nvalid = 0;
if (tupleDesc != NULL)
{
slot->tts_values = (Datum *)
(((char *) slot)
+ MAXALIGN(basesz));
slot->tts_isnull = (bool *)
(((char *) slot)
+ MAXALIGN(basesz)
+ MAXALIGN(tupleDesc->natts * sizeof(Datum)));
PinTupleDesc(tupleDesc);
}
/*
* And allow slot type specific initialization.
*/
slot->tts_ops->init(slot);
return slot;
}
代码5
/* ----------------------------------------------------------------
* ExecTypeFromTL
*
* Generate a tuple descriptor for the result tuple of a targetlist.
* (A parse/plan tlist must be passed, not an ExprState tlist.)
* Note that resjunk columns, if any, are included in the result.
*
* Currently there are about 4 different places where we create
* TupleDescriptors. They should all be merged, or perhaps
* be rewritten to call BuildDesc().
* ----------------------------------------------------------------
*/
TupleDesc
ExecTypeFromTL(List *targetList)
{
return ExecTypeFromTLInternal(targetList, false);
}
static TupleDesc
ExecTypeFromTLInternal(List *targetList, bool skipjunk)
{
TupleDesc typeInfo;
ListCell *l;
int len;
int cur_resno = 1;
if (skipjunk)
len = ExecCleanTargetListLength(targetList);
else
len = ExecTargetListLength(targetList);
typeInfo = CreateTemplateTupleDesc(len);
foreach(l, targetList)
{
TargetEntry *tle = lfirst(l);
if (skipjunk && tle->resjunk)
continue;
/*
length
*(FuncExpr*) tle->expr
$84 = {xpr = {type = T_FuncExpr}, funcid = 1317, funcresulttype = 23, funcretset = false, funcvariadic = false, funcformat = COERCE_EXPLICIT_CALL, funccollid = 0,
inputcollid = 100, args = 0x25281a0, location = 7}
select 1317::regprocedure;
regprocedure
--------------
length(text)
*/
TupleDescInitEntry(typeInfo,
cur_resno,
tle->resname,
exprType((Node *) tle->expr),
exprTypmod((Node *) tle->expr),
0);
TupleDescInitEntryCollation(typeInfo,
cur_resno,
exprCollation((Node *) tle->expr));
cur_resno++;
}
return typeInfo;
}