PostgreSQL Source Code  git master
indexcmds.c File Reference
#include "postgres.h"
#include "access/amapi.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/reloptions.h"
#include "access/sysattr.h"
#include "access/tableam.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/pg_am.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_type.h"
#include "commands/comment.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/progress.h"
#include "commands/tablecmds.h"
#include "commands/tablespace.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "parser/parse_coerce.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "partitioning/partdesc.h"
#include "pgstat.h"
#include "rewrite/rewriteManip.h"
#include "storage/lmgr.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "storage/sinvaladt.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/partcache.h"
#include "utils/pg_rusage.h"
#include "utils/regproc.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
Include dependency graph for indexcmds.c:

Go to the source code of this file.

Data Structures

struct  ReindexIndexCallbackState
 

Functions

static void CheckPredicate (Expr *predicate)
 
static void ComputeIndexAttrs (IndexInfo *indexInfo, Oid *typeOidP, Oid *collationOidP, Oid *classOidP, int16 *colOptionP, List *attList, List *exclusionOpNames, Oid relId, const char *accessMethodName, Oid accessMethodId, bool amcanorder, bool isconstraint)
 
static char * ChooseIndexName (const char *tabname, Oid namespaceId, List *colnames, List *exclusionOpNames, bool primary, bool isconstraint)
 
static char * ChooseIndexNameAddition (List *colnames)
 
static ListChooseIndexColumnNames (List *indexElems)
 
static void RangeVarCallbackForReindexIndex (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
static bool ReindexRelationConcurrently (Oid relationOid, int options)
 
static void ReindexPartitionedIndex (Relation parentIdx)
 
static void update_relispartition (Oid relationId, bool newval)
 
static bool CompareOpclassOptions (Datum *opts1, Datum *opts2, int natts)
 
bool CheckIndexCompatible (Oid oldId, const char *accessMethodName, List *attributeList, List *exclusionOpNames)
 
static void WaitForOlderSnapshots (TransactionId limitXmin, bool progress)
 
ObjectAddress DefineIndex (Oid relationId, IndexStmt *stmt, Oid indexRelationId, Oid parentIndexId, Oid parentConstraintId, bool is_alter_table, bool check_rights, bool check_not_in_use, bool skip_build, bool quiet)
 
static bool CheckMutability (Expr *expr)
 
Oid ResolveOpClass (List *opclass, Oid attrType, const char *accessMethodName, Oid accessMethodId)
 
Oid GetDefaultOpClass (Oid type_id, Oid am_id)
 
char * makeObjectName (const char *name1, const char *name2, const char *label)
 
char * ChooseRelationName (const char *name1, const char *name2, const char *label, Oid namespaceid, bool isconstraint)
 
void ReindexIndex (RangeVar *indexRelation, int options, bool concurrent)
 
Oid ReindexTable (RangeVar *relation, int options, bool concurrent)
 
void ReindexMultipleTables (const char *objectName, ReindexObjectType objectKind, int options, bool concurrent)
 
void IndexSetParentIndex (Relation partitionIdx, Oid parentOid)
 

Function Documentation

◆ CheckIndexCompatible()

bool CheckIndexCompatible ( Oid  oldId,
const char *  accessMethodName,
List attributeList,
List exclusionOpNames 
)

Definition at line 142 of file indexcmds.c.

References AccessShareLock, IndexAmRoutine::amcanorder, AMNAME, Assert, CompareOpclassOptions(), ComputeIndexAttrs(), DatumGetPointer, elog, ereport, errcode(), errmsg(), ERROR, get_opclass_input_type(), GetIndexAmRoutine(), GETSTRUCT, heap_attisnull(), HeapTupleIsValid, i, IndexInfo::ii_ExclusionOps, IndexInfo::ii_OpclassOptions, index_close(), INDEX_MAX_KEYS, index_open(), IndexGetRelation(), INDEXRELID, list_length(), makeIndexInfo(), NIL, NoLock, ObjectIdGetDatum, op_input_types(), palloc(), pfree(), PointerGetDatum, RelationData::rd_att, RelationGetExclusionInfo(), RelationGetIndexRawAttOptions(), ReleaseSysCache(), SearchSysCache1(), SysCacheGetAttr(), TupleDescAttr, and oidvector::values.

Referenced by TryReuseIndex().

146 {
147  bool isconstraint;
148  Oid *typeObjectId;
149  Oid *collationObjectId;
150  Oid *classObjectId;
151  Oid accessMethodId;
152  Oid relationId;
153  HeapTuple tuple;
154  Form_pg_index indexForm;
155  Form_pg_am accessMethodForm;
156  IndexAmRoutine *amRoutine;
157  bool amcanorder;
158  int16 *coloptions;
159  IndexInfo *indexInfo;
160  int numberOfAttributes;
161  int old_natts;
162  bool isnull;
163  bool ret = true;
164  oidvector *old_indclass;
165  oidvector *old_indcollation;
166  Relation irel;
167  int i;
168  Datum d;
169 
170  /* Caller should already have the relation locked in some way. */
171  relationId = IndexGetRelation(oldId, false);
172 
173  /*
174  * We can pretend isconstraint = false unconditionally. It only serves to
175  * decide the text of an error message that should never happen for us.
176  */
177  isconstraint = false;
178 
179  numberOfAttributes = list_length(attributeList);
180  Assert(numberOfAttributes > 0);
181  Assert(numberOfAttributes <= INDEX_MAX_KEYS);
182 
183  /* look up the access method */
184  tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
185  if (!HeapTupleIsValid(tuple))
186  ereport(ERROR,
187  (errcode(ERRCODE_UNDEFINED_OBJECT),
188  errmsg("access method \"%s\" does not exist",
189  accessMethodName)));
190  accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
191  accessMethodId = accessMethodForm->oid;
192  amRoutine = GetIndexAmRoutine(accessMethodForm->amhandler);
193  ReleaseSysCache(tuple);
194 
195  amcanorder = amRoutine->amcanorder;
196 
197  /*
198  * Compute the operator classes, collations, and exclusion operators for
199  * the new index, so we can test whether it's compatible with the existing
200  * one. Note that ComputeIndexAttrs might fail here, but that's OK:
201  * DefineIndex would have called this function with the same arguments
202  * later on, and it would have failed then anyway. Our attributeList
203  * contains only key attributes, thus we're filling ii_NumIndexAttrs and
204  * ii_NumIndexKeyAttrs with same value.
205  */
206  indexInfo = makeIndexInfo(numberOfAttributes, numberOfAttributes,
207  accessMethodId, NIL, NIL, false, false, false);
208  typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
209  collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
210  classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
211  coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16));
212  ComputeIndexAttrs(indexInfo,
213  typeObjectId, collationObjectId, classObjectId,
214  coloptions, attributeList,
215  exclusionOpNames, relationId,
216  accessMethodName, accessMethodId,
217  amcanorder, isconstraint);
218 
219 
220  /* Get the soon-obsolete pg_index tuple. */
222  if (!HeapTupleIsValid(tuple))
223  elog(ERROR, "cache lookup failed for index %u", oldId);
224  indexForm = (Form_pg_index) GETSTRUCT(tuple);
225 
226  /*
227  * We don't assess expressions or predicates; assume incompatibility.
228  * Also, if the index is invalid for any reason, treat it as incompatible.
229  */
230  if (!(heap_attisnull(tuple, Anum_pg_index_indpred, NULL) &&
231  heap_attisnull(tuple, Anum_pg_index_indexprs, NULL) &&
232  indexForm->indisvalid))
233  {
234  ReleaseSysCache(tuple);
235  return false;
236  }
237 
238  /* Any change in operator class or collation breaks compatibility. */
239  old_natts = indexForm->indnkeyatts;
240  Assert(old_natts == numberOfAttributes);
241 
242  d = SysCacheGetAttr(INDEXRELID, tuple, Anum_pg_index_indcollation, &isnull);
243  Assert(!isnull);
244  old_indcollation = (oidvector *) DatumGetPointer(d);
245 
246  d = SysCacheGetAttr(INDEXRELID, tuple, Anum_pg_index_indclass, &isnull);
247  Assert(!isnull);
248  old_indclass = (oidvector *) DatumGetPointer(d);
249 
250  ret = (memcmp(old_indclass->values, classObjectId,
251  old_natts * sizeof(Oid)) == 0 &&
252  memcmp(old_indcollation->values, collationObjectId,
253  old_natts * sizeof(Oid)) == 0);
254 
255  ReleaseSysCache(tuple);
256 
257  if (!ret)
258  return false;
259 
260  /* For polymorphic opcintype, column type changes break compatibility. */
261  irel = index_open(oldId, AccessShareLock); /* caller probably has a lock */
262  for (i = 0; i < old_natts; i++)
263  {
264  if (IsPolymorphicType(get_opclass_input_type(classObjectId[i])) &&
265  TupleDescAttr(irel->rd_att, i)->atttypid != typeObjectId[i])
266  {
267  ret = false;
268  break;
269  }
270  }
271 
272  /* Any change in opclass options break compatibility. */
273  if (ret)
274  {
275  Datum *opclassOptions = RelationGetIndexRawAttOptions(irel);
276 
277  ret = CompareOpclassOptions(opclassOptions,
278  indexInfo->ii_OpclassOptions, old_natts);
279 
280  if (opclassOptions)
281  pfree(opclassOptions);
282  }
283 
284  /* Any change in exclusion operator selections breaks compatibility. */
285  if (ret && indexInfo->ii_ExclusionOps != NULL)
286  {
287  Oid *old_operators,
288  *old_procs;
289  uint16 *old_strats;
290 
291  RelationGetExclusionInfo(irel, &old_operators, &old_procs, &old_strats);
292  ret = memcmp(old_operators, indexInfo->ii_ExclusionOps,
293  old_natts * sizeof(Oid)) == 0;
294 
295  /* Require an exact input type match for polymorphic operators. */
296  if (ret)
297  {
298  for (i = 0; i < old_natts && ret; i++)
299  {
300  Oid left,
301  right;
302 
303  op_input_types(indexInfo->ii_ExclusionOps[i], &left, &right);
304  if ((IsPolymorphicType(left) || IsPolymorphicType(right)) &&
305  TupleDescAttr(irel->rd_att, i)->atttypid != typeObjectId[i])
306  {
307  ret = false;
308  break;
309  }
310  }
311  }
312  }
313 
314  index_close(irel, NoLock);
315  return ret;
316 }
signed short int16
Definition: c.h:361
#define NIL
Definition: pg_list.h:65
Definition: c.h:601
Oid IndexGetRelation(Oid indexId, bool missing_ok)
Definition: index.c:3384
void RelationGetExclusionInfo(Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
Definition: relcache.c:5175
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define PointerGetDatum(X)
Definition: postgres.h:556
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:610
static bool CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts)
Definition: indexcmds.c:325
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:359
unsigned int Oid
Definition: postgres_ext.h:31
unsigned short uint16
Definition: c.h:373
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition: amapi.c:33
#define NoLock
Definition: lockdefs.h:34
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:609
void op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
Definition: lsyscache.c:1275
IndexInfo * makeIndexInfo(int numattrs, int numkeyattrs, Oid amoid, List *expressions, List *predicates, bool unique, bool isready, bool concurrent)
Definition: makefuncs.c:742
Datum * RelationGetIndexRawAttOptions(Relation indexrel)
Definition: relcache.c:5383
FormData_pg_index * Form_pg_index
Definition: pg_index.h:68
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1377
TupleDesc rd_att
Definition: rel.h:110
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:745
#define INDEX_MAX_KEYS
static int list_length(const List *l)
Definition: pg_list.h:169
bool amcanorder
Definition: amapi.h:219
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
#define DatumGetPointer(X)
Definition: postgres.h:549
Oid * ii_ExclusionOps
Definition: execnodes.h:165
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
int i
static void ComputeIndexAttrs(IndexInfo *indexInfo, Oid *typeOidP, Oid *collationOidP, Oid *classOidP, int16 *colOptionP, List *attList, List *exclusionOpNames, Oid relId, const char *accessMethodName, Oid accessMethodId, bool amcanorder, bool isconstraint)
Definition: indexcmds.c:1638
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132
Datum * ii_OpclassOptions
Definition: execnodes.h:171
Oid get_opclass_input_type(Oid opclass)
Definition: lsyscache.c:1151

◆ CheckMutability()

static bool CheckMutability ( Expr expr)
static

Definition at line 1581 of file indexcmds.c.

References contain_mutable_functions(), and expression_planner().

Referenced by CheckPredicate(), and ComputeIndexAttrs().

1582 {
1583  /*
1584  * First run the expression through the planner. This has a couple of
1585  * important consequences. First, function default arguments will get
1586  * inserted, which may affect volatility (consider "default now()").
1587  * Second, inline-able functions will get inlined, which may allow us to
1588  * conclude that the function is really less volatile than it's marked. As
1589  * an example, polymorphic functions must be marked with the most volatile
1590  * behavior that they have for any input type, but once we inline the
1591  * function we may be able to conclude that it's not so volatile for the
1592  * particular input type we're dealing with.
1593  *
1594  * We assume here that expression_planner() won't scribble on its input.
1595  */
1596  expr = expression_planner(expr);
1597 
1598  /* Now we can search for non-immutable functions */
1599  return contain_mutable_functions((Node *) expr);
1600 }
Expr * expression_planner(Expr *expr)
Definition: planner.c:6151
Definition: nodes.h:529
bool contain_mutable_functions(Node *clause)
Definition: clauses.c:647

◆ CheckPredicate()

static void CheckPredicate ( Expr predicate)
static

Definition at line 1615 of file indexcmds.c.

References CheckMutability(), ereport, errcode(), errmsg(), and ERROR.

Referenced by DefineIndex().

1616 {
1617  /*
1618  * transformExpr() should have already rejected subqueries, aggregates,
1619  * and window functions, based on the EXPR_KIND_ for a predicate.
1620  */
1621 
1622  /*
1623  * A predicate using mutable functions is probably wrong, for the same
1624  * reasons that we don't allow an index expression to use one.
1625  */
1626  if (CheckMutability(predicate))
1627  ereport(ERROR,
1628  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1629  errmsg("functions in index predicate must be marked IMMUTABLE")));
1630 }
static bool CheckMutability(Expr *expr)
Definition: indexcmds.c:1581
int errcode(int sqlerrcode)
Definition: elog.c:610
#define ERROR
Definition: elog.h:43
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ ChooseIndexColumnNames()

static List * ChooseIndexColumnNames ( List indexElems)
static

Definition at line 2365 of file indexcmds.c.

References buf, i, IndexElem::indexcolname, lappend(), lfirst, IndexElem::name, NAMEDATALEN, NIL, pg_mbcliplen(), pstrdup(), and sprintf.

Referenced by DefineIndex().

2366 {
2367  List *result = NIL;
2368  ListCell *lc;
2369 
2370  foreach(lc, indexElems)
2371  {
2372  IndexElem *ielem = (IndexElem *) lfirst(lc);
2373  const char *origname;
2374  const char *curname;
2375  int i;
2376  char buf[NAMEDATALEN];
2377 
2378  /* Get the preliminary name from the IndexElem */
2379  if (ielem->indexcolname)
2380  origname = ielem->indexcolname; /* caller-specified name */
2381  else if (ielem->name)
2382  origname = ielem->name; /* simple column reference */
2383  else
2384  origname = "expr"; /* default name for expression */
2385 
2386  /* If it conflicts with any previous column, tweak it */
2387  curname = origname;
2388  for (i = 1;; i++)
2389  {
2390  ListCell *lc2;
2391  char nbuf[32];
2392  int nlen;
2393 
2394  foreach(lc2, result)
2395  {
2396  if (strcmp(curname, (char *) lfirst(lc2)) == 0)
2397  break;
2398  }
2399  if (lc2 == NULL)
2400  break; /* found nonconflicting name */
2401 
2402  sprintf(nbuf, "%d", i);
2403 
2404  /* Ensure generated names are shorter than NAMEDATALEN */
2405  nlen = pg_mbcliplen(origname, strlen(origname),
2406  NAMEDATALEN - 1 - strlen(nbuf));
2407  memcpy(buf, origname, nlen);
2408  strcpy(buf + nlen, nbuf);
2409  curname = buf;
2410  }
2411 
2412  /* And attach to the result list */
2413  result = lappend(result, pstrdup(curname));
2414  }
2415  return result;
2416 }
#define NIL
Definition: pg_list.h:65
char * pstrdup(const char *in)
Definition: mcxt.c:1186
#define NAMEDATALEN
#define sprintf
Definition: port.h:195
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition: mbutils.c:967
static char * buf
Definition: pg_test_fsync.c:67
char * indexcolname
Definition: parsenodes.h:702
List * lappend(List *list, void *datum)
Definition: list.c:321
#define lfirst(lc)
Definition: pg_list.h:190
char * name
Definition: parsenodes.h:700
int i
Definition: pg_list.h:50

◆ ChooseIndexName()

static char * ChooseIndexName ( const char *  tabname,
Oid  namespaceId,
List colnames,
List exclusionOpNames,
bool  primary,
bool  isconstraint 
)
static

Definition at line 2276 of file indexcmds.c.

References ChooseIndexNameAddition(), ChooseRelationName(), and NIL.

Referenced by DefineIndex().

2279 {
2280  char *indexname;
2281 
2282  if (primary)
2283  {
2284  /* the primary key's name does not depend on the specific column(s) */
2285  indexname = ChooseRelationName(tabname,
2286  NULL,
2287  "pkey",
2288  namespaceId,
2289  true);
2290  }
2291  else if (exclusionOpNames != NIL)
2292  {
2293  indexname = ChooseRelationName(tabname,
2294  ChooseIndexNameAddition(colnames),
2295  "excl",
2296  namespaceId,
2297  true);
2298  }
2299  else if (isconstraint)
2300  {
2301  indexname = ChooseRelationName(tabname,
2302  ChooseIndexNameAddition(colnames),
2303  "key",
2304  namespaceId,
2305  true);
2306  }
2307  else
2308  {
2309  indexname = ChooseRelationName(tabname,
2310  ChooseIndexNameAddition(colnames),
2311  "idx",
2312  namespaceId,
2313  false);
2314  }
2315 
2316  return indexname;
2317 }
#define NIL
Definition: pg_list.h:65
static char * ChooseIndexNameAddition(List *colnames)
Definition: indexcmds.c:2331
char * ChooseRelationName(const char *name1, const char *name2, const char *label, Oid namespaceid, bool isconstraint)
Definition: indexcmds.c:2240

◆ ChooseIndexNameAddition()

static char * ChooseIndexNameAddition ( List colnames)
static

Definition at line 2331 of file indexcmds.c.

References buf, lfirst, name, NAMEDATALEN, pstrdup(), and strlcpy().

Referenced by ChooseIndexName().

2332 {
2333  char buf[NAMEDATALEN * 2];
2334  int buflen = 0;
2335  ListCell *lc;
2336 
2337  buf[0] = '\0';
2338  foreach(lc, colnames)
2339  {
2340  const char *name = (const char *) lfirst(lc);
2341 
2342  if (buflen > 0)
2343  buf[buflen++] = '_'; /* insert _ between names */
2344 
2345  /*
2346  * At this point we have buflen <= NAMEDATALEN. name should be less
2347  * than NAMEDATALEN already, but use strlcpy for paranoia.
2348  */
2349  strlcpy(buf + buflen, name, NAMEDATALEN);
2350  buflen += strlen(buf + buflen);
2351  if (buflen >= NAMEDATALEN)
2352  break;
2353  }
2354  return pstrdup(buf);
2355 }
char * pstrdup(const char *in)
Definition: mcxt.c:1186
#define NAMEDATALEN
static char * buf
Definition: pg_test_fsync.c:67
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
#define lfirst(lc)
Definition: pg_list.h:190
const char * name
Definition: encode.c:561

◆ ChooseRelationName()

char* ChooseRelationName ( const char *  name1,
const char *  name2,
const char *  label,
Oid  namespaceid,
bool  isconstraint 
)

Definition at line 2240 of file indexcmds.c.

References ConstraintNameExists(), get_relname_relid(), makeObjectName(), NAMEDATALEN, OidIsValid, pfree(), relname, snprintf, and strlcpy().

Referenced by ChooseIndexName(), generateSerialExtraStmts(), and ReindexRelationConcurrently().

2243 {
2244  int pass = 0;
2245  char *relname = NULL;
2246  char modlabel[NAMEDATALEN];
2247 
2248  /* try the unmodified label first */
2249  strlcpy(modlabel, label, sizeof(modlabel));
2250 
2251  for (;;)
2252  {
2253  relname = makeObjectName(name1, name2, modlabel);
2254 
2255  if (!OidIsValid(get_relname_relid(relname, namespaceid)))
2256  {
2257  if (!isconstraint ||
2258  !ConstraintNameExists(relname, namespaceid))
2259  break;
2260  }
2261 
2262  /* found a conflict, so try a new name component */
2263  pfree(relname);
2264  snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
2265  }
2266 
2267  return relname;
2268 }
bool ConstraintNameExists(const char *conname, Oid namespaceid)
NameData relname
Definition: pg_class.h:38
#define OidIsValid(objectId)
Definition: c.h:651
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition: indexcmds.c:2154
#define NAMEDATALEN
void pfree(void *pointer)
Definition: mcxt.c:1056
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1797
static char * label
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
#define snprintf
Definition: port.h:193

◆ CompareOpclassOptions()

static bool CompareOpclassOptions ( Datum opts1,
Datum opts2,
int  natts 
)
static

Definition at line 325 of file indexcmds.c.

References array_eq(), DatumGetBool, DirectFunctionCall2, and i.

Referenced by CheckIndexCompatible().

326 {
327  int i;
328 
329  if (!opts1 && !opts2)
330  return true;
331 
332  for (i = 0; i < natts; i++)
333  {
334  Datum opt1 = opts1 ? opts1[i] : (Datum) 0;
335  Datum opt2 = opts2 ? opts2[i] : (Datum) 0;
336 
337  if (opt1 == (Datum) 0)
338  {
339  if (opt2 == (Datum) 0)
340  continue;
341  else
342  return false;
343  }
344  else if (opt2 == (Datum) 0)
345  return false;
346 
347  /* Compare non-NULL text[] datums. */
348  if (!DatumGetBool(DirectFunctionCall2(array_eq, opt1, opt2)))
349  return false;
350  }
351 
352  return true;
353 }
#define DatumGetBool(X)
Definition: postgres.h:393
uintptr_t Datum
Definition: postgres.h:367
Datum array_eq(PG_FUNCTION_ARGS)
Definition: arrayfuncs.c:3597
int i
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:626

◆ ComputeIndexAttrs()

static void ComputeIndexAttrs ( IndexInfo indexInfo,
Oid typeOidP,
Oid collationOidP,
Oid classOidP,
int16 colOptionP,
List attList,
List exclusionOpNames,
Oid  relId,
const char *  accessMethodName,
Oid  accessMethodId,
bool  amcanorder,
bool  isconstraint 
)
static

Definition at line 1638 of file indexcmds.c.

References arg, Assert, attcollation, CheckMutability(), IndexElem::collation, compatible_oper_opid(), elog, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, IndexElem::expr, exprCollation(), exprType(), format_operator(), format_type_be(), get_collation_oid(), get_commutator(), get_op_opfamily_strategy(), get_opclass_family(), get_opcode(), GETSTRUCT, HeapTupleIsValid, IndexInfo::ii_ExclusionOps, IndexInfo::ii_ExclusionProcs, IndexInfo::ii_ExclusionStrats, IndexInfo::ii_Expressions, IndexInfo::ii_IndexAttrNumbers, IndexInfo::ii_NumIndexAttrs, IndexInfo::ii_NumIndexKeyAttrs, IndexInfo::ii_OpclassOptions, InvalidAttrNumber, InvalidOid, IsA, lappend(), lfirst, list_head(), list_length(), lnext(), IndexElem::name, NameStr, IndexElem::nulls_ordering, ObjectIdGetDatum, OidIsValid, IndexElem::opclass, IndexElem::opclassopts, OPFAMILYOID, IndexElem::ordering, palloc(), palloc0(), ReleaseSysCache(), ResolveOpClass(), SearchSysCache1(), SearchSysCacheAttName(), SORTBY_DEFAULT, SORTBY_DESC, SORTBY_NULLS_DEFAULT, SORTBY_NULLS_FIRST, transformRelOptions(), and type_is_collatable().

Referenced by CheckIndexCompatible(), and DefineIndex().

1650 {
1651  ListCell *nextExclOp;
1652  ListCell *lc;
1653  int attn;
1654  int nkeycols = indexInfo->ii_NumIndexKeyAttrs;
1655 
1656  /* Allocate space for exclusion operator info, if needed */
1657  if (exclusionOpNames)
1658  {
1659  Assert(list_length(exclusionOpNames) == nkeycols);
1660  indexInfo->ii_ExclusionOps = (Oid *) palloc(sizeof(Oid) * nkeycols);
1661  indexInfo->ii_ExclusionProcs = (Oid *) palloc(sizeof(Oid) * nkeycols);
1662  indexInfo->ii_ExclusionStrats = (uint16 *) palloc(sizeof(uint16) * nkeycols);
1663  nextExclOp = list_head(exclusionOpNames);
1664  }
1665  else
1666  nextExclOp = NULL;
1667 
1668  /*
1669  * process attributeList
1670  */
1671  attn = 0;
1672  foreach(lc, attList)
1673  {
1674  IndexElem *attribute = (IndexElem *) lfirst(lc);
1675  Oid atttype;
1676  Oid attcollation;
1677 
1678  /*
1679  * Process the column-or-expression to be indexed.
1680  */
1681  if (attribute->name != NULL)
1682  {
1683  /* Simple index attribute */
1684  HeapTuple atttuple;
1685  Form_pg_attribute attform;
1686 
1687  Assert(attribute->expr == NULL);
1688  atttuple = SearchSysCacheAttName(relId, attribute->name);
1689  if (!HeapTupleIsValid(atttuple))
1690  {
1691  /* difference in error message spellings is historical */
1692  if (isconstraint)
1693  ereport(ERROR,
1694  (errcode(ERRCODE_UNDEFINED_COLUMN),
1695  errmsg("column \"%s\" named in key does not exist",
1696  attribute->name)));
1697  else
1698  ereport(ERROR,
1699  (errcode(ERRCODE_UNDEFINED_COLUMN),
1700  errmsg("column \"%s\" does not exist",
1701  attribute->name)));
1702  }
1703  attform = (Form_pg_attribute) GETSTRUCT(atttuple);
1704  indexInfo->ii_IndexAttrNumbers[attn] = attform->attnum;
1705  atttype = attform->atttypid;
1706  attcollation = attform->attcollation;
1707  ReleaseSysCache(atttuple);
1708  }
1709  else
1710  {
1711  /* Index expression */
1712  Node *expr = attribute->expr;
1713 
1714  Assert(expr != NULL);
1715 
1716  if (attn >= nkeycols)
1717  ereport(ERROR,
1718  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1719  errmsg("expressions are not supported in included columns")));
1720  atttype = exprType(expr);
1721  attcollation = exprCollation(expr);
1722 
1723  /*
1724  * Strip any top-level COLLATE clause. This ensures that we treat
1725  * "x COLLATE y" and "(x COLLATE y)" alike.
1726  */
1727  while (IsA(expr, CollateExpr))
1728  expr = (Node *) ((CollateExpr *) expr)->arg;
1729 
1730  if (IsA(expr, Var) &&
1731  ((Var *) expr)->varattno != InvalidAttrNumber)
1732  {
1733  /*
1734  * User wrote "(column)" or "(column COLLATE something)".
1735  * Treat it like simple attribute anyway.
1736  */
1737  indexInfo->ii_IndexAttrNumbers[attn] = ((Var *) expr)->varattno;
1738  }
1739  else
1740  {
1741  indexInfo->ii_IndexAttrNumbers[attn] = 0; /* marks expression */
1742  indexInfo->ii_Expressions = lappend(indexInfo->ii_Expressions,
1743  expr);
1744 
1745  /*
1746  * transformExpr() should have already rejected subqueries,
1747  * aggregates, and window functions, based on the EXPR_KIND_
1748  * for an index expression.
1749  */
1750 
1751  /*
1752  * An expression using mutable functions is probably wrong,
1753  * since if you aren't going to get the same result for the
1754  * same data every time, it's not clear what the index entries
1755  * mean at all.
1756  */
1757  if (CheckMutability((Expr *) expr))
1758  ereport(ERROR,
1759  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1760  errmsg("functions in index expression must be marked IMMUTABLE")));
1761  }
1762  }
1763 
1764  typeOidP[attn] = atttype;
1765 
1766  /*
1767  * Included columns have no collation, no opclass and no ordering
1768  * options.
1769  */
1770  if (attn >= nkeycols)
1771  {
1772  if (attribute->collation)
1773  ereport(ERROR,
1774  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1775  errmsg("including column does not support a collation")));
1776  if (attribute->opclass)
1777  ereport(ERROR,
1778  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1779  errmsg("including column does not support an operator class")));
1780  if (attribute->ordering != SORTBY_DEFAULT)
1781  ereport(ERROR,
1782  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1783  errmsg("including column does not support ASC/DESC options")));
1784  if (attribute->nulls_ordering != SORTBY_NULLS_DEFAULT)
1785  ereport(ERROR,
1786  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1787  errmsg("including column does not support NULLS FIRST/LAST options")));
1788 
1789  classOidP[attn] = InvalidOid;
1790  colOptionP[attn] = 0;
1791  collationOidP[attn] = InvalidOid;
1792  attn++;
1793 
1794  continue;
1795  }
1796 
1797  /*
1798  * Apply collation override if any
1799  */
1800  if (attribute->collation)
1801  attcollation = get_collation_oid(attribute->collation, false);
1802 
1803  /*
1804  * Check we have a collation iff it's a collatable type. The only
1805  * expected failures here are (1) COLLATE applied to a noncollatable
1806  * type, or (2) index expression had an unresolved collation. But we
1807  * might as well code this to be a complete consistency check.
1808  */
1809  if (type_is_collatable(atttype))
1810  {
1811  if (!OidIsValid(attcollation))
1812  ereport(ERROR,
1813  (errcode(ERRCODE_INDETERMINATE_COLLATION),
1814  errmsg("could not determine which collation to use for index expression"),
1815  errhint("Use the COLLATE clause to set the collation explicitly.")));
1816  }
1817  else
1818  {
1819  if (OidIsValid(attcollation))
1820  ereport(ERROR,
1821  (errcode(ERRCODE_DATATYPE_MISMATCH),
1822  errmsg("collations are not supported by type %s",
1823  format_type_be(atttype))));
1824  }
1825 
1826  collationOidP[attn] = attcollation;
1827 
1828  /*
1829  * Identify the opclass to use.
1830  */
1831  classOidP[attn] = ResolveOpClass(attribute->opclass,
1832  atttype,
1833  accessMethodName,
1834  accessMethodId);
1835 
1836  /*
1837  * Identify the exclusion operator, if any.
1838  */
1839  if (nextExclOp)
1840  {
1841  List *opname = (List *) lfirst(nextExclOp);
1842  Oid opid;
1843  Oid opfamily;
1844  int strat;
1845 
1846  /*
1847  * Find the operator --- it must accept the column datatype
1848  * without runtime coercion (but binary compatibility is OK)
1849  */
1850  opid = compatible_oper_opid(opname, atttype, atttype, false);
1851 
1852  /*
1853  * Only allow commutative operators to be used in exclusion
1854  * constraints. If X conflicts with Y, but Y does not conflict
1855  * with X, bad things will happen.
1856  */
1857  if (get_commutator(opid) != opid)
1858  ereport(ERROR,
1859  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1860  errmsg("operator %s is not commutative",
1861  format_operator(opid)),
1862  errdetail("Only commutative operators can be used in exclusion constraints.")));
1863 
1864  /*
1865  * Operator must be a member of the right opfamily, too
1866  */
1867  opfamily = get_opclass_family(classOidP[attn]);
1868  strat = get_op_opfamily_strategy(opid, opfamily);
1869  if (strat == 0)
1870  {
1871  HeapTuple opftuple;
1872  Form_pg_opfamily opfform;
1873 
1874  /*
1875  * attribute->opclass might not explicitly name the opfamily,
1876  * so fetch the name of the selected opfamily for use in the
1877  * error message.
1878  */
1879  opftuple = SearchSysCache1(OPFAMILYOID,
1880  ObjectIdGetDatum(opfamily));
1881  if (!HeapTupleIsValid(opftuple))
1882  elog(ERROR, "cache lookup failed for opfamily %u",
1883  opfamily);
1884  opfform = (Form_pg_opfamily) GETSTRUCT(opftuple);
1885 
1886  ereport(ERROR,
1887  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1888  errmsg("operator %s is not a member of operator family \"%s\"",
1889  format_operator(opid),
1890  NameStr(opfform->opfname)),
1891  errdetail("The exclusion operator must be related to the index operator class for the constraint.")));
1892  }
1893 
1894  indexInfo->ii_ExclusionOps[attn] = opid;
1895  indexInfo->ii_ExclusionProcs[attn] = get_opcode(opid);
1896  indexInfo->ii_ExclusionStrats[attn] = strat;
1897  nextExclOp = lnext(exclusionOpNames, nextExclOp);
1898  }
1899 
1900  /*
1901  * Set up the per-column options (indoption field). For now, this is
1902  * zero for any un-ordered index, while ordered indexes have DESC and
1903  * NULLS FIRST/LAST options.
1904  */
1905  colOptionP[attn] = 0;
1906  if (amcanorder)
1907  {
1908  /* default ordering is ASC */
1909  if (attribute->ordering == SORTBY_DESC)
1910  colOptionP[attn] |= INDOPTION_DESC;
1911  /* default null ordering is LAST for ASC, FIRST for DESC */
1912  if (attribute->nulls_ordering == SORTBY_NULLS_DEFAULT)
1913  {
1914  if (attribute->ordering == SORTBY_DESC)
1915  colOptionP[attn] |= INDOPTION_NULLS_FIRST;
1916  }
1917  else if (attribute->nulls_ordering == SORTBY_NULLS_FIRST)
1918  colOptionP[attn] |= INDOPTION_NULLS_FIRST;
1919  }
1920  else
1921  {
1922  /* index AM does not support ordering */
1923  if (attribute->ordering != SORTBY_DEFAULT)
1924  ereport(ERROR,
1925  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1926  errmsg("access method \"%s\" does not support ASC/DESC options",
1927  accessMethodName)));
1928  if (attribute->nulls_ordering != SORTBY_NULLS_DEFAULT)
1929  ereport(ERROR,
1930  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1931  errmsg("access method \"%s\" does not support NULLS FIRST/LAST options",
1932  accessMethodName)));
1933  }
1934 
1935  /* Set up the per-column opclass options (attoptions field). */
1936  if (attribute->opclassopts)
1937  {
1938  Assert(attn < nkeycols);
1939 
1940  if (!indexInfo->ii_OpclassOptions)
1941  indexInfo->ii_OpclassOptions =
1942  palloc0(sizeof(Datum) * indexInfo->ii_NumIndexAttrs);
1943 
1944  indexInfo->ii_OpclassOptions[attn] =
1945  transformRelOptions((Datum) 0, attribute->opclassopts,
1946  NULL, NULL, false, false);
1947  }
1948 
1949  attn++;
1950  }
1951 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
static bool CheckMutability(Expr *expr)
Definition: indexcmds.c:1581
Oid get_commutator(Oid opno)
Definition: lsyscache.c:1421
int errhint(const char *fmt,...)
Definition: elog.c:1071
SortByDir ordering
Definition: parsenodes.h:706
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Datum transformRelOptions(Datum oldOptions, List *defList, const char *namspace, char *validnsps[], bool acceptOidsOff, bool isReset)
Definition: reloptions.c:1132
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:321
Definition: nodes.h:529
Oid * ii_ExclusionProcs
Definition: execnodes.h:166
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
char * format_operator(Oid operator_oid)
Definition: regproc.c:851
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:181
#define OidIsValid(objectId)
Definition: c.h:651
List * opclassopts
Definition: parsenodes.h:705
Node * expr
Definition: parsenodes.h:701
unsigned short uint16
Definition: c.h:373
SortByNulls nulls_ordering
Definition: parsenodes.h:707
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
int ii_NumIndexKeyAttrs
Definition: execnodes.h:159
Oid attcollation
Definition: pg_attribute.h:157
Oid ResolveOpClass(List *opclass, Oid attrType, const char *accessMethodName, Oid accessMethodId)
Definition: indexcmds.c:1960
int errdetail(const char *fmt,...)
Definition: elog.c:957
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
List * lappend(List *list, void *datum)
Definition: list.c:321
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:51
void * palloc0(Size size)
Definition: mcxt.c:980
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
int ii_NumIndexAttrs
Definition: execnodes.h:158
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1202
#define ereport(elevel,...)
Definition: elog.h:144
List * opclass
Definition: parsenodes.h:704
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
List * ii_Expressions
Definition: execnodes.h:161
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:190
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
static int list_length(const List *l)
Definition: pg_list.h:169
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:719
char * name
Definition: parsenodes.h:700
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition: syscache.c:1257
Oid get_opclass_family(Oid opclass)
Definition: lsyscache.c:1129
#define InvalidAttrNumber
Definition: attnum.h:23
int get_op_opfamily_strategy(Oid opno, Oid opfamily)
Definition: lsyscache.c:81
Oid * ii_ExclusionOps
Definition: execnodes.h:165
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:824
Oid compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError)
Definition: parse_oper.c:494
#define elog(elevel,...)
Definition: elog.h:214
#define NameStr(name)
Definition: c.h:622
void * arg
List * collation
Definition: parsenodes.h:703
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition: execnodes.h:160
uint16 * ii_ExclusionStrats
Definition: execnodes.h:167
bool type_is_collatable(Oid typid)
Definition: lsyscache.c:2958
Definition: pg_list.h:50
Oid get_collation_oid(List *name, bool missing_ok)
Definition: namespace.c:3601
Datum * ii_OpclassOptions
Definition: execnodes.h:171

◆ DefineIndex()

ObjectAddress DefineIndex ( Oid  relationId,
IndexStmt stmt,
Oid  indexRelationId,
Oid  parentIndexId,
Oid  parentConstraintId,
bool  is_alter_table,
bool  check_rights,
bool  check_not_in_use,
bool  skip_build,
bool  quiet 
)

Definition at line 479 of file indexcmds.c.

References IndexStmt::accessMethod, ACL_CREATE, aclcheck_error(), ACLCHECK_OK, allowSystemTableMods, IndexAmRoutine::amcaninclude, IndexAmRoutine::amcanmulticol, IndexAmRoutine::amcanorder, IndexAmRoutine::amcanunique, IndexAmRoutine::amgettuple, AMNAME, IndexAmRoutine::amoptions, Assert, AtEOXact_GUC(), bms_is_member(), BTEqualStrategyNumber, build_attrmap_by_name(), BuildIndexInfo(), CacheInvalidateRelcacheByRelid(), CatalogTupleUpdate(), CheckPredicate(), CheckTableNotInUse(), ChooseIndexColumnNames(), ChooseIndexName(), CommitTransactionCommand(), CompareIndexInfo(), ComputeIndexAttrs(), ReindexIndexCallbackState::concurrent, IndexStmt::concurrent, ConstraintSetParentConstraint(), copyObject, CreateComments(), LockRelId::dbId, DEBUG1, IndexStmt::deferrable, DefineIndex(), elog, ereport, errcode(), errdetail(), errmsg(), ERROR, IndexStmt::excludeOpNames, IndexElem::expr, FirstLowInvalidHeapAttributeNumber, free_attrmap(), get_namespace_name(), get_opclass_family(), get_opclass_opfamily_and_input_type(), get_opfamily_member(), get_rel_persistence(), get_relation_idx_constraint_oid(), get_tablespace_name(), get_tablespace_oid(), GetDefaultTablespace(), GetIndexAmRoutine(), GETSTRUCT, GetTransactionSnapshot(), GetUserId(), GUC_ACTION_SAVE, has_superclass(), heap_copytuple(), heap_freetuple(), HeapTupleIsValid, HTEqualStrategyNumber, i, IndexStmt::idxcomment, IndexStmt::idxname, IndexStmt::if_not_exists, IndexInfo::ii_Expressions, IndexInfo::ii_IndexAttrNumbers, IndexInfo::ii_NumIndexAttrs, IndexInfo::ii_NumIndexKeyAttrs, IndexInfo::ii_Predicate, index_check_primary_key(), index_close(), index_concurrently_build(), INDEX_CONSTR_CREATE_DEFERRABLE, INDEX_CONSTR_CREATE_INIT_DEFERRED, index_create(), INDEX_CREATE_ADD_CONSTRAINT, INDEX_CREATE_CONCURRENT, INDEX_CREATE_IF_NOT_EXISTS, INDEX_CREATE_INVALID, INDEX_CREATE_IS_PRIMARY, INDEX_CREATE_PARTITIONED, INDEX_CREATE_SET_VALID, INDEX_CREATE_SKIP_BUILD, INDEX_MAX_KEYS, index_open(), index_reloptions(), index_set_state_flags(), IndexStmt::indexIncludingParams, IndexStmt::indexOid, IndexStmt::indexParams, INDEXRELID, IndexSetParentIndex(), RangeVar::inh, IndexStmt::initdeferred, InvalidOid, InvalidSubTransactionId, InvalidTransactionId, IsBootstrapProcessingMode, IndexStmt::isconstraint, sort-test::key, lfirst, lfirst_oid, list_concat_copy(), list_free(), list_length(), LockRelationIdForSession(), LockInfoData::lockRelId, make_ands_implicit(), makeIndexInfo(), map_variable_attnos(), MyDatabaseTableSpace, MyPgXact, NameStr, NewGUCNestLevel(), NIL, NoLock, NOTICE, PartitionDescData::nparts, OBJECT_SCHEMA, OBJECT_TABLESPACE, ObjectAddressSet, ObjectIdGetDatum, OidIsValid, PartitionDescData::oids, IndexStmt::oldCreateSubid, IndexStmt::oldFirstRelfilenodeSubid, IndexStmt::oldNode, IndexStmt::options, palloc(), PartitionKeyData::partattrs, PARTITION_STRATEGY_HASH, PartitionKeyData::partnatts, PartitionKeyData::partopcintype, PartitionKeyData::partopfamily, pfree(), pg_namespace_aclcheck(), pg_tablespace_aclcheck(), PGC_S_SESSION, PGC_USERSET, pgstat_progress_end_command(), pgstat_progress_start_command(), pgstat_progress_update_param(), PointerGetDatum, PopActiveSnapshot(), IndexStmt::primary, PROGRESS_COMMAND_CREATE_INDEX, PROGRESS_CREATEIDX_ACCESS_METHOD_OID, PROGRESS_CREATEIDX_COMMAND, PROGRESS_CREATEIDX_COMMAND_CREATE, PROGRESS_CREATEIDX_COMMAND_CREATE_CONCURRENTLY, PROGRESS_CREATEIDX_INDEX_OID, PROGRESS_CREATEIDX_PARTITIONS_DONE, PROGRESS_CREATEIDX_PARTITIONS_TOTAL, PROGRESS_CREATEIDX_PHASE, PROGRESS_CREATEIDX_PHASE_WAIT_1, PROGRESS_CREATEIDX_PHASE_WAIT_2, PROGRESS_CREATEIDX_PHASE_WAIT_3, pull_varattnos(), PushActiveSnapshot(), RelationData::rd_indcollation, RelationData::rd_index, RelationData::rd_lockInfo, RelationData::rd_opfamily, RelationData::rd_rel, RegisterSnapshot(), IndexStmt::relation, RELATION_IS_OTHER_TEMP, RelationGetDescr, RelationGetIndexList(), RelationGetNamespace, RelationGetPartitionDesc(), RelationGetPartitionKey(), RelationGetRelationName, ReleaseSysCache(), LockRelId::relId, IndexStmt::reset_default_tblspc, RowExclusiveLock, SearchSysCache1(), set_config_option(), SET_LOCKTAG_RELATION, ShareLock, ShareUpdateExclusiveLock, StartTransactionCommand(), PartitionKeyData::strategy, HeapTupleData::t_self, table_close(), table_open(), IndexStmt::tableSpace, transformRelOptions(), TupleDescAttr, IndexStmt::unique, UnlockRelationIdForSession(), UnregisterSnapshot(), validate_index(), WaitForLockers(), WaitForOlderSnapshots(), IndexStmt::whereClause, SnapshotData::xmin, and PGXACT::xmin.

Referenced by ATExecAddIndex(), AttachPartitionEnsureIndexes(), DefineIndex(), DefineRelation(), and ProcessUtilitySlow().

489 {
490  bool concurrent;
491  char *indexRelationName;
492  char *accessMethodName;
493  Oid *typeObjectId;
494  Oid *collationObjectId;
495  Oid *classObjectId;
496  Oid accessMethodId;
497  Oid namespaceId;
498  Oid tablespaceId;
499  Oid createdConstraintId = InvalidOid;
500  List *indexColNames;
501  List *allIndexParams;
502  Relation rel;
503  HeapTuple tuple;
504  Form_pg_am accessMethodForm;
505  IndexAmRoutine *amRoutine;
506  bool amcanorder;
507  amoptions_function amoptions;
508  bool partitioned;
509  Datum reloptions;
510  int16 *coloptions;
511  IndexInfo *indexInfo;
512  bits16 flags;
513  bits16 constr_flags;
514  int numberOfAttributes;
515  int numberOfKeyAttributes;
516  TransactionId limitXmin;
517  ObjectAddress address;
518  LockRelId heaprelid;
519  LOCKTAG heaplocktag;
520  LOCKMODE lockmode;
521  Snapshot snapshot;
522  int save_nestlevel = -1;
523  int i;
524 
525  /*
526  * Some callers need us to run with an empty default_tablespace; this is a
527  * necessary hack to be able to reproduce catalog state accurately when
528  * recreating indexes after table-rewriting ALTER TABLE.
529  */
530  if (stmt->reset_default_tblspc)
531  {
532  save_nestlevel = NewGUCNestLevel();
533  (void) set_config_option("default_tablespace", "",
535  GUC_ACTION_SAVE, true, 0, false);
536  }
537 
538  /*
539  * Force non-concurrent build on temporary relations, even if CONCURRENTLY
540  * was requested. Other backends can't access a temporary relation, so
541  * there's no harm in grabbing a stronger lock, and a non-concurrent DROP
542  * is more efficient. Do this before any use of the concurrent option is
543  * done.
544  */
545  if (stmt->concurrent && get_rel_persistence(relationId) != RELPERSISTENCE_TEMP)
546  concurrent = true;
547  else
548  concurrent = false;
549 
550  /*
551  * Start progress report. If we're building a partition, this was already
552  * done.
553  */
554  if (!OidIsValid(parentIndexId))
555  {
557  relationId);
559  concurrent ?
562  }
563 
564  /*
565  * No index OID to report yet
566  */
568  InvalidOid);
569 
570  /*
571  * count key attributes in index
572  */
573  numberOfKeyAttributes = list_length(stmt->indexParams);
574 
575  /*
576  * Calculate the new list of index columns including both key columns and
577  * INCLUDE columns. Later we can determine which of these are key
578  * columns, and which are just part of the INCLUDE list by checking the
579  * list position. A list item in a position less than ii_NumIndexKeyAttrs
580  * is part of the key columns, and anything equal to and over is part of
581  * the INCLUDE columns.
582  */
583  allIndexParams = list_concat_copy(stmt->indexParams,
584  stmt->indexIncludingParams);
585  numberOfAttributes = list_length(allIndexParams);
586 
587  if (numberOfAttributes <= 0)
588  ereport(ERROR,
589  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
590  errmsg("must specify at least one column")));
591  if (numberOfAttributes > INDEX_MAX_KEYS)
592  ereport(ERROR,
593  (errcode(ERRCODE_TOO_MANY_COLUMNS),
594  errmsg("cannot use more than %d columns in an index",
595  INDEX_MAX_KEYS)));
596 
597  /*
598  * Only SELECT ... FOR UPDATE/SHARE are allowed while doing a standard
599  * index build; but for concurrent builds we allow INSERT/UPDATE/DELETE
600  * (but not VACUUM).
601  *
602  * NB: Caller is responsible for making sure that relationId refers to the
603  * relation on which the index should be built; except in bootstrap mode,
604  * this will typically require the caller to have already locked the
605  * relation. To avoid lock upgrade hazards, that lock should be at least
606  * as strong as the one we take here.
607  *
608  * NB: If the lock strength here ever changes, code that is run by
609  * parallel workers under the control of certain particular ambuild
610  * functions will need to be updated, too.
611  */
612  lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock;
613  rel = table_open(relationId, lockmode);
614 
615  namespaceId = RelationGetNamespace(rel);
616 
617  /* Ensure that it makes sense to index this kind of relation */
618  switch (rel->rd_rel->relkind)
619  {
620  case RELKIND_RELATION:
621  case RELKIND_MATVIEW:
622  case RELKIND_PARTITIONED_TABLE:
623  /* OK */
624  break;
625  case RELKIND_FOREIGN_TABLE:
626 
627  /*
628  * Custom error message for FOREIGN TABLE since the term is close
629  * to a regular table and can confuse the user.
630  */
631  ereport(ERROR,
632  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
633  errmsg("cannot create index on foreign table \"%s\"",
634  RelationGetRelationName(rel))));
635  break;
636  default:
637  ereport(ERROR,
638  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
639  errmsg("\"%s\" is not a table or materialized view",
640  RelationGetRelationName(rel))));
641  break;
642  }
643 
644  /*
645  * Establish behavior for partitioned tables, and verify sanity of
646  * parameters.
647  *
648  * We do not build an actual index in this case; we only create a few
649  * catalog entries. The actual indexes are built by recursing for each
650  * partition.
651  */
652  partitioned = rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE;
653  if (partitioned)
654  {
655  /*
656  * Note: we check 'stmt->concurrent' rather than 'concurrent', so that
657  * the error is thrown also for temporary tables. Seems better to be
658  * consistent, even though we could do it on temporary table because
659  * we're not actually doing it concurrently.
660  */
661  if (stmt->concurrent)
662  ereport(ERROR,
663  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
664  errmsg("cannot create index on partitioned table \"%s\" concurrently",
665  RelationGetRelationName(rel))));
666  if (stmt->excludeOpNames)
667  ereport(ERROR,
668  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
669  errmsg("cannot create exclusion constraints on partitioned table \"%s\"",
670  RelationGetRelationName(rel))));
671  }
672 
673  /*
674  * Don't try to CREATE INDEX on temp tables of other backends.
675  */
676  if (RELATION_IS_OTHER_TEMP(rel))
677  ereport(ERROR,
678  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
679  errmsg("cannot create indexes on temporary tables of other sessions")));
680 
681  /*
682  * Unless our caller vouches for having checked this already, insist that
683  * the table not be in use by our own session, either. Otherwise we might
684  * fail to make entries in the new index (for instance, if an INSERT or
685  * UPDATE is in progress and has already made its list of target indexes).
686  */
687  if (check_not_in_use)
688  CheckTableNotInUse(rel, "CREATE INDEX");
689 
690  /*
691  * Verify we (still) have CREATE rights in the rel's namespace.
692  * (Presumably we did when the rel was created, but maybe not anymore.)
693  * Skip check if caller doesn't want it. Also skip check if
694  * bootstrapping, since permissions machinery may not be working yet.
695  */
696  if (check_rights && !IsBootstrapProcessingMode())
697  {
698  AclResult aclresult;
699 
700  aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
701  ACL_CREATE);
702  if (aclresult != ACLCHECK_OK)
703  aclcheck_error(aclresult, OBJECT_SCHEMA,
704  get_namespace_name(namespaceId));
705  }
706 
707  /*
708  * Select tablespace to use. If not specified, use default tablespace
709  * (which may in turn default to database's default).
710  */
711  if (stmt->tableSpace)
712  {
713  tablespaceId = get_tablespace_oid(stmt->tableSpace, false);
714  if (partitioned && tablespaceId == MyDatabaseTableSpace)
715  ereport(ERROR,
716  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
717  errmsg("cannot specify default tablespace for partitioned relations")));
718  }
719  else
720  {
721  tablespaceId = GetDefaultTablespace(rel->rd_rel->relpersistence,
722  partitioned);
723  /* note InvalidOid is OK in this case */
724  }
725 
726  /* Check tablespace permissions */
727  if (check_rights &&
728  OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
729  {
730  AclResult aclresult;
731 
732  aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),
733  ACL_CREATE);
734  if (aclresult != ACLCHECK_OK)
736  get_tablespace_name(tablespaceId));
737  }
738 
739  /*
740  * Force shared indexes into the pg_global tablespace. This is a bit of a
741  * hack but seems simpler than marking them in the BKI commands. On the
742  * other hand, if it's not shared, don't allow it to be placed there.
743  */
744  if (rel->rd_rel->relisshared)
745  tablespaceId = GLOBALTABLESPACE_OID;
746  else if (tablespaceId == GLOBALTABLESPACE_OID)
747  ereport(ERROR,
748  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
749  errmsg("only shared relations can be placed in pg_global tablespace")));
750 
751  /*
752  * Choose the index column names.
753  */
754  indexColNames = ChooseIndexColumnNames(allIndexParams);
755 
756  /*
757  * Select name for index if caller didn't specify
758  */
759  indexRelationName = stmt->idxname;
760  if (indexRelationName == NULL)
761  indexRelationName = ChooseIndexName(RelationGetRelationName(rel),
762  namespaceId,
763  indexColNames,
764  stmt->excludeOpNames,
765  stmt->primary,
766  stmt->isconstraint);
767 
768  /*
769  * look up the access method, verify it can handle the requested features
770  */
771  accessMethodName = stmt->accessMethod;
772  tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
773  if (!HeapTupleIsValid(tuple))
774  {
775  /*
776  * Hack to provide more-or-less-transparent updating of old RTREE
777  * indexes to GiST: if RTREE is requested and not found, use GIST.
778  */
779  if (strcmp(accessMethodName, "rtree") == 0)
780  {
781  ereport(NOTICE,
782  (errmsg("substituting access method \"gist\" for obsolete method \"rtree\"")));
783  accessMethodName = "gist";
784  tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
785  }
786 
787  if (!HeapTupleIsValid(tuple))
788  ereport(ERROR,
789  (errcode(ERRCODE_UNDEFINED_OBJECT),
790  errmsg("access method \"%s\" does not exist",
791  accessMethodName)));
792  }
793  accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
794  accessMethodId = accessMethodForm->oid;
795  amRoutine = GetIndexAmRoutine(accessMethodForm->amhandler);
796 
798  accessMethodId);
799 
800  if (stmt->unique && !amRoutine->amcanunique)
801  ereport(ERROR,
802  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
803  errmsg("access method \"%s\" does not support unique indexes",
804  accessMethodName)));
805  if (stmt->indexIncludingParams != NIL && !amRoutine->amcaninclude)
806  ereport(ERROR,
807  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
808  errmsg("access method \"%s\" does not support included columns",
809  accessMethodName)));
810  if (numberOfAttributes > 1 && !amRoutine->amcanmulticol)
811  ereport(ERROR,
812  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
813  errmsg("access method \"%s\" does not support multicolumn indexes",
814  accessMethodName)));
815  if (stmt->excludeOpNames && amRoutine->amgettuple == NULL)
816  ereport(ERROR,
817  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
818  errmsg("access method \"%s\" does not support exclusion constraints",
819  accessMethodName)));
820 
821  amcanorder = amRoutine->amcanorder;
822  amoptions = amRoutine->amoptions;
823 
824  pfree(amRoutine);
825  ReleaseSysCache(tuple);
826 
827  /*
828  * Validate predicate, if given
829  */
830  if (stmt->whereClause)
831  CheckPredicate((Expr *) stmt->whereClause);
832 
833  /*
834  * Parse AM-specific options, convert to text array form, validate.
835  */
836  reloptions = transformRelOptions((Datum) 0, stmt->options,
837  NULL, NULL, false, false);
838 
839  (void) index_reloptions(amoptions, reloptions, true);
840 
841  /*
842  * Prepare arguments for index_create, primarily an IndexInfo structure.
843  * Note that predicates must be in implicit-AND format. In a concurrent
844  * build, mark it not-ready-for-inserts.
845  */
846  indexInfo = makeIndexInfo(numberOfAttributes,
847  numberOfKeyAttributes,
848  accessMethodId,
849  NIL, /* expressions, NIL for now */
851  stmt->unique,
852  !concurrent,
853  concurrent);
854 
855  typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
856  collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
857  classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
858  coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16));
859  ComputeIndexAttrs(indexInfo,
860  typeObjectId, collationObjectId, classObjectId,
861  coloptions, allIndexParams,
862  stmt->excludeOpNames, relationId,
863  accessMethodName, accessMethodId,
864  amcanorder, stmt->isconstraint);
865 
866  /*
867  * Extra checks when creating a PRIMARY KEY index.
868  */
869  if (stmt->primary)
870  index_check_primary_key(rel, indexInfo, is_alter_table, stmt);
871 
872  /*
873  * If this table is partitioned and we're creating a unique index or a
874  * primary key, make sure that the partition key is a subset of the
875  * index's columns. Otherwise it would be possible to violate uniqueness
876  * by putting values that ought to be unique in different partitions.
877  *
878  * We could lift this limitation if we had global indexes, but those have
879  * their own problems, so this is a useful feature combination.
880  */
881  if (partitioned && (stmt->unique || stmt->primary))
882  {
884  const char *constraint_type;
885  int i;
886 
887  if (stmt->primary)
888  constraint_type = "PRIMARY KEY";
889  else if (stmt->unique)
890  constraint_type = "UNIQUE";
891  else if (stmt->excludeOpNames != NIL)
892  constraint_type = "EXCLUDE";
893  else
894  {
895  elog(ERROR, "unknown constraint type");
896  constraint_type = NULL; /* keep compiler quiet */
897  }
898 
899  /*
900  * Verify that all the columns in the partition key appear in the
901  * unique key definition, with the same notion of equality.
902  */
903  for (i = 0; i < key->partnatts; i++)
904  {
905  bool found = false;
906  int eq_strategy;
907  Oid ptkey_eqop;
908  int j;
909 
910  /*
911  * Identify the equality operator associated with this partkey
912  * column. For list and range partitioning, partkeys use btree
913  * operator classes; hash partitioning uses hash operator classes.
914  * (Keep this in sync with ComputePartitionAttrs!)
915  */
916  if (key->strategy == PARTITION_STRATEGY_HASH)
917  eq_strategy = HTEqualStrategyNumber;
918  else
919  eq_strategy = BTEqualStrategyNumber;
920 
921  ptkey_eqop = get_opfamily_member(key->partopfamily[i],
922  key->partopcintype[i],
923  key->partopcintype[i],
924  eq_strategy);
925  if (!OidIsValid(ptkey_eqop))
926  elog(ERROR, "missing operator %d(%u,%u) in partition opfamily %u",
927  eq_strategy, key->partopcintype[i], key->partopcintype[i],
928  key->partopfamily[i]);
929 
930  /*
931  * We'll need to be able to identify the equality operators
932  * associated with index columns, too. We know what to do with
933  * btree opclasses; if there are ever any other index types that
934  * support unique indexes, this logic will need extension.
935  */
936  if (accessMethodId == BTREE_AM_OID)
937  eq_strategy = BTEqualStrategyNumber;
938  else
939  ereport(ERROR,
940  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
941  errmsg("cannot match partition key to an index using access method \"%s\"",
942  accessMethodName)));
943 
944  /*
945  * It may be possible to support UNIQUE constraints when partition
946  * keys are expressions, but is it worth it? Give up for now.
947  */
948  if (key->partattrs[i] == 0)
949  ereport(ERROR,
950  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
951  errmsg("unsupported %s constraint with partition key definition",
952  constraint_type),
953  errdetail("%s constraints cannot be used when partition keys include expressions.",
954  constraint_type)));
955 
956  /* Search the index column(s) for a match */
957  for (j = 0; j < indexInfo->ii_NumIndexKeyAttrs; j++)
958  {
959  if (key->partattrs[i] == indexInfo->ii_IndexAttrNumbers[j])
960  {
961  /* Matched the column, now what about the equality op? */
962  Oid idx_opfamily;
963  Oid idx_opcintype;
964 
965  if (get_opclass_opfamily_and_input_type(classObjectId[j],
966  &idx_opfamily,
967  &idx_opcintype))
968  {
969  Oid idx_eqop;
970 
971  idx_eqop = get_opfamily_member(idx_opfamily,
972  idx_opcintype,
973  idx_opcintype,
974  eq_strategy);
975  if (ptkey_eqop == idx_eqop)
976  {
977  found = true;
978  break;
979  }
980  }
981  }
982  }
983 
984  if (!found)
985  {
986  Form_pg_attribute att;
987 
988  att = TupleDescAttr(RelationGetDescr(rel),
989  key->partattrs[i] - 1);
990  ereport(ERROR,
991  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
992  errmsg("insufficient columns in %s constraint definition",
993  constraint_type),
994  errdetail("%s constraint on table \"%s\" lacks column \"%s\" which is part of the partition key.",
995  constraint_type, RelationGetRelationName(rel),
996  NameStr(att->attname))));
997  }
998  }
999  }
1000 
1001 
1002  /*
1003  * We disallow indexes on system columns. They would not necessarily get
1004  * updated correctly, and they don't seem useful anyway.
1005  */
1006  for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
1007  {
1008  AttrNumber attno = indexInfo->ii_IndexAttrNumbers[i];
1009 
1010  if (attno < 0)
1011  ereport(ERROR,
1012  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1013  errmsg("index creation on system columns is not supported")));
1014  }
1015 
1016  /*
1017  * Also check for system columns used in expressions or predicates.
1018  */
1019  if (indexInfo->ii_Expressions || indexInfo->ii_Predicate)
1020  {
1021  Bitmapset *indexattrs = NULL;
1022 
1023  pull_varattnos((Node *) indexInfo->ii_Expressions, 1, &indexattrs);
1024  pull_varattnos((Node *) indexInfo->ii_Predicate, 1, &indexattrs);
1025 
1026  for (i = FirstLowInvalidHeapAttributeNumber + 1; i < 0; i++)
1027  {
1029  indexattrs))
1030  ereport(ERROR,
1031  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1032  errmsg("index creation on system columns is not supported")));
1033  }
1034  }
1035 
1036  /*
1037  * Report index creation if appropriate (delay this till after most of the
1038  * error checks)
1039  */
1040  if (stmt->isconstraint && !quiet)
1041  {
1042  const char *constraint_type;
1043 
1044  if (stmt->primary)
1045  constraint_type = "PRIMARY KEY";
1046  else if (stmt->unique)
1047  constraint_type = "UNIQUE";
1048  else if (stmt->excludeOpNames != NIL)
1049  constraint_type = "EXCLUDE";
1050  else
1051  {
1052  elog(ERROR, "unknown constraint type");
1053  constraint_type = NULL; /* keep compiler quiet */
1054  }
1055 
1056  ereport(DEBUG1,
1057  (errmsg("%s %s will create implicit index \"%s\" for table \"%s\"",
1058  is_alter_table ? "ALTER TABLE / ADD" : "CREATE TABLE /",
1059  constraint_type,
1060  indexRelationName, RelationGetRelationName(rel))));
1061  }
1062 
1063  /*
1064  * A valid stmt->oldNode implies that we already have a built form of the
1065  * index. The caller should also decline any index build.
1066  */
1067  Assert(!OidIsValid(stmt->oldNode) || (skip_build && !concurrent));
1068 
1069  /*
1070  * Make the catalog entries for the index, including constraints. This
1071  * step also actually builds the index, except if caller requested not to
1072  * or in concurrent mode, in which case it'll be done later, or doing a
1073  * partitioned index (because those don't have storage).
1074  */
1075  flags = constr_flags = 0;
1076  if (stmt->isconstraint)
1077  flags |= INDEX_CREATE_ADD_CONSTRAINT;
1078  if (skip_build || concurrent || partitioned)
1079  flags |= INDEX_CREATE_SKIP_BUILD;
1080  if (stmt->if_not_exists)
1081  flags |= INDEX_CREATE_IF_NOT_EXISTS;
1082  if (concurrent)
1083  flags |= INDEX_CREATE_CONCURRENT;
1084  if (partitioned)
1085  flags |= INDEX_CREATE_PARTITIONED;
1086  if (stmt->primary)
1087  flags |= INDEX_CREATE_IS_PRIMARY;
1088 
1089  /*
1090  * If the table is partitioned, and recursion was declined but partitions
1091  * exist, mark the index as invalid.
1092  */
1093  if (partitioned && stmt->relation && !stmt->relation->inh)
1094  {
1096 
1097  if (pd->nparts != 0)
1098  flags |= INDEX_CREATE_INVALID;
1099  }
1100 
1101  if (stmt->deferrable)
1102  constr_flags |= INDEX_CONSTR_CREATE_DEFERRABLE;
1103  if (stmt->initdeferred)
1104  constr_flags |= INDEX_CONSTR_CREATE_INIT_DEFERRED;
1105 
1106  indexRelationId =
1107  index_create(rel, indexRelationName, indexRelationId, parentIndexId,
1108  parentConstraintId,
1109  stmt->oldNode, indexInfo, indexColNames,
1110  accessMethodId, tablespaceId,
1111  collationObjectId, classObjectId,
1112  coloptions, reloptions,
1113  flags, constr_flags,
1114  allowSystemTableMods, !check_rights,
1115  &createdConstraintId);
1116 
1117  ObjectAddressSet(address, RelationRelationId, indexRelationId);
1118 
1119  /*
1120  * Revert to original default_tablespace. Must do this before any return
1121  * from this function, but after index_create, so this is a good time.
1122  */
1123  if (save_nestlevel >= 0)
1124  AtEOXact_GUC(true, save_nestlevel);
1125 
1126  if (!OidIsValid(indexRelationId))
1127  {
1128  table_close(rel, NoLock);
1129 
1130  /* If this is the top-level index, we're done */
1131  if (!OidIsValid(parentIndexId))
1133 
1134  return address;
1135  }
1136 
1137  /* Add any requested comment */
1138  if (stmt->idxcomment != NULL)
1139  CreateComments(indexRelationId, RelationRelationId, 0,
1140  stmt->idxcomment);
1141 
1142  if (partitioned)
1143  {
1144  /*
1145  * Unless caller specified to skip this step (via ONLY), process each
1146  * partition to make sure they all contain a corresponding index.
1147  *
1148  * If we're called internally (no stmt->relation), recurse always.
1149  */
1150  if (!stmt->relation || stmt->relation->inh)
1151  {
1152  PartitionDesc partdesc = RelationGetPartitionDesc(rel);
1153  int nparts = partdesc->nparts;
1154  Oid *part_oids = palloc(sizeof(Oid) * nparts);
1155  bool invalidate_parent = false;
1156  TupleDesc parentDesc;
1157  Oid *opfamOids;
1158 
1160  nparts);
1161 
1162  memcpy(part_oids, partdesc->oids, sizeof(Oid) * nparts);
1163 
1164  parentDesc = RelationGetDescr(rel);
1165  opfamOids = palloc(sizeof(Oid) * numberOfKeyAttributes);
1166  for (i = 0; i < numberOfKeyAttributes; i++)
1167  opfamOids[i] = get_opclass_family(classObjectId[i]);
1168 
1169  /*
1170  * For each partition, scan all existing indexes; if one matches
1171  * our index definition and is not already attached to some other
1172  * parent index, attach it to the one we just created.
1173  *
1174  * If none matches, build a new index by calling ourselves
1175  * recursively with the same options (except for the index name).
1176  */
1177  for (i = 0; i < nparts; i++)
1178  {
1179  Oid childRelid = part_oids[i];
1180  Relation childrel;
1181  List *childidxs;
1182  ListCell *cell;
1183  AttrMap *attmap;
1184  bool found = false;
1185 
1186  childrel = table_open(childRelid, lockmode);
1187 
1188  /*
1189  * Don't try to create indexes on foreign tables, though. Skip
1190  * those if a regular index, or fail if trying to create a
1191  * constraint index.
1192  */
1193  if (childrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1194  {
1195  if (stmt->unique || stmt->primary)
1196  ereport(ERROR,
1197  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1198  errmsg("cannot create unique index on partitioned table \"%s\"",
1200  errdetail("Table \"%s\" contains partitions that are foreign tables.",
1201  RelationGetRelationName(rel))));
1202 
1203  table_close(childrel, lockmode);
1204  continue;
1205  }
1206 
1207  childidxs = RelationGetIndexList(childrel);
1208  attmap =
1210  parentDesc);
1211 
1212  foreach(cell, childidxs)
1213  {
1214  Oid cldidxid = lfirst_oid(cell);
1215  Relation cldidx;
1216  IndexInfo *cldIdxInfo;
1217 
1218  /* this index is already partition of another one */
1219  if (has_superclass(cldidxid))
1220  continue;
1221 
1222  cldidx = index_open(cldidxid, lockmode);
1223  cldIdxInfo = BuildIndexInfo(cldidx);
1224  if (CompareIndexInfo(cldIdxInfo, indexInfo,
1225  cldidx->rd_indcollation,
1226  collationObjectId,
1227  cldidx->rd_opfamily,
1228  opfamOids,
1229  attmap))
1230  {
1231  Oid cldConstrOid = InvalidOid;
1232 
1233  /*
1234  * Found a match.
1235  *
1236  * If this index is being created in the parent
1237  * because of a constraint, then the child needs to
1238  * have a constraint also, so look for one. If there
1239  * is no such constraint, this index is no good, so
1240  * keep looking.
1241  */
1242  if (createdConstraintId != InvalidOid)
1243  {
1244  cldConstrOid =
1246  cldidxid);
1247  if (cldConstrOid == InvalidOid)
1248  {
1249  index_close(cldidx, lockmode);
1250  continue;
1251  }
1252  }
1253 
1254  /* Attach index to parent and we're done. */
1255  IndexSetParentIndex(cldidx, indexRelationId);
1256  if (createdConstraintId != InvalidOid)
1257  ConstraintSetParentConstraint(cldConstrOid,
1258  createdConstraintId,
1259  childRelid);
1260 
1261  if (!cldidx->rd_index->indisvalid)
1262  invalidate_parent = true;
1263 
1264  found = true;
1265  /* keep lock till commit */
1266  index_close(cldidx, NoLock);
1267  break;
1268  }
1269 
1270  index_close(cldidx, lockmode);
1271  }
1272 
1273  list_free(childidxs);
1274  table_close(childrel, NoLock);
1275 
1276  /*
1277  * If no matching index was found, create our own.
1278  */
1279  if (!found)
1280  {
1281  IndexStmt *childStmt = copyObject(stmt);
1282  bool found_whole_row;
1283  ListCell *lc;
1284 
1285  /*
1286  * We can't use the same index name for the child index,
1287  * so clear idxname to let the recursive invocation choose
1288  * a new name. Likewise, the existing target relation
1289  * field is wrong, and if indexOid or oldNode are set,
1290  * they mustn't be applied to the child either.
1291  */
1292  childStmt->idxname = NULL;
1293  childStmt->relation = NULL;
1294  childStmt->indexOid = InvalidOid;
1295  childStmt->oldNode = InvalidOid;
1298 
1299  /*
1300  * Adjust any Vars (both in expressions and in the index's
1301  * WHERE clause) to match the partition's column numbering
1302  * in case it's different from the parent's.
1303  */
1304  foreach(lc, childStmt->indexParams)
1305  {
1306  IndexElem *ielem = lfirst(lc);
1307 
1308  /*
1309  * If the index parameter is an expression, we must
1310  * translate it to contain child Vars.
1311  */
1312  if (ielem->expr)
1313  {
1314  ielem->expr =
1315  map_variable_attnos((Node *) ielem->expr,
1316  1, 0, attmap,
1317  InvalidOid,
1318  &found_whole_row);
1319  if (found_whole_row)
1320  elog(ERROR, "cannot convert whole-row table reference");
1321  }
1322  }
1323  childStmt->whereClause =
1324  map_variable_attnos(stmt->whereClause, 1, 0,
1325  attmap,
1326  InvalidOid, &found_whole_row);
1327  if (found_whole_row)
1328  elog(ERROR, "cannot convert whole-row table reference");
1329 
1330  DefineIndex(childRelid, childStmt,
1331  InvalidOid, /* no predefined OID */
1332  indexRelationId, /* this is our child */
1333  createdConstraintId,
1334  is_alter_table, check_rights, check_not_in_use,
1335  skip_build, quiet);
1336  }
1337 
1339  i + 1);
1340  free_attrmap(attmap);
1341  }
1342 
1343  /*
1344  * The pg_index row we inserted for this index was marked
1345  * indisvalid=true. But if we attached an existing index that is
1346  * invalid, this is incorrect, so update our row to invalid too.
1347  */
1348  if (invalidate_parent)
1349  {
1350  Relation pg_index = table_open(IndexRelationId, RowExclusiveLock);
1351  HeapTuple tup,
1352  newtup;
1353 
1355  ObjectIdGetDatum(indexRelationId));
1356  if (!HeapTupleIsValid(tup))
1357  elog(ERROR, "cache lookup failed for index %u",
1358  indexRelationId);
1359  newtup = heap_copytuple(tup);
1360  ((Form_pg_index) GETSTRUCT(newtup))->indisvalid = false;
1361  CatalogTupleUpdate(pg_index, &tup->t_self, newtup);
1362  ReleaseSysCache(tup);
1363  table_close(pg_index, RowExclusiveLock);
1364  heap_freetuple(newtup);
1365  }
1366  }
1367 
1368  /*
1369  * Indexes on partitioned tables are not themselves built, so we're
1370  * done here.
1371  */
1372  table_close(rel, NoLock);
1373  if (!OidIsValid(parentIndexId))
1375  return address;
1376  }
1377 
1378  if (!concurrent)
1379  {
1380  /* Close the heap and we're done, in the non-concurrent case */
1381  table_close(rel, NoLock);
1382 
1383  /* If this is the top-level index, we're done. */
1384  if (!OidIsValid(parentIndexId))
1386 
1387  return address;
1388  }
1389 
1390  /* save lockrelid and locktag for below, then close rel */
1391  heaprelid = rel->rd_lockInfo.lockRelId;
1392  SET_LOCKTAG_RELATION(heaplocktag, heaprelid.dbId, heaprelid.relId);
1393  table_close(rel, NoLock);
1394 
1395  /*
1396  * For a concurrent build, it's important to make the catalog entries
1397  * visible to other transactions before we start to build the index. That
1398  * will prevent them from making incompatible HOT updates. The new index
1399  * will be marked not indisready and not indisvalid, so that no one else
1400  * tries to either insert into it or use it for queries.
1401  *
1402  * We must commit our current transaction so that the index becomes
1403  * visible; then start another. Note that all the data structures we just
1404  * built are lost in the commit. The only data we keep past here are the
1405  * relation IDs.
1406  *
1407  * Before committing, get a session-level lock on the table, to ensure
1408  * that neither it nor the index can be dropped before we finish. This
1409  * cannot block, even if someone else is waiting for access, because we
1410  * already have the same lock within our transaction.
1411  *
1412  * Note: we don't currently bother with a session lock on the index,
1413  * because there are no operations that could change its state while we
1414  * hold lock on the parent table. This might need to change later.
1415  */
1417 
1421 
1422  /*
1423  * The index is now visible, so we can report the OID.
1424  */
1426  indexRelationId);
1427 
1428  /*
1429  * Phase 2 of concurrent index build (see comments for validate_index()
1430  * for an overview of how this works)
1431  *
1432  * Now we must wait until no running transaction could have the table open
1433  * with the old list of indexes. Use ShareLock to consider running
1434  * transactions that hold locks that permit writing to the table. Note we
1435  * do not need to worry about xacts that open the table for writing after
1436  * this point; they will see the new index when they open it.
1437  *
1438  * Note: the reason we use actual lock acquisition here, rather than just
1439  * checking the ProcArray and sleeping, is that deadlock is possible if
1440  * one of the transactions in question is blocked trying to acquire an
1441  * exclusive lock on our table. The lock code will detect deadlock and
1442  * error out properly.
1443  */
1446  WaitForLockers(heaplocktag, ShareLock, true);
1447 
1448  /*
1449  * At this moment we are sure that there are no transactions with the
1450  * table open for write that don't have this new index in their list of
1451  * indexes. We have waited out all the existing transactions and any new
1452  * transaction will have the new index in its list, but the index is still
1453  * marked as "not-ready-for-inserts". The index is consulted while
1454  * deciding HOT-safety though. This arrangement ensures that no new HOT
1455  * chains can be created where the new tuple and the old tuple in the
1456  * chain have different index keys.
1457  *
1458  * We now take a new snapshot, and build the index using all tuples that
1459  * are visible in this snapshot. We can be sure that any HOT updates to
1460  * these tuples will be compatible with the index, since any updates made
1461  * by transactions that didn't know about the index are now committed or
1462  * rolled back. Thus, each visible tuple is either the end of its
1463  * HOT-chain or the extension of the chain is HOT-safe for this index.
1464  */
1465 
1466  /* Set ActiveSnapshot since functions in the indexes may need it */
1468 
1469  /* Perform concurrent build of index */
1470  index_concurrently_build(relationId, indexRelationId);
1471 
1472  /* we can do away with our snapshot */
1474 
1475  /*
1476  * Commit this transaction to make the indisready update visible.
1477  */
1480 
1481  /*
1482  * Phase 3 of concurrent index build
1483  *
1484  * We once again wait until no transaction can have the table open with
1485  * the index marked as read-only for updates.
1486  */
1489  WaitForLockers(heaplocktag, ShareLock, true);
1490 
1491  /*
1492  * Now take the "reference snapshot" that will be used by validate_index()
1493  * to filter candidate tuples. Beware! There might still be snapshots in
1494  * use that treat some transaction as in-progress that our reference
1495  * snapshot treats as committed. If such a recently-committed transaction
1496  * deleted tuples in the table, we will not include them in the index; yet
1497  * those transactions which see the deleting one as still-in-progress will
1498  * expect such tuples to be there once we mark the index as valid.
1499  *
1500  * We solve this by waiting for all endangered transactions to exit before
1501  * we mark the index as valid.
1502  *
1503  * We also set ActiveSnapshot to this snap, since functions in indexes may
1504  * need a snapshot.
1505  */
1507  PushActiveSnapshot(snapshot);
1508 
1509  /*
1510  * Scan the index and the heap, insert any missing index entries.
1511  */
1512  validate_index(relationId, indexRelationId, snapshot);
1513 
1514  /*
1515  * Drop the reference snapshot. We must do this before waiting out other
1516  * snapshot holders, else we will deadlock against other processes also
1517  * doing CREATE INDEX CONCURRENTLY, which would see our snapshot as one
1518  * they must wait for. But first, save the snapshot's xmin to use as
1519  * limitXmin for GetCurrentVirtualXIDs().
1520  */
1521  limitXmin = snapshot->xmin;
1522 
1524  UnregisterSnapshot(snapshot);
1525 
1526  /*
1527  * The snapshot subsystem could still contain registered snapshots that
1528  * are holding back our process's advertised xmin; in particular, if
1529  * default_transaction_isolation = serializable, there is a transaction
1530  * snapshot that is still active. The CatalogSnapshot is likewise a
1531  * hazard. To ensure no deadlocks, we must commit and start yet another
1532  * transaction, and do our wait before any snapshot has been taken in it.
1533  */
1536 
1537  /* We should now definitely not be advertising any xmin. */
1539 
1540  /*
1541  * The index is now valid in the sense that it contains all currently
1542  * interesting tuples. But since it might not contain tuples deleted just
1543  * before the reference snap was taken, we have to wait out any
1544  * transactions that might have older snapshots.
1545  */
1548  WaitForOlderSnapshots(limitXmin, true);
1549 
1550  /*
1551  * Index can now be marked valid -- update its pg_index entry
1552  */
1554 
1555  /*
1556  * The pg_index update will cause backends (including this one) to update
1557  * relcache entries for the index itself, but we should also send a
1558  * relcache inval on the parent table to force replanning of cached plans.
1559  * Otherwise existing sessions might fail to use the new index where it
1560  * would be useful. (Note that our earlier commits did not create reasons
1561  * to replan; so relcache flush on the index itself was sufficient.)
1562  */
1564 
1565  /*
1566  * Last thing to do is release the session-level lock on the parent table.
1567  */
1569 
1571 
1572  return address;
1573 }
bool deferrable
Definition: parsenodes.h:2794
#define PROGRESS_CREATEIDX_PHASE_WAIT_3
Definition: progress.h:97
signed short int16
Definition: c.h:361
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
void WaitForLockers(LOCKTAG heaplocktag, LOCKMODE lockmode, bool progress)
Definition: lmgr.c:942
#define NIL
Definition: pg_list.h:65
bool primary
Definition: parsenodes.h:2792
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1421
void CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment)
Definition: comment.c:142
LockRelId lockRelId
Definition: rel.h:44
bool CompareIndexInfo(IndexInfo *info1, IndexInfo *info2, Oid *collations1, Oid *collations2, Oid *opfamilies1, Oid *opfamilies2, AttrMap *attmap)
Definition: index.c:2392
bool amcanmulticol
Definition: amapi.h:227
AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4637
ObjectAddress DefineIndex(Oid relationId, IndexStmt *stmt, Oid indexRelationId, Oid parentIndexId, Oid parentConstraintId, bool is_alter_table, bool check_rights, bool check_not_in_use, bool skip_build, bool quiet)
Definition: indexcmds.c:479
#define DEBUG1
Definition: elog.h:25
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define PROGRESS_CREATEIDX_PARTITIONS_DONE
Definition: progress.h:87
Oid get_relation_idx_constraint_oid(Oid relationId, Oid indexId)
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
List * ii_Predicate
Definition: execnodes.h:163
Datum transformRelOptions(Datum oldOptions, List *defList, const char *namspace, char *validnsps[], bool acceptOidsOff, bool isReset)
Definition: reloptions.c:1132
List * options
Definition: parsenodes.h:2782
void free_attrmap(AttrMap *map)
Definition: attmap.c:57
SubTransactionId oldCreateSubid
Definition: parsenodes.h:2788
uint32 TransactionId
Definition: c.h:520
#define INDEX_CREATE_IF_NOT_EXISTS
Definition: index.h:51
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:865
amgettuple_function amgettuple
Definition: amapi.h:272
#define RelationGetDescr(relation)
Definition: rel.h:482
#define INDEX_CREATE_INVALID
Definition: index.h:53
int LOCKMODE
Definition: lockdefs.h:26
Oid GetUserId(void)
Definition: miscinit.c:450
void pgstat_progress_start_command(ProgressCommandType cmdtype, Oid relid)
Definition: pgstat.c:3210
Oid * partopfamily
Definition: partcache.h:33
void index_set_state_flags(Oid indexId, IndexStateFlagsAction action)
Definition: index.c:3305
uint16 bits16
Definition: c.h:382
TransactionId xmin
Definition: proc.h:234
#define PointerGetDatum(X)
Definition: postgres.h:556
char * tableSpace
Definition: parsenodes.h:2778
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
void pgstat_progress_update_param(int index, int64 val)
Definition: pgstat.c:3231
void CommitTransactionCommand(void)
Definition: xact.c:2947
Oid dbId
Definition: rel.h:39
Node * whereClause
Definition: parsenodes.h:2783
Definition: lock.h:163
Definition: nodes.h:529
int errcode(int sqlerrcode)
Definition: elog.c:610
#define PROGRESS_CREATEIDX_PHASE_WAIT_1
Definition: progress.h:91
static void WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
Definition: indexcmds.c:389
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
void PopActiveSnapshot(void)
Definition: snapmgr.c:814
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2287
void index_check_primary_key(Relation heapRel, IndexInfo *indexInfo, bool is_alter_table, IndexStmt *stmt)
Definition: index.c:200
Node * map_variable_attnos(Node *node, int target_varno, int sublevels_up, const AttrMap *attno_map, Oid to_rowtype, bool *found_whole_row)
static List * ChooseIndexColumnNames(List *indexElems)
Definition: indexcmds.c:2365
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
Form_pg_class rd_rel
Definition: rel.h:109
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
Oid index_create(Relation heapRelation, const char *indexRelationName, Oid indexRelationId, Oid parentIndexRelid, Oid parentConstraintId, Oid relFileNode, IndexInfo *indexInfo, List *indexColNames, Oid accessMethodObjectId, Oid tableSpaceId, Oid *collationObjectId, Oid *classObjectId, int16 *coloptions, Datum reloptions, bits16 flags, bits16 constr_flags, bool allow_system_table_mods, bool is_internal, Oid *constraintId)
Definition: index.c:683
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:306
#define OidIsValid(objectId)
Definition: c.h:651
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4625
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:219
Oid MyDatabaseTableSpace
Definition: globals.c:87
Definition: attmap.h:34
PGXACT * MyPgXact
Definition: proc.c:68
List * indexIncludingParams
Definition: parsenodes.h:2780
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition: index.h:77
bool get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
Definition: lsyscache.c:1174
Oid indexOid
Definition: parsenodes.h:2786
Node * expr
Definition: parsenodes.h:701
RangeVar * relation
Definition: parsenodes.h:2776
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
Form_pg_index rd_index
Definition: rel.h:174
void pfree(void *pointer)
Definition: mcxt.c:1056
Oid * rd_indcollation
Definition: rel.h:199
void UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
Definition: lmgr.c:382
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
int ii_NumIndexKeyAttrs
Definition: execnodes.h:159
#define PROGRESS_CREATEIDX_PHASE_WAIT_2
Definition: progress.h:93
Definition: rel.h:36
#define ACL_CREATE
Definition: parsenodes.h:84
void LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
Definition: lmgr.c:369
amoptions_function amoptions
Definition: amapi.h:265
IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition: amapi.c:33
#define HTEqualStrategyNumber
Definition: stratnum.h:41
ItemPointerData t_self
Definition: htup.h:65
bool has_superclass(Oid relationId)
Definition: pg_inherits.c:286
bool amcaninclude
Definition: amapi.h:243
bool amcanunique
Definition: amapi.h:225
Oid GetDefaultTablespace(char relpersistence, bool partitioned)
Definition: tablespace.c:1138
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition: lock.h:180
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
#define NoLock
Definition: lockdefs.h:34
LockInfoData rd_lockInfo
Definition: rel.h:112
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:735
void IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
Definition: indexcmds.c:3501
List * list_concat_copy(const List *list1, const List *list2)
Definition: list.c:552
#define PROGRESS_CREATEIDX_COMMAND_CREATE
Definition: progress.h:108
#define RowExclusiveLock
Definition: lockdefs.h:38
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:5956
#define PROGRESS_CREATEIDX_INDEX_OID
Definition: progress.h:80
int errdetail(const char *fmt,...)
Definition: elog.c:957
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:164
PartitionDesc RelationGetPartitionDesc(Relation rel)
Definition: partdesc.c:65
void CacheInvalidateRelcacheByRelid(Oid relid)
Definition: inval.c:1337
#define InvalidTransactionId
Definition: transam.h:31
#define RelationGetRelationName(relation)
Definition: rel.h:490
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
Oid * rd_opfamily
Definition: rel.h:189
SubTransactionId oldFirstRelfilenodeSubid
Definition: parsenodes.h:2789
TransactionId xmin
Definition: snapshot.h:157
void ConstraintSetParentConstraint(Oid childConstrId, Oid parentConstrId, Oid childTableId)
IndexInfo * makeIndexInfo(int numattrs, int numkeyattrs, Oid amoid, List *expressions, List *predicates, bool unique, bool isready, bool concurrent)
Definition: makefuncs.c:742
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3533
bool inh
Definition: primnodes.h:69
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:907
#define PROGRESS_CREATEIDX_PARTITIONS_TOTAL
Definition: progress.h:86
char * idxname
Definition: parsenodes.h:2775
void validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
Definition: index.c:3149
FormData_pg_index * Form_pg_index
Definition: pg_index.h:68
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
#define PROGRESS_CREATEIDX_PHASE
Definition: progress.h:82
bool reset_default_tblspc
Definition: parsenodes.h:2799
bool if_not_exists
Definition: parsenodes.h:2798
AclResult
Definition: acl.h:177
AttrNumber * partattrs
Definition: partcache.h:28
void pgstat_progress_end_command(void)
Definition: pgstat.c:3282
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
int ii_NumIndexAttrs
Definition: execnodes.h:158
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:718
bool unique
Definition: parsenodes.h:2791
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:800
char * accessMethod
Definition: parsenodes.h:2777
#define INDEX_CREATE_IS_PRIMARY
Definition: index.h:47
bool allowSystemTableMods
Definition: globals.c:120
#define InvalidOid
Definition: postgres_ext.h:36
#define INDEX_CREATE_CONCURRENT
Definition: index.h:50
#define ereport(elevel,...)
Definition: elog.h:144
bytea * index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate)
Definition: reloptions.c:2031
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc)
Definition: attmap.c:174
#define NOTICE
Definition: elog.h:37
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
List * ii_Expressions
Definition: execnodes.h:161
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:190
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:593
void StartTransactionCommand(void)
Definition: xact.c:2846
List * indexParams
Definition: parsenodes.h:2779
static void CheckPredicate(Expr *predicate)
Definition: indexcmds.c:1615
#define INDEX_MAX_KEYS
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
List * excludeOpNames
Definition: parsenodes.h:2784
static int list_length(const List *l)
Definition: pg_list.h:169
#define PROGRESS_CREATEIDX_COMMAND_CREATE_CONCURRENTLY
Definition: progress.h:109
bool initdeferred
Definition: parsenodes.h:2795
bool amcanorder
Definition: amapi.h:219
char * idxcomment
Definition: parsenodes.h:2785
#define InvalidSubTransactionId
Definition: c.h:526
Oid get_opclass_family(Oid opclass)
Definition: lsyscache.c:1129
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4507
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
char get_rel_persistence(Oid relid)
Definition: lsyscache.c:1990
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:393
#define INDEX_CREATE_SKIP_BUILD
Definition: index.h:49
bool concurrent
Definition: parsenodes.h:2797
#define INDEX_CREATE_PARTITIONED
Definition: index.h:52
int NewGUCNestLevel(void)
Definition: guc.c:5942
bool isconstraint
Definition: parsenodes.h:2793
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:824
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1467
Oid * partopcintype
Definition: partcache.h:34
void list_free(List *list)
Definition: list.c:1376
#define elog(elevel,...)
Definition: elog.h:214
#define ShareLock
Definition: lockdefs.h:41
int i
#define NameStr(name)
Definition: c.h:622
static void ComputeIndexAttrs(IndexInfo *indexInfo, Oid *typeOidP, Oid *collationOidP, Oid *classOidP, int16 *colOptionP, List *attList, List *exclusionOpNames, Oid relId, const char *accessMethodName, Oid accessMethodId, bool amcanorder, bool isconstraint)
Definition: indexcmds.c:1638
static char * ChooseIndexName(const char *tabname, Oid namespaceId, List *colnames, List *exclusionOpNames, bool primary, bool isconstraint)
Definition: indexcmds.c:2276
bytea *(* amoptions_function)(Datum reloptions, bool validate)
Definition: amapi.h:139
#define copyObject(obj)
Definition: nodes.h:645
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition: execnodes.h:160
#define INDEX_CREATE_ADD_CONSTRAINT
Definition: index.h:48
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
void index_concurrently_build(Oid heapRelationId, Oid indexRelationId)
Definition: index.c:1382
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:6949
Definition: pg_list.h:50
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
int16 AttrNumber
Definition: attnum.h:21
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition: index.h:76
#define PROGRESS_CREATEIDX_COMMAND
Definition: progress.h:79
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:192
Oid relId
Definition: rel.h:38
#define PROGRESS_CREATEIDX_ACCESS_METHOD_OID
Definition: progress.h:81
#define RelationGetNamespace(relation)
Definition: rel.h:497

◆ GetDefaultOpClass()

Oid GetDefaultOpClass ( Oid  type_id,
Oid  am_id 
)

Definition at line 2045 of file indexcmds.c.

References AccessShareLock, BTEqualStrategyNumber, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, format_type_be(), getBaseType(), GETSTRUCT, HeapTupleIsValid, InvalidOid, IsBinaryCoercible(), IsPreferredType(), ObjectIdGetDatum, OpclassAmNameNspIndexId, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), and TypeCategory().

Referenced by ComputePartitionAttrs(), findRangeSubOpclass(), get_opclass(), get_opclass_name(), lookup_type_cache(), ResolveOpClass(), and transformIndexConstraint().

2046 {
2047  Oid result = InvalidOid;
2048  int nexact = 0;
2049  int ncompatible = 0;
2050  int ncompatiblepreferred = 0;
2051  Relation rel;
2052  ScanKeyData skey[1];
2053  SysScanDesc scan;
2054  HeapTuple tup;
2055  TYPCATEGORY tcategory;
2056 
2057  /* If it's a domain, look at the base type instead */
2058  type_id = getBaseType(type_id);
2059 
2060  tcategory = TypeCategory(type_id);
2061 
2062  /*
2063  * We scan through all the opclasses available for the access method,
2064  * looking for one that is marked default and matches the target type
2065  * (either exactly or binary-compatibly, but prefer an exact match).
2066  *
2067  * We could find more than one binary-compatible match. If just one is
2068  * for a preferred type, use that one; otherwise we fail, forcing the user
2069  * to specify which one he wants. (The preferred-type special case is a
2070  * kluge for varchar: it's binary-compatible to both text and bpchar, so
2071  * we need a tiebreaker.) If we find more than one exact match, then
2072  * someone put bogus entries in pg_opclass.
2073  */
2074  rel = table_open(OperatorClassRelationId, AccessShareLock);
2075 
2076  ScanKeyInit(&skey[0],
2077  Anum_pg_opclass_opcmethod,
2078  BTEqualStrategyNumber, F_OIDEQ,
2079  ObjectIdGetDatum(am_id));
2080 
2081  scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
2082  NULL, 1, skey);
2083 
2084  while (HeapTupleIsValid(tup = systable_getnext(scan)))
2085  {
2086  Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
2087 
2088  /* ignore altogether if not a default opclass */
2089  if (!opclass->opcdefault)
2090  continue;
2091  if (opclass->opcintype == type_id)
2092  {
2093  nexact++;
2094  result = opclass->oid;
2095  }
2096  else if (nexact == 0 &&
2097  IsBinaryCoercible(type_id, opclass->opcintype))
2098  {
2099  if (IsPreferredType(tcategory, opclass->opcintype))
2100  {
2101  ncompatiblepreferred++;
2102  result = opclass->oid;
2103  }
2104  else if (ncompatiblepreferred == 0)
2105  {
2106  ncompatible++;
2107  result = opclass->oid;
2108  }
2109  }
2110  }
2111 
2112  systable_endscan(scan);
2113 
2115 
2116  /* raise error if pg_opclass contains inconsistent data */
2117  if (nexact > 1)
2118  ereport(ERROR,
2120  errmsg("there are multiple default operator classes for data type %s",
2121  format_type_be(type_id))));
2122 
2123  if (nexact == 1 ||
2124  ncompatiblepreferred == 1 ||
2125  (ncompatiblepreferred == 0 && ncompatible == 1))
2126  return result;
2127 
2128  return InvalidOid;
2129 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:569
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
unsigned int Oid
Definition: postgres_ext.h:31
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:357
#define OpclassAmNameNspIndexId
Definition: indexing.h:200
bool IsPreferredType(TYPCATEGORY category, Oid type)
char TYPCATEGORY
Definition: parse_coerce.h:21
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:476
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
bool IsBinaryCoercible(Oid srctype, Oid targettype)
#define InvalidOid
Definition: postgres_ext.h:36
TYPCATEGORY TypeCategory(Oid type)
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
int errmsg(const char *fmt,...)
Definition: elog.c:824
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2409
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ IndexSetParentIndex()

void IndexSetParentIndex ( Relation  partitionIdx,
Oid  parentOid 
)

Definition at line 3501 of file indexcmds.c.

References Assert, BTEqualStrategyNumber, CatalogTupleDelete(), CatalogTupleInsert(), CommandCounterIncrement(), deleteDependencyRecordsForClass(), DEPENDENCY_PARTITION_PRI, DEPENDENCY_PARTITION_SEC, elog, ERROR, fix_dependencies(), GETSTRUCT, heap_form_tuple(), HeapTupleIsValid, InheritsRelidSeqnoIndexId, Int32GetDatum, InvalidOid, sort-test::key, ObjectAddressSet, ObjectIdGetDatum, OidIsValid, RelationData::rd_index, RelationData::rd_rel, recordDependencyOn(), relation_close(), relation_open(), RelationGetDescr, RelationGetRelid, RowExclusiveLock, ScanKeyInit(), SetRelationHasSubclass(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, update_relispartition(), and values.

Referenced by ATExecAttachPartitionIdx(), ATExecDetachPartition(), AttachPartitionEnsureIndexes(), and DefineIndex().

3502 {
3503  Relation pg_inherits;
3504  ScanKeyData key[2];
3505  SysScanDesc scan;
3506  Oid partRelid = RelationGetRelid(partitionIdx);
3507  HeapTuple tuple;
3508  bool fix_dependencies;
3509 
3510  /* Make sure this is an index */
3511  Assert(partitionIdx->rd_rel->relkind == RELKIND_INDEX ||
3512  partitionIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
3513 
3514  /*
3515  * Scan pg_inherits for rows linking our index to some parent.
3516  */
3517  pg_inherits = relation_open(InheritsRelationId, RowExclusiveLock);
3518  ScanKeyInit(&key[0],
3519  Anum_pg_inherits_inhrelid,
3520  BTEqualStrategyNumber, F_OIDEQ,
3521  ObjectIdGetDatum(partRelid));
3522  ScanKeyInit(&key[1],
3523  Anum_pg_inherits_inhseqno,
3524  BTEqualStrategyNumber, F_INT4EQ,
3525  Int32GetDatum(1));
3526  scan = systable_beginscan(pg_inherits, InheritsRelidSeqnoIndexId, true,
3527  NULL, 2, key);
3528  tuple = systable_getnext(scan);
3529 
3530  if (!HeapTupleIsValid(tuple))
3531  {
3532  if (parentOid == InvalidOid)
3533  {
3534  /*
3535  * No pg_inherits row, and no parent wanted: nothing to do in this
3536  * case.
3537  */
3538  fix_dependencies = false;
3539  }
3540  else
3541  {
3542  Datum values[Natts_pg_inherits];
3543  bool isnull[Natts_pg_inherits];
3544 
3545  /*
3546  * No pg_inherits row exists, and we want a parent for this index,
3547  * so insert it.
3548  */
3549  values[Anum_pg_inherits_inhrelid - 1] = ObjectIdGetDatum(partRelid);
3550  values[Anum_pg_inherits_inhparent - 1] =
3551  ObjectIdGetDatum(parentOid);
3552  values[Anum_pg_inherits_inhseqno - 1] = Int32GetDatum(1);
3553  memset(isnull, false, sizeof(isnull));
3554 
3555  tuple = heap_form_tuple(RelationGetDescr(pg_inherits),
3556  values, isnull);
3557  CatalogTupleInsert(pg_inherits, tuple);
3558 
3559  fix_dependencies = true;
3560  }
3561  }
3562  else
3563  {
3564  Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(tuple);
3565 
3566  if (parentOid == InvalidOid)
3567  {
3568  /*
3569  * There exists a pg_inherits row, which we want to clear; do so.
3570  */
3571  CatalogTupleDelete(pg_inherits, &tuple->t_self);
3572  fix_dependencies = true;
3573  }
3574  else
3575  {
3576  /*
3577  * A pg_inherits row exists. If it's the same we want, then we're
3578  * good; if it differs, that amounts to a corrupt catalog and
3579  * should not happen.
3580  */
3581  if (inhForm->inhparent != parentOid)
3582  {
3583  /* unexpected: we should not get called in this case */
3584  elog(ERROR, "bogus pg_inherit row: inhrelid %u inhparent %u",
3585  inhForm->inhrelid, inhForm->inhparent);
3586  }
3587 
3588  /* already in the right state */
3589  fix_dependencies = false;
3590  }
3591  }
3592 
3593  /* done with pg_inherits */
3594  systable_endscan(scan);
3595  relation_close(pg_inherits, RowExclusiveLock);
3596 
3597  /* set relhassubclass if an index partition has been added to the parent */
3598  if (OidIsValid(parentOid))
3599  SetRelationHasSubclass(parentOid, true);
3600 
3601  /* set relispartition correctly on the partition */
3602  update_relispartition(partRelid, OidIsValid(parentOid));
3603 
3604  if (fix_dependencies)
3605  {
3606  /*
3607  * Insert/delete pg_depend rows. If setting a parent, add PARTITION
3608  * dependencies on the parent index and the table; if removing a
3609  * parent, delete PARTITION dependencies.
3610  */
3611  if (OidIsValid(parentOid))
3612  {
3613  ObjectAddress partIdx;
3614  ObjectAddress parentIdx;
3615  ObjectAddress partitionTbl;
3616 
3617  ObjectAddressSet(partIdx, RelationRelationId, partRelid);
3618  ObjectAddressSet(parentIdx, RelationRelationId, parentOid);
3619  ObjectAddressSet(partitionTbl, RelationRelationId,
3620  partitionIdx->rd_index->indrelid);
3621  recordDependencyOn(&partIdx, &parentIdx,
3623  recordDependencyOn(&partIdx, &partitionTbl,
3625  }
3626  else
3627  {
3628  deleteDependencyRecordsForClass(RelationRelationId, partRelid,
3629  RelationRelationId,
3631  deleteDependencyRecordsForClass(RelationRelationId, partRelid,
3632  RelationRelationId,
3634  }
3635 
3636  /* make our updates visible */
3638  }
3639 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:569
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define RelationGetDescr(relation)
Definition: rel.h:482
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:350
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:651
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:357
void SetRelationHasSubclass(Oid relationId, bool relhassubclass)
Definition: tablecmds.c:2949
Form_pg_index rd_index
Definition: rel.h:174
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:476
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
ItemPointerData t_self
Definition: htup.h:65
static void update_relispartition(Oid relationId, bool newval)
Definition: indexcmds.c:3646
#define RowExclusiveLock
Definition: lockdefs.h:38
uintptr_t Datum
Definition: postgres.h:367
void CommandCounterIncrement(void)
Definition: xact.c:1021
static void fix_dependencies(ArchiveHandle *AH)
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:240
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:745
#define InheritsRelidSeqnoIndexId
Definition: indexing.h:176
FormData_pg_inherits * Form_pg_inherits
Definition: pg_inherits.h:44
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
static Datum values[MAXATTR]
Definition: bootstrap.c:167
#define Int32GetDatum(X)
Definition: postgres.h:479
#define elog(elevel,...)
Definition: elog.h:214
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define RelationGetRelid(relation)
Definition: rel.h:456
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:221
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ makeObjectName()

char* makeObjectName ( const char *  name1,
const char *  name2,
const char *  label 
)

Definition at line 2154 of file indexcmds.c.

References Assert, name, NAMEDATALEN, palloc(), and pg_mbcliplen().

Referenced by ChooseConstraintName(), ChooseExtendedStatisticName(), and ChooseRelationName().

2155 {
2156  char *name;
2157  int overhead = 0; /* chars needed for label and underscores */
2158  int availchars; /* chars available for name(s) */
2159  int name1chars; /* chars allocated to name1 */
2160  int name2chars; /* chars allocated to name2 */
2161  int ndx;
2162 
2163  name1chars = strlen(name1);
2164  if (name2)
2165  {
2166  name2chars = strlen(name2);
2167  overhead++; /* allow for separating underscore */
2168  }
2169  else
2170  name2chars = 0;
2171  if (label)
2172  overhead += strlen(label) + 1;
2173 
2174  availchars = NAMEDATALEN - 1 - overhead;
2175  Assert(availchars > 0); /* else caller chose a bad label */
2176 
2177  /*
2178  * If we must truncate, preferentially truncate the longer name. This
2179  * logic could be expressed without a loop, but it's simple and obvious as
2180  * a loop.
2181  */
2182  while (name1chars + name2chars > availchars)
2183  {
2184  if (name1chars > name2chars)
2185  name1chars--;
2186  else
2187  name2chars--;
2188  }
2189 
2190  name1chars = pg_mbcliplen(name1, name1chars, name1chars);
2191  if (name2)
2192  name2chars = pg_mbcliplen(name2, name2chars, name2chars);
2193 
2194  /* Now construct the string using the chosen lengths */
2195  name = palloc(name1chars + name2chars + overhead + 1);
2196  memcpy(name, name1, name1chars);
2197  ndx = name1chars;
2198  if (name2)
2199  {
2200  name[ndx++] = '_';
2201  memcpy(name + ndx, name2, name2chars);
2202  ndx += name2chars;
2203  }
2204  if (label)
2205  {
2206  name[ndx++] = '_';
2207  strcpy(name + ndx, label);
2208  }
2209  else
2210  name[ndx] = '\0';
2211 
2212  return name;
2213 }
#define NAMEDATALEN
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition: mbutils.c:967
static char * label
#define Assert(condition)
Definition: c.h:745
const char * name
Definition: encode.c:561
void * palloc(Size size)
Definition: mcxt.c:949

◆ RangeVarCallbackForReindexIndex()

static void RangeVarCallbackForReindexIndex ( const RangeVar relation,
Oid  relId,
Oid  oldRelId,
void *  arg 
)
static

Definition at line 2476 of file indexcmds.c.

References aclcheck_error(), ACLCHECK_NOT_OWNER, arg, ReindexIndexCallbackState::concurrent, ereport, errcode(), errmsg(), ERROR, get_rel_relkind(), GetUserId(), IndexGetRelation(), InvalidOid, ReindexIndexCallbackState::locked_table_oid, LockRelationOid(), OBJECT_INDEX, OidIsValid, pg_class_ownercheck(), RangeVar::relname, ShareLock, ShareUpdateExclusiveLock, and UnlockRelationOid().

Referenced by ReindexIndex().

2478 {
2479  char relkind;
2481  LOCKMODE table_lockmode;
2482 
2483  /*
2484  * Lock level here should match table lock in reindex_index() for
2485  * non-concurrent case and table locks used by index_concurrently_*() for
2486  * concurrent case.
2487  */
2488  table_lockmode = state->concurrent ? ShareUpdateExclusiveLock : ShareLock;
2489 
2490  /*
2491  * If we previously locked some other index's heap, and the name we're
2492  * looking up no longer refers to that relation, release the now-useless
2493  * lock.
2494  */
2495  if (relId != oldRelId && OidIsValid(oldRelId))
2496  {
2497  UnlockRelationOid(state->locked_table_oid, table_lockmode);
2498  state->locked_table_oid = InvalidOid;
2499  }
2500 
2501  /* If the relation does not exist, there's nothing more to do. */
2502  if (!OidIsValid(relId))
2503  return;
2504 
2505  /*
2506  * If the relation does exist, check whether it's an index. But note that
2507  * the relation might have been dropped between the time we did the name
2508  * lookup and now. In that case, there's nothing to do.
2509  */
2510  relkind = get_rel_relkind(relId);
2511  if (!relkind)
2512  return;
2513  if (relkind != RELKIND_INDEX &&
2514  relkind != RELKIND_PARTITIONED_INDEX)
2515  ereport(ERROR,
2516  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2517  errmsg("\"%s\" is not an index", relation->relname)));
2518 
2519  /* Check permissions */
2520  if (!pg_class_ownercheck(relId, GetUserId()))
2522 
2523  /* Lock heap before index to avoid deadlock. */
2524  if (relId != oldRelId)
2525  {
2526  Oid table_oid = IndexGetRelation(relId, true);
2527 
2528  /*
2529  * If the OID isn't valid, it means the index was concurrently
2530  * dropped, which is not a problem for us; just return normally.
2531  */
2532  if (OidIsValid(table_oid))
2533  {
2534  LockRelationOid(table_oid, table_lockmode);
2535  state->locked_table_oid = table_oid;
2536  }
2537  }
2538 }
Oid IndexGetRelation(Oid indexId, bool missing_ok)
Definition: index.c:3384
int LOCKMODE
Definition: lockdefs.h:26
Oid GetUserId(void)
Definition: miscinit.c:450
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:199
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1915
int errcode(int sqlerrcode)
Definition: elog.c:610
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:651
char * relname
Definition: primnodes.h:68
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
#define ERROR
Definition: elog.h:43
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
Definition: regguts.h:298
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4687
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define ShareLock
Definition: lockdefs.h:41
void * arg
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108

◆ ReindexIndex()

void ReindexIndex ( RangeVar indexRelation,
int  options,
bool  concurrent 
)

Definition at line 2423 of file indexcmds.c.

References AccessExclusiveLock, ReindexIndexCallbackState::concurrent, index_close(), index_open(), InvalidOid, ReindexIndexCallbackState::locked_table_oid, NoLock, RangeVarCallbackForReindexIndex(), RangeVarGetRelidExtended(), RelationData::rd_rel, reindex_index(), REINDEXOPT_REPORT_PROGRESS, ReindexPartitionedIndex(), ReindexRelationConcurrently(), and ShareUpdateExclusiveLock.

Referenced by standard_ProcessUtility().

2424 {
2426  Oid indOid;
2427  Relation irel;
2428  char persistence;
2429 
2430  /*
2431  * Find and lock index, and check permissions on table; use callback to
2432  * obtain lock on table first, to avoid deadlock hazard. The lock level
2433  * used here must match the index lock obtained in reindex_index().
2434  *
2435  * If it's a temporary index, we will perform a non-concurrent reindex,
2436  * even if CONCURRENTLY was requested. In that case, reindex_index() will
2437  * upgrade the lock, but that's OK, because other sessions can't hold
2438  * locks on our temporary table.
2439  */
2440  state.concurrent = concurrent;
2441  state.locked_table_oid = InvalidOid;
2442  indOid = RangeVarGetRelidExtended(indexRelation,
2444  0,
2446  &state);
2447 
2448  /*
2449  * Obtain the current persistence of the existing index. We already hold
2450  * lock on the index.
2451  */
2452  irel = index_open(indOid, NoLock);
2453 
2454  if (irel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
2455  {
2457  return;
2458  }
2459 
2460  persistence = irel->rd_rel->relpersistence;
2461  index_close(irel, NoLock);
2462 
2463  if (concurrent && persistence != RELPERSISTENCE_TEMP)
2465  else
2466  reindex_index(indOid, false, persistence,
2468 }
#define REINDEXOPT_REPORT_PROGRESS
Definition: parsenodes.h:3353
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
static bool ReindexRelationConcurrently(Oid relationOid, int options)
Definition: indexcmds.c:2825
#define NoLock
Definition: lockdefs.h:34
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:236
static void RangeVarCallbackForReindexIndex(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: indexcmds.c:2476
#define InvalidOid
Definition: postgres_ext.h:36
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
Definition: regguts.h:298
void reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, int options)
Definition: index.c:3409
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
#define AccessExclusiveLock
Definition: lockdefs.h:45
static void ReindexPartitionedIndex(Relation parentIdx)
Definition: indexcmds.c:3487
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132

◆ ReindexMultipleTables()

void ReindexMultipleTables ( const char *  objectName,
ReindexObjectType  objectKind,
int  options,
bool  concurrent 
)

Definition at line 2596 of file indexcmds.c.

References AccessShareLock, aclcheck_error(), ACLCHECK_NOT_OWNER, ALLOCSET_SMALL_SIZES, AllocSetContextCreate, Assert, AssertArg, BTEqualStrategyNumber, CommitTransactionCommand(), ereport, errcode(), errmsg(), ERROR, ForwardScanDirection, get_database_name(), get_namespace_name(), get_namespace_oid(), get_rel_name(), get_rel_namespace(), get_rel_persistence(), GETSTRUCT, GetTransactionSnapshot(), GetUserId(), heap_getnext(), INFO, IsCatalogRelationOid(), IsSystemClass(), isTempNamespace(), lappend_oid(), lcons_oid(), lfirst_oid, MemoryContextDelete(), MemoryContextSwitchTo(), MyDatabaseId, NIL, OBJECT_DATABASE, OBJECT_SCHEMA, ObjectIdGetDatum, pg_class_ownercheck(), pg_database_ownercheck(), pg_namespace_ownercheck(), PopActiveSnapshot(), PortalContext, PushActiveSnapshot(), REINDEX_OBJECT_DATABASE, REINDEX_OBJECT_SCHEMA, REINDEX_OBJECT_SYSTEM, REINDEX_REL_CHECK_CONSTRAINTS, REINDEX_REL_PROCESS_TOAST, reindex_relation(), REINDEXOPT_REPORT_PROGRESS, REINDEXOPT_VERBOSE, ReindexRelationConcurrently(), ScanKeyInit(), StartTransactionCommand(), table_beginscan_catalog(), table_close(), table_endscan(), table_open(), and WARNING.

Referenced by standard_ProcessUtility().

2598 {
2599  Oid objectOid;
2600  Relation relationRelation;
2601  TableScanDesc scan;
2602  ScanKeyData scan_keys[1];
2603  HeapTuple tuple;
2604  MemoryContext private_context;
2605  MemoryContext old;
2606  List *relids = NIL;
2607  ListCell *l;
2608  int num_keys;
2609  bool concurrent_warning = false;
2610 
2611  AssertArg(objectName);
2612  Assert(objectKind == REINDEX_OBJECT_SCHEMA ||
2613  objectKind == REINDEX_OBJECT_SYSTEM ||
2614  objectKind == REINDEX_OBJECT_DATABASE);
2615 
2616  if (objectKind == REINDEX_OBJECT_SYSTEM && concurrent)
2617  ereport(ERROR,
2618  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2619  errmsg("cannot reindex system catalogs concurrently")));
2620 
2621  /*
2622  * Get OID of object to reindex, being the database currently being used
2623  * by session for a database or for system catalogs, or the schema defined
2624  * by caller. At the same time do permission checks that need different
2625  * processing depending on the object type.
2626  */
2627  if (objectKind == REINDEX_OBJECT_SCHEMA)
2628  {
2629  objectOid = get_namespace_oid(objectName, false);
2630 
2631  if (!pg_namespace_ownercheck(objectOid, GetUserId()))
2633  objectName);
2634  }
2635  else
2636  {
2637  objectOid = MyDatabaseId;
2638 
2639  if (strcmp(objectName, get_database_name(objectOid)) != 0)
2640  ereport(ERROR,
2641  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2642  errmsg("can only reindex the currently open database")));
2643  if (!pg_database_ownercheck(objectOid, GetUserId()))
2645  objectName);
2646  }
2647 
2648  /*
2649  * Create a memory context that will survive forced transaction commits we
2650  * do below. Since it is a child of PortalContext, it will go away
2651  * eventually even if we suffer an error; there's no need for special
2652  * abort cleanup logic.
2653  */
2654  private_context = AllocSetContextCreate(PortalContext,
2655  "ReindexMultipleTables",
2657 
2658  /*
2659  * Define the search keys to find the objects to reindex. For a schema, we
2660  * select target relations using relnamespace, something not necessary for
2661  * a database-wide operation.
2662  */
2663  if (objectKind == REINDEX_OBJECT_SCHEMA)
2664  {
2665  num_keys = 1;
2666  ScanKeyInit(&scan_keys[0],
2667  Anum_pg_class_relnamespace,
2668  BTEqualStrategyNumber, F_OIDEQ,
2669  ObjectIdGetDatum(objectOid));
2670  }
2671  else
2672  num_keys = 0;
2673 
2674  /*
2675  * Scan pg_class to build a list of the relations we need to reindex.
2676  *
2677  * We only consider plain relations and materialized views here (toast
2678  * rels will be processed indirectly by reindex_relation).
2679  */
2680  relationRelation = table_open(RelationRelationId, AccessShareLock);
2681  scan = table_beginscan_catalog(relationRelation, num_keys, scan_keys);
2682  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2683  {
2684  Form_pg_class classtuple = (Form_pg_class) GETSTRUCT(tuple);
2685  Oid relid = classtuple->oid;
2686 
2687  /*
2688  * Only regular tables and matviews can have indexes, so ignore any
2689  * other kind of relation.
2690  *
2691  * It is tempting to also consider partitioned tables here, but that
2692  * has the problem that if the children are in the same schema, they
2693  * would be processed twice. Maybe we could have a separate list of
2694  * partitioned tables, and expand that afterwards into relids,
2695  * ignoring any duplicates.
2696  */
2697  if (classtuple->relkind != RELKIND_RELATION &&
2698  classtuple->relkind != RELKIND_MATVIEW)
2699  continue;
2700 
2701  /* Skip temp tables of other backends; we can't reindex them at all */
2702  if (classtuple->relpersistence == RELPERSISTENCE_TEMP &&
2703  !isTempNamespace(classtuple->relnamespace))
2704  continue;
2705 
2706  /* Check user/system classification, and optionally skip */
2707  if (objectKind == REINDEX_OBJECT_SYSTEM &&
2708  !IsSystemClass(relid, classtuple))
2709  continue;
2710 
2711  /*
2712  * The table can be reindexed if the user is superuser, the table
2713  * owner, or the database/schema owner (but in the latter case, only
2714  * if it's not a shared relation). pg_class_ownercheck includes the
2715  * superuser case, and depending on objectKind we already know that
2716  * the user has permission to run REINDEX on this database or schema
2717  * per the permission checks at the beginning of this routine.
2718  */
2719  if (classtuple->relisshared &&
2720  !pg_class_ownercheck(relid, GetUserId()))
2721  continue;
2722 
2723  /*
2724  * Skip system tables, since index_create() would reject indexing them
2725  * concurrently (and it would likely fail if we tried).
2726  */
2727  if (concurrent &&
2728  IsCatalogRelationOid(relid))
2729  {
2730  if (!concurrent_warning)
2731  ereport(WARNING,
2732  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2733  errmsg("cannot reindex system catalogs concurrently, skipping all")));
2734  concurrent_warning = true;
2735  continue;
2736  }
2737 
2738  /* Save the list of relation OIDs in private context */
2739  old = MemoryContextSwitchTo(private_context);
2740 
2741  /*
2742  * We always want to reindex pg_class first if it's selected to be
2743  * reindexed. This ensures that if there is any corruption in
2744  * pg_class' indexes, they will be fixed before we process any other
2745  * tables. This is critical because reindexing itself will try to
2746  * update pg_class.
2747  */
2748  if (relid == RelationRelationId)
2749  relids = lcons_oid(relid, relids);
2750  else
2751  relids = lappend_oid(relids, relid);
2752 
2753  MemoryContextSwitchTo(old);
2754  }
2755  table_endscan(scan);
2756  table_close(relationRelation, AccessShareLock);
2757 
2758  /* Now reindex each rel in a separate transaction */
2761  foreach(l, relids)
2762  {
2763  Oid relid = lfirst_oid(l);
2764 
2766  /* functions in indexes may want a snapshot set */
2768 
2769  if (concurrent && get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
2770  {
2771  (void) ReindexRelationConcurrently(relid, options);
2772  /* ReindexRelationConcurrently() does the verbose output */
2773  }
2774  else
2775  {
2776  bool result;
2777 
2778  result = reindex_relation(relid,
2782 
2783  if (result && (options & REINDEXOPT_VERBOSE))
2784  ereport(INFO,
2785  (errmsg("table \"%s.%s\" was reindexed",
2787  get_rel_name(relid))));
2788 
2790  }
2791 
2793  }
2795 
2796  MemoryContextDelete(private_context);
2797 }
#define NIL
Definition: pg_list.h:65
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
#define AllocSetContextCreate
Definition: memutils.h:170
Oid get_namespace_oid(const char *nspname, bool missing_ok)
Definition: namespace.c:3043
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
Definition: tableam.c:112
Oid GetUserId(void)
Definition: miscinit.c:450
void CommitTransactionCommand(void)
Definition: xact.c:2947
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:202
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1864
#define REINDEXOPT_REPORT_PROGRESS
Definition: parsenodes.h:3353
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:610
#define INFO
Definition: elog.h:33
void PopActiveSnapshot(void)
Definition: snapmgr.c:814
bool pg_namespace_ownercheck(Oid nsp_oid, Oid roleid)
Definition: aclchk.c:4863
List * lcons_oid(Oid datum, List *list)
Definition: list.c:489
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:306
#define REINDEXOPT_VERBOSE
Definition: parsenodes.h:3352
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:80
MemoryContext PortalContext
Definition: mcxt.c:53
bool IsCatalogRelationOid(Oid relid)
Definition: catalog.c:115
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
static bool ReindexRelationConcurrently(Oid relationOid, int options)
Definition: indexcmds.c:2825
char * get_database_name(Oid dbid)
Definition: dbcommands.c:2155
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1286
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:735
bool isTempNamespace(Oid namespaceId)
Definition: namespace.c:3157
#define AssertArg(condition)
Definition: c.h:747
bool pg_database_ownercheck(Oid db_oid, Oid roleid)
Definition: aclchk.c:5105
#define WARNING
Definition: elog.h:40
Oid MyDatabaseId
Definition: globals.c:85
#define ereport(elevel,...)
Definition: elog.h:144
#define Assert(condition)
Definition: c.h:745
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4687
void StartTransactionCommand(void)
Definition: xact.c:2846
#define REINDEX_REL_CHECK_CONSTRAINTS
Definition: index.h:142
char get_rel_persistence(Oid relid)
Definition: lsyscache.c:1990
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:863
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
int errmsg(const char *fmt,...)
Definition: elog.c:824
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define REINDEX_REL_PROCESS_TOAST
Definition: index.h:140
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
bool reindex_relation(Oid relid, int flags, int options)
Definition: index.c:3646
Definition: pg_list.h:50
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1840
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:192

◆ ReindexPartitionedIndex()

static void ReindexPartitionedIndex ( Relation  parentIdx)
static

Definition at line 3487 of file indexcmds.c.

References ereport, errcode(), errmsg(), and ERROR.

Referenced by ReindexIndex().

3488 {
3489  ereport(ERROR,
3490  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3491  errmsg("REINDEX is not yet implemented for partitioned indexes")));
3492 }
int errcode(int sqlerrcode)
Definition: elog.c:610
#define ERROR
Definition: elog.h:43
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ ReindexRelationConcurrently()

static bool ReindexRelationConcurrently ( Oid  relationOid,
int  options 
)
static

Definition at line 2825 of file indexcmds.c.

References AccessExclusiveLock, add_exact_object_address(), ALLOCSET_SMALL_SIZES, AllocSetContextCreate, Assert, CacheInvalidateRelcacheByRelid(), CHECK_FOR_INTERRUPTS, ChooseRelationName(), ObjectAddress::classId, CommandCounterIncrement(), CommitTransactionCommand(), LockRelId::dbId, DROP_RESTRICT, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, forboth, get_index_isvalid(), get_namespace_name(), get_rel_name(), get_rel_namespace(), get_rel_relkind(), GetTransactionSnapshot(), index_close(), index_concurrently_build(), index_concurrently_create_copy(), index_concurrently_set_dead(), index_concurrently_swap(), index_open(), IndexGetRelation(), INFO, IsCatalogRelationOid(), IsToastNamespace(), lappend(), lappend_oid(), lfirst, lfirst_oid, list_make1_oid, LockRelationIdForSession(), LockInfoData::lockRelId, MemoryContextDelete(), MemoryContextSwitchTo(), new_object_addresses(), NIL, NoLock, OidIsValid, palloc(), PERFORM_DELETION_CONCURRENT_LOCK, PERFORM_DELETION_INTERNAL, performMultipleDeletions(), pg_rusage_init(), pg_rusage_show(), pgstat_progress_end_command(), pgstat_progress_start_command(), pgstat_progress_update_param(), PopActiveSnapshot(), PortalContext, PROGRESS_COMMAND_CREATE_INDEX, PROGRESS_CREATEIDX_ACCESS_METHOD_OID, PROGRESS_CREATEIDX_COMMAND, PROGRESS_CREATEIDX_COMMAND_REINDEX_CONCURRENTLY, PROGRESS_CREATEIDX_INDEX_OID, PROGRESS_CREATEIDX_PHASE, PROGRESS_CREATEIDX_PHASE_WAIT_1, PROGRESS_CREATEIDX_PHASE_WAIT_2, PROGRESS_CREATEIDX_PHASE_WAIT_3, PROGRESS_CREATEIDX_PHASE_WAIT_4, PushActiveSnapshot(), RelationData::rd_index, RelationData::rd_lockInfo, RelationData::rd_rel, RegisterSnapshot(), REINDEXOPT_VERBOSE, RelationGetIndexList(), RelationGetRelid, LockRelId::relId, SET_LOCKTAG_RELATION, ShareLock, ShareUpdateExclusiveLock, StartTransactionCommand(), table_close(), table_open(), UnlockRelationIdForSession(), UnregisterSnapshot(), validate_index(), WaitForLockersMultiple(), WaitForOlderSnapshots(), WARNING, and SnapshotData::xmin.

Referenced by ReindexIndex(), ReindexMultipleTables(), and ReindexTable().

2826 {
2827  List *heapRelationIds = NIL;
2828  List *indexIds = NIL;
2829  List *newIndexIds = NIL;
2830  List *relationLocks = NIL;
2831  List *lockTags = NIL;
2832  ListCell *lc,
2833  *lc2;
2834  MemoryContext private_context;
2835  MemoryContext oldcontext;
2836  char relkind;
2837  char *relationName = NULL;
2838  char *relationNamespace = NULL;
2839  PGRUsage ru0;
2840 
2841  /*
2842  * Create a memory context that will survive forced transaction commits we
2843  * do below. Since it is a child of PortalContext, it will go away
2844  * eventually even if we suffer an error; there's no need for special
2845  * abort cleanup logic.
2846  */
2847  private_context = AllocSetContextCreate(PortalContext,
2848  "ReindexConcurrent",
2850 
2852  {
2853  /* Save data needed by REINDEX VERBOSE in private context */
2854  oldcontext = MemoryContextSwitchTo(private_context);
2855 
2856  relationName = get_rel_name(relationOid);
2857  relationNamespace = get_namespace_name(get_rel_namespace(relationOid));
2858 
2859  pg_rusage_init(&ru0);
2860 
2861  MemoryContextSwitchTo(oldcontext);
2862  }
2863 
2864  relkind = get_rel_relkind(relationOid);
2865 
2866  /*
2867  * Extract the list of indexes that are going to be rebuilt based on the
2868  * relation Oid given by caller.
2869  */
2870  switch (relkind)
2871  {
2872  case RELKIND_RELATION:
2873  case RELKIND_MATVIEW:
2874  case RELKIND_TOASTVALUE:
2875  {
2876  /*
2877  * In the case of a relation, find all its indexes including
2878  * toast indexes.
2879  */
2880  Relation heapRelation;
2881 
2882  /* Save the list of relation OIDs in private context */
2883  oldcontext = MemoryContextSwitchTo(private_context);
2884 
2885  /* Track this relation for session locks */
2886  heapRelationIds = lappend_oid(heapRelationIds, relationOid);
2887 
2888  MemoryContextSwitchTo(oldcontext);
2889 
2890  if (IsCatalogRelationOid(relationOid))
2891  ereport(ERROR,
2892  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2893  errmsg("cannot reindex system catalogs concurrently")));
2894 
2895  /* Open relation to get its indexes */
2896  heapRelation = table_open(relationOid, ShareUpdateExclusiveLock);
2897 
2898  /* Add all the valid indexes of relation to list */
2899  foreach(lc, RelationGetIndexList(heapRelation))
2900  {
2901  Oid cellOid = lfirst_oid(lc);
2902  Relation indexRelation = index_open(cellOid,
2904 
2905  if (!indexRelation->rd_index->indisvalid)
2906  ereport(WARNING,
2907  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2908  errmsg("cannot reindex invalid index \"%s.%s\" concurrently, skipping",
2910  get_rel_name(cellOid))));
2911  else if (indexRelation->rd_index->indisexclusion)
2912  ereport(WARNING,
2913  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2914  errmsg("cannot reindex exclusion constraint index \"%s.%s\" concurrently, skipping",
2916  get_rel_name(cellOid))));
2917  else
2918  {
2919  /* Save the list of relation OIDs in private context */
2920  oldcontext = MemoryContextSwitchTo(private_context);
2921 
2922  indexIds = lappend_oid(indexIds, cellOid);
2923 
2924  MemoryContextSwitchTo(oldcontext);
2925  }
2926 
2927  index_close(indexRelation, NoLock);
2928  }
2929 
2930  /* Also add the toast indexes */
2931  if (OidIsValid(heapRelation->rd_rel->reltoastrelid))
2932  {
2933  Oid toastOid = heapRelation->rd_rel->reltoastrelid;
2934  Relation toastRelation = table_open(toastOid,
2936 
2937  /* Save the list of relation OIDs in private context */
2938  oldcontext = MemoryContextSwitchTo(private_context);
2939 
2940  /* Track this relation for session locks */
2941  heapRelationIds = lappend_oid(heapRelationIds, toastOid);
2942 
2943  MemoryContextSwitchTo(oldcontext);
2944 
2945  foreach(lc2, RelationGetIndexList(toastRelation))
2946  {
2947  Oid cellOid = lfirst_oid(lc2);
2948  Relation indexRelation = index_open(cellOid,
2950 
2951  if (!indexRelation->rd_index->indisvalid)
2952  ereport(WARNING,
2953  (errcode(ERRCODE_INDEX_CORRUPTED),
2954  errmsg("cannot reindex invalid index \"%s.%s\" concurrently, skipping",
2956  get_rel_name(cellOid))));
2957  else
2958  {
2959  /*
2960  * Save the list of relation OIDs in private
2961  * context
2962  */
2963  oldcontext = MemoryContextSwitchTo(private_context);
2964 
2965  indexIds = lappend_oid(indexIds, cellOid);
2966 
2967  MemoryContextSwitchTo(oldcontext);
2968  }
2969 
2970  index_close(indexRelation, NoLock);
2971  }
2972 
2973  table_close(toastRelation, NoLock);
2974  }
2975 
2976  table_close(heapRelation, NoLock);
2977  break;
2978  }
2979  case RELKIND_INDEX:
2980  {
2981  Oid heapId = IndexGetRelation(relationOid, false);
2982 
2983  if (IsCatalogRelationOid(heapId))
2984  ereport(ERROR,
2985  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2986  errmsg("cannot reindex system catalogs concurrently")));
2987 
2988  /*
2989  * Don't allow reindex for an invalid index on TOAST table, as
2990  * if rebuilt it would not be possible to drop it.
2991  */
2992  if (IsToastNamespace(get_rel_namespace(relationOid)) &&
2993  !get_index_isvalid(relationOid))
2994  ereport(ERROR,
2995  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2996  errmsg("cannot reindex invalid index on TOAST table concurrently")));
2997 
2998  /* Save the list of relation OIDs in private context */
2999  oldcontext = MemoryContextSwitchTo(private_context);
3000 
3001  /* Track the heap relation of this index for session locks */
3002  heapRelationIds = list_make1_oid(heapId);
3003 
3004  /*
3005  * Save the list of relation OIDs in private context. Note
3006  * that invalid indexes are allowed here.
3007  */
3008  indexIds = lappend_oid(indexIds, relationOid);
3009 
3010  MemoryContextSwitchTo(oldcontext);
3011  break;
3012  }
3013  case RELKIND_PARTITIONED_TABLE:
3014  /* see reindex_relation() */
3015  ereport(WARNING,
3016  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3017  errmsg("REINDEX of partitioned tables is not yet implemented, skipping \"%s\"",
3018  get_rel_name(relationOid))));
3019  return false;
3020  default:
3021  /* Return error if type of relation is not supported */
3022  ereport(ERROR,
3023  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3024  errmsg("cannot reindex this type of relation concurrently")));
3025  break;
3026  }
3027 
3028  /* Definitely no indexes, so leave */
3029  if (indexIds == NIL)
3030  {
3032  return false;
3033  }
3034 
3035  Assert(heapRelationIds != NIL);
3036 
3037  /*-----
3038  * Now we have all the indexes we want to process in indexIds.
3039  *
3040  * The phases now are:
3041  *
3042  * 1. create new indexes in the catalog
3043  * 2. build new indexes
3044  * 3. let new indexes catch up with tuples inserted in the meantime
3045  * 4. swap index names
3046  * 5. mark old indexes as dead
3047  * 6. drop old indexes
3048  *
3049  * We process each phase for all indexes before moving to the next phase,
3050  * for efficiency.
3051  */
3052 
3053  /*
3054  * Phase 1 of REINDEX CONCURRENTLY
3055  *
3056  * Create a new index with the same properties as the old one, but it is
3057  * only registered in catalogs and will be built later. Then get session
3058  * locks on all involved tables. See analogous code in DefineIndex() for
3059  * more detailed comments.
3060  */
3061 
3062  foreach(lc, indexIds)
3063  {
3064  char *concurrentName;
3065  Oid indexId = lfirst_oid(lc);
3066  Oid newIndexId;
3067  Relation indexRel;
3068  Relation heapRel;
3069  Relation newIndexRel;
3070  LockRelId *lockrelid;
3071 
3072  indexRel = index_open(indexId, ShareUpdateExclusiveLock);
3073  heapRel = table_open(indexRel->rd_index->indrelid,
3075 
3076  /* This function shouldn't be called for temporary relations. */
3077  if (indexRel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
3078  elog(ERROR, "cannot reindex a temporary table concurrently");
3079 
3081  RelationGetRelid(heapRel));
3085  indexId);
3087  indexRel->rd_rel->relam);
3088 
3089  /* Choose a temporary relation name for the new index */
3090  concurrentName = ChooseRelationName(get_rel_name(indexId),
3091  NULL,
3092  "ccnew",
3093  get_rel_namespace(indexRel->rd_index->indrelid),
3094  false);
3095 
3096  /* Create new index definition based on given index */
3097  newIndexId = index_concurrently_create_copy(heapRel,
3098  indexId,
3099  concurrentName);
3100 
3101  /*
3102  * Now open the relation of the new index, a session-level lock is
3103  * also needed on it.
3104  */
3105  newIndexRel = index_open(newIndexId, ShareUpdateExclusiveLock);
3106 
3107  /*
3108  * Save the list of OIDs and locks in private context
3109  */
3110  oldcontext = MemoryContextSwitchTo(private_context);
3111 
3112  newIndexIds = lappend_oid(newIndexIds, newIndexId);
3113 
3114  /*
3115  * Save lockrelid to protect each relation from drop then close
3116  * relations. The lockrelid on parent relation is not taken here to
3117  * avoid multiple locks taken on the same relation, instead we rely on
3118  * parentRelationIds built earlier.
3119  */
3120  lockrelid = palloc(sizeof(*lockrelid));
3121  *lockrelid = indexRel->rd_lockInfo.lockRelId;
3122  relationLocks = lappend(relationLocks, lockrelid);
3123  lockrelid = palloc(sizeof(*lockrelid));
3124  *lockrelid = newIndexRel->rd_lockInfo.lockRelId;
3125  relationLocks = lappend(relationLocks, lockrelid);
3126 
3127  MemoryContextSwitchTo(oldcontext);
3128 
3129  index_close(indexRel, NoLock);
3130  index_close(newIndexRel, NoLock);
3131  table_close(heapRel, NoLock);
3132  }
3133 
3134  /*
3135  * Save the heap lock for following visibility checks with other backends
3136  * might conflict with this session.
3137  */
3138  foreach(lc, heapRelationIds)
3139  {
3141  LockRelId *lockrelid;
3142  LOCKTAG *heaplocktag;
3143 
3144  /* Save the list of locks in private context */
3145  oldcontext = MemoryContextSwitchTo(private_context);
3146 
3147  /* Add lockrelid of heap relation to the list of locked relations */
3148  lockrelid = palloc(sizeof(*lockrelid));
3149  *lockrelid = heapRelation->rd_lockInfo.lockRelId;
3150  relationLocks = lappend(relationLocks, lockrelid);
3151 
3152  heaplocktag = (LOCKTAG *) palloc(sizeof(LOCKTAG));
3153 
3154  /* Save the LOCKTAG for this parent relation for the wait phase */
3155  SET_LOCKTAG_RELATION(*heaplocktag, lockrelid->dbId, lockrelid->relId);
3156  lockTags = lappend(lockTags, heaplocktag);
3157 
3158  MemoryContextSwitchTo(oldcontext);
3159 
3160  /* Close heap relation */
3161  table_close(heapRelation, NoLock);
3162  }
3163 
3164  /* Get a session-level lock on each table. */
3165  foreach(lc, relationLocks)
3166  {
3167  LockRelId *lockrelid = (LockRelId *) lfirst(lc);
3168 
3170  }
3171 
3175 
3176  /*
3177  * Phase 2 of REINDEX CONCURRENTLY
3178  *
3179  * Build the new indexes in a separate transaction for each index to avoid
3180  * having open transactions for an unnecessary long time. But before
3181  * doing that, wait until no running transactions could have the table of
3182  * the index open with the old list of indexes. See "phase 2" in
3183  * DefineIndex() for more details.
3184  */
3185 
3188  WaitForLockersMultiple(lockTags, ShareLock, true);
3190 
3191  forboth(lc, indexIds, lc2, newIndexIds)
3192  {
3193  Relation indexRel;
3194  Oid oldIndexId = lfirst_oid(lc);
3195  Oid newIndexId = lfirst_oid(lc2);
3196  Oid heapId;
3197 
3198  /* Start new transaction for this index's concurrent build */
3200 
3201  /*
3202  * Check for user-requested abort. This is inside a transaction so as
3203  * xact.c does not issue a useless WARNING, and ensures that
3204  * session-level locks are cleaned up on abort.
3205  */
3207 
3208  /* Set ActiveSnapshot since functions in the indexes may need it */
3210 
3211  /*
3212  * Index relation has been closed by previous commit, so reopen it to
3213  * get its information.
3214  */
3215  indexRel = index_open(oldIndexId, ShareUpdateExclusiveLock);
3216  heapId = indexRel->rd_index->indrelid;
3217  index_close(indexRel, NoLock);
3218 
3219  /* Perform concurrent build of new index */
3220  index_concurrently_build(heapId, newIndexId);
3221 
3224  }
3226 
3227  /*
3228  * Phase 3 of REINDEX CONCURRENTLY
3229  *
3230  * During this phase the old indexes catch up with any new tuples that
3231  * were created during the previous phase. See "phase 3" in DefineIndex()
3232  * for more details.
3233  */
3234 
3237  WaitForLockersMultiple(lockTags, ShareLock, true);
3239 
3240  foreach(lc, newIndexIds)
3241  {
3242  Oid newIndexId = lfirst_oid(lc);
3243  Oid heapId;
3244  TransactionId limitXmin;
3245  Snapshot snapshot;
3246 
3248 
3249  /*
3250  * Check for user-requested abort. This is inside a transaction so as
3251  * xact.c does not issue a useless WARNING, and ensures that
3252  * session-level locks are cleaned up on abort.
3253  */
3255 
3256  heapId = IndexGetRelation(newIndexId, false);
3257 
3258  /*
3259  * Take the "reference snapshot" that will be used by validate_index()
3260  * to filter candidate tuples.
3261  */
3263  PushActiveSnapshot(snapshot);
3264 
3265  validate_index(heapId, newIndexId, snapshot);
3266 
3267  /*
3268  * We can now do away with our active snapshot, we still need to save
3269  * the xmin limit to wait for older snapshots.
3270  */
3271  limitXmin = snapshot->xmin;
3272 
3274  UnregisterSnapshot(snapshot);
3275 
3276  /*
3277  * To ensure no deadlocks, we must commit and start yet another
3278  * transaction, and do our wait before any snapshot has been taken in
3279  * it.
3280  */
3283 
3284  /*
3285  * The index is now valid in the sense that it contains all currently
3286  * interesting tuples. But since it might not contain tuples deleted
3287  * just before the reference snap was taken, we have to wait out any
3288  * transactions that might have older snapshots.
3289  */
3292  WaitForOlderSnapshots(limitXmin, true);
3293 
3295  }
3296 
3297  /*
3298  * Phase 4 of REINDEX CONCURRENTLY
3299  *
3300  * Now that the new indexes have been validated, swap each new index with
3301  * its corresponding old index.
3302  *
3303  * We mark the new indexes as valid and the old indexes as not valid at
3304  * the same time to make sure we only get constraint violations from the
3305  * indexes with the correct names.
3306  */
3307 
3309 
3310  forboth(lc, indexIds, lc2, newIndexIds)
3311  {
3312  char *oldName;
3313  Oid oldIndexId = lfirst_oid(lc);
3314  Oid newIndexId = lfirst_oid(lc2);
3315  Oid heapId;
3316 
3317  /*
3318  * Check for user-requested abort. This is inside a transaction so as
3319  * xact.c does not issue a useless WARNING, and ensures that
3320  * session-level locks are cleaned up on abort.
3321  */
3323 
3324  heapId = IndexGetRelation(oldIndexId, false);
3325 
3326  /* Choose a relation name for old index */
3327  oldName = ChooseRelationName(get_rel_name(oldIndexId),
3328  NULL,
3329  "ccold",
3330  get_rel_namespace(heapId),
3331  false);
3332 
3333  /*
3334  * Swap old index with the new one. This also marks the new one as
3335  * valid and the old one as not valid.
3336  */
3337  index_concurrently_swap(newIndexId, oldIndexId, oldName);
3338 
3339  /*
3340  * Invalidate the relcache for the table, so that after this commit
3341  * all sessions will refresh any cached plans that might reference the
3342  * index.
3343  */
3345 
3346  /*
3347  * CCI here so that subsequent iterations see the oldName in the
3348  * catalog and can choose a nonconflicting name for their oldName.
3349  * Otherwise, this could lead to conflicts if a table has two indexes
3350  * whose names are equal for the first NAMEDATALEN-minus-a-few
3351  * characters.
3352  */
3354  }
3355 
3356  /* Commit this transaction and make index swaps visible */
3359 
3360  /*
3361  * Phase 5 of REINDEX CONCURRENTLY
3362  *
3363  * Mark the old indexes as dead. First we must wait until no running
3364  * transaction could be using the index for a query. See also
3365  * index_drop() for more details.
3366  */
3367 
3371 
3372  foreach(lc, indexIds)
3373  {
3374  Oid oldIndexId = lfirst_oid(lc);
3375  Oid heapId;
3376 
3377  /*
3378  * Check for user-requested abort. This is inside a transaction so as
3379  * xact.c does not issue a useless WARNING, and ensures that
3380  * session-level locks are cleaned up on abort.
3381  */
3383 
3384  heapId = IndexGetRelation(oldIndexId, false);
3385  index_concurrently_set_dead(heapId, oldIndexId);
3386  }
3387 
3388  /* Commit this transaction to make the updates visible. */
3391 
3392  /*
3393  * Phase 6 of REINDEX CONCURRENTLY
3394  *
3395  * Drop the old indexes.
3396  */
3397 
3401 
3403 
3404  {
3406 
3407  foreach(lc, indexIds)
3408  {
3409  Oid oldIndexId = lfirst_oid(lc);
3410  ObjectAddress object;
3411 
3412  object.classId = RelationRelationId;
3413  object.objectId = oldIndexId;
3414  object.objectSubId = 0;
3415 
3416  add_exact_object_address(&object, objects);
3417  }
3418 
3419  /*
3420  * Use PERFORM_DELETION_CONCURRENT_LOCK so that index_drop() uses the
3421  * right lock level.
3422  */
3425  }
3426 
3429 
3430  /*
3431  * Finally, release the session-level lock on the table.
3432  */
3433  foreach(lc, relationLocks)
3434  {
3435  LockRelId *lockrelid = (LockRelId *) lfirst(lc);
3436 
3438  }
3439 
3440  /* Start a new transaction to finish process properly */
3442 
3443  /* Log what we did */
3444  if (options & REINDEXOPT_VERBOSE)
3445  {
3446  if (relkind == RELKIND_INDEX)
3447  ereport(INFO,
3448  (errmsg("index \"%s.%s\" was reindexed",
3449  relationNamespace, relationName),
3450  errdetail("%s.",
3451  pg_rusage_show(&ru0))));
3452  else
3453  {
3454  foreach(lc, newIndexIds)
3455  {
3456  Oid indOid = lfirst_oid(lc);
3457 
3458  ereport(INFO,
3459  (errmsg("index \"%s.%s\" was reindexed",
3461  get_rel_name(indOid))));
3462  /* Don't show rusage here, since it's not per index. */
3463  }
3464 
3465  ereport(INFO,
3466  (errmsg("table \"%s.%s\" was reindexed",
3467  relationNamespace, relationName),
3468  errdetail("%s.",
3469  pg_rusage_show(&ru0))));
3470  }
3471  }
3472 
3473  MemoryContextDelete(private_context);
3474 
3476 
3477  return true;
3478 }
#define PROGRESS_CREATEIDX_PHASE_WAIT_3
Definition: progress.h:97
#define NIL
Definition: pg_list.h:65
Oid IndexGetRelation(Oid indexId, bool missing_ok)
Definition: index.c:3384
LockRelId lockRelId
Definition: rel.h:44
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
#define AllocSetContextCreate
Definition: memutils.h:170
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:419
uint32 TransactionId
Definition: c.h:520
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:865
void pgstat_progress_start_command(ProgressCommandType cmdtype, Oid relid)
Definition: pgstat.c:3210
void pgstat_progress_update_param(int index, int64 val)
Definition: pgstat.c:3231
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1915
void CommitTransactionCommand(void)
Definition: xact.c:2947
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:202
Oid dbId
Definition: rel.h:39
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1864
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Definition: lock.h:163
void WaitForLockersMultiple(List *locktags, LOCKMODE lockmode, bool progress)
Definition: lmgr.c:863
int errcode(int sqlerrcode)
Definition: elog.c:610
#define PROGRESS_CREATEIDX_PHASE_WAIT_1
Definition: progress.h:91
#define INFO
Definition: elog.h:33
static void WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
Definition: indexcmds.c:389
void PopActiveSnapshot(void)
Definition: snapmgr.c:814
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2467
char * ChooseRelationName(const char *name1, const char *name2, const char *label, Oid namespaceid, bool isconstraint)
Definition: indexcmds.c:2240
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2412
void index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName)
Definition: index.c:1430
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:195
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:306
#define OidIsValid(objectId)
Definition: c.h:651
#define REINDEXOPT_VERBOSE
Definition: parsenodes.h:3352
#define PROGRESS_CREATEIDX_COMMAND_REINDEX_CONCURRENTLY
Definition: progress.h:111
MemoryContext PortalContext
Definition: mcxt.c:53
bool IsCatalogRelationOid(Oid relid)
Definition: catalog.c:115
void pg_rusage_init(PGRUsage *ru0)
Definition: pg_rusage.c:27
#define PROGRESS_CREATEIDX_PHASE_WAIT_4
Definition: progress.h:98
Form_pg_index rd_index
Definition: rel.h:174
void UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
Definition: lmgr.c:382
#define ERROR
Definition: elog.h:43
#define PROGRESS_CREATEIDX_PHASE_WAIT_2
Definition: progress.h:93
Definition: rel.h:36
void LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
Definition: lmgr.c:369
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition: lock.h:180
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
#define NoLock
Definition: lockdefs.h:34
LockInfoData rd_lockInfo
Definition: rel.h:112
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:735
#define PROGRESS_CREATEIDX_INDEX_OID
Definition: progress.h:80
int errdetail(const char *fmt,...)
Definition: elog.c:957
const char * pg_rusage_show(const PGRUsage *ru0)
Definition: pg_rusage.c:40
void CacheInvalidateRelcacheByRelid(Oid relid)
Definition: inval.c:1337
TransactionId xmin
Definition: snapshot.h:157
Oid index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char *newName)
Definition: index.c:1223
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:907
List * lappend(List *list, void *datum)
Definition: list.c:321
#define WARNING
Definition: elog.h:40
void validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
Definition: index.c:3149
#define PROGRESS_CREATEIDX_PHASE
Definition: progress.h:82
void pgstat_progress_end_command(void)
Definition: pgstat.c:3282
void CommandCounterIncrement(void)
Definition: xact.c:1021
#define list_make1_oid(x1)
Definition: pg_list.h:249
#define ereport(elevel,...)
Definition: elog.h:144
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:190
void StartTransactionCommand(void)
Definition: xact.c:2846
bool get_index_isvalid(Oid index_oid)
Definition: lsyscache.c:3357
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4507
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
#define AccessExclusiveLock
Definition: lockdefs.h:45
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
#define ShareLock
Definition: lockdefs.h:41
#define PERFORM_DELETION_CONCURRENT_LOCK
Definition: dependency.h:139
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:371
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
void index_concurrently_set_dead(Oid heapId, Oid indexId)
Definition: index.c:1720
void index_concurrently_build(Oid heapRelationId, Oid indexRelationId)
Definition: index.c:1382
Definition: pg_list.h:50
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1840
#define RelationGetRelid(relation)
Definition: rel.h:456
#define PROGRESS_CREATEIDX_COMMAND
Definition: progress.h:79
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132
#define lfirst_oid(lc)
Definition: pg_list.h:192
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:134
Oid relId
Definition: rel.h:38
#define PROGRESS_CREATEIDX_ACCESS_METHOD_OID
Definition: progress.h:81

◆ ReindexTable()

Oid ReindexTable ( RangeVar relation,
int  options,
bool  concurrent 
)

Definition at line 2545 of file indexcmds.c.

References ereport, errmsg(), get_rel_persistence(), NOTICE, RangeVarCallbackOwnsTable(), RangeVarGetRelidExtended(), REINDEX_REL_CHECK_CONSTRAINTS, REINDEX_REL_PROCESS_TOAST, reindex_relation(), REINDEXOPT_REPORT_PROGRESS, ReindexRelationConcurrently(), RangeVar::relname, ShareLock, and ShareUpdateExclusiveLock.

Referenced by standard_ProcessUtility().

2546 {
2547  Oid heapOid;
2548  bool result;
2549 
2550  /*
2551  * The lock level used here should match reindex_relation().
2552  *
2553  * If it's a temporary table, we will perform a non-concurrent reindex,
2554  * even if CONCURRENTLY was requested. In that case, reindex_relation()
2555  * will upgrade the lock, but that's OK, because other sessions can't hold
2556  * locks on our temporary table.
2557  */
2558  heapOid = RangeVarGetRelidExtended(relation,
2560  0,
2562 
2563  if (concurrent && get_rel_persistence(heapOid) != RELPERSISTENCE_TEMP)
2564  {
2565  result = ReindexRelationConcurrently(heapOid, options);
2566 
2567  if (!result)
2568  ereport(NOTICE,
2569  (errmsg("table \"%s\" has no indexes that can be reindexed concurrently",
2570  relation->relname)));
2571  }
2572  else
2573  {
2574  result = reindex_relation(heapOid,
2578  if (!result)
2579  ereport(NOTICE,
2580  (errmsg("table \"%s\" has no indexes to reindex",
2581  relation->relname)));
2582  }
2583 
2584  return heapOid;
2585 }
void RangeVarCallbackOwnsTable(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:15412
#define REINDEXOPT_REPORT_PROGRESS
Definition: parsenodes.h:3353
unsigned int Oid
Definition: postgres_ext.h:31
char * relname
Definition: primnodes.h:68
static bool ReindexRelationConcurrently(Oid relationOid, int options)
Definition: indexcmds.c:2825
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:236
#define ereport(elevel,...)
Definition: elog.h:144
#define NOTICE
Definition: elog.h:37
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define REINDEX_REL_CHECK_CONSTRAINTS
Definition: index.h:142
char get_rel_persistence(Oid relid)
Definition: lsyscache.c:1990
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define ShareLock
Definition: lockdefs.h:41
#define REINDEX_REL_PROCESS_TOAST
Definition: index.h:140
bool reindex_relation(Oid relid, int flags, int options)
Definition: index.c:3646

◆ ResolveOpClass()

Oid ResolveOpClass ( List opclass,
Oid  attrType,
const char *  accessMethodName,
Oid  accessMethodId 
)

Definition at line 1960 of file indexcmds.c.

References CLAAMNAMENSP, CLAOID, DeconstructQualifiedName(), ereport, errcode(), errhint(), errmsg(), ERROR, format_type_be(), GetDefaultOpClass(), GETSTRUCT, HeapTupleIsValid, IsBinaryCoercible(), LookupExplicitNamespace(), NameListToString(), NIL, ObjectIdGetDatum, OidIsValid, OpclassnameGetOpcid(), PointerGetDatum, ReleaseSysCache(), SearchSysCache1(), and SearchSysCache3().

Referenced by ComputeIndexAttrs(), and ComputePartitionAttrs().

1962 {
1963  char *schemaname;
1964  char *opcname;
1965  HeapTuple tuple;
1966  Form_pg_opclass opform;
1967  Oid opClassId,
1968  opInputType;
1969 
1970  if (opclass == NIL)
1971  {
1972  /* no operator class specified, so find the default */
1973  opClassId = GetDefaultOpClass(attrType, accessMethodId);
1974  if (!OidIsValid(opClassId))
1975  ereport(ERROR,
1976  (errcode(ERRCODE_UNDEFINED_OBJECT),
1977  errmsg("data type %s has no default operator class for access method \"%s\"",
1978  format_type_be(attrType), accessMethodName),
1979  errhint("You must specify an operator class for the index or define a default operator class for the data type.")));
1980  return opClassId;
1981  }
1982 
1983  /*
1984  * Specific opclass name given, so look up the opclass.
1985  */
1986 
1987  /* deconstruct the name list */
1988  DeconstructQualifiedName(opclass, &schemaname, &opcname);
1989 
1990  if (schemaname)
1991  {
1992  /* Look in specific schema only */
1993  Oid namespaceId;
1994 
1995  namespaceId = LookupExplicitNamespace(schemaname, false);
1996  tuple = SearchSysCache3(CLAAMNAMENSP,
1997  ObjectIdGetDatum(accessMethodId),
1998  PointerGetDatum(opcname),
1999  ObjectIdGetDatum(namespaceId));
2000  }
2001  else
2002  {
2003  /* Unqualified opclass name, so search the search path */
2004  opClassId = OpclassnameGetOpcid(accessMethodId, opcname);
2005  if (!OidIsValid(opClassId))
2006  ereport(ERROR,
2007  (errcode(ERRCODE_UNDEFINED_OBJECT),
2008  errmsg("operator class \"%s\" does not exist for access method \"%s\"",
2009  opcname, accessMethodName)));
2010  tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opClassId));
2011  }
2012 
2013  if (!HeapTupleIsValid(tuple))
2014  ereport(ERROR,
2015  (errcode(ERRCODE_UNDEFINED_OBJECT),
2016  errmsg("operator class \"%s\" does not exist for access method \"%s\"",
2017  NameListToString(opclass), accessMethodName)));
2018 
2019  /*
2020  * Verify that the index operator class accepts this datatype. Note we
2021  * will accept binary compatibility.
2022  */
2023  opform = (Form_pg_opclass) GETSTRUCT(tuple);
2024  opClassId = opform->oid;
2025  opInputType = opform->opcintype;
2026 
2027  if (!IsBinaryCoercible(attrType, opInputType))
2028  ereport(ERROR,
2029  (errcode(ERRCODE_DATATYPE_MISMATCH),
2030  errmsg("operator class \"%s\" does not accept data type %s",
2031  NameListToString(opclass), format_type_be(attrType))));
2032 
2033  ReleaseSysCache(tuple);
2034 
2035  return opClassId;
2036 }
#define NIL
Definition: pg_list.h:65
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:2893
int errhint(const char *fmt,...)
Definition: elog.c:1071
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:2045
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define PointerGetDatum(X)
Definition: postgres.h:556
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
void DeconstructQualifiedName(List *names, char **nspname_p, char **objname_p)
Definition: namespace.c:2809
unsigned int Oid
Definition: postgres_ext.h:31
Oid OpclassnameGetOpcid(Oid amid, const char *opcname)
Definition: namespace.c:1800
#define OidIsValid(objectId)
Definition: c.h:651
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:1138
bool IsBinaryCoercible(Oid srctype, Oid targettype)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
char * NameListToString(List *names)
Definition: namespace.c:3102
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
int errmsg(const char *fmt,...)
Definition: elog.c:824
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83

◆ update_relispartition()

static void update_relispartition ( Oid  relationId,
bool  newval 
)
static

Definition at line 3646 of file indexcmds.c.

References Assert, CatalogTupleUpdate(), elog, ERROR, GETSTRUCT, heap_freetuple(), HeapTupleIsValid, ObjectIdGetDatum, RELOID, RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, table_close(), and table_open().

Referenced by IndexSetParentIndex().

3647 {
3648  HeapTuple tup;
3649  Relation classRel;
3650 
3651  classRel = table_open(RelationRelationId, RowExclusiveLock);
3652  tup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
3653  if (!HeapTupleIsValid(tup))
3654  elog(ERROR, "cache lookup failed for relation %u", relationId);
3655  Assert(((Form_pg_class) GETSTRUCT(tup))->relispartition != newval);
3656  ((Form_pg_class) GETSTRUCT(tup))->relispartition = newval;
3657  CatalogTupleUpdate(classRel, &tup->t_self, tup);
3658  heap_freetuple(tup);
3659  table_close(classRel, RowExclusiveLock);
3660 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:745
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
#define newval
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
#define elog(elevel,...)
Definition: elog.h:214
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39

◆ WaitForOlderSnapshots()

static void WaitForOlderSnapshots ( TransactionId  limitXmin,
bool  progress 
)
static

Definition at line 389 of file indexcmds.c.

References BackendIdGetProc(), GetCurrentVirtualXIDs(), i, pfree(), pgstat_progress_update_param(), PGPROC::pid, PROC_IN_VACUUM, PROC_IS_AUTOVACUUM, PROGRESS_WAITFOR_CURRENT_PID, PROGRESS_WAITFOR_DONE, PROGRESS_WAITFOR_TOTAL, SetInvalidVirtualTransactionId, VirtualTransactionIdEquals, VirtualTransactionIdIsValid, and VirtualXactLock().

Referenced by DefineIndex(), and ReindexRelationConcurrently().

390 {
391  int n_old_snapshots;
392  int i;
393  VirtualTransactionId *old_snapshots;
394 
395  old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false,
397  &n_old_snapshots);
398  if (progress)
400 
401  for (i = 0; i < n_old_snapshots; i++)
402  {
403  if (!VirtualTransactionIdIsValid(old_snapshots[i]))
404  continue; /* found uninteresting in previous cycle */
405 
406  if (i > 0)
407  {
408  /* see if anything's changed ... */
409  VirtualTransactionId *newer_snapshots;
410  int n_newer_snapshots;
411  int j;
412  int k;
413 
414  newer_snapshots = GetCurrentVirtualXIDs(limitXmin,
415  true, false,
417  &n_newer_snapshots);
418  for (j = i; j < n_old_snapshots; j++)
419  {
420  if (!VirtualTransactionIdIsValid(old_snapshots[j]))
421  continue; /* found uninteresting in previous cycle */
422  for (k = 0; k < n_newer_snapshots; k++)
423  {
424  if (VirtualTransactionIdEquals(old_snapshots[j],
425  newer_snapshots[k]))
426  break;
427  }
428  if (k >= n_newer_snapshots) /* not there anymore */
429  SetInvalidVirtualTransactionId(old_snapshots[j]);
430  }
431  pfree(newer_snapshots);
432  }
433 
434  if (VirtualTransactionIdIsValid(old_snapshots[i]))
435  {
436  /* If requested, publish who we're going to wait for. */
437  if (progress)
438  {
439  PGPROC *holder = BackendIdGetProc(old_snapshots[i].backendId);
440 
441  if (holder)
443  holder->pid);
444  }
445  VirtualXactLock(old_snapshots[i], true);
446  }
447 
448  if (progress)
450  }
451 }
VirtualTransactionId * GetCurrentVirtualXIDs(TransactionId limitXmin, bool excludeXmin0, bool allDbs, int excludeVacuum, int *nvxids)
Definition: procarray.c:2490
void pgstat_progress_update_param(int index, int64 val)
Definition: pgstat.c:3231
bool VirtualXactLock(VirtualTransactionId vxid, bool wait)
Definition: lock.c:4462
#define VirtualTransactionIdEquals(vxid1, vxid2)
Definition: lock.h:73
void pfree(void *pointer)
Definition: mcxt.c:1056
#define PROC_IN_VACUUM
Definition: proc.h:54
#define PROGRESS_WAITFOR_CURRENT_PID
Definition: progress.h:116
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:70
int progress
Definition: pgbench.c:234
#define SetInvalidVirtualTransactionId(vxid)
Definition: lock.h:76
#define PROGRESS_WAITFOR_DONE
Definition: progress.h:115
int i
#define PROGRESS_WAITFOR_TOTAL
Definition: progress.h:114
Definition: proc.h:101
int pid
Definition: proc.h:115
#define PROC_IS_AUTOVACUUM
Definition: proc.h:53
PGPROC * BackendIdGetProc(int backendID)
Definition: sinvaladt.c:376