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

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

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

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

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

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;
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 */
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
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:868
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
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:781
@ BMS_MULTIPLE
Definition: bitmapset.h:73
#define Assert(condition)
Definition: c.h:815
MVDependencies * statext_dependencies_load(Oid mvoid, bool inh)
Definition: dependencies.c:619
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
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:73
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc(Size size)
Definition: mcxt.c:1317
double Selectivity
Definition: nodes.h:250
#define planner_rt_fetch(rti, root)
Definition: pathnodes.h:570
int16 attnum
Definition: pg_attribute.h:74
static const struct exclude_list_item skip[]
Definition: pg_checksums.c:107
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
char * s1
tree ctl root
Definition: radixtree.h:1857
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:918
List * statlist
Definition: pathnodes.h:946

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, root, 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 1115 of file extended_stats.c.

1116{
1117 ListCell *l;
1118
1119 foreach(l, stats)
1120 {
1122
1123 if (stat->kind == requiredkind)
1124 return true;
1125 }
1126
1127 return false;
1128}

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

2005{
2006 Selectivity sel;
2007
2008 /* First, try estimating clauses using a multivariate MCV list. */
2009 sel = statext_mcv_clauselist_selectivity(root, clauses, varRelid, jointype,
2010 sjinfo, rel, estimatedclauses, is_or);
2011
2012 /*
2013 * Functional dependencies only work for clauses connected by AND, so for
2014 * OR clauses we're done.
2015 */
2016 if (is_or)
2017 return sel;
2018
2019 /*
2020 * Then, apply functional dependencies on the remaining clauses by calling
2021 * dependencies_clauselist_selectivity. Pass 'estimatedclauses' so the
2022 * function can properly skip clauses already estimated above.
2023 *
2024 * The reasoning for applying dependencies last is that the more complex
2025 * stats can track more complex correlations between the attributes, and
2026 * so may be considered more reliable.
2027 *
2028 * For example, MCV list can give us an exact selectivity for values in
2029 * two columns, while functional dependencies can only provide information
2030 * about the overall strength of the dependency.
2031 */
2032 sel *= dependencies_clauselist_selectivity(root, clauses, varRelid,
2033 jointype, sjinfo, rel,
2034 estimatedclauses);
2035
2036 return sel;
2037}
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(), root, 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:107
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:600
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:232

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

2422{
2423 bool isnull;
2424 Datum value;
2425 HeapTuple htup;
2427 HeapTupleHeader td;
2428 HeapTupleData tmptup;
2429 HeapTuple tup;
2430
2431 htup = SearchSysCache2(STATEXTDATASTXOID,
2432 ObjectIdGetDatum(stxoid), BoolGetDatum(inh));
2433 if (!HeapTupleIsValid(htup))
2434 elog(ERROR, "cache lookup failed for statistics object %u", stxoid);
2435
2436 value = SysCacheGetAttr(STATEXTDATASTXOID, htup,
2437 Anum_pg_statistic_ext_data_stxdexpr, &isnull);
2438 if (isnull)
2439 elog(ERROR,
2440 "requested statistics kind \"%c\" is not yet built for statistics object %u",
2441 STATS_EXT_EXPRESSIONS, stxoid);
2442
2444
2446
2448
2449 /* Build a temporary HeapTuple control structure */
2451 ItemPointerSetInvalid(&(tmptup.t_self));
2452 tmptup.t_tableOid = InvalidOid;
2453 tmptup.t_data = td;
2454
2455 tup = heap_copytuple(&tmptup);
2456
2457 ReleaseSysCache(htup);
2458
2459 return tup;
2460}
void deconstruct_expanded_array(ExpandedArrayHeader *eah)
ExpandedArrayHeader * DatumGetExpandedArray(Datum d)
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:295
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:778
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:450
static struct @162 value
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition: itemptr.h:184
#define InvalidOid
Definition: postgres_ext.h:37
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 386 of file extended_stats.c.

387{
389
390 switch (type)
391 {
392 case STATS_EXT_NDISTINCT:
393 attnum = Anum_pg_statistic_ext_data_stxdndistinct;
394 break;
395
396 case STATS_EXT_DEPENDENCIES:
397 attnum = Anum_pg_statistic_ext_data_stxddependencies;
398 break;
399
400 case STATS_EXT_MCV:
401 attnum = Anum_pg_statistic_ext_data_stxdmcv;
402 break;
403
404 case STATS_EXT_EXPRESSIONS:
405 attnum = Anum_pg_statistic_ext_data_stxdexpr;
406 break;
407
408 default:
409 elog(ERROR, "unexpected statistics type requested: %d", type);
410 }
411
412 return !heap_attisnull(htup, attnum, NULL);
413}
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:456
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().