Commit b36df04c authored by Tom Lane's avatar Tom Lane

Guard against roundoff errors in new selectivity-estimation code,

per bug report from Laurette Cisneros.
parent bb2bff49
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.102 2001/11/05 17:46:29 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.103 2002/01/03 04:02:34 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -124,6 +124,19 @@ ...@@ -124,6 +124,19 @@
#define DEFAULT_NOT_UNK_SEL (1.0 - DEFAULT_UNK_SEL) #define DEFAULT_NOT_UNK_SEL (1.0 - DEFAULT_UNK_SEL)
#define DEFAULT_BOOL_SEL 0.5 #define DEFAULT_BOOL_SEL 0.5
/*
* Clamp a computed probability estimate (which may suffer from roundoff or
* estimation errors) to valid range. Argument must be a float variable.
*/
#define CLAMP_PROBABILITY(p) \
do { \
if (p < 0.0) \
p = 0.0; \
else if (p > 1.0) \
p = 1.0; \
} while (0)
static bool convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue, static bool convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
Datum lobound, Datum hibound, Oid boundstypid, Datum lobound, Datum hibound, Oid boundstypid,
double *scaledlobound, double *scaledhibound); double *scaledlobound, double *scaledhibound);
...@@ -285,6 +298,7 @@ eqsel(PG_FUNCTION_ARGS) ...@@ -285,6 +298,7 @@ eqsel(PG_FUNCTION_ARGS)
for (i = 0; i < nnumbers; i++) for (i = 0; i < nnumbers; i++)
sumcommon += numbers[i]; sumcommon += numbers[i];
selec = 1.0 - sumcommon - stats->stanullfrac; selec = 1.0 - sumcommon - stats->stanullfrac;
CLAMP_PROBABILITY(selec);
/* /*
* and in fact it's probably a good deal less. We * and in fact it's probably a good deal less. We
...@@ -356,10 +370,7 @@ eqsel(PG_FUNCTION_ARGS) ...@@ -356,10 +370,7 @@ eqsel(PG_FUNCTION_ARGS)
} }
/* result should be in range, but make sure... */ /* result should be in range, but make sure... */
if (selec < 0.0) CLAMP_PROBABILITY(selec);
selec = 0.0;
else if (selec > 1.0)
selec = 1.0;
PG_RETURN_FLOAT8((float8) selec); PG_RETURN_FLOAT8((float8) selec);
} }
...@@ -669,10 +680,7 @@ scalarineqsel(Query *root, Oid operator, bool isgt, ...@@ -669,10 +680,7 @@ scalarineqsel(Query *root, Oid operator, bool isgt,
ReleaseSysCache(statsTuple); ReleaseSysCache(statsTuple);
/* result should be in range, but make sure... */ /* result should be in range, but make sure... */
if (selec < 0.0) CLAMP_PROBABILITY(selec);
selec = 0.0;
else if (selec > 1.0)
selec = 1.0;
return selec; return selec;
} }
...@@ -867,10 +875,7 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype) ...@@ -867,10 +875,7 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
restsel = pattern_selectivity(rest, ptype); restsel = pattern_selectivity(rest, ptype);
selec = prefixsel * restsel; selec = prefixsel * restsel;
/* result should be in range, but make sure... */ /* result should be in range, but make sure... */
if (selec < 0.0) CLAMP_PROBABILITY(selec);
selec = 0.0;
else if (selec > 1.0)
selec = 1.0;
result = selec; result = selec;
} }
...@@ -1179,10 +1184,7 @@ booltestsel(Query *root, BooleanTest *clause, int varRelid) ...@@ -1179,10 +1184,7 @@ booltestsel(Query *root, BooleanTest *clause, int varRelid)
} }
/* result should be in range, but make sure... */ /* result should be in range, but make sure... */
if (selec < 0.0) CLAMP_PROBABILITY(selec);
selec = 0.0;
else if (selec > 1.0)
selec = 1.0;
return (Selectivity) selec; return (Selectivity) selec;
} }
...@@ -1285,10 +1287,7 @@ nulltestsel(Query *root, NullTest *clause, int varRelid) ...@@ -1285,10 +1287,7 @@ nulltestsel(Query *root, NullTest *clause, int varRelid)
} }
/* result should be in range, but make sure... */ /* result should be in range, but make sure... */
if (selec < 0.0) CLAMP_PROBABILITY(selec);
selec = 0.0;
else if (selec > 1.0)
selec = 1.0;
return (Selectivity) selec; return (Selectivity) selec;
} }
...@@ -1448,6 +1447,7 @@ eqjoinsel(PG_FUNCTION_ARGS) ...@@ -1448,6 +1447,7 @@ eqjoinsel(PG_FUNCTION_ARGS)
} }
} }
} }
CLAMP_PROBABILITY(matchprodfreq);
/* Sum up frequencies of matched and unmatched MCVs */ /* Sum up frequencies of matched and unmatched MCVs */
matchfreq1 = unmatchfreq1 = 0.0; matchfreq1 = unmatchfreq1 = 0.0;
for (i = 0; i < nvalues1; i++) for (i = 0; i < nvalues1; i++)
...@@ -1457,6 +1457,8 @@ eqjoinsel(PG_FUNCTION_ARGS) ...@@ -1457,6 +1457,8 @@ eqjoinsel(PG_FUNCTION_ARGS)
else else
unmatchfreq1 += numbers1[i]; unmatchfreq1 += numbers1[i];
} }
CLAMP_PROBABILITY(matchfreq1);
CLAMP_PROBABILITY(unmatchfreq1);
matchfreq2 = unmatchfreq2 = 0.0; matchfreq2 = unmatchfreq2 = 0.0;
for (i = 0; i < nvalues2; i++) for (i = 0; i < nvalues2; i++)
{ {
...@@ -1465,6 +1467,8 @@ eqjoinsel(PG_FUNCTION_ARGS) ...@@ -1465,6 +1467,8 @@ eqjoinsel(PG_FUNCTION_ARGS)
else else
unmatchfreq2 += numbers2[i]; unmatchfreq2 += numbers2[i];
} }
CLAMP_PROBABILITY(matchfreq2);
CLAMP_PROBABILITY(unmatchfreq2);
pfree(hasmatch1); pfree(hasmatch1);
pfree(hasmatch2); pfree(hasmatch2);
...@@ -1474,6 +1478,8 @@ eqjoinsel(PG_FUNCTION_ARGS) ...@@ -1474,6 +1478,8 @@ eqjoinsel(PG_FUNCTION_ARGS)
*/ */
otherfreq1 = 1.0 - stats1->stanullfrac - matchfreq1 - unmatchfreq1; otherfreq1 = 1.0 - stats1->stanullfrac - matchfreq1 - unmatchfreq1;
otherfreq2 = 1.0 - stats2->stanullfrac - matchfreq2 - unmatchfreq2; otherfreq2 = 1.0 - stats2->stanullfrac - matchfreq2 - unmatchfreq2;
CLAMP_PROBABILITY(otherfreq1);
CLAMP_PROBABILITY(otherfreq2);
/* /*
* We can estimate the total selectivity from the point of * We can estimate the total selectivity from the point of
...@@ -1544,6 +1550,9 @@ eqjoinsel(PG_FUNCTION_ARGS) ...@@ -1544,6 +1550,9 @@ eqjoinsel(PG_FUNCTION_ARGS)
if (HeapTupleIsValid(statsTuple2)) if (HeapTupleIsValid(statsTuple2))
ReleaseSysCache(statsTuple2); ReleaseSysCache(statsTuple2);
} }
CLAMP_PROBABILITY(selec);
PG_RETURN_FLOAT8((float8) selec); PG_RETURN_FLOAT8((float8) selec);
} }
...@@ -2213,6 +2222,9 @@ convert_timevalue_to_scalar(Datum value, Oid typid) ...@@ -2213,6 +2222,9 @@ convert_timevalue_to_scalar(Datum value, Oid typid)
* *
* var: identifies the attribute to examine. * var: identifies the attribute to examine.
* stats: pg_statistic tuple for attribute, or NULL if not available. * stats: pg_statistic tuple for attribute, or NULL if not available.
*
* NB: be careful to produce an integral result, since callers may compare
* the result to exact integer counts.
*/ */
static double static double
get_att_numdistinct(Query *root, Var *var, Form_pg_statistic stats) get_att_numdistinct(Query *root, Var *var, Form_pg_statistic stats)
...@@ -2254,7 +2266,7 @@ get_att_numdistinct(Query *root, Var *var, Form_pg_statistic stats) ...@@ -2254,7 +2266,7 @@ get_att_numdistinct(Query *root, Var *var, Form_pg_statistic stats)
if (stats->stadistinct > 0.0) if (stats->stadistinct > 0.0)
return stats->stadistinct; return stats->stadistinct;
if (stats->stadistinct < 0.0) if (stats->stadistinct < 0.0)
return -stats->stadistinct * ntuples; return floor((-stats->stadistinct * ntuples) + 0.5);
} }
/* /*
......
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