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

    接前面,继续分析:

    PortalStrategy
    ChoosePortalStrategy(List *stmts)
    {
        int            nSetTag;
        ListCell   *lc;
    
        /*
         * PORTAL_ONE_SELECT and PORTAL_UTIL_SELECT need only consider the
         * single-statement case, since there are no rewrite rules that can add
         * auxiliary queries to a SELECT or a utility command. PORTAL_ONE_MOD_WITH
         * likewise allows only one top-level statement.
         */
        if (list_length(stmts) == 1)
        {
    
            Node       *stmt = (Node *) linitial(stmts);
    
            if (IsA(stmt, Query))
            {
                Query       *query = (Query *) stmt;
                ...
            }
            else if (IsA(stmt, PlannedStmt))
            {
               ...
            }
            else
            {
               ...
            }
        }
    
        /*
         * PORTAL_ONE_RETURNING has to allow auxiliary queries added by rewrite.
         * Choose PORTAL_ONE_RETURNING if there is exactly one canSetTag query and
         * it has a RETURNING list.
         */
        nSetTag = 0;
        foreach(lc, stmts)
        {
           ...
        }
        if (nSetTag == 1)
            return PORTAL_ONE_RETURNING;
    
        /* Else, it's the general case... */
        return PORTAL_MULTI_QUERY;
    }

    对  if (IsA(stmt, Query)) 进行分析:

    #define IsA(nodeptr,_type_)        (nodeTag(nodeptr) == T_##_type_)
    #define nodeTag(nodeptr)        (((const Node*)(nodeptr))->type)

     从上面看到,就是 获得计划树的Head, 把它转为 Node类型指针。

    然后看看它的 type是否是 T_Query

    经过实际测试,满足条件的是: else if (IsA(stmt, PlannedStmt)),
    也就是说 Node指针所指向Node结构的 type是 T_PlannedStmt。

    typedef struct Node
    {
        NodeTag        type;
    } Node;
    typedef struct List
    {
        NodeTag        type;            /* T_List, T_IntList, or T_OidList */
        int            length;
        ListCell   *head;
        ListCell   *tail;
    } List;
    
    struct ListCell
    {
        union
        {
            void       *ptr_value;
            int            int_value;
            Oid            oid_value;
        }            data;
        ListCell   *next;
    };

     可以说, List 的头是一个Node,内有Nodetag说明其为何种类型:

    #define lfirst(lc)                 ((lc)->data.ptr_value)
    
    #define linitial(l)                lfirst(list_head(l))
    
    static inline ListCell *
    list_head(const List *l)
    {
        return l ? l->head : NULL;
    }

     stmt再被强制转为 PlannedStmt:

    * ----------------
     *        PlannedStmt node
     *
     * The output of the planner is a Plan tree headed by a PlannedStmt node.
     * PlannedStmt holds the "one time" information needed by the executor.
     * ----------------
     */
    typedef struct PlannedStmt
    {
        NodeTag        type;
    
        CmdType        commandType;    /* select|insert|update|delete */
    
        uint32        queryId;        /* query identifier (copied from Query) */
    
        bool        hasReturning;    /* is it insert|update|delete RETURNING? */
    
        bool        hasModifyingCTE;    /* has insert|update|delete in WITH? */
    
        bool        canSetTag;        /* do I set the command result tag? */
    
        bool        transientPlan;    /* redo plan when TransactionXmin changes? */
    
        struct Plan *planTree;        /* tree of Plan nodes */
    
        List       *rtable;            /* list of RangeTblEntry nodes */
    
        /* rtable indexes of target relations for INSERT/UPDATE/DELETE */
        List       *resultRelations;    /* integer list of RT indexes, or NIL */
    
        Node       *utilityStmt;    /* non-null if this is DECLARE CURSOR */
    
        List       *subplans;        /* Plan trees for SubPlan expressions */
    
        Bitmapset  *rewindPlanIDs;    /* indices of subplans that require REWIND */
    
        List       *rowMarks;        /* a list of PlanRowMark's */
    
        List       *relationOids;    /* OIDs of relations the plan depends on */
    
        List       *invalItems;        /* other dependencies, as PlanInvalItems */
    
        int            nParamExec;        /* number of PARAM_EXEC Params used */
    } PlannedStmt;

    由此,再来重点看 elseif (IsA(stmt, PlannedStmt)) 判断分支:

            else if (IsA(stmt, PlannedStmt))
            {
                fprintf(stderr,"It is a PlannedStmt... by process %d\n",getpid());
    
                PlannedStmt *pstmt = (PlannedStmt *) stmt;
    
                if (pstmt->canSetTag)
                {
                    
                    if (pstmt->commandType == CMD_SELECT &&
                        pstmt->utilityStmt == NULL)
                    {
    
                        if (pstmt->hasModifyingCTE)
                            return PORTAL_ONE_MOD_WITH;
                        else
                            return PORTAL_ONE_SELECT;
                    }
                }
            }

    根据实际运行 select * from tst01 语句,可以得知返回 PORTAL_ONE_SELECT 类型。

  • 相关阅读:
    第四篇Scrum冲刺博客
    第三篇Scrum冲刺博客
    蔡勒公式和吉姆拉尔森公式计算星期几
    事后诸葛亮
    Alpha阶段项目复审
    团队作业6——复审与事后分析
    第7篇 Scrum 冲刺博客
    第6篇 Scrum 冲刺博客
    第5篇 Scrum 冲刺博客
    第4篇 Scrum 冲刺博客
  • 原文地址:https://www.cnblogs.com/gaojian/p/3105965.html
Copyright © 2011-2022 走看看