PostgreSQL Source Code  git master
statscmds.c File Reference
#include "postgres.h"
#include "access/heapam.h"
#include "access/relation.h"
#include "access/relscan.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 "statistics/statistics.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/memutils.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 RemoveStatisticsById (Oid statsOid)
 
void UpdateStatisticsForTypeChange (Oid statsOid, Oid relationOid, int attnum, Oid oldColumnType, Oid newColumnType)
 

Function Documentation

◆ AlterStatistics()

ObjectAddress AlterStatistics ( AlterStatsStmt stmt)

Definition at line 427 of file statscmds.c.

References aclcheck_error(), ACLCHECK_NOT_OWNER, Assert, CatalogTupleUpdate(), DeconstructQualifiedName(), AlterStatsStmt::defnames, ereport, errcode(), errmsg(), ERROR, get_statistics_object_oid(), GetUserId(), heap_freetuple(), heap_modify_tuple(), Int32GetDatum, InvalidObjectAddress, InvokeObjectPostAlterHook, AlterStatsStmt::missing_ok, NameListToString(), NOTICE, OBJECT_STATISTIC_EXT, ObjectAddressSet, ObjectIdGetDatum, OidIsValid, pg_statistics_object_ownercheck(), RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), STATEXTOID, AlterStatsStmt::stxstattarget, HeapTupleData::t_self, table_close(), table_open(), and WARNING.

Referenced by ProcessUtilitySlow().

428 {
429  Relation rel;
430  Oid stxoid;
431  HeapTuple oldtup;
432  HeapTuple newtup;
433  Datum repl_val[Natts_pg_statistic_ext];
434  bool repl_null[Natts_pg_statistic_ext];
435  bool repl_repl[Natts_pg_statistic_ext];
436  ObjectAddress address;
437  int newtarget = stmt->stxstattarget;
438 
439  /* Limit statistics target to a sane range */
440  if (newtarget < -1)
441  {
442  ereport(ERROR,
443  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
444  errmsg("statistics target %d is too low",
445  newtarget)));
446  }
447  else if (newtarget > 10000)
448  {
449  newtarget = 10000;
451  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
452  errmsg("lowering statistics target to %d",
453  newtarget)));
454  }
455 
456  /* lookup OID of the statistics object */
457  stxoid = get_statistics_object_oid(stmt->defnames, stmt->missing_ok);
458 
459  /*
460  * If we got here and the OID is not valid, it means the statistics does
461  * not exist, but the command specified IF EXISTS. So report this as a
462  * simple NOTICE and we're done.
463  */
464  if (!OidIsValid(stxoid))
465  {
466  char *schemaname;
467  char *statname;
468 
469  Assert(stmt->missing_ok);
470 
471  DeconstructQualifiedName(stmt->defnames, &schemaname, &statname);
472 
473  if (schemaname)
474  ereport(NOTICE,
475  (errmsg("statistics object \"%s.%s\" does not exist, skipping",
476  schemaname, statname)));
477  else
478  ereport(NOTICE,
479  (errmsg("statistics object \"%s\" does not exist, skipping",
480  statname)));
481 
482  return InvalidObjectAddress;
483  }
484 
485  /* Search pg_statistic_ext */
486  rel = table_open(StatisticExtRelationId, RowExclusiveLock);
487 
488  oldtup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(stxoid));
489 
490  /* Must be owner of the existing statistics object */
493  NameListToString(stmt->defnames));
494 
495  /* Build new tuple. */
496  memset(repl_val, 0, sizeof(repl_val));
497  memset(repl_null, false, sizeof(repl_null));
498  memset(repl_repl, false, sizeof(repl_repl));
499 
500  /* replace the stxstattarget column */
501  repl_repl[Anum_pg_statistic_ext_stxstattarget - 1] = true;
502  repl_val[Anum_pg_statistic_ext_stxstattarget - 1] = Int32GetDatum(newtarget);
503 
504  newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
505  repl_val, repl_null, repl_repl);
506 
507  /* Update system catalog. */
508  CatalogTupleUpdate(rel, &newtup->t_self, newtup);
509 
510  InvokeObjectPostAlterHook(StatisticExtRelationId, stxoid, 0);
511 
512  ObjectAddressSet(address, StatisticExtRelationId, stxoid);
513 
514  /*
515  * NOTE: because we only support altering the statistics target, not the
516  * other fields, there is no need to update dependencies.
517  */
518 
519  heap_freetuple(newtup);
520  ReleaseSysCache(oldtup);
521 
523 
524  return address;
525 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define RelationGetDescr(relation)
Definition: rel.h:483
Oid GetUserId(void)
Definition: miscinit.c:476
int errcode(int sqlerrcode)
Definition: elog.c:691
void DeconstructQualifiedName(List *names, char **nspname_p, char **objname_p)
Definition: namespace.c:2808
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:706
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
Oid get_statistics_object_oid(List *names, bool missing_ok)
Definition: namespace.c:2177
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
#define WARNING
Definition: elog.h:40
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1115
char * NameListToString(List *names)
Definition: namespace.c:3101
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1163
#define ereport(elevel,...)
Definition: elog.h:155
#define NOTICE
Definition: elog.h:37
#define Assert(condition)
Definition: c.h:800
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define Int32GetDatum(X)
Definition: postgres.h:479
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:902
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
bool pg_statistics_object_ownercheck(Oid stat_oid, Oid roleid)
Definition: aclchk.c:5277

◆ ChooseExtendedStatisticName()

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

Definition at line 676 of file statscmds.c.

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

Referenced by CreateStatistics().

678 {
679  int pass = 0;
680  char *stxname = NULL;
681  char modlabel[NAMEDATALEN];
682 
683  /* try the unmodified label first */
684  strlcpy(modlabel, label, sizeof(modlabel));
685 
686  for (;;)
687  {
688  Oid existingstats;
689 
690  stxname = makeObjectName(name1, name2, modlabel);
691 
692  existingstats = GetSysCacheOid2(STATEXTNAMENSP, Anum_pg_statistic_ext_oid,
693  PointerGetDatum(stxname),
694  ObjectIdGetDatum(namespaceid));
695  if (!OidIsValid(existingstats))
696  break;
697 
698  /* found a conflict, so try a new name component */
699  pfree(stxname);
700  snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
701  }
702 
703  return stxname;
704 }
#define PointerGetDatum(X)
Definition: postgres.h:556
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:706
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition: indexcmds.c:2190
#define NAMEDATALEN
void pfree(void *pointer)
Definition: mcxt.c:1057
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
static char * label
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:194
#define snprintf
Definition: port.h:215

◆ ChooseExtendedStatisticNameAddition()

static char * ChooseExtendedStatisticNameAddition ( List exprs)
static

Definition at line 718 of file statscmds.c.

References buf, ColumnRef::fields, IsA, lfirst, linitial, name, NAMEDATALEN, pstrdup(), strlcpy(), and strVal.

Referenced by CreateStatistics().

719 {
720  char buf[NAMEDATALEN * 2];
721  int buflen = 0;
722  ListCell *lc;
723 
724  buf[0] = '\0';
725  foreach(lc, exprs)
726  {
727  ColumnRef *cref = (ColumnRef *) lfirst(lc);
728  const char *name;
729 
730  /* It should be one of these, but just skip if it happens not to be */
731  if (!IsA(cref, ColumnRef))
732  continue;
733 
734  name = strVal((Value *) linitial(cref->fields));
735 
736  if (buflen > 0)
737  buf[buflen++] = '_'; /* insert _ between names */
738 
739  /*
740  * At this point we have buflen <= NAMEDATALEN. name should be less
741  * than NAMEDATALEN already, but use strlcpy for paranoia.
742  */
743  strlcpy(buf + buflen, name, NAMEDATALEN);
744  buflen += strlen(buf + buflen);
745  if (buflen >= NAMEDATALEN)
746  break;
747  }
748  return pstrdup(buf);
749 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:578
char * pstrdup(const char *in)
Definition: mcxt.c:1187
#define strVal(v)
Definition: value.h:54
#define NAMEDATALEN
#define linitial(l)
Definition: pg_list.h:174
static char * buf
Definition: pg_test_fsync.c:68
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
#define lfirst(lc)
Definition: pg_list.h:169
Definition: value.h:42
const char * name
Definition: encode.c:561
List * fields
Definition: parsenodes.h:236

◆ compare_int16()

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

Definition at line 49 of file statscmds.c.

References av.

Referenced by CreateStatistics().

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 }
signed short int16
Definition: c.h:416
struct @17::@18 av[32]

◆ CreateStatistics()

ObjectAddress CreateStatistics ( CreateStatsStmt stmt)

Definition at line 62 of file statscmds.c.

References aclcheck_error(), ACLCHECK_NOT_OWNER, Assert, attname, buildint2vector(), CacheInvalidateRelcache(), CatalogTupleInsert(), CharGetDatum, ChooseExtendedStatisticName(), ChooseExtendedStatisticNameAddition(), compare_int16(), construct_array(), CreateComments(), CStringGetDatum, CreateStatsStmt::defnames, DEPENDENCY_AUTO, DEPENDENCY_NORMAL, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, CreateStatsStmt::exprs, ColumnRef::fields, format_type_be(), get_relkind_objtype(), GetNewOidWithIndex(), GETSTRUCT, GetUserId(), heap_form_tuple(), heap_freetuple(), HeapTupleIsValid, i, CreateStatsStmt::if_not_exists, Int32GetDatum, InvalidObjectAddress, InvalidOid, InvokeObjectPostCreateHook, IsA, lengthof, lfirst, linitial, list_length(), lookup_type_cache(), TypeCacheEntry::lt_opr, NameGetDatum, namestrcpy(), NoLock, NOTICE, ObjectAddressSet, ObjectAddressSubSet, ObjectIdGetDatum, pg_class_ownercheck(), PointerGetDatum, qsort, QualifiedNameGetCreationNamespace(), RelationData::rd_att, RelationData::rd_rel, recordDependencyOn(), recordDependencyOnOwner(), relation_close(), relation_openrv(), RelationGetNamespace, RelationGetRelationName, RelationGetRelid, CreateStatsStmt::relations, ReleaseSysCache(), RowExclusiveLock, SearchSysCacheAttName(), SearchSysCacheExists2, ShareUpdateExclusiveLock, CreateStatsStmt::stat_types, STATEXTNAMENSP, StatisticExtOidIndexId, STATS_MAX_DIMENSIONS, strVal, CreateStatsStmt::stxcomment, table_open(), generate_unaccent_rules::type, TYPECACHE_LT_OPR, types, and values.

Referenced by ProcessUtilitySlow().

63 {
64  int16 attnums[STATS_MAX_DIMENSIONS];
65  int numcols = 0;
66  char *namestr;
67  NameData stxname;
68  Oid statoid;
69  Oid namespaceId;
70  Oid stxowner = GetUserId();
71  HeapTuple htup;
72  Datum values[Natts_pg_statistic_ext];
73  bool nulls[Natts_pg_statistic_ext];
74  Datum datavalues[Natts_pg_statistic_ext_data];
75  bool datanulls[Natts_pg_statistic_ext_data];
76  int2vector *stxkeys;
77  Relation statrel;
78  Relation datarel;
79  Relation rel = NULL;
80  Oid relid;
81  ObjectAddress parentobject,
82  myself;
83  Datum types[3]; /* 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 requested_type = false;
90  int i;
91  ListCell *cell;
92 
93  Assert(IsA(stmt, CreateStatsStmt));
94 
95  /*
96  * Examine the FROM clause. Currently, we only allow it to be a single
97  * simple table, but later we'll probably allow multiple tables and JOIN
98  * syntax. The grammar is already prepared for that, so we have to check
99  * here that what we got is what we can support.
100  */
101  if (list_length(stmt->relations) != 1)
102  ereport(ERROR,
103  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
104  errmsg("only a single relation is allowed in CREATE STATISTICS")));
105 
106  foreach(cell, stmt->relations)
107  {
108  Node *rln = (Node *) lfirst(cell);
109 
110  if (!IsA(rln, RangeVar))
111  ereport(ERROR,
112  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
113  errmsg("only a single relation is allowed in CREATE STATISTICS")));
114 
115  /*
116  * CREATE STATISTICS will influence future execution plans but does
117  * not interfere with currently executing plans. So it should be
118  * enough to take only ShareUpdateExclusiveLock on relation,
119  * conflicting with ANALYZE and other DDL that sets statistical
120  * information, but not with normal queries.
121  */
123 
124  /* Restrict to allowed relation types */
125  if (rel->rd_rel->relkind != RELKIND_RELATION &&
126  rel->rd_rel->relkind != RELKIND_MATVIEW &&
127  rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
128  rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
129  ereport(ERROR,
130  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
131  errmsg("relation \"%s\" is not a table, foreign table, or materialized view",
132  RelationGetRelationName(rel))));
133 
134  /* You must own the relation to create stats on it */
135  if (!pg_class_ownercheck(RelationGetRelid(rel), stxowner))
138  }
139 
140  Assert(rel);
141  relid = RelationGetRelid(rel);
142 
143  /*
144  * If the node has a name, split it up and determine creation namespace.
145  * If not (a possibility not considered by the grammar, but one which can
146  * occur via the "CREATE TABLE ... (LIKE)" command), then we put the
147  * object in the same namespace as the relation, and cons up a name for
148  * it.
149  */
150  if (stmt->defnames)
151  namespaceId = QualifiedNameGetCreationNamespace(stmt->defnames,
152  &namestr);
153  else
154  {
155  namespaceId = RelationGetNamespace(rel);
158  "stat",
159  namespaceId);
160  }
161  namestrcpy(&stxname, namestr);
162 
163  /*
164  * Deal with the possibility that the statistics object already exists.
165  */
167  CStringGetDatum(namestr),
168  ObjectIdGetDatum(namespaceId)))
169  {
170  if (stmt->if_not_exists)
171  {
172  ereport(NOTICE,
174  errmsg("statistics object \"%s\" already exists, skipping",
175  namestr)));
176  relation_close(rel, NoLock);
177  return InvalidObjectAddress;
178  }
179 
180  ereport(ERROR,
182  errmsg("statistics object \"%s\" already exists", namestr)));
183  }
184 
185  /*
186  * Currently, we only allow simple column references in the expression
187  * list. That will change someday, and again the grammar already supports
188  * it so we have to enforce restrictions here. For now, we can convert
189  * the expression list to a simple array of attnums. While at it, enforce
190  * some constraints.
191  */
192  foreach(cell, stmt->exprs)
193  {
194  Node *expr = (Node *) lfirst(cell);
195  ColumnRef *cref;
196  char *attname;
197  HeapTuple atttuple;
198  Form_pg_attribute attForm;
200 
201  if (!IsA(expr, ColumnRef))
202  ereport(ERROR,
203  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
204  errmsg("only simple column references are allowed in CREATE STATISTICS")));
205  cref = (ColumnRef *) expr;
206 
207  if (list_length(cref->fields) != 1)
208  ereport(ERROR,
209  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
210  errmsg("only simple column references are allowed in CREATE STATISTICS")));
211  attname = strVal((Value *) linitial(cref->fields));
212 
213  atttuple = SearchSysCacheAttName(relid, attname);
214  if (!HeapTupleIsValid(atttuple))
215  ereport(ERROR,
216  (errcode(ERRCODE_UNDEFINED_COLUMN),
217  errmsg("column \"%s\" does not exist",
218  attname)));
219  attForm = (Form_pg_attribute) GETSTRUCT(atttuple);
220 
221  /* Disallow use of system attributes in extended stats */
222  if (attForm->attnum <= 0)
223  ereport(ERROR,
224  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
225  errmsg("statistics creation on system columns is not supported")));
226 
227  /* Disallow data types without a less-than operator */
228  type = lookup_type_cache(attForm->atttypid, TYPECACHE_LT_OPR);
229  if (type->lt_opr == InvalidOid)
230  ereport(ERROR,
231  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
232  errmsg("column \"%s\" cannot be used in statistics because its type %s has no default btree operator class",
233  attname, format_type_be(attForm->atttypid))));
234 
235  /* Make sure no more than STATS_MAX_DIMENSIONS columns are used */
236  if (numcols >= STATS_MAX_DIMENSIONS)
237  ereport(ERROR,
238  (errcode(ERRCODE_TOO_MANY_COLUMNS),
239  errmsg("cannot have more than %d columns in statistics",
241 
242  attnums[numcols] = attForm->attnum;
243  numcols++;
244  ReleaseSysCache(atttuple);
245  }
246 
247  /*
248  * Check that at least two columns were specified in the statement. The
249  * upper bound was already checked in the loop above.
250  */
251  if (numcols < 2)
252  ereport(ERROR,
253  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
254  errmsg("extended statistics require at least 2 columns")));
255 
256  /*
257  * Sort the attnums, which makes detecting duplicates somewhat easier, and
258  * it does not hurt (it does not affect the efficiency, unlike for
259  * indexes, for example).
260  */
261  qsort(attnums, numcols, sizeof(int16), compare_int16);
262 
263  /*
264  * Check for duplicates in the list of columns. The attnums are sorted so
265  * just check consecutive elements.
266  */
267  for (i = 1; i < numcols; i++)
268  {
269  if (attnums[i] == attnums[i - 1])
270  ereport(ERROR,
271  (errcode(ERRCODE_DUPLICATE_COLUMN),
272  errmsg("duplicate column name in statistics definition")));
273  }
274 
275  /* Form an int2vector representation of the sorted column list */
276  stxkeys = buildint2vector(attnums, numcols);
277 
278  /*
279  * Parse the statistics kinds.
280  */
281  build_ndistinct = false;
282  build_dependencies = false;
283  build_mcv = false;
284  foreach(cell, stmt->stat_types)
285  {
286  char *type = strVal((Value *) lfirst(cell));
287 
288  if (strcmp(type, "ndistinct") == 0)
289  {
290  build_ndistinct = true;
291  requested_type = true;
292  }
293  else if (strcmp(type, "dependencies") == 0)
294  {
295  build_dependencies = true;
296  requested_type = true;
297  }
298  else if (strcmp(type, "mcv") == 0)
299  {
300  build_mcv = true;
301  requested_type = true;
302  }
303  else
304  ereport(ERROR,
305  (errcode(ERRCODE_SYNTAX_ERROR),
306  errmsg("unrecognized statistics kind \"%s\"",
307  type)));
308  }
309  /* If no statistic type was specified, build them all. */
310  if (!requested_type)
311  {
312  build_ndistinct = true;
313  build_dependencies = true;
314  build_mcv = true;
315  }
316 
317  /* construct the char array of enabled statistic types */
318  ntypes = 0;
319  if (build_ndistinct)
320  types[ntypes++] = CharGetDatum(STATS_EXT_NDISTINCT);
321  if (build_dependencies)
322  types[ntypes++] = CharGetDatum(STATS_EXT_DEPENDENCIES);
323  if (build_mcv)
324  types[ntypes++] = CharGetDatum(STATS_EXT_MCV);
325  Assert(ntypes > 0 && ntypes <= lengthof(types));
326  stxkind = construct_array(types, ntypes, CHAROID, 1, true, TYPALIGN_CHAR);
327 
328  statrel = table_open(StatisticExtRelationId, RowExclusiveLock);
329 
330  /*
331  * Everything seems fine, so let's build the pg_statistic_ext tuple.
332  */
333  memset(values, 0, sizeof(values));
334  memset(nulls, false, sizeof(nulls));
335 
336  statoid = GetNewOidWithIndex(statrel, StatisticExtOidIndexId,
337  Anum_pg_statistic_ext_oid);
338  values[Anum_pg_statistic_ext_oid - 1] = ObjectIdGetDatum(statoid);
339  values[Anum_pg_statistic_ext_stxrelid - 1] = ObjectIdGetDatum(relid);
340  values[Anum_pg_statistic_ext_stxname - 1] = NameGetDatum(&stxname);
341  values[Anum_pg_statistic_ext_stxnamespace - 1] = ObjectIdGetDatum(namespaceId);
342  values[Anum_pg_statistic_ext_stxstattarget - 1] = Int32GetDatum(-1);
343  values[Anum_pg_statistic_ext_stxowner - 1] = ObjectIdGetDatum(stxowner);
344  values[Anum_pg_statistic_ext_stxkeys - 1] = PointerGetDatum(stxkeys);
345  values[Anum_pg_statistic_ext_stxkind - 1] = PointerGetDatum(stxkind);
346 
347  /* insert it into pg_statistic_ext */
348  htup = heap_form_tuple(statrel->rd_att, values, nulls);
349  CatalogTupleInsert(statrel, htup);
350  heap_freetuple(htup);
351 
353 
354  /*
355  * Also build the pg_statistic_ext_data tuple, to hold the actual
356  * statistics data.
357  */
358  datarel = table_open(StatisticExtDataRelationId, RowExclusiveLock);
359 
360  memset(datavalues, 0, sizeof(datavalues));
361  memset(datanulls, false, sizeof(datanulls));
362 
363  datavalues[Anum_pg_statistic_ext_data_stxoid - 1] = ObjectIdGetDatum(statoid);
364 
365  /* no statistics built yet */
366  datanulls[Anum_pg_statistic_ext_data_stxdndistinct - 1] = true;
367  datanulls[Anum_pg_statistic_ext_data_stxddependencies - 1] = true;
368  datanulls[Anum_pg_statistic_ext_data_stxdmcv - 1] = true;
369 
370  /* insert it into pg_statistic_ext_data */
371  htup = heap_form_tuple(datarel->rd_att, datavalues, datanulls);
372  CatalogTupleInsert(datarel, htup);
373  heap_freetuple(htup);
374 
376 
377  InvokeObjectPostCreateHook(StatisticExtRelationId, statoid, 0);
378 
379  /*
380  * Invalidate relcache so that others see the new statistics object.
381  */
383 
384  relation_close(rel, NoLock);
385 
386  /*
387  * Add an AUTO dependency on each column used in the stats, so that the
388  * stats object goes away if any or all of them get dropped.
389  */
390  ObjectAddressSet(myself, StatisticExtRelationId, statoid);
391 
392  for (i = 0; i < numcols; i++)
393  {
394  ObjectAddressSubSet(parentobject, RelationRelationId, relid, attnums[i]);
395  recordDependencyOn(&myself, &parentobject, DEPENDENCY_AUTO);
396  }
397 
398  /*
399  * Also add dependencies on namespace and owner. These are required
400  * because the stats object might have a different namespace and/or owner
401  * than the underlying table(s).
402  */
403  ObjectAddressSet(parentobject, NamespaceRelationId, namespaceId);
404  recordDependencyOn(&myself, &parentobject, DEPENDENCY_NORMAL);
405 
406  recordDependencyOnOwner(StatisticExtRelationId, statoid, stxowner);
407 
408  /*
409  * XXX probably there should be a recordDependencyOnCurrentExtension call
410  * here too, but we'd have to add support for ALTER EXTENSION ADD/DROP
411  * STATISTICS, which is more work than it seems worth.
412  */
413 
414  /* Add any requested comment */
415  if (stmt->stxcomment != NULL)
416  CreateComments(statoid, StatisticExtRelationId, 0,
417  stmt->stxcomment);
418 
419  /* Return stats object's address */
420  return myself;
421 }
signed short int16
Definition: c.h:416
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:315
void CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment)
Definition: comment.c:142
#define IsA(nodeptr, _type_)
Definition: nodes.h:578
#define NameGetDatum(X)
Definition: postgres.h:595
static char * ChooseExtendedStatisticName(const char *name1, const char *name2, const char *label, Oid namespaceid)
Definition: statscmds.c:676
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:151
struct typedefs * types
Definition: ecpg.c:29
Oid GetUserId(void)
Definition: miscinit.c:476
void namestrcpy(Name name, const char *str)
Definition: name.c:233
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2994
#define PointerGetDatum(X)
Definition: postgres.h:556
#define StatisticExtOidIndexId
int2vector * buildint2vector(const int16 *int2s, int n)
Definition: int.c:114
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3313
Definition: nodes.h:527
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:691
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:46
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:164
#define lengthof(array)
Definition: c.h:730
Form_pg_class rd_rel
Definition: rel.h:110
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
#define linitial(l)
Definition: pg_list.h:174
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
NameData attname
Definition: pg_attribute.h:40
Definition: c.h:671
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:578
#define RelationGetRelationName(relation)
Definition: rel.h:491
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
static int compare_int16(const void *a, const void *b)
Definition: statscmds.c:49
Definition: c.h:645
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1163
Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: relation.c:138
TupleDesc rd_att
Definition: rel.h:111
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:334
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:155
#define NOTICE
Definition: elog.h:37
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:800
#define lfirst(lc)
Definition: pg_list.h:169
Definition: value.h:42
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4687
static char * ChooseExtendedStatisticNameAddition(List *exprs)
Definition: statscmds.c:718
static int list_length(const List *l)
Definition: pg_list.h:149
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:185
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition: syscache.c:1256
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define CharGetDatum(X)
Definition: postgres.h:416
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1278
static Datum values[MAXATTR]
Definition: bootstrap.c:165
#define Int32GetDatum(X)
Definition: postgres.h:479
#define STATS_MAX_DIMENSIONS
Definition: statistics.h:19
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:902
int i
ObjectType get_relkind_objtype(char relkind)
#define TYPECACHE_LT_OPR
Definition: typcache.h:131
#define qsort(a, b, c, d)
Definition: port.h:497
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
#define RelationGetRelid(relation)
Definition: rel.h:457
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:221
List * fields
Definition: parsenodes.h:236
#define RelationGetNamespace(relation)
Definition: rel.h:498

◆ RemoveStatisticsById()

void RemoveStatisticsById ( Oid  statsOid)

Definition at line 531 of file statscmds.c.

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

Referenced by doDeletion().

532 {
533  Relation relation;
534  HeapTuple tup;
535  Form_pg_statistic_ext statext;
536  Oid relid;
537 
538  /*
539  * First delete the pg_statistic_ext_data tuple holding the actual
540  * statistical data.
541  */
542  relation = table_open(StatisticExtDataRelationId, RowExclusiveLock);
543 
545 
546  if (!HeapTupleIsValid(tup)) /* should not happen */
547  elog(ERROR, "cache lookup failed for statistics data %u", statsOid);
548 
549  CatalogTupleDelete(relation, &tup->t_self);
550 
551  ReleaseSysCache(tup);
552 
553  table_close(relation, RowExclusiveLock);
554 
555  /*
556  * Delete the pg_statistic_ext tuple. Also send out a cache inval on the
557  * associated table, so that dependent plans will be rebuilt.
558  */
559  relation = table_open(StatisticExtRelationId, RowExclusiveLock);
560 
561  tup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statsOid));
562 
563  if (!HeapTupleIsValid(tup)) /* should not happen */
564  elog(ERROR, "cache lookup failed for statistics object %u", statsOid);
565 
566  statext = (Form_pg_statistic_ext) GETSTRUCT(tup);
567  relid = statext->stxrelid;
568 
570 
571  CatalogTupleDelete(relation, &tup->t_self);
572 
573  ReleaseSysCache(tup);
574 
575  table_close(relation, RowExclusiveLock);
576 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:350
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
void CacheInvalidateRelcacheByRelid(Oid relid)
Definition: inval.c:1337
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1115
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1163
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define elog(elevel,...)
Definition: elog.h:228
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
FormData_pg_statistic_ext * Form_pg_statistic_ext

◆ UpdateStatisticsForTypeChange()

void UpdateStatisticsForTypeChange ( Oid  statsOid,
Oid  relationOid,
int  attnum,
Oid  oldColumnType,
Oid  newColumnType 
)

Definition at line 604 of file statscmds.c.

References CatalogTupleUpdate(), elog, ERROR, heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, ObjectIdGetDatum, RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), statext_is_kind_built(), STATEXTDATASTXOID, HeapTupleData::t_self, table_close(), table_open(), and values.

Referenced by ATExecAlterColumnType().

606 {
607  HeapTuple stup,
608  oldtup;
609 
610  Relation rel;
611 
612  Datum values[Natts_pg_statistic_ext_data];
613  bool nulls[Natts_pg_statistic_ext_data];
614  bool replaces[Natts_pg_statistic_ext_data];
615 
617  if (!HeapTupleIsValid(oldtup))
618  elog(ERROR, "cache lookup failed for statistics object %u", statsOid);
619 
620  /*
621  * When none of the defined statistics types contain datum values from the
622  * table's columns then there's no need to reset the stats. Functional
623  * dependencies and ndistinct stats should still hold true.
624  */
625  if (!statext_is_kind_built(oldtup, STATS_EXT_MCV))
626  {
627  ReleaseSysCache(oldtup);
628  return;
629  }
630 
631  /*
632  * OK, we need to reset some statistics. So let's build the new tuple,
633  * replacing the affected statistics types with NULL.
634  */
635  memset(nulls, 0, Natts_pg_statistic_ext_data * sizeof(bool));
636  memset(replaces, 0, Natts_pg_statistic_ext_data * sizeof(bool));
637  memset(values, 0, Natts_pg_statistic_ext_data * sizeof(Datum));
638 
639  replaces[Anum_pg_statistic_ext_data_stxdmcv - 1] = true;
640  nulls[Anum_pg_statistic_ext_data_stxdmcv - 1] = true;
641 
642  rel = table_open(StatisticExtDataRelationId, RowExclusiveLock);
643 
644  /* replace the old tuple */
645  stup = heap_modify_tuple(oldtup,
646  RelationGetDescr(rel),
647  values,
648  nulls,
649  replaces);
650 
651  ReleaseSysCache(oldtup);
652  CatalogTupleUpdate(rel, &stup->t_self, stup);
653 
654  heap_freetuple(stup);
655 
657 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define RelationGetDescr(relation)
Definition: rel.h:483
bool statext_is_kind_built(HeapTuple htup, char type)
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1115
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1163
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
static Datum values[MAXATTR]
Definition: bootstrap.c:165
#define elog(elevel,...)
Definition: elog.h:228
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113