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 charChooseIndexName (const char *tabname, Oid namespaceId, const List *colnames, const List *exclusionOpNames, bool primary, bool isconstraint)
 
static charChooseIndexNameAddition (const List *colnames)
 
static ListChooseIndexColumnNames (Relation rel, const List *indexElems)
 
static charChooseIndexExpressionName (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)
 
charmakeObjectName (const char *name1, const char *name2, const char *label)
 
charChooseRelationName (const char *name1, const char *name2, const char *label, Oid namespaceid, bool isconstraint)
 
void ExecReindex (ParseState *pstate, const ReindexStmt *stmt, bool isTopLevel)
 
void IndexSetParentIndex (Relation partitionIdx, Oid parentOid)
 

Typedef Documentation

◆ 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:3604
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:5663
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:832
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:1303
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:3371
void index_set_state_flags(Oid indexId, IndexStateFlagsAction action)
Definition index.c:3524
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:922
@ 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:4846
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:863
ParseLoc location
Definition parsenodes.h:867
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:3629
#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:3969
#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:1435
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:5220
List * RelationGetIndexExpressions(Relation relation)
Definition relcache.c:5107
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().