Header And Logo

PostgreSQL
| The world's most advanced open source database.

Functions

orindxpath.c File Reference

#include "postgres.h"
#include "optimizer/cost.h"
#include "optimizer/paths.h"
#include "optimizer/restrictinfo.h"
Include dependency graph for orindxpath.c:

Go to the source code of this file.

Functions

bool create_or_index_quals (PlannerInfo *root, RelOptInfo *rel)

Function Documentation

bool create_or_index_quals ( PlannerInfo root,
RelOptInfo rel 
)

Definition at line 81 of file orindxpath.c.

References Assert, RelOptInfo::baserestrictinfo, clause_selectivity(), generate_bitmap_or_paths(), i, RelOptInfo::indexlist, IsA, join_clause_is_movable_to(), JOIN_INNER, RelOptInfo::joininfo, lfirst, linitial, list_concat(), list_length(), list_make1, make_restrictinfo_from_bitmapqual(), NIL, NULL, BitmapOrPath::path, RelOptInfo::relid, restriction_is_or_clause(), and Path::total_cost.

Referenced by set_plain_rel_size().

{
    BitmapOrPath *bestpath = NULL;
    RestrictInfo *bestrinfo = NULL;
    List       *newrinfos;
    RestrictInfo *or_rinfo;
    Selectivity or_selec,
                orig_selec;
    ListCell   *i;

    /* Skip the whole mess if no indexes */
    if (rel->indexlist == NIL)
        return false;

    /*
     * Find potentially interesting OR joinclauses.  We can use any joinclause
     * that is considered safe to move to this rel by the parameterized-path
     * machinery, even though what we are going to do with it is not exactly a
     * parameterized path.
     */
    foreach(i, rel->joininfo)
    {
        RestrictInfo *rinfo = (RestrictInfo *) lfirst(i);

        if (restriction_is_or_clause(rinfo) &&
            join_clause_is_movable_to(rinfo, rel->relid))
        {
            /*
             * Use the generate_bitmap_or_paths() machinery to estimate the
             * value of each OR clause.  We can use regular restriction
             * clauses along with the OR clause contents to generate
             * indexquals.  We pass restriction_only = true so that any
             * sub-clauses that are actually joins will be ignored.
             */
            List       *orpaths;
            ListCell   *k;

            orpaths = generate_bitmap_or_paths(root, rel,
                                               list_make1(rinfo),
                                               rel->baserestrictinfo,
                                               true);

            /* Locate the cheapest OR path */
            foreach(k, orpaths)
            {
                BitmapOrPath *path = (BitmapOrPath *) lfirst(k);

                Assert(IsA(path, BitmapOrPath));
                if (bestpath == NULL ||
                    path->path.total_cost < bestpath->path.total_cost)
                {
                    bestpath = path;
                    bestrinfo = rinfo;
                }
            }
        }
    }

    /* Fail if no suitable clauses found */
    if (bestpath == NULL)
        return false;

    /*
     * Convert the path's indexclauses structure to a RestrictInfo tree. We
     * include any partial-index predicates so as to get a reasonable
     * representation of what the path is actually scanning.
     */
    newrinfos = make_restrictinfo_from_bitmapqual((Path *) bestpath,
                                                  true, true);

    /* It's possible we get back something other than a single OR clause */
    if (list_length(newrinfos) != 1)
        return false;
    or_rinfo = (RestrictInfo *) linitial(newrinfos);
    Assert(IsA(or_rinfo, RestrictInfo));
    if (!restriction_is_or_clause(or_rinfo))
        return false;

    /*
     * OK, add it to the rel's restriction list.
     */
    rel->baserestrictinfo = list_concat(rel->baserestrictinfo, newrinfos);

    /*
     * Adjust the original OR clause's cached selectivity to compensate for
     * the selectivity of the added (but redundant) lower-level qual. This
     * should result in the join rel getting approximately the same rows
     * estimate as it would have gotten without all these shenanigans. (XXX
     * major hack alert ... this depends on the assumption that the
     * selectivity will stay cached ...)
     */
    or_selec = clause_selectivity(root, (Node *) or_rinfo,
                                  0, JOIN_INNER, NULL);
    if (or_selec > 0 && or_selec < 1)
    {
        orig_selec = clause_selectivity(root, (Node *) bestrinfo,
                                        0, JOIN_INNER, NULL);
        bestrinfo->norm_selec = orig_selec / or_selec;
        /* clamp result to sane range */
        if (bestrinfo->norm_selec > 1)
            bestrinfo->norm_selec = 1;
        /* It isn't an outer join clause, so no need to adjust outer_selec */
    }

    /* Tell caller to recompute partial index status and rowcount estimate */
    return true;
}