当前位置: 首页 > 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.dtcms.com/a/279477.html

相关文章:

  • k8s-高级调度(二)
  • 如何使用Cisco DevNet提供的免费ACI学习实验室(Learning Labs)?(Grok3 回答)
  • PostgreSQL 16 Administration Cookbook 读书笔记:第6章 Security
  • DLL 文件 OSError: [WinError 1401] 应用程序无法启动问题解决
  • 七、深度学习——RNN
  • HTTPS 协议原理
  • ZYNQ双核通信终极指南:FreeRTOS移植+OpenAMP双核通信+固化实战
  • 一文明白AI、AIGC、LLM、GPT、Agent、workFlow、MCP、RAG概念与关系
  • 浏览器防录屏是怎样提高视频安全性?
  • 现有医疗AI记忆、规划与工具使用的创新路径分析
  • 【Linux网络】多路转接poll、epoll
  • vue3 JavaScript 获取 el-table 单元格 赋红色外框
  • mac上用datagrip连接es
  • MFC/C++语言怎么比较CString类型最后一个字符
  • K8S的平台核心架构思想[面向抽象编程]
  • LVS(Linux Virtual Server)集群技术详解
  • linux 内核: 访问当前进程的 task_struct
  • 【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 架构搭建
  • C++-linux 6.makefile和cmake
  • 深入掌握Performance面板与LCP/FCP指标优化指南
  • 学习笔记——农作物遥感识别与大范围农作物类别制图的若干关键问题
  • 计算两个经纬度之间的距离(JavaScript 实现)
  • HashMap的长度为什么要是2的n次幂以及HashMap的继承关系(元码解析)
  • 前缀和题目:使数组互补的最少操作次数
  • 闲庭信步使用图像验证平台加速FPGA的开发:第十四课——图像二值化的FPGA实现
  • 如何集成光栅传感器到FPGA+ARM系统中?
  • JVM 内存模型详解:GC 是如何拯救内存世界的?
  • Oracle Virtualbox 虚拟机配置静态IP
  • 《亿级流量系统架构设计与实战》通用高并发架构设计 读场景
  • 1. 深入理解ArrayList源码