Greenplum資料庫外部表執行節點相關函數位于src/backend/executor/nodeExternalscan.c檔案中,用于支援外部表掃描。由以下曆程構成:
INTERFACE ROUTINES
ExecInitExternalScan creates and initializes a externalscan node.
ExecExternalScan sequentially scans a relation.
ExecExternalNext retrieve next tuple in sequential order.
ExecEndExternalScan releases any storage allocated.
ExecExternalReScan rescans the relation
ExecInitExternalScan
ExecInitExternalScan
函數建立并初始化一個externalscan節點,形參ExternalScan代表External Scan node【scan.scanrelid是此節點的外部表的index。filenames是N個字元串節點指針(或NULL)的清單,其中N是數組中的segment數。位置I的指針為NULL或指向包含segment I的檔案名的字元串節點】 。其初始化流程如下所示。
- 将形參
和ExternalScan *node
關聯到ExternalScanState對應成員中EState *estate
- 建立experssion context
- 初始化child experssions
- 檢查targetlist或qual是否包含var node引用ctid列
- 初始化tuple table
- 擷取Relation和FileScanDesc,設定到
和externalstate->ss.ss_currentRelation
externalstate->ess_ScanDesc
- 初始化result tuple type和projection info
- 設定
externalstate->delayEagerFree
ExternalScanState *ExecInitExternalScan(ExternalScan *node, EState *estate, int eflags){
ExternalScanState *externalstate = makeNode(ExternalScanState); /* create state structure */
externalstate->ss.ps.plan = (Plan *) node;
externalstate->ss.ps.state = estate;
ExecAssignExprContext(estate, &externalstate->ss.ps); /* Miscellaneous initialization: create expression context for node */
/* initialize child expressions */
externalstate->ss.ps.targetlist = (List *)ExecInitExpr((Expr *) node->scan.plan.targetlist,(PlanState *) externalstate);
externalstate->ss.ps.qual = (List *)ExecInitExpr((Expr *) node->scan.plan.qual,(PlanState *) externalstate);
/* Check if targetlist or qual contains a var node referencing the ctid column */
externalstate->cdb_want_ctid = contain_ctid_var_reference(&node->scan);
ItemPointerSetInvalid(&externalstate->cdb_fake_ctid);
/* tuple table initialization */
ExecInitResultTupleSlot(estate, &externalstate->ss.ps);
ExecInitScanTupleSlot(estate, &externalstate->ss);
/* get the relation object id from the relid'th entry in the range table and open that relation. */
Relation currentRelation = ExecOpenScanExternalRelation(estate, node->scan.scanrelid);
FileScanDesc currentScanDesc = external_beginscan(currentRelation, node->scancounter, node->uriList, node->fmtOptString, node->fmtType, node->isMasterOnly, node->rejLimit, node->rejLimitInRows, node->logErrors, node->encoding);
externalstate->ss.ss_currentRelation = currentRelation;
externalstate->ess_ScanDesc = currentScanDesc;
ExecAssignScanType(&externalstate->ss, RelationGetDescr(currentRelation));
/* Initialize result tuple type and projection info. */
ExecAssignResultTypeFromTL(&externalstate->ss.ps);
ExecAssignScanProjectionInfo(&externalstate->ss);
/* If eflag contains EXEC_FLAG_REWIND or EXEC_FLAG_BACKWARD or EXEC_FLAG_MARK, then this node is not eager free safe. */
externalstate->delayEagerFree = ((eflags & (EXEC_FLAG_REWIND | EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)) != 0);
return externalstate;
}
ExecExternalScan
ExecExternalScan
函數順序掃描外部表,傳回符合要求的元組。其調用ExecScan函數,向其傳遞通路方法。
/* ExecExternalScan(node) Scans the external relation sequentially and returns the next qualifying tuple. It calls the ExecScan() routine and passes it the access method which retrieve tuples sequentially. */
TupleTableSlot *ExecExternalScan(ExternalScanState *node) {
return ExecScan(&node->ss, (ExecScanAccessMtd) ExternalNext, (ExecScanRecheckMtd) ExternalRecheck); /* use SeqNext as access method */
}
static TupleTableSlot *ExternalNext(ExternalScanState *node) {
/* get information from the estate and scan state */
EState *estate = node->ss.ps.state;
FileScanDesc scandesc = node->ess_ScanDesc;
ScanDirection direction = estate->es_direction;
TupleTableSlot *slot = node->ss.ss_ScanTupleSlot;
bool scanNext = true;
ExternalSelectDesc externalSelectDesc = external_getnext_init(&(node->ss.ps));
if (gp_external_enable_filter_pushdown) externalSelectDesc->filter_quals = node->ss.ps.plan->qual;
while(scanNext){ /* get the next tuple from the file access methods */
HeapTuple tuple = external_getnext(scandesc, direction, externalSelectDesc);
/* save the tuple and the buffer returned to us by the access methods in our scan tuple slot and return the slot. Note: we pass 'false' because tuples returned by heap_getnext() are pointers onto disk pages and were not created with palloc() and so should not be pfree()'d. Note also that ExecStoreTuple will increment the refcount of the buffer; the refcount will not be dropped until the tuple table slot is cleared. */ // 将通路方法傳回的元組和緩沖區儲存在掃描元組槽中,并傳回槽。注意:我們傳遞“false”是因為heap_getnext()傳回的元組是指向磁盤頁的指針,不是用palloc()建立的,是以不應該是pfree()。還請注意,ExecStoreTople将增加緩沖區的refcount;在清除元組表槽之前,不會删除refcount。
if (tuple) {
ExecStoreHeapTuple(tuple, slot, InvalidBuffer, true);
if (node->ess_ScanDesc->fs_hasConstraints && !ExternalConstraintCheck(slot, node)){
ExecClearTuple(slot); continue;
}
/* CDB: Label each row with a synthetic ctid if needed for subquery dedup. */
if (node->cdb_want_ctid && !TupIsNull(slot)) {
slot_set_ctid_from_fake(slot, &node->cdb_fake_ctid);
}
}else{
ExecClearTuple(slot);
if (!node->delayEagerFree) { ExecEagerFreeExternalScan(node); }
}
scanNext = false;
}
pfree(externalSelectDesc);
return slot;
}