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-2019, 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, '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 }
420 
421 /*
422  * ALTER STATISTICS
423  */
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 }
524 
525 /*
526  * Guts of statistics object deletion.
527  */
528 void
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 }
575 
576 /*
577  * Update a statistics object for ALTER COLUMN TYPE on a source column.
578  *
579  * This could throw an error if the type change can't be supported.
580  * If it can be supported, but the stats must be recomputed, a likely choice
581  * would be to set the relevant column(s) of the pg_statistic_ext_data tuple
582  * to null until the next ANALYZE. (Note that the type change hasn't actually
583  * happened yet, so one option that's *not* on the table is to recompute
584  * immediately.)
585  *
586  * For both ndistinct and functional-dependencies stats, the on-disk
587  * representation is independent of the source column data types, and it is
588  * plausible to assume that the old statistic values will still be good for
589  * the new column contents. (Obviously, if the ALTER COLUMN TYPE has a USING
590  * expression that substantially alters the semantic meaning of the column
591  * values, this assumption could fail. But that seems like a corner case
592  * that doesn't justify zapping the stats in common cases.)
593  *
594  * For MCV lists that's not the case, as those statistics store the datums
595  * internally. In this case we simply reset the statistics value to NULL.
596  *
597  * Note that "type change" includes collation change, which means we can rely
598  * on the MCV list being consistent with the collation info in pg_attribute
599  * during estimation.
600  */
601 void
602 UpdateStatisticsForTypeChange(Oid statsOid, Oid relationOid, int attnum,
603  Oid oldColumnType, Oid newColumnType)
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 }
656 
657 /*
658  * Select a nonconflicting name for a new statistics.
659  *
660  * name1, name2, and label are used the same way as for makeObjectName(),
661  * except that the label can't be NULL; digits will be appended to the label
662  * if needed to create a name that is unique within the specified namespace.
663  *
664  * Returns a palloc'd string.
665  *
666  * Note: it is theoretically possible to get a collision anyway, if someone
667  * else chooses the same name concurrently. This is fairly unlikely to be
668  * a problem in practice, especially if one is holding a share update
669  * exclusive lock on the relation identified by name1. However, if choosing
670  * multiple names within a single command, you'd better create the new object
671  * and do CommandCounterIncrement before choosing the next one!
672  */
673 static char *
674 ChooseExtendedStatisticName(const char *name1, const char *name2,
675  const char *label, Oid namespaceid)
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 }
703 
704 /*
705  * Generate "name2" for a new statistics given the list of column names for it
706  * This will be passed to ChooseExtendedStatisticName along with the parent
707  * table name and a suitable label.
708  *
709  * We know that less than NAMEDATALEN characters will actually be used,
710  * so we can truncate the result once we've generated that many.
711  *
712  * XXX see also ChooseForeignKeyConstraintNameAddition and
713  * ChooseIndexNameAddition.
714  */
715 static char *
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 }
signed short int16
Definition: c.h:346
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:322
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
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:674
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
void RemoveStatisticsById(Oid statsOid)
Definition: statscmds.c:529
struct typedefs * types
Definition: ecpg.c:29
#define RelationGetDescr(relation)
Definition: rel.h:448
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
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:3291
Definition: nodes.h:525
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:608
char * format_type_be(Oid type_oid)
Definition: format_type.c:326
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:2801
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:669
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
#define OidIsValid(objectId)
Definition: c.h:645
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition: indexcmds.c:2048
#define NAMEDATALEN
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
ObjectAddress AlterStatistics(AlterStatsStmt *stmt)
Definition: statscmds.c:425
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:2170
Definition: c.h:610
#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:456
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
#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:3094
struct @18::@19 av[32]
Definition: c.h:584
void UpdateStatisticsForTypeChange(Oid statsOid, Oid relationOid, int attnum, Oid oldColumnType, Oid newColumnType)
Definition: statscmds.c:602
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
static char * label
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
int16 attnum
Definition: pg_attribute.h:79
#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:739
#define lfirst(lc)
Definition: pg_list.h:190
#define StrNCpy(dst, src, len)
Definition: c.h:935
Definition: value.h:42
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4753
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:194
static char * ChooseExtendedStatisticNameAddition(List *exprs)
Definition: statscmds.c:716
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:521
#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:822
#define elog(elevel,...)
Definition: elog.h:228
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:488
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:192
#define RelationGetRelid(relation)
Definition: rel.h:422
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:183
List * fields
Definition: parsenodes.h:235
FormData_pg_statistic_ext * Form_pg_statistic_ext
#define RelationGetNamespace(relation)
Definition: rel.h:463
bool pg_statistics_object_ownercheck(Oid stat_oid, Oid roleid)
Definition: aclchk.c:5343
ObjectAddress CreateStatistics(CreateStatsStmt *stmt)
Definition: statscmds.c:62