PostgreSQL Source Code git master
Loading...
Searching...
No Matches
indexcmds.c File Reference
#include "postgres.h"
#include "access/amapi.h"
#include "access/attmap.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, const 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 179 of file indexcmds.c.

184{
185 bool isconstraint;
186 Oid *typeIds;
192 HeapTuple tuple;
196 bool amcanorder;
197 bool amsummarizing;
199 IndexInfo *indexInfo;
201 int old_natts;
202 bool ret = true;
205 Relation irel;
206 int i;
207 Datum d;
208
209 /* Caller should already have the relation locked in some way. */
211
212 /*
213 * We can pretend isconstraint = false unconditionally. It only serves to
214 * decide the text of an error message that should never happen for us.
215 */
216 isconstraint = false;
217
221
222 /* look up the access method */
224 if (!HeapTupleIsValid(tuple))
227 errmsg("access method \"%s\" does not exist",
232 ReleaseSysCache(tuple);
233
234 amcanorder = amRoutine->amcanorder;
235 amsummarizing = amRoutine->amsummarizing;
236
237 /*
238 * Compute the operator classes, collations, and exclusion operators for
239 * the new index, so we can test whether it's compatible with the existing
240 * one. Note that ComputeIndexAttrs might fail here, but that's OK:
241 * DefineIndex would have failed later. Our attributeList contains only
242 * key attributes, thus we're filling ii_NumIndexAttrs and
243 * ii_NumIndexKeyAttrs with same value.
244 */
246 accessMethodId, NIL, NIL, false, false,
247 false, false, amsummarizing, isWithoutOverlaps);
253 ComputeIndexAttrs(NULL, indexInfo,
258 amcanorder, isconstraint, isWithoutOverlaps, InvalidOid,
259 0, NULL);
260
261 /* Get the soon-obsolete pg_index tuple. */
263 if (!HeapTupleIsValid(tuple))
264 elog(ERROR, "cache lookup failed for index %u", oldId);
266
267 /*
268 * We don't assess expressions or predicates; assume incompatibility.
269 * Also, if the index is invalid for any reason, treat it as incompatible.
270 */
273 indexForm->indisvalid))
274 {
275 ReleaseSysCache(tuple);
276 return false;
277 }
278
279 /* Any change in operator class or collation breaks compatibility. */
280 old_natts = indexForm->indnkeyatts;
282
285
288
289 ret = (memcmp(old_indclass->values, opclassIds, old_natts * sizeof(Oid)) == 0 &&
290 memcmp(old_indcollation->values, collationIds, old_natts * sizeof(Oid)) == 0);
291
292 ReleaseSysCache(tuple);
293
294 if (!ret)
295 return false;
296
297 /* For polymorphic opcintype, column type changes break compatibility. */
298 irel = index_open(oldId, AccessShareLock); /* caller probably has a lock */
299 for (i = 0; i < old_natts; i++)
300 {
302 TupleDescAttr(irel->rd_att, i)->atttypid != typeIds[i])
303 {
304 ret = false;
305 break;
306 }
307 }
308
309 /* Any change in opclass options break compatibility. */
310 if (ret)
311 {
313
314 for (i = 0; i < old_natts; i++)
316
318
320 }
321
322 /* Any change in exclusion operator selections breaks compatibility. */
323 if (ret && indexInfo->ii_ExclusionOps != NULL)
324 {
326 *old_procs;
328
330 ret = memcmp(old_operators, indexInfo->ii_ExclusionOps,
331 old_natts * sizeof(Oid)) == 0;
332
333 /* Require an exact input type match for polymorphic operators. */
334 if (ret)
335 {
336 for (i = 0; i < old_natts && ret; i++)
337 {
338 Oid left,
339 right;
340
341 op_input_types(indexInfo->ii_ExclusionOps[i], &left, &right);
342 if ((IsPolymorphicType(left) || IsPolymorphicType(right)) &&
343 TupleDescAttr(irel->rd_att, i)->atttypid != typeIds[i])
344 {
345 ret = false;
346 break;
347 }
348 }
349 }
350 }
351
352 index_close(irel, NoLock);
353 return ret;
354}
const IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition amapi.c:33
#define Assert(condition)
Definition c.h:943
int16_t int16
Definition c.h:619
uint16_t uint16
Definition c.h:623
int errcode(int sqlerrcode)
Definition elog.c:874
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:227
#define ereport(elevel,...)
Definition elog.h:151
#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:3584
void index_close(Relation relation, LOCKMODE lockmode)
Definition indexam.c:178
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition indexam.c:134
static bool CompareOpclassOptions(const Datum *opts1, const Datum *opts2, int natts)
Definition indexcmds.c:363
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:1881
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:1384
Datum get_attoptions(Oid relid, int16 attnum)
Definition lsyscache.c:1089
void op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
Definition lsyscache.c:1578
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
static char * errmsg
END_CATALOG_STRUCT typedef FormData_pg_am * Form_pg_am
Definition pg_am.h:52
#define INDEX_MAX_KEYS
END_CATALOG_STRUCT typedef FormData_pg_index * Form_pg_index
Definition pg_index.h:74
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:342
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
#define InvalidOid
unsigned int Oid
static int fb(int x)
void RelationGetExclusionInfo(Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
Definition relcache.c:5644
Oid * ii_ExclusionOps
Definition execnodes.h:200
TupleDesc rd_att
Definition rel.h:112
Definition c.h:815
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
Datum SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:626
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178

References AccessShareLock, Assert, CompareOpclassOptions(), ComputeIndexAttrs(), DatumGetPointer(), elog, ereport, errcode(), errmsg, ERROR, fb(), Form_pg_am, Form_pg_index, 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 1854 of file indexcmds.c.

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

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

2792{
2793 List *result = NIL;
2794 ListCell *lc;
2795
2796 foreach(lc, indexElems)
2797 {
2799 const char *origname;
2800 const char *curname;
2801 int i;
2802 char buf[NAMEDATALEN];
2803
2804 /* Get the preliminary name from the IndexElem */
2805 if (ielem->indexcolname)
2806 origname = ielem->indexcolname; /* caller-specified name */
2807 else if (ielem->name)
2808 origname = ielem->name; /* simple column reference */
2809 else
2810 origname = "expr"; /* default name for expression */
2811
2812 /* If it conflicts with any previous column, tweak it */
2813 curname = origname;
2814 for (i = 1;; i++)
2815 {
2816 ListCell *lc2;
2817 char nbuf[32];
2818 int nlen;
2819
2820 foreach(lc2, result)
2821 {
2822 if (strcmp(curname, (char *) lfirst(lc2)) == 0)
2823 break;
2824 }
2825 if (lc2 == NULL)
2826 break; /* found nonconflicting name */
2827
2828 sprintf(nbuf, "%d", i);
2829
2830 /* Ensure generated names are shorter than NAMEDATALEN */
2832 NAMEDATALEN - 1 - strlen(nbuf));
2834 strcpy(buf + nlen, nbuf);
2835 curname = buf;
2836 }
2837
2838 /* And attach to the result list */
2839 result = lappend(result, pstrdup(curname));
2840 }
2841 return result;
2842}
List * lappend(List *list, void *datum)
Definition list.c:339
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition mbutils.c:1211
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:829
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 2702 of file indexcmds.c.

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

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

Referenced by DefineIndex().

◆ ChooseIndexNameAddition()

static char * ChooseIndexNameAddition ( const List colnames)
static

Definition at line 2757 of file indexcmds.c.

2758{
2759 char buf[NAMEDATALEN * 2];
2760 int buflen = 0;
2761 ListCell *lc;
2762
2763 buf[0] = '\0';
2764 foreach(lc, colnames)
2765 {
2766 const char *name = (const char *) lfirst(lc);
2767
2768 if (buflen > 0)
2769 buf[buflen++] = '_'; /* insert _ between names */
2770
2771 /*
2772 * At this point we have buflen <= NAMEDATALEN. name should be less
2773 * than NAMEDATALEN already, but use strlcpy for paranoia.
2774 */
2775 strlcpy(buf + buflen, name, NAMEDATALEN);
2776 buflen += strlen(buf + buflen);
2777 if (buflen >= NAMEDATALEN)
2778 break;
2779 }
2780 return pstrdup(buf);
2781}
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 2634 of file indexcmds.c.

2637{
2638 int pass = 0;
2639 char *relname = NULL;
2640 char modlabel[NAMEDATALEN];
2643
2644 /* prepare to search pg_class with a dirty snapshot */
2647
2648 /* try the unmodified label first */
2649 strlcpy(modlabel, label, sizeof(modlabel));
2650
2651 for (;;)
2652 {
2653 ScanKeyData key[2];
2654 SysScanDesc scan;
2655 bool collides;
2656
2658
2659 /* is there any conflicting relation name? */
2660 ScanKeyInit(&key[0],
2664 ScanKeyInit(&key[1],
2668
2670 true /* indexOK */ ,
2672 2, key);
2673
2675
2676 systable_endscan(scan);
2677
2678 /* break out of loop if no conflict */
2679 if (!collides)
2680 {
2681 if (!isconstraint ||
2683 break;
2684 }
2685
2686 /* found a conflict, so try a new name component */
2687 pfree(relname);
2688 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
2689 }
2690
2692
2693 return relname;
2694}
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:515
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:2546
static char * label
NameData relname
Definition pg_class.h:40
bool ConstraintNameExists(const char *conname, Oid namespaceid)
#define snprintf
Definition port.h:260
static Datum CStringGetDatum(const char *X)
Definition postgres.h:370
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 363 of file indexcmds.c.

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

1899{
1901 ListCell *lc;
1902 int attn;
1903 int nkeycols = indexInfo->ii_NumIndexKeyAttrs;
1904 Oid save_userid;
1905 int save_sec_context;
1906
1907 /* Allocate space for exclusion operator info, if needed */
1908 if (exclusionOpNames)
1909 {
1915 }
1916 else
1917 nextExclOp = NULL;
1918
1919 /*
1920 * If this is a WITHOUT OVERLAPS constraint, we need space for exclusion
1921 * ops, but we don't need to parse anything, so we can let nextExclOp be
1922 * NULL. Note that for partitions/inheriting/LIKE, exclusionOpNames will
1923 * be set, so we already allocated above.
1924 */
1925 if (iswithoutoverlaps)
1926 {
1927 if (exclusionOpNames == NIL)
1928 {
1932 }
1933 nextExclOp = NULL;
1934 }
1935
1937 GetUserIdAndSecContext(&save_userid, &save_sec_context);
1938
1939 /*
1940 * process attributeList
1941 */
1942 attn = 0;
1943 foreach(lc, attList)
1944 {
1945 IndexElem *attribute = (IndexElem *) lfirst(lc);
1946 Oid atttype;
1947 Oid attcollation;
1948
1949 /*
1950 * Process the column-or-expression to be indexed.
1951 */
1952 if (attribute->name != NULL)
1953 {
1954 /* Simple index attribute */
1957
1958 Assert(attribute->expr == NULL);
1959 atttuple = SearchSysCacheAttName(relId, attribute->name);
1961 {
1962 /* difference in error message spellings is historical */
1963 if (isconstraint)
1964 ereport(ERROR,
1966 errmsg("column \"%s\" named in key does not exist",
1967 attribute->name),
1968 parser_errposition(pstate, attribute->location)));
1969 else
1970 ereport(ERROR,
1972 errmsg("column \"%s\" does not exist",
1973 attribute->name),
1974 parser_errposition(pstate, attribute->location)));
1975 }
1977 indexInfo->ii_IndexAttrNumbers[attn] = attform->attnum;
1978 atttype = attform->atttypid;
1979 attcollation = attform->attcollation;
1981 }
1982 else
1983 {
1984 /* Index expression */
1985 Node *expr = attribute->expr;
1986
1987 Assert(expr != NULL);
1988
1989 if (attn >= nkeycols)
1990 ereport(ERROR,
1992 errmsg("expressions are not supported in included columns"),
1993 parser_errposition(pstate, attribute->location)));
1994 atttype = exprType(expr);
1995 attcollation = exprCollation(expr);
1996
1997 /*
1998 * Strip any top-level COLLATE clause. This ensures that we treat
1999 * "x COLLATE y" and "(x COLLATE y)" alike.
2000 */
2001 while (IsA(expr, CollateExpr))
2002 expr = (Node *) ((CollateExpr *) expr)->arg;
2003
2004 if (IsA(expr, Var) &&
2005 ((Var *) expr)->varattno != InvalidAttrNumber)
2006 {
2007 /*
2008 * User wrote "(column)" or "(column COLLATE something)".
2009 * Treat it like simple attribute anyway.
2010 */
2011 indexInfo->ii_IndexAttrNumbers[attn] = ((Var *) expr)->varattno;
2012 }
2013 else
2014 {
2015 indexInfo->ii_IndexAttrNumbers[attn] = 0; /* marks expression */
2016 indexInfo->ii_Expressions = lappend(indexInfo->ii_Expressions,
2017 expr);
2018
2019 /*
2020 * transformExpr() should have already rejected subqueries,
2021 * aggregates, and window functions, based on the EXPR_KIND_
2022 * for an index expression.
2023 */
2024
2025 /*
2026 * An expression using mutable functions is probably wrong,
2027 * since if you aren't going to get the same result for the
2028 * same data every time, it's not clear what the index entries
2029 * mean at all.
2030 */
2032 ereport(ERROR,
2034 errmsg("functions in index expression must be marked IMMUTABLE"),
2035 parser_errposition(pstate, attribute->location)));
2036 }
2037 }
2038
2039 typeOids[attn] = atttype;
2040
2041 /*
2042 * Included columns have no collation, no opclass and no ordering
2043 * options.
2044 */
2045 if (attn >= nkeycols)
2046 {
2047 if (attribute->collation)
2048 ereport(ERROR,
2050 errmsg("including column does not support a collation"),
2051 parser_errposition(pstate, attribute->location)));
2052 if (attribute->opclass)
2053 ereport(ERROR,
2055 errmsg("including column does not support an operator class"),
2056 parser_errposition(pstate, attribute->location)));
2057 if (attribute->ordering != SORTBY_DEFAULT)
2058 ereport(ERROR,
2060 errmsg("including column does not support ASC/DESC options"),
2061 parser_errposition(pstate, attribute->location)));
2062 if (attribute->nulls_ordering != SORTBY_NULLS_DEFAULT)
2063 ereport(ERROR,
2065 errmsg("including column does not support NULLS FIRST/LAST options"),
2066 parser_errposition(pstate, attribute->location)));
2067
2069 opclassOptions[attn] = (Datum) 0;
2070 colOptions[attn] = 0;
2072 attn++;
2073
2074 continue;
2075 }
2076
2077 /*
2078 * Apply collation override if any. Use of ddl_userid is necessary
2079 * due to ACL checks therein, and it's safe because collations don't
2080 * contain opaque expressions (or non-opaque expressions).
2081 */
2082 if (attribute->collation)
2083 {
2085 {
2088 }
2089 attcollation = get_collation_oid(attribute->collation, false);
2091 {
2092 SetUserIdAndSecContext(save_userid, save_sec_context);
2095 }
2096 }
2097
2098 /*
2099 * Check we have a collation iff it's a collatable type. The only
2100 * expected failures here are (1) COLLATE applied to a noncollatable
2101 * type, or (2) index expression had an unresolved collation. But we
2102 * might as well code this to be a complete consistency check.
2103 */
2104 if (type_is_collatable(atttype))
2105 {
2106 if (!OidIsValid(attcollation))
2107 ereport(ERROR,
2109 errmsg("could not determine which collation to use for index expression"),
2110 errhint("Use the COLLATE clause to set the collation explicitly."),
2111 parser_errposition(pstate, attribute->location)));
2112 }
2113 else
2114 {
2115 if (OidIsValid(attcollation))
2116 ereport(ERROR,
2118 errmsg("collations are not supported by type %s",
2119 format_type_be(atttype)),
2120 parser_errposition(pstate, attribute->location)));
2121 }
2122
2123 collationOids[attn] = attcollation;
2124
2125 /*
2126 * Identify the opclass to use. Use of ddl_userid is necessary due to
2127 * ACL checks therein. This is safe despite opclasses containing
2128 * opaque expressions (specifically, functions), because only
2129 * superusers can define opclasses.
2130 */
2132 {
2135 }
2136 opclassOids[attn] = ResolveOpClass(attribute->opclass,
2137 atttype,
2141 {
2142 SetUserIdAndSecContext(save_userid, save_sec_context);
2145 }
2146
2147 /*
2148 * Identify the exclusion operator, if any.
2149 */
2150 if (nextExclOp)
2151 {
2153 Oid opid;
2154 Oid opfamily;
2155 int strat;
2156
2157 /*
2158 * Find the operator --- it must accept the column datatype
2159 * without runtime coercion (but binary compatibility is OK).
2160 * Operators contain opaque expressions (specifically, functions).
2161 * compatible_oper_opid() boils down to oper() and
2162 * IsBinaryCoercible(). PostgreSQL would have security problems
2163 * elsewhere if oper() started calling opaque expressions.
2164 */
2166 {
2169 }
2170 opid = compatible_oper_opid(opname, atttype, atttype, false);
2172 {
2173 SetUserIdAndSecContext(save_userid, save_sec_context);
2176 }
2177
2178 /*
2179 * Only allow commutative operators to be used in exclusion
2180 * constraints. If X conflicts with Y, but Y does not conflict
2181 * with X, bad things will happen.
2182 */
2183 if (get_commutator(opid) != opid)
2184 ereport(ERROR,
2186 errmsg("operator %s is not commutative",
2188 errdetail("Only commutative operators can be used in exclusion constraints."),
2189 parser_errposition(pstate, attribute->location)));
2190
2191 /*
2192 * Operator must be a member of the right opfamily, too
2193 */
2194 opfamily = get_opclass_family(opclassOids[attn]);
2195 strat = get_op_opfamily_strategy(opid, opfamily);
2196 if (strat == 0)
2197 ereport(ERROR,
2199 errmsg("operator %s is not a member of operator family \"%s\"",
2201 get_opfamily_name(opfamily, false)),
2202 errdetail("The exclusion operator must be related to the index operator class for the constraint."),
2203 parser_errposition(pstate, attribute->location)));
2204
2205 indexInfo->ii_ExclusionOps[attn] = opid;
2206 indexInfo->ii_ExclusionProcs[attn] = get_opcode(opid);
2207 indexInfo->ii_ExclusionStrats[attn] = strat;
2209 }
2210 else if (iswithoutoverlaps)
2211 {
2212 CompareType cmptype;
2214 Oid opid;
2215
2216 if (attn == nkeycols - 1)
2217 cmptype = COMPARE_OVERLAP;
2218 else
2219 cmptype = COMPARE_EQ;
2221 indexInfo->ii_ExclusionOps[attn] = opid;
2222 indexInfo->ii_ExclusionProcs[attn] = get_opcode(opid);
2223 indexInfo->ii_ExclusionStrats[attn] = strat;
2224 }
2225
2226 /*
2227 * Set up the per-column options (indoption field). For now, this is
2228 * zero for any un-ordered index, while ordered indexes have DESC and
2229 * NULLS FIRST/LAST options.
2230 */
2231 colOptions[attn] = 0;
2232 if (amcanorder)
2233 {
2234 /* default ordering is ASC */
2235 if (attribute->ordering == SORTBY_DESC)
2237 /* default null ordering is LAST for ASC, FIRST for DESC */
2238 if (attribute->nulls_ordering == SORTBY_NULLS_DEFAULT)
2239 {
2240 if (attribute->ordering == SORTBY_DESC)
2242 }
2243 else if (attribute->nulls_ordering == SORTBY_NULLS_FIRST)
2245 }
2246 else
2247 {
2248 /* index AM does not support ordering */
2249 if (attribute->ordering != SORTBY_DEFAULT)
2250 ereport(ERROR,
2252 errmsg("access method \"%s\" does not support ASC/DESC options",
2254 parser_errposition(pstate, attribute->location)));
2255 if (attribute->nulls_ordering != SORTBY_NULLS_DEFAULT)
2256 ereport(ERROR,
2258 errmsg("access method \"%s\" does not support NULLS FIRST/LAST options",
2260 parser_errposition(pstate, attribute->location)));
2261 }
2262
2263 /* Set up the per-column opclass options (attoptions field). */
2264 if (attribute->opclassopts)
2265 {
2266 Assert(attn < nkeycols);
2267
2269 transformRelOptions((Datum) 0, attribute->opclassopts,
2270 NULL, NULL, false, false);
2271 }
2272 else
2273 opclassOptions[attn] = (Datum) 0;
2274
2275 attn++;
2276 }
2277}
#define InvalidAttrNumber
Definition attnum.h:23
#define OidIsValid(objectId)
Definition c.h:858
CompareType
Definition cmptype.h:32
@ COMPARE_OVERLAP
Definition cmptype.h:40
@ COMPARE_EQ
Definition cmptype.h:36
Datum arg
Definition elog.c:1322
int errhint(const char *fmt,...) pg_attribute_printf(1
int errdetail(const char *fmt,...) pg_attribute_printf(1
char * format_type_be(Oid type_oid)
int NewGUCNestLevel(void)
Definition guc.c:2142
void RestrictSearchPath(void)
Definition guc.c:2153
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition guc.c:2169
Oid ResolveOpClass(const List *opclass, Oid attrType, const char *accessMethodName, Oid accessMethodId)
Definition indexcmds.c:2286
void GetOperatorFromCompareType(Oid opclass, Oid rhstype, CompareType cmptype, Oid *opid, StrategyNumber *strat)
Definition indexcmds.c:2473
Oid get_opclass_family(Oid opclass)
Definition lsyscache.c:1362
RegProcedure get_opcode(Oid opno)
Definition lsyscache.c:1505
int get_op_opfamily_strategy(Oid opno, Oid opfamily)
Definition lsyscache.c:87
char * get_opfamily_name(Oid opfid, bool missing_ok)
Definition lsyscache.c:1473
bool type_is_collatable(Oid typid)
Definition lsyscache.c:3303
Oid get_commutator(Oid opno)
Definition lsyscache.c:1729
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition miscinit.c:613
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition miscinit.c:620
Oid get_collation_oid(List *collname, bool missing_ok)
Definition namespace.c:4043
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
Oid exprCollation(const Node *expr)
Definition nodeFuncs.c:826
#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:492
@ 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
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:375
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:828
SortByDir ordering
Definition parsenodes.h:833
List * opclassopts
Definition parsenodes.h:832
ParseLoc location
Definition parsenodes.h:835
SortByNulls nulls_ordering
Definition parsenodes.h:834
List * opclass
Definition parsenodes.h:831
char * name
Definition parsenodes.h:827
List * collation
Definition parsenodes.h:830
uint16 * ii_ExclusionStrats
Definition execnodes.h:204
int ii_NumIndexKeyAttrs
Definition execnodes.h:181
List * ii_Expressions
Definition execnodes.h:190
Oid * ii_ExclusionProcs
Definition execnodes.h:202
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition execnodes.h:187
Definition nodes.h:135
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition syscache.c:476

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,
const 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 545 of file indexcmds.c.

557{
558 bool concurrent;
559 char *indexRelationName;
560 char *accessMethodName;
561 Oid *typeIds;
571 Relation rel;
572 HeapTuple tuple;
575 bool amcanorder;
576 bool amissummarizing;
577 amoptions_function amoptions;
578 bool exclusion;
579 bool partitioned;
580 bool safe_index;
581 Datum reloptions;
583 IndexInfo *indexInfo;
584 uint16 flags;
589 ObjectAddress address;
590 LockRelId heaprelid;
592 LOCKMODE lockmode;
593 Snapshot snapshot;
597
599
601
602 /*
603 * Some callers need us to run with an empty default_tablespace; this is a
604 * necessary hack to be able to reproduce catalog state accurately when
605 * recreating indexes after table-rewriting ALTER TABLE.
606 */
607 if (stmt->reset_default_tblspc)
608 (void) set_config_option("default_tablespace", "",
610 GUC_ACTION_SAVE, true, 0, false);
611
612 /*
613 * Force non-concurrent build on temporary relations, even if CONCURRENTLY
614 * was requested. Other backends can't access a temporary relation, so
615 * there's no harm in grabbing a stronger lock, and a non-concurrent DROP
616 * is more efficient. Do this before any use of the concurrent option is
617 * done.
618 */
620 concurrent = true;
621 else
622 concurrent = false;
623
624 /*
625 * Start progress report. If we're building a partition, this was already
626 * done.
627 */
629 {
632 concurrent ?
635 }
636
637 /*
638 * No index OID to report yet
639 */
641 InvalidOid);
642
643 /*
644 * count key attributes in index
645 */
646 numberOfKeyAttributes = list_length(stmt->indexParams);
647
648 /*
649 * Calculate the new list of index columns including both key columns and
650 * INCLUDE columns. Later we can determine which of these are key
651 * columns, and which are just part of the INCLUDE list by checking the
652 * list position. A list item in a position less than ii_NumIndexKeyAttrs
653 * is part of the key columns, and anything equal to and over is part of
654 * the INCLUDE columns.
655 */
656 allIndexParams = list_concat_copy(stmt->indexParams,
657 stmt->indexIncludingParams);
659
660 if (numberOfKeyAttributes <= 0)
663 errmsg("must specify at least one column")));
667 errmsg("cannot use more than %d columns in an index",
669
670 /*
671 * Only SELECT ... FOR UPDATE/SHARE are allowed while doing a standard
672 * index build; but for concurrent builds we allow INSERT/UPDATE/DELETE
673 * (but not VACUUM).
674 *
675 * NB: Caller is responsible for making sure that tableId refers to the
676 * relation on which the index should be built; except in bootstrap mode,
677 * this will typically require the caller to have already locked the
678 * relation. To avoid lock upgrade hazards, that lock should be at least
679 * as strong as the one we take here.
680 *
681 * NB: If the lock strength here ever changes, code that is run by
682 * parallel workers under the control of certain particular ambuild
683 * functions will need to be updated, too.
684 */
685 lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock;
686 rel = table_open(tableId, lockmode);
687
688 /*
689 * Switch to the table owner's userid, so that any index functions are run
690 * as that user. Also lock down security-restricted operations. We
691 * already arranged to make GUC variable changes local to this command.
692 */
694 SetUserIdAndSecContext(rel->rd_rel->relowner,
696
698
699 /*
700 * It has exclusion constraint behavior if it's an EXCLUDE constraint or a
701 * temporal PRIMARY KEY/UNIQUE constraint
702 */
703 exclusion = stmt->excludeOpNames || stmt->iswithoutoverlaps;
704
705 /* Ensure that it makes sense to index this kind of relation */
706 switch (rel->rd_rel->relkind)
707 {
708 case RELKIND_RELATION:
709 case RELKIND_MATVIEW:
711 /* OK */
712 break;
713 default:
716 errmsg("cannot create index on relation \"%s\"",
719 break;
720 }
721
722 /*
723 * Establish behavior for partitioned tables, and verify sanity of
724 * parameters.
725 *
726 * We do not build an actual index in this case; we only create a few
727 * catalog entries. The actual indexes are built by recursing for each
728 * partition.
729 */
731 if (partitioned)
732 {
733 /*
734 * Note: we check 'stmt->concurrent' rather than 'concurrent', so that
735 * the error is thrown also for temporary tables. Seems better to be
736 * consistent, even though we could do it on temporary table because
737 * we're not actually doing it concurrently.
738 */
739 if (stmt->concurrent)
742 errmsg("cannot create index on partitioned table \"%s\" concurrently",
744 }
745
746 /*
747 * Don't try to CREATE INDEX on temp tables of other backends.
748 */
749 if (RELATION_IS_OTHER_TEMP(rel))
752 errmsg("cannot create indexes on temporary tables of other sessions")));
753
754 /*
755 * Unless our caller vouches for having checked this already, insist that
756 * the table not be in use by our own session, either. Otherwise we might
757 * fail to make entries in the new index (for instance, if an INSERT or
758 * UPDATE is in progress and has already made its list of target indexes).
759 */
761 CheckTableNotInUse(rel, "CREATE INDEX");
762
763 /*
764 * Verify we (still) have CREATE rights in the rel's namespace.
765 * (Presumably we did when the rel was created, but maybe not anymore.)
766 * Skip check if caller doesn't want it. Also skip check if
767 * bootstrapping, since permissions machinery may not be working yet.
768 */
770 {
772
774 ACL_CREATE);
775 if (aclresult != ACLCHECK_OK)
778 }
779
780 /*
781 * Select tablespace to use. If not specified, use default tablespace
782 * (which may in turn default to database's default).
783 */
784 if (stmt->tableSpace)
785 {
786 tablespaceId = get_tablespace_oid(stmt->tableSpace, false);
790 errmsg("cannot specify default tablespace for partitioned relations")));
791 }
792 else
793 {
794 tablespaceId = GetDefaultTablespace(rel->rd_rel->relpersistence,
796 /* note InvalidOid is OK in this case */
797 }
798
799 /* Check tablespace permissions */
800 if (check_rights &&
802 {
804
806 ACL_CREATE);
807 if (aclresult != ACLCHECK_OK)
810 }
811
812 /*
813 * Force shared indexes into the pg_global tablespace. This is a bit of a
814 * hack but seems simpler than marking them in the BKI commands. On the
815 * other hand, if it's not shared, don't allow it to be placed there.
816 */
817 if (rel->rd_rel->relisshared)
822 errmsg("only shared relations can be placed in pg_global tablespace")));
823
824 /*
825 * Choose the index column names.
826 */
828
829 /*
830 * Select name for index if caller didn't specify
831 */
832 indexRelationName = stmt->idxname;
833 if (indexRelationName == NULL)
837 stmt->excludeOpNames,
838 stmt->primary,
839 stmt->isconstraint);
840
841 /*
842 * look up the access method, verify it can handle the requested features
843 */
844 accessMethodName = stmt->accessMethod;
846 if (!HeapTupleIsValid(tuple))
847 {
848 /*
849 * Hack to provide more-or-less-transparent updating of old RTREE
850 * indexes to GiST: if RTREE is requested and not found, use GIST.
851 */
852 if (strcmp(accessMethodName, "rtree") == 0)
853 {
855 (errmsg("substituting access method \"gist\" for obsolete method \"rtree\"")));
856 accessMethodName = "gist";
858 }
859
860 if (!HeapTupleIsValid(tuple))
863 errmsg("access method \"%s\" does not exist",
865 }
869
872
873 if (stmt->unique && !stmt->iswithoutoverlaps && !amRoutine->amcanunique)
876 errmsg("access method \"%s\" does not support unique indexes",
878 if (stmt->indexIncludingParams != NIL && !amRoutine->amcaninclude)
881 errmsg("access method \"%s\" does not support included columns",
883 if (numberOfKeyAttributes > 1 && !amRoutine->amcanmulticol)
886 errmsg("access method \"%s\" does not support multicolumn indexes",
888 if (exclusion && amRoutine->amgettuple == NULL)
891 errmsg("access method \"%s\" does not support exclusion constraints",
893 if (stmt->iswithoutoverlaps && strcmp(accessMethodName, "gist") != 0)
896 errmsg("access method \"%s\" does not support WITHOUT OVERLAPS constraints",
898
899 amcanorder = amRoutine->amcanorder;
900 amoptions = amRoutine->amoptions;
901 amissummarizing = amRoutine->amsummarizing;
902
903 ReleaseSysCache(tuple);
904
905 /*
906 * Validate predicate, if given
907 */
908 if (stmt->whereClause)
909 CheckPredicate((Expr *) stmt->whereClause);
910
911 /*
912 * Parse AM-specific options, convert to text array form, validate.
913 */
914 reloptions = transformRelOptions((Datum) 0, stmt->options,
915 NULL, NULL, false, false);
916
917 (void) index_reloptions(amoptions, reloptions, true);
918
919 /*
920 * Prepare arguments for index_create, primarily an IndexInfo structure.
921 * Note that predicates must be in implicit-AND format. In a concurrent
922 * build, mark it not-ready-for-inserts.
923 */
927 NIL, /* expressions, NIL for now */
928 make_ands_implicit((Expr *) stmt->whereClause),
929 stmt->unique,
930 stmt->nulls_not_distinct,
931 !concurrent,
932 concurrent,
934 stmt->iswithoutoverlaps);
935
941 ComputeIndexAttrs(pstate,
942 indexInfo,
945 stmt->excludeOpNames, tableId,
947 amcanorder, stmt->isconstraint, stmt->iswithoutoverlaps,
950
951 /*
952 * Extra checks when creating a PRIMARY KEY index.
953 */
954 if (stmt->primary)
956
957 /*
958 * If this table is partitioned and we're creating a unique index, primary
959 * key, or exclusion constraint, make sure that the partition key is a
960 * subset of the index's columns. Otherwise it would be possible to
961 * violate uniqueness by putting values that ought to be unique in
962 * different partitions.
963 *
964 * We could lift this limitation if we had global indexes, but those have
965 * their own problems, so this is a useful feature combination.
966 */
967 if (partitioned && (stmt->unique || exclusion))
968 {
970 const char *constraint_type;
971 int i;
972
973 if (stmt->primary)
974 constraint_type = "PRIMARY KEY";
975 else if (stmt->unique)
976 constraint_type = "UNIQUE";
977 else if (stmt->excludeOpNames)
978 constraint_type = "EXCLUDE";
979 else
980 {
981 elog(ERROR, "unknown constraint type");
982 constraint_type = NULL; /* keep compiler quiet */
983 }
984
985 /*
986 * Verify that all the columns in the partition key appear in the
987 * unique key definition, with the same notion of equality.
988 */
989 for (i = 0; i < key->partnatts; i++)
990 {
991 bool found = false;
992 int eq_strategy;
994 int j;
995
996 /*
997 * Identify the equality operator associated with this partkey
998 * column. For list and range partitioning, partkeys use btree
999 * operator classes; hash partitioning uses hash operator classes.
1000 * (Keep this in sync with ComputePartitionAttrs!)
1001 */
1002 if (key->strategy == PARTITION_STRATEGY_HASH)
1004 else
1006
1007 ptkey_eqop = get_opfamily_member(key->partopfamily[i],
1008 key->partopcintype[i],
1009 key->partopcintype[i],
1010 eq_strategy);
1011 if (!OidIsValid(ptkey_eqop))
1012 elog(ERROR, "missing operator %d(%u,%u) in partition opfamily %u",
1013 eq_strategy, key->partopcintype[i], key->partopcintype[i],
1014 key->partopfamily[i]);
1015
1016 /*
1017 * It may be possible to support UNIQUE constraints when partition
1018 * keys are expressions, but is it worth it? Give up for now.
1019 */
1020 if (key->partattrs[i] == 0)
1021 ereport(ERROR,
1023 errmsg("unsupported %s constraint with partition key definition",
1025 errdetail("%s constraints cannot be used when partition keys include expressions.",
1026 constraint_type)));
1027
1028 /* Search the index column(s) for a match */
1029 for (j = 0; j < indexInfo->ii_NumIndexKeyAttrs; j++)
1030 {
1031 if (key->partattrs[i] == indexInfo->ii_IndexAttrNumbers[j])
1032 {
1033 /*
1034 * Matched the column, now what about the collation and
1035 * equality op?
1036 */
1039
1040 if (key->partcollation[i] != collationIds[j])
1041 continue;
1042
1044 &idx_opfamily,
1045 &idx_opcintype))
1046 {
1048
1049 if (stmt->unique && !stmt->iswithoutoverlaps)
1053 COMPARE_EQ);
1054 else if (exclusion)
1055 idx_eqop = indexInfo->ii_ExclusionOps[j];
1056
1057 if (!idx_eqop)
1058 ereport(ERROR,
1060 errmsg("could not identify an equality operator for type %s", format_type_be(idx_opcintype)),
1061 errdetail("There is no suitable operator in operator family \"%s\" for access method \"%s\".",
1063
1064 if (ptkey_eqop == idx_eqop)
1065 {
1066 found = true;
1067 break;
1068 }
1069 else if (exclusion)
1070 {
1071 /*
1072 * We found a match, but it's not an equality
1073 * operator. Instead of failing below with an
1074 * error message about a missing column, fail now
1075 * and explain that the operator is wrong.
1076 */
1077 Form_pg_attribute att = TupleDescAttr(RelationGetDescr(rel), key->partattrs[i] - 1);
1078
1079 ereport(ERROR,
1081 errmsg("cannot match partition key to index on column \"%s\" using non-equal operator \"%s\"",
1082 NameStr(att->attname),
1083 get_opname(indexInfo->ii_ExclusionOps[j]))));
1084 }
1085 }
1086 }
1087 }
1088
1089 if (!found)
1090 {
1092
1094 key->partattrs[i] - 1);
1095 ereport(ERROR,
1097 /* translator: %s is UNIQUE, PRIMARY KEY, etc */
1098 errmsg("%s constraint on partitioned table must include all partitioning columns",
1100 /* translator: first %s is UNIQUE, PRIMARY KEY, etc */
1101 errdetail("%s constraint on table \"%s\" lacks column \"%s\" which is part of the partition key.",
1103 NameStr(att->attname))));
1104 }
1105 }
1106 }
1107
1108
1109 /*
1110 * We disallow indexes on system columns. They would not necessarily get
1111 * updated correctly, and they don't seem useful anyway.
1112 *
1113 * Also disallow virtual generated columns in indexes (use expression
1114 * index instead).
1115 */
1116 for (int i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
1117 {
1118 AttrNumber attno = indexInfo->ii_IndexAttrNumbers[i];
1119
1120 if (attno < 0)
1121 ereport(ERROR,
1123 errmsg("index creation on system columns is not supported")));
1124
1125
1126 if (attno > 0 &&
1127 TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
1128 ereport(ERROR,
1130 stmt->primary ?
1131 errmsg("primary keys on virtual generated columns are not supported") :
1132 stmt->isconstraint ?
1133 errmsg("unique constraints on virtual generated columns are not supported") :
1134 errmsg("indexes on virtual generated columns are not supported"));
1135 }
1136
1137 /*
1138 * Also check for system and generated columns used in expressions or
1139 * predicates.
1140 */
1141 if (indexInfo->ii_Expressions || indexInfo->ii_Predicate)
1142 {
1144 int j;
1145
1146 pull_varattnos((Node *) indexInfo->ii_Expressions, 1, &indexattrs);
1147 pull_varattnos((Node *) indexInfo->ii_Predicate, 1, &indexattrs);
1148
1149 for (int i = FirstLowInvalidHeapAttributeNumber + 1; i < 0; i++)
1150 {
1152 indexattrs))
1153 ereport(ERROR,
1155 errmsg("index creation on system columns is not supported")));
1156 }
1157
1158 /*
1159 * XXX Virtual generated columns in index expressions or predicates
1160 * could be supported, but it needs support in
1161 * RelationGetIndexExpressions() and RelationGetIndexPredicate().
1162 */
1163 j = -1;
1164 while ((j = bms_next_member(indexattrs, j)) >= 0)
1165 {
1167
1168 if (attno > 0 &&
1169 TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
1170 ereport(ERROR,
1172 stmt->isconstraint ?
1173 errmsg("unique constraints on virtual generated columns are not supported") :
1174 errmsg("indexes on virtual generated columns are not supported")));
1175 }
1176 }
1177
1178 /* Is index safe for others to ignore? See set_indexsafe_procflags() */
1179 safe_index = indexInfo->ii_Expressions == NIL &&
1180 indexInfo->ii_Predicate == NIL;
1181
1182 /*
1183 * Report index creation if appropriate (delay this till after most of the
1184 * error checks)
1185 */
1186 if (stmt->isconstraint && !quiet)
1187 {
1188 const char *constraint_type;
1189
1190 if (stmt->primary)
1191 constraint_type = "PRIMARY KEY";
1192 else if (stmt->unique)
1193 constraint_type = "UNIQUE";
1194 else if (stmt->excludeOpNames)
1195 constraint_type = "EXCLUDE";
1196 else
1197 {
1198 elog(ERROR, "unknown constraint type");
1199 constraint_type = NULL; /* keep compiler quiet */
1200 }
1201
1203 (errmsg_internal("%s %s will create implicit index \"%s\" for table \"%s\"",
1204 is_alter_table ? "ALTER TABLE / ADD" : "CREATE TABLE /",
1207 }
1208
1209 /*
1210 * A valid stmt->oldNumber implies that we already have a built form of
1211 * the index. The caller should also decline any index build.
1212 */
1213 Assert(!RelFileNumberIsValid(stmt->oldNumber) || (skip_build && !concurrent));
1214
1215 /*
1216 * Make the catalog entries for the index, including constraints. This
1217 * step also actually builds the index, except if caller requested not to
1218 * or in concurrent mode, in which case it'll be done later, or doing a
1219 * partitioned index (because those don't have storage).
1220 */
1221 flags = constr_flags = 0;
1222 if (stmt->isconstraint)
1224 if (skip_build || concurrent || partitioned)
1225 flags |= INDEX_CREATE_SKIP_BUILD;
1226 if (stmt->if_not_exists)
1228 if (concurrent)
1229 flags |= INDEX_CREATE_CONCURRENT;
1230 if (partitioned)
1231 flags |= INDEX_CREATE_PARTITIONED;
1232 if (stmt->primary)
1233 flags |= INDEX_CREATE_IS_PRIMARY;
1234
1235 /*
1236 * If the table is partitioned, and recursion was declined but partitions
1237 * exist, mark the index as invalid.
1238 */
1239 if (partitioned && stmt->relation && !stmt->relation->inh)
1240 {
1242
1243 if (pd->nparts != 0)
1244 flags |= INDEX_CREATE_INVALID;
1245 }
1246
1247 if (stmt->deferrable)
1249 if (stmt->initdeferred)
1251 if (stmt->iswithoutoverlaps)
1253
1257 stmt->oldNumber, indexInfo, indexColNames,
1260 coloptions, NULL, reloptions,
1261 flags, constr_flags,
1264
1266
1268 {
1269 /*
1270 * Roll back any GUC changes executed by index functions. Also revert
1271 * to original default_tablespace if we changed it above.
1272 */
1274
1275 /* Restore userid and security context */
1277
1278 table_close(rel, NoLock);
1279
1280 /* If this is the top-level index, we're done */
1283
1284 return address;
1285 }
1286
1287 /*
1288 * Roll back any GUC changes executed by index functions, and keep
1289 * subsequent changes local to this command. This is essential if some
1290 * index function changed a behavior-affecting GUC, e.g. search_path.
1291 */
1295
1296 /* Add any requested comment */
1297 if (stmt->idxcomment != NULL)
1299 stmt->idxcomment);
1300
1301 if (partitioned)
1302 {
1303 PartitionDesc partdesc;
1304
1305 /*
1306 * Unless caller specified to skip this step (via ONLY), process each
1307 * partition to make sure they all contain a corresponding index.
1308 *
1309 * If we're called internally (no stmt->relation), recurse always.
1310 */
1311 partdesc = RelationGetPartitionDesc(rel, true);
1312 if ((!stmt->relation || stmt->relation->inh) && partdesc->nparts > 0)
1313 {
1314 int nparts = partdesc->nparts;
1315 Oid *part_oids = palloc_array(Oid, nparts);
1316 bool invalidate_parent = false;
1319
1320 /*
1321 * Report the total number of partitions at the start of the
1322 * command; don't update it when being called recursively.
1323 */
1325 {
1326 /*
1327 * When called by ProcessUtilitySlow, the number of partitions
1328 * is passed in as an optimization; but other callers pass -1
1329 * since they don't have the value handy. This should count
1330 * partitions the same way, ie one less than the number of
1331 * relations find_all_inheritors reports.
1332 *
1333 * We assume we needn't ask find_all_inheritors to take locks,
1334 * because that should have happened already for all callers.
1335 * Even if it did not, this is safe as long as we don't try to
1336 * touch the partitions here; the worst consequence would be a
1337 * bogus progress-reporting total.
1338 */
1339 if (total_parts < 0)
1340 {
1342
1343 total_parts = list_length(children) - 1;
1344 list_free(children);
1345 }
1346
1348 total_parts);
1349 }
1350
1351 /* Make a local copy of partdesc->oids[], just for safety */
1352 memcpy(part_oids, partdesc->oids, sizeof(Oid) * nparts);
1353
1354 /*
1355 * We'll need an IndexInfo describing the parent index. The one
1356 * built above is almost good enough, but not quite, because (for
1357 * example) its predicate expression if any hasn't been through
1358 * expression preprocessing. The most reliable way to get an
1359 * IndexInfo that will match those for child indexes is to build
1360 * it the same way, using BuildIndexInfo().
1361 */
1363 indexInfo = BuildIndexInfo(parentIndex);
1364
1366
1367 /*
1368 * For each partition, scan all existing indexes; if one matches
1369 * our index definition and is not already attached to some other
1370 * parent index, attach it to the one we just created.
1371 *
1372 * If none matches, build a new index by calling ourselves
1373 * recursively with the same options (except for the index name).
1374 */
1375 for (int i = 0; i < nparts; i++)
1376 {
1382 List *childidxs;
1383 ListCell *cell;
1384 AttrMap *attmap;
1385 bool found = false;
1386
1387 childrel = table_open(childRelid, lockmode);
1388
1391 SetUserIdAndSecContext(childrel->rd_rel->relowner,
1395
1396 /*
1397 * Don't try to create indexes on foreign tables, though. Skip
1398 * those if a regular index, or fail if trying to create a
1399 * constraint index.
1400 */
1401 if (childrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1402 {
1403 if (stmt->unique || stmt->primary)
1404 ereport(ERROR,
1406 errmsg("cannot create unique index on partitioned table \"%s\"",
1408 errdetail("Table \"%s\" contains partitions that are foreign tables.",
1410
1414 table_close(childrel, lockmode);
1415 continue;
1416 }
1417
1419 attmap =
1421 parentDesc,
1422 false);
1423
1424 foreach(cell, childidxs)
1425 {
1426 Oid cldidxid = lfirst_oid(cell);
1429
1430 /* this index is already partition of another one */
1432 continue;
1433
1434 cldidx = index_open(cldidxid, lockmode);
1436 if (CompareIndexInfo(cldIdxInfo, indexInfo,
1437 cldidx->rd_indcollation,
1438 parentIndex->rd_indcollation,
1439 cldidx->rd_opfamily,
1440 parentIndex->rd_opfamily,
1441 attmap))
1442 {
1444
1445 /*
1446 * Found a match.
1447 *
1448 * If this index is being created in the parent
1449 * because of a constraint, then the child needs to
1450 * have a constraint also, so look for one. If there
1451 * is no such constraint, this index is no good, so
1452 * keep looking.
1453 */
1455 {
1456 cldConstrOid =
1458 cldidxid);
1459 if (cldConstrOid == InvalidOid)
1460 {
1461 index_close(cldidx, lockmode);
1462 continue;
1463 }
1464 }
1465
1466 /* Attach index to parent and we're done. */
1471 childRelid);
1472
1473 if (!cldidx->rd_index->indisvalid)
1474 invalidate_parent = true;
1475
1476 found = true;
1477
1478 /*
1479 * Report this partition as processed. Note that if
1480 * the partition has children itself, we'd ideally
1481 * count the children and update the progress report
1482 * for all of them; but that seems unduly expensive.
1483 * Instead, the progress report will act like all such
1484 * indirect children were processed in zero time at
1485 * the end of the command.
1486 */
1488
1489 /* keep lock till commit */
1491 break;
1492 }
1493
1494 index_close(cldidx, lockmode);
1495 }
1496
1502
1503 /*
1504 * If no matching index was found, create our own.
1505 */
1506 if (!found)
1507 {
1510
1511 /*
1512 * Build an IndexStmt describing the desired child index
1513 * in the same way that we do during ATTACH PARTITION.
1514 * Notably, we rely on generateClonedIndexStmt to produce
1515 * a search-path-independent representation, which the
1516 * original IndexStmt might not be.
1517 */
1520 attmap,
1521 NULL);
1522
1523 /*
1524 * Recurse as the starting user ID. Callee will use that
1525 * for permission checks, then switch again.
1526 */
1530 childAddr =
1531 DefineIndex(NULL, /* original pstate not applicable */
1533 InvalidOid, /* no predefined OID */
1534 indexRelationId, /* this is our child */
1536 -1,
1539 skip_build, quiet);
1542
1543 /*
1544 * Check if the index just created is valid or not, as it
1545 * could be possible that it has been switched as invalid
1546 * when recursing across multiple partition levels.
1547 */
1548 if (!get_index_isvalid(childAddr.objectId))
1549 invalidate_parent = true;
1550 }
1551
1553 }
1554
1555 index_close(parentIndex, lockmode);
1556
1557 /*
1558 * The pg_index row we inserted for this index was marked
1559 * indisvalid=true. But if we attached an existing index that is
1560 * invalid, this is incorrect, so update our row to invalid too.
1561 */
1563 {
1565 HeapTuple tup,
1566 newtup;
1567
1570 if (!HeapTupleIsValid(tup))
1571 elog(ERROR, "cache lookup failed for index %u",
1579
1580 /*
1581 * CCI here to make this update visible, in case this recurses
1582 * across multiple partition levels.
1583 */
1585 }
1586 }
1587
1588 /*
1589 * Indexes on partitioned tables are not themselves built, so we're
1590 * done here.
1591 */
1594 table_close(rel, NoLock);
1597 else
1598 {
1599 /* Update progress for an intermediate partitioned index itself */
1601 }
1602
1603 return address;
1604 }
1605
1608
1609 if (!concurrent)
1610 {
1611 /* Close the heap and we're done, in the non-concurrent case */
1612 table_close(rel, NoLock);
1613
1614 /*
1615 * If this is the top-level index, the command is done overall;
1616 * otherwise, increment progress to report one child index is done.
1617 */
1620 else
1622
1623 return address;
1624 }
1625
1626 /* save lockrelid and locktag for below, then close rel */
1627 heaprelid = rel->rd_lockInfo.lockRelId;
1628 SET_LOCKTAG_RELATION(heaplocktag, heaprelid.dbId, heaprelid.relId);
1629 table_close(rel, NoLock);
1630
1631 /*
1632 * For a concurrent build, it's important to make the catalog entries
1633 * visible to other transactions before we start to build the index. That
1634 * will prevent them from making incompatible HOT updates. The new index
1635 * will be marked not indisready and not indisvalid, so that no one else
1636 * tries to either insert into it or use it for queries.
1637 *
1638 * We must commit our current transaction so that the index becomes
1639 * visible; then start another. Note that all the data structures we just
1640 * built are lost in the commit. The only data we keep past here are the
1641 * relation IDs.
1642 *
1643 * Before committing, get a session-level lock on the table, to ensure
1644 * that neither it nor the index can be dropped before we finish. This
1645 * cannot block, even if someone else is waiting for access, because we
1646 * already have the same lock within our transaction.
1647 *
1648 * Note: we don't currently bother with a session lock on the index,
1649 * because there are no operations that could change its state while we
1650 * hold lock on the parent table. This might need to change later.
1651 */
1653
1657
1658 /* Tell concurrent index builds to ignore us, if index qualifies */
1659 if (safe_index)
1661
1662 /*
1663 * The index is now visible, so we can report the OID. While on it,
1664 * include the report for the beginning of phase 2.
1665 */
1666 {
1667 const int progress_cols[] = {
1670 };
1671 const int64 progress_vals[] = {
1674 };
1675
1677 }
1678
1679 /*
1680 * Phase 2 of concurrent index build (see comments for validate_index()
1681 * for an overview of how this works)
1682 *
1683 * Now we must wait until no running transaction could have the table open
1684 * with the old list of indexes. Use ShareLock to consider running
1685 * transactions that hold locks that permit writing to the table. Note we
1686 * do not need to worry about xacts that open the table for writing after
1687 * this point; they will see the new index when they open it.
1688 *
1689 * Note: the reason we use actual lock acquisition here, rather than just
1690 * checking the ProcArray and sleeping, is that deadlock is possible if
1691 * one of the transactions in question is blocked trying to acquire an
1692 * exclusive lock on our table. The lock code will detect deadlock and
1693 * error out properly.
1694 */
1696
1697 /*
1698 * At this moment we are sure that there are no transactions with the
1699 * table open for write that don't have this new index in their list of
1700 * indexes. We have waited out all the existing transactions and any new
1701 * transaction will have the new index in its list, but the index is still
1702 * marked as "not-ready-for-inserts". The index is consulted while
1703 * deciding HOT-safety though. This arrangement ensures that no new HOT
1704 * chains can be created where the new tuple and the old tuple in the
1705 * chain have different index keys.
1706 *
1707 * We now take a new snapshot, and build the index using all tuples that
1708 * are visible in this snapshot. We can be sure that any HOT updates to
1709 * these tuples will be compatible with the index, since any updates made
1710 * by transactions that didn't know about the index are now committed or
1711 * rolled back. Thus, each visible tuple is either the end of its
1712 * HOT-chain or the extension of the chain is HOT-safe for this index.
1713 */
1714
1715 /* Set ActiveSnapshot since functions in the indexes may need it */
1717
1718 /* Perform concurrent build of index */
1720
1721 /* we can do away with our snapshot */
1723
1724 /*
1725 * Commit this transaction to make the indisready update visible.
1726 */
1729
1730 /* Tell concurrent index builds to ignore us, if index qualifies */
1731 if (safe_index)
1733
1734 /*
1735 * Phase 3 of concurrent index build
1736 *
1737 * We once again wait until no transaction can have the table open with
1738 * the index marked as read-only for updates.
1739 */
1743
1744 /*
1745 * Now take the "reference snapshot" that will be used by validate_index()
1746 * to filter candidate tuples. Beware! There might still be snapshots in
1747 * use that treat some transaction as in-progress that our reference
1748 * snapshot treats as committed. If such a recently-committed transaction
1749 * deleted tuples in the table, we will not include them in the index; yet
1750 * those transactions which see the deleting one as still-in-progress will
1751 * expect such tuples to be there once we mark the index as valid.
1752 *
1753 * We solve this by waiting for all endangered transactions to exit before
1754 * we mark the index as valid.
1755 *
1756 * We also set ActiveSnapshot to this snap, since functions in indexes may
1757 * need a snapshot.
1758 */
1760 PushActiveSnapshot(snapshot);
1761
1762 /*
1763 * Scan the index and the heap, insert any missing index entries.
1764 */
1766
1767 /*
1768 * Drop the reference snapshot. We must do this before waiting out other
1769 * snapshot holders, else we will deadlock against other processes also
1770 * doing CREATE INDEX CONCURRENTLY, which would see our snapshot as one
1771 * they must wait for. But first, save the snapshot's xmin to use as
1772 * limitXmin for GetCurrentVirtualXIDs().
1773 */
1774 limitXmin = snapshot->xmin;
1775
1777 UnregisterSnapshot(snapshot);
1778
1779 /*
1780 * The snapshot subsystem could still contain registered snapshots that
1781 * are holding back our process's advertised xmin; in particular, if
1782 * default_transaction_isolation = serializable, there is a transaction
1783 * snapshot that is still active. The CatalogSnapshot is likewise a
1784 * hazard. To ensure no deadlocks, we must commit and start yet another
1785 * transaction, and do our wait before any snapshot has been taken in it.
1786 */
1789
1790 /* Tell concurrent index builds to ignore us, if index qualifies */
1791 if (safe_index)
1793
1794 /* We should now definitely not be advertising any xmin. */
1796
1797 /*
1798 * The index is now valid in the sense that it contains all currently
1799 * interesting tuples. But since it might not contain tuples deleted just
1800 * before the reference snap was taken, we have to wait out any
1801 * transactions that might have older snapshots.
1802 */
1803 INJECTION_POINT("define-index-before-set-valid", NULL);
1807
1808 /*
1809 * Updating pg_index might involve TOAST table access, so ensure we have a
1810 * valid snapshot.
1811 */
1813
1814 /*
1815 * Index can now be marked valid -- update its pg_index entry
1816 */
1818
1820
1821 /*
1822 * The pg_index update will cause backends (including this one) to update
1823 * relcache entries for the index itself, but we should also send a
1824 * relcache inval on the parent table to force replanning of cached plans.
1825 * Otherwise existing sessions might fail to use the new index where it
1826 * would be useful. (Note that our earlier commits did not create reasons
1827 * to replan; so relcache flush on the index itself was sufficient.)
1828 */
1830
1831 /*
1832 * Last thing to do is release the session-level lock on the parent table.
1833 */
1835
1837
1838 return address;
1839}
AclResult
Definition acl.h:183
@ ACLCHECK_OK
Definition acl.h:184
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2672
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition aclchk.c:3879
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:1290
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:510
#define NameStr(name)
Definition c.h:835
int64_t int64
Definition c.h:621
uint32 TransactionId
Definition c.h:736
void CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment)
Definition comment.c:153
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
#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:3248
@ 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:686
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1372
#define stmt
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, uint16 flags, uint16 constr_flags, bool allow_system_table_mods, bool is_internal, Oid *constraintId)
Definition index.c:727
void validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
Definition index.c:3351
void index_set_state_flags(Oid indexId, IndexStateFlagsAction action)
Definition index.c:3504
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:2538
IndexInfo * BuildIndexInfo(Relation index)
Definition index.c:2429
void index_check_primary_key(Relation heapRel, const IndexInfo *indexInfo, bool is_alter_table, const IndexStmt *stmt)
Definition index.c:203
void index_concurrently_build(Oid heapRelationId, Oid indexRelationId)
Definition index.c:1486
#define INDEX_CREATE_IS_PRIMARY
Definition index.h:67
#define INDEX_CREATE_IF_NOT_EXISTS
Definition index.h:71
#define INDEX_CREATE_PARTITIONED
Definition index.h:72
#define INDEX_CREATE_INVALID
Definition index.h:73
#define INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS
Definition index.h:102
#define INDEX_CREATE_ADD_CONSTRAINT
Definition index.h:68
#define INDEX_CREATE_SKIP_BUILD
Definition index.h:69
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition index.h:98
@ INDEX_CREATE_SET_VALID
Definition index.h:33
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition index.h:99
#define INDEX_CREATE_CONCURRENT
Definition index.h:70
static void set_indexsafe_procflags(void)
Definition indexcmds.c:4643
void IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
Definition indexcmds.c:4473
void WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
Definition indexcmds.c:436
ObjectAddress DefineIndex(ParseState *pstate, Oid tableId, const 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:545
static void CheckPredicate(Expr *predicate)
Definition indexcmds.c:1854
static List * ChooseIndexColumnNames(const List *indexElems)
Definition indexcmds.c:2791
static char * ChooseIndexName(const char *tabname, Oid namespaceId, const List *colnames, const List *exclusionOpNames, bool primary, bool isconstraint)
Definition indexcmds.c:2702
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
int LOCKMODE
Definition lockdefs.h:26
#define ShareUpdateExclusiveLock
Definition lockdefs.h:39
#define ShareLock
Definition lockdefs.h:40
#define RowExclusiveLock
Definition lockdefs.h:38
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition locktag.h:81
char get_rel_persistence(Oid relid)
Definition lsyscache.c:2298
bool get_index_isvalid(Oid index_oid)
Definition lsyscache.c:3825
Oid get_opfamily_member_for_cmptype(Oid opfamily, Oid lefttype, Oid righttype, CompareType cmptype)
Definition lsyscache.c:199
bool get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
Definition lsyscache.c:1407
char * get_opname(Oid opno)
Definition lsyscache.c:1530
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition lsyscache.c:170
Oid get_opfamily_method(Oid opfid)
Definition lsyscache.c:1456
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3588
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:470
#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:919
@ 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:115
#define PROGRESS_CREATEIDX_PHASE_WAIT_1
Definition progress.h:119
#define PROGRESS_CREATEIDX_COMMAND_CREATE_CONCURRENTLY
Definition progress.h:137
#define PROGRESS_CREATEIDX_ACCESS_METHOD_OID
Definition progress.h:109
#define PROGRESS_CREATEIDX_PHASE_WAIT_3
Definition progress.h:125
#define PROGRESS_CREATEIDX_COMMAND_CREATE
Definition progress.h:136
#define PROGRESS_CREATEIDX_PHASE_WAIT_2
Definition progress.h:121
#define PROGRESS_CREATEIDX_PHASE
Definition progress.h:110
#define PROGRESS_CREATEIDX_INDEX_OID
Definition progress.h:108
#define PROGRESS_CREATEIDX_PARTITIONS_TOTAL
Definition progress.h:114
#define PROGRESS_CREATEIDX_COMMAND
Definition progress.h:107
#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:4827
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:69
#define HTEqualStrategyNumber
Definition stratnum.h:41
int ii_NumIndexAttrs
Definition execnodes.h:179
List * ii_Predicate
Definition execnodes.h:195
LockRelId lockRelId
Definition rel.h:46
Oid relId
Definition rel.h:40
Oid dbId
Definition rel.h:41
TransactionId xmin
Definition proc.h:241
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:4447
#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:1102
void StartTransactionCommand(void)
Definition xact.c:3081
void CommitTransactionCommand(void)
Definition xact.c:3179

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, Form_pg_am, Form_pg_index, 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 2852 of file indexcmds.c.

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

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

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

References AccessShareLock, BTEqualStrategyNumber, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg, ERROR, fb(), Form_pg_opclass, 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(), propgraph_edge_get_ref_keys(), ResolveOpClass(), transformForPortionOfClause(), and transformIndexConstraint().

◆ GetOperatorFromCompareType()

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

Definition at line 2473 of file indexcmds.c.

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

◆ IndexSetParentIndex()

void IndexSetParentIndex ( Relation  partitionIdx,
Oid  parentOid 
)

Definition at line 4473 of file indexcmds.c.

4474{
4476 ScanKeyData key[2];
4477 SysScanDesc scan;
4478 Oid partRelid = RelationGetRelid(partitionIdx);
4479 HeapTuple tuple;
4480 bool fix_dependencies;
4481
4482 /* Make sure this is an index */
4483 Assert(partitionIdx->rd_rel->relkind == RELKIND_INDEX ||
4484 partitionIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
4485
4486 /*
4487 * Scan pg_inherits for rows linking our index to some parent.
4488 */
4490 ScanKeyInit(&key[0],
4494 ScanKeyInit(&key[1],
4497 Int32GetDatum(1));
4499 NULL, 2, key);
4500 tuple = systable_getnext(scan);
4501
4502 if (!HeapTupleIsValid(tuple))
4503 {
4504 if (parentOid == InvalidOid)
4505 {
4506 /*
4507 * No pg_inherits row, and no parent wanted: nothing to do in this
4508 * case.
4509 */
4510 fix_dependencies = false;
4511 }
4512 else
4513 {
4515 fix_dependencies = true;
4516 }
4517 }
4518 else
4519 {
4521
4522 if (parentOid == InvalidOid)
4523 {
4524 /*
4525 * There exists a pg_inherits row, which we want to clear; do so.
4526 */
4528 fix_dependencies = true;
4529 }
4530 else
4531 {
4532 /*
4533 * A pg_inherits row exists. If it's the same we want, then we're
4534 * good; if it differs, that amounts to a corrupt catalog and
4535 * should not happen.
4536 */
4537 if (inhForm->inhparent != parentOid)
4538 {
4539 /* unexpected: we should not get called in this case */
4540 elog(ERROR, "bogus pg_inherit row: inhrelid %u inhparent %u",
4541 inhForm->inhrelid, inhForm->inhparent);
4542 }
4543
4544 /* already in the right state */
4545 fix_dependencies = false;
4546 }
4547 }
4548
4549 /* done with pg_inherits */
4550 systable_endscan(scan);
4552
4553 /* set relhassubclass if an index partition has been added to the parent */
4554 if (OidIsValid(parentOid))
4555 {
4558 }
4559
4560 /* set relispartition correctly on the partition */
4562
4563 if (fix_dependencies)
4564 {
4565 /*
4566 * Insert/delete pg_depend rows. If setting a parent, add PARTITION
4567 * dependencies on the parent index and the table; if removing a
4568 * parent, delete PARTITION dependencies.
4569 */
4570 if (OidIsValid(parentOid))
4571 {
4573 ObjectAddress parentIdx;
4574 ObjectAddress partitionTbl;
4575
4579 partitionIdx->rd_index->indrelid);
4580 recordDependencyOn(&partIdx, &parentIdx,
4582 recordDependencyOn(&partIdx, &partitionTbl,
4584 }
4585 else
4586 {
4593 }
4594
4595 /* make our updates visible */
4597 }
4598}
@ 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:4605
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:47
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition pg_depend.c:353
void StoreSingleInheritance(Oid relationId, Oid parentOid, int32 seqNumber)
END_CATALOG_STRUCT typedef FormData_pg_inherits * Form_pg_inherits
Definition pg_inherits.h:49
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212
#define RelationGetRelid(relation)
Definition rel.h:514
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:206
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition relation.c:48
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:3678

References Assert, BTEqualStrategyNumber, CatalogTupleDelete(), CommandCounterIncrement(), deleteDependencyRecordsForClass(), DEPENDENCY_PARTITION_PRI, DEPENDENCY_PARTITION_SEC, elog, ERROR, fb(), fix_dependencies(), Form_pg_inherits, 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 2546 of file indexcmds.c.

2547{
2548 char *name;
2549 int overhead = 0; /* chars needed for label and underscores */
2550 int availchars; /* chars available for name(s) */
2551 int name1chars; /* chars allocated to name1 */
2552 int name2chars; /* chars allocated to name2 */
2553 int ndx;
2554
2556 if (name2)
2557 {
2559 overhead++; /* allow for separating underscore */
2560 }
2561 else
2562 name2chars = 0;
2563 if (label)
2564 overhead += strlen(label) + 1;
2565
2567 Assert(availchars > 0); /* else caller chose a bad label */
2568
2569 /*
2570 * If we must truncate, preferentially truncate the longer name. This
2571 * logic could be expressed without a loop, but it's simple and obvious as
2572 * a loop.
2573 */
2574 while (name1chars + name2chars > availchars)
2575 {
2576 if (name1chars > name2chars)
2577 name1chars--;
2578 else
2579 name2chars--;
2580 }
2581
2583 if (name2)
2585
2586 /* Now construct the string using the chosen lengths */
2589 ndx = name1chars;
2590 if (name2)
2591 {
2592 name[ndx++] = '_';
2594 ndx += name2chars;
2595 }
2596 if (label)
2597 {
2598 name[ndx++] = '_';
2599 strcpy(name + ndx, label);
2600 }
2601 else
2602 name[ndx] = '\0';
2603
2604 return name;
2605}
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 3001 of file indexcmds.c.

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

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

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

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

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

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

3471{
3472 ListCell *l;
3473
3476
3477 foreach(l, relids)
3478 {
3479 Oid relid = lfirst_oid(l);
3480 char relkind;
3481 char relpersistence;
3482
3484
3485 /* functions in indexes may want a snapshot set */
3487
3488 /* check if the relation still exists */
3490 {
3493 continue;
3494 }
3495
3496 /*
3497 * Check permissions except when moving to database's default if a new
3498 * tablespace is chosen. Note that this check also happens in
3499 * ExecReindex(), but we do an extra check here as this runs across
3500 * multiple transactions.
3501 */
3502 if (OidIsValid(params->tablespaceOid) &&
3504 {
3506
3509 if (aclresult != ACLCHECK_OK)
3512 }
3513
3514 relkind = get_rel_relkind(relid);
3515 relpersistence = get_rel_persistence(relid);
3516
3517 /*
3518 * Partitioned tables and indexes can never be processed directly, and
3519 * a list of their leaves should be built first.
3520 */
3521 Assert(!RELKIND_HAS_PARTITIONS(relkind));
3522
3523 if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
3524 relpersistence != RELPERSISTENCE_TEMP)
3525 {
3526 ReindexParams newparams = *params;
3527
3530 if (ActiveSnapshotSet())
3532 /* ReindexRelationConcurrently() does the verbose output */
3533 }
3534 else if (relkind == RELKIND_INDEX)
3535 {
3536 ReindexParams newparams = *params;
3537
3540 reindex_index(stmt, relid, false, relpersistence, &newparams);
3542 /* reindex_index() does the verbose output */
3543 }
3544 else
3545 {
3546 bool result;
3547 ReindexParams newparams = *params;
3548
3551 result = reindex_relation(stmt, relid,
3554 &newparams);
3555
3556 if (result && (params->options & REINDEXOPT_VERBOSE) != 0)
3557 ereport(INFO,
3558 (errmsg("table \"%s.%s\" was reindexed",
3560 get_rel_name(relid))));
3561
3563 }
3564
3566 }
3567
3569}
#define INFO
Definition elog.h:34
bool reindex_relation(const ReindexStmt *stmt, Oid relid, int flags, const ReindexParams *params)
Definition index.c:3949
#define REINDEX_REL_PROCESS_TOAST
Definition index.h:165
#define REINDEXOPT_MISSING_OK
Definition index.h:49
#define REINDEX_REL_CHECK_CONSTRAINTS
Definition index.h:167
char * get_rel_name(Oid relid)
Definition lsyscache.c:2148
Oid get_rel_namespace(Oid relid)
Definition lsyscache.c:2172
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 3136 of file indexcmds.c.

3137{
3138
3139 Oid objectOid;
3141 TableScanDesc scan;
3143 HeapTuple tuple;
3146 List *relids = NIL;
3147 int num_keys;
3148 bool concurrent_warning = false;
3149 bool tablespace_warning = false;
3150 const char *objectName = stmt->name;
3151 const ReindexObjectType objectKind = stmt->kind;
3152
3156
3157 /*
3158 * This matches the options enforced by the grammar, where the object name
3159 * is optional for DATABASE and SYSTEM.
3160 */
3162
3164 (params->options & REINDEXOPT_CONCURRENTLY) != 0)
3165 ereport(ERROR,
3167 errmsg("cannot reindex system catalogs concurrently")));
3168
3169 /*
3170 * Get OID of object to reindex, being the database currently being used
3171 * by session for a database or for system catalogs, or the schema defined
3172 * by caller. At the same time do permission checks that need different
3173 * processing depending on the object type.
3174 */
3176 {
3178
3182 objectName);
3183 }
3184 else
3185 {
3187
3189 ereport(ERROR,
3191 errmsg("can only reindex the currently open database")));
3196 }
3197
3198 /*
3199 * Create a memory context that will survive forced transaction commits we
3200 * do below. Since it is a child of PortalContext, it will go away
3201 * eventually even if we suffer an error; there's no need for special
3202 * abort cleanup logic.
3203 */
3205 "ReindexMultipleTables",
3207
3208 /*
3209 * Define the search keys to find the objects to reindex. For a schema, we
3210 * select target relations using relnamespace, something not necessary for
3211 * a database-wide operation.
3212 */
3214 {
3215 num_keys = 1;
3220 }
3221 else
3222 num_keys = 0;
3223
3224 /*
3225 * Scan pg_class to build a list of the relations we need to reindex.
3226 *
3227 * We only consider plain relations and materialized views here (toast
3228 * rels will be processed indirectly by reindex_relation).
3229 */
3232 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
3233 {
3235 Oid relid = classtuple->oid;
3236
3237 /*
3238 * Only regular tables and matviews can have indexes, so ignore any
3239 * other kind of relation.
3240 *
3241 * Partitioned tables/indexes are skipped but matching leaf partitions
3242 * are processed.
3243 */
3244 if (classtuple->relkind != RELKIND_RELATION &&
3245 classtuple->relkind != RELKIND_MATVIEW)
3246 continue;
3247
3248 /* Skip temp tables of other backends; we can't reindex them at all */
3249 if (classtuple->relpersistence == RELPERSISTENCE_TEMP &&
3250 !isTempNamespace(classtuple->relnamespace))
3251 continue;
3252
3253 /*
3254 * Check user/system classification. SYSTEM processes all the
3255 * catalogs, and DATABASE processes everything that's not a catalog.
3256 */
3258 !IsCatalogRelationOid(relid))
3259 continue;
3260 else if (objectKind == REINDEX_OBJECT_DATABASE &&
3261 IsCatalogRelationOid(relid))
3262 continue;
3263
3264 /*
3265 * We already checked privileges on the database or schema, but we
3266 * further restrict reindexing shared catalogs to roles with the
3267 * MAINTAIN privilege on the relation.
3268 */
3269 if (classtuple->relisshared &&
3271 continue;
3272
3273 /*
3274 * Skip system tables, since index_create() would reject indexing them
3275 * concurrently (and it would likely fail if we tried).
3276 */
3277 if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
3278 IsCatalogRelationOid(relid))
3279 {
3280 if (!concurrent_warning)
3283 errmsg("cannot reindex system catalogs concurrently, skipping all")));
3284 concurrent_warning = true;
3285 continue;
3286 }
3287
3288 /*
3289 * If a new tablespace is set, check if this relation has to be
3290 * skipped.
3291 */
3292 if (OidIsValid(params->tablespaceOid))
3293 {
3294 bool skip_rel = false;
3295
3296 /*
3297 * Mapped relations cannot be moved to different tablespaces (in
3298 * particular this eliminates all shared catalogs.).
3299 */
3300 if (RELKIND_HAS_STORAGE(classtuple->relkind) &&
3301 !RelFileNumberIsValid(classtuple->relfilenode))
3302 skip_rel = true;
3303
3304 /*
3305 * A system relation is always skipped, even with
3306 * allow_system_table_mods enabled.
3307 */
3308 if (IsSystemClass(relid, classtuple))
3309 skip_rel = true;
3310
3311 if (skip_rel)
3312 {
3313 if (!tablespace_warning)
3316 errmsg("cannot move system relations, skipping all")));
3317 tablespace_warning = true;
3318 continue;
3319 }
3320 }
3321
3322 /* Save the list of relation OIDs in private context */
3324
3325 /*
3326 * We always want to reindex pg_class first if it's selected to be
3327 * reindexed. This ensures that if there is any corruption in
3328 * pg_class' indexes, they will be fixed before we process any other
3329 * tables. This is critical because reindexing itself will try to
3330 * update pg_class.
3331 */
3332 if (relid == RelationRelationId)
3333 relids = lcons_oid(relid, relids);
3334 else
3335 relids = lappend_oid(relids, relid);
3336
3338 }
3339 table_endscan(scan);
3341
3342 /*
3343 * Process each relation listed in a separate transaction. Note that this
3344 * commits and then starts a new transaction immediately.
3345 */
3346 ReindexMultipleInternal(stmt, relids, params);
3347
3349}
bool has_privs_of_role(Oid member, Oid role)
Definition acl.c:5314
@ ACLCHECK_NOT_OWNER
Definition acl.h:186
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition aclchk.c:4133
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:1421
static void ReindexMultipleInternal(const ReindexStmt *stmt, const List *relids, const ReindexParams *params)
Definition indexcmds.c:3470
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:1312
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:3721
Oid get_namespace_oid(const char *nspname, bool missing_ok)
Definition namespace.c:3607
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
@ OBJECT_DATABASE
ReindexObjectType
FormData_pg_class * Form_pg_class
Definition pg_class.h:160
@ 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:1056

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

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

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

3597{
3598 typedef struct ReindexIndexInfo
3599 {
3600 Oid indexId;
3601 Oid tableId;
3602 Oid amId;
3603 bool safe; /* for set_indexsafe_procflags */
3606 List *indexIds = NIL;
3607 List *newIndexIds = NIL;
3609 List *lockTags = NIL;
3610 ListCell *lc,
3611 *lc2;
3613 MemoryContext oldcontext;
3614 char relkind;
3615 char *relationName = NULL;
3616 char *relationNamespace = NULL;
3617 PGRUsage ru0;
3618 const int progress_index[] = {
3623 };
3625
3626 /*
3627 * Create a memory context that will survive forced transaction commits we
3628 * do below. Since it is a child of PortalContext, it will go away
3629 * eventually even if we suffer an error; there's no need for special
3630 * abort cleanup logic.
3631 */
3633 "ReindexConcurrent",
3635
3636 if ((params->options & REINDEXOPT_VERBOSE) != 0)
3637 {
3638 /* Save data needed by REINDEX VERBOSE in private context */
3640
3641 relationName = get_rel_name(relationOid);
3643
3645
3646 MemoryContextSwitchTo(oldcontext);
3647 }
3648
3649 relkind = get_rel_relkind(relationOid);
3650
3651 /*
3652 * Extract the list of indexes that are going to be rebuilt based on the
3653 * relation Oid given by caller.
3654 */
3655 switch (relkind)
3656 {
3657 case RELKIND_RELATION:
3658 case RELKIND_MATVIEW:
3659 case RELKIND_TOASTVALUE:
3660 {
3661 /*
3662 * In the case of a relation, find all its indexes including
3663 * toast indexes.
3664 */
3665 Relation heapRelation;
3666
3667 /* Save the list of relation OIDs in private context */
3669
3670 /* Track this relation for session locks */
3672
3673 MemoryContextSwitchTo(oldcontext);
3674
3675 if (IsCatalogRelationOid(relationOid))
3676 ereport(ERROR,
3678 errmsg("cannot reindex system catalogs concurrently")));
3679
3680 /* Open relation to get its indexes */
3681 if ((params->options & REINDEXOPT_MISSING_OK) != 0)
3682 {
3683 heapRelation = try_table_open(relationOid,
3685 /* leave if relation does not exist */
3686 if (!heapRelation)
3687 break;
3688 }
3689 else
3690 heapRelation = table_open(relationOid,
3692
3693 if (OidIsValid(params->tablespaceOid) &&
3694 IsSystemRelation(heapRelation))
3695 ereport(ERROR,
3697 errmsg("cannot move system relation \"%s\"",
3698 RelationGetRelationName(heapRelation))));
3699
3700 /* Add all the valid indexes of relation to list */
3701 foreach(lc, RelationGetIndexList(heapRelation))
3702 {
3704 Relation indexRelation = index_open(cellOid,
3706
3707 if (!indexRelation->rd_index->indisvalid)
3710 errmsg("skipping reindex of invalid index \"%s.%s\"",
3713 errhint("Use DROP INDEX or REINDEX INDEX.")));
3714 else if (indexRelation->rd_index->indisexclusion)
3717 errmsg("cannot reindex exclusion constraint index \"%s.%s\" concurrently, skipping",
3720 else
3721 {
3723
3724 /* Save the list of relation OIDs in private context */
3726
3728 idx->indexId = cellOid;
3729 /* other fields set later */
3730
3732
3733 MemoryContextSwitchTo(oldcontext);
3734 }
3735
3736 index_close(indexRelation, NoLock);
3737 }
3738
3739 /* Also add the toast indexes */
3740 if (OidIsValid(heapRelation->rd_rel->reltoastrelid))
3741 {
3742 Oid toastOid = heapRelation->rd_rel->reltoastrelid;
3745
3746 /* Save the list of relation OIDs in private context */
3748
3749 /* Track this relation for session locks */
3751
3752 MemoryContextSwitchTo(oldcontext);
3753
3755 {
3757 Relation indexRelation = index_open(cellOid,
3759
3760 if (!indexRelation->rd_index->indisvalid)
3763 errmsg("skipping reindex of invalid index \"%s.%s\"",
3766 errhint("Use DROP INDEX or REINDEX INDEX.")));
3767 else
3768 {
3770
3771 /*
3772 * Save the list of relation OIDs in private
3773 * context
3774 */
3776
3778 idx->indexId = cellOid;
3780 /* other fields set later */
3781
3782 MemoryContextSwitchTo(oldcontext);
3783 }
3784
3785 index_close(indexRelation, NoLock);
3786 }
3787
3789 }
3790
3791 table_close(heapRelation, NoLock);
3792 break;
3793 }
3794 case RELKIND_INDEX:
3795 {
3796 Oid heapId = IndexGetRelation(relationOid,
3797 (params->options & REINDEXOPT_MISSING_OK) != 0);
3798 Relation heapRelation;
3800
3801 /* if relation is missing, leave */
3802 if (!OidIsValid(heapId))
3803 break;
3804
3806 ereport(ERROR,
3808 errmsg("cannot reindex system catalogs concurrently")));
3809
3810 /*
3811 * Don't allow reindex for an invalid index on TOAST table, as
3812 * if rebuilt it would not be possible to drop it. Match
3813 * error message in reindex_index().
3814 */
3815 if (IsToastNamespace(get_rel_namespace(relationOid)) &&
3816 !get_index_isvalid(relationOid))
3817 ereport(ERROR,
3819 errmsg("cannot reindex invalid index on TOAST table")));
3820
3821 /*
3822 * Check if parent relation can be locked and if it exists,
3823 * this needs to be done at this stage as the list of indexes
3824 * to rebuild is not complete yet, and REINDEXOPT_MISSING_OK
3825 * should not be used once all the session locks are taken.
3826 */
3827 if ((params->options & REINDEXOPT_MISSING_OK) != 0)
3828 {
3829 heapRelation = try_table_open(heapId,
3831 /* leave if relation does not exist */
3832 if (!heapRelation)
3833 break;
3834 }
3835 else
3836 heapRelation = table_open(heapId,
3838
3839 if (OidIsValid(params->tablespaceOid) &&
3840 IsSystemRelation(heapRelation))
3841 ereport(ERROR,
3843 errmsg("cannot move system relation \"%s\"",
3844 get_rel_name(relationOid))));
3845
3846 table_close(heapRelation, NoLock);
3847
3848 /* Save the list of relation OIDs in private context */
3850
3851 /* Track the heap relation of this index for session locks */
3853
3854 /*
3855 * Save the list of relation OIDs in private context. Note
3856 * that invalid indexes are allowed here.
3857 */
3859 idx->indexId = relationOid;
3861 /* other fields set later */
3862
3863 MemoryContextSwitchTo(oldcontext);
3864 break;
3865 }
3866
3869 default:
3870 /* Return error if type of relation is not supported */
3871 ereport(ERROR,
3873 errmsg("cannot reindex this type of relation concurrently")));
3874 break;
3875 }
3876
3877 /*
3878 * Definitely no indexes, so leave. Any checks based on
3879 * REINDEXOPT_MISSING_OK should be done only while the list of indexes to
3880 * work on is built as the session locks taken before this transaction
3881 * commits will make sure that they cannot be dropped by a concurrent
3882 * session until this operation completes.
3883 */
3884 if (indexIds == NIL)
3885 return false;
3886
3887 /* It's not a shared catalog, so refuse to move it to shared tablespace */
3888 if (params->tablespaceOid == GLOBALTABLESPACE_OID)
3889 ereport(ERROR,
3891 errmsg("cannot move non-shared relation to tablespace \"%s\"",
3893
3895
3896 /*-----
3897 * Now we have all the indexes we want to process in indexIds.
3898 *
3899 * The phases now are:
3900 *
3901 * 1. create new indexes in the catalog
3902 * 2. build new indexes
3903 * 3. let new indexes catch up with tuples inserted in the meantime
3904 * 4. swap index names
3905 * 5. mark old indexes as dead
3906 * 6. drop old indexes
3907 *
3908 * We process each phase for all indexes before moving to the next phase,
3909 * for efficiency.
3910 */
3911
3912 /*
3913 * Phase 1 of REINDEX CONCURRENTLY
3914 *
3915 * Create a new index with the same properties as the old one, but it is
3916 * only registered in catalogs and will be built later. Then get session
3917 * locks on all involved tables. See analogous code in DefineIndex() for
3918 * more detailed comments.
3919 */
3920
3921 foreach(lc, indexIds)
3922 {
3923 char *concurrentName;
3927 Relation indexRel;
3928 Relation heapRel;
3929 Oid save_userid;
3930 int save_sec_context;
3931 int save_nestlevel;
3935
3936 indexRel = index_open(idx->indexId, ShareUpdateExclusiveLock);
3937 heapRel = table_open(indexRel->rd_index->indrelid,
3939
3940 /*
3941 * Switch to the table owner's userid, so that any index functions are
3942 * run as that user. Also lock down security-restricted operations
3943 * and arrange to make GUC variable changes local to this command.
3944 */
3945 GetUserIdAndSecContext(&save_userid, &save_sec_context);
3946 SetUserIdAndSecContext(heapRel->rd_rel->relowner,
3947 save_sec_context | SECURITY_RESTRICTED_OPERATION);
3948 save_nestlevel = NewGUCNestLevel();
3950
3951 /* determine safety of this index for set_indexsafe_procflags */
3952 idx->safe = (RelationGetIndexExpressions(indexRel) == NIL &&
3953 RelationGetIndexPredicate(indexRel) == NIL);
3954
3955#ifdef USE_INJECTION_POINTS
3956 if (idx->safe)
3957 INJECTION_POINT("reindex-conc-index-safe", NULL);
3958 else
3959 INJECTION_POINT("reindex-conc-index-not-safe", NULL);
3960#endif
3961
3962 idx->tableId = RelationGetRelid(heapRel);
3963 idx->amId = indexRel->rd_rel->relam;
3964
3965 /* This function shouldn't be called for temporary relations. */
3966 if (indexRel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
3967 elog(ERROR, "cannot reindex a temporary table concurrently");
3968
3970
3972 progress_vals[1] = 0; /* initializing */
3973 progress_vals[2] = idx->indexId;
3974 progress_vals[3] = idx->amId;
3976
3977 /* Choose a temporary relation name for the new index */
3979 NULL,
3980 "ccnew",
3981 get_rel_namespace(indexRel->rd_index->indrelid),
3982 false);
3983
3984 /* Choose the new tablespace, indexes of toast tables are not moved */
3985 if (OidIsValid(params->tablespaceOid) &&
3986 heapRel->rd_rel->relkind != RELKIND_TOASTVALUE)
3987 tablespaceid = params->tablespaceOid;
3988 else
3989 tablespaceid = indexRel->rd_rel->reltablespace;
3990
3991 /* Create new index definition based on given index */
3993 idx->indexId,
3996
3997 /*
3998 * Now open the relation of the new index, a session-level lock is
3999 * also needed on it.
4000 */
4002
4003 /*
4004 * Save the list of OIDs and locks in private context
4005 */
4007
4009 newidx->indexId = newIndexId;
4010 newidx->safe = idx->safe;
4011 newidx->tableId = idx->tableId;
4012 newidx->amId = idx->amId;
4013
4015
4016 /*
4017 * Save lockrelid to protect each relation from drop then close
4018 * relations. The lockrelid on parent relation is not taken here to
4019 * avoid multiple locks taken on the same relation, instead we rely on
4020 * parentRelationIds built earlier.
4021 */
4023 *lockrelid = indexRel->rd_lockInfo.lockRelId;
4026 *lockrelid = newIndexRel->rd_lockInfo.lockRelId;
4028
4029 MemoryContextSwitchTo(oldcontext);
4030
4031 index_close(indexRel, NoLock);
4033
4034 /* Roll back any GUC changes executed by index functions */
4035 AtEOXact_GUC(false, save_nestlevel);
4036
4037 /* Restore userid and security context */
4038 SetUserIdAndSecContext(save_userid, save_sec_context);
4039
4040 table_close(heapRel, NoLock);
4041
4042 /*
4043 * If a statement is available, telling that this comes from a REINDEX
4044 * command, collect the new index for event triggers.
4045 */
4046 if (stmt)
4047 {
4048 ObjectAddress address;
4049
4053 (const Node *) stmt);
4054 }
4055 }
4056
4057 /*
4058 * Save the heap lock for following visibility checks with other backends
4059 * might conflict with this session.
4060 */
4061 foreach(lc, heapRelationIds)
4062 {
4066
4067 /* Save the list of locks in private context */
4069
4070 /* Add lockrelid of heap relation to the list of locked relations */
4072 *lockrelid = heapRelation->rd_lockInfo.lockRelId;
4074
4076
4077 /* Save the LOCKTAG for this parent relation for the wait phase */
4080
4081 MemoryContextSwitchTo(oldcontext);
4082
4083 /* Close heap relation */
4084 table_close(heapRelation, NoLock);
4085 }
4086
4087 /* Get a session-level lock on each table. */
4088 foreach(lc, relationLocks)
4089 {
4091
4093 }
4094
4098
4099 /*
4100 * Because we don't take a snapshot in this transaction, there's no need
4101 * to set the PROC_IN_SAFE_IC flag here.
4102 */
4103
4104 /*
4105 * Phase 2 of REINDEX CONCURRENTLY
4106 *
4107 * Build the new indexes in a separate transaction for each index to avoid
4108 * having open transactions for an unnecessary long time. But before
4109 * doing that, wait until no running transactions could have the table of
4110 * the index open with the old list of indexes. See "phase 2" in
4111 * DefineIndex() for more details.
4112 */
4113
4118
4119 foreach(lc, newIndexIds)
4120 {
4122
4123 /* Start new transaction for this index's concurrent build */
4125
4126 /*
4127 * Check for user-requested abort. This is inside a transaction so as
4128 * xact.c does not issue a useless WARNING, and ensures that
4129 * session-level locks are cleaned up on abort.
4130 */
4132
4133 /* Tell concurrent indexing to ignore us, if index qualifies */
4134 if (newidx->safe)
4136
4137 /* Set ActiveSnapshot since functions in the indexes may need it */
4139
4140 /*
4141 * Update progress for the index to build, with the correct parent
4142 * table involved.
4143 */
4147 progress_vals[2] = newidx->indexId;
4148 progress_vals[3] = newidx->amId;
4150
4151 /* Perform concurrent build of new index */
4152 index_concurrently_build(newidx->tableId, newidx->indexId);
4153
4156 }
4157
4159
4160 /*
4161 * Because we don't take a snapshot or Xid in this transaction, there's no
4162 * need to set the PROC_IN_SAFE_IC flag here.
4163 */
4164
4165 /*
4166 * Phase 3 of REINDEX CONCURRENTLY
4167 *
4168 * During this phase the old indexes catch up with any new tuples that
4169 * were created during the previous phase. See "phase 3" in DefineIndex()
4170 * for more details.
4171 */
4172
4177
4178 foreach(lc, newIndexIds)
4179 {
4182 Snapshot snapshot;
4183
4185
4186 /*
4187 * Check for user-requested abort. This is inside a transaction so as
4188 * xact.c does not issue a useless WARNING, and ensures that
4189 * session-level locks are cleaned up on abort.
4190 */
4192
4193 /* Tell concurrent indexing to ignore us, if index qualifies */
4194 if (newidx->safe)
4196
4197 /*
4198 * Take the "reference snapshot" that will be used by validate_index()
4199 * to filter candidate tuples.
4200 */
4202 PushActiveSnapshot(snapshot);
4203
4204 /*
4205 * Update progress for the index to build, with the correct parent
4206 * table involved.
4207 */
4211 progress_vals[2] = newidx->indexId;
4212 progress_vals[3] = newidx->amId;
4214
4215 validate_index(newidx->tableId, newidx->indexId, snapshot);
4216
4217 /*
4218 * We can now do away with our active snapshot, we still need to save
4219 * the xmin limit to wait for older snapshots.
4220 */
4221 limitXmin = snapshot->xmin;
4222
4224 UnregisterSnapshot(snapshot);
4225
4226 /*
4227 * To ensure no deadlocks, we must commit and start yet another
4228 * transaction, and do our wait before any snapshot has been taken in
4229 * it.
4230 */
4233
4234 /*
4235 * The index is now valid in the sense that it contains all currently
4236 * interesting tuples. But since it might not contain tuples deleted
4237 * just before the reference snap was taken, we have to wait out any
4238 * transactions that might have older snapshots.
4239 *
4240 * Because we don't take a snapshot or Xid in this transaction,
4241 * there's no need to set the PROC_IN_SAFE_IC flag here.
4242 */
4246
4248 }
4249
4250 /*
4251 * Phase 4 of REINDEX CONCURRENTLY
4252 *
4253 * Now that the new indexes have been validated, swap each new index with
4254 * its corresponding old index.
4255 *
4256 * We mark the new indexes as valid and the old indexes as not valid at
4257 * the same time to make sure we only get constraint violations from the
4258 * indexes with the correct names.
4259 */
4260
4261 INJECTION_POINT("reindex-relation-concurrently-before-swap", NULL);
4263
4264 /*
4265 * Because this transaction only does catalog manipulations and doesn't do
4266 * any index operations, we can set the PROC_IN_SAFE_IC flag here
4267 * unconditionally.
4268 */
4270
4272 {
4275 char *oldName;
4276
4277 /*
4278 * Check for user-requested abort. This is inside a transaction so as
4279 * xact.c does not issue a useless WARNING, and ensures that
4280 * session-level locks are cleaned up on abort.
4281 */
4283
4284 /* Choose a relation name for old index */
4286 NULL,
4287 "ccold",
4288 get_rel_namespace(oldidx->tableId),
4289 false);
4290
4291 /*
4292 * Swapping the indexes might involve TOAST table access, so ensure we
4293 * have a valid snapshot.
4294 */
4296
4297 /*
4298 * Swap old index with the new one. This also marks the new one as
4299 * valid and the old one as not valid.
4300 */
4301 index_concurrently_swap(newidx->indexId, oldidx->indexId, oldName);
4302
4304
4305 /*
4306 * Invalidate the relcache for the table, so that after this commit
4307 * all sessions will refresh any cached plans that might reference the
4308 * index.
4309 */
4311
4312 /*
4313 * CCI here so that subsequent iterations see the oldName in the
4314 * catalog and can choose a nonconflicting name for their oldName.
4315 * Otherwise, this could lead to conflicts if a table has two indexes
4316 * whose names are equal for the first NAMEDATALEN-minus-a-few
4317 * characters.
4318 */
4320 }
4321
4322 /* Commit this transaction and make index swaps visible */
4325
4326 /*
4327 * While we could set PROC_IN_SAFE_IC if all indexes qualified, there's no
4328 * real need for that, because we only acquire an Xid after the wait is
4329 * done, and that lasts for a very short period.
4330 */
4331
4332 /*
4333 * Phase 5 of REINDEX CONCURRENTLY
4334 *
4335 * Mark the old indexes as dead. First we must wait until no running
4336 * transaction could be using the index for a query. See also
4337 * index_drop() for more details.
4338 */
4339
4340 INJECTION_POINT("reindex-relation-concurrently-before-set-dead", NULL);
4344
4345 foreach(lc, indexIds)
4346 {
4348
4349 /*
4350 * Check for user-requested abort. This is inside a transaction so as
4351 * xact.c does not issue a useless WARNING, and ensures that
4352 * session-level locks are cleaned up on abort.
4353 */
4355
4356 /*
4357 * Updating pg_index might involve TOAST table access, so ensure we
4358 * have a valid snapshot.
4359 */
4361
4362 index_concurrently_set_dead(oldidx->tableId, oldidx->indexId);
4363
4365 }
4366
4367 /* Commit this transaction to make the updates visible. */
4370
4371 /*
4372 * While we could set PROC_IN_SAFE_IC if all indexes qualified, there's no
4373 * real need for that, because we only acquire an Xid after the wait is
4374 * done, and that lasts for a very short period.
4375 */
4376
4377 /*
4378 * Phase 6 of REINDEX CONCURRENTLY
4379 *
4380 * Drop the old indexes.
4381 */
4382
4386
4388
4389 {
4391
4392 foreach(lc, indexIds)
4393 {
4395 ObjectAddress object;
4396
4397 object.classId = RelationRelationId;
4398 object.objectId = idx->indexId;
4399 object.objectSubId = 0;
4400
4401 add_exact_object_address(&object, objects);
4402 }
4403
4404 /*
4405 * Use PERFORM_DELETION_CONCURRENT_LOCK so that index_drop() uses the
4406 * right lock level.
4407 */
4410 }
4411
4414
4415 /*
4416 * Finally, release the session-level lock on the table.
4417 */
4418 foreach(lc, relationLocks)
4419 {
4421
4423 }
4424
4425 /* Start a new transaction to finish process properly */
4427
4428 /* Log what we did */
4429 if ((params->options & REINDEXOPT_VERBOSE) != 0)
4430 {
4431 if (relkind == RELKIND_INDEX)
4432 ereport(INFO,
4433 (errmsg("index \"%s.%s\" was reindexed",
4435 errdetail("%s.",
4436 pg_rusage_show(&ru0))));
4437 else
4438 {
4439 foreach(lc, newIndexIds)
4440 {
4442 Oid indOid = idx->indexId;
4443
4444 ereport(INFO,
4445 (errmsg("index \"%s.%s\" was reindexed",
4447 get_rel_name(indOid))));
4448 /* Don't show rusage here, since it's not per index. */
4449 }
4450
4451 ereport(INFO,
4452 (errmsg("table \"%s.%s\" was reindexed",
4454 errdetail("%s.",
4455 pg_rusage_show(&ru0))));
4456 }
4457 }
4458
4460
4462
4463 return true;
4464}
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:388
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, const Node *parsetree)
#define palloc_object(type)
Definition fe_memutils.h:74
void index_concurrently_set_dead(Oid heapId, Oid indexId)
Definition index.c:1824
void index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName)
Definition index.c:1553
Oid index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, Oid tablespaceOid, const char *newName)
Definition index.c:1301
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:550
#define list_make1_oid(x1)
Definition pg_list.h:274
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:126
#define PROGRESS_CREATEIDX_PHASE_BUILD
Definition progress.h:120
#define PROGRESS_CREATEIDX_COMMAND_REINDEX_CONCURRENTLY
Definition progress.h:139
#define PROGRESS_CREATEIDX_PHASE_VALIDATE_IDXSCAN
Definition progress.h:122
#define PROGRESS_CREATEIDX_PHASE_WAIT_5
Definition progress.h:127
List * RelationGetIndexPredicate(Relation relation)
Definition relcache.c:5201
List * RelationGetIndexExpressions(Relation relation)
Definition relcache.c:5088
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 3077 of file indexcmds.c.

3078{
3079 Oid heapOid;
3080 bool result;
3081 const RangeVar *relation = stmt->relation;
3082
3083 /*
3084 * The lock level used here should match reindex_relation().
3085 *
3086 * If it's a temporary table, we will perform a non-concurrent reindex,
3087 * even if CONCURRENTLY was requested. In that case, reindex_relation()
3088 * will upgrade the lock, but that's OK, because other sessions can't hold
3089 * locks on our temporary table.
3090 */
3091 heapOid = RangeVarGetRelidExtended(relation,
3092 (params->options & REINDEXOPT_CONCURRENTLY) != 0 ?
3094 0,
3096
3098 ReindexPartitions(stmt, heapOid, params, isTopLevel);
3099 else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
3101 {
3102 result = ReindexRelationConcurrently(stmt, heapOid, params);
3103
3104 if (!result)
3106 (errmsg("table \"%s\" has no indexes that can be reindexed concurrently",
3107 relation->relname)));
3108 }
3109 else
3110 {
3111 ReindexParams newparams = *params;
3112
3114 result = reindex_relation(stmt, heapOid,
3117 &newparams);
3118 if (!result)
3120 (errmsg("table \"%s\" has no indexes to reindex",
3121 relation->relname)));
3122 }
3123
3124 return heapOid;
3125}
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 2286 of file indexcmds.c.

2288{
2289 char *schemaname;
2290 char *opcname;
2291 HeapTuple tuple;
2293 Oid opClassId,
2295
2296 if (opclass == NIL)
2297 {
2298 /* no operator class specified, so find the default */
2300 if (!OidIsValid(opClassId))
2301 ereport(ERROR,
2303 errmsg("data type %s has no default operator class for access method \"%s\"",
2305 errhint("You must specify an operator class for the index or define a default operator class for the data type.")));
2306 return opClassId;
2307 }
2308
2309 /*
2310 * Specific opclass name given, so look up the opclass.
2311 */
2312
2313 /* deconstruct the name list */
2314 DeconstructQualifiedName(opclass, &schemaname, &opcname);
2315
2316 if (schemaname)
2317 {
2318 /* Look in specific schema only */
2320
2321 namespaceId = LookupExplicitNamespace(schemaname, false);
2326 }
2327 else
2328 {
2329 /* Unqualified opclass name, so search the search path */
2331 if (!OidIsValid(opClassId))
2332 ereport(ERROR,
2334 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
2337 }
2338
2339 if (!HeapTupleIsValid(tuple))
2340 ereport(ERROR,
2342 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
2344
2345 /*
2346 * Verify that the index operator class accepts this datatype. Note we
2347 * will accept binary compatibility.
2348 */
2349 opform = (Form_pg_opclass) GETSTRUCT(tuple);
2350 opClassId = opform->oid;
2351 opInputType = opform->opcintype;
2352
2354 ereport(ERROR,
2356 errmsg("operator class \"%s\" does not accept data type %s",
2358
2359 ReleaseSysCache(tuple);
2360
2361 return opClassId;
2362}
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition indexcmds.c:2371
Oid OpclassnameGetOpcid(Oid amid, const char *opcname)
Definition namespace.c:2190
char * NameListToString(const List *names)
Definition namespace.c:3666
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition namespace.c:3457
void DeconstructQualifiedName(const List *names, char **nspname_p, char **objname_p)
Definition namespace.c:3373
HeapTuple SearchSysCache3(SysCacheIdentifier cacheId, Datum key1, Datum key2, Datum key3)
Definition syscache.c:241

References DeconstructQualifiedName(), ereport, errcode(), errhint(), errmsg, ERROR, fb(), Form_pg_opclass, 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 4643 of file indexcmds.c.

4644{
4645 /*
4646 * This should only be called before installing xid or xmin in MyProc;
4647 * otherwise, concurrent processes could see an Xmin that moves backwards.
4648 */
4651
4656}
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1149
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1766
@ LW_EXCLUSIVE
Definition lwlock.h:104
#define PROC_IN_SAFE_IC
Definition proc.h:62
PROC_HDR * ProcGlobal
Definition proc.c:72
uint8 statusFlags
Definition proc.h:209
int pgxactoff
Definition proc.h:206
TransactionId xid
Definition proc.h:236
uint8 * statusFlags
Definition proc.h:455

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

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

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

437{
438 int n_old_snapshots;
439 int i;
441
446 if (progress)
448
449 for (i = 0; i < n_old_snapshots; i++)
450 {
452 continue; /* found uninteresting in previous cycle */
453
454 if (i > 0)
455 {
456 /* see if anything's changed ... */
459 int j;
460 int k;
461
463 true, false,
467 for (j = i; j < n_old_snapshots; j++)
468 {
470 continue; /* found uninteresting in previous cycle */
471 for (k = 0; k < n_newer_snapshots; k++)
472 {
474 newer_snapshots[k]))
475 break;
476 }
477 if (k >= n_newer_snapshots) /* not there anymore */
479 }
481 }
482
484 {
485 /* If requested, publish who we're going to wait for. */
486 if (progress)
487 {
489
490 if (holder)
492 holder->pid);
493 }
495 }
496
497 if (progress)
499 }
500}
bool VirtualXactLock(VirtualTransactionId vxid, bool wait)
Definition lock.c:4754
#define VirtualTransactionIdIsValid(vxid)
Definition lock.h:70
#define VirtualTransactionIdEquals(vxid1, vxid2)
Definition lock.h:74
#define SetInvalidVirtualTransactionId(vxid)
Definition lock.h:77
static int progress
Definition pgbench.c:262
#define PROC_IN_VACUUM
Definition proc.h:61
#define PROC_IS_AUTOVACUUM
Definition proc.h:60
VirtualTransactionId * GetCurrentVirtualXIDs(TransactionId limitXmin, bool excludeXmin0, bool allDbs, int excludeVacuum, int *nvxids)
Definition procarray.c:3284
PGPROC * ProcNumberGetProc(ProcNumber procNumber)
Definition procarray.c:3098
#define PROGRESS_WAITFOR_DONE
Definition progress.h:143
#define PROGRESS_WAITFOR_TOTAL
Definition progress.h:142
#define PROGRESS_WAITFOR_CURRENT_PID
Definition progress.h:144
Definition proc.h:178

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().