PostgreSQL Source Code  git master
indexcmds.c File Reference
#include "postgres.h"
#include "access/amapi.h"
#include "access/htup_details.h"
#include "access/reloptions.h"
#include "access/sysattr.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/partition.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/tablecmds.h"
#include "commands/tablespace.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/planner.h"
#include "optimizer/var.h"
#include "parser/parse_coerce.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "rewrite/rewriteManip.h"
#include "storage/lmgr.h"
#include "storage/proc.h"
#include "storage/procarray.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/regproc.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
Include dependency graph for indexcmds.c:

Go to the source code of this file.

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 void ReindexPartitionedIndex (Relation parentIdx)
 
bool CheckIndexCompatible (Oid oldId, const char *accessMethodName, List *attributeList, List *exclusionOpNames)
 
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)
 
void ReindexIndex (RangeVar *indexRelation, int options)
 
Oid ReindexTable (RangeVar *relation, int options)
 
void ReindexMultipleTables (const char *objectName, ReindexObjectType objectKind, int options)
 
void IndexSetParentIndex (Relation partitionIdx, Oid parentOid)
 

Function Documentation

◆ CheckIndexCompatible()

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

Definition at line 126 of file indexcmds.c.

References AccessShareLock, IndexAmRoutine::amcanorder, AMNAME, Assert, ComputeIndexAttrs(), CurrentMemoryContext, DatumGetPointer, elog, ereport, errcode(), errmsg(), ERROR, get_opclass_input_type(), GetIndexAmRoutine(), GETSTRUCT, heap_attisnull(), HeapTupleGetOid, HeapTupleIsValid, i, IndexInfo::ii_Am, IndexInfo::ii_AmCache, IndexInfo::ii_Context, IndexInfo::ii_ExclusionOps, IndexInfo::ii_ExclusionProcs, IndexInfo::ii_ExclusionStrats, IndexInfo::ii_Expressions, IndexInfo::ii_ExpressionsState, IndexInfo::ii_NumIndexAttrs, IndexInfo::ii_NumIndexKeyAttrs, IndexInfo::ii_PredicateState, index_close(), INDEX_MAX_KEYS, index_open(), IndexGetRelation(), IndexIsValid, INDEXRELID, list_length(), makeNode, NIL, NoLock, ObjectIdGetDatum, op_input_types(), palloc(), PointerGetDatum, RelationData::rd_att, RelationGetExclusionInfo(), ReleaseSysCache(), SearchSysCache1(), SysCacheGetAttr(), TupleDescAttr, and oidvector::values.

Referenced by TryReuseIndex().

130 {
131  bool isconstraint;
132  Oid *typeObjectId;
133  Oid *collationObjectId;
134  Oid *classObjectId;
135  Oid accessMethodId;
136  Oid relationId;
137  HeapTuple tuple;
138  Form_pg_index indexForm;
139  Form_pg_am accessMethodForm;
140  IndexAmRoutine *amRoutine;
141  bool amcanorder;
142  int16 *coloptions;
143  IndexInfo *indexInfo;
144  int numberOfAttributes;
145  int old_natts;
146  bool isnull;
147  bool ret = true;
148  oidvector *old_indclass;
149  oidvector *old_indcollation;
150  Relation irel;
151  int i;
152  Datum d;
153 
154  /* Caller should already have the relation locked in some way. */
155  relationId = IndexGetRelation(oldId, false);
156 
157  /*
158  * We can pretend isconstraint = false unconditionally. It only serves to
159  * decide the text of an error message that should never happen for us.
160  */
161  isconstraint = false;
162 
163  numberOfAttributes = list_length(attributeList);
164  Assert(numberOfAttributes > 0);
165  Assert(numberOfAttributes <= INDEX_MAX_KEYS);
166 
167  /* look up the access method */
168  tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
169  if (!HeapTupleIsValid(tuple))
170  ereport(ERROR,
171  (errcode(ERRCODE_UNDEFINED_OBJECT),
172  errmsg("access method \"%s\" does not exist",
173  accessMethodName)));
174  accessMethodId = HeapTupleGetOid(tuple);
175  accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
176  amRoutine = GetIndexAmRoutine(accessMethodForm->amhandler);
177  ReleaseSysCache(tuple);
178 
179  amcanorder = amRoutine->amcanorder;
180 
181  /*
182  * Compute the operator classes, collations, and exclusion operators for
183  * the new index, so we can test whether it's compatible with the existing
184  * one. Note that ComputeIndexAttrs might fail here, but that's OK:
185  * DefineIndex would have called this function with the same arguments
186  * later on, and it would have failed then anyway. Our attributeList
187  * contains only key attributes, thus we're filling ii_NumIndexAttrs and
188  * ii_NumIndexKeyAttrs with same value.
189  */
190  indexInfo = makeNode(IndexInfo);
191  indexInfo->ii_NumIndexAttrs = numberOfAttributes;
192  indexInfo->ii_NumIndexKeyAttrs = numberOfAttributes;
193  indexInfo->ii_Expressions = NIL;
194  indexInfo->ii_ExpressionsState = NIL;
195  indexInfo->ii_PredicateState = NULL;
196  indexInfo->ii_ExclusionOps = NULL;
197  indexInfo->ii_ExclusionProcs = NULL;
198  indexInfo->ii_ExclusionStrats = NULL;
199  indexInfo->ii_Am = accessMethodId;
200  indexInfo->ii_AmCache = NULL;
201  indexInfo->ii_Context = CurrentMemoryContext;
202  typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
203  collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
204  classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
205  coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16));
206  ComputeIndexAttrs(indexInfo,
207  typeObjectId, collationObjectId, classObjectId,
208  coloptions, attributeList,
209  exclusionOpNames, relationId,
210  accessMethodName, accessMethodId,
211  amcanorder, isconstraint);
212 
213 
214  /* Get the soon-obsolete pg_index tuple. */
216  if (!HeapTupleIsValid(tuple))
217  elog(ERROR, "cache lookup failed for index %u", oldId);
218  indexForm = (Form_pg_index) GETSTRUCT(tuple);
219 
220  /*
221  * We don't assess expressions or predicates; assume incompatibility.
222  * Also, if the index is invalid for any reason, treat it as incompatible.
223  */
224  if (!(heap_attisnull(tuple, Anum_pg_index_indpred, NULL) &&
225  heap_attisnull(tuple, Anum_pg_index_indexprs, NULL) &&
226  IndexIsValid(indexForm)))
227  {
228  ReleaseSysCache(tuple);
229  return false;
230  }
231 
232  /* Any change in operator class or collation breaks compatibility. */
233  old_natts = indexForm->indnkeyatts;
234  Assert(old_natts == numberOfAttributes);
235 
236  d = SysCacheGetAttr(INDEXRELID, tuple, Anum_pg_index_indcollation, &isnull);
237  Assert(!isnull);
238  old_indcollation = (oidvector *) DatumGetPointer(d);
239 
240  d = SysCacheGetAttr(INDEXRELID, tuple, Anum_pg_index_indclass, &isnull);
241  Assert(!isnull);
242  old_indclass = (oidvector *) DatumGetPointer(d);
243 
244  ret = (memcmp(old_indclass->values, classObjectId,
245  old_natts * sizeof(Oid)) == 0 &&
246  memcmp(old_indcollation->values, collationObjectId,
247  old_natts * sizeof(Oid)) == 0);
248 
249  ReleaseSysCache(tuple);
250 
251  if (!ret)
252  return false;
253 
254  /* For polymorphic opcintype, column type changes break compatibility. */
255  irel = index_open(oldId, AccessShareLock); /* caller probably has a lock */
256  for (i = 0; i < old_natts; i++)
257  {
258  if (IsPolymorphicType(get_opclass_input_type(classObjectId[i])) &&
259  TupleDescAttr(irel->rd_att, i)->atttypid != typeObjectId[i])
260  {
261  ret = false;
262  break;
263  }
264  }
265 
266  /* Any change in exclusion operator selections breaks compatibility. */
267  if (ret && indexInfo->ii_ExclusionOps != NULL)
268  {
269  Oid *old_operators,
270  *old_procs;
271  uint16 *old_strats;
272 
273  RelationGetExclusionInfo(irel, &old_operators, &old_procs, &old_strats);
274  ret = memcmp(old_operators, indexInfo->ii_ExclusionOps,
275  old_natts * sizeof(Oid)) == 0;
276 
277  /* Require an exact input type match for polymorphic operators. */
278  if (ret)
279  {
280  for (i = 0; i < old_natts && ret; i++)
281  {
282  Oid left,
283  right;
284 
285  op_input_types(indexInfo->ii_ExclusionOps[i], &left, &right);
286  if ((IsPolymorphicType(left) || IsPolymorphicType(right)) &&
287  TupleDescAttr(irel->rd_att, i)->atttypid != typeObjectId[i])
288  {
289  ret = false;
290  break;
291  }
292  }
293  }
294  }
295 
296  index_close(irel, NoLock);
297  return ret;
298 }
signed short int16
Definition: c.h:312
#define NIL
Definition: pg_list.h:69
Definition: c.h:555
MemoryContext ii_Context
Definition: execnodes.h:171
Oid IndexGetRelation(Oid indexId, bool missing_ok)
Definition: index.c:3591
void RelationGetExclusionInfo(Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
Definition: relcache.c:5000
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
#define IndexIsValid(indexForm)
Definition: pg_index.h:85
#define PointerGetDatum(X)
Definition: postgres.h:539
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
ExprState * ii_PredicateState
Definition: execnodes.h:157
#define AccessShareLock
Definition: lockdefs.h:36
Oid * ii_ExclusionProcs
Definition: execnodes.h:159
int errcode(int sqlerrcode)
Definition: elog.c:575
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:397
unsigned int Oid
Definition: postgres_ext.h:31
List * ii_ExpressionsState
Definition: execnodes.h:155
unsigned short uint16
Definition: c.h:324
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
int ii_NumIndexKeyAttrs
Definition: execnodes.h:152
IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition: amapi.c:33
#define NoLock
Definition: lockdefs.h:34
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:563
void op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
Definition: lsyscache.c:1152
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define ereport(elevel, rest)
Definition: elog.h:122
void * ii_AmCache
Definition: execnodes.h:170
FormData_pg_index * Form_pg_index
Definition: pg_index.h:66
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
uintptr_t Datum
Definition: postgres.h:365
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
int ii_NumIndexAttrs
Definition: execnodes.h:151
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1368
TupleDesc rd_att
Definition: rel.h:85
#define makeNode(_type_)
Definition: nodes.h:565
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
List * ii_Expressions
Definition: execnodes.h:154
#define Assert(condition)
Definition: c.h:699
#define INDEX_MAX_KEYS
static int list_length(const List *l)
Definition: pg_list.h:89
bool amcanorder
Definition: amapi.h:172
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
#define DatumGetPointer(X)
Definition: postgres.h:532
Oid * ii_ExclusionOps
Definition: execnodes.h:158
FormData_pg_am * Form_pg_am
Definition: pg_am.h:46
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:797
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:1379
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:712
uint16 * ii_ExclusionStrats
Definition: execnodes.h:160
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:150
Oid get_opclass_input_type(Oid opclass)
Definition: lsyscache.c:1054
Oid ii_Am
Definition: execnodes.h:169

◆ CheckMutability()

static bool CheckMutability ( Expr expr)
static

Definition at line 1322 of file indexcmds.c.

References contain_mutable_functions(), and expression_planner().

Referenced by CheckPredicate(), and ComputeIndexAttrs().

1323 {
1324  /*
1325  * First run the expression through the planner. This has a couple of
1326  * important consequences. First, function default arguments will get
1327  * inserted, which may affect volatility (consider "default now()").
1328  * Second, inline-able functions will get inlined, which may allow us to
1329  * conclude that the function is really less volatile than it's marked. As
1330  * an example, polymorphic functions must be marked with the most volatile
1331  * behavior that they have for any input type, but once we inline the
1332  * function we may be able to conclude that it's not so volatile for the
1333  * particular input type we're dealing with.
1334  *
1335  * We assume here that expression_planner() won't scribble on its input.
1336  */
1337  expr = expression_planner(expr);
1338 
1339  /* Now we can search for non-immutable functions */
1340  return contain_mutable_functions((Node *) expr);
1341 }
Expr * expression_planner(Expr *expr)
Definition: planner.c:5888
Definition: nodes.h:517
bool contain_mutable_functions(Node *clause)
Definition: clauses.c:879

◆ CheckPredicate()

static void CheckPredicate ( Expr predicate)
static

Definition at line 1356 of file indexcmds.c.

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

Referenced by DefineIndex().

1357 {
1358  /*
1359  * transformExpr() should have already rejected subqueries, aggregates,
1360  * and window functions, based on the EXPR_KIND_ for a predicate.
1361  */
1362 
1363  /*
1364  * A predicate using mutable functions is probably wrong, for the same
1365  * reasons that we don't allow an index expression to use one.
1366  */
1367  if (CheckMutability(predicate))
1368  ereport(ERROR,
1369  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1370  errmsg("functions in index predicate must be marked IMMUTABLE")));
1371 }
static bool CheckMutability(Expr *expr)
Definition: indexcmds.c:1322
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ ChooseIndexColumnNames()

static List * ChooseIndexColumnNames ( List indexElems)
static

Definition at line 2101 of file indexcmds.c.

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

Referenced by DefineIndex().

2102 {
2103  List *result = NIL;
2104  ListCell *lc;
2105 
2106  foreach(lc, indexElems)
2107  {
2108  IndexElem *ielem = (IndexElem *) lfirst(lc);
2109  const char *origname;
2110  const char *curname;
2111  int i;
2112  char buf[NAMEDATALEN];
2113 
2114  /* Get the preliminary name from the IndexElem */
2115  if (ielem->indexcolname)
2116  origname = ielem->indexcolname; /* caller-specified name */
2117  else if (ielem->name)
2118  origname = ielem->name; /* simple column reference */
2119  else
2120  origname = "expr"; /* default name for expression */
2121 
2122  /* If it conflicts with any previous column, tweak it */
2123  curname = origname;
2124  for (i = 1;; i++)
2125  {
2126  ListCell *lc2;
2127  char nbuf[32];
2128  int nlen;
2129 
2130  foreach(lc2, result)
2131  {
2132  if (strcmp(curname, (char *) lfirst(lc2)) == 0)
2133  break;
2134  }
2135  if (lc2 == NULL)
2136  break; /* found nonconflicting name */
2137 
2138  sprintf(nbuf, "%d", i);
2139 
2140  /* Ensure generated names are shorter than NAMEDATALEN */
2141  nlen = pg_mbcliplen(origname, strlen(origname),
2142  NAMEDATALEN - 1 - strlen(nbuf));
2143  memcpy(buf, origname, nlen);
2144  strcpy(buf + nlen, nbuf);
2145  curname = buf;
2146  }
2147 
2148  /* And attach to the result list */
2149  result = lappend(result, pstrdup(curname));
2150  }
2151  return result;
2152 }
#define NIL
Definition: pg_list.h:69
char * pstrdup(const char *in)
Definition: mcxt.c:1161
#define NAMEDATALEN
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition: mbutils.c:820
static char * buf
Definition: pg_test_fsync.c:67
char * indexcolname
Definition: parsenodes.h:701
List * lappend(List *list, void *datum)
Definition: list.c:128
#define lfirst(lc)
Definition: pg_list.h:106
char * name
Definition: parsenodes.h:699
int i
Definition: pg_list.h:45

◆ ChooseIndexName()

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

Definition at line 2017 of file indexcmds.c.

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

Referenced by DefineIndex().

2020 {
2021  char *indexname;
2022 
2023  if (primary)
2024  {
2025  /* the primary key's name does not depend on the specific column(s) */
2026  indexname = ChooseRelationName(tabname,
2027  NULL,
2028  "pkey",
2029  namespaceId);
2030  }
2031  else if (exclusionOpNames != NIL)
2032  {
2033  indexname = ChooseRelationName(tabname,
2034  ChooseIndexNameAddition(colnames),
2035  "excl",
2036  namespaceId);
2037  }
2038  else if (isconstraint)
2039  {
2040  indexname = ChooseRelationName(tabname,
2041  ChooseIndexNameAddition(colnames),
2042  "key",
2043  namespaceId);
2044  }
2045  else
2046  {
2047  indexname = ChooseRelationName(tabname,
2048  ChooseIndexNameAddition(colnames),
2049  "idx",
2050  namespaceId);
2051  }
2052 
2053  return indexname;
2054 }
#define NIL
Definition: pg_list.h:69
static char * ChooseIndexNameAddition(List *colnames)
Definition: indexcmds.c:2067
char * ChooseRelationName(const char *name1, const char *name2, const char *label, Oid namespaceid)
Definition: indexcmds.c:1986

◆ ChooseIndexNameAddition()

static char * ChooseIndexNameAddition ( List colnames)
static

Definition at line 2067 of file indexcmds.c.

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

Referenced by ChooseIndexName().

2068 {
2069  char buf[NAMEDATALEN * 2];
2070  int buflen = 0;
2071  ListCell *lc;
2072 
2073  buf[0] = '\0';
2074  foreach(lc, colnames)
2075  {
2076  const char *name = (const char *) lfirst(lc);
2077 
2078  if (buflen > 0)
2079  buf[buflen++] = '_'; /* insert _ between names */
2080 
2081  /*
2082  * At this point we have buflen <= NAMEDATALEN. name should be less
2083  * than NAMEDATALEN already, but use strlcpy for paranoia.
2084  */
2085  strlcpy(buf + buflen, name, NAMEDATALEN);
2086  buflen += strlen(buf + buflen);
2087  if (buflen >= NAMEDATALEN)
2088  break;
2089  }
2090  return pstrdup(buf);
2091 }
char * pstrdup(const char *in)
Definition: mcxt.c:1161
#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:106
const char * name
Definition: encode.c:521

◆ ChooseRelationName()

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

Definition at line 1986 of file indexcmds.c.

References get_relname_relid(), makeObjectName(), NAMEDATALEN, OidIsValid, pfree(), snprintf(), and StrNCpy.

Referenced by ChooseIndexName(), and generateSerialExtraStmts().

1988 {
1989  int pass = 0;
1990  char *relname = NULL;
1991  char modlabel[NAMEDATALEN];
1992 
1993  /* try the unmodified label first */
1994  StrNCpy(modlabel, label, sizeof(modlabel));
1995 
1996  for (;;)
1997  {
1998  relname = makeObjectName(name1, name2, modlabel);
1999 
2000  if (!OidIsValid(get_relname_relid(relname, namespaceid)))
2001  break;
2002 
2003  /* found a conflict, so try a new name component */
2004  pfree(relname);
2005  snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
2006  }
2007 
2008  return relname;
2009 }
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define OidIsValid(objectId)
Definition: c.h:605
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition: indexcmds.c:1906
#define NAMEDATALEN
void pfree(void *pointer)
Definition: mcxt.c:1031
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1687
static char * label
Definition: pg_basebackup.c:84
#define StrNCpy(dst, src, len)
Definition: c.h:881

◆ 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 1379 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_NumIndexKeyAttrs, InvalidAttrNumber, InvalidOid, IsA, lappend(), lfirst, list_head(), list_length(), lnext, IndexElem::name, NameStr, IndexElem::nulls_ordering, ObjectIdGetDatum, OidIsValid, IndexElem::opclass, OPFAMILYOID, IndexElem::ordering, palloc(), ReleaseSysCache(), ResolveOpClass(), SearchSysCache1(), SearchSysCacheAttName(), SORTBY_DEFAULT, SORTBY_DESC, SORTBY_NULLS_DEFAULT, SORTBY_NULLS_FIRST, and type_is_collatable().

Referenced by CheckIndexCompatible(), and DefineIndex().

1391 {
1392  ListCell *nextExclOp;
1393  ListCell *lc;
1394  int attn;
1395  int nkeycols = indexInfo->ii_NumIndexKeyAttrs;
1396 
1397  /* Allocate space for exclusion operator info, if needed */
1398  if (exclusionOpNames)
1399  {
1400  Assert(list_length(exclusionOpNames) == nkeycols);
1401  indexInfo->ii_ExclusionOps = (Oid *) palloc(sizeof(Oid) * nkeycols);
1402  indexInfo->ii_ExclusionProcs = (Oid *) palloc(sizeof(Oid) * nkeycols);
1403  indexInfo->ii_ExclusionStrats = (uint16 *) palloc(sizeof(uint16) * nkeycols);
1404  nextExclOp = list_head(exclusionOpNames);
1405  }
1406  else
1407  nextExclOp = NULL;
1408 
1409  /*
1410  * process attributeList
1411  */
1412  attn = 0;
1413  foreach(lc, attList)
1414  {
1415  IndexElem *attribute = (IndexElem *) lfirst(lc);
1416  Oid atttype;
1417  Oid attcollation;
1418 
1419  /*
1420  * Process the column-or-expression to be indexed.
1421  */
1422  if (attribute->name != NULL)
1423  {
1424  /* Simple index attribute */
1425  HeapTuple atttuple;
1426  Form_pg_attribute attform;
1427 
1428  Assert(attribute->expr == NULL);
1429  atttuple = SearchSysCacheAttName(relId, attribute->name);
1430  if (!HeapTupleIsValid(atttuple))
1431  {
1432  /* difference in error message spellings is historical */
1433  if (isconstraint)
1434  ereport(ERROR,
1435  (errcode(ERRCODE_UNDEFINED_COLUMN),
1436  errmsg("column \"%s\" named in key does not exist",
1437  attribute->name)));
1438  else
1439  ereport(ERROR,
1440  (errcode(ERRCODE_UNDEFINED_COLUMN),
1441  errmsg("column \"%s\" does not exist",
1442  attribute->name)));
1443  }
1444  attform = (Form_pg_attribute) GETSTRUCT(atttuple);
1445  indexInfo->ii_IndexAttrNumbers[attn] = attform->attnum;
1446  atttype = attform->atttypid;
1447  attcollation = attform->attcollation;
1448  ReleaseSysCache(atttuple);
1449  }
1450  else
1451  {
1452  /* Index expression */
1453  Node *expr = attribute->expr;
1454 
1455  Assert(expr != NULL);
1456 
1457  if (attn >= nkeycols)
1458  ereport(ERROR,
1459  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1460  errmsg("expressions are not supported in included columns")));
1461  atttype = exprType(expr);
1462  attcollation = exprCollation(expr);
1463 
1464  /*
1465  * Strip any top-level COLLATE clause. This ensures that we treat
1466  * "x COLLATE y" and "(x COLLATE y)" alike.
1467  */
1468  while (IsA(expr, CollateExpr))
1469  expr = (Node *) ((CollateExpr *) expr)->arg;
1470 
1471  if (IsA(expr, Var) &&
1472  ((Var *) expr)->varattno != InvalidAttrNumber)
1473  {
1474  /*
1475  * User wrote "(column)" or "(column COLLATE something)".
1476  * Treat it like simple attribute anyway.
1477  */
1478  indexInfo->ii_IndexAttrNumbers[attn] = ((Var *) expr)->varattno;
1479  }
1480  else
1481  {
1482  indexInfo->ii_IndexAttrNumbers[attn] = 0; /* marks expression */
1483  indexInfo->ii_Expressions = lappend(indexInfo->ii_Expressions,
1484  expr);
1485 
1486  /*
1487  * transformExpr() should have already rejected subqueries,
1488  * aggregates, and window functions, based on the EXPR_KIND_
1489  * for an index expression.
1490  */
1491 
1492  /*
1493  * An expression using mutable functions is probably wrong,
1494  * since if you aren't going to get the same result for the
1495  * same data every time, it's not clear what the index entries
1496  * mean at all.
1497  */
1498  if (CheckMutability((Expr *) expr))
1499  ereport(ERROR,
1500  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1501  errmsg("functions in index expression must be marked IMMUTABLE")));
1502  }
1503  }
1504 
1505  typeOidP[attn] = atttype;
1506 
1507  /*
1508  * Included columns have no collation, no opclass and no ordering options.
1509  */
1510  if (attn >= nkeycols)
1511  {
1512  if (attribute->collation)
1513  ereport(ERROR,
1514  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1515  errmsg("including column does not support a collation")));
1516  if (attribute->opclass)
1517  ereport(ERROR,
1518  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1519  errmsg("including column does not support an operator class")));
1520  if (attribute->ordering != SORTBY_DEFAULT)
1521  ereport(ERROR,
1522  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1523  errmsg("including column does not support ASC/DESC options")));
1524  if (attribute->nulls_ordering != SORTBY_NULLS_DEFAULT)
1525  ereport(ERROR,
1526  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1527  errmsg("including column does not support NULLS FIRST/LAST options")));
1528 
1529  classOidP[attn] = InvalidOid;
1530  colOptionP[attn] = 0;
1531  collationOidP[attn] = InvalidOid;
1532  attn++;
1533 
1534  continue;
1535  }
1536 
1537  /*
1538  * Apply collation override if any
1539  */
1540  if (attribute->collation)
1541  attcollation = get_collation_oid(attribute->collation, false);
1542 
1543  /*
1544  * Check we have a collation iff it's a collatable type. The only
1545  * expected failures here are (1) COLLATE applied to a noncollatable
1546  * type, or (2) index expression had an unresolved collation. But we
1547  * might as well code this to be a complete consistency check.
1548  */
1549  if (type_is_collatable(atttype))
1550  {
1551  if (!OidIsValid(attcollation))
1552  ereport(ERROR,
1553  (errcode(ERRCODE_INDETERMINATE_COLLATION),
1554  errmsg("could not determine which collation to use for index expression"),
1555  errhint("Use the COLLATE clause to set the collation explicitly.")));
1556  }
1557  else
1558  {
1559  if (OidIsValid(attcollation))
1560  ereport(ERROR,
1561  (errcode(ERRCODE_DATATYPE_MISMATCH),
1562  errmsg("collations are not supported by type %s",
1563  format_type_be(atttype))));
1564  }
1565 
1566  collationOidP[attn] = attcollation;
1567 
1568  /*
1569  * Identify the opclass to use.
1570  */
1571  classOidP[attn] = ResolveOpClass(attribute->opclass,
1572  atttype,
1573  accessMethodName,
1574  accessMethodId);
1575 
1576  /*
1577  * Identify the exclusion operator, if any.
1578  */
1579  if (nextExclOp)
1580  {
1581  List *opname = (List *) lfirst(nextExclOp);
1582  Oid opid;
1583  Oid opfamily;
1584  int strat;
1585 
1586  /*
1587  * Find the operator --- it must accept the column datatype
1588  * without runtime coercion (but binary compatibility is OK)
1589  */
1590  opid = compatible_oper_opid(opname, atttype, atttype, false);
1591 
1592  /*
1593  * Only allow commutative operators to be used in exclusion
1594  * constraints. If X conflicts with Y, but Y does not conflict
1595  * with X, bad things will happen.
1596  */
1597  if (get_commutator(opid) != opid)
1598  ereport(ERROR,
1599  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1600  errmsg("operator %s is not commutative",
1601  format_operator(opid)),
1602  errdetail("Only commutative operators can be used in exclusion constraints.")));
1603 
1604  /*
1605  * Operator must be a member of the right opfamily, too
1606  */
1607  opfamily = get_opclass_family(classOidP[attn]);
1608  strat = get_op_opfamily_strategy(opid, opfamily);
1609  if (strat == 0)
1610  {
1611  HeapTuple opftuple;
1612  Form_pg_opfamily opfform;
1613 
1614  /*
1615  * attribute->opclass might not explicitly name the opfamily,
1616  * so fetch the name of the selected opfamily for use in the
1617  * error message.
1618  */
1619  opftuple = SearchSysCache1(OPFAMILYOID,
1620  ObjectIdGetDatum(opfamily));
1621  if (!HeapTupleIsValid(opftuple))
1622  elog(ERROR, "cache lookup failed for opfamily %u",
1623  opfamily);
1624  opfform = (Form_pg_opfamily) GETSTRUCT(opftuple);
1625 
1626  ereport(ERROR,
1627  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1628  errmsg("operator %s is not a member of operator family \"%s\"",
1629  format_operator(opid),
1630  NameStr(opfform->opfname)),
1631  errdetail("The exclusion operator must be related to the index operator class for the constraint.")));
1632  }
1633 
1634  indexInfo->ii_ExclusionOps[attn] = opid;
1635  indexInfo->ii_ExclusionProcs[attn] = get_opcode(opid);
1636  indexInfo->ii_ExclusionStrats[attn] = strat;
1637  nextExclOp = lnext(nextExclOp);
1638  }
1639 
1640  /*
1641  * Set up the per-column options (indoption field). For now, this is
1642  * zero for any un-ordered index, while ordered indexes have DESC and
1643  * NULLS FIRST/LAST options.
1644  */
1645  colOptionP[attn] = 0;
1646  if (amcanorder)
1647  {
1648  /* default ordering is ASC */
1649  if (attribute->ordering == SORTBY_DESC)
1650  colOptionP[attn] |= INDOPTION_DESC;
1651  /* default null ordering is LAST for ASC, FIRST for DESC */
1652  if (attribute->nulls_ordering == SORTBY_NULLS_DEFAULT)
1653  {
1654  if (attribute->ordering == SORTBY_DESC)
1655  colOptionP[attn] |= INDOPTION_NULLS_FIRST;
1656  }
1657  else if (attribute->nulls_ordering == SORTBY_NULLS_FIRST)
1658  colOptionP[attn] |= INDOPTION_NULLS_FIRST;
1659  }
1660  else
1661  {
1662  /* index AM does not support ordering */
1663  if (attribute->ordering != SORTBY_DEFAULT)
1664  ereport(ERROR,
1665  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1666  errmsg("access method \"%s\" does not support ASC/DESC options",
1667  accessMethodName)));
1668  if (attribute->nulls_ordering != SORTBY_NULLS_DEFAULT)
1669  ereport(ERROR,
1670  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1671  errmsg("access method \"%s\" does not support NULLS FIRST/LAST options",
1672  accessMethodName)));
1673  }
1674 
1675  attn++;
1676  }
1677 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
static bool CheckMutability(Expr *expr)
Definition: indexcmds.c:1322
Oid get_commutator(Oid opno)
Definition: lsyscache.c:1298
int errhint(const char *fmt,...)
Definition: elog.c:987
SortByDir ordering
Definition: parsenodes.h:704
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
Definition: nodes.h:517
Oid * ii_ExclusionProcs
Definition: execnodes.h:159
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:328
char * format_operator(Oid operator_oid)
Definition: regproc.c:820
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:164
#define OidIsValid(objectId)
Definition: c.h:605
Node * expr
Definition: parsenodes.h:700
unsigned short uint16
Definition: c.h:324
SortByNulls nulls_ordering
Definition: parsenodes.h:705
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
int ii_NumIndexKeyAttrs
Definition: execnodes.h:152
Oid attcollation
Definition: pg_attribute.h:161
Oid ResolveOpClass(List *opclass, Oid attrType, const char *accessMethodName, Oid accessMethodId)
Definition: indexcmds.c:1686
int errdetail(const char *fmt,...)
Definition: elog.c:873
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
#define lnext(lc)
Definition: pg_list.h:105
#define ereport(elevel, rest)
Definition: elog.h:122
List * lappend(List *list, void *datum)
Definition: list.c:128
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:49
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1079
List * opclass
Definition: parsenodes.h:703
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
List * ii_Expressions
Definition: execnodes.h:154
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
static int list_length(const List *l)
Definition: pg_list.h:89
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:720
char * name
Definition: parsenodes.h:699
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition: syscache.c:1248
Oid get_opclass_family(Oid opclass)
Definition: lsyscache.c:1032
#define InvalidAttrNumber
Definition: attnum.h:23
int get_op_opfamily_strategy(Oid opno, Oid opfamily)
Definition: lsyscache.c:80
Oid * ii_ExclusionOps
Definition: execnodes.h:158
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:797
Oid compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError)
Definition: parse_oper.c:494
#define NameStr(name)
Definition: c.h:576
void * arg
List * collation
Definition: parsenodes.h:702
#define elog
Definition: elog.h:219
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition: execnodes.h:153
uint16 * ii_ExclusionStrats
Definition: execnodes.h:160
bool type_is_collatable(Oid typid)
Definition: lsyscache.c:2824
Definition: pg_list.h:45
Oid get_collation_oid(List *name, bool missing_ok)
Definition: namespace.c:3512

◆ 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 325 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, bms_is_member(), BuildIndexInfo(), CacheInvalidateRelcacheByRelid(), CatalogTupleUpdate(), CheckPredicate(), CheckTableNotInUse(), ChooseIndexColumnNames(), ChooseIndexName(), CommitTransactionCommand(), CompareIndexInfo(), ComputeIndexAttrs(), IndexStmt::concurrent, ConstraintSetParentConstraint(), convert_tuples_by_name_map(), copyObject, CreateComments(), CreateTupleDescCopy(), CurrentMemoryContext, LockRelId::dbId, DEBUG1, IndexStmt::deferrable, DefineIndex(), elog, ereport, errcode(), errdetail(), errmsg(), ERROR, IndexStmt::excludeOpNames, FirstLowInvalidHeapAttributeNumber, get_namespace_name(), get_opclass_family(), get_relation_idx_constraint_oid(), get_tablespace_name(), get_tablespace_oid(), GetCurrentVirtualXIDs(), GetDefaultTablespace(), GetIndexAmRoutine(), GETSTRUCT, gettext_noop, GetTransactionSnapshot(), GetUserId(), has_superclass(), heap_close, heap_copytuple(), heap_freetuple(), heap_open(), heap_openrv(), HeapTupleGetOid, HeapTupleIsValid, i, IndexStmt::idxcomment, IndexStmt::idxname, IndexStmt::if_not_exists, IndexInfo::ii_Am, IndexInfo::ii_AmCache, IndexInfo::ii_BrokenHotChain, IndexInfo::ii_Concurrent, IndexInfo::ii_Context, IndexInfo::ii_ExclusionOps, IndexInfo::ii_ExclusionProcs, IndexInfo::ii_ExclusionStrats, IndexInfo::ii_Expressions, IndexInfo::ii_ExpressionsState, IndexInfo::ii_IndexAttrNumbers, IndexInfo::ii_NumIndexAttrs, IndexInfo::ii_NumIndexKeyAttrs, IndexInfo::ii_ParallelWorkers, IndexInfo::ii_Predicate, IndexInfo::ii_PredicateState, IndexInfo::ii_ReadyForInserts, IndexInfo::ii_Unique, index_build(), index_check_primary_key(), index_close(), 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_READY, INDEX_CREATE_SET_VALID, INDEX_CREATE_SKIP_BUILD, INDEX_MAX_KEYS, index_open(), index_reloptions(), index_set_state_flags(), IndexStmt::indexIncludingParams, IndexIsValid, IndexStmt::indexParams, INDEXRELID, IndexSetParentIndex(), RangeVar::inh, IndexStmt::initdeferred, InvalidOid, InvalidTransactionId, IsBootstrapProcessingMode, IndexStmt::isconstraint, lfirst_oid, list_concat(), list_copy(), list_free(), list_intersection(), list_length(), LockRelationIdForSession(), LockInfoData::lockRelId, make_ands_implicit(), makeNode, map_variable_attnos(), MyDatabaseTableSpace, MyPgXact, NameStr, tupleDesc::natts, NIL, NoLock, NOTICE, PartitionDescData::nparts, OBJECT_SCHEMA, OBJECT_TABLESPACE, ObjectAddressSet, ObjectIdAttributeNumber, ObjectIdGetDatum, OidIsValid, PartitionDescData::oids, IndexStmt::oldNode, IndexStmt::options, palloc(), PartitionKeyData::partattrs, PartitionKeyData::partnatts, pfree(), pg_namespace_aclcheck(), pg_tablespace_aclcheck(), PointerGetDatum, PopActiveSnapshot(), IndexStmt::primary, PROC_IN_VACUUM, PROC_IS_AUTOVACUUM, pull_varattnos(), PushActiveSnapshot(), RelationData::rd_indcollation, RelationData::rd_index, RelationData::rd_lockInfo, RelationData::rd_opfamily, RelationData::rd_partkey, RelationData::rd_rel, RegisterSnapshot(), IndexStmt::relation, RELATION_IS_OTHER_TEMP, RelationGetDescr, RelationGetIndexList(), RelationGetNamespace, RelationGetPartitionDesc, RelationGetRelationName, RelationGetRelid, IndexStmt::relationId, ReleaseSysCache(), LockRelId::relId, RowExclusiveLock, SearchSysCache1(), SET_LOCKTAG_RELATION, SetInvalidVirtualTransactionId, ShareLock, ShareUpdateExclusiveLock, StartTransactionCommand(), HeapTupleData::t_self, IndexStmt::tableSpace, transformRelOptions(), TupleDescAttr, IndexStmt::unique, UnlockRelationIdForSession(), UnregisterSnapshot(), validate_index(), VirtualTransactionIdEquals, VirtualTransactionIdIsValid, VirtualXactLock(), WaitForLockers(), IndexStmt::whereClause, SnapshotData::xmin, and PGXACT::xmin.

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

335 {
336  char *indexRelationName;
337  char *accessMethodName;
338  Oid *typeObjectId;
339  Oid *collationObjectId;
340  Oid *classObjectId;
341  Oid accessMethodId;
342  Oid namespaceId;
343  Oid tablespaceId;
344  Oid createdConstraintId = InvalidOid;
345  List *indexColNames;
346  List *allIndexParams;
347  Relation rel;
348  Relation indexRelation;
349  HeapTuple tuple;
350  Form_pg_am accessMethodForm;
351  IndexAmRoutine *amRoutine;
352  bool amcanorder;
353  amoptions_function amoptions;
354  bool partitioned;
355  Datum reloptions;
356  int16 *coloptions;
357  IndexInfo *indexInfo;
358  bits16 flags;
359  bits16 constr_flags;
360  int numberOfAttributes;
361  int numberOfKeyAttributes;
362  TransactionId limitXmin;
363  VirtualTransactionId *old_snapshots;
364  ObjectAddress address;
365  int n_old_snapshots;
366  LockRelId heaprelid;
367  LOCKTAG heaplocktag;
368  LOCKMODE lockmode;
369  Snapshot snapshot;
370  int i;
371 
373  ereport(ERROR,
374  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
375  errmsg("included columns must not intersect with key columns")));
376 
377  /*
378  * count key attributes in index
379  */
380  numberOfKeyAttributes = list_length(stmt->indexParams);
381 
382  /*
383  * Calculate the new list of index columns including both key columns and
384  * INCLUDE columns. Later we can determine which of these are key columns,
385  * and which are just part of the INCLUDE list by checking the list
386  * position. A list item in a position less than ii_NumIndexKeyAttrs is
387  * part of the key columns, and anything equal to and over is part of the
388  * INCLUDE columns.
389  */
390  allIndexParams = list_concat(list_copy(stmt->indexParams),
392  numberOfAttributes = list_length(allIndexParams);
393 
394  if (numberOfAttributes <= 0)
395  ereport(ERROR,
396  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
397  errmsg("must specify at least one column")));
398  if (numberOfAttributes > INDEX_MAX_KEYS)
399  ereport(ERROR,
400  (errcode(ERRCODE_TOO_MANY_COLUMNS),
401  errmsg("cannot use more than %d columns in an index",
402  INDEX_MAX_KEYS)));
403 
404  /*
405  * Only SELECT ... FOR UPDATE/SHARE are allowed while doing a standard
406  * index build; but for concurrent builds we allow INSERT/UPDATE/DELETE
407  * (but not VACUUM).
408  *
409  * NB: Caller is responsible for making sure that relationId refers to the
410  * relation on which the index should be built; except in bootstrap mode,
411  * this will typically require the caller to have already locked the
412  * relation. To avoid lock upgrade hazards, that lock should be at least
413  * as strong as the one we take here.
414  *
415  * NB: If the lock strength here ever changes, code that is run by
416  * parallel workers under the control of certain particular ambuild
417  * functions will need to be updated, too.
418  */
419  lockmode = stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock;
420  rel = heap_open(relationId, lockmode);
421 
422  relationId = RelationGetRelid(rel);
423  namespaceId = RelationGetNamespace(rel);
424 
425  /* Ensure that it makes sense to index this kind of relation */
426  switch (rel->rd_rel->relkind)
427  {
428  case RELKIND_RELATION:
429  case RELKIND_MATVIEW:
430  case RELKIND_PARTITIONED_TABLE:
431  /* OK */
432  break;
433  case RELKIND_FOREIGN_TABLE:
434  /*
435  * Custom error message for FOREIGN TABLE since the term is close
436  * to a regular table and can confuse the user.
437  */
438  ereport(ERROR,
439  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
440  errmsg("cannot create index on foreign table \"%s\"",
441  RelationGetRelationName(rel))));
442  default:
443  ereport(ERROR,
444  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
445  errmsg("\"%s\" is not a table or materialized view",
446  RelationGetRelationName(rel))));
447  break;
448  }
449 
450  /*
451  * Establish behavior for partitioned tables, and verify sanity of
452  * parameters.
453  *
454  * We do not build an actual index in this case; we only create a few
455  * catalog entries. The actual indexes are built by recursing for each
456  * partition.
457  */
458  partitioned = rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE;
459  if (partitioned)
460  {
461  if (stmt->concurrent)
462  ereport(ERROR,
463  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
464  errmsg("cannot create index on partitioned table \"%s\" concurrently",
465  RelationGetRelationName(rel))));
466  if (stmt->excludeOpNames)
467  ereport(ERROR,
468  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
469  errmsg("cannot create exclusion constraints on partitioned table \"%s\"",
470  RelationGetRelationName(rel))));
471  }
472 
473  /*
474  * Don't try to CREATE INDEX on temp tables of other backends.
475  */
476  if (RELATION_IS_OTHER_TEMP(rel))
477  ereport(ERROR,
478  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
479  errmsg("cannot create indexes on temporary tables of other sessions")));
480 
481  /*
482  * Unless our caller vouches for having checked this already, insist that
483  * the table not be in use by our own session, either. Otherwise we might
484  * fail to make entries in the new index (for instance, if an INSERT or
485  * UPDATE is in progress and has already made its list of target indexes).
486  */
487  if (check_not_in_use)
488  CheckTableNotInUse(rel, "CREATE INDEX");
489 
490  /*
491  * Verify we (still) have CREATE rights in the rel's namespace.
492  * (Presumably we did when the rel was created, but maybe not anymore.)
493  * Skip check if caller doesn't want it. Also skip check if
494  * bootstrapping, since permissions machinery may not be working yet.
495  */
496  if (check_rights && !IsBootstrapProcessingMode())
497  {
498  AclResult aclresult;
499 
500  aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
501  ACL_CREATE);
502  if (aclresult != ACLCHECK_OK)
503  aclcheck_error(aclresult, OBJECT_SCHEMA,
504  get_namespace_name(namespaceId));
505  }
506 
507  /*
508  * Select tablespace to use. If not specified, use default tablespace
509  * (which may in turn default to database's default).
510  */
511  if (stmt->tableSpace)
512  {
513  tablespaceId = get_tablespace_oid(stmt->tableSpace, false);
514  }
515  else
516  {
517  tablespaceId = GetDefaultTablespace(rel->rd_rel->relpersistence);
518  /* note InvalidOid is OK in this case */
519  }
520 
521  /* Check tablespace permissions */
522  if (check_rights &&
523  OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
524  {
525  AclResult aclresult;
526 
527  aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),
528  ACL_CREATE);
529  if (aclresult != ACLCHECK_OK)
531  get_tablespace_name(tablespaceId));
532  }
533 
534  /*
535  * Force shared indexes into the pg_global tablespace. This is a bit of a
536  * hack but seems simpler than marking them in the BKI commands. On the
537  * other hand, if it's not shared, don't allow it to be placed there.
538  */
539  if (rel->rd_rel->relisshared)
540  tablespaceId = GLOBALTABLESPACE_OID;
541  else if (tablespaceId == GLOBALTABLESPACE_OID)
542  ereport(ERROR,
543  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
544  errmsg("only shared relations can be placed in pg_global tablespace")));
545 
546  /*
547  * Choose the index column names.
548  */
549  indexColNames = ChooseIndexColumnNames(allIndexParams);
550 
551  /*
552  * Select name for index if caller didn't specify
553  */
554  indexRelationName = stmt->idxname;
555  if (indexRelationName == NULL)
556  indexRelationName = ChooseIndexName(RelationGetRelationName(rel),
557  namespaceId,
558  indexColNames,
559  stmt->excludeOpNames,
560  stmt->primary,
561  stmt->isconstraint);
562 
563  /*
564  * look up the access method, verify it can handle the requested features
565  */
566  accessMethodName = stmt->accessMethod;
567  tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
568  if (!HeapTupleIsValid(tuple))
569  {
570  /*
571  * Hack to provide more-or-less-transparent updating of old RTREE
572  * indexes to GiST: if RTREE is requested and not found, use GIST.
573  */
574  if (strcmp(accessMethodName, "rtree") == 0)
575  {
576  ereport(NOTICE,
577  (errmsg("substituting access method \"gist\" for obsolete method \"rtree\"")));
578  accessMethodName = "gist";
579  tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
580  }
581 
582  if (!HeapTupleIsValid(tuple))
583  ereport(ERROR,
584  (errcode(ERRCODE_UNDEFINED_OBJECT),
585  errmsg("access method \"%s\" does not exist",
586  accessMethodName)));
587  }
588  accessMethodId = HeapTupleGetOid(tuple);
589  accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
590  amRoutine = GetIndexAmRoutine(accessMethodForm->amhandler);
591 
592  if (stmt->unique && !amRoutine->amcanunique)
593  ereport(ERROR,
594  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
595  errmsg("access method \"%s\" does not support unique indexes",
596  accessMethodName)));
597  if (list_length(stmt->indexIncludingParams) > 0 && !amRoutine->amcaninclude)
598  ereport(ERROR,
599  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
600  errmsg("access method \"%s\" does not support included columns",
601  accessMethodName)));
602  if (numberOfAttributes > 1 && !amRoutine->amcanmulticol)
603  ereport(ERROR,
604  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
605  errmsg("access method \"%s\" does not support multicolumn indexes",
606  accessMethodName)));
607  if (stmt->excludeOpNames && amRoutine->amgettuple == NULL)
608  ereport(ERROR,
609  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
610  errmsg("access method \"%s\" does not support exclusion constraints",
611  accessMethodName)));
612 
613  amcanorder = amRoutine->amcanorder;
614  amoptions = amRoutine->amoptions;
615 
616  pfree(amRoutine);
617  ReleaseSysCache(tuple);
618 
619  /*
620  * Validate predicate, if given
621  */
622  if (stmt->whereClause)
623  CheckPredicate((Expr *) stmt->whereClause);
624 
625  /*
626  * Parse AM-specific options, convert to text array form, validate.
627  */
628  reloptions = transformRelOptions((Datum) 0, stmt->options,
629  NULL, NULL, false, false);
630 
631  (void) index_reloptions(amoptions, reloptions, true);
632 
633  /*
634  * Prepare arguments for index_create, primarily an IndexInfo structure.
635  * Note that ii_Predicate must be in implicit-AND format.
636  */
637  indexInfo = makeNode(IndexInfo);
638  indexInfo->ii_NumIndexAttrs = numberOfAttributes;
639  indexInfo->ii_NumIndexKeyAttrs = numberOfKeyAttributes;
640  indexInfo->ii_Expressions = NIL; /* for now */
641  indexInfo->ii_ExpressionsState = NIL;
642  indexInfo->ii_Predicate = make_ands_implicit((Expr *) stmt->whereClause);
643  indexInfo->ii_PredicateState = NULL;
644  indexInfo->ii_ExclusionOps = NULL;
645  indexInfo->ii_ExclusionProcs = NULL;
646  indexInfo->ii_ExclusionStrats = NULL;
647  indexInfo->ii_Unique = stmt->unique;
648  /* In a concurrent build, mark it not-ready-for-inserts */
649  indexInfo->ii_ReadyForInserts = !stmt->concurrent;
650  indexInfo->ii_Concurrent = stmt->concurrent;
651  indexInfo->ii_BrokenHotChain = false;
652  indexInfo->ii_ParallelWorkers = 0;
653  indexInfo->ii_Am = accessMethodId;
654  indexInfo->ii_AmCache = NULL;
655  indexInfo->ii_Context = CurrentMemoryContext;
656 
657  typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
658  collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
659  classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
660  coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16));
661  ComputeIndexAttrs(indexInfo,
662  typeObjectId, collationObjectId, classObjectId,
663  coloptions, allIndexParams,
664  stmt->excludeOpNames, relationId,
665  accessMethodName, accessMethodId,
666  amcanorder, stmt->isconstraint);
667 
668  /*
669  * Extra checks when creating a PRIMARY KEY index.
670  */
671  if (stmt->primary)
672  index_check_primary_key(rel, indexInfo, is_alter_table);
673 
674  /*
675  * If this table is partitioned and we're creating a unique index or a
676  * primary key, make sure that the indexed columns are part of the
677  * partition key. Otherwise it would be possible to violate uniqueness by
678  * putting values that ought to be unique in different partitions.
679  *
680  * We could lift this limitation if we had global indexes, but those have
681  * their own problems, so this is a useful feature combination.
682  */
683  if (partitioned && (stmt->unique || stmt->primary))
684  {
685  PartitionKey key = rel->rd_partkey;
686  int i;
687 
688  /*
689  * A partitioned table can have unique indexes, as long as all the
690  * columns in the partition key appear in the unique key. A
691  * partition-local index can enforce global uniqueness iff the PK
692  * value completely determines the partition that a row is in.
693  *
694  * Thus, verify that all the columns in the partition key appear
695  * in the unique key definition.
696  */
697  for (i = 0; i < key->partnatts; i++)
698  {
699  bool found = false;
700  int j;
701  const char *constraint_type;
702 
703  if (stmt->primary)
704  constraint_type = "PRIMARY KEY";
705  else if (stmt->unique)
706  constraint_type = "UNIQUE";
707  else if (stmt->excludeOpNames != NIL)
708  constraint_type = "EXCLUDE";
709  else
710  {
711  elog(ERROR, "unknown constraint type");
712  constraint_type = NULL; /* keep compiler quiet */
713  }
714 
715  /*
716  * It may be possible to support UNIQUE constraints when partition
717  * keys are expressions, but is it worth it? Give up for now.
718  */
719  if (key->partattrs[i] == 0)
720  ereport(ERROR,
721  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
722  errmsg("unsupported %s constraint with partition key definition",
723  constraint_type),
724  errdetail("%s constraints cannot be used when partition keys include expressions.",
725  constraint_type)));
726 
727  for (j = 0; j < indexInfo->ii_NumIndexAttrs; j++)
728  {
729  if (key->partattrs[i] == indexInfo->ii_IndexAttrNumbers[j])
730  {
731  found = true;
732  break;
733  }
734  }
735  if (!found)
736  {
737  Form_pg_attribute att;
738 
739  att = TupleDescAttr(RelationGetDescr(rel), key->partattrs[i] - 1);
740  ereport(ERROR,
741  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
742  errmsg("insufficient columns in %s constraint definition",
743  constraint_type),
744  errdetail("%s constraint on table \"%s\" lacks column \"%s\" which is part of the partition key.",
745  constraint_type, RelationGetRelationName(rel),
746  NameStr(att->attname))));
747  }
748  }
749  }
750 
751 
752  /*
753  * We disallow indexes on system columns other than OID. They would not
754  * necessarily get updated correctly, and they don't seem useful anyway.
755  */
756  for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
757  {
758  AttrNumber attno = indexInfo->ii_IndexAttrNumbers[i];
759 
760  if (attno < 0 && attno != ObjectIdAttributeNumber)
761  ereport(ERROR,
762  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
763  errmsg("index creation on system columns is not supported")));
764  }
765 
766  /*
767  * Also check for system columns used in expressions or predicates.
768  */
769  if (indexInfo->ii_Expressions || indexInfo->ii_Predicate)
770  {
771  Bitmapset *indexattrs = NULL;
772 
773  pull_varattnos((Node *) indexInfo->ii_Expressions, 1, &indexattrs);
774  pull_varattnos((Node *) indexInfo->ii_Predicate, 1, &indexattrs);
775 
776  for (i = FirstLowInvalidHeapAttributeNumber + 1; i < 0; i++)
777  {
778  if (i != ObjectIdAttributeNumber &&
780  indexattrs))
781  ereport(ERROR,
782  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
783  errmsg("index creation on system columns is not supported")));
784  }
785  }
786 
787  /*
788  * Report index creation if appropriate (delay this till after most of the
789  * error checks)
790  */
791  if (stmt->isconstraint && !quiet)
792  {
793  const char *constraint_type;
794 
795  if (stmt->primary)
796  constraint_type = "PRIMARY KEY";
797  else if (stmt->unique)
798  constraint_type = "UNIQUE";
799  else if (stmt->excludeOpNames != NIL)
800  constraint_type = "EXCLUDE";
801  else
802  {
803  elog(ERROR, "unknown constraint type");
804  constraint_type = NULL; /* keep compiler quiet */
805  }
806 
807  ereport(DEBUG1,
808  (errmsg("%s %s will create implicit index \"%s\" for table \"%s\"",
809  is_alter_table ? "ALTER TABLE / ADD" : "CREATE TABLE /",
810  constraint_type,
811  indexRelationName, RelationGetRelationName(rel))));
812  }
813 
814  /*
815  * A valid stmt->oldNode implies that we already have a built form of the
816  * index. The caller should also decline any index build.
817  */
818  Assert(!OidIsValid(stmt->oldNode) || (skip_build && !stmt->concurrent));
819 
820  /*
821  * Make the catalog entries for the index, including constraints. This
822  * step also actually builds the index, except if caller requested not to
823  * or in concurrent mode, in which case it'll be done later, or
824  * doing a partitioned index (because those don't have storage).
825  */
826  flags = constr_flags = 0;
827  if (stmt->isconstraint)
829  if (skip_build || stmt->concurrent || partitioned)
830  flags |= INDEX_CREATE_SKIP_BUILD;
831  if (stmt->if_not_exists)
833  if (stmt->concurrent)
834  flags |= INDEX_CREATE_CONCURRENT;
835  if (partitioned)
836  flags |= INDEX_CREATE_PARTITIONED;
837  if (stmt->primary)
838  flags |= INDEX_CREATE_IS_PRIMARY;
839  if (partitioned && stmt->relation && !stmt->relation->inh)
840  flags |= INDEX_CREATE_INVALID;
841 
842  if (stmt->deferrable)
843  constr_flags |= INDEX_CONSTR_CREATE_DEFERRABLE;
844  if (stmt->initdeferred)
845  constr_flags |= INDEX_CONSTR_CREATE_INIT_DEFERRED;
846 
847  indexRelationId =
848  index_create(rel, indexRelationName, indexRelationId, parentIndexId,
849  parentConstraintId,
850  stmt->oldNode, indexInfo, indexColNames,
851  accessMethodId, tablespaceId,
852  collationObjectId, classObjectId,
853  coloptions, reloptions,
854  flags, constr_flags,
855  allowSystemTableMods, !check_rights,
856  &createdConstraintId);
857 
858  ObjectAddressSet(address, RelationRelationId, indexRelationId);
859 
860  if (!OidIsValid(indexRelationId))
861  {
862  heap_close(rel, NoLock);
863  return address;
864  }
865 
866  /* Add any requested comment */
867  if (stmt->idxcomment != NULL)
868  CreateComments(indexRelationId, RelationRelationId, 0,
869  stmt->idxcomment);
870 
871  if (partitioned)
872  {
873  /*
874  * Unless caller specified to skip this step (via ONLY), process
875  * each partition to make sure they all contain a corresponding index.
876  *
877  * If we're called internally (no stmt->relation), recurse always.
878  */
879  if (!stmt->relation || stmt->relation->inh)
880  {
881  PartitionDesc partdesc = RelationGetPartitionDesc(rel);
882  int nparts = partdesc->nparts;
883  Oid *part_oids = palloc(sizeof(Oid) * nparts);
884  bool invalidate_parent = false;
885  TupleDesc parentDesc;
886  Oid *opfamOids;
887 
888  memcpy(part_oids, partdesc->oids, sizeof(Oid) * nparts);
889 
890  parentDesc = CreateTupleDescCopy(RelationGetDescr(rel));
891  opfamOids = palloc(sizeof(Oid) * numberOfKeyAttributes);
892  for (i = 0; i < numberOfKeyAttributes; i++)
893  opfamOids[i] = get_opclass_family(classObjectId[i]);
894 
895  heap_close(rel, NoLock);
896 
897  /*
898  * For each partition, scan all existing indexes; if one matches
899  * our index definition and is not already attached to some other
900  * parent index, attach it to the one we just created.
901  *
902  * If none matches, build a new index by calling ourselves
903  * recursively with the same options (except for the index name).
904  */
905  for (i = 0; i < nparts; i++)
906  {
907  Oid childRelid = part_oids[i];
908  Relation childrel;
909  List *childidxs;
910  ListCell *cell;
911  AttrNumber *attmap;
912  bool found = false;
913  int maplen;
914 
915  childrel = heap_open(childRelid, lockmode);
916  childidxs = RelationGetIndexList(childrel);
917  attmap =
919  parentDesc,
920  gettext_noop("could not convert row type"));
921  maplen = parentDesc->natts;
922 
923 
924  foreach(cell, childidxs)
925  {
926  Oid cldidxid = lfirst_oid(cell);
927  Relation cldidx;
928  IndexInfo *cldIdxInfo;
929 
930  /* this index is already partition of another one */
931  if (has_superclass(cldidxid))
932  continue;
933 
934  cldidx = index_open(cldidxid, lockmode);
935  cldIdxInfo = BuildIndexInfo(cldidx);
936  if (CompareIndexInfo(cldIdxInfo, indexInfo,
937  cldidx->rd_indcollation,
938  collationObjectId,
939  cldidx->rd_opfamily,
940  opfamOids,
941  attmap, maplen))
942  {
943  Oid cldConstrOid = InvalidOid;
944 
945  /*
946  * Found a match.
947  *
948  * If this index is being created in the parent
949  * because of a constraint, then the child needs to
950  * have a constraint also, so look for one. If there
951  * is no such constraint, this index is no good, so
952  * keep looking.
953  */
954  if (createdConstraintId != InvalidOid)
955  {
956  cldConstrOid =
958  cldidxid);
959  if (cldConstrOid == InvalidOid)
960  {
961  index_close(cldidx, lockmode);
962  continue;
963  }
964  }
965 
966  /* Attach index to parent and we're done. */
967  IndexSetParentIndex(cldidx, indexRelationId);
968  if (createdConstraintId != InvalidOid)
969  ConstraintSetParentConstraint(cldConstrOid,
970  createdConstraintId);
971 
972  if (!IndexIsValid(cldidx->rd_index))
973  invalidate_parent = true;
974 
975  found = true;
976  /* keep lock till commit */
977  index_close(cldidx, NoLock);
978  break;
979  }
980 
981  index_close(cldidx, lockmode);
982  }
983 
984  list_free(childidxs);
985  heap_close(childrel, NoLock);
986 
987  /*
988  * If no matching index was found, create our own.
989  */
990  if (!found)
991  {
992  IndexStmt *childStmt = copyObject(stmt);
993  bool found_whole_row;
994 
995  childStmt->whereClause =
996  map_variable_attnos(stmt->whereClause, 1, 0,
997  attmap, maplen,
998  InvalidOid, &found_whole_row);
999  if (found_whole_row)
1000  elog(ERROR, "cannot convert whole-row table reference");
1001 
1002  childStmt->idxname = NULL;
1003  childStmt->relationId = childRelid;
1004  DefineIndex(childRelid, childStmt,
1005  InvalidOid, /* no predefined OID */
1006  indexRelationId, /* this is our child */
1007  createdConstraintId,
1008  is_alter_table, check_rights, check_not_in_use,
1009  false, quiet);
1010  }
1011 
1012  pfree(attmap);
1013  }
1014 
1015  /*
1016  * The pg_index row we inserted for this index was marked
1017  * indisvalid=true. But if we attached an existing index that
1018  * is invalid, this is incorrect, so update our row to
1019  * invalid too.
1020  */
1021  if (invalidate_parent)
1022  {
1023  Relation pg_index = heap_open(IndexRelationId, RowExclusiveLock);
1024  HeapTuple tup,
1025  newtup;
1026 
1028  ObjectIdGetDatum(indexRelationId));
1029  if (!tup)
1030  elog(ERROR, "cache lookup failed for index %u",
1031  indexRelationId);
1032  newtup = heap_copytuple(tup);
1033  ((Form_pg_index) GETSTRUCT(newtup))->indisvalid = false;
1034  CatalogTupleUpdate(pg_index, &tup->t_self, newtup);
1035  ReleaseSysCache(tup);
1036  heap_close(pg_index, RowExclusiveLock);
1037  heap_freetuple(newtup);
1038  }
1039  }
1040  else
1041  heap_close(rel, NoLock);
1042 
1043  /*
1044  * Indexes on partitioned tables are not themselves built, so we're
1045  * done here.
1046  */
1047  return address;
1048  }
1049 
1050  if (!stmt->concurrent)
1051  {
1052  /* Close the heap and we're done, in the non-concurrent case */
1053  heap_close(rel, NoLock);
1054  return address;
1055  }
1056 
1057  /* save lockrelid and locktag for below, then close rel */
1058  heaprelid = rel->rd_lockInfo.lockRelId;
1059  SET_LOCKTAG_RELATION(heaplocktag, heaprelid.dbId, heaprelid.relId);
1060  heap_close(rel, NoLock);
1061 
1062  /*
1063  * For a concurrent build, it's important to make the catalog entries
1064  * visible to other transactions before we start to build the index. That
1065  * will prevent them from making incompatible HOT updates. The new index
1066  * will be marked not indisready and not indisvalid, so that no one else
1067  * tries to either insert into it or use it for queries.
1068  *
1069  * We must commit our current transaction so that the index becomes
1070  * visible; then start another. Note that all the data structures we just
1071  * built are lost in the commit. The only data we keep past here are the
1072  * relation IDs.
1073  *
1074  * Before committing, get a session-level lock on the table, to ensure
1075  * that neither it nor the index can be dropped before we finish. This
1076  * cannot block, even if someone else is waiting for access, because we
1077  * already have the same lock within our transaction.
1078  *
1079  * Note: we don't currently bother with a session lock on the index,
1080  * because there are no operations that could change its state while we
1081  * hold lock on the parent table. This might need to change later.
1082  */
1084 
1088 
1089  /*
1090  * Phase 2 of concurrent index build (see comments for validate_index()
1091  * for an overview of how this works)
1092  *
1093  * Now we must wait until no running transaction could have the table open
1094  * with the old list of indexes. Use ShareLock to consider running
1095  * transactions that hold locks that permit writing to the table. Note we
1096  * do not need to worry about xacts that open the table for writing after
1097  * this point; they will see the new index when they open it.
1098  *
1099  * Note: the reason we use actual lock acquisition here, rather than just
1100  * checking the ProcArray and sleeping, is that deadlock is possible if
1101  * one of the transactions in question is blocked trying to acquire an
1102  * exclusive lock on our table. The lock code will detect deadlock and
1103  * error out properly.
1104  */
1105  WaitForLockers(heaplocktag, ShareLock);
1106 
1107  /*
1108  * At this moment we are sure that there are no transactions with the
1109  * table open for write that don't have this new index in their list of
1110  * indexes. We have waited out all the existing transactions and any new
1111  * transaction will have the new index in its list, but the index is still
1112  * marked as "not-ready-for-inserts". The index is consulted while
1113  * deciding HOT-safety though. This arrangement ensures that no new HOT
1114  * chains can be created where the new tuple and the old tuple in the
1115  * chain have different index keys.
1116  *
1117  * We now take a new snapshot, and build the index using all tuples that
1118  * are visible in this snapshot. We can be sure that any HOT updates to
1119  * these tuples will be compatible with the index, since any updates made
1120  * by transactions that didn't know about the index are now committed or
1121  * rolled back. Thus, each visible tuple is either the end of its
1122  * HOT-chain or the extension of the chain is HOT-safe for this index.
1123  */
1124 
1125  /* Open and lock the parent heap relation */
1127 
1128  /* And the target index relation */
1129  indexRelation = index_open(indexRelationId, RowExclusiveLock);
1130 
1131  /* Set ActiveSnapshot since functions in the indexes may need it */
1133 
1134  /* We have to re-build the IndexInfo struct, since it was lost in commit */
1135  indexInfo = BuildIndexInfo(indexRelation);
1136  Assert(!indexInfo->ii_ReadyForInserts);
1137  indexInfo->ii_Concurrent = true;
1138  indexInfo->ii_BrokenHotChain = false;
1139 
1140  /* Now build the index */
1141  index_build(rel, indexRelation, indexInfo, stmt->primary, false, true);
1142 
1143  /* Close both the relations, but keep the locks */
1144  heap_close(rel, NoLock);
1145  index_close(indexRelation, NoLock);
1146 
1147  /*
1148  * Update the pg_index row to mark the index as ready for inserts. Once we
1149  * commit this transaction, any new transactions that open the table must
1150  * insert new entries into the index for insertions and non-HOT updates.
1151  */
1153 
1154  /* we can do away with our snapshot */
1156 
1157  /*
1158  * Commit this transaction to make the indisready update visible.
1159  */
1162 
1163  /*
1164  * Phase 3 of concurrent index build
1165  *
1166  * We once again wait until no transaction can have the table open with
1167  * the index marked as read-only for updates.
1168  */
1169  WaitForLockers(heaplocktag, ShareLock);
1170 
1171  /*
1172  * Now take the "reference snapshot" that will be used by validate_index()
1173  * to filter candidate tuples. Beware! There might still be snapshots in
1174  * use that treat some transaction as in-progress that our reference
1175  * snapshot treats as committed. If such a recently-committed transaction
1176  * deleted tuples in the table, we will not include them in the index; yet
1177  * those transactions which see the deleting one as still-in-progress will
1178  * expect such tuples to be there once we mark the index as valid.
1179  *
1180  * We solve this by waiting for all endangered transactions to exit before
1181  * we mark the index as valid.
1182  *
1183  * We also set ActiveSnapshot to this snap, since functions in indexes may
1184  * need a snapshot.
1185  */
1187  PushActiveSnapshot(snapshot);
1188 
1189  /*
1190  * Scan the index and the heap, insert any missing index entries.
1191  */
1192  validate_index(relationId, indexRelationId, snapshot);
1193 
1194  /*
1195  * Drop the reference snapshot. We must do this before waiting out other
1196  * snapshot holders, else we will deadlock against other processes also
1197  * doing CREATE INDEX CONCURRENTLY, which would see our snapshot as one
1198  * they must wait for. But first, save the snapshot's xmin to use as
1199  * limitXmin for GetCurrentVirtualXIDs().
1200  */
1201  limitXmin = snapshot->xmin;
1202 
1204  UnregisterSnapshot(snapshot);
1205 
1206  /*
1207  * The snapshot subsystem could still contain registered snapshots that
1208  * are holding back our process's advertised xmin; in particular, if
1209  * default_transaction_isolation = serializable, there is a transaction
1210  * snapshot that is still active. The CatalogSnapshot is likewise a
1211  * hazard. To ensure no deadlocks, we must commit and start yet another
1212  * transaction, and do our wait before any snapshot has been taken in it.
1213  */
1216 
1217  /* We should now definitely not be advertising any xmin. */
1219 
1220  /*
1221  * The index is now valid in the sense that it contains all currently
1222  * interesting tuples. But since it might not contain tuples deleted just
1223  * before the reference snap was taken, we have to wait out any
1224  * transactions that might have older snapshots. Obtain a list of VXIDs
1225  * of such transactions, and wait for them individually.
1226  *
1227  * We can exclude any running transactions that have xmin > the xmin of
1228  * our reference snapshot; their oldest snapshot must be newer than ours.
1229  * We can also exclude any transactions that have xmin = zero, since they
1230  * evidently have no live snapshot at all (and any one they might be in
1231  * process of taking is certainly newer than ours). Transactions in other
1232  * DBs can be ignored too, since they'll never even be able to see this
1233  * index.
1234  *
1235  * We can also exclude autovacuum processes and processes running manual
1236  * lazy VACUUMs, because they won't be fazed by missing index entries
1237  * either. (Manual ANALYZEs, however, can't be excluded because they
1238  * might be within transactions that are going to do arbitrary operations
1239  * later.)
1240  *
1241  * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not
1242  * check for that.
1243  *
1244  * If a process goes idle-in-transaction with xmin zero, we do not need to
1245  * wait for it anymore, per the above argument. We do not have the
1246  * infrastructure right now to stop waiting if that happens, but we can at
1247  * least avoid the folly of waiting when it is idle at the time we would
1248  * begin to wait. We do this by repeatedly rechecking the output of
1249  * GetCurrentVirtualXIDs. If, during any iteration, a particular vxid
1250  * doesn't show up in the output, we know we can forget about it.
1251  */
1252  old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false,
1254  &n_old_snapshots);
1255 
1256  for (i = 0; i < n_old_snapshots; i++)
1257  {
1258  if (!VirtualTransactionIdIsValid(old_snapshots[i]))
1259  continue; /* found uninteresting in previous cycle */
1260 
1261  if (i > 0)
1262  {
1263  /* see if anything's changed ... */
1264  VirtualTransactionId *newer_snapshots;
1265  int n_newer_snapshots;
1266  int j;
1267  int k;
1268 
1269  newer_snapshots = GetCurrentVirtualXIDs(limitXmin,
1270  true, false,
1272  &n_newer_snapshots);
1273  for (j = i; j < n_old_snapshots; j++)
1274  {
1275  if (!VirtualTransactionIdIsValid(old_snapshots[j]))
1276  continue; /* found uninteresting in previous cycle */
1277  for (k = 0; k < n_newer_snapshots; k++)
1278  {
1279  if (VirtualTransactionIdEquals(old_snapshots[j],
1280  newer_snapshots[k]))
1281  break;
1282  }
1283  if (k >= n_newer_snapshots) /* not there anymore */
1284  SetInvalidVirtualTransactionId(old_snapshots[j]);
1285  }
1286  pfree(newer_snapshots);
1287  }
1288 
1289  if (VirtualTransactionIdIsValid(old_snapshots[i]))
1290  VirtualXactLock(old_snapshots[i], true);
1291  }
1292 
1293  /*
1294  * Index can now be marked valid -- update its pg_index entry
1295  */
1297 
1298  /*
1299  * The pg_index update will cause backends (including this one) to update
1300  * relcache entries for the index itself, but we should also send a
1301  * relcache inval on the parent table to force replanning of cached plans.
1302  * Otherwise existing sessions might fail to use the new index where it
1303  * would be useful. (Note that our earlier commits did not create reasons
1304  * to replan; so relcache flush on the index itself was sufficient.)
1305  */
1307 
1308  /*
1309  * Last thing to do is release the session-level lock on the parent table.
1310  */
1312 
1313  return address;
1314 }
bool deferrable
Definition: parsenodes.h:2734
signed short int16
Definition: c.h:312
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:722
#define NIL
Definition: pg_list.h:69
bool primary
Definition: parsenodes.h:2732
VirtualTransactionId * GetCurrentVirtualXIDs(TransactionId limitXmin, bool excludeXmin0, bool allDbs, int excludeVacuum, int *nvxids)
Definition: procarray.c:2474
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1382
MemoryContext ii_Context
Definition: execnodes.h:171
void CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment)
Definition: comment.c:142
LockRelId lockRelId
Definition: rel.h:44
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:112
bool amcanmulticol
Definition: amapi.h:180
AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4698
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:325
bool CompareIndexInfo(IndexInfo *info1, IndexInfo *info2, Oid *collations1, Oid *collations2, Oid *opfamilies1, Oid *opfamilies2, AttrNumber *attmap, int maplen)
Definition: index.c:1820
#define DEBUG1
Definition: elog.h:25
Oid get_relation_idx_constraint_oid(Oid relationId, Oid indexId)
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
List * ii_Predicate
Definition: execnodes.h:156
List * options
Definition: parsenodes.h:2725
#define IndexIsValid(indexForm)
Definition: pg_index.h:85
uint32 TransactionId
Definition: c.h:474
#define INDEX_CREATE_IF_NOT_EXISTS
Definition: index.h:49
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:863
amgettuple_function amgettuple
Definition: amapi.h:219
#define RelationGetDescr(relation)
Definition: rel.h:433
#define INDEX_CREATE_INVALID
Definition: index.h:51
int LOCKMODE
Definition: lockdefs.h:26
Oid GetUserId(void)
Definition: miscinit.c:379
#define ObjectIdAttributeNumber
Definition: sysattr.h:22
void index_set_state_flags(Oid indexId, IndexStateFlagsAction action)
Definition: index.c:3512
uint16 bits16
Definition: c.h:333
TransactionId xmin
Definition: proc.h:225
#define PointerGetDatum(X)
Definition: postgres.h:539
char * tableSpace
Definition: parsenodes.h:2721
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
ExprState * ii_PredicateState
Definition: execnodes.h:157
void CommitTransactionCommand(void)
Definition: xact.c:2744
Oid dbId
Definition: rel.h:39
Node * whereClause
Definition: parsenodes.h:2726
Definition: lock.h:178
#define gettext_noop(x)
Definition: c.h:1036
List * list_copy(const List *oldlist)
Definition: list.c:1160
void index_check_primary_key(Relation heapRel, IndexInfo *indexInfo, bool is_alter_table)
Definition: index.c:213
Definition: nodes.h:517
Oid * ii_ExclusionProcs
Definition: execnodes.h:159
int errcode(int sqlerrcode)
Definition: elog.c:575
List * list_concat(List *list1, List *list2)
Definition: list.c:321
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:28
void PopActiveSnapshot(void)
Definition: snapmgr.c:812
#define heap_close(r, l)
Definition: heapam.h:97
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:1745
static List * ChooseIndexColumnNames(List *indexElems)
Definition: indexcmds.c:2101
Form_pg_class rd_rel
Definition: rel.h:84
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
unsigned int Oid
Definition: postgres_ext.h:31
void index_build(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, bool isprimary, bool isreindex, bool parallel)
Definition: index.c:2229
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:745
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:304
#define OidIsValid(objectId)
Definition: c.h:605
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4686
int natts
Definition: tupdesc.h:82
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:219
Datum transformRelOptions(Datum oldOptions, List *defList, const char *namspace, char *validnsps[], bool ignoreOids, bool isReset)
Definition: reloptions.c:773
Oid GetDefaultTablespace(char relpersistence)
Definition: tablespace.c:1113
Oid MyDatabaseTableSpace
Definition: globals.c:88
PGXACT * MyPgXact
Definition: proc.c:68
List * indexIncludingParams
Definition: parsenodes.h:2723
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition: index.h:75
bool VirtualXactLock(VirtualTransactionId vxid, bool wait)
Definition: lock.c:4291
#define VirtualTransactionIdEquals(vxid1, vxid2)
Definition: lock.h:74
RangeVar * relation
Definition: parsenodes.h:2718
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3348
List * ii_ExpressionsState
Definition: execnodes.h:155
Form_pg_index rd_index
Definition: rel.h:131
void pfree(void *pointer)
Definition: mcxt.c:1031
#define PROC_IN_VACUUM
Definition: proc.h:54
List * make_ands_implicit(Expr *clause)
Definition: clauses.c:379
Oid * rd_indcollation
Definition: rel.h:165
void UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
Definition: lmgr.c:312
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
int ii_NumIndexKeyAttrs
Definition: execnodes.h:152
Definition: rel.h:36
#define ACL_CREATE
Definition: parsenodes.h:84
void LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
Definition: lmgr.c:299
amoptions_function amoptions
Definition: amapi.h:214
IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition: amapi.c:33
struct PartitionKeyData * rd_partkey
Definition: rel.h:99
ItemPointerData t_self
Definition: htup.h:65
bool has_superclass(Oid relationId)
Definition: pg_inherits.c:281
bool amcaninclude
Definition: amapi.h:196
bool amcanunique
Definition: amapi.h:178
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition: lock.h:193
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3051
#define NoLock
Definition: lockdefs.h:34
LockInfoData rd_lockInfo
Definition: rel.h:87
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:733
void IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
Definition: indexcmds.c:2465
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:873
List * list_intersection(const List *list1, const List *list2)
Definition: list.c:800
void CacheInvalidateRelcacheByRelid(Oid relid)
Definition: inval.c:1292
#define InvalidTransactionId
Definition: transam.h:31
#define RelationGetRelationName(relation)
Definition: rel.h:441
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
bool ii_BrokenHotChain
Definition: execnodes.h:167
Oid * rd_opfamily
Definition: rel.h:154
TransactionId xmin
Definition: snapshot.h:68
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3208
bool ii_ReadyForInserts
Definition: execnodes.h:165
#define ereport(elevel, rest)
Definition: elog.h:122
Node * map_variable_attnos(Node *node, int target_varno, int sublevels_up, const AttrNumber *attno_map, int map_length, Oid to_rowtype, bool *found_whole_row)
bool inh
Definition: primnodes.h:70
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:905
void * ii_AmCache
Definition: execnodes.h:170
char * idxname
Definition: parsenodes.h:2717
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:71
void validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
Definition: index.c:3113
AttrNumber * convert_tuples_by_name_map(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:293
FormData_pg_index * Form_pg_index
Definition: pg_index.h:66
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
bool if_not_exists
Definition: parsenodes.h:2738
AclResult
Definition: acl.h:178
AttrNumber * partattrs
Definition: partcache.h:28
uintptr_t Datum
Definition: postgres.h:365
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
int ii_NumIndexAttrs
Definition: execnodes.h:151
bool unique
Definition: parsenodes.h:2731
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
char * accessMethod
Definition: parsenodes.h:2720
#define INDEX_CREATE_IS_PRIMARY
Definition: index.h:45
void WaitForLockers(LOCKTAG heaplocktag, LOCKMODE lockmode)
Definition: lmgr.c:837
Relation heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: heapam.c:1323
bool allowSystemTableMods
Definition: globals.c:121
#define InvalidOid
Definition: postgres_ext.h:36
#define INDEX_CREATE_CONCURRENT
Definition: index.h:48
bytea * index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate)
Definition: reloptions.c:1478
#define NOTICE
Definition: elog.h:37
bool ii_Unique
Definition: execnodes.h:164
#define makeNode(_type_)
Definition: nodes.h:565
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
List * ii_Expressions
Definition: execnodes.h:154
#define Assert(condition)
Definition: c.h:699
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:538
void StartTransactionCommand(void)
Definition: xact.c:2673
#define SetInvalidVirtualTransactionId(vxid)
Definition: lock.h:77
List * indexParams
Definition: parsenodes.h:2722
static void CheckPredicate(Expr *predicate)
Definition: indexcmds.c:1356
#define INDEX_MAX_KEYS
int ii_ParallelWorkers
Definition: execnodes.h:168
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:211
List * excludeOpNames
Definition: parsenodes.h:2727
static int list_length(const List *l)
Definition: pg_list.h:89
bool initdeferred
Definition: parsenodes.h:2735
bool amcanorder
Definition: amapi.h:172
char * idxcomment
Definition: parsenodes.h:2728
Oid get_opclass_family(Oid opclass)
Definition: lsyscache.c:1032
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4190
bool ii_Concurrent
Definition: execnodes.h:166
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
void ConstraintSetParentConstraint(Oid childConstrId, Oid parentConstrId)
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:372
#define INDEX_CREATE_SKIP_BUILD
Definition: index.h:47
bool concurrent
Definition: parsenodes.h:2737
#define INDEX_CREATE_PARTITIONED
Definition: index.h:50
bool isconstraint
Definition: parsenodes.h:2733
Oid * ii_ExclusionOps
Definition: execnodes.h:158
FormData_pg_am * Form_pg_am
Definition: pg_am.h:46
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:797
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1428
void list_free(List *list)
Definition: list.c:1133
#define ShareLock
Definition: lockdefs.h:41
int i
#define NameStr(name)
Definition: c.h:576
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:1379
static char * ChooseIndexName(const char *tabname, Oid namespaceId, List *colnames, List *exclusionOpNames, bool primary, bool isconstraint)
Definition: indexcmds.c:2017
bytea *(* amoptions_function)(Datum reloptions, bool validate)
Definition: amapi.h:103
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:712
#define copyObject(obj)
Definition: nodes.h:630
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition: execnodes.h:153
uint16 * ii_ExclusionStrats
Definition: execnodes.h:160
#define INDEX_CREATE_ADD_CONSTRAINT
Definition: index.h:46
Definition: pg_list.h:45
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:486
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:407
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition: index.h:74
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:150
Oid relationId
Definition: parsenodes.h:2719
#define PROC_IS_AUTOVACUUM
Definition: proc.h:53
#define lfirst_oid(lc)
Definition: pg_list.h:108
#define RelationGetPartitionDesc(relation)
Definition: rel.h:595
Oid relId
Definition: rel.h:38
Oid ii_Am
Definition: execnodes.h:169
#define RelationGetNamespace(relation)
Definition: rel.h:448

◆ GetDefaultOpClass()

Oid GetDefaultOpClass ( Oid  type_id,
Oid  am_id 
)

Definition at line 1797 of file indexcmds.c.

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

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

1798 {
1799  Oid result = InvalidOid;
1800  int nexact = 0;
1801  int ncompatible = 0;
1802  int ncompatiblepreferred = 0;
1803  Relation rel;
1804  ScanKeyData skey[1];
1805  SysScanDesc scan;
1806  HeapTuple tup;
1807  TYPCATEGORY tcategory;
1808 
1809  /* If it's a domain, look at the base type instead */
1810  type_id = getBaseType(type_id);
1811 
1812  tcategory = TypeCategory(type_id);
1813 
1814  /*
1815  * We scan through all the opclasses available for the access method,
1816  * looking for one that is marked default and matches the target type
1817  * (either exactly or binary-compatibly, but prefer an exact match).
1818  *
1819  * We could find more than one binary-compatible match. If just one is
1820  * for a preferred type, use that one; otherwise we fail, forcing the user
1821  * to specify which one he wants. (The preferred-type special case is a
1822  * kluge for varchar: it's binary-compatible to both text and bpchar, so
1823  * we need a tiebreaker.) If we find more than one exact match, then
1824  * someone put bogus entries in pg_opclass.
1825  */
1826  rel = heap_open(OperatorClassRelationId, AccessShareLock);
1827 
1828  ScanKeyInit(&skey[0],
1829  Anum_pg_opclass_opcmethod,
1830  BTEqualStrategyNumber, F_OIDEQ,
1831  ObjectIdGetDatum(am_id));
1832 
1833  scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
1834  NULL, 1, skey);
1835 
1836  while (HeapTupleIsValid(tup = systable_getnext(scan)))
1837  {
1838  Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
1839 
1840  /* ignore altogether if not a default opclass */
1841  if (!opclass->opcdefault)
1842  continue;
1843  if (opclass->opcintype == type_id)
1844  {
1845  nexact++;
1846  result = HeapTupleGetOid(tup);
1847  }
1848  else if (nexact == 0 &&
1849  IsBinaryCoercible(type_id, opclass->opcintype))
1850  {
1851  if (IsPreferredType(tcategory, opclass->opcintype))
1852  {
1853  ncompatiblepreferred++;
1854  result = HeapTupleGetOid(tup);
1855  }
1856  else if (ncompatiblepreferred == 0)
1857  {
1858  ncompatible++;
1859  result = HeapTupleGetOid(tup);
1860  }
1861  }
1862  }
1863 
1864  systable_endscan(scan);
1865 
1867 
1868  /* raise error if pg_opclass contains inconsistent data */
1869  if (nexact > 1)
1870  ereport(ERROR,
1872  errmsg("there are multiple default operator classes for data type %s",
1873  format_type_be(type_id))));
1874 
1875  if (nexact == 1 ||
1876  ncompatiblepreferred == 1 ||
1877  (ncompatiblepreferred == 0 && ncompatible == 1))
1878  return result;
1879 
1880  return InvalidOid;
1881 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:502
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:328
#define heap_close(r, l)
Definition: heapam.h:97
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:331
#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:419
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
bool IsBinaryCoercible(Oid srctype, Oid targettype)
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define InvalidOid
Definition: postgres_ext.h:36
TYPCATEGORY TypeCategory(Oid type)
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
int errmsg(const char *fmt,...)
Definition: elog.c:797
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:712
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2275
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:81
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ IndexSetParentIndex()

void IndexSetParentIndex ( Relation  partitionIdx,
Oid  parentOid 
)

Definition at line 2465 of file indexcmds.c.

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

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

2466 {
2467  Relation pg_inherits;
2468  ScanKeyData key[2];
2469  SysScanDesc scan;
2470  Oid partRelid = RelationGetRelid(partitionIdx);
2471  HeapTuple tuple;
2472  bool fix_dependencies;
2473 
2474  /* Make sure this is an index */
2475  Assert(partitionIdx->rd_rel->relkind == RELKIND_INDEX ||
2476  partitionIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
2477 
2478  /*
2479  * Scan pg_inherits for rows linking our index to some parent.
2480  */
2481  pg_inherits = relation_open(InheritsRelationId, RowExclusiveLock);
2482  ScanKeyInit(&key[0],
2483  Anum_pg_inherits_inhrelid,
2484  BTEqualStrategyNumber, F_OIDEQ,
2485  ObjectIdGetDatum(partRelid));
2486  ScanKeyInit(&key[1],
2487  Anum_pg_inherits_inhseqno,
2488  BTEqualStrategyNumber, F_INT4EQ,
2489  Int32GetDatum(1));
2490  scan = systable_beginscan(pg_inherits, InheritsRelidSeqnoIndexId, true,
2491  NULL, 2, key);
2492  tuple = systable_getnext(scan);
2493 
2494  if (!HeapTupleIsValid(tuple))
2495  {
2496  if (parentOid == InvalidOid)
2497  {
2498  /*
2499  * No pg_inherits row, and no parent wanted: nothing to do in
2500  * this case.
2501  */
2502  fix_dependencies = false;
2503  }
2504  else
2505  {
2506  Datum values[Natts_pg_inherits];
2507  bool isnull[Natts_pg_inherits];
2508 
2509  /*
2510  * No pg_inherits row exists, and we want a parent for this index,
2511  * so insert it.
2512  */
2513  values[Anum_pg_inherits_inhrelid - 1] = ObjectIdGetDatum(partRelid);
2514  values[Anum_pg_inherits_inhparent - 1] =
2515  ObjectIdGetDatum(parentOid);
2516  values[Anum_pg_inherits_inhseqno - 1] = Int32GetDatum(1);
2517  memset(isnull, false, sizeof(isnull));
2518 
2519  tuple = heap_form_tuple(RelationGetDescr(pg_inherits),
2520  values, isnull);
2521  CatalogTupleInsert(pg_inherits, tuple);
2522 
2523  fix_dependencies = true;
2524  }
2525  }
2526  else
2527  {
2528  Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(tuple);
2529 
2530  if (parentOid == InvalidOid)
2531  {
2532  /*
2533  * There exists a pg_inherits row, which we want to clear; do so.
2534  */
2535  CatalogTupleDelete(pg_inherits, &tuple->t_self);
2536  fix_dependencies = true;
2537  }
2538  else
2539  {
2540  /*
2541  * A pg_inherits row exists. If it's the same we want, then we're
2542  * good; if it differs, that amounts to a corrupt catalog and
2543  * should not happen.
2544  */
2545  if (inhForm->inhparent != parentOid)
2546  {
2547  /* unexpected: we should not get called in this case */
2548  elog(ERROR, "bogus pg_inherit row: inhrelid %u inhparent %u",
2549  inhForm->inhrelid, inhForm->inhparent);
2550  }
2551 
2552  /* already in the right state */
2553  fix_dependencies = false;
2554  }
2555  }
2556 
2557  /* done with pg_inherits */
2558  systable_endscan(scan);
2559  relation_close(pg_inherits, RowExclusiveLock);
2560 
2561  if (fix_dependencies)
2562  {
2563  ObjectAddress partIdx;
2564 
2565  /*
2566  * Insert/delete pg_depend rows. If setting a parent, add an
2567  * INTERNAL_AUTO dependency to the parent index; if making standalone,
2568  * remove all existing rows and put back the regular dependency on the
2569  * table.
2570  */
2571  ObjectAddressSet(partIdx, RelationRelationId, partRelid);
2572 
2573  if (OidIsValid(parentOid))
2574  {
2575  ObjectAddress parentIdx;
2576 
2577  ObjectAddressSet(parentIdx, RelationRelationId, parentOid);
2578  recordDependencyOn(&partIdx, &parentIdx, DEPENDENCY_INTERNAL_AUTO);
2579  }
2580  else
2581  {
2582  ObjectAddress partitionTbl;
2583 
2584  ObjectAddressSet(partitionTbl, RelationRelationId,
2585  partitionIdx->rd_index->indrelid);
2586 
2587  deleteDependencyRecordsForClass(RelationRelationId, partRelid,
2588  RelationRelationId,
2590 
2591  recordDependencyOn(&partIdx, &partitionTbl, DEPENDENCY_AUTO);
2592  }
2593 
2594  /* make our updates visible */
2596  }
2597 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:502
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
#define RelationGetDescr(relation)
Definition: rel.h:433
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1270
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:256
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1074
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:331
Form_pg_index rd_index
Definition: rel.h:131
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:419
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:163
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
uintptr_t Datum
Definition: postgres.h:365
void CommandCounterIncrement(void)
Definition: xact.c:914
static void fix_dependencies(ArchiveHandle *AH)
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:241
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:699
#define InheritsRelidSeqnoIndexId
Definition: indexing.h:169
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:164
#define Int32GetDatum(X)
Definition: postgres.h:462
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1124
#define elog
Definition: elog.h:219
#define RelationGetRelid(relation)
Definition: rel.h:407
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ makeObjectName()

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

Definition at line 1906 of file indexcmds.c.

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

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

1907 {
1908  char *name;
1909  int overhead = 0; /* chars needed for label and underscores */
1910  int availchars; /* chars available for name(s) */
1911  int name1chars; /* chars allocated to name1 */
1912  int name2chars; /* chars allocated to name2 */
1913  int ndx;
1914 
1915  name1chars = strlen(name1);
1916  if (name2)
1917  {
1918  name2chars = strlen(name2);
1919  overhead++; /* allow for separating underscore */
1920  }
1921  else
1922  name2chars = 0;
1923  if (label)
1924  overhead += strlen(label) + 1;
1925 
1926  availchars = NAMEDATALEN - 1 - overhead;
1927  Assert(availchars > 0); /* else caller chose a bad label */
1928 
1929  /*
1930  * If we must truncate, preferentially truncate the longer name. This
1931  * logic could be expressed without a loop, but it's simple and obvious as
1932  * a loop.
1933  */
1934  while (name1chars + name2chars > availchars)
1935  {
1936  if (name1chars > name2chars)
1937  name1chars--;
1938  else
1939  name2chars--;
1940  }
1941 
1942  name1chars = pg_mbcliplen(name1, name1chars, name1chars);
1943  if (name2)
1944  name2chars = pg_mbcliplen(name2, name2chars, name2chars);
1945 
1946  /* Now construct the string using the chosen lengths */
1947  name = palloc(name1chars + name2chars + overhead + 1);
1948  memcpy(name, name1, name1chars);
1949  ndx = name1chars;
1950  if (name2)
1951  {
1952  name[ndx++] = '_';
1953  memcpy(name + ndx, name2, name2chars);
1954  ndx += name2chars;
1955  }
1956  if (label)
1957  {
1958  name[ndx++] = '_';
1959  strcpy(name + ndx, label);
1960  }
1961  else
1962  name[ndx] = '\0';
1963 
1964  return name;
1965 }
#define NAMEDATALEN
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition: mbutils.c:820
static char * label
Definition: pg_basebackup.c:84
#define Assert(condition)
Definition: c.h:699
const char * name
Definition: encode.c:521
void * palloc(Size size)
Definition: mcxt.c:924

◆ RangeVarCallbackForReindexIndex()

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

Definition at line 2200 of file indexcmds.c.

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

Referenced by ReindexIndex().

2202 {
2203  char relkind;
2204  Oid *heapOid = (Oid *) arg;
2205 
2206  /*
2207  * If we previously locked some other index's heap, and the name we're
2208  * looking up no longer refers to that relation, release the now-useless
2209  * lock.
2210  */
2211  if (relId != oldRelId && OidIsValid(oldRelId))
2212  {
2213  /* lock level here should match reindex_index() heap lock */
2214  UnlockRelationOid(*heapOid, ShareLock);
2215  *heapOid = InvalidOid;
2216  }
2217 
2218  /* If the relation does not exist, there's nothing more to do. */
2219  if (!OidIsValid(relId))
2220  return;
2221 
2222  /*
2223  * If the relation does exist, check whether it's an index. But note that
2224  * the relation might have been dropped between the time we did the name
2225  * lookup and now. In that case, there's nothing to do.
2226  */
2227  relkind = get_rel_relkind(relId);
2228  if (!relkind)
2229  return;
2230  if (relkind != RELKIND_INDEX &&
2231  relkind != RELKIND_PARTITIONED_INDEX)
2232  ereport(ERROR,
2233  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2234  errmsg("\"%s\" is not an index", relation->relname)));
2235 
2236  /* Check permissions */
2237  if (!pg_class_ownercheck(relId, GetUserId()))
2239 
2240  /* Lock heap before index to avoid deadlock. */
2241  if (relId != oldRelId)
2242  {
2243  /*
2244  * Lock level here should match reindex_index() heap lock. If the OID
2245  * isn't valid, it means the index as concurrently dropped, which is
2246  * not a problem for us; just return normally.
2247  */
2248  *heapOid = IndexGetRelation(relId, true);
2249  if (OidIsValid(*heapOid))
2250  LockRelationOid(*heapOid, ShareLock);
2251  }
2252 }
Oid IndexGetRelation(Oid indexId, bool missing_ok)
Definition: index.c:3591
Oid GetUserId(void)
Definition: miscinit.c:379
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:182
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
int errcode(int sqlerrcode)
Definition: elog.c:575
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
char relkind
Definition: pg_class.h:51
char * relname
Definition: primnodes.h:69
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3348
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvalidOid
Definition: postgres_ext.h:36
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4748
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ShareLock
Definition: lockdefs.h:41
void * arg
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:105

◆ ReindexIndex()

void ReindexIndex ( RangeVar indexRelation,
int  options 
)

Definition at line 2159 of file indexcmds.c.

References AccessExclusiveLock, index_close(), index_open(), InvalidOid, NoLock, RangeVarCallbackForReindexIndex(), RangeVarGetRelidExtended(), RelationData::rd_rel, reindex_index(), and ReindexPartitionedIndex().

Referenced by standard_ProcessUtility().

2160 {
2161  Oid indOid;
2162  Oid heapOid = InvalidOid;
2163  Relation irel;
2164  char persistence;
2165 
2166  /*
2167  * Find and lock index, and check permissions on table; use callback to
2168  * obtain lock on table first, to avoid deadlock hazard. The lock level
2169  * used here must match the index lock obtained in reindex_index().
2170  */
2171  indOid = RangeVarGetRelidExtended(indexRelation, AccessExclusiveLock,
2172  0,
2174  (void *) &heapOid);
2175 
2176  /*
2177  * Obtain the current persistence of the existing index. We already hold
2178  * lock on the index.
2179  */
2180  irel = index_open(indOid, NoLock);
2181 
2182  if (irel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
2183  {
2185  return;
2186  }
2187 
2188  persistence = irel->rd_rel->relpersistence;
2189  index_close(irel, NoLock);
2190 
2191  reindex_index(indOid, false, persistence, options);
2192 }
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
#define NoLock
Definition: lockdefs.h:34
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:227
static void RangeVarCallbackForReindexIndex(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: indexcmds.c:2200
#define InvalidOid
Definition: postgres_ext.h:36
void reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, int options)
Definition: index.c:3616
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
#define AccessExclusiveLock
Definition: lockdefs.h:45
static void ReindexPartitionedIndex(Relation parentIdx)
Definition: indexcmds.c:2451
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:150

◆ ReindexMultipleTables()

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

Definition at line 2287 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(), GETSTRUCT, GetTransactionSnapshot(), GetUserId(), heap_beginscan_catalog(), heap_close, heap_endscan(), heap_getnext(), heap_open(), HeapTupleGetOid, INFO, IsSystemClass(), isTempNamespace(), lappend_oid(), lcons_oid(), lfirst_oid, MemoryContextDelete(), MemoryContextSwitchTo(), MyDatabaseId, NIL, OBJECT_DATABASE, OBJECT_SCHEMA, ObjectIdGetDatum, 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_VERBOSE, ScanKeyInit(), and StartTransactionCommand().

Referenced by standard_ProcessUtility().

2289 {
2290  Oid objectOid;
2291  Relation relationRelation;
2292  HeapScanDesc scan;
2293  ScanKeyData scan_keys[1];
2294  HeapTuple tuple;
2295  MemoryContext private_context;
2296  MemoryContext old;
2297  List *relids = NIL;
2298  ListCell *l;
2299  int num_keys;
2300 
2301  AssertArg(objectName);
2302  Assert(objectKind == REINDEX_OBJECT_SCHEMA ||
2303  objectKind == REINDEX_OBJECT_SYSTEM ||
2304  objectKind == REINDEX_OBJECT_DATABASE);
2305 
2306  /*
2307  * Get OID of object to reindex, being the database currently being used
2308  * by session for a database or for system catalogs, or the schema defined
2309  * by caller. At the same time do permission checks that need different
2310  * processing depending on the object type.
2311  */
2312  if (objectKind == REINDEX_OBJECT_SCHEMA)
2313  {
2314  objectOid = get_namespace_oid(objectName, false);
2315 
2316  if (!pg_namespace_ownercheck(objectOid, GetUserId()))
2318  objectName);
2319  }
2320  else
2321  {
2322  objectOid = MyDatabaseId;
2323 
2324  if (strcmp(objectName, get_database_name(objectOid)) != 0)
2325  ereport(ERROR,
2326  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2327  errmsg("can only reindex the currently open database")));
2328  if (!pg_database_ownercheck(objectOid, GetUserId()))
2330  objectName);
2331  }
2332 
2333  /*
2334  * Create a memory context that will survive forced transaction commits we
2335  * do below. Since it is a child of PortalContext, it will go away
2336  * eventually even if we suffer an error; there's no need for special
2337  * abort cleanup logic.
2338  */
2339  private_context = AllocSetContextCreate(PortalContext,
2340  "ReindexMultipleTables",
2342 
2343  /*
2344  * Define the search keys to find the objects to reindex. For a schema, we
2345  * select target relations using relnamespace, something not necessary for
2346  * a database-wide operation.
2347  */
2348  if (objectKind == REINDEX_OBJECT_SCHEMA)
2349  {
2350  num_keys = 1;
2351  ScanKeyInit(&scan_keys[0],
2352  Anum_pg_class_relnamespace,
2353  BTEqualStrategyNumber, F_OIDEQ,
2354  ObjectIdGetDatum(objectOid));
2355  }
2356  else
2357  num_keys = 0;
2358 
2359  /*
2360  * Scan pg_class to build a list of the relations we need to reindex.
2361  *
2362  * We only consider plain relations and materialized views here (toast
2363  * rels will be processed indirectly by reindex_relation).
2364  */
2365  relationRelation = heap_open(RelationRelationId, AccessShareLock);
2366  scan = heap_beginscan_catalog(relationRelation, num_keys, scan_keys);
2367  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2368  {
2369  Form_pg_class classtuple = (Form_pg_class) GETSTRUCT(tuple);
2370  Oid relid = HeapTupleGetOid(tuple);
2371 
2372  /*
2373  * Only regular tables and matviews can have indexes, so ignore any
2374  * other kind of relation.
2375  *
2376  * It is tempting to also consider partitioned tables here, but that
2377  * has the problem that if the children are in the same schema, they
2378  * would be processed twice. Maybe we could have a separate list of
2379  * partitioned tables, and expand that afterwards into relids,
2380  * ignoring any duplicates.
2381  */
2382  if (classtuple->relkind != RELKIND_RELATION &&
2383  classtuple->relkind != RELKIND_MATVIEW)
2384  continue;
2385 
2386  /* Skip temp tables of other backends; we can't reindex them at all */
2387  if (classtuple->relpersistence == RELPERSISTENCE_TEMP &&
2388  !isTempNamespace(classtuple->relnamespace))
2389  continue;
2390 
2391  /* Check user/system classification, and optionally skip */
2392  if (objectKind == REINDEX_OBJECT_SYSTEM &&
2393  !IsSystemClass(relid, classtuple))
2394  continue;
2395 
2396  /* Save the list of relation OIDs in private context */
2397  old = MemoryContextSwitchTo(private_context);
2398 
2399  /*
2400  * We always want to reindex pg_class first if it's selected to be
2401  * reindexed. This ensures that if there is any corruption in
2402  * pg_class' indexes, they will be fixed before we process any other
2403  * tables. This is critical because reindexing itself will try to
2404  * update pg_class.
2405  */
2406  if (relid == RelationRelationId)
2407  relids = lcons_oid(relid, relids);
2408  else
2409  relids = lappend_oid(relids, relid);
2410 
2411  MemoryContextSwitchTo(old);
2412  }
2413  heap_endscan(scan);
2414  heap_close(relationRelation, AccessShareLock);
2415 
2416  /* Now reindex each rel in a separate transaction */
2419  foreach(l, relids)
2420  {
2421  Oid relid = lfirst_oid(l);
2422 
2424  /* functions in indexes may want a snapshot set */
2426  if (reindex_relation(relid,
2429  options))
2430 
2432  ereport(INFO,
2433  (errmsg("table \"%s.%s\" was reindexed",
2435  get_rel_name(relid))));
2438  }
2440 
2441  MemoryContextDelete(private_context);
2442 }
#define NIL
Definition: pg_list.h:69
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
Oid get_namespace_oid(const char *nspname, bool missing_ok)
Definition: namespace.c:3024
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
void heap_endscan(HeapScanDesc scan)
Definition: heapam.c:1572
Oid GetUserId(void)
Definition: miscinit.c:379
void CommitTransactionCommand(void)
Definition: xact.c:2744
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:202
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1754
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
#define INFO
Definition: elog.h:33
void PopActiveSnapshot(void)
Definition: snapmgr.c:812
bool pg_namespace_ownercheck(Oid nsp_oid, Oid roleid)
Definition: aclchk.c:4924
List * lcons_oid(Oid datum, List *list)
Definition: list.c:295
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:304
#define REINDEXOPT_VERBOSE
Definition: parsenodes.h:3272
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:75
MemoryContext PortalContext
Definition: mcxt.c:53
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3348
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
char * get_database_name(Oid dbid)
Definition: dbcommands.c:2056
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3051
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:733
bool isTempNamespace(Oid namespaceId)
Definition: namespace.c:3137
HeapScanDesc heap_beginscan_catalog(Relation relation, int nkeys, ScanKey key)
Definition: heapam.c:1412
#define ereport(elevel, rest)
Definition: elog.h:122
#define AssertArg(condition)
Definition: c.h:701
bool pg_database_ownercheck(Oid db_oid, Oid roleid)
Definition: aclchk.c:5166
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:170
Oid MyDatabaseId
Definition: globals.c:86
HeapTuple heap_getnext(HeapScanDesc scan, ScanDirection direction)
Definition: heapam.c:1835
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define Assert(condition)
Definition: c.h:699
void StartTransactionCommand(void)
Definition: xact.c:2673
#define REINDEX_REL_CHECK_CONSTRAINTS
Definition: index.h:141
FormData_pg_class * Form_pg_class
Definition: pg_class.h:92
int errmsg(const char *fmt,...)
Definition: elog.c:797
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define REINDEX_REL_PROCESS_TOAST
Definition: index.h:139
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:712
bool reindex_relation(Oid relid, int flags, int options)
Definition: index.c:3833
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:108

◆ ReindexPartitionedIndex()

static void ReindexPartitionedIndex ( Relation  parentIdx)
static

Definition at line 2451 of file indexcmds.c.

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

Referenced by ReindexIndex().

2452 {
2453  ereport(ERROR,
2454  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2455  errmsg("REINDEX is not yet implemented for partitioned indexes")));
2456 }
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ ReindexTable()

Oid ReindexTable ( RangeVar relation,
int  options 
)

Definition at line 2259 of file indexcmds.c.

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

Referenced by standard_ProcessUtility().

2260 {
2261  Oid heapOid;
2262 
2263  /* The lock level used here should match reindex_relation(). */
2264  heapOid = RangeVarGetRelidExtended(relation, ShareLock, 0,
2266 
2267  if (!reindex_relation(heapOid,
2270  options))
2271  ereport(NOTICE,
2272  (errmsg("table \"%s\" has no indexes",
2273  relation->relname)));
2274 
2275  return heapOid;
2276 }
void RangeVarCallbackOwnsTable(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:13373
unsigned int Oid
Definition: postgres_ext.h:31
char * relname
Definition: primnodes.h:69
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:227
#define ereport(elevel, rest)
Definition: elog.h:122
#define NOTICE
Definition: elog.h:37
#define REINDEX_REL_CHECK_CONSTRAINTS
Definition: index.h:141
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ShareLock
Definition: lockdefs.h:41
#define REINDEX_REL_PROCESS_TOAST
Definition: index.h:139
bool reindex_relation(Oid relid, int flags, int options)
Definition: index.c:3833

◆ ResolveOpClass()

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

Definition at line 1686 of file indexcmds.c.

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

Referenced by ComputeIndexAttrs(), and ComputePartitionAttrs().

1688 {
1689  char *schemaname;
1690  char *opcname;
1691  HeapTuple tuple;
1692  Oid opClassId,
1693  opInputType;
1694 
1695  /*
1696  * Release 7.0 removed network_ops, timespan_ops, and datetime_ops, so we
1697  * ignore those opclass names so the default *_ops is used. This can be
1698  * removed in some later release. bjm 2000/02/07
1699  *
1700  * Release 7.1 removes lztext_ops, so suppress that too for a while. tgl
1701  * 2000/07/30
1702  *
1703  * Release 7.2 renames timestamp_ops to timestamptz_ops, so suppress that
1704  * too for awhile. I'm starting to think we need a better approach. tgl
1705  * 2000/10/01
1706  *
1707  * Release 8.0 removes bigbox_ops (which was dead code for a long while
1708  * anyway). tgl 2003/11/11
1709  */
1710  if (list_length(opclass) == 1)
1711  {
1712  char *claname = strVal(linitial(opclass));
1713 
1714  if (strcmp(claname, "network_ops") == 0 ||
1715  strcmp(claname, "timespan_ops") == 0 ||
1716  strcmp(claname, "datetime_ops") == 0 ||
1717  strcmp(claname, "lztext_ops") == 0 ||
1718  strcmp(claname, "timestamp_ops") == 0 ||
1719  strcmp(claname, "bigbox_ops") == 0)
1720  opclass = NIL;
1721  }
1722 
1723  if (opclass == NIL)
1724  {
1725  /* no operator class specified, so find the default */
1726  opClassId = GetDefaultOpClass(attrType, accessMethodId);
1727  if (!OidIsValid(opClassId))
1728  ereport(ERROR,
1729  (errcode(ERRCODE_UNDEFINED_OBJECT),
1730  errmsg("data type %s has no default operator class for access method \"%s\"",
1731  format_type_be(attrType), accessMethodName),
1732  errhint("You must specify an operator class for the index or define a default operator class for the data type.")));
1733  return opClassId;
1734  }
1735 
1736  /*
1737  * Specific opclass name given, so look up the opclass.
1738  */
1739 
1740  /* deconstruct the name list */
1741  DeconstructQualifiedName(opclass, &schemaname, &opcname);
1742 
1743  if (schemaname)
1744  {
1745  /* Look in specific schema only */
1746  Oid namespaceId;
1747 
1748  namespaceId = LookupExplicitNamespace(schemaname, false);
1749  tuple = SearchSysCache3(CLAAMNAMENSP,
1750  ObjectIdGetDatum(accessMethodId),
1751  PointerGetDatum(opcname),
1752  ObjectIdGetDatum(namespaceId));
1753  }
1754  else
1755  {
1756  /* Unqualified opclass name, so search the search path */
1757  opClassId = OpclassnameGetOpcid(accessMethodId, opcname);
1758  if (!OidIsValid(opClassId))
1759  ereport(ERROR,
1760  (errcode(ERRCODE_UNDEFINED_OBJECT),
1761  errmsg("operator class \"%s\" does not exist for access method \"%s\"",
1762  opcname, accessMethodName)));
1763  tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opClassId));
1764  }
1765 
1766  if (!HeapTupleIsValid(tuple))
1767  ereport(ERROR,
1768  (errcode(ERRCODE_UNDEFINED_OBJECT),
1769  errmsg("operator class \"%s\" does not exist for access method \"%s\"",
1770  NameListToString(opclass), accessMethodName)));
1771 
1772  /*
1773  * Verify that the index operator class accepts this datatype. Note we
1774  * will accept binary compatibility.
1775  */
1776  opClassId = HeapTupleGetOid(tuple);
1777  opInputType = ((Form_pg_opclass) GETSTRUCT(tuple))->opcintype;
1778 
1779  if (!IsBinaryCoercible(attrType, opInputType))
1780  ereport(ERROR,
1781  (errcode(ERRCODE_DATATYPE_MISMATCH),
1782  errmsg("operator class \"%s\" does not accept data type %s",
1783  NameListToString(opclass), format_type_be(attrType))));
1784 
1785  ReleaseSysCache(tuple);
1786 
1787  return opClassId;
1788 }
#define NIL
Definition: pg_list.h:69
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:2872
int errhint(const char *fmt,...)
Definition: elog.c:987
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:1797
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
#define PointerGetDatum(X)
Definition: postgres.h:539
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:328
void DeconstructQualifiedName(List *names, char **nspname_p, char **objname_p)
Definition: namespace.c:2788
unsigned int Oid
Definition: postgres_ext.h:31
Oid OpclassnameGetOpcid(Oid amid, const char *opcname)
Definition: namespace.c:1779
#define OidIsValid(objectId)
Definition: c.h:605
#define linitial(l)
Definition: pg_list.h:111
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:1134
#define ereport(elevel, rest)
Definition: elog.h:122
bool IsBinaryCoercible(Oid srctype, Oid targettype)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
char * NameListToString(List *names)
Definition: namespace.c:3082
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static int list_length(const List *l)
Definition: pg_list.h:89
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:712
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:81