• 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函数调用时报错。

  • 相关阅读:
    春秋战国时期灭了三个国家的陈国女人
    学历史有什么用?
    真正的奴才韩非
    深度学习的历史
    深度学习三十年
    图算法
    几种常见的查找算法
    数据结构之基于堆的优先队列
    几种常见的排序算法
    数据结构(背包、队列和栈)
  • 原文地址:https://www.cnblogs.com/gaojian/p/3094269.html
Copyright © 2020-2023  润新知