PostgreSQL Source Code  git master
extended_stats.c File Reference
#include "postgres.h"
#include "access/detoast.h"
#include "access/genam.h"
#include "access/htup_details.h"
#include "access/table.h"
#include "catalog/indexing.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_statistic_ext.h"
#include "catalog/pg_statistic_ext_data.h"
#include "commands/progress.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/optimizer.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "statistics/extended_stats_internal.h"
#include "statistics/statistics.h"
#include "utils/acl.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/selfuncs.h"
#include "utils/syscache.h"
Include dependency graph for extended_stats.c:

Go to the source code of this file.

Data Structures

struct  StatExtEntry
 

Macros

#define WIDTH_THRESHOLD   1024
 

Typedefs

typedef struct StatExtEntry StatExtEntry
 

Functions

static Listfetch_statentries_for_relation (Relation pg_statext, Oid relid)
 
static VacAttrStats ** lookup_var_attr_stats (Relation rel, Bitmapset *attrs, int nvacatts, VacAttrStats **vacatts)
 
static void statext_store (Oid relid, MVNDistinct *ndistinct, MVDependencies *dependencies, MCVList *mcv, VacAttrStats **stats)
 
static int statext_compute_stattarget (int stattarget, int natts, VacAttrStats **stats)
 
void BuildRelationExtStatistics (Relation onerel, double totalrows, int numrows, HeapTuple *rows, int natts, VacAttrStats **vacattrstats)
 
int ComputeExtStatisticsRows (Relation onerel, int natts, VacAttrStats **vacattrstats)
 
bool statext_is_kind_built (HeapTuple htup, char type)
 
MultiSortSupport multi_sort_init (int ndims)
 
void multi_sort_add_dimension (MultiSortSupport mss, int sortdim, Oid oper, Oid collation)
 
int multi_sort_compare (const void *a, const void *b, void *arg)
 
int multi_sort_compare_dim (int dim, const SortItem *a, const SortItem *b, MultiSortSupport mss)
 
int multi_sort_compare_dims (int start, int end, const SortItem *a, const SortItem *b, MultiSortSupport mss)
 
int compare_scalars_simple (const void *a, const void *b, void *arg)
 
int compare_datums_simple (Datum a, Datum b, SortSupport ssup)
 
void * bsearch_arg (const void *key, const void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *, void *), void *arg)
 
AttrNumberbuild_attnums_array (Bitmapset *attrs, int *numattrs)
 
SortItembuild_sorted_items (int numrows, int *nitems, HeapTuple *rows, TupleDesc tdesc, MultiSortSupport mss, int numattrs, AttrNumber *attnums)
 
bool has_stats_of_kind (List *stats, char requiredkind)
 
StatisticExtInfochoose_best_statistics (List *stats, char requiredkind, Bitmapset **clause_attnums, int nclauses)
 
static bool statext_is_compatible_clause_internal (PlannerInfo *root, Node *clause, Index relid, Bitmapset **attnums)
 
static bool statext_is_compatible_clause (PlannerInfo *root, Node *clause, Index relid, Bitmapset **attnums)
 
static Selectivity statext_mcv_clauselist_selectivity (PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, RelOptInfo *rel, Bitmapset **estimatedclauses)
 
Selectivity statext_clauselist_selectivity (PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, RelOptInfo *rel, Bitmapset **estimatedclauses)
 
bool examine_clause_args (List *args, Var **varp, Const **cstp, bool *varonleftp)
 

Macro Definition Documentation

◆ WIDTH_THRESHOLD

#define WIDTH_THRESHOLD   1024

Definition at line 55 of file extended_stats.c.

Referenced by build_sorted_items().

Typedef Documentation

◆ StatExtEntry

typedef struct StatExtEntry StatExtEntry

Function Documentation

◆ bsearch_arg()

void* bsearch_arg ( const void *  key,
const void *  base,
size_t  nmemb,
size_t  size,
int(*)(const void *, const void *, void *)  compar,
void *  arg 
)

Definition at line 664 of file extended_stats.c.

References arg, idx(), and sort-test::key.

Referenced by statext_mcv_build(), and statext_mcv_serialize().

667 {
668  size_t l,
669  u,
670  idx;
671  const void *p;
672  int comparison;
673 
674  l = 0;
675  u = nmemb;
676  while (l < u)
677  {
678  idx = (l + u) / 2;
679  p = (void *) (((const char *) base) + (idx * size));
680  comparison = (*compar) (key, p, arg);
681 
682  if (comparison < 0)
683  u = idx;
684  else if (comparison > 0)
685  l = idx + 1;
686  else
687  return (void *) p;
688  }
689 
690  return NULL;
691 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
void * arg

◆ build_attnums_array()

AttrNumber* build_attnums_array ( Bitmapset attrs,
int *  numattrs 
)

Definition at line 702 of file extended_stats.c.

References Assert, AttrNumberIsForUserDefinedAttr, bms_next_member(), bms_num_members(), i, MaxAttrNumber, and palloc().

Referenced by dependency_degree(), statext_dependencies_build(), and statext_mcv_build().

703 {
704  int i,
705  j;
706  AttrNumber *attnums;
707  int num = bms_num_members(attrs);
708 
709  if (numattrs)
710  *numattrs = num;
711 
712  /* build attnums from the bitmapset */
713  attnums = (AttrNumber *) palloc(sizeof(AttrNumber) * num);
714  i = 0;
715  j = -1;
716  while ((j = bms_next_member(attrs, j)) >= 0)
717  {
718  /*
719  * Make sure the bitmap contains only user-defined attributes. As
720  * bitmaps can't contain negative values, this can be violated in two
721  * ways. Firstly, the bitmap might contain 0 as a member, and secondly
722  * the integer value might be larger than MaxAttrNumber.
723  */
725  Assert(j <= MaxAttrNumber);
726 
727  attnums[i++] = (AttrNumber) j;
728 
729  /* protect against overflows */
730  Assert(i <= num);
731  }
732 
733  return attnums;
734 }
#define MaxAttrNumber
Definition: attnum.h:24
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
#define AttrNumberIsForUserDefinedAttr(attributeNumber)
Definition: attnum.h:41
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:646
#define Assert(condition)
Definition: c.h:745
void * palloc(Size size)
Definition: mcxt.c:950
int i
int16 AttrNumber
Definition: attnum.h:21

◆ build_sorted_items()

SortItem* build_sorted_items ( int  numrows,
int *  nitems,
HeapTuple rows,
TupleDesc  tdesc,
MultiSortSupport  mss,
int  numattrs,
AttrNumber attnums 
)

Definition at line 744 of file extended_stats.c.

References Assert, attlen, heap_getattr, i, idx(), multi_sort_compare(), palloc0(), pfree(), PG_DETOAST_DATUM, PointerGetDatum, qsort_arg(), toast_raw_datum_size(), TupleDescAttr, value, values, and WIDTH_THRESHOLD.

Referenced by dependency_degree(), and statext_mcv_build().

746 {
747  int i,
748  j,
749  len,
750  idx;
751  int nvalues = numrows * numattrs;
752 
753  SortItem *items;
754  Datum *values;
755  bool *isnull;
756  char *ptr;
757 
758  /* Compute the total amount of memory we need (both items and values). */
759  len = numrows * sizeof(SortItem) + nvalues * (sizeof(Datum) + sizeof(bool));
760 
761  /* Allocate the memory and split it into the pieces. */
762  ptr = palloc0(len);
763 
764  /* items to sort */
765  items = (SortItem *) ptr;
766  ptr += numrows * sizeof(SortItem);
767 
768  /* values and null flags */
769  values = (Datum *) ptr;
770  ptr += nvalues * sizeof(Datum);
771 
772  isnull = (bool *) ptr;
773  ptr += nvalues * sizeof(bool);
774 
775  /* make sure we consumed the whole buffer exactly */
776  Assert((ptr - (char *) items) == len);
777 
778  /* fix the pointers to Datum and bool arrays */
779  idx = 0;
780  for (i = 0; i < numrows; i++)
781  {
782  bool toowide = false;
783 
784  items[idx].values = &values[idx * numattrs];
785  items[idx].isnull = &isnull[idx * numattrs];
786 
787  /* load the values/null flags from sample rows */
788  for (j = 0; j < numattrs; j++)
789  {
790  Datum value;
791  bool isnull;
792 
793  value = heap_getattr(rows[i], attnums[j], tdesc, &isnull);
794 
795  /*
796  * If this is a varlena value, check if it's too wide and if yes
797  * then skip the whole item. Otherwise detoast the value.
798  *
799  * XXX It may happen that we've already detoasted some preceding
800  * values for the current item. We don't bother to cleanup those
801  * on the assumption that those are small (below WIDTH_THRESHOLD)
802  * and will be discarded at the end of analyze.
803  */
804  if ((!isnull) &&
805  (TupleDescAttr(tdesc, attnums[j] - 1)->attlen == -1))
806  {
808  {
809  toowide = true;
810  break;
811  }
812 
813  value = PointerGetDatum(PG_DETOAST_DATUM(value));
814  }
815 
816  items[idx].values[j] = value;
817  items[idx].isnull[j] = isnull;
818  }
819 
820  if (toowide)
821  continue;
822 
823  idx++;
824  }
825 
826  /* store the actual number of items (ignoring the too-wide ones) */
827  *nitems = idx;
828 
829  /* all items were too wide */
830  if (idx == 0)
831  {
832  /* everything is allocated as a single chunk */
833  pfree(items);
834  return NULL;
835  }
836 
837  /* do the sort, using the multi-sort */
838  qsort_arg((void *) items, idx, sizeof(SortItem),
839  multi_sort_compare, mss);
840 
841  return items;
842 }
#define PointerGetDatum(X)
Definition: postgres.h:556
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
void pfree(void *pointer)
Definition: mcxt.c:1057
Size toast_raw_datum_size(Datum value)
Definition: detoast.c:502
void qsort_arg(void *base, size_t nel, size_t elsize, qsort_arg_comparator cmp, void *arg)
Definition: qsort_arg.c:113
int16 attlen
Definition: pg_attribute.h:64
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:762
void * palloc0(Size size)
Definition: mcxt.c:981
uintptr_t Datum
Definition: postgres.h:367
struct SortItem SortItem
#define WIDTH_THRESHOLD
static struct @143 value
#define Assert(condition)
Definition: c.h:745
int multi_sort_compare(const void *a, const void *b, void *arg)
static Datum values[MAXATTR]
Definition: bootstrap.c:165
int i
#define PG_DETOAST_DATUM(datum)
Definition: fmgr.h:240
unsigned char bool
Definition: c.h:324

◆ BuildRelationExtStatistics()

void BuildRelationExtStatistics ( Relation  onerel,
double  totalrows,
int  numrows,
HeapTuple rows,
int  natts,
VacAttrStats **  vacattrstats 
)

Definition at line 89 of file extended_stats.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, bms_num_members(), StatExtEntry::columns, CurrentMemoryContext, ereport, errcode(), errmsg(), errtable(), fetch_statentries_for_relation(), get_namespace_name(), IsAutoVacuumWorkerProcess(), lfirst, lfirst_int, list_length(), lookup_var_attr_stats(), MemoryContextDelete(), MemoryContextSwitchTo(), StatExtEntry::name, NIL, pgstat_progress_update_multi_param(), pgstat_progress_update_param(), PROGRESS_ANALYZE_EXT_STATS_COMPUTED, PROGRESS_ANALYZE_EXT_STATS_TOTAL, PROGRESS_ANALYZE_PHASE, PROGRESS_ANALYZE_PHASE_COMPUTE_EXT_STATS, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, RowExclusiveLock, StatExtEntry::schema, stat, statext_compute_stattarget(), statext_dependencies_build(), statext_mcv_build(), statext_ndistinct_build(), statext_store(), StatExtEntry::statOid, STATS_MAX_DIMENSIONS, StatExtEntry::stattarget, table_close(), table_open(), StatExtEntry::types, val, and WARNING.

Referenced by do_analyze_rel().

92 {
93  Relation pg_stext;
94  ListCell *lc;
95  List *stats;
96  MemoryContext cxt;
97  MemoryContext oldcxt;
98  int64 ext_cnt;
99 
101  "BuildRelationExtStatistics",
103  oldcxt = MemoryContextSwitchTo(cxt);
104 
105  pg_stext = table_open(StatisticExtRelationId, RowExclusiveLock);
106  stats = fetch_statentries_for_relation(pg_stext, RelationGetRelid(onerel));
107 
108  /* report this phase */
109  if (stats != NIL)
110  {
111  const int index[] = {
114  };
115  const int64 val[] = {
117  list_length(stats)
118  };
119 
120  pgstat_progress_update_multi_param(2, index, val);
121  }
122 
123  ext_cnt = 0;
124  foreach(lc, stats)
125  {
127  MVNDistinct *ndistinct = NULL;
128  MVDependencies *dependencies = NULL;
129  MCVList *mcv = NULL;
130  VacAttrStats **stats;
131  ListCell *lc2;
132  int stattarget;
133 
134  /*
135  * Check if we can build these stats based on the column analyzed. If
136  * not, report this fact (except in autovacuum) and move on.
137  */
138  stats = lookup_var_attr_stats(onerel, stat->columns,
139  natts, vacattrstats);
140  if (!stats)
141  {
144  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
145  errmsg("statistics object \"%s.%s\" could not be computed for relation \"%s.%s\"",
146  stat->schema, stat->name,
147  get_namespace_name(onerel->rd_rel->relnamespace),
148  RelationGetRelationName(onerel)),
149  errtable(onerel)));
150  continue;
151  }
152 
153  /* check allowed number of dimensions */
154  Assert(bms_num_members(stat->columns) >= 2 &&
156 
157  /* compute statistics target for this statistics */
158  stattarget = statext_compute_stattarget(stat->stattarget,
159  bms_num_members(stat->columns),
160  stats);
161 
162  /*
163  * Don't rebuild statistics objects with statistics target set to 0
164  * (we just leave the existing values around, just like we do for
165  * regular per-column statistics).
166  */
167  if (stattarget == 0)
168  continue;
169 
170  /* compute statistic of each requested type */
171  foreach(lc2, stat->types)
172  {
173  char t = (char) lfirst_int(lc2);
174 
175  if (t == STATS_EXT_NDISTINCT)
176  ndistinct = statext_ndistinct_build(totalrows, numrows, rows,
177  stat->columns, stats);
178  else if (t == STATS_EXT_DEPENDENCIES)
179  dependencies = statext_dependencies_build(numrows, rows,
180  stat->columns, stats);
181  else if (t == STATS_EXT_MCV)
182  mcv = statext_mcv_build(numrows, rows, stat->columns, stats,
183  totalrows, stattarget);
184  }
185 
186  /* store the statistics in the catalog */
187  statext_store(stat->statOid, ndistinct, dependencies, mcv, stats);
188 
189  /* for reporting progress */
191  ++ext_cnt);
192  }
193 
194  table_close(pg_stext, RowExclusiveLock);
195 
196  MemoryContextSwitchTo(oldcxt);
197  MemoryContextDelete(cxt);
198 }
#define NIL
Definition: pg_list.h:65
MCVList * statext_mcv_build(int numrows, HeapTuple *rows, Bitmapset *attrs, VacAttrStats **stats, double totalrows, int stattarget)
Definition: mcv.c:183
#define PROGRESS_ANALYZE_EXT_STATS_COMPUTED
Definition: progress.h:42
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:212
#define AllocSetContextCreate
Definition: memutils.h:170
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define PROGRESS_ANALYZE_PHASE
Definition: progress.h:38
void pgstat_progress_update_param(int index, int64 val)
Definition: pgstat.c:3231
static int statext_compute_stattarget(int stattarget, int natts, VacAttrStats **stats)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:610
static List * fetch_statentries_for_relation(Relation pg_statext, Oid relid)
Form_pg_class rd_rel
Definition: rel.h:109
Bitmapset * columns
Definition: type.h:89
#define lfirst_int(lc)
Definition: pg_list.h:191
#define PROGRESS_ANALYZE_EXT_STATS_TOTAL
Definition: progress.h:41
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:646
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
#define RowExclusiveLock
Definition: lockdefs.h:38
#define RelationGetRelationName(relation)
Definition: rel.h:490
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:3325
#define WARNING
Definition: elog.h:40
#define stat(a, b)
Definition: win32_port.h:255
MVDependencies * statext_dependencies_build(int numrows, HeapTuple *rows, Bitmapset *attrs, VacAttrStats **stats)
Definition: dependencies.c:363
#define ereport(elevel,...)
Definition: elog.h:144
MVNDistinct * statext_ndistinct_build(double totalrows, int numrows, HeapTuple *rows, Bitmapset *attrs, VacAttrStats **stats)
Definition: mvdistinct.c:86
#define PROGRESS_ANALYZE_PHASE_COMPUTE_EXT_STATS
Definition: progress.h:51
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:190
void pgstat_progress_update_multi_param(int nparam, const int *index, const int64 *val)
Definition: pgstat.c:3253
static int list_length(const List *l)
Definition: pg_list.h:169
static void statext_store(Oid relid, MVNDistinct *ndistinct, MVDependencies *dependencies, MCVList *mcv, VacAttrStats **stats)
#define STATS_MAX_DIMENSIONS
Definition: statistics.h:19
int errmsg(const char *fmt,...)
Definition: elog.c:824
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
int errtable(Relation rel)
Definition: relcache.c:5497
static VacAttrStats ** lookup_var_attr_stats(Relation rel, Bitmapset *attrs, int nvacatts, VacAttrStats **vacatts)
#define RelationGetRelid(relation)
Definition: rel.h:456
long val
Definition: informix.c:664

◆ choose_best_statistics()

StatisticExtInfo* choose_best_statistics ( List stats,
char  requiredkind,
Bitmapset **  clause_attnums,
int  nclauses 
)

Definition at line 883 of file extended_stats.c.

References bms_add_members(), bms_free(), bms_is_subset(), bms_num_members(), i, StatisticExtInfo::keys, StatisticExtInfo::kind, lfirst, and STATS_MAX_DIMENSIONS.

Referenced by statext_mcv_clauselist_selectivity().

885 {
886  ListCell *lc;
887  StatisticExtInfo *best_match = NULL;
888  int best_num_matched = 2; /* goal #1: maximize */
889  int best_match_keys = (STATS_MAX_DIMENSIONS + 1); /* goal #2: minimize */
890 
891  foreach(lc, stats)
892  {
893  int i;
894  StatisticExtInfo *info = (StatisticExtInfo *) lfirst(lc);
895  Bitmapset *matched = NULL;
896  int num_matched;
897  int numkeys;
898 
899  /* skip statistics that are not of the correct type */
900  if (info->kind != requiredkind)
901  continue;
902 
903  /*
904  * Collect attributes in remaining (unestimated) clauses fully covered
905  * by this statistic object.
906  */
907  for (i = 0; i < nclauses; i++)
908  {
909  /* ignore incompatible/estimated clauses */
910  if (!clause_attnums[i])
911  continue;
912 
913  /* ignore clauses that are not covered by this object */
914  if (!bms_is_subset(clause_attnums[i], info->keys))
915  continue;
916 
917  matched = bms_add_members(matched, clause_attnums[i]);
918  }
919 
920  num_matched = bms_num_members(matched);
921  bms_free(matched);
922 
923  /*
924  * save the actual number of keys in the stats so that we can choose
925  * the narrowest stats with the most matching keys.
926  */
927  numkeys = bms_num_members(info->keys);
928 
929  /*
930  * Use this object when it increases the number of matched clauses or
931  * when it matches the same number of attributes but these stats have
932  * fewer keys than any previous match.
933  */
934  if (num_matched > best_num_matched ||
935  (num_matched == best_num_matched && numkeys < best_match_keys))
936  {
937  best_match = info;
938  best_num_matched = num_matched;
939  best_match_keys = numkeys;
940  }
941  }
942 
943  return best_match;
944 }
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:315
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:646
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
#define lfirst(lc)
Definition: pg_list.h:190
Bitmapset * keys
Definition: pathnodes.h:915
#define STATS_MAX_DIMENSIONS
Definition: statistics.h:19
int i
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793

◆ compare_datums_simple()

int compare_datums_simple ( Datum  a,
Datum  b,
SortSupport  ssup 
)

Definition at line 657 of file extended_stats.c.

References ApplySortComparator().

Referenced by compare_scalars_simple(), and statext_mcv_serialize().

658 {
659  return ApplySortComparator(a, false, b, false, ssup);
660 }
static int ApplySortComparator(Datum datum1, bool isNull1, Datum datum2, bool isNull2, SortSupport ssup)
Definition: sortsupport.h:200

◆ compare_scalars_simple()

int compare_scalars_simple ( const void *  a,
const void *  b,
void *  arg 
)

Definition at line 649 of file extended_stats.c.

References compare_datums_simple().

Referenced by statext_mcv_serialize().

650 {
651  return compare_datums_simple(*(Datum *) a,
652  *(Datum *) b,
653  (SortSupport) arg);
654 }
int compare_datums_simple(Datum a, Datum b, SortSupport ssup)
uintptr_t Datum
Definition: postgres.h:367
void * arg

◆ ComputeExtStatisticsRows()

int ComputeExtStatisticsRows ( Relation  onerel,
int  natts,
VacAttrStats **  vacattrstats 
)

Definition at line 214 of file extended_stats.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, bms_num_members(), StatExtEntry::columns, CurrentMemoryContext, fetch_statentries_for_relation(), lfirst, lookup_var_attr_stats(), MemoryContextDelete(), MemoryContextSwitchTo(), RelationGetRelid, RowExclusiveLock, stat, statext_compute_stattarget(), StatExtEntry::stattarget, table_close(), and table_open().

Referenced by do_analyze_rel().

216 {
217  Relation pg_stext;
218  ListCell *lc;
219  List *lstats;
220  MemoryContext cxt;
221  MemoryContext oldcxt;
222  int result = 0;
223 
225  "ComputeExtStatisticsRows",
227  oldcxt = MemoryContextSwitchTo(cxt);
228 
229  pg_stext = table_open(StatisticExtRelationId, RowExclusiveLock);
230  lstats = fetch_statentries_for_relation(pg_stext, RelationGetRelid(onerel));
231 
232  foreach(lc, lstats)
233  {
235  int stattarget;
236  VacAttrStats **stats;
237  int nattrs = bms_num_members(stat->columns);
238 
239  /*
240  * Check if we can build this statistics object based on the columns
241  * analyzed. If not, ignore it (don't report anything, we'll do that
242  * during the actual build BuildRelationExtStatistics).
243  */
244  stats = lookup_var_attr_stats(onerel, stat->columns,
245  natts, vacattrstats);
246 
247  if (!stats)
248  continue;
249 
250  /*
251  * Compute statistics target, based on what's set for the statistic
252  * object itself, and for its attributes.
253  */
254  stattarget = statext_compute_stattarget(stat->stattarget,
255  nattrs, stats);
256 
257  /* Use the largest value for all statistics objects. */
258  if (stattarget > result)
259  result = stattarget;
260  }
261 
262  table_close(pg_stext, RowExclusiveLock);
263 
264  MemoryContextSwitchTo(oldcxt);
265  MemoryContextDelete(cxt);
266 
267  /* compute sample size based on the statistics target */
268  return (300 * result);
269 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:212
#define AllocSetContextCreate
Definition: memutils.h:170
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
static int statext_compute_stattarget(int stattarget, int natts, VacAttrStats **stats)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static List * fetch_statentries_for_relation(Relation pg_statext, Oid relid)
Bitmapset * columns
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:646
#define RowExclusiveLock
Definition: lockdefs.h:38
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define stat(a, b)
Definition: win32_port.h:255
int result
Definition: header.h:19
#define lfirst(lc)
Definition: pg_list.h:190
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
static VacAttrStats ** lookup_var_attr_stats(Relation rel, Bitmapset *attrs, int nvacatts, VacAttrStats **vacatts)
#define RelationGetRelid(relation)
Definition: rel.h:456

◆ examine_clause_args()

bool examine_clause_args ( List args,
Var **  varp,
Const **  cstp,
bool varonleftp 
)

Definition at line 1461 of file extended_stats.c.

References arg, Assert, IsA, linitial, list_length(), and lsecond.

Referenced by mcv_get_match_bitmap(), and statext_is_compatible_clause_internal().

1462 {
1463  Var *var;
1464  Const *cst;
1465  bool varonleft;
1466  Node *leftop,
1467  *rightop;
1468 
1469  /* enforced by statext_is_compatible_clause_internal */
1470  Assert(list_length(args) == 2);
1471 
1472  leftop = linitial(args);
1473  rightop = lsecond(args);
1474 
1475  /* strip RelabelType from either side of the expression */
1476  if (IsA(leftop, RelabelType))
1477  leftop = (Node *) ((RelabelType *) leftop)->arg;
1478 
1479  if (IsA(rightop, RelabelType))
1480  rightop = (Node *) ((RelabelType *) rightop)->arg;
1481 
1482  if (IsA(leftop, Var) && IsA(rightop, Const))
1483  {
1484  var = (Var *) leftop;
1485  cst = (Const *) rightop;
1486  varonleft = true;
1487  }
1488  else if (IsA(leftop, Const) && IsA(rightop, Var))
1489  {
1490  var = (Var *) rightop;
1491  cst = (Const *) leftop;
1492  varonleft = false;
1493  }
1494  else
1495  return false;
1496 
1497  /* return pointers to the extracted parts if requested */
1498  if (varp)
1499  *varp = var;
1500 
1501  if (cstp)
1502  *cstp = cst;
1503 
1504  if (varonleftp)
1505  *varonleftp = varonleft;
1506 
1507  return true;
1508 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
Definition: nodes.h:529
Definition: primnodes.h:181
#define lsecond(l)
Definition: pg_list.h:200
#define linitial(l)
Definition: pg_list.h:195
#define Assert(condition)
Definition: c.h:745
static int list_length(const List *l)
Definition: pg_list.h:169
void * arg

◆ fetch_statentries_for_relation()

static List * fetch_statentries_for_relation ( Relation  pg_statext,
Oid  relid 
)
static

Definition at line 363 of file extended_stats.c.

References ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_NDIM, Assert, bms_add_member(), BTEqualStrategyNumber, StatExtEntry::columns, DatumGetArrayTypeP, elog, ERROR, get_namespace_name(), GETSTRUCT, HeapTupleIsValid, i, lappend(), lappend_int(), StatExtEntry::name, NameStr, NIL, ObjectIdGetDatum, palloc0(), pstrdup(), ScanKeyInit(), StatExtEntry::schema, STATEXTOID, StatisticExtRelidIndexId, StatExtEntry::statOid, StatExtEntry::stattarget, SysCacheGetAttr(), systable_beginscan(), systable_endscan(), systable_getnext(), and StatExtEntry::types.

Referenced by BuildRelationExtStatistics(), and ComputeExtStatisticsRows().

364 {
365  SysScanDesc scan;
366  ScanKeyData skey;
367  HeapTuple htup;
368  List *result = NIL;
369 
370  /*
371  * Prepare to scan pg_statistic_ext for entries having stxrelid = this
372  * rel.
373  */
374  ScanKeyInit(&skey,
375  Anum_pg_statistic_ext_stxrelid,
376  BTEqualStrategyNumber, F_OIDEQ,
377  ObjectIdGetDatum(relid));
378 
379  scan = systable_beginscan(pg_statext, StatisticExtRelidIndexId, true,
380  NULL, 1, &skey);
381 
382  while (HeapTupleIsValid(htup = systable_getnext(scan)))
383  {
384  StatExtEntry *entry;
385  Datum datum;
386  bool isnull;
387  int i;
388  ArrayType *arr;
389  char *enabled;
390  Form_pg_statistic_ext staForm;
391 
392  entry = palloc0(sizeof(StatExtEntry));
393  staForm = (Form_pg_statistic_ext) GETSTRUCT(htup);
394  entry->statOid = staForm->oid;
395  entry->schema = get_namespace_name(staForm->stxnamespace);
396  entry->name = pstrdup(NameStr(staForm->stxname));
397  entry->stattarget = staForm->stxstattarget;
398  for (i = 0; i < staForm->stxkeys.dim1; i++)
399  {
400  entry->columns = bms_add_member(entry->columns,
401  staForm->stxkeys.values[i]);
402  }
403 
404  /* decode the stxkind char array into a list of chars */
405  datum = SysCacheGetAttr(STATEXTOID, htup,
406  Anum_pg_statistic_ext_stxkind, &isnull);
407  Assert(!isnull);
408  arr = DatumGetArrayTypeP(datum);
409  if (ARR_NDIM(arr) != 1 ||
410  ARR_HASNULL(arr) ||
411  ARR_ELEMTYPE(arr) != CHAROID)
412  elog(ERROR, "stxkind is not a 1-D char array");
413  enabled = (char *) ARR_DATA_PTR(arr);
414  for (i = 0; i < ARR_DIMS(arr)[0]; i++)
415  {
416  Assert((enabled[i] == STATS_EXT_NDISTINCT) ||
417  (enabled[i] == STATS_EXT_DEPENDENCIES) ||
418  (enabled[i] == STATS_EXT_MCV));
419  entry->types = lappend_int(entry->types, (int) enabled[i]);
420  }
421 
422  result = lappend(result, entry);
423  }
424 
425  systable_endscan(scan);
426 
427  return result;
428 }
#define NIL
Definition: pg_list.h:65
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:569
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
char * pstrdup(const char *in)
Definition: mcxt.c:1187
#define StatisticExtRelidIndexId
Definition: indexing.h:246
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:357
Bitmapset * columns
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:476
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ARR_DIMS(a)
Definition: array.h:282
#define ARR_DATA_PTR(a)
Definition: array.h:310
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
#define ARR_HASNULL(a)
Definition: array.h:279
List * lappend_int(List *list, int datum)
Definition: list.c:339
List * lappend(List *list, void *datum)
Definition: list.c:321
void * palloc0(Size size)
Definition: mcxt.c:981
uintptr_t Datum
Definition: postgres.h:367
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1377
int result
Definition: header.h:19
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:745
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define ARR_NDIM(a)
Definition: array.h:278
#define elog(elevel,...)
Definition: elog.h:214
int i
#define NameStr(name)
Definition: c.h:622
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Definition: pg_list.h:50
#define ARR_ELEMTYPE(a)
Definition: array.h:280
#define BTEqualStrategyNumber
Definition: stratnum.h:31
FormData_pg_statistic_ext * Form_pg_statistic_ext
#define DatumGetArrayTypeP(X)
Definition: array.h:249

◆ has_stats_of_kind()

bool has_stats_of_kind ( List stats,
char  requiredkind 
)

Definition at line 849 of file extended_stats.c.

References StatisticExtInfo::kind, lfirst, and stat.

Referenced by dependencies_clauselist_selectivity(), and statext_mcv_clauselist_selectivity().

850 {
851  ListCell *l;
852 
853  foreach(l, stats)
854  {
856 
857  if (stat->kind == requiredkind)
858  return true;
859  }
860 
861  return false;
862 }
#define stat(a, b)
Definition: win32_port.h:255
#define lfirst(lc)
Definition: pg_list.h:190

◆ lookup_var_attr_stats()

static VacAttrStats ** lookup_var_attr_stats ( Relation  rel,
Bitmapset attrs,
int  nvacatts,
VacAttrStats **  vacatts 
)
static

Definition at line 438 of file extended_stats.c.

References Assert, bms_next_member(), bms_num_members(), i, palloc(), and pfree().

Referenced by BuildRelationExtStatistics(), and ComputeExtStatisticsRows().

440 {
441  int i = 0;
442  int x = -1;
443  VacAttrStats **stats;
444 
445  stats = (VacAttrStats **)
446  palloc(bms_num_members(attrs) * sizeof(VacAttrStats *));
447 
448  /* lookup VacAttrStats info for the requested columns (same attnum) */
449  while ((x = bms_next_member(attrs, x)) >= 0)
450  {
451  int j;
452 
453  stats[i] = NULL;
454  for (j = 0; j < nvacatts; j++)
455  {
456  if (x == vacatts[j]->tupattnum)
457  {
458  stats[i] = vacatts[j];
459  break;
460  }
461  }
462 
463  if (!stats[i])
464  {
465  /*
466  * Looks like stats were not gathered for one of the columns
467  * required. We'll be unable to build the extended stats without
468  * this column.
469  */
470  pfree(stats);
471  return NULL;
472  }
473 
474  /*
475  * Sanity check that the column is not dropped - stats should have
476  * been removed in this case.
477  */
478  Assert(!stats[i]->attr->attisdropped);
479 
480  i++;
481  }
482 
483  return stats;
484 }
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
void pfree(void *pointer)
Definition: mcxt.c:1057
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:646
#define Assert(condition)
Definition: c.h:745
void * palloc(Size size)
Definition: mcxt.c:950
int i

◆ multi_sort_add_dimension()

void multi_sort_add_dimension ( MultiSortSupport  mss,
int  sortdim,
Oid  oper,
Oid  collation 
)

Definition at line 581 of file extended_stats.c.

References CurrentMemoryContext, PrepareSortSupportFromOrderingOp(), MultiSortSupportData::ssup, SortSupportData::ssup_collation, SortSupportData::ssup_cxt, and SortSupportData::ssup_nulls_first.

Referenced by build_mss(), dependency_degree(), and ndistinct_for_combination().

583 {
584  SortSupport ssup = &mss->ssup[sortdim];
585 
587  ssup->ssup_collation = collation;
588  ssup->ssup_nulls_first = false;
589 
591 }
bool ssup_nulls_first
Definition: sortsupport.h:75
void PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
Definition: sortsupport.c:135
SortSupportData ssup[FLEXIBLE_ARRAY_MEMBER]
MemoryContext ssup_cxt
Definition: sortsupport.h:66
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
Definition: parse_oper.c:382

◆ multi_sort_compare()

int multi_sort_compare ( const void *  a,
const void *  b,
void *  arg 
)

Definition at line 595 of file extended_stats.c.

References ApplySortComparator(), compare(), i, SortItem::isnull, MultiSortSupportData::ndims, MultiSortSupportData::ssup, and SortItem::values.

Referenced by build_distinct_groups(), build_sorted_items(), count_distinct_groups(), ndistinct_for_combination(), and statext_mcv_build().

596 {
598  SortItem *ia = (SortItem *) a;
599  SortItem *ib = (SortItem *) b;
600  int i;
601 
602  for (i = 0; i < mss->ndims; i++)
603  {
604  int compare;
605 
606  compare = ApplySortComparator(ia->values[i], ia->isnull[i],
607  ib->values[i], ib->isnull[i],
608  &mss->ssup[i]);
609 
610  if (compare != 0)
611  return compare;
612  }
613 
614  /* equal by default */
615  return 0;
616 }
static int compare(const void *arg1, const void *arg2)
Definition: geqo_pool.c:145
SortSupportData ssup[FLEXIBLE_ARRAY_MEMBER]
int i
void * arg
MultiSortSupportData * MultiSortSupport
static int ApplySortComparator(Datum datum1, bool isNull1, Datum datum2, bool isNull2, SortSupport ssup)
Definition: sortsupport.h:200

◆ multi_sort_compare_dim()

int multi_sort_compare_dim ( int  dim,
const SortItem a,
const SortItem b,
MultiSortSupport  mss 
)

Definition at line 620 of file extended_stats.c.

References ApplySortComparator(), SortItem::isnull, MultiSortSupportData::ssup, and SortItem::values.

Referenced by dependency_degree().

622 {
623  return ApplySortComparator(a->values[dim], a->isnull[dim],
624  b->values[dim], b->isnull[dim],
625  &mss->ssup[dim]);
626 }
SortSupportData ssup[FLEXIBLE_ARRAY_MEMBER]
static int ApplySortComparator(Datum datum1, bool isNull1, Datum datum2, bool isNull2, SortSupport ssup)
Definition: sortsupport.h:200

◆ multi_sort_compare_dims()

int multi_sort_compare_dims ( int  start,
int  end,
const SortItem a,
const SortItem b,
MultiSortSupport  mss 
)

Definition at line 629 of file extended_stats.c.

References ApplySortComparator(), SortItem::isnull, MultiSortSupportData::ssup, and SortItem::values.

Referenced by dependency_degree().

632 {
633  int dim;
634 
635  for (dim = start; dim <= end; dim++)
636  {
637  int r = ApplySortComparator(a->values[dim], a->isnull[dim],
638  b->values[dim], b->isnull[dim],
639  &mss->ssup[dim]);
640 
641  if (r != 0)
642  return r;
643  }
644 
645  return 0;
646 }
SortSupportData ssup[FLEXIBLE_ARRAY_MEMBER]
static int ApplySortComparator(Datum datum1, bool isNull1, Datum datum2, bool isNull2, SortSupport ssup)
Definition: sortsupport.h:200

◆ multi_sort_init()

MultiSortSupport multi_sort_init ( int  ndims)

Definition at line 562 of file extended_stats.c.

References Assert, MultiSortSupportData::ndims, offsetof, and palloc0().

Referenced by build_mss(), dependency_degree(), and ndistinct_for_combination().

563 {
564  MultiSortSupport mss;
565 
566  Assert(ndims >= 2);
567 
569  + sizeof(SortSupportData) * ndims);
570 
571  mss->ndims = ndims;
572 
573  return mss;
574 }
struct SortSupportData SortSupportData
void * palloc0(Size size)
Definition: mcxt.c:981
#define Assert(condition)
Definition: c.h:745
MultiSortSupportData * MultiSortSupport
#define offsetof(type, field)
Definition: c.h:668

◆ statext_clauselist_selectivity()

Selectivity statext_clauselist_selectivity ( PlannerInfo root,
List clauses,
int  varRelid,
JoinType  jointype,
SpecialJoinInfo sjinfo,
RelOptInfo rel,
Bitmapset **  estimatedclauses 
)

Definition at line 1418 of file extended_stats.c.

References dependencies_clauselist_selectivity(), and statext_mcv_clauselist_selectivity().

Referenced by clauselist_selectivity().

1421 {
1422  Selectivity sel;
1423 
1424  /* First, try estimating clauses using a multivariate MCV list. */
1425  sel = statext_mcv_clauselist_selectivity(root, clauses, varRelid, jointype,
1426  sjinfo, rel, estimatedclauses);
1427 
1428  /*
1429  * Then, apply functional dependencies on the remaining clauses by calling
1430  * dependencies_clauselist_selectivity. Pass 'estimatedclauses' so the
1431  * function can properly skip clauses already estimated above.
1432  *
1433  * The reasoning for applying dependencies last is that the more complex
1434  * stats can track more complex correlations between the attributes, and
1435  * so may be considered more reliable.
1436  *
1437  * For example, MCV list can give us an exact selectivity for values in
1438  * two columns, while functional dependencies can only provide information
1439  * about the overall strength of the dependency.
1440  */
1441  sel *= dependencies_clauselist_selectivity(root, clauses, varRelid,
1442  jointype, sjinfo, rel,
1443  estimatedclauses);
1444 
1445  return sel;
1446 }
Selectivity dependencies_clauselist_selectivity(PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, RelOptInfo *rel, Bitmapset **estimatedclauses)
double Selectivity
Definition: nodes.h:662
static Selectivity statext_mcv_clauselist_selectivity(PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, RelOptInfo *rel, Bitmapset **estimatedclauses)

◆ statext_compute_stattarget()

static int statext_compute_stattarget ( int  stattarget,
int  natts,
VacAttrStats **  stats 
)
static

Definition at line 292 of file extended_stats.c.

References Assert, VacAttrStats::attr, default_statistics_target, i, and StatExtEntry::stattarget.

Referenced by BuildRelationExtStatistics(), and ComputeExtStatisticsRows().

293 {
294  int i;
295 
296  /*
297  * If there's statistics target set for the statistics object, use it. It
298  * may be set to 0 which disables building of that statistic.
299  */
300  if (stattarget >= 0)
301  return stattarget;
302 
303  /*
304  * The target for the statistics object is set to -1, in which case we
305  * look at the maximum target set for any of the attributes the object is
306  * defined on.
307  */
308  for (i = 0; i < nattrs; i++)
309  {
310  /* keep the maximmum statistics target */
311  if (stats[i]->attr->attstattarget > stattarget)
312  stattarget = stats[i]->attr->attstattarget;
313  }
314 
315  /*
316  * If the value is still negative (so neither the statistics object nor
317  * any of the columns have custom statistics target set), use the global
318  * default target.
319  */
320  if (stattarget < 0)
321  stattarget = default_statistics_target;
322 
323  /* As this point we should have a valid statistics target. */
324  Assert((stattarget >= 0) && (stattarget <= 10000));
325 
326  return stattarget;
327 }
Form_pg_attribute attr
Definition: vacuum.h:123
#define Assert(condition)
Definition: c.h:745
int i
int default_statistics_target
Definition: analyze.c:81

◆ statext_is_compatible_clause()

static bool statext_is_compatible_clause ( PlannerInfo root,
Node clause,
Index  relid,
Bitmapset **  attnums 
)
static

Definition at line 1170 of file extended_stats.c.

References ACL_SELECT, ACLCHECK_OK, ACLMASK_ALL, attnum, bms_is_member(), bms_membership(), bms_next_member(), BMS_SINGLETON, RangeTblEntry::checkAsUser, RestrictInfo::clause, RestrictInfo::clause_relids, GetUserId(), InvalidAttrNumber, IsA, pg_attribute_aclcheck(), pg_attribute_aclcheck_all(), pg_class_aclcheck(), RestrictInfo::pseudoconstant, RangeTblEntry::relid, PlannerInfo::simple_rte_array, and statext_is_compatible_clause_internal().

Referenced by statext_mcv_clauselist_selectivity().

1172 {
1173  RangeTblEntry *rte = root->simple_rte_array[relid];
1174  RestrictInfo *rinfo = (RestrictInfo *) clause;
1175  Oid userid;
1176 
1177  if (!IsA(rinfo, RestrictInfo))
1178  return false;
1179 
1180  /* Pseudoconstants are not really interesting here. */
1181  if (rinfo->pseudoconstant)
1182  return false;
1183 
1184  /* clauses referencing multiple varnos are incompatible */
1186  return false;
1187 
1188  /* Check the clause and determine what attributes it references. */
1189  if (!statext_is_compatible_clause_internal(root, (Node *) rinfo->clause,
1190  relid, attnums))
1191  return false;
1192 
1193  /*
1194  * Check that the user has permission to read all these attributes. Use
1195  * checkAsUser if it's set, in case we're accessing the table via a view.
1196  */
1197  userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
1198 
1199  if (pg_class_aclcheck(rte->relid, userid, ACL_SELECT) != ACLCHECK_OK)
1200  {
1201  /* Don't have table privilege, must check individual columns */
1202  if (bms_is_member(InvalidAttrNumber, *attnums))
1203  {
1204  /* Have a whole-row reference, must have access to all columns */
1205  if (pg_attribute_aclcheck_all(rte->relid, userid, ACL_SELECT,
1207  return false;
1208  }
1209  else
1210  {
1211  /* Check the columns referenced by the clause */
1212  int attnum = -1;
1213 
1214  while ((attnum = bms_next_member(*attnums, attnum)) >= 0)
1215  {
1216  if (pg_attribute_aclcheck(rte->relid, attnum, userid,
1217  ACL_SELECT) != ACLCHECK_OK)
1218  return false;
1219  }
1220  }
1221  }
1222 
1223  /* If we reach here, the clause is OK */
1224  return true;
1225 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode)
Definition: aclchk.c:4449
Oid GetUserId(void)
Definition: miscinit.c:476
Relids clause_relids
Definition: pathnodes.h:2000
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
bool pseudoconstant
Definition: pathnodes.h:1993
Definition: nodes.h:529
unsigned int Oid
Definition: postgres_ext.h:31
RangeTblEntry ** simple_rte_array
Definition: pathnodes.h:211
Expr * clause
Definition: pathnodes.h:1985
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:672
#define ACL_SELECT
Definition: parsenodes.h:75
int16 attnum
Definition: pg_attribute.h:79
AclResult pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode, AclMaskHow how)
Definition: aclchk.c:4478
#define InvalidAttrNumber
Definition: attnum.h:23
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4563
static bool statext_is_compatible_clause_internal(PlannerInfo *root, Node *clause, Index relid, Bitmapset **attnums)
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427

◆ statext_is_compatible_clause_internal()

static bool statext_is_compatible_clause_internal ( PlannerInfo root,
Node clause,
Index  relid,
Bitmapset **  attnums 
)
static

Definition at line 956 of file extended_stats.c.

References arg, NullTest::arg, OpExpr::args, ScalarArrayOpExpr::args, BoolExpr::args, AttrNumberIsForUserDefinedAttr, bms_add_member(), examine_clause_args(), get_func_leakproof(), get_opcode(), get_oprrest(), is_andclause(), is_notclause(), is_opclause(), is_orclause(), IsA, lfirst, list_length(), NIL, OpExpr::opno, ScalarArrayOpExpr::opno, RangeTblEntry::securityQuals, PlannerInfo::simple_rte_array, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by statext_is_compatible_clause().

958 {
959  /* Look inside any binary-compatible relabeling (as in examine_variable) */
960  if (IsA(clause, RelabelType))
961  clause = (Node *) ((RelabelType *) clause)->arg;
962 
963  /* plain Var references (boolean Vars or recursive checks) */
964  if (IsA(clause, Var))
965  {
966  Var *var = (Var *) clause;
967 
968  /* Ensure var is from the correct relation */
969  if (var->varno != relid)
970  return false;
971 
972  /* we also better ensure the Var is from the current level */
973  if (var->varlevelsup > 0)
974  return false;
975 
976  /* Also skip system attributes (we don't allow stats on those). */
978  return false;
979 
980  *attnums = bms_add_member(*attnums, var->varattno);
981 
982  return true;
983  }
984 
985  /* (Var op Const) or (Const op Var) */
986  if (is_opclause(clause))
987  {
988  RangeTblEntry *rte = root->simple_rte_array[relid];
989  OpExpr *expr = (OpExpr *) clause;
990  Var *var;
991 
992  /* Only expressions with two arguments are considered compatible. */
993  if (list_length(expr->args) != 2)
994  return false;
995 
996  /* Check if the expression has the right shape (one Var, one Const) */
997  if (!examine_clause_args(expr->args, &var, NULL, NULL))
998  return false;
999 
1000  /*
1001  * If it's not one of the supported operators ("=", "<", ">", etc.),
1002  * just ignore the clause, as it's not compatible with MCV lists.
1003  *
1004  * This uses the function for estimating selectivity, not the operator
1005  * directly (a bit awkward, but well ...).
1006  */
1007  switch (get_oprrest(expr->opno))
1008  {
1009  case F_EQSEL:
1010  case F_NEQSEL:
1011  case F_SCALARLTSEL:
1012  case F_SCALARLESEL:
1013  case F_SCALARGTSEL:
1014  case F_SCALARGESEL:
1015  /* supported, will continue with inspection of the Var */
1016  break;
1017 
1018  default:
1019  /* other estimators are considered unknown/unsupported */
1020  return false;
1021  }
1022 
1023  /*
1024  * If there are any securityQuals on the RTE from security barrier
1025  * views or RLS policies, then the user may not have access to all the
1026  * table's data, and we must check that the operator is leak-proof.
1027  *
1028  * If the operator is leaky, then we must ignore this clause for the
1029  * purposes of estimating with MCV lists, otherwise the operator might
1030  * reveal values from the MCV list that the user doesn't have
1031  * permission to see.
1032  */
1033  if (rte->securityQuals != NIL &&
1035  return false;
1036 
1037  return statext_is_compatible_clause_internal(root, (Node *) var,
1038  relid, attnums);
1039  }
1040 
1041  /* Var IN Array */
1042  if (IsA(clause, ScalarArrayOpExpr))
1043  {
1044  RangeTblEntry *rte = root->simple_rte_array[relid];
1045  ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) clause;
1046  Var *var;
1047 
1048  /* Only expressions with two arguments are considered compatible. */
1049  if (list_length(expr->args) != 2)
1050  return false;
1051 
1052  /* Check if the expression has the right shape (one Var, one Const) */
1053  if (!examine_clause_args(expr->args, &var, NULL, NULL))
1054  return false;
1055 
1056  /*
1057  * If it's not one of the supported operators ("=", "<", ">", etc.),
1058  * just ignore the clause, as it's not compatible with MCV lists.
1059  *
1060  * This uses the function for estimating selectivity, not the operator
1061  * directly (a bit awkward, but well ...).
1062  */
1063  switch (get_oprrest(expr->opno))
1064  {
1065  case F_EQSEL:
1066  case F_NEQSEL:
1067  case F_SCALARLTSEL:
1068  case F_SCALARLESEL:
1069  case F_SCALARGTSEL:
1070  case F_SCALARGESEL:
1071  /* supported, will continue with inspection of the Var */
1072  break;
1073 
1074  default:
1075  /* other estimators are considered unknown/unsupported */
1076  return false;
1077  }
1078 
1079  /*
1080  * If there are any securityQuals on the RTE from security barrier
1081  * views or RLS policies, then the user may not have access to all the
1082  * table's data, and we must check that the operator is leak-proof.
1083  *
1084  * If the operator is leaky, then we must ignore this clause for the
1085  * purposes of estimating with MCV lists, otherwise the operator might
1086  * reveal values from the MCV list that the user doesn't have
1087  * permission to see.
1088  */
1089  if (rte->securityQuals != NIL &&
1091  return false;
1092 
1093  return statext_is_compatible_clause_internal(root, (Node *) var,
1094  relid, attnums);
1095  }
1096 
1097  /* AND/OR/NOT clause */
1098  if (is_andclause(clause) ||
1099  is_orclause(clause) ||
1100  is_notclause(clause))
1101  {
1102  /*
1103  * AND/OR/NOT-clauses are supported if all sub-clauses are supported
1104  *
1105  * Perhaps we could improve this by handling mixed cases, when some of
1106  * the clauses are supported and some are not. Selectivity for the
1107  * supported subclauses would be computed using extended statistics,
1108  * and the remaining clauses would be estimated using the traditional
1109  * algorithm (product of selectivities).
1110  *
1111  * It however seems overly complex, and in a way we already do that
1112  * because if we reject the whole clause as unsupported here, it will
1113  * be eventually passed to clauselist_selectivity() which does exactly
1114  * this (split into supported/unsupported clauses etc).
1115  */
1116  BoolExpr *expr = (BoolExpr *) clause;
1117  ListCell *lc;
1118 
1119  foreach(lc, expr->args)
1120  {
1121  /*
1122  * Had we found incompatible clause in the arguments, treat the
1123  * whole clause as incompatible.
1124  */
1126  (Node *) lfirst(lc),
1127  relid, attnums))
1128  return false;
1129  }
1130 
1131  return true;
1132  }
1133 
1134  /* Var IS NULL */
1135  if (IsA(clause, NullTest))
1136  {
1137  NullTest *nt = (NullTest *) clause;
1138 
1139  /*
1140  * Only simple (Var IS NULL) expressions supported for now. Maybe we
1141  * could use examine_variable to fix this?
1142  */
1143  if (!IsA(nt->arg, Var))
1144  return false;
1145 
1146  return statext_is_compatible_clause_internal(root, (Node *) (nt->arg),
1147  relid, attnums);
1148  }
1149 
1150  return false;
1151 }
#define NIL
Definition: pg_list.h:65
bool get_func_leakproof(Oid funcid)
Definition: lsyscache.c:1749
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
Index varlevelsup
Definition: primnodes.h:191
static bool is_orclause(const void *clause)
Definition: nodeFuncs.h:106
List * securityQuals
Definition: parsenodes.h:1126
static bool is_andclause(const void *clause)
Definition: nodeFuncs.h:97
#define AttrNumberIsForUserDefinedAttr(attributeNumber)
Definition: attnum.h:41
Definition: nodes.h:529
AttrNumber varattno
Definition: primnodes.h:186
Definition: primnodes.h:181
Expr * arg
Definition: primnodes.h:1219
bool examine_clause_args(List *args, Var **varp, Const **cstp, bool *varonleftp)
RangeTblEntry ** simple_rte_array
Definition: pathnodes.h:211
Index varno
Definition: primnodes.h:184
static bool is_notclause(const void *clause)
Definition: nodeFuncs.h:115
RegProcedure get_oprrest(Oid opno)
Definition: lsyscache.c:1469
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1202
#define lfirst(lc)
Definition: pg_list.h:190
static int list_length(const List *l)
Definition: pg_list.h:169
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
List * args
Definition: primnodes.h:583
static bool statext_is_compatible_clause_internal(PlannerInfo *root, Node *clause, Index relid, Bitmapset **attnums)
void * arg
Oid opno
Definition: primnodes.h:516
static bool is_opclause(const void *clause)
Definition: nodeFuncs.h:66
List * args
Definition: primnodes.h:522

◆ statext_is_kind_built()

bool statext_is_kind_built ( HeapTuple  htup,
char  type 
)

Definition at line 334 of file extended_stats.c.

References attnum, elog, ERROR, and heap_attisnull().

Referenced by get_relation_statistics(), and UpdateStatisticsForTypeChange().

335 {
337 
338  switch (type)
339  {
340  case STATS_EXT_NDISTINCT:
341  attnum = Anum_pg_statistic_ext_data_stxdndistinct;
342  break;
343 
344  case STATS_EXT_DEPENDENCIES:
345  attnum = Anum_pg_statistic_ext_data_stxddependencies;
346  break;
347 
348  case STATS_EXT_MCV:
349  attnum = Anum_pg_statistic_ext_data_stxdmcv;
350  break;
351 
352  default:
353  elog(ERROR, "unexpected statistics type requested: %d", type);
354  }
355 
356  return !heap_attisnull(htup, attnum, NULL);
357 }
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:359
#define ERROR
Definition: elog.h:43
int16 attnum
Definition: pg_attribute.h:79
#define elog(elevel,...)
Definition: elog.h:214
int16 AttrNumber
Definition: attnum.h:21

◆ statext_mcv_clauselist_selectivity()

static Selectivity statext_mcv_clauselist_selectivity ( PlannerInfo root,
List clauses,
int  varRelid,
JoinType  jointype,
SpecialJoinInfo sjinfo,
RelOptInfo rel,
Bitmapset **  estimatedclauses 
)
static

Definition at line 1283 of file extended_stats.c.

References Assert, bms_add_member(), bms_free(), bms_is_member(), bms_is_subset(), choose_best_statistics(), CLAMP_PROBABILITY, clauselist_selectivity_simple(), has_stats_of_kind(), StatisticExtInfo::keys, StatisticExtInfo::kind, lappend(), lfirst, list_length(), mcv_clauselist_selectivity(), NIL, palloc(), RelOptInfo::relid, stat, statext_is_compatible_clause(), and RelOptInfo::statlist.

Referenced by statext_clauselist_selectivity().

1286 {
1287  ListCell *l;
1288  Bitmapset **list_attnums;
1289  int listidx;
1290  Selectivity sel = 1.0;
1291 
1292  /* check if there's any stats that might be useful for us. */
1293  if (!has_stats_of_kind(rel->statlist, STATS_EXT_MCV))
1294  return 1.0;
1295 
1296  list_attnums = (Bitmapset **) palloc(sizeof(Bitmapset *) *
1297  list_length(clauses));
1298 
1299  /*
1300  * Pre-process the clauses list to extract the attnums seen in each item.
1301  * We need to determine if there's any clauses which will be useful for
1302  * selectivity estimations with extended stats. Along the way we'll record
1303  * all of the attnums for each clause in a list which we'll reference
1304  * later so we don't need to repeat the same work again. We'll also keep
1305  * track of all attnums seen.
1306  *
1307  * We also skip clauses that we already estimated using different types of
1308  * statistics (we treat them as incompatible).
1309  */
1310  listidx = 0;
1311  foreach(l, clauses)
1312  {
1313  Node *clause = (Node *) lfirst(l);
1314  Bitmapset *attnums = NULL;
1315 
1316  if (!bms_is_member(listidx, *estimatedclauses) &&
1317  statext_is_compatible_clause(root, clause, rel->relid, &attnums))
1318  list_attnums[listidx] = attnums;
1319  else
1320  list_attnums[listidx] = NULL;
1321 
1322  listidx++;
1323  }
1324 
1325  /* apply as many extended statistics as possible */
1326  while (true)
1327  {
1329  List *stat_clauses;
1330  Selectivity simple_sel,
1331  mcv_sel,
1332  mcv_basesel,
1333  mcv_totalsel,
1334  other_sel,
1335  stat_sel;
1336 
1337  /* find the best suited statistics object for these attnums */
1338  stat = choose_best_statistics(rel->statlist, STATS_EXT_MCV,
1339  list_attnums, list_length(clauses));
1340 
1341  /*
1342  * if no (additional) matching stats could be found then we've nothing
1343  * to do
1344  */
1345  if (!stat)
1346  break;
1347 
1348  /* Ensure choose_best_statistics produced an expected stats type. */
1349  Assert(stat->kind == STATS_EXT_MCV);
1350 
1351  /* now filter the clauses to be estimated using the selected MCV */
1352  stat_clauses = NIL;
1353 
1354  listidx = 0;
1355  foreach(l, clauses)
1356  {
1357  /*
1358  * If the clause is compatible with the selected statistics, mark
1359  * it as estimated and add it to the list to estimate.
1360  */
1361  if (list_attnums[listidx] != NULL &&
1362  bms_is_subset(list_attnums[listidx], stat->keys))
1363  {
1364  stat_clauses = lappend(stat_clauses, (Node *) lfirst(l));
1365  *estimatedclauses = bms_add_member(*estimatedclauses, listidx);
1366 
1367  bms_free(list_attnums[listidx]);
1368  list_attnums[listidx] = NULL;
1369  }
1370 
1371  listidx++;
1372  }
1373 
1374  /*
1375  * First compute "simple" selectivity, i.e. without the extended
1376  * statistics, and essentially assuming independence of the
1377  * columns/clauses. We'll then use the various selectivities computed
1378  * from MCV list to improve it.
1379  */
1380  simple_sel = clauselist_selectivity_simple(root, stat_clauses, varRelid,
1381  jointype, sjinfo, NULL);
1382 
1383  /*
1384  * Now compute the multi-column estimate from the MCV list, along with
1385  * the other selectivities (base & total selectivity).
1386  */
1387  mcv_sel = mcv_clauselist_selectivity(root, stat, stat_clauses, varRelid,
1388  jointype, sjinfo, rel,
1389  &mcv_basesel, &mcv_totalsel);
1390 
1391  /* Estimated selectivity of values not covered by MCV matches */
1392  other_sel = simple_sel - mcv_basesel;
1393  CLAMP_PROBABILITY(other_sel);
1394 
1395  /* The non-MCV selectivity can't exceed the 1 - mcv_totalsel. */
1396  if (other_sel > 1.0 - mcv_totalsel)
1397  other_sel = 1.0 - mcv_totalsel;
1398 
1399  /*
1400  * Overall selectivity is the combination of MCV and non-MCV
1401  * estimates.
1402  */
1403  stat_sel = mcv_sel + other_sel;
1404  CLAMP_PROBABILITY(stat_sel);
1405 
1406  /* Factor the estimate from this MCV to the oveall estimate. */
1407  sel *= stat_sel;
1408  }
1409 
1410  return sel;
1411 }
#define NIL
Definition: pg_list.h:65
List * statlist
Definition: pathnodes.h:703
Definition: nodes.h:529
double Selectivity
Definition: nodes.h:662
Selectivity clauselist_selectivity_simple(PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, Bitmapset *estimatedclauses)
Definition: clausesel.c:150
#define CLAMP_PROBABILITY(p)
Definition: selfuncs.h:60
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:315
Index relid
Definition: pathnodes.h:693
List * lappend(List *list, void *datum)
Definition: list.c:321
#define stat(a, b)
Definition: win32_port.h:255
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:190
static int list_length(const List *l)
Definition: pg_list.h:169
static bool statext_is_compatible_clause(PlannerInfo *root, Node *clause, Index relid, Bitmapset **attnums)
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
Bitmapset * keys
Definition: pathnodes.h:915
void * palloc(Size size)
Definition: mcxt.c:950
Selectivity mcv_clauselist_selectivity(PlannerInfo *root, StatisticExtInfo *stat, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, RelOptInfo *rel, Selectivity *basesel, Selectivity *totalsel)
Definition: mcv.c:1903
Definition: pg_list.h:50
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
bool has_stats_of_kind(List *stats, char requiredkind)
StatisticExtInfo * choose_best_statistics(List *stats, char requiredkind, Bitmapset **clause_attnums, int nclauses)

◆ statext_store()

static void statext_store ( Oid  relid,
MVNDistinct ndistinct,
MVDependencies dependencies,
MCVList mcv,
VacAttrStats **  stats 
)
static

Definition at line 492 of file extended_stats.c.

References CatalogTupleUpdate(), elog, ERROR, heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, ObjectIdGetDatum, PointerGetDatum, RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), statext_dependencies_serialize(), statext_mcv_serialize(), statext_ndistinct_serialize(), STATEXTDATASTXOID, HeapTupleData::t_self, table_close(), table_open(), and values.

Referenced by BuildRelationExtStatistics().

495 {
496  Relation pg_stextdata;
497  HeapTuple stup,
498  oldtup;
499  Datum values[Natts_pg_statistic_ext_data];
500  bool nulls[Natts_pg_statistic_ext_data];
501  bool replaces[Natts_pg_statistic_ext_data];
502 
503  pg_stextdata = table_open(StatisticExtDataRelationId, RowExclusiveLock);
504 
505  memset(nulls, true, sizeof(nulls));
506  memset(replaces, false, sizeof(replaces));
507  memset(values, 0, sizeof(values));
508 
509  /*
510  * Construct a new pg_statistic_ext_data tuple, replacing the calculated
511  * stats.
512  */
513  if (ndistinct != NULL)
514  {
515  bytea *data = statext_ndistinct_serialize(ndistinct);
516 
517  nulls[Anum_pg_statistic_ext_data_stxdndistinct - 1] = (data == NULL);
518  values[Anum_pg_statistic_ext_data_stxdndistinct - 1] = PointerGetDatum(data);
519  }
520 
521  if (dependencies != NULL)
522  {
523  bytea *data = statext_dependencies_serialize(dependencies);
524 
525  nulls[Anum_pg_statistic_ext_data_stxddependencies - 1] = (data == NULL);
526  values[Anum_pg_statistic_ext_data_stxddependencies - 1] = PointerGetDatum(data);
527  }
528  if (mcv != NULL)
529  {
530  bytea *data = statext_mcv_serialize(mcv, stats);
531 
532  nulls[Anum_pg_statistic_ext_data_stxdmcv - 1] = (data == NULL);
533  values[Anum_pg_statistic_ext_data_stxdmcv - 1] = PointerGetDatum(data);
534  }
535 
536  /* always replace the value (either by bytea or NULL) */
537  replaces[Anum_pg_statistic_ext_data_stxdndistinct - 1] = true;
538  replaces[Anum_pg_statistic_ext_data_stxddependencies - 1] = true;
539  replaces[Anum_pg_statistic_ext_data_stxdmcv - 1] = true;
540 
541  /* there should already be a pg_statistic_ext_data tuple */
543  if (!HeapTupleIsValid(oldtup))
544  elog(ERROR, "cache lookup failed for statistics object %u", statOid);
545 
546  /* replace it */
547  stup = heap_modify_tuple(oldtup,
548  RelationGetDescr(pg_stextdata),
549  values,
550  nulls,
551  replaces);
552  ReleaseSysCache(oldtup);
553  CatalogTupleUpdate(pg_stextdata, &stup->t_self, stup);
554 
555  heap_freetuple(stup);
556 
557  table_close(pg_stextdata, RowExclusiveLock);
558 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define RelationGetDescr(relation)
Definition: rel.h:482
#define PointerGetDatum(X)
Definition: postgres.h:556
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
bytea * statext_mcv_serialize(MCVList *mcvlist, VacAttrStats **stats)
Definition: mcv.c:618
#define RowExclusiveLock
Definition: lockdefs.h:38
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
bytea * statext_ndistinct_serialize(MVNDistinct *ndistinct)
Definition: mvdistinct.c:171
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
static Datum values[MAXATTR]
Definition: bootstrap.c:165
bytea * statext_dependencies_serialize(MVDependencies *dependencies)
Definition: dependencies.c:452
#define elog(elevel,...)
Definition: elog.h:214
Definition: c.h:562
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113