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

Go to the source code of this file.

Data Structures

struct  ReindexIndexCallbackState
 
struct  ReindexErrorInfo
 

Typedefs

typedef struct ReindexErrorInfo ReindexErrorInfo
 

Functions

static bool CompareOpclassOptions (const Datum *opts1, const Datum *opts2, int natts)
 
static void CheckPredicate (Expr *predicate)
 
static void ComputeIndexAttrs (ParseState *pstate, IndexInfo *indexInfo, Oid *typeOids, Oid *collationOids, Oid *opclassOids, Datum *opclassOptions, int16 *colOptions, const List *attList, const List *exclusionOpNames, Oid relId, const char *accessMethodName, Oid accessMethodId, bool amcanorder, bool isconstraint, bool iswithoutoverlaps, Oid ddl_userid, int ddl_sec_context, int *ddl_save_nestlevel)
 
static charChooseIndexName (const char *tabname, Oid namespaceId, const List *colnames, const List *exclusionOpNames, bool primary, bool isconstraint)
 
static charChooseIndexNameAddition (const List *colnames)
 
static ListChooseIndexColumnNames (const List *indexElems)
 
static void ReindexIndex (const ReindexStmt *stmt, const ReindexParams *params, bool isTopLevel)
 
static void RangeVarCallbackForReindexIndex (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
static Oid ReindexTable (const ReindexStmt *stmt, const ReindexParams *params, bool isTopLevel)
 
static void ReindexMultipleTables (const ReindexStmt *stmt, const ReindexParams *params)
 
static void reindex_error_callback (void *arg)
 
static void ReindexPartitions (const ReindexStmt *stmt, Oid relid, const ReindexParams *params, bool isTopLevel)
 
static void ReindexMultipleInternal (const ReindexStmt *stmt, const List *relids, const ReindexParams *params)
 
static bool ReindexRelationConcurrently (const ReindexStmt *stmt, Oid relationOid, const ReindexParams *params)
 
static void update_relispartition (Oid relationId, bool newval)
 
static void set_indexsafe_procflags (void)
 
bool CheckIndexCompatible (Oid oldId, const char *accessMethodName, const List *attributeList, const List *exclusionOpNames, bool isWithoutOverlaps)
 
void WaitForOlderSnapshots (TransactionId limitXmin, bool progress)
 
ObjectAddress DefineIndex (ParseState *pstate, Oid tableId, IndexStmt *stmt, Oid indexRelationId, Oid parentIndexId, Oid parentConstraintId, int total_parts, bool is_alter_table, bool check_rights, bool check_not_in_use, bool skip_build, bool quiet)
 
Oid ResolveOpClass (const List *opclass, Oid attrType, const char *accessMethodName, Oid accessMethodId)
 
Oid GetDefaultOpClass (Oid type_id, Oid am_id)
 
void GetOperatorFromCompareType (Oid opclass, Oid rhstype, CompareType cmptype, Oid *opid, StrategyNumber *strat)
 
charmakeObjectName (const char *name1, const char *name2, const char *label)
 
charChooseRelationName (const char *name1, const char *name2, const char *label, Oid namespaceid, bool isconstraint)
 
void ExecReindex (ParseState *pstate, const ReindexStmt *stmt, bool isTopLevel)
 
void IndexSetParentIndex (Relation partitionIdx, Oid parentOid)
 

Typedef Documentation

◆ ReindexErrorInfo

Function Documentation

◆ CheckIndexCompatible()

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

Definition at line 178 of file indexcmds.c.

183{
184 bool isconstraint;
185 Oid *typeIds;
191 HeapTuple tuple;
195 bool amcanorder;
196 bool amsummarizing;
198 IndexInfo *indexInfo;
200 int old_natts;
201 bool ret = true;
204 Relation irel;
205 int i;
206 Datum d;
207
208 /* Caller should already have the relation locked in some way. */
210
211 /*
212 * We can pretend isconstraint = false unconditionally. It only serves to
213 * decide the text of an error message that should never happen for us.
214 */
215 isconstraint = false;
216
220
221 /* look up the access method */
223 if (!HeapTupleIsValid(tuple))
226 errmsg("access method \"%s\" does not exist",
231 ReleaseSysCache(tuple);
232
233 amcanorder = amRoutine->amcanorder;
234 amsummarizing = amRoutine->amsummarizing;
235
236 /*
237 * Compute the operator classes, collations, and exclusion operators for
238 * the new index, so we can test whether it's compatible with the existing
239 * one. Note that ComputeIndexAttrs might fail here, but that's OK:
240 * DefineIndex would have failed later. Our attributeList contains only
241 * key attributes, thus we're filling ii_NumIndexAttrs and
242 * ii_NumIndexKeyAttrs with same value.
243 */
245 accessMethodId, NIL, NIL, false, false,
246 false, false, amsummarizing, isWithoutOverlaps);
252 ComputeIndexAttrs(NULL, indexInfo,
257 amcanorder, isconstraint, isWithoutOverlaps, InvalidOid,
258 0, NULL);
259
260 /* Get the soon-obsolete pg_index tuple. */
262 if (!HeapTupleIsValid(tuple))
263 elog(ERROR, "cache lookup failed for index %u", oldId);
265
266 /*
267 * We don't assess expressions or predicates; assume incompatibility.
268 * Also, if the index is invalid for any reason, treat it as incompatible.
269 */
272 indexForm->indisvalid))
273 {
274 ReleaseSysCache(tuple);
275 return false;
276 }
277
278 /* Any change in operator class or collation breaks compatibility. */
279 old_natts = indexForm->indnkeyatts;
281
284
287
288 ret = (memcmp(old_indclass->values, opclassIds, old_natts * sizeof(Oid)) == 0 &&
289 memcmp(old_indcollation->values, collationIds, old_natts * sizeof(Oid)) == 0);
290
291 ReleaseSysCache(tuple);
292
293 if (!ret)
294 return false;
295
296 /* For polymorphic opcintype, column type changes break compatibility. */
297 irel = index_open(oldId, AccessShareLock); /* caller probably has a lock */
298 for (i = 0; i < old_natts; i++)
299 {
301 TupleDescAttr(irel->rd_att, i)->atttypid != typeIds[i])
302 {
303 ret = false;
304 break;
305 }
306 }
307
308 /* Any change in opclass options break compatibility. */
309 if (ret)
310 {
312
313 for (i = 0; i < old_natts; i++)
315
317
319 }
320
321 /* Any change in exclusion operator selections breaks compatibility. */
322 if (ret && indexInfo->ii_ExclusionOps != NULL)
323 {
325 *old_procs;
327
329 ret = memcmp(old_operators, indexInfo->ii_ExclusionOps,
330 old_natts * sizeof(Oid)) == 0;
331
332 /* Require an exact input type match for polymorphic operators. */
333 if (ret)
334 {
335 for (i = 0; i < old_natts && ret; i++)
336 {
337 Oid left,
338 right;
339
340 op_input_types(indexInfo->ii_ExclusionOps[i], &left, &right);
341 if ((IsPolymorphicType(left) || IsPolymorphicType(right)) &&
342 TupleDescAttr(irel->rd_att, i)->atttypid != typeIds[i])
343 {
344 ret = false;
345 break;
346 }
347 }
348 }
349 }
350
351 index_close(irel, NoLock);
352 return ret;
353}
const IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition amapi.c:33
#define Assert(condition)
Definition c.h:873
int16_t int16
Definition c.h:541
uint16_t uint16
Definition c.h:545
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
#define palloc_array(type, count)
Definition fe_memutils.h:76
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition heaptuple.c:456
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Oid IndexGetRelation(Oid indexId, bool missing_ok)
Definition index.c:3581
void index_close(Relation relation, LOCKMODE lockmode)
Definition indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition indexam.c:133
static bool CompareOpclassOptions(const Datum *opts1, const Datum *opts2, int natts)
Definition indexcmds.c:362
static void ComputeIndexAttrs(ParseState *pstate, IndexInfo *indexInfo, Oid *typeOids, Oid *collationOids, Oid *opclassOids, Datum *opclassOptions, int16 *colOptions, const List *attList, const List *exclusionOpNames, Oid relId, const char *accessMethodName, Oid accessMethodId, bool amcanorder, bool isconstraint, bool iswithoutoverlaps, Oid ddl_userid, int ddl_sec_context, int *ddl_save_nestlevel)
Definition indexcmds.c:1878
int i
Definition isn.c:77
#define NoLock
Definition lockdefs.h:34
#define AccessShareLock
Definition lockdefs.h:36
Oid get_opclass_input_type(Oid opclass)
Definition lsyscache.c:1314
Datum get_attoptions(Oid relid, int16 attnum)
Definition lsyscache.c:1046
void op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
Definition lsyscache.c:1508
IndexInfo * makeIndexInfo(int numattrs, int numkeyattrs, Oid amoid, List *expressions, List *predicates, bool unique, bool nulls_not_distinct, bool isready, bool concurrent, bool summarizing, bool withoutoverlaps)
Definition makefuncs.c:834
void pfree(void *pointer)
Definition mcxt.c:1616
FormData_pg_am * Form_pg_am
Definition pg_am.h:48
#define INDEX_MAX_KEYS
FormData_pg_index * Form_pg_index
Definition pg_index.h:70
static int list_length(const List *l)
Definition pg_list.h:152
#define NIL
Definition pg_list.h:68
static Datum PointerGetDatum(const void *X)
Definition postgres.h:352
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:342
#define InvalidOid
unsigned int Oid
static int fb(int x)
void RelationGetExclusionInfo(Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
Definition relcache.c:5648
Oid * ii_ExclusionOps
Definition execnodes.h:190
TupleDesc rd_att
Definition rel.h:112
Definition c.h:745
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition syscache.c:220
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:625
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:160

References AccessShareLock, Assert, CompareOpclassOptions(), ComputeIndexAttrs(), DatumGetPointer(), elog, ereport, errcode(), errmsg(), ERROR, fb(), get_attoptions(), get_opclass_input_type(), GetIndexAmRoutine(), GETSTRUCT(), heap_attisnull(), HeapTupleIsValid, i, IndexInfo::ii_ExclusionOps, index_close(), INDEX_MAX_KEYS, index_open(), IndexGetRelation(), InvalidOid, list_length(), makeIndexInfo(), NIL, NoLock, ObjectIdGetDatum(), op_input_types(), palloc_array, pfree(), PointerGetDatum(), RelationData::rd_att, RelationGetExclusionInfo(), ReleaseSysCache(), SearchSysCache1(), SysCacheGetAttrNotNull(), and TupleDescAttr().

Referenced by TryReuseIndex().

◆ CheckPredicate()

static void CheckPredicate ( Expr predicate)
static

Definition at line 1851 of file indexcmds.c.

1852{
1853 /*
1854 * transformExpr() should have already rejected subqueries, aggregates,
1855 * and window functions, based on the EXPR_KIND_ for a predicate.
1856 */
1857
1858 /*
1859 * A predicate using mutable functions is probably wrong, for the same
1860 * reasons that we don't allow an index expression to use one.
1861 */
1863 ereport(ERROR,
1865 errmsg("functions in index predicate must be marked IMMUTABLE")));
1866}
bool contain_mutable_functions_after_planning(Expr *expr)
Definition clauses.c:499

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

Referenced by DefineIndex().

◆ ChooseIndexColumnNames()

static List * ChooseIndexColumnNames ( const List indexElems)
static

Definition at line 2788 of file indexcmds.c.

2789{
2790 List *result = NIL;
2791 ListCell *lc;
2792
2793 foreach(lc, indexElems)
2794 {
2796 const char *origname;
2797 const char *curname;
2798 int i;
2799 char buf[NAMEDATALEN];
2800
2801 /* Get the preliminary name from the IndexElem */
2802 if (ielem->indexcolname)
2803 origname = ielem->indexcolname; /* caller-specified name */
2804 else if (ielem->name)
2805 origname = ielem->name; /* simple column reference */
2806 else
2807 origname = "expr"; /* default name for expression */
2808
2809 /* If it conflicts with any previous column, tweak it */
2810 curname = origname;
2811 for (i = 1;; i++)
2812 {
2813 ListCell *lc2;
2814 char nbuf[32];
2815 int nlen;
2816
2817 foreach(lc2, result)
2818 {
2819 if (strcmp(curname, (char *) lfirst(lc2)) == 0)
2820 break;
2821 }
2822 if (lc2 == NULL)
2823 break; /* found nonconflicting name */
2824
2825 sprintf(nbuf, "%d", i);
2826
2827 /* Ensure generated names are shorter than NAMEDATALEN */
2829 NAMEDATALEN - 1 - strlen(nbuf));
2831 strcpy(buf + nlen, nbuf);
2832 curname = buf;
2833 }
2834
2835 /* And attach to the result list */
2836 result = lappend(result, pstrdup(curname));
2837 }
2838 return result;
2839}
List * lappend(List *list, void *datum)
Definition list.c:339
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition mbutils.c:1086
char * pstrdup(const char *in)
Definition mcxt.c:1781
#define NAMEDATALEN
#define lfirst(lc)
Definition pg_list.h:172
static char buf[DEFAULT_XLOG_SEG_SIZE]
#define sprintf
Definition port.h:262
char * indexcolname
Definition parsenodes.h:813
Definition pg_list.h:54

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

Referenced by DefineIndex().

◆ ChooseIndexName()

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

Definition at line 2699 of file indexcmds.c.

2702{
2703 char *indexname;
2704
2705 if (primary)
2706 {
2707 /* the primary key's name does not depend on the specific column(s) */
2708 indexname = ChooseRelationName(tabname,
2709 NULL,
2710 "pkey",
2712 true);
2713 }
2714 else if (exclusionOpNames != NIL)
2715 {
2716 indexname = ChooseRelationName(tabname,
2717 ChooseIndexNameAddition(colnames),
2718 "excl",
2720 true);
2721 }
2722 else if (isconstraint)
2723 {
2724 indexname = ChooseRelationName(tabname,
2725 ChooseIndexNameAddition(colnames),
2726 "key",
2728 true);
2729 }
2730 else
2731 {
2732 indexname = ChooseRelationName(tabname,
2733 ChooseIndexNameAddition(colnames),
2734 "idx",
2736 false);
2737 }
2738
2739 return indexname;
2740}
char * ChooseRelationName(const char *name1, const char *name2, const char *label, Oid namespaceid, bool isconstraint)
Definition indexcmds.c:2631
static char * ChooseIndexNameAddition(const List *colnames)
Definition indexcmds.c:2754

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

Referenced by DefineIndex().

◆ ChooseIndexNameAddition()

static char * ChooseIndexNameAddition ( const List colnames)
static

Definition at line 2754 of file indexcmds.c.

2755{
2756 char buf[NAMEDATALEN * 2];
2757 int buflen = 0;
2758 ListCell *lc;
2759
2760 buf[0] = '\0';
2761 foreach(lc, colnames)
2762 {
2763 const char *name = (const char *) lfirst(lc);
2764
2765 if (buflen > 0)
2766 buf[buflen++] = '_'; /* insert _ between names */
2767
2768 /*
2769 * At this point we have buflen <= NAMEDATALEN. name should be less
2770 * than NAMEDATALEN already, but use strlcpy for paranoia.
2771 */
2772 strlcpy(buf + buflen, name, NAMEDATALEN);
2773 buflen += strlen(buf + buflen);
2774 if (buflen >= NAMEDATALEN)
2775 break;
2776 }
2777 return pstrdup(buf);
2778}
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition strlcpy.c:45
const char * name

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

Referenced by ChooseIndexName().

◆ ChooseRelationName()

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

Definition at line 2631 of file indexcmds.c.

2634{
2635 int pass = 0;
2636 char *relname = NULL;
2637 char modlabel[NAMEDATALEN];
2640
2641 /* prepare to search pg_class with a dirty snapshot */
2644
2645 /* try the unmodified label first */
2646 strlcpy(modlabel, label, sizeof(modlabel));
2647
2648 for (;;)
2649 {
2650 ScanKeyData key[2];
2651 SysScanDesc scan;
2652 bool collides;
2653
2655
2656 /* is there any conflicting relation name? */
2657 ScanKeyInit(&key[0],
2661 ScanKeyInit(&key[1],
2665
2667 true /* indexOK */ ,
2669 2, key);
2670
2672
2673 systable_endscan(scan);
2674
2675 /* break out of loop if no conflict */
2676 if (!collides)
2677 {
2678 if (!isconstraint ||
2680 break;
2681 }
2682
2683 /* found a conflict, so try a new name component */
2684 pfree(relname);
2685 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
2686 }
2687
2689
2690 return relname;
2691}
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:603
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:514
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition genam.c:388
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition indexcmds.c:2543
static char * label
NameData relname
Definition pg_class.h:38
bool ConstraintNameExists(const char *conname, Oid namespaceid)
#define snprintf
Definition port.h:260
static Datum CStringGetDatum(const char *X)
Definition postgres.h:380
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
#define InitDirtySnapshot(snapshotdata)
Definition snapmgr.h:42
#define BTEqualStrategyNumber
Definition stratnum.h:31
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40

References AccessShareLock, BTEqualStrategyNumber, ConstraintNameExists(), CStringGetDatum(), fb(), HeapTupleIsValid, InitDirtySnapshot, label, makeObjectName(), NAMEDATALEN, ObjectIdGetDatum(), pfree(), relname, ScanKeyInit(), snprintf, strlcpy(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

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

◆ CompareOpclassOptions()

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

Definition at line 362 of file indexcmds.c.

363{
364 int i;
365 FmgrInfo fm;
366
367 if (!opts1 && !opts2)
368 return true;
369
371 for (i = 0; i < natts; i++)
372 {
373 Datum opt1 = opts1 ? opts1[i] : (Datum) 0;
374 Datum opt2 = opts2 ? opts2[i] : (Datum) 0;
375
376 if (opt1 == (Datum) 0)
377 {
378 if (opt2 == (Datum) 0)
379 continue;
380 else
381 return false;
382 }
383 else if (opt2 == (Datum) 0)
384 return false;
385
386 /*
387 * Compare non-NULL text[] datums. Use C collation to enforce binary
388 * equivalence of texts, because we don't know anything about the
389 * semantics of opclass options.
390 */
392 return false;
393 }
394
395 return true;
396}
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition fmgr.c:1150
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition fmgr.c:128
static bool DatumGetBool(Datum X)
Definition postgres.h:100

References DatumGetBool(), fb(), fmgr_info(), FunctionCall2Coll(), and i.

Referenced by CheckIndexCompatible().

◆ ComputeIndexAttrs()

static void ComputeIndexAttrs ( ParseState pstate,
IndexInfo indexInfo,
Oid typeOids,
Oid collationOids,
Oid opclassOids,
Datum opclassOptions,
int16 colOptions,
const List attList,
const List exclusionOpNames,
Oid  relId,
const char accessMethodName,
Oid  accessMethodId,
bool  amcanorder,
bool  isconstraint,
bool  iswithoutoverlaps,
Oid  ddl_userid,
int  ddl_sec_context,
int ddl_save_nestlevel 
)
static

Definition at line 1878 of file indexcmds.c.

1896{
1898 ListCell *lc;
1899 int attn;
1900 int nkeycols = indexInfo->ii_NumIndexKeyAttrs;
1901 Oid save_userid;
1902 int save_sec_context;
1903
1904 /* Allocate space for exclusion operator info, if needed */
1905 if (exclusionOpNames)
1906 {
1912 }
1913 else
1914 nextExclOp = NULL;
1915
1916 /*
1917 * If this is a WITHOUT OVERLAPS constraint, we need space for exclusion
1918 * ops, but we don't need to parse anything, so we can let nextExclOp be
1919 * NULL. Note that for partitions/inheriting/LIKE, exclusionOpNames will
1920 * be set, so we already allocated above.
1921 */
1922 if (iswithoutoverlaps)
1923 {
1924 if (exclusionOpNames == NIL)
1925 {
1929 }
1930 nextExclOp = NULL;
1931 }
1932
1934 GetUserIdAndSecContext(&save_userid, &save_sec_context);
1935
1936 /*
1937 * process attributeList
1938 */
1939 attn = 0;
1940 foreach(lc, attList)
1941 {
1942 IndexElem *attribute = (IndexElem *) lfirst(lc);
1943 Oid atttype;
1944 Oid attcollation;
1945
1946 /*
1947 * Process the column-or-expression to be indexed.
1948 */
1949 if (attribute->name != NULL)
1950 {
1951 /* Simple index attribute */
1954
1955 Assert(attribute->expr == NULL);
1956 atttuple = SearchSysCacheAttName(relId, attribute->name);
1958 {
1959 /* difference in error message spellings is historical */
1960 if (isconstraint)
1961 ereport(ERROR,
1963 errmsg("column \"%s\" named in key does not exist",
1964 attribute->name),
1965 parser_errposition(pstate, attribute->location)));
1966 else
1967 ereport(ERROR,
1969 errmsg("column \"%s\" does not exist",
1970 attribute->name),
1971 parser_errposition(pstate, attribute->location)));
1972 }
1974 indexInfo->ii_IndexAttrNumbers[attn] = attform->attnum;
1975 atttype = attform->atttypid;
1976 attcollation = attform->attcollation;
1978 }
1979 else
1980 {
1981 /* Index expression */
1982 Node *expr = attribute->expr;
1983
1984 Assert(expr != NULL);
1985
1986 if (attn >= nkeycols)
1987 ereport(ERROR,
1989 errmsg("expressions are not supported in included columns"),
1990 parser_errposition(pstate, attribute->location)));
1991 atttype = exprType(expr);
1992 attcollation = exprCollation(expr);
1993
1994 /*
1995 * Strip any top-level COLLATE clause. This ensures that we treat
1996 * "x COLLATE y" and "(x COLLATE y)" alike.
1997 */
1998 while (IsA(expr, CollateExpr))
1999 expr = (Node *) ((CollateExpr *) expr)->arg;
2000
2001 if (IsA(expr, Var) &&
2002 ((Var *) expr)->varattno != InvalidAttrNumber)
2003 {
2004 /*
2005 * User wrote "(column)" or "(column COLLATE something)".
2006 * Treat it like simple attribute anyway.
2007 */
2008 indexInfo->ii_IndexAttrNumbers[attn] = ((Var *) expr)->varattno;
2009 }
2010 else
2011 {
2012 indexInfo->ii_IndexAttrNumbers[attn] = 0; /* marks expression */
2013 indexInfo->ii_Expressions = lappend(indexInfo->ii_Expressions,
2014 expr);
2015
2016 /*
2017 * transformExpr() should have already rejected subqueries,
2018 * aggregates, and window functions, based on the EXPR_KIND_
2019 * for an index expression.
2020 */
2021
2022 /*
2023 * An expression using mutable functions is probably wrong,
2024 * since if you aren't going to get the same result for the
2025 * same data every time, it's not clear what the index entries
2026 * mean at all.
2027 */
2029 ereport(ERROR,
2031 errmsg("functions in index expression must be marked IMMUTABLE"),
2032 parser_errposition(pstate, attribute->location)));
2033 }
2034 }
2035
2036 typeOids[attn] = atttype;
2037
2038 /*
2039 * Included columns have no collation, no opclass and no ordering
2040 * options.
2041 */
2042 if (attn >= nkeycols)
2043 {
2044 if (attribute->collation)
2045 ereport(ERROR,
2047 errmsg("including column does not support a collation"),
2048 parser_errposition(pstate, attribute->location)));
2049 if (attribute->opclass)
2050 ereport(ERROR,
2052 errmsg("including column does not support an operator class"),
2053 parser_errposition(pstate, attribute->location)));
2054 if (attribute->ordering != SORTBY_DEFAULT)
2055 ereport(ERROR,
2057 errmsg("including column does not support ASC/DESC options"),
2058 parser_errposition(pstate, attribute->location)));
2059 if (attribute->nulls_ordering != SORTBY_NULLS_DEFAULT)
2060 ereport(ERROR,
2062 errmsg("including column does not support NULLS FIRST/LAST options"),
2063 parser_errposition(pstate, attribute->location)));
2064
2066 opclassOptions[attn] = (Datum) 0;
2067 colOptions[attn] = 0;
2069 attn++;
2070
2071 continue;
2072 }
2073
2074 /*
2075 * Apply collation override if any. Use of ddl_userid is necessary
2076 * due to ACL checks therein, and it's safe because collations don't
2077 * contain opaque expressions (or non-opaque expressions).
2078 */
2079 if (attribute->collation)
2080 {
2082 {
2085 }
2086 attcollation = get_collation_oid(attribute->collation, false);
2088 {
2089 SetUserIdAndSecContext(save_userid, save_sec_context);
2092 }
2093 }
2094
2095 /*
2096 * Check we have a collation iff it's a collatable type. The only
2097 * expected failures here are (1) COLLATE applied to a noncollatable
2098 * type, or (2) index expression had an unresolved collation. But we
2099 * might as well code this to be a complete consistency check.
2100 */
2101 if (type_is_collatable(atttype))
2102 {
2103 if (!OidIsValid(attcollation))
2104 ereport(ERROR,
2106 errmsg("could not determine which collation to use for index expression"),
2107 errhint("Use the COLLATE clause to set the collation explicitly."),
2108 parser_errposition(pstate, attribute->location)));
2109 }
2110 else
2111 {
2112 if (OidIsValid(attcollation))
2113 ereport(ERROR,
2115 errmsg("collations are not supported by type %s",
2116 format_type_be(atttype)),
2117 parser_errposition(pstate, attribute->location)));
2118 }
2119
2120 collationOids[attn] = attcollation;
2121
2122 /*
2123 * Identify the opclass to use. Use of ddl_userid is necessary due to
2124 * ACL checks therein. This is safe despite opclasses containing
2125 * opaque expressions (specifically, functions), because only
2126 * superusers can define opclasses.
2127 */
2129 {
2132 }
2133 opclassOids[attn] = ResolveOpClass(attribute->opclass,
2134 atttype,
2138 {
2139 SetUserIdAndSecContext(save_userid, save_sec_context);
2142 }
2143
2144 /*
2145 * Identify the exclusion operator, if any.
2146 */
2147 if (nextExclOp)
2148 {
2150 Oid opid;
2151 Oid opfamily;
2152 int strat;
2153
2154 /*
2155 * Find the operator --- it must accept the column datatype
2156 * without runtime coercion (but binary compatibility is OK).
2157 * Operators contain opaque expressions (specifically, functions).
2158 * compatible_oper_opid() boils down to oper() and
2159 * IsBinaryCoercible(). PostgreSQL would have security problems
2160 * elsewhere if oper() started calling opaque expressions.
2161 */
2163 {
2166 }
2167 opid = compatible_oper_opid(opname, atttype, atttype, false);
2169 {
2170 SetUserIdAndSecContext(save_userid, save_sec_context);
2173 }
2174
2175 /*
2176 * Only allow commutative operators to be used in exclusion
2177 * constraints. If X conflicts with Y, but Y does not conflict
2178 * with X, bad things will happen.
2179 */
2180 if (get_commutator(opid) != opid)
2181 ereport(ERROR,
2183 errmsg("operator %s is not commutative",
2185 errdetail("Only commutative operators can be used in exclusion constraints."),
2186 parser_errposition(pstate, attribute->location)));
2187
2188 /*
2189 * Operator must be a member of the right opfamily, too
2190 */
2191 opfamily = get_opclass_family(opclassOids[attn]);
2192 strat = get_op_opfamily_strategy(opid, opfamily);
2193 if (strat == 0)
2194 ereport(ERROR,
2196 errmsg("operator %s is not a member of operator family \"%s\"",
2198 get_opfamily_name(opfamily, false)),
2199 errdetail("The exclusion operator must be related to the index operator class for the constraint."),
2200 parser_errposition(pstate, attribute->location)));
2201
2202 indexInfo->ii_ExclusionOps[attn] = opid;
2203 indexInfo->ii_ExclusionProcs[attn] = get_opcode(opid);
2204 indexInfo->ii_ExclusionStrats[attn] = strat;
2206 }
2207 else if (iswithoutoverlaps)
2208 {
2209 CompareType cmptype;
2211 Oid opid;
2212
2213 if (attn == nkeycols - 1)
2214 cmptype = COMPARE_OVERLAP;
2215 else
2216 cmptype = COMPARE_EQ;
2218 indexInfo->ii_ExclusionOps[attn] = opid;
2219 indexInfo->ii_ExclusionProcs[attn] = get_opcode(opid);
2220 indexInfo->ii_ExclusionStrats[attn] = strat;
2221 }
2222
2223 /*
2224 * Set up the per-column options (indoption field). For now, this is
2225 * zero for any un-ordered index, while ordered indexes have DESC and
2226 * NULLS FIRST/LAST options.
2227 */
2228 colOptions[attn] = 0;
2229 if (amcanorder)
2230 {
2231 /* default ordering is ASC */
2232 if (attribute->ordering == SORTBY_DESC)
2234 /* default null ordering is LAST for ASC, FIRST for DESC */
2235 if (attribute->nulls_ordering == SORTBY_NULLS_DEFAULT)
2236 {
2237 if (attribute->ordering == SORTBY_DESC)
2239 }
2240 else if (attribute->nulls_ordering == SORTBY_NULLS_FIRST)
2242 }
2243 else
2244 {
2245 /* index AM does not support ordering */
2246 if (attribute->ordering != SORTBY_DEFAULT)
2247 ereport(ERROR,
2249 errmsg("access method \"%s\" does not support ASC/DESC options",
2251 parser_errposition(pstate, attribute->location)));
2252 if (attribute->nulls_ordering != SORTBY_NULLS_DEFAULT)
2253 ereport(ERROR,
2255 errmsg("access method \"%s\" does not support NULLS FIRST/LAST options",
2257 parser_errposition(pstate, attribute->location)));
2258 }
2259
2260 /* Set up the per-column opclass options (attoptions field). */
2261 if (attribute->opclassopts)
2262 {
2263 Assert(attn < nkeycols);
2264
2266 transformRelOptions((Datum) 0, attribute->opclassopts,
2267 NULL, NULL, false, false);
2268 }
2269 else
2270 opclassOptions[attn] = (Datum) 0;
2271
2272 attn++;
2273 }
2274}
#define InvalidAttrNumber
Definition attnum.h:23
#define OidIsValid(objectId)
Definition c.h:788
CompareType
Definition cmptype.h:32
@ COMPARE_OVERLAP
Definition cmptype.h:40
@ COMPARE_EQ
Definition cmptype.h:36
int errdetail(const char *fmt,...)
Definition elog.c:1216
int errhint(const char *fmt,...)
Definition elog.c:1330
char * format_type_be(Oid type_oid)
int NewGUCNestLevel(void)
Definition guc.c:2110
void RestrictSearchPath(void)
Definition guc.c:2121
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition guc.c:2137
Oid ResolveOpClass(const List *opclass, Oid attrType, const char *accessMethodName, Oid accessMethodId)
Definition indexcmds.c:2283
void GetOperatorFromCompareType(Oid opclass, Oid rhstype, CompareType cmptype, Oid *opid, StrategyNumber *strat)
Definition indexcmds.c:2470
Oid get_opclass_family(Oid opclass)
Definition lsyscache.c:1292
RegProcedure get_opcode(Oid opno)
Definition lsyscache.c:1435
int get_op_opfamily_strategy(Oid opno, Oid opfamily)
Definition lsyscache.c:85
char * get_opfamily_name(Oid opfid, bool missing_ok)
Definition lsyscache.c:1403
bool type_is_collatable(Oid typid)
Definition lsyscache.c:3231
Oid get_commutator(Oid opno)
Definition lsyscache.c:1659
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition miscinit.c:612
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition miscinit.c:619
Oid get_collation_oid(List *collname, bool missing_ok)
Definition namespace.c:4041
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
Oid exprCollation(const Node *expr)
Definition nodeFuncs.c:821
#define IsA(nodeptr, _type_)
Definition nodes.h:164
int parser_errposition(ParseState *pstate, int location)
Definition parse_node.c:106
Oid compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError)
Definition parse_oper.c:490
@ SORTBY_NULLS_DEFAULT
Definition parsenodes.h:54
@ SORTBY_NULLS_FIRST
Definition parsenodes.h:55
@ SORTBY_DESC
Definition parsenodes.h:48
@ SORTBY_DEFAULT
Definition parsenodes.h:46
FormData_pg_attribute * Form_pg_attribute
void * arg
static ListCell * list_head(const List *l)
Definition pg_list.h:128
static ListCell * lnext(const List *l, const ListCell *c)
Definition pg_list.h:343
char * format_operator(Oid operator_oid)
Definition regproc.c:801
Datum transformRelOptions(Datum oldOptions, List *defList, const char *nameSpace, const char *const validnsps[], bool acceptOidsOff, bool isReset)
uint16 StrategyNumber
Definition stratnum.h:22
Node * expr
Definition parsenodes.h:812
SortByDir ordering
Definition parsenodes.h:817
List * opclassopts
Definition parsenodes.h:816
ParseLoc location
Definition parsenodes.h:819
SortByNulls nulls_ordering
Definition parsenodes.h:818
List * opclass
Definition parsenodes.h:815
char * name
Definition parsenodes.h:811
List * collation
Definition parsenodes.h:814
uint16 * ii_ExclusionStrats
Definition execnodes.h:194
int ii_NumIndexKeyAttrs
Definition execnodes.h:171
List * ii_Expressions
Definition execnodes.h:180
Oid * ii_ExclusionProcs
Definition execnodes.h:192
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition execnodes.h:177
Definition nodes.h:135
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition syscache.c:475

References arg, Assert, AtEOXact_GUC(), IndexElem::collation, COMPARE_EQ, COMPARE_OVERLAP, compatible_oper_opid(), contain_mutable_functions_after_planning(), ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, IndexElem::expr, exprCollation(), exprType(), fb(), format_operator(), format_type_be(), get_collation_oid(), get_commutator(), get_op_opfamily_strategy(), get_opclass_family(), get_opcode(), get_opfamily_name(), GetOperatorFromCompareType(), GETSTRUCT(), GetUserIdAndSecContext(), HeapTupleIsValid, IndexInfo::ii_ExclusionOps, IndexInfo::ii_ExclusionProcs, IndexInfo::ii_ExclusionStrats, IndexInfo::ii_Expressions, IndexInfo::ii_IndexAttrNumbers, IndexInfo::ii_NumIndexKeyAttrs, InvalidAttrNumber, InvalidOid, IsA, lappend(), lfirst, list_head(), list_length(), lnext(), IndexElem::location, IndexElem::name, NewGUCNestLevel(), NIL, IndexElem::nulls_ordering, OidIsValid, IndexElem::opclass, IndexElem::opclassopts, IndexElem::ordering, palloc_array, parser_errposition(), ReleaseSysCache(), ResolveOpClass(), RestrictSearchPath(), SearchSysCacheAttName(), SetUserIdAndSecContext(), SORTBY_DEFAULT, SORTBY_DESC, SORTBY_NULLS_DEFAULT, SORTBY_NULLS_FIRST, transformRelOptions(), and type_is_collatable().

Referenced by CheckIndexCompatible(), and DefineIndex().

◆ DefineIndex()

ObjectAddress DefineIndex ( ParseState pstate,
Oid  tableId,
IndexStmt stmt,
Oid  indexRelationId,
Oid  parentIndexId,
Oid  parentConstraintId,
int  total_parts,
bool  is_alter_table,
bool  check_rights,
bool  check_not_in_use,
bool  skip_build,
bool  quiet 
)

Definition at line 544 of file indexcmds.c.

556{
557 bool concurrent;
558 char *indexRelationName;
559 char *accessMethodName;
560 Oid *typeIds;
570 Relation rel;
571 HeapTuple tuple;
574 bool amcanorder;
575 bool amissummarizing;
576 amoptions_function amoptions;
577 bool exclusion;
578 bool partitioned;
579 bool safe_index;
580 Datum reloptions;
582 IndexInfo *indexInfo;
583 bits16 flags;
588 ObjectAddress address;
589 LockRelId heaprelid;
591 LOCKMODE lockmode;
592 Snapshot snapshot;
596
598
600
601 /*
602 * Some callers need us to run with an empty default_tablespace; this is a
603 * necessary hack to be able to reproduce catalog state accurately when
604 * recreating indexes after table-rewriting ALTER TABLE.
605 */
606 if (stmt->reset_default_tblspc)
607 (void) set_config_option("default_tablespace", "",
609 GUC_ACTION_SAVE, true, 0, false);
610
611 /*
612 * Force non-concurrent build on temporary relations, even if CONCURRENTLY
613 * was requested. Other backends can't access a temporary relation, so
614 * there's no harm in grabbing a stronger lock, and a non-concurrent DROP
615 * is more efficient. Do this before any use of the concurrent option is
616 * done.
617 */
619 concurrent = true;
620 else
621 concurrent = false;
622
623 /*
624 * Start progress report. If we're building a partition, this was already
625 * done.
626 */
628 {
631 concurrent ?
634 }
635
636 /*
637 * No index OID to report yet
638 */
640 InvalidOid);
641
642 /*
643 * count key attributes in index
644 */
645 numberOfKeyAttributes = list_length(stmt->indexParams);
646
647 /*
648 * Calculate the new list of index columns including both key columns and
649 * INCLUDE columns. Later we can determine which of these are key
650 * columns, and which are just part of the INCLUDE list by checking the
651 * list position. A list item in a position less than ii_NumIndexKeyAttrs
652 * is part of the key columns, and anything equal to and over is part of
653 * the INCLUDE columns.
654 */
655 allIndexParams = list_concat_copy(stmt->indexParams,
656 stmt->indexIncludingParams);
658
659 if (numberOfKeyAttributes <= 0)
662 errmsg("must specify at least one column")));
666 errmsg("cannot use more than %d columns in an index",
668
669 /*
670 * Only SELECT ... FOR UPDATE/SHARE are allowed while doing a standard
671 * index build; but for concurrent builds we allow INSERT/UPDATE/DELETE
672 * (but not VACUUM).
673 *
674 * NB: Caller is responsible for making sure that tableId refers to the
675 * relation on which the index should be built; except in bootstrap mode,
676 * this will typically require the caller to have already locked the
677 * relation. To avoid lock upgrade hazards, that lock should be at least
678 * as strong as the one we take here.
679 *
680 * NB: If the lock strength here ever changes, code that is run by
681 * parallel workers under the control of certain particular ambuild
682 * functions will need to be updated, too.
683 */
684 lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock;
685 rel = table_open(tableId, lockmode);
686
687 /*
688 * Switch to the table owner's userid, so that any index functions are run
689 * as that user. Also lock down security-restricted operations. We
690 * already arranged to make GUC variable changes local to this command.
691 */
693 SetUserIdAndSecContext(rel->rd_rel->relowner,
695
697
698 /*
699 * It has exclusion constraint behavior if it's an EXCLUDE constraint or a
700 * temporal PRIMARY KEY/UNIQUE constraint
701 */
702 exclusion = stmt->excludeOpNames || stmt->iswithoutoverlaps;
703
704 /* Ensure that it makes sense to index this kind of relation */
705 switch (rel->rd_rel->relkind)
706 {
707 case RELKIND_RELATION:
708 case RELKIND_MATVIEW:
710 /* OK */
711 break;
712 default:
715 errmsg("cannot create index on relation \"%s\"",
718 break;
719 }
720
721 /*
722 * Establish behavior for partitioned tables, and verify sanity of
723 * parameters.
724 *
725 * We do not build an actual index in this case; we only create a few
726 * catalog entries. The actual indexes are built by recursing for each
727 * partition.
728 */
730 if (partitioned)
731 {
732 /*
733 * Note: we check 'stmt->concurrent' rather than 'concurrent', so that
734 * the error is thrown also for temporary tables. Seems better to be
735 * consistent, even though we could do it on temporary table because
736 * we're not actually doing it concurrently.
737 */
738 if (stmt->concurrent)
741 errmsg("cannot create index on partitioned table \"%s\" concurrently",
743 }
744
745 /*
746 * Don't try to CREATE INDEX on temp tables of other backends.
747 */
748 if (RELATION_IS_OTHER_TEMP(rel))
751 errmsg("cannot create indexes on temporary tables of other sessions")));
752
753 /*
754 * Unless our caller vouches for having checked this already, insist that
755 * the table not be in use by our own session, either. Otherwise we might
756 * fail to make entries in the new index (for instance, if an INSERT or
757 * UPDATE is in progress and has already made its list of target indexes).
758 */
760 CheckTableNotInUse(rel, "CREATE INDEX");
761
762 /*
763 * Verify we (still) have CREATE rights in the rel's namespace.
764 * (Presumably we did when the rel was created, but maybe not anymore.)
765 * Skip check if caller doesn't want it. Also skip check if
766 * bootstrapping, since permissions machinery may not be working yet.
767 */
769 {
771
773 ACL_CREATE);
774 if (aclresult != ACLCHECK_OK)
777 }
778
779 /*
780 * Select tablespace to use. If not specified, use default tablespace
781 * (which may in turn default to database's default).
782 */
783 if (stmt->tableSpace)
784 {
785 tablespaceId = get_tablespace_oid(stmt->tableSpace, false);
789 errmsg("cannot specify default tablespace for partitioned relations")));
790 }
791 else
792 {
793 tablespaceId = GetDefaultTablespace(rel->rd_rel->relpersistence,
795 /* note InvalidOid is OK in this case */
796 }
797
798 /* Check tablespace permissions */
799 if (check_rights &&
801 {
803
805 ACL_CREATE);
806 if (aclresult != ACLCHECK_OK)
809 }
810
811 /*
812 * Force shared indexes into the pg_global tablespace. This is a bit of a
813 * hack but seems simpler than marking them in the BKI commands. On the
814 * other hand, if it's not shared, don't allow it to be placed there.
815 */
816 if (rel->rd_rel->relisshared)
821 errmsg("only shared relations can be placed in pg_global tablespace")));
822
823 /*
824 * Choose the index column names.
825 */
827
828 /*
829 * Select name for index if caller didn't specify
830 */
831 indexRelationName = stmt->idxname;
832 if (indexRelationName == NULL)
836 stmt->excludeOpNames,
837 stmt->primary,
838 stmt->isconstraint);
839
840 /*
841 * look up the access method, verify it can handle the requested features
842 */
843 accessMethodName = stmt->accessMethod;
845 if (!HeapTupleIsValid(tuple))
846 {
847 /*
848 * Hack to provide more-or-less-transparent updating of old RTREE
849 * indexes to GiST: if RTREE is requested and not found, use GIST.
850 */
851 if (strcmp(accessMethodName, "rtree") == 0)
852 {
854 (errmsg("substituting access method \"gist\" for obsolete method \"rtree\"")));
855 accessMethodName = "gist";
857 }
858
859 if (!HeapTupleIsValid(tuple))
862 errmsg("access method \"%s\" does not exist",
864 }
868
871
872 if (stmt->unique && !stmt->iswithoutoverlaps && !amRoutine->amcanunique)
875 errmsg("access method \"%s\" does not support unique indexes",
877 if (stmt->indexIncludingParams != NIL && !amRoutine->amcaninclude)
880 errmsg("access method \"%s\" does not support included columns",
882 if (numberOfKeyAttributes > 1 && !amRoutine->amcanmulticol)
885 errmsg("access method \"%s\" does not support multicolumn indexes",
887 if (exclusion && amRoutine->amgettuple == NULL)
890 errmsg("access method \"%s\" does not support exclusion constraints",
892 if (stmt->iswithoutoverlaps && strcmp(accessMethodName, "gist") != 0)
895 errmsg("access method \"%s\" does not support WITHOUT OVERLAPS constraints",
897
898 amcanorder = amRoutine->amcanorder;
899 amoptions = amRoutine->amoptions;
900 amissummarizing = amRoutine->amsummarizing;
901
902 ReleaseSysCache(tuple);
903
904 /*
905 * Validate predicate, if given
906 */
907 if (stmt->whereClause)
908 CheckPredicate((Expr *) stmt->whereClause);
909
910 /*
911 * Parse AM-specific options, convert to text array form, validate.
912 */
913 reloptions = transformRelOptions((Datum) 0, stmt->options,
914 NULL, NULL, false, false);
915
916 (void) index_reloptions(amoptions, reloptions, true);
917
918 /*
919 * Prepare arguments for index_create, primarily an IndexInfo structure.
920 * Note that predicates must be in implicit-AND format. In a concurrent
921 * build, mark it not-ready-for-inserts.
922 */
926 NIL, /* expressions, NIL for now */
927 make_ands_implicit((Expr *) stmt->whereClause),
928 stmt->unique,
929 stmt->nulls_not_distinct,
930 !concurrent,
931 concurrent,
933 stmt->iswithoutoverlaps);
934
940 ComputeIndexAttrs(pstate,
941 indexInfo,
944 stmt->excludeOpNames, tableId,
946 amcanorder, stmt->isconstraint, stmt->iswithoutoverlaps,
949
950 /*
951 * Extra checks when creating a PRIMARY KEY index.
952 */
953 if (stmt->primary)
955
956 /*
957 * If this table is partitioned and we're creating a unique index, primary
958 * key, or exclusion constraint, make sure that the partition key is a
959 * subset of the index's columns. Otherwise it would be possible to
960 * violate uniqueness by putting values that ought to be unique in
961 * different partitions.
962 *
963 * We could lift this limitation if we had global indexes, but those have
964 * their own problems, so this is a useful feature combination.
965 */
966 if (partitioned && (stmt->unique || exclusion))
967 {
969 const char *constraint_type;
970 int i;
971
972 if (stmt->primary)
973 constraint_type = "PRIMARY KEY";
974 else if (stmt->unique)
975 constraint_type = "UNIQUE";
976 else if (stmt->excludeOpNames)
977 constraint_type = "EXCLUDE";
978 else
979 {
980 elog(ERROR, "unknown constraint type");
981 constraint_type = NULL; /* keep compiler quiet */
982 }
983
984 /*
985 * Verify that all the columns in the partition key appear in the
986 * unique key definition, with the same notion of equality.
987 */
988 for (i = 0; i < key->partnatts; i++)
989 {
990 bool found = false;
991 int eq_strategy;
993 int j;
994
995 /*
996 * Identify the equality operator associated with this partkey
997 * column. For list and range partitioning, partkeys use btree
998 * operator classes; hash partitioning uses hash operator classes.
999 * (Keep this in sync with ComputePartitionAttrs!)
1000 */
1001 if (key->strategy == PARTITION_STRATEGY_HASH)
1003 else
1005
1006 ptkey_eqop = get_opfamily_member(key->partopfamily[i],
1007 key->partopcintype[i],
1008 key->partopcintype[i],
1009 eq_strategy);
1010 if (!OidIsValid(ptkey_eqop))
1011 elog(ERROR, "missing operator %d(%u,%u) in partition opfamily %u",
1012 eq_strategy, key->partopcintype[i], key->partopcintype[i],
1013 key->partopfamily[i]);
1014
1015 /*
1016 * It may be possible to support UNIQUE constraints when partition
1017 * keys are expressions, but is it worth it? Give up for now.
1018 */
1019 if (key->partattrs[i] == 0)
1020 ereport(ERROR,
1022 errmsg("unsupported %s constraint with partition key definition",
1024 errdetail("%s constraints cannot be used when partition keys include expressions.",
1025 constraint_type)));
1026
1027 /* Search the index column(s) for a match */
1028 for (j = 0; j < indexInfo->ii_NumIndexKeyAttrs; j++)
1029 {
1030 if (key->partattrs[i] == indexInfo->ii_IndexAttrNumbers[j])
1031 {
1032 /*
1033 * Matched the column, now what about the collation and
1034 * equality op?
1035 */
1038
1039 if (key->partcollation[i] != collationIds[j])
1040 continue;
1041
1043 &idx_opfamily,
1044 &idx_opcintype))
1045 {
1047
1048 if (stmt->unique && !stmt->iswithoutoverlaps)
1052 COMPARE_EQ);
1053 else if (exclusion)
1054 idx_eqop = indexInfo->ii_ExclusionOps[j];
1055
1056 if (!idx_eqop)
1057 ereport(ERROR,
1059 errmsg("could not identify an equality operator for type %s", format_type_be(idx_opcintype)),
1060 errdetail("There is no suitable operator in operator family \"%s\" for access method \"%s\".",
1062
1063 if (ptkey_eqop == idx_eqop)
1064 {
1065 found = true;
1066 break;
1067 }
1068 else if (exclusion)
1069 {
1070 /*
1071 * We found a match, but it's not an equality
1072 * operator. Instead of failing below with an
1073 * error message about a missing column, fail now
1074 * and explain that the operator is wrong.
1075 */
1076 Form_pg_attribute att = TupleDescAttr(RelationGetDescr(rel), key->partattrs[i] - 1);
1077
1078 ereport(ERROR,
1080 errmsg("cannot match partition key to index on column \"%s\" using non-equal operator \"%s\"",
1081 NameStr(att->attname),
1082 get_opname(indexInfo->ii_ExclusionOps[j]))));
1083 }
1084 }
1085 }
1086 }
1087
1088 if (!found)
1089 {
1091
1093 key->partattrs[i] - 1);
1094 ereport(ERROR,
1096 /* translator: %s is UNIQUE, PRIMARY KEY, etc */
1097 errmsg("%s constraint on partitioned table must include all partitioning columns",
1099 /* translator: first %s is UNIQUE, PRIMARY KEY, etc */
1100 errdetail("%s constraint on table \"%s\" lacks column \"%s\" which is part of the partition key.",
1102 NameStr(att->attname))));
1103 }
1104 }
1105 }
1106
1107
1108 /*
1109 * We disallow indexes on system columns. They would not necessarily get
1110 * updated correctly, and they don't seem useful anyway.
1111 *
1112 * Also disallow virtual generated columns in indexes (use expression
1113 * index instead).
1114 */
1115 for (int i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
1116 {
1117 AttrNumber attno = indexInfo->ii_IndexAttrNumbers[i];
1118
1119 if (attno < 0)
1120 ereport(ERROR,
1122 errmsg("index creation on system columns is not supported")));
1123
1124
1125 if (TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
1126 ereport(ERROR,
1128 stmt->primary ?
1129 errmsg("primary keys on virtual generated columns are not supported") :
1130 stmt->isconstraint ?
1131 errmsg("unique constraints on virtual generated columns are not supported") :
1132 errmsg("indexes on virtual generated columns are not supported"));
1133 }
1134
1135 /*
1136 * Also check for system and generated columns used in expressions or
1137 * predicates.
1138 */
1139 if (indexInfo->ii_Expressions || indexInfo->ii_Predicate)
1140 {
1142 int j;
1143
1144 pull_varattnos((Node *) indexInfo->ii_Expressions, 1, &indexattrs);
1145 pull_varattnos((Node *) indexInfo->ii_Predicate, 1, &indexattrs);
1146
1147 for (int i = FirstLowInvalidHeapAttributeNumber + 1; i < 0; i++)
1148 {
1150 indexattrs))
1151 ereport(ERROR,
1153 errmsg("index creation on system columns is not supported")));
1154 }
1155
1156 /*
1157 * XXX Virtual generated columns in index expressions or predicates
1158 * could be supported, but it needs support in
1159 * RelationGetIndexExpressions() and RelationGetIndexPredicate().
1160 */
1161 j = -1;
1162 while ((j = bms_next_member(indexattrs, j)) >= 0)
1163 {
1165
1166 if (TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
1167 ereport(ERROR,
1169 stmt->isconstraint ?
1170 errmsg("unique constraints on virtual generated columns are not supported") :
1171 errmsg("indexes on virtual generated columns are not supported")));
1172 }
1173 }
1174
1175 /* Is index safe for others to ignore? See set_indexsafe_procflags() */
1176 safe_index = indexInfo->ii_Expressions == NIL &&
1177 indexInfo->ii_Predicate == NIL;
1178
1179 /*
1180 * Report index creation if appropriate (delay this till after most of the
1181 * error checks)
1182 */
1183 if (stmt->isconstraint && !quiet)
1184 {
1185 const char *constraint_type;
1186
1187 if (stmt->primary)
1188 constraint_type = "PRIMARY KEY";
1189 else if (stmt->unique)
1190 constraint_type = "UNIQUE";
1191 else if (stmt->excludeOpNames)
1192 constraint_type = "EXCLUDE";
1193 else
1194 {
1195 elog(ERROR, "unknown constraint type");
1196 constraint_type = NULL; /* keep compiler quiet */
1197 }
1198
1200 (errmsg_internal("%s %s will create implicit index \"%s\" for table \"%s\"",
1201 is_alter_table ? "ALTER TABLE / ADD" : "CREATE TABLE /",
1204 }
1205
1206 /*
1207 * A valid stmt->oldNumber implies that we already have a built form of
1208 * the index. The caller should also decline any index build.
1209 */
1210 Assert(!RelFileNumberIsValid(stmt->oldNumber) || (skip_build && !concurrent));
1211
1212 /*
1213 * Make the catalog entries for the index, including constraints. This
1214 * step also actually builds the index, except if caller requested not to
1215 * or in concurrent mode, in which case it'll be done later, or doing a
1216 * partitioned index (because those don't have storage).
1217 */
1218 flags = constr_flags = 0;
1219 if (stmt->isconstraint)
1221 if (skip_build || concurrent || partitioned)
1222 flags |= INDEX_CREATE_SKIP_BUILD;
1223 if (stmt->if_not_exists)
1225 if (concurrent)
1226 flags |= INDEX_CREATE_CONCURRENT;
1227 if (partitioned)
1228 flags |= INDEX_CREATE_PARTITIONED;
1229 if (stmt->primary)
1230 flags |= INDEX_CREATE_IS_PRIMARY;
1231
1232 /*
1233 * If the table is partitioned, and recursion was declined but partitions
1234 * exist, mark the index as invalid.
1235 */
1236 if (partitioned && stmt->relation && !stmt->relation->inh)
1237 {
1239
1240 if (pd->nparts != 0)
1241 flags |= INDEX_CREATE_INVALID;
1242 }
1243
1244 if (stmt->deferrable)
1246 if (stmt->initdeferred)
1248 if (stmt->iswithoutoverlaps)
1250
1254 stmt->oldNumber, indexInfo, indexColNames,
1257 coloptions, NULL, reloptions,
1258 flags, constr_flags,
1261
1263
1265 {
1266 /*
1267 * Roll back any GUC changes executed by index functions. Also revert
1268 * to original default_tablespace if we changed it above.
1269 */
1271
1272 /* Restore userid and security context */
1274
1275 table_close(rel, NoLock);
1276
1277 /* If this is the top-level index, we're done */
1280
1281 return address;
1282 }
1283
1284 /*
1285 * Roll back any GUC changes executed by index functions, and keep
1286 * subsequent changes local to this command. This is essential if some
1287 * index function changed a behavior-affecting GUC, e.g. search_path.
1288 */
1292
1293 /* Add any requested comment */
1294 if (stmt->idxcomment != NULL)
1296 stmt->idxcomment);
1297
1298 if (partitioned)
1299 {
1300 PartitionDesc partdesc;
1301
1302 /*
1303 * Unless caller specified to skip this step (via ONLY), process each
1304 * partition to make sure they all contain a corresponding index.
1305 *
1306 * If we're called internally (no stmt->relation), recurse always.
1307 */
1308 partdesc = RelationGetPartitionDesc(rel, true);
1309 if ((!stmt->relation || stmt->relation->inh) && partdesc->nparts > 0)
1310 {
1311 int nparts = partdesc->nparts;
1312 Oid *part_oids = palloc_array(Oid, nparts);
1313 bool invalidate_parent = false;
1316
1317 /*
1318 * Report the total number of partitions at the start of the
1319 * command; don't update it when being called recursively.
1320 */
1322 {
1323 /*
1324 * When called by ProcessUtilitySlow, the number of partitions
1325 * is passed in as an optimization; but other callers pass -1
1326 * since they don't have the value handy. This should count
1327 * partitions the same way, ie one less than the number of
1328 * relations find_all_inheritors reports.
1329 *
1330 * We assume we needn't ask find_all_inheritors to take locks,
1331 * because that should have happened already for all callers.
1332 * Even if it did not, this is safe as long as we don't try to
1333 * touch the partitions here; the worst consequence would be a
1334 * bogus progress-reporting total.
1335 */
1336 if (total_parts < 0)
1337 {
1339
1340 total_parts = list_length(children) - 1;
1341 list_free(children);
1342 }
1343
1345 total_parts);
1346 }
1347
1348 /* Make a local copy of partdesc->oids[], just for safety */
1349 memcpy(part_oids, partdesc->oids, sizeof(Oid) * nparts);
1350
1351 /*
1352 * We'll need an IndexInfo describing the parent index. The one
1353 * built above is almost good enough, but not quite, because (for
1354 * example) its predicate expression if any hasn't been through
1355 * expression preprocessing. The most reliable way to get an
1356 * IndexInfo that will match those for child indexes is to build
1357 * it the same way, using BuildIndexInfo().
1358 */
1360 indexInfo = BuildIndexInfo(parentIndex);
1361
1363
1364 /*
1365 * For each partition, scan all existing indexes; if one matches
1366 * our index definition and is not already attached to some other
1367 * parent index, attach it to the one we just created.
1368 *
1369 * If none matches, build a new index by calling ourselves
1370 * recursively with the same options (except for the index name).
1371 */
1372 for (int i = 0; i < nparts; i++)
1373 {
1379 List *childidxs;
1380 ListCell *cell;
1381 AttrMap *attmap;
1382 bool found = false;
1383
1384 childrel = table_open(childRelid, lockmode);
1385
1388 SetUserIdAndSecContext(childrel->rd_rel->relowner,
1392
1393 /*
1394 * Don't try to create indexes on foreign tables, though. Skip
1395 * those if a regular index, or fail if trying to create a
1396 * constraint index.
1397 */
1398 if (childrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1399 {
1400 if (stmt->unique || stmt->primary)
1401 ereport(ERROR,
1403 errmsg("cannot create unique index on partitioned table \"%s\"",
1405 errdetail("Table \"%s\" contains partitions that are foreign tables.",
1407
1411 table_close(childrel, lockmode);
1412 continue;
1413 }
1414
1416 attmap =
1418 parentDesc,
1419 false);
1420
1421 foreach(cell, childidxs)
1422 {
1423 Oid cldidxid = lfirst_oid(cell);
1426
1427 /* this index is already partition of another one */
1429 continue;
1430
1431 cldidx = index_open(cldidxid, lockmode);
1433 if (CompareIndexInfo(cldIdxInfo, indexInfo,
1434 cldidx->rd_indcollation,
1435 parentIndex->rd_indcollation,
1436 cldidx->rd_opfamily,
1437 parentIndex->rd_opfamily,
1438 attmap))
1439 {
1441
1442 /*
1443 * Found a match.
1444 *
1445 * If this index is being created in the parent
1446 * because of a constraint, then the child needs to
1447 * have a constraint also, so look for one. If there
1448 * is no such constraint, this index is no good, so
1449 * keep looking.
1450 */
1452 {
1453 cldConstrOid =
1455 cldidxid);
1456 if (cldConstrOid == InvalidOid)
1457 {
1458 index_close(cldidx, lockmode);
1459 continue;
1460 }
1461 }
1462
1463 /* Attach index to parent and we're done. */
1468 childRelid);
1469
1470 if (!cldidx->rd_index->indisvalid)
1471 invalidate_parent = true;
1472
1473 found = true;
1474
1475 /*
1476 * Report this partition as processed. Note that if
1477 * the partition has children itself, we'd ideally
1478 * count the children and update the progress report
1479 * for all of them; but that seems unduly expensive.
1480 * Instead, the progress report will act like all such
1481 * indirect children were processed in zero time at
1482 * the end of the command.
1483 */
1485
1486 /* keep lock till commit */
1488 break;
1489 }
1490
1491 index_close(cldidx, lockmode);
1492 }
1493
1499
1500 /*
1501 * If no matching index was found, create our own.
1502 */
1503 if (!found)
1504 {
1507
1508 /*
1509 * Build an IndexStmt describing the desired child index
1510 * in the same way that we do during ATTACH PARTITION.
1511 * Notably, we rely on generateClonedIndexStmt to produce
1512 * a search-path-independent representation, which the
1513 * original IndexStmt might not be.
1514 */
1517 attmap,
1518 NULL);
1519
1520 /*
1521 * Recurse as the starting user ID. Callee will use that
1522 * for permission checks, then switch again.
1523 */
1527 childAddr =
1528 DefineIndex(NULL, /* original pstate not applicable */
1530 InvalidOid, /* no predefined OID */
1531 indexRelationId, /* this is our child */
1533 -1,
1536 skip_build, quiet);
1539
1540 /*
1541 * Check if the index just created is valid or not, as it
1542 * could be possible that it has been switched as invalid
1543 * when recursing across multiple partition levels.
1544 */
1545 if (!get_index_isvalid(childAddr.objectId))
1546 invalidate_parent = true;
1547 }
1548
1550 }
1551
1552 index_close(parentIndex, lockmode);
1553
1554 /*
1555 * The pg_index row we inserted for this index was marked
1556 * indisvalid=true. But if we attached an existing index that is
1557 * invalid, this is incorrect, so update our row to invalid too.
1558 */
1560 {
1562 HeapTuple tup,
1563 newtup;
1564
1567 if (!HeapTupleIsValid(tup))
1568 elog(ERROR, "cache lookup failed for index %u",
1576
1577 /*
1578 * CCI here to make this update visible, in case this recurses
1579 * across multiple partition levels.
1580 */
1582 }
1583 }
1584
1585 /*
1586 * Indexes on partitioned tables are not themselves built, so we're
1587 * done here.
1588 */
1591 table_close(rel, NoLock);
1594 else
1595 {
1596 /* Update progress for an intermediate partitioned index itself */
1598 }
1599
1600 return address;
1601 }
1602
1605
1606 if (!concurrent)
1607 {
1608 /* Close the heap and we're done, in the non-concurrent case */
1609 table_close(rel, NoLock);
1610
1611 /*
1612 * If this is the top-level index, the command is done overall;
1613 * otherwise, increment progress to report one child index is done.
1614 */
1617 else
1619
1620 return address;
1621 }
1622
1623 /* save lockrelid and locktag for below, then close rel */
1624 heaprelid = rel->rd_lockInfo.lockRelId;
1625 SET_LOCKTAG_RELATION(heaplocktag, heaprelid.dbId, heaprelid.relId);
1626 table_close(rel, NoLock);
1627
1628 /*
1629 * For a concurrent build, it's important to make the catalog entries
1630 * visible to other transactions before we start to build the index. That
1631 * will prevent them from making incompatible HOT updates. The new index
1632 * will be marked not indisready and not indisvalid, so that no one else
1633 * tries to either insert into it or use it for queries.
1634 *
1635 * We must commit our current transaction so that the index becomes
1636 * visible; then start another. Note that all the data structures we just
1637 * built are lost in the commit. The only data we keep past here are the
1638 * relation IDs.
1639 *
1640 * Before committing, get a session-level lock on the table, to ensure
1641 * that neither it nor the index can be dropped before we finish. This
1642 * cannot block, even if someone else is waiting for access, because we
1643 * already have the same lock within our transaction.
1644 *
1645 * Note: we don't currently bother with a session lock on the index,
1646 * because there are no operations that could change its state while we
1647 * hold lock on the parent table. This might need to change later.
1648 */
1650
1654
1655 /* Tell concurrent index builds to ignore us, if index qualifies */
1656 if (safe_index)
1658
1659 /*
1660 * The index is now visible, so we can report the OID. While on it,
1661 * include the report for the beginning of phase 2.
1662 */
1663 {
1664 const int progress_cols[] = {
1667 };
1668 const int64 progress_vals[] = {
1671 };
1672
1674 }
1675
1676 /*
1677 * Phase 2 of concurrent index build (see comments for validate_index()
1678 * for an overview of how this works)
1679 *
1680 * Now we must wait until no running transaction could have the table open
1681 * with the old list of indexes. Use ShareLock to consider running
1682 * transactions that hold locks that permit writing to the table. Note we
1683 * do not need to worry about xacts that open the table for writing after
1684 * this point; they will see the new index when they open it.
1685 *
1686 * Note: the reason we use actual lock acquisition here, rather than just
1687 * checking the ProcArray and sleeping, is that deadlock is possible if
1688 * one of the transactions in question is blocked trying to acquire an
1689 * exclusive lock on our table. The lock code will detect deadlock and
1690 * error out properly.
1691 */
1693
1694 /*
1695 * At this moment we are sure that there are no transactions with the
1696 * table open for write that don't have this new index in their list of
1697 * indexes. We have waited out all the existing transactions and any new
1698 * transaction will have the new index in its list, but the index is still
1699 * marked as "not-ready-for-inserts". The index is consulted while
1700 * deciding HOT-safety though. This arrangement ensures that no new HOT
1701 * chains can be created where the new tuple and the old tuple in the
1702 * chain have different index keys.
1703 *
1704 * We now take a new snapshot, and build the index using all tuples that
1705 * are visible in this snapshot. We can be sure that any HOT updates to
1706 * these tuples will be compatible with the index, since any updates made
1707 * by transactions that didn't know about the index are now committed or
1708 * rolled back. Thus, each visible tuple is either the end of its
1709 * HOT-chain or the extension of the chain is HOT-safe for this index.
1710 */
1711
1712 /* Set ActiveSnapshot since functions in the indexes may need it */
1714
1715 /* Perform concurrent build of index */
1717
1718 /* we can do away with our snapshot */
1720
1721 /*
1722 * Commit this transaction to make the indisready update visible.
1723 */
1726
1727 /* Tell concurrent index builds to ignore us, if index qualifies */
1728 if (safe_index)
1730
1731 /*
1732 * Phase 3 of concurrent index build
1733 *
1734 * We once again wait until no transaction can have the table open with
1735 * the index marked as read-only for updates.
1736 */
1740
1741 /*
1742 * Now take the "reference snapshot" that will be used by validate_index()
1743 * to filter candidate tuples. Beware! There might still be snapshots in
1744 * use that treat some transaction as in-progress that our reference
1745 * snapshot treats as committed. If such a recently-committed transaction
1746 * deleted tuples in the table, we will not include them in the index; yet
1747 * those transactions which see the deleting one as still-in-progress will
1748 * expect such tuples to be there once we mark the index as valid.
1749 *
1750 * We solve this by waiting for all endangered transactions to exit before
1751 * we mark the index as valid.
1752 *
1753 * We also set ActiveSnapshot to this snap, since functions in indexes may
1754 * need a snapshot.
1755 */
1757 PushActiveSnapshot(snapshot);
1758
1759 /*
1760 * Scan the index and the heap, insert any missing index entries.
1761 */
1763
1764 /*
1765 * Drop the reference snapshot. We must do this before waiting out other
1766 * snapshot holders, else we will deadlock against other processes also
1767 * doing CREATE INDEX CONCURRENTLY, which would see our snapshot as one
1768 * they must wait for. But first, save the snapshot's xmin to use as
1769 * limitXmin for GetCurrentVirtualXIDs().
1770 */
1771 limitXmin = snapshot->xmin;
1772
1774 UnregisterSnapshot(snapshot);
1775
1776 /*
1777 * The snapshot subsystem could still contain registered snapshots that
1778 * are holding back our process's advertised xmin; in particular, if
1779 * default_transaction_isolation = serializable, there is a transaction
1780 * snapshot that is still active. The CatalogSnapshot is likewise a
1781 * hazard. To ensure no deadlocks, we must commit and start yet another
1782 * transaction, and do our wait before any snapshot has been taken in it.
1783 */
1786
1787 /* Tell concurrent index builds to ignore us, if index qualifies */
1788 if (safe_index)
1790
1791 /* We should now definitely not be advertising any xmin. */
1793
1794 /*
1795 * The index is now valid in the sense that it contains all currently
1796 * interesting tuples. But since it might not contain tuples deleted just
1797 * before the reference snap was taken, we have to wait out any
1798 * transactions that might have older snapshots.
1799 */
1800 INJECTION_POINT("define-index-before-set-valid", NULL);
1804
1805 /*
1806 * Updating pg_index might involve TOAST table access, so ensure we have a
1807 * valid snapshot.
1808 */
1810
1811 /*
1812 * Index can now be marked valid -- update its pg_index entry
1813 */
1815
1817
1818 /*
1819 * The pg_index update will cause backends (including this one) to update
1820 * relcache entries for the index itself, but we should also send a
1821 * relcache inval on the parent table to force replanning of cached plans.
1822 * Otherwise existing sessions might fail to use the new index where it
1823 * would be useful. (Note that our earlier commits did not create reasons
1824 * to replan; so relcache flush on the index itself was sufficient.)
1825 */
1827
1828 /*
1829 * Last thing to do is release the session-level lock on the parent table.
1830 */
1832
1834
1835 return address;
1836}
AclResult
Definition acl.h:182
@ ACLCHECK_OK
Definition acl.h:183
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2654
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition aclchk.c:3836
bytea *(* amoptions_function)(Datum reloptions, bool validate)
Definition amapi.h:165
char * get_am_name(Oid amOid)
Definition amcmds.c:192
void free_attrmap(AttrMap *map)
Definition attmap.c:56
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition attmap.c:175
int16 AttrNumber
Definition attnum.h:21
char * get_tablespace_name(Oid spc_oid)
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Oid GetDefaultTablespace(char relpersistence, bool partitioned)
void pgstat_progress_start_command(ProgressCommandType cmdtype, Oid relid)
void pgstat_progress_incr_param(int index, int64 incr)
void pgstat_progress_update_param(int index, int64 val)
void pgstat_progress_update_multi_param(int nparam, const int *index, const int64 *val)
void pgstat_progress_end_command(void)
@ PROGRESS_COMMAND_CREATE_INDEX
int bms_next_member(const Bitmapset *a, int prevbit)
Definition bitmapset.c:1305
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:510
#define NameStr(name)
Definition c.h:765
uint16 bits16
Definition c.h:554
int64_t int64
Definition c.h:543
uint32 TransactionId
Definition c.h:666
void CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment)
Definition comment.c:143
int errmsg_internal(const char *fmt,...)
Definition elog.c:1170
#define DEBUG1
Definition elog.h:30
#define NOTICE
Definition elog.h:35
bool allowSystemTableMods
Definition globals.c:130
Oid MyDatabaseTableSpace
Definition globals.c:96
int set_config_option(const char *name, const char *value, GucContext context, GucSource source, GucAction action, bool changeVal, int elevel, bool is_reload)
Definition guc.c:3216
@ GUC_ACTION_SAVE
Definition guc.h:205
@ PGC_S_SESSION
Definition guc.h:126
@ PGC_USERSET
Definition guc.h:79
HeapTuple heap_copytuple(HeapTuple tuple)
Definition heaptuple.c:778
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1435
#define stmt
void validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
Definition index.c:3348
Oid index_create(Relation heapRelation, const char *indexRelationName, Oid indexRelationId, Oid parentIndexRelid, Oid parentConstraintId, RelFileNumber relFileNumber, IndexInfo *indexInfo, const List *indexColNames, Oid accessMethodId, Oid tableSpaceId, const Oid *collationIds, const Oid *opclassIds, const Datum *opclassOptions, const int16 *coloptions, const NullableDatum *stattargets, Datum reloptions, bits16 flags, bits16 constr_flags, bool allow_system_table_mods, bool is_internal, Oid *constraintId)
Definition index.c:724
void index_set_state_flags(Oid indexId, IndexStateFlagsAction action)
Definition index.c:3501
bool CompareIndexInfo(const IndexInfo *info1, const IndexInfo *info2, const Oid *collations1, const Oid *collations2, const Oid *opfamilies1, const Oid *opfamilies2, const AttrMap *attmap)
Definition index.c:2535
IndexInfo * BuildIndexInfo(Relation index)
Definition index.c:2426
void index_check_primary_key(Relation heapRel, const IndexInfo *indexInfo, bool is_alter_table, const IndexStmt *stmt)
Definition index.c:202
void index_concurrently_build(Oid heapRelationId, Oid indexRelationId)
Definition index.c:1483
#define INDEX_CREATE_IS_PRIMARY
Definition index.h:61
#define INDEX_CREATE_IF_NOT_EXISTS
Definition index.h:65
#define INDEX_CREATE_PARTITIONED
Definition index.h:66
#define INDEX_CREATE_INVALID
Definition index.h:67
#define INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS
Definition index.h:96
#define INDEX_CREATE_ADD_CONSTRAINT
Definition index.h:62
#define INDEX_CREATE_SKIP_BUILD
Definition index.h:63
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition index.h:92
@ INDEX_CREATE_SET_VALID
Definition index.h:27
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition index.h:93
#define INDEX_CREATE_CONCURRENT
Definition index.h:64
static void set_indexsafe_procflags(void)
Definition indexcmds.c:4640
ObjectAddress DefineIndex(ParseState *pstate, Oid tableId, IndexStmt *stmt, Oid indexRelationId, Oid parentIndexId, Oid parentConstraintId, int total_parts, bool is_alter_table, bool check_rights, bool check_not_in_use, bool skip_build, bool quiet)
Definition indexcmds.c:544
void IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
Definition indexcmds.c:4470
void WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
Definition indexcmds.c:435
static void CheckPredicate(Expr *predicate)
Definition indexcmds.c:1851
static List * ChooseIndexColumnNames(const List *indexElems)
Definition indexcmds.c:2788
static char * ChooseIndexName(const char *tabname, Oid namespaceId, const List *colnames, const List *exclusionOpNames, bool primary, bool isconstraint)
Definition indexcmds.c:2699
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition indexing.c:313
#define INJECTION_POINT(name, arg)
void CacheInvalidateRelcacheByRelid(Oid relid)
Definition inval.c:1691
int j
Definition isn.c:78
List * list_concat_copy(const List *list1, const List *list2)
Definition list.c:598
void list_free(List *list)
Definition list.c:1546
void LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
Definition lmgr.c:391
void WaitForLockers(LOCKTAG heaplocktag, LOCKMODE lockmode, bool progress)
Definition lmgr.c:989
void UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
Definition lmgr.c:404
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition lock.h:183
int LOCKMODE
Definition lockdefs.h:26
#define ShareUpdateExclusiveLock
Definition lockdefs.h:39
#define ShareLock
Definition lockdefs.h:40
#define RowExclusiveLock
Definition lockdefs.h:38
char get_rel_persistence(Oid relid)
Definition lsyscache.c:2228
bool get_index_isvalid(Oid index_oid)
Definition lsyscache.c:3728
Oid get_opfamily_member_for_cmptype(Oid opfamily, Oid lefttype, Oid righttype, CompareType cmptype)
Definition lsyscache.c:197
bool get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
Definition lsyscache.c:1337
char * get_opname(Oid opno)
Definition lsyscache.c:1460
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition lsyscache.c:168
Oid get_opfamily_method(Oid opfid)
Definition lsyscache.c:1386
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3516
List * make_ands_implicit(Expr *clause)
Definition makefuncs.c:810
#define IsBootstrapProcessingMode()
Definition miscadmin.h:477
#define SECURITY_RESTRICTED_OPERATION
Definition miscadmin.h:319
Oid GetUserId(void)
Definition miscinit.c:469
#define ObjectAddressSet(addr, class_id, object_id)
IndexStmt * generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx, const AttrMap *attmap, Oid *constraintOid)
@ PARTITION_STRATEGY_HASH
Definition parsenodes.h:903
@ OBJECT_SCHEMA
@ OBJECT_TABLESPACE
#define ACL_CREATE
Definition parsenodes.h:85
PartitionKey RelationGetPartitionKey(Relation rel)
Definition partcache.c:51
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition partdesc.c:71
int errdetail_relkind_not_supported(char relkind)
Definition pg_class.c:24
Oid get_relation_idx_constraint_oid(Oid relationId, Oid indexId)
void ConstraintSetParentConstraint(Oid childConstrId, Oid parentConstrId, Oid childTableId)
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
bool has_superclass(Oid relationId)
#define lfirst_oid(lc)
Definition pg_list.h:174
#define PROGRESS_CREATEIDX_PARTITIONS_DONE
Definition progress.h:109
#define PROGRESS_CREATEIDX_PHASE_WAIT_1
Definition progress.h:113
#define PROGRESS_CREATEIDX_COMMAND_CREATE_CONCURRENTLY
Definition progress.h:131
#define PROGRESS_CREATEIDX_ACCESS_METHOD_OID
Definition progress.h:103
#define PROGRESS_CREATEIDX_PHASE_WAIT_3
Definition progress.h:119
#define PROGRESS_CREATEIDX_COMMAND_CREATE
Definition progress.h:130
#define PROGRESS_CREATEIDX_PHASE_WAIT_2
Definition progress.h:115
#define PROGRESS_CREATEIDX_PHASE
Definition progress.h:104
#define PROGRESS_CREATEIDX_INDEX_OID
Definition progress.h:102
#define PROGRESS_CREATEIDX_PARTITIONS_TOTAL
Definition progress.h:108
#define PROGRESS_CREATEIDX_COMMAND
Definition progress.h:101
#define RelationGetDescr(relation)
Definition rel.h:540
#define RelationGetRelationName(relation)
Definition rel.h:548
#define RELATION_IS_OTHER_TEMP(relation)
Definition rel.h:667
#define RelationGetNamespace(relation)
Definition rel.h:555
List * RelationGetIndexList(Relation relation)
Definition relcache.c:4831
bytea * index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate)
#define RelFileNumberIsValid(relnumber)
Definition relpath.h:27
Snapshot GetTransactionSnapshot(void)
Definition snapmgr.c:272
void UnregisterSnapshot(Snapshot snapshot)
Definition snapmgr.c:866
void PushActiveSnapshot(Snapshot snapshot)
Definition snapmgr.c:682
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition snapmgr.c:824
void PopActiveSnapshot(void)
Definition snapmgr.c:775
PGPROC * MyProc
Definition proc.c:67
#define HTEqualStrategyNumber
Definition stratnum.h:41
int ii_NumIndexAttrs
Definition execnodes.h:169
List * ii_Predicate
Definition execnodes.h:185
LockRelId lockRelId
Definition rel.h:46
Oid relId
Definition rel.h:40
Oid dbId
Definition rel.h:41
TransactionId xmin
Definition proc.h:194
LockInfoData rd_lockInfo
Definition rel.h:114
Form_pg_class rd_rel
Definition rel.h:111
TransactionId xmin
Definition snapshot.h:153
#define FirstLowInvalidHeapAttributeNumber
Definition sysattr.h:27
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition tablecmds.c:4414
#define InvalidTransactionId
Definition transam.h:31
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition var.c:296
void CommandCounterIncrement(void)
Definition xact.c:1101
void StartTransactionCommand(void)
Definition xact.c:3080
void CommitTransactionCommand(void)
Definition xact.c:3178

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, allowSystemTableMods, Assert, AtEOXact_GUC(), bms_is_member(), bms_next_member(), BTEqualStrategyNumber, build_attrmap_by_name(), BuildIndexInfo(), CacheInvalidateRelcacheByRelid(), CatalogTupleUpdate(), CheckPredicate(), CheckTableNotInUse(), ChooseIndexColumnNames(), ChooseIndexName(), CommandCounterIncrement(), CommitTransactionCommand(), COMPARE_EQ, CompareIndexInfo(), ComputeIndexAttrs(), ConstraintSetParentConstraint(), CreateComments(), LockRelId::dbId, DEBUG1, DefineIndex(), elog, ereport, errcode(), errdetail(), errdetail_relkind_not_supported(), errmsg(), errmsg_internal(), ERROR, fb(), find_all_inheritors(), FirstLowInvalidHeapAttributeNumber, format_type_be(), free_attrmap(), generateClonedIndexStmt(), get_am_name(), get_index_isvalid(), get_namespace_name(), get_opclass_opfamily_and_input_type(), get_opfamily_member(), get_opfamily_member_for_cmptype(), get_opfamily_method(), get_opfamily_name(), get_opname(), get_rel_persistence(), get_relation_idx_constraint_oid(), get_tablespace_name(), get_tablespace_oid(), GetDefaultTablespace(), GetIndexAmRoutine(), GETSTRUCT(), GetTransactionSnapshot(), GetUserId(), GetUserIdAndSecContext(), GUC_ACTION_SAVE, has_superclass(), heap_copytuple(), heap_freetuple(), HeapTupleIsValid, HTEqualStrategyNumber, i, IndexInfo::ii_ExclusionOps, IndexInfo::ii_Expressions, IndexInfo::ii_IndexAttrNumbers, IndexInfo::ii_NumIndexAttrs, IndexInfo::ii_NumIndexKeyAttrs, IndexInfo::ii_Predicate, index_check_primary_key(), index_close(), index_concurrently_build(), INDEX_CONSTR_CREATE_DEFERRABLE, INDEX_CONSTR_CREATE_INIT_DEFERRED, INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS, index_create(), INDEX_CREATE_ADD_CONSTRAINT, INDEX_CREATE_CONCURRENT, INDEX_CREATE_IF_NOT_EXISTS, INDEX_CREATE_INVALID, INDEX_CREATE_IS_PRIMARY, INDEX_CREATE_PARTITIONED, INDEX_CREATE_SET_VALID, INDEX_CREATE_SKIP_BUILD, INDEX_MAX_KEYS, index_open(), index_reloptions(), index_set_state_flags(), IndexSetParentIndex(), INJECTION_POINT, InvalidOid, InvalidTransactionId, IsBootstrapProcessingMode, j, lfirst_oid, list_concat_copy(), list_free(), list_length(), LockRelationIdForSession(), LockInfoData::lockRelId, make_ands_implicit(), makeIndexInfo(), MyDatabaseTableSpace, MyProc, NameStr, NewGUCNestLevel(), NIL, NoLock, NOTICE, PartitionDescData::nparts, object_aclcheck(), OBJECT_SCHEMA, OBJECT_TABLESPACE, ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, PartitionDescData::oids, palloc_array, PARTITION_STRATEGY_HASH, PGC_S_SESSION, PGC_USERSET, pgstat_progress_end_command(), pgstat_progress_incr_param(), pgstat_progress_start_command(), pgstat_progress_update_multi_param(), pgstat_progress_update_param(), PointerGetDatum(), PopActiveSnapshot(), PROGRESS_COMMAND_CREATE_INDEX, PROGRESS_CREATEIDX_ACCESS_METHOD_OID, PROGRESS_CREATEIDX_COMMAND, PROGRESS_CREATEIDX_COMMAND_CREATE, PROGRESS_CREATEIDX_COMMAND_CREATE_CONCURRENTLY, PROGRESS_CREATEIDX_INDEX_OID, PROGRESS_CREATEIDX_PARTITIONS_DONE, PROGRESS_CREATEIDX_PARTITIONS_TOTAL, PROGRESS_CREATEIDX_PHASE, PROGRESS_CREATEIDX_PHASE_WAIT_1, PROGRESS_CREATEIDX_PHASE_WAIT_2, PROGRESS_CREATEIDX_PHASE_WAIT_3, pull_varattnos(), PushActiveSnapshot(), RelationData::rd_lockInfo, RelationData::rd_rel, RegisterSnapshot(), RELATION_IS_OTHER_TEMP, RelationGetDescr, RelationGetIndexList(), RelationGetNamespace, RelationGetPartitionDesc(), RelationGetPartitionKey(), RelationGetRelationName, ReleaseSysCache(), RelFileNumberIsValid, LockRelId::relId, RestrictSearchPath(), RowExclusiveLock, SearchSysCache1(), SECURITY_RESTRICTED_OPERATION, set_config_option(), set_indexsafe_procflags(), SET_LOCKTAG_RELATION, SetUserIdAndSecContext(), ShareLock, ShareUpdateExclusiveLock, StartTransactionCommand(), stmt, table_close(), table_open(), transformRelOptions(), TupleDescAttr(), UnlockRelationIdForSession(), UnregisterSnapshot(), validate_index(), WaitForLockers(), WaitForOlderSnapshots(), PGPROC::xmin, and SnapshotData::xmin.

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

◆ ExecReindex()

void ExecReindex ( ParseState pstate,
const ReindexStmt stmt,
bool  isTopLevel 
)

Definition at line 2849 of file indexcmds.c.

2850{
2851 ReindexParams params = {0};
2852 ListCell *lc;
2853 bool concurrently = false;
2854 bool verbose = false;
2855 char *tablespacename = NULL;
2856
2857 /* Parse option list */
2858 foreach(lc, stmt->params)
2859 {
2860 DefElem *opt = (DefElem *) lfirst(lc);
2861
2862 if (strcmp(opt->defname, "verbose") == 0)
2863 verbose = defGetBoolean(opt);
2864 else if (strcmp(opt->defname, "concurrently") == 0)
2866 else if (strcmp(opt->defname, "tablespace") == 0)
2867 tablespacename = defGetString(opt);
2868 else
2869 ereport(ERROR,
2871 errmsg("unrecognized %s option \"%s\"",
2872 "REINDEX", opt->defname),
2873 parser_errposition(pstate, opt->location)));
2874 }
2875
2876 if (concurrently)
2878 "REINDEX CONCURRENTLY");
2879
2880 params.options =
2881 (verbose ? REINDEXOPT_VERBOSE : 0) |
2883
2884 /*
2885 * Assign the tablespace OID to move indexes to, with InvalidOid to do
2886 * nothing.
2887 */
2888 if (tablespacename != NULL)
2889 {
2890 params.tablespaceOid = get_tablespace_oid(tablespacename, false);
2891
2892 /* Check permissions except when moving to database's default */
2893 if (OidIsValid(params.tablespaceOid) &&
2895 {
2897
2900 if (aclresult != ACLCHECK_OK)
2903 }
2904 }
2905 else
2906 params.tablespaceOid = InvalidOid;
2907
2908 switch (stmt->kind)
2909 {
2911 ReindexIndex(stmt, &params, isTopLevel);
2912 break;
2914 ReindexTable(stmt, &params, isTopLevel);
2915 break;
2919
2920 /*
2921 * This cannot run inside a user transaction block; if we were
2922 * inside a transaction, then its commit- and
2923 * start-transaction-command calls would not have the intended
2924 * effect!
2925 */
2927 (stmt->kind == REINDEX_OBJECT_SCHEMA) ? "REINDEX SCHEMA" :
2928 (stmt->kind == REINDEX_OBJECT_SYSTEM) ? "REINDEX SYSTEM" :
2929 "REINDEX DATABASE");
2930 ReindexMultipleTables(stmt, &params);
2931 break;
2932 default:
2933 elog(ERROR, "unrecognized object type: %d",
2934 (int) stmt->kind);
2935 break;
2936 }
2937}
char * defGetString(DefElem *def)
Definition define.c:34
bool defGetBoolean(DefElem *def)
Definition define.c:93
#define REINDEXOPT_CONCURRENTLY
Definition index.h:44
#define REINDEXOPT_VERBOSE
Definition index.h:41
static void ReindexIndex(const ReindexStmt *stmt, const ReindexParams *params, bool isTopLevel)
Definition indexcmds.c:2944
static void ReindexMultipleTables(const ReindexStmt *stmt, const ReindexParams *params)
Definition indexcmds.c:3133
static Oid ReindexTable(const ReindexStmt *stmt, const ReindexParams *params, bool isTopLevel)
Definition indexcmds.c:3074
@ REINDEX_OBJECT_DATABASE
@ REINDEX_OBJECT_INDEX
@ REINDEX_OBJECT_SCHEMA
@ REINDEX_OBJECT_SYSTEM
@ REINDEX_OBJECT_TABLE
static int verbose
char * defname
Definition parsenodes.h:844
ParseLoc location
Definition parsenodes.h:848
Oid tablespaceOid
Definition index.h:36
bits32 options
Definition index.h:35
void PreventInTransactionBlock(bool isTopLevel, const char *stmtType)
Definition xact.c:3669

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, defGetBoolean(), defGetString(), DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, fb(), get_tablespace_name(), get_tablespace_oid(), GetUserId(), InvalidOid, lfirst, DefElem::location, MyDatabaseTableSpace, object_aclcheck(), OBJECT_TABLESPACE, OidIsValid, ReindexParams::options, parser_errposition(), PreventInTransactionBlock(), REINDEX_OBJECT_DATABASE, REINDEX_OBJECT_INDEX, REINDEX_OBJECT_SCHEMA, REINDEX_OBJECT_SYSTEM, REINDEX_OBJECT_TABLE, ReindexIndex(), ReindexMultipleTables(), REINDEXOPT_CONCURRENTLY, REINDEXOPT_VERBOSE, ReindexTable(), stmt, ReindexParams::tablespaceOid, and verbose.

Referenced by ProcessUtilitySlow().

◆ GetDefaultOpClass()

Oid GetDefaultOpClass ( Oid  type_id,
Oid  am_id 
)

Definition at line 2368 of file indexcmds.c.

2369{
2370 Oid result = InvalidOid;
2371 int nexact = 0;
2372 int ncompatible = 0;
2373 int ncompatiblepreferred = 0;
2374 Relation rel;
2375 ScanKeyData skey[1];
2376 SysScanDesc scan;
2377 HeapTuple tup;
2379
2380 /* If it's a domain, look at the base type instead */
2381 type_id = getBaseType(type_id);
2382
2383 tcategory = TypeCategory(type_id);
2384
2385 /*
2386 * We scan through all the opclasses available for the access method,
2387 * looking for one that is marked default and matches the target type
2388 * (either exactly or binary-compatibly, but prefer an exact match).
2389 *
2390 * We could find more than one binary-compatible match. If just one is
2391 * for a preferred type, use that one; otherwise we fail, forcing the user
2392 * to specify which one he wants. (The preferred-type special case is a
2393 * kluge for varchar: it's binary-compatible to both text and bpchar, so
2394 * we need a tiebreaker.) If we find more than one exact match, then
2395 * someone put bogus entries in pg_opclass.
2396 */
2398
2399 ScanKeyInit(&skey[0],
2403
2405 NULL, 1, skey);
2406
2407 while (HeapTupleIsValid(tup = systable_getnext(scan)))
2408 {
2410
2411 /* ignore altogether if not a default opclass */
2412 if (!opclass->opcdefault)
2413 continue;
2414 if (opclass->opcintype == type_id)
2415 {
2416 nexact++;
2417 result = opclass->oid;
2418 }
2419 else if (nexact == 0 &&
2420 IsBinaryCoercible(type_id, opclass->opcintype))
2421 {
2422 if (IsPreferredType(tcategory, opclass->opcintype))
2423 {
2425 result = opclass->oid;
2426 }
2427 else if (ncompatiblepreferred == 0)
2428 {
2429 ncompatible++;
2430 result = opclass->oid;
2431 }
2432 }
2433 }
2434
2435 systable_endscan(scan);
2436
2438
2439 /* raise error if pg_opclass contains inconsistent data */
2440 if (nexact > 1)
2441 ereport(ERROR,
2443 errmsg("there are multiple default operator classes for data type %s",
2444 format_type_be(type_id))));
2445
2446 if (nexact == 1 ||
2447 ncompatiblepreferred == 1 ||
2448 (ncompatiblepreferred == 0 && ncompatible == 1))
2449 return result;
2450
2451 return InvalidOid;
2452}
Oid getBaseType(Oid typid)
Definition lsyscache.c:2671
TYPCATEGORY TypeCategory(Oid type)
bool IsBinaryCoercible(Oid srctype, Oid targettype)
bool IsPreferredType(TYPCATEGORY category, Oid type)
char TYPCATEGORY
FormData_pg_opclass * Form_pg_opclass
Definition pg_opclass.h:83
#define ERRCODE_DUPLICATE_OBJECT
Definition streamutil.c:30

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

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

◆ GetOperatorFromCompareType()

void GetOperatorFromCompareType ( Oid  opclass,
Oid  rhstype,
CompareType  cmptype,
Oid opid,
StrategyNumber strat 
)

Definition at line 2470 of file indexcmds.c.

2472{
2473 Oid amid;
2474 Oid opfamily;
2475 Oid opcintype;
2476
2477 Assert(cmptype == COMPARE_EQ || cmptype == COMPARE_OVERLAP || cmptype == COMPARE_CONTAINED_BY);
2478
2479 /*
2480 * Use the opclass to get the opfamily, opcintype, and access method. If
2481 * any of this fails, quit early.
2482 */
2483 if (!get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
2484 elog(ERROR, "cache lookup failed for opclass %u", opclass);
2485
2486 amid = get_opclass_method(opclass);
2487
2488 /*
2489 * Ask the index AM to translate to its internal stratnum
2490 */
2491 *strat = IndexAmTranslateCompareType(cmptype, amid, opfamily, true);
2492 if (*strat == InvalidStrategy)
2493 ereport(ERROR,
2495 cmptype == COMPARE_EQ ? errmsg("could not identify an equality operator for type %s", format_type_be(opcintype)) :
2496 cmptype == COMPARE_OVERLAP ? errmsg("could not identify an overlaps operator for type %s", format_type_be(opcintype)) :
2497 cmptype == COMPARE_CONTAINED_BY ? errmsg("could not identify a contained-by operator for type %s", format_type_be(opcintype)) : 0,
2498 errdetail("Could not translate compare type %d for operator family \"%s\" of access method \"%s\".",
2499 cmptype, get_opfamily_name(opfamily, false), get_am_name(amid)));
2500
2501 /*
2502 * We parameterize rhstype so foreign keys can ask for a <@ operator whose
2503 * rhs matches the aggregate function. For example range_agg returns
2504 * anymultirange.
2505 */
2506 if (!OidIsValid(rhstype))
2507 rhstype = opcintype;
2508 *opid = get_opfamily_member(opfamily, opcintype, rhstype, *strat);
2509
2510 if (!OidIsValid(*opid))
2511 ereport(ERROR,
2513 cmptype == COMPARE_EQ ? errmsg("could not identify an equality operator for type %s", format_type_be(opcintype)) :
2514 cmptype == COMPARE_OVERLAP ? errmsg("could not identify an overlaps operator for type %s", format_type_be(opcintype)) :
2515 cmptype == COMPARE_CONTAINED_BY ? errmsg("could not identify a contained-by operator for type %s", format_type_be(opcintype)) : 0,
2516 errdetail("There is no suitable operator in operator family \"%s\" for access method \"%s\".",
2517 get_opfamily_name(opfamily, false), get_am_name(amid)));
2518}
StrategyNumber IndexAmTranslateCompareType(CompareType cmptype, Oid amoid, Oid opfamily, bool missing_ok)
Definition amapi.c:161
@ COMPARE_CONTAINED_BY
Definition cmptype.h:41
#define false
Oid get_opclass_method(Oid opclass)
Definition lsyscache.c:1362
#define InvalidStrategy
Definition stratnum.h:24

References Assert, COMPARE_CONTAINED_BY, COMPARE_EQ, COMPARE_OVERLAP, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, fb(), format_type_be(), get_am_name(), get_opclass_method(), get_opclass_opfamily_and_input_type(), get_opfamily_member(), get_opfamily_name(), IndexAmTranslateCompareType(), InvalidStrategy, and OidIsValid.

Referenced by ComputeIndexAttrs(), and FindFKPeriodOpers().

◆ IndexSetParentIndex()

void IndexSetParentIndex ( Relation  partitionIdx,
Oid  parentOid 
)

Definition at line 4470 of file indexcmds.c.

4471{
4473 ScanKeyData key[2];
4474 SysScanDesc scan;
4475 Oid partRelid = RelationGetRelid(partitionIdx);
4476 HeapTuple tuple;
4477 bool fix_dependencies;
4478
4479 /* Make sure this is an index */
4480 Assert(partitionIdx->rd_rel->relkind == RELKIND_INDEX ||
4481 partitionIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
4482
4483 /*
4484 * Scan pg_inherits for rows linking our index to some parent.
4485 */
4487 ScanKeyInit(&key[0],
4491 ScanKeyInit(&key[1],
4494 Int32GetDatum(1));
4496 NULL, 2, key);
4497 tuple = systable_getnext(scan);
4498
4499 if (!HeapTupleIsValid(tuple))
4500 {
4501 if (parentOid == InvalidOid)
4502 {
4503 /*
4504 * No pg_inherits row, and no parent wanted: nothing to do in this
4505 * case.
4506 */
4507 fix_dependencies = false;
4508 }
4509 else
4510 {
4512 fix_dependencies = true;
4513 }
4514 }
4515 else
4516 {
4518
4519 if (parentOid == InvalidOid)
4520 {
4521 /*
4522 * There exists a pg_inherits row, which we want to clear; do so.
4523 */
4525 fix_dependencies = true;
4526 }
4527 else
4528 {
4529 /*
4530 * A pg_inherits row exists. If it's the same we want, then we're
4531 * good; if it differs, that amounts to a corrupt catalog and
4532 * should not happen.
4533 */
4534 if (inhForm->inhparent != parentOid)
4535 {
4536 /* unexpected: we should not get called in this case */
4537 elog(ERROR, "bogus pg_inherit row: inhrelid %u inhparent %u",
4538 inhForm->inhrelid, inhForm->inhparent);
4539 }
4540
4541 /* already in the right state */
4542 fix_dependencies = false;
4543 }
4544 }
4545
4546 /* done with pg_inherits */
4547 systable_endscan(scan);
4549
4550 /* set relhassubclass if an index partition has been added to the parent */
4551 if (OidIsValid(parentOid))
4552 {
4555 }
4556
4557 /* set relispartition correctly on the partition */
4559
4560 if (fix_dependencies)
4561 {
4562 /*
4563 * Insert/delete pg_depend rows. If setting a parent, add PARTITION
4564 * dependencies on the parent index and the table; if removing a
4565 * parent, delete PARTITION dependencies.
4566 */
4567 if (OidIsValid(parentOid))
4568 {
4570 ObjectAddress parentIdx;
4571 ObjectAddress partitionTbl;
4572
4576 partitionIdx->rd_index->indrelid);
4577 recordDependencyOn(&partIdx, &parentIdx,
4579 recordDependencyOn(&partIdx, &partitionTbl,
4581 }
4582 else
4583 {
4590 }
4591
4592 /* make our updates visible */
4594 }
4595}
@ DEPENDENCY_PARTITION_PRI
Definition dependency.h:36
@ DEPENDENCY_PARTITION_SEC
Definition dependency.h:37
static void update_relispartition(Oid relationId, bool newval)
Definition indexcmds.c:4602
void CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid)
Definition indexing.c:365
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition lmgr.c:107
static void fix_dependencies(ArchiveHandle *AH)
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition pg_depend.c:45
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition pg_depend.c:351
void StoreSingleInheritance(Oid relationId, Oid parentOid, int32 seqNumber)
FormData_pg_inherits * Form_pg_inherits
Definition pg_inherits.h:45
static Datum Int32GetDatum(int32 X)
Definition postgres.h:222
#define RelationGetRelid(relation)
Definition rel.h:514
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:205
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition relation.c:47
ItemPointerData t_self
Definition htup.h:65
Form_pg_index rd_index
Definition rel.h:192
void SetRelationHasSubclass(Oid relationId, bool relhassubclass)
Definition tablecmds.c:3645

References Assert, BTEqualStrategyNumber, CatalogTupleDelete(), CommandCounterIncrement(), deleteDependencyRecordsForClass(), DEPENDENCY_PARTITION_PRI, DEPENDENCY_PARTITION_SEC, elog, ERROR, fb(), fix_dependencies(), GETSTRUCT(), HeapTupleIsValid, Int32GetDatum(), InvalidOid, LockRelationOid(), ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, RelationData::rd_index, RelationData::rd_rel, recordDependencyOn(), relation_close(), relation_open(), RelationGetRelid, RowExclusiveLock, ScanKeyInit(), SetRelationHasSubclass(), ShareUpdateExclusiveLock, StoreSingleInheritance(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, and update_relispartition().

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

◆ makeObjectName()

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

Definition at line 2543 of file indexcmds.c.

2544{
2545 char *name;
2546 int overhead = 0; /* chars needed for label and underscores */
2547 int availchars; /* chars available for name(s) */
2548 int name1chars; /* chars allocated to name1 */
2549 int name2chars; /* chars allocated to name2 */
2550 int ndx;
2551
2553 if (name2)
2554 {
2556 overhead++; /* allow for separating underscore */
2557 }
2558 else
2559 name2chars = 0;
2560 if (label)
2561 overhead += strlen(label) + 1;
2562
2564 Assert(availchars > 0); /* else caller chose a bad label */
2565
2566 /*
2567 * If we must truncate, preferentially truncate the longer name. This
2568 * logic could be expressed without a loop, but it's simple and obvious as
2569 * a loop.
2570 */
2571 while (name1chars + name2chars > availchars)
2572 {
2573 if (name1chars > name2chars)
2574 name1chars--;
2575 else
2576 name2chars--;
2577 }
2578
2580 if (name2)
2582
2583 /* Now construct the string using the chosen lengths */
2586 ndx = name1chars;
2587 if (name2)
2588 {
2589 name[ndx++] = '_';
2591 ndx += name2chars;
2592 }
2593 if (label)
2594 {
2595 name[ndx++] = '_';
2596 strcpy(name + ndx, label);
2597 }
2598 else
2599 name[ndx] = '\0';
2600
2601 return name;
2602}
void * palloc(Size size)
Definition mcxt.c:1387

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

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

◆ RangeVarCallbackForReindexIndex()

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

Definition at line 2998 of file indexcmds.c.

3000{
3001 char relkind;
3004 Oid table_oid;
3006
3007 /*
3008 * Lock level here should match table lock in reindex_index() for
3009 * non-concurrent case and table locks used by index_concurrently_*() for
3010 * concurrent case.
3011 */
3012 table_lockmode = (state->params.options & REINDEXOPT_CONCURRENTLY) != 0 ?
3014
3015 /*
3016 * If we previously locked some other index's heap, and the name we're
3017 * looking up no longer refers to that relation, release the now-useless
3018 * lock.
3019 */
3020 if (relId != oldRelId && OidIsValid(oldRelId))
3021 {
3022 UnlockRelationOid(state->locked_table_oid, table_lockmode);
3023 state->locked_table_oid = InvalidOid;
3024 }
3025
3026 /* If the relation does not exist, there's nothing more to do. */
3027 if (!OidIsValid(relId))
3028 return;
3029
3030 /* If the relation does exist, check whether it's an index. */
3031 relkind = get_rel_relkind(relId);
3032 if (relkind != RELKIND_INDEX &&
3033 relkind != RELKIND_PARTITIONED_INDEX)
3034 ereport(ERROR,
3036 errmsg("\"%s\" is not an index", relation->relname)));
3037
3038 /* Look up the index's table. */
3039 table_oid = IndexGetRelation(relId, false);
3040
3041 /*
3042 * In the unlikely event that, upon retry, we get the same index OID with
3043 * a different table OID, fail. RangeVarGetRelidExtended() will have
3044 * already locked the index in this case, and it won't retry again, so we
3045 * can't lock the newly discovered table OID without risking deadlock.
3046 * Also, while this corner case is indeed possible, it is extremely
3047 * unlikely to happen in practice, so it's probably not worth any more
3048 * effort than this.
3049 */
3050 if (relId == oldRelId && table_oid != state->locked_table_oid)
3051 ereport(ERROR,
3053 errmsg("index \"%s\" was concurrently dropped",
3054 relation->relname)));
3055
3056 /* Check permissions. */
3058 if (aclresult != ACLCHECK_OK)
3060
3061 /* Lock heap before index to avoid deadlock. */
3062 if (relId != oldRelId)
3063 {
3065 state->locked_table_oid = table_oid;
3066 }
3067}
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition aclchk.c:4039
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition lmgr.c:229
char get_rel_relkind(Oid relid)
Definition lsyscache.c:2153
#define ACL_MAINTAIN
Definition parsenodes.h:90
@ OBJECT_INDEX
char * relname
Definition primnodes.h:83

References ACL_MAINTAIN, aclcheck_error(), ACLCHECK_OK, arg, ereport, errcode(), errmsg(), ERROR, fb(), get_rel_relkind(), GetUserId(), IndexGetRelation(), InvalidOid, LockRelationOid(), OBJECT_INDEX, OidIsValid, pg_class_aclcheck(), REINDEXOPT_CONCURRENTLY, RangeVar::relname, ShareLock, ShareUpdateExclusiveLock, and UnlockRelationOid().

Referenced by ReindexIndex().

◆ reindex_error_callback()

static void reindex_error_callback ( void arg)
static

Definition at line 3352 of file indexcmds.c.

3353{
3355
3357
3358 if (errinfo->relkind == RELKIND_PARTITIONED_TABLE)
3359 errcontext("while reindexing partitioned table \"%s.%s\"",
3360 errinfo->relnamespace, errinfo->relname);
3361 else if (errinfo->relkind == RELKIND_PARTITIONED_INDEX)
3362 errcontext("while reindexing partitioned index \"%s.%s\"",
3363 errinfo->relnamespace, errinfo->relname);
3364}
#define errcontext
Definition elog.h:198

References arg, Assert, errcontext, and fb().

Referenced by ReindexPartitions().

◆ ReindexIndex()

static void ReindexIndex ( const ReindexStmt stmt,
const ReindexParams params,
bool  isTopLevel 
)
static

Definition at line 2944 of file indexcmds.c.

2945{
2946 const RangeVar *indexRelation = stmt->relation;
2948 Oid indOid;
2949 char persistence;
2950 char relkind;
2951
2952 /*
2953 * Find and lock index, and check permissions on table; use callback to
2954 * obtain lock on table first, to avoid deadlock hazard. The lock level
2955 * used here must match the index lock obtained in reindex_index().
2956 *
2957 * If it's a temporary index, we will perform a non-concurrent reindex,
2958 * even if CONCURRENTLY was requested. In that case, reindex_index() will
2959 * upgrade the lock, but that's OK, because other sessions can't hold
2960 * locks on our temporary table.
2961 */
2962 state.params = *params;
2963 state.locked_table_oid = InvalidOid;
2964 indOid = RangeVarGetRelidExtended(indexRelation,
2967 0,
2969 &state);
2970
2971 /*
2972 * Obtain the current persistence and kind of the existing index. We
2973 * already hold a lock on the index.
2974 */
2975 persistence = get_rel_persistence(indOid);
2976 relkind = get_rel_relkind(indOid);
2977
2978 if (relkind == RELKIND_PARTITIONED_INDEX)
2980 else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
2981 persistence != RELPERSISTENCE_TEMP)
2983 else
2984 {
2986
2988 reindex_index(stmt, indOid, false, persistence, &newparams);
2989 }
2990}
void reindex_index(const ReindexStmt *stmt, Oid indexId, bool skip_constraint_checks, char persistence, const ReindexParams *params)
Definition index.c:3606
#define REINDEXOPT_REPORT_PROGRESS
Definition index.h:42
static bool ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const ReindexParams *params)
Definition indexcmds.c:3593
static void ReindexPartitions(const ReindexStmt *stmt, Oid relid, const ReindexParams *params, bool isTopLevel)
Definition indexcmds.c:3373
static void RangeVarCallbackForReindexIndex(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition indexcmds.c:2998
#define AccessExclusiveLock
Definition lockdefs.h:43
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition namespace.c:440

References AccessExclusiveLock, fb(), get_rel_persistence(), get_rel_relkind(), InvalidOid, ReindexParams::options, ReindexIndexCallbackState::params, RangeVarCallbackForReindexIndex(), RangeVarGetRelidExtended(), reindex_index(), REINDEXOPT_CONCURRENTLY, REINDEXOPT_REPORT_PROGRESS, ReindexPartitions(), ReindexRelationConcurrently(), ShareUpdateExclusiveLock, and stmt.

Referenced by ExecReindex().

◆ ReindexMultipleInternal()

static void ReindexMultipleInternal ( const ReindexStmt stmt,
const List relids,
const ReindexParams params 
)
static

Definition at line 3467 of file indexcmds.c.

3468{
3469 ListCell *l;
3470
3473
3474 foreach(l, relids)
3475 {
3476 Oid relid = lfirst_oid(l);
3477 char relkind;
3478 char relpersistence;
3479
3481
3482 /* functions in indexes may want a snapshot set */
3484
3485 /* check if the relation still exists */
3487 {
3490 continue;
3491 }
3492
3493 /*
3494 * Check permissions except when moving to database's default if a new
3495 * tablespace is chosen. Note that this check also happens in
3496 * ExecReindex(), but we do an extra check here as this runs across
3497 * multiple transactions.
3498 */
3499 if (OidIsValid(params->tablespaceOid) &&
3501 {
3503
3506 if (aclresult != ACLCHECK_OK)
3509 }
3510
3511 relkind = get_rel_relkind(relid);
3512 relpersistence = get_rel_persistence(relid);
3513
3514 /*
3515 * Partitioned tables and indexes can never be processed directly, and
3516 * a list of their leaves should be built first.
3517 */
3518 Assert(!RELKIND_HAS_PARTITIONS(relkind));
3519
3520 if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
3521 relpersistence != RELPERSISTENCE_TEMP)
3522 {
3523 ReindexParams newparams = *params;
3524
3527 if (ActiveSnapshotSet())
3529 /* ReindexRelationConcurrently() does the verbose output */
3530 }
3531 else if (relkind == RELKIND_INDEX)
3532 {
3533 ReindexParams newparams = *params;
3534
3537 reindex_index(stmt, relid, false, relpersistence, &newparams);
3539 /* reindex_index() does the verbose output */
3540 }
3541 else
3542 {
3543 bool result;
3544 ReindexParams newparams = *params;
3545
3548 result = reindex_relation(stmt, relid,
3551 &newparams);
3552
3553 if (result && (params->options & REINDEXOPT_VERBOSE) != 0)
3554 ereport(INFO,
3555 (errmsg("table \"%s.%s\" was reindexed",
3557 get_rel_name(relid))));
3558
3560 }
3561
3563 }
3564
3566}
#define INFO
Definition elog.h:34
bool reindex_relation(const ReindexStmt *stmt, Oid relid, int flags, const ReindexParams *params)
Definition index.c:3946
#define REINDEX_REL_PROCESS_TOAST
Definition index.h:159
#define REINDEXOPT_MISSING_OK
Definition index.h:43
#define REINDEX_REL_CHECK_CONSTRAINTS
Definition index.h:161
char * get_rel_name(Oid relid)
Definition lsyscache.c:2078
Oid get_rel_namespace(Oid relid)
Definition lsyscache.c:2102
bool ActiveSnapshotSet(void)
Definition snapmgr.c:812
#define SearchSysCacheExists1(cacheId, key1)
Definition syscache.h:100

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, ActiveSnapshotSet(), Assert, CommitTransactionCommand(), ereport, errmsg(), fb(), get_namespace_name(), get_rel_name(), get_rel_namespace(), get_rel_persistence(), get_rel_relkind(), get_tablespace_name(), GetTransactionSnapshot(), GetUserId(), INFO, lfirst_oid, MyDatabaseTableSpace, object_aclcheck(), OBJECT_TABLESPACE, ObjectIdGetDatum(), OidIsValid, ReindexParams::options, ReindexIndexCallbackState::params, PopActiveSnapshot(), PushActiveSnapshot(), reindex_index(), REINDEX_REL_CHECK_CONSTRAINTS, REINDEX_REL_PROCESS_TOAST, reindex_relation(), REINDEXOPT_CONCURRENTLY, REINDEXOPT_MISSING_OK, REINDEXOPT_REPORT_PROGRESS, REINDEXOPT_VERBOSE, ReindexRelationConcurrently(), SearchSysCacheExists1, StartTransactionCommand(), stmt, and ReindexParams::tablespaceOid.

Referenced by ReindexMultipleTables(), and ReindexPartitions().

◆ ReindexMultipleTables()

static void ReindexMultipleTables ( const ReindexStmt stmt,
const ReindexParams params 
)
static

Definition at line 3133 of file indexcmds.c.

3134{
3135
3136 Oid objectOid;
3138 TableScanDesc scan;
3140 HeapTuple tuple;
3143 List *relids = NIL;
3144 int num_keys;
3145 bool concurrent_warning = false;
3146 bool tablespace_warning = false;
3147 const char *objectName = stmt->name;
3148 const ReindexObjectType objectKind = stmt->kind;
3149
3153
3154 /*
3155 * This matches the options enforced by the grammar, where the object name
3156 * is optional for DATABASE and SYSTEM.
3157 */
3159
3161 (params->options & REINDEXOPT_CONCURRENTLY) != 0)
3162 ereport(ERROR,
3164 errmsg("cannot reindex system catalogs concurrently")));
3165
3166 /*
3167 * Get OID of object to reindex, being the database currently being used
3168 * by session for a database or for system catalogs, or the schema defined
3169 * by caller. At the same time do permission checks that need different
3170 * processing depending on the object type.
3171 */
3173 {
3175
3179 objectName);
3180 }
3181 else
3182 {
3184
3186 ereport(ERROR,
3188 errmsg("can only reindex the currently open database")));
3193 }
3194
3195 /*
3196 * Create a memory context that will survive forced transaction commits we
3197 * do below. Since it is a child of PortalContext, it will go away
3198 * eventually even if we suffer an error; there's no need for special
3199 * abort cleanup logic.
3200 */
3202 "ReindexMultipleTables",
3204
3205 /*
3206 * Define the search keys to find the objects to reindex. For a schema, we
3207 * select target relations using relnamespace, something not necessary for
3208 * a database-wide operation.
3209 */
3211 {
3212 num_keys = 1;
3217 }
3218 else
3219 num_keys = 0;
3220
3221 /*
3222 * Scan pg_class to build a list of the relations we need to reindex.
3223 *
3224 * We only consider plain relations and materialized views here (toast
3225 * rels will be processed indirectly by reindex_relation).
3226 */
3229 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
3230 {
3232 Oid relid = classtuple->oid;
3233
3234 /*
3235 * Only regular tables and matviews can have indexes, so ignore any
3236 * other kind of relation.
3237 *
3238 * Partitioned tables/indexes are skipped but matching leaf partitions
3239 * are processed.
3240 */
3241 if (classtuple->relkind != RELKIND_RELATION &&
3242 classtuple->relkind != RELKIND_MATVIEW)
3243 continue;
3244
3245 /* Skip temp tables of other backends; we can't reindex them at all */
3246 if (classtuple->relpersistence == RELPERSISTENCE_TEMP &&
3247 !isTempNamespace(classtuple->relnamespace))
3248 continue;
3249
3250 /*
3251 * Check user/system classification. SYSTEM processes all the
3252 * catalogs, and DATABASE processes everything that's not a catalog.
3253 */
3255 !IsCatalogRelationOid(relid))
3256 continue;
3257 else if (objectKind == REINDEX_OBJECT_DATABASE &&
3258 IsCatalogRelationOid(relid))
3259 continue;
3260
3261 /*
3262 * We already checked privileges on the database or schema, but we
3263 * further restrict reindexing shared catalogs to roles with the
3264 * MAINTAIN privilege on the relation.
3265 */
3266 if (classtuple->relisshared &&
3268 continue;
3269
3270 /*
3271 * Skip system tables, since index_create() would reject indexing them
3272 * concurrently (and it would likely fail if we tried).
3273 */
3274 if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
3275 IsCatalogRelationOid(relid))
3276 {
3277 if (!concurrent_warning)
3280 errmsg("cannot reindex system catalogs concurrently, skipping all")));
3281 concurrent_warning = true;
3282 continue;
3283 }
3284
3285 /*
3286 * If a new tablespace is set, check if this relation has to be
3287 * skipped.
3288 */
3289 if (OidIsValid(params->tablespaceOid))
3290 {
3291 bool skip_rel = false;
3292
3293 /*
3294 * Mapped relations cannot be moved to different tablespaces (in
3295 * particular this eliminates all shared catalogs.).
3296 */
3297 if (RELKIND_HAS_STORAGE(classtuple->relkind) &&
3298 !RelFileNumberIsValid(classtuple->relfilenode))
3299 skip_rel = true;
3300
3301 /*
3302 * A system relation is always skipped, even with
3303 * allow_system_table_mods enabled.
3304 */
3305 if (IsSystemClass(relid, classtuple))
3306 skip_rel = true;
3307
3308 if (skip_rel)
3309 {
3310 if (!tablespace_warning)
3313 errmsg("cannot move system relations, skipping all")));
3314 tablespace_warning = true;
3315 continue;
3316 }
3317 }
3318
3319 /* Save the list of relation OIDs in private context */
3321
3322 /*
3323 * We always want to reindex pg_class first if it's selected to be
3324 * reindexed. This ensures that if there is any corruption in
3325 * pg_class' indexes, they will be fixed before we process any other
3326 * tables. This is critical because reindexing itself will try to
3327 * update pg_class.
3328 */
3329 if (relid == RelationRelationId)
3330 relids = lcons_oid(relid, relids);
3331 else
3332 relids = lappend_oid(relids, relid);
3333
3335 }
3336 table_endscan(scan);
3338
3339 /*
3340 * Process each relation listed in a separate transaction. Note that this
3341 * commits and then starts a new transaction immediately.
3342 */
3343 ReindexMultipleInternal(stmt, relids, params);
3344
3346}
bool has_privs_of_role(Oid member, Oid role)
Definition acl.c:5284
@ ACLCHECK_NOT_OWNER
Definition acl.h:185
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition aclchk.c:4090
bool IsCatalogRelationOid(Oid relid)
Definition catalog.c:121
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition catalog.c:86
#define WARNING
Definition elog.h:36
Oid MyDatabaseId
Definition globals.c:94
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition heapam.c:1408
static void ReindexMultipleInternal(const ReindexStmt *stmt, const List *relids, const ReindexParams *params)
Definition indexcmds.c:3467
List * lcons_oid(Oid datum, List *list)
Definition list.c:531
List * lappend_oid(List *list, Oid datum)
Definition list.c:375
char * get_database_name(Oid dbid)
Definition lsyscache.c:1242
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
MemoryContext PortalContext
Definition mcxt.c:175
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition memutils.h:170
bool isTempNamespace(Oid namespaceId)
Definition namespace.c:3719
Oid get_namespace_oid(const char *nspname, bool missing_ok)
Definition namespace.c:3605
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
@ OBJECT_DATABASE
ReindexObjectType
FormData_pg_class * Form_pg_class
Definition pg_class.h:156
@ ForwardScanDirection
Definition sdir.h:28
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, ScanKeyData *key)
Definition tableam.c:113
static void table_endscan(TableScanDesc scan)
Definition tableam.h:985

References AccessShareLock, ACL_MAINTAIN, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, ALLOCSET_SMALL_SIZES, AllocSetContextCreate, Assert, BTEqualStrategyNumber, ereport, errcode(), errmsg(), ERROR, fb(), ForwardScanDirection, get_database_name(), get_namespace_oid(), GETSTRUCT(), GetUserId(), has_privs_of_role(), heap_getnext(), IsCatalogRelationOid(), IsSystemClass(), isTempNamespace(), lappend_oid(), lcons_oid(), MemoryContextDelete(), MemoryContextSwitchTo(), MyDatabaseId, NIL, OBJECT_DATABASE, object_ownercheck(), OBJECT_SCHEMA, ObjectIdGetDatum(), OidIsValid, ReindexParams::options, ReindexIndexCallbackState::params, pg_class_aclcheck(), PortalContext, REINDEX_OBJECT_DATABASE, REINDEX_OBJECT_SCHEMA, REINDEX_OBJECT_SYSTEM, ReindexMultipleInternal(), REINDEXOPT_CONCURRENTLY, RelFileNumberIsValid, ScanKeyInit(), stmt, table_beginscan_catalog(), table_close(), table_endscan(), table_open(), ReindexParams::tablespaceOid, and WARNING.

Referenced by ExecReindex().

◆ ReindexPartitions()

static void ReindexPartitions ( const ReindexStmt stmt,
Oid  relid,
const ReindexParams params,
bool  isTopLevel 
)
static

Definition at line 3373 of file indexcmds.c.

3374{
3375 List *partitions = NIL;
3376 char relkind = get_rel_relkind(relid);
3377 char *relname = get_rel_name(relid);
3378 char *relnamespace = get_namespace_name(get_rel_namespace(relid));
3380 List *inhoids;
3381 ListCell *lc;
3382 ErrorContextCallback errcallback;
3384
3386
3387 /*
3388 * Check if this runs in a transaction block, with an error callback to
3389 * provide more context under which a problem happens.
3390 */
3391 errinfo.relname = pstrdup(relname);
3392 errinfo.relnamespace = pstrdup(relnamespace);
3393 errinfo.relkind = relkind;
3394 errcallback.callback = reindex_error_callback;
3395 errcallback.arg = &errinfo;
3396 errcallback.previous = error_context_stack;
3397 error_context_stack = &errcallback;
3398
3400 relkind == RELKIND_PARTITIONED_TABLE ?
3401 "REINDEX TABLE" : "REINDEX INDEX");
3402
3403 /* Pop the error context stack */
3404 error_context_stack = errcallback.previous;
3405
3406 /*
3407 * Create special memory context for cross-transaction storage.
3408 *
3409 * Since it is a child of PortalContext, it will go away eventually even
3410 * if we suffer an error so there is no need for special abort cleanup
3411 * logic.
3412 */
3415
3416 /* ShareLock is enough to prevent schema modifications */
3418
3419 /*
3420 * The list of relations to reindex are the physical partitions of the
3421 * tree so discard any partitioned table or index.
3422 */
3423 foreach(lc, inhoids)
3424 {
3425 Oid partoid = lfirst_oid(lc);
3426 char partkind = get_rel_relkind(partoid);
3428
3429 /*
3430 * This discards partitioned tables, partitioned indexes and foreign
3431 * tables.
3432 */
3434 continue;
3435
3438
3439 /* Save partition OID */
3441 partitions = lappend_oid(partitions, partoid);
3443 }
3444
3445 /*
3446 * Process each partition listed in a separate transaction. Note that
3447 * this commits and then starts a new transaction immediately.
3448 */
3450
3451 /*
3452 * Clean up working storage --- note we must do this after
3453 * StartTransactionCommand, else we might be trying to delete the active
3454 * context!
3455 */
3457}
ErrorContextCallback * error_context_stack
Definition elog.c:95
static void reindex_error_callback(void *arg)
Definition indexcmds.c:3352
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
static int partitions
Definition pgbench.c:224
struct ErrorContextCallback * previous
Definition elog.h:297
void(* callback)(void *arg)
Definition elog.h:298

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, ErrorContextCallback::arg, Assert, ErrorContextCallback::callback, error_context_stack, fb(), find_all_inheritors(), get_namespace_name(), get_rel_name(), get_rel_namespace(), get_rel_relkind(), lappend_oid(), lfirst_oid, MemoryContextDelete(), MemoryContextSwitchTo(), NIL, ReindexIndexCallbackState::params, partitions, PortalContext, PreventInTransactionBlock(), ErrorContextCallback::previous, pstrdup(), reindex_error_callback(), ReindexMultipleInternal(), relname, ShareLock, and stmt.

Referenced by ReindexIndex(), and ReindexTable().

◆ ReindexRelationConcurrently()

static bool ReindexRelationConcurrently ( const ReindexStmt stmt,
Oid  relationOid,
const ReindexParams params 
)
static

Definition at line 3593 of file indexcmds.c.

3594{
3595 typedef struct ReindexIndexInfo
3596 {
3597 Oid indexId;
3598 Oid tableId;
3599 Oid amId;
3600 bool safe; /* for set_indexsafe_procflags */
3603 List *indexIds = NIL;
3604 List *newIndexIds = NIL;
3606 List *lockTags = NIL;
3607 ListCell *lc,
3608 *lc2;
3610 MemoryContext oldcontext;
3611 char relkind;
3612 char *relationName = NULL;
3613 char *relationNamespace = NULL;
3614 PGRUsage ru0;
3615 const int progress_index[] = {
3620 };
3622
3623 /*
3624 * Create a memory context that will survive forced transaction commits we
3625 * do below. Since it is a child of PortalContext, it will go away
3626 * eventually even if we suffer an error; there's no need for special
3627 * abort cleanup logic.
3628 */
3630 "ReindexConcurrent",
3632
3633 if ((params->options & REINDEXOPT_VERBOSE) != 0)
3634 {
3635 /* Save data needed by REINDEX VERBOSE in private context */
3637
3638 relationName = get_rel_name(relationOid);
3640
3642
3643 MemoryContextSwitchTo(oldcontext);
3644 }
3645
3646 relkind = get_rel_relkind(relationOid);
3647
3648 /*
3649 * Extract the list of indexes that are going to be rebuilt based on the
3650 * relation Oid given by caller.
3651 */
3652 switch (relkind)
3653 {
3654 case RELKIND_RELATION:
3655 case RELKIND_MATVIEW:
3656 case RELKIND_TOASTVALUE:
3657 {
3658 /*
3659 * In the case of a relation, find all its indexes including
3660 * toast indexes.
3661 */
3662 Relation heapRelation;
3663
3664 /* Save the list of relation OIDs in private context */
3666
3667 /* Track this relation for session locks */
3669
3670 MemoryContextSwitchTo(oldcontext);
3671
3672 if (IsCatalogRelationOid(relationOid))
3673 ereport(ERROR,
3675 errmsg("cannot reindex system catalogs concurrently")));
3676
3677 /* Open relation to get its indexes */
3678 if ((params->options & REINDEXOPT_MISSING_OK) != 0)
3679 {
3680 heapRelation = try_table_open(relationOid,
3682 /* leave if relation does not exist */
3683 if (!heapRelation)
3684 break;
3685 }
3686 else
3687 heapRelation = table_open(relationOid,
3689
3690 if (OidIsValid(params->tablespaceOid) &&
3691 IsSystemRelation(heapRelation))
3692 ereport(ERROR,
3694 errmsg("cannot move system relation \"%s\"",
3695 RelationGetRelationName(heapRelation))));
3696
3697 /* Add all the valid indexes of relation to list */
3698 foreach(lc, RelationGetIndexList(heapRelation))
3699 {
3701 Relation indexRelation = index_open(cellOid,
3703
3704 if (!indexRelation->rd_index->indisvalid)
3707 errmsg("skipping reindex of invalid index \"%s.%s\"",
3710 errhint("Use DROP INDEX or REINDEX INDEX.")));
3711 else if (indexRelation->rd_index->indisexclusion)
3714 errmsg("cannot reindex exclusion constraint index \"%s.%s\" concurrently, skipping",
3717 else
3718 {
3720
3721 /* Save the list of relation OIDs in private context */
3723
3725 idx->indexId = cellOid;
3726 /* other fields set later */
3727
3729
3730 MemoryContextSwitchTo(oldcontext);
3731 }
3732
3733 index_close(indexRelation, NoLock);
3734 }
3735
3736 /* Also add the toast indexes */
3737 if (OidIsValid(heapRelation->rd_rel->reltoastrelid))
3738 {
3739 Oid toastOid = heapRelation->rd_rel->reltoastrelid;
3742
3743 /* Save the list of relation OIDs in private context */
3745
3746 /* Track this relation for session locks */
3748
3749 MemoryContextSwitchTo(oldcontext);
3750
3752 {
3754 Relation indexRelation = index_open(cellOid,
3756
3757 if (!indexRelation->rd_index->indisvalid)
3760 errmsg("skipping reindex of invalid index \"%s.%s\"",
3763 errhint("Use DROP INDEX or REINDEX INDEX.")));
3764 else
3765 {
3767
3768 /*
3769 * Save the list of relation OIDs in private
3770 * context
3771 */
3773
3775 idx->indexId = cellOid;
3777 /* other fields set later */
3778
3779 MemoryContextSwitchTo(oldcontext);
3780 }
3781
3782 index_close(indexRelation, NoLock);
3783 }
3784
3786 }
3787
3788 table_close(heapRelation, NoLock);
3789 break;
3790 }
3791 case RELKIND_INDEX:
3792 {
3793 Oid heapId = IndexGetRelation(relationOid,
3794 (params->options & REINDEXOPT_MISSING_OK) != 0);
3795 Relation heapRelation;
3797
3798 /* if relation is missing, leave */
3799 if (!OidIsValid(heapId))
3800 break;
3801
3803 ereport(ERROR,
3805 errmsg("cannot reindex system catalogs concurrently")));
3806
3807 /*
3808 * Don't allow reindex for an invalid index on TOAST table, as
3809 * if rebuilt it would not be possible to drop it. Match
3810 * error message in reindex_index().
3811 */
3812 if (IsToastNamespace(get_rel_namespace(relationOid)) &&
3813 !get_index_isvalid(relationOid))
3814 ereport(ERROR,
3816 errmsg("cannot reindex invalid index on TOAST table")));
3817
3818 /*
3819 * Check if parent relation can be locked and if it exists,
3820 * this needs to be done at this stage as the list of indexes
3821 * to rebuild is not complete yet, and REINDEXOPT_MISSING_OK
3822 * should not be used once all the session locks are taken.
3823 */
3824 if ((params->options & REINDEXOPT_MISSING_OK) != 0)
3825 {
3826 heapRelation = try_table_open(heapId,
3828 /* leave if relation does not exist */
3829 if (!heapRelation)
3830 break;
3831 }
3832 else
3833 heapRelation = table_open(heapId,
3835
3836 if (OidIsValid(params->tablespaceOid) &&
3837 IsSystemRelation(heapRelation))
3838 ereport(ERROR,
3840 errmsg("cannot move system relation \"%s\"",
3841 get_rel_name(relationOid))));
3842
3843 table_close(heapRelation, NoLock);
3844
3845 /* Save the list of relation OIDs in private context */
3847
3848 /* Track the heap relation of this index for session locks */
3850
3851 /*
3852 * Save the list of relation OIDs in private context. Note
3853 * that invalid indexes are allowed here.
3854 */
3856 idx->indexId = relationOid;
3858 /* other fields set later */
3859
3860 MemoryContextSwitchTo(oldcontext);
3861 break;
3862 }
3863
3866 default:
3867 /* Return error if type of relation is not supported */
3868 ereport(ERROR,
3870 errmsg("cannot reindex this type of relation concurrently")));
3871 break;
3872 }
3873
3874 /*
3875 * Definitely no indexes, so leave. Any checks based on
3876 * REINDEXOPT_MISSING_OK should be done only while the list of indexes to
3877 * work on is built as the session locks taken before this transaction
3878 * commits will make sure that they cannot be dropped by a concurrent
3879 * session until this operation completes.
3880 */
3881 if (indexIds == NIL)
3882 return false;
3883
3884 /* It's not a shared catalog, so refuse to move it to shared tablespace */
3885 if (params->tablespaceOid == GLOBALTABLESPACE_OID)
3886 ereport(ERROR,
3888 errmsg("cannot move non-shared relation to tablespace \"%s\"",
3890
3892
3893 /*-----
3894 * Now we have all the indexes we want to process in indexIds.
3895 *
3896 * The phases now are:
3897 *
3898 * 1. create new indexes in the catalog
3899 * 2. build new indexes
3900 * 3. let new indexes catch up with tuples inserted in the meantime
3901 * 4. swap index names
3902 * 5. mark old indexes as dead
3903 * 6. drop old indexes
3904 *
3905 * We process each phase for all indexes before moving to the next phase,
3906 * for efficiency.
3907 */
3908
3909 /*
3910 * Phase 1 of REINDEX CONCURRENTLY
3911 *
3912 * Create a new index with the same properties as the old one, but it is
3913 * only registered in catalogs and will be built later. Then get session
3914 * locks on all involved tables. See analogous code in DefineIndex() for
3915 * more detailed comments.
3916 */
3917
3918 foreach(lc, indexIds)
3919 {
3920 char *concurrentName;
3924 Relation indexRel;
3925 Relation heapRel;
3926 Oid save_userid;
3927 int save_sec_context;
3928 int save_nestlevel;
3932
3933 indexRel = index_open(idx->indexId, ShareUpdateExclusiveLock);
3934 heapRel = table_open(indexRel->rd_index->indrelid,
3936
3937 /*
3938 * Switch to the table owner's userid, so that any index functions are
3939 * run as that user. Also lock down security-restricted operations
3940 * and arrange to make GUC variable changes local to this command.
3941 */
3942 GetUserIdAndSecContext(&save_userid, &save_sec_context);
3943 SetUserIdAndSecContext(heapRel->rd_rel->relowner,
3944 save_sec_context | SECURITY_RESTRICTED_OPERATION);
3945 save_nestlevel = NewGUCNestLevel();
3947
3948 /* determine safety of this index for set_indexsafe_procflags */
3949 idx->safe = (RelationGetIndexExpressions(indexRel) == NIL &&
3950 RelationGetIndexPredicate(indexRel) == NIL);
3951
3952#ifdef USE_INJECTION_POINTS
3953 if (idx->safe)
3954 INJECTION_POINT("reindex-conc-index-safe", NULL);
3955 else
3956 INJECTION_POINT("reindex-conc-index-not-safe", NULL);
3957#endif
3958
3959 idx->tableId = RelationGetRelid(heapRel);
3960 idx->amId = indexRel->rd_rel->relam;
3961
3962 /* This function shouldn't be called for temporary relations. */
3963 if (indexRel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
3964 elog(ERROR, "cannot reindex a temporary table concurrently");
3965
3967
3969 progress_vals[1] = 0; /* initializing */
3970 progress_vals[2] = idx->indexId;
3971 progress_vals[3] = idx->amId;
3973
3974 /* Choose a temporary relation name for the new index */
3976 NULL,
3977 "ccnew",
3978 get_rel_namespace(indexRel->rd_index->indrelid),
3979 false);
3980
3981 /* Choose the new tablespace, indexes of toast tables are not moved */
3982 if (OidIsValid(params->tablespaceOid) &&
3983 heapRel->rd_rel->relkind != RELKIND_TOASTVALUE)
3984 tablespaceid = params->tablespaceOid;
3985 else
3986 tablespaceid = indexRel->rd_rel->reltablespace;
3987
3988 /* Create new index definition based on given index */
3990 idx->indexId,
3993
3994 /*
3995 * Now open the relation of the new index, a session-level lock is
3996 * also needed on it.
3997 */
3999
4000 /*
4001 * Save the list of OIDs and locks in private context
4002 */
4004
4006 newidx->indexId = newIndexId;
4007 newidx->safe = idx->safe;
4008 newidx->tableId = idx->tableId;
4009 newidx->amId = idx->amId;
4010
4012
4013 /*
4014 * Save lockrelid to protect each relation from drop then close
4015 * relations. The lockrelid on parent relation is not taken here to
4016 * avoid multiple locks taken on the same relation, instead we rely on
4017 * parentRelationIds built earlier.
4018 */
4020 *lockrelid = indexRel->rd_lockInfo.lockRelId;
4023 *lockrelid = newIndexRel->rd_lockInfo.lockRelId;
4025
4026 MemoryContextSwitchTo(oldcontext);
4027
4028 index_close(indexRel, NoLock);
4030
4031 /* Roll back any GUC changes executed by index functions */
4032 AtEOXact_GUC(false, save_nestlevel);
4033
4034 /* Restore userid and security context */
4035 SetUserIdAndSecContext(save_userid, save_sec_context);
4036
4037 table_close(heapRel, NoLock);
4038
4039 /*
4040 * If a statement is available, telling that this comes from a REINDEX
4041 * command, collect the new index for event triggers.
4042 */
4043 if (stmt)
4044 {
4045 ObjectAddress address;
4046
4050 (Node *) stmt);
4051 }
4052 }
4053
4054 /*
4055 * Save the heap lock for following visibility checks with other backends
4056 * might conflict with this session.
4057 */
4058 foreach(lc, heapRelationIds)
4059 {
4063
4064 /* Save the list of locks in private context */
4066
4067 /* Add lockrelid of heap relation to the list of locked relations */
4069 *lockrelid = heapRelation->rd_lockInfo.lockRelId;
4071
4073
4074 /* Save the LOCKTAG for this parent relation for the wait phase */
4077
4078 MemoryContextSwitchTo(oldcontext);
4079
4080 /* Close heap relation */
4081 table_close(heapRelation, NoLock);
4082 }
4083
4084 /* Get a session-level lock on each table. */
4085 foreach(lc, relationLocks)
4086 {
4088
4090 }
4091
4095
4096 /*
4097 * Because we don't take a snapshot in this transaction, there's no need
4098 * to set the PROC_IN_SAFE_IC flag here.
4099 */
4100
4101 /*
4102 * Phase 2 of REINDEX CONCURRENTLY
4103 *
4104 * Build the new indexes in a separate transaction for each index to avoid
4105 * having open transactions for an unnecessary long time. But before
4106 * doing that, wait until no running transactions could have the table of
4107 * the index open with the old list of indexes. See "phase 2" in
4108 * DefineIndex() for more details.
4109 */
4110
4115
4116 foreach(lc, newIndexIds)
4117 {
4119
4120 /* Start new transaction for this index's concurrent build */
4122
4123 /*
4124 * Check for user-requested abort. This is inside a transaction so as
4125 * xact.c does not issue a useless WARNING, and ensures that
4126 * session-level locks are cleaned up on abort.
4127 */
4129
4130 /* Tell concurrent indexing to ignore us, if index qualifies */
4131 if (newidx->safe)
4133
4134 /* Set ActiveSnapshot since functions in the indexes may need it */
4136
4137 /*
4138 * Update progress for the index to build, with the correct parent
4139 * table involved.
4140 */
4144 progress_vals[2] = newidx->indexId;
4145 progress_vals[3] = newidx->amId;
4147
4148 /* Perform concurrent build of new index */
4149 index_concurrently_build(newidx->tableId, newidx->indexId);
4150
4153 }
4154
4156
4157 /*
4158 * Because we don't take a snapshot or Xid in this transaction, there's no
4159 * need to set the PROC_IN_SAFE_IC flag here.
4160 */
4161
4162 /*
4163 * Phase 3 of REINDEX CONCURRENTLY
4164 *
4165 * During this phase the old indexes catch up with any new tuples that
4166 * were created during the previous phase. See "phase 3" in DefineIndex()
4167 * for more details.
4168 */
4169
4174
4175 foreach(lc, newIndexIds)
4176 {
4179 Snapshot snapshot;
4180
4182
4183 /*
4184 * Check for user-requested abort. This is inside a transaction so as
4185 * xact.c does not issue a useless WARNING, and ensures that
4186 * session-level locks are cleaned up on abort.
4187 */
4189
4190 /* Tell concurrent indexing to ignore us, if index qualifies */
4191 if (newidx->safe)
4193
4194 /*
4195 * Take the "reference snapshot" that will be used by validate_index()
4196 * to filter candidate tuples.
4197 */
4199 PushActiveSnapshot(snapshot);
4200
4201 /*
4202 * Update progress for the index to build, with the correct parent
4203 * table involved.
4204 */
4208 progress_vals[2] = newidx->indexId;
4209 progress_vals[3] = newidx->amId;
4211
4212 validate_index(newidx->tableId, newidx->indexId, snapshot);
4213
4214 /*
4215 * We can now do away with our active snapshot, we still need to save
4216 * the xmin limit to wait for older snapshots.
4217 */
4218 limitXmin = snapshot->xmin;
4219
4221 UnregisterSnapshot(snapshot);
4222
4223 /*
4224 * To ensure no deadlocks, we must commit and start yet another
4225 * transaction, and do our wait before any snapshot has been taken in
4226 * it.
4227 */
4230
4231 /*
4232 * The index is now valid in the sense that it contains all currently
4233 * interesting tuples. But since it might not contain tuples deleted
4234 * just before the reference snap was taken, we have to wait out any
4235 * transactions that might have older snapshots.
4236 *
4237 * Because we don't take a snapshot or Xid in this transaction,
4238 * there's no need to set the PROC_IN_SAFE_IC flag here.
4239 */
4243
4245 }
4246
4247 /*
4248 * Phase 4 of REINDEX CONCURRENTLY
4249 *
4250 * Now that the new indexes have been validated, swap each new index with
4251 * its corresponding old index.
4252 *
4253 * We mark the new indexes as valid and the old indexes as not valid at
4254 * the same time to make sure we only get constraint violations from the
4255 * indexes with the correct names.
4256 */
4257
4258 INJECTION_POINT("reindex-relation-concurrently-before-swap", NULL);
4260
4261 /*
4262 * Because this transaction only does catalog manipulations and doesn't do
4263 * any index operations, we can set the PROC_IN_SAFE_IC flag here
4264 * unconditionally.
4265 */
4267
4269 {
4272 char *oldName;
4273
4274 /*
4275 * Check for user-requested abort. This is inside a transaction so as
4276 * xact.c does not issue a useless WARNING, and ensures that
4277 * session-level locks are cleaned up on abort.
4278 */
4280
4281 /* Choose a relation name for old index */
4283 NULL,
4284 "ccold",
4285 get_rel_namespace(oldidx->tableId),
4286 false);
4287
4288 /*
4289 * Swapping the indexes might involve TOAST table access, so ensure we
4290 * have a valid snapshot.
4291 */
4293
4294 /*
4295 * Swap old index with the new one. This also marks the new one as
4296 * valid and the old one as not valid.
4297 */
4298 index_concurrently_swap(newidx->indexId, oldidx->indexId, oldName);
4299
4301
4302 /*
4303 * Invalidate the relcache for the table, so that after this commit
4304 * all sessions will refresh any cached plans that might reference the
4305 * index.
4306 */
4308
4309 /*
4310 * CCI here so that subsequent iterations see the oldName in the
4311 * catalog and can choose a nonconflicting name for their oldName.
4312 * Otherwise, this could lead to conflicts if a table has two indexes
4313 * whose names are equal for the first NAMEDATALEN-minus-a-few
4314 * characters.
4315 */
4317 }
4318
4319 /* Commit this transaction and make index swaps visible */
4322
4323 /*
4324 * While we could set PROC_IN_SAFE_IC if all indexes qualified, there's no
4325 * real need for that, because we only acquire an Xid after the wait is
4326 * done, and that lasts for a very short period.
4327 */
4328
4329 /*
4330 * Phase 5 of REINDEX CONCURRENTLY
4331 *
4332 * Mark the old indexes as dead. First we must wait until no running
4333 * transaction could be using the index for a query. See also
4334 * index_drop() for more details.
4335 */
4336
4337 INJECTION_POINT("reindex-relation-concurrently-before-set-dead", NULL);
4341
4342 foreach(lc, indexIds)
4343 {
4345
4346 /*
4347 * Check for user-requested abort. This is inside a transaction so as
4348 * xact.c does not issue a useless WARNING, and ensures that
4349 * session-level locks are cleaned up on abort.
4350 */
4352
4353 /*
4354 * Updating pg_index might involve TOAST table access, so ensure we
4355 * have a valid snapshot.
4356 */
4358
4359 index_concurrently_set_dead(oldidx->tableId, oldidx->indexId);
4360
4362 }
4363
4364 /* Commit this transaction to make the updates visible. */
4367
4368 /*
4369 * While we could set PROC_IN_SAFE_IC if all indexes qualified, there's no
4370 * real need for that, because we only acquire an Xid after the wait is
4371 * done, and that lasts for a very short period.
4372 */
4373
4374 /*
4375 * Phase 6 of REINDEX CONCURRENTLY
4376 *
4377 * Drop the old indexes.
4378 */
4379
4383
4385
4386 {
4388
4389 foreach(lc, indexIds)
4390 {
4392 ObjectAddress object;
4393
4394 object.classId = RelationRelationId;
4395 object.objectId = idx->indexId;
4396 object.objectSubId = 0;
4397
4398 add_exact_object_address(&object, objects);
4399 }
4400
4401 /*
4402 * Use PERFORM_DELETION_CONCURRENT_LOCK so that index_drop() uses the
4403 * right lock level.
4404 */
4407 }
4408
4411
4412 /*
4413 * Finally, release the session-level lock on the table.
4414 */
4415 foreach(lc, relationLocks)
4416 {
4418
4420 }
4421
4422 /* Start a new transaction to finish process properly */
4424
4425 /* Log what we did */
4426 if ((params->options & REINDEXOPT_VERBOSE) != 0)
4427 {
4428 if (relkind == RELKIND_INDEX)
4429 ereport(INFO,
4430 (errmsg("index \"%s.%s\" was reindexed",
4432 errdetail("%s.",
4433 pg_rusage_show(&ru0))));
4434 else
4435 {
4436 foreach(lc, newIndexIds)
4437 {
4439 Oid indOid = idx->indexId;
4440
4441 ereport(INFO,
4442 (errmsg("index \"%s.%s\" was reindexed",
4444 get_rel_name(indOid))));
4445 /* Don't show rusage here, since it's not per index. */
4446 }
4447
4448 ereport(INFO,
4449 (errmsg("table \"%s.%s\" was reindexed",
4451 errdetail("%s.",
4452 pg_rusage_show(&ru0))));
4453 }
4454 }
4455
4457
4459
4460 return true;
4461}
Datum idx(PG_FUNCTION_ARGS)
Definition _int_op.c:262
bool IsToastNamespace(Oid namespaceId)
Definition catalog.c:261
bool IsSystemRelation(Relation relation)
Definition catalog.c:74
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition dependency.c:383
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
ObjectAddresses * new_object_addresses(void)
#define PERFORM_DELETION_CONCURRENT_LOCK
Definition dependency.h:97
#define PERFORM_DELETION_INTERNAL
Definition dependency.h:92
void EventTriggerCollectSimpleCommand(ObjectAddress address, ObjectAddress secondaryObject, Node *parsetree)
#define palloc_object(type)
Definition fe_memutils.h:74
void index_concurrently_set_dead(Oid heapId, Oid indexId)
Definition index.c:1821
void index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName)
Definition index.c:1550
Oid index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, Oid tablespaceOid, const char *newName)
Definition index.c:1298
void WaitForLockersMultiple(List *locktags, LOCKMODE lockmode, bool progress)
Definition lmgr.c:911
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
const ObjectAddress InvalidObjectAddress
@ DROP_RESTRICT
#define forboth(cell1, list1, cell2, list2)
Definition pg_list.h:518
#define list_make1_oid(x1)
Definition pg_list.h:242
const char * pg_rusage_show(const PGRUsage *ru0)
Definition pg_rusage.c:40
void pg_rusage_init(PGRUsage *ru0)
Definition pg_rusage.c:27
#define PROGRESS_CREATEIDX_PHASE_WAIT_4
Definition progress.h:120
#define PROGRESS_CREATEIDX_PHASE_BUILD
Definition progress.h:114
#define PROGRESS_CREATEIDX_COMMAND_REINDEX_CONCURRENTLY
Definition progress.h:133
#define PROGRESS_CREATEIDX_PHASE_VALIDATE_IDXSCAN
Definition progress.h:116
#define PROGRESS_CREATEIDX_PHASE_WAIT_5
Definition progress.h:121
List * RelationGetIndexPredicate(Relation relation)
Definition relcache.c:5205
List * RelationGetIndexExpressions(Relation relation)
Definition relcache.c:5092
Relation try_table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:60

References AccessExclusiveLock, add_exact_object_address(), ALLOCSET_SMALL_SIZES, AllocSetContextCreate, Assert, AtEOXact_GUC(), CacheInvalidateRelcacheByRelid(), CHECK_FOR_INTERRUPTS, ChooseRelationName(), ObjectAddress::classId, CommandCounterIncrement(), CommitTransactionCommand(), DROP_RESTRICT, elog, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, EventTriggerCollectSimpleCommand(), fb(), forboth, get_index_isvalid(), get_namespace_name(), get_rel_name(), get_rel_namespace(), get_rel_relkind(), get_tablespace_name(), GetTransactionSnapshot(), GetUserIdAndSecContext(), idx(), index_close(), index_concurrently_build(), index_concurrently_create_copy(), index_concurrently_set_dead(), index_concurrently_swap(), index_open(), IndexGetRelation(), INFO, INJECTION_POINT, InvalidObjectAddress, IsCatalogRelationOid(), IsSystemRelation(), IsToastNamespace(), lappend(), lappend_oid(), lfirst, lfirst_oid, list_make1_oid, LockRelationIdForSession(), LockInfoData::lockRelId, MemoryContextDelete(), MemoryContextSwitchTo(), new_object_addresses(), NewGUCNestLevel(), NIL, NoLock, ObjectAddressSet, OidIsValid, ReindexParams::options, palloc_object, PERFORM_DELETION_CONCURRENT_LOCK, PERFORM_DELETION_INTERNAL, performMultipleDeletions(), pg_rusage_init(), pg_rusage_show(), pgstat_progress_end_command(), pgstat_progress_start_command(), pgstat_progress_update_multi_param(), pgstat_progress_update_param(), PopActiveSnapshot(), PortalContext, PROGRESS_COMMAND_CREATE_INDEX, PROGRESS_CREATEIDX_ACCESS_METHOD_OID, PROGRESS_CREATEIDX_COMMAND, PROGRESS_CREATEIDX_COMMAND_REINDEX_CONCURRENTLY, PROGRESS_CREATEIDX_INDEX_OID, PROGRESS_CREATEIDX_PHASE, PROGRESS_CREATEIDX_PHASE_BUILD, PROGRESS_CREATEIDX_PHASE_VALIDATE_IDXSCAN, PROGRESS_CREATEIDX_PHASE_WAIT_1, PROGRESS_CREATEIDX_PHASE_WAIT_2, PROGRESS_CREATEIDX_PHASE_WAIT_3, PROGRESS_CREATEIDX_PHASE_WAIT_4, PROGRESS_CREATEIDX_PHASE_WAIT_5, PushActiveSnapshot(), RelationData::rd_index, RelationData::rd_lockInfo, RelationData::rd_rel, RegisterSnapshot(), REINDEXOPT_MISSING_OK, REINDEXOPT_VERBOSE, RelationGetIndexExpressions(), RelationGetIndexList(), RelationGetIndexPredicate(), RelationGetRelationName, RelationGetRelid, RestrictSearchPath(), SECURITY_RESTRICTED_OPERATION, set_indexsafe_procflags(), SET_LOCKTAG_RELATION, SetUserIdAndSecContext(), ShareLock, ShareUpdateExclusiveLock, StartTransactionCommand(), stmt, table_close(), table_open(), ReindexParams::tablespaceOid, try_table_open(), UnlockRelationIdForSession(), UnregisterSnapshot(), validate_index(), WaitForLockersMultiple(), WaitForOlderSnapshots(), WARNING, and SnapshotData::xmin.

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

◆ ReindexTable()

static Oid ReindexTable ( const ReindexStmt stmt,
const ReindexParams params,
bool  isTopLevel 
)
static

Definition at line 3074 of file indexcmds.c.

3075{
3076 Oid heapOid;
3077 bool result;
3078 const RangeVar *relation = stmt->relation;
3079
3080 /*
3081 * The lock level used here should match reindex_relation().
3082 *
3083 * If it's a temporary table, we will perform a non-concurrent reindex,
3084 * even if CONCURRENTLY was requested. In that case, reindex_relation()
3085 * will upgrade the lock, but that's OK, because other sessions can't hold
3086 * locks on our temporary table.
3087 */
3088 heapOid = RangeVarGetRelidExtended(relation,
3089 (params->options & REINDEXOPT_CONCURRENTLY) != 0 ?
3091 0,
3093
3095 ReindexPartitions(stmt, heapOid, params, isTopLevel);
3096 else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
3098 {
3099 result = ReindexRelationConcurrently(stmt, heapOid, params);
3100
3101 if (!result)
3103 (errmsg("table \"%s\" has no indexes that can be reindexed concurrently",
3104 relation->relname)));
3105 }
3106 else
3107 {
3108 ReindexParams newparams = *params;
3109
3111 result = reindex_relation(stmt, heapOid,
3114 &newparams);
3115 if (!result)
3117 (errmsg("table \"%s\" has no indexes to reindex",
3118 relation->relname)));
3119 }
3120
3121 return heapOid;
3122}
void RangeVarCallbackMaintainsTable(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)

References ereport, errmsg(), fb(), get_rel_persistence(), get_rel_relkind(), NOTICE, ReindexParams::options, ReindexIndexCallbackState::params, RangeVarCallbackMaintainsTable(), RangeVarGetRelidExtended(), REINDEX_REL_CHECK_CONSTRAINTS, REINDEX_REL_PROCESS_TOAST, reindex_relation(), REINDEXOPT_CONCURRENTLY, REINDEXOPT_REPORT_PROGRESS, ReindexPartitions(), ReindexRelationConcurrently(), RangeVar::relname, ShareLock, ShareUpdateExclusiveLock, and stmt.

Referenced by ExecReindex().

◆ ResolveOpClass()

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

Definition at line 2283 of file indexcmds.c.

2285{
2286 char *schemaname;
2287 char *opcname;
2288 HeapTuple tuple;
2290 Oid opClassId,
2292
2293 if (opclass == NIL)
2294 {
2295 /* no operator class specified, so find the default */
2297 if (!OidIsValid(opClassId))
2298 ereport(ERROR,
2300 errmsg("data type %s has no default operator class for access method \"%s\"",
2302 errhint("You must specify an operator class for the index or define a default operator class for the data type.")));
2303 return opClassId;
2304 }
2305
2306 /*
2307 * Specific opclass name given, so look up the opclass.
2308 */
2309
2310 /* deconstruct the name list */
2311 DeconstructQualifiedName(opclass, &schemaname, &opcname);
2312
2313 if (schemaname)
2314 {
2315 /* Look in specific schema only */
2317
2318 namespaceId = LookupExplicitNamespace(schemaname, false);
2323 }
2324 else
2325 {
2326 /* Unqualified opclass name, so search the search path */
2328 if (!OidIsValid(opClassId))
2329 ereport(ERROR,
2331 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
2334 }
2335
2336 if (!HeapTupleIsValid(tuple))
2337 ereport(ERROR,
2339 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
2341
2342 /*
2343 * Verify that the index operator class accepts this datatype. Note we
2344 * will accept binary compatibility.
2345 */
2346 opform = (Form_pg_opclass) GETSTRUCT(tuple);
2347 opClassId = opform->oid;
2348 opInputType = opform->opcintype;
2349
2351 ereport(ERROR,
2353 errmsg("operator class \"%s\" does not accept data type %s",
2355
2356 ReleaseSysCache(tuple);
2357
2358 return opClassId;
2359}
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition indexcmds.c:2368
Oid OpclassnameGetOpcid(Oid amid, const char *opcname)
Definition namespace.c:2188
char * NameListToString(const List *names)
Definition namespace.c:3664
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition namespace.c:3455
void DeconstructQualifiedName(const List *names, char **nspname_p, char **objname_p)
Definition namespace.c:3371
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition syscache.c:240

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

Referenced by ComputeIndexAttrs(), and ComputePartitionAttrs().

◆ set_indexsafe_procflags()

static void set_indexsafe_procflags ( void  )
inlinestatic

Definition at line 4640 of file indexcmds.c.

4641{
4642 /*
4643 * This should only be called before installing xid or xmin in MyProc;
4644 * otherwise, concurrent processes could see an Xmin that moves backwards.
4645 */
4648
4653}
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1176
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1793
@ LW_EXCLUSIVE
Definition lwlock.h:112
#define PROC_IN_SAFE_IC
Definition proc.h:59
PROC_HDR * ProcGlobal
Definition proc.c:79
uint8 statusFlags
Definition proc.h:265
int pgxactoff
Definition proc.h:201
TransactionId xid
Definition proc.h:189
uint8 * statusFlags
Definition proc.h:409

References Assert, fb(), InvalidTransactionId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MyProc, PGPROC::pgxactoff, PROC_IN_SAFE_IC, ProcGlobal, PGPROC::statusFlags, PROC_HDR::statusFlags, PGPROC::xid, and PGPROC::xmin.

Referenced by DefineIndex(), and ReindexRelationConcurrently().

◆ update_relispartition()

static void update_relispartition ( Oid  relationId,
bool  newval 
)
static

Definition at line 4602 of file indexcmds.c.

4603{
4604 HeapTuple tup;
4607
4610 if (!HeapTupleIsValid(tup))
4611 elog(ERROR, "cache lookup failed for relation %u", relationId);
4612 otid = tup->t_self;
4619}
#define newval
void UnlockTuple(Relation relation, const ItemPointerData *tid, LOCKMODE lockmode)
Definition lmgr.c:601
#define InplaceUpdateTupleLock
Definition lockdefs.h:48
HeapTuple SearchSysCacheLockedCopy1(int cacheId, Datum key1)
Definition syscache.c:399

References Assert, CatalogTupleUpdate(), elog, ERROR, fb(), GETSTRUCT(), heap_freetuple(), HeapTupleIsValid, InplaceUpdateTupleLock, newval, ObjectIdGetDatum(), RowExclusiveLock, SearchSysCacheLockedCopy1(), table_close(), table_open(), and UnlockTuple().

Referenced by IndexSetParentIndex().

◆ WaitForOlderSnapshots()

void WaitForOlderSnapshots ( TransactionId  limitXmin,
bool  progress 
)

Definition at line 435 of file indexcmds.c.

436{
437 int n_old_snapshots;
438 int i;
440
445 if (progress)
447
448 for (i = 0; i < n_old_snapshots; i++)
449 {
451 continue; /* found uninteresting in previous cycle */
452
453 if (i > 0)
454 {
455 /* see if anything's changed ... */
458 int j;
459 int k;
460
462 true, false,
466 for (j = i; j < n_old_snapshots; j++)
467 {
469 continue; /* found uninteresting in previous cycle */
470 for (k = 0; k < n_newer_snapshots; k++)
471 {
473 newer_snapshots[k]))
474 break;
475 }
476 if (k >= n_newer_snapshots) /* not there anymore */
478 }
480 }
481
483 {
484 /* If requested, publish who we're going to wait for. */
485 if (progress)
486 {
488
489 if (holder)
491 holder->pid);
492 }
494 }
495
496 if (progress)
498 }
499}
bool VirtualXactLock(VirtualTransactionId vxid, bool wait)
Definition lock.c:4743
#define VirtualTransactionIdIsValid(vxid)
Definition lock.h:69
#define VirtualTransactionIdEquals(vxid1, vxid2)
Definition lock.h:73
#define SetInvalidVirtualTransactionId(vxid)
Definition lock.h:76
static int progress
Definition pgbench.c:262
#define PROC_IN_VACUUM
Definition proc.h:58
#define PROC_IS_AUTOVACUUM
Definition proc.h:57
VirtualTransactionId * GetCurrentVirtualXIDs(TransactionId limitXmin, bool excludeXmin0, bool allDbs, int excludeVacuum, int *nvxids)
Definition procarray.c:3287
PGPROC * ProcNumberGetProc(ProcNumber procNumber)
Definition procarray.c:3101
#define PROGRESS_WAITFOR_DONE
Definition progress.h:137
#define PROGRESS_WAITFOR_TOTAL
Definition progress.h:136
#define PROGRESS_WAITFOR_CURRENT_PID
Definition progress.h:138
Definition proc.h:179

References fb(), GetCurrentVirtualXIDs(), i, j, pfree(), pgstat_progress_update_param(), PROC_IN_SAFE_IC, PROC_IN_VACUUM, PROC_IS_AUTOVACUUM, ProcNumberGetProc(), progress, PROGRESS_WAITFOR_CURRENT_PID, PROGRESS_WAITFOR_DONE, PROGRESS_WAITFOR_TOTAL, SetInvalidVirtualTransactionId, VirtualTransactionIdEquals, VirtualTransactionIdIsValid, and VirtualXactLock().

Referenced by ATExecDetachPartitionFinalize(), DefineIndex(), and ReindexRelationConcurrently().