mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-24 18:55:04 +08:00
Fix a pair of related issues with estimation of inequalities that involve
binary-compatible relabeling of one or both operands. examine_variable should avoid stripping RelabelType from non-variable expressions, so that they will continue to have the correct type; and convert_to_scalar should just use that type and ignore the other input type. This isn't perfect but it beats failing entirely. Per example from Michael Fuhr.
This commit is contained in:
parent
d4f727808f
commit
90ce397ad6
@ -15,7 +15,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.169.4.2 2005/02/01 23:08:56 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.169.4.3 2005/03/26 20:55:58 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -2309,14 +2309,17 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
|
|||||||
* constant-folding will ensure that any Const passed to the operator
|
* constant-folding will ensure that any Const passed to the operator
|
||||||
* has been reduced to the correct type). However, the boundstypid is
|
* has been reduced to the correct type). However, the boundstypid is
|
||||||
* the type of some variable that might be only binary-compatible with
|
* the type of some variable that might be only binary-compatible with
|
||||||
* the declared type; in particular it might be a domain type. Must
|
* the declared type; for example it might be a domain type. So we
|
||||||
* fold the variable type down to base type so we can recognize it.
|
* ignore it and work with the valuetypid only.
|
||||||
* (But we can skip that lookup if the variable type matches the
|
*
|
||||||
* const.)
|
* 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.
|
||||||
*/
|
*/
|
||||||
if (boundstypid != valuetypid)
|
|
||||||
boundstypid = getBaseType(boundstypid);
|
|
||||||
|
|
||||||
switch (valuetypid)
|
switch (valuetypid)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -2337,8 +2340,8 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
|
|||||||
case REGCLASSOID:
|
case REGCLASSOID:
|
||||||
case REGTYPEOID:
|
case REGTYPEOID:
|
||||||
*scaledvalue = convert_numeric_to_scalar(value, valuetypid);
|
*scaledvalue = convert_numeric_to_scalar(value, valuetypid);
|
||||||
*scaledlobound = convert_numeric_to_scalar(lobound, boundstypid);
|
*scaledlobound = convert_numeric_to_scalar(lobound, valuetypid);
|
||||||
*scaledhibound = convert_numeric_to_scalar(hibound, boundstypid);
|
*scaledhibound = convert_numeric_to_scalar(hibound, valuetypid);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2351,8 +2354,8 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
|
|||||||
case NAMEOID:
|
case NAMEOID:
|
||||||
{
|
{
|
||||||
unsigned char *valstr = convert_string_datum(value, valuetypid);
|
unsigned char *valstr = convert_string_datum(value, valuetypid);
|
||||||
unsigned char *lostr = convert_string_datum(lobound, boundstypid);
|
unsigned char *lostr = convert_string_datum(lobound, valuetypid);
|
||||||
unsigned char *histr = convert_string_datum(hibound, boundstypid);
|
unsigned char *histr = convert_string_datum(hibound, valuetypid);
|
||||||
|
|
||||||
convert_string_to_scalar(valstr, scaledvalue,
|
convert_string_to_scalar(valstr, scaledvalue,
|
||||||
lostr, scaledlobound,
|
lostr, scaledlobound,
|
||||||
@ -2387,8 +2390,8 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
|
|||||||
case TIMEOID:
|
case TIMEOID:
|
||||||
case TIMETZOID:
|
case TIMETZOID:
|
||||||
*scaledvalue = convert_timevalue_to_scalar(value, valuetypid);
|
*scaledvalue = convert_timevalue_to_scalar(value, valuetypid);
|
||||||
*scaledlobound = convert_timevalue_to_scalar(lobound, boundstypid);
|
*scaledlobound = convert_timevalue_to_scalar(lobound, valuetypid);
|
||||||
*scaledhibound = convert_timevalue_to_scalar(hibound, boundstypid);
|
*scaledhibound = convert_timevalue_to_scalar(hibound, valuetypid);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2398,8 +2401,8 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
|
|||||||
case CIDROID:
|
case CIDROID:
|
||||||
case MACADDROID:
|
case MACADDROID:
|
||||||
*scaledvalue = convert_network_to_scalar(value, valuetypid);
|
*scaledvalue = convert_network_to_scalar(value, valuetypid);
|
||||||
*scaledlobound = convert_network_to_scalar(lobound, boundstypid);
|
*scaledlobound = convert_network_to_scalar(lobound, valuetypid);
|
||||||
*scaledhibound = convert_network_to_scalar(hibound, boundstypid);
|
*scaledhibound = convert_network_to_scalar(hibound, valuetypid);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
/* Don't know how to convert */
|
/* Don't know how to convert */
|
||||||
@ -2848,8 +2851,7 @@ convert_timevalue_to_scalar(Datum value, Oid typid)
|
|||||||
*
|
*
|
||||||
* Outputs: (these are valid only if TRUE is returned)
|
* Outputs: (these are valid only if TRUE is returned)
|
||||||
* *vardata: gets information about variable (see examine_variable)
|
* *vardata: gets information about variable (see examine_variable)
|
||||||
* *other: gets other clause argument, stripped of binary relabeling,
|
* *other: gets other clause argument, aggressively reduced to a constant
|
||||||
* and aggressively reduced to a constant
|
|
||||||
* *varonleft: set TRUE if variable is on the left, FALSE if on the right
|
* *varonleft: set TRUE if variable is on the left, FALSE if on the right
|
||||||
*
|
*
|
||||||
* Returns TRUE if a variable is identified, otherwise FALSE.
|
* Returns TRUE if a variable is identified, otherwise FALSE.
|
||||||
@ -2939,7 +2941,8 @@ get_join_variables(Query *root, List *args,
|
|||||||
* varRelid: see specs for restriction selectivity functions
|
* varRelid: see specs for restriction selectivity functions
|
||||||
*
|
*
|
||||||
* Outputs: *vardata is filled as follows:
|
* Outputs: *vardata is filled as follows:
|
||||||
* var: the input expression (with any binary relabeling stripped)
|
* var: the input expression (with any binary relabeling stripped, if
|
||||||
|
* it is or contains a variable; but otherwise the type is preserved)
|
||||||
* rel: RelOptInfo for relation containing variable; NULL if expression
|
* rel: RelOptInfo for relation containing variable; NULL if expression
|
||||||
* contains no Vars (NOTE this could point to a RelOptInfo of a
|
* contains no Vars (NOTE this could point to a RelOptInfo of a
|
||||||
* subquery, not one in the current query).
|
* subquery, not one in the current query).
|
||||||
@ -2955,27 +2958,29 @@ static void
|
|||||||
examine_variable(Query *root, Node *node, int varRelid,
|
examine_variable(Query *root, Node *node, int varRelid,
|
||||||
VariableStatData *vardata)
|
VariableStatData *vardata)
|
||||||
{
|
{
|
||||||
|
Node *basenode;
|
||||||
Relids varnos;
|
Relids varnos;
|
||||||
RelOptInfo *onerel;
|
RelOptInfo *onerel;
|
||||||
|
|
||||||
/* Make sure we don't return dangling pointers in vardata */
|
/* Make sure we don't return dangling pointers in vardata */
|
||||||
MemSet(vardata, 0, sizeof(VariableStatData));
|
MemSet(vardata, 0, sizeof(VariableStatData));
|
||||||
|
|
||||||
/* Ignore any binary-compatible relabeling */
|
/* Look inside any binary-compatible relabeling */
|
||||||
|
|
||||||
if (IsA(node, RelabelType))
|
if (IsA(node, RelabelType))
|
||||||
node = (Node *) ((RelabelType *) node)->arg;
|
basenode = (Node *) ((RelabelType *) node)->arg;
|
||||||
|
else
|
||||||
vardata->var = node;
|
basenode = node;
|
||||||
|
|
||||||
/* Fast path for a simple Var */
|
/* Fast path for a simple Var */
|
||||||
|
|
||||||
if (IsA(node, Var) &&
|
if (IsA(basenode, Var) &&
|
||||||
(varRelid == 0 || varRelid == ((Var *) node)->varno))
|
(varRelid == 0 || varRelid == ((Var *) basenode)->varno))
|
||||||
{
|
{
|
||||||
Var *var = (Var *) node;
|
Var *var = (Var *) basenode;
|
||||||
Oid relid;
|
Oid relid;
|
||||||
|
|
||||||
|
vardata->var = basenode; /* return Var without relabeling */
|
||||||
vardata->rel = find_base_rel(root, var->varno);
|
vardata->rel = find_base_rel(root, var->varno);
|
||||||
vardata->atttype = var->vartype;
|
vardata->atttype = var->vartype;
|
||||||
vardata->atttypmod = var->vartypmod;
|
vardata->atttypmod = var->vartypmod;
|
||||||
@ -3009,7 +3014,7 @@ examine_variable(Query *root, Node *node, int varRelid,
|
|||||||
* membership. Note that when varRelid isn't zero, only vars of that
|
* membership. Note that when varRelid isn't zero, only vars of that
|
||||||
* relation are considered "real" vars.
|
* relation are considered "real" vars.
|
||||||
*/
|
*/
|
||||||
varnos = pull_varnos(node);
|
varnos = pull_varnos(basenode);
|
||||||
|
|
||||||
onerel = NULL;
|
onerel = NULL;
|
||||||
|
|
||||||
@ -3024,6 +3029,7 @@ examine_variable(Query *root, Node *node, int varRelid,
|
|||||||
onerel = find_base_rel(root,
|
onerel = find_base_rel(root,
|
||||||
(varRelid ? varRelid : bms_singleton_member(varnos)));
|
(varRelid ? varRelid : bms_singleton_member(varnos)));
|
||||||
vardata->rel = onerel;
|
vardata->rel = onerel;
|
||||||
|
node = basenode; /* strip any relabeling */
|
||||||
}
|
}
|
||||||
/* else treat it as a constant */
|
/* else treat it as a constant */
|
||||||
break;
|
break;
|
||||||
@ -3032,11 +3038,13 @@ examine_variable(Query *root, Node *node, int varRelid,
|
|||||||
{
|
{
|
||||||
/* treat it as a variable of a join relation */
|
/* treat it as a variable of a join relation */
|
||||||
vardata->rel = find_join_rel(root, varnos);
|
vardata->rel = find_join_rel(root, varnos);
|
||||||
|
node = basenode; /* strip any relabeling */
|
||||||
}
|
}
|
||||||
else if (bms_is_member(varRelid, varnos))
|
else if (bms_is_member(varRelid, varnos))
|
||||||
{
|
{
|
||||||
/* ignore the vars belonging to other relations */
|
/* ignore the vars belonging to other relations */
|
||||||
vardata->rel = find_base_rel(root, varRelid);
|
vardata->rel = find_base_rel(root, varRelid);
|
||||||
|
node = basenode; /* strip any relabeling */
|
||||||
/* note: no point in expressional-index search here */
|
/* note: no point in expressional-index search here */
|
||||||
}
|
}
|
||||||
/* else treat it as a constant */
|
/* else treat it as a constant */
|
||||||
@ -3045,6 +3053,7 @@ examine_variable(Query *root, Node *node, int varRelid,
|
|||||||
|
|
||||||
bms_free(varnos);
|
bms_free(varnos);
|
||||||
|
|
||||||
|
vardata->var = node;
|
||||||
vardata->atttype = exprType(node);
|
vardata->atttype = exprType(node);
|
||||||
vardata->atttypmod = exprTypmod(node);
|
vardata->atttypmod = exprTypmod(node);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user