Coverage Report

Created: 2026-11-09 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/statistics/extended_stats.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * extended_stats.c
4
 *    POSTGRES extended statistics
5
 *
6
 * Generic code supporting statistics objects created via CREATE STATISTICS.
7
 *
8
 *
9
 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
10
 * Portions Copyright (c) 1994, Regents of the University of California
11
 *
12
 * IDENTIFICATION
13
 *    src/backend/statistics/extended_stats.c
14
 *
15
 *-------------------------------------------------------------------------
16
 */
17
#include "postgres.h"
18
19
#include "access/detoast.h"
20
#include "access/genam.h"
21
#include "access/htup_details.h"
22
#include "access/table.h"
23
#include "catalog/indexing.h"
24
#include "catalog/pg_statistic_ext.h"
25
#include "catalog/pg_statistic_ext_data.h"
26
#include "commands/defrem.h"
27
#include "commands/progress.h"
28
#include "executor/executor.h"
29
#include "miscadmin.h"
30
#include "nodes/nodeFuncs.h"
31
#include "optimizer/optimizer.h"
32
#include "parser/parsetree.h"
33
#include "pgstat.h"
34
#include "postmaster/autovacuum.h"
35
#include "rewrite/rewriteHandler.h"
36
#include "statistics/extended_stats_internal.h"
37
#include "statistics/statistics.h"
38
#include "utils/acl.h"
39
#include "utils/array.h"
40
#include "utils/attoptcache.h"
41
#include "utils/builtins.h"
42
#include "utils/datum.h"
43
#include "utils/fmgroids.h"
44
#include "utils/lsyscache.h"
45
#include "utils/memutils.h"
46
#include "utils/rel.h"
47
#include "utils/selfuncs.h"
48
#include "utils/syscache.h"
49
50
/*
51
 * To avoid consuming too much memory during analysis and/or too much space
52
 * in the resulting pg_statistic rows, we ignore varlena datums that are wider
53
 * than WIDTH_THRESHOLD (after detoasting!).  This is legitimate for MCV
54
 * and distinct-value calculations since a wide value is unlikely to be
55
 * duplicated at all, much less be a most-common value.  For the same reason,
56
 * ignoring wide values will not affect our estimates of histogram bin
57
 * boundaries very much.
58
 */
59
0
#define WIDTH_THRESHOLD  1024
60
61
/*
62
 * Used internally to refer to an individual statistics object, i.e.,
63
 * a pg_statistic_ext entry.
64
 */
65
typedef struct StatExtEntry
66
{
67
  Oid     statOid;    /* OID of pg_statistic_ext entry */
68
  char     *schema;     /* statistics object's schema */
69
  char     *name;     /* statistics object's name */
70
  Bitmapset  *columns;    /* attribute numbers covered by the object */
71
  List     *types;      /* 'char' list of enabled statistics kinds */
72
  int     stattarget;   /* statistics target (-1 for default) */
73
  List     *exprs;      /* expressions */
74
} StatExtEntry;
75
76
77
static List *fetch_statentries_for_relation(Relation pg_statext, Relation rel);
78
static VacAttrStats **lookup_var_attr_stats(Bitmapset *attrs, List *exprs,
79
                      int nvacatts, VacAttrStats **vacatts);
80
static void statext_store(Oid statOid, bool inh,
81
              MVNDistinct *ndistinct, MVDependencies *dependencies,
82
              MCVList *mcv, Datum exprs, VacAttrStats **stats);
83
static int  statext_compute_stattarget(int stattarget,
84
                     int nattrs, VacAttrStats **stats);
85
86
/* Information needed to analyze a single simple expression. */
87
typedef struct AnlExprData
88
{
89
  Node     *expr;     /* expression to analyze */
90
  VacAttrStats *vacattrstat;  /* statistics attrs to analyze */
91
} AnlExprData;
92
93
static void compute_expr_stats(Relation onerel, AnlExprData *exprdata,
94
                 int nexprs, HeapTuple *rows, int numrows);
95
static Datum serialize_expr_stats(AnlExprData *exprdata, int nexprs);
96
static Datum expr_fetch_func(VacAttrStatsP stats, int rownum, bool *isNull);
97
static AnlExprData *build_expr_data(List *exprs, int stattarget);
98
99
static StatsBuildData *make_build_data(Relation rel, StatExtEntry *stat,
100
                     int numrows, HeapTuple *rows,
101
                     VacAttrStats **stats, int stattarget);
102
103
static inline void
104
report_ext_stats_not_computed(Relation onerel, StatExtEntry *stat)
105
{
106
  if (!AmAutoVacuumWorkerProcess())
107
    ereport(WARNING,
108
        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
109
         errmsg("statistics object \"%s.%s\" could not be computed for relation \"%s.%s\"",
110
            stat->schema, stat->name,
111
            get_namespace_name(onerel->rd_rel->relnamespace),
112
            RelationGetRelationName(onerel)),
113
         errtable(onerel)));
114
}
115
116
/*
117
 * Compute requested extended stats, using the rows sampled for the plain
118
 * (single-column) stats.
119
 *
120
 * This fetches a list of stats types from pg_statistic_ext, computes the
121
 * requested stats, and serializes them back into the catalog.
122
 */
123
void
124
BuildRelationExtStatistics(Relation onerel, bool inh, double totalrows,
125
               int numrows, HeapTuple *rows,
126
               int natts, VacAttrStats **vacattrstats)
127
0
{
128
0
  Relation  pg_stext;
129
0
  ListCell   *lc;
130
0
  List     *statslist;
131
0
  MemoryContext cxt;
132
0
  MemoryContext oldcxt;
133
0
  int64   ext_cnt;
134
135
  /* Do nothing if there are no columns to analyze. */
136
0
  if (!natts)
137
0
    return;
138
139
  /* the list of stats has to be allocated outside the memory context */
140
0
  pg_stext = table_open(StatisticExtRelationId, RowExclusiveLock);
141
0
  statslist = fetch_statentries_for_relation(pg_stext, onerel);
142
143
  /* memory context for building each statistics object */
144
0
  cxt = AllocSetContextCreate(CurrentMemoryContext,
145
0
                "BuildRelationExtStatistics",
146
0
                ALLOCSET_DEFAULT_SIZES);
147
0
  oldcxt = MemoryContextSwitchTo(cxt);
148
149
  /* report this phase */
150
0
  if (statslist != NIL)
151
0
  {
152
0
    const int index[] = {
153
0
      PROGRESS_ANALYZE_PHASE,
154
0
      PROGRESS_ANALYZE_EXT_STATS_TOTAL
155
0
    };
156
0
    const int64 val[] = {
157
0
      PROGRESS_ANALYZE_PHASE_COMPUTE_EXT_STATS,
158
0
      list_length(statslist)
159
0
    };
160
161
0
    pgstat_progress_update_multi_param(2, index, val);
162
0
  }
163
164
0
  ext_cnt = 0;
165
0
  foreach(lc, statslist)
166
0
  {
167
0
    StatExtEntry *stat = (StatExtEntry *) lfirst(lc);
168
0
    MVNDistinct *ndistinct = NULL;
169
0
    MVDependencies *dependencies = NULL;
170
0
    MCVList    *mcv = NULL;
171
0
    Datum   exprstats = (Datum) 0;
172
0
    VacAttrStats **stats;
173
0
    ListCell   *lc2;
174
0
    int     stattarget;
175
0
    StatsBuildData *data;
176
177
    /*
178
     * Check if we can build these stats based on the column analyzed. If
179
     * not, report this fact (except in autovacuum) and move on.
180
     */
181
0
    stats = lookup_var_attr_stats(stat->columns, stat->exprs,
182
0
                    natts, vacattrstats);
183
0
    if (!stats)
184
0
    {
185
0
      report_ext_stats_not_computed(onerel, stat);
186
0
      continue;
187
0
    }
188
189
    /* compute statistics target for this statistics object */
190
0
    stattarget = statext_compute_stattarget(stat->stattarget,
191
0
                        bms_num_members(stat->columns),
192
0
                        stats);
193
194
    /*
195
     * Don't rebuild statistics objects with statistics target set to 0
196
     * (we just leave the existing values around, just like we do for
197
     * regular per-column statistics).
198
     */
199
0
    if (stattarget == 0)
200
0
      continue;
201
202
    /* evaluate expressions (if the statistics object has any) */
203
0
    data = make_build_data(onerel, stat, numrows, rows, stats, stattarget);
204
0
    if (!data)
205
0
    {
206
0
      report_ext_stats_not_computed(onerel, stat);
207
0
      continue;
208
0
    }
209
210
    /* compute statistic of each requested type */
211
0
    foreach(lc2, stat->types)
212
0
    {
213
0
      char    t = (char) lfirst_int(lc2);
214
215
0
      if (t == STATS_EXT_NDISTINCT)
216
0
        ndistinct = statext_ndistinct_build(totalrows, data);
217
0
      else if (t == STATS_EXT_DEPENDENCIES)
218
0
        dependencies = statext_dependencies_build(data);
219
0
      else if (t == STATS_EXT_MCV)
220
0
        mcv = statext_mcv_build(data, totalrows, stattarget);
221
0
      else if (t == STATS_EXT_EXPRESSIONS)
222
0
      {
223
0
        AnlExprData *exprdata;
224
0
        int     nexprs;
225
226
        /* should not happen, thanks to checks when defining stats */
227
0
        if (!stat->exprs)
228
0
          elog(ERROR, "requested expression stats, but there are no expressions");
229
230
0
        exprdata = build_expr_data(stat->exprs, stattarget);
231
0
        if (!exprdata)
232
0
        {
233
0
          report_ext_stats_not_computed(onerel, stat);
234
0
          data = NULL;
235
0
          break;
236
0
        }
237
0
        nexprs = list_length(stat->exprs);
238
239
0
        compute_expr_stats(onerel, exprdata, nexprs, rows, numrows);
240
241
0
        exprstats = serialize_expr_stats(exprdata, nexprs);
242
0
      }
243
0
    }
244
245
0
    if (!data)
246
0
      continue;
247
248
    /* store the statistics in the catalog */
249
0
    statext_store(stat->statOid, inh,
250
0
            ndistinct, dependencies, mcv, exprstats, stats);
251
252
    /* for reporting progress */
253
0
    pgstat_progress_update_param(PROGRESS_ANALYZE_EXT_STATS_COMPUTED,
254
0
                   ++ext_cnt);
255
256
    /* free the data used for building this statistics object */
257
0
    MemoryContextReset(cxt);
258
0
  }
259
260
0
  MemoryContextSwitchTo(oldcxt);
261
0
  MemoryContextDelete(cxt);
262
263
0
  list_free(statslist);
264
265
0
  table_close(pg_stext, RowExclusiveLock);
266
0
}
267
268
/*
269
 * Test if the given relation has extended statistics objects.
270
 */
271
bool
272
HasRelationExtStatistics(Relation onerel)
273
0
{
274
0
  Relation  pg_statext;
275
0
  SysScanDesc scan;
276
0
  ScanKeyData skey;
277
0
  bool    found;
278
279
0
  pg_statext = table_open(StatisticExtRelationId, RowExclusiveLock);
280
281
  /*
282
   * Prepare to scan pg_statistic_ext for entries having stxrelid = this
283
   * rel.
284
   */
285
0
  ScanKeyInit(&skey,
286
0
        Anum_pg_statistic_ext_stxrelid,
287
0
        BTEqualStrategyNumber, F_OIDEQ,
288
0
        ObjectIdGetDatum(RelationGetRelid(onerel)));
289
290
0
  scan = systable_beginscan(pg_statext, StatisticExtRelidIndexId, true,
291
0
                NULL, 1, &skey);
292
293
0
  found = HeapTupleIsValid(systable_getnext(scan));
294
295
0
  systable_endscan(scan);
296
297
0
  table_close(pg_statext, RowExclusiveLock);
298
299
0
  return found;
300
0
}
301
302
/*
303
 * ComputeExtStatisticsRows
304
 *    Compute number of rows required by extended statistics on a table.
305
 *
306
 * Computes number of rows we need to sample to build extended statistics on a
307
 * table. This only looks at statistics we can actually build - for example
308
 * when analyzing only some of the columns, this will skip statistics objects
309
 * that would require additional columns.
310
 *
311
 * See statext_compute_stattarget for details about how we compute the
312
 * statistics target for a statistics object (from the object target,
313
 * attribute targets and default statistics target).
314
 */
315
int
316
ComputeExtStatisticsRows(Relation onerel,
317
             int natts, VacAttrStats **vacattrstats)
318
0
{
319
0
  Relation  pg_stext;
320
0
  ListCell   *lc;
321
0
  List     *lstats;
322
0
  MemoryContext cxt;
323
0
  MemoryContext oldcxt;
324
0
  int     result = 0;
325
326
  /* If there are no columns to analyze, just return 0. */
327
0
  if (!natts)
328
0
    return 0;
329
330
0
  cxt = AllocSetContextCreate(CurrentMemoryContext,
331
0
                "ComputeExtStatisticsRows",
332
0
                ALLOCSET_DEFAULT_SIZES);
333
0
  oldcxt = MemoryContextSwitchTo(cxt);
334
335
0
  pg_stext = table_open(StatisticExtRelationId, RowExclusiveLock);
336
0
  lstats = fetch_statentries_for_relation(pg_stext, onerel);
337
338
0
  foreach(lc, lstats)
339
0
  {
340
0
    StatExtEntry *stat = (StatExtEntry *) lfirst(lc);
341
0
    int     stattarget;
342
0
    VacAttrStats **stats;
343
0
    int     nattrs = bms_num_members(stat->columns);
344
345
    /*
346
     * Check if we can build this statistics object based on the columns
347
     * analyzed. If not, ignore it (don't report anything, we'll do that
348
     * during the actual build BuildRelationExtStatistics).
349
     */
350
0
    stats = lookup_var_attr_stats(stat->columns, stat->exprs,
351
0
                    natts, vacattrstats);
352
353
0
    if (!stats)
354
0
      continue;
355
356
    /*
357
     * Compute statistics target, based on what's set for the statistic
358
     * object itself, and for its attributes.
359
     */
360
0
    stattarget = statext_compute_stattarget(stat->stattarget,
361
0
                        nattrs, stats);
362
363
    /* Use the largest value for all statistics objects. */
364
0
    if (stattarget > result)
365
0
      result = stattarget;
366
0
  }
367
368
0
  table_close(pg_stext, RowExclusiveLock);
369
370
0
  MemoryContextSwitchTo(oldcxt);
371
0
  MemoryContextDelete(cxt);
372
373
  /* compute sample size based on the statistics target */
374
0
  return (300 * result);
375
0
}
376
377
/*
378
 * statext_compute_stattarget
379
 *    compute statistics target for an extended statistic
380
 *
381
 * When computing target for extended statistics objects, we consider three
382
 * places where the target may be set - the statistics object itself,
383
 * attributes the statistics object is defined on, and then the default
384
 * statistics target.
385
 *
386
 * First we look at what's set for the statistics object itself, using the
387
 * ALTER STATISTICS ... SET STATISTICS command. If we find a valid value
388
 * there (i.e. not -1) we're done. Otherwise we look at targets set for any
389
 * of the attributes the statistic is defined on, and if there are columns
390
 * with defined target, we use the maximum value. We do this mostly for
391
 * backwards compatibility, because this is what we did before having
392
 * statistics target for extended statistics.
393
 *
394
 * And finally, if we still don't have a statistics target, we use the value
395
 * set in default_statistics_target.
396
 */
397
static int
398
statext_compute_stattarget(int stattarget, int nattrs, VacAttrStats **stats)
399
0
{
400
0
  int     i;
401
402
  /*
403
   * If there's statistics target set for the statistics object, use it. It
404
   * may be set to 0 which disables building of that statistic.
405
   */
406
0
  if (stattarget >= 0)
407
0
    return stattarget;
408
409
  /*
410
   * The target for the statistics object is set to -1, in which case we
411
   * look at the maximum target set for any of the attributes the object is
412
   * defined on.
413
   */
414
0
  for (i = 0; i < nattrs; i++)
415
0
  {
416
    /* keep the maximum statistics target */
417
0
    if (stats[i]->attstattarget > stattarget)
418
0
      stattarget = stats[i]->attstattarget;
419
0
  }
420
421
  /*
422
   * If the value is still negative (so neither the statistics object nor
423
   * any of the columns have custom statistics target set), use the global
424
   * default target.
425
   */
426
0
  if (stattarget < 0)
427
0
    stattarget = default_statistics_target;
428
429
  /* As this point we should have a valid statistics target. */
430
0
  Assert((stattarget >= 0) && (stattarget <= MAX_STATISTICS_TARGET));
431
432
0
  return stattarget;
433
0
}
434
435
/*
436
 * statext_is_kind_built
437
 *    Is this stat kind built in the given pg_statistic_ext_data tuple?
438
 */
439
bool
440
statext_is_kind_built(HeapTuple htup, char type)
441
0
{
442
0
  AttrNumber  attnum;
443
444
0
  switch (type)
445
0
  {
446
0
    case STATS_EXT_NDISTINCT:
447
0
      attnum = Anum_pg_statistic_ext_data_stxdndistinct;
448
0
      break;
449
450
0
    case STATS_EXT_DEPENDENCIES:
451
0
      attnum = Anum_pg_statistic_ext_data_stxddependencies;
452
0
      break;
453
454
0
    case STATS_EXT_MCV:
455
0
      attnum = Anum_pg_statistic_ext_data_stxdmcv;
456
0
      break;
457
458
0
    case STATS_EXT_EXPRESSIONS:
459
0
      attnum = Anum_pg_statistic_ext_data_stxdexpr;
460
0
      break;
461
462
0
    default:
463
0
      elog(ERROR, "unexpected statistics type requested: %d", type);
464
0
  }
465
466
0
  return !heap_attisnull(htup, attnum, NULL);
467
0
}
468
469
/*
470
 * Return a list (of StatExtEntry) of statistics objects for the given relation.
471
 */
472
static List *
473
fetch_statentries_for_relation(Relation pg_statext, Relation rel)
474
0
{
475
0
  SysScanDesc scan;
476
0
  ScanKeyData skey;
477
0
  HeapTuple htup;
478
0
  List     *result = NIL;
479
0
  Oid     relid = RelationGetRelid(rel);
480
481
  /*
482
   * Prepare to scan pg_statistic_ext for entries having stxrelid = this
483
   * rel.
484
   */
485
0
  ScanKeyInit(&skey,
486
0
        Anum_pg_statistic_ext_stxrelid,
487
0
        BTEqualStrategyNumber, F_OIDEQ,
488
0
        ObjectIdGetDatum(relid));
489
490
0
  scan = systable_beginscan(pg_statext, StatisticExtRelidIndexId, true,
491
0
                NULL, 1, &skey);
492
493
0
  while (HeapTupleIsValid(htup = systable_getnext(scan)))
494
0
  {
495
0
    StatExtEntry *entry;
496
0
    Datum   datum;
497
0
    bool    isnull;
498
0
    int     i;
499
0
    ArrayType  *arr;
500
0
    char     *enabled;
501
0
    Form_pg_statistic_ext staForm;
502
0
    List     *exprs = NIL;
503
504
0
    entry = palloc0_object(StatExtEntry);
505
0
    staForm = (Form_pg_statistic_ext) GETSTRUCT(htup);
506
0
    entry->statOid = staForm->oid;
507
0
    entry->schema = get_namespace_name(staForm->stxnamespace);
508
0
    entry->name = pstrdup(NameStr(staForm->stxname));
509
0
    for (i = 0; i < staForm->stxkeys.dim1; i++)
510
0
    {
511
0
      entry->columns = bms_add_member(entry->columns,
512
0
                      staForm->stxkeys.values[i]);
513
0
    }
514
515
0
    datum = SysCacheGetAttr(STATEXTOID, htup, Anum_pg_statistic_ext_stxstattarget, &isnull);
516
0
    entry->stattarget = isnull ? -1 : DatumGetInt16(datum);
517
518
    /* decode the stxkind char array into a list of chars */
519
0
    datum = SysCacheGetAttrNotNull(STATEXTOID, htup,
520
0
                     Anum_pg_statistic_ext_stxkind);
521
0
    arr = DatumGetArrayTypeP(datum);
522
0
    if (ARR_NDIM(arr) != 1 ||
523
0
      ARR_HASNULL(arr) ||
524
0
      ARR_ELEMTYPE(arr) != CHAROID)
525
0
      elog(ERROR, "stxkind is not a 1-D char array");
526
0
    enabled = (char *) ARR_DATA_PTR(arr);
527
0
    for (i = 0; i < ARR_DIMS(arr)[0]; i++)
528
0
    {
529
0
      Assert((enabled[i] == STATS_EXT_NDISTINCT) ||
530
0
           (enabled[i] == STATS_EXT_DEPENDENCIES) ||
531
0
           (enabled[i] == STATS_EXT_MCV) ||
532
0
           (enabled[i] == STATS_EXT_EXPRESSIONS));
533
0
      entry->types = lappend_int(entry->types, (int) enabled[i]);
534
0
    }
535
536
    /* decode expression (if any) */
537
0
    datum = SysCacheGetAttr(STATEXTOID, htup,
538
0
                Anum_pg_statistic_ext_stxexprs, &isnull);
539
540
0
    if (!isnull)
541
0
    {
542
0
      char     *exprsString;
543
544
0
      exprsString = TextDatumGetCString(datum);
545
0
      exprs = (List *) stringToNode(exprsString);
546
547
0
      pfree(exprsString);
548
549
      /* Expand virtual generated columns in the expressions */
550
0
      exprs = (List *) expand_generated_columns_in_expr((Node *) exprs, rel, 1);
551
552
      /*
553
       * Run the expressions through eval_const_expressions. This is not
554
       * just an optimization, but is necessary, because the planner
555
       * will be comparing them to similarly-processed qual clauses, and
556
       * may fail to detect valid matches without this.  We must not use
557
       * canonicalize_qual, however, since these aren't qual
558
       * expressions.
559
       */
560
0
      exprs = (List *) eval_const_expressions(NULL, (Node *) exprs);
561
562
      /* May as well fix opfuncids too */
563
0
      fix_opfuncids((Node *) exprs);
564
0
    }
565
566
0
    entry->exprs = exprs;
567
568
0
    result = lappend(result, entry);
569
0
  }
570
571
0
  systable_endscan(scan);
572
573
0
  return result;
574
0
}
575
576
/*
577
 * examine_attribute -- pre-analysis of a single column
578
 *
579
 * Determine whether the column is analyzable; if so, create and initialize
580
 * a VacAttrStats struct for it.  If not, return NULL.
581
 */
582
static VacAttrStats *
583
examine_attribute(Node *expr)
584
0
{
585
0
  HeapTuple typtuple;
586
0
  VacAttrStats *stats;
587
0
  int     i;
588
0
  bool    ok;
589
590
  /*
591
   * Create the VacAttrStats struct.
592
   */
593
0
  stats = palloc0_object(VacAttrStats);
594
0
  stats->attstattarget = -1;
595
596
  /*
597
   * When analyzing an expression, believe the expression tree's type not
598
   * the column datatype --- the latter might be the opckeytype storage type
599
   * of the opclass, which is not interesting for our purposes.  (Note: if
600
   * we did anything with non-expression statistics columns, we'd need to
601
   * figure out where to get the correct type info from, but for now that's
602
   * not a problem.)  It's not clear whether anyone will care about the
603
   * typmod, but we store that too just in case.
604
   */
605
0
  stats->attrtypid = exprType(expr);
606
0
  stats->attrtypmod = exprTypmod(expr);
607
0
  stats->attrcollid = exprCollation(expr);
608
609
0
  typtuple = SearchSysCacheCopy1(TYPEOID,
610
0
                   ObjectIdGetDatum(stats->attrtypid));
611
0
  if (!HeapTupleIsValid(typtuple))
612
0
    elog(ERROR, "cache lookup failed for type %u", stats->attrtypid);
613
0
  stats->attrtype = (Form_pg_type) GETSTRUCT(typtuple);
614
615
  /*
616
   * We don't actually analyze individual attributes, so no need to set the
617
   * memory context.
618
   */
619
0
  stats->anl_context = NULL;
620
0
  stats->tupattnum = InvalidAttrNumber;
621
622
  /*
623
   * The fields describing the stats->stavalues[n] element types default to
624
   * the type of the data being analyzed, but the type-specific typanalyze
625
   * function can change them if it wants to store something else.
626
   */
627
0
  for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
628
0
  {
629
0
    stats->statypid[i] = stats->attrtypid;
630
0
    stats->statyplen[i] = stats->attrtype->typlen;
631
0
    stats->statypbyval[i] = stats->attrtype->typbyval;
632
0
    stats->statypalign[i] = stats->attrtype->typalign;
633
0
  }
634
635
  /*
636
   * Call the type-specific typanalyze function.  If none is specified, use
637
   * std_typanalyze().
638
   */
639
0
  if (OidIsValid(stats->attrtype->typanalyze))
640
0
    ok = DatumGetBool(OidFunctionCall1(stats->attrtype->typanalyze,
641
0
                       PointerGetDatum(stats)));
642
0
  else
643
0
    ok = std_typanalyze(stats);
644
645
0
  if (!ok || stats->compute_stats == NULL || stats->minrows <= 0)
646
0
  {
647
0
    heap_freetuple(typtuple);
648
0
    pfree(stats);
649
0
    return NULL;
650
0
  }
651
652
0
  return stats;
653
0
}
654
655
/*
656
 * examine_expression -- pre-analysis of a single expression
657
 *
658
 * Determine whether the expression is analyzable; if so, create and initialize
659
 * a VacAttrStats struct for it.  If not, return NULL.
660
 */
661
static VacAttrStats *
662
examine_expression(Node *expr, int stattarget)
663
0
{
664
0
  HeapTuple typtuple;
665
0
  VacAttrStats *stats;
666
0
  int     i;
667
0
  bool    ok;
668
669
0
  Assert(expr != NULL);
670
671
  /*
672
   * Create the VacAttrStats struct.
673
   */
674
0
  stats = palloc0_object(VacAttrStats);
675
676
  /*
677
   * We can't have statistics target specified for the expression, so we
678
   * could use either the default_statistics_target, or the target computed
679
   * for the extended statistics. The second option seems more reasonable.
680
   */
681
0
  stats->attstattarget = stattarget;
682
683
  /*
684
   * When analyzing an expression, believe the expression tree's type.
685
   */
686
0
  stats->attrtypid = exprType(expr);
687
0
  stats->attrtypmod = exprTypmod(expr);
688
689
  /*
690
   * We don't allow collation to be specified in CREATE STATISTICS, so we
691
   * have to use the collation specified for the expression. It's possible
692
   * to specify the collation in the expression "(col COLLATE "en_US")" in
693
   * which case exprCollation() does the right thing.
694
   */
695
0
  stats->attrcollid = exprCollation(expr);
696
697
0
  typtuple = SearchSysCacheCopy1(TYPEOID,
698
0
                   ObjectIdGetDatum(stats->attrtypid));
699
0
  if (!HeapTupleIsValid(typtuple))
700
0
    elog(ERROR, "cache lookup failed for type %u", stats->attrtypid);
701
702
0
  stats->attrtype = (Form_pg_type) GETSTRUCT(typtuple);
703
0
  stats->anl_context = CurrentMemoryContext;  /* XXX should be using
704
                         * something else? */
705
0
  stats->tupattnum = InvalidAttrNumber;
706
707
  /*
708
   * The fields describing the stats->stavalues[n] element types default to
709
   * the type of the data being analyzed, but the type-specific typanalyze
710
   * function can change them if it wants to store something else.
711
   */
712
0
  for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
713
0
  {
714
0
    stats->statypid[i] = stats->attrtypid;
715
0
    stats->statyplen[i] = stats->attrtype->typlen;
716
0
    stats->statypbyval[i] = stats->attrtype->typbyval;
717
0
    stats->statypalign[i] = stats->attrtype->typalign;
718
0
  }
719
720
  /*
721
   * Call the type-specific typanalyze function.  If none is specified, use
722
   * std_typanalyze().
723
   */
724
0
  if (OidIsValid(stats->attrtype->typanalyze))
725
0
    ok = DatumGetBool(OidFunctionCall1(stats->attrtype->typanalyze,
726
0
                       PointerGetDatum(stats)));
727
0
  else
728
0
    ok = std_typanalyze(stats);
729
730
0
  if (!ok || stats->compute_stats == NULL || stats->minrows <= 0)
731
0
  {
732
0
    heap_freetuple(typtuple);
733
0
    pfree(stats);
734
0
    return NULL;
735
0
  }
736
737
0
  return stats;
738
0
}
739
740
/*
741
 * Using 'vacatts' of size 'nvacatts' as input data, return a newly-built
742
 * VacAttrStats array which includes only the items corresponding to
743
 * attributes indicated by 'attrs'.  If we don't have all of the per-column
744
 * stats available to compute the extended stats, then we return NULL to
745
 * indicate to the caller that the stats should not be built.
746
 */
747
static VacAttrStats **
748
lookup_var_attr_stats(Bitmapset *attrs, List *exprs,
749
            int nvacatts, VacAttrStats **vacatts)
750
0
{
751
0
  int     i = 0;
752
0
  int     x = -1;
753
0
  int     natts;
754
0
  VacAttrStats **stats;
755
0
  ListCell   *lc;
756
757
0
  natts = bms_num_members(attrs) + list_length(exprs);
758
759
0
  stats = palloc_array(VacAttrStats *, natts);
760
761
  /* lookup VacAttrStats info for the requested columns (same attnum) */
762
0
  while ((x = bms_next_member(attrs, x)) >= 0)
763
0
  {
764
0
    int     j;
765
766
0
    stats[i] = NULL;
767
0
    for (j = 0; j < nvacatts; j++)
768
0
    {
769
0
      if (x == vacatts[j]->tupattnum)
770
0
      {
771
0
        stats[i] = vacatts[j];
772
0
        break;
773
0
      }
774
0
    }
775
776
0
    if (!stats[i])
777
0
    {
778
      /*
779
       * Looks like stats were not gathered for one of the columns
780
       * required. We'll be unable to build the extended stats without
781
       * this column.
782
       */
783
0
      pfree(stats);
784
0
      return NULL;
785
0
    }
786
787
0
    i++;
788
0
  }
789
790
  /* also add info for expressions */
791
0
  foreach(lc, exprs)
792
0
  {
793
0
    Node     *expr = (Node *) lfirst(lc);
794
795
0
    stats[i] = examine_attribute(expr);
796
797
    /*
798
     * If the expression has been found as non-analyzable, give up.  We
799
     * will not be able to build extended stats with it.
800
     */
801
0
    if (stats[i] == NULL)
802
0
    {
803
0
      pfree(stats);
804
0
      return NULL;
805
0
    }
806
807
    /*
808
     * XXX We need tuple descriptor later, and we just grab it from
809
     * stats[0]->tupDesc (see e.g. statext_mcv_build). But as coded
810
     * examine_attribute does not set that, so just grab it from the first
811
     * vacatts element.
812
     */
813
0
    stats[i]->tupDesc = vacatts[0]->tupDesc;
814
815
0
    i++;
816
0
  }
817
818
0
  return stats;
819
0
}
820
821
/*
822
 * statext_store
823
 *  Serializes the statistics and stores them into the pg_statistic_ext_data
824
 *  tuple.
825
 */
826
static void
827
statext_store(Oid statOid, bool inh,
828
        MVNDistinct *ndistinct, MVDependencies *dependencies,
829
        MCVList *mcv, Datum exprs, VacAttrStats **stats)
830
0
{
831
0
  Relation  pg_stextdata;
832
0
  HeapTuple stup;
833
0
  Datum   values[Natts_pg_statistic_ext_data];
834
0
  bool    nulls[Natts_pg_statistic_ext_data];
835
836
0
  pg_stextdata = table_open(StatisticExtDataRelationId, RowExclusiveLock);
837
838
0
  memset(nulls, true, sizeof(nulls));
839
0
  memset(values, 0, sizeof(values));
840
841
  /* basic info */
842
0
  values[Anum_pg_statistic_ext_data_stxoid - 1] = ObjectIdGetDatum(statOid);
843
0
  nulls[Anum_pg_statistic_ext_data_stxoid - 1] = false;
844
845
0
  values[Anum_pg_statistic_ext_data_stxdinherit - 1] = BoolGetDatum(inh);
846
0
  nulls[Anum_pg_statistic_ext_data_stxdinherit - 1] = false;
847
848
  /*
849
   * Construct a new pg_statistic_ext_data tuple, replacing the calculated
850
   * stats.
851
   */
852
0
  if (ndistinct != NULL)
853
0
  {
854
0
    bytea    *data = statext_ndistinct_serialize(ndistinct);
855
856
0
    nulls[Anum_pg_statistic_ext_data_stxdndistinct - 1] = (data == NULL);
857
0
    values[Anum_pg_statistic_ext_data_stxdndistinct - 1] = PointerGetDatum(data);
858
0
  }
859
860
0
  if (dependencies != NULL)
861
0
  {
862
0
    bytea    *data = statext_dependencies_serialize(dependencies);
863
864
0
    nulls[Anum_pg_statistic_ext_data_stxddependencies - 1] = (data == NULL);
865
0
    values[Anum_pg_statistic_ext_data_stxddependencies - 1] = PointerGetDatum(data);
866
0
  }
867
0
  if (mcv != NULL)
868
0
  {
869
0
    bytea    *data = statext_mcv_serialize(mcv, stats);
870
871
0
    nulls[Anum_pg_statistic_ext_data_stxdmcv - 1] = (data == NULL);
872
0
    values[Anum_pg_statistic_ext_data_stxdmcv - 1] = PointerGetDatum(data);
873
0
  }
874
0
  if (exprs != (Datum) 0)
875
0
  {
876
0
    nulls[Anum_pg_statistic_ext_data_stxdexpr - 1] = false;
877
0
    values[Anum_pg_statistic_ext_data_stxdexpr - 1] = exprs;
878
0
  }
879
880
  /*
881
   * Delete the old tuple if it exists, and insert a new one. It's easier
882
   * than trying to update or insert, based on various conditions.
883
   */
884
0
  RemoveStatisticsDataById(statOid, inh);
885
886
  /* form and insert a new tuple */
887
0
  stup = heap_form_tuple(RelationGetDescr(pg_stextdata), values, nulls);
888
0
  CatalogTupleInsert(pg_stextdata, stup);
889
890
0
  heap_freetuple(stup);
891
892
0
  table_close(pg_stextdata, RowExclusiveLock);
893
0
}
894
895
/* initialize multi-dimensional sort */
896
MultiSortSupport
897
multi_sort_init(int ndims)
898
0
{
899
0
  MultiSortSupport mss;
900
901
0
  Assert(ndims >= 2);
902
903
0
  mss = (MultiSortSupport) palloc0(offsetof(MultiSortSupportData, ssup)
904
0
                   + sizeof(SortSupportData) * ndims);
905
906
0
  mss->ndims = ndims;
907
908
0
  return mss;
909
0
}
910
911
/*
912
 * Prepare sort support info using the given sort operator and collation
913
 * at the position 'sortdim'
914
 */
915
void
916
multi_sort_add_dimension(MultiSortSupport mss, int sortdim,
917
             Oid oper, Oid collation)
918
0
{
919
0
  SortSupport ssup = &mss->ssup[sortdim];
920
921
0
  ssup->ssup_cxt = CurrentMemoryContext;
922
0
  ssup->ssup_collation = collation;
923
0
  ssup->ssup_nulls_first = false;
924
925
0
  PrepareSortSupportFromOrderingOp(oper, ssup);
926
0
}
927
928
/* compare all the dimensions in the selected order */
929
int
930
multi_sort_compare(const void *a, const void *b, void *arg)
931
0
{
932
0
  MultiSortSupport mss = (MultiSortSupport) arg;
933
0
  const SortItem *ia = a;
934
0
  const SortItem *ib = b;
935
0
  int     i;
936
937
0
  for (i = 0; i < mss->ndims; i++)
938
0
  {
939
0
    int     compare;
940
941
0
    compare = ApplySortComparator(ia->values[i], ia->isnull[i],
942
0
                    ib->values[i], ib->isnull[i],
943
0
                    &mss->ssup[i]);
944
945
0
    if (compare != 0)
946
0
      return compare;
947
0
  }
948
949
  /* equal by default */
950
0
  return 0;
951
0
}
952
953
/* compare selected dimension */
954
int
955
multi_sort_compare_dim(int dim, const SortItem *a, const SortItem *b,
956
             MultiSortSupport mss)
957
0
{
958
0
  return ApplySortComparator(a->values[dim], a->isnull[dim],
959
0
                 b->values[dim], b->isnull[dim],
960
0
                 &mss->ssup[dim]);
961
0
}
962
963
int
964
multi_sort_compare_dims(int start, int end,
965
            const SortItem *a, const SortItem *b,
966
            MultiSortSupport mss)
967
0
{
968
0
  int     dim;
969
970
0
  for (dim = start; dim <= end; dim++)
971
0
  {
972
0
    int     r = ApplySortComparator(a->values[dim], a->isnull[dim],
973
0
                      b->values[dim], b->isnull[dim],
974
0
                      &mss->ssup[dim]);
975
976
0
    if (r != 0)
977
0
      return r;
978
0
  }
979
980
0
  return 0;
981
0
}
982
983
int
984
compare_scalars_simple(const void *a, const void *b, void *arg)
985
0
{
986
0
  return compare_datums_simple(*(const Datum *) a,
987
0
                 *(const Datum *) b,
988
0
                 (SortSupport) arg);
989
0
}
990
991
int
992
compare_datums_simple(Datum a, Datum b, SortSupport ssup)
993
0
{
994
0
  return ApplySortComparator(a, false, b, false, ssup);
995
0
}
996
997
/*
998
 * build_attnums_array
999
 *    Transforms a bitmap into an array of AttrNumber values.
1000
 *
1001
 * This is used for extended statistics only, so all the attributes must be
1002
 * user-defined. That means offsetting by FirstLowInvalidHeapAttributeNumber
1003
 * is not necessary here (and when querying the bitmap).
1004
 */
1005
AttrNumber *
1006
build_attnums_array(Bitmapset *attrs, int nexprs, int *numattrs)
1007
0
{
1008
0
  int     i,
1009
0
        j;
1010
0
  AttrNumber *attnums;
1011
0
  int     num = bms_num_members(attrs);
1012
1013
0
  if (numattrs)
1014
0
    *numattrs = num;
1015
1016
  /* build attnums from the bitmapset */
1017
0
  attnums = palloc_array(AttrNumber, num);
1018
0
  i = 0;
1019
0
  j = -1;
1020
0
  while ((j = bms_next_member(attrs, j)) >= 0)
1021
0
  {
1022
0
    int     attnum = (j - nexprs);
1023
1024
    /*
1025
     * Make sure the bitmap contains only user-defined attributes. As
1026
     * bitmaps can't contain negative values, this can be violated in two
1027
     * ways. Firstly, the bitmap might contain 0 as a member, and secondly
1028
     * the integer value might be larger than MaxAttrNumber.
1029
     */
1030
0
    Assert(AttributeNumberIsValid(attnum));
1031
0
    Assert(attnum <= MaxAttrNumber);
1032
0
    Assert(attnum >= (-nexprs));
1033
1034
0
    attnums[i++] = (AttrNumber) attnum;
1035
1036
    /* protect against overflows */
1037
0
    Assert(i <= num);
1038
0
  }
1039
1040
0
  return attnums;
1041
0
}
1042
1043
/*
1044
 * build_sorted_items
1045
 *    build a sorted array of SortItem with values from rows
1046
 *
1047
 * Note: All the memory is allocated in a single chunk, so that the caller
1048
 * can simply pfree the return value to release all of it.
1049
 */
1050
SortItem *
1051
build_sorted_items(StatsBuildData *data, int *nitems,
1052
           MultiSortSupport mss,
1053
           int numattrs, AttrNumber *attnums)
1054
0
{
1055
0
  int     i,
1056
0
        j,
1057
0
        nrows;
1058
0
  int     nvalues = data->numrows * numattrs;
1059
0
  Size    len;
1060
0
  SortItem   *items;
1061
0
  Datum    *values;
1062
0
  bool     *nulls;
1063
0
  char     *ptr;
1064
0
  int      *typlen;
1065
1066
  /* Compute the total amount of memory we need (both items and values). */
1067
0
  len = MAXALIGN(data->numrows * sizeof(SortItem)) +
1068
0
    nvalues * (sizeof(Datum) + sizeof(bool));
1069
1070
  /* Allocate the memory and split it into the pieces. */
1071
0
  ptr = palloc0(len);
1072
1073
  /* items to sort */
1074
0
  items = (SortItem *) ptr;
1075
  /* MAXALIGN ensures that the following Datums are suitably aligned */
1076
0
  ptr += MAXALIGN(data->numrows * sizeof(SortItem));
1077
1078
  /* values and null flags */
1079
0
  values = (Datum *) ptr;
1080
0
  ptr += nvalues * sizeof(Datum);
1081
1082
0
  nulls = (bool *) ptr;
1083
0
  ptr += nvalues * sizeof(bool);
1084
1085
  /* make sure we consumed the whole buffer exactly */
1086
0
  Assert((ptr - (char *) items) == len);
1087
1088
  /* fix the pointers to Datum and bool arrays */
1089
0
  nrows = 0;
1090
0
  for (i = 0; i < data->numrows; i++)
1091
0
  {
1092
0
    items[nrows].values = &values[nrows * numattrs];
1093
0
    items[nrows].isnull = &nulls[nrows * numattrs];
1094
1095
0
    nrows++;
1096
0
  }
1097
1098
  /* build a local cache of typlen for all attributes */
1099
0
  typlen = palloc_array(int, data->nattnums);
1100
0
  for (i = 0; i < data->nattnums; i++)
1101
0
    typlen[i] = get_typlen(data->stats[i]->attrtypid);
1102
1103
0
  nrows = 0;
1104
0
  for (i = 0; i < data->numrows; i++)
1105
0
  {
1106
0
    bool    toowide = false;
1107
1108
    /* load the values/null flags from sample rows */
1109
0
    for (j = 0; j < numattrs; j++)
1110
0
    {
1111
0
      Datum   value;
1112
0
      bool    isnull;
1113
0
      int     attlen;
1114
0
      AttrNumber  attnum = attnums[j];
1115
1116
0
      int     idx;
1117
1118
      /* match attnum to the pre-calculated data */
1119
0
      for (idx = 0; idx < data->nattnums; idx++)
1120
0
      {
1121
0
        if (attnum == data->attnums[idx])
1122
0
          break;
1123
0
      }
1124
1125
0
      Assert(idx < data->nattnums);
1126
1127
0
      value = data->values[idx][i];
1128
0
      isnull = data->nulls[idx][i];
1129
0
      attlen = typlen[idx];
1130
1131
      /*
1132
       * If this is a varlena value, check if it's too wide and if yes
1133
       * then skip the whole item. Otherwise detoast the value.
1134
       *
1135
       * XXX It may happen that we've already detoasted some preceding
1136
       * values for the current item. We don't bother to cleanup those
1137
       * on the assumption that those are small (below WIDTH_THRESHOLD)
1138
       * and will be discarded at the end of analyze.
1139
       */
1140
0
      if ((!isnull) && (attlen == -1))
1141
0
      {
1142
0
        if (toast_raw_datum_size(value) > WIDTH_THRESHOLD)
1143
0
        {
1144
0
          toowide = true;
1145
0
          break;
1146
0
        }
1147
1148
0
        value = PointerGetDatum(PG_DETOAST_DATUM(value));
1149
0
      }
1150
1151
0
      items[nrows].values[j] = value;
1152
0
      items[nrows].isnull[j] = isnull;
1153
0
    }
1154
1155
0
    if (toowide)
1156
0
      continue;
1157
1158
0
    nrows++;
1159
0
  }
1160
1161
  /* store the actual number of items (ignoring the too-wide ones) */
1162
0
  *nitems = nrows;
1163
1164
  /* all items were too wide */
1165
0
  if (nrows == 0)
1166
0
  {
1167
    /* everything is allocated as a single chunk */
1168
0
    pfree(items);
1169
0
    return NULL;
1170
0
  }
1171
1172
  /* do the sort, using the multi-sort */
1173
0
  qsort_interruptible(items, nrows, sizeof(SortItem),
1174
0
            multi_sort_compare, mss);
1175
1176
0
  return items;
1177
0
}
1178
1179
/*
1180
 * has_stats_of_kind
1181
 *    Check whether the list contains statistic of a given kind
1182
 */
1183
bool
1184
has_stats_of_kind(List *stats, char requiredkind)
1185
0
{
1186
0
  ListCell   *l;
1187
1188
0
  foreach(l, stats)
1189
0
  {
1190
0
    StatisticExtInfo *stat = (StatisticExtInfo *) lfirst(l);
1191
1192
0
    if (stat->kind == requiredkind)
1193
0
      return true;
1194
0
  }
1195
1196
0
  return false;
1197
0
}
1198
1199
/*
1200
 * stat_find_expression
1201
 *    Search for an expression in statistics object's list of expressions.
1202
 *
1203
 * Returns the index of the expression in the statistics object's list of
1204
 * expressions, or -1 if not found.
1205
 */
1206
static int
1207
stat_find_expression(StatisticExtInfo *stat, Node *expr)
1208
0
{
1209
0
  ListCell   *lc;
1210
0
  int     idx;
1211
1212
0
  idx = 0;
1213
0
  foreach(lc, stat->exprs)
1214
0
  {
1215
0
    Node     *stat_expr = (Node *) lfirst(lc);
1216
1217
0
    if (equal(stat_expr, expr))
1218
0
      return idx;
1219
0
    idx++;
1220
0
  }
1221
1222
  /* Expression not found */
1223
0
  return -1;
1224
0
}
1225
1226
/*
1227
 * stat_covers_expressions
1228
 *    Test whether a statistics object covers all expressions in a list.
1229
 *
1230
 * Returns true if all expressions are covered.  If expr_idxs is non-NULL, it
1231
 * is populated with the indexes of the expressions found.
1232
 */
1233
static bool
1234
stat_covers_expressions(StatisticExtInfo *stat, List *exprs,
1235
            Bitmapset **expr_idxs)
1236
0
{
1237
0
  ListCell   *lc;
1238
1239
0
  foreach(lc, exprs)
1240
0
  {
1241
0
    Node     *expr = (Node *) lfirst(lc);
1242
0
    int     expr_idx;
1243
1244
0
    expr_idx = stat_find_expression(stat, expr);
1245
0
    if (expr_idx == -1)
1246
0
      return false;
1247
1248
0
    if (expr_idxs != NULL)
1249
0
      *expr_idxs = bms_add_member(*expr_idxs, expr_idx);
1250
0
  }
1251
1252
  /* If we reach here, all expressions are covered */
1253
0
  return true;
1254
0
}
1255
1256
/*
1257
 * choose_best_statistics
1258
 *    Look for and return statistics with the specified 'requiredkind' which
1259
 *    have keys that match at least two of the given attnums.  Return NULL if
1260
 *    there's no match.
1261
 *
1262
 * The current selection criteria is very simple - we choose the statistics
1263
 * object referencing the most attributes in covered (and still unestimated
1264
 * clauses), breaking ties in favor of objects with fewer keys overall.
1265
 *
1266
 * The clause_attnums is an array of bitmaps, storing attnums for individual
1267
 * clauses. A NULL element means the clause is either incompatible or already
1268
 * estimated.
1269
 *
1270
 * XXX If multiple statistics objects tie on both criteria, then which object
1271
 * is chosen depends on the order that they appear in the stats list. Perhaps
1272
 * further tiebreakers are needed.
1273
 */
1274
StatisticExtInfo *
1275
choose_best_statistics(List *stats, char requiredkind, bool inh,
1276
             Bitmapset **clause_attnums, List **clause_exprs,
1277
             int nclauses)
1278
0
{
1279
0
  ListCell   *lc;
1280
0
  StatisticExtInfo *best_match = NULL;
1281
0
  int     best_num_matched = 2; /* goal #1: maximize */
1282
0
  int     best_match_keys = (STATS_MAX_DIMENSIONS + 1);  /* goal #2: minimize */
1283
1284
0
  foreach(lc, stats)
1285
0
  {
1286
0
    int     i;
1287
0
    StatisticExtInfo *info = (StatisticExtInfo *) lfirst(lc);
1288
0
    Bitmapset  *matched_attnums = NULL;
1289
0
    Bitmapset  *matched_exprs = NULL;
1290
0
    int     num_matched;
1291
0
    int     numkeys;
1292
1293
    /* skip statistics that are not of the correct type */
1294
0
    if (info->kind != requiredkind)
1295
0
      continue;
1296
1297
    /* skip statistics with mismatching inheritance flag */
1298
0
    if (info->inherit != inh)
1299
0
      continue;
1300
1301
    /*
1302
     * Collect attributes and expressions in remaining (unestimated)
1303
     * clauses fully covered by this statistic object.
1304
     *
1305
     * We know already estimated clauses have both clause_attnums and
1306
     * clause_exprs set to NULL. We leave the pointers NULL if already
1307
     * estimated, or we reset them to NULL after estimating the clause.
1308
     */
1309
0
    for (i = 0; i < nclauses; i++)
1310
0
    {
1311
0
      Bitmapset  *expr_idxs = NULL;
1312
1313
      /* ignore incompatible/estimated clauses */
1314
0
      if (!clause_attnums[i] && !clause_exprs[i])
1315
0
        continue;
1316
1317
      /* ignore clauses that are not covered by this object */
1318
0
      if (!bms_is_subset(clause_attnums[i], info->keys) ||
1319
0
        !stat_covers_expressions(info, clause_exprs[i], &expr_idxs))
1320
0
        continue;
1321
1322
      /* record attnums and indexes of expressions covered */
1323
0
      matched_attnums = bms_add_members(matched_attnums, clause_attnums[i]);
1324
0
      matched_exprs = bms_add_members(matched_exprs, expr_idxs);
1325
0
    }
1326
1327
0
    num_matched = bms_num_members(matched_attnums) + bms_num_members(matched_exprs);
1328
1329
0
    bms_free(matched_attnums);
1330
0
    bms_free(matched_exprs);
1331
1332
    /*
1333
     * save the actual number of keys in the stats so that we can choose
1334
     * the narrowest stats with the most matching keys.
1335
     */
1336
0
    numkeys = bms_num_members(info->keys) + list_length(info->exprs);
1337
1338
    /*
1339
     * Use this object when it increases the number of matched attributes
1340
     * and expressions or when it matches the same number of attributes
1341
     * and expressions but these stats have fewer keys than any previous
1342
     * match.
1343
     */
1344
0
    if (num_matched > best_num_matched ||
1345
0
      (num_matched == best_num_matched && numkeys < best_match_keys))
1346
0
    {
1347
0
      best_match = info;
1348
0
      best_num_matched = num_matched;
1349
0
      best_match_keys = numkeys;
1350
0
    }
1351
0
  }
1352
1353
0
  return best_match;
1354
0
}
1355
1356
/*
1357
 * statext_is_compatible_clause_internal
1358
 *    Determines if the clause is compatible with MCV lists.
1359
 *
1360
 * To be compatible, the given clause must be a combination of supported
1361
 * clauses built from Vars or sub-expressions (where a sub-expression is
1362
 * something that exactly matches an expression found in statistics objects).
1363
 * This function recursively examines the clause and extracts any
1364
 * sub-expressions that will need to be matched against statistics.
1365
 *
1366
 * Currently, we only support the following types of clauses:
1367
 *
1368
 * (a) OpExprs of the form (Var/Expr op Const), or (Const op Var/Expr), where
1369
 * the op is one of ("=", "<", ">", ">=", "<=")
1370
 *
1371
 * (b) (Var/Expr IS [NOT] NULL)
1372
 *
1373
 * (c) combinations using AND/OR/NOT
1374
 *
1375
 * (d) ScalarArrayOpExprs of the form (Var/Expr op ANY (Const)) or
1376
 * (Var/Expr op ALL (Const))
1377
 *
1378
 * In the future, the range of supported clauses may be expanded to more
1379
 * complex cases, for example (Var op Var).
1380
 *
1381
 * Arguments:
1382
 * clause: (sub)clause to be inspected (bare clause, not a RestrictInfo)
1383
 * relid: rel that all Vars in clause must belong to
1384
 * *attnums: input/output parameter collecting attribute numbers of all
1385
 *    mentioned Vars.  Note that we do not offset the attribute numbers,
1386
 *    so we can't cope with system columns.
1387
 * *exprs: input/output parameter collecting primitive subclauses within
1388
 *    the clause tree
1389
 * *leakproof: input/output parameter recording the leakproofness of the
1390
 *    clause tree.  This should be true initially, and will be set to false
1391
 *    if any operator function used in an OpExpr is not leakproof.
1392
 *
1393
 * Returns false if there is something we definitively can't handle.
1394
 * On true return, we can proceed to match the *exprs against statistics.
1395
 */
1396
static bool
1397
statext_is_compatible_clause_internal(PlannerInfo *root, Node *clause,
1398
                    Index relid, Bitmapset **attnums,
1399
                    List **exprs, bool *leakproof)
1400
0
{
1401
  /* Look inside any binary-compatible relabeling (as in examine_variable) */
1402
0
  if (IsA(clause, RelabelType))
1403
0
    clause = (Node *) ((RelabelType *) clause)->arg;
1404
1405
  /* plain Var references (boolean Vars or recursive checks) */
1406
0
  if (IsA(clause, Var))
1407
0
  {
1408
0
    Var      *var = (Var *) clause;
1409
1410
    /* Ensure var is from the correct relation */
1411
0
    if (var->varno != relid)
1412
0
      return false;
1413
1414
    /* we also better ensure the Var is from the current level */
1415
0
    if (var->varlevelsup > 0)
1416
0
      return false;
1417
1418
    /*
1419
     * Also reject system attributes and whole-row Vars (we don't allow
1420
     * stats on those).
1421
     */
1422
0
    if (!AttrNumberIsForUserDefinedAttr(var->varattno))
1423
0
      return false;
1424
1425
    /* OK, record the attnum for later permissions checks. */
1426
0
    *attnums = bms_add_member(*attnums, var->varattno);
1427
1428
0
    return true;
1429
0
  }
1430
1431
  /* (Var/Expr op Const) or (Const op Var/Expr) */
1432
0
  if (is_opclause(clause))
1433
0
  {
1434
0
    OpExpr     *expr = (OpExpr *) clause;
1435
0
    Node     *clause_expr;
1436
1437
    /* Only expressions with two arguments are considered compatible. */
1438
0
    if (list_length(expr->args) != 2)
1439
0
      return false;
1440
1441
    /* Check if the expression has the right shape */
1442
0
    if (!examine_opclause_args(expr->args, &clause_expr, NULL, NULL))
1443
0
      return false;
1444
1445
    /*
1446
     * If it's not one of the supported operators ("=", "<", ">", etc.),
1447
     * just ignore the clause, as it's not compatible with MCV lists.
1448
     *
1449
     * This uses the function for estimating selectivity, not the operator
1450
     * directly (a bit awkward, but well ...).
1451
     */
1452
0
    switch (get_oprrest(expr->opno))
1453
0
    {
1454
0
      case F_EQSEL:
1455
0
      case F_NEQSEL:
1456
0
      case F_SCALARLTSEL:
1457
0
      case F_SCALARLESEL:
1458
0
      case F_SCALARGTSEL:
1459
0
      case F_SCALARGESEL:
1460
        /* supported, will continue with inspection of the Var/Expr */
1461
0
        break;
1462
1463
0
      default:
1464
        /* other estimators are considered unknown/unsupported */
1465
0
        return false;
1466
0
    }
1467
1468
    /* Check if the operator is leakproof */
1469
0
    if (*leakproof)
1470
0
      *leakproof = get_func_leakproof(get_opcode(expr->opno));
1471
1472
    /* Check (Var op Const) or (Const op Var) clauses by recursing. */
1473
0
    if (IsA(clause_expr, Var))
1474
0
      return statext_is_compatible_clause_internal(root, clause_expr,
1475
0
                             relid, attnums,
1476
0
                             exprs, leakproof);
1477
1478
    /* Otherwise we have (Expr op Const) or (Const op Expr). */
1479
0
    *exprs = lappend(*exprs, clause_expr);
1480
0
    return true;
1481
0
  }
1482
1483
  /* Var/Expr IN Array */
1484
0
  if (IsA(clause, ScalarArrayOpExpr))
1485
0
  {
1486
0
    ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) clause;
1487
0
    Node     *clause_expr;
1488
0
    bool    expronleft;
1489
1490
    /* Only expressions with two arguments are considered compatible. */
1491
0
    if (list_length(expr->args) != 2)
1492
0
      return false;
1493
1494
    /* Check if the expression has the right shape (one Var, one Const) */
1495
0
    if (!examine_opclause_args(expr->args, &clause_expr, NULL, &expronleft))
1496
0
      return false;
1497
1498
    /* We only support Var on left, Const on right */
1499
0
    if (!expronleft)
1500
0
      return false;
1501
1502
    /*
1503
     * If it's not one of the supported operators ("=", "<", ">", etc.),
1504
     * just ignore the clause, as it's not compatible with MCV lists.
1505
     *
1506
     * This uses the function for estimating selectivity, not the operator
1507
     * directly (a bit awkward, but well ...).
1508
     */
1509
0
    switch (get_oprrest(expr->opno))
1510
0
    {
1511
0
      case F_EQSEL:
1512
0
      case F_NEQSEL:
1513
0
      case F_SCALARLTSEL:
1514
0
      case F_SCALARLESEL:
1515
0
      case F_SCALARGTSEL:
1516
0
      case F_SCALARGESEL:
1517
        /* supported, will continue with inspection of the Var/Expr */
1518
0
        break;
1519
1520
0
      default:
1521
        /* other estimators are considered unknown/unsupported */
1522
0
        return false;
1523
0
    }
1524
1525
    /* Check if the operator is leakproof */
1526
0
    if (*leakproof)
1527
0
      *leakproof = get_func_leakproof(get_opcode(expr->opno));
1528
1529
    /* Check Var IN Array clauses by recursing. */
1530
0
    if (IsA(clause_expr, Var))
1531
0
      return statext_is_compatible_clause_internal(root, clause_expr,
1532
0
                             relid, attnums,
1533
0
                             exprs, leakproof);
1534
1535
    /* Otherwise we have Expr IN Array. */
1536
0
    *exprs = lappend(*exprs, clause_expr);
1537
0
    return true;
1538
0
  }
1539
1540
  /* AND/OR/NOT clause */
1541
0
  if (is_andclause(clause) ||
1542
0
    is_orclause(clause) ||
1543
0
    is_notclause(clause))
1544
0
  {
1545
    /*
1546
     * AND/OR/NOT-clauses are supported if all sub-clauses are supported
1547
     *
1548
     * Perhaps we could improve this by handling mixed cases, when some of
1549
     * the clauses are supported and some are not. Selectivity for the
1550
     * supported subclauses would be computed using extended statistics,
1551
     * and the remaining clauses would be estimated using the traditional
1552
     * algorithm (product of selectivities).
1553
     *
1554
     * It however seems overly complex, and in a way we already do that
1555
     * because if we reject the whole clause as unsupported here, it will
1556
     * be eventually passed to clauselist_selectivity() which does exactly
1557
     * this (split into supported/unsupported clauses etc).
1558
     */
1559
0
    BoolExpr   *expr = (BoolExpr *) clause;
1560
0
    ListCell   *lc;
1561
1562
0
    foreach(lc, expr->args)
1563
0
    {
1564
      /*
1565
       * If we find an incompatible clause in the arguments, treat the
1566
       * whole clause as incompatible.
1567
       */
1568
0
      if (!statext_is_compatible_clause_internal(root,
1569
0
                             (Node *) lfirst(lc),
1570
0
                             relid, attnums, exprs,
1571
0
                             leakproof))
1572
0
        return false;
1573
0
    }
1574
1575
0
    return true;
1576
0
  }
1577
1578
  /* Var/Expr IS NULL */
1579
0
  if (IsA(clause, NullTest))
1580
0
  {
1581
0
    NullTest   *nt = (NullTest *) clause;
1582
1583
    /* Check Var IS NULL clauses by recursing. */
1584
0
    if (IsA(nt->arg, Var))
1585
0
      return statext_is_compatible_clause_internal(root,
1586
0
                             (Node *) (nt->arg),
1587
0
                             relid, attnums,
1588
0
                             exprs, leakproof);
1589
1590
    /* Otherwise we have Expr IS NULL. */
1591
0
    *exprs = lappend(*exprs, nt->arg);
1592
0
    return true;
1593
0
  }
1594
1595
  /*
1596
   * Treat any other expressions as bare expressions to be matched against
1597
   * expressions in statistics objects.
1598
   */
1599
0
  *exprs = lappend(*exprs, clause);
1600
0
  return true;
1601
0
}
1602
1603
/*
1604
 * statext_is_compatible_clause
1605
 *    Determines if the clause is compatible with MCV lists.
1606
 *
1607
 * See statext_is_compatible_clause_internal, above, for the basic rules.
1608
 * This layer deals with RestrictInfo superstructure and applies permissions
1609
 * checks to verify that it's okay to examine all mentioned Vars.
1610
 *
1611
 * Arguments:
1612
 * clause: clause to be inspected (in RestrictInfo form)
1613
 * relid: rel that all Vars in clause must belong to
1614
 * *attnums: input/output parameter collecting attribute numbers of all
1615
 *    mentioned Vars.  Note that we do not offset the attribute numbers,
1616
 *    so we can't cope with system columns.
1617
 * *exprs: input/output parameter collecting primitive subclauses within
1618
 *    the clause tree
1619
 *
1620
 * Returns false if there is something we definitively can't handle.
1621
 * On true return, we can proceed to match the *exprs against statistics.
1622
 */
1623
static bool
1624
statext_is_compatible_clause(PlannerInfo *root, Node *clause, Index relid,
1625
               Bitmapset **attnums, List **exprs)
1626
0
{
1627
0
  RestrictInfo *rinfo;
1628
0
  int     clause_relid;
1629
0
  bool    leakproof;
1630
1631
  /*
1632
   * Special-case handling for bare BoolExpr AND clauses, because the
1633
   * restrictinfo machinery doesn't build RestrictInfos on top of AND
1634
   * clauses.
1635
   */
1636
0
  if (is_andclause(clause))
1637
0
  {
1638
0
    BoolExpr   *expr = (BoolExpr *) clause;
1639
0
    ListCell   *lc;
1640
1641
    /*
1642
     * Check that each sub-clause is compatible.  We expect these to be
1643
     * RestrictInfos.
1644
     */
1645
0
    foreach(lc, expr->args)
1646
0
    {
1647
0
      if (!statext_is_compatible_clause(root, (Node *) lfirst(lc),
1648
0
                        relid, attnums, exprs))
1649
0
        return false;
1650
0
    }
1651
1652
0
    return true;
1653
0
  }
1654
1655
  /* Otherwise it must be a RestrictInfo. */
1656
0
  if (!IsA(clause, RestrictInfo))
1657
0
    return false;
1658
0
  rinfo = (RestrictInfo *) clause;
1659
1660
  /* Pseudoconstants are not really interesting here. */
1661
0
  if (rinfo->pseudoconstant)
1662
0
    return false;
1663
1664
  /* Clauses referencing other varnos are incompatible. */
1665
0
  if (!bms_get_singleton_member(rinfo->clause_relids, &clause_relid) ||
1666
0
    clause_relid != relid)
1667
0
    return false;
1668
1669
  /*
1670
   * Check the clause, determine what attributes it references, and whether
1671
   * it includes any non-leakproof operators.
1672
   */
1673
0
  leakproof = true;
1674
0
  if (!statext_is_compatible_clause_internal(root, (Node *) rinfo->clause,
1675
0
                         relid, attnums, exprs,
1676
0
                         &leakproof))
1677
0
    return false;
1678
1679
  /*
1680
   * If the clause includes any non-leakproof operators, check that the user
1681
   * has permission to read all required attributes, otherwise the operators
1682
   * might reveal values from the MCV list that the user doesn't have
1683
   * permission to see.  We require all rows to be selectable --- there must
1684
   * be no securityQuals from security barrier views or RLS policies.  See
1685
   * similar code in examine_variable(), examine_simple_variable(), and
1686
   * statistic_proc_security_check().
1687
   *
1688
   * Note that for an inheritance child, the permission checks are performed
1689
   * on the inheritance root parent, and whole-table select privilege on the
1690
   * parent doesn't guarantee that the user could read all columns of the
1691
   * child. Therefore we must check all referenced columns.
1692
   */
1693
0
  if (!leakproof)
1694
0
  {
1695
0
    Bitmapset  *clause_attnums;
1696
1697
    /*
1698
     * We have to check per-column privileges.  *attnums has the attnums
1699
     * for individual Vars we saw, but there may also be Vars within
1700
     * subexpressions in *exprs.  We can use pull_varattnos() to extract
1701
     * those, but there's an impedance mismatch: attnums returned by
1702
     * pull_varattnos() are offset by FirstLowInvalidHeapAttributeNumber,
1703
     * while attnums within *attnums aren't.  Convert *attnums to the
1704
     * offset style so we can combine the results.
1705
     */
1706
0
    clause_attnums = bms_offset_members(*attnums,
1707
0
                      0 - FirstLowInvalidHeapAttributeNumber);
1708
    /* Now merge attnums from *exprs into clause_attnums */
1709
0
    if (*exprs != NIL)
1710
0
      pull_varattnos((Node *) *exprs, relid, &clause_attnums);
1711
1712
    /* Must have permission to read all rows from these columns */
1713
0
    if (!all_rows_selectable(root, relid, clause_attnums))
1714
0
      return false;
1715
0
  }
1716
1717
  /* If we reach here, the clause is OK */
1718
0
  return true;
1719
0
}
1720
1721
/*
1722
 * statext_mcv_clauselist_selectivity
1723
 *    Estimate clauses using the best multi-column statistics.
1724
 *
1725
 * Applies available extended (multi-column) statistics on a table. There may
1726
 * be multiple applicable statistics (with respect to the clauses), in which
1727
 * case we use greedy approach. In each round we select the best statistic on
1728
 * a table (measured by the number of attributes extracted from the clauses
1729
 * and covered by it), and compute the selectivity for the supplied clauses.
1730
 * We repeat this process with the remaining clauses (if any), until none of
1731
 * the available statistics can be used.
1732
 *
1733
 * One of the main challenges with using MCV lists is how to extrapolate the
1734
 * estimate to the data not covered by the MCV list. To do that, we compute
1735
 * not only the "MCV selectivity" (selectivities for MCV items matching the
1736
 * supplied clauses), but also the following related selectivities:
1737
 *
1738
 * - simple selectivity:  Computed without extended statistics, i.e. as if the
1739
 * columns/clauses were independent.
1740
 *
1741
 * - base selectivity:  Similar to simple selectivity, but is computed using
1742
 * the extended statistic by adding up the base frequencies (that we compute
1743
 * and store for each MCV item) of matching MCV items.
1744
 *
1745
 * - total selectivity: Selectivity covered by the whole MCV list.
1746
 *
1747
 * These are passed to mcv_combine_selectivities() which combines them to
1748
 * produce a selectivity estimate that makes use of both per-column statistics
1749
 * and the multi-column MCV statistics.
1750
 *
1751
 * 'estimatedclauses' is an input/output parameter.  We set bits for the
1752
 * 0-based 'clauses' indexes we estimate for and also skip clause items that
1753
 * already have a bit set.
1754
 */
1755
static Selectivity
1756
statext_mcv_clauselist_selectivity(PlannerInfo *root, List *clauses, int varRelid,
1757
                   JoinType jointype, SpecialJoinInfo *sjinfo,
1758
                   RelOptInfo *rel, Bitmapset **estimatedclauses,
1759
                   bool is_or)
1760
0
{
1761
0
  ListCell   *l;
1762
0
  Bitmapset **list_attnums; /* attnums extracted from the clause */
1763
0
  List    **list_exprs;   /* expressions matched to any statistic */
1764
0
  int     listidx;
1765
0
  Selectivity sel = (is_or) ? 0.0 : 1.0;
1766
0
  RangeTblEntry *rte = planner_rt_fetch(rel->relid, root);
1767
1768
  /* check if there's any stats that might be useful for us. */
1769
0
  if (!has_stats_of_kind(rel->statlist, STATS_EXT_MCV))
1770
0
    return sel;
1771
1772
0
  list_attnums = palloc_array(Bitmapset *, list_length(clauses));
1773
1774
  /* expressions extracted from complex expressions */
1775
0
  list_exprs = palloc_array(List *, list_length(clauses));
1776
1777
  /*
1778
   * Pre-process the clauses list to extract the attnums and expressions
1779
   * seen in each item.  We need to determine if there are any clauses which
1780
   * will be useful for selectivity estimations with extended stats.  Along
1781
   * the way we'll record all of the attnums and expressions for each clause
1782
   * in lists which we'll reference later so we don't need to repeat the
1783
   * same work again.
1784
   *
1785
   * We also skip clauses that we already estimated using different types of
1786
   * statistics (we treat them as incompatible).
1787
   */
1788
0
  listidx = 0;
1789
0
  foreach(l, clauses)
1790
0
  {
1791
0
    Node     *clause = (Node *) lfirst(l);
1792
0
    Bitmapset  *attnums = NULL;
1793
0
    List     *exprs = NIL;
1794
1795
0
    if (!bms_is_member(listidx, *estimatedclauses) &&
1796
0
      statext_is_compatible_clause(root, clause, rel->relid, &attnums, &exprs))
1797
0
    {
1798
0
      list_attnums[listidx] = attnums;
1799
0
      list_exprs[listidx] = exprs;
1800
0
    }
1801
0
    else
1802
0
    {
1803
0
      list_attnums[listidx] = NULL;
1804
0
      list_exprs[listidx] = NIL;
1805
0
    }
1806
1807
0
    listidx++;
1808
0
  }
1809
1810
  /* apply as many extended statistics as possible */
1811
0
  while (true)
1812
0
  {
1813
0
    StatisticExtInfo *stat;
1814
0
    List     *stat_clauses;
1815
0
    Bitmapset  *simple_clauses;
1816
1817
    /* find the best suited statistics object for these attnums */
1818
0
    stat = choose_best_statistics(rel->statlist, STATS_EXT_MCV, rte->inh,
1819
0
                    list_attnums, list_exprs,
1820
0
                    list_length(clauses));
1821
1822
    /*
1823
     * if no (additional) matching stats could be found then we've nothing
1824
     * to do
1825
     */
1826
0
    if (!stat)
1827
0
      break;
1828
1829
    /* Ensure choose_best_statistics produced an expected stats type. */
1830
0
    Assert(stat->kind == STATS_EXT_MCV);
1831
1832
    /* now filter the clauses to be estimated using the selected MCV */
1833
0
    stat_clauses = NIL;
1834
1835
    /* record which clauses are simple (single column or expression) */
1836
0
    simple_clauses = NULL;
1837
1838
0
    listidx = -1;
1839
0
    foreach(l, clauses)
1840
0
    {
1841
      /* Increment the index before we decide if to skip the clause. */
1842
0
      listidx++;
1843
1844
      /*
1845
       * Ignore clauses from which we did not extract any attnums or
1846
       * expressions (this needs to be consistent with what we do in
1847
       * choose_best_statistics).
1848
       *
1849
       * This also eliminates already estimated clauses - both those
1850
       * estimated before and during applying extended statistics.
1851
       *
1852
       * XXX This check is needed because both bms_is_subset and
1853
       * stat_covers_expressions return true for empty attnums and
1854
       * expressions.
1855
       */
1856
0
      if (!list_attnums[listidx] && !list_exprs[listidx])
1857
0
        continue;
1858
1859
      /*
1860
       * The clause was not estimated yet, and we've extracted either
1861
       * attnums or expressions from it. Ignore it if it's not fully
1862
       * covered by the chosen statistics object.
1863
       *
1864
       * We need to check both attributes and expressions, and reject if
1865
       * either is not covered.
1866
       */
1867
0
      if (!bms_is_subset(list_attnums[listidx], stat->keys) ||
1868
0
        !stat_covers_expressions(stat, list_exprs[listidx], NULL))
1869
0
        continue;
1870
1871
      /*
1872
       * Now we know the clause is compatible (we have either attnums or
1873
       * expressions extracted from it), and was not estimated yet.
1874
       */
1875
1876
      /* record simple clauses (single column or expression) */
1877
0
      if ((list_attnums[listidx] == NULL &&
1878
0
         list_length(list_exprs[listidx]) == 1) ||
1879
0
        (list_exprs[listidx] == NIL &&
1880
0
         bms_membership(list_attnums[listidx]) == BMS_SINGLETON))
1881
0
        simple_clauses = bms_add_member(simple_clauses,
1882
0
                        list_length(stat_clauses));
1883
1884
      /* add clause to list and mark it as estimated */
1885
0
      stat_clauses = lappend(stat_clauses, (Node *) lfirst(l));
1886
0
      *estimatedclauses = bms_add_member(*estimatedclauses, listidx);
1887
1888
      /*
1889
       * Reset the pointers, so that choose_best_statistics knows this
1890
       * clause was estimated and does not consider it again.
1891
       */
1892
0
      bms_free(list_attnums[listidx]);
1893
0
      list_attnums[listidx] = NULL;
1894
1895
0
      list_free(list_exprs[listidx]);
1896
0
      list_exprs[listidx] = NULL;
1897
0
    }
1898
1899
0
    if (is_or)
1900
0
    {
1901
0
      bool     *or_matches = NULL;
1902
0
      Selectivity simple_or_sel = 0.0,
1903
0
            stat_sel = 0.0;
1904
0
      MCVList    *mcv_list;
1905
1906
      /* Load the MCV list stored in the statistics object */
1907
0
      mcv_list = statext_mcv_load(stat->statOid, rte->inh);
1908
1909
      /*
1910
       * Compute the selectivity of the ORed list of clauses covered by
1911
       * this statistics object by estimating each in turn and combining
1912
       * them using the formula P(A OR B) = P(A) + P(B) - P(A AND B).
1913
       * This allows us to use the multivariate MCV stats to better
1914
       * estimate the individual terms and their overlap.
1915
       *
1916
       * Each time we iterate this formula, the clause "A" above is
1917
       * equal to all the clauses processed so far, combined with "OR".
1918
       */
1919
0
      listidx = 0;
1920
0
      foreach(l, stat_clauses)
1921
0
      {
1922
0
        Node     *clause = (Node *) lfirst(l);
1923
0
        Selectivity simple_sel,
1924
0
              overlap_simple_sel,
1925
0
              mcv_sel,
1926
0
              mcv_basesel,
1927
0
              overlap_mcvsel,
1928
0
              overlap_basesel,
1929
0
              mcv_totalsel,
1930
0
              clause_sel,
1931
0
              overlap_sel;
1932
1933
        /*
1934
         * "Simple" selectivity of the next clause and its overlap
1935
         * with any of the previous clauses.  These are our initial
1936
         * estimates of P(B) and P(A AND B), assuming independence of
1937
         * columns/clauses.
1938
         */
1939
0
        simple_sel = clause_selectivity_ext(root, clause, varRelid,
1940
0
                          jointype, sjinfo, false);
1941
1942
0
        overlap_simple_sel = simple_or_sel * simple_sel;
1943
1944
        /*
1945
         * New "simple" selectivity of all clauses seen so far,
1946
         * assuming independence.
1947
         */
1948
0
        simple_or_sel += simple_sel - overlap_simple_sel;
1949
0
        CLAMP_PROBABILITY(simple_or_sel);
1950
1951
        /*
1952
         * Multi-column estimate of this clause using MCV statistics,
1953
         * along with base and total selectivities, and corresponding
1954
         * selectivities for the overlap term P(A AND B).
1955
         */
1956
0
        mcv_sel = mcv_clause_selectivity_or(root, stat, mcv_list,
1957
0
                          clause, &or_matches,
1958
0
                          &mcv_basesel,
1959
0
                          &overlap_mcvsel,
1960
0
                          &overlap_basesel,
1961
0
                          &mcv_totalsel);
1962
1963
        /*
1964
         * Combine the simple and multi-column estimates.
1965
         *
1966
         * If this clause is a simple single-column clause, then we
1967
         * just use the simple selectivity estimate for it, since the
1968
         * multi-column statistics are unlikely to improve on that
1969
         * (and in fact could make it worse).  For the overlap, we
1970
         * always make use of the multi-column statistics.
1971
         */
1972
0
        if (bms_is_member(listidx, simple_clauses))
1973
0
          clause_sel = simple_sel;
1974
0
        else
1975
0
          clause_sel = mcv_combine_selectivities(simple_sel,
1976
0
                               mcv_sel,
1977
0
                               mcv_basesel,
1978
0
                               mcv_totalsel);
1979
1980
0
        overlap_sel = mcv_combine_selectivities(overlap_simple_sel,
1981
0
                            overlap_mcvsel,
1982
0
                            overlap_basesel,
1983
0
                            mcv_totalsel);
1984
1985
        /* Factor these into the result for this statistics object */
1986
0
        stat_sel += clause_sel - overlap_sel;
1987
0
        CLAMP_PROBABILITY(stat_sel);
1988
1989
0
        listidx++;
1990
0
      }
1991
1992
      /*
1993
       * Factor the result for this statistics object into the overall
1994
       * result.  We treat the results from each separate statistics
1995
       * object as independent of one another.
1996
       */
1997
0
      sel = sel + stat_sel - sel * stat_sel;
1998
0
    }
1999
0
    else          /* Implicitly-ANDed list of clauses */
2000
0
    {
2001
0
      Selectivity simple_sel,
2002
0
            mcv_sel,
2003
0
            mcv_basesel,
2004
0
            mcv_totalsel,
2005
0
            stat_sel;
2006
2007
      /*
2008
       * "Simple" selectivity, i.e. without any extended statistics,
2009
       * essentially assuming independence of the columns/clauses.
2010
       */
2011
0
      simple_sel = clauselist_selectivity_ext(root, stat_clauses,
2012
0
                          varRelid, jointype,
2013
0
                          sjinfo, false);
2014
2015
      /*
2016
       * Multi-column estimate using MCV statistics, along with base and
2017
       * total selectivities.
2018
       */
2019
0
      mcv_sel = mcv_clauselist_selectivity(root, stat, stat_clauses,
2020
0
                         varRelid, jointype, sjinfo,
2021
0
                         rel, &mcv_basesel,
2022
0
                         &mcv_totalsel);
2023
2024
      /* Combine the simple and multi-column estimates. */
2025
0
      stat_sel = mcv_combine_selectivities(simple_sel,
2026
0
                         mcv_sel,
2027
0
                         mcv_basesel,
2028
0
                         mcv_totalsel);
2029
2030
      /* Factor this into the overall result */
2031
0
      sel *= stat_sel;
2032
0
    }
2033
0
  }
2034
2035
0
  return sel;
2036
0
}
2037
2038
/*
2039
 * statext_clauselist_selectivity
2040
 *    Estimate clauses using the best multi-column statistics.
2041
 */
2042
Selectivity
2043
statext_clauselist_selectivity(PlannerInfo *root, List *clauses, int varRelid,
2044
                 JoinType jointype, SpecialJoinInfo *sjinfo,
2045
                 RelOptInfo *rel, Bitmapset **estimatedclauses,
2046
                 bool is_or)
2047
0
{
2048
0
  Selectivity sel;
2049
2050
  /* First, try estimating clauses using a multivariate MCV list. */
2051
0
  sel = statext_mcv_clauselist_selectivity(root, clauses, varRelid, jointype,
2052
0
                       sjinfo, rel, estimatedclauses, is_or);
2053
2054
  /*
2055
   * Functional dependencies only work for clauses connected by AND, so for
2056
   * OR clauses we're done.
2057
   */
2058
0
  if (is_or)
2059
0
    return sel;
2060
2061
  /*
2062
   * Then, apply functional dependencies on the remaining clauses by calling
2063
   * dependencies_clauselist_selectivity.  Pass 'estimatedclauses' so the
2064
   * function can properly skip clauses already estimated above.
2065
   *
2066
   * The reasoning for applying dependencies last is that the more complex
2067
   * stats can track more complex correlations between the attributes, and
2068
   * so may be considered more reliable.
2069
   *
2070
   * For example, MCV list can give us an exact selectivity for values in
2071
   * two columns, while functional dependencies can only provide information
2072
   * about the overall strength of the dependency.
2073
   */
2074
0
  sel *= dependencies_clauselist_selectivity(root, clauses, varRelid,
2075
0
                         jointype, sjinfo, rel,
2076
0
                         estimatedclauses);
2077
2078
0
  return sel;
2079
0
}
2080
2081
/*
2082
 * examine_opclause_args
2083
 *    Split an operator expression's arguments into Expr and Const parts.
2084
 *
2085
 * Attempts to match the arguments to either (Expr op Const) or (Const op
2086
 * Expr), possibly with a RelabelType on top. When the expression matches this
2087
 * form, returns true, otherwise returns false.
2088
 *
2089
 * Optionally returns pointers to the extracted Expr/Const nodes, when passed
2090
 * non-null pointers (exprp, cstp and expronleftp). The expronleftp flag
2091
 * specifies on which side of the operator we found the expression node.
2092
 */
2093
bool
2094
examine_opclause_args(List *args, Node **exprp, Const **cstp,
2095
            bool *expronleftp)
2096
0
{
2097
0
  Node     *expr;
2098
0
  Const    *cst;
2099
0
  bool    expronleft;
2100
0
  Node     *leftop,
2101
0
         *rightop;
2102
2103
  /* enforced by statext_is_compatible_clause_internal */
2104
0
  Assert(list_length(args) == 2);
2105
2106
0
  leftop = linitial(args);
2107
0
  rightop = lsecond(args);
2108
2109
  /* strip RelabelType from either side of the expression */
2110
0
  if (IsA(leftop, RelabelType))
2111
0
    leftop = (Node *) ((RelabelType *) leftop)->arg;
2112
2113
0
  if (IsA(rightop, RelabelType))
2114
0
    rightop = (Node *) ((RelabelType *) rightop)->arg;
2115
2116
0
  if (IsA(rightop, Const))
2117
0
  {
2118
0
    expr = leftop;
2119
0
    cst = (Const *) rightop;
2120
0
    expronleft = true;
2121
0
  }
2122
0
  else if (IsA(leftop, Const))
2123
0
  {
2124
0
    expr = rightop;
2125
0
    cst = (Const *) leftop;
2126
0
    expronleft = false;
2127
0
  }
2128
0
  else
2129
0
    return false;
2130
2131
  /* return pointers to the extracted parts if requested */
2132
0
  if (exprp)
2133
0
    *exprp = expr;
2134
2135
0
  if (cstp)
2136
0
    *cstp = cst;
2137
2138
0
  if (expronleftp)
2139
0
    *expronleftp = expronleft;
2140
2141
0
  return true;
2142
0
}
2143
2144
2145
/*
2146
 * Compute statistics about expressions of a relation.
2147
 */
2148
static void
2149
compute_expr_stats(Relation onerel, AnlExprData *exprdata, int nexprs,
2150
           HeapTuple *rows, int numrows)
2151
0
{
2152
0
  MemoryContext expr_context,
2153
0
        old_context;
2154
0
  int     ind,
2155
0
        i;
2156
2157
0
  expr_context = AllocSetContextCreate(CurrentMemoryContext,
2158
0
                     "Analyze Expression",
2159
0
                     ALLOCSET_DEFAULT_SIZES);
2160
0
  old_context = MemoryContextSwitchTo(expr_context);
2161
2162
0
  for (ind = 0; ind < nexprs; ind++)
2163
0
  {
2164
0
    AnlExprData *thisdata = &exprdata[ind];
2165
0
    VacAttrStats *stats = thisdata->vacattrstat;
2166
0
    Node     *expr = thisdata->expr;
2167
0
    TupleTableSlot *slot;
2168
0
    EState     *estate;
2169
0
    ExprContext *econtext;
2170
0
    Datum    *exprvals;
2171
0
    bool     *exprnulls;
2172
0
    ExprState  *exprstate;
2173
0
    int     tcnt;
2174
2175
    /* Are we still in the main context? */
2176
0
    Assert(CurrentMemoryContext == expr_context);
2177
2178
    /*
2179
     * Need an EState for evaluation of expressions.  Create it in the
2180
     * per-expression context to be sure it gets cleaned up at the bottom
2181
     * of the loop.
2182
     */
2183
0
    estate = CreateExecutorState();
2184
0
    econtext = GetPerTupleExprContext(estate);
2185
2186
    /* Set up expression evaluation state */
2187
0
    exprstate = ExecPrepareExpr((Expr *) expr, estate);
2188
2189
    /* Need a slot to hold the current heap tuple, too */
2190
0
    slot = MakeSingleTupleTableSlot(RelationGetDescr(onerel),
2191
0
                    &TTSOpsHeapTuple);
2192
2193
    /* Arrange for econtext's scan tuple to be the tuple under test */
2194
0
    econtext->ecxt_scantuple = slot;
2195
2196
    /* Compute and save expression values */
2197
0
    exprvals = palloc_array(Datum, numrows);
2198
0
    exprnulls = palloc_array(bool, numrows);
2199
2200
0
    tcnt = 0;
2201
0
    for (i = 0; i < numrows; i++)
2202
0
    {
2203
0
      Datum   datum;
2204
0
      bool    isnull;
2205
2206
      /*
2207
       * Reset the per-tuple context each time, to reclaim any cruft
2208
       * left behind by evaluating the statistics expressions.
2209
       */
2210
0
      ResetExprContext(econtext);
2211
2212
      /* Set up for expression evaluation */
2213
0
      ExecStoreHeapTuple(rows[i], slot, false);
2214
2215
      /*
2216
       * Evaluate the expression. We do this in the per-tuple context so
2217
       * as not to leak memory, and then copy the result into the
2218
       * context created at the beginning of this function.
2219
       */
2220
0
      datum = ExecEvalExprSwitchContext(exprstate,
2221
0
                        GetPerTupleExprContext(estate),
2222
0
                        &isnull);
2223
0
      if (isnull)
2224
0
      {
2225
0
        exprvals[tcnt] = (Datum) 0;
2226
0
        exprnulls[tcnt] = true;
2227
0
      }
2228
0
      else
2229
0
      {
2230
        /* Make sure we copy the data into the context. */
2231
0
        Assert(CurrentMemoryContext == expr_context);
2232
2233
0
        exprvals[tcnt] = datumCopy(datum,
2234
0
                       stats->attrtype->typbyval,
2235
0
                       stats->attrtype->typlen);
2236
0
        exprnulls[tcnt] = false;
2237
0
      }
2238
2239
0
      tcnt++;
2240
0
    }
2241
2242
    /*
2243
     * Now we can compute the statistics for the expression columns.
2244
     *
2245
     * XXX Unlike compute_index_stats we don't need to switch and reset
2246
     * memory contexts here, because we're only computing stats for a
2247
     * single expression (and not iterating over many indexes), so we just
2248
     * do it in expr_context. Note that compute_stats copies the result
2249
     * into stats->anl_context, so it does not disappear.
2250
     */
2251
0
    if (tcnt > 0)
2252
0
    {
2253
0
      AttributeOpts *aopt =
2254
0
        get_attribute_options(onerel->rd_id, stats->tupattnum);
2255
2256
0
      stats->exprvals = exprvals;
2257
0
      stats->exprnulls = exprnulls;
2258
0
      stats->rowstride = 1;
2259
0
      stats->compute_stats(stats,
2260
0
                 expr_fetch_func,
2261
0
                 tcnt,
2262
0
                 tcnt);
2263
2264
      /*
2265
       * If the n_distinct option is specified, it overrides the above
2266
       * computation.
2267
       */
2268
0
      if (aopt != NULL && aopt->n_distinct != 0.0)
2269
0
        stats->stadistinct = aopt->n_distinct;
2270
0
    }
2271
2272
    /* And clean up */
2273
0
    MemoryContextSwitchTo(expr_context);
2274
2275
0
    ExecDropSingleTupleTableSlot(slot);
2276
0
    FreeExecutorState(estate);
2277
0
    MemoryContextReset(expr_context);
2278
0
  }
2279
2280
0
  MemoryContextSwitchTo(old_context);
2281
0
  MemoryContextDelete(expr_context);
2282
0
}
2283
2284
2285
/*
2286
 * Fetch function for analyzing statistics object expressions.
2287
 *
2288
 * We have not bothered to construct tuples from the data, instead the data
2289
 * is just in Datum arrays.
2290
 */
2291
static Datum
2292
expr_fetch_func(VacAttrStatsP stats, int rownum, bool *isNull)
2293
0
{
2294
0
  int     i;
2295
2296
  /* exprvals and exprnulls are already offset for proper column */
2297
0
  i = rownum * stats->rowstride;
2298
0
  *isNull = stats->exprnulls[i];
2299
0
  return stats->exprvals[i];
2300
0
}
2301
2302
/*
2303
 * Build analyze data for a list of expressions. As this is not tied
2304
 * directly to a relation (table or index), we have to fake some of
2305
 * the fields in examine_expression().
2306
 */
2307
static AnlExprData *
2308
build_expr_data(List *exprs, int stattarget)
2309
0
{
2310
0
  int     idx;
2311
0
  int     nexprs = list_length(exprs);
2312
0
  AnlExprData *exprdata;
2313
0
  ListCell   *lc;
2314
2315
0
  exprdata = palloc0_array(AnlExprData, nexprs);
2316
2317
0
  idx = 0;
2318
0
  foreach(lc, exprs)
2319
0
  {
2320
0
    Node     *expr = (Node *) lfirst(lc);
2321
0
    AnlExprData *thisdata = &exprdata[idx];
2322
2323
0
    thisdata->expr = expr;
2324
0
    thisdata->vacattrstat = examine_expression(expr, stattarget);
2325
0
    if (thisdata->vacattrstat == NULL)
2326
0
    {
2327
0
      pfree(exprdata);
2328
0
      return NULL;
2329
0
    }
2330
0
    idx++;
2331
0
  }
2332
2333
0
  return exprdata;
2334
0
}
2335
2336
/* form an array of pg_statistic rows (per update_attstats) */
2337
static Datum
2338
serialize_expr_stats(AnlExprData *exprdata, int nexprs)
2339
0
{
2340
0
  int     exprno;
2341
0
  Oid     typOid;
2342
0
  Relation  sd;
2343
2344
0
  ArrayBuildState *astate = NULL;
2345
2346
0
  sd = table_open(StatisticRelationId, RowExclusiveLock);
2347
2348
  /* lookup OID of composite type for pg_statistic */
2349
0
  typOid = get_rel_type_id(StatisticRelationId);
2350
0
  if (!OidIsValid(typOid))
2351
0
    ereport(ERROR,
2352
0
        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2353
0
         errmsg("relation \"%s\" does not have a composite type",
2354
0
            "pg_statistic")));
2355
2356
0
  for (exprno = 0; exprno < nexprs; exprno++)
2357
0
  {
2358
0
    int     i,
2359
0
          k;
2360
0
    VacAttrStats *stats = exprdata[exprno].vacattrstat;
2361
2362
0
    Datum   values[Natts_pg_statistic];
2363
0
    bool    nulls[Natts_pg_statistic];
2364
0
    HeapTuple stup;
2365
2366
0
    if (!stats->stats_valid)
2367
0
    {
2368
0
      astate = accumArrayResult(astate,
2369
0
                    (Datum) 0,
2370
0
                    true,
2371
0
                    typOid,
2372
0
                    CurrentMemoryContext);
2373
0
      continue;
2374
0
    }
2375
2376
    /*
2377
     * Construct a new pg_statistic tuple
2378
     */
2379
0
    for (i = 0; i < Natts_pg_statistic; ++i)
2380
0
    {
2381
0
      nulls[i] = false;
2382
0
    }
2383
2384
0
    values[Anum_pg_statistic_starelid - 1] = ObjectIdGetDatum(InvalidOid);
2385
0
    values[Anum_pg_statistic_staattnum - 1] = Int16GetDatum(InvalidAttrNumber);
2386
0
    values[Anum_pg_statistic_stainherit - 1] = BoolGetDatum(false);
2387
0
    values[Anum_pg_statistic_stanullfrac - 1] = Float4GetDatum(stats->stanullfrac);
2388
0
    values[Anum_pg_statistic_stawidth - 1] = Int32GetDatum(stats->stawidth);
2389
0
    values[Anum_pg_statistic_stadistinct - 1] = Float4GetDatum(stats->stadistinct);
2390
0
    i = Anum_pg_statistic_stakind1 - 1;
2391
0
    for (k = 0; k < STATISTIC_NUM_SLOTS; k++)
2392
0
    {
2393
0
      values[i++] = Int16GetDatum(stats->stakind[k]); /* stakindN */
2394
0
    }
2395
0
    i = Anum_pg_statistic_staop1 - 1;
2396
0
    for (k = 0; k < STATISTIC_NUM_SLOTS; k++)
2397
0
    {
2398
0
      values[i++] = ObjectIdGetDatum(stats->staop[k]);  /* staopN */
2399
0
    }
2400
0
    i = Anum_pg_statistic_stacoll1 - 1;
2401
0
    for (k = 0; k < STATISTIC_NUM_SLOTS; k++)
2402
0
    {
2403
0
      values[i++] = ObjectIdGetDatum(stats->stacoll[k]);  /* stacollN */
2404
0
    }
2405
0
    i = Anum_pg_statistic_stanumbers1 - 1;
2406
0
    for (k = 0; k < STATISTIC_NUM_SLOTS; k++)
2407
0
    {
2408
0
      int     nnum = stats->numnumbers[k];
2409
2410
0
      if (nnum > 0)
2411
0
      {
2412
0
        int     n;
2413
0
        Datum    *numdatums = palloc_array(Datum, nnum);
2414
0
        ArrayType  *arry;
2415
2416
0
        for (n = 0; n < nnum; n++)
2417
0
          numdatums[n] = Float4GetDatum(stats->stanumbers[k][n]);
2418
0
        arry = construct_array_builtin(numdatums, nnum, FLOAT4OID);
2419
0
        values[i++] = PointerGetDatum(arry); /* stanumbersN */
2420
0
      }
2421
0
      else
2422
0
      {
2423
0
        nulls[i] = true;
2424
0
        values[i++] = (Datum) 0;
2425
0
      }
2426
0
    }
2427
0
    i = Anum_pg_statistic_stavalues1 - 1;
2428
0
    for (k = 0; k < STATISTIC_NUM_SLOTS; k++)
2429
0
    {
2430
0
      if (stats->numvalues[k] > 0)
2431
0
      {
2432
0
        ArrayType  *arry;
2433
2434
0
        arry = construct_array(stats->stavalues[k],
2435
0
                     stats->numvalues[k],
2436
0
                     stats->statypid[k],
2437
0
                     stats->statyplen[k],
2438
0
                     stats->statypbyval[k],
2439
0
                     stats->statypalign[k]);
2440
0
        values[i++] = PointerGetDatum(arry); /* stavaluesN */
2441
0
      }
2442
0
      else
2443
0
      {
2444
0
        nulls[i] = true;
2445
0
        values[i++] = (Datum) 0;
2446
0
      }
2447
0
    }
2448
2449
0
    stup = heap_form_tuple(RelationGetDescr(sd), values, nulls);
2450
2451
0
    astate = accumArrayResult(astate,
2452
0
                  heap_copy_tuple_as_datum(stup, RelationGetDescr(sd)),
2453
0
                  false,
2454
0
                  typOid,
2455
0
                  CurrentMemoryContext);
2456
0
  }
2457
2458
0
  table_close(sd, RowExclusiveLock);
2459
2460
0
  return makeArrayResult(astate, CurrentMemoryContext);
2461
0
}
2462
2463
/*
2464
 * Loads pg_statistic record from expression statistics for expression
2465
 * identified by the supplied index.
2466
 *
2467
 * Returns the pg_statistic record found, or NULL if there is no statistics
2468
 * data to use.
2469
 */
2470
HeapTuple
2471
statext_expressions_load(Oid stxoid, bool inh, int idx)
2472
0
{
2473
0
  bool    isnull;
2474
0
  Datum   value;
2475
0
  HeapTuple htup;
2476
0
  ExpandedArrayHeader *eah;
2477
0
  HeapTupleHeader td;
2478
0
  HeapTupleData tmptup;
2479
0
  HeapTuple tup;
2480
2481
0
  htup = SearchSysCache2(STATEXTDATASTXOID,
2482
0
               ObjectIdGetDatum(stxoid), BoolGetDatum(inh));
2483
0
  if (!HeapTupleIsValid(htup))
2484
0
    elog(ERROR, "cache lookup failed for statistics object %u", stxoid);
2485
2486
0
  value = SysCacheGetAttr(STATEXTDATASTXOID, htup,
2487
0
              Anum_pg_statistic_ext_data_stxdexpr, &isnull);
2488
0
  if (isnull)
2489
0
    elog(ERROR,
2490
0
       "requested statistics kind \"%c\" is not yet built for statistics object %u",
2491
0
       STATS_EXT_EXPRESSIONS, stxoid);
2492
2493
0
  eah = DatumGetExpandedArray(value);
2494
2495
0
  deconstruct_expanded_array(eah);
2496
2497
0
  if (eah->dnulls && eah->dnulls[idx])
2498
0
  {
2499
    /* No data found for this expression, give up. */
2500
0
    ReleaseSysCache(htup);
2501
0
    return NULL;
2502
0
  }
2503
2504
0
  td = DatumGetHeapTupleHeader(eah->dvalues[idx]);
2505
2506
  /* Build a temporary HeapTuple control structure */
2507
0
  tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
2508
0
  ItemPointerSetInvalid(&(tmptup.t_self));
2509
0
  tmptup.t_tableOid = InvalidOid;
2510
0
  tmptup.t_data = td;
2511
2512
0
  tup = heap_copytuple(&tmptup);
2513
2514
0
  ReleaseSysCache(htup);
2515
2516
0
  return tup;
2517
0
}
2518
2519
/*
2520
 * Evaluate the expressions, so that we can use the results to build
2521
 * all the requested statistics types. This matters especially for
2522
 * expensive expressions, of course.
2523
 *
2524
 * Returns NULL if an expression cannot be analyzed.
2525
 */
2526
static StatsBuildData *
2527
make_build_data(Relation rel, StatExtEntry *stat, int numrows, HeapTuple *rows,
2528
        VacAttrStats **stats, int stattarget)
2529
0
{
2530
  /* evaluated expressions */
2531
0
  StatsBuildData *result;
2532
0
  char     *ptr;
2533
0
  Size    len;
2534
2535
0
  int     i;
2536
0
  int     k;
2537
0
  int     idx;
2538
0
  TupleTableSlot *slot;
2539
0
  EState     *estate;
2540
0
  ExprContext *econtext;
2541
0
  List     *exprstates = NIL;
2542
0
  int     nkeys = bms_num_members(stat->columns) + list_length(stat->exprs);
2543
0
  ListCell   *lc;
2544
2545
  /* allocate everything as a single chunk, so we can free it easily */
2546
0
  len = MAXALIGN(sizeof(StatsBuildData));
2547
0
  len += MAXALIGN(sizeof(AttrNumber) * nkeys); /* attnums */
2548
0
  len += MAXALIGN(sizeof(VacAttrStats *) * nkeys); /* stats */
2549
2550
  /* values */
2551
0
  len += MAXALIGN(sizeof(Datum *) * nkeys);
2552
0
  len += nkeys * MAXALIGN(sizeof(Datum) * numrows);
2553
2554
  /* nulls */
2555
0
  len += MAXALIGN(sizeof(bool *) * nkeys);
2556
0
  len += nkeys * MAXALIGN(sizeof(bool) * numrows);
2557
2558
0
  ptr = palloc(len);
2559
2560
  /* set the pointers */
2561
0
  result = (StatsBuildData *) ptr;
2562
0
  ptr += MAXALIGN(sizeof(StatsBuildData));
2563
2564
  /* attnums */
2565
0
  result->attnums = (AttrNumber *) ptr;
2566
0
  ptr += MAXALIGN(sizeof(AttrNumber) * nkeys);
2567
2568
  /* stats */
2569
0
  result->stats = (VacAttrStats **) ptr;
2570
0
  ptr += MAXALIGN(sizeof(VacAttrStats *) * nkeys);
2571
2572
  /* values */
2573
0
  result->values = (Datum **) ptr;
2574
0
  ptr += MAXALIGN(sizeof(Datum *) * nkeys);
2575
2576
  /* nulls */
2577
0
  result->nulls = (bool **) ptr;
2578
0
  ptr += MAXALIGN(sizeof(bool *) * nkeys);
2579
2580
0
  for (i = 0; i < nkeys; i++)
2581
0
  {
2582
0
    result->values[i] = (Datum *) ptr;
2583
0
    ptr += MAXALIGN(sizeof(Datum) * numrows);
2584
2585
0
    result->nulls[i] = (bool *) ptr;
2586
0
    ptr += MAXALIGN(sizeof(bool) * numrows);
2587
0
  }
2588
2589
0
  Assert((ptr - (char *) result) == len);
2590
2591
  /* we have it allocated, so let's fill the values */
2592
0
  result->nattnums = nkeys;
2593
0
  result->numrows = numrows;
2594
2595
  /* fill the attribute info - first attributes, then expressions */
2596
0
  idx = 0;
2597
0
  k = -1;
2598
0
  while ((k = bms_next_member(stat->columns, k)) >= 0)
2599
0
  {
2600
0
    result->attnums[idx] = k;
2601
0
    result->stats[idx] = stats[idx];
2602
2603
0
    idx++;
2604
0
  }
2605
2606
0
  k = -1;
2607
0
  foreach(lc, stat->exprs)
2608
0
  {
2609
0
    Node     *expr = (Node *) lfirst(lc);
2610
2611
0
    result->attnums[idx] = k;
2612
0
    result->stats[idx] = examine_expression(expr, stattarget);
2613
2614
0
    if (result->stats[idx] == NULL)
2615
0
    {
2616
0
      pfree(result);
2617
0
      return NULL;
2618
0
    }
2619
2620
0
    idx++;
2621
0
    k--;
2622
0
  }
2623
2624
  /* first extract values for all the regular attributes */
2625
0
  for (i = 0; i < numrows; i++)
2626
0
  {
2627
0
    idx = 0;
2628
0
    k = -1;
2629
0
    while ((k = bms_next_member(stat->columns, k)) >= 0)
2630
0
    {
2631
0
      result->values[idx][i] = heap_getattr(rows[i], k,
2632
0
                          result->stats[idx]->tupDesc,
2633
0
                          &result->nulls[idx][i]);
2634
2635
0
      idx++;
2636
0
    }
2637
0
  }
2638
2639
  /* Need an EState for evaluation expressions. */
2640
0
  estate = CreateExecutorState();
2641
0
  econtext = GetPerTupleExprContext(estate);
2642
2643
  /* Need a slot to hold the current heap tuple, too */
2644
0
  slot = MakeSingleTupleTableSlot(RelationGetDescr(rel),
2645
0
                  &TTSOpsHeapTuple);
2646
2647
  /* Arrange for econtext's scan tuple to be the tuple under test */
2648
0
  econtext->ecxt_scantuple = slot;
2649
2650
  /* Set up expression evaluation state */
2651
0
  exprstates = ExecPrepareExprList(stat->exprs, estate);
2652
2653
0
  for (i = 0; i < numrows; i++)
2654
0
  {
2655
    /*
2656
     * Reset the per-tuple context each time, to reclaim any cruft left
2657
     * behind by evaluating the statistics object expressions.
2658
     */
2659
0
    ResetExprContext(econtext);
2660
2661
    /* Set up for expression evaluation */
2662
0
    ExecStoreHeapTuple(rows[i], slot, false);
2663
2664
0
    idx = bms_num_members(stat->columns);
2665
0
    foreach(lc, exprstates)
2666
0
    {
2667
0
      Datum   datum;
2668
0
      bool    isnull;
2669
0
      ExprState  *exprstate = (ExprState *) lfirst(lc);
2670
2671
      /*
2672
       * XXX This probably leaks memory. Maybe we should use
2673
       * ExecEvalExprSwitchContext but then we need to copy the result
2674
       * somewhere else.
2675
       */
2676
0
      datum = ExecEvalExpr(exprstate,
2677
0
                 GetPerTupleExprContext(estate),
2678
0
                 &isnull);
2679
0
      if (isnull)
2680
0
      {
2681
0
        result->values[idx][i] = (Datum) 0;
2682
0
        result->nulls[idx][i] = true;
2683
0
      }
2684
0
      else
2685
0
      {
2686
0
        result->values[idx][i] = datum;
2687
0
        result->nulls[idx][i] = false;
2688
0
      }
2689
2690
0
      idx++;
2691
0
    }
2692
0
  }
2693
2694
0
  ExecDropSingleTupleTableSlot(slot);
2695
0
  FreeExecutorState(estate);
2696
2697
0
  return result;
2698
0
}