PostgreSQL Source Code  git master
statscmds.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * statscmds.c
4  * Commands for creating and altering extended statistics objects
5  *
6  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/commands/statscmds.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "access/heapam.h"
18 #include "access/relation.h"
19 #include "access/relscan.h"
20 #include "access/table.h"
21 #include "catalog/catalog.h"
22 #include "catalog/dependency.h"
23 #include "catalog/indexing.h"
24 #include "catalog/namespace.h"
25 #include "catalog/objectaccess.h"
26 #include "catalog/pg_namespace.h"
29 #include "commands/comment.h"
30 #include "commands/defrem.h"
31 #include "miscadmin.h"
32 #include "statistics/statistics.h"
33 #include "utils/builtins.h"
34 #include "utils/fmgroids.h"
35 #include "utils/inval.h"
36 #include "utils/memutils.h"
37 #include "utils/rel.h"
38 #include "utils/syscache.h"
39 #include "utils/typcache.h"
40 
41 
42 static char *ChooseExtendedStatisticName(const char *name1, const char *name2,
43  const char *label, Oid namespaceid);
44 static char *ChooseExtendedStatisticNameAddition(List *exprs);
45 
46 
47 /* qsort comparator for the attnums in CreateStatistics */
48 static int
49 compare_int16(const void *a, const void *b)
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 }
57 
58 /*
59  * CREATE STATISTICS
60  */
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 }
422 
423 /*
424  * ALTER STATISTICS
425  */
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 }
526 
527 /*
528  * Guts of statistics object deletion.
529  */
530 void
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 }
577 
578 /*
579  * Update a statistics object for ALTER COLUMN TYPE on a source column.
580  *
581  * This could throw an error if the type change can't be supported.
582  * If it can be supported, but the stats must be recomputed, a likely choice
583  * would be to set the relevant column(s) of the pg_statistic_ext_data tuple
584  * to null until the next ANALYZE. (Note that the type change hasn't actually
585  * happened yet, so one option that's *not* on the table is to recompute
586  * immediately.)
587  *
588  * For both ndistinct and functional-dependencies stats, the on-disk
589  * representation is independent of the source column data types, and it is
590  * plausible to assume that the old statistic values will still be good for
591  * the new column contents. (Obviously, if the ALTER COLUMN TYPE has a USING
592  * expression that substantially alters the semantic meaning of the column
593  * values, this assumption could fail. But that seems like a corner case
594  * that doesn't justify zapping the stats in common cases.)
595  *
596  * For MCV lists that's not the case, as those statistics store the datums
597  * internally. In this case we simply reset the statistics value to NULL.
598  *
599  * Note that "type change" includes collation change, which means we can rely
600  * on the MCV list being consistent with the collation info in pg_attribute
601  * during estimation.
602  */
603 void
604 UpdateStatisticsForTypeChange(Oid statsOid, Oid relationOid, int attnum,
605  Oid oldColumnType, Oid newColumnType)
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 }
658 
659 /*
660  * Select a nonconflicting name for a new statistics.
661  *
662  * name1, name2, and label are used the same way as for makeObjectName(),
663  * except that the label can't be NULL; digits will be appended to the label
664  * if needed to create a name that is unique within the specified namespace.
665  *
666  * Returns a palloc'd string.
667  *
668  * Note: it is theoretically possible to get a collision anyway, if someone
669  * else chooses the same name concurrently. This is fairly unlikely to be
670  * a problem in practice, especially if one is holding a share update
671  * exclusive lock on the relation identified by name1. However, if choosing
672  * multiple names within a single command, you'd better create the new object
673  * and do CommandCounterIncrement before choosing the next one!
674  */
675 static char *
676 ChooseExtendedStatisticName(const char *name1, const char *name2,
677  const char *label, Oid namespaceid)
678 {
679  int pass = 0;
680  char *stxname = NULL;
681  char modlabel[NAMEDATALEN];
682 
683  /* try the unmodified label first */
684  StrNCpy(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 }
705 
706 /*
707  * Generate "name2" for a new statistics given the list of column names for it
708  * This will be passed to ChooseExtendedStatisticName along with the parent
709  * table name and a suitable label.
710  *
711  * We know that less than NAMEDATALEN characters will actually be used,
712  * so we can truncate the result once we've generated that many.
713  *
714  * XXX see also ChooseForeignKeyConstraintNameAddition and
715  * ChooseIndexNameAddition.
716  */
717 static char *
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 }
signed short int16
Definition: c.h:354
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:317
void CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment)
Definition: comment.c:142
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
#define NameGetDatum(X)
Definition: postgres.h:595
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
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
void RemoveStatisticsById(Oid statsOid)
Definition: statscmds.c:531
struct typedefs * types
Definition: ecpg.c:29
#define RelationGetDescr(relation)
Definition: rel.h:482
Oid GetUserId(void)
Definition: miscinit.c:448
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2995
#define PointerGetDatum(X)
Definition: postgres.h:556
char * pstrdup(const char *in)
Definition: mcxt.c:1186
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:3292
Definition: nodes.h:529
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:327
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:269
bool statext_is_kind_built(HeapTuple htup, char type)
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
void DeconstructQualifiedName(List *names, char **nspname_p, char **objname_p)
Definition: namespace.c:2809
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:668
Form_pg_class rd_rel
Definition: rel.h:109
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
#define OidIsValid(objectId)
Definition: c.h:644
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition: indexcmds.c:2154
#define NAMEDATALEN
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3327
ObjectAddress AlterStatistics(AlterStatsStmt *stmt)
Definition: statscmds.c:427
void pfree(void *pointer)
Definition: mcxt.c:1056
#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
ItemPointerData t_self
Definition: htup.h:65
Oid get_statistics_object_oid(List *names, bool missing_ok)
Definition: namespace.c:2178
Definition: c.h:609
#define NoLock
Definition: lockdefs.h:34
static char * buf
Definition: pg_test_fsync.c:67
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:578
void CacheInvalidateRelcacheByRelid(Oid relid)
Definition: inval.c:1329
#define RelationGetRelationName(relation)
Definition: rel.h:490
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
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
#define WARNING
Definition: elog.h:40
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
char * NameListToString(List *names)
Definition: namespace.c:3102
Definition: c.h:583
void UpdateStatisticsForTypeChange(Oid statsOid, Oid relationOid, int attnum, Oid oldColumnType, Oid newColumnType)
Definition: statscmds.c:604
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
struct @17::@18 av[32]
static char * label
Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: relation.c:138
TupleDesc rd_att
Definition: rel.h:110
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:331
#define InvalidOid
Definition: postgres_ext.h:36
int16 attnum
Definition: pg_attribute.h:79
#define ereport(elevel,...)
Definition: elog.h:144
#define NOTICE
Definition: elog.h:37
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
#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:738
#define lfirst(lc)
Definition: pg_list.h:190
#define StrNCpy(dst, src, len)
Definition: c.h:944
Definition: value.h:42
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4720
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:194
static char * ChooseExtendedStatisticNameAddition(List *exprs)
Definition: statscmds.c:718
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
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:1257
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
const char * name
Definition: encode.c:555
#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:824
#define elog(elevel,...)
Definition: elog.h:214
int i
ObjectType get_relkind_objtype(char relkind)
#define TYPECACHE_LT_OPR
Definition: typcache.h:131
#define StatisticExtOidIndexId
Definition: indexing.h:231
#define qsort(a, b, c, d)
Definition: port.h:479
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
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31
Definition: pg_list.h:50
#define snprintf
Definition: port.h:193
#define RelationGetRelid(relation)
Definition: rel.h:456
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:183
List * fields
Definition: parsenodes.h:236
FormData_pg_statistic_ext * Form_pg_statistic_ext
#define RelationGetNamespace(relation)
Definition: rel.h:497
bool pg_statistics_object_ownercheck(Oid stat_oid, Oid roleid)
Definition: aclchk.c:5310
ObjectAddress CreateStatistics(CreateStatsStmt *stmt)
Definition: statscmds.c:62