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 425 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().

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

◆ ChooseExtendedStatisticName()

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

Definition at line 674 of file statscmds.c.

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

Referenced by CreateStatistics().

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

◆ ChooseExtendedStatisticNameAddition()

static char * ChooseExtendedStatisticNameAddition ( List exprs)
static

Definition at line 716 of file statscmds.c.

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

Referenced by CreateStatistics().

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

◆ 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:345
struct @18::@19 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, 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, 'c');
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  /*
378  * Invalidate relcache so that others see the new statistics object.
379  */
381 
382  relation_close(rel, NoLock);
383 
384  /*
385  * Add an AUTO dependency on each column used in the stats, so that the
386  * stats object goes away if any or all of them get dropped.
387  */
388  ObjectAddressSet(myself, StatisticExtRelationId, statoid);
389 
390  for (i = 0; i < numcols; i++)
391  {
392  ObjectAddressSubSet(parentobject, RelationRelationId, relid, attnums[i]);
393  recordDependencyOn(&myself, &parentobject, DEPENDENCY_AUTO);
394  }
395 
396  /*
397  * Also add dependencies on namespace and owner. These are required
398  * because the stats object might have a different namespace and/or owner
399  * than the underlying table(s).
400  */
401  ObjectAddressSet(parentobject, NamespaceRelationId, namespaceId);
402  recordDependencyOn(&myself, &parentobject, DEPENDENCY_NORMAL);
403 
404  recordDependencyOnOwner(StatisticExtRelationId, statoid, stxowner);
405 
406  /*
407  * XXX probably there should be a recordDependencyOnCurrentExtension call
408  * here too, but we'd have to add support for ALTER EXTENSION ADD/DROP
409  * STATISTICS, which is more work than it seems worth.
410  */
411 
412  /* Add any requested comment */
413  if (stmt->stxcomment != NULL)
414  CreateComments(statoid, StatisticExtRelationId, 0,
415  stmt->stxcomment);
416 
417  /* Return stats object's address */
418  return myself;
419 }
signed short int16
Definition: c.h:345
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:323
void CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment)
Definition: comment.c:142
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
#define NameGetDatum(X)
Definition: postgres.h:595
static char * ChooseExtendedStatisticName(const char *name1, const char *name2, const char *label, Oid namespaceid)
Definition: statscmds.c:674
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
struct typedefs * types
Definition: ecpg.c:29
Oid GetUserId(void)
Definition: miscinit.c:380
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2987
#define PointerGetDatum(X)
Definition: postgres.h:556
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:3291
Definition: nodes.h:525
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:570
char * format_type_be(Oid type_oid)
Definition: format_type.c:326
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
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:165
#define lengthof(array)
Definition: c.h:662
Form_pg_class rd_rel
Definition: rel.h:83
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
int namestrcpy(Name name, const char *str)
Definition: name.c:250
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3353
#define linitial(l)
Definition: pg_list.h:195
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
NameData attname
Definition: pg_attribute.h:40
Definition: c.h:603
#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:453
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
static int compare_int16(const void *a, const void *b)
Definition: statscmds.c:49
#define ereport(elevel, rest)
Definition: elog.h:141
Definition: c.h:577
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: relation.c:138
TupleDesc rd_att
Definition: rel.h:84
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:322
#define InvalidOid
Definition: postgres_ext.h:36
#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:732
#define lfirst(lc)
Definition: pg_list.h:190
Definition: value.h:42
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4755
static char * ChooseExtendedStatisticNameAddition(List *exprs)
Definition: statscmds.c:716
static int list_length(const List *l)
Definition: pg_list.h:169
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:185
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition: syscache.c:1265
#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:1270
static Datum values[MAXATTR]
Definition: bootstrap.c:167
#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:784
int i
ObjectType get_relkind_objtype(char relkind)
#define TYPECACHE_LT_OPR
Definition: typcache.h:129
#define StatisticExtOidIndexId
Definition: indexing.h:234
#define qsort(a, b, c, d)
Definition: port.h:492
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:33
#define RelationGetRelid(relation)
Definition: rel.h:419
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:183
List * fields
Definition: parsenodes.h:235
#define RelationGetNamespace(relation)
Definition: rel.h:460

◆ RemoveStatisticsById()

void RemoveStatisticsById ( Oid  statsOid)

Definition at line 529 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().

530 {
531  Relation relation;
532  HeapTuple tup;
533  Form_pg_statistic_ext statext;
534  Oid relid;
535 
536  /*
537  * First delete the pg_statistic_ext_data tuple holding the actual
538  * statistical data.
539  */
540  relation = table_open(StatisticExtDataRelationId, RowExclusiveLock);
541 
543 
544  if (!HeapTupleIsValid(tup)) /* should not happen */
545  elog(ERROR, "cache lookup failed for statistics data %u", statsOid);
546 
547  CatalogTupleDelete(relation, &tup->t_self);
548 
549  ReleaseSysCache(tup);
550 
551  table_close(relation, RowExclusiveLock);
552 
553  /*
554  * Delete the pg_statistic_ext tuple. Also send out a cache inval on the
555  * associated table, so that dependent plans will be rebuilt.
556  */
557  relation = table_open(StatisticExtRelationId, RowExclusiveLock);
558 
559  tup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statsOid));
560 
561  if (!HeapTupleIsValid(tup)) /* should not happen */
562  elog(ERROR, "cache lookup failed for statistics object %u", statsOid);
563 
564  statext = (Form_pg_statistic_ext) GETSTRUCT(tup);
565  relid = statext->stxrelid;
566 
568 
569  CatalogTupleDelete(relation, &tup->t_self);
570 
571  ReleaseSysCache(tup);
572 
573  table_close(relation, RowExclusiveLock);
574 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:269
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:1329
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1124
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define elog(elevel,...)
Definition: elog.h:226
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 602 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().

604 {
605  HeapTuple stup,
606  oldtup;
607 
608  Relation rel;
609 
610  Datum values[Natts_pg_statistic_ext_data];
611  bool nulls[Natts_pg_statistic_ext_data];
612  bool replaces[Natts_pg_statistic_ext_data];
613 
615  if (!HeapTupleIsValid(oldtup))
616  elog(ERROR, "cache lookup failed for statistics object %u", statsOid);
617 
618  /*
619  * When none of the defined statistics types contain datum values from the
620  * table's columns then there's no need to reset the stats. Functional
621  * dependencies and ndistinct stats should still hold true.
622  */
623  if (!statext_is_kind_built(oldtup, STATS_EXT_MCV))
624  {
625  ReleaseSysCache(oldtup);
626  return;
627  }
628 
629  /*
630  * OK, we need to reset some statistics. So let's build the new tuple,
631  * replacing the affected statistics types with NULL.
632  */
633  memset(nulls, 0, Natts_pg_statistic_ext_data * sizeof(bool));
634  memset(replaces, 0, Natts_pg_statistic_ext_data * sizeof(bool));
635  memset(values, 0, Natts_pg_statistic_ext_data * sizeof(Datum));
636 
637  replaces[Anum_pg_statistic_ext_data_stxdmcv - 1] = true;
638  nulls[Anum_pg_statistic_ext_data_stxdmcv - 1] = true;
639 
640  rel = table_open(StatisticExtDataRelationId, RowExclusiveLock);
641 
642  /* replace the old tuple */
643  stup = heap_modify_tuple(oldtup,
644  RelationGetDescr(rel),
645  values,
646  nulls,
647  replaces);
648 
649  ReleaseSysCache(oldtup);
650  CatalogTupleUpdate(rel, &stup->t_self, stup);
651 
652  heap_freetuple(stup);
653 
655 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define RelationGetDescr(relation)
Definition: rel.h:445
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:1124
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
static Datum values[MAXATTR]
Definition: bootstrap.c:167
#define elog(elevel,...)
Definition: elog.h:226
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