00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "postgres.h"
00026
00027 #include "catalog/pg_operator.h"
00028 #include "commands/vacuum.h"
00029 #include "utils/builtins.h"
00030 #include "utils/rangetypes.h"
00031
00032 static int float8_qsort_cmp(const void *a1, const void *a2);
00033 static int range_bound_qsort_cmp(const void *a1, const void *a2, void *arg);
00034 static void compute_range_stats(VacAttrStats *stats,
00035 AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows);
00036
00037
00038
00039
00040 Datum
00041 range_typanalyze(PG_FUNCTION_ARGS)
00042 {
00043 VacAttrStats *stats = (VacAttrStats *) PG_GETARG_POINTER(0);
00044 TypeCacheEntry *typcache;
00045 Form_pg_attribute attr = stats->attr;
00046
00047
00048 typcache = range_get_typcache(fcinfo, stats->attrtypid);
00049
00050 if (attr->attstattarget < 0)
00051 attr->attstattarget = default_statistics_target;
00052
00053 stats->compute_stats = compute_range_stats;
00054 stats->extra_data = typcache;
00055
00056 stats->minrows = 300 * attr->attstattarget;
00057
00058 PG_RETURN_BOOL(true);
00059 }
00060
00061
00062
00063
00064 static int
00065 float8_qsort_cmp(const void *a1, const void *a2)
00066 {
00067 const float8 *f1 = (const float8 *) a1;
00068 const float8 *f2 = (const float8 *) a2;
00069
00070 if (*f1 < *f2)
00071 return -1;
00072 else if (*f1 == *f2)
00073 return 0;
00074 else
00075 return 1;
00076 }
00077
00078
00079
00080
00081 static int
00082 range_bound_qsort_cmp(const void *a1, const void *a2, void *arg)
00083 {
00084 RangeBound *b1 = (RangeBound *)a1;
00085 RangeBound *b2 = (RangeBound *)a2;
00086 TypeCacheEntry *typcache = (TypeCacheEntry *)arg;
00087
00088 return range_cmp_bounds(typcache, b1, b2);
00089 }
00090
00091
00092
00093
00094 static void
00095 compute_range_stats(VacAttrStats *stats, AnalyzeAttrFetchFunc fetchfunc,
00096 int samplerows, double totalrows)
00097 {
00098 TypeCacheEntry *typcache = (TypeCacheEntry *) stats->extra_data;
00099 bool has_subdiff = OidIsValid(typcache->rng_subdiff_finfo.fn_oid);
00100 int null_cnt = 0;
00101 int non_null_cnt = 0;
00102 int non_empty_cnt = 0;
00103 int empty_cnt = 0;
00104 int range_no;
00105 int slot_idx;
00106 int num_bins = stats->attr->attstattarget;
00107 int num_hist;
00108 float8 *lengths;
00109 RangeBound *lowers, *uppers;
00110 double total_width = 0;
00111
00112
00113 lowers = (RangeBound *) palloc(sizeof(RangeBound) * samplerows);
00114 uppers = (RangeBound *) palloc(sizeof(RangeBound) * samplerows);
00115 lengths = (float8 *) palloc(sizeof(float8) * samplerows);
00116
00117
00118 for (range_no = 0; range_no < samplerows; range_no++)
00119 {
00120 Datum value;
00121 bool isnull,
00122 empty;
00123 RangeType *range;
00124 RangeBound lower,
00125 upper;
00126 float8 length;
00127
00128 vacuum_delay_point();
00129
00130 value = fetchfunc(stats, range_no, &isnull);
00131 if (isnull)
00132 {
00133
00134 null_cnt++;
00135 continue;
00136 }
00137
00138
00139
00140
00141
00142 total_width += VARSIZE_ANY(DatumGetPointer(value));
00143
00144
00145 range = DatumGetRangeType(value);
00146 range_deserialize(typcache, range, &lower, &upper, &empty);
00147
00148 if (!empty)
00149 {
00150
00151 lowers[non_empty_cnt] = lower;
00152 uppers[non_empty_cnt] = upper;
00153
00154 if (lower.infinite || upper.infinite)
00155 {
00156
00157 length = get_float8_infinity();
00158 }
00159 else if (has_subdiff)
00160 {
00161
00162
00163
00164
00165 length = DatumGetFloat8(FunctionCall2Coll(
00166 &typcache->rng_subdiff_finfo,
00167 typcache->rng_collation,
00168 upper.val, lower.val));
00169 }
00170 else
00171 {
00172
00173 length = 1.0;
00174 }
00175 lengths[non_empty_cnt] = length;
00176
00177 non_empty_cnt++;
00178 }
00179 else
00180 empty_cnt++;
00181
00182 non_null_cnt++;
00183 }
00184
00185 slot_idx = 0;
00186
00187
00188 if (non_null_cnt > 0)
00189 {
00190 Datum *bound_hist_values;
00191 Datum *length_hist_values;
00192 int pos,
00193 posfrac,
00194 delta,
00195 deltafrac,
00196 i;
00197 MemoryContext old_cxt;
00198 float4 *emptyfrac;
00199
00200 stats->stats_valid = true;
00201
00202 stats->stanullfrac = (double) null_cnt / (double) samplerows;
00203 stats->stawidth = total_width / (double) non_null_cnt;
00204 stats->stadistinct = -1.0;
00205
00206
00207 old_cxt = MemoryContextSwitchTo(stats->anl_context);
00208
00209
00210
00211
00212
00213 if (non_empty_cnt >= 2)
00214 {
00215
00216 qsort_arg(lowers, non_empty_cnt, sizeof(RangeBound),
00217 range_bound_qsort_cmp, typcache);
00218 qsort_arg(uppers, non_empty_cnt, sizeof(RangeBound),
00219 range_bound_qsort_cmp, typcache);
00220
00221 num_hist = non_empty_cnt;
00222 if (num_hist > num_bins)
00223 num_hist = num_bins + 1;
00224
00225 bound_hist_values = (Datum *) palloc(num_hist * sizeof(Datum));
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238 delta = (non_empty_cnt - 1) / (num_hist - 1);
00239 deltafrac = (non_empty_cnt - 1) % (num_hist - 1);
00240 pos = posfrac = 0;
00241
00242 for (i = 0; i < num_hist; i++)
00243 {
00244 bound_hist_values[i] = PointerGetDatum(range_serialize(
00245 typcache, &lowers[pos], &uppers[pos], false));
00246 pos += delta;
00247 posfrac += deltafrac;
00248 if (posfrac >= (num_hist - 1))
00249 {
00250
00251 pos++;
00252 posfrac -= (num_hist - 1);
00253 }
00254 }
00255
00256 stats->stakind[slot_idx] = STATISTIC_KIND_BOUNDS_HISTOGRAM;
00257 stats->stavalues[slot_idx] = bound_hist_values;
00258 stats->numvalues[slot_idx] = num_hist;
00259 slot_idx++;
00260 }
00261
00262
00263
00264
00265
00266 if (non_empty_cnt >= 2)
00267 {
00268
00269
00270
00271
00272 qsort(lengths, non_empty_cnt, sizeof(float8), float8_qsort_cmp);
00273
00274 num_hist = non_empty_cnt;
00275 if (num_hist > num_bins)
00276 num_hist = num_bins + 1;
00277
00278 length_hist_values = (Datum *) palloc(num_hist * sizeof(Datum));
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289 delta = (non_empty_cnt - 1) / (num_hist - 1);
00290 deltafrac = (non_empty_cnt - 1) % (num_hist - 1);
00291 pos = posfrac = 0;
00292
00293 for (i = 0; i < num_hist; i++)
00294 {
00295 length_hist_values[i] = Float8GetDatum(lengths[pos]);
00296 pos += delta;
00297 posfrac += deltafrac;
00298 if (posfrac >= (num_hist - 1))
00299 {
00300
00301 pos++;
00302 posfrac -= (num_hist - 1);
00303 }
00304 }
00305 }
00306 else
00307 {
00308
00309
00310
00311
00312
00313
00314 length_hist_values = palloc(0);
00315 num_hist = 0;
00316 }
00317 stats->staop[slot_idx] = Float8LessOperator;
00318 stats->stavalues[slot_idx] = length_hist_values;
00319 stats->numvalues[slot_idx] = num_hist;
00320 stats->statypid[slot_idx] = FLOAT8OID;
00321 stats->statyplen[slot_idx] = sizeof(float8);
00322 #ifdef USE_FLOAT8_BYVAL
00323 stats->statypbyval[slot_idx] = true;
00324 #else
00325 stats->statypbyval[slot_idx] = false;
00326 #endif
00327 stats->statypalign[slot_idx] = 'd';
00328
00329
00330 emptyfrac = (float4 *) palloc(sizeof(float4));
00331 *emptyfrac = ((double) empty_cnt) / ((double) non_null_cnt);
00332 stats->stanumbers[slot_idx] = emptyfrac;
00333 stats->numnumbers[slot_idx] = 1;
00334
00335 stats->stakind[slot_idx] = STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM;
00336 slot_idx++;
00337
00338 MemoryContextSwitchTo(old_cxt);
00339 }
00340 else if (null_cnt > 0)
00341 {
00342
00343 stats->stats_valid = true;
00344 stats->stanullfrac = 1.0;
00345 stats->stawidth = 0;
00346 stats->stadistinct = 0.0;
00347 }
00348
00349
00350
00351
00352 }