当前位置: 首页 > news >正文

PostgreSQL ExecInitIndexScan 函数解析

该函数初始化索引扫描状态信息,创建扫描键,并打开表和索引的relation

测试表结构:

test=# \d poly100w数据表 "sde.poly100w"栏位        |         类型          | 校对规则 |  可空的  |                            预设
-------------------+-----------------------+----------+----------+-------------------------------------------------------------objectid          | integer               |          | not null |globalid          | character varying(38) |          | not null | '{00000000-0000-0000-0000-000000000000}'::character varyinggdb_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_currentRelationindexstate->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.*//*voidExecInitResultTypeTL(PlanState *planstate){/*p *planstate->plan->targetlist
$69 = {type = T_List, length = 1, max_length = 5, elements = 0x25ee438, initial_elements = 0x25ee438}*///具体查看代码5TupleDesc	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.5501ExecAssignScanProjectionInfo(&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 *///单表的扫描tupleecontext->ecxt_scantuple = NULL;//关联内表的扫描tupleecontext->ecxt_innertuple = NULL;//关联外表的扫描tupleecontext->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));elseallocsz = basesz;//CurrentMemoryText: ExecutorStateslot = 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);elselen = 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;
}

http://www.lryc.cn/news/587690.html

相关文章:

  • Cesium源码打包
  • MyBatis 在执行 SQL 时找不到名为 name 的参数
  • 项目进度压缩影响质量,如何平衡进度与质量
  • 多模态数据处理新趋势:阿里云ODPS技术栈深度解析与未来展望
  • 【Echarts】 电影票房汇总实时数据横向柱状图比图
  • 【PostgreSQL异常解决】`PostgreSQL`异常之类型转换错误
  • 第十九篇 自动化报表生成:Python一键生成可视化Excel图表与专业PDF报告,老板看了都点赞!
  • C++11 std::is_permutation:从用法到原理的深度解析
  • grpo nl2sql qwen3 模型强化学习训练有效果的成立条件有哪些
  • c#如何将不同类型的数据存储到一起
  • 基于hadoop的竞赛网站日志数据分析与可视化(下)
  • 基于光栅传感器+FPGA+ARM的测量控制解决方案
  • 图像修复:深度学习GLCIC神经网络实现老照片划痕修复
  • RNN(循环神经网络)
  • 【git fetch submodule报错】Errors during submodule fetch 如何解决?
  • VUE export import
  • 【算法深练】BFS:“由近及远”的遍历艺术,广度优先算法题型全解析
  • 人工智能如何重构能源系统以应对气候变化?
  • 从数据洞察到设计创新:UI前端如何利用数字孪生提升产品交互体验?
  • Pythonic:Python 语言习惯和哲学的代码风格
  • vue中使用西瓜播放器xgplayer (封装)+xgplayer-hls 播放.m3u8格式视频
  • Vue+axios
  • Rust语言实战:LeetCode算法精解
  • 从“炼丹”到“流水线”——如何用Prompt Engineering把LLM微调成本打下来?
  • 内容管理系统指南:企业内容运营的核心引擎
  • Retinex视网膜算法(SSR、MSR、MSRCR)
  • JVM监控及诊断工具-命令行篇
  • AI香烟检测实战:YOLO11模型训练全过程解析
  • 【第一章编辑器开发基础第一节绘制编辑器元素_7折叠面板控件(7/7)】
  • python学智能算法(十八)|SVM基础概念-向量点积