*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.51 2002/06/20 20:29:29 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.52 2002/10/19 02:56:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* see that hisel is the fraction of the range below the high bound, while
* losel is the fraction above the low bound; so hisel can be interpreted
* directly as a 0..1 value but we need to convert losel to 1-losel before
- * interpreting it as a value. Then the available range is 1-losel to hisel.)
+ * interpreting it as a value. Then the available range is 1-losel to hisel.
+ * However, this calculation double-excludes nulls, so really we need
+ * hisel + losel + null_frac - 1.)
* If the calculation yields zero or negative, however, we chicken out and
* use a default estimate; that probably means that one or both
* selectivities is a default estimate rather than an actual range value.
/* Successfully matched a pair of range clauses */
Selectivity s2 = rqlist->hibound + rqlist->lobound - 1.0;
+ /* Adjust for double-exclusion of NULLs */
+ s2 += nulltestsel(root, IS_NULL, rqlist->var, varRelid);
+
/*
* A zero or slightly negative s2 should be converted into a
* small positive value; we probably are dealing with a very
else if (IsA(clause, NullTest))
{
/* Use node specific selectivity calculation function */
- s1 = nulltestsel(root, (NullTest *) clause, varRelid);
+ s1 = nulltestsel(root,
+ ((NullTest *) clause)->nulltesttype,
+ ((NullTest *) clause)->arg,
+ varRelid);
}
else if (IsA(clause, BooleanTest))
{
/* Use node specific selectivity calculation function */
- s1 = booltestsel(root, (BooleanTest *) clause, varRelid);
+ s1 = booltestsel(root,
+ ((BooleanTest *) clause)->booltesttype,
+ ((BooleanTest *) clause)->arg,
+ varRelid);
}
else if (IsA(clause, RelabelType))
{
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.118 2002/09/20 03:55:40 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.119 2002/10/19 02:56:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* booltestsel - Selectivity of BooleanTest Node.
*/
Selectivity
-booltestsel(Query *root, BooleanTest *clause, int varRelid)
+booltestsel(Query *root, BoolTestType booltesttype, Node *arg, int varRelid)
{
Var *var;
- Node *arg;
Oid relid;
HeapTuple statsTuple;
Datum *values;
int nnumbers;
double selec;
- Assert(clause && IsA(clause, BooleanTest));
-
- arg = (Node *) clause->arg;
-
/*
* Ignore any binary-compatible relabeling (probably unnecessary, but
* can't hurt)
* the possibility of a NULL value when using clause_selectivity,
* and just assume the value is either TRUE or FALSE.
*/
- switch (clause->booltesttype)
+ switch (booltesttype)
{
case IS_UNKNOWN:
selec = DEFAULT_UNK_SEL;
break;
default:
elog(ERROR, "booltestsel: unexpected booltesttype %d",
- (int) clause->booltesttype);
+ (int) booltesttype);
selec = 0.0; /* Keep compiler quiet */
break;
}
*/
freq_false = 1.0 - freq_true - freq_null;
- switch (clause->booltesttype)
+ switch (booltesttype)
{
case IS_UNKNOWN:
/* select only NULL values */
break;
default:
elog(ERROR, "booltestsel: unexpected booltesttype %d",
- (int) clause->booltesttype);
+ (int) booltesttype);
selec = 0.0; /* Keep compiler quiet */
break;
}
* Otherwise adjust for null fraction and assume an even split
* for boolean tests.
*/
- switch (clause->booltesttype)
+ switch (booltesttype)
{
case IS_UNKNOWN:
break;
default:
elog(ERROR, "booltestsel: unexpected booltesttype %d",
- (int) clause->booltesttype);
+ (int) booltesttype);
selec = 0.0; /* Keep compiler quiet */
break;
}
* No VACUUM ANALYZE stats available, so use a default value.
* (Note: not much point in recursing to clause_selectivity here.)
*/
- switch (clause->booltesttype)
+ switch (booltesttype)
{
case IS_UNKNOWN:
selec = DEFAULT_UNK_SEL;
break;
default:
elog(ERROR, "booltestsel: unexpected booltesttype %d",
- (int) clause->booltesttype);
+ (int) booltesttype);
selec = 0.0; /* Keep compiler quiet */
break;
}
* nulltestsel - Selectivity of NullTest Node.
*/
Selectivity
-nulltestsel(Query *root, NullTest *clause, int varRelid)
+nulltestsel(Query *root, NullTestType nulltesttype, Node *arg, int varRelid)
{
Var *var;
- Node *arg;
Oid relid;
HeapTuple statsTuple;
double selec;
double defselec;
double freq_null;
- Assert(clause && IsA(clause, NullTest));
-
- switch (clause->nulltesttype)
+ switch (nulltesttype)
{
case IS_NULL:
defselec = DEFAULT_UNK_SEL;
break;
default:
elog(ERROR, "nulltestsel: unexpected nulltesttype %d",
- (int) clause->nulltesttype);
+ (int) nulltesttype);
return (Selectivity) 0; /* keep compiler quiet */
}
- arg = (Node *) clause->arg;
-
/*
* Ignore any binary-compatible relabeling
*/
if (IsA(arg, RelabelType))
arg = ((RelabelType *) arg)->arg;
- if (IsA(arg, Var) &&(varRelid == 0 || varRelid == ((Var *) arg)->varno))
+ if (IsA(arg, Var) &&
+ (varRelid == 0 || varRelid == ((Var *) arg)->varno))
var = (Var *) arg;
else
{
- /*
- * punt if non-Var argument
- */
+ /* punt if non-Var argument */
return (Selectivity) defselec;
}
stats = (Form_pg_statistic) GETSTRUCT(statsTuple);
freq_null = stats->stanullfrac;
- switch (clause->nulltesttype)
+ switch (nulltesttype)
{
case IS_NULL:
break;
default:
elog(ERROR, "nulltestsel: unexpected nulltesttype %d",
- (int) clause->nulltesttype);
+ (int) nulltesttype);
return (Selectivity) 0; /* keep compiler quiet */
}
else
prefix = DatumGetCString(DirectFunctionCall1(byteaout, prefixcon->constvalue));
+ /* If var is type NAME, must adjust type of comparison constant */
+ if (var->vartype == NAMEOID)
+ prefixcon = string_to_const(prefix, NAMEOID);
+
cmpargs = makeList2(var, prefixcon);
/* Assume scalargtsel is appropriate for all supported types */
prefixsel = DatumGetFloat8(DirectFunctionCall4(scalargtsel,
*/
prefixsel = topsel + prefixsel - 1.0;
+ /* Adjust for double-exclusion of NULLs */
+ prefixsel += nulltestsel(root, IS_NULL, (Node *) var, var->varno);
+
/*
* A zero or slightly negative prefixsel should be converted into
* a small positive value; we probably are dealing with a very
while (len > 0)
{
unsigned char *lastchar = (unsigned char *) (workstr + len - 1);
+ unsigned char savelastchar = *lastchar;
/*
* Try to generate a larger string by incrementing the last byte.
}
}
+ /* restore last byte so we don't confuse pg_mbcliplen */
+ *lastchar = savelastchar;
+
/*
* Truncate off the last character, which might be more than 1
* byte, depending on the character encoding.
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: selfuncs.h,v 1.8 2002/09/04 20:31:46 momjian Exp $
+ * $Id: selfuncs.h,v 1.9 2002/10/19 02:56:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern Datum nlikejoinsel(PG_FUNCTION_ARGS);
extern Datum icnlikejoinsel(PG_FUNCTION_ARGS);
-extern Selectivity booltestsel(Query *root, BooleanTest *clause, int varRelid);
-extern Selectivity nulltestsel(Query *root, NullTest *clause, int varRelid);
+extern Selectivity booltestsel(Query *root, BoolTestType booltesttype,
+ Node *arg, int varRelid);
+extern Selectivity nulltestsel(Query *root, NullTestType nulltesttype,
+ Node *arg, int varRelid);
extern void mergejoinscansel(Query *root, Node *clause,
Selectivity *leftscan,