PostgreSQL Source Code git master
statscmds.c File Reference
#include "postgres.h"
#include "access/relation.h"
#include "access/table.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_statistic_ext.h"
#include "catalog/pg_statistic_ext_data.h"
#include "commands/comment.h"
#include "commands/defrem.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "statistics/statistics.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
Include dependency graph for statscmds.c:

Go to the source code of this file.

Functions

static char * ChooseExtendedStatisticName (const char *name1, const char *name2, const char *label, Oid namespaceid)
 
static char * ChooseExtendedStatisticNameAddition (List *exprs)
 
static int compare_int16 (const void *a, const void *b)
 
ObjectAddress CreateStatistics (CreateStatsStmt *stmt)
 
ObjectAddress AlterStatistics (AlterStatsStmt *stmt)
 
void RemoveStatisticsDataById (Oid statsOid, bool inh)
 
void RemoveStatisticsById (Oid statsOid)
 
Oid StatisticsGetRelation (Oid statId, bool missing_ok)
 

Function Documentation

◆ AlterStatistics()

ObjectAddress AlterStatistics ( AlterStatsStmt stmt)

Definition at line 599 of file statscmds.c.

600{
601 Relation rel;
602 Oid stxoid;
603 HeapTuple oldtup;
604 HeapTuple newtup;
605 Datum repl_val[Natts_pg_statistic_ext];
606 bool repl_null[Natts_pg_statistic_ext];
607 bool repl_repl[Natts_pg_statistic_ext];
608 ObjectAddress address;
609 int newtarget = 0;
610 bool newtarget_default;
611
612 /* -1 was used in previous versions for the default setting */
613 if (stmt->stxstattarget && intVal(stmt->stxstattarget) != -1)
614 {
615 newtarget = intVal(stmt->stxstattarget);
616 newtarget_default = false;
617 }
618 else
619 newtarget_default = true;
620
621 if (!newtarget_default)
622 {
623 /* Limit statistics target to a sane range */
624 if (newtarget < 0)
625 {
627 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
628 errmsg("statistics target %d is too low",
629 newtarget)));
630 }
631 else if (newtarget > MAX_STATISTICS_TARGET)
632 {
633 newtarget = MAX_STATISTICS_TARGET;
635 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
636 errmsg("lowering statistics target to %d",
637 newtarget)));
638 }
639 }
640
641 /* lookup OID of the statistics object */
642 stxoid = get_statistics_object_oid(stmt->defnames, stmt->missing_ok);
643
644 /*
645 * If we got here and the OID is not valid, it means the statistics object
646 * does not exist, but the command specified IF EXISTS. So report this as
647 * a simple NOTICE and we're done.
648 */
649 if (!OidIsValid(stxoid))
650 {
651 char *schemaname;
652 char *statname;
653
654 Assert(stmt->missing_ok);
655
656 DeconstructQualifiedName(stmt->defnames, &schemaname, &statname);
657
658 if (schemaname)
660 (errmsg("statistics object \"%s.%s\" does not exist, skipping",
661 schemaname, statname)));
662 else
664 (errmsg("statistics object \"%s\" does not exist, skipping",
665 statname)));
666
668 }
669
670 /* Search pg_statistic_ext */
671 rel = table_open(StatisticExtRelationId, RowExclusiveLock);
672
673 oldtup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(stxoid));
674 if (!HeapTupleIsValid(oldtup))
675 elog(ERROR, "cache lookup failed for extended statistics object %u", stxoid);
676
677 /* Must be owner of the existing statistics object */
678 if (!object_ownercheck(StatisticExtRelationId, stxoid, GetUserId()))
680 NameListToString(stmt->defnames));
681
682 /* Build new tuple. */
683 memset(repl_val, 0, sizeof(repl_val));
684 memset(repl_null, false, sizeof(repl_null));
685 memset(repl_repl, false, sizeof(repl_repl));
686
687 /* replace the stxstattarget column */
688 repl_repl[Anum_pg_statistic_ext_stxstattarget - 1] = true;
689 if (!newtarget_default)
690 repl_val[Anum_pg_statistic_ext_stxstattarget - 1] = Int16GetDatum(newtarget);
691 else
692 repl_null[Anum_pg_statistic_ext_stxstattarget - 1] = true;
693
694 newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
695 repl_val, repl_null, repl_repl);
696
697 /* Update system catalog. */
698 CatalogTupleUpdate(rel, &newtup->t_self, newtup);
699
700 InvokeObjectPostAlterHook(StatisticExtRelationId, stxoid, 0);
701
702 ObjectAddressSet(address, StatisticExtRelationId, stxoid);
703
704 /*
705 * NOTE: because we only support altering the statistics target, not the
706 * other fields, there is no need to update dependencies.
707 */
708
709 heap_freetuple(newtup);
710 ReleaseSysCache(oldtup);
711
713
714 return address;
715}
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2622
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4058
#define Assert(condition)
Definition: c.h:815
#define OidIsValid(objectId)
Definition: c.h:732
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 NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:149
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1210
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define stmt
Definition: indent_codes.h:59
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
#define RowExclusiveLock
Definition: lockdefs.h:38
Oid GetUserId(void)
Definition: miscinit.c:517
char * NameListToString(const List *names)
Definition: namespace.c:3594
Oid get_statistics_object_oid(List *names, bool missing_ok)
Definition: namespace.c:2575
void DeconstructQualifiedName(const List *names, char **nspname_p, char **objname_p)
Definition: namespace.c:3301
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
const ObjectAddress InvalidObjectAddress
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
@ OBJECT_STATISTIC_EXT
Definition: parsenodes.h:2351
uintptr_t Datum
Definition: postgres.h:69
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:177
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
unsigned int Oid
Definition: postgres_ext.h:32
#define RelationGetDescr(relation)
Definition: rel.h:531
ItemPointerData t_self
Definition: htup.h:65
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
#define MAX_STATISTICS_TARGET
Definition: vacuum.h:305
#define intVal(v)
Definition: value.h:79

References aclcheck_error(), ACLCHECK_NOT_OWNER, Assert, CatalogTupleUpdate(), DeconstructQualifiedName(), elog, ereport, errcode(), errmsg(), ERROR, get_statistics_object_oid(), GetUserId(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, Int16GetDatum(), intVal, InvalidObjectAddress, InvokeObjectPostAlterHook, MAX_STATISTICS_TARGET, NameListToString(), NOTICE, object_ownercheck(), OBJECT_STATISTIC_EXT, ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), stmt, HeapTupleData::t_self, table_close(), table_open(), and WARNING.

Referenced by ProcessUtilitySlow().

◆ ChooseExtendedStatisticName()

static char * ChooseExtendedStatisticName ( const char *  name1,
const char *  name2,
const char *  label,
Oid  namespaceid 
)
static

Definition at line 809 of file statscmds.c.

811{
812 int pass = 0;
813 char *stxname = NULL;
814 char modlabel[NAMEDATALEN];
815
816 /* try the unmodified label first */
817 strlcpy(modlabel, label, sizeof(modlabel));
818
819 for (;;)
820 {
821 Oid existingstats;
822
823 stxname = makeObjectName(name1, name2, modlabel);
824
825 existingstats = GetSysCacheOid2(STATEXTNAMENSP, Anum_pg_statistic_ext_oid,
826 PointerGetDatum(stxname),
827 ObjectIdGetDatum(namespaceid));
828 if (!OidIsValid(existingstats))
829 break;
830
831 /* found a conflict, so try a new name component */
832 pfree(stxname);
833 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
834 }
835
836 return stxname;
837}
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition: indexcmds.c:2527
void pfree(void *pointer)
Definition: mcxt.c:1521
static char * label
#define NAMEDATALEN
#define snprintf
Definition: port.h:238
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:111

References GetSysCacheOid2, label, makeObjectName(), NAMEDATALEN, ObjectIdGetDatum(), OidIsValid, pfree(), PointerGetDatum(), snprintf, and strlcpy().

Referenced by CreateStatistics().

◆ ChooseExtendedStatisticNameAddition()

static char * ChooseExtendedStatisticNameAddition ( List exprs)
static

Definition at line 851 of file statscmds.c.

852{
853 char buf[NAMEDATALEN * 2];
854 int buflen = 0;
855 ListCell *lc;
856
857 buf[0] = '\0';
858 foreach(lc, exprs)
859 {
860 StatsElem *selem = (StatsElem *) lfirst(lc);
861 const char *name;
862
863 /* It should be one of these, but just skip if it happens not to be */
864 if (!IsA(selem, StatsElem))
865 continue;
866
867 name = selem->name;
868
869 if (buflen > 0)
870 buf[buflen++] = '_'; /* insert _ between names */
871
872 /*
873 * We use fixed 'expr' for expressions, which have empty column names.
874 * For indexes this is handled in ChooseIndexColumnNames, but we have
875 * no such function for stats and it does not seem worth adding. If a
876 * better name is needed, the user can specify it explicitly.
877 */
878 if (!name)
879 name = "expr";
880
881 /*
882 * At this point we have buflen <= NAMEDATALEN. name should be less
883 * than NAMEDATALEN already, but use strlcpy for paranoia.
884 */
885 strlcpy(buf + buflen, name, NAMEDATALEN);
886 buflen += strlen(buf + buflen);
887 if (buflen >= NAMEDATALEN)
888 break;
889 }
890 return pstrdup(buf);
891}
char * pstrdup(const char *in)
Definition: mcxt.c:1696
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define lfirst(lc)
Definition: pg_list.h:172
static char * buf
Definition: pg_test_fsync.c:72
char * name
Definition: parsenodes.h:3480
const char * name

References buf, IsA, lfirst, name, StatsElem::name, NAMEDATALEN, pstrdup(), and strlcpy().

Referenced by CreateStatistics().

◆ compare_int16()

static int compare_int16 ( const void *  a,
const void *  b 
)
static

Definition at line 49 of file statscmds.c.

50{
51 int av = *(const int16 *) a;
52 int bv = *(const int16 *) b;
53
54 /* this can't overflow if int is wider than int16 */
55 return (av - bv);
56}
int16_t int16
Definition: c.h:483
int b
Definition: isn.c:69
int a
Definition: isn.c:68
struct @10::@11 av[32]

References a, av, and b.

Referenced by CreateStatistics().

◆ CreateStatistics()

ObjectAddress CreateStatistics ( CreateStatsStmt stmt)

Definition at line 62 of file statscmds.c.

63{
65 int nattnums = 0;
66 int numcols;
67 char *namestr;
68 NameData stxname;
69 Oid statoid;
70 Oid namespaceId;
71 Oid stxowner = GetUserId();
72 HeapTuple htup;
73 Datum values[Natts_pg_statistic_ext];
74 bool nulls[Natts_pg_statistic_ext];
75 int2vector *stxkeys;
76 List *stxexprs = NIL;
77 Datum exprsDatum;
78 Relation statrel;
79 Relation rel = NULL;
80 Oid relid;
81 ObjectAddress parentobject,
82 myself;
83 Datum types[4]; /* one for each possible type of statistic */
84 int ntypes;
85 ArrayType *stxkind;
86 bool build_ndistinct;
87 bool build_dependencies;
88 bool build_mcv;
89 bool build_expressions;
90 bool requested_type = false;
91 int i;
92 ListCell *cell;
93 ListCell *cell2;
94
96
97 /*
98 * Examine the FROM clause. Currently, we only allow it to be a single
99 * simple table, but later we'll probably allow multiple tables and JOIN
100 * syntax. The grammar is already prepared for that, so we have to check
101 * here that what we got is what we can support.
102 */
103 if (list_length(stmt->relations) != 1)
105 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
106 errmsg("only a single relation is allowed in CREATE STATISTICS")));
107
108 foreach(cell, stmt->relations)
109 {
110 Node *rln = (Node *) lfirst(cell);
111
112 if (!IsA(rln, RangeVar))
114 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
115 errmsg("only a single relation is allowed in CREATE STATISTICS")));
116
117 /*
118 * CREATE STATISTICS will influence future execution plans but does
119 * not interfere with currently executing plans. So it should be
120 * enough to take only ShareUpdateExclusiveLock on relation,
121 * conflicting with ANALYZE and other DDL that sets statistical
122 * information, but not with normal queries.
123 */
125
126 /* Restrict to allowed relation types */
127 if (rel->rd_rel->relkind != RELKIND_RELATION &&
128 rel->rd_rel->relkind != RELKIND_MATVIEW &&
129 rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
130 rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
132 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
133 errmsg("cannot define statistics for relation \"%s\"",
136
137 /* You must own the relation to create stats on it */
138 if (!object_ownercheck(RelationRelationId, RelationGetRelid(rel), stxowner))
141
142 /* Creating statistics on system catalogs is not allowed */
145 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
146 errmsg("permission denied: \"%s\" is a system catalog",
148 }
149
150 Assert(rel);
151 relid = RelationGetRelid(rel);
152
153 /*
154 * If the node has a name, split it up and determine creation namespace.
155 * If not, put the object in the same namespace as the relation, and cons
156 * up a name for it. (This can happen either via "CREATE STATISTICS ..."
157 * or via "CREATE TABLE ... (LIKE)".)
158 */
159 if (stmt->defnames)
160 namespaceId = QualifiedNameGetCreationNamespace(stmt->defnames,
161 &namestr);
162 else
163 {
164 namespaceId = RelationGetNamespace(rel);
167 "stat",
168 namespaceId);
169 }
170 namestrcpy(&stxname, namestr);
171
172 /*
173 * Deal with the possibility that the statistics object already exists.
174 */
175 if (SearchSysCacheExists2(STATEXTNAMENSP,
176 CStringGetDatum(namestr),
177 ObjectIdGetDatum(namespaceId)))
178 {
179 if (stmt->if_not_exists)
180 {
181 /*
182 * Since stats objects aren't members of extensions (see comments
183 * below), no need for checkMembershipInCurrentExtension here.
184 */
187 errmsg("statistics object \"%s\" already exists, skipping",
188 namestr)));
191 }
192
195 errmsg("statistics object \"%s\" already exists", namestr)));
196 }
197
198 /*
199 * Make sure no more than STATS_MAX_DIMENSIONS columns are used. There
200 * might be duplicates and so on, but we'll deal with those later.
201 */
202 numcols = list_length(stmt->exprs);
203 if (numcols > STATS_MAX_DIMENSIONS)
205 (errcode(ERRCODE_TOO_MANY_COLUMNS),
206 errmsg("cannot have more than %d columns in statistics",
208
209 /*
210 * Convert the expression list to a simple array of attnums, but also keep
211 * a list of more complex expressions. While at it, enforce some
212 * constraints - we don't allow extended statistics on system attributes,
213 * and we require the data type to have a less-than operator.
214 *
215 * There are many ways to "mask" a simple attribute reference as an
216 * expression, for example "(a+0)" etc. We can't possibly detect all of
217 * them, but we handle at least the simple case with the attribute in
218 * parens. There'll always be a way around this, if the user is determined
219 * (like the "(a+0)" example), but this makes it somewhat consistent with
220 * how indexes treat attributes/expressions.
221 */
222 foreach(cell, stmt->exprs)
223 {
224 StatsElem *selem = lfirst_node(StatsElem, cell);
225
226 if (selem->name) /* column reference */
227 {
228 char *attname;
229 HeapTuple atttuple;
230 Form_pg_attribute attForm;
232
233 attname = selem->name;
234
235 atttuple = SearchSysCacheAttName(relid, attname);
236 if (!HeapTupleIsValid(atttuple))
238 (errcode(ERRCODE_UNDEFINED_COLUMN),
239 errmsg("column \"%s\" does not exist",
240 attname)));
241 attForm = (Form_pg_attribute) GETSTRUCT(atttuple);
242
243 /* Disallow use of system attributes in extended stats */
244 if (attForm->attnum <= 0)
246 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
247 errmsg("statistics creation on system columns is not supported")));
248
249 /* Disallow data types without a less-than operator */
250 type = lookup_type_cache(attForm->atttypid, TYPECACHE_LT_OPR);
251 if (type->lt_opr == InvalidOid)
253 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
254 errmsg("column \"%s\" cannot be used in statistics because its type %s has no default btree operator class",
255 attname, format_type_be(attForm->atttypid))));
256
257 attnums[nattnums] = attForm->attnum;
258 nattnums++;
259 ReleaseSysCache(atttuple);
260 }
261 else if (IsA(selem->expr, Var)) /* column reference in parens */
262 {
263 Var *var = (Var *) selem->expr;
265
266 /* Disallow use of system attributes in extended stats */
267 if (var->varattno <= 0)
269 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
270 errmsg("statistics creation on system columns is not supported")));
271
272 /* Disallow data types without a less-than operator */
273 type = lookup_type_cache(var->vartype, TYPECACHE_LT_OPR);
274 if (type->lt_opr == InvalidOid)
276 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
277 errmsg("column \"%s\" cannot be used in statistics because its type %s has no default btree operator class",
278 get_attname(relid, var->varattno, false), format_type_be(var->vartype))));
279
280 attnums[nattnums] = var->varattno;
281 nattnums++;
282 }
283 else /* expression */
284 {
285 Node *expr = selem->expr;
286 Oid atttype;
288 Bitmapset *attnums = NULL;
289 int k;
290
291 Assert(expr != NULL);
292
293 /* Disallow expressions referencing system attributes. */
294 pull_varattnos(expr, 1, &attnums);
295
296 k = -1;
297 while ((k = bms_next_member(attnums, k)) >= 0)
298 {
300
301 if (attnum <= 0)
303 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
304 errmsg("statistics creation on system columns is not supported")));
305 }
306
307 /*
308 * Disallow data types without a less-than operator.
309 *
310 * We ignore this for statistics on a single expression, in which
311 * case we'll build the regular statistics only (and that code can
312 * deal with such data types).
313 */
314 if (list_length(stmt->exprs) > 1)
315 {
316 atttype = exprType(expr);
318 if (type->lt_opr == InvalidOid)
320 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
321 errmsg("expression cannot be used in multivariate statistics because its type %s has no default btree operator class",
322 format_type_be(atttype))));
323 }
324
325 stxexprs = lappend(stxexprs, expr);
326 }
327 }
328
329 /*
330 * Parse the statistics kinds.
331 *
332 * First check that if this is the case with a single expression, there
333 * are no statistics kinds specified (we don't allow that for the simple
334 * CREATE STATISTICS form).
335 */
336 if ((list_length(stmt->exprs) == 1) && (list_length(stxexprs) == 1))
337 {
338 /* statistics kinds not specified */
339 if (stmt->stat_types != NIL)
341 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
342 errmsg("when building statistics on a single expression, statistics kinds may not be specified")));
343 }
344
345 /* OK, let's check that we recognize the statistics kinds. */
346 build_ndistinct = false;
347 build_dependencies = false;
348 build_mcv = false;
349 foreach(cell, stmt->stat_types)
350 {
351 char *type = strVal(lfirst(cell));
352
353 if (strcmp(type, "ndistinct") == 0)
354 {
355 build_ndistinct = true;
356 requested_type = true;
357 }
358 else if (strcmp(type, "dependencies") == 0)
359 {
360 build_dependencies = true;
361 requested_type = true;
362 }
363 else if (strcmp(type, "mcv") == 0)
364 {
365 build_mcv = true;
366 requested_type = true;
367 }
368 else
370 (errcode(ERRCODE_SYNTAX_ERROR),
371 errmsg("unrecognized statistics kind \"%s\"",
372 type)));
373 }
374
375 /*
376 * If no statistic type was specified, build them all (but only when the
377 * statistics is defined on more than one column/expression).
378 */
379 if ((!requested_type) && (numcols >= 2))
380 {
381 build_ndistinct = true;
382 build_dependencies = true;
383 build_mcv = true;
384 }
385
386 /*
387 * When there are non-trivial expressions, build the expression stats
388 * automatically. This allows calculating good estimates for stats that
389 * consider per-clause estimates (e.g. functional dependencies).
390 */
391 build_expressions = (stxexprs != NIL);
392
393 /*
394 * Check that at least two columns were specified in the statement, or
395 * that we're building statistics on a single expression.
396 */
397 if ((numcols < 2) && (list_length(stxexprs) != 1))
399 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
400 errmsg("extended statistics require at least 2 columns")));
401
402 /*
403 * Sort the attnums, which makes detecting duplicates somewhat easier, and
404 * it does not hurt (it does not matter for the contents, unlike for
405 * indexes, for example).
406 */
407 qsort(attnums, nattnums, sizeof(int16), compare_int16);
408
409 /*
410 * Check for duplicates in the list of columns. The attnums are sorted so
411 * just check consecutive elements.
412 */
413 for (i = 1; i < nattnums; i++)
414 {
415 if (attnums[i] == attnums[i - 1])
417 (errcode(ERRCODE_DUPLICATE_COLUMN),
418 errmsg("duplicate column name in statistics definition")));
419 }
420
421 /*
422 * Check for duplicate expressions. We do two loops, counting the
423 * occurrences of each expression. This is O(N^2) but we only allow small
424 * number of expressions and it's not executed often.
425 *
426 * XXX We don't cross-check attributes and expressions, because it does
427 * not seem worth it. In principle we could check that expressions don't
428 * contain trivial attribute references like "(a)", but the reasoning is
429 * similar to why we don't bother with extracting columns from
430 * expressions. It's either expensive or very easy to defeat for
431 * determined user, and there's no risk if we allow such statistics (the
432 * statistics is useless, but harmless).
433 */
434 foreach(cell, stxexprs)
435 {
436 Node *expr1 = (Node *) lfirst(cell);
437 int cnt = 0;
438
439 foreach(cell2, stxexprs)
440 {
441 Node *expr2 = (Node *) lfirst(cell2);
442
443 if (equal(expr1, expr2))
444 cnt += 1;
445 }
446
447 /* every expression should find at least itself */
448 Assert(cnt >= 1);
449
450 if (cnt > 1)
452 (errcode(ERRCODE_DUPLICATE_COLUMN),
453 errmsg("duplicate expression in statistics definition")));
454 }
455
456 /* Form an int2vector representation of the sorted column list */
457 stxkeys = buildint2vector(attnums, nattnums);
458
459 /* construct the char array of enabled statistic types */
460 ntypes = 0;
461 if (build_ndistinct)
462 types[ntypes++] = CharGetDatum(STATS_EXT_NDISTINCT);
463 if (build_dependencies)
464 types[ntypes++] = CharGetDatum(STATS_EXT_DEPENDENCIES);
465 if (build_mcv)
466 types[ntypes++] = CharGetDatum(STATS_EXT_MCV);
467 if (build_expressions)
468 types[ntypes++] = CharGetDatum(STATS_EXT_EXPRESSIONS);
469 Assert(ntypes > 0 && ntypes <= lengthof(types));
470 stxkind = construct_array_builtin(types, ntypes, CHAROID);
471
472 /* convert the expressions (if any) to a text datum */
473 if (stxexprs != NIL)
474 {
475 char *exprsString;
476
477 exprsString = nodeToString(stxexprs);
478 exprsDatum = CStringGetTextDatum(exprsString);
479 pfree(exprsString);
480 }
481 else
482 exprsDatum = (Datum) 0;
483
484 statrel = table_open(StatisticExtRelationId, RowExclusiveLock);
485
486 /*
487 * Everything seems fine, so let's build the pg_statistic_ext tuple.
488 */
489 memset(values, 0, sizeof(values));
490 memset(nulls, false, sizeof(nulls));
491
492 statoid = GetNewOidWithIndex(statrel, StatisticExtOidIndexId,
493 Anum_pg_statistic_ext_oid);
494 values[Anum_pg_statistic_ext_oid - 1] = ObjectIdGetDatum(statoid);
495 values[Anum_pg_statistic_ext_stxrelid - 1] = ObjectIdGetDatum(relid);
496 values[Anum_pg_statistic_ext_stxname - 1] = NameGetDatum(&stxname);
497 values[Anum_pg_statistic_ext_stxnamespace - 1] = ObjectIdGetDatum(namespaceId);
498 values[Anum_pg_statistic_ext_stxowner - 1] = ObjectIdGetDatum(stxowner);
499 values[Anum_pg_statistic_ext_stxkeys - 1] = PointerGetDatum(stxkeys);
500 nulls[Anum_pg_statistic_ext_stxstattarget - 1] = true;
501 values[Anum_pg_statistic_ext_stxkind - 1] = PointerGetDatum(stxkind);
502
503 values[Anum_pg_statistic_ext_stxexprs - 1] = exprsDatum;
504 if (exprsDatum == (Datum) 0)
505 nulls[Anum_pg_statistic_ext_stxexprs - 1] = true;
506
507 /* insert it into pg_statistic_ext */
508 htup = heap_form_tuple(statrel->rd_att, values, nulls);
509 CatalogTupleInsert(statrel, htup);
510 heap_freetuple(htup);
511
513
514 /*
515 * We used to create the pg_statistic_ext_data tuple too, but it's not
516 * clear what value should the stxdinherit flag have (it depends on
517 * whether the rel is partitioned, contains data, etc.)
518 */
519
520 InvokeObjectPostCreateHook(StatisticExtRelationId, statoid, 0);
521
522 /*
523 * Invalidate relcache so that others see the new statistics object.
524 */
526
528
529 /*
530 * Add an AUTO dependency on each column used in the stats, so that the
531 * stats object goes away if any or all of them get dropped.
532 */
533 ObjectAddressSet(myself, StatisticExtRelationId, statoid);
534
535 /* add dependencies for plain column references */
536 for (i = 0; i < nattnums; i++)
537 {
538 ObjectAddressSubSet(parentobject, RelationRelationId, relid, attnums[i]);
539 recordDependencyOn(&myself, &parentobject, DEPENDENCY_AUTO);
540 }
541
542 /*
543 * If there are no dependencies on a column, give the statistics object an
544 * auto dependency on the whole table. In most cases, this will be
545 * redundant, but it might not be if the statistics expressions contain no
546 * Vars (which might seem strange but possible). This is consistent with
547 * what we do for indexes in index_create.
548 *
549 * XXX We intentionally don't consider the expressions before adding this
550 * dependency, because recordDependencyOnSingleRelExpr may not create any
551 * dependencies for whole-row Vars.
552 */
553 if (!nattnums)
554 {
555 ObjectAddressSet(parentobject, RelationRelationId, relid);
556 recordDependencyOn(&myself, &parentobject, DEPENDENCY_AUTO);
557 }
558
559 /*
560 * Store dependencies on anything mentioned in statistics expressions,
561 * just like we do for index expressions.
562 */
563 if (stxexprs)
565 (Node *) stxexprs,
566 relid,
568 DEPENDENCY_AUTO, false);
569
570 /*
571 * Also add dependencies on namespace and owner. These are required
572 * because the stats object might have a different namespace and/or owner
573 * than the underlying table(s).
574 */
575 ObjectAddressSet(parentobject, NamespaceRelationId, namespaceId);
576 recordDependencyOn(&myself, &parentobject, DEPENDENCY_NORMAL);
577
578 recordDependencyOnOwner(StatisticExtRelationId, statoid, stxowner);
579
580 /*
581 * XXX probably there should be a recordDependencyOnCurrentExtension call
582 * here too, but we'd have to add support for ALTER EXTENSION ADD/DROP
583 * STATISTICS, which is more work than it seems worth.
584 */
585
586 /* Add any requested comment */
587 if (stmt->stxcomment != NULL)
588 CreateComments(statoid, StatisticExtRelationId, 0,
589 stmt->stxcomment);
590
591 /* Return stats object's address */
592 return myself;
593}
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
Definition: arrayfuncs.c:3381
int16 AttrNumber
Definition: attnum.h:21
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define lengthof(array)
Definition: c.h:745
bool IsSystemRelation(Relation relation)
Definition: catalog.c:73
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:419
void CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment)
Definition: comment.c:143
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
Definition: dependency.c:1596
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
struct typedefs * types
Definition: ecpg.c:30
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
bool allowSystemTableMods
Definition: globals.c:129
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
int2vector * buildint2vector(const int16 *int2s, int n)
Definition: int.c:114
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1553
int i
Definition: isn.c:72
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
List * lappend(List *list, void *datum)
Definition: list.c:339
#define NoLock
Definition: lockdefs.h:34
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:827
void namestrcpy(Name name, const char *str)
Definition: name.c:233
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
Definition: namespace.c:3487
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
ObjectType get_relkind_objtype(char relkind)
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
char * nodeToString(const void *obj)
Definition: outfuncs.c:794
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
int errdetail_relkind_not_supported(char relkind)
Definition: pg_class.c:24
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:45
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:168
#define qsort(a, b, c, d)
Definition: port.h:474
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:378
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:355
static Datum CharGetDatum(char X)
Definition: postgres.h:127
#define InvalidOid
Definition: postgres_ext.h:37
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define RelationGetNamespace(relation)
Definition: rel.h:546
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: relation.c:137
#define STATS_MAX_DIMENSIONS
Definition: statistics.h:19
static char * ChooseExtendedStatisticNameAddition(List *exprs)
Definition: statscmds.c:851
static char * ChooseExtendedStatisticName(const char *name1, const char *name2, const char *label, Oid namespaceid)
Definition: statscmds.c:809
static int compare_int16(const void *a, const void *b)
Definition: statscmds.c:49
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30
Definition: pg_list.h:54
Definition: nodes.h:129
TupleDesc rd_att
Definition: rel.h:112
Form_pg_class rd_rel
Definition: rel.h:111
Node * expr
Definition: parsenodes.h:3481
Definition: primnodes.h:261
AttrNumber varattno
Definition: primnodes.h:273
Definition: c.h:672
Definition: c.h:698
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition: syscache.c:480
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:102
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:386
#define TYPECACHE_LT_OPR
Definition: typcache.h:138
#define strVal(v)
Definition: value.h:82
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:296
const char * type

References aclcheck_error(), ACLCHECK_NOT_OWNER, allowSystemTableMods, Assert, attname, attnum, bms_next_member(), buildint2vector(), CacheInvalidateRelcache(), CatalogTupleInsert(), CharGetDatum(), ChooseExtendedStatisticName(), ChooseExtendedStatisticNameAddition(), compare_int16(), construct_array_builtin(), CreateComments(), CStringGetDatum(), CStringGetTextDatum, DEPENDENCY_AUTO, DEPENDENCY_NORMAL, equal(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail_relkind_not_supported(), errmsg(), ERROR, StatsElem::expr, exprType(), FirstLowInvalidHeapAttributeNumber, format_type_be(), get_attname(), get_relkind_objtype(), GetNewOidWithIndex(), GETSTRUCT(), GetUserId(), heap_form_tuple(), heap_freetuple(), HeapTupleIsValid, i, if(), InvalidObjectAddress, InvalidOid, InvokeObjectPostCreateHook, IsA, IsSystemRelation(), lappend(), lengthof, lfirst, lfirst_node, list_length(), lookup_type_cache(), StatsElem::name, NameGetDatum(), namestrcpy(), NIL, nodeToString(), NoLock, NOTICE, object_ownercheck(), ObjectAddressSet, ObjectAddressSubSet, ObjectIdGetDatum(), pfree(), PointerGetDatum(), pull_varattnos(), qsort, QualifiedNameGetCreationNamespace(), RelationData::rd_att, RelationData::rd_rel, recordDependencyOn(), recordDependencyOnOwner(), recordDependencyOnSingleRelExpr(), relation_close(), relation_openrv(), RelationGetNamespace, RelationGetRelationName, RelationGetRelid, ReleaseSysCache(), RowExclusiveLock, SearchSysCacheAttName(), SearchSysCacheExists2, ShareUpdateExclusiveLock, STATS_MAX_DIMENSIONS, stmt, strVal, table_open(), type, TYPECACHE_LT_OPR, types, values, and Var::varattno.

Referenced by ATExecAddStatistics(), and ProcessUtilitySlow().

◆ RemoveStatisticsById()

void RemoveStatisticsById ( Oid  statsOid)

Definition at line 747 of file statscmds.c.

748{
749 Relation relation;
750 Relation rel;
751 HeapTuple tup;
752 Form_pg_statistic_ext statext;
753 Oid relid;
754
755 /*
756 * Delete the pg_statistic_ext tuple. Also send out a cache inval on the
757 * associated table, so that dependent plans will be rebuilt.
758 */
759 relation = table_open(StatisticExtRelationId, RowExclusiveLock);
760
761 tup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statsOid));
762
763 if (!HeapTupleIsValid(tup)) /* should not happen */
764 elog(ERROR, "cache lookup failed for statistics object %u", statsOid);
765
766 statext = (Form_pg_statistic_ext) GETSTRUCT(tup);
767 relid = statext->stxrelid;
768
769 /*
770 * Delete the pg_statistic_ext_data tuples holding the actual statistical
771 * data. There might be data with/without inheritance, so attempt deleting
772 * both. We lock the user table first, to prevent other processes (e.g.
773 * DROP STATISTICS) from removing the row concurrently.
774 */
776
777 RemoveStatisticsDataById(statsOid, true);
778 RemoveStatisticsDataById(statsOid, false);
779
781
782 CatalogTupleDelete(relation, &tup->t_self);
783
784 ReleaseSysCache(tup);
785
786 /* Keep lock until the end of the transaction. */
787 table_close(rel, NoLock);
788
789 table_close(relation, RowExclusiveLock);
790}
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
void CacheInvalidateRelcacheByRelid(Oid relid)
Definition: inval.c:1609
FormData_pg_statistic_ext * Form_pg_statistic_ext
void RemoveStatisticsDataById(Oid statsOid, bool inh)
Definition: statscmds.c:722

References CacheInvalidateRelcacheByRelid(), CatalogTupleDelete(), elog, ERROR, GETSTRUCT(), HeapTupleIsValid, NoLock, ObjectIdGetDatum(), ReleaseSysCache(), RemoveStatisticsDataById(), RowExclusiveLock, SearchSysCache1(), ShareUpdateExclusiveLock, HeapTupleData::t_self, table_close(), and table_open().

Referenced by doDeletion().

◆ RemoveStatisticsDataById()

void RemoveStatisticsDataById ( Oid  statsOid,
bool  inh 
)

Definition at line 722 of file statscmds.c.

723{
724 Relation relation;
725 HeapTuple tup;
726
727 relation = table_open(StatisticExtDataRelationId, RowExclusiveLock);
728
729 tup = SearchSysCache2(STATEXTDATASTXOID, ObjectIdGetDatum(statsOid),
730 BoolGetDatum(inh));
731
732 /* We don't know if the data row for inh value exists. */
733 if (HeapTupleIsValid(tup))
734 {
735 CatalogTupleDelete(relation, &tup->t_self);
736
737 ReleaseSysCache(tup);
738 }
739
740 table_close(relation, RowExclusiveLock);
741}
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:232

References BoolGetDatum(), CatalogTupleDelete(), HeapTupleIsValid, ObjectIdGetDatum(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache2(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by RemoveStatisticsById(), and statext_store().

◆ StatisticsGetRelation()

Oid StatisticsGetRelation ( Oid  statId,
bool  missing_ok 
)

Definition at line 898 of file statscmds.c.

899{
900 HeapTuple tuple;
902 Oid result;
903
904 tuple = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statId));
905 if (!HeapTupleIsValid(tuple))
906 {
907 if (missing_ok)
908 return InvalidOid;
909 elog(ERROR, "cache lookup failed for statistics object %u", statId);
910 }
911 stx = (Form_pg_statistic_ext) GETSTRUCT(tuple);
912 Assert(stx->oid == statId);
913
914 result = stx->stxrelid;
915 ReleaseSysCache(tuple);
916 return result;
917}

References Assert, elog, ERROR, GETSTRUCT(), HeapTupleIsValid, InvalidOid, ObjectIdGetDatum(), ReleaseSysCache(), and SearchSysCache1().