Commit eef8c006 authored by Tom Lane's avatar Tom Lane

Clean up bugs in clause_selectivity() cleanup.

Commit ac2b0950 was not terribly carefully reviewed.  Band-aid it to
not fail on non-RestrictInfo input, per report from Andreas Seltenreich.
Also make it do something more reasonable with variable-free clauses,
and improve nearby comments.

Discussion: https://postgr.es/m/87inmf5rdx.fsf@credativ.de
parent aba696d1
...@@ -41,8 +41,8 @@ typedef struct RangeQueryClause ...@@ -41,8 +41,8 @@ typedef struct RangeQueryClause
static void addRangeClause(RangeQueryClause **rqlist, Node *clause, static void addRangeClause(RangeQueryClause **rqlist, Node *clause,
bool varonleft, bool isLTsel, Selectivity s2); bool varonleft, bool isLTsel, Selectivity s2);
static RelOptInfo *find_relation_from_clauses(PlannerInfo *root, static RelOptInfo *find_single_rel_for_clauses(PlannerInfo *root,
List *clauses); List *clauses);
/**************************************************************************** /****************************************************************************
* ROUTINES TO COMPUTE SELECTIVITIES * ROUTINES TO COMPUTE SELECTIVITIES
...@@ -63,10 +63,8 @@ static RelOptInfo *find_relation_from_clauses(PlannerInfo *root, ...@@ -63,10 +63,8 @@ static RelOptInfo *find_relation_from_clauses(PlannerInfo *root,
* probabilities, and in reality they are often NOT independent. So, * probabilities, and in reality they are often NOT independent. So,
* we want to be smarter where we can. * we want to be smarter where we can.
* *
* When 'rel' is not null and rtekind = RTE_RELATION, we'll try to apply * If the clauses taken together refer to just one relation, we'll try to
* selectivity estimates using any extended statistcs on 'rel'. * apply selectivity estimates using any extended statistics for that rel.
*
* If we identify such extended statistics exist, we try to apply them.
* Currently we only have (soft) functional dependencies, so apply these in as * Currently we only have (soft) functional dependencies, so apply these in as
* many cases as possible, and fall back on normal estimates for remaining * many cases as possible, and fall back on normal estimates for remaining
* clauses. * clauses.
...@@ -105,41 +103,36 @@ clauselist_selectivity(PlannerInfo *root, ...@@ -105,41 +103,36 @@ clauselist_selectivity(PlannerInfo *root,
SpecialJoinInfo *sjinfo) SpecialJoinInfo *sjinfo)
{ {
Selectivity s1 = 1.0; Selectivity s1 = 1.0;
RelOptInfo *rel;
Bitmapset *estimatedclauses = NULL;
RangeQueryClause *rqlist = NULL; RangeQueryClause *rqlist = NULL;
ListCell *l; ListCell *l;
Bitmapset *estimatedclauses = NULL;
int listidx; int listidx;
RelOptInfo *rel;
/* /*
* If there's exactly one clause, then extended statistics is futile at * If there's exactly one clause, just go directly to
* this level (we might be able to apply them later if it's AND/OR * clause_selectivity(). None of what we might do below is relevant.
* clause). So just go directly to clause_selectivity().
*/ */
if (list_length(clauses) == 1) if (list_length(clauses) == 1)
return clause_selectivity(root, (Node *) linitial(clauses), return clause_selectivity(root, (Node *) linitial(clauses),
varRelid, jointype, sjinfo); varRelid, jointype, sjinfo);
/* /*
* Determine if these clauses reference a single relation. If so we might * Determine if these clauses reference a single relation. If so, and if
* like to try applying any extended statistics which exist on it. * it has extended statistics, try to apply those.
* Called many time during joins, so must return NULL quickly if not.
*/
rel = find_relation_from_clauses(root, clauses);
/*
* When a relation of RTE_RELATION is given as 'rel', we'll try to
* perform selectivity estimation using extended statistics.
*/ */
rel = find_single_rel_for_clauses(root, clauses);
if (rel && rel->rtekind == RTE_RELATION && rel->statlist != NIL) if (rel && rel->rtekind == RTE_RELATION && rel->statlist != NIL)
{ {
/* /*
* Perform selectivity estimations on any clauses found applicable by * Perform selectivity estimations on any clauses found applicable by
* dependencies_clauselist_selectivity. The 0-based list position of * dependencies_clauselist_selectivity. 'estimatedclauses' will be
* estimated clauses will be populated in 'estimatedclauses'. * filled with the 0-based list positions of clauses used that way, so
* that we can ignore them below.
*/ */
s1 *= dependencies_clauselist_selectivity(root, clauses, varRelid, s1 *= dependencies_clauselist_selectivity(root, clauses, varRelid,
jointype, sjinfo, rel, &estimatedclauses); jointype, sjinfo, rel,
&estimatedclauses);
/* /*
* This would be the place to apply any other types of extended * This would be the place to apply any other types of extended
...@@ -426,36 +419,46 @@ addRangeClause(RangeQueryClause **rqlist, Node *clause, ...@@ -426,36 +419,46 @@ addRangeClause(RangeQueryClause **rqlist, Node *clause,
} }
/* /*
* find_relation_from_clauses * find_single_rel_for_clauses
* Process each clause in 'clauses' and determine if all clauses * Examine each clause in 'clauses' and determine if all clauses
* reference only a single relation. If so return that relation, * reference only a single relation. If so return that relation,
* otherwise return NULL. * otherwise return NULL.
*/ */
static RelOptInfo * static RelOptInfo *
find_relation_from_clauses(PlannerInfo *root, List *clauses) find_single_rel_for_clauses(PlannerInfo *root, List *clauses)
{ {
ListCell *l; int lastrelid = 0;
int relid; ListCell *l;
int lastrelid = 0;
foreach(l, clauses) foreach(l, clauses)
{ {
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
int relid;
if (bms_get_singleton_member(rinfo->clause_relids, &relid)) /*
{ * If we have a list of bare clauses rather than RestrictInfos, we
if (lastrelid != 0 && relid != lastrelid) * could pull out their relids the hard way with pull_varnos().
return NULL; /* relation not the same as last one */ * However, currently the extended-stats machinery won't do anything
lastrelid = relid; * with non-RestrictInfo clauses anyway, so there's no point in
} * spending extra cycles; just fail if that's what we have.
else */
return NULL; /* multiple relations in clause */ if (!IsA(rinfo, RestrictInfo))
return NULL;
if (bms_is_empty(rinfo->clause_relids))
continue; /* we can ignore variable-free clauses */
if (!bms_get_singleton_member(rinfo->clause_relids, &relid))
return NULL; /* multiple relations in this clause */
if (lastrelid == 0)
lastrelid = relid; /* first clause referencing a relation */
else if (relid != lastrelid)
return NULL; /* relation not same as last one */
} }
if (lastrelid != 0) if (lastrelid != 0)
return find_base_rel(root, lastrelid); return find_base_rel(root, lastrelid);
return NULL; /* no clauses */ return NULL; /* no clauses */
} }
/* /*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment