接前面,再次上溯。可以知道:
ExecProcNode: 会根据情况不同,将PlanNode转为各种类型Node再参与运算:
TupleTableSlot * ExecProcNode(PlanState *node) { //ExecProcNode
fprintf(stderr,"ExecProcNode:node->ss_currentScanDesc->rs_startblock is: %d by process %d\n",
((SeqScanState *) node)->ss_currentScanDesc->rs_startblock,getpid()); TupleTableSlot *result; CHECK_FOR_INTERRUPTS(); if (node->chgParam != NULL) /* something changed */ ExecReScan(node); /* let ReScan handle this */ if (node->instrument) InstrStartNode(node->instrument); switch (nodeTag(node)) { /* * control nodes */ case T_ResultState: result = ExecResult((ResultState *) node); break; ... /* * scan nodes */ case T_SeqScanState: result = ExecSeqScan((SeqScanState *) node); break; case T_IndexScanState: result = ExecIndexScan((IndexScanState *) node); break; ... default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node)); result = NULL; break; } if (node->instrument) InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0); return result; }
各种 Node,有点像 Java里的 类和基类,这是如何实现的呢?
看下面就清楚了:
/* ---------------- * PlanState node * * We never actually instantiate any PlanState nodes; this is just the common * abstract superclass for all PlanState-type nodes. * ---------------- */ typedef struct PlanState { NodeTag type; Plan *plan; /* associated Plan node */ EState *state; /* at execution time, states of individual * nodes point to one EState for the whole * top-level plan */ Instrumentation *instrument; /* Optional runtime stats for this node */ /* * Common structural data for all Plan types. These links to subsidiary * state trees parallel links in the associated plan tree (except for the * subPlan list, which does not exist in the plan tree). */ List *targetlist; /* target list to be computed at this node */ List *qual; /* implicitly-ANDed qual conditions */ struct PlanState *lefttree; /* input plan tree(s) */ struct PlanState *righttree; List *initPlan; /* Init SubPlanState nodes (un-correlated expr * subselects) */ List *subPlan; /* SubPlanState nodes in my expressions */ /* * State for management of parameter-change-driven rescanning */ Bitmapset *chgParam; /* set of IDs of changed Params */ /* * Other run-time state needed by most if not all node types. */ TupleTableSlot *ps_ResultTupleSlot; /* slot for my result tuples */ ExprContext *ps_ExprContext; /* node's expression-evaluation context */ ProjectionInfo *ps_ProjInfo; /* info for doing tuple projection */ bool ps_TupFromTlist;/* state flag for processing set-valued * functions in targetlist */ } PlanState;
再看:
/* ---------------- * ResultState information * ---------------- */ typedef struct ResultState { PlanState ps; /* its first field is NodeTag */ ExprState *resconstantqual; bool rs_done; /* are we done? */ bool rs_checkqual; /* do we need to check the qual? */ } ResultState;
再看:
/* ---------------- * ScanState information * * ScanState extends PlanState for node types that represent * scans of an underlying relation. It can also be used for nodes * that scan the output of an underlying plan node --- in that case, * only ScanTupleSlot is actually useful, and it refers to the tuple * retrieved from the subplan. * * currentRelation relation being scanned (NULL if none) * currentScanDesc current scan descriptor for scan (NULL if none) * ScanTupleSlot pointer to slot in tuple table holding scan tuple * ---------------- */ typedef struct ScanState { PlanState ps; /* its first field is NodeTag */ Relation ss_currentRelation; HeapScanDesc ss_currentScanDesc; TupleTableSlot *ss_ScanTupleSlot; } ScanState;
甚至还有这个:
/* ---------------- * IndexScanState information * * indexqualorig execution state for indexqualorig expressions * ScanKeys Skey structures for index quals * NumScanKeys number of ScanKeys * OrderByKeys Skey structures for index ordering operators * NumOrderByKeys number of OrderByKeys * RuntimeKeys info about Skeys that must be evaluated at runtime * NumRuntimeKeys number of RuntimeKeys * RuntimeKeysReady true if runtime Skeys have been computed * RuntimeContext expr context for evaling runtime Skeys * RelationDesc index relation descriptor * ScanDesc index scan descriptor * ---------------- */ typedef struct IndexScanState { ScanState ss; /* its first field is NodeTag */ List *indexqualorig; ScanKey iss_ScanKeys; int iss_NumScanKeys; ScanKey iss_OrderByKeys; int iss_NumOrderByKeys; IndexRuntimeKeyInfo *iss_RuntimeKeys; int iss_NumRuntimeKeys; bool iss_RuntimeKeysReady; ExprContext *iss_RuntimeContext; Relation iss_RelationDesc; IndexScanDesc iss_ScanDesc; } IndexScanState;
那就相当于 子类的子类了。
我的感觉,与其说C语言是面向过程语言,不如说它是数据结构为中心的语言。
熟练掌握各类数据结构以及指针的用法,那就无往而不利了。