Skip to content

Commit 9d388e1

Browse files
committed
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.
1 parent bb34970 commit 9d388e1

File tree

1 file changed

+36
-27
lines changed

1 file changed

+36
-27
lines changed

src/backend/utils/adt/selfuncs.c

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*
1616
*
1717
* IDENTIFICATION
18-
* $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.173 2005/03/07 04:30:51 momjian Exp $
18+
* $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.174 2005/03/26 20:55:39 tgl Exp $
1919
*
2020
*-------------------------------------------------------------------------
2121
*/
@@ -2309,14 +2309,17 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
23092309
* constant-folding will ensure that any Const passed to the operator
23102310
* has been reduced to the correct type). However, the boundstypid is
23112311
* the type of some variable that might be only binary-compatible with
2312-
* the declared type; in particular it might be a domain type. Must
2313-
* fold the variable type down to base type so we can recognize it.
2314-
* (But we can skip that lookup if the variable type matches the
2315-
* const.)
2312+
* the declared type; for example it might be a domain type. So we
2313+
* ignore it and work with the valuetypid only.
2314+
*
2315+
* XXX What's really going on here is that we assume that the scalar
2316+
* representations of binary-compatible types are enough alike that we
2317+
* can use a histogram generated with one type's operators to estimate
2318+
* selectivity for the other's. This is outright wrong in some cases ---
2319+
* in particular signed versus unsigned interpretation could trip us up.
2320+
* But it's useful enough in the majority of cases that we do it anyway.
2321+
* Should think about more rigorous ways to do it.
23162322
*/
2317-
if (boundstypid != valuetypid)
2318-
boundstypid = getBaseType(boundstypid);
2319-
23202323
switch (valuetypid)
23212324
{
23222325
/*
@@ -2337,8 +2340,8 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
23372340
case REGCLASSOID:
23382341
case REGTYPEOID:
23392342
*scaledvalue = convert_numeric_to_scalar(value, valuetypid);
2340-
*scaledlobound = convert_numeric_to_scalar(lobound, boundstypid);
2341-
*scaledhibound = convert_numeric_to_scalar(hibound, boundstypid);
2343+
*scaledlobound = convert_numeric_to_scalar(lobound, valuetypid);
2344+
*scaledhibound = convert_numeric_to_scalar(hibound, valuetypid);
23422345
return true;
23432346

23442347
/*
@@ -2351,8 +2354,8 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
23512354
case NAMEOID:
23522355
{
23532356
unsigned char *valstr = convert_string_datum(value, valuetypid);
2354-
unsigned char *lostr = convert_string_datum(lobound, boundstypid);
2355-
unsigned char *histr = convert_string_datum(hibound, boundstypid);
2357+
unsigned char *lostr = convert_string_datum(lobound, valuetypid);
2358+
unsigned char *histr = convert_string_datum(hibound, valuetypid);
23562359

23572360
convert_string_to_scalar(valstr, scaledvalue,
23582361
lostr, scaledlobound,
@@ -2387,8 +2390,8 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
23872390
case TIMEOID:
23882391
case TIMETZOID:
23892392
*scaledvalue = convert_timevalue_to_scalar(value, valuetypid);
2390-
*scaledlobound = convert_timevalue_to_scalar(lobound, boundstypid);
2391-
*scaledhibound = convert_timevalue_to_scalar(hibound, boundstypid);
2393+
*scaledlobound = convert_timevalue_to_scalar(lobound, valuetypid);
2394+
*scaledhibound = convert_timevalue_to_scalar(hibound, valuetypid);
23922395
return true;
23932396

23942397
/*
@@ -2398,8 +2401,8 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
23982401
case CIDROID:
23992402
case MACADDROID:
24002403
*scaledvalue = convert_network_to_scalar(value, valuetypid);
2401-
*scaledlobound = convert_network_to_scalar(lobound, boundstypid);
2402-
*scaledhibound = convert_network_to_scalar(hibound, boundstypid);
2404+
*scaledlobound = convert_network_to_scalar(lobound, valuetypid);
2405+
*scaledhibound = convert_network_to_scalar(hibound, valuetypid);
24032406
return true;
24042407
}
24052408
/* Don't know how to convert */
@@ -2848,8 +2851,7 @@ convert_timevalue_to_scalar(Datum value, Oid typid)
28482851
*
28492852
* Outputs: (these are valid only if TRUE is returned)
28502853
* *vardata: gets information about variable (see examine_variable)
2851-
* *other: gets other clause argument, stripped of binary relabeling,
2852-
* and aggressively reduced to a constant
2854+
* *other: gets other clause argument, aggressively reduced to a constant
28532855
* *varonleft: set TRUE if variable is on the left, FALSE if on the right
28542856
*
28552857
* Returns TRUE if a variable is identified, otherwise FALSE.
@@ -2939,7 +2941,8 @@ get_join_variables(Query *root, List *args,
29392941
* varRelid: see specs for restriction selectivity functions
29402942
*
29412943
* Outputs: *vardata is filled as follows:
2942-
* var: the input expression (with any binary relabeling stripped)
2944+
* var: the input expression (with any binary relabeling stripped, if
2945+
* it is or contains a variable; but otherwise the type is preserved)
29432946
* rel: RelOptInfo for relation containing variable; NULL if expression
29442947
* contains no Vars (NOTE this could point to a RelOptInfo of a
29452948
* subquery, not one in the current query).
@@ -2955,27 +2958,29 @@ static void
29552958
examine_variable(Query *root, Node *node, int varRelid,
29562959
VariableStatData *vardata)
29572960
{
2961+
Node *basenode;
29582962
Relids varnos;
29592963
RelOptInfo *onerel;
29602964

29612965
/* Make sure we don't return dangling pointers in vardata */
29622966
MemSet(vardata, 0, sizeof(VariableStatData));
29632967

2964-
/* Ignore any binary-compatible relabeling */
2968+
/* Look inside any binary-compatible relabeling */
29652969

29662970
if (IsA(node, RelabelType))
2967-
node = (Node *) ((RelabelType *) node)->arg;
2968-
2969-
vardata->var = node;
2971+
basenode = (Node *) ((RelabelType *) node)->arg;
2972+
else
2973+
basenode = node;
29702974

29712975
/* Fast path for a simple Var */
29722976

2973-
if (IsA(node, Var) &&
2974-
(varRelid == 0 || varRelid == ((Var *) node)->varno))
2977+
if (IsA(basenode, Var) &&
2978+
(varRelid == 0 || varRelid == ((Var *) basenode)->varno))
29752979
{
2976-
Var *var = (Var *) node;
2980+
Var *var = (Var *) basenode;
29772981
Oid relid;
29782982

2983+
vardata->var = basenode; /* return Var without relabeling */
29792984
vardata->rel = find_base_rel(root, var->varno);
29802985
vardata->atttype = var->vartype;
29812986
vardata->atttypmod = var->vartypmod;
@@ -3009,7 +3014,7 @@ examine_variable(Query *root, Node *node, int varRelid,
30093014
* membership. Note that when varRelid isn't zero, only vars of that
30103015
* relation are considered "real" vars.
30113016
*/
3012-
varnos = pull_varnos(node);
3017+
varnos = pull_varnos(basenode);
30133018

30143019
onerel = NULL;
30153020

@@ -3024,6 +3029,7 @@ examine_variable(Query *root, Node *node, int varRelid,
30243029
onerel = find_base_rel(root,
30253030
(varRelid ? varRelid : bms_singleton_member(varnos)));
30263031
vardata->rel = onerel;
3032+
node = basenode; /* strip any relabeling */
30273033
}
30283034
/* else treat it as a constant */
30293035
break;
@@ -3032,11 +3038,13 @@ examine_variable(Query *root, Node *node, int varRelid,
30323038
{
30333039
/* treat it as a variable of a join relation */
30343040
vardata->rel = find_join_rel(root, varnos);
3041+
node = basenode; /* strip any relabeling */
30353042
}
30363043
else if (bms_is_member(varRelid, varnos))
30373044
{
30383045
/* ignore the vars belonging to other relations */
30393046
vardata->rel = find_base_rel(root, varRelid);
3047+
node = basenode; /* strip any relabeling */
30403048
/* note: no point in expressional-index search here */
30413049
}
30423050
/* else treat it as a constant */
@@ -3045,6 +3053,7 @@ examine_variable(Query *root, Node *node, int varRelid,
30453053

30463054
bms_free(varnos);
30473055

3056+
vardata->var = node;
30483057
vardata->atttype = exprType(node);
30493058
vardata->atttypmod = exprTypmod(node);
30503059

0 commit comments

Comments
 (0)