对get_baserel_parampathinfo函数的学习

/*
 * get_baserel_parampathinfo
 *        Get the ParamPathInfo for a parameterized path for a base relation,
 *        constructing one if we don't have one already.
 *
 * This centralizes estimating the rowcounts for parameterized paths.
 * We need to cache those to be sure we use the same rowcount for all paths
 * of the same parameterization for a given rel.  This is also a convenient
 * place to determine which movable join clauses the parameterized path will
 * be responsible for evaluating.
 */
ParamPathInfo *
get_baserel_parampathinfo(PlannerInfo *root, RelOptInfo *baserel,
                          Relids required_outer)
{
    ParamPathInfo *ppi;
    Relids        joinrelids;
    List       *pclauses;
    double        rows;
    ListCell   *lc;

    /* Unparameterized paths have no ParamPathInfo */
    if (bms_is_empty(required_outer))
        return NULL;

    Assert(!bms_overlap(baserel->relids, required_outer));

    /* If we already have a PPI for this parameterization, just return it */
    foreach(lc, baserel->ppilist)
    {
        ppi = (ParamPathInfo *) lfirst(lc);
        if (bms_equal(ppi->ppi_req_outer, required_outer))
            return ppi;
    }

    /*
     * Identify all joinclauses that are movable to this base rel given this
     * parameterization.
     */
    joinrelids = bms_union(baserel->relids, required_outer);
    pclauses = NIL;
    foreach(lc, baserel->joininfo)
    {
        RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);

        if (join_clause_is_movable_into(rinfo,
                                        baserel->relids,
                                        joinrelids))
            pclauses = lappend(pclauses, rinfo);
    }

    /*
     * Add in joinclauses generated by EquivalenceClasses, too.  (These
     * necessarily satisfy join_clause_is_movable_into.)
     */
    pclauses = list_concat(pclauses,
                           generate_join_implied_equalities(root,
                                                            joinrelids,
                                                            required_outer,
                                                            baserel));

    /* Estimate the number of rows returned by the parameterized scan */
    rows = get_parameterized_baserel_size(root, baserel, pclauses);

    /* And now we can build the ParamPathInfo */
    ppi = makeNode(ParamPathInfo);
    ppi->ppi_req_outer = required_outer;
    ppi->ppi_rows = rows;
    ppi->ppi_clauses = pclauses;
    baserel->ppilist = lappend(baserel->ppilist, ppi);

    return ppi;
}

 上溯来看:

/*
 * set_plain_rel_pathlist
 *      Build access paths for a plain relation (no subquery, no inheritance)
 */
static void
set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
{
/* Consider sequential scan */
    add_path(rel, create_seqscan_path(root, rel, NULL));

    /* Consider index scans */
    create_index_paths(root, rel);

    /* Consider TID scans */
    create_tidscan_paths(root, rel);

    /* Now find the cheapest of the paths for this rel */
    set_cheapest(rel);
}

只要进入了 set_plain_rel_pathlist 函数,进行 

add_path(rel, create_seqscan_path(root, rel, NULL))调用是,给予 create_seqscan_path 的第三个参数是NULL

再看 create_seqscan_path:

/*
 * create_seqscan_path
 *      Creates a path corresponding to a sequential scan, returning the
 *      pathnode.
 */
Path *
create_seqscan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
{
    Path       *pathnode = makeNode(Path);

    pathnode->pathtype = T_SeqScan;
    pathnode->parent = rel;
    pathnode->param_info = get_baserel_parampathinfo(root, rel,
                                                     required_outer);

    pathnode->pathkeys = NIL;    /* seqscan has unordered result */

    cost_seqscan(pathnode, root, rel, pathnode->param_info);

    return pathnode;
}

看这句话:pathnode->param_info = get_baserel_parampathinfo(root, rel, required_outer);

由于传递的required_outer是NULL,所以就是 get_baserel_parampathinfo(root, rel, NULL);                                         

那么:

/*
 * get_baserel_parampathinfo
 *        Get the ParamPathInfo for a parameterized path for a base relation,
 *        constructing one if we don't have one already.
 *
 * This centralizes estimating the rowcounts for parameterized paths.
 * We need to cache those to be sure we use the same rowcount for all paths
 * of the same parameterization for a given rel.  This is also a convenient
 * place to determine which movable join clauses the parameterized path will
 * be responsible for evaluating.
 */
ParamPathInfo *
get_baserel_parampathinfo(PlannerInfo *root, RelOptInfo *baserel,
                          Relids required_outer)
{
    ParamPathInfo *ppi;
    Relids        joinrelids;
    List       *pclauses;
    double        rows;
    ListCell   *lc;

    /* Unparameterized paths have no ParamPathInfo */
    if (bms_is_empty(required_outer))
        return NULL;

    Assert(!bms_overlap(baserel->relids, required_outer));

    /* If we already have a PPI for this parameterization, just return it */
    foreach(lc, baserel->ppilist)
    {
        ppi = (ParamPathInfo *) lfirst(lc);
        if (bms_equal(ppi->ppi_req_outer, required_outer))
            return ppi;
    }

    /*
     * Identify all joinclauses that are movable to this base rel given this
     * parameterization.
     */
    joinrelids = bms_union(baserel->relids, required_outer);
    pclauses = NIL;
    foreach(lc, baserel->joininfo)
    {
        RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);

        if (join_clause_is_movable_into(rinfo,
                                        baserel->relids,
                                        joinrelids))
            pclauses = lappend(pclauses, rinfo);
    }

    /*
     * Add in joinclauses generated by EquivalenceClasses, too.  (These
     * necessarily satisfy join_clause_is_movable_into.)
     */
    pclauses = list_concat(pclauses,
                           generate_join_implied_equalities(root,
                                                            joinrelids,
                                                            required_outer,
                                                            baserel));

    /* Estimate the number of rows returned by the parameterized scan */
    rows = get_parameterized_baserel_size(root, baserel, pclauses);

    /* And now we can build the ParamPathInfo */
    ppi = makeNode(ParamPathInfo);
    ppi->ppi_req_outer = required_outer;
    ppi->ppi_rows = rows;
    ppi->ppi_clauses = pclauses;
    baserel->ppilist = lappend(baserel->ppilist, ppi);

    return ppi;
}

看这一小段:

    /* Unparameterized paths have no ParamPathInfo */
    if (bms_is_empty(required_outer))
        return NULL;

看看 bms_is_empty:

/*
 * bms_is_empty - is a set empty?
 *
 * This is even faster than bms_membership().
 */
bool
bms_is_empty(const Bitmapset *a)
{
    int            nwords;
    int            wordnum;

    if (a == NULL)
        return true;
    
    nwords = a->nwords;
    for (wordnum = 0; wordnum < nwords; wordnum++)
    {
        bitmapword    w = a->words[wordnum];

        if (w != 0)
            return false;
    }
    return true;
}
原文地址:https://www.cnblogs.com/gaojian/p/3143632.html