00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "postgres.h"
00019
00020 #include "access/htup_details.h"
00021 #include "catalog/pg_operator.h"
00022 #include "catalog/pg_statistic.h"
00023 #include "utils/builtins.h"
00024 #include "utils/lsyscache.h"
00025 #include "utils/rangetypes.h"
00026 #include "utils/selfuncs.h"
00027 #include "utils/typcache.h"
00028
00029 static double calc_rangesel(TypeCacheEntry *typcache, VariableStatData *vardata,
00030 RangeType *constval, Oid operator);
00031 static double default_range_selectivity(Oid operator);
00032 static double calc_hist_selectivity(TypeCacheEntry *typcache,
00033 VariableStatData *vardata, RangeType *constval,
00034 Oid operator);
00035 static double calc_hist_selectivity_scalar(TypeCacheEntry *typcache,
00036 RangeBound *constbound,
00037 RangeBound *hist, int hist_nvalues,
00038 bool equal);
00039 static int rbound_bsearch(TypeCacheEntry *typcache, RangeBound *value,
00040 RangeBound *hist, int hist_length, bool equal);
00041 static float8 get_position(TypeCacheEntry *typcache, RangeBound *value,
00042 RangeBound *hist1, RangeBound *hist2);
00043 static float8 get_len_position(double value, double hist1, double hist2);
00044 static float8 get_distance(TypeCacheEntry *typcache, RangeBound *bound1,
00045 RangeBound *bound2);
00046 static int length_hist_bsearch(Datum *length_hist_values,
00047 int length_hist_nvalues, double value, bool equal);
00048 static double calc_length_hist_frac(Datum *length_hist_values,
00049 int length_hist_nvalues, double length1, double length2, bool equal);
00050 static double calc_hist_selectivity_contained(TypeCacheEntry *typcache,
00051 RangeBound *lower, RangeBound *upper,
00052 RangeBound *hist_lower, int hist_nvalues,
00053 Datum *length_hist_values, int length_hist_nvalues);
00054 static double calc_hist_selectivity_contains(TypeCacheEntry *typcache,
00055 RangeBound *lower, RangeBound *upper,
00056 RangeBound *hist_lower, int hist_nvalues,
00057 Datum *length_hist_values, int length_hist_nvalues);
00058
00059
00060
00061
00062
00063 static double
00064 default_range_selectivity(Oid operator)
00065 {
00066 switch (operator)
00067 {
00068 case OID_RANGE_OVERLAP_OP:
00069 return 0.01;
00070
00071 case OID_RANGE_CONTAINS_OP:
00072 case OID_RANGE_CONTAINED_OP:
00073 return 0.005;
00074
00075 case OID_RANGE_CONTAINS_ELEM_OP:
00076
00077
00078
00079
00080 return DEFAULT_RANGE_INEQ_SEL;
00081
00082 case OID_RANGE_LESS_OP:
00083 case OID_RANGE_LESS_EQUAL_OP:
00084 case OID_RANGE_GREATER_OP:
00085 case OID_RANGE_GREATER_EQUAL_OP:
00086 case OID_RANGE_LEFT_OP:
00087 case OID_RANGE_RIGHT_OP:
00088
00089 return DEFAULT_INEQ_SEL;
00090
00091 default:
00092
00093 return 0.01;
00094 }
00095 }
00096
00097
00098
00099
00100 Datum
00101 rangesel(PG_FUNCTION_ARGS)
00102 {
00103 PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
00104 Oid operator = PG_GETARG_OID(1);
00105 List *args = (List *) PG_GETARG_POINTER(2);
00106 int varRelid = PG_GETARG_INT32(3);
00107 VariableStatData vardata;
00108 Node *other;
00109 bool varonleft;
00110 Selectivity selec;
00111 TypeCacheEntry *typcache;
00112 RangeType *constrange = NULL;
00113
00114
00115
00116
00117
00118 if (!get_restriction_variable(root, args, varRelid,
00119 &vardata, &other, &varonleft))
00120 PG_RETURN_FLOAT8(default_range_selectivity(operator));
00121
00122
00123
00124
00125 if (!IsA(other, Const))
00126 {
00127 ReleaseVariableStats(vardata);
00128 PG_RETURN_FLOAT8(default_range_selectivity(operator));
00129 }
00130
00131
00132
00133
00134
00135 if (((Const *) other)->constisnull)
00136 {
00137 ReleaseVariableStats(vardata);
00138 PG_RETURN_FLOAT8(0.0);
00139 }
00140
00141
00142
00143
00144
00145 if (!varonleft)
00146 {
00147
00148 operator = get_commutator(operator);
00149 if (!operator)
00150 {
00151
00152 ReleaseVariableStats(vardata);
00153 PG_RETURN_FLOAT8(default_range_selectivity(operator));
00154 }
00155 }
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168 if (operator == OID_RANGE_CONTAINS_ELEM_OP)
00169 {
00170 typcache = range_get_typcache(fcinfo, vardata.vartype);
00171
00172 if (((Const *) other)->consttype == typcache->rngelemtype->type_id)
00173 {
00174 RangeBound lower, upper;
00175 lower.inclusive = true;
00176 lower.val = ((Const *) other)->constvalue;
00177 lower.infinite = false;
00178 lower.lower = true;
00179 upper.inclusive = true;
00180 upper.val = ((Const *) other)->constvalue;
00181 upper.infinite = false;
00182 upper.lower = false;
00183 constrange = range_serialize(typcache, &lower, &upper, false);
00184 }
00185 }
00186 else
00187 {
00188 typcache = range_get_typcache(fcinfo, ((Const *) other)->consttype);
00189
00190 if (((Const *) other)->consttype == vardata.vartype)
00191 constrange = DatumGetRangeType(((Const *) other)->constvalue);
00192 }
00193
00194
00195
00196
00197
00198
00199 if (constrange)
00200 selec = calc_rangesel(typcache, &vardata, constrange, operator);
00201 else
00202 selec = default_range_selectivity(operator);
00203
00204 ReleaseVariableStats(vardata);
00205
00206 CLAMP_PROBABILITY(selec);
00207
00208 PG_RETURN_FLOAT8((float8) selec);
00209 }
00210
00211 static double
00212 calc_rangesel(TypeCacheEntry *typcache, VariableStatData *vardata,
00213 RangeType *constval, Oid operator)
00214 {
00215 double hist_selec;
00216 double selec;
00217 float4 empty_frac, null_frac;
00218
00219
00220
00221
00222 if (HeapTupleIsValid(vardata->statsTuple))
00223 {
00224 Form_pg_statistic stats;
00225 float4 *numbers;
00226 int nnumbers;
00227
00228 stats = (Form_pg_statistic) GETSTRUCT(vardata->statsTuple);
00229 null_frac = stats->stanullfrac;
00230
00231
00232 if (get_attstatsslot(vardata->statsTuple,
00233 vardata->atttype, vardata->atttypmod,
00234 STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM, InvalidOid,
00235 NULL,
00236 NULL, NULL,
00237 &numbers, &nnumbers))
00238 {
00239 if (nnumbers != 1)
00240 elog(ERROR, "invalid empty fraction statistic");
00241 empty_frac = numbers[0];
00242 }
00243 else
00244 {
00245
00246 empty_frac = 0.0;
00247 }
00248 }
00249 else
00250 {
00251
00252
00253
00254
00255
00256
00257 null_frac = 0.0;
00258 empty_frac = 0.0;
00259 }
00260
00261 if (RangeIsEmpty(constval))
00262 {
00263
00264
00265
00266
00267 switch (operator)
00268 {
00269 case OID_RANGE_OVERLAP_OP:
00270 case OID_RANGE_OVERLAPS_LEFT_OP:
00271 case OID_RANGE_OVERLAPS_RIGHT_OP:
00272 case OID_RANGE_LEFT_OP:
00273 case OID_RANGE_RIGHT_OP:
00274
00275 selec = 0.0;
00276 break;
00277
00278 case OID_RANGE_CONTAINED_OP:
00279 case OID_RANGE_LESS_EQUAL_OP:
00280 case OID_RANGE_GREATER_EQUAL_OP:
00281
00282
00283
00284
00285 selec = empty_frac;
00286 break;
00287
00288 case OID_RANGE_CONTAINS_OP:
00289
00290 selec = 1.0;
00291 break;
00292
00293 case OID_RANGE_CONTAINS_ELEM_OP:
00294 default:
00295 elog(ERROR, "unexpected operator %u", operator);
00296 selec = 0.0;
00297 break;
00298 }
00299 }
00300 else
00301 {
00302
00303
00304
00305
00306
00307
00308
00309
00310 hist_selec = calc_hist_selectivity(typcache, vardata, constval,
00311 operator);
00312 if (hist_selec < 0.0)
00313 hist_selec = default_range_selectivity(operator);
00314
00315
00316
00317
00318
00319
00320 if (operator == OID_RANGE_CONTAINED_OP)
00321 {
00322
00323 selec = (1.0 - empty_frac) * hist_selec + empty_frac;
00324 }
00325 else
00326 {
00327
00328 selec = (1.0 - empty_frac) * hist_selec;
00329 }
00330 }
00331
00332
00333 selec *= (1.0 - null_frac);
00334
00335
00336 CLAMP_PROBABILITY(selec);
00337
00338 return selec;
00339 }
00340
00341
00342
00343
00344
00345
00346
00347 static double
00348 calc_hist_selectivity(TypeCacheEntry *typcache, VariableStatData *vardata,
00349 RangeType *constval, Oid operator)
00350 {
00351 Datum *hist_values;
00352 int nhist;
00353 Datum *length_hist_values;
00354 int length_nhist;
00355 RangeBound *hist_lower;
00356 RangeBound *hist_upper;
00357 int i;
00358 RangeBound const_lower;
00359 RangeBound const_upper;
00360 bool empty;
00361 double hist_selec;
00362
00363
00364 if (!(HeapTupleIsValid(vardata->statsTuple) &&
00365 get_attstatsslot(vardata->statsTuple,
00366 vardata->atttype, vardata->atttypmod,
00367 STATISTIC_KIND_BOUNDS_HISTOGRAM, InvalidOid,
00368 NULL,
00369 &hist_values, &nhist,
00370 NULL, NULL)))
00371 return -1.0;
00372
00373
00374
00375
00376
00377 hist_lower = (RangeBound *) palloc(sizeof(RangeBound) * nhist);
00378 hist_upper = (RangeBound *) palloc(sizeof(RangeBound) * nhist);
00379 for (i = 0; i < nhist; i++)
00380 {
00381 range_deserialize(typcache, DatumGetRangeType(hist_values[i]),
00382 &hist_lower[i], &hist_upper[i], &empty);
00383
00384 if (empty)
00385 elog(ERROR, "bounds histogram contains an empty range");
00386 }
00387
00388
00389 if (operator == OID_RANGE_CONTAINS_OP ||
00390 operator == OID_RANGE_CONTAINED_OP)
00391 {
00392 if (!(HeapTupleIsValid(vardata->statsTuple) &&
00393 get_attstatsslot(vardata->statsTuple,
00394 vardata->atttype, vardata->atttypmod,
00395 STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM,
00396 InvalidOid,
00397 NULL,
00398 &length_hist_values, &length_nhist,
00399 NULL, NULL)))
00400 return -1.0;
00401
00402
00403 if (length_nhist < 2)
00404 return -1.0;
00405 }
00406
00407
00408 range_deserialize(typcache, constval, &const_lower, &const_upper, &empty);
00409 Assert (!empty);
00410
00411
00412
00413
00414
00415 switch (operator)
00416 {
00417 case OID_RANGE_LESS_OP:
00418
00419
00420
00421
00422
00423
00424
00425
00426 hist_selec =
00427 calc_hist_selectivity_scalar(typcache, &const_lower,
00428 hist_lower, nhist, false);
00429 break;
00430
00431 case OID_RANGE_LESS_EQUAL_OP:
00432 hist_selec =
00433 calc_hist_selectivity_scalar(typcache, &const_lower,
00434 hist_lower, nhist, true);
00435 break;
00436
00437 case OID_RANGE_GREATER_OP:
00438 hist_selec =
00439 1 - calc_hist_selectivity_scalar(typcache, &const_lower,
00440 hist_lower, nhist, true);
00441 break;
00442
00443 case OID_RANGE_GREATER_EQUAL_OP:
00444 hist_selec =
00445 1 - calc_hist_selectivity_scalar(typcache, &const_lower,
00446 hist_lower, nhist, false);
00447 break;
00448
00449 case OID_RANGE_LEFT_OP:
00450
00451 hist_selec =
00452 calc_hist_selectivity_scalar(typcache, &const_lower,
00453 hist_upper, nhist, false);
00454 break;
00455
00456 case OID_RANGE_RIGHT_OP:
00457
00458 hist_selec =
00459 1 - calc_hist_selectivity_scalar(typcache, &const_upper,
00460 hist_lower, nhist, true);
00461 break;
00462
00463 case OID_RANGE_OVERLAPS_RIGHT_OP:
00464
00465 hist_selec =
00466 1 - calc_hist_selectivity_scalar(typcache, &const_lower,
00467 hist_lower, nhist, false);
00468 break;
00469
00470 case OID_RANGE_OVERLAPS_LEFT_OP:
00471
00472 hist_selec =
00473 calc_hist_selectivity_scalar(typcache, &const_upper,
00474 hist_upper, nhist, true);
00475 break;
00476
00477 case OID_RANGE_OVERLAP_OP:
00478 case OID_RANGE_CONTAINS_ELEM_OP:
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489 hist_selec =
00490 calc_hist_selectivity_scalar(typcache, &const_lower, hist_upper,
00491 nhist, false);
00492 hist_selec +=
00493 (1.0 - calc_hist_selectivity_scalar(typcache, &const_upper, hist_lower,
00494 nhist, true));
00495 hist_selec = 1.0 - hist_selec;
00496 break;
00497
00498 case OID_RANGE_CONTAINS_OP:
00499 hist_selec =
00500 calc_hist_selectivity_contains(typcache, &const_lower,
00501 &const_upper, hist_lower, nhist,
00502 length_hist_values, length_nhist);
00503 break;
00504
00505 case OID_RANGE_CONTAINED_OP:
00506 if (const_lower.infinite)
00507 {
00508
00509
00510
00511
00512 hist_selec =
00513 calc_hist_selectivity_scalar(typcache, &const_upper,
00514 hist_upper, nhist, true);
00515 }
00516 else if (const_upper.infinite)
00517 {
00518 hist_selec =
00519 1.0 - calc_hist_selectivity_scalar(typcache, &const_lower,
00520 hist_lower, nhist, false);
00521 }
00522 else
00523 {
00524 hist_selec =
00525 calc_hist_selectivity_contained(typcache, &const_lower,
00526 &const_upper, hist_lower, nhist,
00527 length_hist_values, length_nhist);
00528 }
00529 break;
00530
00531 default:
00532 elog(ERROR, "unknown range operator %u", operator);
00533 hist_selec = -1.0;
00534 break;
00535 }
00536
00537 return hist_selec;
00538 }
00539
00540
00541
00542
00543
00544
00545 static double
00546 calc_hist_selectivity_scalar(TypeCacheEntry *typcache, RangeBound *constbound,
00547 RangeBound *hist, int hist_nvalues, bool equal)
00548 {
00549 Selectivity selec;
00550 int index;
00551
00552
00553
00554
00555
00556 index = rbound_bsearch(typcache, constbound, hist, hist_nvalues, equal);
00557 selec = (Selectivity) (Max(index, 0)) / (Selectivity) (hist_nvalues - 1);
00558
00559
00560 if (index >= 0 && index < hist_nvalues - 1)
00561 selec += get_position(typcache, constbound, &hist[index],
00562 &hist[index + 1]) / (Selectivity) (hist_nvalues - 1);
00563
00564 return selec;
00565 }
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577 static int
00578 rbound_bsearch(TypeCacheEntry *typcache, RangeBound *value, RangeBound *hist,
00579 int hist_length, bool equal)
00580 {
00581 int lower = -1,
00582 upper = hist_length - 1,
00583 cmp,
00584 middle;
00585
00586 while (lower < upper)
00587 {
00588 middle = (lower + upper + 1) / 2;
00589 cmp = range_cmp_bounds(typcache, &hist[middle], value);
00590
00591 if (cmp < 0 || (equal && cmp == 0))
00592 lower = middle;
00593 else
00594 upper = middle - 1;
00595 }
00596 return lower;
00597 }
00598
00599
00600
00601
00602
00603
00604
00605
00606 static int
00607 length_hist_bsearch(Datum *length_hist_values, int length_hist_nvalues,
00608 double value, bool equal)
00609 {
00610 int lower = -1,
00611 upper = length_hist_nvalues - 1,
00612 middle;
00613
00614 while (lower < upper)
00615 {
00616 double middleval;
00617
00618 middle = (lower + upper + 1) / 2;
00619
00620 middleval = DatumGetFloat8(length_hist_values[middle]);
00621 if (middleval < value || (equal && middleval <= value))
00622 lower = middle;
00623 else
00624 upper = middle - 1;
00625 }
00626 return lower;
00627 }
00628
00629
00630
00631
00632 static float8
00633 get_position(TypeCacheEntry *typcache, RangeBound *value, RangeBound *hist1,
00634 RangeBound *hist2)
00635 {
00636 bool has_subdiff = OidIsValid(typcache->rng_subdiff_finfo.fn_oid);
00637 float8 position;
00638
00639 if (!hist1->infinite && !hist2->infinite)
00640 {
00641 float8 bin_width;
00642
00643
00644
00645
00646
00647
00648 if (value->infinite)
00649 return 0.5;
00650
00651
00652 if (!has_subdiff)
00653 return 0.5;
00654
00655
00656 bin_width = DatumGetFloat8(FunctionCall2Coll(
00657 &typcache->rng_subdiff_finfo,
00658 typcache->rng_collation,
00659 hist2->val,
00660 hist1->val));
00661 if (bin_width <= 0.0)
00662 return 0.5;
00663
00664 position = DatumGetFloat8(FunctionCall2Coll(
00665 &typcache->rng_subdiff_finfo,
00666 typcache->rng_collation,
00667 value->val,
00668 hist1->val))
00669 / bin_width;
00670
00671
00672 position = Max(position, 0.0);
00673 position = Min(position, 1.0);
00674 return position;
00675 }
00676 else if (hist1->infinite && !hist2->infinite)
00677 {
00678
00679
00680
00681
00682
00683
00684 return ((value->infinite && value->lower) ? 0.0 : 1.0);
00685 }
00686 else if (!hist1->infinite && hist2->infinite)
00687 {
00688
00689 return ((value->infinite && !value->lower) ? 1.0 : 0.0);
00690 }
00691 else
00692 {
00693
00694
00695
00696
00697
00698
00699
00700
00701 return 0.5;
00702 }
00703 }
00704
00705
00706
00707
00708
00709 static double
00710 get_len_position(double value, double hist1, double hist2)
00711 {
00712 if (!is_infinite(hist1) && !is_infinite(hist2))
00713 {
00714
00715
00716
00717
00718
00719 if (is_infinite(value))
00720 return 0.5;
00721
00722 return 1.0 - (hist2 - value) / (hist2 - hist1);
00723 }
00724 else if (is_infinite(hist1) && !is_infinite(hist2))
00725 {
00726
00727
00728
00729
00730
00731 return 1.0;
00732 }
00733 else if (is_infinite(hist1) && is_infinite(hist2))
00734 {
00735
00736 return 0.0;
00737 }
00738 else
00739 {
00740
00741
00742
00743
00744
00745
00746
00747
00748 return 0.5;
00749 }
00750 }
00751
00752
00753
00754
00755 static float8
00756 get_distance(TypeCacheEntry *typcache, RangeBound *bound1, RangeBound *bound2)
00757 {
00758 bool has_subdiff = OidIsValid(typcache->rng_subdiff_finfo.fn_oid);
00759
00760 if (!bound1->infinite && !bound2->infinite)
00761 {
00762
00763
00764
00765
00766 if (has_subdiff)
00767 return
00768 DatumGetFloat8(FunctionCall2Coll(&typcache->rng_subdiff_finfo,
00769 typcache->rng_collation,
00770 bound2->val,
00771 bound1->val));
00772 else
00773 return 1.0;
00774 }
00775 else if (bound1->infinite && bound2->infinite)
00776 {
00777
00778 if (bound1->lower == bound2->lower)
00779 return 0.0;
00780 else
00781 return get_float8_infinity();
00782 }
00783 else
00784 {
00785
00786 return get_float8_infinity();
00787 }
00788 }
00789
00790
00791
00792
00793
00794
00795 static double
00796 calc_length_hist_frac(Datum *length_hist_values, int length_hist_nvalues,
00797 double length1, double length2, bool equal)
00798 {
00799 double frac;
00800 double A, B, PA, PB;
00801 double pos;
00802 int i;
00803 double area;
00804
00805 Assert(length2 >= length1);
00806
00807 if (length2 < 0.0)
00808 return 0.0;
00809
00810
00811 if (is_infinite(length2) && equal)
00812 return 1.0;
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853 i = length_hist_bsearch(length_hist_values, length_hist_nvalues, length1, equal);
00854 if (i >= length_hist_nvalues - 1)
00855 return 1.0;
00856
00857 if (i < 0)
00858 {
00859 i = 0;
00860 pos = 0.0;
00861 }
00862 else
00863 {
00864
00865 pos = get_len_position(length1,
00866 DatumGetFloat8(length_hist_values[i]),
00867 DatumGetFloat8(length_hist_values[i + 1]));
00868 }
00869 PB = (((double) i) + pos) / (double) (length_hist_nvalues - 1);
00870 B = length1;
00871
00872
00873
00874
00875
00876
00877 if (length2 == length1)
00878 return PB;
00879
00880
00881
00882
00883
00884
00885 area = 0.0;
00886 for (; i < length_hist_nvalues - 1; i++)
00887 {
00888 double bin_upper = DatumGetFloat8(length_hist_values[i + 1]);
00889
00890
00891 if (!(bin_upper < length2 || (equal && bin_upper <= length2)))
00892 break;
00893
00894
00895 A = B; PA = PB;
00896
00897 B = bin_upper;
00898 PB = (double) i / (double) (length_hist_nvalues - 1);
00899
00900
00901
00902
00903
00904
00905
00906 if (PA > 0 || PB > 0)
00907 area += 0.5 * (PB + PA) * (B - A);
00908 }
00909
00910
00911 A = B; PA = PB;
00912
00913 B = length2;
00914 if (i >= length_hist_nvalues - 1)
00915 pos = 0.0;
00916 else
00917 {
00918 if (DatumGetFloat8(length_hist_values[i]) == DatumGetFloat8(length_hist_values[i + 1]))
00919 pos = 0.0;
00920 else
00921 pos = get_len_position(length2, DatumGetFloat8(length_hist_values[i]), DatumGetFloat8(length_hist_values[i + 1]));
00922 }
00923 PB = (((double) i) + pos) / (double) (length_hist_nvalues - 1);
00924
00925 if (PA > 0 || PB > 0)
00926 area += 0.5 * (PB + PA) * (B - A);
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936 if (is_infinite(area) && is_infinite(length2))
00937 frac = 0.5;
00938 else
00939 frac = area / (length2 - length1);
00940
00941 return frac;
00942 }
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953 static double
00954 calc_hist_selectivity_contained(TypeCacheEntry *typcache,
00955 RangeBound *lower, RangeBound *upper,
00956 RangeBound *hist_lower, int hist_nvalues,
00957 Datum *length_hist_values, int length_hist_nvalues)
00958 {
00959 int i,
00960 upper_index;
00961 float8 prev_dist;
00962 double bin_width;
00963 double upper_bin_width;
00964 double sum_frac;
00965
00966
00967
00968
00969
00970
00971 upper->inclusive = !upper->inclusive;
00972 upper->lower = true;
00973 upper_index = rbound_bsearch(typcache, upper, hist_lower, hist_nvalues,
00974 false);
00975
00976
00977
00978
00979
00980
00981 if (upper_index >= 0 && upper_index < hist_nvalues - 1)
00982 upper_bin_width = get_position(typcache, upper,
00983 &hist_lower[upper_index],
00984 &hist_lower[upper_index + 1]);
00985 else
00986 upper_bin_width = 0.0;
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997 prev_dist = 0.0;
00998 bin_width = upper_bin_width;
00999
01000 sum_frac = 0.0;
01001 for (i = upper_index; i >= 0; i--)
01002 {
01003 double dist;
01004 double length_hist_frac;
01005 bool final_bin = false;
01006
01007
01008
01009
01010
01011
01012
01013 if (range_cmp_bounds(typcache, &hist_lower[i], lower) < 0)
01014 {
01015 dist = get_distance(typcache, lower, upper);
01016
01017
01018
01019
01020 bin_width -= get_position(typcache, lower, &hist_lower[i],
01021 &hist_lower[i + 1]);
01022 if (bin_width < 0.0)
01023 bin_width = 0.0;
01024 final_bin = true;
01025 }
01026 else
01027 dist = get_distance(typcache, &hist_lower[i], upper);
01028
01029
01030
01031
01032
01033 length_hist_frac = calc_length_hist_frac(length_hist_values,
01034 length_hist_nvalues,
01035 prev_dist, dist, true);
01036
01037
01038
01039
01040
01041 sum_frac += length_hist_frac * bin_width / (double) (hist_nvalues - 1);
01042
01043 if (final_bin)
01044 break;
01045
01046 bin_width = 1.0;
01047 prev_dist = dist;
01048 }
01049
01050 return sum_frac;
01051 }
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062 static double
01063 calc_hist_selectivity_contains(TypeCacheEntry *typcache,
01064 RangeBound *lower, RangeBound *upper,
01065 RangeBound *hist_lower, int hist_nvalues,
01066 Datum *length_hist_values, int length_hist_nvalues)
01067 {
01068 int i,
01069 lower_index;
01070 double bin_width,
01071 lower_bin_width;
01072 double sum_frac;
01073 float8 prev_dist;
01074
01075
01076 lower_index = rbound_bsearch(typcache, lower, hist_lower, hist_nvalues,
01077 true);
01078
01079
01080
01081
01082
01083
01084 if (lower_index >= 0 && lower_index < hist_nvalues - 1)
01085 lower_bin_width = get_position(typcache, lower, &hist_lower[lower_index],
01086 &hist_lower[lower_index + 1]);
01087 else
01088 lower_bin_width = 0.0;
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102 prev_dist = get_distance(typcache, lower, upper);
01103 sum_frac = 0.0;
01104 bin_width = lower_bin_width;
01105 for (i = lower_index; i >= 0; i--)
01106 {
01107 float8 dist;
01108 double length_hist_frac;
01109
01110
01111
01112
01113
01114
01115 dist = get_distance(typcache, &hist_lower[i], upper);
01116
01117
01118
01119
01120
01121 length_hist_frac =
01122 1.0 - calc_length_hist_frac(length_hist_values,
01123 length_hist_nvalues,
01124 prev_dist, dist, false);
01125
01126 sum_frac += length_hist_frac * bin_width / (double) (hist_nvalues - 1);
01127
01128 bin_width = 1.0;
01129 prev_dist = dist;
01130 }
01131
01132 return sum_frac;
01133 }