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  CIEN_context
 
struct  ReindexIndexCallbackState
 
struct  ReindexErrorInfo
 

Typedefs

typedef struct CIEN_context CIEN_context
 
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 char * ChooseIndexName (const char *tabname, Oid namespaceId, const List *colnames, const List *exclusionOpNames, bool primary, bool isconstraint)
 
static char * ChooseIndexNameAddition (const List *colnames)
 
static List * ChooseIndexColumnNames (Relation rel, const List *indexElems)
 
static char * ChooseIndexExpressionName (Relation rel, Node *indexExpr)
 
static bool ChooseIndexExpressionName_walker (Node *node, CIEN_context *context)
 
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)
 
char * makeObjectName (const char *name1, const char *name2, const char *label)
 
char * ChooseRelationName (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

◆ CIEN_context

◆ ReindexErrorInfo

Function Documentation

◆ CheckIndexCompatible()

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

Definition at line 189 of file indexcmds.c.

194{
195 bool isconstraint;
196 Oid *typeIds;
202 HeapTuple tuple;
206 bool amcanorder;
207 bool amsummarizing;
209 IndexInfo *indexInfo;
211 int old_natts;
212 bool ret = true;
215 Relation irel;
216 int i;
217 Datum d;
218
219 /* Caller should already have the relation locked in some way. */
221
222 /*
223 * We can pretend isconstraint = false unconditionally. It only serves to
224 * decide the text of an error message that should never happen for us.
225 */
226 isconstraint = false;
227
231
232 /* look up the access method */
234 if (!HeapTupleIsValid(tuple))
237 errmsg("access method \"%s\" does not exist",
242 ReleaseSysCache(tuple);
243
244 amcanorder = amRoutine->amcanorder;
245 amsummarizing = amRoutine->amsummarizing;
246
247 /*
248 * Compute the operator classes, collations, and exclusion operators for
249 * the new index, so we can test whether it's compatible with the existing
250 * one. Note that ComputeIndexAttrs might fail here, but that's OK:
251 * DefineIndex would have failed later. Our attributeList contains only
252 * key attributes, thus we're filling ii_NumIndexAttrs and
253 * ii_NumIndexKeyAttrs with same value.
254 */
256 accessMethodId, NIL, NIL, false, false,
257 false, false, amsummarizing, isWithoutOverlaps);
263 ComputeIndexAttrs(NULL, indexInfo,
268 amcanorder, isconstraint, isWithoutOverlaps, InvalidOid,
269 0, NULL);
270
271 /* Get the soon-obsolete pg_index tuple. */
273 if (!HeapTupleIsValid(tuple))
274 elog(ERROR, "cache lookup failed for index %u", oldId);
276
277 /*
278 * We don't assess expressions or predicates; assume incompatibility.
279 * Also, if the index is invalid for any reason, treat it as incompatible.
280 */
283 indexForm->indisvalid))
284 {
285 ReleaseSysCache(tuple);
286 return false;
287 }
288
289 /* Any change in operator class or collation breaks compatibility. */
290 old_natts = indexForm->indnkeyatts;
292
295
298
299 ret = (memcmp(old_indclass->values, opclassIds, old_natts * sizeof(Oid)) == 0 &&
300 memcmp(old_indcollation->values, collationIds, old_natts * sizeof(Oid)) == 0);
301
302 ReleaseSysCache(tuple);
303
304 if (!ret)
305 return false;
306
307 /* For polymorphic opcintype, column type changes break compatibility. */
308 irel = index_open(oldId, AccessShareLock); /* caller probably has a lock */
309 for (i = 0; i < old_natts; i++)
310 {
312 TupleDescAttr(irel->rd_att, i)->atttypid != typeIds[i])
313 {
314 ret = false;
315 break;
316 }
317 }
318
319 /* Any change in opclass options break compatibility. */
320 if (ret)
321 {
323
324 for (i = 0; i < old_natts; i++)
326
328
330 }
331
332 /* Any change in exclusion operator selections breaks compatibility. */
333 if (ret && indexInfo->ii_ExclusionOps != NULL)
334 {
336 *old_procs;
338
340 ret = memcmp(old_operators, indexInfo->ii_ExclusionOps,
341 old_natts * sizeof(Oid)) == 0;
342
343 /* Require an exact input type match for polymorphic operators. */
344 if (ret)
345 {
346 for (i = 0; i < old_natts && ret; i++)
347 {
348 Oid left,
349 right;
350
351 op_input_types(indexInfo->ii_ExclusionOps[i], &left, &right);
352 if ((IsPolymorphicType(left) || IsPolymorphicType(right)) &&
353 TupleDescAttr(irel->rd_att, i)->atttypid != typeIds[i])
354 {
355 ret = false;
356 break;
357 }
358 }
359 }
360 }
361
362 index_close(irel, NoLock);
363 return ret;
364}
const IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition amapi.c:33
#define Assert(condition)
Definition c.h:1002
int16_t int16
Definition c.h:678
uint16_t uint16
Definition c.h:682
int errcode(int sqlerrcode)
Definition elog.c:875
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
#define palloc_array(type, count)
Definition fe_memutils.h:91
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:3616
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:373
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:1891
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:1464
Datum get_attoptions(Oid relid, int16 attnum)
Definition lsyscache.c:1196
void op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
Definition lsyscache.c:1658
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:1619
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 ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
#define PointerGetDatum(X)
Definition postgres.h:354
#define InvalidOid
unsigned int Oid
static int fb(int x)
void RelationGetExclusionInfo(Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
Definition relcache.c:5665
Oid * ii_ExclusionOps
Definition execnodes.h:202
TupleDesc rd_att
Definition rel.h:112
Definition c.h:874
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 1864 of file indexcmds.c.

1865{
1866 /*
1867 * transformExpr() should have already rejected subqueries, aggregates,
1868 * and window functions, based on the EXPR_KIND_ for a predicate.
1869 */
1870
1871 /*
1872 * A predicate using mutable functions is probably wrong, for the same
1873 * reasons that we don't allow an index expression to use one.
1874 */
1876 ereport(ERROR,
1878 errmsg("functions in index predicate must be marked IMMUTABLE")));
1879}
bool contain_mutable_functions_after_planning(Expr *expr)
Definition clauses.c:519

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

Referenced by DefineIndex().

◆ ChooseIndexColumnNames()

static List * ChooseIndexColumnNames ( Relation  rel,
const List *  indexElems 
)
static

Definition at line 2802 of file indexcmds.c.

2803{
2804 List *result = NIL;
2805 ListCell *lc;
2806
2807 foreach(lc, indexElems)
2808 {
2810 const char *origname;
2811 const char *curname;
2812 int i;
2813 char buf[NAMEDATALEN];
2814
2815 /* Get the preliminary name from the IndexElem */
2816 if (ielem->indexcolname)
2817 origname = ielem->indexcolname; /* caller-specified name */
2818 else if (ielem->name)
2819 origname = ielem->name; /* simple column reference */
2820 else
2822
2823 /* If it conflicts with any previous column, tweak it */
2824 curname = origname;
2825 for (i = 1;; i++)
2826 {
2827 ListCell *lc2;
2828 char nbuf[32];
2829 int nlen;
2830
2831 foreach(lc2, result)
2832 {
2833 if (strcmp(curname, (char *) lfirst(lc2)) == 0)
2834 break;
2835 }
2836 if (lc2 == NULL)
2837 break; /* found nonconflicting name */
2838
2839 sprintf(nbuf, "%d", i);
2840
2841 /* Ensure generated names are shorter than NAMEDATALEN */
2843 NAMEDATALEN - 1 - strlen(nbuf));
2845 strcpy(buf + nlen, nbuf);
2846 curname = buf;
2847 }
2848
2849 /* And attach to the result list */
2851 }
2852 return result;
2853}
uint32 result
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
static char * ChooseIndexExpressionName(Relation rel, Node *indexExpr)
Definition indexcmds.c:2865
List * lappend(List *list, void *datum)
Definition list.c:339
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition mbutils.c:1212
char * pstrdup(const char *in)
Definition mcxt.c:1910
#define NAMEDATALEN
#define lfirst(lc)
Definition pg_list.h:172
static char buf[DEFAULT_XLOG_SEG_SIZE]
#define sprintf
Definition port.h:263
char * indexcolname
Definition parsenodes.h:831
Definition pg_list.h:54

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

Referenced by DefineIndex().

◆ ChooseIndexExpressionName()

static char * ChooseIndexExpressionName ( Relation  rel,
Node *  indexExpr 
)
static

Definition at line 2865 of file indexcmds.c.

2866{
2868 CIEN_context context;
2869 int nlen;
2870
2871 /* Prepare ... */
2873 context.rel = rel;
2874 context.buf = &buf;
2875 /* Walk the tree, stopping when we have enough text */
2877 /* Ensure generated names are shorter than NAMEDATALEN */
2878 nlen = pg_mbcliplen(buf.data, buf.len, NAMEDATALEN - 1);
2879 buf.data[nlen] = '\0';
2880 return buf.data;
2881}
static bool ChooseIndexExpressionName_walker(Node *node, CIEN_context *context)
Definition indexcmds.c:2885
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
StringInfo buf
Definition indexcmds.c:80
Relation rel
Definition indexcmds.c:79

References CIEN_context::buf, buf, ChooseIndexExpressionName_walker(), fb(), initStringInfo(), NAMEDATALEN, pg_mbcliplen(), and CIEN_context::rel.

Referenced by ChooseIndexColumnNames().

◆ ChooseIndexExpressionName_walker()

static bool ChooseIndexExpressionName_walker ( Node *  node,
CIEN_context *  context 
)
static

Definition at line 2885 of file indexcmds.c.

2887{
2888 if (node == NULL)
2889 return false;
2890 if (IsA(node, Var))
2891 {
2892 Var *var = (Var *) node;
2893 TupleDesc tupdesc = RelationGetDescr(context->rel);
2895
2896 /* Paranoia: ignore the Var if it looks fishy */
2897 if (var->varno != 1 || var->varlevelsup != 0 ||
2898 var->varattno <= 0 || var->varattno > tupdesc->natts)
2899 return false;
2900 att = TupleDescAttr(tupdesc, var->varattno - 1);
2901 if (att->attisdropped)
2902 return false; /* even more paranoia; shouldn't happen */
2903
2904 if (context->buf->len > 0)
2905 appendStringInfoChar(context->buf, '_');
2906 appendStringInfoString(context->buf, NameStr(att->attname));
2907
2908 /* Done if we've already reached NAMEDATALEN */
2909 return (context->buf->len >= NAMEDATALEN);
2910 }
2911 else if (IsA(node, Const))
2912 {
2913 Const *constval = (Const *) node;
2914
2915 if (context->buf->len > 0)
2916 appendStringInfoChar(context->buf, '_');
2917 if (constval->constisnull)
2918 appendStringInfoString(context->buf, "NULL");
2919 else
2920 {
2921 Oid typoutput;
2922 bool typIsVarlena;
2923 char *extval;
2924
2925 getTypeOutputInfo(constval->consttype,
2926 &typoutput, &typIsVarlena);
2927 extval = OidOutputFunctionCall(typoutput, constval->constvalue);
2928
2929 /*
2930 * We sanitize constant values by dropping non-alphanumeric ASCII
2931 * characters. This is probably not really necessary, but it
2932 * reduces the odds of needing to double-quote the generated name.
2933 */
2934 for (const char *ptr = extval; *ptr; ptr++)
2935 {
2936 if (IS_HIGHBIT_SET(*ptr) ||
2937 strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2938 "abcdefghijklmnopqrstuvwxyz"
2939 "0123456789", *ptr) != NULL)
2940 appendStringInfoChar(context->buf, *ptr);
2941 }
2942 }
2943
2944 /* Done if we've already reached NAMEDATALEN */
2945 return (context->buf->len >= NAMEDATALEN);
2946 }
2947 else if (IsA(node, FuncExpr))
2948 {
2949 FuncExpr *funcexpr = (FuncExpr *) node;
2950 char *fname = get_func_name(funcexpr->funcid);
2951
2952 if (fname)
2953 {
2954 if (context->buf->len > 0)
2955 appendStringInfoChar(context->buf, '_');
2956 appendStringInfoString(context->buf, fname);
2957 }
2958 /* fall through to examine arguments */
2959 }
2960
2961 /* Abandon recursion once we reach NAMEDATALEN */
2962 if (context->buf->len >= NAMEDATALEN)
2963 return true;
2964
2966 context);
2967}
#define NameStr(name)
Definition c.h:894
#define IS_HIGHBIT_SET(ch)
Definition c.h:1284
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition fmgr.c:1764
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition lsyscache.c:3223
char * get_func_name(Oid funcid)
Definition lsyscache.c:1922
#define expression_tree_walker(n, w, c)
Definition nodeFuncs.h:153
#define IsA(nodeptr, _type_)
Definition nodes.h:162
FormData_pg_attribute * Form_pg_attribute
#define RelationGetDescr(relation)
Definition rel.h:542
void appendStringInfoString(StringInfo str, const char *s)
Definition stringinfo.c:230
void appendStringInfoChar(StringInfo str, char ch)
Definition stringinfo.c:242
Oid consttype
Definition primnodes.h:333
Oid funcid
Definition primnodes.h:770
AttrNumber varattno
Definition primnodes.h:275
int varno
Definition primnodes.h:270
Index varlevelsup
Definition primnodes.h:295

References appendStringInfoChar(), appendStringInfoString(), CIEN_context::buf, ChooseIndexExpressionName_walker(), Const::consttype, expression_tree_walker, fb(), FuncExpr::funcid, get_func_name(), getTypeOutputInfo(), IS_HIGHBIT_SET, IsA, StringInfoData::len, NAMEDATALEN, NameStr, TupleDescData::natts, OidOutputFunctionCall(), CIEN_context::rel, RelationGetDescr, TupleDescAttr(), Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by ChooseIndexExpressionName(), and ChooseIndexExpressionName_walker().

◆ ChooseIndexName()

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

Definition at line 2712 of file indexcmds.c.

2715{
2716 char *indexname;
2717
2718 if (primary)
2719 {
2720 /* the primary key's name does not depend on the specific column(s) */
2721 indexname = ChooseRelationName(tabname,
2722 NULL,
2723 "pkey",
2725 true);
2726 }
2727 else if (exclusionOpNames != NIL)
2728 {
2729 indexname = ChooseRelationName(tabname,
2730 ChooseIndexNameAddition(colnames),
2731 "excl",
2733 true);
2734 }
2735 else if (isconstraint)
2736 {
2737 indexname = ChooseRelationName(tabname,
2738 ChooseIndexNameAddition(colnames),
2739 "key",
2741 true);
2742 }
2743 else
2744 {
2745 indexname = ChooseRelationName(tabname,
2746 ChooseIndexNameAddition(colnames),
2747 "idx",
2749 false);
2750 }
2751
2752 return indexname;
2753}
char * ChooseRelationName(const char *name1, const char *name2, const char *label, Oid namespaceid, bool isconstraint)
Definition indexcmds.c:2644
static char * ChooseIndexNameAddition(const List *colnames)
Definition indexcmds.c:2767

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

Referenced by DefineIndex().

◆ ChooseIndexNameAddition()

static char * ChooseIndexNameAddition ( const List *  colnames)
static

Definition at line 2767 of file indexcmds.c.

2768{
2769 char buf[NAMEDATALEN * 2];
2770 int buflen = 0;
2771 ListCell *lc;
2772
2773 buf[0] = '\0';
2774 foreach(lc, colnames)
2775 {
2776 const char *name = (const char *) lfirst(lc);
2777
2778 if (buflen > 0)
2779 buf[buflen++] = '_'; /* insert _ between names */
2780
2781 /*
2782 * At this point we have buflen <= NAMEDATALEN. name should be less
2783 * than NAMEDATALEN already, but use strlcpy for paranoia.
2784 */
2785 strlcpy(buf + buflen, name, NAMEDATALEN);
2786 buflen += strlen(buf + buflen);
2787 if (buflen >= NAMEDATALEN)
2788 break;
2789 }
2790 return pstrdup(buf);
2791}
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 2644 of file indexcmds.c.

2647{
2648 int pass = 0;
2649 char *relname = NULL;
2650 char modlabel[NAMEDATALEN];
2653
2654 /* prepare to search pg_class with a dirty snapshot */
2657
2658 /* try the unmodified label first */
2659 strlcpy(modlabel, label, sizeof(modlabel));
2660
2661 for (;;)
2662 {
2663 ScanKeyData key[2];
2664 SysScanDesc scan;
2665 bool collides;
2666
2668
2669 /* is there any conflicting relation name? */
2670 ScanKeyInit(&key[0],
2674 ScanKeyInit(&key[1],
2678
2680 true /* indexOK */ ,
2682 2, key);
2683
2685
2686 systable_endscan(scan);
2687
2688 /* break out of loop if no conflict */
2689 if (!collides)
2690 {
2691 if (!isconstraint ||
2693 break;
2694 }
2695
2696 /* found a conflict, so try a new name component */
2697 pfree(relname);
2698 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
2699 }
2700
2702
2703 return relname;
2704}
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:2556
static char * label
NameData relname
Definition pg_class.h:40
bool ConstraintNameExists(const char *conname, Oid namespaceid)
#define snprintf
Definition port.h:261
static Datum CStringGetDatum(const char *X)
Definition postgres.h:383
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 build_new_indexes(), ChooseIndexName(), generateSerialExtraStmts(), and ReindexRelationConcurrently().

◆ CompareOpclassOptions()

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

Definition at line 373 of file indexcmds.c.

374{
375 int i;
376 FmgrInfo fm;
377
378 if (!opts1 && !opts2)
379 return true;
380
382 for (i = 0; i < natts; i++)
383 {
384 Datum opt1 = opts1 ? opts1[i] : (Datum) 0;
385 Datum opt2 = opts2 ? opts2[i] : (Datum) 0;
386
387 if (opt1 == (Datum) 0)
388 {
389 if (opt2 == (Datum) 0)
390 continue;
391 else
392 return false;
393 }
394 else if (opt2 == (Datum) 0)
395 return false;
396
397 /*
398 * Compare non-NULL text[] datums. Use C collation to enforce binary
399 * equivalence of texts, because we don't know anything about the
400 * semantics of opclass options.
401 */
403 return false;
404 }
405
406 return true;
407}
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 1891 of file indexcmds.c.

1909{
1911 ListCell *lc;
1912 int attn;
1913 int nkeycols = indexInfo->ii_NumIndexKeyAttrs;
1914 Oid save_userid;
1915 int save_sec_context;
1916
1917 /* Allocate space for exclusion operator info, if needed */
1918 if (exclusionOpNames)
1919 {
1925 }
1926 else
1927 nextExclOp = NULL;
1928
1929 /*
1930 * If this is a WITHOUT OVERLAPS constraint, we need space for exclusion
1931 * ops, but we don't need to parse anything, so we can let nextExclOp be
1932 * NULL. Note that for partitions/inheriting/LIKE, exclusionOpNames will
1933 * be set, so we already allocated above.
1934 */
1935 if (iswithoutoverlaps)
1936 {
1937 if (exclusionOpNames == NIL)
1938 {
1942 }
1943 nextExclOp = NULL;
1944 }
1945
1947 GetUserIdAndSecContext(&save_userid, &save_sec_context);
1948
1949 /*
1950 * process attributeList
1951 */
1952 attn = 0;
1953 foreach(lc, attList)
1954 {
1956 Oid atttype;
1957 Oid attcollation;
1958
1959 /*
1960 * Process the column-or-expression to be indexed.
1961 */
1962 if (attribute->name != NULL)
1963 {
1964 /* Simple index attribute */
1967
1968 Assert(attribute->expr == NULL);
1971 {
1972 /* difference in error message spellings is historical */
1973 if (isconstraint)
1974 ereport(ERROR,
1976 errmsg("column \"%s\" named in key does not exist",
1977 attribute->name),
1978 parser_errposition(pstate, attribute->location)));
1979 else
1980 ereport(ERROR,
1982 errmsg("column \"%s\" does not exist",
1983 attribute->name),
1984 parser_errposition(pstate, attribute->location)));
1985 }
1987 indexInfo->ii_IndexAttrNumbers[attn] = attform->attnum;
1988 atttype = attform->atttypid;
1989 attcollation = attform->attcollation;
1991 }
1992 else
1993 {
1994 /* Index expression */
1995 Node *expr = attribute->expr;
1996
1997 Assert(expr != NULL);
1998
1999 if (attn >= nkeycols)
2000 ereport(ERROR,
2002 errmsg("expressions are not supported in included columns"),
2003 parser_errposition(pstate, attribute->location)));
2004 atttype = exprType(expr);
2005 attcollation = exprCollation(expr);
2006
2007 /*
2008 * Strip any top-level COLLATE clause. This ensures that we treat
2009 * "x COLLATE y" and "(x COLLATE y)" alike.
2010 */
2011 while (IsA(expr, CollateExpr))
2012 expr = (Node *) ((CollateExpr *) expr)->arg;
2013
2014 if (IsA(expr, Var) &&
2015 ((Var *) expr)->varattno != InvalidAttrNumber)
2016 {
2017 /*
2018 * User wrote "(column)" or "(column COLLATE something)".
2019 * Treat it like simple attribute anyway.
2020 */
2021 indexInfo->ii_IndexAttrNumbers[attn] = ((Var *) expr)->varattno;
2022 }
2023 else
2024 {
2025 indexInfo->ii_IndexAttrNumbers[attn] = 0; /* marks expression */
2026 indexInfo->ii_Expressions = lappend(indexInfo->ii_Expressions,
2027 expr);
2028
2029 /*
2030 * transformExpr() should have already rejected subqueries,
2031 * aggregates, and window functions, based on the EXPR_KIND_
2032 * for an index expression.
2033 */
2034
2035 /*
2036 * An expression using mutable functions is probably wrong,
2037 * since if you aren't going to get the same result for the
2038 * same data every time, it's not clear what the index entries
2039 * mean at all.
2040 */
2042 ereport(ERROR,
2044 errmsg("functions in index expression must be marked IMMUTABLE"),
2045 parser_errposition(pstate, attribute->location)));
2046 }
2047 }
2048
2049 typeOids[attn] = atttype;
2050
2051 /*
2052 * Included columns have no collation, no opclass and no ordering
2053 * options.
2054 */
2055 if (attn >= nkeycols)
2056 {
2057 if (attribute->collation)
2058 ereport(ERROR,
2060 errmsg("including column does not support a collation"),
2061 parser_errposition(pstate, attribute->location)));
2062 if (attribute->opclass)
2063 ereport(ERROR,
2065 errmsg("including column does not support an operator class"),
2066 parser_errposition(pstate, attribute->location)));
2067 if (attribute->ordering != SORTBY_DEFAULT)
2068 ereport(ERROR,
2070 errmsg("including column does not support ASC/DESC options"),
2071 parser_errposition(pstate, attribute->location)));
2072 if (attribute->nulls_ordering != SORTBY_NULLS_DEFAULT)
2073 ereport(ERROR,
2075 errmsg("including column does not support NULLS FIRST/LAST options"),
2076 parser_errposition(pstate, attribute->location)));
2077
2079 opclassOptions[attn] = (Datum) 0;
2080 colOptions[attn] = 0;
2082 attn++;
2083
2084 continue;
2085 }
2086
2087 /*
2088 * Apply collation override if any. Use of ddl_userid is necessary
2089 * due to ACL checks therein, and it's safe because collations don't
2090 * contain opaque expressions (or non-opaque expressions).
2091 */
2092 if (attribute->collation)
2093 {
2095 {
2098 }
2099 attcollation = get_collation_oid(attribute->collation, false);
2101 {
2102 SetUserIdAndSecContext(save_userid, save_sec_context);
2105 }
2106 }
2107
2108 /*
2109 * Check we have a collation iff it's a collatable type. The only
2110 * expected failures here are (1) COLLATE applied to a noncollatable
2111 * type, or (2) index expression had an unresolved collation. But we
2112 * might as well code this to be a complete consistency check.
2113 */
2114 if (type_is_collatable(atttype))
2115 {
2116 if (!OidIsValid(attcollation))
2117 ereport(ERROR,
2119 errmsg("could not determine which collation to use for index expression"),
2120 errhint("Use the COLLATE clause to set the collation explicitly."),
2121 parser_errposition(pstate, attribute->location)));
2122 }
2123 else
2124 {
2125 if (OidIsValid(attcollation))
2126 ereport(ERROR,
2128 errmsg("collations are not supported by type %s",
2129 format_type_be(atttype)),
2130 parser_errposition(pstate, attribute->location)));
2131 }
2132
2133 collationOids[attn] = attcollation;
2134
2135 /*
2136 * Identify the opclass to use. Use of ddl_userid is necessary due to
2137 * ACL checks therein. This is safe despite opclasses containing
2138 * opaque expressions (specifically, functions), because only
2139 * superusers can define opclasses.
2140 */
2142 {
2145 }
2147 atttype,
2151 {
2152 SetUserIdAndSecContext(save_userid, save_sec_context);
2155 }
2156
2157 /*
2158 * Identify the exclusion operator, if any.
2159 */
2160 if (nextExclOp)
2161 {
2163 Oid opid;
2164 Oid opfamily;
2165 int strat;
2166
2167 /*
2168 * Find the operator --- it must accept the column datatype
2169 * without runtime coercion (but binary compatibility is OK).
2170 * Operators contain opaque expressions (specifically, functions).
2171 * compatible_oper_opid() boils down to oper() and
2172 * IsBinaryCoercible(). PostgreSQL would have security problems
2173 * elsewhere if oper() started calling opaque expressions.
2174 */
2176 {
2179 }
2180 opid = compatible_oper_opid(opname, atttype, atttype, false);
2182 {
2183 SetUserIdAndSecContext(save_userid, save_sec_context);
2186 }
2187
2188 /*
2189 * Only allow commutative operators to be used in exclusion
2190 * constraints. If X conflicts with Y, but Y does not conflict
2191 * with X, bad things will happen.
2192 */
2193 if (get_commutator(opid) != opid)
2194 ereport(ERROR,
2196 errmsg("operator %s is not commutative",
2197 format_operator(opid)),
2198 errdetail("Only commutative operators can be used in exclusion constraints."),
2199 parser_errposition(pstate, attribute->location)));
2200
2201 /*
2202 * Operator must be a member of the right opfamily, too
2203 */
2204 opfamily = get_opclass_family(opclassOids[attn]);
2205 strat = get_op_opfamily_strategy(opid, opfamily);
2206 if (strat == 0)
2207 ereport(ERROR,
2209 errmsg("operator %s is not a member of operator family \"%s\"",
2210 format_operator(opid),
2211 get_opfamily_name(opfamily, false)),
2212 errdetail("The exclusion operator must be related to the index operator class for the constraint."),
2213 parser_errposition(pstate, attribute->location)));
2214
2215 indexInfo->ii_ExclusionOps[attn] = opid;
2216 indexInfo->ii_ExclusionProcs[attn] = get_opcode(opid);
2217 indexInfo->ii_ExclusionStrats[attn] = strat;
2219 }
2220 else if (iswithoutoverlaps)
2221 {
2222 CompareType cmptype;
2224 Oid opid;
2225
2226 if (attn == nkeycols - 1)
2227 cmptype = COMPARE_OVERLAP;
2228 else
2229 cmptype = COMPARE_EQ;
2231 indexInfo->ii_ExclusionOps[attn] = opid;
2232 indexInfo->ii_ExclusionProcs[attn] = get_opcode(opid);
2233 indexInfo->ii_ExclusionStrats[attn] = strat;
2234 }
2235
2236 /*
2237 * Set up the per-column options (indoption field). For now, this is
2238 * zero for any un-ordered index, while ordered indexes have DESC and
2239 * NULLS FIRST/LAST options.
2240 */
2241 colOptions[attn] = 0;
2242 if (amcanorder)
2243 {
2244 /* default ordering is ASC */
2245 if (attribute->ordering == SORTBY_DESC)
2247 /* default null ordering is LAST for ASC, FIRST for DESC */
2248 if (attribute->nulls_ordering == SORTBY_NULLS_DEFAULT)
2249 {
2250 if (attribute->ordering == SORTBY_DESC)
2252 }
2253 else if (attribute->nulls_ordering == SORTBY_NULLS_FIRST)
2255 }
2256 else
2257 {
2258 /* index AM does not support ordering */
2259 if (attribute->ordering != SORTBY_DEFAULT)
2260 ereport(ERROR,
2262 errmsg("access method \"%s\" does not support ASC/DESC options",
2264 parser_errposition(pstate, attribute->location)));
2265 if (attribute->nulls_ordering != SORTBY_NULLS_DEFAULT)
2266 ereport(ERROR,
2268 errmsg("access method \"%s\" does not support NULLS FIRST/LAST options",
2270 parser_errposition(pstate, attribute->location)));
2271 }
2272
2273 /* Set up the per-column opclass options (attoptions field). */
2274 if (attribute->opclassopts)
2275 {
2276 Assert(attn < nkeycols);
2277
2279 transformRelOptions((Datum) 0, attribute->opclassopts,
2280 NULL, NULL, false, false);
2281 }
2282 else
2283 opclassOptions[attn] = (Datum) 0;
2284
2285 attn++;
2286 }
2287}
#define InvalidAttrNumber
Definition attnum.h:23
#define OidIsValid(objectId)
Definition c.h:917
CompareType
Definition cmptype.h:32
@ COMPARE_OVERLAP
Definition cmptype.h:40
@ COMPARE_EQ
Definition cmptype.h:36
Datum arg
Definition elog.c:1323
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:2296
void GetOperatorFromCompareType(Oid opclass, Oid rhstype, CompareType cmptype, Oid *opid, StrategyNumber *strat)
Definition indexcmds.c:2483
Oid get_opclass_family(Oid opclass)
Definition lsyscache.c:1442
RegProcedure get_opcode(Oid opno)
Definition lsyscache.c:1585
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:1553
bool type_is_collatable(Oid typid)
Definition lsyscache.c:3397
Oid get_commutator(Oid opno)
Definition lsyscache.c:1823
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
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:497
@ 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
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
uint16 * ii_ExclusionStrats
Definition execnodes.h:206
int ii_NumIndexKeyAttrs
Definition execnodes.h:183
List * ii_Expressions
Definition execnodes.h:192
Oid * ii_ExclusionProcs
Definition execnodes.h:204
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition execnodes.h:189
Definition nodes.h:133
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition syscache.c:476

References arg, Assert, AtEOXact_GUC(), COMPARE_EQ, COMPARE_OVERLAP, compatible_oper_opid(), contain_mutable_functions_after_planning(), ereport, errcode(), errdetail(), errhint(), errmsg, ERROR, 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(), NewGUCNestLevel(), NIL, OidIsValid, 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 555 of file indexcmds.c.

567{
568 bool concurrent;
569 char *indexRelationName;
570 char *accessMethodName;
571 Oid *typeIds;
581 Relation rel;
582 HeapTuple tuple;
585 bool amcanorder;
586 bool amissummarizing;
587 amoptions_function amoptions;
588 bool exclusion;
589 bool partitioned;
590 bool safe_index;
591 Datum reloptions;
593 IndexInfo *indexInfo;
594 uint16 flags;
599 ObjectAddress address;
600 LockRelId heaprelid;
602 LOCKMODE lockmode;
603 Snapshot snapshot;
607
609
611
612 /*
613 * Some callers need us to run with an empty default_tablespace; this is a
614 * necessary hack to be able to reproduce catalog state accurately when
615 * recreating indexes after table-rewriting ALTER TABLE.
616 */
617 if (stmt->reset_default_tblspc)
618 (void) set_config_option("default_tablespace", "",
620 GUC_ACTION_SAVE, true, 0, false);
621
622 /*
623 * Force non-concurrent build on temporary relations, even if CONCURRENTLY
624 * was requested. Other backends can't access a temporary relation, so
625 * there's no harm in grabbing a stronger lock, and a non-concurrent DROP
626 * is more efficient. Do this before any use of the concurrent option is
627 * done.
628 */
630 concurrent = true;
631 else
632 concurrent = false;
633
634 /*
635 * Start progress report. If we're building a partition, this was already
636 * done.
637 */
639 {
642 concurrent ?
645 }
646
647 /*
648 * No index OID to report yet
649 */
651 InvalidOid);
652
653 /*
654 * count key attributes in index
655 */
656 numberOfKeyAttributes = list_length(stmt->indexParams);
657
658 /*
659 * Calculate the new list of index columns including both key columns and
660 * INCLUDE columns. Later we can determine which of these are key
661 * columns, and which are just part of the INCLUDE list by checking the
662 * list position. A list item in a position less than ii_NumIndexKeyAttrs
663 * is part of the key columns, and anything equal to and over is part of
664 * the INCLUDE columns.
665 */
666 allIndexParams = list_concat_copy(stmt->indexParams,
667 stmt->indexIncludingParams);
669
670 if (numberOfKeyAttributes <= 0)
673 errmsg("must specify at least one column")));
677 errmsg("cannot use more than %d columns in an index",
679
680 /*
681 * Only SELECT ... FOR UPDATE/SHARE are allowed while doing a standard
682 * index build; but for concurrent builds we allow INSERT/UPDATE/DELETE
683 * (but not VACUUM).
684 *
685 * NB: Caller is responsible for making sure that tableId refers to the
686 * relation on which the index should be built; except in bootstrap mode,
687 * this will typically require the caller to have already locked the
688 * relation. To avoid lock upgrade hazards, that lock should be at least
689 * as strong as the one we take here.
690 *
691 * NB: If the lock strength here ever changes, code that is run by
692 * parallel workers under the control of certain particular ambuild
693 * functions will need to be updated, too.
694 */
695 lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock;
696 rel = table_open(tableId, lockmode);
697
698 /*
699 * Switch to the table owner's userid, so that any index functions are run
700 * as that user. Also lock down security-restricted operations. We
701 * already arranged to make GUC variable changes local to this command.
702 */
704 SetUserIdAndSecContext(rel->rd_rel->relowner,
706
708
709 /*
710 * It has exclusion constraint behavior if it's an EXCLUDE constraint or a
711 * temporal PRIMARY KEY/UNIQUE constraint
712 */
713 exclusion = stmt->excludeOpNames || stmt->iswithoutoverlaps;
714
715 /* Ensure that it makes sense to index this kind of relation */
716 switch (rel->rd_rel->relkind)
717 {
718 case RELKIND_RELATION:
719 case RELKIND_MATVIEW:
721 /* OK */
722 break;
723 default:
726 errmsg("cannot create index on relation \"%s\"",
729 break;
730 }
731
732 /*
733 * Establish behavior for partitioned tables, and verify sanity of
734 * parameters.
735 *
736 * We do not build an actual index in this case; we only create a few
737 * catalog entries. The actual indexes are built by recursing for each
738 * partition.
739 */
741 if (partitioned)
742 {
743 /*
744 * Note: we check 'stmt->concurrent' rather than 'concurrent', so that
745 * the error is thrown also for temporary tables. Seems better to be
746 * consistent, even though we could do it on temporary table because
747 * we're not actually doing it concurrently.
748 */
749 if (stmt->concurrent)
752 errmsg("cannot create index on partitioned table \"%s\" concurrently",
754 }
755
756 /*
757 * Don't try to CREATE INDEX on temp tables of other backends.
758 */
759 if (RELATION_IS_OTHER_TEMP(rel))
762 errmsg("cannot create indexes on temporary tables of other sessions")));
763
764 /*
765 * Unless our caller vouches for having checked this already, insist that
766 * the table not be in use by our own session, either. Otherwise we might
767 * fail to make entries in the new index (for instance, if an INSERT or
768 * UPDATE is in progress and has already made its list of target indexes).
769 */
771 CheckTableNotInUse(rel, "CREATE INDEX");
772
773 /*
774 * Verify we (still) have CREATE rights in the rel's namespace.
775 * (Presumably we did when the rel was created, but maybe not anymore.)
776 * Skip check if caller doesn't want it. Also skip check if
777 * bootstrapping, since permissions machinery may not be working yet.
778 */
780 {
782
784 ACL_CREATE);
785 if (aclresult != ACLCHECK_OK)
788 }
789
790 /*
791 * Select tablespace to use. If not specified, use default tablespace
792 * (which may in turn default to database's default).
793 */
794 if (stmt->tableSpace)
795 {
796 tablespaceId = get_tablespace_oid(stmt->tableSpace, false);
800 errmsg("cannot specify default tablespace for partitioned relations")));
801 }
802 else
803 {
804 tablespaceId = GetDefaultTablespace(rel->rd_rel->relpersistence,
806 /* note InvalidOid is OK in this case */
807 }
808
809 /* Check tablespace permissions */
810 if (check_rights &&
812 {
814
816 ACL_CREATE);
817 if (aclresult != ACLCHECK_OK)
820 }
821
822 /*
823 * Force shared indexes into the pg_global tablespace. This is a bit of a
824 * hack but seems simpler than marking them in the BKI commands. On the
825 * other hand, if it's not shared, don't allow it to be placed there.
826 */
827 if (rel->rd_rel->relisshared)
832 errmsg("only shared relations can be placed in pg_global tablespace")));
833
834 /*
835 * Choose the index column names.
836 */
838
839 /*
840 * Select name for index if caller didn't specify
841 */
842 indexRelationName = stmt->idxname;
843 if (indexRelationName == NULL)
847 stmt->excludeOpNames,
848 stmt->primary,
849 stmt->isconstraint);
850
851 /*
852 * look up the access method, verify it can handle the requested features
853 */
854 accessMethodName = stmt->accessMethod;
856 if (!HeapTupleIsValid(tuple))
857 {
858 /*
859 * Hack to provide more-or-less-transparent updating of old RTREE
860 * indexes to GiST: if RTREE is requested and not found, use GIST.
861 */
862 if (strcmp(accessMethodName, "rtree") == 0)
863 {
865 (errmsg("substituting access method \"gist\" for obsolete method \"rtree\"")));
866 accessMethodName = "gist";
868 }
869
870 if (!HeapTupleIsValid(tuple))
873 errmsg("access method \"%s\" does not exist",
875 }
879
882
883 if (stmt->unique && !stmt->iswithoutoverlaps && !amRoutine->amcanunique)
886 errmsg("access method \"%s\" does not support unique indexes",
888 if (stmt->indexIncludingParams != NIL && !amRoutine->amcaninclude)
891 errmsg("access method \"%s\" does not support included columns",
893 if (numberOfKeyAttributes > 1 && !amRoutine->amcanmulticol)
896 errmsg("access method \"%s\" does not support multicolumn indexes",
898 if (exclusion && amRoutine->amgettuple == NULL)
901 errmsg("access method \"%s\" does not support exclusion constraints",
903 if (stmt->iswithoutoverlaps && strcmp(accessMethodName, "gist") != 0)
906 errmsg("access method \"%s\" does not support WITHOUT OVERLAPS constraints",
908
909 amcanorder = amRoutine->amcanorder;
910 amoptions = amRoutine->amoptions;
911 amissummarizing = amRoutine->amsummarizing;
912
913 ReleaseSysCache(tuple);
914
915 /*
916 * Validate predicate, if given
917 */
918 if (stmt->whereClause)
919 CheckPredicate((Expr *) stmt->whereClause);
920
921 /*
922 * Parse AM-specific options, convert to text array form, validate.
923 */
924 reloptions = transformRelOptions((Datum) 0, stmt->options,
925 NULL, NULL, false, false);
926
927 (void) index_reloptions(amoptions, reloptions, true);
928
929 /*
930 * Prepare arguments for index_create, primarily an IndexInfo structure.
931 * Note that predicates must be in implicit-AND format. In a concurrent
932 * build, mark it not-ready-for-inserts.
933 */
937 NIL, /* expressions, NIL for now */
938 make_ands_implicit((Expr *) stmt->whereClause),
939 stmt->unique,
940 stmt->nulls_not_distinct,
941 !concurrent,
942 concurrent,
944 stmt->iswithoutoverlaps);
945
951 ComputeIndexAttrs(pstate,
952 indexInfo,
955 stmt->excludeOpNames, tableId,
957 amcanorder, stmt->isconstraint, stmt->iswithoutoverlaps,
960
961 /*
962 * Extra checks when creating a PRIMARY KEY index.
963 */
964 if (stmt->primary)
966
967 /*
968 * If this table is partitioned and we're creating a unique index, primary
969 * key, or exclusion constraint, make sure that the partition key is a
970 * subset of the index's columns. Otherwise it would be possible to
971 * violate uniqueness by putting values that ought to be unique in
972 * different partitions.
973 *
974 * We could lift this limitation if we had global indexes, but those have
975 * their own problems, so this is a useful feature combination.
976 */
977 if (partitioned && (stmt->unique || exclusion))
978 {
980 const char *constraint_type;
981 int i;
982
983 if (stmt->primary)
984 constraint_type = "PRIMARY KEY";
985 else if (stmt->unique)
986 constraint_type = "UNIQUE";
987 else if (stmt->excludeOpNames)
988 constraint_type = "EXCLUDE";
989 else
990 {
991 elog(ERROR, "unknown constraint type");
992 constraint_type = NULL; /* keep compiler quiet */
993 }
994
995 /*
996 * Verify that all the columns in the partition key appear in the
997 * unique key definition, with the same notion of equality.
998 */
999 for (i = 0; i < key->partnatts; i++)
1000 {
1001 bool found = false;
1002 int eq_strategy;
1004 int j;
1005
1006 /*
1007 * Identify the equality operator associated with this partkey
1008 * column. For list and range partitioning, partkeys use btree
1009 * operator classes; hash partitioning uses hash operator classes.
1010 * (Keep this in sync with ComputePartitionAttrs!)
1011 */
1012 if (key->strategy == PARTITION_STRATEGY_HASH)
1014 else
1016
1017 ptkey_eqop = get_opfamily_member(key->partopfamily[i],
1018 key->partopcintype[i],
1019 key->partopcintype[i],
1020 eq_strategy);
1021 if (!OidIsValid(ptkey_eqop))
1022 elog(ERROR, "missing operator %d(%u,%u) in partition opfamily %u",
1023 eq_strategy, key->partopcintype[i], key->partopcintype[i],
1024 key->partopfamily[i]);
1025
1026 /*
1027 * It may be possible to support UNIQUE constraints when partition
1028 * keys are expressions, but is it worth it? Give up for now.
1029 */
1030 if (key->partattrs[i] == 0)
1031 ereport(ERROR,
1033 errmsg("unsupported %s constraint with partition key definition",
1035 errdetail("%s constraints cannot be used when partition keys include expressions.",
1036 constraint_type)));
1037
1038 /* Search the index column(s) for a match */
1039 for (j = 0; j < indexInfo->ii_NumIndexKeyAttrs; j++)
1040 {
1041 if (key->partattrs[i] == indexInfo->ii_IndexAttrNumbers[j])
1042 {
1043 /*
1044 * Matched the column, now what about the collation and
1045 * equality op?
1046 */
1049
1050 if (key->partcollation[i] != collationIds[j])
1051 continue;
1052
1054 &idx_opfamily,
1055 &idx_opcintype))
1056 {
1058
1059 if (stmt->unique && !stmt->iswithoutoverlaps)
1063 COMPARE_EQ);
1064 else if (exclusion)
1065 idx_eqop = indexInfo->ii_ExclusionOps[j];
1066
1067 if (!idx_eqop)
1068 ereport(ERROR,
1070 errmsg("could not identify an equality operator for type %s", format_type_be(idx_opcintype)),
1071 errdetail("There is no suitable operator in operator family \"%s\" for access method \"%s\".",
1073
1074 if (ptkey_eqop == idx_eqop)
1075 {
1076 found = true;
1077 break;
1078 }
1079 else if (exclusion)
1080 {
1081 /*
1082 * We found a match, but it's not an equality
1083 * operator. Instead of failing below with an
1084 * error message about a missing column, fail now
1085 * and explain that the operator is wrong.
1086 */
1087 Form_pg_attribute att = TupleDescAttr(RelationGetDescr(rel), key->partattrs[i] - 1);
1088
1089 ereport(ERROR,
1091 errmsg("cannot match partition key to index on column \"%s\" using non-equal operator \"%s\"",
1092 NameStr(att->attname),
1093 get_opname(indexInfo->ii_ExclusionOps[j]))));
1094 }
1095 }
1096 }
1097 }
1098
1099 if (!found)
1100 {
1102
1104 key->partattrs[i] - 1);
1105 ereport(ERROR,
1107 /* translator: %s is UNIQUE, PRIMARY KEY, etc */
1108 errmsg("%s constraint on partitioned table must include all partitioning columns",
1110 /* translator: first %s is UNIQUE, PRIMARY KEY, etc */
1111 errdetail("%s constraint on table \"%s\" lacks column \"%s\" which is part of the partition key.",
1113 NameStr(att->attname))));
1114 }
1115 }
1116 }
1117
1118
1119 /*
1120 * We disallow indexes on system columns. They would not necessarily get
1121 * updated correctly, and they don't seem useful anyway.
1122 *
1123 * Also disallow virtual generated columns in indexes (use expression
1124 * index instead).
1125 */
1126 for (int i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
1127 {
1128 AttrNumber attno = indexInfo->ii_IndexAttrNumbers[i];
1129
1130 if (attno < 0)
1131 ereport(ERROR,
1133 errmsg("index creation on system columns is not supported")));
1134
1135
1136 if (attno > 0 &&
1137 TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
1138 ereport(ERROR,
1140 stmt->primary ?
1141 errmsg("primary keys on virtual generated columns are not supported") :
1142 stmt->isconstraint ?
1143 errmsg("unique constraints on virtual generated columns are not supported") :
1144 errmsg("indexes on virtual generated columns are not supported"));
1145 }
1146
1147 /*
1148 * Also check for system and generated columns used in expressions or
1149 * predicates.
1150 */
1151 if (indexInfo->ii_Expressions || indexInfo->ii_Predicate)
1152 {
1154 int j;
1155
1156 pull_varattnos((Node *) indexInfo->ii_Expressions, 1, &indexattrs);
1157 pull_varattnos((Node *) indexInfo->ii_Predicate, 1, &indexattrs);
1158
1159 for (int i = FirstLowInvalidHeapAttributeNumber + 1; i < 0; i++)
1160 {
1162 indexattrs))
1163 ereport(ERROR,
1165 errmsg("index creation on system columns is not supported")));
1166 }
1167
1168 /*
1169 * XXX Virtual generated columns in index expressions or predicates
1170 * could be supported, but it needs support in
1171 * RelationGetIndexExpressions() and RelationGetIndexPredicate().
1172 */
1173 j = -1;
1174 while ((j = bms_next_member(indexattrs, j)) >= 0)
1175 {
1177
1178 if (attno > 0 &&
1179 TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
1180 ereport(ERROR,
1182 stmt->isconstraint ?
1183 errmsg("unique constraints on virtual generated columns are not supported") :
1184 errmsg("indexes on virtual generated columns are not supported")));
1185 }
1186 }
1187
1188 /* Is index safe for others to ignore? See set_indexsafe_procflags() */
1189 safe_index = indexInfo->ii_Expressions == NIL &&
1190 indexInfo->ii_Predicate == NIL;
1191
1192 /*
1193 * Report index creation if appropriate (delay this till after most of the
1194 * error checks)
1195 */
1196 if (stmt->isconstraint && !quiet)
1197 {
1198 const char *constraint_type;
1199
1200 if (stmt->primary)
1201 constraint_type = "PRIMARY KEY";
1202 else if (stmt->unique)
1203 constraint_type = "UNIQUE";
1204 else if (stmt->excludeOpNames)
1205 constraint_type = "EXCLUDE";
1206 else
1207 {
1208 elog(ERROR, "unknown constraint type");
1209 constraint_type = NULL; /* keep compiler quiet */
1210 }
1211
1213 (errmsg_internal("%s %s will create implicit index \"%s\" for table \"%s\"",
1214 is_alter_table ? "ALTER TABLE / ADD" : "CREATE TABLE /",
1217 }
1218
1219 /*
1220 * A valid stmt->oldNumber implies that we already have a built form of
1221 * the index. The caller should also decline any index build.
1222 */
1223 Assert(!RelFileNumberIsValid(stmt->oldNumber) || (skip_build && !concurrent));
1224
1225 /*
1226 * Make the catalog entries for the index, including constraints. This
1227 * step also actually builds the index, except if caller requested not to
1228 * or in concurrent mode, in which case it'll be done later, or doing a
1229 * partitioned index (because those don't have storage).
1230 */
1231 flags = constr_flags = 0;
1232 if (stmt->isconstraint)
1234 if (skip_build || concurrent || partitioned)
1235 flags |= INDEX_CREATE_SKIP_BUILD;
1236 if (stmt->if_not_exists)
1238 if (concurrent)
1239 flags |= INDEX_CREATE_CONCURRENT;
1240 if (partitioned)
1241 flags |= INDEX_CREATE_PARTITIONED;
1242 if (stmt->primary)
1243 flags |= INDEX_CREATE_IS_PRIMARY;
1244
1245 /*
1246 * If the table is partitioned, and recursion was declined but partitions
1247 * exist, mark the index as invalid.
1248 */
1249 if (partitioned && stmt->relation && !stmt->relation->inh)
1250 {
1252
1253 if (pd->nparts != 0)
1254 flags |= INDEX_CREATE_INVALID;
1255 }
1256
1257 if (stmt->deferrable)
1259 if (stmt->initdeferred)
1261 if (stmt->iswithoutoverlaps)
1263
1267 stmt->oldNumber, indexInfo, indexColNames,
1270 coloptions, NULL, reloptions,
1271 flags, constr_flags,
1274
1276
1278 {
1279 /*
1280 * Roll back any GUC changes executed by index functions. Also revert
1281 * to original default_tablespace if we changed it above.
1282 */
1284
1285 /* Restore userid and security context */
1287
1288 table_close(rel, NoLock);
1289
1290 /* If this is the top-level index, we're done */
1293
1294 return address;
1295 }
1296
1297 /*
1298 * Roll back any GUC changes executed by index functions, and keep
1299 * subsequent changes local to this command. This is essential if some
1300 * index function changed a behavior-affecting GUC, e.g. search_path.
1301 */
1305
1306 /* Add any requested comment */
1307 if (stmt->idxcomment != NULL)
1309 stmt->idxcomment);
1310
1311 if (partitioned)
1312 {
1313 PartitionDesc partdesc;
1314
1315 /*
1316 * Unless caller specified to skip this step (via ONLY), process each
1317 * partition to make sure they all contain a corresponding index.
1318 *
1319 * If we're called internally (no stmt->relation), recurse always.
1320 */
1321 partdesc = RelationGetPartitionDesc(rel, true);
1322 if ((!stmt->relation || stmt->relation->inh) && partdesc->nparts > 0)
1323 {
1324 int nparts = partdesc->nparts;
1325 Oid *part_oids = palloc_array(Oid, nparts);
1326 bool invalidate_parent = false;
1329
1330 /*
1331 * Report the total number of partitions at the start of the
1332 * command; don't update it when being called recursively.
1333 */
1335 {
1336 /*
1337 * When called by ProcessUtilitySlow, the number of partitions
1338 * is passed in as an optimization; but other callers pass -1
1339 * since they don't have the value handy. This should count
1340 * partitions the same way, ie one less than the number of
1341 * relations find_all_inheritors reports.
1342 *
1343 * We assume we needn't ask find_all_inheritors to take locks,
1344 * because that should have happened already for all callers.
1345 * Even if it did not, this is safe as long as we don't try to
1346 * touch the partitions here; the worst consequence would be a
1347 * bogus progress-reporting total.
1348 */
1349 if (total_parts < 0)
1350 {
1352
1353 total_parts = list_length(children) - 1;
1354 list_free(children);
1355 }
1356
1358 total_parts);
1359 }
1360
1361 /* Make a local copy of partdesc->oids[], just for safety */
1362 memcpy(part_oids, partdesc->oids, sizeof(Oid) * nparts);
1363
1364 /*
1365 * We'll need an IndexInfo describing the parent index. The one
1366 * built above is almost good enough, but not quite, because (for
1367 * example) its predicate expression if any hasn't been through
1368 * expression preprocessing. The most reliable way to get an
1369 * IndexInfo that will match those for child indexes is to build
1370 * it the same way, using BuildIndexInfo().
1371 */
1373 indexInfo = BuildIndexInfo(parentIndex);
1374
1376
1377 /*
1378 * For each partition, scan all existing indexes; if one matches
1379 * our index definition and is not already attached to some other
1380 * parent index, attach it to the one we just created.
1381 *
1382 * If none matches, build a new index by calling ourselves
1383 * recursively with the same options (except for the index name).
1384 */
1385 for (int i = 0; i < nparts; i++)
1386 {
1392 List *childidxs;
1393 ListCell *cell;
1394 AttrMap *attmap;
1395 bool found = false;
1396
1397 childrel = table_open(childRelid, lockmode);
1398
1401 SetUserIdAndSecContext(childrel->rd_rel->relowner,
1405
1406 /*
1407 * Don't try to create indexes on foreign tables, though. Skip
1408 * those if a regular index, or fail if trying to create a
1409 * constraint index.
1410 */
1411 if (childrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1412 {
1413 if (stmt->unique || stmt->primary)
1414 ereport(ERROR,
1416 errmsg("cannot create unique index on partitioned table \"%s\"",
1418 errdetail("Table \"%s\" contains partitions that are foreign tables.",
1420
1424 table_close(childrel, lockmode);
1425 continue;
1426 }
1427
1429 attmap =
1431 parentDesc,
1432 false);
1433
1434 foreach(cell, childidxs)
1435 {
1436 Oid cldidxid = lfirst_oid(cell);
1439
1440 /* this index is already partition of another one */
1442 continue;
1443
1444 cldidx = index_open(cldidxid, lockmode);
1446 if (CompareIndexInfo(cldIdxInfo, indexInfo,
1447 cldidx->rd_indcollation,
1448 parentIndex->rd_indcollation,
1449 cldidx->rd_opfamily,
1450 parentIndex->rd_opfamily,
1451 attmap))
1452 {
1454
1455 /*
1456 * Found a match.
1457 *
1458 * If this index is being created in the parent
1459 * because of a constraint, then the child needs to
1460 * have a constraint also, so look for one. If there
1461 * is no such constraint, this index is no good, so
1462 * keep looking.
1463 */
1465 {
1466 cldConstrOid =
1468 cldidxid);
1469 if (cldConstrOid == InvalidOid)
1470 {
1471 index_close(cldidx, lockmode);
1472 continue;
1473 }
1474 }
1475
1476 /* Attach index to parent and we're done. */
1481 childRelid);
1482
1483 if (!cldidx->rd_index->indisvalid)
1484 invalidate_parent = true;
1485
1486 found = true;
1487
1488 /*
1489 * Report this partition as processed. Note that if
1490 * the partition has children itself, we'd ideally
1491 * count the children and update the progress report
1492 * for all of them; but that seems unduly expensive.
1493 * Instead, the progress report will act like all such
1494 * indirect children were processed in zero time at
1495 * the end of the command.
1496 */
1498
1499 /* keep lock till commit */
1501 break;
1502 }
1503
1504 index_close(cldidx, lockmode);
1505 }
1506
1512
1513 /*
1514 * If no matching index was found, create our own.
1515 */
1516 if (!found)
1517 {
1520
1521 /*
1522 * Build an IndexStmt describing the desired child index
1523 * in the same way that we do during ATTACH PARTITION.
1524 * Notably, we rely on generateClonedIndexStmt to produce
1525 * a search-path-independent representation, which the
1526 * original IndexStmt might not be.
1527 */
1530 attmap,
1531 NULL);
1532
1533 /*
1534 * Recurse as the starting user ID. Callee will use that
1535 * for permission checks, then switch again.
1536 */
1540 childAddr =
1541 DefineIndex(NULL, /* original pstate not applicable */
1543 InvalidOid, /* no predefined OID */
1544 indexRelationId, /* this is our child */
1546 -1,
1549 skip_build, quiet);
1552
1553 /*
1554 * Check if the index just created is valid or not, as it
1555 * could be possible that it has been switched as invalid
1556 * when recursing across multiple partition levels.
1557 */
1558 if (!get_index_isvalid(childAddr.objectId))
1559 invalidate_parent = true;
1560 }
1561
1563 }
1564
1565 index_close(parentIndex, lockmode);
1566
1567 /*
1568 * The pg_index row we inserted for this index was marked
1569 * indisvalid=true. But if we attached an existing index that is
1570 * invalid, this is incorrect, so update our row to invalid too.
1571 */
1573 {
1575 HeapTuple tup,
1576 newtup;
1577
1580 if (!HeapTupleIsValid(tup))
1581 elog(ERROR, "cache lookup failed for index %u",
1589
1590 /*
1591 * CCI here to make this update visible, in case this recurses
1592 * across multiple partition levels.
1593 */
1595 }
1596 }
1597
1598 /*
1599 * Indexes on partitioned tables are not themselves built, so we're
1600 * done here.
1601 */
1604 table_close(rel, NoLock);
1607 else
1608 {
1609 /* Update progress for an intermediate partitioned index itself */
1611 }
1612
1613 return address;
1614 }
1615
1618
1619 if (!concurrent)
1620 {
1621 /* Close the heap and we're done, in the non-concurrent case */
1622 table_close(rel, NoLock);
1623
1624 /*
1625 * If this is the top-level index, the command is done overall;
1626 * otherwise, increment progress to report one child index is done.
1627 */
1630 else
1632
1633 return address;
1634 }
1635
1636 /* save lockrelid and locktag for below, then close rel */
1637 heaprelid = rel->rd_lockInfo.lockRelId;
1638 SET_LOCKTAG_RELATION(heaplocktag, heaprelid.dbId, heaprelid.relId);
1639 table_close(rel, NoLock);
1640
1641 /*
1642 * For a concurrent build, it's important to make the catalog entries
1643 * visible to other transactions before we start to build the index. That
1644 * will prevent them from making incompatible HOT updates. The new index
1645 * will be marked not indisready and not indisvalid, so that no one else
1646 * tries to either insert into it or use it for queries.
1647 *
1648 * We must commit our current transaction so that the index becomes
1649 * visible; then start another. Note that all the data structures we just
1650 * built are lost in the commit. The only data we keep past here are the
1651 * relation IDs.
1652 *
1653 * Before committing, get a session-level lock on the table, to ensure
1654 * that neither it nor the index can be dropped before we finish. This
1655 * cannot block, even if someone else is waiting for access, because we
1656 * already have the same lock within our transaction.
1657 *
1658 * Note: we don't currently bother with a session lock on the index,
1659 * because there are no operations that could change its state while we
1660 * hold lock on the parent table. This might need to change later.
1661 */
1663
1667
1668 /* Tell concurrent index builds to ignore us, if index qualifies */
1669 if (safe_index)
1671
1672 /*
1673 * The index is now visible, so we can report the OID. While on it,
1674 * include the report for the beginning of phase 2.
1675 */
1676 {
1677 const int progress_cols[] = {
1680 };
1681 const int64 progress_vals[] = {
1684 };
1685
1687 }
1688
1689 /*
1690 * Phase 2 of concurrent index build (see comments for validate_index()
1691 * for an overview of how this works)
1692 *
1693 * Now we must wait until no running transaction could have the table open
1694 * with the old list of indexes. Use ShareLock to consider running
1695 * transactions that hold locks that permit writing to the table. Note we
1696 * do not need to worry about xacts that open the table for writing after
1697 * this point; they will see the new index when they open it.
1698 *
1699 * Note: the reason we use actual lock acquisition here, rather than just
1700 * checking the ProcArray and sleeping, is that deadlock is possible if
1701 * one of the transactions in question is blocked trying to acquire an
1702 * exclusive lock on our table. The lock code will detect deadlock and
1703 * error out properly.
1704 */
1706
1707 /*
1708 * At this moment we are sure that there are no transactions with the
1709 * table open for write that don't have this new index in their list of
1710 * indexes. We have waited out all the existing transactions and any new
1711 * transaction will have the new index in its list, but the index is still
1712 * marked as "not-ready-for-inserts". The index is consulted while
1713 * deciding HOT-safety though. This arrangement ensures that no new HOT
1714 * chains can be created where the new tuple and the old tuple in the
1715 * chain have different index keys.
1716 *
1717 * We now take a new snapshot, and build the index using all tuples that
1718 * are visible in this snapshot. We can be sure that any HOT updates to
1719 * these tuples will be compatible with the index, since any updates made
1720 * by transactions that didn't know about the index are now committed or
1721 * rolled back. Thus, each visible tuple is either the end of its
1722 * HOT-chain or the extension of the chain is HOT-safe for this index.
1723 */
1724
1725 /* Set ActiveSnapshot since functions in the indexes may need it */
1727
1728 /* Perform concurrent build of index */
1730
1731 /* we can do away with our snapshot */
1733
1734 /*
1735 * Commit this transaction to make the indisready update visible.
1736 */
1739
1740 /* Tell concurrent index builds to ignore us, if index qualifies */
1741 if (safe_index)
1743
1744 /*
1745 * Phase 3 of concurrent index build
1746 *
1747 * We once again wait until no transaction can have the table open with
1748 * the index marked as read-only for updates.
1749 */
1753
1754 /*
1755 * Now take the "reference snapshot" that will be used by validate_index()
1756 * to filter candidate tuples. Beware! There might still be snapshots in
1757 * use that treat some transaction as in-progress that our reference
1758 * snapshot treats as committed. If such a recently-committed transaction
1759 * deleted tuples in the table, we will not include them in the index; yet
1760 * those transactions which see the deleting one as still-in-progress will
1761 * expect such tuples to be there once we mark the index as valid.
1762 *
1763 * We solve this by waiting for all endangered transactions to exit before
1764 * we mark the index as valid.
1765 *
1766 * We also set ActiveSnapshot to this snap, since functions in indexes may
1767 * need a snapshot.
1768 */
1770 PushActiveSnapshot(snapshot);
1771
1772 /*
1773 * Scan the index and the heap, insert any missing index entries.
1774 */
1776
1777 /*
1778 * Drop the reference snapshot. We must do this before waiting out other
1779 * snapshot holders, else we will deadlock against other processes also
1780 * doing CREATE INDEX CONCURRENTLY, which would see our snapshot as one
1781 * they must wait for. But first, save the snapshot's xmin to use as
1782 * limitXmin for GetCurrentVirtualXIDs().
1783 */
1784 limitXmin = snapshot->xmin;
1785
1787 UnregisterSnapshot(snapshot);
1788
1789 /*
1790 * The snapshot subsystem could still contain registered snapshots that
1791 * are holding back our process's advertised xmin; in particular, if
1792 * default_transaction_isolation = serializable, there is a transaction
1793 * snapshot that is still active. The CatalogSnapshot is likewise a
1794 * hazard. To ensure no deadlocks, we must commit and start yet another
1795 * transaction, and do our wait before any snapshot has been taken in it.
1796 */
1799
1800 /* Tell concurrent index builds to ignore us, if index qualifies */
1801 if (safe_index)
1803
1804 /* We should now definitely not be advertising any xmin. */
1806
1807 /*
1808 * The index is now valid in the sense that it contains all currently
1809 * interesting tuples. But since it might not contain tuples deleted just
1810 * before the reference snap was taken, we have to wait out any
1811 * transactions that might have older snapshots.
1812 */
1813 INJECTION_POINT("define-index-before-set-valid", NULL);
1817
1818 /*
1819 * Updating pg_index might involve TOAST table access, so ensure we have a
1820 * valid snapshot.
1821 */
1823
1824 /*
1825 * Index can now be marked valid -- update its pg_index entry
1826 */
1828
1830
1831 /*
1832 * The pg_index update will cause backends (including this one) to update
1833 * relcache entries for the index itself, but we should also send a
1834 * relcache inval on the parent table to force replanning of cached plans.
1835 * Otherwise existing sessions might fail to use the new index where it
1836 * would be useful. (Note that our earlier commits did not create reasons
1837 * to replan; so relcache flush on the index itself was sufficient.)
1838 */
1840
1841 /*
1842 * Last thing to do is release the session-level lock on the parent table.
1843 */
1845
1847
1848 return address;
1849}
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:3902
bytea *(* amoptions_function)(Datum reloptions, bool validate)
Definition amapi.h:166
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:1425
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:645
int64_t int64
Definition c.h:680
uint32 TransactionId
Definition c.h:795
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:31
#define NOTICE
Definition elog.h:36
bool allowSystemTableMods
Definition globals.c:132
Oid MyDatabaseTableSpace
Definition globals.c:98
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:730
void validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
Definition index.c:3383
void index_set_state_flags(Oid indexId, IndexStateFlagsAction action)
Definition index.c:3536
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:2555
IndexInfo * BuildIndexInfo(Relation index)
Definition index.c:2446
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:1503
#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:103
#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:99
@ INDEX_CREATE_SET_VALID
Definition index.h:33
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition index.h:100
#define INDEX_CREATE_CONCURRENT
Definition index.h:70
static void set_indexsafe_procflags(void)
Definition indexcmds.c:4771
static List * ChooseIndexColumnNames(Relation rel, const List *indexElems)
Definition indexcmds.c:2802
void IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
Definition indexcmds.c:4601
void WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
Definition indexcmds.c:446
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:555
static void CheckPredicate(Expr *predicate)
Definition indexcmds.c:1864
static char * ChooseIndexName(const char *tabname, Oid namespaceId, const List *colnames, const List *exclusionOpNames, bool primary, bool isconstraint)
Definition indexcmds.c:2712
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:1688
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:2392
bool get_index_isvalid(Oid index_oid)
Definition lsyscache.c:3939
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:1487
char * get_opname(Oid opno)
Definition lsyscache.c:1610
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:1536
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3682
List * make_ands_implicit(Expr *clause)
Definition makefuncs.c:810
#define IsBootstrapProcessingMode()
Definition miscadmin.h:486
#define SECURITY_RESTRICTED_OPERATION
Definition miscadmin.h:322
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:921
@ 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:118
#define PROGRESS_CREATEIDX_PHASE_WAIT_1
Definition progress.h:122
#define PROGRESS_CREATEIDX_COMMAND_CREATE_CONCURRENTLY
Definition progress.h:140
#define PROGRESS_CREATEIDX_ACCESS_METHOD_OID
Definition progress.h:112
#define PROGRESS_CREATEIDX_PHASE_WAIT_3
Definition progress.h:128
#define PROGRESS_CREATEIDX_COMMAND_CREATE
Definition progress.h:139
#define PROGRESS_CREATEIDX_PHASE_WAIT_2
Definition progress.h:124
#define PROGRESS_CREATEIDX_PHASE
Definition progress.h:113
#define PROGRESS_CREATEIDX_INDEX_OID
Definition progress.h:111
#define PROGRESS_CREATEIDX_PARTITIONS_TOTAL
Definition progress.h:117
#define PROGRESS_CREATEIDX_COMMAND
Definition progress.h:110
#define RelationGetRelationName(relation)
Definition rel.h:550
#define RELATION_IS_OTHER_TEMP(relation)
Definition rel.h:678
#define RelationGetNamespace(relation)
Definition rel.h:557
List * RelationGetIndexList(Relation relation)
Definition relcache.c:4848
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:71
#define HTEqualStrategyNumber
Definition stratnum.h:41
int ii_NumIndexAttrs
Definition execnodes.h:181
List * ii_Predicate
Definition execnodes.h:197
LockRelId lockRelId
Definition rel.h:46
Oid relId
Definition rel.h:40
Oid dbId
Definition rel.h:41
TransactionId xmin
Definition proc.h:242
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:4508
#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:1130
void StartTransactionCommand(void)
Definition xact.c:3112
void CommitTransactionCommand(void)
Definition xact.c:3210

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(), memcpy(), 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 2977 of file indexcmds.c.

2978{
2979 ReindexParams params = {0};
2980 ListCell *lc;
2981 bool concurrently = false;
2982 bool verbose = false;
2983 char *tablespacename = NULL;
2984
2985 /* Parse option list */
2986 foreach(lc, stmt->params)
2987 {
2988 DefElem *opt = (DefElem *) lfirst(lc);
2989
2990 if (strcmp(opt->defname, "verbose") == 0)
2991 verbose = defGetBoolean(opt);
2992 else if (strcmp(opt->defname, "concurrently") == 0)
2994 else if (strcmp(opt->defname, "tablespace") == 0)
2995 tablespacename = defGetString(opt);
2996 else
2997 ereport(ERROR,
2999 errmsg("unrecognized %s option \"%s\"",
3000 "REINDEX", opt->defname),
3001 parser_errposition(pstate, opt->location)));
3002 }
3003
3004 if (concurrently)
3006 "REINDEX CONCURRENTLY");
3007
3008 params.options =
3009 (verbose ? REINDEXOPT_VERBOSE : 0) |
3011
3012 /*
3013 * Assign the tablespace OID to move indexes to, with InvalidOid to do
3014 * nothing.
3015 */
3016 if (tablespacename != NULL)
3017 {
3018 params.tablespaceOid = get_tablespace_oid(tablespacename, false);
3019
3020 /* Check permissions except when moving to database's default */
3021 if (OidIsValid(params.tablespaceOid) &&
3023 {
3025
3028 if (aclresult != ACLCHECK_OK)
3031 }
3032 }
3033 else
3034 params.tablespaceOid = InvalidOid;
3035
3036 switch (stmt->kind)
3037 {
3039 ReindexIndex(stmt, &params, isTopLevel);
3040 break;
3042 ReindexTable(stmt, &params, isTopLevel);
3043 break;
3047
3048 /*
3049 * This cannot run inside a user transaction block; if we were
3050 * inside a transaction, then its commit- and
3051 * start-transaction-command calls would not have the intended
3052 * effect!
3053 */
3055 (stmt->kind == REINDEX_OBJECT_SCHEMA) ? "REINDEX SCHEMA" :
3056 (stmt->kind == REINDEX_OBJECT_SYSTEM) ? "REINDEX SYSTEM" :
3057 "REINDEX DATABASE");
3058 ReindexMultipleTables(stmt, &params);
3059 break;
3060 default:
3061 elog(ERROR, "unrecognized object type: %d",
3062 (int) stmt->kind);
3063 break;
3064 }
3065}
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:3072
static void ReindexMultipleTables(const ReindexStmt *stmt, const ReindexParams *params)
Definition indexcmds.c:3261
static Oid ReindexTable(const ReindexStmt *stmt, const ReindexParams *params, bool isTopLevel)
Definition indexcmds.c:3202
@ REINDEX_OBJECT_DATABASE
@ REINDEX_OBJECT_INDEX
@ REINDEX_OBJECT_SCHEMA
@ REINDEX_OBJECT_SYSTEM
@ REINDEX_OBJECT_TABLE
static int verbose
char * defname
Definition parsenodes.h:862
ParseLoc location
Definition parsenodes.h:866
Oid tablespaceOid
Definition index.h:42
uint32 options
Definition index.h:41
void PreventInTransactionBlock(bool isTopLevel, const char *stmtType)
Definition xact.c:3701

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

2382{
2384 int nexact = 0;
2385 int ncompatible = 0;
2386 int ncompatiblepreferred = 0;
2387 Relation rel;
2388 ScanKeyData skey[1];
2389 SysScanDesc scan;
2390 HeapTuple tup;
2392
2393 /* If it's a domain, look at the base type instead */
2394 type_id = getBaseType(type_id);
2395
2396 tcategory = TypeCategory(type_id);
2397
2398 /*
2399 * We scan through all the opclasses available for the access method,
2400 * looking for one that is marked default and matches the target type
2401 * (either exactly or binary-compatibly, but prefer an exact match).
2402 *
2403 * We could find more than one binary-compatible match. If just one is
2404 * for a preferred type, use that one; otherwise we fail, forcing the user
2405 * to specify which one he wants. (The preferred-type special case is a
2406 * kluge for varchar: it's binary-compatible to both text and bpchar, so
2407 * we need a tiebreaker.) If we find more than one exact match, then
2408 * someone put bogus entries in pg_opclass.
2409 */
2411
2412 ScanKeyInit(&skey[0],
2416
2418 NULL, 1, skey);
2419
2420 while (HeapTupleIsValid(tup = systable_getnext(scan)))
2421 {
2423
2424 /* ignore altogether if not a default opclass */
2425 if (!opclass->opcdefault)
2426 continue;
2427 if (opclass->opcintype == type_id)
2428 {
2429 nexact++;
2430 result = opclass->oid;
2431 }
2432 else if (nexact == 0 &&
2433 IsBinaryCoercible(type_id, opclass->opcintype))
2434 {
2435 if (IsPreferredType(tcategory, opclass->opcintype))
2436 {
2438 result = opclass->oid;
2439 }
2440 else if (ncompatiblepreferred == 0)
2441 {
2442 ncompatible++;
2443 result = opclass->oid;
2444 }
2445 }
2446 }
2447
2448 systable_endscan(scan);
2449
2451
2452 /* raise error if pg_opclass contains inconsistent data */
2453 if (nexact > 1)
2454 ereport(ERROR,
2456 errmsg("there are multiple default operator classes for data type %s",
2457 format_type_be(type_id))));
2458
2459 if (nexact == 1 ||
2460 ncompatiblepreferred == 1 ||
2461 (ncompatiblepreferred == 0 && ncompatible == 1))
2462 return result;
2463
2464 return InvalidOid;
2465}
Oid getBaseType(Oid typid)
Definition lsyscache.c:2837
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(), result, 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 2483 of file indexcmds.c.

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

4602{
4604 ScanKeyData key[2];
4605 SysScanDesc scan;
4606 Oid partRelid = RelationGetRelid(partitionIdx);
4607 HeapTuple tuple;
4608 bool fix_dependencies;
4609
4610 /* Make sure this is an index */
4611 Assert(partitionIdx->rd_rel->relkind == RELKIND_INDEX ||
4612 partitionIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
4613
4614 /*
4615 * Scan pg_inherits for rows linking our index to some parent.
4616 */
4618 ScanKeyInit(&key[0],
4622 ScanKeyInit(&key[1],
4625 Int32GetDatum(1));
4627 NULL, 2, key);
4628 tuple = systable_getnext(scan);
4629
4630 if (!HeapTupleIsValid(tuple))
4631 {
4632 if (parentOid == InvalidOid)
4633 {
4634 /*
4635 * No pg_inherits row, and no parent wanted: nothing to do in this
4636 * case.
4637 */
4638 fix_dependencies = false;
4639 }
4640 else
4641 {
4643 fix_dependencies = true;
4644 }
4645 }
4646 else
4647 {
4649
4650 if (parentOid == InvalidOid)
4651 {
4652 /*
4653 * There exists a pg_inherits row, which we want to clear; do so.
4654 */
4656 fix_dependencies = true;
4657 }
4658 else
4659 {
4660 /*
4661 * A pg_inherits row exists. If it's the same we want, then we're
4662 * good; if it differs, that amounts to a corrupt catalog and
4663 * should not happen.
4664 */
4665 if (inhForm->inhparent != parentOid)
4666 {
4667 /* unexpected: we should not get called in this case */
4668 elog(ERROR, "bogus pg_inherit row: inhrelid %u inhparent %u",
4669 inhForm->inhrelid, inhForm->inhparent);
4670 }
4671
4672 /* already in the right state */
4673 fix_dependencies = false;
4674 }
4675 }
4676
4677 /* done with pg_inherits */
4678 systable_endscan(scan);
4680
4681 /* set relhassubclass if an index partition has been added to the parent */
4682 if (OidIsValid(parentOid))
4683 {
4686 }
4687
4688 /* set relispartition correctly on the partition */
4690
4691 if (fix_dependencies)
4692 {
4693 /*
4694 * Insert/delete pg_depend rows. If setting a parent, add PARTITION
4695 * dependencies on the parent index and the table; if removing a
4696 * parent, delete PARTITION dependencies.
4697 */
4698 if (OidIsValid(parentOid))
4699 {
4701 ObjectAddress parentIdx;
4702 ObjectAddress partitionTbl;
4703
4707 partitionIdx->rd_index->indrelid);
4708 recordDependencyOn(&partIdx, &parentIdx,
4710 recordDependencyOn(&partIdx, &partitionTbl,
4712 }
4713 else
4714 {
4721 }
4722
4723 /* make our updates visible */
4725 }
4726}
@ 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:4733
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:51
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition pg_depend.c:364
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:516
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:3726

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

2557{
2558 char *name;
2559 int overhead = 0; /* chars needed for label and underscores */
2560 int availchars; /* chars available for name(s) */
2561 int name1chars; /* chars allocated to name1 */
2562 int name2chars; /* chars allocated to name2 */
2563 int ndx;
2564
2566 if (name2)
2567 {
2569 overhead++; /* allow for separating underscore */
2570 }
2571 else
2572 name2chars = 0;
2573 if (label)
2574 overhead += strlen(label) + 1;
2575
2577 Assert(availchars > 0); /* else caller chose a bad label */
2578
2579 /*
2580 * If we must truncate, preferentially truncate the longer name. This
2581 * logic could be expressed without a loop, but it's simple and obvious as
2582 * a loop.
2583 */
2584 while (name1chars + name2chars > availchars)
2585 {
2586 if (name1chars > name2chars)
2587 name1chars--;
2588 else
2589 name2chars--;
2590 }
2591
2593 if (name2)
2595
2596 /* Now construct the string using the chosen lengths */
2599 ndx = name1chars;
2600 if (name2)
2601 {
2602 name[ndx++] = '_';
2604 ndx += name2chars;
2605 }
2606 if (label)
2607 {
2608 name[ndx++] = '_';
2609 strcpy(name + ndx, label);
2610 }
2611 else
2612 name[ndx] = '\0';
2613
2614 return name;
2615}
void * palloc(Size size)
Definition mcxt.c:1390

References Assert, fb(), label, memcpy(), 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 3126 of file indexcmds.c.

3128{
3129 char relkind;
3132 Oid table_oid;
3134
3135 /*
3136 * Lock level here should match table lock in reindex_index() for
3137 * non-concurrent case and table locks used by index_concurrently_*() for
3138 * concurrent case.
3139 */
3140 table_lockmode = (state->params.options & REINDEXOPT_CONCURRENTLY) != 0 ?
3142
3143 /*
3144 * If we previously locked some other index's heap, and the name we're
3145 * looking up no longer refers to that relation, release the now-useless
3146 * lock.
3147 */
3148 if (relId != oldRelId && OidIsValid(oldRelId))
3149 {
3150 UnlockRelationOid(state->locked_table_oid, table_lockmode);
3151 state->locked_table_oid = InvalidOid;
3152 }
3153
3154 /* If the relation does not exist, there's nothing more to do. */
3155 if (!OidIsValid(relId))
3156 return;
3157
3158 /* If the relation does exist, check whether it's an index. */
3159 relkind = get_rel_relkind(relId);
3160 if (relkind != RELKIND_INDEX &&
3161 relkind != RELKIND_PARTITIONED_INDEX)
3162 ereport(ERROR,
3164 errmsg("\"%s\" is not an index", relation->relname)));
3165
3166 /* Look up the index's table. */
3167 table_oid = IndexGetRelation(relId, false);
3168
3169 /*
3170 * In the unlikely event that, upon retry, we get the same index OID with
3171 * a different table OID, fail. RangeVarGetRelidExtended() will have
3172 * already locked the index in this case, and it won't retry again, so we
3173 * can't lock the newly discovered table OID without risking deadlock.
3174 * Also, while this corner case is indeed possible, it is extremely
3175 * unlikely to happen in practice, so it's probably not worth any more
3176 * effort than this.
3177 */
3178 if (relId == oldRelId && table_oid != state->locked_table_oid)
3179 ereport(ERROR,
3181 errmsg("index \"%s\" was concurrently dropped",
3182 relation->relname)));
3183
3184 /* Check permissions. */
3186 if (aclresult != ACLCHECK_OK)
3188
3189 /* Lock heap before index to avoid deadlock. */
3190 if (relId != oldRelId)
3191 {
3193 state->locked_table_oid = table_oid;
3194 }
3195}
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition aclchk.c:4105
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition lmgr.c:229
char get_rel_relkind(Oid relid)
Definition lsyscache.c:2317
#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 3480 of file indexcmds.c.

3481{
3483
3485
3486 if (errinfo->relkind == RELKIND_PARTITIONED_TABLE)
3487 errcontext("while reindexing partitioned table \"%s.%s\"",
3488 errinfo->relnamespace, errinfo->relname);
3489 else if (errinfo->relkind == RELKIND_PARTITIONED_INDEX)
3490 errcontext("while reindexing partitioned index \"%s.%s\"",
3491 errinfo->relnamespace, errinfo->relname);
3492}
#define errcontext
Definition elog.h:200

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

3073{
3074 const RangeVar *indexRelation = stmt->relation;
3076 Oid indOid;
3077 char persistence;
3078 char relkind;
3079
3080 /*
3081 * Find and lock index, and check permissions on table; use callback to
3082 * obtain lock on table first, to avoid deadlock hazard. The lock level
3083 * used here must match the index lock obtained in reindex_index().
3084 *
3085 * If it's a temporary index, we will perform a non-concurrent reindex,
3086 * even if CONCURRENTLY was requested. In that case, reindex_index() will
3087 * upgrade the lock, but that's OK, because other sessions can't hold
3088 * locks on our temporary table.
3089 */
3090 state.params = *params;
3091 state.locked_table_oid = InvalidOid;
3092 indOid = RangeVarGetRelidExtended(indexRelation,
3095 0,
3097 &state);
3098
3099 /*
3100 * Obtain the current persistence and kind of the existing index. We
3101 * already hold a lock on the index.
3102 */
3103 persistence = get_rel_persistence(indOid);
3104 relkind = get_rel_relkind(indOid);
3105
3106 if (relkind == RELKIND_PARTITIONED_INDEX)
3108 else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
3109 persistence != RELPERSISTENCE_TEMP)
3111 else
3112 {
3114
3116 reindex_index(stmt, indOid, false, persistence, &newparams);
3117 }
3118}
void reindex_index(const ReindexStmt *stmt, Oid indexId, bool skip_constraint_checks, char persistence, const ReindexParams *params)
Definition index.c:3641
#define REINDEXOPT_REPORT_PROGRESS
Definition index.h:48
static bool ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const ReindexParams *params)
Definition indexcmds.c:3721
static void ReindexPartitions(const ReindexStmt *stmt, Oid relid, const ReindexParams *params, bool isTopLevel)
Definition indexcmds.c:3501
static void RangeVarCallbackForReindexIndex(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition indexcmds.c:3126
#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 3595 of file indexcmds.c.

3596{
3597 ListCell *l;
3598
3601
3602 foreach(l, relids)
3603 {
3604 Oid relid = lfirst_oid(l);
3605 char relkind;
3606 char relpersistence;
3607
3609
3610 /* functions in indexes may want a snapshot set */
3612
3613 /* check if the relation still exists */
3615 {
3618 continue;
3619 }
3620
3621 /*
3622 * Check permissions except when moving to database's default if a new
3623 * tablespace is chosen. Note that this check also happens in
3624 * ExecReindex(), but we do an extra check here as this runs across
3625 * multiple transactions.
3626 */
3627 if (OidIsValid(params->tablespaceOid) &&
3629 {
3631
3634 if (aclresult != ACLCHECK_OK)
3637 }
3638
3639 relkind = get_rel_relkind(relid);
3640 relpersistence = get_rel_persistence(relid);
3641
3642 /*
3643 * Partitioned tables and indexes can never be processed directly, and
3644 * a list of their leaves should be built first.
3645 */
3646 Assert(!RELKIND_HAS_PARTITIONS(relkind));
3647
3648 if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
3649 relpersistence != RELPERSISTENCE_TEMP)
3650 {
3651 ReindexParams newparams = *params;
3652
3655 if (ActiveSnapshotSet())
3657 /* ReindexRelationConcurrently() does the verbose output */
3658 }
3659 else if (relkind == RELKIND_INDEX)
3660 {
3661 ReindexParams newparams = *params;
3662
3665 reindex_index(stmt, relid, false, relpersistence, &newparams);
3667 /* reindex_index() does the verbose output */
3668 }
3669 else
3670 {
3671 bool result;
3672 ReindexParams newparams = *params;
3673
3676 result = reindex_relation(stmt, relid,
3679 &newparams);
3680
3681 if (result && (params->options & REINDEXOPT_VERBOSE) != 0)
3682 ereport(INFO,
3683 (errmsg("table \"%s.%s\" was reindexed",
3685 get_rel_name(relid))));
3686
3688 }
3689
3691 }
3692
3694}
#define INFO
Definition elog.h:35
bool reindex_relation(const ReindexStmt *stmt, Oid relid, int flags, const ReindexParams *params)
Definition index.c:3981
#define REINDEX_REL_PROCESS_TOAST
Definition index.h:166
#define REINDEXOPT_MISSING_OK
Definition index.h:49
#define REINDEX_REL_CHECK_CONSTRAINTS
Definition index.h:168
char * get_rel_name(Oid relid)
Definition lsyscache.c:2242
Oid get_rel_namespace(Oid relid)
Definition lsyscache.c:2266
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(), result, 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 3261 of file indexcmds.c.

3262{
3263
3264 Oid objectOid;
3266 TableScanDesc scan;
3268 HeapTuple tuple;
3271 List *relids = NIL;
3272 int num_keys;
3273 bool concurrent_warning = false;
3274 bool tablespace_warning = false;
3275 const char *objectName = stmt->name;
3276 const ReindexObjectType objectKind = stmt->kind;
3277
3281
3282 /*
3283 * This matches the options enforced by the grammar, where the object name
3284 * is optional for DATABASE and SYSTEM.
3285 */
3287
3289 (params->options & REINDEXOPT_CONCURRENTLY) != 0)
3290 ereport(ERROR,
3292 errmsg("cannot reindex system catalogs concurrently")));
3293
3294 /*
3295 * Get OID of object to reindex, being the database currently being used
3296 * by session for a database or for system catalogs, or the schema defined
3297 * by caller. At the same time do permission checks that need different
3298 * processing depending on the object type.
3299 */
3301 {
3303
3307 objectName);
3308 }
3309 else
3310 {
3312
3314 ereport(ERROR,
3316 errmsg("can only reindex the currently open database")));
3321 }
3322
3323 /*
3324 * Create a memory context that will survive forced transaction commits we
3325 * do below. Since it is a child of PortalContext, it will go away
3326 * eventually even if we suffer an error; there's no need for special
3327 * abort cleanup logic.
3328 */
3330 "ReindexMultipleTables",
3332
3333 /*
3334 * Define the search keys to find the objects to reindex. For a schema, we
3335 * select target relations using relnamespace, something not necessary for
3336 * a database-wide operation.
3337 */
3339 {
3340 num_keys = 1;
3345 }
3346 else
3347 num_keys = 0;
3348
3349 /*
3350 * Scan pg_class to build a list of the relations we need to reindex.
3351 *
3352 * We only consider plain relations and materialized views here (toast
3353 * rels will be processed indirectly by reindex_relation).
3354 */
3357 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
3358 {
3360 Oid relid = classtuple->oid;
3361
3362 /*
3363 * Only regular tables and matviews can have indexes, so ignore any
3364 * other kind of relation.
3365 *
3366 * Partitioned tables/indexes are skipped but matching leaf partitions
3367 * are processed.
3368 */
3369 if (classtuple->relkind != RELKIND_RELATION &&
3370 classtuple->relkind != RELKIND_MATVIEW)
3371 continue;
3372
3373 /* Skip temp tables of other backends; we can't reindex them at all */
3374 if (classtuple->relpersistence == RELPERSISTENCE_TEMP &&
3375 !isTempNamespace(classtuple->relnamespace))
3376 continue;
3377
3378 /*
3379 * Check user/system classification. SYSTEM processes all the
3380 * catalogs, and DATABASE processes everything that's not a catalog.
3381 */
3383 !IsCatalogRelationOid(relid))
3384 continue;
3385 else if (objectKind == REINDEX_OBJECT_DATABASE &&
3386 IsCatalogRelationOid(relid))
3387 continue;
3388
3389 /*
3390 * We already checked privileges on the database or schema, but we
3391 * further restrict reindexing shared catalogs to roles with the
3392 * MAINTAIN privilege on the relation.
3393 */
3394 if (classtuple->relisshared &&
3396 continue;
3397
3398 /*
3399 * Skip system tables, since index_create() would reject indexing them
3400 * concurrently (and it would likely fail if we tried).
3401 */
3402 if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
3403 IsCatalogRelationOid(relid))
3404 {
3405 if (!concurrent_warning)
3408 errmsg("cannot reindex system catalogs concurrently, skipping all")));
3409 concurrent_warning = true;
3410 continue;
3411 }
3412
3413 /*
3414 * If a new tablespace is set, check if this relation has to be
3415 * skipped.
3416 */
3417 if (OidIsValid(params->tablespaceOid))
3418 {
3419 bool skip_rel = false;
3420
3421 /*
3422 * Mapped relations cannot be moved to different tablespaces (in
3423 * particular this eliminates all shared catalogs.).
3424 */
3425 if (RELKIND_HAS_STORAGE(classtuple->relkind) &&
3426 !RelFileNumberIsValid(classtuple->relfilenode))
3427 skip_rel = true;
3428
3429 /*
3430 * A system relation is always skipped, even with
3431 * allow_system_table_mods enabled.
3432 */
3433 if (IsSystemClass(relid, classtuple))
3434 skip_rel = true;
3435
3436 if (skip_rel)
3437 {
3438 if (!tablespace_warning)
3441 errmsg("cannot move system relations, skipping all")));
3442 tablespace_warning = true;
3443 continue;
3444 }
3445 }
3446
3447 /* Save the list of relation OIDs in private context */
3449
3450 /*
3451 * We always want to reindex pg_class first if it's selected to be
3452 * reindexed. This ensures that if there is any corruption in
3453 * pg_class' indexes, they will be fixed before we process any other
3454 * tables. This is critical because reindexing itself will try to
3455 * update pg_class.
3456 */
3457 if (relid == RelationRelationId)
3458 relids = lcons_oid(relid, relids);
3459 else
3460 relids = lappend_oid(relids, relid);
3461
3463 }
3464 table_endscan(scan);
3466
3467 /*
3468 * Process each relation listed in a separate transaction. Note that this
3469 * commits and then starts a new transaction immediately.
3470 */
3471 ReindexMultipleInternal(stmt, relids, params);
3472
3474}
bool has_privs_of_role(Oid member, Oid role)
Definition acl.c:5317
@ ACLCHECK_NOT_OWNER
Definition acl.h:186
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition aclchk.c:4156
bool IsCatalogRelationOid(Oid relid)
Definition catalog.c:123
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition catalog.c:86
#define WARNING
Definition elog.h:37
Oid MyDatabaseId
Definition globals.c:96
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition heapam.c:1436
static void ReindexMultipleInternal(const ReindexStmt *stmt, const List *relids, const ReindexParams *params)
Definition indexcmds.c:3595
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:1392
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:475
MemoryContext PortalContext
Definition mcxt.c:176
#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:138
@ 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:1061

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

3502{
3503 List *partitions = NIL;
3504 char relkind = get_rel_relkind(relid);
3505 char *relname = get_rel_name(relid);
3506 char *relnamespace = get_namespace_name(get_rel_namespace(relid));
3508 List *inhoids;
3509 ListCell *lc;
3510 ErrorContextCallback errcallback;
3512
3514
3515 /*
3516 * Check if this runs in a transaction block, with an error callback to
3517 * provide more context under which a problem happens.
3518 */
3519 errinfo.relname = pstrdup(relname);
3520 errinfo.relnamespace = pstrdup(relnamespace);
3521 errinfo.relkind = relkind;
3522 errcallback.callback = reindex_error_callback;
3523 errcallback.arg = &errinfo;
3524 errcallback.previous = error_context_stack;
3525 error_context_stack = &errcallback;
3526
3528 relkind == RELKIND_PARTITIONED_TABLE ?
3529 "REINDEX TABLE" : "REINDEX INDEX");
3530
3531 /* Pop the error context stack */
3532 error_context_stack = errcallback.previous;
3533
3534 /*
3535 * Create special memory context for cross-transaction storage.
3536 *
3537 * Since it is a child of PortalContext, it will go away eventually even
3538 * if we suffer an error so there is no need for special abort cleanup
3539 * logic.
3540 */
3543
3544 /* ShareLock is enough to prevent schema modifications */
3546
3547 /*
3548 * The list of relations to reindex are the physical partitions of the
3549 * tree so discard any partitioned table or index.
3550 */
3551 foreach(lc, inhoids)
3552 {
3553 Oid partoid = lfirst_oid(lc);
3554 char partkind = get_rel_relkind(partoid);
3556
3557 /*
3558 * This discards partitioned tables, partitioned indexes and foreign
3559 * tables.
3560 */
3562 continue;
3563
3566
3567 /* Save partition OID */
3569 partitions = lappend_oid(partitions, partoid);
3571 }
3572
3573 /*
3574 * Process each partition listed in a separate transaction. Note that
3575 * this commits and then starts a new transaction immediately.
3576 */
3578
3579 /*
3580 * Clean up working storage --- note we must do this after
3581 * StartTransactionCommand, else we might be trying to delete the active
3582 * context!
3583 */
3585}
ErrorContextCallback * error_context_stack
Definition elog.c:100
static void reindex_error_callback(void *arg)
Definition indexcmds.c:3480
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
static int partitions
Definition pgbench.c:224
struct ErrorContextCallback * previous
Definition elog.h:299
void(* callback)(void *arg)
Definition elog.h:300

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

3722{
3723 typedef struct ReindexIndexInfo
3724 {
3725 Oid indexId;
3726 Oid tableId;
3727 Oid amId;
3728 bool safe; /* for set_indexsafe_procflags */
3731 List *indexIds = NIL;
3732 List *newIndexIds = NIL;
3734 List *lockTags = NIL;
3735 ListCell *lc,
3736 *lc2;
3738 MemoryContext oldcontext;
3739 char relkind;
3740 char *relationName = NULL;
3741 char *relationNamespace = NULL;
3742 PGRUsage ru0;
3743 const int progress_index[] = {
3748 };
3750
3751 /*
3752 * Create a memory context that will survive forced transaction commits we
3753 * do below. Since it is a child of PortalContext, it will go away
3754 * eventually even if we suffer an error; there's no need for special
3755 * abort cleanup logic.
3756 */
3758 "ReindexConcurrent",
3760
3761 if ((params->options & REINDEXOPT_VERBOSE) != 0)
3762 {
3763 /* Save data needed by REINDEX VERBOSE in private context */
3765
3766 relationName = get_rel_name(relationOid);
3768
3770
3771 MemoryContextSwitchTo(oldcontext);
3772 }
3773
3774 relkind = get_rel_relkind(relationOid);
3775
3776 /*
3777 * Extract the list of indexes that are going to be rebuilt based on the
3778 * relation Oid given by caller.
3779 */
3780 switch (relkind)
3781 {
3782 case RELKIND_RELATION:
3783 case RELKIND_MATVIEW:
3784 case RELKIND_TOASTVALUE:
3785 {
3786 /*
3787 * In the case of a relation, find all its indexes including
3788 * toast indexes.
3789 */
3790 Relation heapRelation;
3791
3792 /* Save the list of relation OIDs in private context */
3794
3795 /* Track this relation for session locks */
3797
3798 MemoryContextSwitchTo(oldcontext);
3799
3800 if (IsCatalogRelationOid(relationOid))
3801 ereport(ERROR,
3803 errmsg("cannot reindex system catalogs concurrently")));
3804
3805 /* Open relation to get its indexes */
3806 if ((params->options & REINDEXOPT_MISSING_OK) != 0)
3807 {
3808 heapRelation = try_table_open(relationOid,
3810 /* leave if relation does not exist */
3811 if (!heapRelation)
3812 break;
3813 }
3814 else
3815 heapRelation = table_open(relationOid,
3817
3818 if (OidIsValid(params->tablespaceOid) &&
3819 IsSystemRelation(heapRelation))
3820 ereport(ERROR,
3822 errmsg("cannot move system relation \"%s\"",
3823 RelationGetRelationName(heapRelation))));
3824
3825 /* Add all the valid indexes of relation to list */
3826 foreach(lc, RelationGetIndexList(heapRelation))
3827 {
3829 Relation indexRelation = index_open(cellOid,
3831
3832 if (!indexRelation->rd_index->indisvalid)
3835 errmsg("skipping reindex of invalid index \"%s.%s\"",
3838 errhint("Use DROP INDEX or REINDEX INDEX.")));
3839 else if (indexRelation->rd_index->indisexclusion)
3842 errmsg("cannot reindex exclusion constraint index \"%s.%s\" concurrently, skipping",
3845 else
3846 {
3848
3849 /* Save the list of relation OIDs in private context */
3851
3853 idx->indexId = cellOid;
3854 /* other fields set later */
3855
3857
3858 MemoryContextSwitchTo(oldcontext);
3859 }
3860
3861 index_close(indexRelation, NoLock);
3862 }
3863
3864 /* Also add the toast indexes */
3865 if (OidIsValid(heapRelation->rd_rel->reltoastrelid))
3866 {
3867 Oid toastOid = heapRelation->rd_rel->reltoastrelid;
3870
3871 /* Save the list of relation OIDs in private context */
3873
3874 /* Track this relation for session locks */
3876
3877 MemoryContextSwitchTo(oldcontext);
3878
3880 {
3882 Relation indexRelation = index_open(cellOid,
3884
3885 if (!indexRelation->rd_index->indisvalid)
3888 errmsg("skipping reindex of invalid index \"%s.%s\"",
3891 errhint("Use DROP INDEX or REINDEX INDEX.")));
3892 else
3893 {
3895
3896 /*
3897 * Save the list of relation OIDs in private
3898 * context
3899 */
3901
3903 idx->indexId = cellOid;
3905 /* other fields set later */
3906
3907 MemoryContextSwitchTo(oldcontext);
3908 }
3909
3910 index_close(indexRelation, NoLock);
3911 }
3912
3914 }
3915
3916 table_close(heapRelation, NoLock);
3917 break;
3918 }
3919 case RELKIND_INDEX:
3920 {
3921 Oid heapId = IndexGetRelation(relationOid,
3922 (params->options & REINDEXOPT_MISSING_OK) != 0);
3923 Relation heapRelation;
3925
3926 /* if relation is missing, leave */
3927 if (!OidIsValid(heapId))
3928 break;
3929
3931 ereport(ERROR,
3933 errmsg("cannot reindex system catalogs concurrently")));
3934
3935 /*
3936 * Don't allow reindex for an invalid index on TOAST table, as
3937 * if rebuilt it would not be possible to drop it. Match
3938 * error message in reindex_index().
3939 */
3940 if (IsToastNamespace(get_rel_namespace(relationOid)) &&
3941 !get_index_isvalid(relationOid))
3942 ereport(ERROR,
3944 errmsg("cannot reindex invalid index on TOAST table")));
3945
3946 /*
3947 * Check if parent relation can be locked and if it exists,
3948 * this needs to be done at this stage as the list of indexes
3949 * to rebuild is not complete yet, and REINDEXOPT_MISSING_OK
3950 * should not be used once all the session locks are taken.
3951 */
3952 if ((params->options & REINDEXOPT_MISSING_OK) != 0)
3953 {
3954 heapRelation = try_table_open(heapId,
3956 /* leave if relation does not exist */
3957 if (!heapRelation)
3958 break;
3959 }
3960 else
3961 heapRelation = table_open(heapId,
3963
3964 if (OidIsValid(params->tablespaceOid) &&
3965 IsSystemRelation(heapRelation))
3966 ereport(ERROR,
3968 errmsg("cannot move system relation \"%s\"",
3969 get_rel_name(relationOid))));
3970
3971 table_close(heapRelation, NoLock);
3972
3973 /* Save the list of relation OIDs in private context */
3975
3976 /* Track the heap relation of this index for session locks */
3978
3979 /*
3980 * Save the list of relation OIDs in private context. Note
3981 * that invalid indexes are allowed here.
3982 */
3984 idx->indexId = relationOid;
3986 /* other fields set later */
3987
3988 MemoryContextSwitchTo(oldcontext);
3989 break;
3990 }
3991
3994 default:
3995 /* Return error if type of relation is not supported */
3996 ereport(ERROR,
3998 errmsg("cannot reindex this type of relation concurrently")));
3999 break;
4000 }
4001
4002 /*
4003 * Definitely no indexes, so leave. Any checks based on
4004 * REINDEXOPT_MISSING_OK should be done only while the list of indexes to
4005 * work on is built as the session locks taken before this transaction
4006 * commits will make sure that they cannot be dropped by a concurrent
4007 * session until this operation completes.
4008 */
4009 if (indexIds == NIL)
4010 return false;
4011
4012 /* It's not a shared catalog, so refuse to move it to shared tablespace */
4013 if (params->tablespaceOid == GLOBALTABLESPACE_OID)
4014 ereport(ERROR,
4016 errmsg("cannot move non-shared relation to tablespace \"%s\"",
4018
4020
4021 /*-----
4022 * Now we have all the indexes we want to process in indexIds.
4023 *
4024 * The phases now are:
4025 *
4026 * 1. create new indexes in the catalog
4027 * 2. build new indexes
4028 * 3. let new indexes catch up with tuples inserted in the meantime
4029 * 4. swap index names
4030 * 5. mark old indexes as dead
4031 * 6. drop old indexes
4032 *
4033 * We process each phase for all indexes before moving to the next phase,
4034 * for efficiency.
4035 */
4036
4037 /*
4038 * Phase 1 of REINDEX CONCURRENTLY
4039 *
4040 * Create a new index with the same properties as the old one, but it is
4041 * only registered in catalogs and will be built later. Then get session
4042 * locks on all involved tables. See analogous code in DefineIndex() for
4043 * more detailed comments.
4044 */
4045
4046 foreach(lc, indexIds)
4047 {
4048 char *concurrentName;
4052 Relation indexRel;
4053 Relation heapRel;
4054 Oid save_userid;
4055 int save_sec_context;
4056 int save_nestlevel;
4060
4061 indexRel = index_open(idx->indexId, ShareUpdateExclusiveLock);
4062 heapRel = table_open(indexRel->rd_index->indrelid,
4064
4065 /*
4066 * Switch to the table owner's userid, so that any index functions are
4067 * run as that user. Also lock down security-restricted operations
4068 * and arrange to make GUC variable changes local to this command.
4069 */
4070 GetUserIdAndSecContext(&save_userid, &save_sec_context);
4071 SetUserIdAndSecContext(heapRel->rd_rel->relowner,
4072 save_sec_context | SECURITY_RESTRICTED_OPERATION);
4073 save_nestlevel = NewGUCNestLevel();
4075
4076 /* determine safety of this index for set_indexsafe_procflags */
4077 idx->safe = (RelationGetIndexExpressions(indexRel) == NIL &&
4078 RelationGetIndexPredicate(indexRel) == NIL);
4079
4080#ifdef USE_INJECTION_POINTS
4081 if (idx->safe)
4082 INJECTION_POINT("reindex-conc-index-safe", NULL);
4083 else
4084 INJECTION_POINT("reindex-conc-index-not-safe", NULL);
4085#endif
4086
4087 idx->tableId = RelationGetRelid(heapRel);
4088 idx->amId = indexRel->rd_rel->relam;
4089
4090 /* This function shouldn't be called for temporary relations. */
4091 if (indexRel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
4092 elog(ERROR, "cannot reindex a temporary table concurrently");
4093
4095
4097 progress_vals[1] = 0; /* initializing */
4098 progress_vals[2] = idx->indexId;
4099 progress_vals[3] = idx->amId;
4101
4102 /* Choose a temporary relation name for the new index */
4104 NULL,
4105 "ccnew",
4106 get_rel_namespace(indexRel->rd_index->indrelid),
4107 false);
4108
4109 /* Choose the new tablespace, indexes of toast tables are not moved */
4110 if (OidIsValid(params->tablespaceOid) &&
4111 heapRel->rd_rel->relkind != RELKIND_TOASTVALUE)
4112 tablespaceid = params->tablespaceOid;
4113 else
4114 tablespaceid = indexRel->rd_rel->reltablespace;
4115
4116 /* Create new index definition based on given index */
4117 newIndexId = index_create_copy(heapRel,
4121 idx->indexId,
4124
4125 /*
4126 * Now open the relation of the new index, a session-level lock is
4127 * also needed on it.
4128 */
4130
4131 /*
4132 * Save the list of OIDs and locks in private context
4133 */
4135
4137 newidx->indexId = newIndexId;
4138 newidx->safe = idx->safe;
4139 newidx->tableId = idx->tableId;
4140 newidx->amId = idx->amId;
4141
4143
4144 /*
4145 * Save lockrelid to protect each relation from drop then close
4146 * relations. The lockrelid on parent relation is not taken here to
4147 * avoid multiple locks taken on the same relation, instead we rely on
4148 * parentRelationIds built earlier.
4149 */
4151 *lockrelid = indexRel->rd_lockInfo.lockRelId;
4154 *lockrelid = newIndexRel->rd_lockInfo.lockRelId;
4156
4157 MemoryContextSwitchTo(oldcontext);
4158
4159 index_close(indexRel, NoLock);
4161
4162 /* Roll back any GUC changes executed by index functions */
4163 AtEOXact_GUC(false, save_nestlevel);
4164
4165 /* Restore userid and security context */
4166 SetUserIdAndSecContext(save_userid, save_sec_context);
4167
4168 table_close(heapRel, NoLock);
4169
4170 /*
4171 * If a statement is available, telling that this comes from a REINDEX
4172 * command, collect the new index for event triggers.
4173 */
4174 if (stmt)
4175 {
4176 ObjectAddress address;
4177
4181 (const Node *) stmt);
4182 }
4183 }
4184
4185 /*
4186 * Save the heap lock for following visibility checks with other backends
4187 * might conflict with this session.
4188 */
4189 foreach(lc, heapRelationIds)
4190 {
4194
4195 /* Save the list of locks in private context */
4197
4198 /* Add lockrelid of heap relation to the list of locked relations */
4200 *lockrelid = heapRelation->rd_lockInfo.lockRelId;
4202
4204
4205 /* Save the LOCKTAG for this parent relation for the wait phase */
4208
4209 MemoryContextSwitchTo(oldcontext);
4210
4211 /* Close heap relation */
4212 table_close(heapRelation, NoLock);
4213 }
4214
4215 /* Get a session-level lock on each table. */
4216 foreach(lc, relationLocks)
4217 {
4219
4221 }
4222
4226
4227 /*
4228 * Because we don't take a snapshot in this transaction, there's no need
4229 * to set the PROC_IN_SAFE_IC flag here.
4230 */
4231
4232 /*
4233 * Phase 2 of REINDEX CONCURRENTLY
4234 *
4235 * Build the new indexes in a separate transaction for each index to avoid
4236 * having open transactions for an unnecessary long time. But before
4237 * doing that, wait until no running transactions could have the table of
4238 * the index open with the old list of indexes. See "phase 2" in
4239 * DefineIndex() for more details.
4240 */
4241
4246
4247 foreach(lc, newIndexIds)
4248 {
4250
4251 /* Start new transaction for this index's concurrent build */
4253
4254 /*
4255 * Check for user-requested abort. This is inside a transaction so as
4256 * xact.c does not issue a useless WARNING, and ensures that
4257 * session-level locks are cleaned up on abort.
4258 */
4260
4261 /* Tell concurrent indexing to ignore us, if index qualifies */
4262 if (newidx->safe)
4264
4265 /* Set ActiveSnapshot since functions in the indexes may need it */
4267
4268 /*
4269 * Update progress for the index to build, with the correct parent
4270 * table involved.
4271 */
4275 progress_vals[2] = newidx->indexId;
4276 progress_vals[3] = newidx->amId;
4278
4279 /* Perform concurrent build of new index */
4280 index_concurrently_build(newidx->tableId, newidx->indexId);
4281
4284 }
4285
4287
4288 /*
4289 * Because we don't take a snapshot or Xid in this transaction, there's no
4290 * need to set the PROC_IN_SAFE_IC flag here.
4291 */
4292
4293 /*
4294 * Phase 3 of REINDEX CONCURRENTLY
4295 *
4296 * During this phase the old indexes catch up with any new tuples that
4297 * were created during the previous phase. See "phase 3" in DefineIndex()
4298 * for more details.
4299 */
4300
4305
4306 foreach(lc, newIndexIds)
4307 {
4310 Snapshot snapshot;
4311
4313
4314 /*
4315 * Check for user-requested abort. This is inside a transaction so as
4316 * xact.c does not issue a useless WARNING, and ensures that
4317 * session-level locks are cleaned up on abort.
4318 */
4320
4321 /* Tell concurrent indexing to ignore us, if index qualifies */
4322 if (newidx->safe)
4324
4325 /*
4326 * Take the "reference snapshot" that will be used by validate_index()
4327 * to filter candidate tuples.
4328 */
4330 PushActiveSnapshot(snapshot);
4331
4332 /*
4333 * Update progress for the index to build, with the correct parent
4334 * table involved.
4335 */
4339 progress_vals[2] = newidx->indexId;
4340 progress_vals[3] = newidx->amId;
4342
4343 validate_index(newidx->tableId, newidx->indexId, snapshot);
4344
4345 /*
4346 * We can now do away with our active snapshot, we still need to save
4347 * the xmin limit to wait for older snapshots.
4348 */
4349 limitXmin = snapshot->xmin;
4350
4352 UnregisterSnapshot(snapshot);
4353
4354 /*
4355 * To ensure no deadlocks, we must commit and start yet another
4356 * transaction, and do our wait before any snapshot has been taken in
4357 * it.
4358 */
4361
4362 /*
4363 * The index is now valid in the sense that it contains all currently
4364 * interesting tuples. But since it might not contain tuples deleted
4365 * just before the reference snap was taken, we have to wait out any
4366 * transactions that might have older snapshots.
4367 *
4368 * Because we don't take a snapshot or Xid in this transaction,
4369 * there's no need to set the PROC_IN_SAFE_IC flag here.
4370 */
4374
4376 }
4377
4378 /*
4379 * Phase 4 of REINDEX CONCURRENTLY
4380 *
4381 * Now that the new indexes have been validated, swap each new index with
4382 * its corresponding old index.
4383 *
4384 * We mark the new indexes as valid and the old indexes as not valid at
4385 * the same time to make sure we only get constraint violations from the
4386 * indexes with the correct names.
4387 */
4388
4389 INJECTION_POINT("reindex-relation-concurrently-before-swap", NULL);
4391
4392 /*
4393 * Because this transaction only does catalog manipulations and doesn't do
4394 * any index operations, we can set the PROC_IN_SAFE_IC flag here
4395 * unconditionally.
4396 */
4398
4400 {
4403 char *oldName;
4404
4405 /*
4406 * Check for user-requested abort. This is inside a transaction so as
4407 * xact.c does not issue a useless WARNING, and ensures that
4408 * session-level locks are cleaned up on abort.
4409 */
4411
4412 /* Choose a relation name for old index */
4414 NULL,
4415 "ccold",
4416 get_rel_namespace(oldidx->tableId),
4417 false);
4418
4419 /*
4420 * Swapping the indexes might involve TOAST table access, so ensure we
4421 * have a valid snapshot.
4422 */
4424
4425 /*
4426 * Swap old index with the new one. This also marks the new one as
4427 * valid and the old one as not valid.
4428 */
4429 index_concurrently_swap(newidx->indexId, oldidx->indexId, oldName);
4430
4432
4433 /*
4434 * Invalidate the relcache for the table, so that after this commit
4435 * all sessions will refresh any cached plans that might reference the
4436 * index.
4437 */
4439
4440 /*
4441 * CCI here so that subsequent iterations see the oldName in the
4442 * catalog and can choose a nonconflicting name for their oldName.
4443 * Otherwise, this could lead to conflicts if a table has two indexes
4444 * whose names are equal for the first NAMEDATALEN-minus-a-few
4445 * characters.
4446 */
4448 }
4449
4450 /* Commit this transaction and make index swaps visible */
4453
4454 /*
4455 * While we could set PROC_IN_SAFE_IC if all indexes qualified, there's no
4456 * real need for that, because we only acquire an Xid after the wait is
4457 * done, and that lasts for a very short period.
4458 */
4459
4460 /*
4461 * Phase 5 of REINDEX CONCURRENTLY
4462 *
4463 * Mark the old indexes as dead. First we must wait until no running
4464 * transaction could be using the index for a query. See also
4465 * index_drop() for more details.
4466 */
4467
4468 INJECTION_POINT("reindex-relation-concurrently-before-set-dead", NULL);
4472
4473 foreach(lc, indexIds)
4474 {
4476
4477 /*
4478 * Check for user-requested abort. This is inside a transaction so as
4479 * xact.c does not issue a useless WARNING, and ensures that
4480 * session-level locks are cleaned up on abort.
4481 */
4483
4484 /*
4485 * Updating pg_index might involve TOAST table access, so ensure we
4486 * have a valid snapshot.
4487 */
4489
4490 index_concurrently_set_dead(oldidx->tableId, oldidx->indexId);
4491
4493 }
4494
4495 /* Commit this transaction to make the updates visible. */
4498
4499 /*
4500 * While we could set PROC_IN_SAFE_IC if all indexes qualified, there's no
4501 * real need for that, because we only acquire an Xid after the wait is
4502 * done, and that lasts for a very short period.
4503 */
4504
4505 /*
4506 * Phase 6 of REINDEX CONCURRENTLY
4507 *
4508 * Drop the old indexes.
4509 */
4510
4514
4516
4517 {
4519
4520 foreach(lc, indexIds)
4521 {
4523 ObjectAddress object;
4524
4525 object.classId = RelationRelationId;
4526 object.objectId = idx->indexId;
4527 object.objectSubId = 0;
4528
4529 add_exact_object_address(&object, objects);
4530 }
4531
4532 /*
4533 * Use PERFORM_DELETION_CONCURRENT_LOCK so that index_drop() uses the
4534 * right lock level.
4535 */
4538 }
4539
4542
4543 /*
4544 * Finally, release the session-level lock on the table.
4545 */
4546 foreach(lc, relationLocks)
4547 {
4549
4551 }
4552
4553 /* Start a new transaction to finish process properly */
4555
4556 /* Log what we did */
4557 if ((params->options & REINDEXOPT_VERBOSE) != 0)
4558 {
4559 if (relkind == RELKIND_INDEX)
4560 ereport(INFO,
4561 (errmsg("index \"%s.%s\" was reindexed",
4563 errdetail("%s.",
4564 pg_rusage_show(&ru0))));
4565 else
4566 {
4567 foreach(lc, newIndexIds)
4568 {
4570 Oid indOid = idx->indexId;
4571
4572 ereport(INFO,
4573 (errmsg("index \"%s.%s\" was reindexed",
4575 get_rel_name(indOid))));
4576 /* Don't show rusage here, since it's not per index. */
4577 }
4578
4579 ereport(INFO,
4580 (errmsg("table \"%s.%s\" was reindexed",
4582 errdetail("%s.",
4583 pg_rusage_show(&ru0))));
4584 }
4585 }
4586
4588
4590
4591 return true;
4592}
Datum idx(PG_FUNCTION_ARGS)
Definition _int_op.c:263
bool IsToastNamespace(Oid namespaceId)
Definition catalog.c:277
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:89
void index_concurrently_set_dead(Oid heapId, Oid indexId)
Definition index.c:1841
void index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName)
Definition index.c:1570
Oid index_create_copy(Relation heapRelation, uint16 flags, Oid oldIndexId, Oid tablespaceOid, const char *newName)
Definition index.c:1306
#define INDEX_CREATE_SUPPRESS_PROGRESS
Definition index.h:74
void WaitForLockersMultiple(List *locktags, LOCKMODE lockmode, bool progress)
Definition lmgr.c:911
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:125
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:129
#define PROGRESS_CREATEIDX_PHASE_BUILD
Definition progress.h:123
#define PROGRESS_CREATEIDX_COMMAND_REINDEX_CONCURRENTLY
Definition progress.h:142
#define PROGRESS_CREATEIDX_PHASE_VALIDATE_IDXSCAN
Definition progress.h:125
#define PROGRESS_CREATEIDX_PHASE_WAIT_5
Definition progress.h:130
List * RelationGetIndexPredicate(Relation relation)
Definition relcache.c:5222
List * RelationGetIndexExpressions(Relation relation)
Definition relcache.c:5109
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_set_dead(), index_concurrently_swap(), INDEX_CREATE_CONCURRENT, index_create_copy(), INDEX_CREATE_SKIP_BUILD, INDEX_CREATE_SUPPRESS_PROGRESS, 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 3202 of file indexcmds.c.

3203{
3204 Oid heapOid;
3205 bool result;
3206 const RangeVar *relation = stmt->relation;
3207
3208 /*
3209 * The lock level used here should match reindex_relation().
3210 *
3211 * If it's a temporary table, we will perform a non-concurrent reindex,
3212 * even if CONCURRENTLY was requested. In that case, reindex_relation()
3213 * will upgrade the lock, but that's OK, because other sessions can't hold
3214 * locks on our temporary table.
3215 */
3216 heapOid = RangeVarGetRelidExtended(relation,
3217 (params->options & REINDEXOPT_CONCURRENTLY) != 0 ?
3219 0,
3221
3223 ReindexPartitions(stmt, heapOid, params, isTopLevel);
3224 else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
3226 {
3227 result = ReindexRelationConcurrently(stmt, heapOid, params);
3228
3229 if (!result)
3231 (errmsg("table \"%s\" has no indexes that can be reindexed concurrently",
3232 relation->relname)));
3233 }
3234 else
3235 {
3236 ReindexParams newparams = *params;
3237
3239 result = reindex_relation(stmt, heapOid,
3242 &newparams);
3243 if (!result)
3245 (errmsg("table \"%s\" has no indexes to reindex",
3246 relation->relname)));
3247 }
3248
3249 return heapOid;
3250}
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, result, ShareLock, ShareUpdateExclusiveLock, and stmt.

Referenced by ExecReindex().

◆ ResolveOpClass()

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

Definition at line 2296 of file indexcmds.c.

2298{
2299 char *schemaname;
2300 char *opcname;
2301 HeapTuple tuple;
2303 Oid opClassId,
2305
2306 if (opclass == NIL)
2307 {
2308 /* no operator class specified, so find the default */
2310 if (!OidIsValid(opClassId))
2311 ereport(ERROR,
2313 errmsg("data type %s has no default operator class for access method \"%s\"",
2315 errhint("You must specify an operator class for the index or define a default operator class for the data type.")));
2316 return opClassId;
2317 }
2318
2319 /*
2320 * Specific opclass name given, so look up the opclass.
2321 */
2322
2323 /* deconstruct the name list */
2324 DeconstructQualifiedName(opclass, &schemaname, &opcname);
2325
2326 if (schemaname)
2327 {
2328 /* Look in specific schema only */
2330
2331 namespaceId = LookupExplicitNamespace(schemaname, false);
2336 }
2337 else
2338 {
2339 /* Unqualified opclass name, so search the search path */
2341 if (!OidIsValid(opClassId))
2342 ereport(ERROR,
2344 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
2347 }
2348
2349 if (!HeapTupleIsValid(tuple))
2350 ereport(ERROR,
2352 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
2354
2355 /*
2356 * Verify that the index operator class accepts this datatype. Note we
2357 * will accept binary compatibility.
2358 */
2359 opform = (Form_pg_opclass) GETSTRUCT(tuple);
2360 opClassId = opform->oid;
2361 opInputType = opform->opcintype;
2362
2364 ereport(ERROR,
2366 errmsg("operator class \"%s\" does not accept data type %s",
2368
2369 ReleaseSysCache(tuple);
2370
2371 return opClassId;
2372}
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition indexcmds.c:2381
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 4771 of file indexcmds.c.

4772{
4773 /*
4774 * This should only be called before installing xid or xmin in MyProc;
4775 * otherwise, concurrent processes could see an Xmin that moves backwards.
4776 */
4779
4784}
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1150
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1767
@ LW_EXCLUSIVE
Definition lwlock.h:104
#define PROC_IN_SAFE_IC
Definition proc.h:63
PROC_HDR * ProcGlobal
Definition proc.c:74
uint8 statusFlags
Definition proc.h:210
int pgxactoff
Definition proc.h:207
TransactionId xid
Definition proc.h:237
uint8 * statusFlags
Definition proc.h:456

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

4734{
4735 HeapTuple tup;
4738
4741 if (!HeapTupleIsValid(tup))
4742 elog(ERROR, "cache lookup failed for relation %u", relationId);
4743 otid = tup->t_self;
4750}
#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 446 of file indexcmds.c.

447{
448 int n_old_snapshots;
449 int i;
451
456 if (progress)
458
459 for (i = 0; i < n_old_snapshots; i++)
460 {
462 continue; /* found uninteresting in previous cycle */
463
464 if (i > 0)
465 {
466 /* see if anything's changed ... */
469 int j;
470 int k;
471
473 true, false,
477 for (j = i; j < n_old_snapshots; j++)
478 {
480 continue; /* found uninteresting in previous cycle */
481 for (k = 0; k < n_newer_snapshots; k++)
482 {
484 newer_snapshots[k]))
485 break;
486 }
487 if (k >= n_newer_snapshots) /* not there anymore */
489 }
491 }
492
494 {
495 /* If requested, publish who we're going to wait for. */
496 if (progress)
497 {
499
500 if (holder)
502 holder->pid);
503 }
505 }
506
507 if (progress)
509 }
510}
bool VirtualXactLock(VirtualTransactionId vxid, bool wait)
Definition lock.c:4723
#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:62
#define PROC_IS_AUTOVACUUM
Definition proc.h:61
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:146
#define PROGRESS_WAITFOR_TOTAL
Definition progress.h:145
#define PROGRESS_WAITFOR_CURRENT_PID
Definition progress.h:147
Definition proc.h:179

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

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