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 "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/optimizer.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, Bitmapset *attnums, char requiredkind)
 
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 52 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 640 of file extended_stats.c.

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

Referenced by statext_mcv_build(), and statext_mcv_serialize().

643 {
644  size_t l,
645  u,
646  idx;
647  const void *p;
648  int comparison;
649 
650  l = 0;
651  u = nmemb;
652  while (l < u)
653  {
654  idx = (l + u) / 2;
655  p = (void *) (((const char *) base) + (idx * size));
656  comparison = (*compar) (key, p, arg);
657 
658  if (comparison < 0)
659  u = idx;
660  else if (comparison > 0)
661  l = idx + 1;
662  else
663  return (void *) p;
664  }
665 
666  return NULL;
667 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:264
void * arg

◆ build_attnums_array()

AttrNumber* build_attnums_array ( Bitmapset attrs,
int *  numattrs 
)

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

679 {
680  int i,
681  j;
682  AttrNumber *attnums;
683  int num = bms_num_members(attrs);
684 
685  if (numattrs)
686  *numattrs = num;
687 
688  /* build attnums from the bitmapset */
689  attnums = (AttrNumber *) palloc(sizeof(AttrNumber) * num);
690  i = 0;
691  j = -1;
692  while ((j = bms_next_member(attrs, j)) >= 0)
693  {
694  /*
695  * Make sure the bitmap contains only user-defined attributes. As
696  * bitmaps can't contain negative values, this can be violated in two
697  * ways. Firstly, the bitmap might contain 0 as a member, and secondly
698  * the integer value might be larger than MaxAttrNumber.
699  */
701  Assert(j <= MaxAttrNumber);
702 
703  attnums[i++] = (AttrNumber) j;
704 
705  /* protect against overflows */
706  Assert(i <= num);
707  }
708 
709  return attnums;
710 }
#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:732
void * palloc(Size size)
Definition: mcxt.c:924
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 720 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().

722 {
723  int i,
724  j,
725  len,
726  idx;
727  int nvalues = numrows * numattrs;
728 
729  SortItem *items;
730  Datum *values;
731  bool *isnull;
732  char *ptr;
733 
734  /* Compute the total amount of memory we need (both items and values). */
735  len = numrows * sizeof(SortItem) + nvalues * (sizeof(Datum) + sizeof(bool));
736 
737  /* Allocate the memory and split it into the pieces. */
738  ptr = palloc0(len);
739 
740  /* items to sort */
741  items = (SortItem *) ptr;
742  ptr += numrows * sizeof(SortItem);
743 
744  /* values and null flags */
745  values = (Datum *) ptr;
746  ptr += nvalues * sizeof(Datum);
747 
748  isnull = (bool *) ptr;
749  ptr += nvalues * sizeof(bool);
750 
751  /* make sure we consumed the whole buffer exactly */
752  Assert((ptr - (char *) items) == len);
753 
754  /* fix the pointers to Datum and bool arrays */
755  idx = 0;
756  for (i = 0; i < numrows; i++)
757  {
758  bool toowide = false;
759 
760  items[idx].values = &values[idx * numattrs];
761  items[idx].isnull = &isnull[idx * numattrs];
762 
763  /* load the values/null flags from sample rows */
764  for (j = 0; j < numattrs; j++)
765  {
766  Datum value;
767  bool isnull;
768 
769  value = heap_getattr(rows[i], attnums[j], tdesc, &isnull);
770 
771  /*
772  * If this is a varlena value, check if it's too wide and if yes
773  * then skip the whole item. Otherwise detoast the value.
774  *
775  * XXX It may happen that we've already detoasted some preceding
776  * values for the current item. We don't bother to cleanup those
777  * on the assumption that those are small (below WIDTH_THRESHOLD)
778  * and will be discarded at the end of analyze.
779  */
780  if ((!isnull) &&
781  (TupleDescAttr(tdesc, attnums[j] - 1)->attlen == -1))
782  {
784  {
785  toowide = true;
786  break;
787  }
788 
789  value = PointerGetDatum(PG_DETOAST_DATUM(value));
790  }
791 
792  items[idx].values[j] = value;
793  items[idx].isnull[j] = isnull;
794  }
795 
796  if (toowide)
797  continue;
798 
799  idx++;
800  }
801 
802  /* store the actual number of items (ignoring the too-wide ones) */
803  *nitems = idx;
804 
805  /* all items were too wide */
806  if (idx == 0)
807  {
808  /* everything is allocated as a single chunk */
809  pfree(items);
810  return NULL;
811  }
812 
813  /* do the sort, using the multi-sort */
814  qsort_arg((void *) items, idx, sizeof(SortItem),
815  multi_sort_compare, mss);
816 
817  return items;
818 }
#define PointerGetDatum(X)
Definition: postgres.h:556
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static struct @144 value
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:264
void pfree(void *pointer)
Definition: mcxt.c:1031
Size toast_raw_datum_size(Datum value)
Definition: detoast.c:768
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:955
uintptr_t Datum
Definition: postgres.h:367
struct SortItem SortItem
#define WIDTH_THRESHOLD
#define Assert(condition)
Definition: c.h:732
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:308

◆ BuildRelationExtStatistics()

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

Definition at line 86 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, lookup_var_attr_stats(), MemoryContextDelete(), MemoryContextSwitchTo(), StatExtEntry::name, 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, and WARNING.

Referenced by do_analyze_rel().

89 {
90  Relation pg_stext;
91  ListCell *lc;
92  List *stats;
93  MemoryContext cxt;
94  MemoryContext oldcxt;
95 
97  "BuildRelationExtStatistics",
99  oldcxt = MemoryContextSwitchTo(cxt);
100 
101  pg_stext = table_open(StatisticExtRelationId, RowExclusiveLock);
102  stats = fetch_statentries_for_relation(pg_stext, RelationGetRelid(onerel));
103 
104  foreach(lc, stats)
105  {
107  MVNDistinct *ndistinct = NULL;
108  MVDependencies *dependencies = NULL;
109  MCVList *mcv = NULL;
110  VacAttrStats **stats;
111  ListCell *lc2;
112  int stattarget;
113 
114  /*
115  * Check if we can build these stats based on the column analyzed. If
116  * not, report this fact (except in autovacuum) and move on.
117  */
118  stats = lookup_var_attr_stats(onerel, stat->columns,
119  natts, vacattrstats);
120  if (!stats)
121  {
124  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
125  errmsg("statistics object \"%s.%s\" could not be computed for relation \"%s.%s\"",
126  stat->schema, stat->name,
127  get_namespace_name(onerel->rd_rel->relnamespace),
128  RelationGetRelationName(onerel)),
129  errtable(onerel)));
130  continue;
131  }
132 
133  /* check allowed number of dimensions */
134  Assert(bms_num_members(stat->columns) >= 2 &&
136 
137  /* compute statistics target for this statistics */
138  stattarget = statext_compute_stattarget(stat->stattarget,
139  bms_num_members(stat->columns),
140  stats);
141 
142  /*
143  * Don't rebuild statistics objects with statistics target set to 0 (we
144  * just leave the existing values around, just like we do for regular
145  * per-column statistics).
146  */
147  if (stattarget == 0)
148  continue;
149 
150  /* compute statistic of each requested type */
151  foreach(lc2, stat->types)
152  {
153  char t = (char) lfirst_int(lc2);
154 
155  if (t == STATS_EXT_NDISTINCT)
156  ndistinct = statext_ndistinct_build(totalrows, numrows, rows,
157  stat->columns, stats);
158  else if (t == STATS_EXT_DEPENDENCIES)
159  dependencies = statext_dependencies_build(numrows, rows,
160  stat->columns, stats);
161  else if (t == STATS_EXT_MCV)
162  mcv = statext_mcv_build(numrows, rows, stat->columns, stats,
163  totalrows, stattarget);
164  }
165 
166  /* store the statistics in the catalog */
167  statext_store(stat->statOid, ndistinct, dependencies, mcv, stats);
168  }
169 
170  table_close(pg_stext, RowExclusiveLock);
171 
172  MemoryContextSwitchTo(oldcxt);
173  MemoryContextDelete(cxt);
174 }
MCVList * statext_mcv_build(int numrows, HeapTuple *rows, Bitmapset *attrs, VacAttrStats **stats, double totalrows, int stattarget)
Definition: mcv.c:183
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
#define AllocSetContextCreate
Definition: memutils.h:169
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
int errcode(int sqlerrcode)
Definition: elog.c:570
static List * fetch_statentries_for_relation(Relation pg_statext, Oid relid)
Form_pg_class rd_rel
Definition: rel.h:83
Bitmapset * columns
#define lfirst_int(lc)
Definition: pg_list.h:191
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:191
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:450
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:3278
#define ereport(elevel, rest)
Definition: elog.h:141
#define WARNING
Definition: elog.h:40
#define stat(a, b)
Definition: win32_port.h:264
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:87
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
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:784
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
int errtable(Relation rel)
Definition: relcache.c:5168
static VacAttrStats ** lookup_var_attr_stats(Relation rel, Bitmapset *attrs, int nvacatts, VacAttrStats **vacatts)
#define RelationGetRelid(relation)
Definition: rel.h:416

◆ choose_best_statistics()

StatisticExtInfo* choose_best_statistics ( List stats,
Bitmapset attnums,
char  requiredkind 
)

Definition at line 855 of file extended_stats.c.

References bms_free(), bms_intersect(), bms_num_members(), StatisticExtInfo::keys, StatisticExtInfo::kind, lfirst, and STATS_MAX_DIMENSIONS.

Referenced by dependencies_clauselist_selectivity(), and statext_mcv_clauselist_selectivity().

856 {
857  ListCell *lc;
858  StatisticExtInfo *best_match = NULL;
859  int best_num_matched = 2; /* goal #1: maximize */
860  int best_match_keys = (STATS_MAX_DIMENSIONS + 1); /* goal #2: minimize */
861 
862  foreach(lc, stats)
863  {
864  StatisticExtInfo *info = (StatisticExtInfo *) lfirst(lc);
865  int num_matched;
866  int numkeys;
867  Bitmapset *matched;
868 
869  /* skip statistics that are not of the correct type */
870  if (info->kind != requiredkind)
871  continue;
872 
873  /* determine how many attributes of these stats can be matched to */
874  matched = bms_intersect(attnums, info->keys);
875  num_matched = bms_num_members(matched);
876  bms_free(matched);
877 
878  /*
879  * save the actual number of keys in the stats so that we can choose
880  * the narrowest stats with the most matching keys.
881  */
882  numkeys = bms_num_members(info->keys);
883 
884  /*
885  * Use this object when it increases the number of matched clauses or
886  * when it matches the same number of attributes but these stats have
887  * fewer keys than any previous match.
888  */
889  if (num_matched > best_num_matched ||
890  (num_matched == best_num_matched && numkeys < best_match_keys))
891  {
892  best_match = info;
893  best_num_matched = num_matched;
894  best_match_keys = numkeys;
895  }
896  }
897 
898  return best_match;
899 }
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:646
Bitmapset * bms_intersect(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:259
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
#define lfirst(lc)
Definition: pg_list.h:190
Bitmapset * keys
Definition: pathnodes.h:885
#define STATS_MAX_DIMENSIONS
Definition: statistics.h:19

◆ compare_datums_simple()

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

Definition at line 633 of file extended_stats.c.

References ApplySortComparator().

Referenced by compare_scalars_simple(), and statext_mcv_serialize().

634 {
635  return ApplySortComparator(a, false, b, false, ssup);
636 }
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 625 of file extended_stats.c.

References compare_datums_simple().

Referenced by statext_mcv_serialize().

626 {
627  return compare_datums_simple(*(Datum *) a,
628  *(Datum *) b,
629  (SortSupport) arg);
630 }
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 190 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().

192 {
193  Relation pg_stext;
194  ListCell *lc;
195  List *lstats;
196  MemoryContext cxt;
197  MemoryContext oldcxt;
198  int result = 0;
199 
201  "ComputeExtStatisticsRows",
203  oldcxt = MemoryContextSwitchTo(cxt);
204 
205  pg_stext = table_open(StatisticExtRelationId, RowExclusiveLock);
206  lstats = fetch_statentries_for_relation(pg_stext, RelationGetRelid(onerel));
207 
208  foreach(lc, lstats)
209  {
211  int stattarget = stat->stattarget;
212  VacAttrStats **stats;
213  int nattrs = bms_num_members(stat->columns);
214 
215  /*
216  * Check if we can build this statistics object based on the columns
217  * analyzed. If not, ignore it (don't report anything, we'll do that
218  * during the actual build BuildRelationExtStatistics).
219  */
220  stats = lookup_var_attr_stats(onerel, stat->columns,
221  natts, vacattrstats);
222 
223  if (!stats)
224  continue;
225 
226  /*
227  * Compute statistics target, based on what's set for the statistic
228  * object itself, and for its attributes.
229  */
230  stattarget = statext_compute_stattarget(stat->stattarget,
231  nattrs, stats);
232 
233  /* Use the largest value for all statistics objects. */
234  if (stattarget > result)
235  result = stattarget;
236  }
237 
238  table_close(pg_stext, RowExclusiveLock);
239 
240  MemoryContextSwitchTo(oldcxt);
241  MemoryContextDelete(cxt);
242 
243  /* compute sample size based on the statistics target */
244  return (300 * result);
245 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
#define AllocSetContextCreate
Definition: memutils.h:169
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:191
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:264
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:416

◆ examine_opclause_expression()

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

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

1351 {
1352  Var *var;
1353  Const *cst;
1354  bool varonleft;
1355  Node *leftop,
1356  *rightop;
1357 
1358  /* enforced by statext_is_compatible_clause_internal */
1359  Assert(list_length(expr->args) == 2);
1360 
1361  leftop = linitial(expr->args);
1362  rightop = lsecond(expr->args);
1363 
1364  /* strip RelabelType from either side of the expression */
1365  if (IsA(leftop, RelabelType))
1366  leftop = (Node *) ((RelabelType *) leftop)->arg;
1367 
1368  if (IsA(rightop, RelabelType))
1369  rightop = (Node *) ((RelabelType *) rightop)->arg;
1370 
1371  if (IsA(leftop, Var) && IsA(rightop, Const))
1372  {
1373  var = (Var *) leftop;
1374  cst = (Const *) rightop;
1375  varonleft = true;
1376  }
1377  else if (IsA(leftop, Const) && IsA(rightop, Var))
1378  {
1379  var = (Var *) rightop;
1380  cst = (Const *) leftop;
1381  varonleft = false;
1382  }
1383  else
1384  return false;
1385 
1386  /* return pointers to the extracted parts if requested */
1387  if (varp)
1388  *varp = var;
1389 
1390  if (cstp)
1391  *cstp = cst;
1392 
1393  if (varonleftp)
1394  *varonleftp = varonleft;
1395 
1396  return true;
1397 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
Definition: nodes.h:525
Definition: primnodes.h:167
#define lsecond(l)
Definition: pg_list.h:200
#define linitial(l)
Definition: pg_list.h:195
#define Assert(condition)
Definition: c.h:732
static int list_length(const List *l)
Definition: pg_list.h:169
void * arg
List * args
Definition: primnodes.h:508

◆ fetch_statentries_for_relation()

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

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

340 {
341  SysScanDesc scan;
342  ScanKeyData skey;
343  HeapTuple htup;
344  List *result = NIL;
345 
346  /*
347  * Prepare to scan pg_statistic_ext for entries having stxrelid = this
348  * rel.
349  */
350  ScanKeyInit(&skey,
351  Anum_pg_statistic_ext_stxrelid,
352  BTEqualStrategyNumber, F_OIDEQ,
353  ObjectIdGetDatum(relid));
354 
355  scan = systable_beginscan(pg_statext, StatisticExtRelidIndexId, true,
356  NULL, 1, &skey);
357 
358  while (HeapTupleIsValid(htup = systable_getnext(scan)))
359  {
360  StatExtEntry *entry;
361  Datum datum;
362  bool isnull;
363  int i;
364  ArrayType *arr;
365  char *enabled;
366  Form_pg_statistic_ext staForm;
367 
368  entry = palloc0(sizeof(StatExtEntry));
369  staForm = (Form_pg_statistic_ext) GETSTRUCT(htup);
370  entry->statOid = staForm->oid;
371  entry->schema = get_namespace_name(staForm->stxnamespace);
372  entry->name = pstrdup(NameStr(staForm->stxname));
373  entry->stattarget = staForm->stxstattarget;
374  for (i = 0; i < staForm->stxkeys.dim1; i++)
375  {
376  entry->columns = bms_add_member(entry->columns,
377  staForm->stxkeys.values[i]);
378  }
379 
380  /* decode the stxkind char array into a list of chars */
381  datum = SysCacheGetAttr(STATEXTOID, htup,
382  Anum_pg_statistic_ext_stxkind, &isnull);
383  Assert(!isnull);
384  arr = DatumGetArrayTypeP(datum);
385  if (ARR_NDIM(arr) != 1 ||
386  ARR_HASNULL(arr) ||
387  ARR_ELEMTYPE(arr) != CHAROID)
388  elog(ERROR, "stxkind is not a 1-D char array");
389  enabled = (char *) ARR_DATA_PTR(arr);
390  for (i = 0; i < ARR_DIMS(arr)[0]; i++)
391  {
392  Assert((enabled[i] == STATS_EXT_NDISTINCT) ||
393  (enabled[i] == STATS_EXT_DEPENDENCIES) ||
394  (enabled[i] == STATS_EXT_MCV));
395  entry->types = lappend_int(entry->types, (int) enabled[i]);
396  }
397 
398  result = lappend(result, entry);
399  }
400 
401  systable_endscan(scan);
402 
403  return result;
404 }
#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:1161
#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:339
List * lappend(List *list, void *datum)
Definition: list.c:321
void * palloc0(Size size)
Definition: mcxt.c:955
uintptr_t Datum
Definition: postgres.h:367
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1385
int result
Definition: header.h:19
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:732
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:226
int i
#define NameStr(name)
Definition: c.h:609
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 825 of file extended_stats.c.

References StatisticExtInfo::kind, lfirst, and stat.

Referenced by dependencies_clauselist_selectivity(), and statext_mcv_clauselist_selectivity().

826 {
827  ListCell *l;
828 
829  foreach(l, stats)
830  {
832 
833  if (stat->kind == requiredkind)
834  return true;
835  }
836 
837  return false;
838 }
#define stat(a, b)
Definition: win32_port.h:264
#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 414 of file extended_stats.c.

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

Referenced by BuildRelationExtStatistics(), and ComputeExtStatisticsRows().

416 {
417  int i = 0;
418  int x = -1;
419  VacAttrStats **stats;
420 
421  stats = (VacAttrStats **)
422  palloc(bms_num_members(attrs) * sizeof(VacAttrStats *));
423 
424  /* lookup VacAttrStats info for the requested columns (same attnum) */
425  while ((x = bms_next_member(attrs, x)) >= 0)
426  {
427  int j;
428 
429  stats[i] = NULL;
430  for (j = 0; j < nvacatts; j++)
431  {
432  if (x == vacatts[j]->tupattnum)
433  {
434  stats[i] = vacatts[j];
435  break;
436  }
437  }
438 
439  if (!stats[i])
440  {
441  /*
442  * Looks like stats were not gathered for one of the columns
443  * required. We'll be unable to build the extended stats without
444  * this column.
445  */
446  pfree(stats);
447  return NULL;
448  }
449 
450  /*
451  * Sanity check that the column is not dropped - stats should have
452  * been removed in this case.
453  */
454  Assert(!stats[i]->attr->attisdropped);
455 
456  i++;
457  }
458 
459  return stats;
460 }
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
void pfree(void *pointer)
Definition: mcxt.c:1031
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:646
#define Assert(condition)
Definition: c.h:732
void * palloc(Size size)
Definition: mcxt.c:924
int i

◆ multi_sort_add_dimension()

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

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

559 {
560  SortSupport ssup = &mss->ssup[sortdim];
561 
563  ssup->ssup_collation = collation;
564  ssup->ssup_nulls_first = false;
565 
567 }
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 571 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().

572 {
574  SortItem *ia = (SortItem *) a;
575  SortItem *ib = (SortItem *) b;
576  int i;
577 
578  for (i = 0; i < mss->ndims; i++)
579  {
580  int compare;
581 
582  compare = ApplySortComparator(ia->values[i], ia->isnull[i],
583  ib->values[i], ib->isnull[i],
584  &mss->ssup[i]);
585 
586  if (compare != 0)
587  return compare;
588  }
589 
590  /* equal by default */
591  return 0;
592 }
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 596 of file extended_stats.c.

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

Referenced by dependency_degree().

598 {
599  return ApplySortComparator(a->values[dim], a->isnull[dim],
600  b->values[dim], b->isnull[dim],
601  &mss->ssup[dim]);
602 }
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 605 of file extended_stats.c.

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

Referenced by dependency_degree().

608 {
609  int dim;
610 
611  for (dim = start; dim <= end; dim++)
612  {
613  int r = ApplySortComparator(a->values[dim], a->isnull[dim],
614  b->values[dim], b->isnull[dim],
615  &mss->ssup[dim]);
616 
617  if (r != 0)
618  return r;
619  }
620 
621  return 0;
622 }
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 538 of file extended_stats.c.

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

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

539 {
540  MultiSortSupport mss;
541 
542  Assert(ndims >= 2);
543 
545  + sizeof(SortSupportData) * ndims);
546 
547  mss->ndims = ndims;
548 
549  return mss;
550 }
struct SortSupportData SortSupportData
void * palloc0(Size size)
Definition: mcxt.c:955
#define Assert(condition)
Definition: c.h:732
MultiSortSupportData * MultiSortSupport
#define offsetof(type, field)
Definition: c.h:655

◆ statext_clauselist_selectivity()

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

Definition at line 1307 of file extended_stats.c.

References dependencies_clauselist_selectivity(), and statext_mcv_clauselist_selectivity().

Referenced by clauselist_selectivity().

1310 {
1311  Selectivity sel;
1312 
1313  /* First, try estimating clauses using a multivariate MCV list. */
1314  sel = statext_mcv_clauselist_selectivity(root, clauses, varRelid, jointype,
1315  sjinfo, rel, estimatedclauses);
1316 
1317  /*
1318  * Then, apply functional dependencies on the remaining clauses by calling
1319  * dependencies_clauselist_selectivity. Pass 'estimatedclauses' so the
1320  * function can properly skip clauses already estimated above.
1321  *
1322  * The reasoning for applying dependencies last is that the more complex
1323  * stats can track more complex correlations between the attributes, and
1324  * so may be considered more reliable.
1325  *
1326  * For example, MCV list can give us an exact selectivity for values in
1327  * two columns, while functional dependencies can only provide information
1328  * about the overall strength of the dependency.
1329  */
1330  sel *= dependencies_clauselist_selectivity(root, clauses, varRelid,
1331  jointype, sjinfo, rel,
1332  estimatedclauses);
1333 
1334  return sel;
1335 }
Selectivity dependencies_clauselist_selectivity(PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, RelOptInfo *rel, Bitmapset **estimatedclauses)
Definition: dependencies.c:941
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 268 of file extended_stats.c.

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

Referenced by BuildRelationExtStatistics(), and ComputeExtStatisticsRows().

269 {
270  int i;
271 
272  /*
273  * If there's statistics target set for the statistics object, use it.
274  * It may be set to 0 which disables building of that statistic.
275  */
276  if (stattarget >= 0)
277  return stattarget;
278 
279  /*
280  * The target for the statistics object is set to -1, in which case we
281  * look at the maximum target set for any of the attributes the object
282  * is defined on.
283  */
284  for (i = 0; i < nattrs; i++)
285  {
286  /* keep the maximmum statistics target */
287  if (stats[i]->attr->attstattarget > stattarget)
288  stattarget = stats[i]->attr->attstattarget;
289  }
290 
291  /*
292  * If the value is still negative (so neither the statistics object nor
293  * any of the columns have custom statistics target set), use the global
294  * default target.
295  */
296  if (stattarget < 0)
297  stattarget = default_statistics_target;
298 
299  /* As this point we should have a valid statistics target. */
300  Assert((stattarget >= 0) && (stattarget <= 10000));
301 
302  return stattarget;
303 }
Form_pg_attribute attr
Definition: vacuum.h:85
#define Assert(condition)
Definition: c.h:732
int i
int default_statistics_target
Definition: analyze.c:80

◆ statext_is_compatible_clause()

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

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

1071 {
1072  RangeTblEntry *rte = root->simple_rte_array[relid];
1073  RestrictInfo *rinfo = (RestrictInfo *) clause;
1074  Oid userid;
1075 
1076  if (!IsA(rinfo, RestrictInfo))
1077  return false;
1078 
1079  /* Pseudoconstants are not really interesting here. */
1080  if (rinfo->pseudoconstant)
1081  return false;
1082 
1083  /* clauses referencing multiple varnos are incompatible */
1085  return false;
1086 
1087  /* Check the clause and determine what attributes it references. */
1088  if (!statext_is_compatible_clause_internal(root, (Node *) rinfo->clause,
1089  relid, attnums))
1090  return false;
1091 
1092  /*
1093  * Check that the user has permission to read all these attributes. Use
1094  * checkAsUser if it's set, in case we're accessing the table via a view.
1095  */
1096  userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
1097 
1098  if (pg_class_aclcheck(rte->relid, userid, ACL_SELECT) != ACLCHECK_OK)
1099  {
1100  /* Don't have table privilege, must check individual columns */
1101  if (bms_is_member(InvalidAttrNumber, *attnums))
1102  {
1103  /* Have a whole-row reference, must have access to all columns */
1104  if (pg_attribute_aclcheck_all(rte->relid, userid, ACL_SELECT,
1106  return false;
1107  }
1108  else
1109  {
1110  /* Check the columns referenced by the clause */
1111  int attnum = -1;
1112 
1113  while ((attnum = bms_next_member(*attnums, attnum)) >= 0)
1114  {
1115  if (pg_attribute_aclcheck(rte->relid, attnum, userid,
1116  ACL_SELECT) != ACLCHECK_OK)
1117  return false;
1118  }
1119  }
1120  }
1121 
1122  /* If we reach here, the clause is OK */
1123  return true;
1124 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode)
Definition: aclchk.c:4517
Oid GetUserId(void)
Definition: miscinit.c:380
Relids clause_relids
Definition: pathnodes.h:1958
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
bool pseudoconstant
Definition: pathnodes.h:1951
Definition: nodes.h:525
unsigned int Oid
Definition: postgres_ext.h:31
RangeTblEntry ** simple_rte_array
Definition: pathnodes.h:209
Expr * clause
Definition: pathnodes.h:1943
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:4546
#define InvalidAttrNumber
Definition: attnum.h:23
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4631
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 911 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().

913 {
914  /* Look inside any binary-compatible relabeling (as in examine_variable) */
915  if (IsA(clause, RelabelType))
916  clause = (Node *) ((RelabelType *) clause)->arg;
917 
918  /* plain Var references (boolean Vars or recursive checks) */
919  if (IsA(clause, Var))
920  {
921  Var *var = (Var *) clause;
922 
923  /* Ensure var is from the correct relation */
924  if (var->varno != relid)
925  return false;
926 
927  /* we also better ensure the Var is from the current level */
928  if (var->varlevelsup > 0)
929  return false;
930 
931  /* Also skip system attributes (we don't allow stats on those). */
933  return false;
934 
935  *attnums = bms_add_member(*attnums, var->varattno);
936 
937  return true;
938  }
939 
940  /* (Var op Const) or (Const op Var) */
941  if (is_opclause(clause))
942  {
943  RangeTblEntry *rte = root->simple_rte_array[relid];
944  OpExpr *expr = (OpExpr *) clause;
945  Var *var;
946 
947  /* Only expressions with two arguments are considered compatible. */
948  if (list_length(expr->args) != 2)
949  return false;
950 
951  /* Check if the expression the right shape (one Var, one Const) */
952  if (!examine_opclause_expression(expr, &var, NULL, NULL))
953  return false;
954 
955  /*
956  * If it's not one of the supported operators ("=", "<", ">", etc.),
957  * just ignore the clause, as it's not compatible with MCV lists.
958  *
959  * This uses the function for estimating selectivity, not the operator
960  * directly (a bit awkward, but well ...).
961  */
962  switch (get_oprrest(expr->opno))
963  {
964  case F_EQSEL:
965  case F_NEQSEL:
966  case F_SCALARLTSEL:
967  case F_SCALARLESEL:
968  case F_SCALARGTSEL:
969  case F_SCALARGESEL:
970  /* supported, will continue with inspection of the Var */
971  break;
972 
973  default:
974  /* other estimators are considered unknown/unsupported */
975  return false;
976  }
977 
978  /*
979  * If there are any securityQuals on the RTE from security barrier
980  * views or RLS policies, then the user may not have access to all the
981  * table's data, and we must check that the operator is leak-proof.
982  *
983  * If the operator is leaky, then we must ignore this clause for the
984  * purposes of estimating with MCV lists, otherwise the operator might
985  * reveal values from the MCV list that the user doesn't have
986  * permission to see.
987  */
988  if (rte->securityQuals != NIL &&
990  return false;
991 
992  return statext_is_compatible_clause_internal(root, (Node *) var,
993  relid, attnums);
994  }
995 
996  /* AND/OR/NOT clause */
997  if (is_andclause(clause) ||
998  is_orclause(clause) ||
999  is_notclause(clause))
1000  {
1001  /*
1002  * AND/OR/NOT-clauses are supported if all sub-clauses are supported
1003  *
1004  * Perhaps we could improve this by handling mixed cases, when some of
1005  * the clauses are supported and some are not. Selectivity for the
1006  * supported subclauses would be computed using extended statistics,
1007  * and the remaining clauses would be estimated using the traditional
1008  * algorithm (product of selectivities).
1009  *
1010  * It however seems overly complex, and in a way we already do that
1011  * because if we reject the whole clause as unsupported here, it will
1012  * be eventually passed to clauselist_selectivity() which does exactly
1013  * this (split into supported/unsupported clauses etc).
1014  */
1015  BoolExpr *expr = (BoolExpr *) clause;
1016  ListCell *lc;
1017 
1018  foreach(lc, expr->args)
1019  {
1020  /*
1021  * Had we found incompatible clause in the arguments, treat the
1022  * whole clause as incompatible.
1023  */
1025  (Node *) lfirst(lc),
1026  relid, attnums))
1027  return false;
1028  }
1029 
1030  return true;
1031  }
1032 
1033  /* Var IS NULL */
1034  if (IsA(clause, NullTest))
1035  {
1036  NullTest *nt = (NullTest *) clause;
1037 
1038  /*
1039  * Only simple (Var IS NULL) expressions supported for now. Maybe we
1040  * could use examine_variable to fix this?
1041  */
1042  if (!IsA(nt->arg, Var))
1043  return false;
1044 
1045  return statext_is_compatible_clause_internal(root, (Node *) (nt->arg),
1046  relid, attnums);
1047  }
1048 
1049  return false;
1050 }
#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:177
static bool is_orclause(const void *clause)
Definition: nodeFuncs.h:102
List * securityQuals
Definition: parsenodes.h:1102
static bool is_andclause(const void *clause)
Definition: nodeFuncs.h:93
#define AttrNumberIsForUserDefinedAttr(attributeNumber)
Definition: attnum.h:41
Definition: nodes.h:525
AttrNumber varattno
Definition: primnodes.h:172
Definition: primnodes.h:167
Expr * arg
Definition: primnodes.h:1205
RangeTblEntry ** simple_rte_array
Definition: pathnodes.h:209
Index varno
Definition: primnodes.h:170
static bool is_notclause(const void *clause)
Definition: nodeFuncs.h:111
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:569
static bool statext_is_compatible_clause_internal(PlannerInfo *root, Node *clause, Index relid, Bitmapset **attnums)
void * arg
Oid opno
Definition: primnodes.h:502
static bool is_opclause(const void *clause)
Definition: nodeFuncs.h:62
bool examine_opclause_expression(OpExpr *expr, Var **varp, Const **cstp, bool *varonleftp)
List * args
Definition: primnodes.h:508

◆ statext_is_kind_built()

bool statext_is_kind_built ( HeapTuple  htup,
char  type 
)

Definition at line 310 of file extended_stats.c.

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

Referenced by get_relation_statistics(), and UpdateStatisticsForTypeChange().

311 {
313 
314  switch (type)
315  {
316  case STATS_EXT_NDISTINCT:
317  attnum = Anum_pg_statistic_ext_data_stxdndistinct;
318  break;
319 
320  case STATS_EXT_DEPENDENCIES:
321  attnum = Anum_pg_statistic_ext_data_stxddependencies;
322  break;
323 
324  case STATS_EXT_MCV:
325  attnum = Anum_pg_statistic_ext_data_stxdmcv;
326  break;
327 
328  default:
329  elog(ERROR, "unexpected statistics type requested: %d", type);
330  }
331 
332  return !heap_attisnull(htup, attnum, NULL);
333 }
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:226
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 1183 of file extended_stats.c.

References Assert, bms_add_member(), bms_add_members(), bms_is_member(), bms_is_subset(), bms_membership(), BMS_MULTIPLE, 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().

1186 {
1187  ListCell *l;
1188  Bitmapset *clauses_attnums = NULL;
1189  Bitmapset **list_attnums;
1190  int listidx;
1192  List *stat_clauses;
1193  Selectivity simple_sel,
1194  mcv_sel,
1195  mcv_basesel,
1196  mcv_totalsel,
1197  other_sel,
1198  sel;
1199 
1200  /* check if there's any stats that might be useful for us. */
1201  if (!has_stats_of_kind(rel->statlist, STATS_EXT_MCV))
1202  return 1.0;
1203 
1204  list_attnums = (Bitmapset **) palloc(sizeof(Bitmapset *) *
1205  list_length(clauses));
1206 
1207  /*
1208  * Pre-process the clauses list to extract the attnums seen in each item.
1209  * We need to determine if there's any clauses which will be useful for
1210  * selectivity estimations with extended stats. Along the way we'll record
1211  * all of the attnums for each clause in a list which we'll reference
1212  * later so we don't need to repeat the same work again. We'll also keep
1213  * track of all attnums seen.
1214  *
1215  * We also skip clauses that we already estimated using different types of
1216  * statistics (we treat them as incompatible).
1217  */
1218  listidx = 0;
1219  foreach(l, clauses)
1220  {
1221  Node *clause = (Node *) lfirst(l);
1222  Bitmapset *attnums = NULL;
1223 
1224  if (!bms_is_member(listidx, *estimatedclauses) &&
1225  statext_is_compatible_clause(root, clause, rel->relid, &attnums))
1226  {
1227  list_attnums[listidx] = attnums;
1228  clauses_attnums = bms_add_members(clauses_attnums, attnums);
1229  }
1230  else
1231  list_attnums[listidx] = NULL;
1232 
1233  listidx++;
1234  }
1235 
1236  /* We need at least two attributes for multivariate statistics. */
1237  if (bms_membership(clauses_attnums) != BMS_MULTIPLE)
1238  return 1.0;
1239 
1240  /* find the best suited statistics object for these attnums */
1241  stat = choose_best_statistics(rel->statlist, clauses_attnums, STATS_EXT_MCV);
1242 
1243  /* if no matching stats could be found then we've nothing to do */
1244  if (!stat)
1245  return 1.0;
1246 
1247  /* Ensure choose_best_statistics produced an expected stats type. */
1248  Assert(stat->kind == STATS_EXT_MCV);
1249 
1250  /* now filter the clauses to be estimated using the selected MCV */
1251  stat_clauses = NIL;
1252 
1253  listidx = 0;
1254  foreach(l, clauses)
1255  {
1256  /*
1257  * If the clause is compatible with the selected statistics, mark it
1258  * as estimated and add it to the list to estimate.
1259  */
1260  if (list_attnums[listidx] != NULL &&
1261  bms_is_subset(list_attnums[listidx], stat->keys))
1262  {
1263  stat_clauses = lappend(stat_clauses, (Node *) lfirst(l));
1264  *estimatedclauses = bms_add_member(*estimatedclauses, listidx);
1265  }
1266 
1267  listidx++;
1268  }
1269 
1270  /*
1271  * First compute "simple" selectivity, i.e. without the extended
1272  * statistics, and essentially assuming independence of the
1273  * columns/clauses. We'll then use the various selectivities computed from
1274  * MCV list to improve it.
1275  */
1276  simple_sel = clauselist_selectivity_simple(root, stat_clauses, varRelid,
1277  jointype, sjinfo, NULL);
1278 
1279  /*
1280  * Now compute the multi-column estimate from the MCV list, along with the
1281  * other selectivities (base & total selectivity).
1282  */
1283  mcv_sel = mcv_clauselist_selectivity(root, stat, stat_clauses, varRelid,
1284  jointype, sjinfo, rel,
1285  &mcv_basesel, &mcv_totalsel);
1286 
1287  /* Estimated selectivity of values not covered by MCV matches */
1288  other_sel = simple_sel - mcv_basesel;
1289  CLAMP_PROBABILITY(other_sel);
1290 
1291  /* The non-MCV selectivity can't exceed the 1 - mcv_totalsel. */
1292  if (other_sel > 1.0 - mcv_totalsel)
1293  other_sel = 1.0 - mcv_totalsel;
1294 
1295  /* Overall selectivity is the combination of MCV and non-MCV estimates. */
1296  sel = mcv_sel + other_sel;
1297  CLAMP_PROBABILITY(sel);
1298 
1299  return sel;
1300 }
#define NIL
Definition: pg_list.h:65
List * statlist
Definition: pathnodes.h:679
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:151
#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:669
List * lappend(List *list, void *datum)
Definition: list.c:321
#define stat(a, b)
Definition: win32_port.h:264
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:672
StatisticExtInfo * choose_best_statistics(List *stats, Bitmapset *attnums, char requiredkind)
#define Assert(condition)
Definition: c.h:732
#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:885
void * palloc(Size size)
Definition: mcxt.c:924
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)
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793

◆ statext_store()

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

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

471 {
472  HeapTuple stup,
473  oldtup;
474  Datum values[Natts_pg_statistic_ext_data];
475  bool nulls[Natts_pg_statistic_ext_data];
476  bool replaces[Natts_pg_statistic_ext_data];
477  Relation pg_stextdata;
478 
479  memset(nulls, true, sizeof(nulls));
480  memset(replaces, false, sizeof(replaces));
481  memset(values, 0, sizeof(values));
482 
483  /*
484  * Construct a new pg_statistic_ext_data tuple, replacing the calculated
485  * stats.
486  */
487  if (ndistinct != NULL)
488  {
489  bytea *data = statext_ndistinct_serialize(ndistinct);
490 
491  nulls[Anum_pg_statistic_ext_data_stxdndistinct - 1] = (data == NULL);
492  values[Anum_pg_statistic_ext_data_stxdndistinct - 1] = PointerGetDatum(data);
493  }
494 
495  if (dependencies != NULL)
496  {
497  bytea *data = statext_dependencies_serialize(dependencies);
498 
499  nulls[Anum_pg_statistic_ext_data_stxddependencies - 1] = (data == NULL);
500  values[Anum_pg_statistic_ext_data_stxddependencies - 1] = PointerGetDatum(data);
501  }
502  if (mcv != NULL)
503  {
504  bytea *data = statext_mcv_serialize(mcv, stats);
505 
506  nulls[Anum_pg_statistic_ext_data_stxdmcv - 1] = (data == NULL);
507  values[Anum_pg_statistic_ext_data_stxdmcv - 1] = PointerGetDatum(data);
508  }
509 
510  /* always replace the value (either by bytea or NULL) */
511  replaces[Anum_pg_statistic_ext_data_stxdndistinct - 1] = true;
512  replaces[Anum_pg_statistic_ext_data_stxddependencies - 1] = true;
513  replaces[Anum_pg_statistic_ext_data_stxdmcv - 1] = true;
514 
515  /* there should already be a pg_statistic_ext_data tuple */
517  if (!HeapTupleIsValid(oldtup))
518  elog(ERROR, "cache lookup failed for statistics object %u", statOid);
519 
520  /* replace it */
521  pg_stextdata = table_open(StatisticExtDataRelationId, RowExclusiveLock);
522 
523  stup = heap_modify_tuple(oldtup,
524  RelationGetDescr(pg_stextdata),
525  values,
526  nulls,
527  replaces);
528  ReleaseSysCache(oldtup);
529  CatalogTupleUpdate(pg_stextdata, &stup->t_self, stup);
530 
531  heap_freetuple(stup);
532 
533  table_close(pg_stextdata, RowExclusiveLock);
534 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define RelationGetDescr(relation)
Definition: rel.h:442
#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:1124
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
bytea * statext_ndistinct_serialize(MVNDistinct *ndistinct)
Definition: mvdistinct.c:172
#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:226
Definition: c.h:549
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