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_fn.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_inherits_fn.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/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 124 of file indexcmds.c.

References AccessShareLock, IndexAmRoutine::amcanorder, AMNAME, Anum_pg_index_indclass, Anum_pg_index_indcollation, Anum_pg_index_indexprs, Anum_pg_index_indpred, 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_PredicateState, index_close(), INDEX_MAX_KEYS, index_open(), IndexGetRelation(), IndexIsValid, INDEXRELID, IsPolymorphicType, 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().

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

◆ CheckMutability()

static bool CheckMutability ( Expr expr)
static

Definition at line 1279 of file indexcmds.c.

References contain_mutable_functions(), and expression_planner().

Referenced by CheckPredicate(), and ComputeIndexAttrs().

1280 {
1281  /*
1282  * First run the expression through the planner. This has a couple of
1283  * important consequences. First, function default arguments will get
1284  * inserted, which may affect volatility (consider "default now()").
1285  * Second, inline-able functions will get inlined, which may allow us to
1286  * conclude that the function is really less volatile than it's marked. As
1287  * an example, polymorphic functions must be marked with the most volatile
1288  * behavior that they have for any input type, but once we inline the
1289  * function we may be able to conclude that it's not so volatile for the
1290  * particular input type we're dealing with.
1291  *
1292  * We assume here that expression_planner() won't scribble on its input.
1293  */
1294  expr = expression_planner(expr);
1295 
1296  /* Now we can search for non-immutable functions */
1297  return contain_mutable_functions((Node *) expr);
1298 }
Expr * expression_planner(Expr *expr)
Definition: planner.c:5667
Definition: nodes.h:513
bool contain_mutable_functions(Node *clause)
Definition: clauses.c:881

◆ CheckPredicate()

static void CheckPredicate ( Expr predicate)
static

Definition at line 1313 of file indexcmds.c.

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

Referenced by DefineIndex().

1314 {
1315  /*
1316  * transformExpr() should have already rejected subqueries, aggregates,
1317  * and window functions, based on the EXPR_KIND_ for a predicate.
1318  */
1319 
1320  /*
1321  * A predicate using mutable functions is probably wrong, for the same
1322  * reasons that we don't allow an index expression to use one.
1323  */
1324  if (CheckMutability(predicate))
1325  ereport(ERROR,
1326  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1327  errmsg("functions in index predicate must be marked IMMUTABLE")));
1328 }
static bool CheckMutability(Expr *expr)
Definition: indexcmds.c:1279
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 2020 of file indexcmds.c.

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

Referenced by DefineIndex().

2021 {
2022  List *result = NIL;
2023  ListCell *lc;
2024 
2025  foreach(lc, indexElems)
2026  {
2027  IndexElem *ielem = (IndexElem *) lfirst(lc);
2028  const char *origname;
2029  const char *curname;
2030  int i;
2031  char buf[NAMEDATALEN];
2032 
2033  /* Get the preliminary name from the IndexElem */
2034  if (ielem->indexcolname)
2035  origname = ielem->indexcolname; /* caller-specified name */
2036  else if (ielem->name)
2037  origname = ielem->name; /* simple column reference */
2038  else
2039  origname = "expr"; /* default name for expression */
2040 
2041  /* If it conflicts with any previous column, tweak it */
2042  curname = origname;
2043  for (i = 1;; i++)
2044  {
2045  ListCell *lc2;
2046  char nbuf[32];
2047  int nlen;
2048 
2049  foreach(lc2, result)
2050  {
2051  if (strcmp(curname, (char *) lfirst(lc2)) == 0)
2052  break;
2053  }
2054  if (lc2 == NULL)
2055  break; /* found nonconflicting name */
2056 
2057  sprintf(nbuf, "%d", i);
2058 
2059  /* Ensure generated names are shorter than NAMEDATALEN */
2060  nlen = pg_mbcliplen(origname, strlen(origname),
2061  NAMEDATALEN - 1 - strlen(nbuf));
2062  memcpy(buf, origname, nlen);
2063  strcpy(buf + nlen, nbuf);
2064  curname = buf;
2065  }
2066 
2067  /* And attach to the result list */
2068  result = lappend(result, pstrdup(curname));
2069  }
2070  return result;
2071 }
#define NIL
Definition: pg_list.h:69
char * pstrdup(const char *in)
Definition: mcxt.c:1063
#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:698
List * lappend(List *list, void *datum)
Definition: list.c:128
#define lfirst(lc)
Definition: pg_list.h:106
char * name
Definition: parsenodes.h:696
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 1938 of file indexcmds.c.

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

Referenced by DefineIndex().

1941 {
1942  char *indexname;
1943 
1944  if (primary)
1945  {
1946  /* the primary key's name does not depend on the specific column(s) */
1947  indexname = ChooseRelationName(tabname,
1948  NULL,
1949  "pkey",
1950  namespaceId);
1951  }
1952  else if (exclusionOpNames != NIL)
1953  {
1954  indexname = ChooseRelationName(tabname,
1955  ChooseIndexNameAddition(colnames),
1956  "excl",
1957  namespaceId);
1958  }
1959  else if (isconstraint)
1960  {
1961  indexname = ChooseRelationName(tabname,
1962  ChooseIndexNameAddition(colnames),
1963  "key",
1964  namespaceId);
1965  }
1966  else
1967  {
1968  indexname = ChooseRelationName(tabname,
1969  ChooseIndexNameAddition(colnames),
1970  "idx",
1971  namespaceId);
1972  }
1973 
1974  return indexname;
1975 }
#define NIL
Definition: pg_list.h:69
static char * ChooseIndexNameAddition(List *colnames)
Definition: indexcmds.c:1986
char * ChooseRelationName(const char *name1, const char *name2, const char *label, Oid namespaceid)
Definition: indexcmds.c:1907

◆ ChooseIndexNameAddition()

static char * ChooseIndexNameAddition ( List colnames)
static

Definition at line 1986 of file indexcmds.c.

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

Referenced by ChooseIndexName().

1987 {
1988  char buf[NAMEDATALEN * 2];
1989  int buflen = 0;
1990  ListCell *lc;
1991 
1992  buf[0] = '\0';
1993  foreach(lc, colnames)
1994  {
1995  const char *name = (const char *) lfirst(lc);
1996 
1997  if (buflen > 0)
1998  buf[buflen++] = '_'; /* insert _ between names */
1999 
2000  /*
2001  * At this point we have buflen <= NAMEDATALEN. name should be less
2002  * than NAMEDATALEN already, but use strlcpy for paranoia.
2003  */
2004  strlcpy(buf + buflen, name, NAMEDATALEN);
2005  buflen += strlen(buf + buflen);
2006  if (buflen >= NAMEDATALEN)
2007  break;
2008  }
2009  return pstrdup(buf);
2010 }
char * pstrdup(const char *in)
Definition: mcxt.c:1063
#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 1907 of file indexcmds.c.

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

Referenced by ChooseIndexName(), and generateSerialExtraStmts().

1909 {
1910  int pass = 0;
1911  char *relname = NULL;
1912  char modlabel[NAMEDATALEN];
1913 
1914  /* try the unmodified label first */
1915  StrNCpy(modlabel, label, sizeof(modlabel));
1916 
1917  for (;;)
1918  {
1919  relname = makeObjectName(name1, name2, modlabel);
1920 
1921  if (!OidIsValid(get_relname_relid(relname, namespaceid)))
1922  break;
1923 
1924  /* found a conflict, so try a new name component */
1925  pfree(relname);
1926  snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
1927  }
1928 
1929  return relname;
1930 }
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define OidIsValid(objectId)
Definition: c.h:594
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition: indexcmds.c:1827
#define NAMEDATALEN
void pfree(void *pointer)
Definition: mcxt.c:936
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1687
static char * label
Definition: pg_basebackup.c:82
#define StrNCpy(dst, src, len)
Definition: c.h:870

◆ 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 1335 of file indexcmds.c.

References arg, Assert, 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_KeyAttrNumbers, INDOPTION_DESC, INDOPTION_NULLS_FIRST, InvalidAttrNumber, 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().

1347 {
1348  ListCell *nextExclOp;
1349  ListCell *lc;
1350  int attn;
1351 
1352  /* Allocate space for exclusion operator info, if needed */
1353  if (exclusionOpNames)
1354  {
1355  int ncols = list_length(attList);
1356 
1357  Assert(list_length(exclusionOpNames) == ncols);
1358  indexInfo->ii_ExclusionOps = (Oid *) palloc(sizeof(Oid) * ncols);
1359  indexInfo->ii_ExclusionProcs = (Oid *) palloc(sizeof(Oid) * ncols);
1360  indexInfo->ii_ExclusionStrats = (uint16 *) palloc(sizeof(uint16) * ncols);
1361  nextExclOp = list_head(exclusionOpNames);
1362  }
1363  else
1364  nextExclOp = NULL;
1365 
1366  /*
1367  * process attributeList
1368  */
1369  attn = 0;
1370  foreach(lc, attList)
1371  {
1372  IndexElem *attribute = (IndexElem *) lfirst(lc);
1373  Oid atttype;
1374  Oid attcollation;
1375 
1376  /*
1377  * Process the column-or-expression to be indexed.
1378  */
1379  if (attribute->name != NULL)
1380  {
1381  /* Simple index attribute */
1382  HeapTuple atttuple;
1383  Form_pg_attribute attform;
1384 
1385  Assert(attribute->expr == NULL);
1386  atttuple = SearchSysCacheAttName(relId, attribute->name);
1387  if (!HeapTupleIsValid(atttuple))
1388  {
1389  /* difference in error message spellings is historical */
1390  if (isconstraint)
1391  ereport(ERROR,
1392  (errcode(ERRCODE_UNDEFINED_COLUMN),
1393  errmsg("column \"%s\" named in key does not exist",
1394  attribute->name)));
1395  else
1396  ereport(ERROR,
1397  (errcode(ERRCODE_UNDEFINED_COLUMN),
1398  errmsg("column \"%s\" does not exist",
1399  attribute->name)));
1400  }
1401  attform = (Form_pg_attribute) GETSTRUCT(atttuple);
1402  indexInfo->ii_KeyAttrNumbers[attn] = attform->attnum;
1403  atttype = attform->atttypid;
1404  attcollation = attform->attcollation;
1405  ReleaseSysCache(atttuple);
1406  }
1407  else
1408  {
1409  /* Index expression */
1410  Node *expr = attribute->expr;
1411 
1412  Assert(expr != NULL);
1413  atttype = exprType(expr);
1414  attcollation = exprCollation(expr);
1415 
1416  /*
1417  * Strip any top-level COLLATE clause. This ensures that we treat
1418  * "x COLLATE y" and "(x COLLATE y)" alike.
1419  */
1420  while (IsA(expr, CollateExpr))
1421  expr = (Node *) ((CollateExpr *) expr)->arg;
1422 
1423  if (IsA(expr, Var) &&
1424  ((Var *) expr)->varattno != InvalidAttrNumber)
1425  {
1426  /*
1427  * User wrote "(column)" or "(column COLLATE something)".
1428  * Treat it like simple attribute anyway.
1429  */
1430  indexInfo->ii_KeyAttrNumbers[attn] = ((Var *) expr)->varattno;
1431  }
1432  else
1433  {
1434  indexInfo->ii_KeyAttrNumbers[attn] = 0; /* marks expression */
1435  indexInfo->ii_Expressions = lappend(indexInfo->ii_Expressions,
1436  expr);
1437 
1438  /*
1439  * transformExpr() should have already rejected subqueries,
1440  * aggregates, and window functions, based on the EXPR_KIND_
1441  * for an index expression.
1442  */
1443 
1444  /*
1445  * An expression using mutable functions is probably wrong,
1446  * since if you aren't going to get the same result for the
1447  * same data every time, it's not clear what the index entries
1448  * mean at all.
1449  */
1450  if (CheckMutability((Expr *) expr))
1451  ereport(ERROR,
1452  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1453  errmsg("functions in index expression must be marked IMMUTABLE")));
1454  }
1455  }
1456 
1457  typeOidP[attn] = atttype;
1458 
1459  /*
1460  * Apply collation override if any
1461  */
1462  if (attribute->collation)
1463  attcollation = get_collation_oid(attribute->collation, false);
1464 
1465  /*
1466  * Check we have a collation iff it's a collatable type. The only
1467  * expected failures here are (1) COLLATE applied to a noncollatable
1468  * type, or (2) index expression had an unresolved collation. But we
1469  * might as well code this to be a complete consistency check.
1470  */
1471  if (type_is_collatable(atttype))
1472  {
1473  if (!OidIsValid(attcollation))
1474  ereport(ERROR,
1475  (errcode(ERRCODE_INDETERMINATE_COLLATION),
1476  errmsg("could not determine which collation to use for index expression"),
1477  errhint("Use the COLLATE clause to set the collation explicitly.")));
1478  }
1479  else
1480  {
1481  if (OidIsValid(attcollation))
1482  ereport(ERROR,
1483  (errcode(ERRCODE_DATATYPE_MISMATCH),
1484  errmsg("collations are not supported by type %s",
1485  format_type_be(atttype))));
1486  }
1487 
1488  collationOidP[attn] = attcollation;
1489 
1490  /*
1491  * Identify the opclass to use.
1492  */
1493  classOidP[attn] = ResolveOpClass(attribute->opclass,
1494  atttype,
1495  accessMethodName,
1496  accessMethodId);
1497 
1498  /*
1499  * Identify the exclusion operator, if any.
1500  */
1501  if (nextExclOp)
1502  {
1503  List *opname = (List *) lfirst(nextExclOp);
1504  Oid opid;
1505  Oid opfamily;
1506  int strat;
1507 
1508  /*
1509  * Find the operator --- it must accept the column datatype
1510  * without runtime coercion (but binary compatibility is OK)
1511  */
1512  opid = compatible_oper_opid(opname, atttype, atttype, false);
1513 
1514  /*
1515  * Only allow commutative operators to be used in exclusion
1516  * constraints. If X conflicts with Y, but Y does not conflict
1517  * with X, bad things will happen.
1518  */
1519  if (get_commutator(opid) != opid)
1520  ereport(ERROR,
1521  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1522  errmsg("operator %s is not commutative",
1523  format_operator(opid)),
1524  errdetail("Only commutative operators can be used in exclusion constraints.")));
1525 
1526  /*
1527  * Operator must be a member of the right opfamily, too
1528  */
1529  opfamily = get_opclass_family(classOidP[attn]);
1530  strat = get_op_opfamily_strategy(opid, opfamily);
1531  if (strat == 0)
1532  {
1533  HeapTuple opftuple;
1534  Form_pg_opfamily opfform;
1535 
1536  /*
1537  * attribute->opclass might not explicitly name the opfamily,
1538  * so fetch the name of the selected opfamily for use in the
1539  * error message.
1540  */
1541  opftuple = SearchSysCache1(OPFAMILYOID,
1542  ObjectIdGetDatum(opfamily));
1543  if (!HeapTupleIsValid(opftuple))
1544  elog(ERROR, "cache lookup failed for opfamily %u",
1545  opfamily);
1546  opfform = (Form_pg_opfamily) GETSTRUCT(opftuple);
1547 
1548  ereport(ERROR,
1549  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1550  errmsg("operator %s is not a member of operator family \"%s\"",
1551  format_operator(opid),
1552  NameStr(opfform->opfname)),
1553  errdetail("The exclusion operator must be related to the index operator class for the constraint.")));
1554  }
1555 
1556  indexInfo->ii_ExclusionOps[attn] = opid;
1557  indexInfo->ii_ExclusionProcs[attn] = get_opcode(opid);
1558  indexInfo->ii_ExclusionStrats[attn] = strat;
1559  nextExclOp = lnext(nextExclOp);
1560  }
1561 
1562  /*
1563  * Set up the per-column options (indoption field). For now, this is
1564  * zero for any un-ordered index, while ordered indexes have DESC and
1565  * NULLS FIRST/LAST options.
1566  */
1567  colOptionP[attn] = 0;
1568  if (amcanorder)
1569  {
1570  /* default ordering is ASC */
1571  if (attribute->ordering == SORTBY_DESC)
1572  colOptionP[attn] |= INDOPTION_DESC;
1573  /* default null ordering is LAST for ASC, FIRST for DESC */
1574  if (attribute->nulls_ordering == SORTBY_NULLS_DEFAULT)
1575  {
1576  if (attribute->ordering == SORTBY_DESC)
1577  colOptionP[attn] |= INDOPTION_NULLS_FIRST;
1578  }
1579  else if (attribute->nulls_ordering == SORTBY_NULLS_FIRST)
1580  colOptionP[attn] |= INDOPTION_NULLS_FIRST;
1581  }
1582  else
1583  {
1584  /* index AM does not support ordering */
1585  if (attribute->ordering != SORTBY_DEFAULT)
1586  ereport(ERROR,
1587  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1588  errmsg("access method \"%s\" does not support ASC/DESC options",
1589  accessMethodName)));
1590  if (attribute->nulls_ordering != SORTBY_NULLS_DEFAULT)
1591  ereport(ERROR,
1592  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1593  errmsg("access method \"%s\" does not support NULLS FIRST/LAST options",
1594  accessMethodName)));
1595  }
1596 
1597  attn++;
1598  }
1599 }
#define INDOPTION_NULLS_FIRST
Definition: pg_index.h:100
#define IsA(nodeptr, _type_)
Definition: nodes.h:564
static bool CheckMutability(Expr *expr)
Definition: indexcmds.c:1279
Oid get_commutator(Oid opno)
Definition: lsyscache.c:1298
int errhint(const char *fmt,...)
Definition: elog.c:987
SortByDir ordering
Definition: parsenodes.h:701
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
Definition: nodes.h:513
Oid * ii_ExclusionProcs
Definition: execnodes.h:153
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:320
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:594
Node * expr
Definition: parsenodes.h:697
unsigned short uint16
Definition: c.h:313
SortByNulls nulls_ordering
Definition: parsenodes.h:702
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
Oid ResolveOpClass(List *opclass, Oid attrType, const char *accessMethodName, Oid accessMethodId)
Definition: indexcmds.c:1608
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:187
#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:44
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1079
List * opclass
Definition: parsenodes.h:700
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
List * ii_Expressions
Definition: execnodes.h:148
#define Assert(condition)
Definition: c.h:688
#define lfirst(lc)
Definition: pg_list.h:106
#define INDOPTION_DESC
Definition: pg_index.h:99
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
AttrNumber ii_KeyAttrNumbers[INDEX_MAX_KEYS]
Definition: execnodes.h:147
char * name
Definition: parsenodes.h:696
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:152
void * palloc(Size size)
Definition: mcxt.c:835
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:565
void * arg
List * collation
Definition: parsenodes.h:699
#define elog
Definition: elog.h:219
uint16 * ii_ExclusionStrats
Definition: execnodes.h:154
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:3493

◆ 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 319 of file indexcmds.c.

References IndexStmt::accessMethod, ACL_CREATE, aclcheck_error(), ACLCHECK_OK, allowSystemTableMods, 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(), GLOBALTABLESPACE_OID, 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_KeyAttrNumbers, IndexInfo::ii_NumIndexAttrs, 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(), IndexIsValid, IndexStmt::indexParams, IndexRelationId, INDEXRELID, IndexSetParentIndex(), RangeVar::inh, IndexStmt::initdeferred, InvalidateCatalogSnapshot(), InvalidOid, IsBootstrapProcessingMode, IndexStmt::isconstraint, lfirst_oid, list_free(), list_length(), LockRelationIdForSession(), LockInfoData::lockRelId, make_ands_implicit(), makeNode, map_variable_attnos(), MyDatabaseTableSpace, 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, RelationRelationId, ReleaseSysCache(), LockRelId::relId, RELKIND_FOREIGN_TABLE, RELKIND_MATVIEW, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, 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, and SnapshotData::xmin.

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

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

◆ GetDefaultOpClass()

Oid GetDefaultOpClass ( Oid  type_id,
Oid  am_id 
)

Definition at line 1719 of file indexcmds.c.

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

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

1720 {
1721  Oid result = InvalidOid;
1722  int nexact = 0;
1723  int ncompatible = 0;
1724  int ncompatiblepreferred = 0;
1725  Relation rel;
1726  ScanKeyData skey[1];
1727  SysScanDesc scan;
1728  HeapTuple tup;
1729  TYPCATEGORY tcategory;
1730 
1731  /* If it's a domain, look at the base type instead */
1732  type_id = getBaseType(type_id);
1733 
1734  tcategory = TypeCategory(type_id);
1735 
1736  /*
1737  * We scan through all the opclasses available for the access method,
1738  * looking for one that is marked default and matches the target type
1739  * (either exactly or binary-compatibly, but prefer an exact match).
1740  *
1741  * We could find more than one binary-compatible match. If just one is
1742  * for a preferred type, use that one; otherwise we fail, forcing the user
1743  * to specify which one he wants. (The preferred-type special case is a
1744  * kluge for varchar: it's binary-compatible to both text and bpchar, so
1745  * we need a tiebreaker.) If we find more than one exact match, then
1746  * someone put bogus entries in pg_opclass.
1747  */
1749 
1750  ScanKeyInit(&skey[0],
1752  BTEqualStrategyNumber, F_OIDEQ,
1753  ObjectIdGetDatum(am_id));
1754 
1755  scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
1756  NULL, 1, skey);
1757 
1758  while (HeapTupleIsValid(tup = systable_getnext(scan)))
1759  {
1760  Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
1761 
1762  /* ignore altogether if not a default opclass */
1763  if (!opclass->opcdefault)
1764  continue;
1765  if (opclass->opcintype == type_id)
1766  {
1767  nexact++;
1768  result = HeapTupleGetOid(tup);
1769  }
1770  else if (nexact == 0 &&
1771  IsBinaryCoercible(type_id, opclass->opcintype))
1772  {
1773  if (IsPreferredType(tcategory, opclass->opcintype))
1774  {
1775  ncompatiblepreferred++;
1776  result = HeapTupleGetOid(tup);
1777  }
1778  else if (ncompatiblepreferred == 0)
1779  {
1780  ncompatible++;
1781  result = HeapTupleGetOid(tup);
1782  }
1783  }
1784  }
1785 
1786  systable_endscan(scan);
1787 
1789 
1790  /* raise error if pg_opclass contains inconsistent data */
1791  if (nexact > 1)
1792  ereport(ERROR,
1794  errmsg("there are multiple default operator classes for data type %s",
1795  format_type_be(type_id))));
1796 
1797  if (nexact == 1 ||
1798  ncompatiblepreferred == 1 ||
1799  (ncompatiblepreferred == 0 && ncompatible == 1))
1800  return result;
1801 
1802  return InvalidOid;
1803 }
#define Anum_pg_opclass_opcmethod
Definition: pg_opclass.h:75
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define AccessShareLock
Definition: lockdefs.h:36
#define OperatorClassRelationId
Definition: pg_opclass.h:49
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:320
#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:328
#define OpclassAmNameNspIndexId
Definition: indexing.h:198
bool IsPreferredType(TYPCATEGORY category, Oid type)
char TYPCATEGORY
Definition: parse_coerce.h:21
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
bool IsBinaryCoercible(Oid srctype, Oid targettype)
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define InvalidOid
Definition: postgres_ext.h:36
TYPCATEGORY TypeCategory(Oid type)
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
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:700
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2275
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:68
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ IndexSetParentIndex()

void IndexSetParentIndex ( Relation  partitionIdx,
Oid  parentOid 
)

Definition at line 2384 of file indexcmds.c.

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

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

2385 {
2386  Relation pg_inherits;
2387  ScanKeyData key[2];
2388  SysScanDesc scan;
2389  Oid partRelid = RelationGetRelid(partitionIdx);
2390  HeapTuple tuple;
2391  bool fix_dependencies;
2392 
2393  /* Make sure this is an index */
2394  Assert(partitionIdx->rd_rel->relkind == RELKIND_INDEX ||
2395  partitionIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
2396 
2397  /*
2398  * Scan pg_inherits for rows linking our index to some parent.
2399  */
2401  ScanKeyInit(&key[0],
2403  BTEqualStrategyNumber, F_OIDEQ,
2404  ObjectIdGetDatum(partRelid));
2405  ScanKeyInit(&key[1],
2407  BTEqualStrategyNumber, F_INT4EQ,
2408  Int32GetDatum(1));
2409  scan = systable_beginscan(pg_inherits, InheritsRelidSeqnoIndexId, true,
2410  NULL, 2, key);
2411  tuple = systable_getnext(scan);
2412 
2413  if (!HeapTupleIsValid(tuple))
2414  {
2415  if (parentOid == InvalidOid)
2416  {
2417  /*
2418  * No pg_inherits row, and no parent wanted: nothing to do in
2419  * this case.
2420  */
2421  fix_dependencies = false;
2422  }
2423  else
2424  {
2426  bool isnull[Natts_pg_inherits];
2427 
2428  /*
2429  * No pg_inherits row exists, and we want a parent for this index,
2430  * so insert it.
2431  */
2432  values[Anum_pg_inherits_inhrelid - 1] = ObjectIdGetDatum(partRelid);
2433  values[Anum_pg_inherits_inhparent - 1] =
2434  ObjectIdGetDatum(parentOid);
2435  values[Anum_pg_inherits_inhseqno - 1] = Int32GetDatum(1);
2436  memset(isnull, false, sizeof(isnull));
2437 
2438  tuple = heap_form_tuple(RelationGetDescr(pg_inherits),
2439  values, isnull);
2440  CatalogTupleInsert(pg_inherits, tuple);
2441 
2442  fix_dependencies = true;
2443  }
2444  }
2445  else
2446  {
2447  Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(tuple);
2448 
2449  if (parentOid == InvalidOid)
2450  {
2451  /*
2452  * There exists a pg_inherits row, which we want to clear; do so.
2453  */
2454  CatalogTupleDelete(pg_inherits, &tuple->t_self);
2455  fix_dependencies = true;
2456  }
2457  else
2458  {
2459  /*
2460  * A pg_inherits row exists. If it's the same we want, then we're
2461  * good; if it differs, that amounts to a corrupt catalog and
2462  * should not happen.
2463  */
2464  if (inhForm->inhparent != parentOid)
2465  {
2466  /* unexpected: we should not get called in this case */
2467  elog(ERROR, "bogus pg_inherit row: inhrelid %u inhparent %u",
2468  inhForm->inhrelid, inhForm->inhparent);
2469  }
2470 
2471  /* already in the right state */
2472  fix_dependencies = false;
2473  }
2474  }
2475 
2476  /* done with pg_inherits */
2477  systable_endscan(scan);
2478  relation_close(pg_inherits, RowExclusiveLock);
2479 
2480  if (fix_dependencies)
2481  {
2482  ObjectAddress partIdx;
2483 
2484  /*
2485  * Insert/delete pg_depend rows. If setting a parent, add an
2486  * INTERNAL_AUTO dependency to the parent index; if making standalone,
2487  * remove all existing rows and put back the regular dependency on the
2488  * table.
2489  */
2490  ObjectAddressSet(partIdx, RelationRelationId, partRelid);
2491 
2492  if (OidIsValid(parentOid))
2493  {
2494  ObjectAddress parentIdx;
2495 
2496  ObjectAddressSet(parentIdx, RelationRelationId, parentOid);
2497  recordDependencyOn(&partIdx, &parentIdx, DEPENDENCY_INTERNAL_AUTO);
2498  }
2499  else
2500  {
2501  ObjectAddress partitionTbl;
2502 
2503  ObjectAddressSet(partitionTbl, RelationRelationId,
2504  partitionIdx->rd_index->indrelid);
2505 
2509 
2510  recordDependencyOn(&partIdx, &partitionTbl, DEPENDENCY_AUTO);
2511  }
2512  }
2513 }
#define Anum_pg_inherits_inhrelid
Definition: pg_inherits.h:50
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define RelationGetDescr(relation)
Definition: rel.h:437
#define Natts_pg_inherits
Definition: pg_inherits.h:49
#define RelationRelationId
Definition: pg_class.h:29
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1266
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:255
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:695
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:594
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
Form_pg_index rd_index
Definition: rel.h:159
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:162
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define RELKIND_PARTITIONED_INDEX
Definition: pg_class.h:169
uintptr_t Datum
Definition: postgres.h:365
static void fix_dependencies(ArchiveHandle *AH)
#define Anum_pg_inherits_inhseqno
Definition: pg_inherits.h:52
#define Anum_pg_inherits_inhparent
Definition: pg_inherits.h:51
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:77
#define Assert(condition)
Definition: c.h:688
#define InheritsRelidSeqnoIndexId
Definition: indexing.h:167
FormData_pg_inherits * Form_pg_inherits
Definition: pg_inherits.h:43
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define InheritsRelationId
Definition: pg_inherits.h:29
static Datum values[MAXATTR]
Definition: bootstrap.c:164
#define Int32GetDatum(X)
Definition: postgres.h:462
#define RELKIND_INDEX
Definition: pg_class.h:161
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:1120
#define elog
Definition: elog.h:219
#define RelationGetRelid(relation)
Definition: rel.h:425
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ makeObjectName()

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

Definition at line 1827 of file indexcmds.c.

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

Referenced by ChooseConstraintName(), and ChooseRelationName().

1828 {
1829  char *name;
1830  int overhead = 0; /* chars needed for label and underscores */
1831  int availchars; /* chars available for name(s) */
1832  int name1chars; /* chars allocated to name1 */
1833  int name2chars; /* chars allocated to name2 */
1834  int ndx;
1835 
1836  name1chars = strlen(name1);
1837  if (name2)
1838  {
1839  name2chars = strlen(name2);
1840  overhead++; /* allow for separating underscore */
1841  }
1842  else
1843  name2chars = 0;
1844  if (label)
1845  overhead += strlen(label) + 1;
1846 
1847  availchars = NAMEDATALEN - 1 - overhead;
1848  Assert(availchars > 0); /* else caller chose a bad label */
1849 
1850  /*
1851  * If we must truncate, preferentially truncate the longer name. This
1852  * logic could be expressed without a loop, but it's simple and obvious as
1853  * a loop.
1854  */
1855  while (name1chars + name2chars > availchars)
1856  {
1857  if (name1chars > name2chars)
1858  name1chars--;
1859  else
1860  name2chars--;
1861  }
1862 
1863  name1chars = pg_mbcliplen(name1, name1chars, name1chars);
1864  if (name2)
1865  name2chars = pg_mbcliplen(name2, name2chars, name2chars);
1866 
1867  /* Now construct the string using the chosen lengths */
1868  name = palloc(name1chars + name2chars + overhead + 1);
1869  memcpy(name, name1, name1chars);
1870  ndx = name1chars;
1871  if (name2)
1872  {
1873  name[ndx++] = '_';
1874  memcpy(name + ndx, name2, name2chars);
1875  ndx += name2chars;
1876  }
1877  if (label)
1878  {
1879  name[ndx++] = '_';
1880  strcpy(name + ndx, label);
1881  }
1882  else
1883  name[ndx] = '\0';
1884 
1885  return name;
1886 }
#define NAMEDATALEN
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition: mbutils.c:820
static char * label
Definition: pg_basebackup.c:82
#define Assert(condition)
Definition: c.h:688
const char * name
Definition: encode.c:521
void * palloc(Size size)
Definition: mcxt.c:835

◆ RangeVarCallbackForReindexIndex()

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

Definition at line 2119 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_INDEX, RELKIND_PARTITIONED_INDEX, RangeVar::relname, ShareLock, and UnlockRelationOid().

Referenced by ReindexIndex().

2121 {
2122  char relkind;
2123  Oid *heapOid = (Oid *) arg;
2124 
2125  /*
2126  * If we previously locked some other index's heap, and the name we're
2127  * looking up no longer refers to that relation, release the now-useless
2128  * lock.
2129  */
2130  if (relId != oldRelId && OidIsValid(oldRelId))
2131  {
2132  /* lock level here should match reindex_index() heap lock */
2133  UnlockRelationOid(*heapOid, ShareLock);
2134  *heapOid = InvalidOid;
2135  }
2136 
2137  /* If the relation does not exist, there's nothing more to do. */
2138  if (!OidIsValid(relId))
2139  return;
2140 
2141  /*
2142  * If the relation does exist, check whether it's an index. But note that
2143  * the relation might have been dropped between the time we did the name
2144  * lookup and now. In that case, there's nothing to do.
2145  */
2146  relkind = get_rel_relkind(relId);
2147  if (!relkind)
2148  return;
2149  if (relkind != RELKIND_INDEX &&
2150  relkind != RELKIND_PARTITIONED_INDEX)
2151  ereport(ERROR,
2152  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2153  errmsg("\"%s\" is not an index", relation->relname)));
2154 
2155  /* Check permissions */
2156  if (!pg_class_ownercheck(relId, GetUserId()))
2158 
2159  /* Lock heap before index to avoid deadlock. */
2160  if (relId != oldRelId)
2161  {
2162  /*
2163  * Lock level here should match reindex_index() heap lock. If the OID
2164  * isn't valid, it means the index as concurrently dropped, which is
2165  * not a problem for us; just return normally.
2166  */
2167  *heapOid = IndexGetRelation(relId, true);
2168  if (OidIsValid(*heapOid))
2169  LockRelationOid(*heapOid, ShareLock);
2170  }
2171 }
Oid IndexGetRelation(Oid indexId, bool missing_ok)
Definition: index.c:3551
Oid GetUserId(void)
Definition: miscinit.c:284
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:594
char * relname
Definition: primnodes.h:68
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
#define RELKIND_PARTITIONED_INDEX
Definition: pg_class.h:169
#define InvalidOid
Definition: postgres_ext.h:36
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4752
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ShareLock
Definition: lockdefs.h:41
#define RELKIND_INDEX
Definition: pg_class.h:161
void * arg
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:105

◆ ReindexIndex()

void ReindexIndex ( RangeVar indexRelation,
int  options 
)

Definition at line 2078 of file indexcmds.c.

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

Referenced by standard_ProcessUtility().

2079 {
2080  Oid indOid;
2081  Oid heapOid = InvalidOid;
2082  Relation irel;
2083  char persistence;
2084 
2085  /*
2086  * Find and lock index, and check permissions on table; use callback to
2087  * obtain lock on table first, to avoid deadlock hazard. The lock level
2088  * used here must match the index lock obtained in reindex_index().
2089  */
2090  indOid = RangeVarGetRelidExtended(indexRelation, AccessExclusiveLock,
2091  false, false,
2093  (void *) &heapOid);
2094 
2095  /*
2096  * Obtain the current persistence of the existing index. We already hold
2097  * lock on the index.
2098  */
2099  irel = index_open(indOid, NoLock);
2100 
2101  if (irel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
2102  {
2104  return;
2105  }
2106 
2107  persistence = irel->rd_rel->relpersistence;
2108  index_close(irel, NoLock);
2109 
2110  reindex_index(indOid, false, persistence, options);
2111 }
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, bool missing_ok, bool nowait, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:218
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
#define NoLock
Definition: lockdefs.h:34
#define RELKIND_PARTITIONED_INDEX
Definition: pg_class.h:169
static void RangeVarCallbackForReindexIndex(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: indexcmds.c:2119
#define InvalidOid
Definition: postgres_ext.h:36
void reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, int options)
Definition: index.c:3576
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
#define AccessExclusiveLock
Definition: lockdefs.h:45
static void ReindexPartitionedIndex(Relation parentIdx)
Definition: indexcmds.c:2370
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:151

◆ ReindexMultipleTables()

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

Definition at line 2206 of file indexcmds.c.

References AccessShareLock, aclcheck_error(), ACLCHECK_NOT_OWNER, ALLOCSET_SMALL_SIZES, AllocSetContextCreate, Anum_pg_class_relnamespace, 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, RelationRelationId, RELKIND_MATVIEW, RELKIND_RELATION, RELPERSISTENCE_TEMP, ScanKeyInit(), and StartTransactionCommand().

Referenced by standard_ProcessUtility().

2208 {
2209  Oid objectOid;
2210  Relation relationRelation;
2211  HeapScanDesc scan;
2212  ScanKeyData scan_keys[1];
2213  HeapTuple tuple;
2214  MemoryContext private_context;
2215  MemoryContext old;
2216  List *relids = NIL;
2217  ListCell *l;
2218  int num_keys;
2219 
2220  AssertArg(objectName);
2221  Assert(objectKind == REINDEX_OBJECT_SCHEMA ||
2222  objectKind == REINDEX_OBJECT_SYSTEM ||
2223  objectKind == REINDEX_OBJECT_DATABASE);
2224 
2225  /*
2226  * Get OID of object to reindex, being the database currently being used
2227  * by session for a database or for system catalogs, or the schema defined
2228  * by caller. At the same time do permission checks that need different
2229  * processing depending on the object type.
2230  */
2231  if (objectKind == REINDEX_OBJECT_SCHEMA)
2232  {
2233  objectOid = get_namespace_oid(objectName, false);
2234 
2235  if (!pg_namespace_ownercheck(objectOid, GetUserId()))
2237  objectName);
2238  }
2239  else
2240  {
2241  objectOid = MyDatabaseId;
2242 
2243  if (strcmp(objectName, get_database_name(objectOid)) != 0)
2244  ereport(ERROR,
2245  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2246  errmsg("can only reindex the currently open database")));
2247  if (!pg_database_ownercheck(objectOid, GetUserId()))
2249  objectName);
2250  }
2251 
2252  /*
2253  * Create a memory context that will survive forced transaction commits we
2254  * do below. Since it is a child of PortalContext, it will go away
2255  * eventually even if we suffer an error; there's no need for special
2256  * abort cleanup logic.
2257  */
2258  private_context = AllocSetContextCreate(PortalContext,
2259  "ReindexMultipleTables",
2261 
2262  /*
2263  * Define the search keys to find the objects to reindex. For a schema, we
2264  * select target relations using relnamespace, something not necessary for
2265  * a database-wide operation.
2266  */
2267  if (objectKind == REINDEX_OBJECT_SCHEMA)
2268  {
2269  num_keys = 1;
2270  ScanKeyInit(&scan_keys[0],
2272  BTEqualStrategyNumber, F_OIDEQ,
2273  ObjectIdGetDatum(objectOid));
2274  }
2275  else
2276  num_keys = 0;
2277 
2278  /*
2279  * Scan pg_class to build a list of the relations we need to reindex.
2280  *
2281  * We only consider plain relations and materialized views here (toast
2282  * rels will be processed indirectly by reindex_relation).
2283  */
2284  relationRelation = heap_open(RelationRelationId, AccessShareLock);
2285  scan = heap_beginscan_catalog(relationRelation, num_keys, scan_keys);
2286  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2287  {
2288  Form_pg_class classtuple = (Form_pg_class) GETSTRUCT(tuple);
2289  Oid relid = HeapTupleGetOid(tuple);
2290 
2291  /*
2292  * Only regular tables and matviews can have indexes, so ignore any
2293  * other kind of relation.
2294  *
2295  * It is tempting to also consider partitioned tables here, but that
2296  * has the problem that if the children are in the same schema, they
2297  * would be processed twice. Maybe we could have a separate list of
2298  * partitioned tables, and expand that afterwards into relids,
2299  * ignoring any duplicates.
2300  */
2301  if (classtuple->relkind != RELKIND_RELATION &&
2302  classtuple->relkind != RELKIND_MATVIEW)
2303  continue;
2304 
2305  /* Skip temp tables of other backends; we can't reindex them at all */
2306  if (classtuple->relpersistence == RELPERSISTENCE_TEMP &&
2307  !isTempNamespace(classtuple->relnamespace))
2308  continue;
2309 
2310  /* Check user/system classification, and optionally skip */
2311  if (objectKind == REINDEX_OBJECT_SYSTEM &&
2312  !IsSystemClass(relid, classtuple))
2313  continue;
2314 
2315  /* Save the list of relation OIDs in private context */
2316  old = MemoryContextSwitchTo(private_context);
2317 
2318  /*
2319  * We always want to reindex pg_class first if it's selected to be
2320  * reindexed. This ensures that if there is any corruption in
2321  * pg_class' indexes, they will be fixed before we process any other
2322  * tables. This is critical because reindexing itself will try to
2323  * update pg_class.
2324  */
2325  if (relid == RelationRelationId)
2326  relids = lcons_oid(relid, relids);
2327  else
2328  relids = lappend_oid(relids, relid);
2329 
2330  MemoryContextSwitchTo(old);
2331  }
2332  heap_endscan(scan);
2333  heap_close(relationRelation, AccessShareLock);
2334 
2335  /* Now reindex each rel in a separate transaction */
2338  foreach(l, relids)
2339  {
2340  Oid relid = lfirst_oid(l);
2341 
2343  /* functions in indexes may want a snapshot set */
2345  if (reindex_relation(relid,
2348  options))
2349 
2351  ereport(INFO,
2352  (errmsg("table \"%s.%s\" was reindexed",
2354  get_rel_name(relid))));
2357  }
2359 
2360  MemoryContextDelete(private_context);
2361 }
#define NIL
Definition: pg_list.h:69
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:198
Oid get_namespace_oid(const char *nspname, bool missing_ok)
Definition: namespace.c:3005
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
void heap_endscan(HeapScanDesc scan)
Definition: heapam.c:1568
Oid GetUserId(void)
Definition: miscinit.c:284
void CommitTransactionCommand(void)
Definition: xact.c:2745
#define RelationRelationId
Definition: pg_class.h:29
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:207
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1754
#define RELKIND_MATVIEW
Definition: pg_class.h:165
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:4928
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 Anum_pg_class_relnamespace
Definition: pg_class.h:104
#define REINDEXOPT_VERBOSE
Definition: parsenodes.h:3262
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:75
MemoryContext PortalContext
Definition: mcxt.c:52
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
char * get_database_name(Oid dbid)
Definition: dbcommands.c:2056
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3051
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:733
bool isTempNamespace(Oid namespaceId)
Definition: namespace.c:3118
HeapScanDesc heap_beginscan_catalog(Relation relation, int nkeys, ScanKey key)
Definition: heapam.c:1408
#define ereport(elevel, rest)
Definition: elog.h:122
#define AssertArg(condition)
Definition: c.h:690
bool pg_database_ownercheck(Oid db_oid, Oid roleid)
Definition: aclchk.c:5170
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:165
Oid MyDatabaseId
Definition: globals.c:77
HeapTuple heap_getnext(HeapScanDesc scan, ScanDirection direction)
Definition: heapam.c:1831
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define Assert(condition)
Definition: c.h:688
void StartTransactionCommand(void)
Definition: xact.c:2674
#define REINDEX_REL_CHECK_CONSTRAINTS
Definition: index.h:141
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
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:700
#define RELPERSISTENCE_TEMP
Definition: pg_class.h:173
#define RELKIND_RELATION
Definition: pg_class.h:160
bool reindex_relation(Oid relid, int flags, int options)
Definition: index.c:3793
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 2370 of file indexcmds.c.

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

Referenced by ReindexIndex().

2371 {
2372  ereport(ERROR,
2373  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2374  errmsg("REINDEX is not yet implemented for partitioned indexes")));
2375 }
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 2178 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().

2179 {
2180  Oid heapOid;
2181 
2182  /* The lock level used here should match reindex_relation(). */
2183  heapOid = RangeVarGetRelidExtended(relation, ShareLock, false, false,
2185 
2186  if (!reindex_relation(heapOid,
2189  options))
2190  ereport(NOTICE,
2191  (errmsg("table \"%s\" has no indexes",
2192  relation->relname)));
2193 
2194  return heapOid;
2195 }
void RangeVarCallbackOwnsTable(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:13169
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, bool missing_ok, bool nowait, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:218
unsigned int Oid
Definition: postgres_ext.h:31
char * relname
Definition: primnodes.h:68
#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:3793

◆ ResolveOpClass()

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

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

1610 {
1611  char *schemaname;
1612  char *opcname;
1613  HeapTuple tuple;
1614  Oid opClassId,
1615  opInputType;
1616 
1617  /*
1618  * Release 7.0 removed network_ops, timespan_ops, and datetime_ops, so we
1619  * ignore those opclass names so the default *_ops is used. This can be
1620  * removed in some later release. bjm 2000/02/07
1621  *
1622  * Release 7.1 removes lztext_ops, so suppress that too for a while. tgl
1623  * 2000/07/30
1624  *
1625  * Release 7.2 renames timestamp_ops to timestamptz_ops, so suppress that
1626  * too for awhile. I'm starting to think we need a better approach. tgl
1627  * 2000/10/01
1628  *
1629  * Release 8.0 removes bigbox_ops (which was dead code for a long while
1630  * anyway). tgl 2003/11/11
1631  */
1632  if (list_length(opclass) == 1)
1633  {
1634  char *claname = strVal(linitial(opclass));
1635 
1636  if (strcmp(claname, "network_ops") == 0 ||
1637  strcmp(claname, "timespan_ops") == 0 ||
1638  strcmp(claname, "datetime_ops") == 0 ||
1639  strcmp(claname, "lztext_ops") == 0 ||
1640  strcmp(claname, "timestamp_ops") == 0 ||
1641  strcmp(claname, "bigbox_ops") == 0)
1642  opclass = NIL;
1643  }
1644 
1645  if (opclass == NIL)
1646  {
1647  /* no operator class specified, so find the default */
1648  opClassId = GetDefaultOpClass(attrType, accessMethodId);
1649  if (!OidIsValid(opClassId))
1650  ereport(ERROR,
1651  (errcode(ERRCODE_UNDEFINED_OBJECT),
1652  errmsg("data type %s has no default operator class for access method \"%s\"",
1653  format_type_be(attrType), accessMethodName),
1654  errhint("You must specify an operator class for the index or define a default operator class for the data type.")));
1655  return opClassId;
1656  }
1657 
1658  /*
1659  * Specific opclass name given, so look up the opclass.
1660  */
1661 
1662  /* deconstruct the name list */
1663  DeconstructQualifiedName(opclass, &schemaname, &opcname);
1664 
1665  if (schemaname)
1666  {
1667  /* Look in specific schema only */
1668  Oid namespaceId;
1669 
1670  namespaceId = LookupExplicitNamespace(schemaname, false);
1671  tuple = SearchSysCache3(CLAAMNAMENSP,
1672  ObjectIdGetDatum(accessMethodId),
1673  PointerGetDatum(opcname),
1674  ObjectIdGetDatum(namespaceId));
1675  }
1676  else
1677  {
1678  /* Unqualified opclass name, so search the search path */
1679  opClassId = OpclassnameGetOpcid(accessMethodId, opcname);
1680  if (!OidIsValid(opClassId))
1681  ereport(ERROR,
1682  (errcode(ERRCODE_UNDEFINED_OBJECT),
1683  errmsg("operator class \"%s\" does not exist for access method \"%s\"",
1684  opcname, accessMethodName)));
1685  tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opClassId));
1686  }
1687 
1688  if (!HeapTupleIsValid(tuple))
1689  ereport(ERROR,
1690  (errcode(ERRCODE_UNDEFINED_OBJECT),
1691  errmsg("operator class \"%s\" does not exist for access method \"%s\"",
1692  NameListToString(opclass), accessMethodName)));
1693 
1694  /*
1695  * Verify that the index operator class accepts this datatype. Note we
1696  * will accept binary compatibility.
1697  */
1698  opClassId = HeapTupleGetOid(tuple);
1699  opInputType = ((Form_pg_opclass) GETSTRUCT(tuple))->opcintype;
1700 
1701  if (!IsBinaryCoercible(attrType, opInputType))
1702  ereport(ERROR,
1703  (errcode(ERRCODE_DATATYPE_MISMATCH),
1704  errmsg("operator class \"%s\" does not accept data type %s",
1705  NameListToString(opclass), format_type_be(attrType))));
1706 
1707  ReleaseSysCache(tuple);
1708 
1709  return opClassId;
1710 }
#define NIL
Definition: pg_list.h:69
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:2853
int errhint(const char *fmt,...)
Definition: elog.c:987
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:1719
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define PointerGetDatum(X)
Definition: postgres.h:539
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:320
void DeconstructQualifiedName(List *names, char **nspname_p, char **objname_p)
Definition: namespace.c:2769
unsigned int Oid
Definition: postgres_ext.h:31
Oid OpclassnameGetOpcid(Oid amid, const char *opcname)
Definition: namespace.c:1760
#define OidIsValid(objectId)
Definition: c.h:594
#define linitial(l)
Definition: pg_list.h:111
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:1134
#define ereport(elevel, rest)
Definition: elog.h:122
bool IsBinaryCoercible(Oid srctype, Oid targettype)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
char * NameListToString(List *names)
Definition: namespace.c:3063
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
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:700
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:68