Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit c0f7dcd

Browse files
committed
Fix range-query estimation to not double-exclude NULLs, per gripe from
Ray Ontko 28-June-02. Also, fix prefix_selectivity for NAME lefthand variables (it was bogusly assuming binary compatibility), and adjust make_greater_string() to not call pg_mbcliplen() with invalid multibyte data (this last per bug report that I can't find at the moment, but it was in July '02).
1 parent a3cb874 commit c0f7dcd

File tree

3 files changed

+49
-36
lines changed

3 files changed

+49
-36
lines changed

src/backend/optimizer/path/clausesel.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.51 2002/06/20 20:29:29 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.52 2002/10/19 02:56:16 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -102,7 +102,9 @@ restrictlist_selectivity(Query *root,
102102
* see that hisel is the fraction of the range below the high bound, while
103103
* losel is the fraction above the low bound; so hisel can be interpreted
104104
* directly as a 0..1 value but we need to convert losel to 1-losel before
105-
* interpreting it as a value. Then the available range is 1-losel to hisel.)
105+
* interpreting it as a value. Then the available range is 1-losel to hisel.
106+
* However, this calculation double-excludes nulls, so really we need
107+
* hisel + losel + null_frac - 1.)
106108
* If the calculation yields zero or negative, however, we chicken out and
107109
* use a default estimate; that probably means that one or both
108110
* selectivities is a default estimate rather than an actual range value.
@@ -199,6 +201,9 @@ clauselist_selectivity(Query *root,
199201
/* Successfully matched a pair of range clauses */
200202
Selectivity s2 = rqlist->hibound + rqlist->lobound - 1.0;
201203

204+
/* Adjust for double-exclusion of NULLs */
205+
s2 += nulltestsel(root, IS_NULL, rqlist->var, varRelid);
206+
202207
/*
203208
* A zero or slightly negative s2 should be converted into a
204209
* small positive value; we probably are dealing with a very
@@ -503,12 +508,18 @@ clause_selectivity(Query *root,
503508
else if (IsA(clause, NullTest))
504509
{
505510
/* Use node specific selectivity calculation function */
506-
s1 = nulltestsel(root, (NullTest *) clause, varRelid);
511+
s1 = nulltestsel(root,
512+
((NullTest *) clause)->nulltesttype,
513+
((NullTest *) clause)->arg,
514+
varRelid);
507515
}
508516
else if (IsA(clause, BooleanTest))
509517
{
510518
/* Use node specific selectivity calculation function */
511-
s1 = booltestsel(root, (BooleanTest *) clause, varRelid);
519+
s1 = booltestsel(root,
520+
((BooleanTest *) clause)->booltesttype,
521+
((BooleanTest *) clause)->arg,
522+
varRelid);
512523
}
513524
else if (IsA(clause, RelabelType))
514525
{

src/backend/utils/adt/selfuncs.c

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*
1616
*
1717
* IDENTIFICATION
18-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.118 2002/09/20 03:55:40 momjian Exp $
18+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.119 2002/10/19 02:56:16 tgl Exp $
1919
*
2020
*-------------------------------------------------------------------------
2121
*/
@@ -1007,10 +1007,9 @@ icnlikesel(PG_FUNCTION_ARGS)
10071007
* booltestsel - Selectivity of BooleanTest Node.
10081008
*/
10091009
Selectivity
1010-
booltestsel(Query *root, BooleanTest *clause, int varRelid)
1010+
booltestsel(Query *root, BoolTestType booltesttype, Node *arg, int varRelid)
10111011
{
10121012
Var *var;
1013-
Node *arg;
10141013
Oid relid;
10151014
HeapTuple statsTuple;
10161015
Datum *values;
@@ -1019,10 +1018,6 @@ booltestsel(Query *root, BooleanTest *clause, int varRelid)
10191018
int nnumbers;
10201019
double selec;
10211020

1022-
Assert(clause && IsA(clause, BooleanTest));
1023-
1024-
arg = (Node *) clause->arg;
1025-
10261021
/*
10271022
* Ignore any binary-compatible relabeling (probably unnecessary, but
10281023
* can't hurt)
@@ -1040,7 +1035,7 @@ booltestsel(Query *root, BooleanTest *clause, int varRelid)
10401035
* the possibility of a NULL value when using clause_selectivity,
10411036
* and just assume the value is either TRUE or FALSE.
10421037
*/
1043-
switch (clause->booltesttype)
1038+
switch (booltesttype)
10441039
{
10451040
case IS_UNKNOWN:
10461041
selec = DEFAULT_UNK_SEL;
@@ -1058,7 +1053,7 @@ booltestsel(Query *root, BooleanTest *clause, int varRelid)
10581053
break;
10591054
default:
10601055
elog(ERROR, "booltestsel: unexpected booltesttype %d",
1061-
(int) clause->booltesttype);
1056+
(int) booltesttype);
10621057
selec = 0.0; /* Keep compiler quiet */
10631058
break;
10641059
}
@@ -1107,7 +1102,7 @@ booltestsel(Query *root, BooleanTest *clause, int varRelid)
11071102
*/
11081103
freq_false = 1.0 - freq_true - freq_null;
11091104

1110-
switch (clause->booltesttype)
1105+
switch (booltesttype)
11111106
{
11121107
case IS_UNKNOWN:
11131108
/* select only NULL values */
@@ -1135,7 +1130,7 @@ booltestsel(Query *root, BooleanTest *clause, int varRelid)
11351130
break;
11361131
default:
11371132
elog(ERROR, "booltestsel: unexpected booltesttype %d",
1138-
(int) clause->booltesttype);
1133+
(int) booltesttype);
11391134
selec = 0.0; /* Keep compiler quiet */
11401135
break;
11411136
}
@@ -1151,7 +1146,7 @@ booltestsel(Query *root, BooleanTest *clause, int varRelid)
11511146
* Otherwise adjust for null fraction and assume an even split
11521147
* for boolean tests.
11531148
*/
1154-
switch (clause->booltesttype)
1149+
switch (booltesttype)
11551150
{
11561151
case IS_UNKNOWN:
11571152

@@ -1176,7 +1171,7 @@ booltestsel(Query *root, BooleanTest *clause, int varRelid)
11761171
break;
11771172
default:
11781173
elog(ERROR, "booltestsel: unexpected booltesttype %d",
1179-
(int) clause->booltesttype);
1174+
(int) booltesttype);
11801175
selec = 0.0; /* Keep compiler quiet */
11811176
break;
11821177
}
@@ -1190,7 +1185,7 @@ booltestsel(Query *root, BooleanTest *clause, int varRelid)
11901185
* No VACUUM ANALYZE stats available, so use a default value.
11911186
* (Note: not much point in recursing to clause_selectivity here.)
11921187
*/
1193-
switch (clause->booltesttype)
1188+
switch (booltesttype)
11941189
{
11951190
case IS_UNKNOWN:
11961191
selec = DEFAULT_UNK_SEL;
@@ -1206,7 +1201,7 @@ booltestsel(Query *root, BooleanTest *clause, int varRelid)
12061201
break;
12071202
default:
12081203
elog(ERROR, "booltestsel: unexpected booltesttype %d",
1209-
(int) clause->booltesttype);
1204+
(int) booltesttype);
12101205
selec = 0.0; /* Keep compiler quiet */
12111206
break;
12121207
}
@@ -1222,19 +1217,16 @@ booltestsel(Query *root, BooleanTest *clause, int varRelid)
12221217
* nulltestsel - Selectivity of NullTest Node.
12231218
*/
12241219
Selectivity
1225-
nulltestsel(Query *root, NullTest *clause, int varRelid)
1220+
nulltestsel(Query *root, NullTestType nulltesttype, Node *arg, int varRelid)
12261221
{
12271222
Var *var;
1228-
Node *arg;
12291223
Oid relid;
12301224
HeapTuple statsTuple;
12311225
double selec;
12321226
double defselec;
12331227
double freq_null;
12341228

1235-
Assert(clause && IsA(clause, NullTest));
1236-
1237-
switch (clause->nulltesttype)
1229+
switch (nulltesttype)
12381230
{
12391231
case IS_NULL:
12401232
defselec = DEFAULT_UNK_SEL;
@@ -1244,25 +1236,22 @@ nulltestsel(Query *root, NullTest *clause, int varRelid)
12441236
break;
12451237
default:
12461238
elog(ERROR, "nulltestsel: unexpected nulltesttype %d",
1247-
(int) clause->nulltesttype);
1239+
(int) nulltesttype);
12481240
return (Selectivity) 0; /* keep compiler quiet */
12491241
}
12501242

1251-
arg = (Node *) clause->arg;
1252-
12531243
/*
12541244
* Ignore any binary-compatible relabeling
12551245
*/
12561246
if (IsA(arg, RelabelType))
12571247
arg = ((RelabelType *) arg)->arg;
12581248

1259-
if (IsA(arg, Var) &&(varRelid == 0 || varRelid == ((Var *) arg)->varno))
1249+
if (IsA(arg, Var) &&
1250+
(varRelid == 0 || varRelid == ((Var *) arg)->varno))
12601251
var = (Var *) arg;
12611252
else
12621253
{
1263-
/*
1264-
* punt if non-Var argument
1265-
*/
1254+
/* punt if non-Var argument */
12661255
return (Selectivity) defselec;
12671256
}
12681257

@@ -1282,7 +1271,7 @@ nulltestsel(Query *root, NullTest *clause, int varRelid)
12821271
stats = (Form_pg_statistic) GETSTRUCT(statsTuple);
12831272
freq_null = stats->stanullfrac;
12841273

1285-
switch (clause->nulltesttype)
1274+
switch (nulltesttype)
12861275
{
12871276
case IS_NULL:
12881277

@@ -1301,7 +1290,7 @@ nulltestsel(Query *root, NullTest *clause, int varRelid)
13011290
break;
13021291
default:
13031292
elog(ERROR, "nulltestsel: unexpected nulltesttype %d",
1304-
(int) clause->nulltesttype);
1293+
(int) nulltesttype);
13051294
return (Selectivity) 0; /* keep compiler quiet */
13061295
}
13071296

@@ -2978,6 +2967,10 @@ prefix_selectivity(Query *root, Var *var, Const *prefixcon)
29782967
else
29792968
prefix = DatumGetCString(DirectFunctionCall1(byteaout, prefixcon->constvalue));
29802969

2970+
/* If var is type NAME, must adjust type of comparison constant */
2971+
if (var->vartype == NAMEOID)
2972+
prefixcon = string_to_const(prefix, NAMEOID);
2973+
29812974
cmpargs = makeList2(var, prefixcon);
29822975
/* Assume scalargtsel is appropriate for all supported types */
29832976
prefixsel = DatumGetFloat8(DirectFunctionCall4(scalargtsel,
@@ -3014,6 +3007,9 @@ prefix_selectivity(Query *root, Var *var, Const *prefixcon)
30143007
*/
30153008
prefixsel = topsel + prefixsel - 1.0;
30163009

3010+
/* Adjust for double-exclusion of NULLs */
3011+
prefixsel += nulltestsel(root, IS_NULL, (Node *) var, var->varno);
3012+
30173013
/*
30183014
* A zero or slightly negative prefixsel should be converted into
30193015
* a small positive value; we probably are dealing with a very
@@ -3351,6 +3347,7 @@ make_greater_string(const Const *str_const)
33513347
while (len > 0)
33523348
{
33533349
unsigned char *lastchar = (unsigned char *) (workstr + len - 1);
3350+
unsigned char savelastchar = *lastchar;
33543351

33553352
/*
33563353
* Try to generate a larger string by incrementing the last byte.
@@ -3369,6 +3366,9 @@ make_greater_string(const Const *str_const)
33693366
}
33703367
}
33713368

3369+
/* restore last byte so we don't confuse pg_mbcliplen */
3370+
*lastchar = savelastchar;
3371+
33723372
/*
33733373
* Truncate off the last character, which might be more than 1
33743374
* byte, depending on the character encoding.

src/include/utils/selfuncs.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
99
* Portions Copyright (c) 1994, Regents of the University of California
1010
*
11-
* $Id: selfuncs.h,v 1.8 2002/09/04 20:31:46 momjian Exp $
11+
* $Id: selfuncs.h,v 1.9 2002/10/19 02:56:16 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -66,8 +66,10 @@ extern Datum icregexnejoinsel(PG_FUNCTION_ARGS);
6666
extern Datum nlikejoinsel(PG_FUNCTION_ARGS);
6767
extern Datum icnlikejoinsel(PG_FUNCTION_ARGS);
6868

69-
extern Selectivity booltestsel(Query *root, BooleanTest *clause, int varRelid);
70-
extern Selectivity nulltestsel(Query *root, NullTest *clause, int varRelid);
69+
extern Selectivity booltestsel(Query *root, BoolTestType booltesttype,
70+
Node *arg, int varRelid);
71+
extern Selectivity nulltestsel(Query *root, NullTestType nulltesttype,
72+
Node *arg, int varRelid);
7173

7274
extern void mergejoinscansel(Query *root, Node *clause,
7375
Selectivity *leftscan,

0 commit comments

Comments
 (0)