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

接前面,继续对 subquery_planner来分析:

下面这一段都是对 表达式进行处理的,对我的简单查询,可以忽略。

    /*

     * Do expression preprocessing on targetlist and quals, as well as other

     * random expressions in the querytree.  Note that we do not need to

     * handle sort/group expressions explicitly, because they are actually

     * part of the targetlist.

     */

    parse->targetList = (List *)

        preprocess_expression(root, (Node *) parse->targetList,

                              EXPRKIND_TARGET);



    parse->returningList = (List *)

        preprocess_expression(root, (Node *) parse->returningList,

                              EXPRKIND_TARGET);



    preprocess_qual_conditions(root, (Node *) parse->jointree);



    parse->havingQual = preprocess_expression(root, parse->havingQual,

                                              EXPRKIND_QUAL);



    foreach(l, parse->windowClause)

    {

        WindowClause *wc = (WindowClause *) lfirst(l);



        /* partitionClause/orderClause are sort/group expressions */

        wc->startOffset = preprocess_expression(root, wc->startOffset,

                                                EXPRKIND_LIMIT);

        wc->endOffset = preprocess_expression(root, wc->endOffset,

                                              EXPRKIND_LIMIT);

    }



    parse->limitOffset = preprocess_expression(root, parse->limitOffset,

                                               EXPRKIND_LIMIT);

    parse->limitCount = preprocess_expression(root, parse->limitCount,

                                              EXPRKIND_LIMIT);



    root->append_rel_list = (List *)

        preprocess_expression(root, (Node *) root->append_rel_list,

                              EXPRKIND_APPINFO);



    /* Also need to preprocess expressions for function and values RTEs */

    foreach(l, parse->rtable)

    {

        RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);



        if (rte->rtekind == RTE_FUNCTION)

            rte->funcexpr = preprocess_expression(root, rte->funcexpr,

                                                  EXPRKIND_RTFUNC);

        else if (rte->rtekind == RTE_VALUES)

            rte->values_lists = (List *)

                preprocess_expression(root, (Node *) rte->values_lists,

                                      EXPRKIND_VALUES);

    }

接着继续,是对HAVING 的处理、对我的简单查询而言,也是可以忽略的。

    /*

     * In some cases we may want to transfer a HAVING clause into WHERE. We

     * cannot do so if the HAVING clause contains aggregates (obviously) or

     * volatile functions (since a HAVING clause is supposed to be executed

     * only once per group).  Also, it may be that the clause is so expensive

     * to execute that we're better off doing it only once per group, despite

     * the loss of selectivity.  This is hard to estimate short of doing the

     * entire planning process twice, so we use a heuristic: clauses

     * containing subplans are left in HAVING.    Otherwise, we move or copy the

     * HAVING clause into WHERE, in hopes of eliminating tuples before

     * aggregation instead of after.

     *

     * If the query has explicit grouping then we can simply move such a

     * clause into WHERE; any group that fails the clause will not be in the

     * output because none of its tuples will reach the grouping or

     * aggregation stage.  Otherwise we must have a degenerate (variable-free)

     * HAVING clause, which we put in WHERE so that query_planner() can use it

     * in a gating Result node, but also keep in HAVING to ensure that we

     * don't emit a bogus aggregated row. (This could be done better, but it

     * seems not worth optimizing.)

     *

     * Note that both havingQual and parse->jointree->quals are in

     * implicitly-ANDed-list form at this point, even though they are declared

     * as Node *.

     */

    newHaving = NIL;

    foreach(l, (List *) parse->havingQual)

    {

        Node       *havingclause = (Node *) lfirst(l);



        if (contain_agg_clause(havingclause) ||

            contain_volatile_functions(havingclause) ||

            contain_subplans(havingclause))

        {

            /* keep it in HAVING */

            newHaving = lappend(newHaving, havingclause);

        }

        else if (parse->groupClause)

        {

            /* move it to WHERE */

            parse->jointree->quals = (Node *)

                lappend((List *) parse->jointree->quals, havingclause);

        }

        else

        {

            /* put a copy in WHERE, keep it in HAVING */

            parse->jointree->quals = (Node *)

                lappend((List *) parse->jointree->quals,

                        copyObject(havingclause));

            newHaving = lappend(newHaving, havingclause);

        }

    }

    parse->havingQual = (Node *) newHaving;

 接下来的一段,因为我的简单查询没有outer join,所以也可以无视。

    /*

     * If we have any outer joins, try to reduce them to plain inner joins.

     * This step is most easily done after we've done expression

     * preprocessing.

     */

    if (hasOuterJoins)

        reduce_outer_joins(root);

紧接着,关键的地方就来了:这里叫作 main planning。

    /*

     * Do the main planning.  If we have an inherited target relation, that

     * needs special processing, else go straight to grouping_planner.

     */

    if (parse->resultRelation &&

        rt_fetch(parse->resultRelation, parse->rtable)->inh)

        plan = inheritance_planner(root);

    else

    {

        plan = grouping_planner(root, tuple_fraction);

        /* If it's not SELECT, we need a ModifyTable node */

        if (parse->commandType != CMD_SELECT)

        {

            List       *returningLists;

            List       *rowMarks;



            /*

             * Set up the RETURNING list-of-lists, if needed.

             */

            if (parse->returningList)

                returningLists = list_make1(parse->returningList);

            else

                returningLists = NIL;



            /*

             * If there was a FOR UPDATE/SHARE clause, the LockRows node will

             * have dealt with fetching non-locked marked rows, else we need

             * to have ModifyTable do that.

             */

            if (parse->rowMarks)

                rowMarks = NIL;

            else

                rowMarks = root->rowMarks;



            plan = (Plan *) make_modifytable(parse->commandType,

                                             parse->canSetTag,

                                       list_make1_int(parse->resultRelation),

                                             list_make1(plan),

                                             returningLists,

                                             rowMarks,

                                             SS_assign_special_param(root));

        }

    }

 由于 上面的 parse->resultRelation 是false。 所以,就变成了:

    else

    {

        plan = grouping_planner(root, tuple_fraction);

        /* If it's not SELECT, we need a ModifyTable node */

        if (parse->commandType != CMD_SELECT)

        {

            List       *returningLists;

            List       *rowMarks;



            /*

             * Set up the RETURNING list-of-lists, if needed.

             */

            if (parse->returningList)

                returningLists = list_make1(parse->returningList);

            else

                returningLists = NIL;



            /*

             * If there was a FOR UPDATE/SHARE clause, the LockRows node will

             * have dealt with fetching non-locked marked rows, else we need

             * to have ModifyTable do that.

             */

            if (parse->rowMarks)

                rowMarks = NIL;

            else

                rowMarks = root->rowMarks;



            plan = (Plan *) make_modifytable(parse->commandType,

                                             parse->canSetTag,

                                       list_make1_int(parse->resultRelation),

                                             list_make1(plan),

                                             returningLists,

                                             rowMarks,

                                             SS_assign_special_param(root));

        }

    }

又由于 parse->commandType != CMD_SELECT 不成立,所以可以简化为:

    else

    {

        plan = grouping_planner(root, tuple_fraction);

                ...



        }

 

你可能感兴趣的:(PostgreSQL)