接前面,继续观察 PortalStart,其中有:
/* * Create QueryDesc in portal's context; for the moment, set * the destination to DestNone. */ queryDesc = CreateQueryDesc((PlannedStmt *) linitial(portal->stmts), portal->sourceText, GetActiveSnapshot(), InvalidSnapshot, None_Receiver, params, 0);
CreateQueryDesc 的程序:
/* * CreateQueryDesc */ QueryDesc * CreateQueryDesc(PlannedStmt *plannedstmt, const char *sourceText, Snapshot snapshot, Snapshot crosscheck_snapshot, DestReceiver *dest, ParamListInfo params, int instrument_options) { QueryDesc *qd = (QueryDesc *) palloc(sizeof(QueryDesc)); qd->operation = plannedstmt->commandType; /* operation */ qd->plannedstmt = plannedstmt; /* plan */ qd->utilitystmt = plannedstmt->utilityStmt; /* in case DECLARE CURSOR */ qd->sourceText = sourceText; /* query text */ qd->snapshot = RegisterSnapshot(snapshot); /* snapshot */ /* RI check snapshot */ qd->crosscheck_snapshot = RegisterSnapshot(crosscheck_snapshot); qd->dest = dest; /* output dest */ qd->params = params; /* parameter values passed into query */ qd->instrument_options = instrument_options; /* instrumentation * wanted? */ /* null these fields until set by ExecutorStart */ qd->tupDesc = NULL; qd->estate = NULL; qd->planstate = NULL; qd->totaltime = NULL; return qd; }
只是准备好了数据而已。
再分析之下的一段:
/* * Call ExecutorStart to prepare the plan for execution */ ExecutorStart(queryDesc, myeflags);
其定义为:
/* ---------------------------------------------------------------- * ExecutorStart * * This routine must be called at the beginning of any execution of any * query plan * * Takes a QueryDesc previously created by CreateQueryDesc (which is separate * only because some places use QueryDescs for utility commands). The tupDesc * field of the QueryDesc is filled in to describe the tuples that will be * returned, and the internal fields (estate and planstate) are set up. * * eflags contains flag bits as described in executor.h. * * NB: the CurrentMemoryContext when this is called will become the parent * of the per-query context used for this Executor invocation. * * We provide a function hook variable that lets loadable plugins * get control when ExecutorStart is called. Such a plugin would * normally call standard_ExecutorStart(). * * ---------------------------------------------------------------- */ void ExecutorStart(QueryDesc *queryDesc, int eflags) { if (ExecutorStart_hook) (*ExecutorStart_hook) (queryDesc, eflags); else standard_ExecutorStart(queryDesc, eflags); } void standard_ExecutorStart(QueryDesc *queryDesc, int eflags) { ... /* * If non-read-only query, set the command ID to mark output tuples with */ switch (queryDesc->operation) { case CMD_SELECT: /* * SELECT FOR UPDATE/SHARE and modifying CTEs need to mark tuples */ if (queryDesc->plannedstmt->rowMarks != NIL || queryDesc->plannedstmt->hasModifyingCTE) estate->es_output_cid = GetCurrentCommandId(true); /* * A SELECT without modifying CTEs can't possibly queue triggers, * so force skip-triggers mode. This is just a marginal efficiency * hack, since AfterTriggerBeginQuery/AfterTriggerEndQuery aren't * all that expensive, but we might as well do it. */ if (!queryDesc->plannedstmt->hasModifyingCTE) eflags |= EXEC_FLAG_SKIP_TRIGGERS; break; case CMD_INSERT: case CMD_DELETE: case CMD_UPDATE: estate->es_output_cid = GetCurrentCommandId(true); break; default: elog(ERROR, "unrecognized operation code: %d", (int) queryDesc->operation); break; } ... }