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 "executor/executor.h"
#include "commands/defrem.h"
#include "commands/progress.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/optimizer.h"
#include "parser/parsetree.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "statistics/extended_stats_internal.h"
#include "statistics/statistics.h"
#include "utils/acl.h"
#include "utils/array.h"
#include "utils/attoptcache.h"
#include "utils/builtins.h"
#include "utils/datum.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 "utils/typcache.h"
Include dependency graph for extended_stats.c:

Go to the source code of this file.

Data Structures

struct  StatExtEntry
 
struct  AnlExprData
 

Macros

#define WIDTH_THRESHOLD   1024
 

Typedefs

typedef struct StatExtEntry StatExtEntry
 
typedef struct AnlExprData AnlExprData
 

Functions

static Listfetch_statentries_for_relation (Relation pg_statext, Oid relid)
 
static VacAttrStats ** lookup_var_attr_stats (Relation rel, Bitmapset *attrs, List *exprs, int nvacatts, VacAttrStats **vacatts)
 
static void statext_store (Oid statOid, bool inh, MVNDistinct *ndistinct, MVDependencies *dependencies, MCVList *mcv, Datum exprs, VacAttrStats **stats)
 
static int statext_compute_stattarget (int stattarget, int nattrs, VacAttrStats **stats)
 
static void compute_expr_stats (Relation onerel, double totalrows, AnlExprData *exprdata, int nexprs, HeapTuple *rows, int numrows)
 
static Datum serialize_expr_stats (AnlExprData *exprdata, int nexprs)
 
static Datum expr_fetch_func (VacAttrStatsP stats, int rownum, bool *isNull)
 
static AnlExprDatabuild_expr_data (List *exprs, int stattarget)
 
static StatsBuildDatamake_build_data (Relation rel, StatExtEntry *stat, int numrows, HeapTuple *rows, VacAttrStats **stats, int stattarget)
 
void BuildRelationExtStatistics (Relation onerel, bool inh, 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)
 
static VacAttrStatsexamine_attribute (Node *expr)
 
static VacAttrStatsexamine_expression (Node *expr, int stattarget)
 
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)
 
AttrNumberbuild_attnums_array (Bitmapset *attrs, int nexprs, int *numattrs)
 
SortItembuild_sorted_items (StatsBuildData *data, int *nitems, MultiSortSupport mss, int numattrs, AttrNumber *attnums)
 
bool has_stats_of_kind (List *stats, char requiredkind)
 
static int stat_find_expression (StatisticExtInfo *stat, Node *expr)
 
static bool stat_covers_expressions (StatisticExtInfo *stat, List *exprs, Bitmapset **expr_idxs)
 
StatisticExtInfochoose_best_statistics (List *stats, char requiredkind, bool inh, Bitmapset **clause_attnums, List **clause_exprs, int nclauses)
 
static bool statext_is_compatible_clause_internal (PlannerInfo *root, Node *clause, Index relid, Bitmapset **attnums, List **exprs)
 
static bool statext_is_compatible_clause (PlannerInfo *root, Node *clause, Index relid, Bitmapset **attnums, List **exprs)
 
static Selectivity statext_mcv_clauselist_selectivity (PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, RelOptInfo *rel, Bitmapset **estimatedclauses, bool is_or)
 
Selectivity statext_clauselist_selectivity (PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, RelOptInfo *rel, Bitmapset **estimatedclauses, bool is_or)
 
bool examine_opclause_args (List *args, Node **exprp, Const **cstp, bool *expronleftp)
 
HeapTuple statext_expressions_load (Oid stxoid, bool inh, int idx)
 

Macro Definition Documentation

◆ WIDTH_THRESHOLD

#define WIDTH_THRESHOLD   1024

Definition at line 61 of file extended_stats.c.

Typedef Documentation

◆ AnlExprData

typedef struct AnlExprData AnlExprData

◆ StatExtEntry

typedef struct StatExtEntry StatExtEntry

Function Documentation

◆ build_attnums_array()

AttrNumber* build_attnums_array ( Bitmapset attrs,
int  nexprs,
int *  numattrs 
)

Definition at line 965 of file extended_stats.c.

966 {
967  int i,
968  j;
969  AttrNumber *attnums;
970  int num = bms_num_members(attrs);
971 
972  if (numattrs)
973  *numattrs = num;
974 
975  /* build attnums from the bitmapset */
976  attnums = (AttrNumber *) palloc(sizeof(AttrNumber) * num);
977  i = 0;
978  j = -1;
979  while ((j = bms_next_member(attrs, j)) >= 0)
980  {
981  int attnum = (j - nexprs);
982 
983  /*
984  * Make sure the bitmap contains only user-defined attributes. As
985  * bitmaps can't contain negative values, this can be violated in two
986  * ways. Firstly, the bitmap might contain 0 as a member, and secondly
987  * the integer value might be larger than MaxAttrNumber.
988  */
991  Assert(attnum >= (-nexprs));
992 
993  attnums[i++] = (AttrNumber) attnum;
994 
995  /* protect against overflows */
996  Assert(i <= num);
997  }
998 
999  return attnums;
1000 }
int16 AttrNumber
Definition: attnum.h:21
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
#define MaxAttrNumber
Definition: attnum.h:24
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1039
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:665
int j
Definition: isn.c:74
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
void * palloc(Size size)
Definition: mcxt.c:1210
int16 attnum
Definition: pg_attribute.h:74

References Assert(), attnum, AttributeNumberIsValid, bms_next_member(), bms_num_members(), i, j, MaxAttrNumber, and palloc().

◆ build_expr_data()

static AnlExprData * build_expr_data ( List exprs,
int  stattarget 
)
static

Definition at line 2295 of file extended_stats.c.

2296 {
2297  int idx;
2298  int nexprs = list_length(exprs);
2299  AnlExprData *exprdata;
2300  ListCell *lc;
2301 
2302  exprdata = (AnlExprData *) palloc0(nexprs * sizeof(AnlExprData));
2303 
2304  idx = 0;
2305  foreach(lc, exprs)
2306  {
2307  Node *expr = (Node *) lfirst(lc);
2308  AnlExprData *thisdata = &exprdata[idx];
2309 
2310  thisdata->expr = expr;
2311  thisdata->vacattrstat = examine_expression(expr, stattarget);
2312  idx++;
2313  }
2314 
2315  return exprdata;
2316 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
static VacAttrStats * examine_expression(Node *expr, int stattarget)
void * palloc0(Size size)
Definition: mcxt.c:1241
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
VacAttrStats * vacattrstat
Definition: nodes.h:129

References examine_expression(), AnlExprData::expr, idx(), lfirst, list_length(), palloc0(), and AnlExprData::vacattrstat.

Referenced by BuildRelationExtStatistics().

◆ build_sorted_items()

SortItem* build_sorted_items ( StatsBuildData data,
int *  nitems,
MultiSortSupport  mss,
int  numattrs,
AttrNumber attnums 
)

Definition at line 1010 of file extended_stats.c.

1013 {
1014  int i,
1015  j,
1016  len,
1017  nrows;
1018  int nvalues = data->numrows * numattrs;
1019 
1020  SortItem *items;
1021  Datum *values;
1022  bool *isnull;
1023  char *ptr;
1024  int *typlen;
1025 
1026  /* Compute the total amount of memory we need (both items and values). */
1027  len = data->numrows * sizeof(SortItem) + nvalues * (sizeof(Datum) + sizeof(bool));
1028 
1029  /* Allocate the memory and split it into the pieces. */
1030  ptr = palloc0(len);
1031 
1032  /* items to sort */
1033  items = (SortItem *) ptr;
1034  ptr += data->numrows * sizeof(SortItem);
1035 
1036  /* values and null flags */
1037  values = (Datum *) ptr;
1038  ptr += nvalues * sizeof(Datum);
1039 
1040  isnull = (bool *) ptr;
1041  ptr += nvalues * sizeof(bool);
1042 
1043  /* make sure we consumed the whole buffer exactly */
1044  Assert((ptr - (char *) items) == len);
1045 
1046  /* fix the pointers to Datum and bool arrays */
1047  nrows = 0;
1048  for (i = 0; i < data->numrows; i++)
1049  {
1050  items[nrows].values = &values[nrows * numattrs];
1051  items[nrows].isnull = &isnull[nrows * numattrs];
1052 
1053  nrows++;
1054  }
1055 
1056  /* build a local cache of typlen for all attributes */
1057  typlen = (int *) palloc(sizeof(int) * data->nattnums);
1058  for (i = 0; i < data->nattnums; i++)
1059  typlen[i] = get_typlen(data->stats[i]->attrtypid);
1060 
1061  nrows = 0;
1062  for (i = 0; i < data->numrows; i++)
1063  {
1064  bool toowide = false;
1065 
1066  /* load the values/null flags from sample rows */
1067  for (j = 0; j < numattrs; j++)
1068  {
1069  Datum value;
1070  bool isnull;
1071  int attlen;
1072  AttrNumber attnum = attnums[j];
1073 
1074  int idx;
1075 
1076  /* match attnum to the pre-calculated data */
1077  for (idx = 0; idx < data->nattnums; idx++)
1078  {
1079  if (attnum == data->attnums[idx])
1080  break;
1081  }
1082 
1083  Assert(idx < data->nattnums);
1084 
1085  value = data->values[idx][i];
1086  isnull = data->nulls[idx][i];
1087  attlen = typlen[idx];
1088 
1089  /*
1090  * If this is a varlena value, check if it's too wide and if yes
1091  * then skip the whole item. Otherwise detoast the value.
1092  *
1093  * XXX It may happen that we've already detoasted some preceding
1094  * values for the current item. We don't bother to cleanup those
1095  * on the assumption that those are small (below WIDTH_THRESHOLD)
1096  * and will be discarded at the end of analyze.
1097  */
1098  if ((!isnull) && (attlen == -1))
1099  {
1101  {
1102  toowide = true;
1103  break;
1104  }
1105 
1107  }
1108 
1109  items[nrows].values[j] = value;
1110  items[nrows].isnull[j] = isnull;
1111  }
1112 
1113  if (toowide)
1114  continue;
1115 
1116  nrows++;
1117  }
1118 
1119  /* store the actual number of items (ignoring the too-wide ones) */
1120  *nitems = nrows;
1121 
1122  /* all items were too wide */
1123  if (nrows == 0)
1124  {
1125  /* everything is allocated as a single chunk */
1126  pfree(items);
1127  return NULL;
1128  }
1129 
1130  /* do the sort, using the multi-sort */
1131  qsort_interruptible(items, nrows, sizeof(SortItem),
1132  multi_sort_compare, mss);
1133 
1134  return items;
1135 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
unsigned char bool
Definition: c.h:440
Size toast_raw_datum_size(Datum value)
Definition: detoast.c:545
#define WIDTH_THRESHOLD
int multi_sort_compare(const void *a, const void *b, void *arg)
struct SortItem SortItem
#define PG_DETOAST_DATUM(datum)
Definition: fmgr.h:240
#define nitems(x)
Definition: indent.h:31
static struct @145 value
int16 get_typlen(Oid typid)
Definition: lsyscache.c:2155
void pfree(void *pointer)
Definition: mcxt.c:1436
int16 attlen
Definition: pg_attribute.h:59
const void size_t len
const void * data
void qsort_interruptible(void *base, size_t nel, size_t elsize, qsort_arg_comparator cmp, void *arg)
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64

References Assert(), attlen, attnum, data, get_typlen(), i, idx(), SortItem::isnull, j, len, multi_sort_compare(), nitems, palloc(), palloc0(), pfree(), PG_DETOAST_DATUM, PointerGetDatum(), qsort_interruptible(), toast_raw_datum_size(), value, values, SortItem::values, and WIDTH_THRESHOLD.

Referenced by dependency_degree(), and statext_mcv_build().

◆ BuildRelationExtStatistics()

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

Definition at line 115 of file extended_stats.c.

118 {
119  Relation pg_stext;
120  ListCell *lc;
121  List *statslist;
122  MemoryContext cxt;
123  MemoryContext oldcxt;
124  int64 ext_cnt;
125 
126  /* Do nothing if there are no columns to analyze. */
127  if (!natts)
128  return;
129 
130  /* the list of stats has to be allocated outside the memory context */
131  pg_stext = table_open(StatisticExtRelationId, RowExclusiveLock);
132  statslist = fetch_statentries_for_relation(pg_stext, RelationGetRelid(onerel));
133 
134  /* memory context for building each statistics object */
136  "BuildRelationExtStatistics",
138  oldcxt = MemoryContextSwitchTo(cxt);
139 
140  /* report this phase */
141  if (statslist != NIL)
142  {
143  const int index[] = {
146  };
147  const int64 val[] = {
149  list_length(statslist)
150  };
151 
153  }
154 
155  ext_cnt = 0;
156  foreach(lc, statslist)
157  {
159  MVNDistinct *ndistinct = NULL;
160  MVDependencies *dependencies = NULL;
161  MCVList *mcv = NULL;
162  Datum exprstats = (Datum) 0;
163  VacAttrStats **stats;
164  ListCell *lc2;
165  int stattarget;
167 
168  /*
169  * Check if we can build these stats based on the column analyzed. If
170  * not, report this fact (except in autovacuum) and move on.
171  */
172  stats = lookup_var_attr_stats(onerel, stat->columns, stat->exprs,
173  natts, vacattrstats);
174  if (!stats)
175  {
178  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
179  errmsg("statistics object \"%s.%s\" could not be computed for relation \"%s.%s\"",
180  stat->schema, stat->name,
181  get_namespace_name(onerel->rd_rel->relnamespace),
182  RelationGetRelationName(onerel)),
183  errtable(onerel)));
184  continue;
185  }
186 
187  /* compute statistics target for this statistics object */
188  stattarget = statext_compute_stattarget(stat->stattarget,
189  bms_num_members(stat->columns),
190  stats);
191 
192  /*
193  * Don't rebuild statistics objects with statistics target set to 0
194  * (we just leave the existing values around, just like we do for
195  * regular per-column statistics).
196  */
197  if (stattarget == 0)
198  continue;
199 
200  /* evaluate expressions (if the statistics object has any) */
201  data = make_build_data(onerel, stat, numrows, rows, stats, stattarget);
202 
203  /* compute statistic of each requested type */
204  foreach(lc2, stat->types)
205  {
206  char t = (char) lfirst_int(lc2);
207 
208  if (t == STATS_EXT_NDISTINCT)
209  ndistinct = statext_ndistinct_build(totalrows, data);
210  else if (t == STATS_EXT_DEPENDENCIES)
211  dependencies = statext_dependencies_build(data);
212  else if (t == STATS_EXT_MCV)
213  mcv = statext_mcv_build(data, totalrows, stattarget);
214  else if (t == STATS_EXT_EXPRESSIONS)
215  {
216  AnlExprData *exprdata;
217  int nexprs;
218 
219  /* should not happen, thanks to checks when defining stats */
220  if (!stat->exprs)
221  elog(ERROR, "requested expression stats, but there are no expressions");
222 
223  exprdata = build_expr_data(stat->exprs, stattarget);
224  nexprs = list_length(stat->exprs);
225 
226  compute_expr_stats(onerel, totalrows,
227  exprdata, nexprs,
228  rows, numrows);
229 
230  exprstats = serialize_expr_stats(exprdata, nexprs);
231  }
232  }
233 
234  /* store the statistics in the catalog */
235  statext_store(stat->statOid, inh,
236  ndistinct, dependencies, mcv, exprstats, stats);
237 
238  /* for reporting progress */
240  ++ext_cnt);
241 
242  /* free the data used for building this statistics object */
243  MemoryContextReset(cxt);
244  }
245 
246  MemoryContextSwitchTo(oldcxt);
247  MemoryContextDelete(cxt);
248 
249  list_free(statslist);
250 
251  table_close(pg_stext, RowExclusiveLock);
252 }
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:3324
void pgstat_progress_update_param(int index, int64 val)
void pgstat_progress_update_multi_param(int nparam, const int *index, const int64 *val)
MVDependencies * statext_dependencies_build(StatsBuildData *data)
Definition: dependencies.c:350
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define WARNING
Definition: elog.h:36
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
static AnlExprData * build_expr_data(List *exprs, int stattarget)
static StatsBuildData * make_build_data(Relation rel, StatExtEntry *stat, int numrows, HeapTuple *rows, VacAttrStats **stats, int stattarget)
static VacAttrStats ** lookup_var_attr_stats(Relation rel, Bitmapset *attrs, List *exprs, int nvacatts, VacAttrStats **vacatts)
static List * fetch_statentries_for_relation(Relation pg_statext, Oid relid)
static void statext_store(Oid statOid, bool inh, MVNDistinct *ndistinct, MVDependencies *dependencies, MCVList *mcv, Datum exprs, VacAttrStats **stats)
static void compute_expr_stats(Relation onerel, double totalrows, AnlExprData *exprdata, int nexprs, HeapTuple *rows, int numrows)
static int statext_compute_stattarget(int stattarget, int nattrs, VacAttrStats **stats)
static Datum serialize_expr_stats(AnlExprData *exprdata, int nexprs)
long val
Definition: informix.c:664
void list_free(List *list)
Definition: list.c:1545
#define RowExclusiveLock
Definition: lockdefs.h:38
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3324
MCVList * statext_mcv_build(StatsBuildData *data, double totalrows, int stattarget)
Definition: mcv.c:184
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:314
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:387
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:153
MVNDistinct * statext_ndistinct_build(double totalrows, StatsBuildData *data)
Definition: mvdistinct.c:89
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
#define NIL
Definition: pg_list.h:68
#define lfirst_int(lc)
Definition: pg_list.h:173
#define PROGRESS_ANALYZE_EXT_STATS_COMPUTED
Definition: progress.h:42
#define PROGRESS_ANALYZE_PHASE
Definition: progress.h:38
#define PROGRESS_ANALYZE_PHASE_COMPUTE_EXT_STATS
Definition: progress.h:51
#define PROGRESS_ANALYZE_EXT_STATS_TOTAL
Definition: progress.h:41
#define RelationGetRelid(relation)
Definition: rel.h:503
#define RelationGetRelationName(relation)
Definition: rel.h:537
int errtable(Relation rel)
Definition: relcache.c:5906
Definition: pg_list.h:54
Form_pg_class rd_rel
Definition: rel.h:110
Definition: type.h:95
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, bms_num_members(), build_expr_data(), compute_expr_stats(), CurrentMemoryContext, data, elog(), ereport, errcode(), errmsg(), ERROR, errtable(), fetch_statentries_for_relation(), get_namespace_name(), IsAutoVacuumWorkerProcess(), lfirst, lfirst_int, list_free(), list_length(), lookup_var_attr_stats(), make_build_data(), MemoryContextDelete(), MemoryContextReset(), MemoryContextSwitchTo(), 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, serialize_expr_stats(), statext_compute_stattarget(), statext_dependencies_build(), statext_mcv_build(), statext_ndistinct_build(), statext_store(), table_close(), table_open(), val, and WARNING.

Referenced by do_analyze_rel().

◆ choose_best_statistics()

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

Definition at line 1233 of file extended_stats.c.

1236 {
1237  ListCell *lc;
1238  StatisticExtInfo *best_match = NULL;
1239  int best_num_matched = 2; /* goal #1: maximize */
1240  int best_match_keys = (STATS_MAX_DIMENSIONS + 1); /* goal #2: minimize */
1241 
1242  foreach(lc, stats)
1243  {
1244  int i;
1245  StatisticExtInfo *info = (StatisticExtInfo *) lfirst(lc);
1246  Bitmapset *matched_attnums = NULL;
1247  Bitmapset *matched_exprs = NULL;
1248  int num_matched;
1249  int numkeys;
1250 
1251  /* skip statistics that are not of the correct type */
1252  if (info->kind != requiredkind)
1253  continue;
1254 
1255  /* skip statistics with mismatching inheritance flag */
1256  if (info->inherit != inh)
1257  continue;
1258 
1259  /*
1260  * Collect attributes and expressions in remaining (unestimated)
1261  * clauses fully covered by this statistic object.
1262  *
1263  * We know already estimated clauses have both clause_attnums and
1264  * clause_exprs set to NULL. We leave the pointers NULL if already
1265  * estimated, or we reset them to NULL after estimating the clause.
1266  */
1267  for (i = 0; i < nclauses; i++)
1268  {
1269  Bitmapset *expr_idxs = NULL;
1270 
1271  /* ignore incompatible/estimated clauses */
1272  if (!clause_attnums[i] && !clause_exprs[i])
1273  continue;
1274 
1275  /* ignore clauses that are not covered by this object */
1276  if (!bms_is_subset(clause_attnums[i], info->keys) ||
1277  !stat_covers_expressions(info, clause_exprs[i], &expr_idxs))
1278  continue;
1279 
1280  /* record attnums and indexes of expressions covered */
1281  matched_attnums = bms_add_members(matched_attnums, clause_attnums[i]);
1282  matched_exprs = bms_add_members(matched_exprs, expr_idxs);
1283  }
1284 
1285  num_matched = bms_num_members(matched_attnums) + bms_num_members(matched_exprs);
1286 
1287  bms_free(matched_attnums);
1288  bms_free(matched_exprs);
1289 
1290  /*
1291  * save the actual number of keys in the stats so that we can choose
1292  * the narrowest stats with the most matching keys.
1293  */
1294  numkeys = bms_num_members(info->keys) + list_length(info->exprs);
1295 
1296  /*
1297  * Use this object when it increases the number of matched attributes
1298  * and expressions or when it matches the same number of attributes
1299  * and expressions but these stats have fewer keys than any previous
1300  * match.
1301  */
1302  if (num_matched > best_num_matched ||
1303  (num_matched == best_num_matched && numkeys < best_match_keys))
1304  {
1305  best_match = info;
1306  best_num_matched = num_matched;
1307  best_match_keys = numkeys;
1308  }
1309  }
1310 
1311  return best_match;
1312 }
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:332
void bms_free(Bitmapset *a)
Definition: bitmapset.c:209
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:818
static bool stat_covers_expressions(StatisticExtInfo *stat, List *exprs, Bitmapset **expr_idxs)
#define STATS_MAX_DIMENSIONS
Definition: statistics.h:19
Bitmapset * keys
Definition: pathnodes.h:1274

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

Referenced by statext_mcv_clauselist_selectivity().

◆ compare_datums_simple()

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

Definition at line 951 of file extended_stats.c.

952 {
953  return ApplySortComparator(a, false, b, false, ssup);
954 }
int b
Definition: isn.c:70
int a
Definition: isn.c:69
static int ApplySortComparator(Datum datum1, bool isNull1, Datum datum2, bool isNull2, SortSupport ssup)
Definition: sortsupport.h:200

References a, ApplySortComparator(), and b.

Referenced by compare_scalars_simple(), and statext_mcv_serialize().

◆ compare_scalars_simple()

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

Definition at line 943 of file extended_stats.c.

944 {
945  return compare_datums_simple(*(Datum *) a,
946  *(Datum *) b,
947  (SortSupport) arg);
948 }
int compare_datums_simple(Datum a, Datum b, SortSupport ssup)
void * arg

References a, arg, b, and compare_datums_simple().

Referenced by statext_mcv_serialize().

◆ compute_expr_stats()

static void compute_expr_stats ( Relation  onerel,
double  totalrows,
AnlExprData exprdata,
int  nexprs,
HeapTuple rows,
int  numrows 
)
static

Definition at line 2134 of file extended_stats.c.

2137 {
2138  MemoryContext expr_context,
2139  old_context;
2140  int ind,
2141  i;
2142 
2144  "Analyze Expression",
2146  old_context = MemoryContextSwitchTo(expr_context);
2147 
2148  for (ind = 0; ind < nexprs; ind++)
2149  {
2150  AnlExprData *thisdata = &exprdata[ind];
2151  VacAttrStats *stats = thisdata->vacattrstat;
2152  Node *expr = thisdata->expr;
2153  TupleTableSlot *slot;
2154  EState *estate;
2155  ExprContext *econtext;
2156  Datum *exprvals;
2157  bool *exprnulls;
2158  ExprState *exprstate;
2159  int tcnt;
2160 
2161  /* Are we still in the main context? */
2162  Assert(CurrentMemoryContext == expr_context);
2163 
2164  /*
2165  * Need an EState for evaluation of expressions. Create it in the
2166  * per-expression context to be sure it gets cleaned up at the bottom
2167  * of the loop.
2168  */
2169  estate = CreateExecutorState();
2170  econtext = GetPerTupleExprContext(estate);
2171 
2172  /* Set up expression evaluation state */
2173  exprstate = ExecPrepareExpr((Expr *) expr, estate);
2174 
2175  /* Need a slot to hold the current heap tuple, too */
2177  &TTSOpsHeapTuple);
2178 
2179  /* Arrange for econtext's scan tuple to be the tuple under test */
2180  econtext->ecxt_scantuple = slot;
2181 
2182  /* Compute and save expression values */
2183  exprvals = (Datum *) palloc(numrows * sizeof(Datum));
2184  exprnulls = (bool *) palloc(numrows * sizeof(bool));
2185 
2186  tcnt = 0;
2187  for (i = 0; i < numrows; i++)
2188  {
2189  Datum datum;
2190  bool isnull;
2191 
2192  /*
2193  * Reset the per-tuple context each time, to reclaim any cruft
2194  * left behind by evaluating the statistics expressions.
2195  */
2196  ResetExprContext(econtext);
2197 
2198  /* Set up for expression evaluation */
2199  ExecStoreHeapTuple(rows[i], slot, false);
2200 
2201  /*
2202  * Evaluate the expression. We do this in the per-tuple context so
2203  * as not to leak memory, and then copy the result into the
2204  * context created at the beginning of this function.
2205  */
2206  datum = ExecEvalExprSwitchContext(exprstate,
2207  GetPerTupleExprContext(estate),
2208  &isnull);
2209  if (isnull)
2210  {
2211  exprvals[tcnt] = (Datum) 0;
2212  exprnulls[tcnt] = true;
2213  }
2214  else
2215  {
2216  /* Make sure we copy the data into the context. */
2217  Assert(CurrentMemoryContext == expr_context);
2218 
2219  exprvals[tcnt] = datumCopy(datum,
2220  stats->attrtype->typbyval,
2221  stats->attrtype->typlen);
2222  exprnulls[tcnt] = false;
2223  }
2224 
2225  tcnt++;
2226  }
2227 
2228  /*
2229  * Now we can compute the statistics for the expression columns.
2230  *
2231  * XXX Unlike compute_index_stats we don't need to switch and reset
2232  * memory contexts here, because we're only computing stats for a
2233  * single expression (and not iterating over many indexes), so we just
2234  * do it in expr_context. Note that compute_stats copies the result
2235  * into stats->anl_context, so it does not disappear.
2236  */
2237  if (tcnt > 0)
2238  {
2239  AttributeOpts *aopt =
2240  get_attribute_options(stats->attr->attrelid,
2241  stats->attr->attnum);
2242 
2243  stats->exprvals = exprvals;
2244  stats->exprnulls = exprnulls;
2245  stats->rowstride = 1;
2246  stats->compute_stats(stats,
2248  tcnt,
2249  tcnt);
2250 
2251  /*
2252  * If the n_distinct option is specified, it overrides the above
2253  * computation.
2254  */
2255  if (aopt != NULL && aopt->n_distinct != 0.0)
2256  stats->stadistinct = aopt->n_distinct;
2257  }
2258 
2259  /* And clean up */
2260  MemoryContextSwitchTo(expr_context);
2261 
2263  FreeExecutorState(estate);
2265  }
2266 
2267  MemoryContextSwitchTo(old_context);
2268  MemoryContextDelete(expr_context);
2269 }
AttributeOpts * get_attribute_options(Oid attrelid, int attnum)
Definition: attoptcache.c:104
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:735
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1254
TupleTableSlot * ExecStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1352
const TupleTableSlotOps TTSOpsHeapTuple
Definition: execTuples.c:84
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1238
EState * CreateExecutorState(void)
Definition: execUtils.c:93
void FreeExecutorState(EState *estate)
Definition: execUtils.c:194
#define GetPerTupleExprContext(estate)
Definition: executor.h:548
#define ResetExprContext(econtext)
Definition: executor.h:542
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:346
static Datum expr_fetch_func(VacAttrStatsP stats, int rownum, bool *isNull)
#define MemoryContextResetAndDeleteChildren(ctx)
Definition: memutils.h:70
#define RelationGetDescr(relation)
Definition: rel.h:529
float8 n_distinct
Definition: attoptcache.h:22
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:249
Form_pg_type attrtype
Definition: vacuum.h:131
int rowstride
Definition: vacuum.h:179
Form_pg_attribute attr
Definition: vacuum.h:128
bool * exprnulls
Definition: vacuum.h:178
Datum * exprvals
Definition: vacuum.h:177
float4 stadistinct
Definition: vacuum.h:150
AnalyzeAttrComputeStatsFunc compute_stats
Definition: vacuum.h:139

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert(), VacAttrStats::attr, VacAttrStats::attrtype, VacAttrStats::compute_stats, CreateExecutorState(), CurrentMemoryContext, datumCopy(), ExprContext::ecxt_scantuple, ExecDropSingleTupleTableSlot(), ExecEvalExprSwitchContext(), ExecPrepareExpr(), ExecStoreHeapTuple(), AnlExprData::expr, expr_fetch_func(), VacAttrStats::exprnulls, VacAttrStats::exprvals, FreeExecutorState(), get_attribute_options(), GetPerTupleExprContext, i, MakeSingleTupleTableSlot(), MemoryContextDelete(), MemoryContextResetAndDeleteChildren, MemoryContextSwitchTo(), AttributeOpts::n_distinct, palloc(), RelationGetDescr, ResetExprContext, VacAttrStats::rowstride, VacAttrStats::stadistinct, TTSOpsHeapTuple, and AnlExprData::vacattrstat.

Referenced by BuildRelationExtStatistics().

◆ ComputeExtStatisticsRows()

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

Definition at line 268 of file extended_stats.c.

270 {
271  Relation pg_stext;
272  ListCell *lc;
273  List *lstats;
274  MemoryContext cxt;
275  MemoryContext oldcxt;
276  int result = 0;
277 
278  /* If there are no columns to analyze, just return 0. */
279  if (!natts)
280  return 0;
281 
283  "ComputeExtStatisticsRows",
285  oldcxt = MemoryContextSwitchTo(cxt);
286 
287  pg_stext = table_open(StatisticExtRelationId, RowExclusiveLock);
288  lstats = fetch_statentries_for_relation(pg_stext, RelationGetRelid(onerel));
289 
290  foreach(lc, lstats)
291  {
293  int stattarget;
294  VacAttrStats **stats;
295  int nattrs = bms_num_members(stat->columns);
296 
297  /*
298  * Check if we can build this statistics object based on the columns
299  * analyzed. If not, ignore it (don't report anything, we'll do that
300  * during the actual build BuildRelationExtStatistics).
301  */
302  stats = lookup_var_attr_stats(onerel, stat->columns, stat->exprs,
303  natts, vacattrstats);
304 
305  if (!stats)
306  continue;
307 
308  /*
309  * Compute statistics target, based on what's set for the statistic
310  * object itself, and for its attributes.
311  */
312  stattarget = statext_compute_stattarget(stat->stattarget,
313  nattrs, stats);
314 
315  /* Use the largest value for all statistics objects. */
316  if (stattarget > result)
317  result = stattarget;
318  }
319 
320  table_close(pg_stext, RowExclusiveLock);
321 
322  MemoryContextSwitchTo(oldcxt);
323  MemoryContextDelete(cxt);
324 
325  /* compute sample size based on the statistics target */
326  return (300 * result);
327 }

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

Referenced by do_analyze_rel().

◆ examine_attribute()

static VacAttrStats* examine_attribute ( Node expr)
static

Definition at line 529 of file extended_stats.c.

530 {
531  HeapTuple typtuple;
532  VacAttrStats *stats;
533  int i;
534  bool ok;
535 
536  /*
537  * Create the VacAttrStats struct. Note that we only have a copy of the
538  * fixed fields of the pg_attribute tuple.
539  */
540  stats = (VacAttrStats *) palloc0(sizeof(VacAttrStats));
541 
542  /* fake the attribute */
544  stats->attr->attstattarget = -1;
545 
546  /*
547  * When analyzing an expression, believe the expression tree's type not
548  * the column datatype --- the latter might be the opckeytype storage type
549  * of the opclass, which is not interesting for our purposes. (Note: if
550  * we did anything with non-expression statistics columns, we'd need to
551  * figure out where to get the correct type info from, but for now that's
552  * not a problem.) It's not clear whether anyone will care about the
553  * typmod, but we store that too just in case.
554  */
555  stats->attrtypid = exprType(expr);
556  stats->attrtypmod = exprTypmod(expr);
557  stats->attrcollid = exprCollation(expr);
558 
559  typtuple = SearchSysCacheCopy1(TYPEOID,
560  ObjectIdGetDatum(stats->attrtypid));
561  if (!HeapTupleIsValid(typtuple))
562  elog(ERROR, "cache lookup failed for type %u", stats->attrtypid);
563  stats->attrtype = (Form_pg_type) GETSTRUCT(typtuple);
564 
565  /*
566  * We don't actually analyze individual attributes, so no need to set the
567  * memory context.
568  */
569  stats->anl_context = NULL;
570  stats->tupattnum = InvalidAttrNumber;
571 
572  /*
573  * The fields describing the stats->stavalues[n] element types default to
574  * the type of the data being analyzed, but the type-specific typanalyze
575  * function can change them if it wants to store something else.
576  */
577  for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
578  {
579  stats->statypid[i] = stats->attrtypid;
580  stats->statyplen[i] = stats->attrtype->typlen;
581  stats->statypbyval[i] = stats->attrtype->typbyval;
582  stats->statypalign[i] = stats->attrtype->typalign;
583  }
584 
585  /*
586  * Call the type-specific typanalyze function. If none is specified, use
587  * std_typanalyze().
588  */
589  if (OidIsValid(stats->attrtype->typanalyze))
590  ok = DatumGetBool(OidFunctionCall1(stats->attrtype->typanalyze,
591  PointerGetDatum(stats)));
592  else
593  ok = std_typanalyze(stats);
594 
595  if (!ok || stats->compute_stats == NULL || stats->minrows <= 0)
596  {
597  heap_freetuple(typtuple);
598  pfree(stats->attr);
599  pfree(stats);
600  return NULL;
601  }
602 
603  return stats;
604 }
#define InvalidAttrNumber
Definition: attnum.h:23
#define OidIsValid(objectId)
Definition: c.h:759
bool std_typanalyze(VacAttrStats *stats)
Definition: analyze.c:1858
#define OidFunctionCall1(functionId, arg1)
Definition: fmgr.h:680
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:278
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:780
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:201
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
#define STATISTIC_NUM_SLOTS
Definition: pg_statistic.h:127
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
int32 attrtypmod
Definition: vacuum.h:130
int tupattnum
Definition: vacuum.h:174
MemoryContext anl_context
Definition: vacuum.h:133
Oid statypid[STATISTIC_NUM_SLOTS]
Definition: vacuum.h:165
char statypalign[STATISTIC_NUM_SLOTS]
Definition: vacuum.h:168
Oid attrtypid
Definition: vacuum.h:129
int minrows
Definition: vacuum.h:140
bool statypbyval[STATISTIC_NUM_SLOTS]
Definition: vacuum.h:167
int16 statyplen[STATISTIC_NUM_SLOTS]
Definition: vacuum.h:166
Oid attrcollid
Definition: vacuum.h:132
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:182
@ TYPEOID
Definition: syscache.h:114

References VacAttrStats::anl_context, VacAttrStats::attr, VacAttrStats::attrcollid, ATTRIBUTE_FIXED_PART_SIZE, VacAttrStats::attrtype, VacAttrStats::attrtypid, VacAttrStats::attrtypmod, VacAttrStats::compute_stats, DatumGetBool(), elog(), ERROR, exprCollation(), exprType(), exprTypmod(), GETSTRUCT, heap_freetuple(), HeapTupleIsValid, i, InvalidAttrNumber, VacAttrStats::minrows, ObjectIdGetDatum(), OidFunctionCall1, OidIsValid, palloc0(), pfree(), PointerGetDatum(), SearchSysCacheCopy1, STATISTIC_NUM_SLOTS, VacAttrStats::statypalign, VacAttrStats::statypbyval, VacAttrStats::statypid, VacAttrStats::statyplen, std_typanalyze(), VacAttrStats::tupattnum, and TYPEOID.

Referenced by lookup_var_attr_stats().

◆ examine_expression()

static VacAttrStats* examine_expression ( Node expr,
int  stattarget 
)
static

Definition at line 613 of file extended_stats.c.

614 {
615  HeapTuple typtuple;
616  VacAttrStats *stats;
617  int i;
618  bool ok;
619 
620  Assert(expr != NULL);
621 
622  /*
623  * Create the VacAttrStats struct.
624  */
625  stats = (VacAttrStats *) palloc0(sizeof(VacAttrStats));
626 
627  /*
628  * When analyzing an expression, believe the expression tree's type.
629  */
630  stats->attrtypid = exprType(expr);
631  stats->attrtypmod = exprTypmod(expr);
632 
633  /*
634  * We don't allow collation to be specified in CREATE STATISTICS, so we
635  * have to use the collation specified for the expression. It's possible
636  * to specify the collation in the expression "(col COLLATE "en_US")" in
637  * which case exprCollation() does the right thing.
638  */
639  stats->attrcollid = exprCollation(expr);
640 
641  /*
642  * We don't have any pg_attribute for expressions, so let's fake something
643  * reasonable into attstattarget, which is the only thing std_typanalyze
644  * needs.
645  */
647 
648  /*
649  * We can't have statistics target specified for the expression, so we
650  * could use either the default_statistics_target, or the target computed
651  * for the extended statistics. The second option seems more reasonable.
652  */
653  stats->attr->attstattarget = stattarget;
654 
655  /* initialize some basic fields */
656  stats->attr->attrelid = InvalidOid;
657  stats->attr->attnum = InvalidAttrNumber;
658  stats->attr->atttypid = stats->attrtypid;
659 
660  typtuple = SearchSysCacheCopy1(TYPEOID,
661  ObjectIdGetDatum(stats->attrtypid));
662  if (!HeapTupleIsValid(typtuple))
663  elog(ERROR, "cache lookup failed for type %u", stats->attrtypid);
664 
665  stats->attrtype = (Form_pg_type) GETSTRUCT(typtuple);
666  stats->anl_context = CurrentMemoryContext; /* XXX should be using
667  * something else? */
668  stats->tupattnum = InvalidAttrNumber;
669 
670  /*
671  * The fields describing the stats->stavalues[n] element types default to
672  * the type of the data being analyzed, but the type-specific typanalyze
673  * function can change them if it wants to store something else.
674  */
675  for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
676  {
677  stats->statypid[i] = stats->attrtypid;
678  stats->statyplen[i] = stats->attrtype->typlen;
679  stats->statypbyval[i] = stats->attrtype->typbyval;
680  stats->statypalign[i] = stats->attrtype->typalign;
681  }
682 
683  /*
684  * Call the type-specific typanalyze function. If none is specified, use
685  * std_typanalyze().
686  */
687  if (OidIsValid(stats->attrtype->typanalyze))
688  ok = DatumGetBool(OidFunctionCall1(stats->attrtype->typanalyze,
689  PointerGetDatum(stats)));
690  else
691  ok = std_typanalyze(stats);
692 
693  if (!ok || stats->compute_stats == NULL || stats->minrows <= 0)
694  {
695  heap_freetuple(typtuple);
696  pfree(stats);
697  return NULL;
698  }
699 
700  return stats;
701 }
#define InvalidOid
Definition: postgres_ext.h:36

References VacAttrStats::anl_context, Assert(), VacAttrStats::attr, VacAttrStats::attrcollid, ATTRIBUTE_FIXED_PART_SIZE, VacAttrStats::attrtype, VacAttrStats::attrtypid, VacAttrStats::attrtypmod, VacAttrStats::compute_stats, CurrentMemoryContext, DatumGetBool(), elog(), ERROR, exprCollation(), exprType(), exprTypmod(), GETSTRUCT, heap_freetuple(), HeapTupleIsValid, i, InvalidAttrNumber, InvalidOid, VacAttrStats::minrows, ObjectIdGetDatum(), OidFunctionCall1, OidIsValid, palloc(), palloc0(), pfree(), PointerGetDatum(), SearchSysCacheCopy1, STATISTIC_NUM_SLOTS, VacAttrStats::statypalign, VacAttrStats::statypbyval, VacAttrStats::statypid, VacAttrStats::statyplen, std_typanalyze(), VacAttrStats::tupattnum, and TYPEOID.

Referenced by build_expr_data(), and make_build_data().

◆ examine_opclause_args()

bool examine_opclause_args ( List args,
Node **  exprp,
Const **  cstp,
bool expronleftp 
)

Definition at line 2079 of file extended_stats.c.

2081 {
2082  Node *expr;
2083  Const *cst;
2084  bool expronleft;
2085  Node *leftop,
2086  *rightop;
2087 
2088  /* enforced by statext_is_compatible_clause_internal */
2089  Assert(list_length(args) == 2);
2090 
2091  leftop = linitial(args);
2092  rightop = lsecond(args);
2093 
2094  /* strip RelabelType from either side of the expression */
2095  if (IsA(leftop, RelabelType))
2096  leftop = (Node *) ((RelabelType *) leftop)->arg;
2097 
2098  if (IsA(rightop, RelabelType))
2099  rightop = (Node *) ((RelabelType *) rightop)->arg;
2100 
2101  if (IsA(rightop, Const))
2102  {
2103  expr = (Node *) leftop;
2104  cst = (Const *) rightop;
2105  expronleft = true;
2106  }
2107  else if (IsA(leftop, Const))
2108  {
2109  expr = (Node *) rightop;
2110  cst = (Const *) leftop;
2111  expronleft = false;
2112  }
2113  else
2114  return false;
2115 
2116  /* return pointers to the extracted parts if requested */
2117  if (exprp)
2118  *exprp = expr;
2119 
2120  if (cstp)
2121  *cstp = cst;
2122 
2123  if (expronleftp)
2124  *expronleftp = expronleft;
2125 
2126  return true;
2127 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
#define linitial(l)
Definition: pg_list.h:178
#define lsecond(l)
Definition: pg_list.h:183

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

Referenced by mcv_get_match_bitmap(), and statext_is_compatible_clause_internal().

◆ expr_fetch_func()

static Datum expr_fetch_func ( VacAttrStatsP  stats,
int  rownum,
bool isNull 
)
static

Definition at line 2279 of file extended_stats.c.

2280 {
2281  int i;
2282 
2283  /* exprvals and exprnulls are already offset for proper column */
2284  i = rownum * stats->rowstride;
2285  *isNull = stats->exprnulls[i];
2286  return stats->exprvals[i];
2287 }

References VacAttrStats::exprnulls, VacAttrStats::exprvals, i, and VacAttrStats::rowstride.

Referenced by compute_expr_stats().

◆ fetch_statentries_for_relation()

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

Definition at line 425 of file extended_stats.c.

426 {
427  SysScanDesc scan;
428  ScanKeyData skey;
429  HeapTuple htup;
430  List *result = NIL;
431 
432  /*
433  * Prepare to scan pg_statistic_ext for entries having stxrelid = this
434  * rel.
435  */
436  ScanKeyInit(&skey,
437  Anum_pg_statistic_ext_stxrelid,
438  BTEqualStrategyNumber, F_OIDEQ,
439  ObjectIdGetDatum(relid));
440 
441  scan = systable_beginscan(pg_statext, StatisticExtRelidIndexId, true,
442  NULL, 1, &skey);
443 
444  while (HeapTupleIsValid(htup = systable_getnext(scan)))
445  {
446  StatExtEntry *entry;
447  Datum datum;
448  bool isnull;
449  int i;
450  ArrayType *arr;
451  char *enabled;
452  Form_pg_statistic_ext staForm;
453  List *exprs = NIL;
454 
455  entry = palloc0(sizeof(StatExtEntry));
456  staForm = (Form_pg_statistic_ext) GETSTRUCT(htup);
457  entry->statOid = staForm->oid;
458  entry->schema = get_namespace_name(staForm->stxnamespace);
459  entry->name = pstrdup(NameStr(staForm->stxname));
460  entry->stattarget = staForm->stxstattarget;
461  for (i = 0; i < staForm->stxkeys.dim1; i++)
462  {
463  entry->columns = bms_add_member(entry->columns,
464  staForm->stxkeys.values[i]);
465  }
466 
467  /* decode the stxkind char array into a list of chars */
468  datum = SysCacheGetAttrNotNull(STATEXTOID, htup,
469  Anum_pg_statistic_ext_stxkind);
470  arr = DatumGetArrayTypeP(datum);
471  if (ARR_NDIM(arr) != 1 ||
472  ARR_HASNULL(arr) ||
473  ARR_ELEMTYPE(arr) != CHAROID)
474  elog(ERROR, "stxkind is not a 1-D char array");
475  enabled = (char *) ARR_DATA_PTR(arr);
476  for (i = 0; i < ARR_DIMS(arr)[0]; i++)
477  {
478  Assert((enabled[i] == STATS_EXT_NDISTINCT) ||
479  (enabled[i] == STATS_EXT_DEPENDENCIES) ||
480  (enabled[i] == STATS_EXT_MCV) ||
481  (enabled[i] == STATS_EXT_EXPRESSIONS));
482  entry->types = lappend_int(entry->types, (int) enabled[i]);
483  }
484 
485  /* decode expression (if any) */
486  datum = SysCacheGetAttr(STATEXTOID, htup,
487  Anum_pg_statistic_ext_stxexprs, &isnull);
488 
489  if (!isnull)
490  {
491  char *exprsString;
492 
493  exprsString = TextDatumGetCString(datum);
494  exprs = (List *) stringToNode(exprsString);
495 
496  pfree(exprsString);
497 
498  /*
499  * Run the expressions through eval_const_expressions. This is not
500  * just an optimization, but is necessary, because the planner
501  * will be comparing them to similarly-processed qual clauses, and
502  * may fail to detect valid matches without this. We must not use
503  * canonicalize_qual, however, since these aren't qual
504  * expressions.
505  */
506  exprs = (List *) eval_const_expressions(NULL, (Node *) exprs);
507 
508  /* May as well fix opfuncids too */
509  fix_opfuncids((Node *) exprs);
510  }
511 
512  entry->exprs = exprs;
513 
514  result = lappend(result, entry);
515  }
516 
517  systable_endscan(scan);
518 
519  return result;
520 }
#define ARR_NDIM(a)
Definition: array.h:283
#define ARR_DATA_PTR(a)
Definition: array.h:315
#define DatumGetArrayTypeP(X)
Definition: array.h:254
#define ARR_ELEMTYPE(a)
Definition: array.h:285
#define ARR_DIMS(a)
Definition: array.h:287
#define ARR_HASNULL(a)
Definition: array.h:284
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:755
#define TextDatumGetCString(d)
Definition: builtins.h:95
#define NameStr(name)
Definition: c.h:730
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2163
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:599
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:506
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
List * lappend(List *list, void *datum)
Definition: list.c:338
List * lappend_int(List *list, int datum)
Definition: list.c:356
char * pstrdup(const char *in)
Definition: mcxt.c:1624
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1691
FormData_pg_statistic_ext * Form_pg_statistic_ext
void * stringToNode(const char *str)
Definition: read.c:90
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Bitmapset * columns
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1079
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:1110
@ STATEXTOID
Definition: syscache.h:96

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

Referenced by BuildRelationExtStatistics(), and ComputeExtStatisticsRows().

◆ has_stats_of_kind()

bool has_stats_of_kind ( List stats,
char  requiredkind 
)

Definition at line 1142 of file extended_stats.c.

1143 {
1144  ListCell *l;
1145 
1146  foreach(l, stats)
1147  {
1149 
1150  if (stat->kind == requiredkind)
1151  return true;
1152  }
1153 
1154  return false;
1155 }

References lfirst.

Referenced by dependencies_clauselist_selectivity(), and statext_mcv_clauselist_selectivity().

◆ lookup_var_attr_stats()

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

Definition at line 711 of file extended_stats.c.

713 {
714  int i = 0;
715  int x = -1;
716  int natts;
717  VacAttrStats **stats;
718  ListCell *lc;
719 
720  natts = bms_num_members(attrs) + list_length(exprs);
721 
722  stats = (VacAttrStats **) palloc(natts * sizeof(VacAttrStats *));
723 
724  /* lookup VacAttrStats info for the requested columns (same attnum) */
725  while ((x = bms_next_member(attrs, x)) >= 0)
726  {
727  int j;
728 
729  stats[i] = NULL;
730  for (j = 0; j < nvacatts; j++)
731  {
732  if (x == vacatts[j]->tupattnum)
733  {
734  stats[i] = vacatts[j];
735  break;
736  }
737  }
738 
739  if (!stats[i])
740  {
741  /*
742  * Looks like stats were not gathered for one of the columns
743  * required. We'll be unable to build the extended stats without
744  * this column.
745  */
746  pfree(stats);
747  return NULL;
748  }
749 
750  /*
751  * Sanity check that the column is not dropped - stats should have
752  * been removed in this case.
753  */
754  Assert(!stats[i]->attr->attisdropped);
755 
756  i++;
757  }
758 
759  /* also add info for expressions */
760  foreach(lc, exprs)
761  {
762  Node *expr = (Node *) lfirst(lc);
763 
764  stats[i] = examine_attribute(expr);
765 
766  /*
767  * XXX We need tuple descriptor later, and we just grab it from
768  * stats[0]->tupDesc (see e.g. statext_mcv_build). But as coded
769  * examine_attribute does not set that, so just grab it from the first
770  * vacatts element.
771  */
772  stats[i]->tupDesc = vacatts[0]->tupDesc;
773 
774  i++;
775  }
776 
777  return stats;
778 }
static VacAttrStats * examine_attribute(Node *expr)
int x
Definition: isn.c:71
TupleDesc tupDesc
Definition: vacuum.h:176

References Assert(), bms_next_member(), bms_num_members(), examine_attribute(), i, j, lfirst, list_length(), palloc(), pfree(), VacAttrStats::tupDesc, and x.

Referenced by BuildRelationExtStatistics(), and ComputeExtStatisticsRows().

◆ make_build_data()

static StatsBuildData * make_build_data ( Relation  rel,
StatExtEntry stat,
int  numrows,
HeapTuple rows,
VacAttrStats **  stats,
int  stattarget 
)
static

Definition at line 2497 of file extended_stats.c.

2499 {
2500  /* evaluated expressions */
2501  StatsBuildData *result;
2502  char *ptr;
2503  Size len;
2504 
2505  int i;
2506  int k;
2507  int idx;
2508  TupleTableSlot *slot;
2509  EState *estate;
2510  ExprContext *econtext;
2511  List *exprstates = NIL;
2512  int nkeys = bms_num_members(stat->columns) + list_length(stat->exprs);
2513  ListCell *lc;
2514 
2515  /* allocate everything as a single chunk, so we can free it easily */
2516  len = MAXALIGN(sizeof(StatsBuildData));
2517  len += MAXALIGN(sizeof(AttrNumber) * nkeys); /* attnums */
2518  len += MAXALIGN(sizeof(VacAttrStats *) * nkeys); /* stats */
2519 
2520  /* values */
2521  len += MAXALIGN(sizeof(Datum *) * nkeys);
2522  len += nkeys * MAXALIGN(sizeof(Datum) * numrows);
2523 
2524  /* nulls */
2525  len += MAXALIGN(sizeof(bool *) * nkeys);
2526  len += nkeys * MAXALIGN(sizeof(bool) * numrows);
2527 
2528  ptr = palloc(len);
2529 
2530  /* set the pointers */
2531  result = (StatsBuildData *) ptr;
2532  ptr += MAXALIGN(sizeof(StatsBuildData));
2533 
2534  /* attnums */
2535  result->attnums = (AttrNumber *) ptr;
2536  ptr += MAXALIGN(sizeof(AttrNumber) * nkeys);
2537 
2538  /* stats */
2539  result->stats = (VacAttrStats **) ptr;
2540  ptr += MAXALIGN(sizeof(VacAttrStats *) * nkeys);
2541 
2542  /* values */
2543  result->values = (Datum **) ptr;
2544  ptr += MAXALIGN(sizeof(Datum *) * nkeys);
2545 
2546  /* nulls */
2547  result->nulls = (bool **) ptr;
2548  ptr += MAXALIGN(sizeof(bool *) * nkeys);
2549 
2550  for (i = 0; i < nkeys; i++)
2551  {
2552  result->values[i] = (Datum *) ptr;
2553  ptr += MAXALIGN(sizeof(Datum) * numrows);
2554 
2555  result->nulls[i] = (bool *) ptr;
2556  ptr += MAXALIGN(sizeof(bool) * numrows);
2557  }
2558 
2559  Assert((ptr - (char *) result) == len);
2560 
2561  /* we have it allocated, so let's fill the values */
2562  result->nattnums = nkeys;
2563  result->numrows = numrows;
2564 
2565  /* fill the attribute info - first attributes, then expressions */
2566  idx = 0;
2567  k = -1;
2568  while ((k = bms_next_member(stat->columns, k)) >= 0)
2569  {
2570  result->attnums[idx] = k;
2571  result->stats[idx] = stats[idx];
2572 
2573  idx++;
2574  }
2575 
2576  k = -1;
2577  foreach(lc, stat->exprs)
2578  {
2579  Node *expr = (Node *) lfirst(lc);
2580 
2581  result->attnums[idx] = k;
2582  result->stats[idx] = examine_expression(expr, stattarget);
2583 
2584  idx++;
2585  k--;
2586  }
2587 
2588  /* first extract values for all the regular attributes */
2589  for (i = 0; i < numrows; i++)
2590  {
2591  idx = 0;
2592  k = -1;
2593  while ((k = bms_next_member(stat->columns, k)) >= 0)
2594  {
2595  result->values[idx][i] = heap_getattr(rows[i], k,
2596  result->stats[idx]->tupDesc,
2597  &result->nulls[idx][i]);
2598 
2599  idx++;
2600  }
2601  }
2602 
2603  /* Need an EState for evaluation expressions. */
2604  estate = CreateExecutorState();
2605  econtext = GetPerTupleExprContext(estate);
2606 
2607  /* Need a slot to hold the current heap tuple, too */
2609  &TTSOpsHeapTuple);
2610 
2611  /* Arrange for econtext's scan tuple to be the tuple under test */
2612  econtext->ecxt_scantuple = slot;
2613 
2614  /* Set up expression evaluation state */
2615  exprstates = ExecPrepareExprList(stat->exprs, estate);
2616 
2617  for (i = 0; i < numrows; i++)
2618  {
2619  /*
2620  * Reset the per-tuple context each time, to reclaim any cruft left
2621  * behind by evaluating the statistics object expressions.
2622  */
2623  ResetExprContext(econtext);
2624 
2625  /* Set up for expression evaluation */
2626  ExecStoreHeapTuple(rows[i], slot, false);
2627 
2628  idx = bms_num_members(stat->columns);
2629  foreach(lc, exprstates)
2630  {
2631  Datum datum;
2632  bool isnull;
2633  ExprState *exprstate = (ExprState *) lfirst(lc);
2634 
2635  /*
2636  * XXX This probably leaks memory. Maybe we should use
2637  * ExecEvalExprSwitchContext but then we need to copy the result
2638  * somewhere else.
2639  */
2640  datum = ExecEvalExpr(exprstate,
2641  GetPerTupleExprContext(estate),
2642  &isnull);
2643  if (isnull)
2644  {
2645  result->values[idx][i] = (Datum) 0;
2646  result->nulls[idx][i] = true;
2647  }
2648  else
2649  {
2650  result->values[idx][i] = (Datum) datum;
2651  result->nulls[idx][i] = false;
2652  }
2653 
2654  idx++;
2655  }
2656  }
2657 
2659  FreeExecutorState(estate);
2660 
2661  return result;
2662 }
#define MAXALIGN(LEN)
Definition: c.h:795
size_t Size
Definition: c.h:589
List * ExecPrepareExprList(List *nodes, EState *estate)
Definition: execExpr.c:809
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:331
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:792
VacAttrStats ** stats

References Assert(), StatsBuildData::attnums, bms_next_member(), bms_num_members(), CreateExecutorState(), ExprContext::ecxt_scantuple, examine_expression(), ExecDropSingleTupleTableSlot(), ExecEvalExpr(), ExecPrepareExprList(), ExecStoreHeapTuple(), FreeExecutorState(), GetPerTupleExprContext, heap_getattr(), i, idx(), len, lfirst, list_length(), MakeSingleTupleTableSlot(), MAXALIGN, StatsBuildData::nattnums, NIL, StatsBuildData::nulls, StatsBuildData::numrows, palloc(), RelationGetDescr, ResetExprContext, StatsBuildData::stats, TTSOpsHeapTuple, VacAttrStats::tupDesc, and StatsBuildData::values.

Referenced by BuildRelationExtStatistics().

◆ multi_sort_add_dimension()

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

Definition at line 875 of file extended_stats.c.

877 {
878  SortSupport ssup = &mss->ssup[sortdim];
879 
881  ssup->ssup_collation = collation;
882  ssup->ssup_nulls_first = false;
883 
885 }
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
Definition: parse_oper.c:382
void PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
Definition: sortsupport.c:135
SortSupportData ssup[FLEXIBLE_ARRAY_MEMBER]
bool ssup_nulls_first
Definition: sortsupport.h:75
MemoryContext ssup_cxt
Definition: sortsupport.h:66

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

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

◆ multi_sort_compare()

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

Definition at line 889 of file extended_stats.c.

890 {
892  SortItem *ia = (SortItem *) a;
893  SortItem *ib = (SortItem *) b;
894  int i;
895 
896  for (i = 0; i < mss->ndims; i++)
897  {
898  int compare;
899 
901  ib->values[i], ib->isnull[i],
902  &mss->ssup[i]);
903 
904  if (compare != 0)
905  return compare;
906  }
907 
908  /* equal by default */
909  return 0;
910 }
MultiSortSupportData * MultiSortSupport
static int compare(const void *arg1, const void *arg2)
Definition: geqo_pool.c:145

References a, ApplySortComparator(), arg, b, 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().

◆ multi_sort_compare_dim()

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

Definition at line 914 of file extended_stats.c.

916 {
917  return ApplySortComparator(a->values[dim], a->isnull[dim],
918  b->values[dim], b->isnull[dim],
919  &mss->ssup[dim]);
920 }

References a, ApplySortComparator(), b, and MultiSortSupportData::ssup.

Referenced by dependency_degree().

◆ multi_sort_compare_dims()

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

Definition at line 923 of file extended_stats.c.

926 {
927  int dim;
928 
929  for (dim = start; dim <= end; dim++)
930  {
931  int r = ApplySortComparator(a->values[dim], a->isnull[dim],
932  b->values[dim], b->isnull[dim],
933  &mss->ssup[dim]);
934 
935  if (r != 0)
936  return r;
937  }
938 
939  return 0;
940 }

References a, ApplySortComparator(), b, and MultiSortSupportData::ssup.

Referenced by dependency_degree().

◆ multi_sort_init()

MultiSortSupport multi_sort_init ( int  ndims)

Definition at line 856 of file extended_stats.c.

857 {
858  MultiSortSupport mss;
859 
860  Assert(ndims >= 2);
861 
862  mss = (MultiSortSupport) palloc0(offsetof(MultiSortSupportData, ssup)
863  + sizeof(SortSupportData) * ndims);
864 
865  mss->ndims = ndims;
866 
867  return mss;
868 }
struct SortSupportData SortSupportData

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

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

◆ serialize_expr_stats()

static Datum serialize_expr_stats ( AnlExprData exprdata,
int  nexprs 
)
static

Definition at line 2320 of file extended_stats.c.

2321 {
2322  int exprno;
2323  Oid typOid;
2324  Relation sd;
2325 
2326  ArrayBuildState *astate = NULL;
2327 
2328  sd = table_open(StatisticRelationId, RowExclusiveLock);
2329 
2330  /* lookup OID of composite type for pg_statistic */
2331  typOid = get_rel_type_id(StatisticRelationId);
2332  if (!OidIsValid(typOid))
2333  ereport(ERROR,
2334  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2335  errmsg("relation \"%s\" does not have a composite type",
2336  "pg_statistic")));
2337 
2338  for (exprno = 0; exprno < nexprs; exprno++)
2339  {
2340  int i,
2341  k;
2342  VacAttrStats *stats = exprdata[exprno].vacattrstat;
2343 
2344  Datum values[Natts_pg_statistic];
2345  bool nulls[Natts_pg_statistic];
2346  HeapTuple stup;
2347 
2348  if (!stats->stats_valid)
2349  {
2350  astate = accumArrayResult(astate,
2351  (Datum) 0,
2352  true,
2353  typOid,
2355  continue;
2356  }
2357 
2358  /*
2359  * Construct a new pg_statistic tuple
2360  */
2361  for (i = 0; i < Natts_pg_statistic; ++i)
2362  {
2363  nulls[i] = false;
2364  }
2365 
2366  values[Anum_pg_statistic_starelid - 1] = ObjectIdGetDatum(InvalidOid);
2367  values[Anum_pg_statistic_staattnum - 1] = Int16GetDatum(InvalidAttrNumber);
2368  values[Anum_pg_statistic_stainherit - 1] = BoolGetDatum(false);
2369  values[Anum_pg_statistic_stanullfrac - 1] = Float4GetDatum(stats->stanullfrac);
2370  values[Anum_pg_statistic_stawidth - 1] = Int32GetDatum(stats->stawidth);
2371  values[Anum_pg_statistic_stadistinct - 1] = Float4GetDatum(stats->stadistinct);
2372  i = Anum_pg_statistic_stakind1 - 1;
2373  for (k = 0; k < STATISTIC_NUM_SLOTS; k++)
2374  {
2375  values[i++] = Int16GetDatum(stats->stakind[k]); /* stakindN */
2376  }
2377  i = Anum_pg_statistic_staop1 - 1;
2378  for (k = 0; k < STATISTIC_NUM_SLOTS; k++)
2379  {
2380  values[i++] = ObjectIdGetDatum(stats->staop[k]); /* staopN */
2381  }
2382  i = Anum_pg_statistic_stacoll1 - 1;
2383  for (k = 0; k < STATISTIC_NUM_SLOTS; k++)
2384  {
2385  values[i++] = ObjectIdGetDatum(stats->stacoll[k]); /* stacollN */
2386  }
2387  i = Anum_pg_statistic_stanumbers1 - 1;
2388  for (k = 0; k < STATISTIC_NUM_SLOTS; k++)
2389  {
2390  int nnum = stats->numnumbers[k];
2391 
2392  if (nnum > 0)
2393  {
2394  int n;
2395  Datum *numdatums = (Datum *) palloc(nnum * sizeof(Datum));
2396  ArrayType *arry;
2397 
2398  for (n = 0; n < nnum; n++)
2399  numdatums[n] = Float4GetDatum(stats->stanumbers[k][n]);
2400  arry = construct_array_builtin(numdatums, nnum, FLOAT4OID);
2401  values[i++] = PointerGetDatum(arry); /* stanumbersN */
2402  }
2403  else
2404  {
2405  nulls[i] = true;
2406  values[i++] = (Datum) 0;
2407  }
2408  }
2409  i = Anum_pg_statistic_stavalues1 - 1;
2410  for (k = 0; k < STATISTIC_NUM_SLOTS; k++)
2411  {
2412  if (stats->numvalues[k] > 0)
2413  {
2414  ArrayType *arry;
2415 
2416  arry = construct_array(stats->stavalues[k],
2417  stats->numvalues[k],
2418  stats->statypid[k],
2419  stats->statyplen[k],
2420  stats->statypbyval[k],
2421  stats->statypalign[k]);
2422  values[i++] = PointerGetDatum(arry); /* stavaluesN */
2423  }
2424  else
2425  {
2426  nulls[i] = true;
2427  values[i++] = (Datum) 0;
2428  }
2429  }
2430 
2431  stup = heap_form_tuple(RelationGetDescr(sd), values, nulls);
2432 
2433  astate = accumArrayResult(astate,
2435  false,
2436  typOid,
2438  }
2439 
2441 
2442  return makeArrayResult(astate, CurrentMemoryContext);
2443 }
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5319
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
Definition: arrayfuncs.c:3361
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3341
Datum makeArrayResult(ArrayBuildState *astate, MemoryContext rcontext)
Definition: arrayfuncs.c:5383
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
Definition: heaptuple.c:984
Oid get_rel_type_id(Oid relid)
Definition: lsyscache.c:1961
static Datum Float4GetDatum(float4 X)
Definition: postgres.h:475
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:172
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
unsigned int Oid
Definition: postgres_ext.h:31
bool stats_valid
Definition: vacuum.h:147
float4 stanullfrac
Definition: vacuum.h:148
int16 stakind[STATISTIC_NUM_SLOTS]
Definition: vacuum.h:151
Oid staop[STATISTIC_NUM_SLOTS]
Definition: vacuum.h:152
Oid stacoll[STATISTIC_NUM_SLOTS]
Definition: vacuum.h:153
float4 * stanumbers[STATISTIC_NUM_SLOTS]
Definition: vacuum.h:155
int32 stawidth
Definition: vacuum.h:149
int numvalues[STATISTIC_NUM_SLOTS]
Definition: vacuum.h:156
Datum * stavalues[STATISTIC_NUM_SLOTS]
Definition: vacuum.h:157
int numnumbers[STATISTIC_NUM_SLOTS]
Definition: vacuum.h:154

References accumArrayResult(), BoolGetDatum(), construct_array(), construct_array_builtin(), CurrentMemoryContext, ereport, errcode(), errmsg(), ERROR, Float4GetDatum(), get_rel_type_id(), heap_copy_tuple_as_datum(), heap_form_tuple(), i, Int16GetDatum(), Int32GetDatum(), InvalidAttrNumber, InvalidOid, makeArrayResult(), VacAttrStats::numnumbers, VacAttrStats::numvalues, ObjectIdGetDatum(), OidIsValid, palloc(), PointerGetDatum(), RelationGetDescr, RowExclusiveLock, VacAttrStats::stacoll, VacAttrStats::stadistinct, VacAttrStats::stakind, VacAttrStats::stanullfrac, VacAttrStats::stanumbers, VacAttrStats::staop, STATISTIC_NUM_SLOTS, VacAttrStats::stats_valid, VacAttrStats::statypalign, VacAttrStats::statypbyval, VacAttrStats::statypid, VacAttrStats::statyplen, VacAttrStats::stavalues, VacAttrStats::stawidth, table_close(), table_open(), AnlExprData::vacattrstat, and values.

Referenced by BuildRelationExtStatistics().

◆ stat_covers_expressions()

static bool stat_covers_expressions ( StatisticExtInfo stat,
List exprs,
Bitmapset **  expr_idxs 
)
static

Definition at line 1192 of file extended_stats.c.

1194 {
1195  ListCell *lc;
1196 
1197  foreach(lc, exprs)
1198  {
1199  Node *expr = (Node *) lfirst(lc);
1200  int expr_idx;
1201 
1202  expr_idx = stat_find_expression(stat, expr);
1203  if (expr_idx == -1)
1204  return false;
1205 
1206  if (expr_idxs != NULL)
1207  *expr_idxs = bms_add_member(*expr_idxs, expr_idx);
1208  }
1209 
1210  /* If we reach here, all expressions are covered */
1211  return true;
1212 }
static int stat_find_expression(StatisticExtInfo *stat, Node *expr)

References bms_add_member(), lfirst, and stat_find_expression().

Referenced by choose_best_statistics(), and statext_mcv_clauselist_selectivity().

◆ stat_find_expression()

static int stat_find_expression ( StatisticExtInfo stat,
Node expr 
)
static

Definition at line 1165 of file extended_stats.c.

1166 {
1167  ListCell *lc;
1168  int idx;
1169 
1170  idx = 0;
1171  foreach(lc, stat->exprs)
1172  {
1173  Node *stat_expr = (Node *) lfirst(lc);
1174 
1175  if (equal(stat_expr, expr))
1176  return idx;
1177  idx++;
1178  }
1179 
1180  /* Expression not found */
1181  return -1;
1182 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223

References equal(), idx(), and lfirst.

Referenced by stat_covers_expressions().

◆ statext_clauselist_selectivity()

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

Definition at line 2028 of file extended_stats.c.

2032 {
2033  Selectivity sel;
2034 
2035  /* First, try estimating clauses using a multivariate MCV list. */
2036  sel = statext_mcv_clauselist_selectivity(root, clauses, varRelid, jointype,
2037  sjinfo, rel, estimatedclauses, is_or);
2038 
2039  /*
2040  * Functional dependencies only work for clauses connected by AND, so for
2041  * OR clauses we're done.
2042  */
2043  if (is_or)
2044  return sel;
2045 
2046  /*
2047  * Then, apply functional dependencies on the remaining clauses by calling
2048  * dependencies_clauselist_selectivity. Pass 'estimatedclauses' so the
2049  * function can properly skip clauses already estimated above.
2050  *
2051  * The reasoning for applying dependencies last is that the more complex
2052  * stats can track more complex correlations between the attributes, and
2053  * so may be considered more reliable.
2054  *
2055  * For example, MCV list can give us an exact selectivity for values in
2056  * two columns, while functional dependencies can only provide information
2057  * about the overall strength of the dependency.
2058  */
2059  sel *= dependencies_clauselist_selectivity(root, clauses, varRelid,
2060  jointype, sjinfo, rel,
2061  estimatedclauses);
2062 
2063  return sel;
2064 }
Selectivity dependencies_clauselist_selectivity(PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, RelOptInfo *rel, Bitmapset **estimatedclauses)
static Selectivity statext_mcv_clauselist_selectivity(PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, RelOptInfo *rel, Bitmapset **estimatedclauses, bool is_or)
double Selectivity
Definition: nodes.h:261

References dependencies_clauselist_selectivity(), and statext_mcv_clauselist_selectivity().

Referenced by clauselist_selectivity_ext(), and clauselist_selectivity_or().

◆ statext_compute_stattarget()

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

Definition at line 350 of file extended_stats.c.

351 {
352  int i;
353 
354  /*
355  * If there's statistics target set for the statistics object, use it. It
356  * may be set to 0 which disables building of that statistic.
357  */
358  if (stattarget >= 0)
359  return stattarget;
360 
361  /*
362  * The target for the statistics object is set to -1, in which case we
363  * look at the maximum target set for any of the attributes the object is
364  * defined on.
365  */
366  for (i = 0; i < nattrs; i++)
367  {
368  /* keep the maximum statistics target */
369  if (stats[i]->attr->attstattarget > stattarget)
370  stattarget = stats[i]->attr->attstattarget;
371  }
372 
373  /*
374  * If the value is still negative (so neither the statistics object nor
375  * any of the columns have custom statistics target set), use the global
376  * default target.
377  */
378  if (stattarget < 0)
379  stattarget = default_statistics_target;
380 
381  /* As this point we should have a valid statistics target. */
382  Assert((stattarget >= 0) && (stattarget <= 10000));
383 
384  return stattarget;
385 }
int default_statistics_target
Definition: analyze.c:83

References Assert(), VacAttrStats::attr, default_statistics_target, and i.

Referenced by BuildRelationExtStatistics(), and ComputeExtStatisticsRows().

◆ statext_expressions_load()

HeapTuple statext_expressions_load ( Oid  stxoid,
bool  inh,
int  idx 
)

Definition at line 2450 of file extended_stats.c.

2451 {
2452  bool isnull;
2453  Datum value;
2454  HeapTuple htup;
2455  ExpandedArrayHeader *eah;
2456  HeapTupleHeader td;
2457  HeapTupleData tmptup;
2458  HeapTuple tup;
2459 
2461  ObjectIdGetDatum(stxoid), BoolGetDatum(inh));
2462  if (!HeapTupleIsValid(htup))
2463  elog(ERROR, "cache lookup failed for statistics object %u", stxoid);
2464 
2466  Anum_pg_statistic_ext_data_stxdexpr, &isnull);
2467  if (isnull)
2468  elog(ERROR,
2469  "requested statistics kind \"%c\" is not yet built for statistics object %u",
2470  STATS_EXT_DEPENDENCIES, stxoid);
2471 
2473 
2475 
2476  td = DatumGetHeapTupleHeader(eah->dvalues[idx]);
2477 
2478  /* Build a temporary HeapTuple control structure */
2479  tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
2480  ItemPointerSetInvalid(&(tmptup.t_self));
2481  tmptup.t_tableOid = InvalidOid;
2482  tmptup.t_data = td;
2483 
2484  tup = heap_copytuple(&tmptup);
2485 
2486  ReleaseSysCache(htup);
2487 
2488  return tup;
2489 }
ExpandedArrayHeader * DatumGetExpandedArray(Datum d)
void deconstruct_expanded_array(ExpandedArrayHeader *eah)
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:295
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:450
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition: itemptr.h:184
Datum * dvalues
Definition: array.h:139
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
HeapTupleHeader t_data
Definition: htup.h:68
Oid t_tableOid
Definition: htup.h:66
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:866
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:829
@ STATEXTDATASTXOID
Definition: syscache.h:94

References BoolGetDatum(), DatumGetExpandedArray(), DatumGetHeapTupleHeader, deconstruct_expanded_array(), ExpandedArrayHeader::dvalues, elog(), ERROR, heap_copytuple(), HeapTupleHeaderGetDatumLength, HeapTupleIsValid, idx(), InvalidOid, ItemPointerSetInvalid(), ObjectIdGetDatum(), ReleaseSysCache(), SearchSysCache2(), STATEXTDATASTXOID, SysCacheGetAttr(), HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, and value.

Referenced by examine_variable().

◆ statext_is_compatible_clause()

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

Definition at line 1596 of file extended_stats.c.

1598 {
1599  RangeTblEntry *rte = root->simple_rte_array[relid];
1600  RelOptInfo *rel = root->simple_rel_array[relid];
1601  RestrictInfo *rinfo;
1602  int clause_relid;
1603  Oid userid;
1604 
1605  /*
1606  * Special-case handling for bare BoolExpr AND clauses, because the
1607  * restrictinfo machinery doesn't build RestrictInfos on top of AND
1608  * clauses.
1609  */
1610  if (is_andclause(clause))
1611  {
1612  BoolExpr *expr = (BoolExpr *) clause;
1613  ListCell *lc;
1614 
1615  /*
1616  * Check that each sub-clause is compatible. We expect these to be
1617  * RestrictInfos.
1618  */
1619  foreach(lc, expr->args)
1620  {
1621  if (!statext_is_compatible_clause(root, (Node *) lfirst(lc),
1622  relid, attnums, exprs))
1623  return false;
1624  }
1625 
1626  return true;
1627  }
1628 
1629  /* Otherwise it must be a RestrictInfo. */
1630  if (!IsA(clause, RestrictInfo))
1631  return false;
1632  rinfo = (RestrictInfo *) clause;
1633 
1634  /* Pseudoconstants are not really interesting here. */
1635  if (rinfo->pseudoconstant)
1636  return false;
1637 
1638  /* Clauses referencing other varnos are incompatible. */
1639  if (!bms_get_singleton_member(rinfo->clause_relids, &clause_relid) ||
1640  clause_relid != relid)
1641  return false;
1642 
1643  /* Check the clause and determine what attributes it references. */
1644  if (!statext_is_compatible_clause_internal(root, (Node *) rinfo->clause,
1645  relid, attnums, exprs))
1646  return false;
1647 
1648  /*
1649  * Check that the user has permission to read all required attributes.
1650  */
1651  userid = OidIsValid(rel->userid) ? rel->userid : GetUserId();
1652 
1653  /* Table-level SELECT privilege is sufficient for all columns */
1654  if (pg_class_aclcheck(rte->relid, userid, ACL_SELECT) != ACLCHECK_OK)
1655  {
1656  Bitmapset *clause_attnums = NULL;
1657  int attnum = -1;
1658 
1659  /*
1660  * We have to check per-column privileges. *attnums has the attnums
1661  * for individual Vars we saw, but there may also be Vars within
1662  * subexpressions in *exprs. We can use pull_varattnos() to extract
1663  * those, but there's an impedance mismatch: attnums returned by
1664  * pull_varattnos() are offset by FirstLowInvalidHeapAttributeNumber,
1665  * while attnums within *attnums aren't. Convert *attnums to the
1666  * offset style so we can combine the results.
1667  */
1668  while ((attnum = bms_next_member(*attnums, attnum)) >= 0)
1669  {
1670  clause_attnums =
1671  bms_add_member(clause_attnums,
1673  }
1674 
1675  /* Now merge attnums from *exprs into clause_attnums */
1676  if (*exprs != NIL)
1677  pull_varattnos((Node *) *exprs, relid, &clause_attnums);
1678 
1679  attnum = -1;
1680  while ((attnum = bms_next_member(clause_attnums, attnum)) >= 0)
1681  {
1682  /* Undo the offset */
1684 
1685  if (attno == InvalidAttrNumber)
1686  {
1687  /* Whole-row reference, so must have access to all columns */
1688  if (pg_attribute_aclcheck_all(rte->relid, userid, ACL_SELECT,
1690  return false;
1691  }
1692  else
1693  {
1694  if (pg_attribute_aclcheck(rte->relid, attno, userid,
1695  ACL_SELECT) != ACLCHECK_OK)
1696  return false;
1697  }
1698  }
1699  }
1700 
1701  /* If we reach here, the clause is OK */
1702  return true;
1703 }
@ ACLCHECK_OK
Definition: acl.h:183
@ ACLMASK_ALL
Definition: acl.h:176
AclResult pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode, AclMaskHow how)
Definition: aclchk.c:3838
AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode)
Definition: aclchk.c:3794
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:3923
bool bms_get_singleton_member(const Bitmapset *a, int *member)
Definition: bitmapset.c:634
static bool statext_is_compatible_clause_internal(PlannerInfo *root, Node *clause, Index relid, Bitmapset **attnums, List **exprs)
static bool statext_is_compatible_clause(PlannerInfo *root, Node *clause, Index relid, Bitmapset **attnums, List **exprs)
Oid GetUserId(void)
Definition: miscinit.c:510
static bool is_andclause(const void *clause)
Definition: nodeFuncs.h:105
#define ACL_SELECT
Definition: parsenodes.h:84
List * args
Definition: primnodes.h:867
Oid userid
Definition: pathnodes.h:951
Expr * clause
Definition: pathnodes.h:2513
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:291

References ACL_SELECT, ACLCHECK_OK, ACLMASK_ALL, BoolExpr::args, attnum, bms_add_member(), bms_get_singleton_member(), bms_next_member(), RestrictInfo::clause, FirstLowInvalidHeapAttributeNumber, GetUserId(), InvalidAttrNumber, is_andclause(), IsA, lfirst, NIL, OidIsValid, pg_attribute_aclcheck(), pg_attribute_aclcheck_all(), pg_class_aclcheck(), pull_varattnos(), RangeTblEntry::relid, statext_is_compatible_clause_internal(), and RelOptInfo::userid.

Referenced by statext_mcv_clauselist_selectivity().

◆ statext_is_compatible_clause_internal()

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

Definition at line 1352 of file extended_stats.c.

1355 {
1356  /* Look inside any binary-compatible relabeling (as in examine_variable) */
1357  if (IsA(clause, RelabelType))
1358  clause = (Node *) ((RelabelType *) clause)->arg;
1359 
1360  /* plain Var references (boolean Vars or recursive checks) */
1361  if (IsA(clause, Var))
1362  {
1363  Var *var = (Var *) clause;
1364 
1365  /* Ensure var is from the correct relation */
1366  if (var->varno != relid)
1367  return false;
1368 
1369  /* we also better ensure the Var is from the current level */
1370  if (var->varlevelsup > 0)
1371  return false;
1372 
1373  /*
1374  * Also reject system attributes and whole-row Vars (we don't allow
1375  * stats on those).
1376  */
1378  return false;
1379 
1380  /* OK, record the attnum for later permissions checks. */
1381  *attnums = bms_add_member(*attnums, var->varattno);
1382 
1383  return true;
1384  }
1385 
1386  /* (Var/Expr op Const) or (Const op Var/Expr) */
1387  if (is_opclause(clause))
1388  {
1389  RangeTblEntry *rte = root->simple_rte_array[relid];
1390  OpExpr *expr = (OpExpr *) clause;
1391  Node *clause_expr;
1392 
1393  /* Only expressions with two arguments are considered compatible. */
1394  if (list_length(expr->args) != 2)
1395  return false;
1396 
1397  /* Check if the expression has the right shape */
1398  if (!examine_opclause_args(expr->args, &clause_expr, NULL, NULL))
1399  return false;
1400 
1401  /*
1402  * If it's not one of the supported operators ("=", "<", ">", etc.),
1403  * just ignore the clause, as it's not compatible with MCV lists.
1404  *
1405  * This uses the function for estimating selectivity, not the operator
1406  * directly (a bit awkward, but well ...).
1407  */
1408  switch (get_oprrest(expr->opno))
1409  {
1410  case F_EQSEL:
1411  case F_NEQSEL:
1412  case F_SCALARLTSEL:
1413  case F_SCALARLESEL:
1414  case F_SCALARGTSEL:
1415  case F_SCALARGESEL:
1416  /* supported, will continue with inspection of the Var/Expr */
1417  break;
1418 
1419  default:
1420  /* other estimators are considered unknown/unsupported */
1421  return false;
1422  }
1423 
1424  /*
1425  * If there are any securityQuals on the RTE from security barrier
1426  * views or RLS policies, then the user may not have access to all the
1427  * table's data, and we must check that the operator is leak-proof.
1428  *
1429  * If the operator is leaky, then we must ignore this clause for the
1430  * purposes of estimating with MCV lists, otherwise the operator might
1431  * reveal values from the MCV list that the user doesn't have
1432  * permission to see.
1433  */
1434  if (rte->securityQuals != NIL &&
1436  return false;
1437 
1438  /* Check (Var op Const) or (Const op Var) clauses by recursing. */
1439  if (IsA(clause_expr, Var))
1440  return statext_is_compatible_clause_internal(root, clause_expr,
1441  relid, attnums, exprs);
1442 
1443  /* Otherwise we have (Expr op Const) or (Const op Expr). */
1444  *exprs = lappend(*exprs, clause_expr);
1445  return true;
1446  }
1447 
1448  /* Var/Expr IN Array */
1449  if (IsA(clause, ScalarArrayOpExpr))
1450  {
1451  RangeTblEntry *rte = root->simple_rte_array[relid];
1452  ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) clause;
1453  Node *clause_expr;
1454  bool expronleft;
1455 
1456  /* Only expressions with two arguments are considered compatible. */
1457  if (list_length(expr->args) != 2)
1458  return false;
1459 
1460  /* Check if the expression has the right shape (one Var, one Const) */
1461  if (!examine_opclause_args(expr->args, &clause_expr, NULL, &expronleft))
1462  return false;
1463 
1464  /* We only support Var on left, Const on right */
1465  if (!expronleft)
1466  return false;
1467 
1468  /*
1469  * If it's not one of the supported operators ("=", "<", ">", etc.),
1470  * just ignore the clause, as it's not compatible with MCV lists.
1471  *
1472  * This uses the function for estimating selectivity, not the operator
1473  * directly (a bit awkward, but well ...).
1474  */
1475  switch (get_oprrest(expr->opno))
1476  {
1477  case F_EQSEL:
1478  case F_NEQSEL:
1479  case F_SCALARLTSEL:
1480  case F_SCALARLESEL:
1481  case F_SCALARGTSEL:
1482  case F_SCALARGESEL:
1483  /* supported, will continue with inspection of the Var/Expr */
1484  break;
1485 
1486  default:
1487  /* other estimators are considered unknown/unsupported */
1488  return false;
1489  }
1490 
1491  /*
1492  * If there are any securityQuals on the RTE from security barrier
1493  * views or RLS policies, then the user may not have access to all the
1494  * table's data, and we must check that the operator is leak-proof.
1495  *
1496  * If the operator is leaky, then we must ignore this clause for the
1497  * purposes of estimating with MCV lists, otherwise the operator might
1498  * reveal values from the MCV list that the user doesn't have
1499  * permission to see.
1500  */
1501  if (rte->securityQuals != NIL &&
1503  return false;
1504 
1505  /* Check Var IN Array clauses by recursing. */
1506  if (IsA(clause_expr, Var))
1507  return statext_is_compatible_clause_internal(root, clause_expr,
1508  relid, attnums, exprs);
1509 
1510  /* Otherwise we have Expr IN Array. */
1511  *exprs = lappend(*exprs, clause_expr);
1512  return true;
1513  }
1514 
1515  /* AND/OR/NOT clause */
1516  if (is_andclause(clause) ||
1517  is_orclause(clause) ||
1518  is_notclause(clause))
1519  {
1520  /*
1521  * AND/OR/NOT-clauses are supported if all sub-clauses are supported
1522  *
1523  * Perhaps we could improve this by handling mixed cases, when some of
1524  * the clauses are supported and some are not. Selectivity for the
1525  * supported subclauses would be computed using extended statistics,
1526  * and the remaining clauses would be estimated using the traditional
1527  * algorithm (product of selectivities).
1528  *
1529  * It however seems overly complex, and in a way we already do that
1530  * because if we reject the whole clause as unsupported here, it will
1531  * be eventually passed to clauselist_selectivity() which does exactly
1532  * this (split into supported/unsupported clauses etc).
1533  */
1534  BoolExpr *expr = (BoolExpr *) clause;
1535  ListCell *lc;
1536 
1537  foreach(lc, expr->args)
1538  {
1539  /*
1540  * If we find an incompatible clause in the arguments, treat the
1541  * whole clause as incompatible.
1542  */
1544  (Node *) lfirst(lc),
1545  relid, attnums, exprs))
1546  return false;
1547  }
1548 
1549  return true;
1550  }
1551 
1552  /* Var/Expr IS NULL */
1553  if (IsA(clause, NullTest))
1554  {
1555  NullTest *nt = (NullTest *) clause;
1556 
1557  /* Check Var IS NULL clauses by recursing. */
1558  if (IsA(nt->arg, Var))
1559  return statext_is_compatible_clause_internal(root, (Node *) (nt->arg),
1560  relid, attnums, exprs);
1561 
1562  /* Otherwise we have Expr IS NULL. */
1563  *exprs = lappend(*exprs, nt->arg);
1564  return true;
1565  }
1566 
1567  /*
1568  * Treat any other expressions as bare expressions to be matched against
1569  * expressions in statistics objects.
1570  */
1571  *exprs = lappend(*exprs, clause);
1572  return true;
1573 }
#define AttrNumberIsForUserDefinedAttr(attributeNumber)
Definition: attnum.h:41
bool examine_opclause_args(List *args, Node **exprp, Const **cstp, bool *expronleftp)
RegProcedure get_oprrest(Oid opno)
Definition: lsyscache.c:1539
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1267
bool get_func_leakproof(Oid funcid)
Definition: lsyscache.c:1819
static bool is_orclause(const void *clause)
Definition: nodeFuncs.h:114
static bool is_opclause(const void *clause)
Definition: nodeFuncs.h:74
static bool is_notclause(const void *clause)
Definition: nodeFuncs.h:123
Expr * arg
Definition: primnodes.h:1613
Oid opno
Definition: primnodes.h:745
List * args
Definition: primnodes.h:763
List * securityQuals
Definition: parsenodes.h:1204
Definition: primnodes.h:226
AttrNumber varattno
Definition: primnodes.h:238
int varno
Definition: primnodes.h:233
Index varlevelsup
Definition: primnodes.h:258

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

Referenced by statext_is_compatible_clause().

◆ statext_is_kind_built()

bool statext_is_kind_built ( HeapTuple  htup,
char  type 
)

Definition at line 392 of file extended_stats.c.

393 {
395 
396  switch (type)
397  {
398  case STATS_EXT_NDISTINCT:
399  attnum = Anum_pg_statistic_ext_data_stxdndistinct;
400  break;
401 
402  case STATS_EXT_DEPENDENCIES:
403  attnum = Anum_pg_statistic_ext_data_stxddependencies;
404  break;
405 
406  case STATS_EXT_MCV:
407  attnum = Anum_pg_statistic_ext_data_stxdmcv;
408  break;
409 
410  case STATS_EXT_EXPRESSIONS:
411  attnum = Anum_pg_statistic_ext_data_stxdexpr;
412  break;
413 
414  default:
415  elog(ERROR, "unexpected statistics type requested: %d", type);
416  }
417 
418  return !heap_attisnull(htup, attnum, NULL);
419 }
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:359

References attnum, elog(), ERROR, heap_attisnull(), and generate_unaccent_rules::type.

Referenced by get_relation_statistics_worker().

◆ statext_mcv_clauselist_selectivity()

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

Definition at line 1740 of file extended_stats.c.

1744 {
1745  ListCell *l;
1746  Bitmapset **list_attnums; /* attnums extracted from the clause */
1747  List **list_exprs; /* expressions matched to any statistic */
1748  int listidx;
1749  Selectivity sel = (is_or) ? 0.0 : 1.0;
1750  RangeTblEntry *rte = planner_rt_fetch(rel->relid, root);
1751 
1752  /* check if there's any stats that might be useful for us. */
1753  if (!has_stats_of_kind(rel->statlist, STATS_EXT_MCV))
1754  return sel;
1755 
1756  list_attnums = (Bitmapset **) palloc(sizeof(Bitmapset *) *
1757  list_length(clauses));
1758 
1759  /* expressions extracted from complex expressions */
1760  list_exprs = (List **) palloc(sizeof(Node *) * list_length(clauses));
1761 
1762  /*
1763  * Pre-process the clauses list to extract the attnums and expressions
1764  * seen in each item. We need to determine if there are any clauses which
1765  * will be useful for selectivity estimations with extended stats. Along
1766  * the way we'll record all of the attnums and expressions for each clause
1767  * in lists which we'll reference later so we don't need to repeat the
1768  * same work again.
1769  *
1770  * We also skip clauses that we already estimated using different types of
1771  * statistics (we treat them as incompatible).
1772  */
1773  listidx = 0;
1774  foreach(l, clauses)
1775  {
1776  Node *clause = (Node *) lfirst(l);
1777  Bitmapset *attnums = NULL;
1778  List *exprs = NIL;
1779 
1780  if (!bms_is_member(listidx, *estimatedclauses) &&
1781  statext_is_compatible_clause(root, clause, rel->relid, &attnums, &exprs))
1782  {
1783  list_attnums[listidx] = attnums;
1784  list_exprs[listidx] = exprs;
1785  }
1786  else
1787  {
1788  list_attnums[listidx] = NULL;
1789  list_exprs[listidx] = NIL;
1790  }
1791 
1792  listidx++;
1793  }
1794 
1795  /* apply as many extended statistics as possible */
1796  while (true)
1797  {
1799  List *stat_clauses;
1800  Bitmapset *simple_clauses;
1801 
1802  /* find the best suited statistics object for these attnums */
1803  stat = choose_best_statistics(rel->statlist, STATS_EXT_MCV, rte->inh,
1804  list_attnums, list_exprs,
1805  list_length(clauses));
1806 
1807  /*
1808  * if no (additional) matching stats could be found then we've nothing
1809  * to do
1810  */
1811  if (!stat)
1812  break;
1813 
1814  /* Ensure choose_best_statistics produced an expected stats type. */
1815  Assert(stat->kind == STATS_EXT_MCV);
1816 
1817  /* now filter the clauses to be estimated using the selected MCV */
1818  stat_clauses = NIL;
1819 
1820  /* record which clauses are simple (single column or expression) */
1821  simple_clauses = NULL;
1822 
1823  listidx = -1;
1824  foreach(l, clauses)
1825  {
1826  /* Increment the index before we decide if to skip the clause. */
1827  listidx++;
1828 
1829  /*
1830  * Ignore clauses from which we did not extract any attnums or
1831  * expressions (this needs to be consistent with what we do in
1832  * choose_best_statistics).
1833  *
1834  * This also eliminates already estimated clauses - both those
1835  * estimated before and during applying extended statistics.
1836  *
1837  * XXX This check is needed because both bms_is_subset and
1838  * stat_covers_expressions return true for empty attnums and
1839  * expressions.
1840  */
1841  if (!list_attnums[listidx] && !list_exprs[listidx])
1842  continue;
1843 
1844  /*
1845  * The clause was not estimated yet, and we've extracted either
1846  * attnums or expressions from it. Ignore it if it's not fully
1847  * covered by the chosen statistics object.
1848  *
1849  * We need to check both attributes and expressions, and reject if
1850  * either is not covered.
1851  */
1852  if (!bms_is_subset(list_attnums[listidx], stat->keys) ||
1853  !stat_covers_expressions(stat, list_exprs[listidx], NULL))
1854  continue;
1855 
1856  /*
1857  * Now we know the clause is compatible (we have either attnums or
1858  * expressions extracted from it), and was not estimated yet.
1859  */
1860 
1861  /* record simple clauses (single column or expression) */
1862  if ((list_attnums[listidx] == NULL &&
1863  list_length(list_exprs[listidx]) == 1) ||
1864  (list_exprs[listidx] == NIL &&
1865  bms_membership(list_attnums[listidx]) == BMS_SINGLETON))
1866  simple_clauses = bms_add_member(simple_clauses,
1867  list_length(stat_clauses));
1868 
1869  /* add clause to list and mark it as estimated */
1870  stat_clauses = lappend(stat_clauses, (Node *) lfirst(l));
1871  *estimatedclauses = bms_add_member(*estimatedclauses, listidx);
1872 
1873  /*
1874  * Reset the pointers, so that choose_best_statistics knows this
1875  * clause was estimated and does not consider it again.
1876  */
1877  bms_free(list_attnums[listidx]);
1878  list_attnums[listidx] = NULL;
1879 
1880  list_free(list_exprs[listidx]);
1881  list_exprs[listidx] = NULL;
1882  }
1883 
1884  if (is_or)
1885  {
1886  bool *or_matches = NULL;
1887  Selectivity simple_or_sel = 0.0,
1888  stat_sel = 0.0;
1889  MCVList *mcv_list;
1890 
1891  /* Load the MCV list stored in the statistics object */
1892  mcv_list = statext_mcv_load(stat->statOid, rte->inh);
1893 
1894  /*
1895  * Compute the selectivity of the ORed list of clauses covered by
1896  * this statistics object by estimating each in turn and combining
1897  * them using the formula P(A OR B) = P(A) + P(B) - P(A AND B).
1898  * This allows us to use the multivariate MCV stats to better
1899  * estimate the individual terms and their overlap.
1900  *
1901  * Each time we iterate this formula, the clause "A" above is
1902  * equal to all the clauses processed so far, combined with "OR".
1903  */
1904  listidx = 0;
1905  foreach(l, stat_clauses)
1906  {
1907  Node *clause = (Node *) lfirst(l);
1908  Selectivity simple_sel,
1909  overlap_simple_sel,
1910  mcv_sel,
1911  mcv_basesel,
1912  overlap_mcvsel,
1913  overlap_basesel,
1914  mcv_totalsel,
1915  clause_sel,
1916  overlap_sel;
1917 
1918  /*
1919  * "Simple" selectivity of the next clause and its overlap
1920  * with any of the previous clauses. These are our initial
1921  * estimates of P(B) and P(A AND B), assuming independence of
1922  * columns/clauses.
1923  */
1924  simple_sel = clause_selectivity_ext(root, clause, varRelid,
1925  jointype, sjinfo, false);
1926 
1927  overlap_simple_sel = simple_or_sel * simple_sel;
1928 
1929  /*
1930  * New "simple" selectivity of all clauses seen so far,
1931  * assuming independence.
1932  */
1933  simple_or_sel += simple_sel - overlap_simple_sel;
1934  CLAMP_PROBABILITY(simple_or_sel);
1935 
1936  /*
1937  * Multi-column estimate of this clause using MCV statistics,
1938  * along with base and total selectivities, and corresponding
1939  * selectivities for the overlap term P(A AND B).
1940  */
1941  mcv_sel = mcv_clause_selectivity_or(root, stat, mcv_list,
1942  clause, &or_matches,
1943  &mcv_basesel,
1944  &overlap_mcvsel,
1945  &overlap_basesel,
1946  &mcv_totalsel);
1947 
1948  /*
1949  * Combine the simple and multi-column estimates.
1950  *
1951  * If this clause is a simple single-column clause, then we
1952  * just use the simple selectivity estimate for it, since the
1953  * multi-column statistics are unlikely to improve on that
1954  * (and in fact could make it worse). For the overlap, we
1955  * always make use of the multi-column statistics.
1956  */
1957  if (bms_is_member(listidx, simple_clauses))
1958  clause_sel = simple_sel;
1959  else
1960  clause_sel = mcv_combine_selectivities(simple_sel,
1961  mcv_sel,
1962  mcv_basesel,
1963  mcv_totalsel);
1964 
1965  overlap_sel = mcv_combine_selectivities(overlap_simple_sel,
1966  overlap_mcvsel,
1967  overlap_basesel,
1968  mcv_totalsel);
1969 
1970  /* Factor these into the result for this statistics object */
1971  stat_sel += clause_sel - overlap_sel;
1972  CLAMP_PROBABILITY(stat_sel);
1973 
1974  listidx++;
1975  }
1976 
1977  /*
1978  * Factor the result for this statistics object into the overall
1979  * result. We treat the results from each separate statistics
1980  * object as independent of one another.
1981  */
1982  sel = sel + stat_sel - sel * stat_sel;
1983  }
1984  else /* Implicitly-ANDed list of clauses */
1985  {
1986  Selectivity simple_sel,
1987  mcv_sel,
1988  mcv_basesel,
1989  mcv_totalsel,
1990  stat_sel;
1991 
1992  /*
1993  * "Simple" selectivity, i.e. without any extended statistics,
1994  * essentially assuming independence of the columns/clauses.
1995  */
1996  simple_sel = clauselist_selectivity_ext(root, stat_clauses,
1997  varRelid, jointype,
1998  sjinfo, false);
1999 
2000  /*
2001  * Multi-column estimate using MCV statistics, along with base and
2002  * total selectivities.
2003  */
2004  mcv_sel = mcv_clauselist_selectivity(root, stat, stat_clauses,
2005  varRelid, jointype, sjinfo,
2006  rel, &mcv_basesel,
2007  &mcv_totalsel);
2008 
2009  /* Combine the simple and multi-column estimates. */
2010  stat_sel = mcv_combine_selectivities(simple_sel,
2011  mcv_sel,
2012  mcv_basesel,
2013  mcv_totalsel);
2014 
2015  /* Factor this into the overall result */
2016  sel *= stat_sel;
2017  }
2018  }
2019 
2020  return sel;
2021 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:444
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:691
@ BMS_SINGLETON
Definition: bitmapset.h:72
Selectivity clause_selectivity_ext(PlannerInfo *root, Node *clause, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, bool use_extended_stats)
Definition: clausesel.c:686
Selectivity clauselist_selectivity_ext(PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, bool use_extended_stats)
Definition: clausesel.c:119
bool has_stats_of_kind(List *stats, char requiredkind)
StatisticExtInfo * choose_best_statistics(List *stats, char requiredkind, bool inh, Bitmapset **clause_attnums, List **clause_exprs, int nclauses)
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:2052
Selectivity mcv_combine_selectivities(Selectivity simple_sel, Selectivity mcv_sel, Selectivity mcv_basesel, Selectivity mcv_totalsel)
Definition: mcv.c:2010
Selectivity mcv_clause_selectivity_or(PlannerInfo *root, StatisticExtInfo *stat, MCVList *mcv, Node *clause, bool **or_matches, Selectivity *basesel, Selectivity *overlap_mcvsel, Selectivity *overlap_basesel, Selectivity *totalsel)
Definition: mcv.c:2130
MCVList * statext_mcv_load(Oid mvoid, bool inh)
Definition: mcv.c:562
#define planner_rt_fetch(rti, root)
Definition: pathnodes.h:561
#define CLAMP_PROBABILITY(p)
Definition: selfuncs.h:63
Index relid
Definition: pathnodes.h:909
List * statlist
Definition: pathnodes.h:931
#define stat
Definition: win32_port.h:286

References Assert(), bms_add_member(), bms_free(), bms_is_member(), bms_is_subset(), bms_membership(), BMS_SINGLETON, choose_best_statistics(), CLAMP_PROBABILITY, clause_selectivity_ext(), clauselist_selectivity_ext(), has_stats_of_kind(), RangeTblEntry::inh, lappend(), lfirst, list_free(), list_length(), mcv_clause_selectivity_or(), mcv_clauselist_selectivity(), mcv_combine_selectivities(), NIL, palloc(), planner_rt_fetch, RelOptInfo::relid, stat, stat_covers_expressions(), statext_is_compatible_clause(), statext_mcv_load(), and RelOptInfo::statlist.

Referenced by statext_clauselist_selectivity().

◆ statext_store()

static void statext_store ( Oid  statOid,
bool  inh,
MVNDistinct ndistinct,
MVDependencies dependencies,
MCVList mcv,
Datum  exprs,
VacAttrStats **  stats 
)
static

Definition at line 786 of file extended_stats.c.

789 {
790  Relation pg_stextdata;
791  HeapTuple stup;
792  Datum values[Natts_pg_statistic_ext_data];
793  bool nulls[Natts_pg_statistic_ext_data];
794 
795  pg_stextdata = table_open(StatisticExtDataRelationId, RowExclusiveLock);
796 
797  memset(nulls, true, sizeof(nulls));
798  memset(values, 0, sizeof(values));
799 
800  /* basic info */
801  values[Anum_pg_statistic_ext_data_stxoid - 1] = ObjectIdGetDatum(statOid);
802  nulls[Anum_pg_statistic_ext_data_stxoid - 1] = false;
803 
804  values[Anum_pg_statistic_ext_data_stxdinherit - 1] = BoolGetDatum(inh);
805  nulls[Anum_pg_statistic_ext_data_stxdinherit - 1] = false;
806 
807  /*
808  * Construct a new pg_statistic_ext_data tuple, replacing the calculated
809  * stats.
810  */
811  if (ndistinct != NULL)
812  {
813  bytea *data = statext_ndistinct_serialize(ndistinct);
814 
815  nulls[Anum_pg_statistic_ext_data_stxdndistinct - 1] = (data == NULL);
816  values[Anum_pg_statistic_ext_data_stxdndistinct - 1] = PointerGetDatum(data);
817  }
818 
819  if (dependencies != NULL)
820  {
821  bytea *data = statext_dependencies_serialize(dependencies);
822 
823  nulls[Anum_pg_statistic_ext_data_stxddependencies - 1] = (data == NULL);
824  values[Anum_pg_statistic_ext_data_stxddependencies - 1] = PointerGetDatum(data);
825  }
826  if (mcv != NULL)
827  {
828  bytea *data = statext_mcv_serialize(mcv, stats);
829 
830  nulls[Anum_pg_statistic_ext_data_stxdmcv - 1] = (data == NULL);
831  values[Anum_pg_statistic_ext_data_stxdmcv - 1] = PointerGetDatum(data);
832  }
833  if (exprs != (Datum) 0)
834  {
835  nulls[Anum_pg_statistic_ext_data_stxdexpr - 1] = false;
836  values[Anum_pg_statistic_ext_data_stxdexpr - 1] = exprs;
837  }
838 
839  /*
840  * Delete the old tuple if it exists, and insert a new one. It's easier
841  * than trying to update or insert, based on various conditions.
842  */
843  RemoveStatisticsDataById(statOid, inh);
844 
845  /* form and insert a new tuple */
846  stup = heap_form_tuple(RelationGetDescr(pg_stextdata), values, nulls);
847  CatalogTupleInsert(pg_stextdata, stup);
848 
849  heap_freetuple(stup);
850 
851  table_close(pg_stextdata, RowExclusiveLock);
852 }
bytea * statext_dependencies_serialize(MVDependencies *dependencies)
Definition: dependencies.c:446
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
bytea * statext_mcv_serialize(MCVList *mcvlist, VacAttrStats **stats)
Definition: mcv.c:625
bytea * statext_ndistinct_serialize(MVNDistinct *ndistinct)
Definition: mvdistinct.c:180
void RemoveStatisticsDataById(Oid statsOid, bool inh)
Definition: statscmds.c:709
Definition: c.h:671

References BoolGetDatum(), CatalogTupleInsert(), data, heap_form_tuple(), heap_freetuple(), ObjectIdGetDatum(), PointerGetDatum(), RelationGetDescr, RemoveStatisticsDataById(), RowExclusiveLock, statext_dependencies_serialize(), statext_mcv_serialize(), statext_ndistinct_serialize(), table_close(), table_open(), and values.

Referenced by BuildRelationExtStatistics().