PostgreSQL Source Code  git master
indexcmds.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * indexcmds.c
4  * POSTGRES define and remove index code.
5  *
6  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/commands/indexcmds.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 
16 #include "postgres.h"
17 
18 #include "access/amapi.h"
19 #include "access/gist.h"
20 #include "access/heapam.h"
21 #include "access/htup_details.h"
22 #include "access/reloptions.h"
23 #include "access/sysattr.h"
24 #include "access/tableam.h"
25 #include "access/xact.h"
26 #include "catalog/catalog.h"
27 #include "catalog/index.h"
28 #include "catalog/indexing.h"
29 #include "catalog/namespace.h"
30 #include "catalog/pg_am.h"
31 #include "catalog/pg_authid.h"
32 #include "catalog/pg_constraint.h"
33 #include "catalog/pg_database.h"
34 #include "catalog/pg_inherits.h"
35 #include "catalog/pg_namespace.h"
36 #include "catalog/pg_opclass.h"
37 #include "catalog/pg_opfamily.h"
38 #include "catalog/pg_tablespace.h"
39 #include "catalog/pg_type.h"
40 #include "commands/comment.h"
41 #include "commands/dbcommands.h"
42 #include "commands/defrem.h"
43 #include "commands/event_trigger.h"
44 #include "commands/progress.h"
45 #include "commands/tablecmds.h"
46 #include "commands/tablespace.h"
47 #include "mb/pg_wchar.h"
48 #include "miscadmin.h"
49 #include "nodes/makefuncs.h"
50 #include "nodes/nodeFuncs.h"
51 #include "optimizer/optimizer.h"
52 #include "parser/parse_coerce.h"
53 #include "parser/parse_oper.h"
54 #include "parser/parse_utilcmd.h"
55 #include "partitioning/partdesc.h"
56 #include "pgstat.h"
57 #include "rewrite/rewriteManip.h"
58 #include "storage/lmgr.h"
59 #include "storage/proc.h"
60 #include "storage/procarray.h"
61 #include "storage/sinvaladt.h"
62 #include "utils/acl.h"
63 #include "utils/builtins.h"
64 #include "utils/fmgroids.h"
65 #include "utils/guc.h"
66 #include "utils/injection_point.h"
67 #include "utils/inval.h"
68 #include "utils/lsyscache.h"
69 #include "utils/memutils.h"
70 #include "utils/partcache.h"
71 #include "utils/pg_rusage.h"
72 #include "utils/regproc.h"
73 #include "utils/snapmgr.h"
74 #include "utils/syscache.h"
75 
76 
77 /* non-export function prototypes */
78 static bool CompareOpclassOptions(const Datum *opts1, const Datum *opts2, int natts);
79 static void CheckPredicate(Expr *predicate);
80 static void ComputeIndexAttrs(IndexInfo *indexInfo,
81  Oid *typeOids,
82  Oid *collationOids,
83  Oid *opclassOids,
84  Datum *opclassOptions,
85  int16 *colOptions,
86  const List *attList,
87  const List *exclusionOpNames,
88  Oid relId,
89  const char *accessMethodName,
90  Oid accessMethodId,
91  bool amcanorder,
92  bool isconstraint,
93  bool iswithoutoverlaps,
94  Oid ddl_userid,
95  int ddl_sec_context,
96  int *ddl_save_nestlevel);
97 static char *ChooseIndexName(const char *tabname, Oid namespaceId,
98  const List *colnames, const List *exclusionOpNames,
99  bool primary, bool isconstraint);
100 static char *ChooseIndexNameAddition(const List *colnames);
101 static List *ChooseIndexColumnNames(const List *indexElems);
102 static void ReindexIndex(const ReindexStmt *stmt, const ReindexParams *params,
103  bool isTopLevel);
104 static void RangeVarCallbackForReindexIndex(const RangeVar *relation,
105  Oid relId, Oid oldRelId, void *arg);
106 static Oid ReindexTable(const ReindexStmt *stmt, const ReindexParams *params,
107  bool isTopLevel);
108 static void ReindexMultipleTables(const ReindexStmt *stmt,
109  const ReindexParams *params);
110 static void reindex_error_callback(void *arg);
111 static void ReindexPartitions(const ReindexStmt *stmt, Oid relid,
112  const ReindexParams *params, bool isTopLevel);
113 static void ReindexMultipleInternal(const ReindexStmt *stmt, const List *relids,
114  const ReindexParams *params);
115 static bool ReindexRelationConcurrently(const ReindexStmt *stmt,
116  Oid relationOid,
117  const ReindexParams *params);
118 static void update_relispartition(Oid relationId, bool newval);
119 static inline void set_indexsafe_procflags(void);
120 
121 /*
122  * callback argument type for RangeVarCallbackForReindexIndex()
123  */
125 {
126  ReindexParams params; /* options from statement */
127  Oid locked_table_oid; /* tracks previously locked table */
128 };
129 
130 /*
131  * callback arguments for reindex_error_callback()
132  */
133 typedef struct ReindexErrorInfo
134 {
135  char *relname;
137  char relkind;
139 
140 /*
141  * CheckIndexCompatible
142  * Determine whether an existing index definition is compatible with a
143  * prospective index definition, such that the existing index storage
144  * could become the storage of the new index, avoiding a rebuild.
145  *
146  * 'oldId': the OID of the existing index
147  * 'accessMethodName': name of the AM to use.
148  * 'attributeList': a list of IndexElem specifying columns and expressions
149  * to index on.
150  * 'exclusionOpNames': list of names of exclusion-constraint operators,
151  * or NIL if not an exclusion constraint.
152  * 'isWithoutOverlaps': true iff this index has a WITHOUT OVERLAPS clause.
153  *
154  * This is tailored to the needs of ALTER TABLE ALTER TYPE, which recreates
155  * any indexes that depended on a changing column from their pg_get_indexdef
156  * or pg_get_constraintdef definitions. We omit some of the sanity checks of
157  * DefineIndex. We assume that the old and new indexes have the same number
158  * of columns and that if one has an expression column or predicate, both do.
159  * Errors arising from the attribute list still apply.
160  *
161  * Most column type changes that can skip a table rewrite do not invalidate
162  * indexes. We acknowledge this when all operator classes, collations and
163  * exclusion operators match. Though we could further permit intra-opfamily
164  * changes for btree and hash indexes, that adds subtle complexity with no
165  * concrete benefit for core types. Note, that INCLUDE columns aren't
166  * checked by this function, for them it's enough that table rewrite is
167  * skipped.
168  *
169  * When a comparison or exclusion operator has a polymorphic input type, the
170  * actual input types must also match. This defends against the possibility
171  * that operators could vary behavior in response to get_fn_expr_argtype().
172  * At present, this hazard is theoretical: check_exclusion_constraint() and
173  * all core index access methods decline to set fn_expr for such calls.
174  *
175  * We do not yet implement a test to verify compatibility of expression
176  * columns or predicates, so assume any such index is incompatible.
177  */
178 bool
180  const char *accessMethodName,
181  const List *attributeList,
182  const List *exclusionOpNames,
183  bool isWithoutOverlaps)
184 {
185  bool isconstraint;
186  Oid *typeIds;
187  Oid *collationIds;
188  Oid *opclassIds;
189  Datum *opclassOptions;
190  Oid accessMethodId;
191  Oid relationId;
192  HeapTuple tuple;
193  Form_pg_index indexForm;
194  Form_pg_am accessMethodForm;
195  IndexAmRoutine *amRoutine;
196  bool amcanorder;
197  bool amsummarizing;
198  int16 *coloptions;
199  IndexInfo *indexInfo;
200  int numberOfAttributes;
201  int old_natts;
202  bool ret = true;
203  oidvector *old_indclass;
204  oidvector *old_indcollation;
205  Relation irel;
206  int i;
207  Datum d;
208 
209  /* Caller should already have the relation locked in some way. */
210  relationId = IndexGetRelation(oldId, false);
211 
212  /*
213  * We can pretend isconstraint = false unconditionally. It only serves to
214  * decide the text of an error message that should never happen for us.
215  */
216  isconstraint = false;
217 
218  numberOfAttributes = list_length(attributeList);
219  Assert(numberOfAttributes > 0);
220  Assert(numberOfAttributes <= INDEX_MAX_KEYS);
221 
222  /* look up the access method */
223  tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
224  if (!HeapTupleIsValid(tuple))
225  ereport(ERROR,
226  (errcode(ERRCODE_UNDEFINED_OBJECT),
227  errmsg("access method \"%s\" does not exist",
228  accessMethodName)));
229  accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
230  accessMethodId = accessMethodForm->oid;
231  amRoutine = GetIndexAmRoutine(accessMethodForm->amhandler);
232  ReleaseSysCache(tuple);
233 
234  amcanorder = amRoutine->amcanorder;
235  amsummarizing = amRoutine->amsummarizing;
236 
237  /*
238  * Compute the operator classes, collations, and exclusion operators for
239  * the new index, so we can test whether it's compatible with the existing
240  * one. Note that ComputeIndexAttrs might fail here, but that's OK:
241  * DefineIndex would have failed later. Our attributeList contains only
242  * key attributes, thus we're filling ii_NumIndexAttrs and
243  * ii_NumIndexKeyAttrs with same value.
244  */
245  indexInfo = makeIndexInfo(numberOfAttributes, numberOfAttributes,
246  accessMethodId, NIL, NIL, false, false,
247  false, false, amsummarizing, isWithoutOverlaps);
248  typeIds = palloc_array(Oid, numberOfAttributes);
249  collationIds = palloc_array(Oid, numberOfAttributes);
250  opclassIds = palloc_array(Oid, numberOfAttributes);
251  opclassOptions = palloc_array(Datum, numberOfAttributes);
252  coloptions = palloc_array(int16, numberOfAttributes);
253  ComputeIndexAttrs(indexInfo,
254  typeIds, collationIds, opclassIds, opclassOptions,
255  coloptions, attributeList,
256  exclusionOpNames, relationId,
257  accessMethodName, accessMethodId,
258  amcanorder, isconstraint, isWithoutOverlaps, InvalidOid,
259  0, NULL);
260 
261  /* Get the soon-obsolete pg_index tuple. */
262  tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(oldId));
263  if (!HeapTupleIsValid(tuple))
264  elog(ERROR, "cache lookup failed for index %u", oldId);
265  indexForm = (Form_pg_index) GETSTRUCT(tuple);
266 
267  /*
268  * We don't assess expressions or predicates; assume incompatibility.
269  * Also, if the index is invalid for any reason, treat it as incompatible.
270  */
271  if (!(heap_attisnull(tuple, Anum_pg_index_indpred, NULL) &&
272  heap_attisnull(tuple, Anum_pg_index_indexprs, NULL) &&
273  indexForm->indisvalid))
274  {
275  ReleaseSysCache(tuple);
276  return false;
277  }
278 
279  /* Any change in operator class or collation breaks compatibility. */
280  old_natts = indexForm->indnkeyatts;
281  Assert(old_natts == numberOfAttributes);
282 
283  d = SysCacheGetAttrNotNull(INDEXRELID, tuple, Anum_pg_index_indcollation);
284  old_indcollation = (oidvector *) DatumGetPointer(d);
285 
286  d = SysCacheGetAttrNotNull(INDEXRELID, tuple, Anum_pg_index_indclass);
287  old_indclass = (oidvector *) DatumGetPointer(d);
288 
289  ret = (memcmp(old_indclass->values, opclassIds, old_natts * sizeof(Oid)) == 0 &&
290  memcmp(old_indcollation->values, collationIds, old_natts * sizeof(Oid)) == 0);
291 
292  ReleaseSysCache(tuple);
293 
294  if (!ret)
295  return false;
296 
297  /* For polymorphic opcintype, column type changes break compatibility. */
298  irel = index_open(oldId, AccessShareLock); /* caller probably has a lock */
299  for (i = 0; i < old_natts; i++)
300  {
301  if (IsPolymorphicType(get_opclass_input_type(opclassIds[i])) &&
302  TupleDescAttr(irel->rd_att, i)->atttypid != typeIds[i])
303  {
304  ret = false;
305  break;
306  }
307  }
308 
309  /* Any change in opclass options break compatibility. */
310  if (ret)
311  {
312  Datum *oldOpclassOptions = palloc_array(Datum, old_natts);
313 
314  for (i = 0; i < old_natts; i++)
315  oldOpclassOptions[i] = get_attoptions(oldId, i + 1);
316 
317  ret = CompareOpclassOptions(oldOpclassOptions, opclassOptions, old_natts);
318 
319  pfree(oldOpclassOptions);
320  }
321 
322  /* Any change in exclusion operator selections breaks compatibility. */
323  if (ret && indexInfo->ii_ExclusionOps != NULL)
324  {
325  Oid *old_operators,
326  *old_procs;
327  uint16 *old_strats;
328 
329  RelationGetExclusionInfo(irel, &old_operators, &old_procs, &old_strats);
330  ret = memcmp(old_operators, indexInfo->ii_ExclusionOps,
331  old_natts * sizeof(Oid)) == 0;
332 
333  /* Require an exact input type match for polymorphic operators. */
334  if (ret)
335  {
336  for (i = 0; i < old_natts && ret; i++)
337  {
338  Oid left,
339  right;
340 
341  op_input_types(indexInfo->ii_ExclusionOps[i], &left, &right);
342  if ((IsPolymorphicType(left) || IsPolymorphicType(right)) &&
343  TupleDescAttr(irel->rd_att, i)->atttypid != typeIds[i])
344  {
345  ret = false;
346  break;
347  }
348  }
349  }
350  }
351 
352  index_close(irel, NoLock);
353  return ret;
354 }
355 
356 /*
357  * CompareOpclassOptions
358  *
359  * Compare per-column opclass options which are represented by arrays of text[]
360  * datums. Both elements of arrays and array themselves can be NULL.
361  */
362 static bool
363 CompareOpclassOptions(const Datum *opts1, const Datum *opts2, int natts)
364 {
365  int i;
366 
367  if (!opts1 && !opts2)
368  return true;
369 
370  for (i = 0; i < natts; i++)
371  {
372  Datum opt1 = opts1 ? opts1[i] : (Datum) 0;
373  Datum opt2 = opts2 ? opts2[i] : (Datum) 0;
374 
375  if (opt1 == (Datum) 0)
376  {
377  if (opt2 == (Datum) 0)
378  continue;
379  else
380  return false;
381  }
382  else if (opt2 == (Datum) 0)
383  return false;
384 
385  /* Compare non-NULL text[] datums. */
386  if (!DatumGetBool(DirectFunctionCall2(array_eq, opt1, opt2)))
387  return false;
388  }
389 
390  return true;
391 }
392 
393 /*
394  * WaitForOlderSnapshots
395  *
396  * Wait for transactions that might have an older snapshot than the given xmin
397  * limit, because it might not contain tuples deleted just before it has
398  * been taken. Obtain a list of VXIDs of such transactions, and wait for them
399  * individually. This is used when building an index concurrently.
400  *
401  * We can exclude any running transactions that have xmin > the xmin given;
402  * their oldest snapshot must be newer than our xmin limit.
403  * We can also exclude any transactions that have xmin = zero, since they
404  * evidently have no live snapshot at all (and any one they might be in
405  * process of taking is certainly newer than ours). Transactions in other
406  * DBs can be ignored too, since they'll never even be able to see the
407  * index being worked on.
408  *
409  * We can also exclude autovacuum processes and processes running manual
410  * lazy VACUUMs, because they won't be fazed by missing index entries
411  * either. (Manual ANALYZEs, however, can't be excluded because they
412  * might be within transactions that are going to do arbitrary operations
413  * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY
414  * on indexes that are neither expressional nor partial are also safe to
415  * ignore, since we know that those processes won't examine any data
416  * outside the table they're indexing.
417  *
418  * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not
419  * check for that.
420  *
421  * If a process goes idle-in-transaction with xmin zero, we do not need to
422  * wait for it anymore, per the above argument. We do not have the
423  * infrastructure right now to stop waiting if that happens, but we can at
424  * least avoid the folly of waiting when it is idle at the time we would
425  * begin to wait. We do this by repeatedly rechecking the output of
426  * GetCurrentVirtualXIDs. If, during any iteration, a particular vxid
427  * doesn't show up in the output, we know we can forget about it.
428  */
429 void
431 {
432  int n_old_snapshots;
433  int i;
434  VirtualTransactionId *old_snapshots;
435 
436  old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false,
438  | PROC_IN_SAFE_IC,
439  &n_old_snapshots);
440  if (progress)
442 
443  for (i = 0; i < n_old_snapshots; i++)
444  {
445  if (!VirtualTransactionIdIsValid(old_snapshots[i]))
446  continue; /* found uninteresting in previous cycle */
447 
448  if (i > 0)
449  {
450  /* see if anything's changed ... */
451  VirtualTransactionId *newer_snapshots;
452  int n_newer_snapshots;
453  int j;
454  int k;
455 
456  newer_snapshots = GetCurrentVirtualXIDs(limitXmin,
457  true, false,
459  | PROC_IN_SAFE_IC,
460  &n_newer_snapshots);
461  for (j = i; j < n_old_snapshots; j++)
462  {
463  if (!VirtualTransactionIdIsValid(old_snapshots[j]))
464  continue; /* found uninteresting in previous cycle */
465  for (k = 0; k < n_newer_snapshots; k++)
466  {
467  if (VirtualTransactionIdEquals(old_snapshots[j],
468  newer_snapshots[k]))
469  break;
470  }
471  if (k >= n_newer_snapshots) /* not there anymore */
472  SetInvalidVirtualTransactionId(old_snapshots[j]);
473  }
474  pfree(newer_snapshots);
475  }
476 
477  if (VirtualTransactionIdIsValid(old_snapshots[i]))
478  {
479  /* If requested, publish who we're going to wait for. */
480  if (progress)
481  {
482  PGPROC *holder = ProcNumberGetProc(old_snapshots[i].procNumber);
483 
484  if (holder)
486  holder->pid);
487  }
488  VirtualXactLock(old_snapshots[i], true);
489  }
490 
491  if (progress)
493  }
494 }
495 
496 
497 /*
498  * DefineIndex
499  * Creates a new index.
500  *
501  * This function manages the current userid according to the needs of pg_dump.
502  * Recreating old-database catalog entries in new-database is fine, regardless
503  * of which users would have permission to recreate those entries now. That's
504  * just preservation of state. Running opaque expressions, like calling a
505  * function named in a catalog entry or evaluating a pg_node_tree in a catalog
506  * entry, as anyone other than the object owner, is not fine. To adhere to
507  * those principles and to remain fail-safe, use the table owner userid for
508  * most ACL checks. Use the original userid for ACL checks reached without
509  * traversing opaque expressions. (pg_dump can predict such ACL checks from
510  * catalogs.) Overall, this is a mess. Future DDL development should
511  * consider offering one DDL command for catalog setup and a separate DDL
512  * command for steps that run opaque expressions.
513  *
514  * 'tableId': the OID of the table relation on which the index is to be
515  * created
516  * 'stmt': IndexStmt describing the properties of the new index.
517  * 'indexRelationId': normally InvalidOid, but during bootstrap can be
518  * nonzero to specify a preselected OID for the index.
519  * 'parentIndexId': the OID of the parent index; InvalidOid if not the child
520  * of a partitioned index.
521  * 'parentConstraintId': the OID of the parent constraint; InvalidOid if not
522  * the child of a constraint (only used when recursing)
523  * 'total_parts': total number of direct and indirect partitions of relation;
524  * pass -1 if not known or rel is not partitioned.
525  * 'is_alter_table': this is due to an ALTER rather than a CREATE operation.
526  * 'check_rights': check for CREATE rights in namespace and tablespace. (This
527  * should be true except when ALTER is deleting/recreating an index.)
528  * 'check_not_in_use': check for table not already in use in current session.
529  * This should be true unless caller is holding the table open, in which
530  * case the caller had better have checked it earlier.
531  * 'skip_build': make the catalog entries but don't create the index files
532  * 'quiet': suppress the NOTICE chatter ordinarily provided for constraints.
533  *
534  * Returns the object address of the created index.
535  */
537 DefineIndex(Oid tableId,
538  IndexStmt *stmt,
539  Oid indexRelationId,
540  Oid parentIndexId,
541  Oid parentConstraintId,
542  int total_parts,
543  bool is_alter_table,
544  bool check_rights,
545  bool check_not_in_use,
546  bool skip_build,
547  bool quiet)
548 {
549  bool concurrent;
550  char *indexRelationName;
551  char *accessMethodName;
552  Oid *typeIds;
553  Oid *collationIds;
554  Oid *opclassIds;
555  Datum *opclassOptions;
556  Oid accessMethodId;
557  Oid namespaceId;
558  Oid tablespaceId;
559  Oid createdConstraintId = InvalidOid;
560  List *indexColNames;
561  List *allIndexParams;
562  Relation rel;
563  HeapTuple tuple;
564  Form_pg_am accessMethodForm;
565  IndexAmRoutine *amRoutine;
566  bool amcanorder;
567  bool amissummarizing;
568  amoptions_function amoptions;
569  bool exclusion;
570  bool partitioned;
571  bool safe_index;
572  Datum reloptions;
573  int16 *coloptions;
574  IndexInfo *indexInfo;
575  bits16 flags;
576  bits16 constr_flags;
577  int numberOfAttributes;
578  int numberOfKeyAttributes;
579  TransactionId limitXmin;
580  ObjectAddress address;
581  LockRelId heaprelid;
582  LOCKTAG heaplocktag;
583  LOCKMODE lockmode;
584  Snapshot snapshot;
585  Oid root_save_userid;
586  int root_save_sec_context;
587  int root_save_nestlevel;
588 
589  root_save_nestlevel = NewGUCNestLevel();
590 
592 
593  /*
594  * Some callers need us to run with an empty default_tablespace; this is a
595  * necessary hack to be able to reproduce catalog state accurately when
596  * recreating indexes after table-rewriting ALTER TABLE.
597  */
598  if (stmt->reset_default_tblspc)
599  (void) set_config_option("default_tablespace", "",
601  GUC_ACTION_SAVE, true, 0, false);
602 
603  /*
604  * Force non-concurrent build on temporary relations, even if CONCURRENTLY
605  * was requested. Other backends can't access a temporary relation, so
606  * there's no harm in grabbing a stronger lock, and a non-concurrent DROP
607  * is more efficient. Do this before any use of the concurrent option is
608  * done.
609  */
610  if (stmt->concurrent && get_rel_persistence(tableId) != RELPERSISTENCE_TEMP)
611  concurrent = true;
612  else
613  concurrent = false;
614 
615  /*
616  * Start progress report. If we're building a partition, this was already
617  * done.
618  */
619  if (!OidIsValid(parentIndexId))
620  {
623  concurrent ?
626  }
627 
628  /*
629  * No index OID to report yet
630  */
632  InvalidOid);
633 
634  /*
635  * count key attributes in index
636  */
637  numberOfKeyAttributes = list_length(stmt->indexParams);
638 
639  /*
640  * Calculate the new list of index columns including both key columns and
641  * INCLUDE columns. Later we can determine which of these are key
642  * columns, and which are just part of the INCLUDE list by checking the
643  * list position. A list item in a position less than ii_NumIndexKeyAttrs
644  * is part of the key columns, and anything equal to and over is part of
645  * the INCLUDE columns.
646  */
647  allIndexParams = list_concat_copy(stmt->indexParams,
648  stmt->indexIncludingParams);
649  numberOfAttributes = list_length(allIndexParams);
650 
651  if (numberOfKeyAttributes <= 0)
652  ereport(ERROR,
653  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
654  errmsg("must specify at least one column")));
655  if (numberOfAttributes > INDEX_MAX_KEYS)
656  ereport(ERROR,
657  (errcode(ERRCODE_TOO_MANY_COLUMNS),
658  errmsg("cannot use more than %d columns in an index",
659  INDEX_MAX_KEYS)));
660 
661  /*
662  * Only SELECT ... FOR UPDATE/SHARE are allowed while doing a standard
663  * index build; but for concurrent builds we allow INSERT/UPDATE/DELETE
664  * (but not VACUUM).
665  *
666  * NB: Caller is responsible for making sure that tableId refers to the
667  * relation on which the index should be built; except in bootstrap mode,
668  * this will typically require the caller to have already locked the
669  * relation. To avoid lock upgrade hazards, that lock should be at least
670  * as strong as the one we take here.
671  *
672  * NB: If the lock strength here ever changes, code that is run by
673  * parallel workers under the control of certain particular ambuild
674  * functions will need to be updated, too.
675  */
676  lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock;
677  rel = table_open(tableId, lockmode);
678 
679  /*
680  * Switch to the table owner's userid, so that any index functions are run
681  * as that user. Also lock down security-restricted operations. We
682  * already arranged to make GUC variable changes local to this command.
683  */
684  GetUserIdAndSecContext(&root_save_userid, &root_save_sec_context);
685  SetUserIdAndSecContext(rel->rd_rel->relowner,
686  root_save_sec_context | SECURITY_RESTRICTED_OPERATION);
687 
688  namespaceId = RelationGetNamespace(rel);
689 
690  /*
691  * It has exclusion constraint behavior if it's an EXCLUDE constraint or a
692  * temporal PRIMARY KEY/UNIQUE constraint
693  */
694  exclusion = stmt->excludeOpNames || stmt->iswithoutoverlaps;
695 
696  /* Ensure that it makes sense to index this kind of relation */
697  switch (rel->rd_rel->relkind)
698  {
699  case RELKIND_RELATION:
700  case RELKIND_MATVIEW:
701  case RELKIND_PARTITIONED_TABLE:
702  /* OK */
703  break;
704  default:
705  ereport(ERROR,
706  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
707  errmsg("cannot create index on relation \"%s\"",
709  errdetail_relkind_not_supported(rel->rd_rel->relkind)));
710  break;
711  }
712 
713  /*
714  * Establish behavior for partitioned tables, and verify sanity of
715  * parameters.
716  *
717  * We do not build an actual index in this case; we only create a few
718  * catalog entries. The actual indexes are built by recursing for each
719  * partition.
720  */
721  partitioned = rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE;
722  if (partitioned)
723  {
724  /*
725  * Note: we check 'stmt->concurrent' rather than 'concurrent', so that
726  * the error is thrown also for temporary tables. Seems better to be
727  * consistent, even though we could do it on temporary table because
728  * we're not actually doing it concurrently.
729  */
730  if (stmt->concurrent)
731  ereport(ERROR,
732  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
733  errmsg("cannot create index on partitioned table \"%s\" concurrently",
734  RelationGetRelationName(rel))));
735  }
736 
737  /*
738  * Don't try to CREATE INDEX on temp tables of other backends.
739  */
740  if (RELATION_IS_OTHER_TEMP(rel))
741  ereport(ERROR,
742  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
743  errmsg("cannot create indexes on temporary tables of other sessions")));
744 
745  /*
746  * Unless our caller vouches for having checked this already, insist that
747  * the table not be in use by our own session, either. Otherwise we might
748  * fail to make entries in the new index (for instance, if an INSERT or
749  * UPDATE is in progress and has already made its list of target indexes).
750  */
751  if (check_not_in_use)
752  CheckTableNotInUse(rel, "CREATE INDEX");
753 
754  /*
755  * Verify we (still) have CREATE rights in the rel's namespace.
756  * (Presumably we did when the rel was created, but maybe not anymore.)
757  * Skip check if caller doesn't want it. Also skip check if
758  * bootstrapping, since permissions machinery may not be working yet.
759  */
760  if (check_rights && !IsBootstrapProcessingMode())
761  {
762  AclResult aclresult;
763 
764  aclresult = object_aclcheck(NamespaceRelationId, namespaceId, root_save_userid,
765  ACL_CREATE);
766  if (aclresult != ACLCHECK_OK)
767  aclcheck_error(aclresult, OBJECT_SCHEMA,
768  get_namespace_name(namespaceId));
769  }
770 
771  /*
772  * Select tablespace to use. If not specified, use default tablespace
773  * (which may in turn default to database's default).
774  */
775  if (stmt->tableSpace)
776  {
777  tablespaceId = get_tablespace_oid(stmt->tableSpace, false);
778  if (partitioned && tablespaceId == MyDatabaseTableSpace)
779  ereport(ERROR,
780  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
781  errmsg("cannot specify default tablespace for partitioned relations")));
782  }
783  else
784  {
785  tablespaceId = GetDefaultTablespace(rel->rd_rel->relpersistence,
786  partitioned);
787  /* note InvalidOid is OK in this case */
788  }
789 
790  /* Check tablespace permissions */
791  if (check_rights &&
792  OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
793  {
794  AclResult aclresult;
795 
796  aclresult = object_aclcheck(TableSpaceRelationId, tablespaceId, root_save_userid,
797  ACL_CREATE);
798  if (aclresult != ACLCHECK_OK)
800  get_tablespace_name(tablespaceId));
801  }
802 
803  /*
804  * Force shared indexes into the pg_global tablespace. This is a bit of a
805  * hack but seems simpler than marking them in the BKI commands. On the
806  * other hand, if it's not shared, don't allow it to be placed there.
807  */
808  if (rel->rd_rel->relisshared)
809  tablespaceId = GLOBALTABLESPACE_OID;
810  else if (tablespaceId == GLOBALTABLESPACE_OID)
811  ereport(ERROR,
812  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
813  errmsg("only shared relations can be placed in pg_global tablespace")));
814 
815  /*
816  * Choose the index column names.
817  */
818  indexColNames = ChooseIndexColumnNames(allIndexParams);
819 
820  /*
821  * Select name for index if caller didn't specify
822  */
823  indexRelationName = stmt->idxname;
824  if (indexRelationName == NULL)
825  indexRelationName = ChooseIndexName(RelationGetRelationName(rel),
826  namespaceId,
827  indexColNames,
828  stmt->excludeOpNames,
829  stmt->primary,
830  stmt->isconstraint);
831 
832  /*
833  * look up the access method, verify it can handle the requested features
834  */
835  accessMethodName = stmt->accessMethod;
836  tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
837  if (!HeapTupleIsValid(tuple))
838  {
839  /*
840  * Hack to provide more-or-less-transparent updating of old RTREE
841  * indexes to GiST: if RTREE is requested and not found, use GIST.
842  */
843  if (strcmp(accessMethodName, "rtree") == 0)
844  {
845  ereport(NOTICE,
846  (errmsg("substituting access method \"gist\" for obsolete method \"rtree\"")));
847  accessMethodName = "gist";
848  tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
849  }
850 
851  if (!HeapTupleIsValid(tuple))
852  ereport(ERROR,
853  (errcode(ERRCODE_UNDEFINED_OBJECT),
854  errmsg("access method \"%s\" does not exist",
855  accessMethodName)));
856  }
857  accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
858  accessMethodId = accessMethodForm->oid;
859  amRoutine = GetIndexAmRoutine(accessMethodForm->amhandler);
860 
862  accessMethodId);
863 
864  if (stmt->unique && !stmt->iswithoutoverlaps && !amRoutine->amcanunique)
865  ereport(ERROR,
866  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
867  errmsg("access method \"%s\" does not support unique indexes",
868  accessMethodName)));
869  if (stmt->indexIncludingParams != NIL && !amRoutine->amcaninclude)
870  ereport(ERROR,
871  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
872  errmsg("access method \"%s\" does not support included columns",
873  accessMethodName)));
874  if (numberOfKeyAttributes > 1 && !amRoutine->amcanmulticol)
875  ereport(ERROR,
876  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
877  errmsg("access method \"%s\" does not support multicolumn indexes",
878  accessMethodName)));
879  if (exclusion && amRoutine->amgettuple == NULL)
880  ereport(ERROR,
881  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
882  errmsg("access method \"%s\" does not support exclusion constraints",
883  accessMethodName)));
884  if (stmt->iswithoutoverlaps && strcmp(accessMethodName, "gist") != 0)
885  ereport(ERROR,
886  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
887  errmsg("access method \"%s\" does not support WITHOUT OVERLAPS constraints",
888  accessMethodName)));
889 
890  amcanorder = amRoutine->amcanorder;
891  amoptions = amRoutine->amoptions;
892  amissummarizing = amRoutine->amsummarizing;
893 
894  pfree(amRoutine);
895  ReleaseSysCache(tuple);
896 
897  /*
898  * Validate predicate, if given
899  */
900  if (stmt->whereClause)
901  CheckPredicate((Expr *) stmt->whereClause);
902 
903  /*
904  * Parse AM-specific options, convert to text array form, validate.
905  */
906  reloptions = transformRelOptions((Datum) 0, stmt->options,
907  NULL, NULL, false, false);
908 
909  (void) index_reloptions(amoptions, reloptions, true);
910 
911  /*
912  * Prepare arguments for index_create, primarily an IndexInfo structure.
913  * Note that predicates must be in implicit-AND format. In a concurrent
914  * build, mark it not-ready-for-inserts.
915  */
916  indexInfo = makeIndexInfo(numberOfAttributes,
917  numberOfKeyAttributes,
918  accessMethodId,
919  NIL, /* expressions, NIL for now */
920  make_ands_implicit((Expr *) stmt->whereClause),
921  stmt->unique,
922  stmt->nulls_not_distinct,
923  !concurrent,
924  concurrent,
925  amissummarizing,
926  stmt->iswithoutoverlaps);
927 
928  typeIds = palloc_array(Oid, numberOfAttributes);
929  collationIds = palloc_array(Oid, numberOfAttributes);
930  opclassIds = palloc_array(Oid, numberOfAttributes);
931  opclassOptions = palloc_array(Datum, numberOfAttributes);
932  coloptions = palloc_array(int16, numberOfAttributes);
933  ComputeIndexAttrs(indexInfo,
934  typeIds, collationIds, opclassIds, opclassOptions,
935  coloptions, allIndexParams,
936  stmt->excludeOpNames, tableId,
937  accessMethodName, accessMethodId,
938  amcanorder, stmt->isconstraint, stmt->iswithoutoverlaps,
939  root_save_userid, root_save_sec_context,
940  &root_save_nestlevel);
941 
942  /*
943  * Extra checks when creating a PRIMARY KEY index.
944  */
945  if (stmt->primary)
946  index_check_primary_key(rel, indexInfo, is_alter_table, stmt);
947 
948  /*
949  * If this table is partitioned and we're creating a unique index, primary
950  * key, or exclusion constraint, make sure that the partition key is a
951  * subset of the index's columns. Otherwise it would be possible to
952  * violate uniqueness by putting values that ought to be unique in
953  * different partitions.
954  *
955  * We could lift this limitation if we had global indexes, but those have
956  * their own problems, so this is a useful feature combination.
957  */
958  if (partitioned && (stmt->unique || exclusion))
959  {
961  const char *constraint_type;
962  int i;
963 
964  if (stmt->primary)
965  constraint_type = "PRIMARY KEY";
966  else if (stmt->unique)
967  constraint_type = "UNIQUE";
968  else if (stmt->excludeOpNames)
969  constraint_type = "EXCLUDE";
970  else
971  {
972  elog(ERROR, "unknown constraint type");
973  constraint_type = NULL; /* keep compiler quiet */
974  }
975 
976  /*
977  * Verify that all the columns in the partition key appear in the
978  * unique key definition, with the same notion of equality.
979  */
980  for (i = 0; i < key->partnatts; i++)
981  {
982  bool found = false;
983  int eq_strategy;
984  Oid ptkey_eqop;
985  int j;
986 
987  /*
988  * Identify the equality operator associated with this partkey
989  * column. For list and range partitioning, partkeys use btree
990  * operator classes; hash partitioning uses hash operator classes.
991  * (Keep this in sync with ComputePartitionAttrs!)
992  */
993  if (key->strategy == PARTITION_STRATEGY_HASH)
994  eq_strategy = HTEqualStrategyNumber;
995  else
996  eq_strategy = BTEqualStrategyNumber;
997 
998  ptkey_eqop = get_opfamily_member(key->partopfamily[i],
999  key->partopcintype[i],
1000  key->partopcintype[i],
1001  eq_strategy);
1002  if (!OidIsValid(ptkey_eqop))
1003  elog(ERROR, "missing operator %d(%u,%u) in partition opfamily %u",
1004  eq_strategy, key->partopcintype[i], key->partopcintype[i],
1005  key->partopfamily[i]);
1006 
1007  /*
1008  * We'll need to be able to identify the equality operators
1009  * associated with index columns, too. We know what to do with
1010  * btree opclasses; if there are ever any other index types that
1011  * support unique indexes, this logic will need extension. But if
1012  * we have an exclusion constraint (or a temporal PK), it already
1013  * knows the operators, so we don't have to infer them.
1014  */
1015  if (stmt->unique && !stmt->iswithoutoverlaps && accessMethodId != BTREE_AM_OID)
1016  ereport(ERROR,
1017  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1018  errmsg("cannot match partition key to an index using access method \"%s\"",
1019  accessMethodName)));
1020 
1021  /*
1022  * It may be possible to support UNIQUE constraints when partition
1023  * keys are expressions, but is it worth it? Give up for now.
1024  */
1025  if (key->partattrs[i] == 0)
1026  ereport(ERROR,
1027  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1028  errmsg("unsupported %s constraint with partition key definition",
1029  constraint_type),
1030  errdetail("%s constraints cannot be used when partition keys include expressions.",
1031  constraint_type)));
1032 
1033  /* Search the index column(s) for a match */
1034  for (j = 0; j < indexInfo->ii_NumIndexKeyAttrs; j++)
1035  {
1036  if (key->partattrs[i] == indexInfo->ii_IndexAttrNumbers[j])
1037  {
1038  /*
1039  * Matched the column, now what about the collation and
1040  * equality op?
1041  */
1042  Oid idx_opfamily;
1043  Oid idx_opcintype;
1044 
1045  if (key->partcollation[i] != collationIds[j])
1046  continue;
1047 
1048  if (get_opclass_opfamily_and_input_type(opclassIds[j],
1049  &idx_opfamily,
1050  &idx_opcintype))
1051  {
1052  Oid idx_eqop = InvalidOid;
1053 
1054  if (stmt->unique && !stmt->iswithoutoverlaps)
1055  idx_eqop = get_opfamily_member(idx_opfamily,
1056  idx_opcintype,
1057  idx_opcintype,
1059  else if (exclusion)
1060  idx_eqop = indexInfo->ii_ExclusionOps[j];
1061  Assert(idx_eqop);
1062 
1063  if (ptkey_eqop == idx_eqop)
1064  {
1065  found = true;
1066  break;
1067  }
1068  else if (exclusion)
1069  {
1070  /*
1071  * We found a match, but it's not an equality
1072  * operator. Instead of failing below with an
1073  * error message about a missing column, fail now
1074  * and explain that the operator is wrong.
1075  */
1076  Form_pg_attribute att = TupleDescAttr(RelationGetDescr(rel), key->partattrs[i] - 1);
1077 
1078  ereport(ERROR,
1079  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1080  errmsg("cannot match partition key to index on column \"%s\" using non-equal operator \"%s\"",
1081  NameStr(att->attname),
1082  get_opname(indexInfo->ii_ExclusionOps[j]))));
1083  }
1084  }
1085  }
1086  }
1087 
1088  if (!found)
1089  {
1090  Form_pg_attribute att;
1091 
1092  att = TupleDescAttr(RelationGetDescr(rel),
1093  key->partattrs[i] - 1);
1094  ereport(ERROR,
1095  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1096  errmsg("unique constraint on partitioned table must include all partitioning columns"),
1097  errdetail("%s constraint on table \"%s\" lacks column \"%s\" which is part of the partition key.",
1098  constraint_type, RelationGetRelationName(rel),
1099  NameStr(att->attname))));
1100  }
1101  }
1102  }
1103 
1104 
1105  /*
1106  * We disallow indexes on system columns. They would not necessarily get
1107  * updated correctly, and they don't seem useful anyway.
1108  */
1109  for (int i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
1110  {
1111  AttrNumber attno = indexInfo->ii_IndexAttrNumbers[i];
1112 
1113  if (attno < 0)
1114  ereport(ERROR,
1115  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1116  errmsg("index creation on system columns is not supported")));
1117  }
1118 
1119  /*
1120  * Also check for system columns used in expressions or predicates.
1121  */
1122  if (indexInfo->ii_Expressions || indexInfo->ii_Predicate)
1123  {
1124  Bitmapset *indexattrs = NULL;
1125 
1126  pull_varattnos((Node *) indexInfo->ii_Expressions, 1, &indexattrs);
1127  pull_varattnos((Node *) indexInfo->ii_Predicate, 1, &indexattrs);
1128 
1129  for (int i = FirstLowInvalidHeapAttributeNumber + 1; i < 0; i++)
1130  {
1132  indexattrs))
1133  ereport(ERROR,
1134  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1135  errmsg("index creation on system columns is not supported")));
1136  }
1137  }
1138 
1139  /* Is index safe for others to ignore? See set_indexsafe_procflags() */
1140  safe_index = indexInfo->ii_Expressions == NIL &&
1141  indexInfo->ii_Predicate == NIL;
1142 
1143  /*
1144  * Report index creation if appropriate (delay this till after most of the
1145  * error checks)
1146  */
1147  if (stmt->isconstraint && !quiet)
1148  {
1149  const char *constraint_type;
1150 
1151  if (stmt->primary)
1152  constraint_type = "PRIMARY KEY";
1153  else if (stmt->unique)
1154  constraint_type = "UNIQUE";
1155  else if (stmt->excludeOpNames)
1156  constraint_type = "EXCLUDE";
1157  else
1158  {
1159  elog(ERROR, "unknown constraint type");
1160  constraint_type = NULL; /* keep compiler quiet */
1161  }
1162 
1163  ereport(DEBUG1,
1164  (errmsg_internal("%s %s will create implicit index \"%s\" for table \"%s\"",
1165  is_alter_table ? "ALTER TABLE / ADD" : "CREATE TABLE /",
1166  constraint_type,
1167  indexRelationName, RelationGetRelationName(rel))));
1168  }
1169 
1170  /*
1171  * A valid stmt->oldNumber implies that we already have a built form of
1172  * the index. The caller should also decline any index build.
1173  */
1174  Assert(!RelFileNumberIsValid(stmt->oldNumber) || (skip_build && !concurrent));
1175 
1176  /*
1177  * Make the catalog entries for the index, including constraints. This
1178  * step also actually builds the index, except if caller requested not to
1179  * or in concurrent mode, in which case it'll be done later, or doing a
1180  * partitioned index (because those don't have storage).
1181  */
1182  flags = constr_flags = 0;
1183  if (stmt->isconstraint)
1184  flags |= INDEX_CREATE_ADD_CONSTRAINT;
1185  if (skip_build || concurrent || partitioned)
1186  flags |= INDEX_CREATE_SKIP_BUILD;
1187  if (stmt->if_not_exists)
1188  flags |= INDEX_CREATE_IF_NOT_EXISTS;
1189  if (concurrent)
1190  flags |= INDEX_CREATE_CONCURRENT;
1191  if (partitioned)
1192  flags |= INDEX_CREATE_PARTITIONED;
1193  if (stmt->primary)
1194  flags |= INDEX_CREATE_IS_PRIMARY;
1195 
1196  /*
1197  * If the table is partitioned, and recursion was declined but partitions
1198  * exist, mark the index as invalid.
1199  */
1200  if (partitioned && stmt->relation && !stmt->relation->inh)
1201  {
1202  PartitionDesc pd = RelationGetPartitionDesc(rel, true);
1203 
1204  if (pd->nparts != 0)
1205  flags |= INDEX_CREATE_INVALID;
1206  }
1207 
1208  if (stmt->deferrable)
1209  constr_flags |= INDEX_CONSTR_CREATE_DEFERRABLE;
1210  if (stmt->initdeferred)
1211  constr_flags |= INDEX_CONSTR_CREATE_INIT_DEFERRED;
1212  if (stmt->iswithoutoverlaps)
1213  constr_flags |= INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS;
1214 
1215  indexRelationId =
1216  index_create(rel, indexRelationName, indexRelationId, parentIndexId,
1217  parentConstraintId,
1218  stmt->oldNumber, indexInfo, indexColNames,
1219  accessMethodId, tablespaceId,
1220  collationIds, opclassIds, opclassOptions,
1221  coloptions, NULL, reloptions,
1222  flags, constr_flags,
1223  allowSystemTableMods, !check_rights,
1224  &createdConstraintId);
1225 
1226  ObjectAddressSet(address, RelationRelationId, indexRelationId);
1227 
1228  if (!OidIsValid(indexRelationId))
1229  {
1230  /*
1231  * Roll back any GUC changes executed by index functions. Also revert
1232  * to original default_tablespace if we changed it above.
1233  */
1234  AtEOXact_GUC(false, root_save_nestlevel);
1235 
1236  /* Restore userid and security context */
1237  SetUserIdAndSecContext(root_save_userid, root_save_sec_context);
1238 
1239  table_close(rel, NoLock);
1240 
1241  /* If this is the top-level index, we're done */
1242  if (!OidIsValid(parentIndexId))
1244 
1245  return address;
1246  }
1247 
1248  /*
1249  * Roll back any GUC changes executed by index functions, and keep
1250  * subsequent changes local to this command. This is essential if some
1251  * index function changed a behavior-affecting GUC, e.g. search_path.
1252  */
1253  AtEOXact_GUC(false, root_save_nestlevel);
1254  root_save_nestlevel = NewGUCNestLevel();
1256 
1257  /* Add any requested comment */
1258  if (stmt->idxcomment != NULL)
1259  CreateComments(indexRelationId, RelationRelationId, 0,
1260  stmt->idxcomment);
1261 
1262  if (partitioned)
1263  {
1264  PartitionDesc partdesc;
1265 
1266  /*
1267  * Unless caller specified to skip this step (via ONLY), process each
1268  * partition to make sure they all contain a corresponding index.
1269  *
1270  * If we're called internally (no stmt->relation), recurse always.
1271  */
1272  partdesc = RelationGetPartitionDesc(rel, true);
1273  if ((!stmt->relation || stmt->relation->inh) && partdesc->nparts > 0)
1274  {
1275  int nparts = partdesc->nparts;
1276  Oid *part_oids = palloc_array(Oid, nparts);
1277  bool invalidate_parent = false;
1278  Relation parentIndex;
1279  TupleDesc parentDesc;
1280 
1281  /*
1282  * Report the total number of partitions at the start of the
1283  * command; don't update it when being called recursively.
1284  */
1285  if (!OidIsValid(parentIndexId))
1286  {
1287  /*
1288  * When called by ProcessUtilitySlow, the number of partitions
1289  * is passed in as an optimization; but other callers pass -1
1290  * since they don't have the value handy. This should count
1291  * partitions the same way, ie one less than the number of
1292  * relations find_all_inheritors reports.
1293  *
1294  * We assume we needn't ask find_all_inheritors to take locks,
1295  * because that should have happened already for all callers.
1296  * Even if it did not, this is safe as long as we don't try to
1297  * touch the partitions here; the worst consequence would be a
1298  * bogus progress-reporting total.
1299  */
1300  if (total_parts < 0)
1301  {
1302  List *children = find_all_inheritors(tableId, NoLock, NULL);
1303 
1304  total_parts = list_length(children) - 1;
1305  list_free(children);
1306  }
1307 
1309  total_parts);
1310  }
1311 
1312  /* Make a local copy of partdesc->oids[], just for safety */
1313  memcpy(part_oids, partdesc->oids, sizeof(Oid) * nparts);
1314 
1315  /*
1316  * We'll need an IndexInfo describing the parent index. The one
1317  * built above is almost good enough, but not quite, because (for
1318  * example) its predicate expression if any hasn't been through
1319  * expression preprocessing. The most reliable way to get an
1320  * IndexInfo that will match those for child indexes is to build
1321  * it the same way, using BuildIndexInfo().
1322  */
1323  parentIndex = index_open(indexRelationId, lockmode);
1324  indexInfo = BuildIndexInfo(parentIndex);
1325 
1326  parentDesc = RelationGetDescr(rel);
1327 
1328  /*
1329  * For each partition, scan all existing indexes; if one matches
1330  * our index definition and is not already attached to some other
1331  * parent index, attach it to the one we just created.
1332  *
1333  * If none matches, build a new index by calling ourselves
1334  * recursively with the same options (except for the index name).
1335  */
1336  for (int i = 0; i < nparts; i++)
1337  {
1338  Oid childRelid = part_oids[i];
1339  Relation childrel;
1340  Oid child_save_userid;
1341  int child_save_sec_context;
1342  int child_save_nestlevel;
1343  List *childidxs;
1344  ListCell *cell;
1345  AttrMap *attmap;
1346  bool found = false;
1347 
1348  childrel = table_open(childRelid, lockmode);
1349 
1350  GetUserIdAndSecContext(&child_save_userid,
1351  &child_save_sec_context);
1352  SetUserIdAndSecContext(childrel->rd_rel->relowner,
1353  child_save_sec_context | SECURITY_RESTRICTED_OPERATION);
1354  child_save_nestlevel = NewGUCNestLevel();
1356 
1357  /*
1358  * Don't try to create indexes on foreign tables, though. Skip
1359  * those if a regular index, or fail if trying to create a
1360  * constraint index.
1361  */
1362  if (childrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1363  {
1364  if (stmt->unique || stmt->primary)
1365  ereport(ERROR,
1366  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1367  errmsg("cannot create unique index on partitioned table \"%s\"",
1369  errdetail("Table \"%s\" contains partitions that are foreign tables.",
1370  RelationGetRelationName(rel))));
1371 
1372  AtEOXact_GUC(false, child_save_nestlevel);
1373  SetUserIdAndSecContext(child_save_userid,
1374  child_save_sec_context);
1375  table_close(childrel, lockmode);
1376  continue;
1377  }
1378 
1379  childidxs = RelationGetIndexList(childrel);
1380  attmap =
1382  parentDesc,
1383  false);
1384 
1385  foreach(cell, childidxs)
1386  {
1387  Oid cldidxid = lfirst_oid(cell);
1388  Relation cldidx;
1389  IndexInfo *cldIdxInfo;
1390 
1391  /* this index is already partition of another one */
1392  if (has_superclass(cldidxid))
1393  continue;
1394 
1395  cldidx = index_open(cldidxid, lockmode);
1396  cldIdxInfo = BuildIndexInfo(cldidx);
1397  if (CompareIndexInfo(cldIdxInfo, indexInfo,
1398  cldidx->rd_indcollation,
1399  parentIndex->rd_indcollation,
1400  cldidx->rd_opfamily,
1401  parentIndex->rd_opfamily,
1402  attmap))
1403  {
1404  Oid cldConstrOid = InvalidOid;
1405 
1406  /*
1407  * Found a match.
1408  *
1409  * If this index is being created in the parent
1410  * because of a constraint, then the child needs to
1411  * have a constraint also, so look for one. If there
1412  * is no such constraint, this index is no good, so
1413  * keep looking.
1414  */
1415  if (createdConstraintId != InvalidOid)
1416  {
1417  cldConstrOid =
1419  cldidxid);
1420  if (cldConstrOid == InvalidOid)
1421  {
1422  index_close(cldidx, lockmode);
1423  continue;
1424  }
1425  }
1426 
1427  /* Attach index to parent and we're done. */
1428  IndexSetParentIndex(cldidx, indexRelationId);
1429  if (createdConstraintId != InvalidOid)
1430  ConstraintSetParentConstraint(cldConstrOid,
1431  createdConstraintId,
1432  childRelid);
1433 
1434  if (!cldidx->rd_index->indisvalid)
1435  invalidate_parent = true;
1436 
1437  found = true;
1438 
1439  /*
1440  * Report this partition as processed. Note that if
1441  * the partition has children itself, we'd ideally
1442  * count the children and update the progress report
1443  * for all of them; but that seems unduly expensive.
1444  * Instead, the progress report will act like all such
1445  * indirect children were processed in zero time at
1446  * the end of the command.
1447  */
1449 
1450  /* keep lock till commit */
1451  index_close(cldidx, NoLock);
1452  break;
1453  }
1454 
1455  index_close(cldidx, lockmode);
1456  }
1457 
1458  list_free(childidxs);
1459  AtEOXact_GUC(false, child_save_nestlevel);
1460  SetUserIdAndSecContext(child_save_userid,
1461  child_save_sec_context);
1462  table_close(childrel, NoLock);
1463 
1464  /*
1465  * If no matching index was found, create our own.
1466  */
1467  if (!found)
1468  {
1469  IndexStmt *childStmt;
1470  ObjectAddress childAddr;
1471 
1472  /*
1473  * Build an IndexStmt describing the desired child index
1474  * in the same way that we do during ATTACH PARTITION.
1475  * Notably, we rely on generateClonedIndexStmt to produce
1476  * a search-path-independent representation, which the
1477  * original IndexStmt might not be.
1478  */
1479  childStmt = generateClonedIndexStmt(NULL,
1480  parentIndex,
1481  attmap,
1482  NULL);
1483 
1484  /*
1485  * Recurse as the starting user ID. Callee will use that
1486  * for permission checks, then switch again.
1487  */
1488  Assert(GetUserId() == child_save_userid);
1489  SetUserIdAndSecContext(root_save_userid,
1490  root_save_sec_context);
1491  childAddr =
1492  DefineIndex(childRelid, childStmt,
1493  InvalidOid, /* no predefined OID */
1494  indexRelationId, /* this is our child */
1495  createdConstraintId,
1496  -1,
1497  is_alter_table, check_rights,
1498  check_not_in_use,
1499  skip_build, quiet);
1500  SetUserIdAndSecContext(child_save_userid,
1501  child_save_sec_context);
1502 
1503  /*
1504  * Check if the index just created is valid or not, as it
1505  * could be possible that it has been switched as invalid
1506  * when recursing across multiple partition levels.
1507  */
1508  if (!get_index_isvalid(childAddr.objectId))
1509  invalidate_parent = true;
1510  }
1511 
1512  free_attrmap(attmap);
1513  }
1514 
1515  index_close(parentIndex, lockmode);
1516 
1517  /*
1518  * The pg_index row we inserted for this index was marked
1519  * indisvalid=true. But if we attached an existing index that is
1520  * invalid, this is incorrect, so update our row to invalid too.
1521  */
1522  if (invalidate_parent)
1523  {
1524  Relation pg_index = table_open(IndexRelationId, RowExclusiveLock);
1525  HeapTuple tup,
1526  newtup;
1527 
1528  tup = SearchSysCache1(INDEXRELID,
1529  ObjectIdGetDatum(indexRelationId));
1530  if (!HeapTupleIsValid(tup))
1531  elog(ERROR, "cache lookup failed for index %u",
1532  indexRelationId);
1533  newtup = heap_copytuple(tup);
1534  ((Form_pg_index) GETSTRUCT(newtup))->indisvalid = false;
1535  CatalogTupleUpdate(pg_index, &tup->t_self, newtup);
1536  ReleaseSysCache(tup);
1537  table_close(pg_index, RowExclusiveLock);
1538  heap_freetuple(newtup);
1539 
1540  /*
1541  * CCI here to make this update visible, in case this recurses
1542  * across multiple partition levels.
1543  */
1545  }
1546  }
1547 
1548  /*
1549  * Indexes on partitioned tables are not themselves built, so we're
1550  * done here.
1551  */
1552  AtEOXact_GUC(false, root_save_nestlevel);
1553  SetUserIdAndSecContext(root_save_userid, root_save_sec_context);
1554  table_close(rel, NoLock);
1555  if (!OidIsValid(parentIndexId))
1557  else
1558  {
1559  /* Update progress for an intermediate partitioned index itself */
1561  }
1562 
1563  return address;
1564  }
1565 
1566  AtEOXact_GUC(false, root_save_nestlevel);
1567  SetUserIdAndSecContext(root_save_userid, root_save_sec_context);
1568 
1569  if (!concurrent)
1570  {
1571  /* Close the heap and we're done, in the non-concurrent case */
1572  table_close(rel, NoLock);
1573 
1574  /*
1575  * If this is the top-level index, the command is done overall;
1576  * otherwise, increment progress to report one child index is done.
1577  */
1578  if (!OidIsValid(parentIndexId))
1580  else
1582 
1583  return address;
1584  }
1585 
1586  /* save lockrelid and locktag for below, then close rel */
1587  heaprelid = rel->rd_lockInfo.lockRelId;
1588  SET_LOCKTAG_RELATION(heaplocktag, heaprelid.dbId, heaprelid.relId);
1589  table_close(rel, NoLock);
1590 
1591  /*
1592  * For a concurrent build, it's important to make the catalog entries
1593  * visible to other transactions before we start to build the index. That
1594  * will prevent them from making incompatible HOT updates. The new index
1595  * will be marked not indisready and not indisvalid, so that no one else
1596  * tries to either insert into it or use it for queries.
1597  *
1598  * We must commit our current transaction so that the index becomes
1599  * visible; then start another. Note that all the data structures we just
1600  * built are lost in the commit. The only data we keep past here are the
1601  * relation IDs.
1602  *
1603  * Before committing, get a session-level lock on the table, to ensure
1604  * that neither it nor the index can be dropped before we finish. This
1605  * cannot block, even if someone else is waiting for access, because we
1606  * already have the same lock within our transaction.
1607  *
1608  * Note: we don't currently bother with a session lock on the index,
1609  * because there are no operations that could change its state while we
1610  * hold lock on the parent table. This might need to change later.
1611  */
1613 
1617 
1618  /* Tell concurrent index builds to ignore us, if index qualifies */
1619  if (safe_index)
1621 
1622  /*
1623  * The index is now visible, so we can report the OID. While on it,
1624  * include the report for the beginning of phase 2.
1625  */
1626  {
1627  const int progress_cols[] = {
1630  };
1631  const int64 progress_vals[] = {
1632  indexRelationId,
1634  };
1635 
1636  pgstat_progress_update_multi_param(2, progress_cols, progress_vals);
1637  }
1638 
1639  /*
1640  * Phase 2 of concurrent index build (see comments for validate_index()
1641  * for an overview of how this works)
1642  *
1643  * Now we must wait until no running transaction could have the table open
1644  * with the old list of indexes. Use ShareLock to consider running
1645  * transactions that hold locks that permit writing to the table. Note we
1646  * do not need to worry about xacts that open the table for writing after
1647  * this point; they will see the new index when they open it.
1648  *
1649  * Note: the reason we use actual lock acquisition here, rather than just
1650  * checking the ProcArray and sleeping, is that deadlock is possible if
1651  * one of the transactions in question is blocked trying to acquire an
1652  * exclusive lock on our table. The lock code will detect deadlock and
1653  * error out properly.
1654  */
1655  WaitForLockers(heaplocktag, ShareLock, true);
1656 
1657  /*
1658  * At this moment we are sure that there are no transactions with the
1659  * table open for write that don't have this new index in their list of
1660  * indexes. We have waited out all the existing transactions and any new
1661  * transaction will have the new index in its list, but the index is still
1662  * marked as "not-ready-for-inserts". The index is consulted while
1663  * deciding HOT-safety though. This arrangement ensures that no new HOT
1664  * chains can be created where the new tuple and the old tuple in the
1665  * chain have different index keys.
1666  *
1667  * We now take a new snapshot, and build the index using all tuples that
1668  * are visible in this snapshot. We can be sure that any HOT updates to
1669  * these tuples will be compatible with the index, since any updates made
1670  * by transactions that didn't know about the index are now committed or
1671  * rolled back. Thus, each visible tuple is either the end of its
1672  * HOT-chain or the extension of the chain is HOT-safe for this index.
1673  */
1674 
1675  /* Set ActiveSnapshot since functions in the indexes may need it */
1677 
1678  /* Perform concurrent build of index */
1679  index_concurrently_build(tableId, indexRelationId);
1680 
1681  /* we can do away with our snapshot */
1683 
1684  /*
1685  * Commit this transaction to make the indisready update visible.
1686  */
1689 
1690  /* Tell concurrent index builds to ignore us, if index qualifies */
1691  if (safe_index)
1693 
1694  /*
1695  * Phase 3 of concurrent index build
1696  *
1697  * We once again wait until no transaction can have the table open with
1698  * the index marked as read-only for updates.
1699  */
1702  WaitForLockers(heaplocktag, ShareLock, true);
1703 
1704  /*
1705  * Now take the "reference snapshot" that will be used by validate_index()
1706  * to filter candidate tuples. Beware! There might still be snapshots in
1707  * use that treat some transaction as in-progress that our reference
1708  * snapshot treats as committed. If such a recently-committed transaction
1709  * deleted tuples in the table, we will not include them in the index; yet
1710  * those transactions which see the deleting one as still-in-progress will
1711  * expect such tuples to be there once we mark the index as valid.
1712  *
1713  * We solve this by waiting for all endangered transactions to exit before
1714  * we mark the index as valid.
1715  *
1716  * We also set ActiveSnapshot to this snap, since functions in indexes may
1717  * need a snapshot.
1718  */
1720  PushActiveSnapshot(snapshot);
1721 
1722  /*
1723  * Scan the index and the heap, insert any missing index entries.
1724  */
1725  validate_index(tableId, indexRelationId, snapshot);
1726 
1727  /*
1728  * Drop the reference snapshot. We must do this before waiting out other
1729  * snapshot holders, else we will deadlock against other processes also
1730  * doing CREATE INDEX CONCURRENTLY, which would see our snapshot as one
1731  * they must wait for. But first, save the snapshot's xmin to use as
1732  * limitXmin for GetCurrentVirtualXIDs().
1733  */
1734  limitXmin = snapshot->xmin;
1735 
1737  UnregisterSnapshot(snapshot);
1738 
1739  /*
1740  * The snapshot subsystem could still contain registered snapshots that
1741  * are holding back our process's advertised xmin; in particular, if
1742  * default_transaction_isolation = serializable, there is a transaction
1743  * snapshot that is still active. The CatalogSnapshot is likewise a
1744  * hazard. To ensure no deadlocks, we must commit and start yet another
1745  * transaction, and do our wait before any snapshot has been taken in it.
1746  */
1749 
1750  /* Tell concurrent index builds to ignore us, if index qualifies */
1751  if (safe_index)
1753 
1754  /* We should now definitely not be advertising any xmin. */
1756 
1757  /*
1758  * The index is now valid in the sense that it contains all currently
1759  * interesting tuples. But since it might not contain tuples deleted just
1760  * before the reference snap was taken, we have to wait out any
1761  * transactions that might have older snapshots.
1762  */
1765  WaitForOlderSnapshots(limitXmin, true);
1766 
1767  /*
1768  * Updating pg_index might involve TOAST table access, so ensure we have a
1769  * valid snapshot.
1770  */
1772 
1773  /*
1774  * Index can now be marked valid -- update its pg_index entry
1775  */
1777 
1779 
1780  /*
1781  * The pg_index update will cause backends (including this one) to update
1782  * relcache entries for the index itself, but we should also send a
1783  * relcache inval on the parent table to force replanning of cached plans.
1784  * Otherwise existing sessions might fail to use the new index where it
1785  * would be useful. (Note that our earlier commits did not create reasons
1786  * to replan; so relcache flush on the index itself was sufficient.)
1787  */
1789 
1790  /*
1791  * Last thing to do is release the session-level lock on the parent table.
1792  */
1794 
1796 
1797  return address;
1798 }
1799 
1800 
1801 /*
1802  * CheckPredicate
1803  * Checks that the given partial-index predicate is valid.
1804  *
1805  * This used to also constrain the form of the predicate to forms that
1806  * indxpath.c could do something with. However, that seems overly
1807  * restrictive. One useful application of partial indexes is to apply
1808  * a UNIQUE constraint across a subset of a table, and in that scenario
1809  * any evaluable predicate will work. So accept any predicate here
1810  * (except ones requiring a plan), and let indxpath.c fend for itself.
1811  */
1812 static void
1814 {
1815  /*
1816  * transformExpr() should have already rejected subqueries, aggregates,
1817  * and window functions, based on the EXPR_KIND_ for a predicate.
1818  */
1819 
1820  /*
1821  * A predicate using mutable functions is probably wrong, for the same
1822  * reasons that we don't allow an index expression to use one.
1823  */
1825  ereport(ERROR,
1826  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1827  errmsg("functions in index predicate must be marked IMMUTABLE")));
1828 }
1829 
1830 /*
1831  * Compute per-index-column information, including indexed column numbers
1832  * or index expressions, opclasses and their options. Note, all output vectors
1833  * should be allocated for all columns, including "including" ones.
1834  *
1835  * If the caller switched to the table owner, ddl_userid is the role for ACL
1836  * checks reached without traversing opaque expressions. Otherwise, it's
1837  * InvalidOid, and other ddl_* arguments are undefined.
1838  */
1839 static void
1841  Oid *typeOids,
1842  Oid *collationOids,
1843  Oid *opclassOids,
1844  Datum *opclassOptions,
1845  int16 *colOptions,
1846  const List *attList, /* list of IndexElem's */
1847  const List *exclusionOpNames,
1848  Oid relId,
1849  const char *accessMethodName,
1850  Oid accessMethodId,
1851  bool amcanorder,
1852  bool isconstraint,
1853  bool iswithoutoverlaps,
1854  Oid ddl_userid,
1855  int ddl_sec_context,
1856  int *ddl_save_nestlevel)
1857 {
1858  ListCell *nextExclOp;
1859  ListCell *lc;
1860  int attn;
1861  int nkeycols = indexInfo->ii_NumIndexKeyAttrs;
1862  Oid save_userid;
1863  int save_sec_context;
1864 
1865  /* Allocate space for exclusion operator info, if needed */
1866  if (exclusionOpNames)
1867  {
1868  Assert(list_length(exclusionOpNames) == nkeycols);
1869  indexInfo->ii_ExclusionOps = palloc_array(Oid, nkeycols);
1870  indexInfo->ii_ExclusionProcs = palloc_array(Oid, nkeycols);
1871  indexInfo->ii_ExclusionStrats = palloc_array(uint16, nkeycols);
1872  nextExclOp = list_head(exclusionOpNames);
1873  }
1874  else
1875  nextExclOp = NULL;
1876 
1877  /*
1878  * If this is a WITHOUT OVERLAPS constraint, we need space for exclusion
1879  * ops, but we don't need to parse anything, so we can let nextExclOp be
1880  * NULL. Note that for partitions/inheriting/LIKE, exclusionOpNames will
1881  * be set, so we already allocated above.
1882  */
1883  if (iswithoutoverlaps)
1884  {
1885  if (exclusionOpNames == NIL)
1886  {
1887  indexInfo->ii_ExclusionOps = palloc_array(Oid, nkeycols);
1888  indexInfo->ii_ExclusionProcs = palloc_array(Oid, nkeycols);
1889  indexInfo->ii_ExclusionStrats = palloc_array(uint16, nkeycols);
1890  }
1891  nextExclOp = NULL;
1892  }
1893 
1894  if (OidIsValid(ddl_userid))
1895  GetUserIdAndSecContext(&save_userid, &save_sec_context);
1896 
1897  /*
1898  * process attributeList
1899  */
1900  attn = 0;
1901  foreach(lc, attList)
1902  {
1903  IndexElem *attribute = (IndexElem *) lfirst(lc);
1904  Oid atttype;
1905  Oid attcollation;
1906 
1907  /*
1908  * Process the column-or-expression to be indexed.
1909  */
1910  if (attribute->name != NULL)
1911  {
1912  /* Simple index attribute */
1913  HeapTuple atttuple;
1914  Form_pg_attribute attform;
1915 
1916  Assert(attribute->expr == NULL);
1917  atttuple = SearchSysCacheAttName(relId, attribute->name);
1918  if (!HeapTupleIsValid(atttuple))
1919  {
1920  /* difference in error message spellings is historical */
1921  if (isconstraint)
1922  ereport(ERROR,
1923  (errcode(ERRCODE_UNDEFINED_COLUMN),
1924  errmsg("column \"%s\" named in key does not exist",
1925  attribute->name)));
1926  else
1927  ereport(ERROR,
1928  (errcode(ERRCODE_UNDEFINED_COLUMN),
1929  errmsg("column \"%s\" does not exist",
1930  attribute->name)));
1931  }
1932  attform = (Form_pg_attribute) GETSTRUCT(atttuple);
1933  indexInfo->ii_IndexAttrNumbers[attn] = attform->attnum;
1934  atttype = attform->atttypid;
1935  attcollation = attform->attcollation;
1936  ReleaseSysCache(atttuple);
1937  }
1938  else
1939  {
1940  /* Index expression */
1941  Node *expr = attribute->expr;
1942 
1943  Assert(expr != NULL);
1944 
1945  if (attn >= nkeycols)
1946  ereport(ERROR,
1947  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1948  errmsg("expressions are not supported in included columns")));
1949  atttype = exprType(expr);
1950  attcollation = exprCollation(expr);
1951 
1952  /*
1953  * Strip any top-level COLLATE clause. This ensures that we treat
1954  * "x COLLATE y" and "(x COLLATE y)" alike.
1955  */
1956  while (IsA(expr, CollateExpr))
1957  expr = (Node *) ((CollateExpr *) expr)->arg;
1958 
1959  if (IsA(expr, Var) &&
1960  ((Var *) expr)->varattno != InvalidAttrNumber)
1961  {
1962  /*
1963  * User wrote "(column)" or "(column COLLATE something)".
1964  * Treat it like simple attribute anyway.
1965  */
1966  indexInfo->ii_IndexAttrNumbers[attn] = ((Var *) expr)->varattno;
1967  }
1968  else
1969  {
1970  indexInfo->ii_IndexAttrNumbers[attn] = 0; /* marks expression */
1971  indexInfo->ii_Expressions = lappend(indexInfo->ii_Expressions,
1972  expr);
1973 
1974  /*
1975  * transformExpr() should have already rejected subqueries,
1976  * aggregates, and window functions, based on the EXPR_KIND_
1977  * for an index expression.
1978  */
1979 
1980  /*
1981  * An expression using mutable functions is probably wrong,
1982  * since if you aren't going to get the same result for the
1983  * same data every time, it's not clear what the index entries
1984  * mean at all.
1985  */
1987  ereport(ERROR,
1988  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1989  errmsg("functions in index expression must be marked IMMUTABLE")));
1990  }
1991  }
1992 
1993  typeOids[attn] = atttype;
1994 
1995  /*
1996  * Included columns have no collation, no opclass and no ordering
1997  * options.
1998  */
1999  if (attn >= nkeycols)
2000  {
2001  if (attribute->collation)
2002  ereport(ERROR,
2003  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2004  errmsg("including column does not support a collation")));
2005  if (attribute->opclass)
2006  ereport(ERROR,
2007  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2008  errmsg("including column does not support an operator class")));
2009  if (attribute->ordering != SORTBY_DEFAULT)
2010  ereport(ERROR,
2011  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2012  errmsg("including column does not support ASC/DESC options")));
2013  if (attribute->nulls_ordering != SORTBY_NULLS_DEFAULT)
2014  ereport(ERROR,
2015  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2016  errmsg("including column does not support NULLS FIRST/LAST options")));
2017 
2018  opclassOids[attn] = InvalidOid;
2019  opclassOptions[attn] = (Datum) 0;
2020  colOptions[attn] = 0;
2021  collationOids[attn] = InvalidOid;
2022  attn++;
2023 
2024  continue;
2025  }
2026 
2027  /*
2028  * Apply collation override if any. Use of ddl_userid is necessary
2029  * due to ACL checks therein, and it's safe because collations don't
2030  * contain opaque expressions (or non-opaque expressions).
2031  */
2032  if (attribute->collation)
2033  {
2034  if (OidIsValid(ddl_userid))
2035  {
2036  AtEOXact_GUC(false, *ddl_save_nestlevel);
2037  SetUserIdAndSecContext(ddl_userid, ddl_sec_context);
2038  }
2039  attcollation = get_collation_oid(attribute->collation, false);
2040  if (OidIsValid(ddl_userid))
2041  {
2042  SetUserIdAndSecContext(save_userid, save_sec_context);
2043  *ddl_save_nestlevel = NewGUCNestLevel();
2045  }
2046  }
2047 
2048  /*
2049  * Check we have a collation iff it's a collatable type. The only
2050  * expected failures here are (1) COLLATE applied to a noncollatable
2051  * type, or (2) index expression had an unresolved collation. But we
2052  * might as well code this to be a complete consistency check.
2053  */
2054  if (type_is_collatable(atttype))
2055  {
2056  if (!OidIsValid(attcollation))
2057  ereport(ERROR,
2058  (errcode(ERRCODE_INDETERMINATE_COLLATION),
2059  errmsg("could not determine which collation to use for index expression"),
2060  errhint("Use the COLLATE clause to set the collation explicitly.")));
2061  }
2062  else
2063  {
2064  if (OidIsValid(attcollation))
2065  ereport(ERROR,
2066  (errcode(ERRCODE_DATATYPE_MISMATCH),
2067  errmsg("collations are not supported by type %s",
2068  format_type_be(atttype))));
2069  }
2070 
2071  collationOids[attn] = attcollation;
2072 
2073  /*
2074  * Identify the opclass to use. Use of ddl_userid is necessary due to
2075  * ACL checks therein. This is safe despite opclasses containing
2076  * opaque expressions (specifically, functions), because only
2077  * superusers can define opclasses.
2078  */
2079  if (OidIsValid(ddl_userid))
2080  {
2081  AtEOXact_GUC(false, *ddl_save_nestlevel);
2082  SetUserIdAndSecContext(ddl_userid, ddl_sec_context);
2083  }
2084  opclassOids[attn] = ResolveOpClass(attribute->opclass,
2085  atttype,
2086  accessMethodName,
2087  accessMethodId);
2088  if (OidIsValid(ddl_userid))
2089  {
2090  SetUserIdAndSecContext(save_userid, save_sec_context);
2091  *ddl_save_nestlevel = NewGUCNestLevel();
2093  }
2094 
2095  /*
2096  * Identify the exclusion operator, if any.
2097  */
2098  if (nextExclOp)
2099  {
2100  List *opname = (List *) lfirst(nextExclOp);
2101  Oid opid;
2102  Oid opfamily;
2103  int strat;
2104 
2105  /*
2106  * Find the operator --- it must accept the column datatype
2107  * without runtime coercion (but binary compatibility is OK).
2108  * Operators contain opaque expressions (specifically, functions).
2109  * compatible_oper_opid() boils down to oper() and
2110  * IsBinaryCoercible(). PostgreSQL would have security problems
2111  * elsewhere if oper() started calling opaque expressions.
2112  */
2113  if (OidIsValid(ddl_userid))
2114  {
2115  AtEOXact_GUC(false, *ddl_save_nestlevel);
2116  SetUserIdAndSecContext(ddl_userid, ddl_sec_context);
2117  }
2118  opid = compatible_oper_opid(opname, atttype, atttype, false);
2119  if (OidIsValid(ddl_userid))
2120  {
2121  SetUserIdAndSecContext(save_userid, save_sec_context);
2122  *ddl_save_nestlevel = NewGUCNestLevel();
2124  }
2125 
2126  /*
2127  * Only allow commutative operators to be used in exclusion
2128  * constraints. If X conflicts with Y, but Y does not conflict
2129  * with X, bad things will happen.
2130  */
2131  if (get_commutator(opid) != opid)
2132  ereport(ERROR,
2133  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2134  errmsg("operator %s is not commutative",
2135  format_operator(opid)),
2136  errdetail("Only commutative operators can be used in exclusion constraints.")));
2137 
2138  /*
2139  * Operator must be a member of the right opfamily, too
2140  */
2141  opfamily = get_opclass_family(opclassOids[attn]);
2142  strat = get_op_opfamily_strategy(opid, opfamily);
2143  if (strat == 0)
2144  {
2145  HeapTuple opftuple;
2146  Form_pg_opfamily opfform;
2147 
2148  /*
2149  * attribute->opclass might not explicitly name the opfamily,
2150  * so fetch the name of the selected opfamily for use in the
2151  * error message.
2152  */
2153  opftuple = SearchSysCache1(OPFAMILYOID,
2154  ObjectIdGetDatum(opfamily));
2155  if (!HeapTupleIsValid(opftuple))
2156  elog(ERROR, "cache lookup failed for opfamily %u",
2157  opfamily);
2158  opfform = (Form_pg_opfamily) GETSTRUCT(opftuple);
2159 
2160  ereport(ERROR,
2161  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2162  errmsg("operator %s is not a member of operator family \"%s\"",
2163  format_operator(opid),
2164  NameStr(opfform->opfname)),
2165  errdetail("The exclusion operator must be related to the index operator class for the constraint.")));
2166  }
2167 
2168  indexInfo->ii_ExclusionOps[attn] = opid;
2169  indexInfo->ii_ExclusionProcs[attn] = get_opcode(opid);
2170  indexInfo->ii_ExclusionStrats[attn] = strat;
2171  nextExclOp = lnext(exclusionOpNames, nextExclOp);
2172  }
2173  else if (iswithoutoverlaps)
2174  {
2175  StrategyNumber strat;
2176  Oid opid;
2177 
2178  if (attn == nkeycols - 1)
2179  strat = RTOverlapStrategyNumber;
2180  else
2181  strat = RTEqualStrategyNumber;
2182  GetOperatorFromWellKnownStrategy(opclassOids[attn], InvalidOid,
2183  &opid, &strat);
2184  indexInfo->ii_ExclusionOps[attn] = opid;
2185  indexInfo->ii_ExclusionProcs[attn] = get_opcode(opid);
2186  indexInfo->ii_ExclusionStrats[attn] = strat;
2187  }
2188 
2189  /*
2190  * Set up the per-column options (indoption field). For now, this is
2191  * zero for any un-ordered index, while ordered indexes have DESC and
2192  * NULLS FIRST/LAST options.
2193  */
2194  colOptions[attn] = 0;
2195  if (amcanorder)
2196  {
2197  /* default ordering is ASC */
2198  if (attribute->ordering == SORTBY_DESC)
2199  colOptions[attn] |= INDOPTION_DESC;
2200  /* default null ordering is LAST for ASC, FIRST for DESC */
2201  if (attribute->nulls_ordering == SORTBY_NULLS_DEFAULT)
2202  {
2203  if (attribute->ordering == SORTBY_DESC)
2204  colOptions[attn] |= INDOPTION_NULLS_FIRST;
2205  }
2206  else if (attribute->nulls_ordering == SORTBY_NULLS_FIRST)
2207  colOptions[attn] |= INDOPTION_NULLS_FIRST;
2208  }
2209  else
2210  {
2211  /* index AM does not support ordering */
2212  if (attribute->ordering != SORTBY_DEFAULT)
2213  ereport(ERROR,
2214  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2215  errmsg("access method \"%s\" does not support ASC/DESC options",
2216  accessMethodName)));
2217  if (attribute->nulls_ordering != SORTBY_NULLS_DEFAULT)
2218  ereport(ERROR,
2219  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2220  errmsg("access method \"%s\" does not support NULLS FIRST/LAST options",
2221  accessMethodName)));
2222  }
2223 
2224  /* Set up the per-column opclass options (attoptions field). */
2225  if (attribute->opclassopts)
2226  {
2227  Assert(attn < nkeycols);
2228 
2229  opclassOptions[attn] =
2230  transformRelOptions((Datum) 0, attribute->opclassopts,
2231  NULL, NULL, false, false);
2232  }
2233  else
2234  opclassOptions[attn] = (Datum) 0;
2235 
2236  attn++;
2237  }
2238 }
2239 
2240 /*
2241  * Resolve possibly-defaulted operator class specification
2242  *
2243  * Note: This is used to resolve operator class specifications in index and
2244  * partition key definitions.
2245  */
2246 Oid
2247 ResolveOpClass(const List *opclass, Oid attrType,
2248  const char *accessMethodName, Oid accessMethodId)
2249 {
2250  char *schemaname;
2251  char *opcname;
2252  HeapTuple tuple;
2253  Form_pg_opclass opform;
2254  Oid opClassId,
2255  opInputType;
2256 
2257  if (opclass == NIL)
2258  {
2259  /* no operator class specified, so find the default */
2260  opClassId = GetDefaultOpClass(attrType, accessMethodId);
2261  if (!OidIsValid(opClassId))
2262  ereport(ERROR,
2263  (errcode(ERRCODE_UNDEFINED_OBJECT),
2264  errmsg("data type %s has no default operator class for access method \"%s\"",
2265  format_type_be(attrType), accessMethodName),
2266  errhint("You must specify an operator class for the index or define a default operator class for the data type.")));
2267  return opClassId;
2268  }
2269 
2270  /*
2271  * Specific opclass name given, so look up the opclass.
2272  */
2273 
2274  /* deconstruct the name list */
2275  DeconstructQualifiedName(opclass, &schemaname, &opcname);
2276 
2277  if (schemaname)
2278  {
2279  /* Look in specific schema only */
2280  Oid namespaceId;
2281 
2282  namespaceId = LookupExplicitNamespace(schemaname, false);
2283  tuple = SearchSysCache3(CLAAMNAMENSP,
2284  ObjectIdGetDatum(accessMethodId),
2285  PointerGetDatum(opcname),
2286  ObjectIdGetDatum(namespaceId));
2287  }
2288  else
2289  {
2290  /* Unqualified opclass name, so search the search path */
2291  opClassId = OpclassnameGetOpcid(accessMethodId, opcname);
2292  if (!OidIsValid(opClassId))
2293  ereport(ERROR,
2294  (errcode(ERRCODE_UNDEFINED_OBJECT),
2295  errmsg("operator class \"%s\" does not exist for access method \"%s\"",
2296  opcname, accessMethodName)));
2297  tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opClassId));
2298  }
2299 
2300  if (!HeapTupleIsValid(tuple))
2301  ereport(ERROR,
2302  (errcode(ERRCODE_UNDEFINED_OBJECT),
2303  errmsg("operator class \"%s\" does not exist for access method \"%s\"",
2304  NameListToString(opclass), accessMethodName)));
2305 
2306  /*
2307  * Verify that the index operator class accepts this datatype. Note we
2308  * will accept binary compatibility.
2309  */
2310  opform = (Form_pg_opclass) GETSTRUCT(tuple);
2311  opClassId = opform->oid;
2312  opInputType = opform->opcintype;
2313 
2314  if (!IsBinaryCoercible(attrType, opInputType))
2315  ereport(ERROR,
2316  (errcode(ERRCODE_DATATYPE_MISMATCH),
2317  errmsg("operator class \"%s\" does not accept data type %s",
2318  NameListToString(opclass), format_type_be(attrType))));
2319 
2320  ReleaseSysCache(tuple);
2321 
2322  return opClassId;
2323 }
2324 
2325 /*
2326  * GetDefaultOpClass
2327  *
2328  * Given the OIDs of a datatype and an access method, find the default
2329  * operator class, if any. Returns InvalidOid if there is none.
2330  */
2331 Oid
2332 GetDefaultOpClass(Oid type_id, Oid am_id)
2333 {
2334  Oid result = InvalidOid;
2335  int nexact = 0;
2336  int ncompatible = 0;
2337  int ncompatiblepreferred = 0;
2338  Relation rel;
2339  ScanKeyData skey[1];
2340  SysScanDesc scan;
2341  HeapTuple tup;
2342  TYPCATEGORY tcategory;
2343 
2344  /* If it's a domain, look at the base type instead */
2345  type_id = getBaseType(type_id);
2346 
2347  tcategory = TypeCategory(type_id);
2348 
2349  /*
2350  * We scan through all the opclasses available for the access method,
2351  * looking for one that is marked default and matches the target type
2352  * (either exactly or binary-compatibly, but prefer an exact match).
2353  *
2354  * We could find more than one binary-compatible match. If just one is
2355  * for a preferred type, use that one; otherwise we fail, forcing the user
2356  * to specify which one he wants. (The preferred-type special case is a
2357  * kluge for varchar: it's binary-compatible to both text and bpchar, so
2358  * we need a tiebreaker.) If we find more than one exact match, then
2359  * someone put bogus entries in pg_opclass.
2360  */
2361  rel = table_open(OperatorClassRelationId, AccessShareLock);
2362 
2363  ScanKeyInit(&skey[0],
2364  Anum_pg_opclass_opcmethod,
2365  BTEqualStrategyNumber, F_OIDEQ,
2366  ObjectIdGetDatum(am_id));
2367 
2368  scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
2369  NULL, 1, skey);
2370 
2371  while (HeapTupleIsValid(tup = systable_getnext(scan)))
2372  {
2373  Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
2374 
2375  /* ignore altogether if not a default opclass */
2376  if (!opclass->opcdefault)
2377  continue;
2378  if (opclass->opcintype == type_id)
2379  {
2380  nexact++;
2381  result = opclass->oid;
2382  }
2383  else if (nexact == 0 &&
2384  IsBinaryCoercible(type_id, opclass->opcintype))
2385  {
2386  if (IsPreferredType(tcategory, opclass->opcintype))
2387  {
2388  ncompatiblepreferred++;
2389  result = opclass->oid;
2390  }
2391  else if (ncompatiblepreferred == 0)
2392  {
2393  ncompatible++;
2394  result = opclass->oid;
2395  }
2396  }
2397  }
2398 
2399  systable_endscan(scan);
2400 
2402 
2403  /* raise error if pg_opclass contains inconsistent data */
2404  if (nexact > 1)
2405  ereport(ERROR,
2407  errmsg("there are multiple default operator classes for data type %s",
2408  format_type_be(type_id))));
2409 
2410  if (nexact == 1 ||
2411  ncompatiblepreferred == 1 ||
2412  (ncompatiblepreferred == 0 && ncompatible == 1))
2413  return result;
2414 
2415  return InvalidOid;
2416 }
2417 
2418 /*
2419  * GetOperatorFromWellKnownStrategy
2420  *
2421  * opclass - the opclass to use
2422  * rhstype - the type for the right-hand side, or InvalidOid to use the type of the given opclass.
2423  * opid - holds the operator we found
2424  * strat - holds the input and output strategy number
2425  *
2426  * Finds an operator from a "well-known" strategy number. This is used for
2427  * temporal index constraints (and other temporal features) to look up
2428  * equality and overlaps operators, since the strategy numbers for non-btree
2429  * indexams need not follow any fixed scheme. We ask an opclass support
2430  * function to translate from the well-known number to the internal value. If
2431  * the function isn't defined or it gives no result, we return
2432  * InvalidStrategy.
2433  */
2434 void
2436  Oid *opid, StrategyNumber *strat)
2437 {
2438  Oid opfamily;
2439  Oid opcintype;
2440  StrategyNumber instrat = *strat;
2441 
2442  Assert(instrat == RTEqualStrategyNumber || instrat == RTOverlapStrategyNumber || instrat == RTContainedByStrategyNumber);
2443 
2444  *opid = InvalidOid;
2445 
2446  if (get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
2447  {
2448  /*
2449  * Ask the opclass to translate to its internal stratnum
2450  *
2451  * For now we only need GiST support, but this could support other
2452  * indexams if we wanted.
2453  */
2454  *strat = GistTranslateStratnum(opclass, instrat);
2455  if (*strat == InvalidStrategy)
2456  {
2457  HeapTuple tuple;
2458 
2459  tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
2460  if (!HeapTupleIsValid(tuple))
2461  elog(ERROR, "cache lookup failed for operator class %u", opclass);
2462 
2463  ereport(ERROR,
2464  errcode(ERRCODE_UNDEFINED_OBJECT),
2465  instrat == RTEqualStrategyNumber ? errmsg("could not identify an equality operator for type %s", format_type_be(opcintype)) :
2466  instrat == RTOverlapStrategyNumber ? errmsg("could not identify an overlaps operator for type %s", format_type_be(opcintype)) :
2467  instrat == RTContainedByStrategyNumber ? errmsg("could not identify a contained-by operator for type %s", format_type_be(opcintype)) : 0,
2468  errdetail("Could not translate strategy number %d for operator class \"%s\" for access method \"%s\".",
2469  instrat, NameStr(((Form_pg_opclass) GETSTRUCT(tuple))->opcname), "gist"));
2470  }
2471 
2472  /*
2473  * We parameterize rhstype so foreign keys can ask for a <@ operator
2474  * whose rhs matches the aggregate function. For example range_agg
2475  * returns anymultirange.
2476  */
2477  if (!OidIsValid(rhstype))
2478  rhstype = opcintype;
2479  *opid = get_opfamily_member(opfamily, opcintype, rhstype, *strat);
2480  }
2481 
2482  if (!OidIsValid(*opid))
2483  {
2484  HeapTuple tuple;
2485 
2486  tuple = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamily));
2487  if (!HeapTupleIsValid(tuple))
2488  elog(ERROR, "cache lookup failed for operator family %u", opfamily);
2489 
2490  ereport(ERROR,
2491  errcode(ERRCODE_UNDEFINED_OBJECT),
2492  instrat == RTEqualStrategyNumber ? errmsg("could not identify an equality operator for type %s", format_type_be(opcintype)) :
2493  instrat == RTOverlapStrategyNumber ? errmsg("could not identify an overlaps operator for type %s", format_type_be(opcintype)) :
2494  instrat == RTContainedByStrategyNumber ? errmsg("could not identify a contained-by operator for type %s", format_type_be(opcintype)) : 0,
2495  errdetail("There is no suitable operator in operator family \"%s\" for access method \"%s\".",
2496  NameStr(((Form_pg_opfamily) GETSTRUCT(tuple))->opfname), "gist"));
2497  }
2498 }
2499 
2500 /*
2501  * makeObjectName()
2502  *
2503  * Create a name for an implicitly created index, sequence, constraint,
2504  * extended statistics, etc.
2505  *
2506  * The parameters are typically: the original table name, the original field
2507  * name, and a "type" string (such as "seq" or "pkey"). The field name
2508  * and/or type can be NULL if not relevant.
2509  *
2510  * The result is a palloc'd string.
2511  *
2512  * The basic result we want is "name1_name2_label", omitting "_name2" or
2513  * "_label" when those parameters are NULL. However, we must generate
2514  * a name with less than NAMEDATALEN characters! So, we truncate one or
2515  * both names if necessary to make a short-enough string. The label part
2516  * is never truncated (so it had better be reasonably short).
2517  *
2518  * The caller is responsible for checking uniqueness of the generated
2519  * name and retrying as needed; retrying will be done by altering the
2520  * "label" string (which is why we never truncate that part).
2521  */
2522 char *
2523 makeObjectName(const char *name1, const char *name2, const char *label)
2524 {
2525  char *name;
2526  int overhead = 0; /* chars needed for label and underscores */
2527  int availchars; /* chars available for name(s) */
2528  int name1chars; /* chars allocated to name1 */
2529  int name2chars; /* chars allocated to name2 */
2530  int ndx;
2531 
2532  name1chars = strlen(name1);
2533  if (name2)
2534  {
2535  name2chars = strlen(name2);
2536  overhead++; /* allow for separating underscore */
2537  }
2538  else
2539  name2chars = 0;
2540  if (label)
2541  overhead += strlen(label) + 1;
2542 
2543  availchars = NAMEDATALEN - 1 - overhead;
2544  Assert(availchars > 0); /* else caller chose a bad label */
2545 
2546  /*
2547  * If we must truncate, preferentially truncate the longer name. This
2548  * logic could be expressed without a loop, but it's simple and obvious as
2549  * a loop.
2550  */
2551  while (name1chars + name2chars > availchars)
2552  {
2553  if (name1chars > name2chars)
2554  name1chars--;
2555  else
2556  name2chars--;
2557  }
2558 
2559  name1chars = pg_mbcliplen(name1, name1chars, name1chars);
2560  if (name2)
2561  name2chars = pg_mbcliplen(name2, name2chars, name2chars);
2562 
2563  /* Now construct the string using the chosen lengths */
2564  name = palloc(name1chars + name2chars + overhead + 1);
2565  memcpy(name, name1, name1chars);
2566  ndx = name1chars;
2567  if (name2)
2568  {
2569  name[ndx++] = '_';
2570  memcpy(name + ndx, name2, name2chars);
2571  ndx += name2chars;
2572  }
2573  if (label)
2574  {
2575  name[ndx++] = '_';
2576  strcpy(name + ndx, label);
2577  }
2578  else
2579  name[ndx] = '\0';
2580 
2581  return name;
2582 }
2583 
2584 /*
2585  * Select a nonconflicting name for a new relation. This is ordinarily
2586  * used to choose index names (which is why it's here) but it can also
2587  * be used for sequences, or any autogenerated relation kind.
2588  *
2589  * name1, name2, and label are used the same way as for makeObjectName(),
2590  * except that the label can't be NULL; digits will be appended to the label
2591  * if needed to create a name that is unique within the specified namespace.
2592  *
2593  * If isconstraint is true, we also avoid choosing a name matching any
2594  * existing constraint in the same namespace. (This is stricter than what
2595  * Postgres itself requires, but the SQL standard says that constraint names
2596  * should be unique within schemas, so we follow that for autogenerated
2597  * constraint names.)
2598  *
2599  * Note: it is theoretically possible to get a collision anyway, if someone
2600  * else chooses the same name concurrently. This is fairly unlikely to be
2601  * a problem in practice, especially if one is holding an exclusive lock on
2602  * the relation identified by name1. However, if choosing multiple names
2603  * within a single command, you'd better create the new object and do
2604  * CommandCounterIncrement before choosing the next one!
2605  *
2606  * Returns a palloc'd string.
2607  */
2608 char *
2609 ChooseRelationName(const char *name1, const char *name2,
2610  const char *label, Oid namespaceid,
2611  bool isconstraint)
2612 {
2613  int pass = 0;
2614  char *relname = NULL;
2615  char modlabel[NAMEDATALEN];
2616 
2617  /* try the unmodified label first */
2618  strlcpy(modlabel, label, sizeof(modlabel));
2619 
2620  for (;;)
2621  {
2622  relname = makeObjectName(name1, name2, modlabel);
2623 
2624  if (!OidIsValid(get_relname_relid(relname, namespaceid)))
2625  {
2626  if (!isconstraint ||
2627  !ConstraintNameExists(relname, namespaceid))
2628  break;
2629  }
2630 
2631  /* found a conflict, so try a new name component */
2632  pfree(relname);
2633  snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
2634  }
2635 
2636  return relname;
2637 }
2638 
2639 /*
2640  * Select the name to be used for an index.
2641  *
2642  * The argument list is pretty ad-hoc :-(
2643  */
2644 static char *
2645 ChooseIndexName(const char *tabname, Oid namespaceId,
2646  const List *colnames, const List *exclusionOpNames,
2647  bool primary, bool isconstraint)
2648 {
2649  char *indexname;
2650 
2651  if (primary)
2652  {
2653  /* the primary key's name does not depend on the specific column(s) */
2654  indexname = ChooseRelationName(tabname,
2655  NULL,
2656  "pkey",
2657  namespaceId,
2658  true);
2659  }
2660  else if (exclusionOpNames != NIL)
2661  {
2662  indexname = ChooseRelationName(tabname,
2663  ChooseIndexNameAddition(colnames),
2664  "excl",
2665  namespaceId,
2666  true);
2667  }
2668  else if (isconstraint)
2669  {
2670  indexname = ChooseRelationName(tabname,
2671  ChooseIndexNameAddition(colnames),
2672  "key",
2673  namespaceId,
2674  true);
2675  }
2676  else
2677  {
2678  indexname = ChooseRelationName(tabname,
2679  ChooseIndexNameAddition(colnames),
2680  "idx",
2681  namespaceId,
2682  false);
2683  }
2684 
2685  return indexname;
2686 }
2687 
2688 /*
2689  * Generate "name2" for a new index given the list of column names for it
2690  * (as produced by ChooseIndexColumnNames). This will be passed to
2691  * ChooseRelationName along with the parent table name and a suitable label.
2692  *
2693  * We know that less than NAMEDATALEN characters will actually be used,
2694  * so we can truncate the result once we've generated that many.
2695  *
2696  * XXX See also ChooseForeignKeyConstraintNameAddition and
2697  * ChooseExtendedStatisticNameAddition.
2698  */
2699 static char *
2701 {
2702  char buf[NAMEDATALEN * 2];
2703  int buflen = 0;
2704  ListCell *lc;
2705 
2706  buf[0] = '\0';
2707  foreach(lc, colnames)
2708  {
2709  const char *name = (const char *) lfirst(lc);
2710 
2711  if (buflen > 0)
2712  buf[buflen++] = '_'; /* insert _ between names */
2713 
2714  /*
2715  * At this point we have buflen <= NAMEDATALEN. name should be less
2716  * than NAMEDATALEN already, but use strlcpy for paranoia.
2717  */
2718  strlcpy(buf + buflen, name, NAMEDATALEN);
2719  buflen += strlen(buf + buflen);
2720  if (buflen >= NAMEDATALEN)
2721  break;
2722  }
2723  return pstrdup(buf);
2724 }
2725 
2726 /*
2727  * Select the actual names to be used for the columns of an index, given the
2728  * list of IndexElems for the columns. This is mostly about ensuring the
2729  * names are unique so we don't get a conflicting-attribute-names error.
2730  *
2731  * Returns a List of plain strings (char *, not String nodes).
2732  */
2733 static List *
2734 ChooseIndexColumnNames(const List *indexElems)
2735 {
2736  List *result = NIL;
2737  ListCell *lc;
2738 
2739  foreach(lc, indexElems)
2740  {
2741  IndexElem *ielem = (IndexElem *) lfirst(lc);
2742  const char *origname;
2743  const char *curname;
2744  int i;
2745  char buf[NAMEDATALEN];
2746 
2747  /* Get the preliminary name from the IndexElem */
2748  if (ielem->indexcolname)
2749  origname = ielem->indexcolname; /* caller-specified name */
2750  else if (ielem->name)
2751  origname = ielem->name; /* simple column reference */
2752  else
2753  origname = "expr"; /* default name for expression */
2754 
2755  /* If it conflicts with any previous column, tweak it */
2756  curname = origname;
2757  for (i = 1;; i++)
2758  {
2759  ListCell *lc2;
2760  char nbuf[32];
2761  int nlen;
2762 
2763  foreach(lc2, result)
2764  {
2765  if (strcmp(curname, (char *) lfirst(lc2)) == 0)
2766  break;
2767  }
2768  if (lc2 == NULL)
2769  break; /* found nonconflicting name */
2770 
2771  sprintf(nbuf, "%d", i);
2772 
2773  /* Ensure generated names are shorter than NAMEDATALEN */
2774  nlen = pg_mbcliplen(origname, strlen(origname),
2775  NAMEDATALEN - 1 - strlen(nbuf));
2776  memcpy(buf, origname, nlen);
2777  strcpy(buf + nlen, nbuf);
2778  curname = buf;
2779  }
2780 
2781  /* And attach to the result list */
2782  result = lappend(result, pstrdup(curname));
2783  }
2784  return result;
2785 }
2786 
2787 /*
2788  * ExecReindex
2789  *
2790  * Primary entry point for manual REINDEX commands. This is mainly a
2791  * preparation wrapper for the real operations that will happen in
2792  * each subroutine of REINDEX.
2793  */
2794 void
2795 ExecReindex(ParseState *pstate, const ReindexStmt *stmt, bool isTopLevel)
2796 {
2797  ReindexParams params = {0};
2798  ListCell *lc;
2799  bool concurrently = false;
2800  bool verbose = false;
2801  char *tablespacename = NULL;
2802 
2803  /* Parse option list */
2804  foreach(lc, stmt->params)
2805  {
2806  DefElem *opt = (DefElem *) lfirst(lc);
2807 
2808  if (strcmp(opt->defname, "verbose") == 0)
2809  verbose = defGetBoolean(opt);
2810  else if (strcmp(opt->defname, "concurrently") == 0)
2811  concurrently = defGetBoolean(opt);
2812  else if (strcmp(opt->defname, "tablespace") == 0)
2813  tablespacename = defGetString(opt);
2814  else
2815  ereport(ERROR,
2816  (errcode(ERRCODE_SYNTAX_ERROR),
2817  errmsg("unrecognized REINDEX option \"%s\"",
2818  opt->defname),
2819  parser_errposition(pstate, opt->location)));
2820  }
2821 
2822  if (concurrently)
2823  PreventInTransactionBlock(isTopLevel,
2824  "REINDEX CONCURRENTLY");
2825 
2826  params.options =
2827  (verbose ? REINDEXOPT_VERBOSE : 0) |
2828  (concurrently ? REINDEXOPT_CONCURRENTLY : 0);
2829 
2830  /*
2831  * Assign the tablespace OID to move indexes to, with InvalidOid to do
2832  * nothing.
2833  */
2834  if (tablespacename != NULL)
2835  {
2836  params.tablespaceOid = get_tablespace_oid(tablespacename, false);
2837 
2838  /* Check permissions except when moving to database's default */
2839  if (OidIsValid(params.tablespaceOid) &&
2841  {
2842  AclResult aclresult;
2843 
2844  aclresult = object_aclcheck(TableSpaceRelationId, params.tablespaceOid,
2845  GetUserId(), ACL_CREATE);
2846  if (aclresult != ACLCHECK_OK)
2847  aclcheck_error(aclresult, OBJECT_TABLESPACE,
2849  }
2850  }
2851  else
2852  params.tablespaceOid = InvalidOid;
2853 
2854  switch (stmt->kind)
2855  {
2856  case REINDEX_OBJECT_INDEX:
2857  ReindexIndex(stmt, &params, isTopLevel);
2858  break;
2859  case REINDEX_OBJECT_TABLE:
2860  ReindexTable(stmt, &params, isTopLevel);
2861  break;
2862  case REINDEX_OBJECT_SCHEMA:
2863  case REINDEX_OBJECT_SYSTEM:
2865 
2866  /*
2867  * This cannot run inside a user transaction block; if we were
2868  * inside a transaction, then its commit- and
2869  * start-transaction-command calls would not have the intended
2870  * effect!
2871  */
2872  PreventInTransactionBlock(isTopLevel,
2873  (stmt->kind == REINDEX_OBJECT_SCHEMA) ? "REINDEX SCHEMA" :
2874  (stmt->kind == REINDEX_OBJECT_SYSTEM) ? "REINDEX SYSTEM" :
2875  "REINDEX DATABASE");
2876  ReindexMultipleTables(stmt, &params);
2877  break;
2878  default:
2879  elog(ERROR, "unrecognized object type: %d",
2880  (int) stmt->kind);
2881  break;
2882  }
2883 }
2884 
2885 /*
2886  * ReindexIndex
2887  * Recreate a specific index.
2888  */
2889 static void
2890 ReindexIndex(const ReindexStmt *stmt, const ReindexParams *params, bool isTopLevel)
2891 {
2892  const RangeVar *indexRelation = stmt->relation;
2894  Oid indOid;
2895  char persistence;
2896  char relkind;
2897 
2898  /*
2899  * Find and lock index, and check permissions on table; use callback to
2900  * obtain lock on table first, to avoid deadlock hazard. The lock level
2901  * used here must match the index lock obtained in reindex_index().
2902  *
2903  * If it's a temporary index, we will perform a non-concurrent reindex,
2904  * even if CONCURRENTLY was requested. In that case, reindex_index() will
2905  * upgrade the lock, but that's OK, because other sessions can't hold
2906  * locks on our temporary table.
2907  */
2908  state.params = *params;
2909  state.locked_table_oid = InvalidOid;
2910  indOid = RangeVarGetRelidExtended(indexRelation,
2913  0,
2915  &state);
2916 
2917  /*
2918  * Obtain the current persistence and kind of the existing index. We
2919  * already hold a lock on the index.
2920  */
2921  persistence = get_rel_persistence(indOid);
2922  relkind = get_rel_relkind(indOid);
2923 
2924  if (relkind == RELKIND_PARTITIONED_INDEX)
2925  ReindexPartitions(stmt, indOid, params, isTopLevel);
2926  else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
2927  persistence != RELPERSISTENCE_TEMP)
2929  else
2930  {
2931  ReindexParams newparams = *params;
2932 
2933  newparams.options |= REINDEXOPT_REPORT_PROGRESS;
2934  reindex_index(stmt, indOid, false, persistence, &newparams);
2935  }
2936 }
2937 
2938 /*
2939  * Check permissions on table before acquiring relation lock; also lock
2940  * the heap before the RangeVarGetRelidExtended takes the index lock, to avoid
2941  * deadlocks.
2942  */
2943 static void
2945  Oid relId, Oid oldRelId, void *arg)
2946 {
2947  char relkind;
2949  LOCKMODE table_lockmode;
2950  Oid table_oid;
2951 
2952  /*
2953  * Lock level here should match table lock in reindex_index() for
2954  * non-concurrent case and table locks used by index_concurrently_*() for
2955  * concurrent case.
2956  */
2957  table_lockmode = (state->params.options & REINDEXOPT_CONCURRENTLY) != 0 ?
2959 
2960  /*
2961  * If we previously locked some other index's heap, and the name we're
2962  * looking up no longer refers to that relation, release the now-useless
2963  * lock.
2964  */
2965  if (relId != oldRelId && OidIsValid(oldRelId))
2966  {
2967  UnlockRelationOid(state->locked_table_oid, table_lockmode);
2968  state->locked_table_oid = InvalidOid;
2969  }
2970 
2971  /* If the relation does not exist, there's nothing more to do. */
2972  if (!OidIsValid(relId))
2973  return;
2974 
2975  /*
2976  * If the relation does exist, check whether it's an index. But note that
2977  * the relation might have been dropped between the time we did the name
2978  * lookup and now. In that case, there's nothing to do.
2979  */
2980  relkind = get_rel_relkind(relId);
2981  if (!relkind)
2982  return;
2983  if (relkind != RELKIND_INDEX &&
2984  relkind != RELKIND_PARTITIONED_INDEX)
2985  ereport(ERROR,
2986  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2987  errmsg("\"%s\" is not an index", relation->relname)));
2988 
2989  /* Check permissions */
2990  table_oid = IndexGetRelation(relId, true);
2991  if (OidIsValid(table_oid))
2992  {
2993  AclResult aclresult;
2994 
2995  aclresult = pg_class_aclcheck(table_oid, GetUserId(), ACL_MAINTAIN);
2996  if (aclresult != ACLCHECK_OK)
2997  aclcheck_error(aclresult, OBJECT_INDEX, relation->relname);
2998  }
2999 
3000  /* Lock heap before index to avoid deadlock. */
3001  if (relId != oldRelId)
3002  {
3003  /*
3004  * If the OID isn't valid, it means the index was concurrently
3005  * dropped, which is not a problem for us; just return normally.
3006  */
3007  if (OidIsValid(table_oid))
3008  {
3009  LockRelationOid(table_oid, table_lockmode);
3010  state->locked_table_oid = table_oid;
3011  }
3012  }
3013 }
3014 
3015 /*
3016  * ReindexTable
3017  * Recreate all indexes of a table (and of its toast table, if any)
3018  */
3019 static Oid
3020 ReindexTable(const ReindexStmt *stmt, const ReindexParams *params, bool isTopLevel)
3021 {
3022  Oid heapOid;
3023  bool result;
3024  const RangeVar *relation = stmt->relation;
3025 
3026  /*
3027  * The lock level used here should match reindex_relation().
3028  *
3029  * If it's a temporary table, we will perform a non-concurrent reindex,
3030  * even if CONCURRENTLY was requested. In that case, reindex_relation()
3031  * will upgrade the lock, but that's OK, because other sessions can't hold
3032  * locks on our temporary table.
3033  */
3034  heapOid = RangeVarGetRelidExtended(relation,
3037  0,
3039 
3040  if (get_rel_relkind(heapOid) == RELKIND_PARTITIONED_TABLE)
3041  ReindexPartitions(stmt, heapOid, params, isTopLevel);
3042  else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
3043  get_rel_persistence(heapOid) != RELPERSISTENCE_TEMP)
3044  {
3045  result = ReindexRelationConcurrently(stmt, heapOid, params);
3046 
3047  if (!result)
3048  ereport(NOTICE,
3049  (errmsg("table \"%s\" has no indexes that can be reindexed concurrently",
3050  relation->relname)));
3051  }
3052  else
3053  {
3054  ReindexParams newparams = *params;
3055 
3056  newparams.options |= REINDEXOPT_REPORT_PROGRESS;
3057  result = reindex_relation(stmt, heapOid,
3060  &newparams);
3061  if (!result)
3062  ereport(NOTICE,
3063  (errmsg("table \"%s\" has no indexes to reindex",
3064  relation->relname)));
3065  }
3066 
3067  return heapOid;
3068 }
3069 
3070 /*
3071  * ReindexMultipleTables
3072  * Recreate indexes of tables selected by objectName/objectKind.
3073  *
3074  * To reduce the probability of deadlocks, each table is reindexed in a
3075  * separate transaction, so we can release the lock on it right away.
3076  * That means this must not be called within a user transaction block!
3077  */
3078 static void
3080 {
3081 
3082  Oid objectOid;
3083  Relation relationRelation;
3084  TableScanDesc scan;
3085  ScanKeyData scan_keys[1];
3086  HeapTuple tuple;
3087  MemoryContext private_context;
3088  MemoryContext old;
3089  List *relids = NIL;
3090  int num_keys;
3091  bool concurrent_warning = false;
3092  bool tablespace_warning = false;
3093  const char *objectName = stmt->name;
3094  const ReindexObjectType objectKind = stmt->kind;
3095 
3096  Assert(objectKind == REINDEX_OBJECT_SCHEMA ||
3097  objectKind == REINDEX_OBJECT_SYSTEM ||
3098  objectKind == REINDEX_OBJECT_DATABASE);
3099 
3100  /*
3101  * This matches the options enforced by the grammar, where the object name
3102  * is optional for DATABASE and SYSTEM.
3103  */
3104  Assert(objectName || objectKind != REINDEX_OBJECT_SCHEMA);
3105 
3106  if (objectKind == REINDEX_OBJECT_SYSTEM &&
3108  ereport(ERROR,
3109  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3110  errmsg("cannot reindex system catalogs concurrently")));
3111 
3112  /*
3113  * Get OID of object to reindex, being the database currently being used
3114  * by session for a database or for system catalogs, or the schema defined
3115  * by caller. At the same time do permission checks that need different
3116  * processing depending on the object type.
3117  */
3118  if (objectKind == REINDEX_OBJECT_SCHEMA)
3119  {
3120  objectOid = get_namespace_oid(objectName, false);
3121 
3122  if (!object_ownercheck(NamespaceRelationId, objectOid, GetUserId()) &&
3123  !has_privs_of_role(GetUserId(), ROLE_PG_MAINTAIN))
3125  objectName);
3126  }
3127  else
3128  {
3129  objectOid = MyDatabaseId;
3130 
3131  if (objectName && strcmp(objectName, get_database_name(objectOid)) != 0)
3132  ereport(ERROR,
3133  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3134  errmsg("can only reindex the currently open database")));
3135  if (!object_ownercheck(DatabaseRelationId, objectOid, GetUserId()) &&
3136  !has_privs_of_role(GetUserId(), ROLE_PG_MAINTAIN))
3138  get_database_name(objectOid));
3139  }
3140 
3141  /*
3142  * Create a memory context that will survive forced transaction commits we
3143  * do below. Since it is a child of PortalContext, it will go away
3144  * eventually even if we suffer an error; there's no need for special
3145  * abort cleanup logic.
3146  */
3147  private_context = AllocSetContextCreate(PortalContext,
3148  "ReindexMultipleTables",
3150 
3151  /*
3152  * Define the search keys to find the objects to reindex. For a schema, we
3153  * select target relations using relnamespace, something not necessary for
3154  * a database-wide operation.
3155  */
3156  if (objectKind == REINDEX_OBJECT_SCHEMA)
3157  {
3158  num_keys = 1;
3159  ScanKeyInit(&scan_keys[0],
3160  Anum_pg_class_relnamespace,
3161  BTEqualStrategyNumber, F_OIDEQ,
3162  ObjectIdGetDatum(objectOid));
3163  }
3164  else
3165  num_keys = 0;
3166 
3167  /*
3168  * Scan pg_class to build a list of the relations we need to reindex.
3169  *
3170  * We only consider plain relations and materialized views here (toast
3171  * rels will be processed indirectly by reindex_relation).
3172  */
3173  relationRelation = table_open(RelationRelationId, AccessShareLock);
3174  scan = table_beginscan_catalog(relationRelation, num_keys, scan_keys);
3175  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
3176  {
3177  Form_pg_class classtuple = (Form_pg_class) GETSTRUCT(tuple);
3178  Oid relid = classtuple->oid;
3179 
3180  /*
3181  * Only regular tables and matviews can have indexes, so ignore any
3182  * other kind of relation.
3183  *
3184  * Partitioned tables/indexes are skipped but matching leaf partitions
3185  * are processed.
3186  */
3187  if (classtuple->relkind != RELKIND_RELATION &&
3188  classtuple->relkind != RELKIND_MATVIEW)
3189  continue;
3190 
3191  /* Skip temp tables of other backends; we can't reindex them at all */
3192  if (classtuple->relpersistence == RELPERSISTENCE_TEMP &&
3193  !isTempNamespace(classtuple->relnamespace))
3194  continue;
3195 
3196  /*
3197  * Check user/system classification. SYSTEM processes all the
3198  * catalogs, and DATABASE processes everything that's not a catalog.
3199  */
3200  if (objectKind == REINDEX_OBJECT_SYSTEM &&
3201  !IsCatalogRelationOid(relid))
3202  continue;
3203  else if (objectKind == REINDEX_OBJECT_DATABASE &&
3204  IsCatalogRelationOid(relid))
3205  continue;
3206 
3207  /*
3208  * We already checked privileges on the database or schema, but we
3209  * further restrict reindexing shared catalogs to roles with the
3210  * MAINTAIN privilege on the relation.
3211  */
3212  if (classtuple->relisshared &&
3214  continue;
3215 
3216  /*
3217  * Skip system tables, since index_create() would reject indexing them
3218  * concurrently (and it would likely fail if we tried).
3219  */
3220  if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
3221  IsCatalogRelationOid(relid))
3222  {
3223  if (!concurrent_warning)
3224  ereport(WARNING,
3225  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3226  errmsg("cannot reindex system catalogs concurrently, skipping all")));
3227  concurrent_warning = true;
3228  continue;
3229  }
3230 
3231  /*
3232  * If a new tablespace is set, check if this relation has to be
3233  * skipped.
3234  */
3236  {
3237  bool skip_rel = false;
3238 
3239  /*
3240  * Mapped relations cannot be moved to different tablespaces (in
3241  * particular this eliminates all shared catalogs.).
3242  */
3243  if (RELKIND_HAS_STORAGE(classtuple->relkind) &&
3244  !RelFileNumberIsValid(classtuple->relfilenode))
3245  skip_rel = true;
3246 
3247  /*
3248  * A system relation is always skipped, even with
3249  * allow_system_table_mods enabled.
3250  */
3251  if (IsSystemClass(relid, classtuple))
3252  skip_rel = true;
3253 
3254  if (skip_rel)
3255  {
3256  if (!tablespace_warning)
3257  ereport(WARNING,
3258  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3259  errmsg("cannot move system relations, skipping all")));
3260  tablespace_warning = true;
3261  continue;
3262  }
3263  }
3264 
3265  /* Save the list of relation OIDs in private context */
3266  old = MemoryContextSwitchTo(private_context);
3267 
3268  /*
3269  * We always want to reindex pg_class first if it's selected to be
3270  * reindexed. This ensures that if there is any corruption in
3271  * pg_class' indexes, they will be fixed before we process any other
3272  * tables. This is critical because reindexing itself will try to
3273  * update pg_class.
3274  */
3275  if (relid == RelationRelationId)
3276  relids = lcons_oid(relid, relids);
3277  else
3278  relids = lappend_oid(relids, relid);
3279 
3280  MemoryContextSwitchTo(old);
3281  }
3282  table_endscan(scan);
3283  table_close(relationRelation, AccessShareLock);
3284 
3285  /*
3286  * Process each relation listed in a separate transaction. Note that this
3287  * commits and then starts a new transaction immediately.
3288  */
3290 
3291  MemoryContextDelete(private_context);
3292 }
3293 
3294 /*
3295  * Error callback specific to ReindexPartitions().
3296  */
3297 static void
3299 {
3300  ReindexErrorInfo *errinfo = (ReindexErrorInfo *) arg;
3301 
3302  Assert(RELKIND_HAS_PARTITIONS(errinfo->relkind));
3303 
3304  if (errinfo->relkind == RELKIND_PARTITIONED_TABLE)
3305  errcontext("while reindexing partitioned table \"%s.%s\"",
3306  errinfo->relnamespace, errinfo->relname);
3307  else if (errinfo->relkind == RELKIND_PARTITIONED_INDEX)
3308  errcontext("while reindexing partitioned index \"%s.%s\"",
3309  errinfo->relnamespace, errinfo->relname);
3310 }
3311 
3312 /*
3313  * ReindexPartitions
3314  *
3315  * Reindex a set of partitions, per the partitioned index or table given
3316  * by the caller.
3317  */
3318 static void
3319 ReindexPartitions(const ReindexStmt *stmt, Oid relid, const ReindexParams *params, bool isTopLevel)
3320 {
3321  List *partitions = NIL;
3322  char relkind = get_rel_relkind(relid);
3323  char *relname = get_rel_name(relid);
3324  char *relnamespace = get_namespace_name(get_rel_namespace(relid));
3325  MemoryContext reindex_context;
3326  List *inhoids;
3327  ListCell *lc;
3328  ErrorContextCallback errcallback;
3329  ReindexErrorInfo errinfo;
3330 
3331  Assert(RELKIND_HAS_PARTITIONS(relkind));
3332 
3333  /*
3334  * Check if this runs in a transaction block, with an error callback to
3335  * provide more context under which a problem happens.
3336  */
3337  errinfo.relname = pstrdup(relname);
3338  errinfo.relnamespace = pstrdup(relnamespace);
3339  errinfo.relkind = relkind;
3340  errcallback.callback = reindex_error_callback;
3341  errcallback.arg = (void *) &errinfo;
3342  errcallback.previous = error_context_stack;
3343  error_context_stack = &errcallback;
3344 
3345  PreventInTransactionBlock(isTopLevel,
3346  relkind == RELKIND_PARTITIONED_TABLE ?
3347  "REINDEX TABLE" : "REINDEX INDEX");
3348 
3349  /* Pop the error context stack */
3350  error_context_stack = errcallback.previous;
3351 
3352  /*
3353  * Create special memory context for cross-transaction storage.
3354  *
3355  * Since it is a child of PortalContext, it will go away eventually even
3356  * if we suffer an error so there is no need for special abort cleanup
3357  * logic.
3358  */
3359  reindex_context = AllocSetContextCreate(PortalContext, "Reindex",
3361 
3362  /* ShareLock is enough to prevent schema modifications */
3363  inhoids = find_all_inheritors(relid, ShareLock, NULL);
3364 
3365  /*
3366  * The list of relations to reindex are the physical partitions of the
3367  * tree so discard any partitioned table or index.
3368  */
3369  foreach(lc, inhoids)
3370  {
3371  Oid partoid = lfirst_oid(lc);
3372  char partkind = get_rel_relkind(partoid);
3373  MemoryContext old_context;
3374 
3375  /*
3376  * This discards partitioned tables, partitioned indexes and foreign
3377  * tables.
3378  */
3379  if (!RELKIND_HAS_STORAGE(partkind))
3380  continue;
3381 
3382  Assert(partkind == RELKIND_INDEX ||
3383  partkind == RELKIND_RELATION);
3384 
3385  /* Save partition OID */
3386  old_context = MemoryContextSwitchTo(reindex_context);
3387  partitions = lappend_oid(partitions, partoid);
3388  MemoryContextSwitchTo(old_context);
3389  }
3390 
3391  /*
3392  * Process each partition listed in a separate transaction. Note that
3393  * this commits and then starts a new transaction immediately.
3394  */
3396 
3397  /*
3398  * Clean up working storage --- note we must do this after
3399  * StartTransactionCommand, else we might be trying to delete the active
3400  * context!
3401  */
3402  MemoryContextDelete(reindex_context);
3403 }
3404 
3405 /*
3406  * ReindexMultipleInternal
3407  *
3408  * Reindex a list of relations, each one being processed in its own
3409  * transaction. This commits the existing transaction immediately,
3410  * and starts a new transaction when finished.
3411  */
3412 static void
3414 {
3415  ListCell *l;
3416 
3419 
3420  foreach(l, relids)
3421  {
3422  Oid relid = lfirst_oid(l);
3423  char relkind;
3424  char relpersistence;
3425 
3427 
3428  /* functions in indexes may want a snapshot set */
3430 
3431  /* check if the relation still exists */
3432  if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(relid)))
3433  {
3436  continue;
3437  }
3438 
3439  /*
3440  * Check permissions except when moving to database's default if a new
3441  * tablespace is chosen. Note that this check also happens in
3442  * ExecReindex(), but we do an extra check here as this runs across
3443  * multiple transactions.
3444  */
3447  {
3448  AclResult aclresult;
3449 
3450  aclresult = object_aclcheck(TableSpaceRelationId, params->tablespaceOid,
3451  GetUserId(), ACL_CREATE);
3452  if (aclresult != ACLCHECK_OK)
3453  aclcheck_error(aclresult, OBJECT_TABLESPACE,
3455  }
3456 
3457  relkind = get_rel_relkind(relid);
3458  relpersistence = get_rel_persistence(relid);
3459 
3460  /*
3461  * Partitioned tables and indexes can never be processed directly, and
3462  * a list of their leaves should be built first.
3463  */
3464  Assert(!RELKIND_HAS_PARTITIONS(relkind));
3465 
3466  if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
3467  relpersistence != RELPERSISTENCE_TEMP)
3468  {
3469  ReindexParams newparams = *params;
3470 
3471  newparams.options |= REINDEXOPT_MISSING_OK;
3472  (void) ReindexRelationConcurrently(stmt, relid, &newparams);
3473  if (ActiveSnapshotSet())
3475  /* ReindexRelationConcurrently() does the verbose output */
3476  }
3477  else if (relkind == RELKIND_INDEX)
3478  {
3479  ReindexParams newparams = *params;
3480 
3481  newparams.options |=
3483  reindex_index(stmt, relid, false, relpersistence, &newparams);
3485  /* reindex_index() does the verbose output */
3486  }
3487  else
3488  {
3489  bool result;
3490  ReindexParams newparams = *params;
3491 
3492  newparams.options |=
3494  result = reindex_relation(stmt, relid,
3497  &newparams);
3498 
3499  if (result && (params->options & REINDEXOPT_VERBOSE) != 0)
3500  ereport(INFO,
3501  (errmsg("table \"%s.%s\" was reindexed",
3503  get_rel_name(relid))));
3504 
3506  }
3507 
3509  }
3510 
3512 }
3513 
3514 
3515 /*
3516  * ReindexRelationConcurrently - process REINDEX CONCURRENTLY for given
3517  * relation OID
3518  *
3519  * 'relationOid' can either belong to an index, a table or a materialized
3520  * view. For tables and materialized views, all its indexes will be rebuilt,
3521  * excluding invalid indexes and any indexes used in exclusion constraints,
3522  * but including its associated toast table indexes. For indexes, the index
3523  * itself will be rebuilt.
3524  *
3525  * The locks taken on parent tables and involved indexes are kept until the
3526  * transaction is committed, at which point a session lock is taken on each
3527  * relation. Both of these protect against concurrent schema changes.
3528  *
3529  * Returns true if any indexes have been rebuilt (including toast table's
3530  * indexes, when relevant), otherwise returns false.
3531  *
3532  * NOTE: This cannot be used on temporary relations. A concurrent build would
3533  * cause issues with ON COMMIT actions triggered by the transactions of the
3534  * concurrent build. Temporary relations are not subject to concurrent
3535  * concerns, so there's no need for the more complicated concurrent build,
3536  * anyway, and a non-concurrent reindex is more efficient.
3537  */
3538 static bool
3540 {
3541  typedef struct ReindexIndexInfo
3542  {
3543  Oid indexId;
3544  Oid tableId;
3545  Oid amId;
3546  bool safe; /* for set_indexsafe_procflags */
3547  } ReindexIndexInfo;
3548  List *heapRelationIds = NIL;
3549  List *indexIds = NIL;
3550  List *newIndexIds = NIL;
3551  List *relationLocks = NIL;
3552  List *lockTags = NIL;
3553  ListCell *lc,
3554  *lc2;
3555  MemoryContext private_context;
3556  MemoryContext oldcontext;
3557  char relkind;
3558  char *relationName = NULL;
3559  char *relationNamespace = NULL;
3560  PGRUsage ru0;
3561  const int progress_index[] = {
3566  };
3567  int64 progress_vals[4];
3568 
3569  /*
3570  * Create a memory context that will survive forced transaction commits we
3571  * do below. Since it is a child of PortalContext, it will go away
3572  * eventually even if we suffer an error; there's no need for special
3573  * abort cleanup logic.
3574  */
3575  private_context = AllocSetContextCreate(PortalContext,
3576  "ReindexConcurrent",
3578 
3579  if ((params->options & REINDEXOPT_VERBOSE) != 0)
3580  {
3581  /* Save data needed by REINDEX VERBOSE in private context */
3582  oldcontext = MemoryContextSwitchTo(private_context);
3583 
3584  relationName = get_rel_name(relationOid);
3585  relationNamespace = get_namespace_name(get_rel_namespace(relationOid));
3586 
3587  pg_rusage_init(&ru0);
3588 
3589  MemoryContextSwitchTo(oldcontext);
3590  }
3591 
3592  relkind = get_rel_relkind(relationOid);
3593 
3594  /*
3595  * Extract the list of indexes that are going to be rebuilt based on the
3596  * relation Oid given by caller.
3597  */
3598  switch (relkind)
3599  {
3600  case RELKIND_RELATION:
3601  case RELKIND_MATVIEW:
3602  case RELKIND_TOASTVALUE:
3603  {
3604  /*
3605  * In the case of a relation, find all its indexes including
3606  * toast indexes.
3607  */
3608  Relation heapRelation;
3609 
3610  /* Save the list of relation OIDs in private context */
3611  oldcontext = MemoryContextSwitchTo(private_context);
3612 
3613  /* Track this relation for session locks */
3614  heapRelationIds = lappend_oid(heapRelationIds, relationOid);
3615 
3616  MemoryContextSwitchTo(oldcontext);
3617 
3618  if (IsCatalogRelationOid(relationOid))
3619  ereport(ERROR,
3620  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3621  errmsg("cannot reindex system catalogs concurrently")));
3622 
3623  /* Open relation to get its indexes */
3624  if ((params->options & REINDEXOPT_MISSING_OK) != 0)
3625  {
3626  heapRelation = try_table_open(relationOid,
3628  /* leave if relation does not exist */
3629  if (!heapRelation)
3630  break;
3631  }
3632  else
3633  heapRelation = table_open(relationOid,
3635 
3636  if (OidIsValid(params->tablespaceOid) &&
3637  IsSystemRelation(heapRelation))
3638  ereport(ERROR,
3639  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3640  errmsg("cannot move system relation \"%s\"",
3641  RelationGetRelationName(heapRelation))));
3642 
3643  /* Add all the valid indexes of relation to list */
3644  foreach(lc, RelationGetIndexList(heapRelation))
3645  {
3646  Oid cellOid = lfirst_oid(lc);
3647  Relation indexRelation = index_open(cellOid,
3649 
3650  if (!indexRelation->rd_index->indisvalid)
3651  ereport(WARNING,
3652  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3653  errmsg("skipping reindex of invalid index \"%s.%s\"",
3655  get_rel_name(cellOid)),
3656  errhint("Use DROP INDEX or REINDEX INDEX.")));
3657  else if (indexRelation->rd_index->indisexclusion)
3658  ereport(WARNING,
3659  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3660  errmsg("cannot reindex exclusion constraint index \"%s.%s\" concurrently, skipping",
3662  get_rel_name(cellOid))));
3663  else
3664  {
3665  ReindexIndexInfo *idx;
3666 
3667  /* Save the list of relation OIDs in private context */
3668  oldcontext = MemoryContextSwitchTo(private_context);
3669 
3670  idx = palloc_object(ReindexIndexInfo);
3671  idx->indexId = cellOid;
3672  /* other fields set later */
3673 
3674  indexIds = lappend(indexIds, idx);
3675 
3676  MemoryContextSwitchTo(oldcontext);
3677  }
3678 
3679  index_close(indexRelation, NoLock);
3680  }
3681 
3682  /* Also add the toast indexes */
3683  if (OidIsValid(heapRelation->rd_rel->reltoastrelid))
3684  {
3685  Oid toastOid = heapRelation->rd_rel->reltoastrelid;
3686  Relation toastRelation = table_open(toastOid,
3688 
3689  /* Save the list of relation OIDs in private context */
3690  oldcontext = MemoryContextSwitchTo(private_context);
3691 
3692  /* Track this relation for session locks */
3693  heapRelationIds = lappend_oid(heapRelationIds, toastOid);
3694 
3695  MemoryContextSwitchTo(oldcontext);
3696 
3697  foreach(lc2, RelationGetIndexList(toastRelation))
3698  {
3699  Oid cellOid = lfirst_oid(lc2);
3700  Relation indexRelation = index_open(cellOid,
3702 
3703  if (!indexRelation->rd_index->indisvalid)
3704  ereport(WARNING,
3705  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3706  errmsg("skipping reindex of invalid index \"%s.%s\"",
3708  get_rel_name(cellOid)),
3709  errhint("Use DROP INDEX or REINDEX INDEX.")));
3710  else
3711  {
3712  ReindexIndexInfo *idx;
3713 
3714  /*
3715  * Save the list of relation OIDs in private
3716  * context
3717  */
3718  oldcontext = MemoryContextSwitchTo(private_context);
3719 
3720  idx = palloc_object(ReindexIndexInfo);
3721  idx->indexId = cellOid;
3722  indexIds = lappend(indexIds, idx);
3723  /* other fields set later */
3724 
3725  MemoryContextSwitchTo(oldcontext);
3726  }
3727 
3728  index_close(indexRelation, NoLock);
3729  }
3730 
3731  table_close(toastRelation, NoLock);
3732  }
3733 
3734  table_close(heapRelation, NoLock);
3735  break;
3736  }
3737  case RELKIND_INDEX:
3738  {
3739  Oid heapId = IndexGetRelation(relationOid,
3740  (params->options & REINDEXOPT_MISSING_OK) != 0);
3741  Relation heapRelation;
3742  ReindexIndexInfo *idx;
3743 
3744  /* if relation is missing, leave */
3745  if (!OidIsValid(heapId))
3746  break;
3747 
3748  if (IsCatalogRelationOid(heapId))
3749  ereport(ERROR,
3750  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3751  errmsg("cannot reindex system catalogs concurrently")));
3752 
3753  /*
3754  * Don't allow reindex for an invalid index on TOAST table, as
3755  * if rebuilt it would not be possible to drop it. Match
3756  * error message in reindex_index().
3757  */
3758  if (IsToastNamespace(get_rel_namespace(relationOid)) &&
3759  !get_index_isvalid(relationOid))
3760  ereport(ERROR,
3761  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3762  errmsg("cannot reindex invalid index on TOAST table")));
3763 
3764  /*
3765  * Check if parent relation can be locked and if it exists,
3766  * this needs to be done at this stage as the list of indexes
3767  * to rebuild is not complete yet, and REINDEXOPT_MISSING_OK
3768  * should not be used once all the session locks are taken.
3769  */
3770  if ((params->options & REINDEXOPT_MISSING_OK) != 0)
3771  {
3772  heapRelation = try_table_open(heapId,
3774  /* leave if relation does not exist */
3775  if (!heapRelation)
3776  break;
3777  }
3778  else
3779  heapRelation = table_open(heapId,
3781 
3782  if (OidIsValid(params->tablespaceOid) &&
3783  IsSystemRelation(heapRelation))
3784  ereport(ERROR,
3785  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3786  errmsg("cannot move system relation \"%s\"",
3787  get_rel_name(relationOid))));
3788 
3789  table_close(heapRelation, NoLock);
3790 
3791  /* Save the list of relation OIDs in private context */
3792  oldcontext = MemoryContextSwitchTo(private_context);
3793 
3794  /* Track the heap relation of this index for session locks */
3795  heapRelationIds = list_make1_oid(heapId);
3796 
3797  /*
3798  * Save the list of relation OIDs in private context. Note
3799  * that invalid indexes are allowed here.
3800  */
3801  idx = palloc_object(ReindexIndexInfo);
3802  idx->indexId = relationOid;
3803  indexIds = lappend(indexIds, idx);
3804  /* other fields set later */
3805 
3806  MemoryContextSwitchTo(oldcontext);
3807  break;
3808  }
3809 
3810  case RELKIND_PARTITIONED_TABLE:
3811  case RELKIND_PARTITIONED_INDEX:
3812  default:
3813  /* Return error if type of relation is not supported */
3814  ereport(ERROR,
3815  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3816  errmsg("cannot reindex this type of relation concurrently")));
3817  break;
3818  }
3819 
3820  /*
3821  * Definitely no indexes, so leave. Any checks based on
3822  * REINDEXOPT_MISSING_OK should be done only while the list of indexes to
3823  * work on is built as the session locks taken before this transaction
3824  * commits will make sure that they cannot be dropped by a concurrent
3825  * session until this operation completes.
3826  */
3827  if (indexIds == NIL)
3828  return false;
3829 
3830  /* It's not a shared catalog, so refuse to move it to shared tablespace */
3831  if (params->tablespaceOid == GLOBALTABLESPACE_OID)
3832  ereport(ERROR,
3833  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3834  errmsg("cannot move non-shared relation to tablespace \"%s\"",
3835  get_tablespace_name(params->tablespaceOid))));
3836 
3837  Assert(heapRelationIds != NIL);
3838 
3839  /*-----
3840  * Now we have all the indexes we want to process in indexIds.
3841  *
3842  * The phases now are:
3843  *
3844  * 1. create new indexes in the catalog
3845  * 2. build new indexes
3846  * 3. let new indexes catch up with tuples inserted in the meantime
3847  * 4. swap index names
3848  * 5. mark old indexes as dead
3849  * 6. drop old indexes
3850  *
3851  * We process each phase for all indexes before moving to the next phase,
3852  * for efficiency.
3853  */
3854 
3855  /*
3856  * Phase 1 of REINDEX CONCURRENTLY
3857  *
3858  * Create a new index with the same properties as the old one, but it is
3859  * only registered in catalogs and will be built later. Then get session
3860  * locks on all involved tables. See analogous code in DefineIndex() for
3861  * more detailed comments.
3862  */
3863 
3864  foreach(lc, indexIds)
3865  {
3866  char *concurrentName;
3867  ReindexIndexInfo *idx = lfirst(lc);
3868  ReindexIndexInfo *newidx;
3869  Oid newIndexId;
3870  Relation indexRel;
3871  Relation heapRel;
3872  Oid save_userid;
3873  int save_sec_context;
3874  int save_nestlevel;
3875  Relation newIndexRel;
3876  LockRelId *lockrelid;
3877  Oid tablespaceid;
3878 
3879  indexRel = index_open(idx->indexId, ShareUpdateExclusiveLock);
3880  heapRel = table_open(indexRel->rd_index->indrelid,
3882 
3883  /*
3884  * Switch to the table owner's userid, so that any index functions are
3885  * run as that user. Also lock down security-restricted operations
3886  * and arrange to make GUC variable changes local to this command.
3887  */
3888  GetUserIdAndSecContext(&save_userid, &save_sec_context);
3889  SetUserIdAndSecContext(heapRel->rd_rel->relowner,
3890  save_sec_context | SECURITY_RESTRICTED_OPERATION);
3891  save_nestlevel = NewGUCNestLevel();
3893 
3894  /* determine safety of this index for set_indexsafe_procflags */
3895  idx->safe = (RelationGetIndexExpressions(indexRel) == NIL &&
3896  RelationGetIndexPredicate(indexRel) == NIL);
3897 
3898 #ifdef USE_INJECTION_POINTS
3899  if (idx->safe)
3900  INJECTION_POINT("reindex-conc-index-safe");
3901  else
3902  INJECTION_POINT("reindex-conc-index-not-safe");
3903 #endif
3904 
3905  idx->tableId = RelationGetRelid(heapRel);
3906  idx->amId = indexRel->rd_rel->relam;
3907 
3908  /* This function shouldn't be called for temporary relations. */
3909  if (indexRel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
3910  elog(ERROR, "cannot reindex a temporary table concurrently");
3911 
3913 
3915  progress_vals[1] = 0; /* initializing */
3916  progress_vals[2] = idx->indexId;
3917  progress_vals[3] = idx->amId;
3918  pgstat_progress_update_multi_param(4, progress_index, progress_vals);
3919 
3920  /* Choose a temporary relation name for the new index */
3921  concurrentName = ChooseRelationName(get_rel_name(idx->indexId),
3922  NULL,
3923  "ccnew",
3924  get_rel_namespace(indexRel->rd_index->indrelid),
3925  false);
3926 
3927  /* Choose the new tablespace, indexes of toast tables are not moved */
3928  if (OidIsValid(params->tablespaceOid) &&
3929  heapRel->rd_rel->relkind != RELKIND_TOASTVALUE)
3930  tablespaceid = params->tablespaceOid;
3931  else
3932  tablespaceid = indexRel->rd_rel->reltablespace;
3933 
3934  /* Create new index definition based on given index */
3935  newIndexId = index_concurrently_create_copy(heapRel,
3936  idx->indexId,
3937  tablespaceid,
3938  concurrentName);
3939 
3940  /*
3941  * Now open the relation of the new index, a session-level lock is
3942  * also needed on it.
3943  */
3944  newIndexRel = index_open(newIndexId, ShareUpdateExclusiveLock);
3945 
3946  /*
3947  * Save the list of OIDs and locks in private context
3948  */
3949  oldcontext = MemoryContextSwitchTo(private_context);
3950 
3951  newidx = palloc_object(ReindexIndexInfo);
3952  newidx->indexId = newIndexId;
3953  newidx->safe = idx->safe;
3954  newidx->tableId = idx->tableId;
3955  newidx->amId = idx->amId;
3956 
3957  newIndexIds = lappend(newIndexIds, newidx);
3958 
3959  /*
3960  * Save lockrelid to protect each relation from drop then close
3961  * relations. The lockrelid on parent relation is not taken here to
3962  * avoid multiple locks taken on the same relation, instead we rely on
3963  * parentRelationIds built earlier.
3964  */
3965  lockrelid = palloc_object(LockRelId);
3966  *lockrelid = indexRel->rd_lockInfo.lockRelId;
3967  relationLocks = lappend(relationLocks, lockrelid);
3968  lockrelid = palloc_object(LockRelId);
3969  *lockrelid = newIndexRel->rd_lockInfo.lockRelId;
3970  relationLocks = lappend(relationLocks, lockrelid);
3971 
3972  MemoryContextSwitchTo(oldcontext);
3973 
3974  index_close(indexRel, NoLock);
3975  index_close(newIndexRel, NoLock);
3976 
3977  /* Roll back any GUC changes executed by index functions */
3978  AtEOXact_GUC(false, save_nestlevel);
3979 
3980  /* Restore userid and security context */
3981  SetUserIdAndSecContext(save_userid, save_sec_context);
3982 
3983  table_close(heapRel, NoLock);
3984 
3985  /*
3986  * If a statement is available, telling that this comes from a REINDEX
3987  * command, collect the new index for event triggers.
3988  */
3989  if (stmt)
3990  {
3991  ObjectAddress address;
3992 
3993  ObjectAddressSet(address, RelationRelationId, newIndexId);
3996  (Node *) stmt);
3997  }
3998  }
3999 
4000  /*
4001  * Save the heap lock for following visibility checks with other backends
4002  * might conflict with this session.
4003  */
4004  foreach(lc, heapRelationIds)
4005  {
4007  LockRelId *lockrelid;
4008  LOCKTAG *heaplocktag;
4009 
4010  /* Save the list of locks in private context */
4011  oldcontext = MemoryContextSwitchTo(private_context);
4012 
4013  /* Add lockrelid of heap relation to the list of locked relations */
4014  lockrelid = palloc_object(LockRelId);
4015  *lockrelid = heapRelation->rd_lockInfo.lockRelId;
4016  relationLocks = lappend(relationLocks, lockrelid);
4017 
4018  heaplocktag = palloc_object(LOCKTAG);
4019 
4020  /* Save the LOCKTAG for this parent relation for the wait phase */
4021  SET_LOCKTAG_RELATION(*heaplocktag, lockrelid->dbId, lockrelid->relId);
4022  lockTags = lappend(lockTags, heaplocktag);
4023 
4024  MemoryContextSwitchTo(oldcontext);
4025 
4026  /* Close heap relation */
4027  table_close(heapRelation, NoLock);
4028  }
4029 
4030  /* Get a session-level lock on each table. */
4031  foreach(lc, relationLocks)
4032  {
4033  LockRelId *lockrelid = (LockRelId *) lfirst(lc);
4034 
4036  }
4037 
4041 
4042  /*
4043  * Because we don't take a snapshot in this transaction, there's no need
4044  * to set the PROC_IN_SAFE_IC flag here.
4045  */
4046 
4047  /*
4048  * Phase 2 of REINDEX CONCURRENTLY
4049  *
4050  * Build the new indexes in a separate transaction for each index to avoid
4051  * having open transactions for an unnecessary long time. But before
4052  * doing that, wait until no running transactions could have the table of
4053  * the index open with the old list of indexes. See "phase 2" in
4054  * DefineIndex() for more details.
4055  */
4056 
4059  WaitForLockersMultiple(lockTags, ShareLock, true);
4061 
4062  foreach(lc, newIndexIds)
4063  {
4064  ReindexIndexInfo *newidx = lfirst(lc);
4065 
4066  /* Start new transaction for this index's concurrent build */
4068 
4069  /*
4070  * Check for user-requested abort. This is inside a transaction so as
4071  * xact.c does not issue a useless WARNING, and ensures that
4072  * session-level locks are cleaned up on abort.
4073  */
4075 
4076  /* Tell concurrent indexing to ignore us, if index qualifies */
4077  if (newidx->safe)
4079 
4080  /* Set ActiveSnapshot since functions in the indexes may need it */
4082 
4083  /*
4084  * Update progress for the index to build, with the correct parent
4085  * table involved.
4086  */
4089  progress_vals[1] = PROGRESS_CREATEIDX_PHASE_BUILD;
4090  progress_vals[2] = newidx->indexId;
4091  progress_vals[3] = newidx->amId;
4092  pgstat_progress_update_multi_param(4, progress_index, progress_vals);
4093 
4094  /* Perform concurrent build of new index */
4095  index_concurrently_build(newidx->tableId, newidx->indexId);
4096 
4099  }
4100 
4102 
4103  /*
4104  * Because we don't take a snapshot or Xid in this transaction, there's no
4105  * need to set the PROC_IN_SAFE_IC flag here.
4106  */
4107 
4108  /*
4109  * Phase 3 of REINDEX CONCURRENTLY
4110  *
4111  * During this phase the old indexes catch up with any new tuples that
4112  * were created during the previous phase. See "phase 3" in DefineIndex()
4113  * for more details.
4114  */
4115 
4118  WaitForLockersMultiple(lockTags, ShareLock, true);
4120 
4121  foreach(lc, newIndexIds)
4122  {
4123  ReindexIndexInfo *newidx = lfirst(lc);
4124  TransactionId limitXmin;
4125  Snapshot snapshot;
4126 
4128 
4129  /*
4130  * Check for user-requested abort. This is inside a transaction so as
4131  * xact.c does not issue a useless WARNING, and ensures that
4132  * session-level locks are cleaned up on abort.
4133  */
4135 
4136  /* Tell concurrent indexing to ignore us, if index qualifies */
4137  if (newidx->safe)
4139 
4140  /*
4141  * Take the "reference snapshot" that will be used by validate_index()
4142  * to filter candidate tuples.
4143  */
4145  PushActiveSnapshot(snapshot);
4146 
4147  /*
4148  * Update progress for the index to build, with the correct parent
4149  * table involved.
4150  */
4153  progress_vals[1] = PROGRESS_CREATEIDX_PHASE_VALIDATE_IDXSCAN;
4154  progress_vals[2] = newidx->indexId;
4155  progress_vals[3] = newidx->amId;
4156  pgstat_progress_update_multi_param(4, progress_index, progress_vals);
4157 
4158  validate_index(newidx->tableId, newidx->indexId, snapshot);
4159 
4160  /*
4161  * We can now do away with our active snapshot, we still need to save
4162  * the xmin limit to wait for older snapshots.
4163  */
4164  limitXmin = snapshot->xmin;
4165 
4167  UnregisterSnapshot(snapshot);
4168 
4169  /*
4170  * To ensure no deadlocks, we must commit and start yet another
4171  * transaction, and do our wait before any snapshot has been taken in
4172  * it.
4173  */
4176 
4177  /*
4178  * The index is now valid in the sense that it contains all currently
4179  * interesting tuples. But since it might not contain tuples deleted
4180  * just before the reference snap was taken, we have to wait out any
4181  * transactions that might have older snapshots.
4182  *
4183  * Because we don't take a snapshot or Xid in this transaction,
4184  * there's no need to set the PROC_IN_SAFE_IC flag here.
4185  */
4188  WaitForOlderSnapshots(limitXmin, true);
4189 
4191  }
4192 
4193  /*
4194  * Phase 4 of REINDEX CONCURRENTLY
4195  *
4196  * Now that the new indexes have been validated, swap each new index with
4197  * its corresponding old index.
4198  *
4199  * We mark the new indexes as valid and the old indexes as not valid at
4200  * the same time to make sure we only get constraint violations from the
4201  * indexes with the correct names.
4202  */
4203 
4205 
4206  /*
4207  * Because this transaction only does catalog manipulations and doesn't do
4208  * any index operations, we can set the PROC_IN_SAFE_IC flag here
4209  * unconditionally.
4210  */
4212 
4213  forboth(lc, indexIds, lc2, newIndexIds)
4214  {
4215  ReindexIndexInfo *oldidx = lfirst(lc);
4216  ReindexIndexInfo *newidx = lfirst(lc2);
4217  char *oldName;
4218 
4219  /*
4220  * Check for user-requested abort. This is inside a transaction so as
4221  * xact.c does not issue a useless WARNING, and ensures that
4222  * session-level locks are cleaned up on abort.
4223  */
4225 
4226  /* Choose a relation name for old index */
4227  oldName = ChooseRelationName(get_rel_name(oldidx->indexId),
4228  NULL,
4229  "ccold",
4230  get_rel_namespace(oldidx->tableId),
4231  false);
4232 
4233  /*
4234  * Updating pg_index might involve TOAST table access, so ensure we
4235  * have a valid snapshot.
4236  */
4238 
4239  /*
4240  * Swap old index with the new one. This also marks the new one as
4241  * valid and the old one as not valid.
4242  */
4243  index_concurrently_swap(newidx->indexId, oldidx->indexId, oldName);
4244 
4246 
4247  /*
4248  * Invalidate the relcache for the table, so that after this commit
4249  * all sessions will refresh any cached plans that might reference the
4250  * index.
4251  */
4252  CacheInvalidateRelcacheByRelid(oldidx->tableId);
4253 
4254  /*
4255  * CCI here so that subsequent iterations see the oldName in the
4256  * catalog and can choose a nonconflicting name for their oldName.
4257  * Otherwise, this could lead to conflicts if a table has two indexes
4258  * whose names are equal for the first NAMEDATALEN-minus-a-few
4259  * characters.
4260  */
4262  }
4263 
4264  /* Commit this transaction and make index swaps visible */
4267 
4268  /*
4269  * While we could set PROC_IN_SAFE_IC if all indexes qualified, there's no
4270  * real need for that, because we only acquire an Xid after the wait is
4271  * done, and that lasts for a very short period.
4272  */
4273 
4274  /*
4275  * Phase 5 of REINDEX CONCURRENTLY
4276  *
4277  * Mark the old indexes as dead. First we must wait until no running
4278  * transaction could be using the index for a query. See also
4279  * index_drop() for more details.
4280  */
4281 
4285 
4286  foreach(lc, indexIds)
4287  {
4288  ReindexIndexInfo *oldidx = lfirst(lc);
4289 
4290  /*
4291  * Check for user-requested abort. This is inside a transaction so as
4292  * xact.c does not issue a useless WARNING, and ensures that
4293  * session-level locks are cleaned up on abort.
4294  */
4296 
4297  /*
4298  * Updating pg_index might involve TOAST table access, so ensure we
4299  * have a valid snapshot.
4300  */
4302 
4303  index_concurrently_set_dead(oldidx->tableId, oldidx->indexId);
4304 
4306  }
4307 
4308  /* Commit this transaction to make the updates visible. */
4311 
4312  /*
4313  * While we could set PROC_IN_SAFE_IC if all indexes qualified, there's no
4314  * real need for that, because we only acquire an Xid after the wait is
4315  * done, and that lasts for a very short period.
4316  */
4317 
4318  /*
4319  * Phase 6 of REINDEX CONCURRENTLY
4320  *
4321  * Drop the old indexes.
4322  */
4323 
4327 
4329 
4330  {
4332 
4333  foreach(lc, indexIds)
4334  {
4335  ReindexIndexInfo *idx = lfirst(lc);
4336  ObjectAddress object;
4337 
4338  object.classId = RelationRelationId;
4339  object.objectId = idx->indexId;
4340  object.objectSubId = 0;
4341 
4342  add_exact_object_address(&object, objects);
4343  }
4344 
4345  /*
4346  * Use PERFORM_DELETION_CONCURRENT_LOCK so that index_drop() uses the
4347  * right lock level.
4348  */
4351  }
4352 
4355 
4356  /*
4357  * Finally, release the session-level lock on the table.
4358  */
4359  foreach(lc, relationLocks)
4360  {
4361  LockRelId *lockrelid = (LockRelId *) lfirst(lc);
4362 
4364  }
4365 
4366  /* Start a new transaction to finish process properly */
4368 
4369  /* Log what we did */
4370  if ((params->options & REINDEXOPT_VERBOSE) != 0)
4371  {
4372  if (relkind == RELKIND_INDEX)
4373  ereport(INFO,
4374  (errmsg("index \"%s.%s\" was reindexed",
4375  relationNamespace, relationName),
4376  errdetail("%s.",
4377  pg_rusage_show(&ru0))));
4378  else
4379  {
4380  foreach(lc, newIndexIds)
4381  {
4382  ReindexIndexInfo *idx = lfirst(lc);
4383  Oid indOid = idx->indexId;
4384 
4385  ereport(INFO,
4386  (errmsg("index \"%s.%s\" was reindexed",
4388  get_rel_name(indOid))));
4389  /* Don't show rusage here, since it's not per index. */
4390  }
4391 
4392  ereport(INFO,
4393  (errmsg("table \"%s.%s\" was reindexed",
4394  relationNamespace, relationName),
4395  errdetail("%s.",
4396  pg_rusage_show(&ru0))));
4397  }
4398  }
4399 
4400  MemoryContextDelete(private_context);
4401 
4403 
4404  return true;
4405 }
4406 
4407 /*
4408  * Insert or delete an appropriate pg_inherits tuple to make the given index
4409  * be a partition of the indicated parent index.
4410  *
4411  * This also corrects the pg_depend information for the affected index.
4412  */
4413 void
4414 IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
4415 {
4416  Relation pg_inherits;
4417  ScanKeyData key[2];
4418  SysScanDesc scan;
4419  Oid partRelid = RelationGetRelid(partitionIdx);
4420  HeapTuple tuple;
4421  bool fix_dependencies;
4422 
4423  /* Make sure this is an index */
4424  Assert(partitionIdx->rd_rel->relkind == RELKIND_INDEX ||
4425  partitionIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
4426 
4427  /*
4428  * Scan pg_inherits for rows linking our index to some parent.
4429  */
4430  pg_inherits = relation_open(InheritsRelationId, RowExclusiveLock);
4431  ScanKeyInit(&key[0],
4432  Anum_pg_inherits_inhrelid,
4433  BTEqualStrategyNumber, F_OIDEQ,
4434  ObjectIdGetDatum(partRelid));
4435  ScanKeyInit(&key[1],
4436  Anum_pg_inherits_inhseqno,
4437  BTEqualStrategyNumber, F_INT4EQ,
4438  Int32GetDatum(1));
4439  scan = systable_beginscan(pg_inherits, InheritsRelidSeqnoIndexId, true,
4440  NULL, 2, key);
4441  tuple = systable_getnext(scan);
4442 
4443  if (!HeapTupleIsValid(tuple))
4444  {
4445  if (parentOid == InvalidOid)
4446  {
4447  /*
4448  * No pg_inherits row, and no parent wanted: nothing to do in this
4449  * case.
4450  */
4451  fix_dependencies = false;
4452  }
4453  else
4454  {
4455  StoreSingleInheritance(partRelid, parentOid, 1);
4456  fix_dependencies = true;
4457  }
4458  }
4459  else
4460  {
4461  Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(tuple);
4462 
4463  if (parentOid == InvalidOid)
4464  {
4465  /*
4466  * There exists a pg_inherits row, which we want to clear; do so.
4467  */
4468  CatalogTupleDelete(pg_inherits, &tuple->t_self);
4469  fix_dependencies = true;
4470  }
4471  else
4472  {
4473  /*
4474  * A pg_inherits row exists. If it's the same we want, then we're
4475  * good; if it differs, that amounts to a corrupt catalog and
4476  * should not happen.
4477  */
4478  if (inhForm->inhparent != parentOid)
4479  {
4480  /* unexpected: we should not get called in this case */
4481  elog(ERROR, "bogus pg_inherit row: inhrelid %u inhparent %u",
4482  inhForm->inhrelid, inhForm->inhparent);
4483  }
4484 
4485  /* already in the right state */
4486  fix_dependencies = false;
4487  }
4488  }
4489 
4490  /* done with pg_inherits */
4491  systable_endscan(scan);
4492  relation_close(pg_inherits, RowExclusiveLock);
4493 
4494  /* set relhassubclass if an index partition has been added to the parent */
4495  if (OidIsValid(parentOid))
4496  {
4498  SetRelationHasSubclass(parentOid, true);
4499  }
4500 
4501  /* set relispartition correctly on the partition */
4502  update_relispartition(partRelid, OidIsValid(parentOid));
4503 
4504  if (fix_dependencies)
4505  {
4506  /*
4507  * Insert/delete pg_depend rows. If setting a parent, add PARTITION
4508  * dependencies on the parent index and the table; if removing a
4509  * parent, delete PARTITION dependencies.
4510  */
4511  if (OidIsValid(parentOid))
4512  {
4513  ObjectAddress partIdx;
4514  ObjectAddress parentIdx;
4515  ObjectAddress partitionTbl;
4516 
4517  ObjectAddressSet(partIdx, RelationRelationId, partRelid);
4518  ObjectAddressSet(parentIdx, RelationRelationId, parentOid);
4519  ObjectAddressSet(partitionTbl, RelationRelationId,
4520  partitionIdx->rd_index->indrelid);
4521  recordDependencyOn(&partIdx, &parentIdx,
4523  recordDependencyOn(&partIdx, &partitionTbl,
4525  }
4526  else
4527  {
4528  deleteDependencyRecordsForClass(RelationRelationId, partRelid,
4529  RelationRelationId,
4531  deleteDependencyRecordsForClass(RelationRelationId, partRelid,
4532  RelationRelationId,
4534  }
4535 
4536  /* make our updates visible */
4538  }
4539 }
4540 
4541 /*
4542  * Subroutine of IndexSetParentIndex to update the relispartition flag of the
4543  * given index to the given value.
4544  */
4545 static void
4547 {
4548  HeapTuple tup;
4549  Relation classRel;
4550  ItemPointerData otid;
4551 
4552  classRel = table_open(RelationRelationId, RowExclusiveLock);
4553  tup = SearchSysCacheLockedCopy1(RELOID, ObjectIdGetDatum(relationId));
4554  if (!HeapTupleIsValid(tup))
4555  elog(ERROR, "cache lookup failed for relation %u", relationId);
4556  otid = tup->t_self;
4557  Assert(((Form_pg_class) GETSTRUCT(tup))->relispartition != newval);
4558  ((Form_pg_class) GETSTRUCT(tup))->relispartition = newval;
4559  CatalogTupleUpdate(classRel, &otid, tup);
4560  UnlockTuple(classRel, &otid, InplaceUpdateTupleLock);
4561  heap_freetuple(tup);
4562  table_close(classRel, RowExclusiveLock);
4563 }
4564 
4565 /*
4566  * Set the PROC_IN_SAFE_IC flag in MyProc->statusFlags.
4567  *
4568  * When doing concurrent index builds, we can set this flag
4569  * to tell other processes concurrently running CREATE
4570  * INDEX CONCURRENTLY or REINDEX CONCURRENTLY to ignore us when
4571  * doing their waits for concurrent snapshots. On one hand it
4572  * avoids pointlessly waiting for a process that's not interesting
4573  * anyway; but more importantly it avoids deadlocks in some cases.
4574  *
4575  * This can be done safely only for indexes that don't execute any
4576  * expressions that could access other tables, so index must not be
4577  * expressional nor partial. Caller is responsible for only calling
4578  * this routine when that assumption holds true.
4579  *
4580  * (The flag is reset automatically at transaction end, so it must be
4581  * set for each transaction.)
4582  */
4583 static inline void
4585 {
4586  /*
4587  * This should only be called before installing xid or xmin in MyProc;
4588  * otherwise, concurrent processes could see an Xmin that moves backwards.
4589  */
4592 
4593  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4596  LWLockRelease(ProcArrayLock);
4597 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:5268
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2703
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3891
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4145
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4094
IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition: amapi.c:33
bytea *(* amoptions_function)(Datum reloptions, bool validate)
Definition: amapi.h:151
Datum array_eq(PG_FUNCTION_ARGS)
Definition: arrayfuncs.c:3814
void free_attrmap(AttrMap *map)
Definition: attmap.c:56
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition: attmap.c:177
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1472
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1426
Oid GetDefaultTablespace(char relpersistence, bool partitioned)
Definition: tablespace.c:1143
void pgstat_progress_start_command(ProgressCommandType cmdtype, Oid relid)
void pgstat_progress_incr_param(int index, int64 incr)
void pgstat_progress_update_param(int index, int64 val)
void pgstat_progress_update_multi_param(int nparam, const int *index, const int64 *val)
void pgstat_progress_end_command(void)
@ PROGRESS_COMMAND_CREATE_INDEX
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
#define NameStr(name)
Definition: c.h:737
unsigned short uint16
Definition: c.h:505
uint16 bits16
Definition: c.h:513
signed short int16
Definition: c.h:495
#define Assert(condition)
Definition: c.h:849
uint32 TransactionId
Definition: c.h:643
#define OidIsValid(objectId)
Definition: c.h:766
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:230
bool IsSystemRelation(Relation relation)
Definition: catalog.c:73
bool IsCatalogRelationOid(Oid relid)
Definition: catalog.c:120
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:85
bool contain_mutable_functions_after_planning(Expr *expr)
Definition: clauses.c:490
void CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment)
Definition: comment.c:143
char * get_database_name(Oid dbid)
Definition: dbcommands.c:3187
bool defGetBoolean(DefElem *def)
Definition: define.c:107
char * defGetString(DefElem *def)
Definition: define.c:48
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:332
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2487
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2533
@ DEPENDENCY_PARTITION_PRI
Definition: dependency.h:36
@ DEPENDENCY_PARTITION_SEC
Definition: dependency.h:37
#define PERFORM_DELETION_CONCURRENT_LOCK
Definition: dependency.h:97
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:92
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1157
int errdetail(const char *fmt,...)
Definition: elog.c:1203
ErrorContextCallback * error_context_stack
Definition: elog.c:94
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define errcontext
Definition: elog.h:196
#define WARNING
Definition: elog.h:36
#define DEBUG1
Definition: elog.h:30
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define NOTICE
Definition: elog.h:35
#define INFO
Definition: elog.h:34
#define ereport(elevel,...)
Definition: elog.h:149
void EventTriggerCollectSimpleCommand(ObjectAddress address, ObjectAddress secondaryObject, Node *parsetree)
#define palloc_object(type)
Definition: fe_memutils.h:62
#define palloc_array(type, count)
Definition: fe_memutils.h:64
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:643
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:511
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
StrategyNumber GistTranslateStratnum(Oid opclass, StrategyNumber strat)
Definition: gistutil.c:1081
bool allowSystemTableMods
Definition: globals.c:129
Oid MyDatabaseTableSpace
Definition: globals.c:95
Oid MyDatabaseId
Definition: globals.c:93
int NewGUCNestLevel(void)
Definition: guc.c:2234
#define newval
void RestrictSearchPath(void)
Definition: guc.c:2245
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:2261
int set_config_option(const char *name, const char *value, GucContext context, GucSource source, GucAction action, bool changeVal, int elevel, bool is_reload)
Definition: guc.c:3341
@ GUC_ACTION_SAVE
Definition: guc.h:201
@ PGC_S_SESSION
Definition: guc.h:122
@ PGC_USERSET
Definition: guc.h:75
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1243
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:776
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:455
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
#define stmt
Definition: indent_codes.h:59
int verbose
void validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
Definition: index.c:3301
Oid IndexGetRelation(Oid indexId, bool missing_ok)
Definition: index.c:3534
void index_concurrently_set_dead(Oid heapId, Oid indexId)
Definition: index.c:1821
Oid index_create(Relation heapRelation, const char *indexRelationName, Oid indexRelationId, Oid parentIndexRelid, Oid parentConstraintId, RelFileNumber relFileNumber, IndexInfo *indexInfo, const List *indexColNames, Oid accessMethodId, Oid tableSpaceId, const Oid *collationIds, const Oid *opclassIds, const Datum *opclassOptions, const int16 *coloptions, const NullableDatum *stattargets, Datum reloptions, bits16 flags, bits16 constr_flags, bool allow_system_table_mods, bool is_internal, Oid *constraintId)
Definition: index.c:724
void index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName)
Definition: index.c:1550
void index_set_state_flags(Oid indexId, IndexStateFlagsAction action)
Definition: index.c:3454
bool CompareIndexInfo(const IndexInfo *info1, const IndexInfo *info2, const Oid *collations1, const Oid *collations2, const Oid *opfamilies1, const Oid *opfamilies2, const AttrMap *attmap)
Definition: index.c:2539
bool reindex_relation(const ReindexStmt *stmt, Oid relid, int flags, const ReindexParams *params)
Definition: index.c:3899
Oid index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, Oid tablespaceOid, const char *newName)
Definition: index.c:1298
void index_check_primary_key(Relation heapRel, const IndexInfo *indexInfo, bool is_alter_table, const IndexStmt *stmt)
Definition: index.c:201
void index_concurrently_build(Oid heapRelationId, Oid indexRelationId)
Definition: index.c:1483
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2430
void reindex_index(const ReindexStmt *stmt, Oid indexId, bool skip_constraint_checks, char persistence, const ReindexParams *params)
Definition: index.c:3559
#define INDEX_CREATE_IS_PRIMARY
Definition: index.h:61
#define INDEX_CREATE_IF_NOT_EXISTS
Definition: index.h:65
#define REINDEX_REL_PROCESS_TOAST
Definition: index.h:159
#define INDEX_CREATE_PARTITIONED
Definition: index.h:66
#define REINDEXOPT_CONCURRENTLY
Definition: index.h:44
#define REINDEXOPT_MISSING_OK
Definition: index.h:43
#define INDEX_CREATE_INVALID
Definition: index.h:67
#define INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS
Definition: index.h:96
#define INDEX_CREATE_ADD_CONSTRAINT
Definition: index.h:62
#define INDEX_CREATE_SKIP_BUILD
Definition: index.h:63
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition: index.h:92
#define REINDEXOPT_REPORT_PROGRESS
Definition: index.h:42
@ INDEX_CREATE_SET_VALID
Definition: index.h:27
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition: index.h:93
#define INDEX_CREATE_CONCURRENT
Definition: index.h:64
#define REINDEXOPT_VERBOSE
Definition: index.h:41
#define REINDEX_REL_CHECK_CONSTRAINTS
Definition: index.h:161
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:133
static bool ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const ReindexParams *params)
Definition: indexcmds.c:3539
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition: indexcmds.c:2523
void ExecReindex(ParseState *pstate, const ReindexStmt *stmt, bool isTopLevel)
Definition: indexcmds.c:2795
ObjectAddress DefineIndex(Oid tableId, IndexStmt *stmt, Oid indexRelationId, Oid parentIndexId, Oid parentConstraintId, int total_parts, bool is_alter_table, bool check_rights, bool check_not_in_use, bool skip_build, bool quiet)
Definition: indexcmds.c:537
static void set_indexsafe_procflags(void)
Definition: indexcmds.c:4584
static void reindex_error_callback(void *arg)
Definition: indexcmds.c:3298
static void ComputeIndexAttrs(IndexInfo *indexInfo, Oid *typeOids, Oid *collationOids, Oid *opclassOids, Datum *opclassOptions, int16 *colOptions, const List *attList, const List *exclusionOpNames, Oid relId, const char *accessMethodName, Oid accessMethodId, bool amcanorder, bool isconstraint, bool iswithoutoverlaps, Oid ddl_userid, int ddl_sec_context, int *ddl_save_nestlevel)
Definition: indexcmds.c:1840
static void ReindexIndex(const ReindexStmt *stmt, const ReindexParams *params, bool isTopLevel)
Definition: indexcmds.c:2890
void IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
Definition: indexcmds.c:4414
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:2332
static char * ChooseIndexNameAddition(const List *colnames)
Definition: indexcmds.c:2700
static void ReindexMultipleTables(const ReindexStmt *stmt, const ReindexParams *params)
Definition: indexcmds.c:3079
static bool CompareOpclassOptions(const Datum *opts1, const Datum *opts2, int natts)
Definition: indexcmds.c:363
static void update_relispartition(Oid relationId, bool newval)
Definition: indexcmds.c:4546
bool CheckIndexCompatible(Oid oldId, const char *accessMethodName, const List *attributeList, const List *exclusionOpNames, bool isWithoutOverlaps)
Definition: indexcmds.c:179
void GetOperatorFromWellKnownStrategy(Oid opclass, Oid rhstype, Oid *opid, StrategyNumber *strat)
Definition: indexcmds.c:2435
void WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
Definition: indexcmds.c:430
Oid ResolveOpClass(const List *opclass, Oid attrType, const char *accessMethodName, Oid accessMethodId)
Definition: indexcmds.c:2247
static void ReindexPartitions(const ReindexStmt *stmt, Oid relid, const ReindexParams *params, bool isTopLevel)
Definition: indexcmds.c:3319
struct ReindexErrorInfo ReindexErrorInfo
static Oid ReindexTable(const ReindexStmt *stmt, const ReindexParams *params, bool isTopLevel)
Definition: indexcmds.c:3020
static void CheckPredicate(Expr *predicate)
Definition: indexcmds.c:1813
static void ReindexMultipleInternal(const ReindexStmt *stmt, const List *relids, const ReindexParams *params)
Definition: indexcmds.c:3413
static void RangeVarCallbackForReindexIndex(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: indexcmds.c:2944
static List * ChooseIndexColumnNames(const List *indexElems)
Definition: indexcmds.c:2734
static char * ChooseIndexName(const char *tabname, Oid namespaceId, const List *colnames, const List *exclusionOpNames, bool primary, bool isconstraint)
Definition: indexcmds.c:2645
char * ChooseRelationName(const char *name1, const char *name2, const char *label, Oid namespaceid, bool isconstraint)
Definition: indexcmds.c:2609
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
#define INJECTION_POINT(name)
void CacheInvalidateRelcacheByRelid(Oid relid)
Definition: inval.c:1419
int j
Definition: isn.c:74
int i
Definition: isn.c:73
List * lappend(List *list, void *datum)
Definition: list.c:339
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
void list_free(List *list)
Definition: list.c:1546
List * lcons_oid(Oid datum, List *list)
Definition: list.c:531
List * list_concat_copy(const List *list1, const List *list2)
Definition: list.c:598
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:227
void WaitForLockersMultiple(List *locktags, LOCKMODE lockmode, bool progress)
Definition: lmgr.c:897
void LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
Definition: lmgr.c:387
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108
void WaitForLockers(LOCKTAG heaplocktag, LOCKMODE lockmode, bool progress)
Definition: lmgr.c:975
void UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
Definition: lmgr.c:400
void UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
Definition: lmgr.c:595
bool VirtualXactLock(VirtualTransactionId vxid, bool wait)
Definition: lock.c:4642
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:67
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition: lock.h:181
#define VirtualTransactionIdEquals(vxid1, vxid2)
Definition: lock.h:71
#define SetInvalidVirtualTransactionId(vxid)
Definition: lock.h:74
int LOCKMODE
Definition: lockdefs.h:26
#define NoLock
Definition: lockdefs.h:34
#define AccessExclusiveLock
Definition: lockdefs.h:43
#define AccessShareLock
Definition: lockdefs.h:36
#define InplaceUpdateTupleLock
Definition: lockdefs.h:48
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define ShareLock
Definition: lockdefs.h:40
#define RowExclusiveLock
Definition: lockdefs.h:38
char get_rel_persistence(Oid relid)
Definition: lsyscache.c:2078
char * get_opname(Oid opno)
Definition: lsyscache.c:1310
bool get_index_isvalid(Oid index_oid)
Definition: lsyscache.c:3578
Oid get_opclass_input_type(Oid opclass)
Definition: lsyscache.c:1212
Oid get_opclass_family(Oid opclass)
Definition: lsyscache.c:1190
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
bool get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
Definition: lsyscache.c:1235
Datum get_attoptions(Oid relid, int16 attnum)
Definition: lsyscache.c:970
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:2003
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1952
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1285
int get_op_opfamily_strategy(Oid opno, Oid opfamily)
Definition: lsyscache.c:83
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1928
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:166
bool type_is_collatable(Oid typid)
Definition: lsyscache.c:3081
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2521
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1885
Oid get_commutator(Oid opno)
Definition: lsyscache.c:1509
void op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
Definition: lsyscache.c:1358
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1168
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781
@ LW_EXCLUSIVE
Definition: lwlock.h:114
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:737
IndexInfo * makeIndexInfo(int numattrs, int numkeyattrs, Oid amoid, List *expressions, List *predicates, bool unique, bool nulls_not_distinct, bool isready, bool concurrent, bool summarizing, bool withoutoverlaps)
Definition: makefuncs.c:761
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition: mbutils.c:1083
char * pstrdup(const char *in)
Definition: mcxt.c:1696
void pfree(void *pointer)
Definition: mcxt.c:1521
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
void * palloc(Size size)
Definition: mcxt.c:1317
MemoryContext PortalContext
Definition: mcxt.c:158
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:170
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:451
#define SECURITY_RESTRICTED_OPERATION
Definition: miscadmin.h:312
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition: miscinit.c:635
Oid GetUserId(void)
Definition: miscinit.c:514
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition: miscinit.c:642
Oid OpclassnameGetOpcid(Oid amid, const char *opcname)
Definition: namespace.c:2121
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:3385
bool isTempNamespace(Oid namespaceId)
Definition: namespace.c:3649
Oid get_collation_oid(List *collname, bool missing_ok)
Definition: namespace.c:3971
void DeconstructQualifiedName(const List *names, char **nspname_p, char **objname_p)
Definition: namespace.c:3301
Oid get_namespace_oid(const char *nspname, bool missing_ok)
Definition: namespace.c:3535
char * NameListToString(const List *names)
Definition: namespace.c:3594
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:441
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:816
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
const ObjectAddress InvalidObjectAddress
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
TYPCATEGORY TypeCategory(Oid type)
bool IsBinaryCoercible(Oid srctype, Oid targettype)
bool IsPreferredType(TYPCATEGORY category, Oid type)
char TYPCATEGORY
Definition: parse_coerce.h:21
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:106
Oid compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError)
Definition: parse_oper.c:487
IndexStmt * generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx, const AttrMap *attmap, Oid *constraintOid)
@ SORTBY_NULLS_DEFAULT
Definition: parsenodes.h:54
@ SORTBY_NULLS_FIRST
Definition: parsenodes.h:55
#define ACL_MAINTAIN
Definition: parsenodes.h:90
@ PARTITION_STRATEGY_HASH
Definition: parsenodes.h:876
@ DROP_RESTRICT
Definition: parsenodes.h:2331
@ OBJECT_SCHEMA
Definition: parsenodes.h:2294
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2300
@ OBJECT_INDEX
Definition: parsenodes.h:2278
@ OBJECT_DATABASE
Definition: parsenodes.h:2267
ReindexObjectType
Definition: parsenodes.h:3983
@ REINDEX_OBJECT_DATABASE
Definition: parsenodes.h:3988
@ REINDEX_OBJECT_INDEX
Definition: parsenodes.h:3984
@ REINDEX_OBJECT_SCHEMA
Definition: parsenodes.h:3986
@ REINDEX_OBJECT_SYSTEM
Definition: parsenodes.h:3987
@ REINDEX_OBJECT_TABLE
Definition: parsenodes.h:3985
#define ACL_CREATE
Definition: parsenodes.h:85
@ SORTBY_DESC
Definition: parsenodes.h:48
@ SORTBY_DEFAULT
Definition: parsenodes.h:46
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:51
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:71
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
static void fix_dependencies(ArchiveHandle *AH)
void * arg
static char * label
int errdetail_relkind_not_supported(char relkind)
Definition: pg_class.c:24
NameData relname
Definition: pg_class.h:38
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define INDEX_MAX_KEYS
#define NAMEDATALEN
Oid get_relation_idx_constraint_oid(Oid relationId, Oid indexId)
void ConstraintSetParentConstraint(Oid childConstrId, Oid parentConstrId, Oid childTableId)
bool ConstraintNameExists(const char *conname, Oid namespaceid)
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:46
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:352
FormData_pg_index * Form_pg_index
Definition: pg_index.h:70
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:255
void StoreSingleInheritance(Oid relationId, Oid parentOid, int32 seqNumber)
Definition: pg_inherits.c:508
bool has_superclass(Oid relationId)
Definition: pg_inherits.c:377
FormData_pg_inherits * Form_pg_inherits
Definition: pg_inherits.h:45
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
#define list_make1_oid(x1)
Definition: pg_list.h:242
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
#define lfirst_oid(lc)
Definition: pg_list.h:174
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:51
const char * pg_rusage_show(const PGRUsage *ru0)
Definition: pg_rusage.c:40
void pg_rusage_init(PGRUsage *ru0)
Definition: pg_rusage.c:27
static char * buf
Definition: pg_test_fsync.c:73
static int progress
Definition: pgbench.c:261
static int partitions
Definition: pgbench.c:223
#define sprintf
Definition: port.h:240
#define snprintf
Definition: port.h:238
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define PROC_IN_SAFE_IC
Definition: proc.h:59
#define PROC_IN_VACUUM
Definition: proc.h:58
#define PROC_IS_AUTOVACUUM
Definition: proc.h:57
PGPROC * ProcNumberGetProc(ProcNumber procNumber)
Definition: procarray.c:3142
VirtualTransactionId * GetCurrentVirtualXIDs(TransactionId limitXmin, bool excludeXmin0, bool allDbs, int excludeVacuum, int *nvxids)
Definition: procarray.c:3328
#define PROGRESS_CREATEIDX_PHASE_WAIT_4
Definition: progress.h:101
#define PROGRESS_CREATEIDX_PHASE_BUILD
Definition: progress.h:95
#define PROGRESS_CREATEIDX_PARTITIONS_DONE
Definition: progress.h:90
#define PROGRESS_CREATEIDX_PHASE_WAIT_1
Definition: progress.h:94
#define PROGRESS_CREATEIDX_COMMAND_CREATE_CONCURRENTLY
Definition: progress.h:112
#define PROGRESS_CREATEIDX_ACCESS_METHOD_OID
Definition: progress.h:84
#define PROGRESS_WAITFOR_DONE
Definition: progress.h:118
#define PROGRESS_CREATEIDX_PHASE_WAIT_3
Definition: progress.h:100
#define PROGRESS_WAITFOR_TOTAL
Definition: progress.h:117
#define PROGRESS_CREATEIDX_COMMAND_REINDEX_CONCURRENTLY
Definition: progress.h:114
#define PROGRESS_CREATEIDX_COMMAND_CREATE
Definition: progress.h:111
#define PROGRESS_WAITFOR_CURRENT_PID
Definition: progress.h:119
#define PROGRESS_CREATEIDX_PHASE_WAIT_2
Definition: progress.h:96
#define PROGRESS_CREATEIDX_PHASE
Definition: progress.h:85
#define PROGRESS_CREATEIDX_PHASE_VALIDATE_IDXSCAN
Definition: progress.h:97
#define PROGRESS_CREATEIDX_PHASE_WAIT_5
Definition: progress.h:102
#define PROGRESS_CREATEIDX_INDEX_OID
Definition: progress.h:83
#define PROGRESS_CREATEIDX_PARTITIONS_TOTAL
Definition: progress.h:89
#define PROGRESS_CREATEIDX_COMMAND
Definition: progress.h:82
MemoryContextSwitchTo(old_ctx)
char * format_operator(Oid operator_oid)
Definition: regproc.c:793
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationGetDescr(relation)
Definition: rel.h:531
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:658
#define RelationGetNamespace(relation)
Definition: rel.h:546
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4804
List * RelationGetIndexPredicate(Relation relation)
Definition: relcache.c:5154
void RelationGetExclusionInfo(Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
Definition: relcache.c:5597
List * RelationGetIndexExpressions(Relation relation)
Definition: relcache.c:5041
bytea * index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate)
Definition: reloptions.c:2054
Datum transformRelOptions(Datum oldOptions, List *defList, const char *namspace, const char *const validnsps[], bool acceptOidsOff, bool isReset)
Definition: reloptions.c:1156
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
@ ForwardScanDirection
Definition: sdir.h:28
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:216
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:836
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:648
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:782
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:794
void PopActiveSnapshot(void)
Definition: snapmgr.c:743
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47
PGPROC * MyProc
Definition: proc.c:67
PROC_HDR * ProcGlobal
Definition: proc.c:79
uint16 StrategyNumber
Definition: stratnum.h:22
#define RTOverlapStrategyNumber
Definition: stratnum.h:53
#define RTEqualStrategyNumber
Definition: stratnum.h:68
#define InvalidStrategy
Definition: stratnum.h:24
#define HTEqualStrategyNumber
Definition: stratnum.h:41
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define RTContainedByStrategyNumber
Definition: stratnum.h:58
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
Definition: attmap.h:35
char * defname
Definition: parsenodes.h:817
ParseLoc location
Definition: parsenodes.h:821
struct ErrorContextCallback * previous
Definition: elog.h:296
void(* callback)(void *arg)
Definition: elog.h:297
ItemPointerData t_self
Definition: htup.h:65
amoptions_function amoptions
Definition: amapi.h:283
amgettuple_function amgettuple
Definition: amapi.h:290
bool amcanunique
Definition: amapi.h:237
bool amsummarizing
Definition: amapi.h:261
bool amcanmulticol
Definition: amapi.h:239
bool amcanorder
Definition: amapi.h:231
bool amcaninclude
Definition: amapi.h:257
Node * expr
Definition: parsenodes.h:786
SortByDir ordering
Definition: parsenodes.h:791
List * opclassopts
Definition: parsenodes.h:790
char * indexcolname
Definition: parsenodes.h:787
SortByNulls nulls_ordering
Definition: parsenodes.h:792
List * opclass
Definition: parsenodes.h:789
char * name
Definition: parsenodes.h:785
List * collation
Definition: parsenodes.h:788
uint16 * ii_ExclusionStrats
Definition: execnodes.h:195
int ii_NumIndexAttrs
Definition: execnodes.h:186
Oid * ii_ExclusionOps
Definition: execnodes.h:193
int ii_NumIndexKeyAttrs
Definition: execnodes.h:187
List * ii_Expressions
Definition: execnodes.h:189
Oid * ii_ExclusionProcs
Definition: execnodes.h:194
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition: execnodes.h:188
List * ii_Predicate
Definition: execnodes.h:191
Definition: lock.h:165
Definition: pg_list.h:54
LockRelId lockRelId
Definition: rel.h:46
Definition: rel.h:39
Oid relId
Definition: rel.h:40
Oid dbId
Definition: rel.h:41
Definition: nodes.h:129
Definition: proc.h:162
TransactionId xmin
Definition: proc.h:177
uint8 statusFlags
Definition: proc.h:242
int pid
Definition: proc.h:182
int pgxactoff
Definition: proc.h:184
TransactionId xid
Definition: proc.h:172
uint8 * statusFlags
Definition: proc.h:399
char * relname
Definition: primnodes.h:82
char * relnamespace
Definition: indexcmds.c:136
ReindexParams params
Definition: indexcmds.c:126
Oid tablespaceOid
Definition: index.h:36
bits32 options
Definition: index.h:35
LockInfoData rd_lockInfo
Definition: rel.h:114
TupleDesc rd_att
Definition: rel.h:112
Form_pg_index rd_index
Definition: rel.h:192
Oid * rd_opfamily
Definition: rel.h:207
Oid * rd_indcollation
Definition: rel.h:217
Form_pg_class rd_rel
Definition: rel.h:111
TransactionId xmin
Definition: snapshot.h:157
Definition: primnodes.h:248
Definition: c.h:717
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:724
Definition: regguts.h:323
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCacheLockedCopy1(int cacheId, Datum key1)
Definition: syscache.c:400
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:243
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition: syscache.c:476
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:627
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:100
Relation try_table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:60
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
Definition: tableam.c:112
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:1019
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:4276
void SetRelationHasSubclass(Oid relationId, bool relhassubclass)
Definition: tablecmds.c:3510
void RangeVarCallbackMaintainsTable(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:17839
#define InvalidTransactionId
Definition: transam.h:31
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:296
const char * name
void CommandCounterIncrement(void)
Definition: xact.c:1099
void PreventInTransactionBlock(bool isTopLevel, const char *stmtType)
Definition: xact.c:3628
void StartTransactionCommand(void)
Definition: xact.c:3039
void CommitTransactionCommand(void)
Definition: xact.c:3137