PostgreSQL在何处处理 sql查询之二十九

接前面,继续分析 ChoosePortalStrategy:

/*

 * ChoosePortalStrategy

 *        Select portal execution strategy given the intended statement list.

 *

 * The list elements can be Querys, PlannedStmts, or utility statements.

 * That's more general than portals need, but plancache.c uses this too.

 *

 * See the comments in portal.h.

 */

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;



            if (query->canSetTag)

            {

                if (query->commandType == CMD_SELECT &&

                    query->utilityStmt == NULL)

                {

                    if (query->hasModifyingCTE)

                        return PORTAL_ONE_MOD_WITH;

                    else

                        return PORTAL_ONE_SELECT;

                }

                if (query->commandType == CMD_UTILITY &&

                    query->utilityStmt != NULL)

                {

                    if (UtilityReturnsTuples(query->utilityStmt))

                        return PORTAL_UTIL_SELECT;

                    /* it can't be ONE_RETURNING, so give up */

                    return PORTAL_MULTI_QUERY;

                }

            }

        }

        else if (IsA(stmt, PlannedStmt))

        {

            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;

                }

            }

        }

        else

        {

            /* must be a utility command; assume it's canSetTag */

            if (UtilityReturnsTuples(stmt))

                return PORTAL_UTIL_SELECT;

            /* it can't be ONE_RETURNING, so give up */

            return PORTAL_MULTI_QUERY;

        }

    }



    /*

     * 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)

    {

        Node       *stmt = (Node *) lfirst(lc);



        if (IsA(stmt, Query))

        {

            Query       *query = (Query *) stmt;



            if (query->canSetTag)

            {

                if (++nSetTag > 1)

                    return PORTAL_MULTI_QUERY;    /* no need to look further */

                if (query->returningList == NIL)

                    return PORTAL_MULTI_QUERY;    /* no need to look further */

            }

        }

        else if (IsA(stmt, PlannedStmt))

        {

            PlannedStmt *pstmt = (PlannedStmt *) stmt;



            if (pstmt->canSetTag)

            {

                if (++nSetTag > 1)

                    return PORTAL_MULTI_QUERY;    /* no need to look further */

                if (!pstmt->hasReturning)

                    return PORTAL_MULTI_QUERY;    /* no need to look further */

            }

        }

        /* otherwise, utility command, assumed not canSetTag */

    }

    if (nSetTag == 1)

        return PORTAL_ONE_RETURNING;



    /* Else, it's the general case... */

    return PORTAL_MULTI_QUERY;

}

先展开第一段的判断:if (list_length(stmts) == 1)

其实是:

static inline int

list_length(const List *l)

{

    return l ? l->length : 0;

}

这里我作一个查询验证一下,

select * from tst01 where id IN (select sid from tst02) or id IN (select sid from tst03);

list_length(stmts) == 1 的条件满足。

再看:

#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;

}

所以呢,这句 :Node *stmt = (Node *) lfirst(lc); 就是拿到了 计划树的头,并且转换为 Node 指针。

你可能感兴趣的:(PostgreSQL)