扫描算子----NodeSeqscan.cpp解析

引言

从本篇文章开始,我将对扫描算子开始学习。本篇文章学习SeqScan算子。

代码位置

src\gausskernel\runtime\executor\nodeSeqscan.cpp

功能作用

SeqScan是最基本的扫描算子,用于扫描一个没有任何索引等信息的普通物理表。其最关键的函数是ExecSeqScan,扫描获取元组并返回一个TupleTableSlot对象。

ExecSeqScan函数代码如下:

 
  1. //代码清单1
  2. TupleTableSlot* ExecSeqScan(SeqScanState* node)
  3. {
  4. if (node->scanBatchMode) {
  5. return (TupleTableSlot *)SeqNextBatchMode(node);
  6. } else {
  7. return ExecScan((ScanState *) node, node->ScanNextMtd, (ExecScanRecheckMtd) SeqRecheck);
  8. }
  9. }

传入参数

其传入参数是一个SeqScanState类型的node节点,SeqScanState结构体定义为:

 
  1. //代码清单2
  2. typedef ScanState SeqScanState;
  3. typedef struct ScanState {
  4. PlanState ps; /* its first field is NodeTag */
  5. Relation ss_currentRelation;
  6. TableScanDesc ss_currentScanDesc;
  7. TupleTableSlot* ss_ScanTupleSlot;
  8. bool ss_ReScan;
  9. Relation ss_currentPartition;
  10. bool isPartTbl;
  11. int currentSlot; /* current iteration position */
  12. ScanDirection partScanDirection;
  13. List* partitions; /* list of Partition */
  14. List* subpartitions; /* list of SubPartition */
  15. LOCKMODE lockMode;
  16. List* runTimeParamPredicates;
  17. bool runTimePredicatesReady;
  18. bool is_scan_end; /* @hdfs Mark whether iterator is over or not, if the scan uses informational constraint. */
  19. SeqScanAccessor* ss_scanaccessor; /* prefetch related */
  20. int part_id;
  21. List* subPartLengthList;
  22. int startPartitionId; /* start partition id for parallel threads. */
  23. int endPartitionId; /* end partition id for parallel threads. */
  24. RangeScanInRedis rangeScanInRedis; /* if it is a range scan in redistribution time */
  25. bool isSampleScan; /* identify is it table sample scan or not. */
  26. SampleScanParams sampleScanInfo; /* TABLESAMPLE params include type/seed/repeatable. */
  27. SeqScanGetNextMtd fillNextSlotFunc;
  28. ExecScanAccessMtd ScanNextMtd;
  29. bool scanBatchMode;
  30. ScanBatchState* scanBatchState;
  31. } ScanState;

类似继承的效果

代码清代2中ScanState结构体内定义的第一行是 PlanState ps;可以视作ScanState结构体“继承”于PlanState结构体。因为对一个ScanState结构体指针node执行(PlanState*)node语句是完全被允许的,并且类型转换后,node视作PlanState*类型使用,并只能访问ps所指向的内容。

图解如下:

继承示意图

node指针和ps指针指向同一个位置,所以类型转换前,node能读取ScanState的信息,类型转换后,node只能读取PlanState的信息。这样达到了一个类似继承的效果。

这样做可以给编写代码带来方便,手动进行函数重载,详细内容我将在后文介绍。

主要字段解释

类型命名含义
Relationss_currentRelation正在被扫描的关系
TableScanDescss_currentScanDesc目前扫描的描述信息
TupleTableSlot*ss_ScanTupleSlot存储扫描获得的元组
boolisPartTbl是否是分区表
LOCKMODElockMode锁模式
boolrunTimePredicatesReady是否准备好运行时过滤谓词
List*runTimeParamPredicates过滤谓词的列表
boolscanBatchMode是否批量获取元组
ScanBatchStatescanBatchState存储批量元组

有关分区表的内容将在今后的文章中解释。

返回参数

其返回参数是一个TupleTableSlot类型结构体的指针。TupleTableSlot结构体是数据库执行过程中临时存储元组数据的一个数据结构,通常在执行过程中作为中间数据,传递给上层进行处理。

结构体定义如下:

 
  1. //代码清单3
  2. typedef struct TupleTableSlot {
  3. NodeTag type;
  4. bool tts_isempty; /* true = slot is empty */
  5. bool tts_shouldFree; /* should pfree tts_tuple? */
  6. bool tts_shouldFreeMin; /* should pfree tts_mintuple? */
  7. bool tts_slow; /* saved state for slot_deform_tuple */
  8. Tuple tts_tuple; /* physical tuple, or NULL if virtual */
  9. #ifdef PGXC
  10. /*
  11. * PGXC extension to support tuples sent from remote Datanode.
  12. */
  13. char* tts_dataRow; /* Tuple data in DataRow format */
  14. int tts_dataLen; /* Actual length of the data row */
  15. bool tts_shouldFreeRow; /* should pfree tts_dataRow? */
  16. struct AttInMetadata* tts_attinmeta; /* store here info to extract values from the DataRow */
  17. Oid tts_xcnodeoid; /* Oid of node from where the datarow is fetched */
  18. MemoryContext tts_per_tuple_mcxt;
  19. #endif
  20. TupleDesc tts_tupleDescriptor; /* slot's tuple descriptor */
  21. MemoryContext tts_mcxt; /* slot itself is in this context */
  22. Buffer tts_buffer; /* tuple's buffer, or InvalidBuffer */
  23. int tts_nvalid; /* # of valid values in tts_values */
  24. Datum* tts_values; /* current per-attribute values */
  25. bool* tts_isnull; /* current per-attribute isnull flags */
  26. Datum* tts_lobPointers;
  27. MinimalTuple tts_mintuple; /* minimal tuple, or NULL if none */
  28. HeapTupleData tts_minhdr; /* workspace for minimal-tuple-only case */
  29. long tts_off; /* saved state for slot_deform_tuple */
  30. long tts_meta_off; /* saved state for slot_deform_cmpr_tuple */
  31. TableAmType tts_tupslotTableAm; /* slots's tuple table type */
  32. } TupleTableSlot;

主要字段解释

类型命名含义
NodeTagtype结点类型
Tupletts_tuple存储的物理元组
MemoryContexttts_mcxtslot槽所在内存上下文
Buffertts_buffer元组的缓冲区
inttts_nvalidtts_values 中的有效值个数
Datum*tts_values属性值
TableAmTypetts_tupslotTableAmslot槽的类型

其中tts_values里存储属性值。例如获取了某一个表的某一行数据:

SeqScan表数据

那么tts_values数组中所存储的就是:

tts_values数据

执行过程

如果scanBatchMode为真,则调用SeqNextBatchMode函数。否则调用ExecScan函数。

  • ExecScan函数:返回单个元组

  • SeqNextBatchMode函数:批量返回元组

    观察SeqNextBatchMode函数的返回值ScanBatchResult结构体指针,如代码清单4.

     
      
    1. //代码清单4
    2. struct ScanBatchResult {
    3. int rows; /* rows number for current page. */
    4. TupleTableSlot** scanTupleSlotInBatch; /* array size of BatchMaxSize, stores tuples scanned in a page */
    5. };

    可以看到结构体里存放着一个TupleTableSlot** 二维指针,用于存放返回的批量元组。

小结

本篇文章中,我学习了TupleTableSlot结构体、ScanState结构体以及ExecSeqScan函数的作用。接下来的几篇文章我将继续学习其他扫描算子。下一篇文章:IndexScan算子。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值