PostgreSQL Source Code  git master
statistics.h File Reference
#include "commands/vacuum.h"
#include "nodes/pathnodes.h"
Include dependency graph for statistics.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  MVNDistinctItem
 
struct  MVNDistinct
 
struct  MVDependency
 
struct  MVDependencies
 
struct  MCVItem
 
struct  MCVList
 

Macros

#define STATS_MAX_DIMENSIONS   8 /* max number of attributes */
 
#define STATS_NDISTINCT_MAGIC   0xA352BFA4 /* struct identifier */
 
#define STATS_NDISTINCT_TYPE_BASIC   1 /* struct version */
 
#define STATS_DEPS_MAGIC   0xB4549A2C /* marks serialized bytea */
 
#define STATS_DEPS_TYPE_BASIC   1 /* basic dependencies type */
 
#define STATS_MCV_MAGIC   0xE1A651C2 /* marks serialized bytea */
 
#define STATS_MCV_TYPE_BASIC   1 /* basic MCV list type */
 
#define STATS_MCVLIST_MAX_ITEMS   10000
 

Typedefs

typedef struct MVNDistinctItem MVNDistinctItem
 
typedef struct MVNDistinct MVNDistinct
 
typedef struct MVDependency MVDependency
 
typedef struct MVDependencies MVDependencies
 
typedef struct MCVItem MCVItem
 
typedef struct MCVList MCVList
 

Functions

MVNDistinctstatext_ndistinct_load (Oid mvoid, bool inh)
 
MVDependenciesstatext_dependencies_load (Oid mvoid, bool inh)
 
MCVListstatext_mcv_load (Oid mvoid, bool inh)
 
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)
 
Selectivity dependencies_clauselist_selectivity (PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, RelOptInfo *rel, Bitmapset **estimatedclauses)
 
Selectivity statext_clauselist_selectivity (PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, RelOptInfo *rel, Bitmapset **estimatedclauses, bool is_or)
 
bool has_stats_of_kind (List *stats, char requiredkind)
 
StatisticExtInfochoose_best_statistics (List *stats, char requiredkind, bool inh, Bitmapset **clause_attnums, List **clause_exprs, int nclauses)
 
HeapTuple statext_expressions_load (Oid stxoid, bool inh, int idx)
 

Macro Definition Documentation

◆ STATS_DEPS_MAGIC

#define STATS_DEPS_MAGIC   0xB4549A2C /* marks serialized bytea */

Definition at line 43 of file statistics.h.

◆ STATS_DEPS_TYPE_BASIC

#define STATS_DEPS_TYPE_BASIC   1 /* basic dependencies type */

Definition at line 44 of file statistics.h.

◆ STATS_MAX_DIMENSIONS

#define STATS_MAX_DIMENSIONS   8 /* max number of attributes */

Definition at line 19 of file statistics.h.

◆ STATS_MCV_MAGIC

#define STATS_MCV_MAGIC   0xE1A651C2 /* marks serialized bytea */

Definition at line 66 of file statistics.h.

◆ STATS_MCV_TYPE_BASIC

#define STATS_MCV_TYPE_BASIC   1 /* basic MCV list type */

Definition at line 67 of file statistics.h.

◆ STATS_MCVLIST_MAX_ITEMS

#define STATS_MCVLIST_MAX_ITEMS   10000

Definition at line 70 of file statistics.h.

◆ STATS_NDISTINCT_MAGIC

#define STATS_NDISTINCT_MAGIC   0xA352BFA4 /* struct identifier */

Definition at line 22 of file statistics.h.

◆ STATS_NDISTINCT_TYPE_BASIC

#define STATS_NDISTINCT_TYPE_BASIC   1 /* struct version */

Definition at line 23 of file statistics.h.

Typedef Documentation

◆ MCVItem

typedef struct MCVItem MCVItem

◆ MCVList

typedef struct MCVList MCVList

◆ MVDependencies

◆ MVDependency

typedef struct MVDependency MVDependency

◆ MVNDistinct

typedef struct MVNDistinct MVNDistinct

◆ MVNDistinctItem

Function Documentation

◆ 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:3385
void pgstat_progress_update_param(int index, int64 val)
void pgstat_progress_update_multi_param(int nparam, const int *index, const int64 *val)
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:665
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:330
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:403
#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
const void * data
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define lfirst_int(lc)
Definition: pg_list.h:173
uintptr_t Datum
Definition: postgres.h:64
#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:504
#define RelationGetRelationName(relation)
Definition: rel.h:538
int errtable(Relation rel)
Definition: relcache.c:5906
Definition: pg_list.h:54
Form_pg_class rd_rel
Definition: rel.h:111
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)
int i
Definition: isn.c:73
#define STATS_MAX_DIMENSIONS
Definition: statistics.h:19
Bitmapset * keys
Definition: pathnodes.h:1268

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().

◆ 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().

◆ dependencies_clauselist_selectivity()

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

Definition at line 1372 of file dependencies.c.

1379 {
1380  Selectivity s1 = 1.0;
1381  ListCell *l;
1382  Bitmapset *clauses_attnums = NULL;
1383  AttrNumber *list_attnums;
1384  int listidx;
1385  MVDependencies **func_dependencies;
1386  int nfunc_dependencies;
1387  int total_ndeps;
1388  MVDependency **dependencies;
1389  int ndependencies;
1390  int i;
1391  AttrNumber attnum_offset;
1392  RangeTblEntry *rte = planner_rt_fetch(rel->relid, root);
1393 
1394  /* unique expressions */
1395  Node **unique_exprs;
1396  int unique_exprs_cnt;
1397 
1398  /* check if there's any stats that might be useful for us. */
1399  if (!has_stats_of_kind(rel->statlist, STATS_EXT_DEPENDENCIES))
1400  return 1.0;
1401 
1402  list_attnums = (AttrNumber *) palloc(sizeof(AttrNumber) *
1403  list_length(clauses));
1404 
1405  /*
1406  * We allocate space as if every clause was a unique expression, although
1407  * that's probably overkill. Some will be simple column references that
1408  * we'll translate to attnums, and there might be duplicates. But it's
1409  * easier and cheaper to just do one allocation than repalloc later.
1410  */
1411  unique_exprs = (Node **) palloc(sizeof(Node *) * list_length(clauses));
1412  unique_exprs_cnt = 0;
1413 
1414  /*
1415  * Pre-process the clauses list to extract the attnums seen in each item.
1416  * We need to determine if there's any clauses which will be useful for
1417  * dependency selectivity estimations. Along the way we'll record all of
1418  * the attnums for each clause in a list which we'll reference later so we
1419  * don't need to repeat the same work again. We'll also keep track of all
1420  * attnums seen.
1421  *
1422  * We also skip clauses that we already estimated using different types of
1423  * statistics (we treat them as incompatible).
1424  *
1425  * To handle expressions, we assign them negative attnums, as if it was a
1426  * system attribute (this is fine, as we only allow extended stats on user
1427  * attributes). And then we offset everything by the number of
1428  * expressions, so that we can store the values in a bitmapset.
1429  */
1430  listidx = 0;
1431  foreach(l, clauses)
1432  {
1433  Node *clause = (Node *) lfirst(l);
1435  Node *expr = NULL;
1436 
1437  /* ignore clause by default */
1438  list_attnums[listidx] = InvalidAttrNumber;
1439 
1440  if (!bms_is_member(listidx, *estimatedclauses))
1441  {
1442  /*
1443  * If it's a simple column reference, just extract the attnum. If
1444  * it's an expression, assign a negative attnum as if it was a
1445  * system attribute.
1446  */
1447  if (dependency_is_compatible_clause(clause, rel->relid, &attnum))
1448  {
1449  list_attnums[listidx] = attnum;
1450  }
1451  else if (dependency_is_compatible_expression(clause, rel->relid,
1452  rel->statlist,
1453  &expr))
1454  {
1455  /* special attnum assigned to this expression */
1457 
1458  Assert(expr != NULL);
1459 
1460  /* If the expression is duplicate, use the same attnum. */
1461  for (i = 0; i < unique_exprs_cnt; i++)
1462  {
1463  if (equal(unique_exprs[i], expr))
1464  {
1465  /* negative attribute number to expression */
1466  attnum = -(i + 1);
1467  break;
1468  }
1469  }
1470 
1471  /* not found in the list, so add it */
1472  if (attnum == InvalidAttrNumber)
1473  {
1474  unique_exprs[unique_exprs_cnt++] = expr;
1475 
1476  /* after incrementing the value, to get -1, -2, ... */
1477  attnum = (-unique_exprs_cnt);
1478  }
1479 
1480  /* remember which attnum was assigned to this clause */
1481  list_attnums[listidx] = attnum;
1482  }
1483  }
1484 
1485  listidx++;
1486  }
1487 
1488  Assert(listidx == list_length(clauses));
1489 
1490  /*
1491  * How much we need to offset the attnums? If there are no expressions,
1492  * then no offset is needed. Otherwise we need to offset enough for the
1493  * lowest value (-unique_exprs_cnt) to become 1.
1494  */
1495  if (unique_exprs_cnt > 0)
1496  attnum_offset = (unique_exprs_cnt + 1);
1497  else
1498  attnum_offset = 0;
1499 
1500  /*
1501  * Now that we know how many expressions there are, we can offset the
1502  * values just enough to build the bitmapset.
1503  */
1504  for (i = 0; i < list_length(clauses); i++)
1505  {
1507 
1508  /* ignore incompatible or already estimated clauses */
1509  if (list_attnums[i] == InvalidAttrNumber)
1510  continue;
1511 
1512  /* make sure the attnum is in the expected range */
1513  Assert(list_attnums[i] >= (-unique_exprs_cnt));
1514  Assert(list_attnums[i] <= MaxHeapAttributeNumber);
1515 
1516  /* make sure the attnum is positive (valid AttrNumber) */
1517  attnum = list_attnums[i] + attnum_offset;
1518 
1519  /*
1520  * Either it's a regular attribute, or it's an expression, in which
1521  * case we must not have seen it before (expressions are unique).
1522  *
1523  * XXX Check whether it's a regular attribute has to be done using the
1524  * original attnum, while the second check has to use the value with
1525  * an offset.
1526  */
1527  Assert(AttrNumberIsForUserDefinedAttr(list_attnums[i]) ||
1528  !bms_is_member(attnum, clauses_attnums));
1529 
1530  /*
1531  * Remember the offset attnum, both for attributes and expressions.
1532  * We'll pass list_attnums to clauselist_apply_dependencies, which
1533  * uses it to identify clauses in a bitmap. We could also pass the
1534  * offset, but this is more convenient.
1535  */
1536  list_attnums[i] = attnum;
1537 
1538  clauses_attnums = bms_add_member(clauses_attnums, attnum);
1539  }
1540 
1541  /*
1542  * If there's not at least two distinct attnums and expressions, then
1543  * reject the whole list of clauses. We must return 1.0 so the calling
1544  * function's selectivity is unaffected.
1545  */
1546  if (bms_membership(clauses_attnums) != BMS_MULTIPLE)
1547  {
1548  bms_free(clauses_attnums);
1549  pfree(list_attnums);
1550  return 1.0;
1551  }
1552 
1553  /*
1554  * Load all functional dependencies matching at least two parameters. We
1555  * can simply consider all dependencies at once, without having to search
1556  * for the best statistics object.
1557  *
1558  * To not waste cycles and memory, we deserialize dependencies only for
1559  * statistics that match at least two attributes. The array is allocated
1560  * with the assumption that all objects match - we could grow the array to
1561  * make it just the right size, but it's likely wasteful anyway thanks to
1562  * moving the freed chunks to freelists etc.
1563  */
1564  func_dependencies = (MVDependencies **) palloc(sizeof(MVDependencies *) *
1565  list_length(rel->statlist));
1566  nfunc_dependencies = 0;
1567  total_ndeps = 0;
1568 
1569  foreach(l, rel->statlist)
1570  {
1572  int nmatched;
1573  int nexprs;
1574  int k;
1575  MVDependencies *deps;
1576 
1577  /* skip statistics that are not of the correct type */
1578  if (stat->kind != STATS_EXT_DEPENDENCIES)
1579  continue;
1580 
1581  /* skip statistics with mismatching stxdinherit value */
1582  if (stat->inherit != rte->inh)
1583  continue;
1584 
1585  /*
1586  * Count matching attributes - we have to undo the attnum offsets. The
1587  * input attribute numbers are not offset (expressions are not
1588  * included in stat->keys, so it's not necessary). But we need to
1589  * offset it before checking against clauses_attnums.
1590  */
1591  nmatched = 0;
1592  k = -1;
1593  while ((k = bms_next_member(stat->keys, k)) >= 0)
1594  {
1596 
1597  /* skip expressions */
1599  continue;
1600 
1601  /* apply the same offset as above */
1602  attnum += attnum_offset;
1603 
1604  if (bms_is_member(attnum, clauses_attnums))
1605  nmatched++;
1606  }
1607 
1608  /* count matching expressions */
1609  nexprs = 0;
1610  for (i = 0; i < unique_exprs_cnt; i++)
1611  {
1612  ListCell *lc;
1613 
1614  foreach(lc, stat->exprs)
1615  {
1616  Node *stat_expr = (Node *) lfirst(lc);
1617 
1618  /* try to match it */
1619  if (equal(stat_expr, unique_exprs[i]))
1620  nexprs++;
1621  }
1622  }
1623 
1624  /*
1625  * Skip objects matching fewer than two attributes/expressions from
1626  * clauses.
1627  */
1628  if (nmatched + nexprs < 2)
1629  continue;
1630 
1631  deps = statext_dependencies_load(stat->statOid, rte->inh);
1632 
1633  /*
1634  * The expressions may be represented by different attnums in the
1635  * stats, we need to remap them to be consistent with the clauses.
1636  * That will make the later steps (e.g. picking the strongest item and
1637  * so on) much simpler and cheaper, because it won't need to care
1638  * about the offset at all.
1639  *
1640  * When we're at it, we can ignore dependencies that are not fully
1641  * matched by clauses (i.e. referencing attributes or expressions that
1642  * are not in the clauses).
1643  *
1644  * We have to do this for all statistics, as long as there are any
1645  * expressions - we need to shift the attnums in all dependencies.
1646  *
1647  * XXX Maybe we should do this always, because it also eliminates some
1648  * of the dependencies early. It might be cheaper than having to walk
1649  * the longer list in find_strongest_dependency later, especially as
1650  * we need to do that repeatedly?
1651  *
1652  * XXX We have to do this even when there are no expressions in
1653  * clauses, otherwise find_strongest_dependency may fail for stats
1654  * with expressions (due to lookup of negative value in bitmap). So we
1655  * need to at least filter out those dependencies. Maybe we could do
1656  * it in a cheaper way (if there are no expr clauses, we can just
1657  * discard all negative attnums without any lookups).
1658  */
1659  if (unique_exprs_cnt > 0 || stat->exprs != NIL)
1660  {
1661  int ndeps = 0;
1662 
1663  for (i = 0; i < deps->ndeps; i++)
1664  {
1665  bool skip = false;
1666  MVDependency *dep = deps->deps[i];
1667  int j;
1668 
1669  for (j = 0; j < dep->nattributes; j++)
1670  {
1671  int idx;
1672  Node *expr;
1673  AttrNumber unique_attnum = InvalidAttrNumber;
1675 
1676  /* undo the per-statistics offset */
1677  attnum = dep->attributes[j];
1678 
1679  /*
1680  * For regular attributes we can simply check if it
1681  * matches any clause. If there's no matching clause, we
1682  * can just ignore it. We need to offset the attnum
1683  * though.
1684  */
1686  {
1687  dep->attributes[j] = attnum + attnum_offset;
1688 
1689  if (!bms_is_member(dep->attributes[j], clauses_attnums))
1690  {
1691  skip = true;
1692  break;
1693  }
1694 
1695  continue;
1696  }
1697 
1698  /*
1699  * the attnum should be a valid system attnum (-1, -2,
1700  * ...)
1701  */
1703 
1704  /*
1705  * For expressions, we need to do two translations. First
1706  * we have to translate the negative attnum to index in
1707  * the list of expressions (in the statistics object).
1708  * Then we need to see if there's a matching clause. The
1709  * index of the unique expression determines the attnum
1710  * (and we offset it).
1711  */
1712  idx = -(1 + attnum);
1713 
1714  /* Is the expression index is valid? */
1715  Assert((idx >= 0) && (idx < list_length(stat->exprs)));
1716 
1717  expr = (Node *) list_nth(stat->exprs, idx);
1718 
1719  /* try to find the expression in the unique list */
1720  for (int m = 0; m < unique_exprs_cnt; m++)
1721  {
1722  /*
1723  * found a matching unique expression, use the attnum
1724  * (derived from index of the unique expression)
1725  */
1726  if (equal(unique_exprs[m], expr))
1727  {
1728  unique_attnum = -(m + 1) + attnum_offset;
1729  break;
1730  }
1731  }
1732 
1733  /*
1734  * Found no matching expression, so we can simply skip
1735  * this dependency, because there's no chance it will be
1736  * fully covered.
1737  */
1738  if (unique_attnum == InvalidAttrNumber)
1739  {
1740  skip = true;
1741  break;
1742  }
1743 
1744  /* otherwise remap it to the new attnum */
1745  dep->attributes[j] = unique_attnum;
1746  }
1747 
1748  /* if found a matching dependency, keep it */
1749  if (!skip)
1750  {
1751  /* maybe we've skipped something earlier, so move it */
1752  if (ndeps != i)
1753  deps->deps[ndeps] = deps->deps[i];
1754 
1755  ndeps++;
1756  }
1757  }
1758 
1759  deps->ndeps = ndeps;
1760  }
1761 
1762  /*
1763  * It's possible we've removed all dependencies, in which case we
1764  * don't bother adding it to the list.
1765  */
1766  if (deps->ndeps > 0)
1767  {
1768  func_dependencies[nfunc_dependencies] = deps;
1769  total_ndeps += deps->ndeps;
1770  nfunc_dependencies++;
1771  }
1772  }
1773 
1774  /* if no matching stats could be found then we've nothing to do */
1775  if (nfunc_dependencies == 0)
1776  {
1777  pfree(func_dependencies);
1778  bms_free(clauses_attnums);
1779  pfree(list_attnums);
1780  pfree(unique_exprs);
1781  return 1.0;
1782  }
1783 
1784  /*
1785  * Work out which dependencies we can apply, starting with the
1786  * widest/strongest ones, and proceeding to smaller/weaker ones.
1787  */
1788  dependencies = (MVDependency **) palloc(sizeof(MVDependency *) *
1789  total_ndeps);
1790  ndependencies = 0;
1791 
1792  while (true)
1793  {
1794  MVDependency *dependency;
1796 
1797  /* the widest/strongest dependency, fully matched by clauses */
1798  dependency = find_strongest_dependency(func_dependencies,
1799  nfunc_dependencies,
1800  clauses_attnums);
1801  if (!dependency)
1802  break;
1803 
1804  dependencies[ndependencies++] = dependency;
1805 
1806  /* Ignore dependencies using this implied attribute in later loops */
1807  attnum = dependency->attributes[dependency->nattributes - 1];
1808  clauses_attnums = bms_del_member(clauses_attnums, attnum);
1809  }
1810 
1811  /*
1812  * If we found applicable dependencies, use them to estimate all
1813  * compatible clauses on attributes that they refer to.
1814  */
1815  if (ndependencies != 0)
1816  s1 = clauselist_apply_dependencies(root, clauses, varRelid, jointype,
1817  sjinfo, dependencies, ndependencies,
1818  list_attnums, estimatedclauses);
1819 
1820  /* free deserialized functional dependencies (and then the array) */
1821  for (i = 0; i < nfunc_dependencies; i++)
1822  pfree(func_dependencies[i]);
1823 
1824  pfree(dependencies);
1825  pfree(func_dependencies);
1826  bms_free(clauses_attnums);
1827  pfree(list_attnums);
1828  pfree(unique_exprs);
1829 
1830  return s1;
1831 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
int16 AttrNumber
Definition: attnum.h:21
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
#define AttrNumberIsForUserDefinedAttr(attributeNumber)
Definition: attnum.h:41
#define InvalidAttrNumber
Definition: attnum.h:23
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1039
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:444
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:755
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:792
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:691
@ BMS_MULTIPLE
Definition: bitmapset.h:73
static bool dependency_is_compatible_expression(Node *clause, Index relid, List *statlist, Node **expr)
static bool dependency_is_compatible_clause(Node *clause, Index relid, AttrNumber *attnum)
Definition: dependencies.c:743
MVDependencies * statext_dependencies_load(Oid mvoid, bool inh)
Definition: dependencies.c:621
static Selectivity clauselist_apply_dependencies(PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, MVDependency **dependencies, int ndependencies, AttrNumber *list_attnums, Bitmapset **estimatedclauses)
static MVDependency * find_strongest_dependency(MVDependencies **dependencies, int ndependencies, Bitmapset *attnums)
Definition: dependencies.c:931
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
bool has_stats_of_kind(List *stats, char requiredkind)
#define MaxHeapAttributeNumber
Definition: htup_details.h:48
int j
Definition: isn.c:74
Assert(fmt[strlen(fmt) - 1] !='\n')
void pfree(void *pointer)
Definition: mcxt.c:1456
void * palloc(Size size)
Definition: mcxt.c:1226
double Selectivity
Definition: nodes.h:261
#define planner_rt_fetch(rti, root)
Definition: pathnodes.h:555
int16 attnum
Definition: pg_attribute.h:74
static const struct exclude_list_item skip[]
Definition: pg_checksums.c:116
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
char * s1
uint32 ndeps
Definition: statistics.h:61
MVDependency * deps[FLEXIBLE_ARRAY_MEMBER]
Definition: statistics.h:62
AttrNumber nattributes
Definition: statistics.h:53
AttrNumber attributes[FLEXIBLE_ARRAY_MEMBER]
Definition: statistics.h:54
Definition: nodes.h:129
Index relid
Definition: pathnodes.h:903
List * statlist
Definition: pathnodes.h:925

References Assert(), attnum, AttributeNumberIsValid, MVDependency::attributes, AttrNumberIsForUserDefinedAttr, bms_add_member(), bms_del_member(), bms_free(), bms_is_member(), bms_membership(), BMS_MULTIPLE, bms_next_member(), clauselist_apply_dependencies(), dependency_is_compatible_clause(), dependency_is_compatible_expression(), MVDependencies::deps, equal(), find_strongest_dependency(), has_stats_of_kind(), i, idx(), RangeTblEntry::inh, InvalidAttrNumber, j, lfirst, list_length(), list_nth(), MaxHeapAttributeNumber, MVDependency::nattributes, MVDependencies::ndeps, NIL, palloc(), pfree(), planner_rt_fetch, RelOptInfo::relid, s1, skip, statext_dependencies_load(), and RelOptInfo::statlist.

Referenced by statext_clauselist_selectivity().

◆ 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().

◆ 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)

References dependencies_clauselist_selectivity(), and statext_mcv_clauselist_selectivity().

Referenced by clauselist_selectivity_ext(), and clauselist_selectivity_or().

◆ statext_dependencies_load()

MVDependencies* statext_dependencies_load ( Oid  mvoid,
bool  inh 
)

Definition at line 621 of file dependencies.c.

622 {
623  MVDependencies *result;
624  bool isnull;
625  Datum deps;
626  HeapTuple htup;
627 
629  ObjectIdGetDatum(mvoid),
630  BoolGetDatum(inh));
631  if (!HeapTupleIsValid(htup))
632  elog(ERROR, "cache lookup failed for statistics object %u", mvoid);
633 
634  deps = SysCacheGetAttr(STATEXTDATASTXOID, htup,
635  Anum_pg_statistic_ext_data_stxddependencies, &isnull);
636  if (isnull)
637  elog(ERROR,
638  "requested statistics kind \"%c\" is not yet built for statistics object %u",
639  STATS_EXT_DEPENDENCIES, mvoid);
640 
642 
643  ReleaseSysCache(htup);
644 
645  return result;
646 }
MVDependencies * statext_dependencies_deserialize(bytea *data)
Definition: dependencies.c:501
#define DatumGetByteaPP(X)
Definition: fmgr.h:291
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:866
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1079
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:829
@ STATEXTDATASTXOID
Definition: syscache.h:94

References BoolGetDatum(), DatumGetByteaPP, elog(), ERROR, HeapTupleIsValid, ObjectIdGetDatum(), ReleaseSysCache(), SearchSysCache2(), statext_dependencies_deserialize(), STATEXTDATASTXOID, and SysCacheGetAttr().

Referenced by dependencies_clauselist_selectivity().

◆ 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 struct @147 value
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition: itemptr.h:184
#define InvalidOid
Definition: postgres_ext.h:36
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

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_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_load()

MCVList* statext_mcv_load ( Oid  mvoid,
bool  inh 
)

Definition at line 562 of file mcv.c.

563 {
564  MCVList *result;
565  bool isnull;
566  Datum mcvlist;
568  ObjectIdGetDatum(mvoid), BoolGetDatum(inh));
569 
570  if (!HeapTupleIsValid(htup))
571  elog(ERROR, "cache lookup failed for statistics object %u", mvoid);
572 
573  mcvlist = SysCacheGetAttr(STATEXTDATASTXOID, htup,
574  Anum_pg_statistic_ext_data_stxdmcv, &isnull);
575 
576  if (isnull)
577  elog(ERROR,
578  "requested statistics kind \"%c\" is not yet built for statistics object %u",
579  STATS_EXT_DEPENDENCIES, mvoid);
580 
581  result = statext_mcv_deserialize(DatumGetByteaP(mcvlist));
582 
583  ReleaseSysCache(htup);
584 
585  return result;
586 }
#define DatumGetByteaP(X)
Definition: fmgr.h:331
MCVList * statext_mcv_deserialize(bytea *data)
Definition: mcv.c:1000

References BoolGetDatum(), DatumGetByteaP, elog(), ERROR, HeapTupleIsValid, ObjectIdGetDatum(), ReleaseSysCache(), SearchSysCache2(), statext_mcv_deserialize(), STATEXTDATASTXOID, and SysCacheGetAttr().

Referenced by mcv_clauselist_selectivity(), and statext_mcv_clauselist_selectivity().

◆ statext_ndistinct_load()

MVNDistinct* statext_ndistinct_load ( Oid  mvoid,
bool  inh 
)

Definition at line 149 of file mvdistinct.c.

150 {
151  MVNDistinct *result;
152  bool isnull;
153  Datum ndist;
154  HeapTuple htup;
155 
157  ObjectIdGetDatum(mvoid), BoolGetDatum(inh));
158  if (!HeapTupleIsValid(htup))
159  elog(ERROR, "cache lookup failed for statistics object %u", mvoid);
160 
161  ndist = SysCacheGetAttr(STATEXTDATASTXOID, htup,
162  Anum_pg_statistic_ext_data_stxdndistinct, &isnull);
163  if (isnull)
164  elog(ERROR,
165  "requested statistics kind \"%c\" is not yet built for statistics object %u",
166  STATS_EXT_NDISTINCT, mvoid);
167 
169 
170  ReleaseSysCache(htup);
171 
172  return result;
173 }
MVNDistinct * statext_ndistinct_deserialize(bytea *data)
Definition: mvdistinct.c:251

References BoolGetDatum(), DatumGetByteaPP, elog(), ERROR, HeapTupleIsValid, ObjectIdGetDatum(), ReleaseSysCache(), SearchSysCache2(), statext_ndistinct_deserialize(), STATEXTDATASTXOID, and SysCacheGetAttr().

Referenced by estimate_multivariate_ndistinct().