调用ExecScan函数,并将SeqNext函数的指针作为ExecScan函数accessMtd参数的值。并将SeqRecheck函数指针作为ExecScan函数recheckMtd参数的值。SeqNext函数将通过存储模块提供的函数heap_getnext获取下一条元组并返回;
ExecScan在利用SeqNext获得一个元组之后,还将根据计划节点中的査询条件和投影要求对得到的元组进行条件检査和投影操作,最后将满足要求的结果元组返回。这里SeqRecheck其实没做任何处理和判断,因为这个函数不使用heap_beginscan返回的keys(也就是自己去表上找,不受并发的影响。这个后面说)。
其他扫描节点的执行函数都采用类似的方式管理,即统一调用ExecScan,但根据节点的类型给ExecScan的参数AccessMtd和recheckMtd賦予不同的函数指针。
SeqScan节点的淸理过程由函数ExecEndSeqScan完成,在该函数中需要额外调用函数heap_endscan来清理ss_currentScanDesc内的信息。
2.SampleScan节点这个是9.5 版本新增的数据取样功能,支持查询返回取样数据。当前只在常规表和物化视图上接受TABLESAMPLE子句。
语法大概是这样:
SELECT select_list FROM table_name TABLESAMPLE sampling_method ( argument [, ...] ) [ REPEATABLE ( seed ) ]用法的话看这里:
(使用Sample)
(自定义Sample函数)
用白话说就是我对表中符合条件的数据可以进行采样。帮你省了一个抽奖系统,棒棒棒!!(微笑脸)。
我们看一下节点结构:
typedef struct SampleScan { Scan scan; /* use struct pointer to avoid including parsenodes.h here */ struct TableSampleClause *tablesample; } SampleScan;可以看到,在Scan的基础上加上了TableSample相关的结构,它的数据结构如下:
typedef struct TableSampleClause { NodeTag type; Oid tsmhandler; /* OID of the tablesample handler function */ List *args; /* tablesample argument expression(s) */ Expr *repeatable; /* REPEATABLE expression, or NULL if none */ } TableSampleClause;描述SampleScan查询状态的数据结构SampleScanState如下,简单而言,它在ScanState的基础上增加了Sample采样策略,随机种子,采样函数这些和Sample相关的数据。而这些数据就来自于SampleScan节点的TableSampleClause结构。
typedef struct SampleScanState { ScanState ss; List *args; /* expr states for TABLESAMPLE params */ ExprState *repeatable; /* expr state for REPEATABLE expr */ /* use struct pointer to avoid including tsmapi.h here */ struct TsmRoutine *tsmroutine; /* descriptor for tablesample method */ void *tsm_state; /* tablesample method can keep state here */ bool use_bulkread; /* use bulkread buffer access strategy? */ bool use_pagemode; /* use page-at-a-time visibility checking? */ bool begun; /* false means need to call BeginSampleScan */ uint32 seed; /* random seed */ } SampleScanState;其他的话,诸君请看代码吧~
3.IndexScan 节点如果选择条件涉及的属性上建立了索引,则生成的査询计划中涉及表的扫描时会使用IndexScan节点。该节点能够利用索引进行表的扫描以获取满足选择条件的元组。
IndexScan节点的定义如下面所示。除了继承Scan节点定义的属性外,IndexScan扩展定义了indexid属性(用于存储索引的OID)、indexqual属性(用于存储索引扫描的条件)、indexqualorig属性(用于存储没有处理的原始扫描条件链表以及indexonierdir属性(用于存储扫描的方向)。
typedef struct IndexScan { Scan scan; Oid indexid; /* OID of index to scan */ List *indexqual; /* list of index quals (usually OpExprs) */ List *indexqualorig; /* the same in original form */ List *indexorderby; /* list of index ORDER BY exprs */ List *indexorderbyorig; /* the same in original form */ List *indexorderbyops; /* OIDs of sort ops for ORDER BY exprs */ ScanDirection indexorderdir; /* forward or backward or don't care */ } IndexScan;IndexScan节点的初始化过程由函数ExecInitlndexScan完成。该函数将构造IndexScanState节点,并使用indexid获取索引的RelationData结构存放于iss_RelationDesc字段中。同时,通过调用ExeclndexBuildScanKeys将indexqual中的索引扫描条件转换为扫描关键字(ScanKey,存储扫描满足的条件)以及运行时关键字计算结构(IndexRuntimeKeylnfo,执行时才能得到结果的表达式信息)分别存储在 iss_ScanKeys 和 iss_RuntimeKeys 这两个数组中。iss_NumScanKeys 和 iss_NumRuntimeKeys 则用于指示前面两个数组的长度,同时还要设罝iss_NumRumimeKeys为false。最后将调用索引模块提供的index_beginscan初始化扫描描述符iss_ScanDesc。而索引扫描未经特殊处理的原始约束条件链表则用于构造indexqualorig字段。
typedef struct IndexOnlyScanState { ScanState ss; /* its first field is NodeTag */ List *indexqual; execution state for indexqual expressions ScanKey ioss_ScanKeys; Skey structures for index quals int ioss_NumScanKeys; number of ScanKeys ScanKey ioss_OrderByKeys; Skey structures for index ordering operators int ioss_NumOrderByKeys; number of OrderByKeys IndexRuntimeKeyInfo *ioss_RuntimeKeys; info about Skeys that must be evaluated at runtime int ioss_NumRuntimeKeys; number of RuntimeKeys bool ioss_RuntimeKeysReady; true if runtime Skeys have been computed ExprContext *ioss_RuntimeContext; expr context for evaling runtime Skeys Relation ioss_RelationDesc; index relation descriptor IndexScanDesc ioss_ScanDesc; index scan descriptor Buffer ioss_VMBuffer; buffer in use for visibility map testing, if any long ioss_HeapFetches; number of tuples we were forced to fetch from heap } IndexOnlyScanState;