PostgreSQL在何处处理 sql查询之十

回到 exec_simple_query函数上来。

/*

 * exec_simple_query

 *

 * Execute a "simple Query" protocol message.

 */

static void

exec_simple_query(const char *query_string)

{

    ...

    start_xact_command();

    
... parsetree_list
= pg_parse_query(query_string); ... /* * Run through the raw parsetree(s) and process each one. */ foreach(parsetree_item, parsetree_list) { Node *parsetree = (Node *) lfirst(parsetree_item); ... querytree_list = pg_analyze_and_rewrite(parsetree, query_string, NULL, 0); plantree_list = pg_plan_queries(querytree_list, 0, NULL); /* If we got a cancel signal in analysis or planning, quit */ CHECK_FOR_INTERRUPTS(); /* * Create unnamed portal to run the query or queries in. If there * already is one, silently drop it. */ portal = CreatePortal("", true, true); /* Don't display the portal in pg_cursors */ portal->visible = false; /* * We don't have to copy anything into the portal, because everything * we are passing here is in MessageContext, which will outlive the * portal anyway. */ PortalDefineQuery(portal, NULL, query_string, commandTag, plantree_list, NULL); /* * Start the portal. * * If we took a snapshot for parsing/planning, the portal may be able * to reuse it for the execution phase. Currently, this will only * happen in PORTAL_ONE_SELECT mode. But even if PortalStart doesn't * end up being able to do this, keeping the parse/plan snapshot * around until after we start the portal doesn't cost much. */ 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); (*receiver->rDestroy) (receiver); PortalDrop(portal, false); ... EndCommand(completionTag, dest); } /* end loop over parsetrees */ /* * Close down transaction statement, if one is open. */ finish_xact_command(); ... }

通过给表文件强制改名进行调试,可以看到对数据库表文件进行实际的物理访问,发生在 pg_plan_queries  函数执行的时候。

这个动作,早于 PortalStart函数。

如果继续追下去看,是这样的:

/*

 * Generate plans for a list of already-rewritten queries.

 *

 * Normal optimizable statements generate PlannedStmt entries in the result

 * list.  Utility statements are simply represented by their statement nodes.

 */

List *

pg_plan_queries(List *querytrees, int cursorOptions, ParamListInfo boundParams)

{

    List       *stmt_list = NIL;

    ListCell   *query_list;



    foreach(query_list, querytrees)

    {

        Query       *query = (Query *) lfirst(query_list);

        Node       *stmt;



        if (query->commandType == CMD_UTILITY)

        {

            /* Utility commands have no plans. */

            stmt = query->utilityStmt;

        }

        else

        {

            stmt = (Node *) pg_plan_query(query, cursorOptions, boundParams);

        }



        stmt_list = lappend(stmt_list, stmt);

    }



    return stmt_list;

}

上面 的 pg_plan_queries,会调用  pg_plan_query。pg_plan_query的主要执行如下:

/*

 * Generate a plan for a single already-rewritten query.

 * This is a thin wrapper around planner() and takes the same parameters.

 */

PlannedStmt *

pg_plan_query(Query *querytree, int cursorOptions, ParamListInfo boundParams)

{


...

/* call the optimizer */ plan = planner(querytree, cursorOptions, boundParams); ... return plan; }

如果发生对应表名的物理文件发生错误,就会在 planner函数调用时报错。

你可能感兴趣的:(PostgreSQL)