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:3592
void RelationGetExclusionInfo(Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
Definition: relcache.c:5071
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
#define IndexIsValid(indexForm)
Definition: pg_index.h:85
#define PointerGetDatum(X)
Definition: postgres.h:541
#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:492
#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:367
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:564
#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:534
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:1380
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:707
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 1323 of file indexcmds.c.

References contain_mutable_functions(), and expression_planner().

Referenced by CheckPredicate(), and ComputeIndexAttrs().

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

◆ CheckPredicate()

static void CheckPredicate ( Expr predicate)
static

Definition at line 1357 of file indexcmds.c.

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

Referenced by DefineIndex().

1358 {
1359  /*
1360  * transformExpr() should have already rejected subqueries, aggregates,
1361  * and window functions, based on the EXPR_KIND_ for a predicate.
1362  */
1363 
1364  /*
1365  * A predicate using mutable functions is probably wrong, for the same
1366  * reasons that we don't allow an index expression to use one.
1367  */
1368  if (CheckMutability(predicate))
1369  ereport(ERROR,
1370  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1371  errmsg("functions in index predicate must be marked IMMUTABLE")));
1372 }
static bool CheckMutability(Expr *expr)
Definition: indexcmds.c:1323
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 2103 of file indexcmds.c.

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

Referenced by DefineIndex().

2104 {
2105  List *result = NIL;
2106  ListCell *lc;
2107 
2108  foreach(lc, indexElems)
2109  {
2110  IndexElem *ielem = (IndexElem *) lfirst(lc);
2111  const char *origname;
2112  const char *curname;
2113  int i;
2114  char buf[NAMEDATALEN];
2115 
2116  /* Get the preliminary name from the IndexElem */
2117  if (ielem->indexcolname)
2118  origname = ielem->indexcolname; /* caller-specified name */
2119  else if (ielem->name)
2120  origname = ielem->name; /* simple column reference */
2121  else
2122  origname = "expr"; /* default name for expression */
2123 
2124  /* If it conflicts with any previous column, tweak it */
2125  curname = origname;
2126  for (i = 1;; i++)
2127  {
2128  ListCell *lc2;
2129  char nbuf[32];
2130  int nlen;
2131 
2132  foreach(lc2, result)
2133  {
2134  if (strcmp(curname, (char *) lfirst(lc2)) == 0)
2135  break;
2136  }
2137  if (lc2 == NULL)
2138  break; /* found nonconflicting name */
2139 
2140  sprintf(nbuf, "%d", i);
2141 
2142  /* Ensure generated names are shorter than NAMEDATALEN */
2143  nlen = pg_mbcliplen(origname, strlen(origname),
2144  NAMEDATALEN - 1 - strlen(nbuf));
2145  memcpy(buf, origname, nlen);
2146  strcpy(buf + nlen, nbuf);
2147  curname = buf;
2148  }
2149 
2150  /* And attach to the result list */
2151  result = lappend(result, pstrdup(curname));
2152  }
2153  return result;
2154 }
#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 2019 of file indexcmds.c.

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

Referenced by DefineIndex().

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

◆ ChooseIndexNameAddition()

static char * ChooseIndexNameAddition ( List colnames)
static

Definition at line 2069 of file indexcmds.c.

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

Referenced by ChooseIndexName().

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

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

Referenced by ChooseIndexName(), and generateSerialExtraStmts().

1990 {
1991  int pass = 0;
1992  char *relname = NULL;
1993  char modlabel[NAMEDATALEN];
1994 
1995  /* try the unmodified label first */
1996  StrNCpy(modlabel, label, sizeof(modlabel));
1997 
1998  for (;;)
1999  {
2000  relname = makeObjectName(name1, name2, modlabel);
2001 
2002  if (!OidIsValid(get_relname_relid(relname, namespaceid)))
2003  break;
2004 
2005  /* found a conflict, so try a new name component */
2006  pfree(relname);
2007  snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
2008  }
2009 
2010  return relname;
2011 }
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:1908
#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 1380 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().

1392 {
1393  ListCell *nextExclOp;
1394  ListCell *lc;
1395  int attn;
1396  int nkeycols = indexInfo->ii_NumIndexKeyAttrs;
1397 
1398  /* Allocate space for exclusion operator info, if needed */
1399  if (exclusionOpNames)
1400  {
1401  Assert(list_length(exclusionOpNames) == nkeycols);
1402  indexInfo->ii_ExclusionOps = (Oid *) palloc(sizeof(Oid) * nkeycols);
1403  indexInfo->ii_ExclusionProcs = (Oid *) palloc(sizeof(Oid) * nkeycols);
1404  indexInfo->ii_ExclusionStrats = (uint16 *) palloc(sizeof(uint16) * nkeycols);
1405  nextExclOp = list_head(exclusionOpNames);
1406  }
1407  else
1408  nextExclOp = NULL;
1409 
1410  /*
1411  * process attributeList
1412  */
1413  attn = 0;
1414  foreach(lc, attList)
1415  {
1416  IndexElem *attribute = (IndexElem *) lfirst(lc);
1417  Oid atttype;
1418  Oid attcollation;
1419 
1420  /*
1421  * Process the column-or-expression to be indexed.
1422  */
1423  if (attribute->name != NULL)
1424  {
1425  /* Simple index attribute */
1426  HeapTuple atttuple;
1427  Form_pg_attribute attform;
1428 
1429  Assert(attribute->expr == NULL);
1430  atttuple = SearchSysCacheAttName(relId, attribute->name);
1431  if (!HeapTupleIsValid(atttuple))
1432  {
1433  /* difference in error message spellings is historical */
1434  if (isconstraint)
1435  ereport(ERROR,
1436  (errcode(ERRCODE_UNDEFINED_COLUMN),
1437  errmsg("column \"%s\" named in key does not exist",
1438  attribute->name)));
1439  else
1440  ereport(ERROR,
1441  (errcode(ERRCODE_UNDEFINED_COLUMN),
1442  errmsg("column \"%s\" does not exist",
1443  attribute->name)));
1444  }
1445  attform = (Form_pg_attribute) GETSTRUCT(atttuple);
1446  indexInfo->ii_IndexAttrNumbers[attn] = attform->attnum;
1447  atttype = attform->atttypid;
1448  attcollation = attform->attcollation;
1449  ReleaseSysCache(atttuple);
1450  }
1451  else
1452  {
1453  /* Index expression */
1454  Node *expr = attribute->expr;
1455 
1456  Assert(expr != NULL);
1457 
1458  if (attn >= nkeycols)
1459  ereport(ERROR,
1460  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1461  errmsg("expressions are not supported in included columns")));
1462  atttype = exprType(expr);
1463  attcollation = exprCollation(expr);
1464 
1465  /*
1466  * Strip any top-level COLLATE clause. This ensures that we treat
1467  * "x COLLATE y" and "(x COLLATE y)" alike.
1468  */
1469  while (IsA(expr, CollateExpr))
1470  expr = (Node *) ((CollateExpr *) expr)->arg;
1471 
1472  if (IsA(expr, Var) &&
1473  ((Var *) expr)->varattno != InvalidAttrNumber)
1474  {
1475  /*
1476  * User wrote "(column)" or "(column COLLATE something)".
1477  * Treat it like simple attribute anyway.
1478  */
1479  indexInfo->ii_IndexAttrNumbers[attn] = ((Var *) expr)->varattno;
1480  }
1481  else
1482  {
1483  indexInfo->ii_IndexAttrNumbers[attn] = 0; /* marks expression */
1484  indexInfo->ii_Expressions = lappend(indexInfo->ii_Expressions,
1485  expr);
1486 
1487  /*
1488  * transformExpr() should have already rejected subqueries,
1489  * aggregates, and window functions, based on the EXPR_KIND_
1490  * for an index expression.
1491  */
1492 
1493  /*
1494  * An expression using mutable functions is probably wrong,
1495  * since if you aren't going to get the same result for the
1496  * same data every time, it's not clear what the index entries
1497  * mean at all.
1498  */
1499  if (CheckMutability((Expr *) expr))
1500  ereport(ERROR,
1501  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1502  errmsg("functions in index expression must be marked IMMUTABLE")));
1503  }
1504  }
1505 
1506  typeOidP[attn] = atttype;
1507 
1508  /*
1509  * Included columns have no collation, no opclass and no ordering
1510  * options.
1511  */
1512  if (attn >= nkeycols)
1513  {
1514  if (attribute->collation)
1515  ereport(ERROR,
1516  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1517  errmsg("including column does not support a collation")));
1518  if (attribute->opclass)
1519  ereport(ERROR,
1520  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1521  errmsg("including column does not support an operator class")));
1522  if (attribute->ordering != SORTBY_DEFAULT)
1523  ereport(ERROR,
1524  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1525  errmsg("including column does not support ASC/DESC options")));
1526  if (attribute->nulls_ordering != SORTBY_NULLS_DEFAULT)
1527  ereport(ERROR,
1528  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1529  errmsg("including column does not support NULLS FIRST/LAST options")));
1530 
1531  classOidP[attn] = InvalidOid;
1532  colOptionP[attn] = 0;
1533  collationOidP[attn] = InvalidOid;
1534  attn++;
1535 
1536  continue;
1537  }
1538 
1539  /*
1540  * Apply collation override if any
1541  */
1542  if (attribute->collation)
1543  attcollation = get_collation_oid(attribute->collation, false);
1544 
1545  /*
1546  * Check we have a collation iff it's a collatable type. The only
1547  * expected failures here are (1) COLLATE applied to a noncollatable
1548  * type, or (2) index expression had an unresolved collation. But we
1549  * might as well code this to be a complete consistency check.
1550  */
1551  if (type_is_collatable(atttype))
1552  {
1553  if (!OidIsValid(attcollation))
1554  ereport(ERROR,
1555  (errcode(ERRCODE_INDETERMINATE_COLLATION),
1556  errmsg("could not determine which collation to use for index expression"),
1557  errhint("Use the COLLATE clause to set the collation explicitly.")));
1558  }
1559  else
1560  {
1561  if (OidIsValid(attcollation))
1562  ereport(ERROR,
1563  (errcode(ERRCODE_DATATYPE_MISMATCH),
1564  errmsg("collations are not supported by type %s",
1565  format_type_be(atttype))));
1566  }
1567 
1568  collationOidP[attn] = attcollation;
1569 
1570  /*
1571  * Identify the opclass to use.
1572  */
1573  classOidP[attn] = ResolveOpClass(attribute->opclass,
1574  atttype,
1575  accessMethodName,
1576  accessMethodId);
1577 
1578  /*
1579  * Identify the exclusion operator, if any.
1580  */
1581  if (nextExclOp)
1582  {
1583  List *opname = (List *) lfirst(nextExclOp);
1584  Oid opid;
1585  Oid opfamily;
1586  int strat;
1587 
1588  /*
1589  * Find the operator --- it must accept the column datatype
1590  * without runtime coercion (but binary compatibility is OK)
1591  */
1592  opid = compatible_oper_opid(opname, atttype, atttype, false);
1593 
1594  /*
1595  * Only allow commutative operators to be used in exclusion
1596  * constraints. If X conflicts with Y, but Y does not conflict
1597  * with X, bad things will happen.
1598  */
1599  if (get_commutator(opid) != opid)
1600  ereport(ERROR,
1601  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1602  errmsg("operator %s is not commutative",
1603  format_operator(opid)),
1604  errdetail("Only commutative operators can be used in exclusion constraints.")));
1605 
1606  /*
1607  * Operator must be a member of the right opfamily, too
1608  */
1609  opfamily = get_opclass_family(classOidP[attn]);
1610  strat = get_op_opfamily_strategy(opid, opfamily);
1611  if (strat == 0)
1612  {
1613  HeapTuple opftuple;
1614  Form_pg_opfamily opfform;
1615 
1616  /*
1617  * attribute->opclass might not explicitly name the opfamily,
1618  * so fetch the name of the selected opfamily for use in the
1619  * error message.
1620  */
1621  opftuple = SearchSysCache1(OPFAMILYOID,
1622  ObjectIdGetDatum(opfamily));
1623  if (!HeapTupleIsValid(opftuple))
1624  elog(ERROR, "cache lookup failed for opfamily %u",
1625  opfamily);
1626  opfform = (Form_pg_opfamily) GETSTRUCT(opftuple);
1627 
1628  ereport(ERROR,
1629  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1630  errmsg("operator %s is not a member of operator family \"%s\"",
1631  format_operator(opid),
1632  NameStr(opfform->opfname)),
1633  errdetail("The exclusion operator must be related to the index operator class for the constraint.")));
1634  }
1635 
1636  indexInfo->ii_ExclusionOps[attn] = opid;
1637  indexInfo->ii_ExclusionProcs[attn] = get_opcode(opid);
1638  indexInfo->ii_ExclusionStrats[attn] = strat;
1639  nextExclOp = lnext(nextExclOp);
1640  }
1641 
1642  /*
1643  * Set up the per-column options (indoption field). For now, this is
1644  * zero for any un-ordered index, while ordered indexes have DESC and
1645  * NULLS FIRST/LAST options.
1646  */
1647  colOptionP[attn] = 0;
1648  if (amcanorder)
1649  {
1650  /* default ordering is ASC */
1651  if (attribute->ordering == SORTBY_DESC)
1652  colOptionP[attn] |= INDOPTION_DESC;
1653  /* default null ordering is LAST for ASC, FIRST for DESC */
1654  if (attribute->nulls_ordering == SORTBY_NULLS_DEFAULT)
1655  {
1656  if (attribute->ordering == SORTBY_DESC)
1657  colOptionP[attn] |= INDOPTION_NULLS_FIRST;
1658  }
1659  else if (attribute->nulls_ordering == SORTBY_NULLS_FIRST)
1660  colOptionP[attn] |= INDOPTION_NULLS_FIRST;
1661  }
1662  else
1663  {
1664  /* index AM does not support ordering */
1665  if (attribute->ordering != SORTBY_DEFAULT)
1666  ereport(ERROR,
1667  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1668  errmsg("access method \"%s\" does not support ASC/DESC options",
1669  accessMethodName)));
1670  if (attribute->nulls_ordering != SORTBY_NULLS_DEFAULT)
1671  ereport(ERROR,
1672  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1673  errmsg("access method \"%s\" does not support NULLS FIRST/LAST options",
1674  accessMethodName)));
1675  }
1676 
1677  attn++;
1678  }
1679 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:567
static bool CheckMutability(Expr *expr)
Definition: indexcmds.c:1323
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:668
Definition: nodes.h:516
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:163
#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:492
#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:1688
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
385  * columns, and which are just part of the INCLUDE list by checking the
386  * list position. A list item in a position less than ii_NumIndexKeyAttrs
387  * is part of the key columns, and anything equal to and over is part of
388  * the 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  /*
436  * Custom error message for FOREIGN TABLE since the term is close
437  * to a regular table and can confuse the user.
438  */
439  ereport(ERROR,
440  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
441  errmsg("cannot create index on foreign table \"%s\"",
442  RelationGetRelationName(rel))));
443  break;
444  default:
445  ereport(ERROR,
446  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
447  errmsg("\"%s\" is not a table or materialized view",
448  RelationGetRelationName(rel))));
449  break;
450  }
451 
452  /*
453  * Establish behavior for partitioned tables, and verify sanity of
454  * parameters.
455  *
456  * We do not build an actual index in this case; we only create a few
457  * catalog entries. The actual indexes are built by recursing for each
458  * partition.
459  */
460  partitioned = rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE;
461  if (partitioned)
462  {
463  if (stmt->concurrent)
464  ereport(ERROR,
465  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
466  errmsg("cannot create index on partitioned table \"%s\" concurrently",
467  RelationGetRelationName(rel))));
468  if (stmt->excludeOpNames)
469  ereport(ERROR,
470  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
471  errmsg("cannot create exclusion constraints on partitioned table \"%s\"",
472  RelationGetRelationName(rel))));
473  }
474 
475  /*
476  * Don't try to CREATE INDEX on temp tables of other backends.
477  */
478  if (RELATION_IS_OTHER_TEMP(rel))
479  ereport(ERROR,
480  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
481  errmsg("cannot create indexes on temporary tables of other sessions")));
482 
483  /*
484  * Unless our caller vouches for having checked this already, insist that
485  * the table not be in use by our own session, either. Otherwise we might
486  * fail to make entries in the new index (for instance, if an INSERT or
487  * UPDATE is in progress and has already made its list of target indexes).
488  */
489  if (check_not_in_use)
490  CheckTableNotInUse(rel, "CREATE INDEX");
491 
492  /*
493  * Verify we (still) have CREATE rights in the rel's namespace.
494  * (Presumably we did when the rel was created, but maybe not anymore.)
495  * Skip check if caller doesn't want it. Also skip check if
496  * bootstrapping, since permissions machinery may not be working yet.
497  */
498  if (check_rights && !IsBootstrapProcessingMode())
499  {
500  AclResult aclresult;
501 
502  aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
503  ACL_CREATE);
504  if (aclresult != ACLCHECK_OK)
505  aclcheck_error(aclresult, OBJECT_SCHEMA,
506  get_namespace_name(namespaceId));
507  }
508 
509  /*
510  * Select tablespace to use. If not specified, use default tablespace
511  * (which may in turn default to database's default).
512  */
513  if (stmt->tableSpace)
514  {
515  tablespaceId = get_tablespace_oid(stmt->tableSpace, false);
516  }
517  else
518  {
519  tablespaceId = GetDefaultTablespace(rel->rd_rel->relpersistence);
520  /* note InvalidOid is OK in this case */
521  }
522 
523  /* Check tablespace permissions */
524  if (check_rights &&
525  OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
526  {
527  AclResult aclresult;
528 
529  aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),
530  ACL_CREATE);
531  if (aclresult != ACLCHECK_OK)
533  get_tablespace_name(tablespaceId));
534  }
535 
536  /*
537  * Force shared indexes into the pg_global tablespace. This is a bit of a
538  * hack but seems simpler than marking them in the BKI commands. On the
539  * other hand, if it's not shared, don't allow it to be placed there.
540  */
541  if (rel->rd_rel->relisshared)
542  tablespaceId = GLOBALTABLESPACE_OID;
543  else if (tablespaceId == GLOBALTABLESPACE_OID)
544  ereport(ERROR,
545  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
546  errmsg("only shared relations can be placed in pg_global tablespace")));
547 
548  /*
549  * Choose the index column names.
550  */
551  indexColNames = ChooseIndexColumnNames(allIndexParams);
552 
553  /*
554  * Select name for index if caller didn't specify
555  */
556  indexRelationName = stmt->idxname;
557  if (indexRelationName == NULL)
558  indexRelationName = ChooseIndexName(RelationGetRelationName(rel),
559  namespaceId,
560  indexColNames,
561  stmt->excludeOpNames,
562  stmt->primary,
563  stmt->isconstraint);
564 
565  /*
566  * look up the access method, verify it can handle the requested features
567  */
568  accessMethodName = stmt->accessMethod;
569  tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
570  if (!HeapTupleIsValid(tuple))
571  {
572  /*
573  * Hack to provide more-or-less-transparent updating of old RTREE
574  * indexes to GiST: if RTREE is requested and not found, use GIST.
575  */
576  if (strcmp(accessMethodName, "rtree") == 0)
577  {
578  ereport(NOTICE,
579  (errmsg("substituting access method \"gist\" for obsolete method \"rtree\"")));
580  accessMethodName = "gist";
581  tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
582  }
583 
584  if (!HeapTupleIsValid(tuple))
585  ereport(ERROR,
586  (errcode(ERRCODE_UNDEFINED_OBJECT),
587  errmsg("access method \"%s\" does not exist",
588  accessMethodName)));
589  }
590  accessMethodId = HeapTupleGetOid(tuple);
591  accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
592  amRoutine = GetIndexAmRoutine(accessMethodForm->amhandler);
593 
594  if (stmt->unique && !amRoutine->amcanunique)
595  ereport(ERROR,
596  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
597  errmsg("access method \"%s\" does not support unique indexes",
598  accessMethodName)));
599  if (list_length(stmt->indexIncludingParams) > 0 && !amRoutine->amcaninclude)
600  ereport(ERROR,
601  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
602  errmsg("access method \"%s\" does not support included columns",
603  accessMethodName)));
604  if (numberOfAttributes > 1 && !amRoutine->amcanmulticol)
605  ereport(ERROR,
606  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
607  errmsg("access method \"%s\" does not support multicolumn indexes",
608  accessMethodName)));
609  if (stmt->excludeOpNames && amRoutine->amgettuple == NULL)
610  ereport(ERROR,
611  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
612  errmsg("access method \"%s\" does not support exclusion constraints",
613  accessMethodName)));
614 
615  amcanorder = amRoutine->amcanorder;
616  amoptions = amRoutine->amoptions;
617 
618  pfree(amRoutine);
619  ReleaseSysCache(tuple);
620 
621  /*
622  * Validate predicate, if given
623  */
624  if (stmt->whereClause)
625  CheckPredicate((Expr *) stmt->whereClause);
626 
627  /*
628  * Parse AM-specific options, convert to text array form, validate.
629  */
630  reloptions = transformRelOptions((Datum) 0, stmt->options,
631  NULL, NULL, false, false);
632 
633  (void) index_reloptions(amoptions, reloptions, true);
634 
635  /*
636  * Prepare arguments for index_create, primarily an IndexInfo structure.
637  * Note that ii_Predicate must be in implicit-AND format.
638  */
639  indexInfo = makeNode(IndexInfo);
640  indexInfo->ii_NumIndexAttrs = numberOfAttributes;
641  indexInfo->ii_NumIndexKeyAttrs = numberOfKeyAttributes;
642  indexInfo->ii_Expressions = NIL; /* for now */
643  indexInfo->ii_ExpressionsState = NIL;
644  indexInfo->ii_Predicate = make_ands_implicit((Expr *) stmt->whereClause);
645  indexInfo->ii_PredicateState = NULL;
646  indexInfo->ii_ExclusionOps = NULL;
647  indexInfo->ii_ExclusionProcs = NULL;
648  indexInfo->ii_ExclusionStrats = NULL;
649  indexInfo->ii_Unique = stmt->unique;
650  /* In a concurrent build, mark it not-ready-for-inserts */
651  indexInfo->ii_ReadyForInserts = !stmt->concurrent;
652  indexInfo->ii_Concurrent = stmt->concurrent;
653  indexInfo->ii_BrokenHotChain = false;
654  indexInfo->ii_ParallelWorkers = 0;
655  indexInfo->ii_Am = accessMethodId;
656  indexInfo->ii_AmCache = NULL;
657  indexInfo->ii_Context = CurrentMemoryContext;
658 
659  typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
660  collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
661  classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
662  coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16));
663  ComputeIndexAttrs(indexInfo,
664  typeObjectId, collationObjectId, classObjectId,
665  coloptions, allIndexParams,
666  stmt->excludeOpNames, relationId,
667  accessMethodName, accessMethodId,
668  amcanorder, stmt->isconstraint);
669 
670  /*
671  * Extra checks when creating a PRIMARY KEY index.
672  */
673  if (stmt->primary)
674  index_check_primary_key(rel, indexInfo, is_alter_table);
675 
676  /*
677  * If this table is partitioned and we're creating a unique index or a
678  * primary key, make sure that the indexed columns are part of the
679  * partition key. Otherwise it would be possible to violate uniqueness by
680  * putting values that ought to be unique in different partitions.
681  *
682  * We could lift this limitation if we had global indexes, but those have
683  * their own problems, so this is a useful feature combination.
684  */
685  if (partitioned && (stmt->unique || stmt->primary))
686  {
687  PartitionKey key = rel->rd_partkey;
688  int i;
689 
690  /*
691  * A partitioned table can have unique indexes, as long as all the
692  * columns in the partition key appear in the unique key. A
693  * partition-local index can enforce global uniqueness iff the PK
694  * value completely determines the partition that a row is in.
695  *
696  * Thus, verify that all the columns in the partition key appear in
697  * the unique key definition.
698  */
699  for (i = 0; i < key->partnatts; i++)
700  {
701  bool found = false;
702  int j;
703  const char *constraint_type;
704 
705  if (stmt->primary)
706  constraint_type = "PRIMARY KEY";
707  else if (stmt->unique)
708  constraint_type = "UNIQUE";
709  else if (stmt->excludeOpNames != NIL)
710  constraint_type = "EXCLUDE";
711  else
712  {
713  elog(ERROR, "unknown constraint type");
714  constraint_type = NULL; /* keep compiler quiet */
715  }
716 
717  /*
718  * It may be possible to support UNIQUE constraints when partition
719  * keys are expressions, but is it worth it? Give up for now.
720  */
721  if (key->partattrs[i] == 0)
722  ereport(ERROR,
723  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
724  errmsg("unsupported %s constraint with partition key definition",
725  constraint_type),
726  errdetail("%s constraints cannot be used when partition keys include expressions.",
727  constraint_type)));
728 
729  for (j = 0; j < indexInfo->ii_NumIndexAttrs; j++)
730  {
731  if (key->partattrs[i] == indexInfo->ii_IndexAttrNumbers[j])
732  {
733  found = true;
734  break;
735  }
736  }
737  if (!found)
738  {
739  Form_pg_attribute att;
740 
741  att = TupleDescAttr(RelationGetDescr(rel), key->partattrs[i] - 1);
742  ereport(ERROR,
743  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
744  errmsg("insufficient columns in %s constraint definition",
745  constraint_type),
746  errdetail("%s constraint on table \"%s\" lacks column \"%s\" which is part of the partition key.",
747  constraint_type, RelationGetRelationName(rel),
748  NameStr(att->attname))));
749  }
750  }
751  }
752 
753 
754  /*
755  * We disallow indexes on system columns other than OID. They would not
756  * necessarily get updated correctly, and they don't seem useful anyway.
757  */
758  for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
759  {
760  AttrNumber attno = indexInfo->ii_IndexAttrNumbers[i];
761 
762  if (attno < 0 && attno != ObjectIdAttributeNumber)
763  ereport(ERROR,
764  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
765  errmsg("index creation on system columns is not supported")));
766  }
767 
768  /*
769  * Also check for system columns used in expressions or predicates.
770  */
771  if (indexInfo->ii_Expressions || indexInfo->ii_Predicate)
772  {
773  Bitmapset *indexattrs = NULL;
774 
775  pull_varattnos((Node *) indexInfo->ii_Expressions, 1, &indexattrs);
776  pull_varattnos((Node *) indexInfo->ii_Predicate, 1, &indexattrs);
777 
778  for (i = FirstLowInvalidHeapAttributeNumber + 1; i < 0; i++)
779  {
780  if (i != ObjectIdAttributeNumber &&
782  indexattrs))
783  ereport(ERROR,
784  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
785  errmsg("index creation on system columns is not supported")));
786  }
787  }
788 
789  /*
790  * Report index creation if appropriate (delay this till after most of the
791  * error checks)
792  */
793  if (stmt->isconstraint && !quiet)
794  {
795  const char *constraint_type;
796 
797  if (stmt->primary)
798  constraint_type = "PRIMARY KEY";
799  else if (stmt->unique)
800  constraint_type = "UNIQUE";
801  else if (stmt->excludeOpNames != NIL)
802  constraint_type = "EXCLUDE";
803  else
804  {
805  elog(ERROR, "unknown constraint type");
806  constraint_type = NULL; /* keep compiler quiet */
807  }
808 
809  ereport(DEBUG1,
810  (errmsg("%s %s will create implicit index \"%s\" for table \"%s\"",
811  is_alter_table ? "ALTER TABLE / ADD" : "CREATE TABLE /",
812  constraint_type,
813  indexRelationName, RelationGetRelationName(rel))));
814  }
815 
816  /*
817  * A valid stmt->oldNode implies that we already have a built form of the
818  * index. The caller should also decline any index build.
819  */
820  Assert(!OidIsValid(stmt->oldNode) || (skip_build && !stmt->concurrent));
821 
822  /*
823  * Make the catalog entries for the index, including constraints. This
824  * step also actually builds the index, except if caller requested not to
825  * or in concurrent mode, in which case it'll be done later, or doing a
826  * partitioned index (because those don't have storage).
827  */
828  flags = constr_flags = 0;
829  if (stmt->isconstraint)
831  if (skip_build || stmt->concurrent || partitioned)
832  flags |= INDEX_CREATE_SKIP_BUILD;
833  if (stmt->if_not_exists)
835  if (stmt->concurrent)
836  flags |= INDEX_CREATE_CONCURRENT;
837  if (partitioned)
838  flags |= INDEX_CREATE_PARTITIONED;
839  if (stmt->primary)
840  flags |= INDEX_CREATE_IS_PRIMARY;
841  if (partitioned && stmt->relation && !stmt->relation->inh)
842  flags |= INDEX_CREATE_INVALID;
843 
844  if (stmt->deferrable)
845  constr_flags |= INDEX_CONSTR_CREATE_DEFERRABLE;
846  if (stmt->initdeferred)
847  constr_flags |= INDEX_CONSTR_CREATE_INIT_DEFERRED;
848 
849  indexRelationId =
850  index_create(rel, indexRelationName, indexRelationId, parentIndexId,
851  parentConstraintId,
852  stmt->oldNode, indexInfo, indexColNames,
853  accessMethodId, tablespaceId,
854  collationObjectId, classObjectId,
855  coloptions, reloptions,
856  flags, constr_flags,
857  allowSystemTableMods, !check_rights,
858  &createdConstraintId);
859 
860  ObjectAddressSet(address, RelationRelationId, indexRelationId);
861 
862  if (!OidIsValid(indexRelationId))
863  {
864  heap_close(rel, NoLock);
865  return address;
866  }
867 
868  /* Add any requested comment */
869  if (stmt->idxcomment != NULL)
870  CreateComments(indexRelationId, RelationRelationId, 0,
871  stmt->idxcomment);
872 
873  if (partitioned)
874  {
875  /*
876  * Unless caller specified to skip this step (via ONLY), process each
877  * partition to make sure they all contain a corresponding index.
878  *
879  * If we're called internally (no stmt->relation), recurse always.
880  */
881  if (!stmt->relation || stmt->relation->inh)
882  {
883  PartitionDesc partdesc = RelationGetPartitionDesc(rel);
884  int nparts = partdesc->nparts;
885  Oid *part_oids = palloc(sizeof(Oid) * nparts);
886  bool invalidate_parent = false;
887  TupleDesc parentDesc;
888  Oid *opfamOids;
889 
890  memcpy(part_oids, partdesc->oids, sizeof(Oid) * nparts);
891 
892  parentDesc = CreateTupleDescCopy(RelationGetDescr(rel));
893  opfamOids = palloc(sizeof(Oid) * numberOfKeyAttributes);
894  for (i = 0; i < numberOfKeyAttributes; i++)
895  opfamOids[i] = get_opclass_family(classObjectId[i]);
896 
897  heap_close(rel, NoLock);
898 
899  /*
900  * For each partition, scan all existing indexes; if one matches
901  * our index definition and is not already attached to some other
902  * parent index, attach it to the one we just created.
903  *
904  * If none matches, build a new index by calling ourselves
905  * recursively with the same options (except for the index name).
906  */
907  for (i = 0; i < nparts; i++)
908  {
909  Oid childRelid = part_oids[i];
910  Relation childrel;
911  List *childidxs;
912  ListCell *cell;
913  AttrNumber *attmap;
914  bool found = false;
915  int maplen;
916 
917  childrel = heap_open(childRelid, lockmode);
918  childidxs = RelationGetIndexList(childrel);
919  attmap =
921  parentDesc,
922  gettext_noop("could not convert row type"));
923  maplen = parentDesc->natts;
924 
925 
926  foreach(cell, childidxs)
927  {
928  Oid cldidxid = lfirst_oid(cell);
929  Relation cldidx;
930  IndexInfo *cldIdxInfo;
931 
932  /* this index is already partition of another one */
933  if (has_superclass(cldidxid))
934  continue;
935 
936  cldidx = index_open(cldidxid, lockmode);
937  cldIdxInfo = BuildIndexInfo(cldidx);
938  if (CompareIndexInfo(cldIdxInfo, indexInfo,
939  cldidx->rd_indcollation,
940  collationObjectId,
941  cldidx->rd_opfamily,
942  opfamOids,
943  attmap, maplen))
944  {
945  Oid cldConstrOid = InvalidOid;
946 
947  /*
948  * Found a match.
949  *
950  * If this index is being created in the parent
951  * because of a constraint, then the child needs to
952  * have a constraint also, so look for one. If there
953  * is no such constraint, this index is no good, so
954  * keep looking.
955  */
956  if (createdConstraintId != InvalidOid)
957  {
958  cldConstrOid =
960  cldidxid);
961  if (cldConstrOid == InvalidOid)
962  {
963  index_close(cldidx, lockmode);
964  continue;
965  }
966  }
967 
968  /* Attach index to parent and we're done. */
969  IndexSetParentIndex(cldidx, indexRelationId);
970  if (createdConstraintId != InvalidOid)
971  ConstraintSetParentConstraint(cldConstrOid,
972  createdConstraintId);
973 
974  if (!IndexIsValid(cldidx->rd_index))
975  invalidate_parent = true;
976 
977  found = true;
978  /* keep lock till commit */
979  index_close(cldidx, NoLock);
980  break;
981  }
982 
983  index_close(cldidx, lockmode);
984  }
985 
986  list_free(childidxs);
987  heap_close(childrel, NoLock);
988 
989  /*
990  * If no matching index was found, create our own.
991  */
992  if (!found)
993  {
994  IndexStmt *childStmt = copyObject(stmt);
995  bool found_whole_row;
996 
997  childStmt->whereClause =
998  map_variable_attnos(stmt->whereClause, 1, 0,
999  attmap, maplen,
1000  InvalidOid, &found_whole_row);
1001  if (found_whole_row)
1002  elog(ERROR, "cannot convert whole-row table reference");
1003 
1004  childStmt->idxname = NULL;
1005  childStmt->relationId = childRelid;
1006  DefineIndex(childRelid, childStmt,
1007  InvalidOid, /* no predefined OID */
1008  indexRelationId, /* this is our child */
1009  createdConstraintId,
1010  is_alter_table, check_rights, check_not_in_use,
1011  false, quiet);
1012  }
1013 
1014  pfree(attmap);
1015  }
1016 
1017  /*
1018  * The pg_index row we inserted for this index was marked
1019  * indisvalid=true. But if we attached an existing index that is
1020  * invalid, this is incorrect, so update our row to invalid too.
1021  */
1022  if (invalidate_parent)
1023  {
1024  Relation pg_index = heap_open(IndexRelationId, RowExclusiveLock);
1025  HeapTuple tup,
1026  newtup;
1027 
1029  ObjectIdGetDatum(indexRelationId));
1030  if (!tup)
1031  elog(ERROR, "cache lookup failed for index %u",
1032  indexRelationId);
1033  newtup = heap_copytuple(tup);
1034  ((Form_pg_index) GETSTRUCT(newtup))->indisvalid = false;
1035  CatalogTupleUpdate(pg_index, &tup->t_self, newtup);
1036  ReleaseSysCache(tup);
1037  heap_close(pg_index, RowExclusiveLock);
1038  heap_freetuple(newtup);
1039  }
1040  }
1041  else
1042  heap_close(rel, NoLock);
1043 
1044  /*
1045  * Indexes on partitioned tables are not themselves built, so we're
1046  * done here.
1047  */
1048  return address;
1049  }
1050 
1051  if (!stmt->concurrent)
1052  {
1053  /* Close the heap and we're done, in the non-concurrent case */
1054  heap_close(rel, NoLock);
1055  return address;
1056  }
1057 
1058  /* save lockrelid and locktag for below, then close rel */
1059  heaprelid = rel->rd_lockInfo.lockRelId;
1060  SET_LOCKTAG_RELATION(heaplocktag, heaprelid.dbId, heaprelid.relId);
1061  heap_close(rel, NoLock);
1062 
1063  /*
1064  * For a concurrent build, it's important to make the catalog entries
1065  * visible to other transactions before we start to build the index. That
1066  * will prevent them from making incompatible HOT updates. The new index
1067  * will be marked not indisready and not indisvalid, so that no one else
1068  * tries to either insert into it or use it for queries.
1069  *
1070  * We must commit our current transaction so that the index becomes
1071  * visible; then start another. Note that all the data structures we just
1072  * built are lost in the commit. The only data we keep past here are the
1073  * relation IDs.
1074  *
1075  * Before committing, get a session-level lock on the table, to ensure
1076  * that neither it nor the index can be dropped before we finish. This
1077  * cannot block, even if someone else is waiting for access, because we
1078  * already have the same lock within our transaction.
1079  *
1080  * Note: we don't currently bother with a session lock on the index,
1081  * because there are no operations that could change its state while we
1082  * hold lock on the parent table. This might need to change later.
1083  */
1085 
1089 
1090  /*
1091  * Phase 2 of concurrent index build (see comments for validate_index()
1092  * for an overview of how this works)
1093  *
1094  * Now we must wait until no running transaction could have the table open
1095  * with the old list of indexes. Use ShareLock to consider running
1096  * transactions that hold locks that permit writing to the table. Note we
1097  * do not need to worry about xacts that open the table for writing after
1098  * this point; they will see the new index when they open it.
1099  *
1100  * Note: the reason we use actual lock acquisition here, rather than just
1101  * checking the ProcArray and sleeping, is that deadlock is possible if
1102  * one of the transactions in question is blocked trying to acquire an
1103  * exclusive lock on our table. The lock code will detect deadlock and
1104  * error out properly.
1105  */
1106  WaitForLockers(heaplocktag, ShareLock);
1107 
1108  /*
1109  * At this moment we are sure that there are no transactions with the
1110  * table open for write that don't have this new index in their list of
1111  * indexes. We have waited out all the existing transactions and any new
1112  * transaction will have the new index in its list, but the index is still
1113  * marked as "not-ready-for-inserts". The index is consulted while
1114  * deciding HOT-safety though. This arrangement ensures that no new HOT
1115  * chains can be created where the new tuple and the old tuple in the
1116  * chain have different index keys.
1117  *
1118  * We now take a new snapshot, and build the index using all tuples that
1119  * are visible in this snapshot. We can be sure that any HOT updates to
1120  * these tuples will be compatible with the index, since any updates made
1121  * by transactions that didn't know about the index are now committed or
1122  * rolled back. Thus, each visible tuple is either the end of its
1123  * HOT-chain or the extension of the chain is HOT-safe for this index.
1124  */
1125 
1126  /* Open and lock the parent heap relation */
1128 
1129  /* And the target index relation */
1130  indexRelation = index_open(indexRelationId, RowExclusiveLock);
1131 
1132  /* Set ActiveSnapshot since functions in the indexes may need it */
1134 
1135  /* We have to re-build the IndexInfo struct, since it was lost in commit */
1136  indexInfo = BuildIndexInfo(indexRelation);
1137  Assert(!indexInfo->ii_ReadyForInserts);
1138  indexInfo->ii_Concurrent = true;
1139  indexInfo->ii_BrokenHotChain = false;
1140 
1141  /* Now build the index */
1142  index_build(rel, indexRelation, indexInfo, stmt->primary, false, true);
1143 
1144  /* Close both the relations, but keep the locks */
1145  heap_close(rel, NoLock);
1146  index_close(indexRelation, NoLock);
1147 
1148  /*
1149  * Update the pg_index row to mark the index as ready for inserts. Once we
1150  * commit this transaction, any new transactions that open the table must
1151  * insert new entries into the index for insertions and non-HOT updates.
1152  */
1154 
1155  /* we can do away with our snapshot */
1157 
1158  /*
1159  * Commit this transaction to make the indisready update visible.
1160  */
1163 
1164  /*
1165  * Phase 3 of concurrent index build
1166  *
1167  * We once again wait until no transaction can have the table open with
1168  * the index marked as read-only for updates.
1169  */
1170  WaitForLockers(heaplocktag, ShareLock);
1171 
1172  /*
1173  * Now take the "reference snapshot" that will be used by validate_index()
1174  * to filter candidate tuples. Beware! There might still be snapshots in
1175  * use that treat some transaction as in-progress that our reference
1176  * snapshot treats as committed. If such a recently-committed transaction
1177  * deleted tuples in the table, we will not include them in the index; yet
1178  * those transactions which see the deleting one as still-in-progress will
1179  * expect such tuples to be there once we mark the index as valid.
1180  *
1181  * We solve this by waiting for all endangered transactions to exit before
1182  * we mark the index as valid.
1183  *
1184  * We also set ActiveSnapshot to this snap, since functions in indexes may
1185  * need a snapshot.
1186  */
1188  PushActiveSnapshot(snapshot);
1189 
1190  /*
1191  * Scan the index and the heap, insert any missing index entries.
1192  */
1193  validate_index(relationId, indexRelationId, snapshot);
1194 
1195  /*
1196  * Drop the reference snapshot. We must do this before waiting out other
1197  * snapshot holders, else we will deadlock against other processes also
1198  * doing CREATE INDEX CONCURRENTLY, which would see our snapshot as one
1199  * they must wait for. But first, save the snapshot's xmin to use as
1200  * limitXmin for GetCurrentVirtualXIDs().
1201  */
1202  limitXmin = snapshot->xmin;
1203 
1205  UnregisterSnapshot(snapshot);
1206 
1207  /*
1208  * The snapshot subsystem could still contain registered snapshots that
1209  * are holding back our process's advertised xmin; in particular, if
1210  * default_transaction_isolation = serializable, there is a transaction
1211  * snapshot that is still active. The CatalogSnapshot is likewise a
1212  * hazard. To ensure no deadlocks, we must commit and start yet another
1213  * transaction, and do our wait before any snapshot has been taken in it.
1214  */
1217 
1218  /* We should now definitely not be advertising any xmin. */
1220 
1221  /*
1222  * The index is now valid in the sense that it contains all currently
1223  * interesting tuples. But since it might not contain tuples deleted just
1224  * before the reference snap was taken, we have to wait out any
1225  * transactions that might have older snapshots. Obtain a list of VXIDs
1226  * of such transactions, and wait for them individually.
1227  *
1228  * We can exclude any running transactions that have xmin > the xmin of
1229  * our reference snapshot; their oldest snapshot must be newer than ours.
1230  * We can also exclude any transactions that have xmin = zero, since they
1231  * evidently have no live snapshot at all (and any one they might be in
1232  * process of taking is certainly newer than ours). Transactions in other
1233  * DBs can be ignored too, since they'll never even be able to see this
1234  * index.
1235  *
1236  * We can also exclude autovacuum processes and processes running manual
1237  * lazy VACUUMs, because they won't be fazed by missing index entries
1238  * either. (Manual ANALYZEs, however, can't be excluded because they
1239  * might be within transactions that are going to do arbitrary operations
1240  * later.)
1241  *
1242  * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not
1243  * check for that.
1244  *
1245  * If a process goes idle-in-transaction with xmin zero, we do not need to
1246  * wait for it anymore, per the above argument. We do not have the
1247  * infrastructure right now to stop waiting if that happens, but we can at
1248  * least avoid the folly of waiting when it is idle at the time we would
1249  * begin to wait. We do this by repeatedly rechecking the output of
1250  * GetCurrentVirtualXIDs. If, during any iteration, a particular vxid
1251  * doesn't show up in the output, we know we can forget about it.
1252  */
1253  old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false,
1255  &n_old_snapshots);
1256 
1257  for (i = 0; i < n_old_snapshots; i++)
1258  {
1259  if (!VirtualTransactionIdIsValid(old_snapshots[i]))
1260  continue; /* found uninteresting in previous cycle */
1261 
1262  if (i > 0)
1263  {
1264  /* see if anything's changed ... */
1265  VirtualTransactionId *newer_snapshots;
1266  int n_newer_snapshots;
1267  int j;
1268  int k;
1269 
1270  newer_snapshots = GetCurrentVirtualXIDs(limitXmin,
1271  true, false,
1273  &n_newer_snapshots);
1274  for (j = i; j < n_old_snapshots; j++)
1275  {
1276  if (!VirtualTransactionIdIsValid(old_snapshots[j]))
1277  continue; /* found uninteresting in previous cycle */
1278  for (k = 0; k < n_newer_snapshots; k++)
1279  {
1280  if (VirtualTransactionIdEquals(old_snapshots[j],
1281  newer_snapshots[k]))
1282  break;
1283  }
1284  if (k >= n_newer_snapshots) /* not there anymore */
1285  SetInvalidVirtualTransactionId(old_snapshots[j]);
1286  }
1287  pfree(newer_snapshots);
1288  }
1289 
1290  if (VirtualTransactionIdIsValid(old_snapshots[i]))
1291  VirtualXactLock(old_snapshots[i], true);
1292  }
1293 
1294  /*
1295  * Index can now be marked valid -- update its pg_index entry
1296  */
1298 
1299  /*
1300  * The pg_index update will cause backends (including this one) to update
1301  * relcache entries for the index itself, but we should also send a
1302  * relcache inval on the parent table to force replanning of cached plans.
1303  * Otherwise existing sessions might fail to use the new index where it
1304  * would be useful. (Note that our earlier commits did not create reasons
1305  * to replan; so relcache flush on the index itself was sufficient.)
1306  */
1308 
1309  /*
1310  * Last thing to do is release the session-level lock on the parent table.
1311  */
1313 
1314  return address;
1315 }
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:2482
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:4701
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:668
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:3513
uint16 bits16
Definition: c.h:333
TransactionId xmin
Definition: proc.h:225
#define PointerGetDatum(X)
Definition: postgres.h:541
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:516
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:2103
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:4689
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:86
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:3349
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:492
#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:2467
#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:1300
#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:3209
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:69
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:3114
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:367
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:119
#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:564
#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:1357
#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:4260
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:1380
static char * ChooseIndexName(const char *tabname, Oid namespaceId, List *colnames, List *exclusionOpNames, bool primary, bool isconstraint)
Definition: indexcmds.c:2019
bytea *(* amoptions_function)(Datum reloptions, bool validate)
Definition: amapi.h:103
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:707
#define copyObject(obj)
Definition: nodes.h:629
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 1799 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().

1800 {
1801  Oid result = InvalidOid;
1802  int nexact = 0;
1803  int ncompatible = 0;
1804  int ncompatiblepreferred = 0;
1805  Relation rel;
1806  ScanKeyData skey[1];
1807  SysScanDesc scan;
1808  HeapTuple tup;
1809  TYPCATEGORY tcategory;
1810 
1811  /* If it's a domain, look at the base type instead */
1812  type_id = getBaseType(type_id);
1813 
1814  tcategory = TypeCategory(type_id);
1815 
1816  /*
1817  * We scan through all the opclasses available for the access method,
1818  * looking for one that is marked default and matches the target type
1819  * (either exactly or binary-compatibly, but prefer an exact match).
1820  *
1821  * We could find more than one binary-compatible match. If just one is
1822  * for a preferred type, use that one; otherwise we fail, forcing the user
1823  * to specify which one he wants. (The preferred-type special case is a
1824  * kluge for varchar: it's binary-compatible to both text and bpchar, so
1825  * we need a tiebreaker.) If we find more than one exact match, then
1826  * someone put bogus entries in pg_opclass.
1827  */
1828  rel = heap_open(OperatorClassRelationId, AccessShareLock);
1829 
1830  ScanKeyInit(&skey[0],
1831  Anum_pg_opclass_opcmethod,
1832  BTEqualStrategyNumber, F_OIDEQ,
1833  ObjectIdGetDatum(am_id));
1834 
1835  scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
1836  NULL, 1, skey);
1837 
1838  while (HeapTupleIsValid(tup = systable_getnext(scan)))
1839  {
1840  Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
1841 
1842  /* ignore altogether if not a default opclass */
1843  if (!opclass->opcdefault)
1844  continue;
1845  if (opclass->opcintype == type_id)
1846  {
1847  nexact++;
1848  result = HeapTupleGetOid(tup);
1849  }
1850  else if (nexact == 0 &&
1851  IsBinaryCoercible(type_id, opclass->opcintype))
1852  {
1853  if (IsPreferredType(tcategory, opclass->opcintype))
1854  {
1855  ncompatiblepreferred++;
1856  result = HeapTupleGetOid(tup);
1857  }
1858  else if (ncompatiblepreferred == 0)
1859  {
1860  ncompatible++;
1861  result = HeapTupleGetOid(tup);
1862  }
1863  }
1864  }
1865 
1866  systable_endscan(scan);
1867 
1869 
1870  /* raise error if pg_opclass contains inconsistent data */
1871  if (nexact > 1)
1872  ereport(ERROR,
1874  errmsg("there are multiple default operator classes for data type %s",
1875  format_type_be(type_id))));
1876 
1877  if (nexact == 1 ||
1878  ncompatiblepreferred == 1 ||
1879  (ncompatiblepreferred == 0 && ncompatible == 1))
1880  return result;
1881 
1882  return InvalidOid;
1883 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:502
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
#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:199
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:492
#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:707
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 2467 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().

2468 {
2469  Relation pg_inherits;
2470  ScanKeyData key[2];
2471  SysScanDesc scan;
2472  Oid partRelid = RelationGetRelid(partitionIdx);
2473  HeapTuple tuple;
2474  bool fix_dependencies;
2475 
2476  /* Make sure this is an index */
2477  Assert(partitionIdx->rd_rel->relkind == RELKIND_INDEX ||
2478  partitionIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
2479 
2480  /*
2481  * Scan pg_inherits for rows linking our index to some parent.
2482  */
2483  pg_inherits = relation_open(InheritsRelationId, RowExclusiveLock);
2484  ScanKeyInit(&key[0],
2485  Anum_pg_inherits_inhrelid,
2486  BTEqualStrategyNumber, F_OIDEQ,
2487  ObjectIdGetDatum(partRelid));
2488  ScanKeyInit(&key[1],
2489  Anum_pg_inherits_inhseqno,
2490  BTEqualStrategyNumber, F_INT4EQ,
2491  Int32GetDatum(1));
2492  scan = systable_beginscan(pg_inherits, InheritsRelidSeqnoIndexId, true,
2493  NULL, 2, key);
2494  tuple = systable_getnext(scan);
2495 
2496  if (!HeapTupleIsValid(tuple))
2497  {
2498  if (parentOid == InvalidOid)
2499  {
2500  /*
2501  * No pg_inherits row, and no parent wanted: nothing to do in this
2502  * case.
2503  */
2504  fix_dependencies = false;
2505  }
2506  else
2507  {
2508  Datum values[Natts_pg_inherits];
2509  bool isnull[Natts_pg_inherits];
2510 
2511  /*
2512  * No pg_inherits row exists, and we want a parent for this index,
2513  * so insert it.
2514  */
2515  values[Anum_pg_inherits_inhrelid - 1] = ObjectIdGetDatum(partRelid);
2516  values[Anum_pg_inherits_inhparent - 1] =
2517  ObjectIdGetDatum(parentOid);
2518  values[Anum_pg_inherits_inhseqno - 1] = Int32GetDatum(1);
2519  memset(isnull, false, sizeof(isnull));
2520 
2521  tuple = heap_form_tuple(RelationGetDescr(pg_inherits),
2522  values, isnull);
2523  CatalogTupleInsert(pg_inherits, tuple);
2524 
2525  fix_dependencies = true;
2526  }
2527  }
2528  else
2529  {
2530  Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(tuple);
2531 
2532  if (parentOid == InvalidOid)
2533  {
2534  /*
2535  * There exists a pg_inherits row, which we want to clear; do so.
2536  */
2537  CatalogTupleDelete(pg_inherits, &tuple->t_self);
2538  fix_dependencies = true;
2539  }
2540  else
2541  {
2542  /*
2543  * A pg_inherits row exists. If it's the same we want, then we're
2544  * good; if it differs, that amounts to a corrupt catalog and
2545  * should not happen.
2546  */
2547  if (inhForm->inhparent != parentOid)
2548  {
2549  /* unexpected: we should not get called in this case */
2550  elog(ERROR, "bogus pg_inherit row: inhrelid %u inhparent %u",
2551  inhForm->inhrelid, inhForm->inhparent);
2552  }
2553 
2554  /* already in the right state */
2555  fix_dependencies = false;
2556  }
2557  }
2558 
2559  /* done with pg_inherits */
2560  systable_endscan(scan);
2561  relation_close(pg_inherits, RowExclusiveLock);
2562 
2563  if (fix_dependencies)
2564  {
2565  ObjectAddress partIdx;
2566 
2567  /*
2568  * Insert/delete pg_depend rows. If setting a parent, add an
2569  * INTERNAL_AUTO dependency to the parent index; if making standalone,
2570  * remove all existing rows and put back the regular dependency on the
2571  * table.
2572  */
2573  ObjectAddressSet(partIdx, RelationRelationId, partRelid);
2574 
2575  if (OidIsValid(parentOid))
2576  {
2577  ObjectAddress parentIdx;
2578 
2579  ObjectAddressSet(parentIdx, RelationRelationId, parentOid);
2580  recordDependencyOn(&partIdx, &parentIdx, DEPENDENCY_INTERNAL_AUTO);
2581  }
2582  else
2583  {
2584  ObjectAddress partitionTbl;
2585 
2586  ObjectAddressSet(partitionTbl, RelationRelationId,
2587  partitionIdx->rd_index->indrelid);
2588 
2589  deleteDependencyRecordsForClass(RelationRelationId, partRelid,
2590  RelationRelationId,
2592 
2593  recordDependencyOn(&partIdx, &partitionTbl, DEPENDENCY_AUTO);
2594  }
2595 
2596  /* make our updates visible */
2598  }
2599 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:502
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
#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:492
#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:367
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:168
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:464
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 1908 of file indexcmds.c.

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

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

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

2204 {
2205  char relkind;
2206  Oid *heapOid = (Oid *) arg;
2207 
2208  /*
2209  * If we previously locked some other index's heap, and the name we're
2210  * looking up no longer refers to that relation, release the now-useless
2211  * lock.
2212  */
2213  if (relId != oldRelId && OidIsValid(oldRelId))
2214  {
2215  /* lock level here should match reindex_index() heap lock */
2216  UnlockRelationOid(*heapOid, ShareLock);
2217  *heapOid = InvalidOid;
2218  }
2219 
2220  /* If the relation does not exist, there's nothing more to do. */
2221  if (!OidIsValid(relId))
2222  return;
2223 
2224  /*
2225  * If the relation does exist, check whether it's an index. But note that
2226  * the relation might have been dropped between the time we did the name
2227  * lookup and now. In that case, there's nothing to do.
2228  */
2229  relkind = get_rel_relkind(relId);
2230  if (!relkind)
2231  return;
2232  if (relkind != RELKIND_INDEX &&
2233  relkind != RELKIND_PARTITIONED_INDEX)
2234  ereport(ERROR,
2235  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2236  errmsg("\"%s\" is not an index", relation->relname)));
2237 
2238  /* Check permissions */
2239  if (!pg_class_ownercheck(relId, GetUserId()))
2241 
2242  /* Lock heap before index to avoid deadlock. */
2243  if (relId != oldRelId)
2244  {
2245  /*
2246  * Lock level here should match reindex_index() heap lock. If the OID
2247  * isn't valid, it means the index as concurrently dropped, which is
2248  * not a problem for us; just return normally.
2249  */
2250  *heapOid = IndexGetRelation(relId, true);
2251  if (OidIsValid(*heapOid))
2252  LockRelationOid(*heapOid, ShareLock);
2253  }
2254 }
Oid IndexGetRelation(Oid indexId, bool missing_ok)
Definition: index.c:3592
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:68
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3349
#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:4751
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 2161 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().

2162 {
2163  Oid indOid;
2164  Oid heapOid = InvalidOid;
2165  Relation irel;
2166  char persistence;
2167 
2168  /*
2169  * Find and lock index, and check permissions on table; use callback to
2170  * obtain lock on table first, to avoid deadlock hazard. The lock level
2171  * used here must match the index lock obtained in reindex_index().
2172  */
2173  indOid = RangeVarGetRelidExtended(indexRelation, AccessExclusiveLock,
2174  0,
2176  (void *) &heapOid);
2177 
2178  /*
2179  * Obtain the current persistence of the existing index. We already hold
2180  * lock on the index.
2181  */
2182  irel = index_open(indOid, NoLock);
2183 
2184  if (irel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
2185  {
2187  return;
2188  }
2189 
2190  persistence = irel->rd_rel->relpersistence;
2191  index_close(irel, NoLock);
2192 
2193  reindex_index(indOid, false, persistence, options);
2194 }
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:2202
#define InvalidOid
Definition: postgres_ext.h:36
void reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, int options)
Definition: index.c:3617
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:2453
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:150

◆ ReindexMultipleTables()

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

Definition at line 2289 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().

2291 {
2292  Oid objectOid;
2293  Relation relationRelation;
2294  HeapScanDesc scan;
2295  ScanKeyData scan_keys[1];
2296  HeapTuple tuple;
2297  MemoryContext private_context;
2298  MemoryContext old;
2299  List *relids = NIL;
2300  ListCell *l;
2301  int num_keys;
2302 
2303  AssertArg(objectName);
2304  Assert(objectKind == REINDEX_OBJECT_SCHEMA ||
2305  objectKind == REINDEX_OBJECT_SYSTEM ||
2306  objectKind == REINDEX_OBJECT_DATABASE);
2307 
2308  /*
2309  * Get OID of object to reindex, being the database currently being used
2310  * by session for a database or for system catalogs, or the schema defined
2311  * by caller. At the same time do permission checks that need different
2312  * processing depending on the object type.
2313  */
2314  if (objectKind == REINDEX_OBJECT_SCHEMA)
2315  {
2316  objectOid = get_namespace_oid(objectName, false);
2317 
2318  if (!pg_namespace_ownercheck(objectOid, GetUserId()))
2320  objectName);
2321  }
2322  else
2323  {
2324  objectOid = MyDatabaseId;
2325 
2326  if (strcmp(objectName, get_database_name(objectOid)) != 0)
2327  ereport(ERROR,
2328  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2329  errmsg("can only reindex the currently open database")));
2330  if (!pg_database_ownercheck(objectOid, GetUserId()))
2332  objectName);
2333  }
2334 
2335  /*
2336  * Create a memory context that will survive forced transaction commits we
2337  * do below. Since it is a child of PortalContext, it will go away
2338  * eventually even if we suffer an error; there's no need for special
2339  * abort cleanup logic.
2340  */
2341  private_context = AllocSetContextCreate(PortalContext,
2342  "ReindexMultipleTables",
2344 
2345  /*
2346  * Define the search keys to find the objects to reindex. For a schema, we
2347  * select target relations using relnamespace, something not necessary for
2348  * a database-wide operation.
2349  */
2350  if (objectKind == REINDEX_OBJECT_SCHEMA)
2351  {
2352  num_keys = 1;
2353  ScanKeyInit(&scan_keys[0],
2354  Anum_pg_class_relnamespace,
2355  BTEqualStrategyNumber, F_OIDEQ,
2356  ObjectIdGetDatum(objectOid));
2357  }
2358  else
2359  num_keys = 0;
2360 
2361  /*
2362  * Scan pg_class to build a list of the relations we need to reindex.
2363  *
2364  * We only consider plain relations and materialized views here (toast
2365  * rels will be processed indirectly by reindex_relation).
2366  */
2367  relationRelation = heap_open(RelationRelationId, AccessShareLock);
2368  scan = heap_beginscan_catalog(relationRelation, num_keys, scan_keys);
2369  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2370  {
2371  Form_pg_class classtuple = (Form_pg_class) GETSTRUCT(tuple);
2372  Oid relid = HeapTupleGetOid(tuple);
2373 
2374  /*
2375  * Only regular tables and matviews can have indexes, so ignore any
2376  * other kind of relation.
2377  *
2378  * It is tempting to also consider partitioned tables here, but that
2379  * has the problem that if the children are in the same schema, they
2380  * would be processed twice. Maybe we could have a separate list of
2381  * partitioned tables, and expand that afterwards into relids,
2382  * ignoring any duplicates.
2383  */
2384  if (classtuple->relkind != RELKIND_RELATION &&
2385  classtuple->relkind != RELKIND_MATVIEW)
2386  continue;
2387 
2388  /* Skip temp tables of other backends; we can't reindex them at all */
2389  if (classtuple->relpersistence == RELPERSISTENCE_TEMP &&
2390  !isTempNamespace(classtuple->relnamespace))
2391  continue;
2392 
2393  /* Check user/system classification, and optionally skip */
2394  if (objectKind == REINDEX_OBJECT_SYSTEM &&
2395  !IsSystemClass(relid, classtuple))
2396  continue;
2397 
2398  /* Save the list of relation OIDs in private context */
2399  old = MemoryContextSwitchTo(private_context);
2400 
2401  /*
2402  * We always want to reindex pg_class first if it's selected to be
2403  * reindexed. This ensures that if there is any corruption in
2404  * pg_class' indexes, they will be fixed before we process any other
2405  * tables. This is critical because reindexing itself will try to
2406  * update pg_class.
2407  */
2408  if (relid == RelationRelationId)
2409  relids = lcons_oid(relid, relids);
2410  else
2411  relids = lappend_oid(relids, relid);
2412 
2413  MemoryContextSwitchTo(old);
2414  }
2415  heap_endscan(scan);
2416  heap_close(relationRelation, AccessShareLock);
2417 
2418  /* Now reindex each rel in a separate transaction */
2421  foreach(l, relids)
2422  {
2423  Oid relid = lfirst_oid(l);
2424 
2426  /* functions in indexes may want a snapshot set */
2428  if (reindex_relation(relid,
2431  options))
2432 
2434  ereport(INFO,
2435  (errmsg("table \"%s.%s\" was reindexed",
2437  get_rel_name(relid))));
2440  }
2442 
2443  MemoryContextDelete(private_context);
2444 }
#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:668
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:4927
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:3349
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#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:5169
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:170
Oid MyDatabaseId
Definition: globals.c:84
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:93
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:707
bool reindex_relation(Oid relid, int flags, int options)
Definition: index.c:3834
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 2453 of file indexcmds.c.

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

Referenced by ReindexIndex().

2454 {
2455  ereport(ERROR,
2456  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2457  errmsg("REINDEX is not yet implemented for partitioned indexes")));
2458 }
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 2261 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().

2262 {
2263  Oid heapOid;
2264 
2265  /* The lock level used here should match reindex_relation(). */
2266  heapOid = RangeVarGetRelidExtended(relation, ShareLock, 0,
2268 
2269  if (!reindex_relation(heapOid,
2272  options))
2273  ereport(NOTICE,
2274  (errmsg("table \"%s\" has no indexes",
2275  relation->relname)));
2276 
2277  return heapOid;
2278 }
void RangeVarCallbackOwnsTable(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:13374
unsigned int Oid
Definition: postgres_ext.h:31
char * relname
Definition: primnodes.h:68
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:3834

◆ ResolveOpClass()

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

Definition at line 1688 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().

1690 {
1691  char *schemaname;
1692  char *opcname;
1693  HeapTuple tuple;
1694  Oid opClassId,
1695  opInputType;
1696 
1697  /*
1698  * Release 7.0 removed network_ops, timespan_ops, and datetime_ops, so we
1699  * ignore those opclass names so the default *_ops is used. This can be
1700  * removed in some later release. bjm 2000/02/07
1701  *
1702  * Release 7.1 removes lztext_ops, so suppress that too for a while. tgl
1703  * 2000/07/30
1704  *
1705  * Release 7.2 renames timestamp_ops to timestamptz_ops, so suppress that
1706  * too for awhile. I'm starting to think we need a better approach. tgl
1707  * 2000/10/01
1708  *
1709  * Release 8.0 removes bigbox_ops (which was dead code for a long while
1710  * anyway). tgl 2003/11/11
1711  */
1712  if (list_length(opclass) == 1)
1713  {
1714  char *claname = strVal(linitial(opclass));
1715 
1716  if (strcmp(claname, "network_ops") == 0 ||
1717  strcmp(claname, "timespan_ops") == 0 ||
1718  strcmp(claname, "datetime_ops") == 0 ||
1719  strcmp(claname, "lztext_ops") == 0 ||
1720  strcmp(claname, "timestamp_ops") == 0 ||
1721  strcmp(claname, "bigbox_ops") == 0)
1722  opclass = NIL;
1723  }
1724 
1725  if (opclass == NIL)
1726  {
1727  /* no operator class specified, so find the default */
1728  opClassId = GetDefaultOpClass(attrType, accessMethodId);
1729  if (!OidIsValid(opClassId))
1730  ereport(ERROR,
1731  (errcode(ERRCODE_UNDEFINED_OBJECT),
1732  errmsg("data type %s has no default operator class for access method \"%s\"",
1733  format_type_be(attrType), accessMethodName),
1734  errhint("You must specify an operator class for the index or define a default operator class for the data type.")));
1735  return opClassId;
1736  }
1737 
1738  /*
1739  * Specific opclass name given, so look up the opclass.
1740  */
1741 
1742  /* deconstruct the name list */
1743  DeconstructQualifiedName(opclass, &schemaname, &opcname);
1744 
1745  if (schemaname)
1746  {
1747  /* Look in specific schema only */
1748  Oid namespaceId;
1749 
1750  namespaceId = LookupExplicitNamespace(schemaname, false);
1751  tuple = SearchSysCache3(CLAAMNAMENSP,
1752  ObjectIdGetDatum(accessMethodId),
1753  PointerGetDatum(opcname),
1754  ObjectIdGetDatum(namespaceId));
1755  }
1756  else
1757  {
1758  /* Unqualified opclass name, so search the search path */
1759  opClassId = OpclassnameGetOpcid(accessMethodId, opcname);
1760  if (!OidIsValid(opClassId))
1761  ereport(ERROR,
1762  (errcode(ERRCODE_UNDEFINED_OBJECT),
1763  errmsg("operator class \"%s\" does not exist for access method \"%s\"",
1764  opcname, accessMethodName)));
1765  tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opClassId));
1766  }
1767 
1768  if (!HeapTupleIsValid(tuple))
1769  ereport(ERROR,
1770  (errcode(ERRCODE_UNDEFINED_OBJECT),
1771  errmsg("operator class \"%s\" does not exist for access method \"%s\"",
1772  NameListToString(opclass), accessMethodName)));
1773 
1774  /*
1775  * Verify that the index operator class accepts this datatype. Note we
1776  * will accept binary compatibility.
1777  */
1778  opClassId = HeapTupleGetOid(tuple);
1779  opInputType = ((Form_pg_opclass) GETSTRUCT(tuple))->opcintype;
1780 
1781  if (!IsBinaryCoercible(attrType, opInputType))
1782  ereport(ERROR,
1783  (errcode(ERRCODE_DATATYPE_MISMATCH),
1784  errmsg("operator class \"%s\" does not accept data type %s",
1785  NameListToString(opclass), format_type_be(attrType))));
1786 
1787  ReleaseSysCache(tuple);
1788 
1789  return opClassId;
1790 }
#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:1799
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
#define PointerGetDatum(X)
Definition: postgres.h:541
#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:492
#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:707
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:81