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   MAX_STATISTICS_TARGET
 

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   MAX_STATISTICS_TARGET

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 112 of file extended_stats.c.

115 {
116  Relation pg_stext;
117  ListCell *lc;
118  List *statslist;
119  MemoryContext cxt;
120  MemoryContext oldcxt;
121  int64 ext_cnt;
122 
123  /* Do nothing if there are no columns to analyze. */
124  if (!natts)
125  return;
126 
127  /* the list of stats has to be allocated outside the memory context */
128  pg_stext = table_open(StatisticExtRelationId, RowExclusiveLock);
129  statslist = fetch_statentries_for_relation(pg_stext, RelationGetRelid(onerel));
130 
131  /* memory context for building each statistics object */
133  "BuildRelationExtStatistics",
135  oldcxt = MemoryContextSwitchTo(cxt);
136 
137  /* report this phase */
138  if (statslist != NIL)
139  {
140  const int index[] = {
143  };
144  const int64 val[] = {
146  list_length(statslist)
147  };
148 
150  }
151 
152  ext_cnt = 0;
153  foreach(lc, statslist)
154  {
156  MVNDistinct *ndistinct = NULL;
157  MVDependencies *dependencies = NULL;
158  MCVList *mcv = NULL;
159  Datum exprstats = (Datum) 0;
160  VacAttrStats **stats;
161  ListCell *lc2;
162  int stattarget;
164 
165  /*
166  * Check if we can build these stats based on the column analyzed. If
167  * not, report this fact (except in autovacuum) and move on.
168  */
169  stats = lookup_var_attr_stats(onerel, stat->columns, stat->exprs,
170  natts, vacattrstats);
171  if (!stats)
172  {
175  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
176  errmsg("statistics object \"%s.%s\" could not be computed for relation \"%s.%s\"",
177  stat->schema, stat->name,
178  get_namespace_name(onerel->rd_rel->relnamespace),
179  RelationGetRelationName(onerel)),
180  errtable(onerel)));
181  continue;
182  }
183 
184  /* compute statistics target for this statistics object */
185  stattarget = statext_compute_stattarget(stat->stattarget,
186  bms_num_members(stat->columns),
187  stats);
188 
189  /*
190  * Don't rebuild statistics objects with statistics target set to 0
191  * (we just leave the existing values around, just like we do for
192  * regular per-column statistics).
193  */
194  if (stattarget == 0)
195  continue;
196 
197  /* evaluate expressions (if the statistics object has any) */
198  data = make_build_data(onerel, stat, numrows, rows, stats, stattarget);
199 
200  /* compute statistic of each requested type */
201  foreach(lc2, stat->types)
202  {
203  char t = (char) lfirst_int(lc2);
204 
205  if (t == STATS_EXT_NDISTINCT)
206  ndistinct = statext_ndistinct_build(totalrows, data);
207  else if (t == STATS_EXT_DEPENDENCIES)
208  dependencies = statext_dependencies_build(data);
209  else if (t == STATS_EXT_MCV)
210  mcv = statext_mcv_build(data, totalrows, stattarget);
211  else if (t == STATS_EXT_EXPRESSIONS)
212  {
213  AnlExprData *exprdata;
214  int nexprs;
215 
216  /* should not happen, thanks to checks when defining stats */
217  if (!stat->exprs)
218  elog(ERROR, "requested expression stats, but there are no expressions");
219 
220  exprdata = build_expr_data(stat->exprs, stattarget);
221  nexprs = list_length(stat->exprs);
222 
223  compute_expr_stats(onerel, totalrows,
224  exprdata, nexprs,
225  rows, numrows);
226 
227  exprstats = serialize_expr_stats(exprdata, nexprs);
228  }
229  }
230 
231  /* store the statistics in the catalog */
232  statext_store(stat->statOid, inh,
233  ndistinct, dependencies, mcv, exprstats, stats);
234 
235  /* for reporting progress */
237  ++ext_cnt);
238 
239  /* free the data used for building this statistics object */
240  MemoryContextReset(cxt);
241  }
242 
243  MemoryContextSwitchTo(oldcxt);
244  MemoryContextDelete(cxt);
245 
246  list_free(statslist);
247 
248  table_close(pg_stext, RowExclusiveLock);
249 }
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:751
MVDependencies * statext_dependencies_build(StatsBuildData *data)
Definition: dependencies.c:348
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define WARNING
Definition: elog.h:36
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#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:1546
#define RowExclusiveLock
Definition: lockdefs.h:38
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3322
MCVList * statext_mcv_build(StatsBuildData *data, double totalrows, int stattarget)
Definition: mcv.c:180
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:371
MemoryContext CurrentMemoryContext
Definition: mcxt.c:131
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:442
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:153
#define AmAutoVacuumWorkerProcess()
Definition: miscadmin.h:372
MVNDistinct * statext_ndistinct_build(double totalrows, StatsBuildData *data)
Definition: mvdistinct.c:88
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
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:44
#define PROGRESS_ANALYZE_PHASE
Definition: progress.h:40
#define PROGRESS_ANALYZE_PHASE_COMPUTE_EXT_STATS
Definition: progress.h:53
#define PROGRESS_ANALYZE_EXT_STATS_TOTAL
Definition: progress.h:43
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationGetRelationName(relation)
Definition: rel.h:539
int errtable(Relation rel)
Definition: relcache.c:5934
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, AmAutoVacuumWorkerProcess, bms_num_members(), build_expr_data(), compute_expr_stats(), CurrentMemoryContext, data, elog, ereport, errcode(), errmsg(), ERROR, errtable(), fetch_statentries_for_relation(), get_namespace_name(), 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 1209 of file extended_stats.c.

1212 {
1213  ListCell *lc;
1214  StatisticExtInfo *best_match = NULL;
1215  int best_num_matched = 2; /* goal #1: maximize */
1216  int best_match_keys = (STATS_MAX_DIMENSIONS + 1); /* goal #2: minimize */
1217 
1218  foreach(lc, stats)
1219  {
1220  int i;
1221  StatisticExtInfo *info = (StatisticExtInfo *) lfirst(lc);
1222  Bitmapset *matched_attnums = NULL;
1223  Bitmapset *matched_exprs = NULL;
1224  int num_matched;
1225  int numkeys;
1226 
1227  /* skip statistics that are not of the correct type */
1228  if (info->kind != requiredkind)
1229  continue;
1230 
1231  /* skip statistics with mismatching inheritance flag */
1232  if (info->inherit != inh)
1233  continue;
1234 
1235  /*
1236  * Collect attributes and expressions in remaining (unestimated)
1237  * clauses fully covered by this statistic object.
1238  *
1239  * We know already estimated clauses have both clause_attnums and
1240  * clause_exprs set to NULL. We leave the pointers NULL if already
1241  * estimated, or we reset them to NULL after estimating the clause.
1242  */
1243  for (i = 0; i < nclauses; i++)
1244  {
1245  Bitmapset *expr_idxs = NULL;
1246 
1247  /* ignore incompatible/estimated clauses */
1248  if (!clause_attnums[i] && !clause_exprs[i])
1249  continue;
1250 
1251  /* ignore clauses that are not covered by this object */
1252  if (!bms_is_subset(clause_attnums[i], info->keys) ||
1253  !stat_covers_expressions(info, clause_exprs[i], &expr_idxs))
1254  continue;
1255 
1256  /* record attnums and indexes of expressions covered */
1257  matched_attnums = bms_add_members(matched_attnums, clause_attnums[i]);
1258  matched_exprs = bms_add_members(matched_exprs, expr_idxs);
1259  }
1260 
1261  num_matched = bms_num_members(matched_attnums) + bms_num_members(matched_exprs);
1262 
1263  bms_free(matched_attnums);
1264  bms_free(matched_exprs);
1265 
1266  /*
1267  * save the actual number of keys in the stats so that we can choose
1268  * the narrowest stats with the most matching keys.
1269  */
1270  numkeys = bms_num_members(info->keys) + list_length(info->exprs);
1271 
1272  /*
1273  * Use this object when it increases the number of matched attributes
1274  * and expressions or when it matches the same number of attributes
1275  * and expressions but these stats have fewer keys than any previous
1276  * match.
1277  */
1278  if (num_matched > best_num_matched ||
1279  (num_matched == best_num_matched && numkeys < best_match_keys))
1280  {
1281  best_match = info;
1282  best_num_matched = num_matched;
1283  best_match_keys = numkeys;
1284  }
1285  }
1286 
1287  return best_match;
1288 }
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:412
void bms_free(Bitmapset *a)
Definition: bitmapset.c:239
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:917
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:1270

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 265 of file extended_stats.c.

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

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 1370 of file dependencies.c.

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

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 1118 of file extended_stats.c.

1119 {
1120  ListCell *l;
1121 
1122  foreach(l, stats)
1123  {
1125 
1126  if (stat->kind == requiredkind)
1127  return true;
1128  }
1129 
1130  return false;
1131 }

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 2004 of file extended_stats.c.

2008 {
2009  Selectivity sel;
2010 
2011  /* First, try estimating clauses using a multivariate MCV list. */
2012  sel = statext_mcv_clauselist_selectivity(root, clauses, varRelid, jointype,
2013  sjinfo, rel, estimatedclauses, is_or);
2014 
2015  /*
2016  * Functional dependencies only work for clauses connected by AND, so for
2017  * OR clauses we're done.
2018  */
2019  if (is_or)
2020  return sel;
2021 
2022  /*
2023  * Then, apply functional dependencies on the remaining clauses by calling
2024  * dependencies_clauselist_selectivity. Pass 'estimatedclauses' so the
2025  * function can properly skip clauses already estimated above.
2026  *
2027  * The reasoning for applying dependencies last is that the more complex
2028  * stats can track more complex correlations between the attributes, and
2029  * so may be considered more reliable.
2030  *
2031  * For example, MCV list can give us an exact selectivity for values in
2032  * two columns, while functional dependencies can only provide information
2033  * about the overall strength of the dependency.
2034  */
2035  sel *= dependencies_clauselist_selectivity(root, clauses, varRelid,
2036  jointype, sjinfo, rel,
2037  estimatedclauses);
2038 
2039  return sel;
2040 }
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 619 of file dependencies.c.

620 {
621  MVDependencies *result;
622  bool isnull;
623  Datum deps;
624  HeapTuple htup;
625 
626  htup = SearchSysCache2(STATEXTDATASTXOID,
627  ObjectIdGetDatum(mvoid),
628  BoolGetDatum(inh));
629  if (!HeapTupleIsValid(htup))
630  elog(ERROR, "cache lookup failed for statistics object %u", mvoid);
631 
632  deps = SysCacheGetAttr(STATEXTDATASTXOID, htup,
633  Anum_pg_statistic_ext_data_stxddependencies, &isnull);
634  if (isnull)
635  elog(ERROR,
636  "requested statistics kind \"%c\" is not yet built for statistics object %u",
637  STATS_EXT_DEPENDENCIES, mvoid);
638 
640 
641  ReleaseSysCache(htup);
642 
643  return result;
644 }
MVDependencies * statext_dependencies_deserialize(bytea *data)
Definition: dependencies.c:499
#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:266
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:479
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:229

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

Referenced by dependencies_clauselist_selectivity().

◆ statext_expressions_load()

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

Definition at line 2425 of file extended_stats.c.

2426 {
2427  bool isnull;
2428  Datum value;
2429  HeapTuple htup;
2430  ExpandedArrayHeader *eah;
2431  HeapTupleHeader td;
2432  HeapTupleData tmptup;
2433  HeapTuple tup;
2434 
2435  htup = SearchSysCache2(STATEXTDATASTXOID,
2436  ObjectIdGetDatum(stxoid), BoolGetDatum(inh));
2437  if (!HeapTupleIsValid(htup))
2438  elog(ERROR, "cache lookup failed for statistics object %u", stxoid);
2439 
2440  value = SysCacheGetAttr(STATEXTDATASTXOID, htup,
2441  Anum_pg_statistic_ext_data_stxdexpr, &isnull);
2442  if (isnull)
2443  elog(ERROR,
2444  "requested statistics kind \"%c\" is not yet built for statistics object %u",
2445  STATS_EXT_EXPRESSIONS, stxoid);
2446 
2448 
2450 
2451  td = DatumGetHeapTupleHeader(eah->dvalues[idx]);
2452 
2453  /* Build a temporary HeapTuple control structure */
2454  tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
2455  ItemPointerSetInvalid(&(tmptup.t_self));
2456  tmptup.t_tableOid = InvalidOid;
2457  tmptup.t_data = td;
2458 
2459  tup = heap_copytuple(&tmptup);
2460 
2461  ReleaseSysCache(htup);
2462 
2463  return tup;
2464 }
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:776
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:450
static struct @150 value
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition: itemptr.h:184
#define InvalidOid
Definition: postgres_ext.h:36
Datum * dvalues
Definition: array.h:146
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(), 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 389 of file extended_stats.c.

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

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

Referenced by get_relation_statistics_worker().

◆ statext_mcv_load()

MCVList* statext_mcv_load ( Oid  mvoid,
bool  inh 
)

Definition at line 558 of file mcv.c.

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

References BoolGetDatum(), DatumGetByteaP, elog, ERROR, HeapTupleIsValid, ObjectIdGetDatum(), ReleaseSysCache(), SearchSysCache2(), statext_mcv_deserialize(), 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 148 of file mvdistinct.c.

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

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

Referenced by estimate_multivariate_ndistinct().