Header And Logo

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

clausesel.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * clausesel.c
00004  *    Routines to compute clause selectivities
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/optimizer/path/clausesel.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 #include "postgres.h"
00016 
00017 #include "catalog/pg_operator.h"
00018 #include "nodes/makefuncs.h"
00019 #include "optimizer/clauses.h"
00020 #include "optimizer/cost.h"
00021 #include "optimizer/pathnode.h"
00022 #include "optimizer/plancat.h"
00023 #include "utils/fmgroids.h"
00024 #include "utils/lsyscache.h"
00025 #include "utils/selfuncs.h"
00026 
00027 
00028 /*
00029  * Data structure for accumulating info about possible range-query
00030  * clause pairs in clauselist_selectivity.
00031  */
00032 typedef struct RangeQueryClause
00033 {
00034     struct RangeQueryClause *next;      /* next in linked list */
00035     Node       *var;            /* The common variable of the clauses */
00036     bool        have_lobound;   /* found a low-bound clause yet? */
00037     bool        have_hibound;   /* found a high-bound clause yet? */
00038     Selectivity lobound;        /* Selectivity of a var > something clause */
00039     Selectivity hibound;        /* Selectivity of a var < something clause */
00040 } RangeQueryClause;
00041 
00042 static void addRangeClause(RangeQueryClause **rqlist, Node *clause,
00043                bool varonleft, bool isLTsel, Selectivity s2);
00044 
00045 
00046 /****************************************************************************
00047  *      ROUTINES TO COMPUTE SELECTIVITIES
00048  ****************************************************************************/
00049 
00050 /*
00051  * clauselist_selectivity -
00052  *    Compute the selectivity of an implicitly-ANDed list of boolean
00053  *    expression clauses.  The list can be empty, in which case 1.0
00054  *    must be returned.  List elements may be either RestrictInfos
00055  *    or bare expression clauses --- the former is preferred since
00056  *    it allows caching of results.
00057  *
00058  * See clause_selectivity() for the meaning of the additional parameters.
00059  *
00060  * Our basic approach is to take the product of the selectivities of the
00061  * subclauses.  However, that's only right if the subclauses have independent
00062  * probabilities, and in reality they are often NOT independent.  So,
00063  * we want to be smarter where we can.
00064 
00065  * Currently, the only extra smarts we have is to recognize "range queries",
00066  * such as "x > 34 AND x < 42".  Clauses are recognized as possible range
00067  * query components if they are restriction opclauses whose operators have
00068  * scalarltsel() or scalargtsel() as their restriction selectivity estimator.
00069  * We pair up clauses of this form that refer to the same variable.  An
00070  * unpairable clause of this kind is simply multiplied into the selectivity
00071  * product in the normal way.  But when we find a pair, we know that the
00072  * selectivities represent the relative positions of the low and high bounds
00073  * within the column's range, so instead of figuring the selectivity as
00074  * hisel * losel, we can figure it as hisel + losel - 1.  (To visualize this,
00075  * see that hisel is the fraction of the range below the high bound, while
00076  * losel is the fraction above the low bound; so hisel can be interpreted
00077  * directly as a 0..1 value but we need to convert losel to 1-losel before
00078  * interpreting it as a value.  Then the available range is 1-losel to hisel.
00079  * However, this calculation double-excludes nulls, so really we need
00080  * hisel + losel + null_frac - 1.)
00081  *
00082  * If either selectivity is exactly DEFAULT_INEQ_SEL, we forget this equation
00083  * and instead use DEFAULT_RANGE_INEQ_SEL.  The same applies if the equation
00084  * yields an impossible (negative) result.
00085  *
00086  * A free side-effect is that we can recognize redundant inequalities such
00087  * as "x < 4 AND x < 5"; only the tighter constraint will be counted.
00088  *
00089  * Of course this is all very dependent on the behavior of
00090  * scalarltsel/scalargtsel; perhaps some day we can generalize the approach.
00091  */
00092 Selectivity
00093 clauselist_selectivity(PlannerInfo *root,
00094                        List *clauses,
00095                        int varRelid,
00096                        JoinType jointype,
00097                        SpecialJoinInfo *sjinfo)
00098 {
00099     Selectivity s1 = 1.0;
00100     RangeQueryClause *rqlist = NULL;
00101     ListCell   *l;
00102 
00103     /*
00104      * If there's exactly one clause, then no use in trying to match up pairs,
00105      * so just go directly to clause_selectivity().
00106      */
00107     if (list_length(clauses) == 1)
00108         return clause_selectivity(root, (Node *) linitial(clauses),
00109                                   varRelid, jointype, sjinfo);
00110 
00111     /*
00112      * Initial scan over clauses.  Anything that doesn't look like a potential
00113      * rangequery clause gets multiplied into s1 and forgotten. Anything that
00114      * does gets inserted into an rqlist entry.
00115      */
00116     foreach(l, clauses)
00117     {
00118         Node       *clause = (Node *) lfirst(l);
00119         RestrictInfo *rinfo;
00120         Selectivity s2;
00121 
00122         /* Always compute the selectivity using clause_selectivity */
00123         s2 = clause_selectivity(root, clause, varRelid, jointype, sjinfo);
00124 
00125         /*
00126          * Check for being passed a RestrictInfo.
00127          *
00128          * If it's a pseudoconstant RestrictInfo, then s2 is either 1.0 or
00129          * 0.0; just use that rather than looking for range pairs.
00130          */
00131         if (IsA(clause, RestrictInfo))
00132         {
00133             rinfo = (RestrictInfo *) clause;
00134             if (rinfo->pseudoconstant)
00135             {
00136                 s1 = s1 * s2;
00137                 continue;
00138             }
00139             clause = (Node *) rinfo->clause;
00140         }
00141         else
00142             rinfo = NULL;
00143 
00144         /*
00145          * See if it looks like a restriction clause with a pseudoconstant on
00146          * one side.  (Anything more complicated than that might not behave in
00147          * the simple way we are expecting.)  Most of the tests here can be
00148          * done more efficiently with rinfo than without.
00149          */
00150         if (is_opclause(clause) && list_length(((OpExpr *) clause)->args) == 2)
00151         {
00152             OpExpr     *expr = (OpExpr *) clause;
00153             bool        varonleft = true;
00154             bool        ok;
00155 
00156             if (rinfo)
00157             {
00158                 ok = (bms_membership(rinfo->clause_relids) == BMS_SINGLETON) &&
00159                     (is_pseudo_constant_clause_relids(lsecond(expr->args),
00160                                                       rinfo->right_relids) ||
00161                      (varonleft = false,
00162                       is_pseudo_constant_clause_relids(linitial(expr->args),
00163                                                        rinfo->left_relids)));
00164             }
00165             else
00166             {
00167                 ok = (NumRelids(clause) == 1) &&
00168                     (is_pseudo_constant_clause(lsecond(expr->args)) ||
00169                      (varonleft = false,
00170                       is_pseudo_constant_clause(linitial(expr->args))));
00171             }
00172 
00173             if (ok)
00174             {
00175                 /*
00176                  * If it's not a "<" or ">" operator, just merge the
00177                  * selectivity in generically.  But if it's the right oprrest,
00178                  * add the clause to rqlist for later processing.
00179                  */
00180                 switch (get_oprrest(expr->opno))
00181                 {
00182                     case F_SCALARLTSEL:
00183                         addRangeClause(&rqlist, clause,
00184                                        varonleft, true, s2);
00185                         break;
00186                     case F_SCALARGTSEL:
00187                         addRangeClause(&rqlist, clause,
00188                                        varonleft, false, s2);
00189                         break;
00190                     default:
00191                         /* Just merge the selectivity in generically */
00192                         s1 = s1 * s2;
00193                         break;
00194                 }
00195                 continue;       /* drop to loop bottom */
00196             }
00197         }
00198 
00199         /* Not the right form, so treat it generically. */
00200         s1 = s1 * s2;
00201     }
00202 
00203     /*
00204      * Now scan the rangequery pair list.
00205      */
00206     while (rqlist != NULL)
00207     {
00208         RangeQueryClause *rqnext;
00209 
00210         if (rqlist->have_lobound && rqlist->have_hibound)
00211         {
00212             /* Successfully matched a pair of range clauses */
00213             Selectivity s2;
00214 
00215             /*
00216              * Exact equality to the default value probably means the
00217              * selectivity function punted.  This is not airtight but should
00218              * be good enough.
00219              */
00220             if (rqlist->hibound == DEFAULT_INEQ_SEL ||
00221                 rqlist->lobound == DEFAULT_INEQ_SEL)
00222             {
00223                 s2 = DEFAULT_RANGE_INEQ_SEL;
00224             }
00225             else
00226             {
00227                 s2 = rqlist->hibound + rqlist->lobound - 1.0;
00228 
00229                 /* Adjust for double-exclusion of NULLs */
00230                 s2 += nulltestsel(root, IS_NULL, rqlist->var,
00231                                   varRelid, jointype, sjinfo);
00232 
00233                 /*
00234                  * A zero or slightly negative s2 should be converted into a
00235                  * small positive value; we probably are dealing with a very
00236                  * tight range and got a bogus result due to roundoff errors.
00237                  * However, if s2 is very negative, then we probably have
00238                  * default selectivity estimates on one or both sides of the
00239                  * range that we failed to recognize above for some reason.
00240                  */
00241                 if (s2 <= 0.0)
00242                 {
00243                     if (s2 < -0.01)
00244                     {
00245                         /*
00246                          * No data available --- use a default estimate that
00247                          * is small, but not real small.
00248                          */
00249                         s2 = DEFAULT_RANGE_INEQ_SEL;
00250                     }
00251                     else
00252                     {
00253                         /*
00254                          * It's just roundoff error; use a small positive
00255                          * value
00256                          */
00257                         s2 = 1.0e-10;
00258                     }
00259                 }
00260             }
00261             /* Merge in the selectivity of the pair of clauses */
00262             s1 *= s2;
00263         }
00264         else
00265         {
00266             /* Only found one of a pair, merge it in generically */
00267             if (rqlist->have_lobound)
00268                 s1 *= rqlist->lobound;
00269             else
00270                 s1 *= rqlist->hibound;
00271         }
00272         /* release storage and advance */
00273         rqnext = rqlist->next;
00274         pfree(rqlist);
00275         rqlist = rqnext;
00276     }
00277 
00278     return s1;
00279 }
00280 
00281 /*
00282  * addRangeClause --- add a new range clause for clauselist_selectivity
00283  *
00284  * Here is where we try to match up pairs of range-query clauses
00285  */
00286 static void
00287 addRangeClause(RangeQueryClause **rqlist, Node *clause,
00288                bool varonleft, bool isLTsel, Selectivity s2)
00289 {
00290     RangeQueryClause *rqelem;
00291     Node       *var;
00292     bool        is_lobound;
00293 
00294     if (varonleft)
00295     {
00296         var = get_leftop((Expr *) clause);
00297         is_lobound = !isLTsel;  /* x < something is high bound */
00298     }
00299     else
00300     {
00301         var = get_rightop((Expr *) clause);
00302         is_lobound = isLTsel;   /* something < x is low bound */
00303     }
00304 
00305     for (rqelem = *rqlist; rqelem; rqelem = rqelem->next)
00306     {
00307         /*
00308          * We use full equal() here because the "var" might be a function of
00309          * one or more attributes of the same relation...
00310          */
00311         if (!equal(var, rqelem->var))
00312             continue;
00313         /* Found the right group to put this clause in */
00314         if (is_lobound)
00315         {
00316             if (!rqelem->have_lobound)
00317             {
00318                 rqelem->have_lobound = true;
00319                 rqelem->lobound = s2;
00320             }
00321             else
00322             {
00323 
00324                 /*------
00325                  * We have found two similar clauses, such as
00326                  * x < y AND x < z.
00327                  * Keep only the more restrictive one.
00328                  *------
00329                  */
00330                 if (rqelem->lobound > s2)
00331                     rqelem->lobound = s2;
00332             }
00333         }
00334         else
00335         {
00336             if (!rqelem->have_hibound)
00337             {
00338                 rqelem->have_hibound = true;
00339                 rqelem->hibound = s2;
00340             }
00341             else
00342             {
00343 
00344                 /*------
00345                  * We have found two similar clauses, such as
00346                  * x > y AND x > z.
00347                  * Keep only the more restrictive one.
00348                  *------
00349                  */
00350                 if (rqelem->hibound > s2)
00351                     rqelem->hibound = s2;
00352             }
00353         }
00354         return;
00355     }
00356 
00357     /* No matching var found, so make a new clause-pair data structure */
00358     rqelem = (RangeQueryClause *) palloc(sizeof(RangeQueryClause));
00359     rqelem->var = var;
00360     if (is_lobound)
00361     {
00362         rqelem->have_lobound = true;
00363         rqelem->have_hibound = false;
00364         rqelem->lobound = s2;
00365     }
00366     else
00367     {
00368         rqelem->have_lobound = false;
00369         rqelem->have_hibound = true;
00370         rqelem->hibound = s2;
00371     }
00372     rqelem->next = *rqlist;
00373     *rqlist = rqelem;
00374 }
00375 
00376 /*
00377  * bms_is_subset_singleton
00378  *
00379  * Same result as bms_is_subset(s, bms_make_singleton(x)),
00380  * but a little faster and doesn't leak memory.
00381  *
00382  * Is this of use anywhere else?  If so move to bitmapset.c ...
00383  */
00384 static bool
00385 bms_is_subset_singleton(const Bitmapset *s, int x)
00386 {
00387     switch (bms_membership(s))
00388     {
00389         case BMS_EMPTY_SET:
00390             return true;
00391         case BMS_SINGLETON:
00392             return bms_is_member(x, s);
00393         case BMS_MULTIPLE:
00394             return false;
00395     }
00396     /* can't get here... */
00397     return false;
00398 }
00399 
00400 /*
00401  * treat_as_join_clause -
00402  *    Decide whether an operator clause is to be handled by the
00403  *    restriction or join estimator.  Subroutine for clause_selectivity().
00404  */
00405 static inline bool
00406 treat_as_join_clause(Node *clause, RestrictInfo *rinfo,
00407                      int varRelid, SpecialJoinInfo *sjinfo)
00408 {
00409     if (varRelid != 0)
00410     {
00411         /*
00412          * Caller is forcing restriction mode (eg, because we are examining an
00413          * inner indexscan qual).
00414          */
00415         return false;
00416     }
00417     else if (sjinfo == NULL)
00418     {
00419         /*
00420          * It must be a restriction clause, since it's being evaluated at a
00421          * scan node.
00422          */
00423         return false;
00424     }
00425     else
00426     {
00427         /*
00428          * Otherwise, it's a join if there's more than one relation used. We
00429          * can optimize this calculation if an rinfo was passed.
00430          *
00431          * XXX  Since we know the clause is being evaluated at a join, the
00432          * only way it could be single-relation is if it was delayed by outer
00433          * joins.  Although we can make use of the restriction qual estimators
00434          * anyway, it seems likely that we ought to account for the
00435          * probability of injected nulls somehow.
00436          */
00437         if (rinfo)
00438             return (bms_membership(rinfo->clause_relids) == BMS_MULTIPLE);
00439         else
00440             return (NumRelids(clause) > 1);
00441     }
00442 }
00443 
00444 
00445 /*
00446  * clause_selectivity -
00447  *    Compute the selectivity of a general boolean expression clause.
00448  *
00449  * The clause can be either a RestrictInfo or a plain expression.  If it's
00450  * a RestrictInfo, we try to cache the selectivity for possible re-use,
00451  * so passing RestrictInfos is preferred.
00452  *
00453  * varRelid is either 0 or a rangetable index.
00454  *
00455  * When varRelid is not 0, only variables belonging to that relation are
00456  * considered in computing selectivity; other vars are treated as constants
00457  * of unknown values.  This is appropriate for estimating the selectivity of
00458  * a join clause that is being used as a restriction clause in a scan of a
00459  * nestloop join's inner relation --- varRelid should then be the ID of the
00460  * inner relation.
00461  *
00462  * When varRelid is 0, all variables are treated as variables.  This
00463  * is appropriate for ordinary join clauses and restriction clauses.
00464  *
00465  * jointype is the join type, if the clause is a join clause.  Pass JOIN_INNER
00466  * if the clause isn't a join clause.
00467  *
00468  * sjinfo is NULL for a non-join clause, otherwise it provides additional
00469  * context information about the join being performed.  There are some
00470  * special cases:
00471  *  1. For a special (not INNER) join, sjinfo is always a member of
00472  *     root->join_info_list.
00473  *  2. For an INNER join, sjinfo is just a transient struct, and only the
00474  *     relids and jointype fields in it can be trusted.
00475  * It is possible for jointype to be different from sjinfo->jointype.
00476  * This indicates we are considering a variant join: either with
00477  * the LHS and RHS switched, or with one input unique-ified.
00478  *
00479  * Note: when passing nonzero varRelid, it's normally appropriate to set
00480  * jointype == JOIN_INNER, sjinfo == NULL, even if the clause is really a
00481  * join clause; because we aren't treating it as a join clause.
00482  */
00483 Selectivity
00484 clause_selectivity(PlannerInfo *root,
00485                    Node *clause,
00486                    int varRelid,
00487                    JoinType jointype,
00488                    SpecialJoinInfo *sjinfo)
00489 {
00490     Selectivity s1 = 0.5;       /* default for any unhandled clause type */
00491     RestrictInfo *rinfo = NULL;
00492     bool        cacheable = false;
00493 
00494     if (clause == NULL)         /* can this still happen? */
00495         return s1;
00496 
00497     if (IsA(clause, RestrictInfo))
00498     {
00499         rinfo = (RestrictInfo *) clause;
00500 
00501         /*
00502          * If the clause is marked pseudoconstant, then it will be used as a
00503          * gating qual and should not affect selectivity estimates; hence
00504          * return 1.0.  The only exception is that a constant FALSE may be
00505          * taken as having selectivity 0.0, since it will surely mean no rows
00506          * out of the plan.  This case is simple enough that we need not
00507          * bother caching the result.
00508          */
00509         if (rinfo->pseudoconstant)
00510         {
00511             if (!IsA(rinfo->clause, Const))
00512                 return (Selectivity) 1.0;
00513         }
00514 
00515         /*
00516          * If the clause is marked redundant, always return 1.0.
00517          */
00518         if (rinfo->norm_selec > 1)
00519             return (Selectivity) 1.0;
00520 
00521         /*
00522          * If possible, cache the result of the selectivity calculation for
00523          * the clause.  We can cache if varRelid is zero or the clause
00524          * contains only vars of that relid --- otherwise varRelid will affect
00525          * the result, so mustn't cache.  Outer join quals might be examined
00526          * with either their join's actual jointype or JOIN_INNER, so we need
00527          * two cache variables to remember both cases.  Note: we assume the
00528          * result won't change if we are switching the input relations or
00529          * considering a unique-ified case, so we only need one cache variable
00530          * for all non-JOIN_INNER cases.
00531          */
00532         if (varRelid == 0 ||
00533             bms_is_subset_singleton(rinfo->clause_relids, varRelid))
00534         {
00535             /* Cacheable --- do we already have the result? */
00536             if (jointype == JOIN_INNER)
00537             {
00538                 if (rinfo->norm_selec >= 0)
00539                     return rinfo->norm_selec;
00540             }
00541             else
00542             {
00543                 if (rinfo->outer_selec >= 0)
00544                     return rinfo->outer_selec;
00545             }
00546             cacheable = true;
00547         }
00548 
00549         /*
00550          * Proceed with examination of contained clause.  If the clause is an
00551          * OR-clause, we want to look at the variant with sub-RestrictInfos,
00552          * so that per-subclause selectivities can be cached.
00553          */
00554         if (rinfo->orclause)
00555             clause = (Node *) rinfo->orclause;
00556         else
00557             clause = (Node *) rinfo->clause;
00558     }
00559 
00560     if (IsA(clause, Var))
00561     {
00562         Var        *var = (Var *) clause;
00563 
00564         /*
00565          * We probably shouldn't ever see an uplevel Var here, but if we do,
00566          * return the default selectivity...
00567          */
00568         if (var->varlevelsup == 0 &&
00569             (varRelid == 0 || varRelid == (int) var->varno))
00570         {
00571             /*
00572              * A Var at the top of a clause must be a bool Var. This is
00573              * equivalent to the clause reln.attribute = 't', so we compute
00574              * the selectivity as if that is what we have.
00575              */
00576             s1 = restriction_selectivity(root,
00577                                          BooleanEqualOperator,
00578                                          list_make2(var,
00579                                                     makeBoolConst(true,
00580                                                                   false)),
00581                                          InvalidOid,
00582                                          varRelid);
00583         }
00584     }
00585     else if (IsA(clause, Const))
00586     {
00587         /* bool constant is pretty easy... */
00588         Const      *con = (Const *) clause;
00589 
00590         s1 = con->constisnull ? 0.0 :
00591             DatumGetBool(con->constvalue) ? 1.0 : 0.0;
00592     }
00593     else if (IsA(clause, Param))
00594     {
00595         /* see if we can replace the Param */
00596         Node       *subst = estimate_expression_value(root, clause);
00597 
00598         if (IsA(subst, Const))
00599         {
00600             /* bool constant is pretty easy... */
00601             Const      *con = (Const *) subst;
00602 
00603             s1 = con->constisnull ? 0.0 :
00604                 DatumGetBool(con->constvalue) ? 1.0 : 0.0;
00605         }
00606         else
00607         {
00608             /* XXX any way to do better than default? */
00609         }
00610     }
00611     else if (not_clause(clause))
00612     {
00613         /* inverse of the selectivity of the underlying clause */
00614         s1 = 1.0 - clause_selectivity(root,
00615                                   (Node *) get_notclausearg((Expr *) clause),
00616                                       varRelid,
00617                                       jointype,
00618                                       sjinfo);
00619     }
00620     else if (and_clause(clause))
00621     {
00622         /* share code with clauselist_selectivity() */
00623         s1 = clauselist_selectivity(root,
00624                                     ((BoolExpr *) clause)->args,
00625                                     varRelid,
00626                                     jointype,
00627                                     sjinfo);
00628     }
00629     else if (or_clause(clause))
00630     {
00631         /*
00632          * Selectivities for an OR clause are computed as s1+s2 - s1*s2 to
00633          * account for the probable overlap of selected tuple sets.
00634          *
00635          * XXX is this too conservative?
00636          */
00637         ListCell   *arg;
00638 
00639         s1 = 0.0;
00640         foreach(arg, ((BoolExpr *) clause)->args)
00641         {
00642             Selectivity s2 = clause_selectivity(root,
00643                                                 (Node *) lfirst(arg),
00644                                                 varRelid,
00645                                                 jointype,
00646                                                 sjinfo);
00647 
00648             s1 = s1 + s2 - s1 * s2;
00649         }
00650     }
00651     else if (is_opclause(clause) || IsA(clause, DistinctExpr))
00652     {
00653         OpExpr     *opclause = (OpExpr *) clause;
00654         Oid         opno = opclause->opno;
00655 
00656         if (treat_as_join_clause(clause, rinfo, varRelid, sjinfo))
00657         {
00658             /* Estimate selectivity for a join clause. */
00659             s1 = join_selectivity(root, opno,
00660                                   opclause->args,
00661                                   opclause->inputcollid,
00662                                   jointype,
00663                                   sjinfo);
00664         }
00665         else
00666         {
00667             /* Estimate selectivity for a restriction clause. */
00668             s1 = restriction_selectivity(root, opno,
00669                                          opclause->args,
00670                                          opclause->inputcollid,
00671                                          varRelid);
00672         }
00673 
00674         /*
00675          * DistinctExpr has the same representation as OpExpr, but the
00676          * contained operator is "=" not "<>", so we must negate the result.
00677          * This estimation method doesn't give the right behavior for nulls,
00678          * but it's better than doing nothing.
00679          */
00680         if (IsA(clause, DistinctExpr))
00681             s1 = 1.0 - s1;
00682     }
00683     else if (is_funcclause(clause))
00684     {
00685         /*
00686          * This is not an operator, so we guess at the selectivity. THIS IS A
00687          * HACK TO GET V4 OUT THE DOOR.  FUNCS SHOULD BE ABLE TO HAVE
00688          * SELECTIVITIES THEMSELVES.       -- JMH 7/9/92
00689          */
00690         s1 = (Selectivity) 0.3333333;
00691     }
00692 #ifdef NOT_USED
00693     else if (IsA(clause, SubPlan) ||
00694              IsA(clause, AlternativeSubPlan))
00695     {
00696         /*
00697          * Just for the moment! FIX ME! - vadim 02/04/98
00698          */
00699         s1 = (Selectivity) 0.5;
00700     }
00701 #endif
00702     else if (IsA(clause, ScalarArrayOpExpr))
00703     {
00704         /* Use node specific selectivity calculation function */
00705         s1 = scalararraysel(root,
00706                             (ScalarArrayOpExpr *) clause,
00707                             treat_as_join_clause(clause, rinfo,
00708                                                  varRelid, sjinfo),
00709                             varRelid,
00710                             jointype,
00711                             sjinfo);
00712     }
00713     else if (IsA(clause, RowCompareExpr))
00714     {
00715         /* Use node specific selectivity calculation function */
00716         s1 = rowcomparesel(root,
00717                            (RowCompareExpr *) clause,
00718                            varRelid,
00719                            jointype,
00720                            sjinfo);
00721     }
00722     else if (IsA(clause, NullTest))
00723     {
00724         /* Use node specific selectivity calculation function */
00725         s1 = nulltestsel(root,
00726                          ((NullTest *) clause)->nulltesttype,
00727                          (Node *) ((NullTest *) clause)->arg,
00728                          varRelid,
00729                          jointype,
00730                          sjinfo);
00731     }
00732     else if (IsA(clause, BooleanTest))
00733     {
00734         /* Use node specific selectivity calculation function */
00735         s1 = booltestsel(root,
00736                          ((BooleanTest *) clause)->booltesttype,
00737                          (Node *) ((BooleanTest *) clause)->arg,
00738                          varRelid,
00739                          jointype,
00740                          sjinfo);
00741     }
00742     else if (IsA(clause, CurrentOfExpr))
00743     {
00744         /* CURRENT OF selects at most one row of its table */
00745         CurrentOfExpr *cexpr = (CurrentOfExpr *) clause;
00746         RelOptInfo *crel = find_base_rel(root, cexpr->cvarno);
00747 
00748         if (crel->tuples > 0)
00749             s1 = 1.0 / crel->tuples;
00750     }
00751     else if (IsA(clause, RelabelType))
00752     {
00753         /* Not sure this case is needed, but it can't hurt */
00754         s1 = clause_selectivity(root,
00755                                 (Node *) ((RelabelType *) clause)->arg,
00756                                 varRelid,
00757                                 jointype,
00758                                 sjinfo);
00759     }
00760     else if (IsA(clause, CoerceToDomain))
00761     {
00762         /* Not sure this case is needed, but it can't hurt */
00763         s1 = clause_selectivity(root,
00764                                 (Node *) ((CoerceToDomain *) clause)->arg,
00765                                 varRelid,
00766                                 jointype,
00767                                 sjinfo);
00768     }
00769 
00770     /* Cache the result if possible */
00771     if (cacheable)
00772     {
00773         if (jointype == JOIN_INNER)
00774             rinfo->norm_selec = s1;
00775         else
00776             rinfo->outer_selec = s1;
00777     }
00778 
00779 #ifdef SELECTIVITY_DEBUG
00780     elog(DEBUG4, "clause_selectivity: s1 %f", s1);
00781 #endif   /* SELECTIVITY_DEBUG */
00782 
00783     return s1;
00784 }