*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.175 2005/03/27 23:53:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.176 2005/04/01 20:31:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
RelOptInfo *rel; /* Relation, or NULL if not identifiable */
HeapTuple statsTuple; /* pg_statistic tuple, or NULL if none */
/* NB: if statsTuple!=NULL, it must be freed when caller is done */
+ Oid vartype; /* exposed type of expression */
Oid atttype; /* type to pass to get_attstatsslot */
int32 atttypmod; /* typmod to pass to get_attstatsslot */
bool isunique; /* true if matched to a unique index */
*/
if (convert_to_scalar(constval, consttype, &val,
values[i - 1], values[i],
- vardata->atttype,
+ vardata->vartype,
&low, &high))
{
if (high <= low)
}
/*
- * The var, on the other hand, might be a binary-compatible type;
- * particularly a domain. Try to fold it if it's not recognized
- * immediately.
- */
- vartype = vardata.atttype;
- if (vartype != consttype)
- vartype = getBaseType(vartype);
-
- /*
- * We should now be able to recognize the var's datatype. Choose the
- * index opclass from which we must draw the comparison operators.
+ * Similarly, the exposed type of the left-hand side should be one
+ * of those we know. (Do not look at vardata.atttype, which might be
+ * something binary-compatible but different.) We can use it to choose
+ * the index opclass from which we must draw the comparison operators.
*
* NOTE: It would be more correct to use the PATTERN opclasses than the
* simple ones, but at the moment ANALYZE will not generate statistics
* for the PATTERN operators. But our results are so approximate
* anyway that it probably hardly matters.
*/
+ vartype = vardata.vartype;
+
switch (vartype)
{
case TEXTOID:
double *scaledlobound, double *scaledhibound)
{
/*
- * In present usage, we can assume that the valuetypid exactly matches
- * the declared input type of the operator we are invoked for (because
- * constant-folding will ensure that any Const passed to the operator
- * has been reduced to the correct type). However, the boundstypid is
- * the type of some variable that might be only binary-compatible with
- * the declared type; for example it might be a domain type. So we
- * ignore it and work with the valuetypid only.
+ * Both the valuetypid and the boundstypid should exactly match
+ * the declared input type(s) of the operator we are invoked for,
+ * so we just error out if either is not recognized.
*
- * XXX What's really going on here is that we assume that the scalar
- * representations of binary-compatible types are enough alike that we
- * can use a histogram generated with one type's operators to estimate
- * selectivity for the other's. This is outright wrong in some cases ---
- * in particular signed versus unsigned interpretation could trip us up.
- * But it's useful enough in the majority of cases that we do it anyway.
- * Should think about more rigorous ways to do it.
+ * XXX The histogram we are interpolating between points of could belong
+ * to a column that's only binary-compatible with the declared type.
+ * In essence we are assuming that the semantics of binary-compatible
+ * types are enough alike that we can use a histogram generated with one
+ * type's operators to estimate selectivity for the other's. This is
+ * outright wrong in some cases --- in particular signed versus unsigned
+ * interpretation could trip us up. But it's useful enough in the
+ * majority of cases that we do it anyway. Should think about more
+ * rigorous ways to do it.
*/
switch (valuetypid)
{
case REGCLASSOID:
case REGTYPEOID:
*scaledvalue = convert_numeric_to_scalar(value, valuetypid);
- *scaledlobound = convert_numeric_to_scalar(lobound, valuetypid);
- *scaledhibound = convert_numeric_to_scalar(hibound, valuetypid);
+ *scaledlobound = convert_numeric_to_scalar(lobound, boundstypid);
+ *scaledhibound = convert_numeric_to_scalar(hibound, boundstypid);
return true;
/*
case NAMEOID:
{
unsigned char *valstr = convert_string_datum(value, valuetypid);
- unsigned char *lostr = convert_string_datum(lobound, valuetypid);
- unsigned char *histr = convert_string_datum(hibound, valuetypid);
+ unsigned char *lostr = convert_string_datum(lobound, boundstypid);
+ unsigned char *histr = convert_string_datum(hibound, boundstypid);
convert_string_to_scalar(valstr, scaledvalue,
lostr, scaledlobound,
case TIMEOID:
case TIMETZOID:
*scaledvalue = convert_timevalue_to_scalar(value, valuetypid);
- *scaledlobound = convert_timevalue_to_scalar(lobound, valuetypid);
- *scaledhibound = convert_timevalue_to_scalar(hibound, valuetypid);
+ *scaledlobound = convert_timevalue_to_scalar(lobound, boundstypid);
+ *scaledhibound = convert_timevalue_to_scalar(hibound, boundstypid);
return true;
/*
case CIDROID:
case MACADDROID:
*scaledvalue = convert_network_to_scalar(value, valuetypid);
- *scaledlobound = convert_network_to_scalar(lobound, valuetypid);
- *scaledhibound = convert_network_to_scalar(hibound, valuetypid);
+ *scaledlobound = convert_network_to_scalar(lobound, boundstypid);
+ *scaledhibound = convert_network_to_scalar(hibound, boundstypid);
return true;
}
/* Don't know how to convert */
* subquery, not one in the current query).
* statsTuple: the pg_statistic entry for the variable, if one exists;
* otherwise NULL.
+ * vartype: exposed type of the expression; this should always match
+ * the declared input type of the operator we are estimating for.
* atttype, atttypmod: type data to pass to get_attstatsslot(). This is
* commonly the same as the exposed type of the variable argument,
* but can be different in binary-compatible-type cases.
/* Make sure we don't return dangling pointers in vardata */
MemSet(vardata, 0, sizeof(VariableStatData));
+ /* Save the exposed type of the expression */
+ vardata->vartype = exprType(node);
+
/* Look inside any binary-compatible relabeling */
if (IsA(node, RelabelType))
stats = (Form_pg_statistic) GETSTRUCT(vardata->statsTuple);
stadistinct = stats->stadistinct;
}
- else if (vardata->atttype == BOOLOID)
+ else if (vardata->vartype == BOOLOID)
{
/*
* Special-case boolean columns: presumably, two distinct values.