回溯:PortalRun --> PortalRunSelect
boolPortalRun(Portal portal, long count, bool isTopLevel, DestReceiver *dest, DestReceiver *altdest, char *completionTag){ ... portal->status = PORTAL_ACTIVE; ... PG_TRY(); { ActivePortal = portal; CurrentResourceOwner = portal->resowner; PortalContext = PortalGetHeapMemory(portal); MemoryContextSwitchTo(PortalContext); switch (portal->strategy) { case PORTAL_ONE_SELECT: case PORTAL_ONE_RETURNING: case PORTAL_ONE_MOD_WITH: case PORTAL_UTIL_SELECT: ... /* * Now fetch desired portion of results. */ nprocessed = PortalRunSelect(portal, true, count, dest); ... break; case PORTAL_MULTI_QUERY: ... break; default: ... break; } } PG_CATCH(); { ... PG_RE_THROW(); } PG_END_TRY(); ... return result;}
再回溯:
static voidexec_simple_query(const char *query_string){ ... parsetree_list = pg_parse_query(query_string); ... /* * Run through the raw parsetree(s) and process each one. */ foreach(parsetree_item, parsetree_list) { ... querytree_list = pg_analyze_and_rewrite(parsetree, query_string,NULL, 0); plantree_list = pg_plan_queries(querytree_list, 0, NULL); ... portal = CreatePortal("", true, true); ... PortalDefineQuery(portal, NULL, query_string, commandTag, plantree_list, NULL); ... PortalStart(portal, NULL, 0, snapshot_set); ... /* * Run the portal to completion, and then drop it (and the receiver). */ (void) PortalRun(portal, FETCH_ALL, isTopLevel, receiver, receiver, completionTag); ... } /* end loop over parsetrees */ ...}
从源代码中查看的结果是:对于我的普通查询,InitScanRelation中对 ss_currentScanDesc 进行了赋值。
经过调查,路径是这样的:
PortalStart-->ExecutorStart-->Standard_ExecutorStart-->InitPlan-->ExecInitNode-->ExecInitSeqscan-->InitScanRelation
再回过头来回味:
PlanState *ExecInitNode(Plan *node, EState *estate, int eflags){ PlanState *result; List *subps; ListCell *l; /* * do nothing when we get to the end of a leaf on tree. */ if (node == NULL) return NULL; switch (nodeTag(node)) { /* * control nodes */ case T_Result: result = (PlanState *) ExecInitResult((Result *) node, estate, eflags); break; .. /* * scan nodes */ case T_SeqScan: result = (PlanState *) ExecInitSeqScan((SeqScan *) node, estate, eflags); break; case T_IndexScan: result = (PlanState *) ExecInitIndexScan((IndexScan *) node, estate, eflags); break; case T_IndexOnlyScan: result = (PlanState *) ExecInitIndexOnlyScan((IndexOnlyScan *) node, estate, eflags); break; ... } /* * Initialize any initPlans present in this node. The planner put them in * a separate list for us. */ subps = NIL; foreach(l, node->initPlan) { SubPlan *subplan = (SubPlan *) lfirst(l); SubPlanState *sstate; Assert(IsA(subplan, SubPlan)); sstate = ExecInitSubPlan(subplan, result); subps = lappend(subps, sstate); } result->initPlan = subps; /* Set up instrumentation for this node if requested */ if (estate->es_instrument) result->instrument = InstrAlloc(1, estate->es_instrument); return result;}
从上面可以看到,在进行 ExecInitNode 的时候,根据tag 进行了特定的初始化。
ExecInitSeqscan:
/* ---------------------------------------------------------------- * ExecInitSeqScan * ---------------------------------------------------------------- */SeqScanState *ExecInitSeqScan(SeqScan *node, EState *estate, int eflags){ SeqScanState *scanstate; /* * Once upon a time it was possible to have an outerPlan of a SeqScan, but * not any more. */ Assert(outerPlan(node) == NULL); Assert(innerPlan(node) == NULL); /* * create state structure */ scanstate = makeNode(SeqScanState); scanstate->ps.plan = (Plan *) node; scanstate->ps.state = estate; /* * Miscellaneous initialization * * create expression context for node */ ExecAssignExprContext(estate, &scanstate->ps); /* * initialize child expressions */ scanstate->ps.targetlist = (List *) ExecInitExpr((Expr *) node->plan.targetlist, (PlanState *) scanstate); scanstate->ps.qual = (List *) ExecInitExpr((Expr *) node->plan.qual, (PlanState *) scanstate); /* * tuple table initialization */ ExecInitResultTupleSlot(estate, &scanstate->ps); ExecInitScanTupleSlot(estate, scanstate); /* * initialize scan relation */ InitScanRelation(scanstate, estate); scanstate->ps.ps_TupFromTlist = false; /* * Initialize result tuple type and projection info. */ ExecAssignResultTypeFromTL(&scanstate->ps); ExecAssignScanProjectionInfo(scanstate); return scanstate;}
与此相对的,还有另外一条路径,非常类似:
PortalRun-->
PortalRunSelect-->ExecutorRun-->Standard_ExecutorRun-->ExecutePlan-->ExecProcNode-->ExecSeqscan
当初在 PortalStart 的时候按 Tag来分别进行初始化,在 PortalRun的时候,也要按照 Tag 来分别执行各自合适的Scan(物理磁盘扫描)。
TupleTableSlot *ExecProcNode(PlanState *node){ 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; ... } if (node->instrument) InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0); return result;}