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/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_opclause_expression (OpExpr *expr, Var **varp, Const **cstp, bool *varonleftp)
 

Macro Definition Documentation

◆ WIDTH_THRESHOLD

#define WIDTH_THRESHOLD   1024

Definition at line 54 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 663 of file extended_stats.c.

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

Referenced by statext_mcv_build(), and statext_mcv_serialize().

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

◆ build_attnums_array()

AttrNumber* build_attnums_array ( Bitmapset attrs,
int *  numattrs 
)

Definition at line 701 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().

702 {
703  int i,
704  j;
705  AttrNumber *attnums;
706  int num = bms_num_members(attrs);
707 
708  if (numattrs)
709  *numattrs = num;
710 
711  /* build attnums from the bitmapset */
712  attnums = (AttrNumber *) palloc(sizeof(AttrNumber) * num);
713  i = 0;
714  j = -1;
715  while ((j = bms_next_member(attrs, j)) >= 0)
716  {
717  /*
718  * Make sure the bitmap contains only user-defined attributes. As
719  * bitmaps can't contain negative values, this can be violated in two
720  * ways. Firstly, the bitmap might contain 0 as a member, and secondly
721  * the integer value might be larger than MaxAttrNumber.
722  */
724  Assert(j <= MaxAttrNumber);
725 
726  attnums[i++] = (AttrNumber) j;
727 
728  /* protect against overflows */
729  Assert(i <= num);
730  }
731 
732  return attnums;
733 }
#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:739
void * palloc(Size size)
Definition: mcxt.c:949
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 743 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().

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

◆ BuildRelationExtStatistics()

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

Definition at line 88 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().

91 {
92  Relation pg_stext;
93  ListCell *lc;
94  List *stats;
95  MemoryContext cxt;
96  MemoryContext oldcxt;
97  int64 ext_cnt;
98 
100  "BuildRelationExtStatistics",
102  oldcxt = MemoryContextSwitchTo(cxt);
103 
104  pg_stext = table_open(StatisticExtRelationId, RowExclusiveLock);
105  stats = fetch_statentries_for_relation(pg_stext, RelationGetRelid(onerel));
106 
107  /* report this phase */
108  if (stats != NIL)
109  {
110  const int index[] = {
113  };
114  const int64 val[] = {
116  list_length(stats)
117  };
118 
119  pgstat_progress_update_multi_param(2, index, val);
120  }
121 
122  ext_cnt = 0;
123  foreach(lc, stats)
124  {
126  MVNDistinct *ndistinct = NULL;
127  MVDependencies *dependencies = NULL;
128  MCVList *mcv = NULL;
129  VacAttrStats **stats;
130  ListCell *lc2;
131  int stattarget;
132 
133  /*
134  * Check if we can build these stats based on the column analyzed. If
135  * not, report this fact (except in autovacuum) and move on.
136  */
137  stats = lookup_var_attr_stats(onerel, stat->columns,
138  natts, vacattrstats);
139  if (!stats)
140  {
143  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
144  errmsg("statistics object \"%s.%s\" could not be computed for relation \"%s.%s\"",
145  stat->schema, stat->name,
146  get_namespace_name(onerel->rd_rel->relnamespace),
147  RelationGetRelationName(onerel)),
148  errtable(onerel)));
149  continue;
150  }
151 
152  /* check allowed number of dimensions */
153  Assert(bms_num_members(stat->columns) >= 2 &&
155 
156  /* compute statistics target for this statistics */
157  stattarget = statext_compute_stattarget(stat->stattarget,
158  bms_num_members(stat->columns),
159  stats);
160 
161  /*
162  * Don't rebuild statistics objects with statistics target set to 0 (we
163  * just leave the existing values around, just like we do for regular
164  * per-column statistics).
165  */
166  if (stattarget == 0)
167  continue;
168 
169  /* compute statistic of each requested type */
170  foreach(lc2, stat->types)
171  {
172  char t = (char) lfirst_int(lc2);
173 
174  if (t == STATS_EXT_NDISTINCT)
175  ndistinct = statext_ndistinct_build(totalrows, numrows, rows,
176  stat->columns, stats);
177  else if (t == STATS_EXT_DEPENDENCIES)
178  dependencies = statext_dependencies_build(numrows, rows,
179  stat->columns, stats);
180  else if (t == STATS_EXT_MCV)
181  mcv = statext_mcv_build(numrows, rows, stat->columns, stats,
182  totalrows, stattarget);
183  }
184 
185  /* store the statistics in the catalog */
186  statext_store(stat->statOid, ndistinct, dependencies, mcv, stats);
187 
188  /* for reporting progress */
190  ++ext_cnt);
191  }
192 
193  table_close(pg_stext, RowExclusiveLock);
194 
195  MemoryContextSwitchTo(oldcxt);
196  MemoryContextDelete(cxt);
197 }
#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:211
#define AllocSetContextCreate
Definition: memutils.h:170
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define PROGRESS_ANALYZE_PHASE
Definition: progress.h:38
void pgstat_progress_update_param(int index, int64 val)
Definition: pgstat.c:3213
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:608
static List * fetch_statentries_for_relation(Relation pg_statext, Oid relid)
Form_pg_class rd_rel
Definition: rel.h:84
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:3094
#define RowExclusiveLock
Definition: lockdefs.h:38
#define RelationGetRelationName(relation)
Definition: rel.h:462
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:3276
#define ereport(elevel, rest)
Definition: elog.h:141
#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:357
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:739
#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:3235
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:822
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
int errtable(Relation rel)
Definition: relcache.c:5201
static VacAttrStats ** lookup_var_attr_stats(Relation rel, Bitmapset *attrs, int nvacatts, VacAttrStats **vacatts)
#define RelationGetRelid(relation)
Definition: rel.h:428
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 882 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().

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

References ApplySortComparator().

Referenced by compare_scalars_simple(), and statext_mcv_serialize().

657 {
658  return ApplySortComparator(a, false, b, false, ssup);
659 }
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 648 of file extended_stats.c.

References compare_datums_simple().

Referenced by statext_mcv_serialize().

649 {
650  return compare_datums_simple(*(Datum *) a,
651  *(Datum *) b,
652  (SortSupport) arg);
653 }
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 213 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().

215 {
216  Relation pg_stext;
217  ListCell *lc;
218  List *lstats;
219  MemoryContext cxt;
220  MemoryContext oldcxt;
221  int result = 0;
222 
224  "ComputeExtStatisticsRows",
226  oldcxt = MemoryContextSwitchTo(cxt);
227 
228  pg_stext = table_open(StatisticExtRelationId, RowExclusiveLock);
229  lstats = fetch_statentries_for_relation(pg_stext, RelationGetRelid(onerel));
230 
231  foreach(lc, lstats)
232  {
234  int stattarget = stat->stattarget;
235  VacAttrStats **stats;
236  int nattrs = bms_num_members(stat->columns);
237 
238  /*
239  * Check if we can build this statistics object based on the columns
240  * analyzed. If not, ignore it (don't report anything, we'll do that
241  * during the actual build BuildRelationExtStatistics).
242  */
243  stats = lookup_var_attr_stats(onerel, stat->columns,
244  natts, vacattrstats);
245 
246  if (!stats)
247  continue;
248 
249  /*
250  * Compute statistics target, based on what's set for the statistic
251  * object itself, and for its attributes.
252  */
253  stattarget = statext_compute_stattarget(stat->stattarget,
254  nattrs, stats);
255 
256  /* Use the largest value for all statistics objects. */
257  if (stattarget > result)
258  result = stattarget;
259  }
260 
261  table_close(pg_stext, RowExclusiveLock);
262 
263  MemoryContextSwitchTo(oldcxt);
264  MemoryContextDelete(cxt);
265 
266  /* compute sample size based on the statistics target */
267  return (300 * result);
268 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
#define AllocSetContextCreate
Definition: memutils.h:170
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
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:428

◆ examine_opclause_expression()

bool examine_opclause_expression ( OpExpr expr,
Var **  varp,
Const **  cstp,
bool varonleftp 
)

Definition at line 1398 of file extended_stats.c.

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

Referenced by mcv_get_match_bitmap(), and statext_is_compatible_clause_internal().

1399 {
1400  Var *var;
1401  Const *cst;
1402  bool varonleft;
1403  Node *leftop,
1404  *rightop;
1405 
1406  /* enforced by statext_is_compatible_clause_internal */
1407  Assert(list_length(expr->args) == 2);
1408 
1409  leftop = linitial(expr->args);
1410  rightop = lsecond(expr->args);
1411 
1412  /* strip RelabelType from either side of the expression */
1413  if (IsA(leftop, RelabelType))
1414  leftop = (Node *) ((RelabelType *) leftop)->arg;
1415 
1416  if (IsA(rightop, RelabelType))
1417  rightop = (Node *) ((RelabelType *) rightop)->arg;
1418 
1419  if (IsA(leftop, Var) && IsA(rightop, Const))
1420  {
1421  var = (Var *) leftop;
1422  cst = (Const *) rightop;
1423  varonleft = true;
1424  }
1425  else if (IsA(leftop, Const) && IsA(rightop, Var))
1426  {
1427  var = (Var *) rightop;
1428  cst = (Const *) leftop;
1429  varonleft = false;
1430  }
1431  else
1432  return false;
1433 
1434  /* return pointers to the extracted parts if requested */
1435  if (varp)
1436  *varp = var;
1437 
1438  if (cstp)
1439  *cstp = cst;
1440 
1441  if (varonleftp)
1442  *varonleftp = varonleft;
1443 
1444  return true;
1445 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
Definition: nodes.h:525
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:739
static int list_length(const List *l)
Definition: pg_list.h:169
void * arg
List * args
Definition: primnodes.h:522

◆ fetch_statentries_for_relation()

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

Definition at line 362 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().

363 {
364  SysScanDesc scan;
365  ScanKeyData skey;
366  HeapTuple htup;
367  List *result = NIL;
368 
369  /*
370  * Prepare to scan pg_statistic_ext for entries having stxrelid = this
371  * rel.
372  */
373  ScanKeyInit(&skey,
374  Anum_pg_statistic_ext_stxrelid,
375  BTEqualStrategyNumber, F_OIDEQ,
376  ObjectIdGetDatum(relid));
377 
378  scan = systable_beginscan(pg_statext, StatisticExtRelidIndexId, true,
379  NULL, 1, &skey);
380 
381  while (HeapTupleIsValid(htup = systable_getnext(scan)))
382  {
383  StatExtEntry *entry;
384  Datum datum;
385  bool isnull;
386  int i;
387  ArrayType *arr;
388  char *enabled;
389  Form_pg_statistic_ext staForm;
390 
391  entry = palloc0(sizeof(StatExtEntry));
392  staForm = (Form_pg_statistic_ext) GETSTRUCT(htup);
393  entry->statOid = staForm->oid;
394  entry->schema = get_namespace_name(staForm->stxnamespace);
395  entry->name = pstrdup(NameStr(staForm->stxname));
396  entry->stattarget = staForm->stxstattarget;
397  for (i = 0; i < staForm->stxkeys.dim1; i++)
398  {
399  entry->columns = bms_add_member(entry->columns,
400  staForm->stxkeys.values[i]);
401  }
402 
403  /* decode the stxkind char array into a list of chars */
404  datum = SysCacheGetAttr(STATEXTOID, htup,
405  Anum_pg_statistic_ext_stxkind, &isnull);
406  Assert(!isnull);
407  arr = DatumGetArrayTypeP(datum);
408  if (ARR_NDIM(arr) != 1 ||
409  ARR_HASNULL(arr) ||
410  ARR_ELEMTYPE(arr) != CHAROID)
411  elog(ERROR, "stxkind is not a 1-D char array");
412  enabled = (char *) ARR_DATA_PTR(arr);
413  for (i = 0; i < ARR_DIMS(arr)[0]; i++)
414  {
415  Assert((enabled[i] == STATS_EXT_NDISTINCT) ||
416  (enabled[i] == STATS_EXT_DEPENDENCIES) ||
417  (enabled[i] == STATS_EXT_MCV));
418  entry->types = lappend_int(entry->types, (int) enabled[i]);
419  }
420 
421  result = lappend(result, entry);
422  }
423 
424  systable_endscan(scan);
425 
426  return result;
427 }
#define NIL
Definition: pg_list.h:65
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
char * pstrdup(const char *in)
Definition: mcxt.c:1186
#define StatisticExtRelidIndexId
Definition: indexing.h:238
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:352
Bitmapset * columns
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
#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:3094
#define ARR_HASNULL(a)
Definition: array.h:279
List * lappend_int(List *list, int datum)
Definition: list.c:340
List * lappend(List *list, void *datum)
Definition: list.c:322
void * palloc0(Size size)
Definition: mcxt.c:980
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:739
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:228
int i
#define NameStr(name)
Definition: c.h:616
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 848 of file extended_stats.c.

References StatisticExtInfo::kind, lfirst, and stat.

Referenced by dependencies_clauselist_selectivity(), and statext_mcv_clauselist_selectivity().

849 {
850  ListCell *l;
851 
852  foreach(l, stats)
853  {
855 
856  if (stat->kind == requiredkind)
857  return true;
858  }
859 
860  return false;
861 }
#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 437 of file extended_stats.c.

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

Referenced by BuildRelationExtStatistics(), and ComputeExtStatisticsRows().

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

◆ multi_sort_add_dimension()

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

Definition at line 580 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().

582 {
583  SortSupport ssup = &mss->ssup[sortdim];
584 
586  ssup->ssup_collation = collation;
587  ssup->ssup_nulls_first = false;
588 
590 }
bool ssup_nulls_first
Definition: sortsupport.h:75
void PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
Definition: sortsupport.c:134
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:377

◆ multi_sort_compare()

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

Definition at line 594 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().

595 {
597  SortItem *ia = (SortItem *) a;
598  SortItem *ib = (SortItem *) b;
599  int i;
600 
601  for (i = 0; i < mss->ndims; i++)
602  {
603  int compare;
604 
605  compare = ApplySortComparator(ia->values[i], ia->isnull[i],
606  ib->values[i], ib->isnull[i],
607  &mss->ssup[i]);
608 
609  if (compare != 0)
610  return compare;
611  }
612 
613  /* equal by default */
614  return 0;
615 }
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 619 of file extended_stats.c.

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

Referenced by dependency_degree().

621 {
622  return ApplySortComparator(a->values[dim], a->isnull[dim],
623  b->values[dim], b->isnull[dim],
624  &mss->ssup[dim]);
625 }
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 628 of file extended_stats.c.

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

Referenced by dependency_degree().

631 {
632  int dim;
633 
634  for (dim = start; dim <= end; dim++)
635  {
636  int r = ApplySortComparator(a->values[dim], a->isnull[dim],
637  b->values[dim], b->isnull[dim],
638  &mss->ssup[dim]);
639 
640  if (r != 0)
641  return r;
642  }
643 
644  return 0;
645 }
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 561 of file extended_stats.c.

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

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

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

◆ statext_clauselist_selectivity()

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

Definition at line 1355 of file extended_stats.c.

References dependencies_clauselist_selectivity(), and statext_mcv_clauselist_selectivity().

Referenced by clauselist_selectivity().

1358 {
1359  Selectivity sel;
1360 
1361  /* First, try estimating clauses using a multivariate MCV list. */
1362  sel = statext_mcv_clauselist_selectivity(root, clauses, varRelid, jointype,
1363  sjinfo, rel, estimatedclauses);
1364 
1365  /*
1366  * Then, apply functional dependencies on the remaining clauses by calling
1367  * dependencies_clauselist_selectivity. Pass 'estimatedclauses' so the
1368  * function can properly skip clauses already estimated above.
1369  *
1370  * The reasoning for applying dependencies last is that the more complex
1371  * stats can track more complex correlations between the attributes, and
1372  * so may be considered more reliable.
1373  *
1374  * For example, MCV list can give us an exact selectivity for values in
1375  * two columns, while functional dependencies can only provide information
1376  * about the overall strength of the dependency.
1377  */
1378  sel *= dependencies_clauselist_selectivity(root, clauses, varRelid,
1379  jointype, sjinfo, rel,
1380  estimatedclauses);
1381 
1382  return sel;
1383 }
Selectivity dependencies_clauselist_selectivity(PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, RelOptInfo *rel, Bitmapset **estimatedclauses)
Definition: dependencies.c:944
double Selectivity
Definition: nodes.h:658
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 291 of file extended_stats.c.

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

Referenced by BuildRelationExtStatistics(), and ComputeExtStatisticsRows().

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

1115 {
1116  RangeTblEntry *rte = root->simple_rte_array[relid];
1117  RestrictInfo *rinfo = (RestrictInfo *) clause;
1118  Oid userid;
1119 
1120  if (!IsA(rinfo, RestrictInfo))
1121  return false;
1122 
1123  /* Pseudoconstants are not really interesting here. */
1124  if (rinfo->pseudoconstant)
1125  return false;
1126 
1127  /* clauses referencing multiple varnos are incompatible */
1129  return false;
1130 
1131  /* Check the clause and determine what attributes it references. */
1132  if (!statext_is_compatible_clause_internal(root, (Node *) rinfo->clause,
1133  relid, attnums))
1134  return false;
1135 
1136  /*
1137  * Check that the user has permission to read all these attributes. Use
1138  * checkAsUser if it's set, in case we're accessing the table via a view.
1139  */
1140  userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
1141 
1142  if (pg_class_aclcheck(rte->relid, userid, ACL_SELECT) != ACLCHECK_OK)
1143  {
1144  /* Don't have table privilege, must check individual columns */
1145  if (bms_is_member(InvalidAttrNumber, *attnums))
1146  {
1147  /* Have a whole-row reference, must have access to all columns */
1148  if (pg_attribute_aclcheck_all(rte->relid, userid, ACL_SELECT,
1150  return false;
1151  }
1152  else
1153  {
1154  /* Check the columns referenced by the clause */
1155  int attnum = -1;
1156 
1157  while ((attnum = bms_next_member(*attnums, attnum)) >= 0)
1158  {
1159  if (pg_attribute_aclcheck(rte->relid, attnum, userid,
1160  ACL_SELECT) != ACLCHECK_OK)
1161  return false;
1162  }
1163  }
1164  }
1165 
1166  /* If we reach here, the clause is OK */
1167  return true;
1168 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode)
Definition: aclchk.c:4515
Oid GetUserId(void)
Definition: miscinit.c:380
Relids clause_relids
Definition: pathnodes.h:1960
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
bool pseudoconstant
Definition: pathnodes.h:1953
Definition: nodes.h:525
unsigned int Oid
Definition: postgres_ext.h:31
RangeTblEntry ** simple_rte_array
Definition: pathnodes.h:211
Expr * clause
Definition: pathnodes.h:1945
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:4544
#define InvalidAttrNumber
Definition: attnum.h:23
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4629
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 955 of file extended_stats.c.

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

Referenced by statext_is_compatible_clause().

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

◆ statext_is_kind_built()

bool statext_is_kind_built ( HeapTuple  htup,
char  type 
)

Definition at line 333 of file extended_stats.c.

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

Referenced by get_relation_statistics(), and UpdateStatisticsForTypeChange().

334 {
336 
337  switch (type)
338  {
339  case STATS_EXT_NDISTINCT:
340  attnum = Anum_pg_statistic_ext_data_stxdndistinct;
341  break;
342 
343  case STATS_EXT_DEPENDENCIES:
344  attnum = Anum_pg_statistic_ext_data_stxddependencies;
345  break;
346 
347  case STATS_EXT_MCV:
348  attnum = Anum_pg_statistic_ext_data_stxdmcv;
349  break;
350 
351  default:
352  elog(ERROR, "unexpected statistics type requested: %d", type);
353  }
354 
355  return !heap_attisnull(htup, attnum, NULL);
356 }
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:228
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 1226 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().

1229 {
1230  ListCell *l;
1231  Bitmapset **list_attnums;
1232  int listidx;
1233  Selectivity sel = 1.0;
1234 
1235  /* check if there's any stats that might be useful for us. */
1236  if (!has_stats_of_kind(rel->statlist, STATS_EXT_MCV))
1237  return 1.0;
1238 
1239  list_attnums = (Bitmapset **) palloc(sizeof(Bitmapset *) *
1240  list_length(clauses));
1241 
1242  /*
1243  * Pre-process the clauses list to extract the attnums seen in each item.
1244  * We need to determine if there's any clauses which will be useful for
1245  * selectivity estimations with extended stats. Along the way we'll record
1246  * all of the attnums for each clause in a list which we'll reference
1247  * later so we don't need to repeat the same work again. We'll also keep
1248  * track of all attnums seen.
1249  *
1250  * We also skip clauses that we already estimated using different types of
1251  * statistics (we treat them as incompatible).
1252  */
1253  listidx = 0;
1254  foreach(l, clauses)
1255  {
1256  Node *clause = (Node *) lfirst(l);
1257  Bitmapset *attnums = NULL;
1258 
1259  if (!bms_is_member(listidx, *estimatedclauses) &&
1260  statext_is_compatible_clause(root, clause, rel->relid, &attnums))
1261  list_attnums[listidx] = attnums;
1262  else
1263  list_attnums[listidx] = NULL;
1264 
1265  listidx++;
1266  }
1267 
1268  /* apply as many extended statistics as possible */
1269  while (true)
1270  {
1272  List *stat_clauses;
1273  Selectivity simple_sel,
1274  mcv_sel,
1275  mcv_basesel,
1276  mcv_totalsel,
1277  other_sel,
1278  stat_sel;
1279 
1280  /* find the best suited statistics object for these attnums */
1281  stat = choose_best_statistics(rel->statlist, STATS_EXT_MCV,
1282  list_attnums, list_length(clauses));
1283 
1284  /* if no (additional) matching stats could be found then we've nothing to do */
1285  if (!stat)
1286  break;
1287 
1288  /* Ensure choose_best_statistics produced an expected stats type. */
1289  Assert(stat->kind == STATS_EXT_MCV);
1290 
1291  /* now filter the clauses to be estimated using the selected MCV */
1292  stat_clauses = NIL;
1293 
1294  listidx = 0;
1295  foreach(l, clauses)
1296  {
1297  /*
1298  * If the clause is compatible with the selected statistics, mark it
1299  * as estimated and add it to the list to estimate.
1300  */
1301  if (list_attnums[listidx] != NULL &&
1302  bms_is_subset(list_attnums[listidx], stat->keys))
1303  {
1304  stat_clauses = lappend(stat_clauses, (Node *) lfirst(l));
1305  *estimatedclauses = bms_add_member(*estimatedclauses, listidx);
1306 
1307  bms_free(list_attnums[listidx]);
1308  list_attnums[listidx] = NULL;
1309  }
1310 
1311  listidx++;
1312  }
1313 
1314  /*
1315  * First compute "simple" selectivity, i.e. without the extended
1316  * statistics, and essentially assuming independence of the
1317  * columns/clauses. We'll then use the various selectivities computed from
1318  * MCV list to improve it.
1319  */
1320  simple_sel = clauselist_selectivity_simple(root, stat_clauses, varRelid,
1321  jointype, sjinfo, NULL);
1322 
1323  /*
1324  * Now compute the multi-column estimate from the MCV list, along with the
1325  * other selectivities (base & total selectivity).
1326  */
1327  mcv_sel = mcv_clauselist_selectivity(root, stat, stat_clauses, varRelid,
1328  jointype, sjinfo, rel,
1329  &mcv_basesel, &mcv_totalsel);
1330 
1331  /* Estimated selectivity of values not covered by MCV matches */
1332  other_sel = simple_sel - mcv_basesel;
1333  CLAMP_PROBABILITY(other_sel);
1334 
1335  /* The non-MCV selectivity can't exceed the 1 - mcv_totalsel. */
1336  if (other_sel > 1.0 - mcv_totalsel)
1337  other_sel = 1.0 - mcv_totalsel;
1338 
1339  /* Overall selectivity is the combination of MCV and non-MCV estimates. */
1340  stat_sel = mcv_sel + other_sel;
1341  CLAMP_PROBABILITY(stat_sel);
1342 
1343  /* Factor the estimate from this MCV to the oveall estimate. */
1344  sel *= stat_sel;
1345  }
1346 
1347  return sel;
1348 }
#define NIL
Definition: pg_list.h:65
List * statlist
Definition: pathnodes.h:681
Definition: nodes.h:525
double Selectivity
Definition: nodes.h:658
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:57
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:315
Index relid
Definition: pathnodes.h:671
List * lappend(List *list, void *datum)
Definition: list.c:322
#define stat(a, b)
Definition: win32_port.h:255
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
#define Assert(condition)
Definition: c.h:739
#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:887
void * palloc(Size size)
Definition: mcxt.c:949
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:1794
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 491 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().

494 {
495  HeapTuple stup,
496  oldtup;
497  Datum values[Natts_pg_statistic_ext_data];
498  bool nulls[Natts_pg_statistic_ext_data];
499  bool replaces[Natts_pg_statistic_ext_data];
500  Relation pg_stextdata;
501 
502  memset(nulls, true, sizeof(nulls));
503  memset(replaces, false, sizeof(replaces));
504  memset(values, 0, sizeof(values));
505 
506  /*
507  * Construct a new pg_statistic_ext_data tuple, replacing the calculated
508  * stats.
509  */
510  if (ndistinct != NULL)
511  {
512  bytea *data = statext_ndistinct_serialize(ndistinct);
513 
514  nulls[Anum_pg_statistic_ext_data_stxdndistinct - 1] = (data == NULL);
515  values[Anum_pg_statistic_ext_data_stxdndistinct - 1] = PointerGetDatum(data);
516  }
517 
518  if (dependencies != NULL)
519  {
520  bytea *data = statext_dependencies_serialize(dependencies);
521 
522  nulls[Anum_pg_statistic_ext_data_stxddependencies - 1] = (data == NULL);
523  values[Anum_pg_statistic_ext_data_stxddependencies - 1] = PointerGetDatum(data);
524  }
525  if (mcv != NULL)
526  {
527  bytea *data = statext_mcv_serialize(mcv, stats);
528 
529  nulls[Anum_pg_statistic_ext_data_stxdmcv - 1] = (data == NULL);
530  values[Anum_pg_statistic_ext_data_stxdmcv - 1] = PointerGetDatum(data);
531  }
532 
533  /* always replace the value (either by bytea or NULL) */
534  replaces[Anum_pg_statistic_ext_data_stxdndistinct - 1] = true;
535  replaces[Anum_pg_statistic_ext_data_stxddependencies - 1] = true;
536  replaces[Anum_pg_statistic_ext_data_stxdmcv - 1] = true;
537 
538  /* there should already be a pg_statistic_ext_data tuple */
540  if (!HeapTupleIsValid(oldtup))
541  elog(ERROR, "cache lookup failed for statistics object %u", statOid);
542 
543  /* replace it */
544  pg_stextdata = table_open(StatisticExtDataRelationId, RowExclusiveLock);
545 
546  stup = heap_modify_tuple(oldtup,
547  RelationGetDescr(pg_stextdata),
548  values,
549  nulls,
550  replaces);
551  ReleaseSysCache(oldtup);
552  CatalogTupleUpdate(pg_stextdata, &stup->t_self, stup);
553 
554  heap_freetuple(stup);
555 
556  table_close(pg_stextdata, RowExclusiveLock);
557 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define RelationGetDescr(relation)
Definition: rel.h:454
#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:224
static Datum values[MAXATTR]
Definition: bootstrap.c:167
bytea * statext_dependencies_serialize(MVDependencies *dependencies)
Definition: dependencies.c:446
#define elog(elevel,...)
Definition: elog.h:228
Definition: c.h:556
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