PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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:539
MVDependencies * statext_dependencies_build(StatsBuildData *data)
Definition: dependencies.c:342
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define WARNING
Definition: elog.h:36
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:150
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:3533
MCVList * statext_mcv_build(StatsBuildData *data, double totalrows, int stattarget)
Definition: mcv.c:180
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:400
MemoryContext CurrentMemoryContext
Definition: mcxt.c:160
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:469
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
#define AmAutoVacuumWorkerProcess()
Definition: miscadmin.h:383
MVNDistinct * statext_ndistinct_build(double totalrows, StatsBuildData *data)
Definition: mvdistinct.c:85
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
uint64_t Datum
Definition: postgres.h:70
#define PROGRESS_ANALYZE_EXT_STATS_COMPUTED
Definition: progress.h:46
#define PROGRESS_ANALYZE_PHASE
Definition: progress.h:42
#define PROGRESS_ANALYZE_PHASE_COMPUTE_EXT_STATS
Definition: progress.h:56
#define PROGRESS_ANALYZE_EXT_STATS_TOTAL
Definition: progress.h:45
#define RelationGetRelid(relation)
Definition: rel.h:515
#define RelationGetRelationName(relation)
Definition: rel.h:549
int errtable(Relation rel)
Definition: relcache.c:6049
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 1207 of file extended_stats.c.

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

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

1286{
1287 Selectivity s1 = 1.0;
1288 ListCell *l;
1289 Bitmapset *clauses_attnums = NULL;
1290 AttrNumber *list_attnums;
1291 int listidx;
1292 MVDependencies **func_dependencies;
1293 int nfunc_dependencies;
1294 int total_ndeps;
1295 MVDependency **dependencies;
1296 int ndependencies;
1297 int i;
1298 AttrNumber attnum_offset;
1300
1301 /* unique expressions */
1302 Node **unique_exprs;
1303 int unique_exprs_cnt;
1304
1305 /* check if there's any stats that might be useful for us. */
1306 if (!has_stats_of_kind(rel->statlist, STATS_EXT_DEPENDENCIES))
1307 return 1.0;
1308
1309 list_attnums = (AttrNumber *) palloc(sizeof(AttrNumber) *
1310 list_length(clauses));
1311
1312 /*
1313 * We allocate space as if every clause was a unique expression, although
1314 * that's probably overkill. Some will be simple column references that
1315 * we'll translate to attnums, and there might be duplicates. But it's
1316 * easier and cheaper to just do one allocation than repalloc later.
1317 */
1318 unique_exprs = (Node **) palloc(sizeof(Node *) * list_length(clauses));
1319 unique_exprs_cnt = 0;
1320
1321 /*
1322 * Pre-process the clauses list to extract the attnums seen in each item.
1323 * We need to determine if there's any clauses which will be useful for
1324 * dependency selectivity estimations. Along the way we'll record all of
1325 * the attnums for each clause in a list which we'll reference later so we
1326 * don't need to repeat the same work again. We'll also keep track of all
1327 * attnums seen.
1328 *
1329 * We also skip clauses that we already estimated using different types of
1330 * statistics (we treat them as incompatible).
1331 *
1332 * To handle expressions, we assign them negative attnums, as if it was a
1333 * system attribute (this is fine, as we only allow extended stats on user
1334 * attributes). And then we offset everything by the number of
1335 * expressions, so that we can store the values in a bitmapset.
1336 */
1337 listidx = 0;
1338 foreach(l, clauses)
1339 {
1340 Node *clause = (Node *) lfirst(l);
1342 Node *expr = NULL;
1343
1344 /* ignore clause by default */
1345 list_attnums[listidx] = InvalidAttrNumber;
1346
1347 if (!bms_is_member(listidx, *estimatedclauses))
1348 {
1349 /*
1350 * If it's a simple column reference, just extract the attnum. If
1351 * it's an expression, assign a negative attnum as if it was a
1352 * system attribute.
1353 */
1354 if (dependency_is_compatible_clause(clause, rel->relid, &attnum))
1355 {
1356 list_attnums[listidx] = attnum;
1357 }
1358 else if (dependency_is_compatible_expression(clause, rel->relid,
1359 rel->statlist,
1360 &expr))
1361 {
1362 /* special attnum assigned to this expression */
1364
1365 Assert(expr != NULL);
1366
1367 /* If the expression is duplicate, use the same attnum. */
1368 for (i = 0; i < unique_exprs_cnt; i++)
1369 {
1370 if (equal(unique_exprs[i], expr))
1371 {
1372 /* negative attribute number to expression */
1373 attnum = -(i + 1);
1374 break;
1375 }
1376 }
1377
1378 /* not found in the list, so add it */
1380 {
1381 unique_exprs[unique_exprs_cnt++] = expr;
1382
1383 /* after incrementing the value, to get -1, -2, ... */
1384 attnum = (-unique_exprs_cnt);
1385 }
1386
1387 /* remember which attnum was assigned to this clause */
1388 list_attnums[listidx] = attnum;
1389 }
1390 }
1391
1392 listidx++;
1393 }
1394
1395 Assert(listidx == list_length(clauses));
1396
1397 /*
1398 * How much we need to offset the attnums? If there are no expressions,
1399 * then no offset is needed. Otherwise we need to offset enough for the
1400 * lowest value (-unique_exprs_cnt) to become 1.
1401 */
1402 if (unique_exprs_cnt > 0)
1403 attnum_offset = (unique_exprs_cnt + 1);
1404 else
1405 attnum_offset = 0;
1406
1407 /*
1408 * Now that we know how many expressions there are, we can offset the
1409 * values just enough to build the bitmapset.
1410 */
1411 for (i = 0; i < list_length(clauses); i++)
1412 {
1414
1415 /* ignore incompatible or already estimated clauses */
1416 if (list_attnums[i] == InvalidAttrNumber)
1417 continue;
1418
1419 /* make sure the attnum is in the expected range */
1420 Assert(list_attnums[i] >= (-unique_exprs_cnt));
1421 Assert(list_attnums[i] <= MaxHeapAttributeNumber);
1422
1423 /* make sure the attnum is positive (valid AttrNumber) */
1424 attnum = list_attnums[i] + attnum_offset;
1425
1426 /*
1427 * Either it's a regular attribute, or it's an expression, in which
1428 * case we must not have seen it before (expressions are unique).
1429 *
1430 * XXX Check whether it's a regular attribute has to be done using the
1431 * original attnum, while the second check has to use the value with
1432 * an offset.
1433 */
1434 Assert(AttrNumberIsForUserDefinedAttr(list_attnums[i]) ||
1435 !bms_is_member(attnum, clauses_attnums));
1436
1437 /*
1438 * Remember the offset attnum, both for attributes and expressions.
1439 * We'll pass list_attnums to clauselist_apply_dependencies, which
1440 * uses it to identify clauses in a bitmap. We could also pass the
1441 * offset, but this is more convenient.
1442 */
1443 list_attnums[i] = attnum;
1444
1445 clauses_attnums = bms_add_member(clauses_attnums, attnum);
1446 }
1447
1448 /*
1449 * If there's not at least two distinct attnums and expressions, then
1450 * reject the whole list of clauses. We must return 1.0 so the calling
1451 * function's selectivity is unaffected.
1452 */
1453 if (bms_membership(clauses_attnums) != BMS_MULTIPLE)
1454 {
1455 bms_free(clauses_attnums);
1456 pfree(list_attnums);
1457 return 1.0;
1458 }
1459
1460 /*
1461 * Load all functional dependencies matching at least two parameters. We
1462 * can simply consider all dependencies at once, without having to search
1463 * for the best statistics object.
1464 *
1465 * To not waste cycles and memory, we deserialize dependencies only for
1466 * statistics that match at least two attributes. The array is allocated
1467 * with the assumption that all objects match - we could grow the array to
1468 * make it just the right size, but it's likely wasteful anyway thanks to
1469 * moving the freed chunks to freelists etc.
1470 */
1471 func_dependencies = (MVDependencies **) palloc(sizeof(MVDependencies *) *
1472 list_length(rel->statlist));
1473 nfunc_dependencies = 0;
1474 total_ndeps = 0;
1475
1476 foreach(l, rel->statlist)
1477 {
1479 int nmatched;
1480 int nexprs;
1481 int k;
1482 MVDependencies *deps;
1483
1484 /* skip statistics that are not of the correct type */
1485 if (stat->kind != STATS_EXT_DEPENDENCIES)
1486 continue;
1487
1488 /* skip statistics with mismatching stxdinherit value */
1489 if (stat->inherit != rte->inh)
1490 continue;
1491
1492 /*
1493 * Count matching attributes - we have to undo the attnum offsets. The
1494 * input attribute numbers are not offset (expressions are not
1495 * included in stat->keys, so it's not necessary). But we need to
1496 * offset it before checking against clauses_attnums.
1497 */
1498 nmatched = 0;
1499 k = -1;
1500 while ((k = bms_next_member(stat->keys, k)) >= 0)
1501 {
1503
1504 /* skip expressions */
1506 continue;
1507
1508 /* apply the same offset as above */
1509 attnum += attnum_offset;
1510
1511 if (bms_is_member(attnum, clauses_attnums))
1512 nmatched++;
1513 }
1514
1515 /* count matching expressions */
1516 nexprs = 0;
1517 for (i = 0; i < unique_exprs_cnt; i++)
1518 {
1519 ListCell *lc;
1520
1521 foreach(lc, stat->exprs)
1522 {
1523 Node *stat_expr = (Node *) lfirst(lc);
1524
1525 /* try to match it */
1526 if (equal(stat_expr, unique_exprs[i]))
1527 nexprs++;
1528 }
1529 }
1530
1531 /*
1532 * Skip objects matching fewer than two attributes/expressions from
1533 * clauses.
1534 */
1535 if (nmatched + nexprs < 2)
1536 continue;
1537
1538 deps = statext_dependencies_load(stat->statOid, rte->inh);
1539
1540 /*
1541 * The expressions may be represented by different attnums in the
1542 * stats, we need to remap them to be consistent with the clauses.
1543 * That will make the later steps (e.g. picking the strongest item and
1544 * so on) much simpler and cheaper, because it won't need to care
1545 * about the offset at all.
1546 *
1547 * When we're at it, we can ignore dependencies that are not fully
1548 * matched by clauses (i.e. referencing attributes or expressions that
1549 * are not in the clauses).
1550 *
1551 * We have to do this for all statistics, as long as there are any
1552 * expressions - we need to shift the attnums in all dependencies.
1553 *
1554 * XXX Maybe we should do this always, because it also eliminates some
1555 * of the dependencies early. It might be cheaper than having to walk
1556 * the longer list in find_strongest_dependency later, especially as
1557 * we need to do that repeatedly?
1558 *
1559 * XXX We have to do this even when there are no expressions in
1560 * clauses, otherwise find_strongest_dependency may fail for stats
1561 * with expressions (due to lookup of negative value in bitmap). So we
1562 * need to at least filter out those dependencies. Maybe we could do
1563 * it in a cheaper way (if there are no expr clauses, we can just
1564 * discard all negative attnums without any lookups).
1565 */
1566 if (unique_exprs_cnt > 0 || stat->exprs != NIL)
1567 {
1568 int ndeps = 0;
1569
1570 for (i = 0; i < deps->ndeps; i++)
1571 {
1572 bool skip = false;
1573 MVDependency *dep = deps->deps[i];
1574 int j;
1575
1576 for (j = 0; j < dep->nattributes; j++)
1577 {
1578 int idx;
1579 Node *expr;
1580 AttrNumber unique_attnum = InvalidAttrNumber;
1582
1583 /* undo the per-statistics offset */
1584 attnum = dep->attributes[j];
1585
1586 /*
1587 * For regular attributes we can simply check if it
1588 * matches any clause. If there's no matching clause, we
1589 * can just ignore it. We need to offset the attnum
1590 * though.
1591 */
1593 {
1594 dep->attributes[j] = attnum + attnum_offset;
1595
1596 if (!bms_is_member(dep->attributes[j], clauses_attnums))
1597 {
1598 skip = true;
1599 break;
1600 }
1601
1602 continue;
1603 }
1604
1605 /*
1606 * the attnum should be a valid system attnum (-1, -2,
1607 * ...)
1608 */
1610
1611 /*
1612 * For expressions, we need to do two translations. First
1613 * we have to translate the negative attnum to index in
1614 * the list of expressions (in the statistics object).
1615 * Then we need to see if there's a matching clause. The
1616 * index of the unique expression determines the attnum
1617 * (and we offset it).
1618 */
1619 idx = -(1 + attnum);
1620
1621 /* Is the expression index is valid? */
1622 Assert((idx >= 0) && (idx < list_length(stat->exprs)));
1623
1624 expr = (Node *) list_nth(stat->exprs, idx);
1625
1626 /* try to find the expression in the unique list */
1627 for (int m = 0; m < unique_exprs_cnt; m++)
1628 {
1629 /*
1630 * found a matching unique expression, use the attnum
1631 * (derived from index of the unique expression)
1632 */
1633 if (equal(unique_exprs[m], expr))
1634 {
1635 unique_attnum = -(m + 1) + attnum_offset;
1636 break;
1637 }
1638 }
1639
1640 /*
1641 * Found no matching expression, so we can simply skip
1642 * this dependency, because there's no chance it will be
1643 * fully covered.
1644 */
1645 if (unique_attnum == InvalidAttrNumber)
1646 {
1647 skip = true;
1648 break;
1649 }
1650
1651 /* otherwise remap it to the new attnum */
1652 dep->attributes[j] = unique_attnum;
1653 }
1654
1655 /* if found a matching dependency, keep it */
1656 if (!skip)
1657 {
1658 /* maybe we've skipped something earlier, so move it */
1659 if (ndeps != i)
1660 deps->deps[ndeps] = deps->deps[i];
1661
1662 ndeps++;
1663 }
1664 }
1665
1666 deps->ndeps = ndeps;
1667 }
1668
1669 /*
1670 * It's possible we've removed all dependencies, in which case we
1671 * don't bother adding it to the list.
1672 */
1673 if (deps->ndeps > 0)
1674 {
1675 func_dependencies[nfunc_dependencies] = deps;
1676 total_ndeps += deps->ndeps;
1677 nfunc_dependencies++;
1678 }
1679 }
1680
1681 /* if no matching stats could be found then we've nothing to do */
1682 if (nfunc_dependencies == 0)
1683 {
1684 pfree(func_dependencies);
1685 bms_free(clauses_attnums);
1686 pfree(list_attnums);
1687 pfree(unique_exprs);
1688 return 1.0;
1689 }
1690
1691 /*
1692 * Work out which dependencies we can apply, starting with the
1693 * widest/strongest ones, and proceeding to smaller/weaker ones.
1694 */
1695 dependencies = (MVDependency **) palloc(sizeof(MVDependency *) *
1696 total_ndeps);
1697 ndependencies = 0;
1698
1699 while (true)
1700 {
1701 MVDependency *dependency;
1703
1704 /* the widest/strongest dependency, fully matched by clauses */
1705 dependency = find_strongest_dependency(func_dependencies,
1706 nfunc_dependencies,
1707 clauses_attnums);
1708 if (!dependency)
1709 break;
1710
1711 dependencies[ndependencies++] = dependency;
1712
1713 /* Ignore dependencies using this implied attribute in later loops */
1714 attnum = dependency->attributes[dependency->nattributes - 1];
1715 clauses_attnums = bms_del_member(clauses_attnums, attnum);
1716 }
1717
1718 /*
1719 * If we found applicable dependencies, use them to estimate all
1720 * compatible clauses on attributes that they refer to.
1721 */
1722 if (ndependencies != 0)
1723 s1 = clauselist_apply_dependencies(root, clauses, varRelid, jointype,
1724 sjinfo, dependencies, ndependencies,
1725 list_attnums, estimatedclauses);
1726
1727 /* free deserialized functional dependencies (and then the array) */
1728 for (i = 0; i < nfunc_dependencies; i++)
1729 pfree(func_dependencies[i]);
1730
1731 pfree(dependencies);
1732 pfree(func_dependencies);
1733 bms_free(clauses_attnums);
1734 pfree(list_attnums);
1735 pfree(unique_exprs);
1736
1737 return s1;
1738}
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:262
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
MVDependencies * statext_dependencies_load(Oid mvoid, bool inh)
Definition: dependencies.c:613
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:650
static Selectivity clauselist_apply_dependencies(PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, MVDependency **dependencies, int ndependencies, AttrNumber *list_attnums, Bitmapset **estimatedclauses)
Definition: dependencies.c:923
static MVDependency * find_strongest_dependency(MVDependencies **dependencies, int ndependencies, Bitmapset *attnums)
Definition: dependencies.c:838
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
bool has_stats_of_kind(List *stats, char requiredkind)
Assert(PointerIsAligned(start, uint64))
#define MaxHeapAttributeNumber
Definition: htup_details.h:48
int j
Definition: isn.c:78
void pfree(void *pointer)
Definition: mcxt.c:1594
void * palloc(Size size)
Definition: mcxt.c:1365
double Selectivity
Definition: nodes.h:260
#define planner_rt_fetch(rti, root)
Definition: pathnodes.h:610
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
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:135
Index relid
Definition: pathnodes.h:973
List * statlist
Definition: pathnodes.h:997

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

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

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

1986{
1987 Selectivity sel;
1988
1989 /* First, try estimating clauses using a multivariate MCV list. */
1990 sel = statext_mcv_clauselist_selectivity(root, clauses, varRelid, jointype,
1991 sjinfo, rel, estimatedclauses, is_or);
1992
1993 /*
1994 * Functional dependencies only work for clauses connected by AND, so for
1995 * OR clauses we're done.
1996 */
1997 if (is_or)
1998 return sel;
1999
2000 /*
2001 * Then, apply functional dependencies on the remaining clauses by calling
2002 * dependencies_clauselist_selectivity. Pass 'estimatedclauses' so the
2003 * function can properly skip clauses already estimated above.
2004 *
2005 * The reasoning for applying dependencies last is that the more complex
2006 * stats can track more complex correlations between the attributes, and
2007 * so may be considered more reliable.
2008 *
2009 * For example, MCV list can give us an exact selectivity for values in
2010 * two columns, while functional dependencies can only provide information
2011 * about the overall strength of the dependency.
2012 */
2013 sel *= dependencies_clauselist_selectivity(root, clauses, varRelid,
2014 jointype, sjinfo, rel,
2015 estimatedclauses);
2016
2017 return sel;
2018}
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 613 of file dependencies.c.

614{
615 MVDependencies *result;
616 bool isnull;
617 Datum deps;
618 HeapTuple htup;
619
620 htup = SearchSysCache2(STATEXTDATASTXOID,
621 ObjectIdGetDatum(mvoid),
622 BoolGetDatum(inh));
623 if (!HeapTupleIsValid(htup))
624 elog(ERROR, "cache lookup failed for statistics object %u", mvoid);
625
626 deps = SysCacheGetAttr(STATEXTDATASTXOID, htup,
627 Anum_pg_statistic_ext_data_stxddependencies, &isnull);
628 if (isnull)
629 elog(ERROR,
630 "requested statistics kind \"%c\" is not yet built for statistics object %u",
631 STATS_EXT_DEPENDENCIES, mvoid);
632
634
635 ReleaseSysCache(htup);
636
637 return result;
638}
MVDependencies * statext_dependencies_deserialize(bytea *data)
Definition: dependencies.c:493
#define DatumGetByteaPP(X)
Definition: fmgr.h:291
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static Datum BoolGetDatum(bool X)
Definition: postgres.h:112
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:264
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:595
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:230

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

2403{
2404 bool isnull;
2405 Datum value;
2406 HeapTuple htup;
2408 HeapTupleHeader td;
2409 HeapTupleData tmptup;
2410 HeapTuple tup;
2411
2412 htup = SearchSysCache2(STATEXTDATASTXOID,
2413 ObjectIdGetDatum(stxoid), BoolGetDatum(inh));
2414 if (!HeapTupleIsValid(htup))
2415 elog(ERROR, "cache lookup failed for statistics object %u", stxoid);
2416
2417 value = SysCacheGetAttr(STATEXTDATASTXOID, htup,
2418 Anum_pg_statistic_ext_data_stxdexpr, &isnull);
2419 if (isnull)
2420 elog(ERROR,
2421 "requested statistics kind \"%c\" is not yet built for statistics object %u",
2422 STATS_EXT_EXPRESSIONS, stxoid);
2423
2425
2427
2429
2430 /* Build a temporary HeapTuple control structure */
2432 ItemPointerSetInvalid(&(tmptup.t_self));
2433 tmptup.t_tableOid = InvalidOid;
2434 tmptup.t_data = td;
2435
2436 tup = heap_copytuple(&tmptup);
2437
2438 ReleaseSysCache(htup);
2439
2440 return tup;
2441}
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
static uint32 HeapTupleHeaderGetDatumLength(const HeapTupleHeaderData *tup)
Definition: htup_details.h:492
static struct @171 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 145 of file mvdistinct.c.

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

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

Referenced by estimate_multivariate_ndistinct().