zoukankan      html  css  js  c++  java
  • PostgreSQL在何处处理 sql查询之四十四

    回溯:PortalRun --> PortalRunSelect

    bool
    PortalRun(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 void
    exec_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;
    }
  • 相关阅读:
    jsonp 请求和回传实现
    序列化实现原型模式
    java基础30问
    模板方法模式
    开发思维导图
    策略模式
    使用vue-router设置每个页面的title
    node.js解决中文乱码问题
    Vue-cli proxyTable代理 解决开发环境的跨域问题
    Vue缓存需要被缓存的页面
  • 原文地址:https://www.cnblogs.com/gaojian/p/3115284.html
Copyright © 2011-2022 走看看