DdengxuyueMisc bugfixes
3d79c591创建于 2021年3月6日历史提交
/* -------------------------------------------------------------------------
 *
 * joininfo.cpp
 *	  joininfo list manipulation routines
 *
 * Portions Copyright (c) 2020 Huawei Technologies Co.,Ltd.
 * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/gausskernel/optimizer/util/joininfo.cpp
 *
 * -------------------------------------------------------------------------
 */
#include "postgres.h"
#include "knl/knl_variable.h"

#include "optimizer/joininfo.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"

/*
 * have_relevant_joinclause
 *		Detect whether there is a joinclause that involves
 *		the two given relations.
 *
 * Note: the joinclause does not have to be evaluatable with only these two
 * relations.  This is intentional.  For example consider
 *		SELECT * FROM a, b, c WHERE a.x = (b.y + c.z)
 * If a is much larger than the other tables, it may be worthwhile to
 * cross-join b and c and then use an inner indexscan on a.x.  Therefore
 * we should consider this joinclause as reason to join b to c, even though
 * it can't be applied at that join step.
 */
bool have_relevant_joinclause(PlannerInfo* root, RelOptInfo* rel1, RelOptInfo* rel2)
{
    bool result = false;
    List* joininfo = NIL;
    Relids other_relids;
    ListCell* l = NULL;

    /*
     * We could scan either relation's joininfo list; may as well use the
     * shorter one.
     */
    if (list_length(rel1->joininfo) <= list_length(rel2->joininfo)) {
        joininfo = rel1->joininfo;
        other_relids = rel2->relids;
    } else {
        joininfo = rel2->joininfo;
        other_relids = rel1->relids;
    }

    foreach (l, joininfo) {
        RestrictInfo* rinfo = (RestrictInfo*)lfirst(l);

        if (bms_overlap(other_relids, rinfo->required_relids)) {
            result = true;
            break;
        }
    }

    /*
     * We also need to check the EquivalenceClass data structure, which might
     * contain relationships not emitted into the joininfo lists.
     */
    if (!result && rel1->has_eclass_joins && rel2->has_eclass_joins)
        result = have_relevant_eclass_joinclause(root, rel1, rel2);

    return result;
}

/*
 * add_join_clause_to_rels
 *	  Add 'restrictinfo' to the joininfo list of each relation it requires.
 *
 * Note that the same copy of the restrictinfo node is linked to by all the
 * lists it is in.	This allows us to exploit caching of information about
 * the restriction clause (but we must be careful that the information does
 * not depend on context).
 *
 * 'restrictinfo' describes the join clause
 * 'join_relids' is the list of relations participating in the join clause
 *				 (there must be more than one)
 */
void add_join_clause_to_rels(PlannerInfo* root, RestrictInfo* restrictinfo, const Relids join_relids)
{
    Relids tmprelids;
    int cur_relid;

    tmprelids = bms_copy(join_relids);
    while ((cur_relid = bms_first_member(tmprelids)) >= 0) {
        RelOptInfo* rel = find_base_rel(root, cur_relid);

        Assert(rel);
        rel->joininfo = lappend(rel->joininfo, restrictinfo);
    }
    bms_free_ext(tmprelids);
}

/*
 * remove_join_clause_from_rels
 *	  Delete 'restrictinfo' from all the joininfo lists it is in
 *
 * This reverses the effect of add_join_clause_to_rels.  It's used when we
 * discover that a relation need not be joined at all.
 *
 * 'restrictinfo' describes the join clause
 * 'join_relids' is the list of relations participating in the join clause
 *				 (there must be more than one)
 */
void remove_join_clause_from_rels(PlannerInfo* root, RestrictInfo* restrictinfo, Relids join_relids)
{
    Relids tmprelids;
    int cur_relid;

    tmprelids = bms_copy(join_relids);
    while ((cur_relid = bms_first_member(tmprelids)) >= 0) {
        RelOptInfo* rel = find_base_rel(root, cur_relid);
        if (rel == NULL)
            ereport(ERROR,
                (errmodule(MOD_OPT), errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), (errmsg("Fail to find base rel."))));

        /*
         * Remove the restrictinfo from the list.  Pointer comparison is
         * sufficient.
         */
        AssertEreport(list_member_ptr(rel->joininfo, restrictinfo), MOD_OPT, "");
        rel->joininfo = list_delete_ptr(rel->joininfo, restrictinfo);
    }
    bms_free_ext(tmprelids);
}