Coverage Report

Created: 2026-08-13 07:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/catalog/index.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * index.c
4
 *    code to create and destroy POSTGRES index relations
5
 *
6
 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7
 * Portions Copyright (c) 1994, Regents of the University of California
8
 *
9
 *
10
 * IDENTIFICATION
11
 *    src/backend/catalog/index.c
12
 *
13
 *
14
 * INTERFACE ROUTINES
15
 *    index_create()      - Create a cataloged index relation
16
 *    index_drop()      - Removes index relation from catalogs
17
 *    BuildIndexInfo()    - Prepare to insert index tuples
18
 *    FormIndexDatum()    - Construct datum vector for one index tuple
19
 *
20
 *-------------------------------------------------------------------------
21
 */
22
#include "postgres.h"
23
24
#include <unistd.h>
25
26
#include "access/amapi.h"
27
#include "access/attmap.h"
28
#include "access/heapam.h"
29
#include "access/multixact.h"
30
#include "access/relscan.h"
31
#include "access/tableam.h"
32
#include "access/toast_compression.h"
33
#include "access/transam.h"
34
#include "access/visibilitymap.h"
35
#include "access/xact.h"
36
#include "bootstrap/bootstrap.h"
37
#include "catalog/binary_upgrade.h"
38
#include "catalog/catalog.h"
39
#include "catalog/dependency.h"
40
#include "catalog/heap.h"
41
#include "catalog/index.h"
42
#include "catalog/objectaccess.h"
43
#include "catalog/partition.h"
44
#include "catalog/pg_am.h"
45
#include "catalog/pg_collation.h"
46
#include "catalog/pg_constraint.h"
47
#include "catalog/pg_description.h"
48
#include "catalog/pg_inherits.h"
49
#include "catalog/pg_opclass.h"
50
#include "catalog/pg_operator.h"
51
#include "catalog/pg_tablespace.h"
52
#include "catalog/pg_trigger.h"
53
#include "catalog/pg_type.h"
54
#include "catalog/storage.h"
55
#include "catalog/storage_xlog.h"
56
#include "commands/event_trigger.h"
57
#include "commands/progress.h"
58
#include "commands/tablecmds.h"
59
#include "commands/trigger.h"
60
#include "executor/executor.h"
61
#include "miscadmin.h"
62
#include "nodes/makefuncs.h"
63
#include "nodes/nodeFuncs.h"
64
#include "optimizer/optimizer.h"
65
#include "parser/parser.h"
66
#include "pgstat.h"
67
#include "postmaster/autovacuum.h"
68
#include "rewrite/rewriteManip.h"
69
#include "storage/bufmgr.h"
70
#include "storage/lmgr.h"
71
#include "storage/predicate.h"
72
#include "storage/smgr.h"
73
#include "utils/builtins.h"
74
#include "utils/fmgroids.h"
75
#include "utils/guc.h"
76
#include "utils/inval.h"
77
#include "utils/lsyscache.h"
78
#include "utils/memutils.h"
79
#include "utils/pg_rusage.h"
80
#include "utils/rel.h"
81
#include "utils/snapmgr.h"
82
#include "utils/syscache.h"
83
#include "utils/tuplesort.h"
84
85
/* Potentially set by pg_upgrade_support functions */
86
Oid     binary_upgrade_next_index_pg_class_oid = InvalidOid;
87
RelFileNumber binary_upgrade_next_index_pg_class_relfilenumber =
88
InvalidRelFileNumber;
89
90
/*
91
 * Pointer-free representation of variables used when reindexing system
92
 * catalogs; we use this to propagate those values to parallel workers.
93
 */
94
typedef struct
95
{
96
  Oid     currentlyReindexedHeap;
97
  Oid     currentlyReindexedIndex;
98
  int     numPendingReindexedIndexes;
99
  Oid     pendingReindexedIndexes[FLEXIBLE_ARRAY_MEMBER];
100
} SerializedReindexState;
101
102
/* non-export function prototypes */
103
static bool relationHasPrimaryKey(Relation rel);
104
static TupleDesc ConstructTupleDescriptor(Relation heapRelation,
105
                      const IndexInfo *indexInfo,
106
                      const List *indexColNames,
107
                      Oid accessMethodId,
108
                      const Oid *collationIds,
109
                      const Oid *opclassIds);
110
static void InitializeAttributeOids(Relation indexRelation,
111
                  int numatts, Oid indexoid);
112
static void AppendAttributeTuples(Relation indexRelation, const Datum *attopts, const NullableDatum *stattargets);
113
static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
114
                Oid parentIndexId,
115
                const IndexInfo *indexInfo,
116
                const Oid *collationOids,
117
                const Oid *opclassOids,
118
                const int16 *coloptions,
119
                bool primary,
120
                bool isexclusion,
121
                bool immediate,
122
                bool isvalid,
123
                bool isready);
124
static void index_update_stats(Relation rel,
125
                 bool hasindex,
126
                 double reltuples);
127
static void IndexCheckExclusion(Relation heapRelation,
128
                Relation indexRelation,
129
                IndexInfo *indexInfo);
130
static bool validate_index_callback(ItemPointer itemptr, void *opaque);
131
static bool ReindexIsCurrentlyProcessingIndex(Oid indexOid);
132
static void SetReindexProcessing(Oid heapOid, Oid indexOid);
133
static void ResetReindexProcessing(void);
134
static void SetReindexPending(List *indexes);
135
static void RemoveReindexPending(Oid indexOid);
136
137
138
/*
139
 * relationHasPrimaryKey
140
 *    See whether an existing relation has a primary key.
141
 *
142
 * Caller must have suitable lock on the relation.
143
 *
144
 * Note: we intentionally do not check indisvalid here; that's because this
145
 * is used to enforce the rule that there can be only one indisprimary index,
146
 * and we want that to be true even if said index is invalid.
147
 */
148
static bool
149
relationHasPrimaryKey(Relation rel)
150
0
{
151
0
  bool    result = false;
152
0
  List     *indexoidlist;
153
0
  ListCell   *indexoidscan;
154
155
  /*
156
   * Get the list of index OIDs for the table from the relcache, and look up
157
   * each one in the pg_index syscache until we find one marked primary key
158
   * (hopefully there isn't more than one such).
159
   */
160
0
  indexoidlist = RelationGetIndexList(rel);
161
162
0
  foreach(indexoidscan, indexoidlist)
163
0
  {
164
0
    Oid     indexoid = lfirst_oid(indexoidscan);
165
0
    HeapTuple indexTuple;
166
167
0
    indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
168
0
    if (!HeapTupleIsValid(indexTuple)) /* should not happen */
169
0
      elog(ERROR, "cache lookup failed for index %u", indexoid);
170
0
    result = ((Form_pg_index) GETSTRUCT(indexTuple))->indisprimary;
171
0
    ReleaseSysCache(indexTuple);
172
0
    if (result)
173
0
      break;
174
0
  }
175
176
0
  list_free(indexoidlist);
177
178
0
  return result;
179
0
}
180
181
/*
182
 * index_check_primary_key
183
 *    Apply special checks needed before creating a PRIMARY KEY index
184
 *
185
 * This processing used to be in DefineIndex(), but has been split out
186
 * so that it can be applied during ALTER TABLE ADD PRIMARY KEY USING INDEX.
187
 *
188
 * We check for a pre-existing primary key, and that all columns of the index
189
 * are simple column references (not expressions), and that all those
190
 * columns are marked NOT NULL.  If not, fail.
191
 *
192
 * We used to automatically change unmarked columns to NOT NULL here by doing
193
 * our own local ALTER TABLE command.  But that doesn't work well if we're
194
 * executing one subcommand of an ALTER TABLE: the operations may not get
195
 * performed in the right order overall.  Now we expect that the parser
196
 * inserted any required ALTER TABLE SET NOT NULL operations before trying
197
 * to create a primary-key index.
198
 *
199
 * Caller had better have at least ShareLock on the table, else the not-null
200
 * checking isn't trustworthy.
201
 */
202
void
203
index_check_primary_key(Relation heapRel,
204
            const IndexInfo *indexInfo,
205
            bool is_alter_table,
206
            const IndexStmt *stmt)
207
0
{
208
0
  int     i;
209
210
  /*
211
   * If ALTER TABLE or CREATE TABLE .. PARTITION OF, check that there isn't
212
   * already a PRIMARY KEY.  In CREATE TABLE for an ordinary relation, we
213
   * have faith that the parser rejected multiple pkey clauses; and CREATE
214
   * INDEX doesn't have a way to say PRIMARY KEY, so it's no problem either.
215
   */
216
0
  if ((is_alter_table || heapRel->rd_rel->relispartition) &&
217
0
    relationHasPrimaryKey(heapRel))
218
0
  {
219
0
    ereport(ERROR,
220
0
        (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
221
0
         errmsg("multiple primary keys for table \"%s\" are not allowed",
222
0
            RelationGetRelationName(heapRel))));
223
0
  }
224
225
  /*
226
   * Indexes created with NULLS NOT DISTINCT cannot be used for primary key
227
   * constraints. While there is no direct syntax to reach here, it can be
228
   * done by creating a separate index and attaching it via ALTER TABLE ..
229
   * USING INDEX.
230
   */
231
0
  if (indexInfo->ii_NullsNotDistinct)
232
0
  {
233
0
    ereport(ERROR,
234
0
        (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
235
0
         errmsg("primary keys cannot use NULLS NOT DISTINCT indexes")));
236
0
  }
237
238
  /*
239
   * Check that all of the attributes in a primary key are marked as not
240
   * null.  (We don't really expect to see that; it'd mean the parser messed
241
   * up.  But it seems wise to check anyway.)
242
   */
243
0
  for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
244
0
  {
245
0
    AttrNumber  attnum = indexInfo->ii_IndexAttrNumbers[i];
246
0
    HeapTuple atttuple;
247
0
    Form_pg_attribute attform;
248
249
0
    if (attnum == 0)
250
0
      ereport(ERROR,
251
0
          (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
252
0
           errmsg("primary keys cannot be expressions")));
253
254
    /* System attributes are never null, so no need to check */
255
0
    if (attnum < 0)
256
0
      continue;
257
258
0
    atttuple = SearchSysCache2(ATTNUM,
259
0
                   ObjectIdGetDatum(RelationGetRelid(heapRel)),
260
0
                   Int16GetDatum(attnum));
261
0
    if (!HeapTupleIsValid(atttuple))
262
0
      elog(ERROR, "cache lookup failed for attribute %d of relation %u",
263
0
         attnum, RelationGetRelid(heapRel));
264
0
    attform = (Form_pg_attribute) GETSTRUCT(atttuple);
265
266
0
    if (!attform->attnotnull)
267
0
      ereport(ERROR,
268
0
          (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
269
0
           errmsg("primary key column \"%s\" is not marked NOT NULL",
270
0
              NameStr(attform->attname))));
271
272
0
    ReleaseSysCache(atttuple);
273
0
  }
274
0
}
275
276
/*
277
 *    ConstructTupleDescriptor
278
 *
279
 * Build an index tuple descriptor for a new index
280
 */
281
static TupleDesc
282
ConstructTupleDescriptor(Relation heapRelation,
283
             const IndexInfo *indexInfo,
284
             const List *indexColNames,
285
             Oid accessMethodId,
286
             const Oid *collationIds,
287
             const Oid *opclassIds)
288
0
{
289
0
  int     numatts = indexInfo->ii_NumIndexAttrs;
290
0
  int     numkeyatts = indexInfo->ii_NumIndexKeyAttrs;
291
0
  ListCell   *colnames_item = list_head(indexColNames);
292
0
  ListCell   *indexpr_item = list_head(indexInfo->ii_Expressions);
293
0
  const IndexAmRoutine *amroutine;
294
0
  TupleDesc heapTupDesc;
295
0
  TupleDesc indexTupDesc;
296
0
  int     natts;      /* #atts in heap rel --- for error checks */
297
0
  int     i;
298
299
  /* We need access to the index AM's API struct */
300
0
  amroutine = GetIndexAmRoutineByAmId(accessMethodId, false);
301
302
  /* ... and to the table's tuple descriptor */
303
0
  heapTupDesc = RelationGetDescr(heapRelation);
304
0
  natts = RelationGetForm(heapRelation)->relnatts;
305
306
  /*
307
   * allocate the new tuple descriptor
308
   */
309
0
  indexTupDesc = CreateTemplateTupleDesc(numatts);
310
311
  /*
312
   * Fill in the pg_attribute row.
313
   */
314
0
  for (i = 0; i < numatts; i++)
315
0
  {
316
0
    AttrNumber  atnum = indexInfo->ii_IndexAttrNumbers[i];
317
0
    Form_pg_attribute to = TupleDescAttr(indexTupDesc, i);
318
0
    HeapTuple tuple;
319
0
    Form_pg_type typeTup;
320
0
    Form_pg_opclass opclassTup;
321
0
    Oid     keyType;
322
323
0
    MemSet(to, 0, ATTRIBUTE_FIXED_PART_SIZE);
324
0
    to->attnum = i + 1;
325
0
    to->attislocal = true;
326
0
    to->attcollation = (i < numkeyatts) ? collationIds[i] : InvalidOid;
327
328
    /*
329
     * Set the attribute name as specified by caller.
330
     */
331
0
    if (colnames_item == NULL) /* shouldn't happen */
332
0
      elog(ERROR, "too few entries in colnames list");
333
0
    namestrcpy(&to->attname, (const char *) lfirst(colnames_item));
334
0
    colnames_item = lnext(indexColNames, colnames_item);
335
336
    /*
337
     * For simple index columns, we copy some pg_attribute fields from the
338
     * parent relation.  For expressions we have to look at the expression
339
     * result.
340
     */
341
0
    if (atnum != 0)
342
0
    {
343
      /* Simple index column */
344
0
      const FormData_pg_attribute *from;
345
346
0
      Assert(atnum > 0);  /* should've been caught above */
347
348
0
      if (atnum > natts) /* safety check */
349
0
        elog(ERROR, "invalid column number %d", atnum);
350
0
      from = TupleDescAttr(heapTupDesc,
351
0
                 AttrNumberGetAttrOffset(atnum));
352
353
0
      to->atttypid = from->atttypid;
354
0
      to->attlen = from->attlen;
355
0
      to->attndims = from->attndims;
356
0
      to->atttypmod = from->atttypmod;
357
0
      to->attbyval = from->attbyval;
358
0
      to->attalign = from->attalign;
359
0
      to->attstorage = from->attstorage;
360
0
      to->attcompression = from->attcompression;
361
0
    }
362
0
    else
363
0
    {
364
      /* Expressional index */
365
0
      Node     *indexkey;
366
367
0
      if (indexpr_item == NULL) /* shouldn't happen */
368
0
        elog(ERROR, "too few entries in indexprs list");
369
0
      indexkey = (Node *) lfirst(indexpr_item);
370
0
      indexpr_item = lnext(indexInfo->ii_Expressions, indexpr_item);
371
372
      /*
373
       * Lookup the expression type in pg_type for the type length etc.
374
       */
375
0
      keyType = exprType(indexkey);
376
0
      tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(keyType));
377
0
      if (!HeapTupleIsValid(tuple))
378
0
        elog(ERROR, "cache lookup failed for type %u", keyType);
379
0
      typeTup = (Form_pg_type) GETSTRUCT(tuple);
380
381
      /*
382
       * Assign some of the attributes values. Leave the rest.
383
       */
384
0
      to->atttypid = keyType;
385
0
      to->attlen = typeTup->typlen;
386
0
      to->atttypmod = exprTypmod(indexkey);
387
0
      to->attbyval = typeTup->typbyval;
388
0
      to->attalign = typeTup->typalign;
389
0
      to->attstorage = typeTup->typstorage;
390
391
      /*
392
       * For expression columns, set attcompression invalid, since
393
       * there's no table column from which to copy the value. Whenever
394
       * we actually need to compress a value, we'll use whatever the
395
       * current value of default_toast_compression is at that point in
396
       * time.
397
       */
398
0
      to->attcompression = InvalidCompressionMethod;
399
400
0
      ReleaseSysCache(tuple);
401
402
      /*
403
       * Make sure the expression yields a type that's safe to store in
404
       * an index.  We need this defense because we have index opclasses
405
       * for pseudo-types such as "record", and the actually stored type
406
       * had better be safe; eg, a named composite type is okay, an
407
       * anonymous record type is not.  The test is the same as for
408
       * whether a table column is of a safe type (which is why we
409
       * needn't check for the non-expression case).
410
       */
411
0
      CheckAttributeType(NameStr(to->attname),
412
0
                 to->atttypid, to->attcollation,
413
0
                 NIL, 0);
414
0
    }
415
416
    /*
417
     * We do not yet have the correct relation OID for the index, so just
418
     * set it invalid for now.  InitializeAttributeOids() will fix it
419
     * later.
420
     */
421
0
    to->attrelid = InvalidOid;
422
423
    /*
424
     * Check the opclass and index AM to see if either provides a keytype
425
     * (overriding the attribute type).  Opclass (if exists) takes
426
     * precedence.
427
     */
428
0
    keyType = amroutine->amkeytype;
429
430
0
    if (i < indexInfo->ii_NumIndexKeyAttrs)
431
0
    {
432
0
      tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassIds[i]));
433
0
      if (!HeapTupleIsValid(tuple))
434
0
        elog(ERROR, "cache lookup failed for opclass %u", opclassIds[i]);
435
0
      opclassTup = (Form_pg_opclass) GETSTRUCT(tuple);
436
0
      if (OidIsValid(opclassTup->opckeytype))
437
0
        keyType = opclassTup->opckeytype;
438
439
      /*
440
       * If keytype is specified as ANYELEMENT, and opcintype is
441
       * ANYARRAY, then the attribute type must be an array (else it'd
442
       * not have matched this opclass); use its element type.
443
       *
444
       * We could also allow ANYCOMPATIBLE/ANYCOMPATIBLEARRAY here, but
445
       * there seems no need to do so; there's no reason to declare an
446
       * opclass as taking ANYCOMPATIBLEARRAY rather than ANYARRAY.
447
       */
448
0
      if (keyType == ANYELEMENTOID && opclassTup->opcintype == ANYARRAYOID)
449
0
      {
450
0
        keyType = get_base_element_type(to->atttypid);
451
0
        if (!OidIsValid(keyType))
452
0
          elog(ERROR, "could not get element type of array type %u",
453
0
             to->atttypid);
454
0
      }
455
456
0
      ReleaseSysCache(tuple);
457
0
    }
458
459
    /*
460
     * If a key type different from the heap value is specified, update
461
     * the type-related fields in the index tupdesc.
462
     */
463
0
    if (OidIsValid(keyType) && keyType != to->atttypid)
464
0
    {
465
0
      tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(keyType));
466
0
      if (!HeapTupleIsValid(tuple))
467
0
        elog(ERROR, "cache lookup failed for type %u", keyType);
468
0
      typeTup = (Form_pg_type) GETSTRUCT(tuple);
469
470
0
      to->atttypid = keyType;
471
0
      to->atttypmod = -1;
472
0
      to->attlen = typeTup->typlen;
473
0
      to->attbyval = typeTup->typbyval;
474
0
      to->attalign = typeTup->typalign;
475
0
      to->attstorage = typeTup->typstorage;
476
      /* As above, use the default compression method in this case */
477
0
      to->attcompression = InvalidCompressionMethod;
478
479
0
      ReleaseSysCache(tuple);
480
0
    }
481
482
0
    populate_compact_attribute(indexTupDesc, i);
483
0
  }
484
485
0
  TupleDescFinalize(indexTupDesc);
486
487
0
  return indexTupDesc;
488
0
}
489
490
/* ----------------------------------------------------------------
491
 *    InitializeAttributeOids
492
 * ----------------------------------------------------------------
493
 */
494
static void
495
InitializeAttributeOids(Relation indexRelation,
496
            int numatts,
497
            Oid indexoid)
498
0
{
499
0
  TupleDesc tupleDescriptor;
500
0
  int     i;
501
502
0
  tupleDescriptor = RelationGetDescr(indexRelation);
503
504
0
  for (i = 0; i < numatts; i += 1)
505
0
    TupleDescAttr(tupleDescriptor, i)->attrelid = indexoid;
506
0
}
507
508
/* ----------------------------------------------------------------
509
 *    AppendAttributeTuples
510
 * ----------------------------------------------------------------
511
 */
512
static void
513
AppendAttributeTuples(Relation indexRelation, const Datum *attopts, const NullableDatum *stattargets)
514
0
{
515
0
  Relation  pg_attribute;
516
0
  CatalogIndexState indstate;
517
0
  TupleDesc indexTupDesc;
518
0
  FormExtraData_pg_attribute *attrs_extra = NULL;
519
520
0
  if (attopts)
521
0
  {
522
0
    attrs_extra = palloc0_array(FormExtraData_pg_attribute, indexRelation->rd_att->natts);
523
524
0
    for (int i = 0; i < indexRelation->rd_att->natts; i++)
525
0
    {
526
0
      if (attopts[i])
527
0
        attrs_extra[i].attoptions.value = attopts[i];
528
0
      else
529
0
        attrs_extra[i].attoptions.isnull = true;
530
531
0
      if (stattargets)
532
0
        attrs_extra[i].attstattarget = stattargets[i];
533
0
      else
534
0
        attrs_extra[i].attstattarget.isnull = true;
535
0
    }
536
0
  }
537
538
  /*
539
   * open the attribute relation and its indexes
540
   */
541
0
  pg_attribute = table_open(AttributeRelationId, RowExclusiveLock);
542
543
0
  indstate = CatalogOpenIndexes(pg_attribute);
544
545
  /*
546
   * insert data from new index's tupdesc into pg_attribute
547
   */
548
0
  indexTupDesc = RelationGetDescr(indexRelation);
549
550
0
  InsertPgAttributeTuples(pg_attribute, indexTupDesc, InvalidOid, attrs_extra, indstate);
551
552
0
  CatalogCloseIndexes(indstate);
553
554
0
  table_close(pg_attribute, RowExclusiveLock);
555
0
}
556
557
/* ----------------------------------------------------------------
558
 *    UpdateIndexRelation
559
 *
560
 * Construct and insert a new entry in the pg_index catalog
561
 * ----------------------------------------------------------------
562
 */
563
static void
564
UpdateIndexRelation(Oid indexoid,
565
          Oid heapoid,
566
          Oid parentIndexId,
567
          const IndexInfo *indexInfo,
568
          const Oid *collationOids,
569
          const Oid *opclassOids,
570
          const int16 *coloptions,
571
          bool primary,
572
          bool isexclusion,
573
          bool immediate,
574
          bool isvalid,
575
          bool isready)
576
0
{
577
0
  int2vector *indkey;
578
0
  oidvector  *indcollation;
579
0
  oidvector  *indclass;
580
0
  int2vector *indoption;
581
0
  Datum   exprsDatum;
582
0
  Datum   predDatum;
583
0
  Datum   values[Natts_pg_index];
584
0
  bool    nulls[Natts_pg_index] = {0};
585
0
  Relation  pg_index;
586
0
  HeapTuple tuple;
587
0
  int     i;
588
589
  /*
590
   * Copy the index key, opclass, and indoption info into arrays (should we
591
   * make the caller pass them like this to start with?)
592
   */
593
0
  indkey = buildint2vector(NULL, indexInfo->ii_NumIndexAttrs);
594
0
  for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
595
0
    indkey->values[i] = indexInfo->ii_IndexAttrNumbers[i];
596
0
  indcollation = buildoidvector(collationOids, indexInfo->ii_NumIndexKeyAttrs);
597
0
  indclass = buildoidvector(opclassOids, indexInfo->ii_NumIndexKeyAttrs);
598
0
  indoption = buildint2vector(coloptions, indexInfo->ii_NumIndexKeyAttrs);
599
600
  /*
601
   * Convert the index expressions (if any) to a text datum
602
   */
603
0
  if (indexInfo->ii_Expressions != NIL)
604
0
  {
605
0
    char     *exprsString;
606
607
0
    exprsString = nodeToString(indexInfo->ii_Expressions);
608
0
    exprsDatum = CStringGetTextDatum(exprsString);
609
0
    pfree(exprsString);
610
0
  }
611
0
  else
612
0
    exprsDatum = (Datum) 0;
613
614
  /*
615
   * Convert the index predicate (if any) to a text datum.  Note we convert
616
   * implicit-AND format to normal explicit-AND for storage.
617
   */
618
0
  if (indexInfo->ii_Predicate != NIL)
619
0
  {
620
0
    char     *predString;
621
622
0
    predString = nodeToString(make_ands_explicit(indexInfo->ii_Predicate));
623
0
    predDatum = CStringGetTextDatum(predString);
624
0
    pfree(predString);
625
0
  }
626
0
  else
627
0
    predDatum = (Datum) 0;
628
629
630
  /*
631
   * open the system catalog index relation
632
   */
633
0
  pg_index = table_open(IndexRelationId, RowExclusiveLock);
634
635
  /*
636
   * Build a pg_index tuple
637
   */
638
0
  values[Anum_pg_index_indexrelid - 1] = ObjectIdGetDatum(indexoid);
639
0
  values[Anum_pg_index_indrelid - 1] = ObjectIdGetDatum(heapoid);
640
0
  values[Anum_pg_index_indnatts - 1] = Int16GetDatum(indexInfo->ii_NumIndexAttrs);
641
0
  values[Anum_pg_index_indnkeyatts - 1] = Int16GetDatum(indexInfo->ii_NumIndexKeyAttrs);
642
0
  values[Anum_pg_index_indisunique - 1] = BoolGetDatum(indexInfo->ii_Unique);
643
0
  values[Anum_pg_index_indnullsnotdistinct - 1] = BoolGetDatum(indexInfo->ii_NullsNotDistinct);
644
0
  values[Anum_pg_index_indisprimary - 1] = BoolGetDatum(primary);
645
0
  values[Anum_pg_index_indisexclusion - 1] = BoolGetDatum(isexclusion);
646
0
  values[Anum_pg_index_indimmediate - 1] = BoolGetDatum(immediate);
647
0
  values[Anum_pg_index_indisclustered - 1] = BoolGetDatum(false);
648
0
  values[Anum_pg_index_indisvalid - 1] = BoolGetDatum(isvalid);
649
0
  values[Anum_pg_index_indcheckxmin - 1] = BoolGetDatum(false);
650
0
  values[Anum_pg_index_indisready - 1] = BoolGetDatum(isready);
651
0
  values[Anum_pg_index_indislive - 1] = BoolGetDatum(true);
652
0
  values[Anum_pg_index_indisreplident - 1] = BoolGetDatum(false);
653
0
  values[Anum_pg_index_indkey - 1] = PointerGetDatum(indkey);
654
0
  values[Anum_pg_index_indcollation - 1] = PointerGetDatum(indcollation);
655
0
  values[Anum_pg_index_indclass - 1] = PointerGetDatum(indclass);
656
0
  values[Anum_pg_index_indoption - 1] = PointerGetDatum(indoption);
657
0
  values[Anum_pg_index_indexprs - 1] = exprsDatum;
658
0
  if (exprsDatum == (Datum) 0)
659
0
    nulls[Anum_pg_index_indexprs - 1] = true;
660
0
  values[Anum_pg_index_indpred - 1] = predDatum;
661
0
  if (predDatum == (Datum) 0)
662
0
    nulls[Anum_pg_index_indpred - 1] = true;
663
664
0
  tuple = heap_form_tuple(RelationGetDescr(pg_index), values, nulls);
665
666
  /*
667
   * insert the tuple into the pg_index catalog
668
   */
669
0
  CatalogTupleInsert(pg_index, tuple);
670
671
  /*
672
   * close the relation and free the tuple
673
   */
674
0
  table_close(pg_index, RowExclusiveLock);
675
0
  heap_freetuple(tuple);
676
0
}
677
678
679
/*
680
 * index_create
681
 *
682
 * heapRelation: table to build index on (suitably locked by caller)
683
 * indexRelationName: what it say
684
 * indexRelationId: normally, pass InvalidOid to let this routine
685
 *    generate an OID for the index.  During bootstrap this may be
686
 *    nonzero to specify a preselected OID.
687
 * parentIndexRelid: if creating an index partition, the OID of the
688
 *    parent index; otherwise InvalidOid.
689
 * parentConstraintId: if creating a constraint on a partition, the OID
690
 *    of the constraint in the parent; otherwise InvalidOid.
691
 * relFileNumber: normally, pass InvalidRelFileNumber to get new storage.
692
 *    May be nonzero to attach an existing valid build.
693
 * indexInfo: same info executor uses to insert into the index
694
 * indexColNames: column names to use for index (List of char *)
695
 * accessMethodId: OID of index AM to use
696
 * tableSpaceId: OID of tablespace to use
697
 * collationIds: array of collation OIDs, one per index column
698
 * opclassIds: array of index opclass OIDs, one per index column
699
 * coloptions: array of per-index-column indoption settings
700
 * reloptions: AM-specific options
701
 * flags: bitmask that can include any combination of these bits:
702
 *    INDEX_CREATE_IS_PRIMARY
703
 *      the index is a primary key
704
 *    INDEX_CREATE_ADD_CONSTRAINT:
705
 *      invoke index_constraint_create also
706
 *    INDEX_CREATE_SKIP_BUILD:
707
 *      skip the index_build() step for the moment; caller must do it
708
 *      later (typically via reindex_index())
709
 *    INDEX_CREATE_CONCURRENT:
710
 *      do not lock the table against writers.  The index will be
711
 *      marked "invalid" and the caller must take additional steps
712
 *      to fix it up.
713
 *    INDEX_CREATE_IF_NOT_EXISTS:
714
 *      do not throw an error if a relation with the same name
715
 *      already exists.
716
 *    INDEX_CREATE_PARTITIONED:
717
 *      create a partitioned index (table must be partitioned)
718
 *    INDEX_CREATE_SUPPRESS_PROGRESS:
719
 *      don't report progress during the index build.
720
 *    INDEX_CREATE_DEFERRABLE:
721
 *      index supports a deferrable constraint, mark it as
722
 *      non-immediate (indimmediate = false).
723
 *
724
 * constr_flags: flags passed to index_constraint_create
725
 *    (only if INDEX_CREATE_ADD_CONSTRAINT is set)
726
 * allow_system_table_mods: allow table to be a system catalog
727
 * is_internal: if true, post creation hook for new index
728
 * constraintId: if not NULL, receives OID of created constraint
729
 *
730
 * Returns the OID of the created index.
731
 *
732
 * NB: Caller is responsible for ensuring the user has USAGE on all types
733
 * indexInfo->ii_{Expressions,Predicate} depend on.
734
 */
735
Oid
736
index_create(Relation heapRelation,
737
       const char *indexRelationName,
738
       Oid indexRelationId,
739
       Oid parentIndexRelid,
740
       Oid parentConstraintId,
741
       RelFileNumber relFileNumber,
742
       IndexInfo *indexInfo,
743
       const List *indexColNames,
744
       Oid accessMethodId,
745
       Oid tableSpaceId,
746
       const Oid *collationIds,
747
       const Oid *opclassIds,
748
       const Datum *opclassOptions,
749
       const int16 *coloptions,
750
       const NullableDatum *stattargets,
751
       Datum reloptions,
752
       uint16 flags,
753
       uint16 constr_flags,
754
       bool allow_system_table_mods,
755
       bool is_internal,
756
       Oid *constraintId)
757
0
{
758
0
  Oid     heapRelationId = RelationGetRelid(heapRelation);
759
0
  Relation  pg_class;
760
0
  Relation  indexRelation;
761
0
  TupleDesc indexTupDesc;
762
0
  bool    shared_relation;
763
0
  bool    mapped_relation;
764
0
  bool    is_exclusion;
765
0
  Oid     namespaceId;
766
0
  int     i;
767
0
  char    relpersistence;
768
0
  bool    isprimary = (flags & INDEX_CREATE_IS_PRIMARY) != 0;
769
0
  bool    invalid = (flags & INDEX_CREATE_INVALID) != 0;
770
0
  bool    concurrent = (flags & INDEX_CREATE_CONCURRENT) != 0;
771
0
  bool    partitioned = (flags & INDEX_CREATE_PARTITIONED) != 0;
772
0
  bool    progress = (flags & INDEX_CREATE_SUPPRESS_PROGRESS) == 0;
773
0
  char    relkind;
774
0
  TransactionId relfrozenxid;
775
0
  MultiXactId relminmxid;
776
0
  bool    create_storage = !RelFileNumberIsValid(relFileNumber);
777
778
  /* constraint flags can only be set when a constraint is requested */
779
0
  Assert((constr_flags == 0) ||
780
0
       ((flags & INDEX_CREATE_ADD_CONSTRAINT) != 0));
781
  /* partitioned indexes must never be "built" by themselves */
782
0
  Assert(!partitioned || (flags & INDEX_CREATE_SKIP_BUILD));
783
784
0
  relkind = partitioned ? RELKIND_PARTITIONED_INDEX : RELKIND_INDEX;
785
0
  is_exclusion = (indexInfo->ii_ExclusionOps != NULL);
786
787
0
  pg_class = table_open(RelationRelationId, RowExclusiveLock);
788
789
  /*
790
   * The index will be in the same namespace as its parent table, and is
791
   * shared across databases if and only if the parent is.  Likewise, it
792
   * will use the relfilenumber map if and only if the parent does; and it
793
   * inherits the parent's relpersistence.
794
   */
795
0
  namespaceId = RelationGetNamespace(heapRelation);
796
0
  shared_relation = heapRelation->rd_rel->relisshared;
797
0
  mapped_relation = RelationIsMapped(heapRelation);
798
0
  relpersistence = heapRelation->rd_rel->relpersistence;
799
800
  /*
801
   * check parameters
802
   */
803
0
  if (indexInfo->ii_NumIndexAttrs < 1)
804
0
    elog(ERROR, "must index at least one column");
805
806
0
  if (!allow_system_table_mods &&
807
0
    IsSystemRelation(heapRelation) &&
808
0
    IsNormalProcessingMode())
809
0
    ereport(ERROR,
810
0
        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
811
0
         errmsg("user-defined indexes on system catalog tables are not supported")));
812
813
  /*
814
   * Btree text_pattern_ops uses texteq as the equality operator, which is
815
   * fine as long as the collation is deterministic; texteq then reduces to
816
   * bitwise equality and so it is semantically compatible with the other
817
   * operators and functions in that opclass.  But with a nondeterministic
818
   * collation, texteq could yield results that are incompatible with the
819
   * actual behavior of the index (which is determined by the opclass's
820
   * comparison function).  We prevent such problems by refusing creation of
821
   * an index with that opclass and a nondeterministic collation.
822
   *
823
   * The same applies to varchar_pattern_ops and bpchar_pattern_ops.  If we
824
   * find more cases, we might decide to create a real mechanism for marking
825
   * opclasses as incompatible with nondeterminism; but for now, this small
826
   * hack suffices.
827
   *
828
   * Another solution is to use a special operator, not texteq, as the
829
   * equality opclass member; but that is undesirable because it would
830
   * prevent index usage in many queries that work fine today.
831
   */
832
0
  for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
833
0
  {
834
0
    Oid     collation = collationIds[i];
835
0
    Oid     opclass = opclassIds[i];
836
837
0
    if (collation)
838
0
    {
839
0
      if ((opclass == TEXT_BTREE_PATTERN_OPS_OID ||
840
0
         opclass == VARCHAR_BTREE_PATTERN_OPS_OID ||
841
0
         opclass == BPCHAR_BTREE_PATTERN_OPS_OID) &&
842
0
        !get_collation_isdeterministic(collation))
843
0
      {
844
0
        HeapTuple classtup;
845
846
0
        classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
847
0
        if (!HeapTupleIsValid(classtup))
848
0
          elog(ERROR, "cache lookup failed for operator class %u", opclass);
849
0
        ereport(ERROR,
850
0
            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
851
0
             errmsg("nondeterministic collations are not supported for operator class \"%s\"",
852
0
                NameStr(((Form_pg_opclass) GETSTRUCT(classtup))->opcname))));
853
0
        ReleaseSysCache(classtup);
854
0
      }
855
0
    }
856
0
  }
857
858
  /*
859
   * Concurrent index build on a system catalog is unsafe because we tend to
860
   * release locks before committing in catalogs.
861
   */
862
0
  if (concurrent &&
863
0
    IsCatalogRelation(heapRelation))
864
0
    ereport(ERROR,
865
0
        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
866
0
         errmsg("concurrent index creation on system catalog tables is not supported")));
867
868
  /*
869
   * This case is currently not supported.  There's no way to ask for it in
870
   * the grammar with CREATE INDEX, but it can happen with REINDEX.
871
   */
872
0
  if (concurrent && is_exclusion)
873
0
    ereport(ERROR,
874
0
        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
875
0
         errmsg("concurrent index creation for exclusion constraints is not supported")));
876
877
  /*
878
   * We cannot allow indexing a shared relation after initdb (because
879
   * there's no way to make the entry in other databases' pg_class).
880
   */
881
0
  if (shared_relation && !IsBootstrapProcessingMode())
882
0
    ereport(ERROR,
883
0
        (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
884
0
         errmsg("shared indexes cannot be created after initdb")));
885
886
  /*
887
   * Shared relations must be in pg_global, too (last-ditch check)
888
   */
889
0
  if (shared_relation && tableSpaceId != GLOBALTABLESPACE_OID)
890
0
    elog(ERROR, "shared relations must be placed in pg_global tablespace");
891
892
  /*
893
   * Check for duplicate name (both as to the index, and as to the
894
   * associated constraint if any).  Such cases would fail on the relevant
895
   * catalogs' unique indexes anyway, but we prefer to give a friendlier
896
   * error message.
897
   */
898
0
  if (get_relname_relid(indexRelationName, namespaceId))
899
0
  {
900
0
    if ((flags & INDEX_CREATE_IF_NOT_EXISTS) != 0)
901
0
    {
902
0
      ereport(NOTICE,
903
0
          (errcode(ERRCODE_DUPLICATE_TABLE),
904
0
           errmsg("relation \"%s\" already exists, skipping",
905
0
              indexRelationName)));
906
0
      table_close(pg_class, RowExclusiveLock);
907
0
      return InvalidOid;
908
0
    }
909
910
0
    ereport(ERROR,
911
0
        (errcode(ERRCODE_DUPLICATE_TABLE),
912
0
         errmsg("relation \"%s\" already exists",
913
0
            indexRelationName)));
914
0
  }
915
916
0
  if ((flags & INDEX_CREATE_ADD_CONSTRAINT) != 0 &&
917
0
    ConstraintNameIsUsed(CONSTRAINT_RELATION, heapRelationId,
918
0
               indexRelationName))
919
0
  {
920
    /*
921
     * INDEX_CREATE_IF_NOT_EXISTS does not apply here, since the
922
     * conflicting constraint is not an index.
923
     */
924
0
    ereport(ERROR,
925
0
        (errcode(ERRCODE_DUPLICATE_OBJECT),
926
0
         errmsg("constraint \"%s\" for relation \"%s\" already exists",
927
0
            indexRelationName, RelationGetRelationName(heapRelation))));
928
0
  }
929
930
  /*
931
   * construct tuple descriptor for index tuples
932
   */
933
0
  indexTupDesc = ConstructTupleDescriptor(heapRelation,
934
0
                      indexInfo,
935
0
                      indexColNames,
936
0
                      accessMethodId,
937
0
                      collationIds,
938
0
                      opclassIds);
939
940
  /*
941
   * Allocate an OID for the index, unless we were told what to use.
942
   *
943
   * The OID will be the relfilenumber as well, so make sure it doesn't
944
   * collide with either pg_class OIDs or existing physical files.
945
   */
946
0
  if (!OidIsValid(indexRelationId))
947
0
  {
948
    /* Use binary-upgrade override for pg_class.oid and relfilenumber */
949
0
    if (IsBinaryUpgrade)
950
0
    {
951
0
      if (!OidIsValid(binary_upgrade_next_index_pg_class_oid))
952
0
        ereport(ERROR,
953
0
            (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
954
0
             errmsg("pg_class index OID value not set when in binary upgrade mode")));
955
956
0
      indexRelationId = binary_upgrade_next_index_pg_class_oid;
957
0
      binary_upgrade_next_index_pg_class_oid = InvalidOid;
958
959
      /* Override the index relfilenumber */
960
0
      if ((relkind == RELKIND_INDEX) &&
961
0
        (!RelFileNumberIsValid(binary_upgrade_next_index_pg_class_relfilenumber)))
962
0
        ereport(ERROR,
963
0
            (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
964
0
             errmsg("index relfilenumber value not set when in binary upgrade mode")));
965
0
      relFileNumber = binary_upgrade_next_index_pg_class_relfilenumber;
966
0
      binary_upgrade_next_index_pg_class_relfilenumber = InvalidRelFileNumber;
967
968
      /*
969
       * Note that we want create_storage = true for binary upgrade. The
970
       * storage we create here will be replaced later, but we need to
971
       * have something on disk in the meanwhile.
972
       */
973
0
      Assert(create_storage);
974
0
    }
975
0
    else
976
0
    {
977
0
      indexRelationId =
978
0
        GetNewRelFileNumber(tableSpaceId, pg_class, relpersistence);
979
0
    }
980
0
  }
981
982
  /*
983
   * create the index relation's relcache entry and, if necessary, the
984
   * physical disk file. (If we fail further down, it's the smgr's
985
   * responsibility to remove the disk file again, if any.)
986
   */
987
0
  indexRelation = heap_create(indexRelationName,
988
0
                namespaceId,
989
0
                tableSpaceId,
990
0
                indexRelationId,
991
0
                relFileNumber,
992
0
                accessMethodId,
993
0
                indexTupDesc,
994
0
                relkind,
995
0
                relpersistence,
996
0
                shared_relation,
997
0
                mapped_relation,
998
0
                allow_system_table_mods,
999
0
                &relfrozenxid,
1000
0
                &relminmxid,
1001
0
                create_storage);
1002
1003
0
  Assert(relfrozenxid == InvalidTransactionId);
1004
0
  Assert(relminmxid == InvalidMultiXactId);
1005
0
  Assert(indexRelationId == RelationGetRelid(indexRelation));
1006
1007
  /*
1008
   * Obtain exclusive lock on it.  Although no other transactions can see it
1009
   * until we commit, this prevents deadlock-risk complaints from lock
1010
   * manager in cases such as CLUSTER.
1011
   */
1012
0
  LockRelation(indexRelation, AccessExclusiveLock);
1013
1014
  /*
1015
   * Fill in fields of the index's pg_class entry that are not set correctly
1016
   * by heap_create.
1017
   *
1018
   * XXX should have a cleaner way to create cataloged indexes
1019
   */
1020
0
  indexRelation->rd_rel->relowner = heapRelation->rd_rel->relowner;
1021
0
  indexRelation->rd_rel->relam = accessMethodId;
1022
0
  indexRelation->rd_rel->relispartition = OidIsValid(parentIndexRelid);
1023
1024
  /*
1025
   * store index's pg_class entry
1026
   */
1027
0
  InsertPgClassTuple(pg_class, indexRelation,
1028
0
             RelationGetRelid(indexRelation),
1029
0
             (Datum) 0,
1030
0
             reloptions);
1031
1032
  /* done with pg_class */
1033
0
  table_close(pg_class, RowExclusiveLock);
1034
1035
  /*
1036
   * now update the object id's of all the attribute tuple forms in the
1037
   * index relation's tuple descriptor
1038
   */
1039
0
  InitializeAttributeOids(indexRelation,
1040
0
              indexInfo->ii_NumIndexAttrs,
1041
0
              indexRelationId);
1042
1043
  /*
1044
   * append ATTRIBUTE tuples for the index
1045
   */
1046
0
  AppendAttributeTuples(indexRelation, opclassOptions, stattargets);
1047
1048
  /* ----------------
1049
   *    update pg_index
1050
   *    (append INDEX tuple)
1051
   *
1052
   *    Note that this stows away a representation of "predicate".
1053
   *    (Or, could define a rule to maintain the predicate) --Nels, Feb '92
1054
   * ----------------
1055
   */
1056
0
  UpdateIndexRelation(indexRelationId, heapRelationId, parentIndexRelid,
1057
0
            indexInfo,
1058
0
            collationIds, opclassIds, coloptions,
1059
0
            isprimary, is_exclusion,
1060
0
            (constr_flags & INDEX_CONSTR_CREATE_DEFERRABLE) == 0 &&
1061
0
            (flags & INDEX_CREATE_DEFERRABLE) == 0,
1062
0
            !concurrent && !invalid,
1063
0
            !concurrent);
1064
1065
  /*
1066
   * Register relcache invalidation on the indexes' heap relation, to
1067
   * maintain consistency of its index list
1068
   */
1069
0
  CacheInvalidateRelcache(heapRelation);
1070
1071
  /* update pg_inherits and the parent's relhassubclass, if needed */
1072
0
  if (OidIsValid(parentIndexRelid))
1073
0
  {
1074
0
    StoreSingleInheritance(indexRelationId, parentIndexRelid, 1);
1075
0
    LockRelationOid(parentIndexRelid, ShareUpdateExclusiveLock);
1076
0
    SetRelationHasSubclass(parentIndexRelid, true);
1077
0
  }
1078
1079
  /*
1080
   * Register constraint and dependencies for the index.
1081
   *
1082
   * If the index is from a CONSTRAINT clause, construct a pg_constraint
1083
   * entry.  The index will be linked to the constraint, which in turn is
1084
   * linked to the table.  If it's not a CONSTRAINT, we need to make a
1085
   * dependency directly on the table.
1086
   *
1087
   * We don't need a dependency on the namespace, because there'll be an
1088
   * indirect dependency via our parent table.
1089
   *
1090
   * During bootstrap we can't register any dependencies, and we don't try
1091
   * to make a constraint either.
1092
   */
1093
0
  if (!IsBootstrapProcessingMode())
1094
0
  {
1095
0
    ObjectAddress myself,
1096
0
          referenced;
1097
0
    ObjectAddresses *addrs;
1098
1099
0
    ObjectAddressSet(myself, RelationRelationId, indexRelationId);
1100
1101
0
    if ((flags & INDEX_CREATE_ADD_CONSTRAINT) != 0)
1102
0
    {
1103
0
      char    constraintType;
1104
0
      ObjectAddress localaddr;
1105
1106
0
      if (isprimary)
1107
0
        constraintType = CONSTRAINT_PRIMARY;
1108
0
      else if (indexInfo->ii_Unique)
1109
0
        constraintType = CONSTRAINT_UNIQUE;
1110
0
      else if (is_exclusion)
1111
0
        constraintType = CONSTRAINT_EXCLUSION;
1112
0
      else
1113
0
      {
1114
0
        elog(ERROR, "constraint must be PRIMARY, UNIQUE or EXCLUDE");
1115
0
        constraintType = 0; /* keep compiler quiet */
1116
0
      }
1117
1118
0
      localaddr = index_constraint_create(heapRelation,
1119
0
                        indexRelationId,
1120
0
                        parentConstraintId,
1121
0
                        indexInfo,
1122
0
                        indexRelationName,
1123
0
                        constraintType,
1124
0
                        constr_flags,
1125
0
                        allow_system_table_mods,
1126
0
                        is_internal);
1127
0
      if (constraintId)
1128
0
        *constraintId = localaddr.objectId;
1129
0
    }
1130
0
    else
1131
0
    {
1132
0
      bool    have_simple_col = false;
1133
1134
0
      addrs = new_object_addresses();
1135
1136
      /* Create auto dependencies on simply-referenced columns */
1137
0
      for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
1138
0
      {
1139
0
        if (indexInfo->ii_IndexAttrNumbers[i] != 0)
1140
0
        {
1141
0
          ObjectAddressSubSet(referenced, RelationRelationId,
1142
0
                    heapRelationId,
1143
0
                    indexInfo->ii_IndexAttrNumbers[i]);
1144
0
          add_exact_object_address(&referenced, addrs);
1145
0
          have_simple_col = true;
1146
0
        }
1147
0
      }
1148
1149
      /*
1150
       * If there are no simply-referenced columns, give the index an
1151
       * auto dependency on the whole table.  In most cases, this will
1152
       * be redundant, but it might not be if the index expressions and
1153
       * predicate contain no Vars or only whole-row Vars.
1154
       */
1155
0
      if (!have_simple_col)
1156
0
      {
1157
0
        ObjectAddressSet(referenced, RelationRelationId,
1158
0
                 heapRelationId);
1159
0
        add_exact_object_address(&referenced, addrs);
1160
0
      }
1161
1162
0
      record_object_address_dependencies(&myself, addrs, DEPENDENCY_AUTO);
1163
0
      free_object_addresses(addrs);
1164
0
    }
1165
1166
    /*
1167
     * If this is an index partition, create partition dependencies on
1168
     * both the parent index and the table.  (Note: these must be *in
1169
     * addition to*, not instead of, all other dependencies.  Otherwise
1170
     * we'll be short some dependencies after DETACH PARTITION.)
1171
     */
1172
0
    if (OidIsValid(parentIndexRelid))
1173
0
    {
1174
0
      ObjectAddressSet(referenced, RelationRelationId, parentIndexRelid);
1175
0
      recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_PRI);
1176
1177
0
      ObjectAddressSet(referenced, RelationRelationId, heapRelationId);
1178
0
      recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC);
1179
0
    }
1180
1181
    /* placeholder for normal dependencies */
1182
0
    addrs = new_object_addresses();
1183
1184
    /* Store dependency on collations */
1185
1186
    /* The default collation is pinned, so don't bother recording it */
1187
0
    for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
1188
0
    {
1189
0
      if (OidIsValid(collationIds[i]) && collationIds[i] != DEFAULT_COLLATION_OID)
1190
0
      {
1191
0
        ObjectAddressSet(referenced, CollationRelationId, collationIds[i]);
1192
0
        add_exact_object_address(&referenced, addrs);
1193
0
      }
1194
0
    }
1195
1196
    /* Store dependency on operator classes */
1197
0
    for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
1198
0
    {
1199
0
      ObjectAddressSet(referenced, OperatorClassRelationId, opclassIds[i]);
1200
0
      add_exact_object_address(&referenced, addrs);
1201
0
    }
1202
1203
0
    record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
1204
0
    free_object_addresses(addrs);
1205
1206
    /* Store dependencies on anything mentioned in index expressions */
1207
0
    if (indexInfo->ii_Expressions)
1208
0
    {
1209
0
      recordDependencyOnSingleRelExpr(&myself,
1210
0
                      (Node *) indexInfo->ii_Expressions,
1211
0
                      heapRelationId,
1212
0
                      DEPENDENCY_NORMAL,
1213
0
                      DEPENDENCY_AUTO, false);
1214
0
    }
1215
1216
    /* Store dependencies on anything mentioned in predicate */
1217
0
    if (indexInfo->ii_Predicate)
1218
0
    {
1219
0
      recordDependencyOnSingleRelExpr(&myself,
1220
0
                      (Node *) indexInfo->ii_Predicate,
1221
0
                      heapRelationId,
1222
0
                      DEPENDENCY_NORMAL,
1223
0
                      DEPENDENCY_AUTO, false);
1224
0
    }
1225
0
  }
1226
0
  else
1227
0
  {
1228
    /* Bootstrap mode - assert we weren't asked for constraint support */
1229
0
    Assert((flags & INDEX_CREATE_ADD_CONSTRAINT) == 0);
1230
0
  }
1231
1232
  /* Post creation hook for new index */
1233
0
  InvokeObjectPostCreateHookArg(RelationRelationId,
1234
0
                  indexRelationId, 0, is_internal);
1235
1236
  /*
1237
   * Advance the command counter so that we can see the newly-entered
1238
   * catalog tuples for the index.
1239
   */
1240
0
  CommandCounterIncrement();
1241
1242
  /*
1243
   * In bootstrap mode, we have to fill in the index strategy structure with
1244
   * information from the catalogs.  If we aren't bootstrapping, then the
1245
   * relcache entry has already been rebuilt thanks to sinval update during
1246
   * CommandCounterIncrement.
1247
   */
1248
0
  if (IsBootstrapProcessingMode())
1249
0
    RelationInitIndexAccessInfo(indexRelation);
1250
0
  else
1251
0
    Assert(indexRelation->rd_indexcxt != NULL);
1252
1253
0
  indexRelation->rd_index->indnkeyatts = indexInfo->ii_NumIndexKeyAttrs;
1254
1255
  /* Validate opclass-specific options */
1256
0
  if (opclassOptions)
1257
0
    for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
1258
0
      (void) index_opclass_options(indexRelation, i + 1,
1259
0
                     opclassOptions[i],
1260
0
                     true);
1261
1262
  /*
1263
   * If this is bootstrap (initdb) time, then we don't actually fill in the
1264
   * index yet.  We'll be creating more indexes and classes later, so we
1265
   * delay filling them in until just before we're done with bootstrapping.
1266
   * Similarly, if the caller specified to skip the build then filling the
1267
   * index is delayed till later (ALTER TABLE can save work in some cases
1268
   * with this).  Otherwise, we call the AM routine that constructs the
1269
   * index.
1270
   */
1271
0
  if (IsBootstrapProcessingMode())
1272
0
  {
1273
0
    index_register(heapRelationId, indexRelationId, indexInfo);
1274
0
  }
1275
0
  else if ((flags & INDEX_CREATE_SKIP_BUILD) != 0)
1276
0
  {
1277
    /*
1278
     * Caller is responsible for filling the index later on.  However,
1279
     * we'd better make sure that the heap relation is correctly marked as
1280
     * having an index.
1281
     */
1282
0
    index_update_stats(heapRelation,
1283
0
               true,
1284
0
               -1.0);
1285
    /* Make the above update visible */
1286
0
    CommandCounterIncrement();
1287
0
  }
1288
0
  else
1289
0
  {
1290
0
    index_build(heapRelation, indexRelation, indexInfo, false, true,
1291
0
          progress);
1292
0
  }
1293
1294
  /*
1295
   * Close the index; but we keep the lock that we acquired above until end
1296
   * of transaction.  Closing the heap is caller's responsibility.
1297
   */
1298
0
  index_close(indexRelation, NoLock);
1299
1300
0
  return indexRelationId;
1301
0
}
1302
1303
/*
1304
 * index_create_copy
1305
 *
1306
 * Create an index based on the definition of the one provided by caller.  The
1307
 * index is inserted into catalogs.  'flags' are passed directly to
1308
 * index_create.
1309
 *
1310
 * "tablespaceOid" is the tablespace to use for this index.
1311
 */
1312
Oid
1313
index_create_copy(Relation heapRelation, uint16 flags,
1314
          Oid oldIndexId, Oid tablespaceOid, const char *newName)
1315
0
{
1316
0
  Relation  indexRelation;
1317
0
  IndexInfo  *oldInfo,
1318
0
         *newInfo;
1319
0
  Oid     newIndexId = InvalidOid;
1320
0
  bool    concurrently = (flags & INDEX_CREATE_CONCURRENT) != 0;
1321
0
  HeapTuple indexTuple,
1322
0
        classTuple;
1323
0
  Datum   indclassDatum,
1324
0
        colOptionDatum,
1325
0
        reloptionsDatum;
1326
0
  Datum    *opclassOptions;
1327
0
  oidvector  *indclass;
1328
0
  int2vector *indcoloptions;
1329
0
  NullableDatum *stattargets;
1330
0
  bool    isnull;
1331
0
  List     *indexColNames = NIL;
1332
0
  List     *indexExprs = NIL;
1333
0
  List     *indexPreds = NIL;
1334
0
  Form_pg_index indexForm;
1335
1336
0
  indexRelation = index_open(oldIndexId, RowExclusiveLock);
1337
1338
  /* The new index needs some information from the old index */
1339
0
  oldInfo = BuildIndexInfo(indexRelation);
1340
1341
  /*
1342
   * Concurrent build of an index with exclusion constraints is not
1343
   * supported.
1344
   */
1345
0
  if (oldInfo->ii_ExclusionOps != NULL && concurrently)
1346
0
    ereport(ERROR,
1347
0
        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1348
0
         errmsg("concurrent index creation for exclusion constraints is not supported")));
1349
1350
  /* Get the array of class and column options IDs from index info */
1351
0
  indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(oldIndexId));
1352
0
  if (!HeapTupleIsValid(indexTuple))
1353
0
    elog(ERROR, "cache lookup failed for index %u", oldIndexId);
1354
1355
0
  indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
1356
1357
  /* Old index is deferrable, do the same for the new index */
1358
0
  if (!indexForm->indimmediate)
1359
0
    flags |= INDEX_CREATE_DEFERRABLE;
1360
1361
0
  indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
1362
0
                       Anum_pg_index_indclass);
1363
0
  indclass = (oidvector *) DatumGetPointer(indclassDatum);
1364
1365
0
  colOptionDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
1366
0
                      Anum_pg_index_indoption);
1367
0
  indcoloptions = (int2vector *) DatumGetPointer(colOptionDatum);
1368
1369
  /* Fetch reloptions of index if any */
1370
0
  classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(oldIndexId));
1371
0
  if (!HeapTupleIsValid(classTuple))
1372
0
    elog(ERROR, "cache lookup failed for relation %u", oldIndexId);
1373
0
  reloptionsDatum = SysCacheGetAttr(RELOID, classTuple,
1374
0
                    Anum_pg_class_reloptions, &isnull);
1375
1376
  /*
1377
   * Fetch the list of expressions and predicates directly from the
1378
   * catalogs.  This cannot rely on the information from IndexInfo of the
1379
   * old index as these have been flattened for the planner.
1380
   */
1381
0
  if (oldInfo->ii_Expressions != NIL)
1382
0
  {
1383
0
    Datum   exprDatum;
1384
0
    char     *exprString;
1385
1386
0
    exprDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
1387
0
                       Anum_pg_index_indexprs);
1388
0
    exprString = TextDatumGetCString(exprDatum);
1389
0
    indexExprs = (List *) stringToNode(exprString);
1390
0
    pfree(exprString);
1391
0
  }
1392
0
  if (oldInfo->ii_Predicate != NIL)
1393
0
  {
1394
0
    Datum   predDatum;
1395
0
    char     *predString;
1396
1397
0
    predDatum = SysCacheGetAttrNotNull(INDEXRELID, indexTuple,
1398
0
                       Anum_pg_index_indpred);
1399
0
    predString = TextDatumGetCString(predDatum);
1400
0
    indexPreds = (List *) stringToNode(predString);
1401
1402
    /* Also convert to implicit-AND format */
1403
0
    indexPreds = make_ands_implicit((Expr *) indexPreds);
1404
0
    pfree(predString);
1405
0
  }
1406
1407
  /*
1408
   * Build the index information for the new index.
1409
   */
1410
0
  newInfo = makeIndexInfo(oldInfo->ii_NumIndexAttrs,
1411
0
              oldInfo->ii_NumIndexKeyAttrs,
1412
0
              oldInfo->ii_Am,
1413
0
              indexExprs,
1414
0
              indexPreds,
1415
0
              oldInfo->ii_Unique,
1416
0
              oldInfo->ii_NullsNotDistinct,
1417
0
              !concurrently,  /* isready */
1418
0
              concurrently, /* concurrent */
1419
0
              indexRelation->rd_indam->amsummarizing,
1420
0
              oldInfo->ii_WithoutOverlaps);
1421
1422
  /* fetch exclusion constraint info if any */
1423
0
  if (indexRelation->rd_index->indisexclusion)
1424
0
  {
1425
    /*
1426
     * XXX Beware: we're making newInfo point to oldInfo-owned memory.  It
1427
     * would be more orthodox to palloc+memcpy, but we don't need that
1428
     * here at present.
1429
     */
1430
0
    newInfo->ii_ExclusionOps = oldInfo->ii_ExclusionOps;
1431
0
    newInfo->ii_ExclusionProcs = oldInfo->ii_ExclusionProcs;
1432
0
    newInfo->ii_ExclusionStrats = oldInfo->ii_ExclusionStrats;
1433
0
  }
1434
1435
  /*
1436
   * Extract the list of column names and the column numbers for the new
1437
   * index information.  All this information will be used for the index
1438
   * creation.
1439
   */
1440
0
  for (int i = 0; i < oldInfo->ii_NumIndexAttrs; i++)
1441
0
  {
1442
0
    TupleDesc indexTupDesc = RelationGetDescr(indexRelation);
1443
0
    Form_pg_attribute att = TupleDescAttr(indexTupDesc, i);
1444
1445
0
    indexColNames = lappend(indexColNames, NameStr(att->attname));
1446
0
    newInfo->ii_IndexAttrNumbers[i] = oldInfo->ii_IndexAttrNumbers[i];
1447
0
  }
1448
1449
  /* Extract opclass options for each attribute */
1450
0
  opclassOptions = palloc0_array(Datum, newInfo->ii_NumIndexAttrs);
1451
0
  for (int i = 0; i < newInfo->ii_NumIndexAttrs; i++)
1452
0
    opclassOptions[i] = get_attoptions(oldIndexId, i + 1);
1453
1454
  /* Extract statistic targets for each attribute */
1455
0
  stattargets = palloc0_array(NullableDatum, newInfo->ii_NumIndexAttrs);
1456
0
  for (int i = 0; i < newInfo->ii_NumIndexAttrs; i++)
1457
0
  {
1458
0
    HeapTuple tp;
1459
0
    Datum   dat;
1460
1461
0
    tp = SearchSysCache2(ATTNUM, ObjectIdGetDatum(oldIndexId), Int16GetDatum(i + 1));
1462
0
    if (!HeapTupleIsValid(tp))
1463
0
      elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1464
0
         i + 1, oldIndexId);
1465
0
    dat = SysCacheGetAttr(ATTNUM, tp, Anum_pg_attribute_attstattarget, &isnull);
1466
0
    ReleaseSysCache(tp);
1467
0
    stattargets[i].value = dat;
1468
0
    stattargets[i].isnull = isnull;
1469
0
  }
1470
1471
  /*
1472
   * Now create the new index.
1473
   *
1474
   * For a partition index, we adjust the partition dependency later, to
1475
   * ensure a consistent state at all times.  That is why parentIndexRelid
1476
   * is not set here.
1477
   */
1478
0
  newIndexId = index_create(heapRelation,
1479
0
                newName,
1480
0
                InvalidOid, /* indexRelationId */
1481
0
                InvalidOid, /* parentIndexRelid */
1482
0
                InvalidOid, /* parentConstraintId */
1483
0
                InvalidRelFileNumber, /* relFileNumber */
1484
0
                newInfo,
1485
0
                indexColNames,
1486
0
                indexRelation->rd_rel->relam,
1487
0
                tablespaceOid,
1488
0
                indexRelation->rd_indcollation,
1489
0
                indclass->values,
1490
0
                opclassOptions,
1491
0
                indcoloptions->values,
1492
0
                stattargets,
1493
0
                reloptionsDatum,
1494
0
                flags,
1495
0
                0,  /* constr_flags */
1496
0
                true, /* allow table to be a system catalog? */
1497
0
                false,  /* is_internal? */
1498
0
                NULL);
1499
1500
  /* Close the relations used and clean up */
1501
0
  index_close(indexRelation, NoLock);
1502
0
  ReleaseSysCache(indexTuple);
1503
0
  ReleaseSysCache(classTuple);
1504
1505
0
  return newIndexId;
1506
0
}
1507
1508
/*
1509
 * index_concurrently_build
1510
 *
1511
 * Build index for a concurrent operation.  Low-level locks are taken when
1512
 * this operation is performed to prevent only schema changes, but they need
1513
 * to be kept until the end of the transaction performing this operation.
1514
 * 'indexOid' refers to an index relation OID already created as part of
1515
 * previous processing, and 'heapOid' refers to its parent heap relation.
1516
 */
1517
void
1518
index_concurrently_build(Oid heapRelationId,
1519
             Oid indexRelationId)
1520
0
{
1521
0
  Relation  heapRel;
1522
0
  Oid     save_userid;
1523
0
  int     save_sec_context;
1524
0
  int     save_nestlevel;
1525
0
  Relation  indexRelation;
1526
0
  IndexInfo  *indexInfo;
1527
1528
  /* This had better make sure that a snapshot is active */
1529
0
  Assert(ActiveSnapshotSet());
1530
1531
  /* Open and lock the parent heap relation */
1532
0
  heapRel = table_open(heapRelationId, ShareUpdateExclusiveLock);
1533
1534
  /*
1535
   * Switch to the table owner's userid, so that any index functions are run
1536
   * as that user.  Also lock down security-restricted operations and
1537
   * arrange to make GUC variable changes local to this command.
1538
   */
1539
0
  GetUserIdAndSecContext(&save_userid, &save_sec_context);
1540
0
  SetUserIdAndSecContext(heapRel->rd_rel->relowner,
1541
0
               save_sec_context | SECURITY_RESTRICTED_OPERATION);
1542
0
  save_nestlevel = NewGUCNestLevel();
1543
0
  RestrictSearchPath();
1544
1545
0
  indexRelation = index_open(indexRelationId, RowExclusiveLock);
1546
1547
  /*
1548
   * We have to re-build the IndexInfo struct, since it was lost in the
1549
   * commit of the transaction where this concurrent index was created at
1550
   * the catalog level.
1551
   */
1552
0
  indexInfo = BuildIndexInfo(indexRelation);
1553
0
  Assert(!indexInfo->ii_ReadyForInserts);
1554
0
  indexInfo->ii_Concurrent = true;
1555
0
  indexInfo->ii_BrokenHotChain = false;
1556
1557
  /* Now build the index */
1558
0
  index_build(heapRel, indexRelation, indexInfo, false, true, true);
1559
1560
  /* Roll back any GUC changes executed by index functions */
1561
0
  AtEOXact_GUC(false, save_nestlevel);
1562
1563
  /* Restore userid and security context */
1564
0
  SetUserIdAndSecContext(save_userid, save_sec_context);
1565
1566
  /* Close both the relations, but keep the locks */
1567
0
  table_close(heapRel, NoLock);
1568
0
  index_close(indexRelation, NoLock);
1569
1570
  /*
1571
   * Update the pg_index row to mark the index as ready for inserts. Once we
1572
   * commit this transaction, any new transactions that open the table must
1573
   * insert new entries into the index for insertions and non-HOT updates.
1574
   */
1575
0
  index_set_state_flags(indexRelationId, INDEX_CREATE_SET_READY);
1576
0
}
1577
1578
/*
1579
 * index_concurrently_swap
1580
 *
1581
 * Swap name, dependencies, and constraints of the old index over to the new
1582
 * index, while marking the old index as invalid and the new as valid.
1583
 */
1584
void
1585
index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName)
1586
0
{
1587
0
  Relation  pg_class,
1588
0
        pg_index,
1589
0
        pg_constraint,
1590
0
        pg_trigger;
1591
0
  Relation  oldClassRel,
1592
0
        newClassRel;
1593
0
  HeapTuple oldClassTuple,
1594
0
        newClassTuple;
1595
0
  Form_pg_class oldClassForm,
1596
0
        newClassForm;
1597
0
  HeapTuple oldIndexTuple,
1598
0
        newIndexTuple;
1599
0
  Form_pg_index oldIndexForm,
1600
0
        newIndexForm;
1601
0
  bool    isPartition;
1602
0
  Oid     indexConstraintOid;
1603
0
  List     *constraintOids = NIL;
1604
0
  ListCell   *lc;
1605
1606
  /*
1607
   * Take a necessary lock on the old and new index before swapping them.
1608
   */
1609
0
  oldClassRel = relation_open(oldIndexId, ShareUpdateExclusiveLock);
1610
0
  newClassRel = relation_open(newIndexId, ShareUpdateExclusiveLock);
1611
1612
  /* Now swap names and dependencies of those indexes */
1613
0
  pg_class = table_open(RelationRelationId, RowExclusiveLock);
1614
1615
0
  oldClassTuple = SearchSysCacheCopy1(RELOID,
1616
0
                    ObjectIdGetDatum(oldIndexId));
1617
0
  if (!HeapTupleIsValid(oldClassTuple))
1618
0
    elog(ERROR, "could not find tuple for relation %u", oldIndexId);
1619
0
  newClassTuple = SearchSysCacheCopy1(RELOID,
1620
0
                    ObjectIdGetDatum(newIndexId));
1621
0
  if (!HeapTupleIsValid(newClassTuple))
1622
0
    elog(ERROR, "could not find tuple for relation %u", newIndexId);
1623
1624
0
  oldClassForm = (Form_pg_class) GETSTRUCT(oldClassTuple);
1625
0
  newClassForm = (Form_pg_class) GETSTRUCT(newClassTuple);
1626
1627
  /* Swap the names */
1628
0
  namestrcpy(&newClassForm->relname, NameStr(oldClassForm->relname));
1629
0
  namestrcpy(&oldClassForm->relname, oldName);
1630
1631
  /* Swap the partition flags to track inheritance properly */
1632
0
  isPartition = newClassForm->relispartition;
1633
0
  newClassForm->relispartition = oldClassForm->relispartition;
1634
0
  oldClassForm->relispartition = isPartition;
1635
1636
0
  CatalogTupleUpdate(pg_class, &oldClassTuple->t_self, oldClassTuple);
1637
0
  CatalogTupleUpdate(pg_class, &newClassTuple->t_self, newClassTuple);
1638
1639
0
  heap_freetuple(oldClassTuple);
1640
0
  heap_freetuple(newClassTuple);
1641
1642
  /* Now swap index info */
1643
0
  pg_index = table_open(IndexRelationId, RowExclusiveLock);
1644
1645
0
  oldIndexTuple = SearchSysCacheCopy1(INDEXRELID,
1646
0
                    ObjectIdGetDatum(oldIndexId));
1647
0
  if (!HeapTupleIsValid(oldIndexTuple))
1648
0
    elog(ERROR, "could not find tuple for relation %u", oldIndexId);
1649
0
  newIndexTuple = SearchSysCacheCopy1(INDEXRELID,
1650
0
                    ObjectIdGetDatum(newIndexId));
1651
0
  if (!HeapTupleIsValid(newIndexTuple))
1652
0
    elog(ERROR, "could not find tuple for relation %u", newIndexId);
1653
1654
0
  oldIndexForm = (Form_pg_index) GETSTRUCT(oldIndexTuple);
1655
0
  newIndexForm = (Form_pg_index) GETSTRUCT(newIndexTuple);
1656
1657
  /*
1658
   * Copy constraint flags from the old index. This is safe because the old
1659
   * index guaranteed uniqueness.
1660
   */
1661
0
  newIndexForm->indisprimary = oldIndexForm->indisprimary;
1662
0
  oldIndexForm->indisprimary = false;
1663
0
  newIndexForm->indisexclusion = oldIndexForm->indisexclusion;
1664
0
  oldIndexForm->indisexclusion = false;
1665
0
  newIndexForm->indimmediate = oldIndexForm->indimmediate;
1666
0
  oldIndexForm->indimmediate = true;
1667
1668
  /* Preserve indisreplident in the new index */
1669
0
  newIndexForm->indisreplident = oldIndexForm->indisreplident;
1670
1671
  /* Preserve indisclustered in the new index */
1672
0
  newIndexForm->indisclustered = oldIndexForm->indisclustered;
1673
1674
  /*
1675
   * Mark the new index as valid, and the old index as invalid similarly to
1676
   * what index_set_state_flags() does.
1677
   */
1678
0
  newIndexForm->indisvalid = true;
1679
0
  oldIndexForm->indisvalid = false;
1680
0
  oldIndexForm->indisclustered = false;
1681
0
  oldIndexForm->indisreplident = false;
1682
1683
0
  CatalogTupleUpdate(pg_index, &oldIndexTuple->t_self, oldIndexTuple);
1684
0
  CatalogTupleUpdate(pg_index, &newIndexTuple->t_self, newIndexTuple);
1685
1686
0
  heap_freetuple(oldIndexTuple);
1687
0
  heap_freetuple(newIndexTuple);
1688
1689
  /*
1690
   * Move constraints and triggers over to the new index
1691
   */
1692
1693
0
  constraintOids = get_index_ref_constraints(oldIndexId);
1694
1695
0
  indexConstraintOid = get_index_constraint(oldIndexId);
1696
1697
0
  if (OidIsValid(indexConstraintOid))
1698
0
    constraintOids = lappend_oid(constraintOids, indexConstraintOid);
1699
1700
0
  pg_constraint = table_open(ConstraintRelationId, RowExclusiveLock);
1701
0
  pg_trigger = table_open(TriggerRelationId, RowExclusiveLock);
1702
1703
0
  foreach(lc, constraintOids)
1704
0
  {
1705
0
    HeapTuple constraintTuple,
1706
0
          triggerTuple;
1707
0
    Form_pg_constraint conForm;
1708
0
    ScanKeyData key[1];
1709
0
    SysScanDesc scan;
1710
0
    Oid     constraintOid = lfirst_oid(lc);
1711
1712
    /* Move the constraint from the old to the new index */
1713
0
    constraintTuple = SearchSysCacheCopy1(CONSTROID,
1714
0
                        ObjectIdGetDatum(constraintOid));
1715
0
    if (!HeapTupleIsValid(constraintTuple))
1716
0
      elog(ERROR, "could not find tuple for constraint %u", constraintOid);
1717
1718
0
    conForm = ((Form_pg_constraint) GETSTRUCT(constraintTuple));
1719
1720
0
    if (conForm->conindid == oldIndexId)
1721
0
    {
1722
0
      conForm->conindid = newIndexId;
1723
1724
0
      CatalogTupleUpdate(pg_constraint, &constraintTuple->t_self, constraintTuple);
1725
0
    }
1726
1727
0
    heap_freetuple(constraintTuple);
1728
1729
    /* Search for trigger records */
1730
0
    ScanKeyInit(&key[0],
1731
0
          Anum_pg_trigger_tgconstraint,
1732
0
          BTEqualStrategyNumber, F_OIDEQ,
1733
0
          ObjectIdGetDatum(constraintOid));
1734
1735
0
    scan = systable_beginscan(pg_trigger, TriggerConstraintIndexId, true,
1736
0
                  NULL, 1, key);
1737
1738
0
    while (HeapTupleIsValid((triggerTuple = systable_getnext(scan))))
1739
0
    {
1740
0
      Form_pg_trigger tgForm = (Form_pg_trigger) GETSTRUCT(triggerTuple);
1741
1742
0
      if (tgForm->tgconstrindid != oldIndexId)
1743
0
        continue;
1744
1745
      /* Make a modifiable copy */
1746
0
      triggerTuple = heap_copytuple(triggerTuple);
1747
0
      tgForm = (Form_pg_trigger) GETSTRUCT(triggerTuple);
1748
1749
0
      tgForm->tgconstrindid = newIndexId;
1750
1751
0
      CatalogTupleUpdate(pg_trigger, &triggerTuple->t_self, triggerTuple);
1752
1753
0
      heap_freetuple(triggerTuple);
1754
0
    }
1755
1756
0
    systable_endscan(scan);
1757
0
  }
1758
1759
  /*
1760
   * Move comment if any
1761
   */
1762
0
  {
1763
0
    Relation  description;
1764
0
    ScanKeyData skey[3];
1765
0
    SysScanDesc sd;
1766
0
    HeapTuple tuple;
1767
0
    Datum   values[Natts_pg_description] = {0};
1768
0
    bool    nulls[Natts_pg_description] = {0};
1769
0
    bool    replaces[Natts_pg_description] = {0};
1770
1771
0
    values[Anum_pg_description_objoid - 1] = ObjectIdGetDatum(newIndexId);
1772
0
    replaces[Anum_pg_description_objoid - 1] = true;
1773
1774
0
    ScanKeyInit(&skey[0],
1775
0
          Anum_pg_description_objoid,
1776
0
          BTEqualStrategyNumber, F_OIDEQ,
1777
0
          ObjectIdGetDatum(oldIndexId));
1778
0
    ScanKeyInit(&skey[1],
1779
0
          Anum_pg_description_classoid,
1780
0
          BTEqualStrategyNumber, F_OIDEQ,
1781
0
          ObjectIdGetDatum(RelationRelationId));
1782
0
    ScanKeyInit(&skey[2],
1783
0
          Anum_pg_description_objsubid,
1784
0
          BTEqualStrategyNumber, F_INT4EQ,
1785
0
          Int32GetDatum(0));
1786
1787
0
    description = table_open(DescriptionRelationId, RowExclusiveLock);
1788
1789
0
    sd = systable_beginscan(description, DescriptionObjIndexId, true,
1790
0
                NULL, 3, skey);
1791
1792
0
    while ((tuple = systable_getnext(sd)) != NULL)
1793
0
    {
1794
0
      tuple = heap_modify_tuple(tuple, RelationGetDescr(description),
1795
0
                    values, nulls, replaces);
1796
0
      CatalogTupleUpdate(description, &tuple->t_self, tuple);
1797
1798
0
      break;        /* Assume there can be only one match */
1799
0
    }
1800
1801
0
    systable_endscan(sd);
1802
0
    table_close(description, NoLock);
1803
0
  }
1804
1805
  /*
1806
   * Swap inheritance relationship with parent index
1807
   */
1808
0
  if (get_rel_relispartition(oldIndexId))
1809
0
  {
1810
0
    List     *ancestors = get_partition_ancestors(oldIndexId);
1811
0
    Oid     parentIndexRelid = linitial_oid(ancestors);
1812
1813
0
    DeleteInheritsTuple(oldIndexId, parentIndexRelid, false, NULL);
1814
0
    StoreSingleInheritance(newIndexId, parentIndexRelid, 1);
1815
1816
0
    list_free(ancestors);
1817
0
  }
1818
1819
  /*
1820
   * Swap all dependencies of and on the old index to the new one, and
1821
   * vice-versa.  Note that a call to CommandCounterIncrement() would cause
1822
   * duplicate entries in pg_depend, so this should not be done.
1823
   */
1824
0
  changeDependenciesOf(RelationRelationId, newIndexId, oldIndexId);
1825
0
  changeDependenciesOn(RelationRelationId, newIndexId, oldIndexId);
1826
1827
0
  changeDependenciesOf(RelationRelationId, oldIndexId, newIndexId);
1828
0
  changeDependenciesOn(RelationRelationId, oldIndexId, newIndexId);
1829
1830
  /* copy over statistics from old to new index */
1831
0
  pgstat_copy_relation_stats(newClassRel, oldClassRel);
1832
1833
  /* Copy data of pg_statistic from the old index to the new one */
1834
0
  CopyStatistics(oldIndexId, newIndexId);
1835
1836
  /* Close relations */
1837
0
  table_close(pg_class, RowExclusiveLock);
1838
0
  table_close(pg_index, RowExclusiveLock);
1839
0
  table_close(pg_constraint, RowExclusiveLock);
1840
0
  table_close(pg_trigger, RowExclusiveLock);
1841
1842
  /* The lock taken previously is not released until the end of transaction */
1843
0
  relation_close(oldClassRel, NoLock);
1844
0
  relation_close(newClassRel, NoLock);
1845
0
}
1846
1847
/*
1848
 * index_concurrently_set_dead
1849
 *
1850
 * Perform the last invalidation stage of DROP INDEX CONCURRENTLY or REINDEX
1851
 * CONCURRENTLY before actually dropping the index.  After calling this
1852
 * function, the index is seen by all the backends as dead.  Low-level locks
1853
 * taken here are kept until the end of the transaction calling this function.
1854
 */
1855
void
1856
index_concurrently_set_dead(Oid heapId, Oid indexId)
1857
0
{
1858
0
  Relation  userHeapRelation;
1859
0
  Relation  userIndexRelation;
1860
1861
  /*
1862
   * No more predicate locks will be acquired on this index, and we're about
1863
   * to stop doing inserts into the index which could show conflicts with
1864
   * existing predicate locks, so now is the time to move them to the heap
1865
   * relation.
1866
   */
1867
0
  userHeapRelation = table_open(heapId, ShareUpdateExclusiveLock);
1868
0
  userIndexRelation = index_open(indexId, ShareUpdateExclusiveLock);
1869
0
  TransferPredicateLocksToHeapRelation(userIndexRelation);
1870
1871
  /*
1872
   * Now we are sure that nobody uses the index for queries; they just might
1873
   * have it open for updating it.  So now we can unset indisready and
1874
   * indislive, then wait till nobody could be using it at all anymore.
1875
   */
1876
0
  index_set_state_flags(indexId, INDEX_DROP_SET_DEAD);
1877
1878
  /*
1879
   * Invalidate the relcache for the table, so that after this commit all
1880
   * sessions will refresh the table's index list.  Forgetting just the
1881
   * index's relcache entry is not enough.
1882
   */
1883
0
  CacheInvalidateRelcache(userHeapRelation);
1884
1885
  /*
1886
   * Close the relations again, though still holding session lock.
1887
   */
1888
0
  table_close(userHeapRelation, NoLock);
1889
0
  index_close(userIndexRelation, NoLock);
1890
0
}
1891
1892
/*
1893
 * index_constraint_create
1894
 *
1895
 * Set up a constraint associated with an index.  Return the new constraint's
1896
 * address.
1897
 *
1898
 * heapRelation: table owning the index (must be suitably locked by caller)
1899
 * indexRelationId: OID of the index
1900
 * parentConstraintId: if constraint is on a partition, the OID of the
1901
 *    constraint in the parent.
1902
 * indexInfo: same info executor uses to insert into the index
1903
 * constraintName: what it say (generally, should match name of index)
1904
 * constraintType: one of CONSTRAINT_PRIMARY, CONSTRAINT_UNIQUE, or
1905
 *    CONSTRAINT_EXCLUSION
1906
 * flags: bitmask that can include any combination of these bits:
1907
 *    INDEX_CONSTR_CREATE_MARK_AS_PRIMARY: index is a PRIMARY KEY
1908
 *    INDEX_CONSTR_CREATE_DEFERRABLE: constraint is DEFERRABLE
1909
 *    INDEX_CONSTR_CREATE_INIT_DEFERRED: constraint is INITIALLY DEFERRED
1910
 *    INDEX_CONSTR_CREATE_UPDATE_INDEX: update the pg_index row
1911
 *    INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS: remove existing dependencies
1912
 *      of index on table's columns
1913
 *    INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS: constraint uses WITHOUT OVERLAPS
1914
 * allow_system_table_mods: allow table to be a system catalog
1915
 * is_internal: index is constructed due to internal process
1916
 */
1917
ObjectAddress
1918
index_constraint_create(Relation heapRelation,
1919
            Oid indexRelationId,
1920
            Oid parentConstraintId,
1921
            const IndexInfo *indexInfo,
1922
            const char *constraintName,
1923
            char constraintType,
1924
            uint16 constr_flags,
1925
            bool allow_system_table_mods,
1926
            bool is_internal)
1927
0
{
1928
0
  Oid     namespaceId = RelationGetNamespace(heapRelation);
1929
0
  ObjectAddress myself,
1930
0
        idxaddr;
1931
0
  Oid     conOid;
1932
0
  bool    deferrable;
1933
0
  bool    initdeferred;
1934
0
  bool    mark_as_primary;
1935
0
  bool    islocal;
1936
0
  bool    noinherit;
1937
0
  bool    is_without_overlaps;
1938
0
  int16   inhcount;
1939
1940
0
  deferrable = (constr_flags & INDEX_CONSTR_CREATE_DEFERRABLE) != 0;
1941
0
  initdeferred = (constr_flags & INDEX_CONSTR_CREATE_INIT_DEFERRED) != 0;
1942
0
  mark_as_primary = (constr_flags & INDEX_CONSTR_CREATE_MARK_AS_PRIMARY) != 0;
1943
0
  is_without_overlaps = (constr_flags & INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS) != 0;
1944
1945
  /* constraint creation support doesn't work while bootstrapping */
1946
0
  Assert(!IsBootstrapProcessingMode());
1947
1948
  /* enforce system-table restriction */
1949
0
  if (!allow_system_table_mods &&
1950
0
    IsSystemRelation(heapRelation) &&
1951
0
    IsNormalProcessingMode())
1952
0
    ereport(ERROR,
1953
0
        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1954
0
         errmsg("user-defined indexes on system catalog tables are not supported")));
1955
1956
  /* primary/unique constraints shouldn't have any expressions */
1957
0
  if (indexInfo->ii_Expressions &&
1958
0
    constraintType != CONSTRAINT_EXCLUSION)
1959
0
    elog(ERROR, "constraints cannot have index expressions");
1960
1961
  /*
1962
   * If we're manufacturing a constraint for a pre-existing index, we need
1963
   * to get rid of the existing auto dependencies for the index (the ones
1964
   * that index_create() would have made instead of calling this function).
1965
   *
1966
   * Note: this code would not necessarily do the right thing if the index
1967
   * has any expressions or predicate, but we'd never be turning such an
1968
   * index into a UNIQUE or PRIMARY KEY constraint.
1969
   */
1970
0
  if (constr_flags & INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS)
1971
0
    deleteDependencyRecordsForClass(RelationRelationId, indexRelationId,
1972
0
                    RelationRelationId, DEPENDENCY_AUTO);
1973
1974
0
  if (OidIsValid(parentConstraintId))
1975
0
  {
1976
0
    islocal = false;
1977
0
    inhcount = 1;
1978
0
    noinherit = false;
1979
0
  }
1980
0
  else
1981
0
  {
1982
0
    islocal = true;
1983
0
    inhcount = 0;
1984
0
    noinherit = true;
1985
0
  }
1986
1987
  /*
1988
   * Construct a pg_constraint entry.
1989
   */
1990
0
  conOid = CreateConstraintEntry(constraintName,
1991
0
                   namespaceId,
1992
0
                   constraintType,
1993
0
                   deferrable,
1994
0
                   initdeferred,
1995
0
                   true, /* Is Enforced */
1996
0
                   true,
1997
0
                   parentConstraintId,
1998
0
                   RelationGetRelid(heapRelation),
1999
0
                   indexInfo->ii_IndexAttrNumbers,
2000
0
                   indexInfo->ii_NumIndexKeyAttrs,
2001
0
                   indexInfo->ii_NumIndexAttrs,
2002
0
                   InvalidOid, /* no domain */
2003
0
                   indexRelationId, /* index OID */
2004
0
                   InvalidOid, /* no foreign key */
2005
0
                   NULL,
2006
0
                   NULL,
2007
0
                   NULL,
2008
0
                   NULL,
2009
0
                   0,
2010
0
                   ' ',
2011
0
                   ' ',
2012
0
                   NULL,
2013
0
                   0,
2014
0
                   ' ',
2015
0
                   indexInfo->ii_ExclusionOps,
2016
0
                   NULL, /* no check constraint */
2017
0
                   NULL,
2018
0
                   islocal,
2019
0
                   inhcount,
2020
0
                   noinherit,
2021
0
                   is_without_overlaps,
2022
0
                   is_internal);
2023
2024
  /*
2025
   * Register the index as internally dependent on the constraint.
2026
   *
2027
   * Note that the constraint has a dependency on the table, so we don't
2028
   * need (or want) any direct dependency from the index to the table.
2029
   */
2030
0
  ObjectAddressSet(myself, ConstraintRelationId, conOid);
2031
0
  ObjectAddressSet(idxaddr, RelationRelationId, indexRelationId);
2032
0
  recordDependencyOn(&idxaddr, &myself, DEPENDENCY_INTERNAL);
2033
2034
  /*
2035
   * Also, if this is a constraint on a partition, give it partition-type
2036
   * dependencies on the parent constraint as well as the table.
2037
   */
2038
0
  if (OidIsValid(parentConstraintId))
2039
0
  {
2040
0
    ObjectAddress referenced;
2041
2042
0
    ObjectAddressSet(referenced, ConstraintRelationId, parentConstraintId);
2043
0
    recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_PRI);
2044
0
    ObjectAddressSet(referenced, RelationRelationId,
2045
0
             RelationGetRelid(heapRelation));
2046
0
    recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC);
2047
0
  }
2048
2049
  /*
2050
   * If the constraint is deferrable, create the deferred uniqueness
2051
   * checking trigger.  (The trigger will be given an internal dependency on
2052
   * the constraint by CreateTrigger.)
2053
   */
2054
0
  if (deferrable)
2055
0
  {
2056
0
    CreateTrigStmt *trigger = makeNode(CreateTrigStmt);
2057
2058
0
    trigger->replace = false;
2059
0
    trigger->isconstraint = true;
2060
0
    trigger->trigname = (constraintType == CONSTRAINT_PRIMARY) ?
2061
0
      "PK_ConstraintTrigger" :
2062
0
      "Unique_ConstraintTrigger";
2063
0
    trigger->relation = NULL;
2064
0
    trigger->funcname = SystemFuncName("unique_key_recheck");
2065
0
    trigger->args = NIL;
2066
0
    trigger->row = true;
2067
0
    trigger->timing = TRIGGER_TYPE_AFTER;
2068
0
    trigger->events = TRIGGER_TYPE_INSERT | TRIGGER_TYPE_UPDATE;
2069
0
    trigger->columns = NIL;
2070
0
    trigger->whenClause = NULL;
2071
0
    trigger->transitionRels = NIL;
2072
0
    trigger->deferrable = true;
2073
0
    trigger->initdeferred = initdeferred;
2074
0
    trigger->constrrel = NULL;
2075
2076
0
    (void) CreateTrigger(trigger, NULL, RelationGetRelid(heapRelation),
2077
0
               InvalidOid, conOid, indexRelationId, InvalidOid,
2078
0
               InvalidOid, NULL, true, false);
2079
0
  }
2080
2081
  /*
2082
   * If needed, mark the index as primary and/or deferred in pg_index.
2083
   *
2084
   * Note: When making an existing index into a constraint, caller must have
2085
   * a table lock that prevents concurrent table updates; otherwise, there
2086
   * is a risk that concurrent readers of the table will miss seeing this
2087
   * index at all.
2088
   */
2089
0
  if ((constr_flags & INDEX_CONSTR_CREATE_UPDATE_INDEX) &&
2090
0
    (mark_as_primary || deferrable))
2091
0
  {
2092
0
    Relation  pg_index;
2093
0
    HeapTuple indexTuple;
2094
0
    Form_pg_index indexForm;
2095
0
    bool    dirty = false;
2096
0
    bool    marked_as_primary = false;
2097
2098
0
    pg_index = table_open(IndexRelationId, RowExclusiveLock);
2099
2100
0
    indexTuple = SearchSysCacheCopy1(INDEXRELID,
2101
0
                     ObjectIdGetDatum(indexRelationId));
2102
0
    if (!HeapTupleIsValid(indexTuple))
2103
0
      elog(ERROR, "cache lookup failed for index %u", indexRelationId);
2104
0
    indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
2105
2106
0
    if (mark_as_primary && !indexForm->indisprimary)
2107
0
    {
2108
0
      indexForm->indisprimary = true;
2109
0
      dirty = true;
2110
0
      marked_as_primary = true;
2111
0
    }
2112
2113
0
    if (deferrable && indexForm->indimmediate)
2114
0
    {
2115
0
      indexForm->indimmediate = false;
2116
0
      dirty = true;
2117
0
    }
2118
2119
0
    if (dirty)
2120
0
    {
2121
0
      CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple);
2122
2123
      /*
2124
       * When we mark an existing index as primary, force a relcache
2125
       * flush on its parent table, so that all sessions will become
2126
       * aware that the table now has a primary key.  This is important
2127
       * because it affects some replication behaviors.
2128
       */
2129
0
      if (marked_as_primary)
2130
0
        CacheInvalidateRelcache(heapRelation);
2131
2132
0
      InvokeObjectPostAlterHookArg(IndexRelationId, indexRelationId, 0,
2133
0
                     InvalidOid, is_internal);
2134
0
    }
2135
2136
0
    heap_freetuple(indexTuple);
2137
0
    table_close(pg_index, RowExclusiveLock);
2138
0
  }
2139
2140
0
  return myself;
2141
0
}
2142
2143
/*
2144
 *    index_drop
2145
 *
2146
 * NOTE: this routine should now only be called through performDeletion(),
2147
 * else associated dependencies won't be cleaned up.
2148
 *
2149
 * If concurrent is true, do a DROP INDEX CONCURRENTLY.  If concurrent is
2150
 * false but concurrent_lock_mode is true, then do a normal DROP INDEX but
2151
 * take a lock for CONCURRENTLY processing.  That is used as part of REINDEX
2152
 * CONCURRENTLY.
2153
 */
2154
void
2155
index_drop(Oid indexId, bool concurrent, bool concurrent_lock_mode)
2156
0
{
2157
0
  Oid     heapId;
2158
0
  Relation  userHeapRelation;
2159
0
  Relation  userIndexRelation;
2160
0
  Relation  indexRelation;
2161
0
  HeapTuple tuple;
2162
0
  bool    hasexprs;
2163
0
  LockRelId heaprelid,
2164
0
        indexrelid;
2165
0
  LOCKTAG   heaplocktag;
2166
0
  LOCKMODE  lockmode;
2167
2168
  /*
2169
   * A temporary relation uses a non-concurrent DROP.  Other backends can't
2170
   * access a temporary relation, so there's no harm in grabbing a stronger
2171
   * lock (see comments in RemoveRelations), and a non-concurrent DROP is
2172
   * more efficient.
2173
   */
2174
0
  Assert(get_rel_persistence(indexId) != RELPERSISTENCE_TEMP ||
2175
0
       (!concurrent && !concurrent_lock_mode));
2176
2177
  /*
2178
   * To drop an index safely, we must grab exclusive lock on its parent
2179
   * table.  Exclusive lock on the index alone is insufficient because
2180
   * another backend might be about to execute a query on the parent table.
2181
   * If it relies on a previously cached list of index OIDs, then it could
2182
   * attempt to access the just-dropped index.  We must therefore take a
2183
   * table lock strong enough to prevent all queries on the table from
2184
   * proceeding until we commit and send out a shared-cache-inval notice
2185
   * that will make them update their index lists.
2186
   *
2187
   * In the concurrent case we avoid this requirement by disabling index use
2188
   * in multiple steps and waiting out any transactions that might be using
2189
   * the index, so we don't need exclusive lock on the parent table. Instead
2190
   * we take ShareUpdateExclusiveLock, to ensure that two sessions aren't
2191
   * doing CREATE/DROP INDEX CONCURRENTLY on the same index.  (We will get
2192
   * AccessExclusiveLock on the index below, once we're sure nobody else is
2193
   * using it.)
2194
   */
2195
0
  heapId = IndexGetRelation(indexId, false);
2196
0
  lockmode = (concurrent || concurrent_lock_mode) ? ShareUpdateExclusiveLock : AccessExclusiveLock;
2197
0
  userHeapRelation = table_open(heapId, lockmode);
2198
0
  userIndexRelation = index_open(indexId, lockmode);
2199
2200
  /*
2201
   * We might still have open queries using it in our own session, which the
2202
   * above locking won't prevent, so test explicitly.
2203
   */
2204
0
  CheckTableNotInUse(userIndexRelation, "DROP INDEX");
2205
2206
  /*
2207
   * Drop Index Concurrently is more or less the reverse process of Create
2208
   * Index Concurrently.
2209
   *
2210
   * First we unset indisvalid so queries starting afterwards don't use the
2211
   * index to answer queries anymore.  We have to keep indisready = true so
2212
   * transactions that are still scanning the index can continue to see
2213
   * valid index contents.  For instance, if they are using READ COMMITTED
2214
   * mode, and another transaction makes changes and commits, they need to
2215
   * see those new tuples in the index.
2216
   *
2217
   * After all transactions that could possibly have used the index for
2218
   * queries end, we can unset indisready and indislive, then wait till
2219
   * nobody could be touching it anymore.  (Note: we need indislive because
2220
   * this state must be distinct from the initial state during CREATE INDEX
2221
   * CONCURRENTLY, which has indislive true while indisready and indisvalid
2222
   * are false.  That's because in that state, transactions must examine the
2223
   * index for HOT-safety decisions, while in this state we don't want them
2224
   * to open it at all.)
2225
   *
2226
   * Since all predicate locks on the index are about to be made invalid, we
2227
   * must promote them to predicate locks on the heap.  In the
2228
   * non-concurrent case we can just do that now.  In the concurrent case
2229
   * it's a bit trickier.  The predicate locks must be moved when there are
2230
   * no index scans in progress on the index and no more can subsequently
2231
   * start, so that no new predicate locks can be made on the index.  Also,
2232
   * they must be moved before heap inserts stop maintaining the index, else
2233
   * the conflict with the predicate lock on the index gap could be missed
2234
   * before the lock on the heap relation is in place to detect a conflict
2235
   * based on the heap tuple insert.
2236
   */
2237
0
  if (concurrent)
2238
0
  {
2239
    /*
2240
     * We must commit our transaction in order to make the first pg_index
2241
     * state update visible to other sessions.  If the DROP machinery has
2242
     * already performed any other actions (removal of other objects,
2243
     * pg_depend entries, etc), the commit would make those actions
2244
     * permanent, which would leave us with inconsistent catalog state if
2245
     * we fail partway through the following sequence.  Since DROP INDEX
2246
     * CONCURRENTLY is restricted to dropping just one index that has no
2247
     * dependencies, we should get here before anything's been done ---
2248
     * but let's check that to be sure.  We can verify that the current
2249
     * transaction has not executed any transactional updates by checking
2250
     * that no XID has been assigned.
2251
     */
2252
0
    if (GetTopTransactionIdIfAny() != InvalidTransactionId)
2253
0
      ereport(ERROR,
2254
0
          (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2255
0
           errmsg("DROP INDEX CONCURRENTLY must be first action in transaction")));
2256
2257
    /*
2258
     * Mark index invalid by updating its pg_index entry
2259
     */
2260
0
    index_set_state_flags(indexId, INDEX_DROP_CLEAR_VALID);
2261
2262
    /*
2263
     * Invalidate the relcache for the table, so that after this commit
2264
     * all sessions will refresh any cached plans that might reference the
2265
     * index.
2266
     */
2267
0
    CacheInvalidateRelcache(userHeapRelation);
2268
2269
    /* save lockrelid and locktag for below, then close but keep locks */
2270
0
    heaprelid = userHeapRelation->rd_lockInfo.lockRelId;
2271
0
    SET_LOCKTAG_RELATION(heaplocktag, heaprelid.dbId, heaprelid.relId);
2272
0
    indexrelid = userIndexRelation->rd_lockInfo.lockRelId;
2273
2274
0
    table_close(userHeapRelation, NoLock);
2275
0
    index_close(userIndexRelation, NoLock);
2276
2277
    /*
2278
     * We must commit our current transaction so that the indisvalid
2279
     * update becomes visible to other transactions; then start another.
2280
     * Note that any previously-built data structures are lost in the
2281
     * commit.  The only data we keep past here are the relation IDs.
2282
     *
2283
     * Before committing, get a session-level lock on the table, to ensure
2284
     * that neither it nor the index can be dropped before we finish. This
2285
     * cannot block, even if someone else is waiting for access, because
2286
     * we already have the same lock within our transaction.
2287
     */
2288
0
    LockRelationIdForSession(&heaprelid, ShareUpdateExclusiveLock);
2289
0
    LockRelationIdForSession(&indexrelid, ShareUpdateExclusiveLock);
2290
2291
0
    PopActiveSnapshot();
2292
0
    CommitTransactionCommand();
2293
0
    StartTransactionCommand();
2294
2295
    /*
2296
     * Now we must wait until no running transaction could be using the
2297
     * index for a query.  Use AccessExclusiveLock here to check for
2298
     * running transactions that hold locks of any kind on the table. Note
2299
     * we do not need to worry about xacts that open the table for reading
2300
     * after this point; they will see the index as invalid when they open
2301
     * the relation.
2302
     *
2303
     * Note: the reason we use actual lock acquisition here, rather than
2304
     * just checking the ProcArray and sleeping, is that deadlock is
2305
     * possible if one of the transactions in question is blocked trying
2306
     * to acquire an exclusive lock on our table.  The lock code will
2307
     * detect deadlock and error out properly.
2308
     *
2309
     * Note: we report progress through WaitForLockers() unconditionally
2310
     * here, even though it will only be used when we're called by REINDEX
2311
     * CONCURRENTLY and not when called by DROP INDEX CONCURRENTLY.
2312
     */
2313
0
    WaitForLockers(heaplocktag, AccessExclusiveLock, true);
2314
2315
    /*
2316
     * Updating pg_index might involve TOAST table access, so ensure we
2317
     * have a valid snapshot.
2318
     */
2319
0
    PushActiveSnapshot(GetTransactionSnapshot());
2320
2321
    /* Finish invalidation of index and mark it as dead */
2322
0
    index_concurrently_set_dead(heapId, indexId);
2323
2324
0
    PopActiveSnapshot();
2325
2326
    /*
2327
     * Again, commit the transaction to make the pg_index update visible
2328
     * to other sessions.
2329
     */
2330
0
    CommitTransactionCommand();
2331
0
    StartTransactionCommand();
2332
2333
    /*
2334
     * Wait till every transaction that saw the old index state has
2335
     * finished.  See above about progress reporting.
2336
     */
2337
0
    WaitForLockers(heaplocktag, AccessExclusiveLock, true);
2338
2339
    /*
2340
     * Re-open relations to allow us to complete our actions.
2341
     *
2342
     * At this point, nothing should be accessing the index, but lets
2343
     * leave nothing to chance and grab AccessExclusiveLock on the index
2344
     * before the physical deletion.
2345
     */
2346
0
    userHeapRelation = table_open(heapId, ShareUpdateExclusiveLock);
2347
0
    userIndexRelation = index_open(indexId, AccessExclusiveLock);
2348
0
  }
2349
0
  else
2350
0
  {
2351
    /* Not concurrent, so just transfer predicate locks and we're good */
2352
0
    TransferPredicateLocksToHeapRelation(userIndexRelation);
2353
0
  }
2354
2355
  /*
2356
   * Schedule physical removal of the files (if any)
2357
   */
2358
0
  if (RELKIND_HAS_STORAGE(userIndexRelation->rd_rel->relkind))
2359
0
    RelationDropStorage(userIndexRelation);
2360
2361
  /* ensure that stats are dropped if transaction commits */
2362
0
  pgstat_drop_relation(userIndexRelation);
2363
2364
  /*
2365
   * Close and flush the index's relcache entry, to ensure relcache doesn't
2366
   * try to rebuild it while we're deleting catalog entries. We keep the
2367
   * lock though.
2368
   */
2369
0
  index_close(userIndexRelation, NoLock);
2370
2371
0
  RelationForgetRelation(indexId);
2372
2373
  /*
2374
   * Updating pg_index might involve TOAST table access, so ensure we have a
2375
   * valid snapshot.
2376
   */
2377
0
  PushActiveSnapshot(GetTransactionSnapshot());
2378
2379
  /*
2380
   * fix INDEX relation, and check for expressional index
2381
   */
2382
0
  indexRelation = table_open(IndexRelationId, RowExclusiveLock);
2383
2384
0
  tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
2385
0
  if (!HeapTupleIsValid(tuple))
2386
0
    elog(ERROR, "cache lookup failed for index %u", indexId);
2387
2388
0
  hasexprs = !heap_attisnull(tuple, Anum_pg_index_indexprs,
2389
0
                 RelationGetDescr(indexRelation));
2390
2391
0
  CatalogTupleDelete(indexRelation, &tuple->t_self);
2392
2393
0
  ReleaseSysCache(tuple);
2394
0
  table_close(indexRelation, RowExclusiveLock);
2395
2396
0
  PopActiveSnapshot();
2397
2398
  /*
2399
   * if it has any expression columns, we might have stored statistics about
2400
   * them.
2401
   */
2402
0
  if (hasexprs)
2403
0
    RemoveStatistics(indexId, 0);
2404
2405
  /*
2406
   * fix ATTRIBUTE relation
2407
   */
2408
0
  DeleteAttributeTuples(indexId);
2409
2410
  /*
2411
   * fix RELATION relation
2412
   */
2413
0
  DeleteRelationTuple(indexId);
2414
2415
  /*
2416
   * fix INHERITS relation
2417
   */
2418
0
  DeleteInheritsTuple(indexId, InvalidOid, false, NULL);
2419
2420
  /*
2421
   * We are presently too lazy to attempt to compute the new correct value
2422
   * of relhasindex (the next VACUUM will fix it if necessary). So there is
2423
   * no need to update the pg_class tuple for the owning relation. But we
2424
   * must send out a shared-cache-inval notice on the owning relation to
2425
   * ensure other backends update their relcache lists of indexes.  (In the
2426
   * concurrent case, this is redundant but harmless.)
2427
   */
2428
0
  CacheInvalidateRelcache(userHeapRelation);
2429
2430
  /*
2431
   * Close owning rel, but keep lock
2432
   */
2433
0
  table_close(userHeapRelation, NoLock);
2434
2435
  /*
2436
   * Release the session locks before we go.
2437
   */
2438
0
  if (concurrent)
2439
0
  {
2440
0
    UnlockRelationIdForSession(&heaprelid, ShareUpdateExclusiveLock);
2441
0
    UnlockRelationIdForSession(&indexrelid, ShareUpdateExclusiveLock);
2442
0
  }
2443
0
}
2444
2445
/* ----------------------------------------------------------------
2446
 *            index_build support
2447
 * ----------------------------------------------------------------
2448
 */
2449
2450
/* ----------------
2451
 *    BuildIndexInfo
2452
 *      Construct an IndexInfo record for an open index
2453
 *
2454
 * IndexInfo stores the information about the index that's needed by
2455
 * FormIndexDatum, which is used for both index_build() and later insertion
2456
 * of individual index tuples.  Normally we build an IndexInfo for an index
2457
 * just once per command, and then use it for (potentially) many tuples.
2458
 * ----------------
2459
 */
2460
IndexInfo *
2461
BuildIndexInfo(Relation index)
2462
0
{
2463
0
  IndexInfo  *ii;
2464
0
  Form_pg_index indexStruct = index->rd_index;
2465
0
  int     i;
2466
0
  int     numAtts;
2467
2468
  /* check the number of keys, and copy attr numbers into the IndexInfo */
2469
0
  numAtts = indexStruct->indnatts;
2470
0
  if (numAtts < 1 || numAtts > INDEX_MAX_KEYS)
2471
0
    elog(ERROR, "invalid indnatts %d for index %u",
2472
0
       numAtts, RelationGetRelid(index));
2473
2474
  /*
2475
   * Create the node, fetching any expressions needed for expressional
2476
   * indexes and index predicate if any.
2477
   */
2478
0
  ii = makeIndexInfo(indexStruct->indnatts,
2479
0
             indexStruct->indnkeyatts,
2480
0
             index->rd_rel->relam,
2481
0
             RelationGetIndexExpressions(index),
2482
0
             RelationGetIndexPredicate(index),
2483
0
             indexStruct->indisunique,
2484
0
             indexStruct->indnullsnotdistinct,
2485
0
             indexStruct->indisready,
2486
0
             false,
2487
0
             index->rd_indam->amsummarizing,
2488
0
             indexStruct->indisexclusion && indexStruct->indisunique);
2489
2490
  /* fill in attribute numbers */
2491
0
  for (i = 0; i < numAtts; i++)
2492
0
    ii->ii_IndexAttrNumbers[i] = indexStruct->indkey.values[i];
2493
2494
  /* fetch exclusion constraint info if any */
2495
0
  if (indexStruct->indisexclusion)
2496
0
  {
2497
0
    RelationGetExclusionInfo(index,
2498
0
                 &ii->ii_ExclusionOps,
2499
0
                 &ii->ii_ExclusionProcs,
2500
0
                 &ii->ii_ExclusionStrats);
2501
0
  }
2502
2503
0
  return ii;
2504
0
}
2505
2506
/* ----------------
2507
 *    BuildDummyIndexInfo
2508
 *      Construct a dummy IndexInfo record for an open index
2509
 *
2510
 * This differs from the real BuildIndexInfo in that it will never run any
2511
 * user-defined code that might exist in index expressions or predicates.
2512
 * Instead of the real index expressions, we return null constants that have
2513
 * the right types/typmods/collations.  Predicates and exclusion clauses are
2514
 * just ignored.  This is sufficient for the purpose of truncating an index,
2515
 * since we will not need to actually evaluate the expressions or predicates;
2516
 * the only thing that's likely to be done with the data is construction of
2517
 * a tupdesc describing the index's rowtype.
2518
 * ----------------
2519
 */
2520
IndexInfo *
2521
BuildDummyIndexInfo(Relation index)
2522
0
{
2523
0
  IndexInfo  *ii;
2524
0
  Form_pg_index indexStruct = index->rd_index;
2525
0
  int     i;
2526
0
  int     numAtts;
2527
2528
  /* check the number of keys, and copy attr numbers into the IndexInfo */
2529
0
  numAtts = indexStruct->indnatts;
2530
0
  if (numAtts < 1 || numAtts > INDEX_MAX_KEYS)
2531
0
    elog(ERROR, "invalid indnatts %d for index %u",
2532
0
       numAtts, RelationGetRelid(index));
2533
2534
  /*
2535
   * Create the node, using dummy index expressions, and pretending there is
2536
   * no predicate.
2537
   */
2538
0
  ii = makeIndexInfo(indexStruct->indnatts,
2539
0
             indexStruct->indnkeyatts,
2540
0
             index->rd_rel->relam,
2541
0
             RelationGetDummyIndexExpressions(index),
2542
0
             NIL,
2543
0
             indexStruct->indisunique,
2544
0
             indexStruct->indnullsnotdistinct,
2545
0
             indexStruct->indisready,
2546
0
             false,
2547
0
             index->rd_indam->amsummarizing,
2548
0
             indexStruct->indisexclusion && indexStruct->indisunique);
2549
2550
  /* fill in attribute numbers */
2551
0
  for (i = 0; i < numAtts; i++)
2552
0
    ii->ii_IndexAttrNumbers[i] = indexStruct->indkey.values[i];
2553
2554
  /* We ignore the exclusion constraint if any */
2555
2556
0
  return ii;
2557
0
}
2558
2559
/*
2560
 * CompareIndexInfo
2561
 *    Return whether the properties of two indexes (in different tables)
2562
 *    indicate that they have the "same" definitions.
2563
 *
2564
 * Note: passing collations and opfamilies separately is a kludge.  Adding
2565
 * them to IndexInfo may result in better coding here and elsewhere.
2566
 *
2567
 * Use build_attrmap_by_name(index2, index1) to build the attmap.
2568
 */
2569
bool
2570
CompareIndexInfo(const IndexInfo *info1, const IndexInfo *info2,
2571
         const Oid *collations1, const Oid *collations2,
2572
         const Oid *opfamilies1, const Oid *opfamilies2,
2573
         const AttrMap *attmap)
2574
0
{
2575
0
  int     i;
2576
2577
0
  if (info1->ii_Unique != info2->ii_Unique)
2578
0
    return false;
2579
2580
0
  if (info1->ii_NullsNotDistinct != info2->ii_NullsNotDistinct)
2581
0
    return false;
2582
2583
  /* indexes are only equivalent if they have the same access method */
2584
0
  if (info1->ii_Am != info2->ii_Am)
2585
0
    return false;
2586
2587
  /* and same number of attributes */
2588
0
  if (info1->ii_NumIndexAttrs != info2->ii_NumIndexAttrs)
2589
0
    return false;
2590
2591
  /* and same number of key attributes */
2592
0
  if (info1->ii_NumIndexKeyAttrs != info2->ii_NumIndexKeyAttrs)
2593
0
    return false;
2594
2595
  /*
2596
   * and columns match through the attribute map (actual attribute numbers
2597
   * might differ!)  Note that this checks that index columns that are
2598
   * expressions appear in the same positions.  We will next compare the
2599
   * expressions themselves.
2600
   */
2601
0
  for (i = 0; i < info1->ii_NumIndexAttrs; i++)
2602
0
  {
2603
0
    if (attmap->maplen < info2->ii_IndexAttrNumbers[i])
2604
0
      elog(ERROR, "incorrect attribute map");
2605
2606
    /* ignore expressions for now (but check their collation/opfamily) */
2607
0
    if (!(info1->ii_IndexAttrNumbers[i] == InvalidAttrNumber &&
2608
0
        info2->ii_IndexAttrNumbers[i] == InvalidAttrNumber))
2609
0
    {
2610
      /* fail if just one index has an expression in this column */
2611
0
      if (info1->ii_IndexAttrNumbers[i] == InvalidAttrNumber ||
2612
0
        info2->ii_IndexAttrNumbers[i] == InvalidAttrNumber)
2613
0
        return false;
2614
2615
      /* both are columns, so check for match after mapping */
2616
0
      if (attmap->attnums[info2->ii_IndexAttrNumbers[i] - 1] !=
2617
0
        info1->ii_IndexAttrNumbers[i])
2618
0
        return false;
2619
0
    }
2620
2621
    /* collation and opfamily are not valid for included columns */
2622
0
    if (i >= info1->ii_NumIndexKeyAttrs)
2623
0
      continue;
2624
2625
0
    if (collations1[i] != collations2[i])
2626
0
      return false;
2627
0
    if (opfamilies1[i] != opfamilies2[i])
2628
0
      return false;
2629
0
  }
2630
2631
  /*
2632
   * For expression indexes: either both are expression indexes, or neither
2633
   * is; if they are, make sure the expressions match.
2634
   */
2635
0
  if ((info1->ii_Expressions != NIL) != (info2->ii_Expressions != NIL))
2636
0
    return false;
2637
0
  if (info1->ii_Expressions != NIL)
2638
0
  {
2639
0
    bool    found_whole_row;
2640
0
    Node     *mapped;
2641
2642
0
    mapped = map_variable_attnos((Node *) info2->ii_Expressions,
2643
0
                   1, 0, attmap,
2644
0
                   InvalidOid, &found_whole_row);
2645
0
    if (found_whole_row)
2646
0
    {
2647
      /*
2648
       * we could throw an error here, but seems out of scope for this
2649
       * routine.
2650
       */
2651
0
      return false;
2652
0
    }
2653
2654
0
    if (!equal(info1->ii_Expressions, mapped))
2655
0
      return false;
2656
0
  }
2657
2658
  /* Partial index predicates must be identical, if they exist */
2659
0
  if ((info1->ii_Predicate == NULL) != (info2->ii_Predicate == NULL))
2660
0
    return false;
2661
0
  if (info1->ii_Predicate != NULL)
2662
0
  {
2663
0
    bool    found_whole_row;
2664
0
    Node     *mapped;
2665
2666
0
    mapped = map_variable_attnos((Node *) info2->ii_Predicate,
2667
0
                   1, 0, attmap,
2668
0
                   InvalidOid, &found_whole_row);
2669
0
    if (found_whole_row)
2670
0
    {
2671
      /*
2672
       * we could throw an error here, but seems out of scope for this
2673
       * routine.
2674
       */
2675
0
      return false;
2676
0
    }
2677
0
    if (!equal(info1->ii_Predicate, mapped))
2678
0
      return false;
2679
0
  }
2680
2681
  /* If they're exclusion indexes, their properties must be identical */
2682
0
  if ((info1->ii_ExclusionOps == NULL) != (info2->ii_ExclusionOps == NULL))
2683
0
    return false;
2684
0
  if (info1->ii_ExclusionOps != NULL)
2685
0
  {
2686
0
    for (i = 0; i < info1->ii_NumIndexKeyAttrs; i++)
2687
0
    {
2688
0
      if (info1->ii_ExclusionOps[i] != info2->ii_ExclusionOps[i])
2689
0
        return false;
2690
0
      if (info1->ii_ExclusionProcs[i] != info2->ii_ExclusionProcs[i])
2691
0
        return false;
2692
0
      if (info1->ii_ExclusionStrats[i] != info2->ii_ExclusionStrats[i])
2693
0
        return false;
2694
0
    }
2695
0
  }
2696
2697
0
  return true;
2698
0
}
2699
2700
/* ----------------
2701
 *    BuildSpeculativeIndexInfo
2702
 *      Add extra state to IndexInfo record
2703
 *
2704
 * For unique indexes, we usually don't want to add info to the IndexInfo for
2705
 * checking uniqueness, since the B-Tree AM handles that directly.  However, in
2706
 * the case of speculative insertion and conflict detection in logical
2707
 * replication, additional support is required.
2708
 *
2709
 * Do this processing here rather than in BuildIndexInfo() to not incur the
2710
 * overhead in the common non-speculative cases.
2711
 * ----------------
2712
 */
2713
void
2714
BuildSpeculativeIndexInfo(Relation index, IndexInfo *ii)
2715
0
{
2716
0
  int     indnkeyatts;
2717
0
  int     i;
2718
2719
0
  indnkeyatts = IndexRelationGetNumberOfKeyAttributes(index);
2720
2721
  /*
2722
   * fetch info for checking unique indexes
2723
   */
2724
0
  Assert(ii->ii_Unique);
2725
2726
0
  ii->ii_UniqueOps = palloc_array(Oid, indnkeyatts);
2727
0
  ii->ii_UniqueProcs = palloc_array(Oid, indnkeyatts);
2728
0
  ii->ii_UniqueStrats = palloc_array(uint16, indnkeyatts);
2729
2730
  /*
2731
   * We have to look up the operator's strategy number.  This provides a
2732
   * cross-check that the operator does match the index.
2733
   */
2734
  /* We need the func OIDs and strategy numbers too */
2735
0
  for (i = 0; i < indnkeyatts; i++)
2736
0
  {
2737
0
    ii->ii_UniqueStrats[i] =
2738
0
      IndexAmTranslateCompareType(COMPARE_EQ,
2739
0
                    index->rd_rel->relam,
2740
0
                    index->rd_opfamily[i],
2741
0
                    false);
2742
0
    ii->ii_UniqueOps[i] =
2743
0
      get_opfamily_member(index->rd_opfamily[i],
2744
0
                index->rd_opcintype[i],
2745
0
                index->rd_opcintype[i],
2746
0
                ii->ii_UniqueStrats[i]);
2747
0
    if (!OidIsValid(ii->ii_UniqueOps[i]))
2748
0
      elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
2749
0
         ii->ii_UniqueStrats[i], index->rd_opcintype[i],
2750
0
         index->rd_opcintype[i], index->rd_opfamily[i]);
2751
0
    ii->ii_UniqueProcs[i] = get_opcode(ii->ii_UniqueOps[i]);
2752
0
  }
2753
0
}
2754
2755
/* ----------------
2756
 *    FormIndexDatum
2757
 *      Construct values[] and isnull[] arrays for a new index tuple.
2758
 *
2759
 *  indexInfo   Info about the index
2760
 *  slot      Heap tuple for which we must prepare an index entry
2761
 *  estate      executor state for evaluating any index expressions
2762
 *  values      Array of index Datums (output area)
2763
 *  isnull      Array of is-null indicators (output area)
2764
 *
2765
 * When there are no index expressions, estate may be NULL.  Otherwise it
2766
 * must be supplied, *and* the ecxt_scantuple slot of its per-tuple expr
2767
 * context must point to the heap tuple passed in.
2768
 *
2769
 * Notice we don't actually call index_form_tuple() here; we just prepare
2770
 * its input arrays values[] and isnull[].  This is because the index AM
2771
 * may wish to alter the data before storage.
2772
 * ----------------
2773
 */
2774
void
2775
FormIndexDatum(IndexInfo *indexInfo,
2776
         TupleTableSlot *slot,
2777
         EState *estate,
2778
         Datum *values,
2779
         bool *isnull)
2780
0
{
2781
0
  ListCell   *indexpr_item;
2782
0
  int     i;
2783
2784
0
  if (indexInfo->ii_Expressions != NIL &&
2785
0
    indexInfo->ii_ExpressionsState == NIL)
2786
0
  {
2787
    /* First time through, set up expression evaluation state */
2788
0
    indexInfo->ii_ExpressionsState =
2789
0
      ExecPrepareExprList(indexInfo->ii_Expressions, estate);
2790
    /* Check caller has set up context correctly */
2791
0
    Assert(GetPerTupleExprContext(estate)->ecxt_scantuple == slot);
2792
0
  }
2793
0
  indexpr_item = list_head(indexInfo->ii_ExpressionsState);
2794
2795
0
  for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
2796
0
  {
2797
0
    int     keycol = indexInfo->ii_IndexAttrNumbers[i];
2798
0
    Datum   iDatum;
2799
0
    bool    isNull;
2800
2801
0
    if (keycol < 0)
2802
0
      iDatum = slot_getsysattr(slot, keycol, &isNull);
2803
0
    else if (keycol != 0)
2804
0
    {
2805
      /*
2806
       * Plain index column; get the value we need directly from the
2807
       * heap tuple.
2808
       */
2809
0
      iDatum = slot_getattr(slot, keycol, &isNull);
2810
0
    }
2811
0
    else
2812
0
    {
2813
      /*
2814
       * Index expression --- need to evaluate it.
2815
       */
2816
0
      if (indexpr_item == NULL)
2817
0
        elog(ERROR, "wrong number of index expressions");
2818
0
      iDatum = ExecEvalExprSwitchContext((ExprState *) lfirst(indexpr_item),
2819
0
                         GetPerTupleExprContext(estate),
2820
0
                         &isNull);
2821
0
      indexpr_item = lnext(indexInfo->ii_ExpressionsState, indexpr_item);
2822
0
    }
2823
0
    values[i] = iDatum;
2824
0
    isnull[i] = isNull;
2825
0
  }
2826
2827
0
  if (indexpr_item != NULL)
2828
0
    elog(ERROR, "wrong number of index expressions");
2829
0
}
2830
2831
2832
/*
2833
 * index_update_stats --- update pg_class entry after CREATE INDEX or REINDEX
2834
 *
2835
 * This routine updates the pg_class row of either an index or its parent
2836
 * relation after CREATE INDEX or REINDEX.  Its rather bizarre API is designed
2837
 * to ensure we can do all the necessary work in just one update.
2838
 *
2839
 * hasindex: set relhasindex to this value
2840
 * reltuples: if >= 0, set reltuples to this value; else no change
2841
 *
2842
 * If reltuples >= 0, relpages, relallvisible, and relallfrozen are also
2843
 * updated (using RelationGetNumberOfBlocks() and visibilitymap_count()).
2844
 *
2845
 * NOTE: an important side-effect of this operation is that an SI invalidation
2846
 * message is sent out to all backends --- including me --- causing relcache
2847
 * entries to be flushed or updated with the new data.  This must happen even
2848
 * if we find that no change is needed in the pg_class row.  When updating
2849
 * a heap entry, this ensures that other backends find out about the new
2850
 * index.  When updating an index, it's important because some index AMs
2851
 * expect a relcache flush to occur after REINDEX.
2852
 */
2853
static void
2854
index_update_stats(Relation rel,
2855
           bool hasindex,
2856
           double reltuples)
2857
0
{
2858
0
  bool    update_stats;
2859
0
  BlockNumber relpages = 0; /* keep compiler quiet */
2860
0
  BlockNumber relallvisible = 0;
2861
0
  BlockNumber relallfrozen = 0;
2862
0
  Oid     relid = RelationGetRelid(rel);
2863
0
  Relation  pg_class;
2864
0
  ScanKeyData key[1];
2865
0
  HeapTuple tuple;
2866
0
  void     *state;
2867
0
  Form_pg_class rd_rel;
2868
0
  bool    dirty;
2869
2870
  /*
2871
   * As a special hack, if we are dealing with an empty table and the
2872
   * existing reltuples is -1, we leave that alone.  This ensures that
2873
   * creating an index as part of CREATE TABLE doesn't cause the table to
2874
   * prematurely look like it's been vacuumed.  The rd_rel we modify may
2875
   * differ from rel->rd_rel due to e.g. commit of concurrent GRANT, but the
2876
   * commands that change reltuples take locks conflicting with ours.  (Even
2877
   * if a command changed reltuples under a weaker lock, this affects only
2878
   * statistics for an empty table.)
2879
   */
2880
0
  if (reltuples == 0 && rel->rd_rel->reltuples < 0)
2881
0
    reltuples = -1;
2882
2883
  /*
2884
   * Don't update statistics during binary upgrade, because the indexes are
2885
   * created before the data is moved into place.
2886
   */
2887
0
  update_stats = reltuples >= 0 && !IsBinaryUpgrade;
2888
2889
  /*
2890
   * If autovacuum is off, user may not be expecting table relstats to
2891
   * change.  This can be important when restoring a dump that includes
2892
   * statistics, as the table statistics may be restored before the index is
2893
   * created, and we want to preserve the restored table statistics.
2894
   */
2895
0
  if (rel->rd_rel->relkind == RELKIND_RELATION ||
2896
0
    rel->rd_rel->relkind == RELKIND_TOASTVALUE ||
2897
0
    rel->rd_rel->relkind == RELKIND_MATVIEW)
2898
0
  {
2899
0
    if (AutoVacuumingActive())
2900
0
    {
2901
0
      StdRdOptions *options = (StdRdOptions *) rel->rd_options;
2902
2903
0
      if (options != NULL && !options->autovacuum.enabled)
2904
0
        update_stats = false;
2905
0
    }
2906
0
    else
2907
0
      update_stats = false;
2908
0
  }
2909
2910
  /*
2911
   * Finish I/O and visibility map buffer locks before
2912
   * systable_inplace_update_begin() locks the pg_class buffer.  The rd_rel
2913
   * we modify may differ from rel->rd_rel due to e.g. commit of concurrent
2914
   * GRANT, but no command changes a relkind from non-index to index.  (Even
2915
   * if one did, relallvisible doesn't break functionality.)
2916
   */
2917
0
  if (update_stats)
2918
0
  {
2919
0
    relpages = RelationGetNumberOfBlocks(rel);
2920
2921
0
    if (rel->rd_rel->relkind != RELKIND_INDEX)
2922
0
      visibilitymap_count(rel, &relallvisible, &relallfrozen);
2923
0
  }
2924
2925
  /*
2926
   * We always update the pg_class row using a non-transactional,
2927
   * overwrite-in-place update.  There are several reasons for this:
2928
   *
2929
   * 1. In bootstrap mode, we have no choice --- UPDATE wouldn't work.
2930
   *
2931
   * 2. We could be reindexing pg_class itself, in which case we can't move
2932
   * its pg_class row because CatalogTupleInsert/CatalogTupleUpdate might
2933
   * not know about all the indexes yet (see reindex_relation).
2934
   *
2935
   * 3. Because we execute CREATE INDEX with just share lock on the parent
2936
   * rel (to allow concurrent index creations), an ordinary update could
2937
   * suffer a tuple-concurrently-updated failure against another CREATE
2938
   * INDEX committing at about the same time.  We can avoid that by having
2939
   * them both do nontransactional updates (we assume they will both be
2940
   * trying to change the pg_class row to the same thing, so it doesn't
2941
   * matter which goes first).
2942
   *
2943
   * It is safe to use a non-transactional update even though our
2944
   * transaction could still fail before committing.  Setting relhasindex
2945
   * true is safe even if there are no indexes (VACUUM will eventually fix
2946
   * it).  And of course the new relpages and reltuples counts are correct
2947
   * regardless.  However, we don't want to change relpages (or
2948
   * relallvisible) if the caller isn't providing an updated reltuples
2949
   * count, because that would bollix the reltuples/relpages ratio which is
2950
   * what's really important.
2951
   */
2952
2953
0
  pg_class = table_open(RelationRelationId, RowExclusiveLock);
2954
2955
0
  ScanKeyInit(&key[0],
2956
0
        Anum_pg_class_oid,
2957
0
        BTEqualStrategyNumber, F_OIDEQ,
2958
0
        ObjectIdGetDatum(relid));
2959
0
  systable_inplace_update_begin(pg_class, ClassOidIndexId, true, NULL,
2960
0
                  1, key, &tuple, &state);
2961
2962
0
  if (!HeapTupleIsValid(tuple))
2963
0
    elog(ERROR, "could not find tuple for relation %u", relid);
2964
0
  rd_rel = (Form_pg_class) GETSTRUCT(tuple);
2965
2966
  /* Should this be a more comprehensive test? */
2967
0
  Assert(rd_rel->relkind != RELKIND_PARTITIONED_INDEX);
2968
2969
  /* Apply required updates, if any, to copied tuple */
2970
2971
0
  dirty = false;
2972
0
  if (rd_rel->relhasindex != hasindex)
2973
0
  {
2974
0
    rd_rel->relhasindex = hasindex;
2975
0
    dirty = true;
2976
0
  }
2977
2978
0
  if (update_stats)
2979
0
  {
2980
0
    if (rd_rel->relpages != (int32) relpages)
2981
0
    {
2982
0
      rd_rel->relpages = (int32) relpages;
2983
0
      dirty = true;
2984
0
    }
2985
0
    if (rd_rel->reltuples != (float4) reltuples)
2986
0
    {
2987
0
      rd_rel->reltuples = (float4) reltuples;
2988
0
      dirty = true;
2989
0
    }
2990
0
    if (rd_rel->relallvisible != (int32) relallvisible)
2991
0
    {
2992
0
      rd_rel->relallvisible = (int32) relallvisible;
2993
0
      dirty = true;
2994
0
    }
2995
0
    if (rd_rel->relallfrozen != (int32) relallfrozen)
2996
0
    {
2997
0
      rd_rel->relallfrozen = (int32) relallfrozen;
2998
0
      dirty = true;
2999
0
    }
3000
0
  }
3001
3002
  /*
3003
   * If anything changed, write out the tuple
3004
   */
3005
0
  if (dirty)
3006
0
  {
3007
0
    systable_inplace_update_finish(state, tuple);
3008
    /* the above sends transactional and immediate cache inval messages */
3009
0
  }
3010
0
  else
3011
0
  {
3012
0
    systable_inplace_update_cancel(state);
3013
3014
    /*
3015
     * While we didn't change relhasindex, CREATE INDEX needs a
3016
     * transactional inval for when the new index's catalog rows become
3017
     * visible.  Other CREATE INDEX and REINDEX code happens to also queue
3018
     * this inval, but keep this in case rare callers rely on this part of
3019
     * our API contract.
3020
     */
3021
0
    CacheInvalidateRelcacheByTuple(tuple);
3022
0
  }
3023
3024
0
  heap_freetuple(tuple);
3025
3026
0
  table_close(pg_class, RowExclusiveLock);
3027
0
}
3028
3029
3030
/*
3031
 * index_build - invoke access-method-specific index build procedure
3032
 *
3033
 * On entry, the index's catalog entries are valid, and its physical disk
3034
 * file has been created but is empty.  We call the AM-specific build
3035
 * procedure to fill in the index contents.  We then update the pg_class
3036
 * entries of the index and heap relation as needed, using statistics
3037
 * returned by ambuild as well as data passed by the caller.
3038
 *
3039
 * isreindex indicates we are recreating a previously-existing index.
3040
 * parallel indicates if parallelism may be useful.
3041
 * progress indicates if the backend should update its progress info.
3042
 *
3043
 * Note: before Postgres 8.2, the passed-in heap and index Relations
3044
 * were automatically closed by this routine.  This is no longer the case.
3045
 * The caller opened 'em, and the caller should close 'em.
3046
 */
3047
void
3048
index_build(Relation heapRelation,
3049
      Relation indexRelation,
3050
      IndexInfo *indexInfo,
3051
      bool isreindex,
3052
      bool parallel,
3053
      bool progress)
3054
0
{
3055
0
  IndexBuildResult *stats;
3056
0
  Oid     save_userid;
3057
0
  int     save_sec_context;
3058
0
  int     save_nestlevel;
3059
3060
  /*
3061
   * sanity checks
3062
   */
3063
0
  Assert(RelationIsValid(indexRelation));
3064
0
  Assert(indexRelation->rd_indam);
3065
0
  Assert(indexRelation->rd_indam->ambuild);
3066
0
  Assert(indexRelation->rd_indam->ambuildempty);
3067
3068
  /*
3069
   * Determine worker process details for parallel CREATE INDEX.  Currently,
3070
   * only btree, GIN, and BRIN have support for parallel builds.
3071
   *
3072
   * Note that planner considers parallel safety for us.
3073
   */
3074
0
  if (parallel && IsNormalProcessingMode() &&
3075
0
    indexRelation->rd_indam->amcanbuildparallel)
3076
0
    indexInfo->ii_ParallelWorkers =
3077
0
      plan_create_index_workers(RelationGetRelid(heapRelation),
3078
0
                    RelationGetRelid(indexRelation));
3079
3080
0
  if (indexInfo->ii_ParallelWorkers == 0)
3081
0
    ereport(DEBUG1,
3082
0
        (errmsg_internal("building index \"%s\" on table \"%s\" serially",
3083
0
                 RelationGetRelationName(indexRelation),
3084
0
                 RelationGetRelationName(heapRelation))));
3085
0
  else
3086
0
    ereport(DEBUG1,
3087
0
        (errmsg_internal("building index \"%s\" on table \"%s\" with request for %d parallel workers",
3088
0
                 RelationGetRelationName(indexRelation),
3089
0
                 RelationGetRelationName(heapRelation),
3090
0
                 indexInfo->ii_ParallelWorkers)));
3091
3092
  /*
3093
   * Switch to the table owner's userid, so that any index functions are run
3094
   * as that user.  Also lock down security-restricted operations and
3095
   * arrange to make GUC variable changes local to this command.
3096
   */
3097
0
  GetUserIdAndSecContext(&save_userid, &save_sec_context);
3098
0
  SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
3099
0
               save_sec_context | SECURITY_RESTRICTED_OPERATION);
3100
0
  save_nestlevel = NewGUCNestLevel();
3101
0
  RestrictSearchPath();
3102
3103
  /* Set up initial progress report status */
3104
0
  if (progress)
3105
0
  {
3106
0
    const int progress_index[] = {
3107
0
      PROGRESS_CREATEIDX_PHASE,
3108
0
      PROGRESS_CREATEIDX_SUBPHASE,
3109
0
      PROGRESS_CREATEIDX_TUPLES_DONE,
3110
0
      PROGRESS_CREATEIDX_TUPLES_TOTAL,
3111
0
      PROGRESS_SCAN_BLOCKS_DONE,
3112
0
      PROGRESS_SCAN_BLOCKS_TOTAL
3113
0
    };
3114
0
    const int64 progress_vals[] = {
3115
0
      PROGRESS_CREATEIDX_PHASE_BUILD,
3116
0
      PROGRESS_CREATEIDX_SUBPHASE_INITIALIZE,
3117
0
      0, 0, 0, 0
3118
0
    };
3119
3120
0
    pgstat_progress_update_multi_param(6, progress_index, progress_vals);
3121
0
  }
3122
3123
  /*
3124
   * Call the access method's build procedure
3125
   */
3126
0
  stats = indexRelation->rd_indam->ambuild(heapRelation, indexRelation,
3127
0
                       indexInfo);
3128
0
  Assert(stats);
3129
3130
  /*
3131
   * If this is an unlogged index, we may need to write out an init fork for
3132
   * it -- but we must first check whether one already exists.  If, for
3133
   * example, an unlogged relation is truncated in the transaction that
3134
   * created it, or truncated twice in a subsequent transaction, the
3135
   * relfilenumber won't change, and nothing needs to be done here.
3136
   */
3137
0
  if (indexRelation->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
3138
0
    !smgrexists(RelationGetSmgr(indexRelation), INIT_FORKNUM))
3139
0
  {
3140
0
    smgrcreate(RelationGetSmgr(indexRelation), INIT_FORKNUM, false);
3141
0
    log_smgrcreate(&indexRelation->rd_locator, INIT_FORKNUM);
3142
0
    indexRelation->rd_indam->ambuildempty(indexRelation);
3143
0
  }
3144
3145
  /*
3146
   * If we found any potentially broken HOT chains, mark the index as not
3147
   * being usable until the current transaction is below the event horizon.
3148
   * See src/backend/access/heap/README.HOT for discussion.  While it might
3149
   * become safe to use the index earlier based on actual cleanup activity
3150
   * and other active transactions, the test for that would be much more
3151
   * complex and would require some form of blocking, so keep it simple and
3152
   * fast by just using the current transaction.
3153
   *
3154
   * However, when reindexing an existing index, we should do nothing here.
3155
   * Any HOT chains that are broken with respect to the index must predate
3156
   * the index's original creation, so there is no need to change the
3157
   * index's usability horizon.  Moreover, we *must not* try to change the
3158
   * index's pg_index entry while reindexing pg_index itself, and this
3159
   * optimization nicely prevents that.  The more complex rules needed for a
3160
   * reindex are handled separately after this function returns.
3161
   *
3162
   * We also need not set indcheckxmin during a concurrent index build,
3163
   * because we won't set indisvalid true until all transactions that care
3164
   * about the broken HOT chains are gone.
3165
   *
3166
   * Therefore, this code path can only be taken during non-concurrent
3167
   * CREATE INDEX.  Thus the fact that heap_update will set the pg_index
3168
   * tuple's xmin doesn't matter, because that tuple was created in the
3169
   * current transaction anyway.  That also means we don't need to worry
3170
   * about any concurrent readers of the tuple; no other transaction can see
3171
   * it yet.
3172
   */
3173
0
  if (indexInfo->ii_BrokenHotChain &&
3174
0
    !isreindex &&
3175
0
    !indexInfo->ii_Concurrent)
3176
0
  {
3177
0
    Oid     indexId = RelationGetRelid(indexRelation);
3178
0
    Relation  pg_index;
3179
0
    HeapTuple indexTuple;
3180
0
    Form_pg_index indexForm;
3181
3182
0
    pg_index = table_open(IndexRelationId, RowExclusiveLock);
3183
3184
0
    indexTuple = SearchSysCacheCopy1(INDEXRELID,
3185
0
                     ObjectIdGetDatum(indexId));
3186
0
    if (!HeapTupleIsValid(indexTuple))
3187
0
      elog(ERROR, "cache lookup failed for index %u", indexId);
3188
0
    indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
3189
3190
    /* If it's a new index, indcheckxmin shouldn't be set ... */
3191
0
    Assert(!indexForm->indcheckxmin);
3192
3193
0
    indexForm->indcheckxmin = true;
3194
0
    CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple);
3195
3196
0
    heap_freetuple(indexTuple);
3197
0
    table_close(pg_index, RowExclusiveLock);
3198
0
  }
3199
3200
  /*
3201
   * Update heap and index pg_class rows
3202
   */
3203
0
  index_update_stats(heapRelation,
3204
0
             true,
3205
0
             stats->heap_tuples);
3206
3207
0
  index_update_stats(indexRelation,
3208
0
             false,
3209
0
             stats->index_tuples);
3210
3211
  /* Make the updated catalog row versions visible */
3212
0
  CommandCounterIncrement();
3213
3214
  /*
3215
   * If it's for an exclusion constraint, make a second pass over the heap
3216
   * to verify that the constraint is satisfied.  We must not do this until
3217
   * the index is fully valid.  (Broken HOT chains shouldn't matter, though;
3218
   * see comments for IndexCheckExclusion.)
3219
   */
3220
0
  if (indexInfo->ii_ExclusionOps != NULL)
3221
0
    IndexCheckExclusion(heapRelation, indexRelation, indexInfo);
3222
3223
  /* Roll back any GUC changes executed by index functions */
3224
0
  AtEOXact_GUC(false, save_nestlevel);
3225
3226
  /* Restore userid and security context */
3227
0
  SetUserIdAndSecContext(save_userid, save_sec_context);
3228
0
}
3229
3230
/*
3231
 * IndexCheckExclusion - verify that a new exclusion constraint is satisfied
3232
 *
3233
 * When creating an exclusion constraint, we first build the index normally
3234
 * and then rescan the heap to check for conflicts.  We assume that we only
3235
 * need to validate tuples that are live according to an up-to-date snapshot,
3236
 * and that these were correctly indexed even in the presence of broken HOT
3237
 * chains.  This should be OK since we are holding at least ShareLock on the
3238
 * table, meaning there can be no uncommitted updates from other transactions.
3239
 * (Note: that wouldn't necessarily work for system catalogs, since many
3240
 * operations release write lock early on the system catalogs.)
3241
 */
3242
static void
3243
IndexCheckExclusion(Relation heapRelation,
3244
          Relation indexRelation,
3245
          IndexInfo *indexInfo)
3246
0
{
3247
0
  TableScanDesc scan;
3248
0
  Datum   values[INDEX_MAX_KEYS];
3249
0
  bool    isnull[INDEX_MAX_KEYS];
3250
0
  ExprState  *predicate;
3251
0
  TupleTableSlot *slot;
3252
0
  EState     *estate;
3253
0
  ExprContext *econtext;
3254
0
  Snapshot  snapshot;
3255
3256
  /*
3257
   * If we are reindexing the target index, mark it as no longer being
3258
   * reindexed, to forestall an Assert in index_beginscan when we try to use
3259
   * the index for probes.  This is OK because the index is now fully valid.
3260
   */
3261
0
  if (ReindexIsCurrentlyProcessingIndex(RelationGetRelid(indexRelation)))
3262
0
    ResetReindexProcessing();
3263
3264
  /*
3265
   * Need an EState for evaluation of index expressions and partial-index
3266
   * predicates.  Also a slot to hold the current tuple.
3267
   */
3268
0
  estate = CreateExecutorState();
3269
0
  econtext = GetPerTupleExprContext(estate);
3270
0
  slot = table_slot_create(heapRelation, NULL);
3271
3272
  /* Arrange for econtext's scan tuple to be the tuple under test */
3273
0
  econtext->ecxt_scantuple = slot;
3274
3275
  /* Set up execution state for predicate, if any. */
3276
0
  predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
3277
3278
  /*
3279
   * Scan all live tuples in the base relation.
3280
   */
3281
0
  snapshot = RegisterSnapshot(GetLatestSnapshot());
3282
0
  scan = table_beginscan_strat(heapRelation,  /* relation */
3283
0
                 snapshot,  /* snapshot */
3284
0
                 0, /* number of keys */
3285
0
                 NULL, /* scan key */
3286
0
                 true, /* buffer access strategy OK */
3287
0
                 true); /* syncscan OK */
3288
3289
0
  while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
3290
0
  {
3291
0
    CHECK_FOR_INTERRUPTS();
3292
3293
    /*
3294
     * In a partial index, ignore tuples that don't satisfy the predicate.
3295
     */
3296
0
    if (predicate != NULL)
3297
0
    {
3298
0
      if (!ExecQual(predicate, econtext))
3299
0
        continue;
3300
0
    }
3301
3302
    /*
3303
     * Extract index column values, including computing expressions.
3304
     */
3305
0
    FormIndexDatum(indexInfo,
3306
0
             slot,
3307
0
             estate,
3308
0
             values,
3309
0
             isnull);
3310
3311
    /*
3312
     * Check that this tuple has no conflicts.
3313
     */
3314
0
    check_exclusion_constraint(heapRelation,
3315
0
                   indexRelation, indexInfo,
3316
0
                   &(slot->tts_tid), values, isnull,
3317
0
                   estate, true);
3318
3319
0
    MemoryContextReset(econtext->ecxt_per_tuple_memory);
3320
0
  }
3321
3322
0
  table_endscan(scan);
3323
0
  UnregisterSnapshot(snapshot);
3324
3325
0
  ExecDropSingleTupleTableSlot(slot);
3326
3327
0
  FreeExecutorState(estate);
3328
3329
  /* These may have been pointing to the now-gone estate */
3330
0
  indexInfo->ii_ExpressionsState = NIL;
3331
0
  indexInfo->ii_PredicateState = NULL;
3332
0
}
3333
3334
/*
3335
 * validate_index - support code for concurrent index builds
3336
 *
3337
 * We do a concurrent index build by first inserting the catalog entry for the
3338
 * index via index_create(), marking it not indisready and not indisvalid.
3339
 * Then we commit our transaction and start a new one, then we wait for all
3340
 * transactions that could have been modifying the table to terminate.  Now
3341
 * we know that any subsequently-started transactions will see the index and
3342
 * honor its constraints on HOT updates; so while existing HOT-chains might
3343
 * be broken with respect to the index, no currently live tuple will have an
3344
 * incompatible HOT update done to it.  We now build the index normally via
3345
 * index_build(), while holding a weak lock that allows concurrent
3346
 * insert/update/delete.  Also, we index only tuples that are valid
3347
 * as of the start of the scan (see table_index_build_scan), whereas a normal
3348
 * build takes care to include recently-dead tuples.  This is OK because
3349
 * we won't mark the index valid until all transactions that might be able
3350
 * to see those tuples are gone.  The reason for doing that is to avoid
3351
 * bogus unique-index failures due to concurrent UPDATEs (we might see
3352
 * different versions of the same row as being valid when we pass over them,
3353
 * if we used HeapTupleSatisfiesVacuum).  This leaves us with an index that
3354
 * does not contain any tuples added to the table while we built the index.
3355
 *
3356
 * Next, we mark the index "indisready" (but still not "indisvalid") and
3357
 * commit the second transaction and start a third.  Again we wait for all
3358
 * transactions that could have been modifying the table to terminate.  Now
3359
 * we know that any subsequently-started transactions will see the index and
3360
 * insert their new tuples into it.  We then take a new reference snapshot
3361
 * which is passed to validate_index().  Any tuples that are valid according
3362
 * to this snap, but are not in the index, must be added to the index.
3363
 * (Any tuples committed live after the snap will be inserted into the
3364
 * index by their originating transaction.  Any tuples committed dead before
3365
 * the snap need not be indexed, because we will wait out all transactions
3366
 * that might care about them before we mark the index valid.)
3367
 *
3368
 * validate_index() works by first gathering all the TIDs currently in the
3369
 * index, using a bulkdelete callback that just stores the TIDs and doesn't
3370
 * ever say "delete it".  (This should be faster than a plain indexscan;
3371
 * also, not all index AMs support full-index indexscan.)  Then we sort the
3372
 * TIDs, and finally scan the table doing a "merge join" against the TID list
3373
 * to see which tuples are missing from the index.  Thus we will ensure that
3374
 * all tuples valid according to the reference snapshot are in the index.
3375
 *
3376
 * Building a unique index this way is tricky: we might try to insert a
3377
 * tuple that is already dead or is in process of being deleted, and we
3378
 * mustn't have a uniqueness failure against an updated version of the same
3379
 * row.  We could try to check the tuple to see if it's already dead and tell
3380
 * index_insert() not to do the uniqueness check, but that still leaves us
3381
 * with a race condition against an in-progress update.  To handle that,
3382
 * we expect the index AM to recheck liveness of the to-be-inserted tuple
3383
 * before it declares a uniqueness error.
3384
 *
3385
 * After completing validate_index(), we wait until all transactions that
3386
 * were alive at the time of the reference snapshot are gone; this is
3387
 * necessary to be sure there are none left with a transaction snapshot
3388
 * older than the reference (and hence possibly able to see tuples we did
3389
 * not index).  Then we mark the index "indisvalid" and commit.  Subsequent
3390
 * transactions will be able to use it for queries.
3391
 *
3392
 * Doing two full table scans is a brute-force strategy.  We could try to be
3393
 * cleverer, eg storing new tuples in a special area of the table (perhaps
3394
 * making the table append-only by setting use_fsm).  However that would
3395
 * add yet more locking issues.
3396
 */
3397
void
3398
validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
3399
{
3400
  Relation  heapRelation,
3401
        indexRelation;
3402
  IndexInfo  *indexInfo;
3403
  IndexVacuumInfo ivinfo;
3404
  ValidateIndexState state;
3405
  Oid     save_userid;
3406
  int     save_sec_context;
3407
  int     save_nestlevel;
3408
3409
  {
3410
    const int progress_index[] = {
3411
      PROGRESS_CREATEIDX_PHASE,
3412
      PROGRESS_CREATEIDX_TUPLES_DONE,
3413
      PROGRESS_CREATEIDX_TUPLES_TOTAL,
3414
      PROGRESS_SCAN_BLOCKS_DONE,
3415
      PROGRESS_SCAN_BLOCKS_TOTAL
3416
    };
3417
    const int64 progress_vals[] = {
3418
      PROGRESS_CREATEIDX_PHASE_VALIDATE_IDXSCAN,
3419
      0, 0, 0, 0
3420
    };
3421
3422
    pgstat_progress_update_multi_param(5, progress_index, progress_vals);
3423
  }
3424
3425
  /* Open and lock the parent heap relation */
3426
  heapRelation = table_open(heapId, ShareUpdateExclusiveLock);
3427
3428
  /*
3429
   * Switch to the table owner's userid, so that any index functions are run
3430
   * as that user.  Also lock down security-restricted operations and
3431
   * arrange to make GUC variable changes local to this command.
3432
   */
3433
  GetUserIdAndSecContext(&save_userid, &save_sec_context);
3434
  SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
3435
               save_sec_context | SECURITY_RESTRICTED_OPERATION);
3436
  save_nestlevel = NewGUCNestLevel();
3437
  RestrictSearchPath();
3438
3439
  indexRelation = index_open(indexId, RowExclusiveLock);
3440
3441
  /*
3442
   * Fetch info needed for index_insert.  (You might think this should be
3443
   * passed in from DefineIndex, but its copy is long gone due to having
3444
   * been built in a previous transaction.)
3445
   */
3446
  indexInfo = BuildIndexInfo(indexRelation);
3447
3448
  /* mark build is concurrent just for consistency */
3449
  indexInfo->ii_Concurrent = true;
3450
3451
  /*
3452
   * Scan the index and gather up all the TIDs into a tuplesort object.
3453
   */
3454
  ivinfo.index = indexRelation;
3455
  ivinfo.heaprel = heapRelation;
3456
  ivinfo.analyze_only = false;
3457
  ivinfo.report_progress = true;
3458
  ivinfo.estimated_count = true;
3459
  ivinfo.message_level = DEBUG2;
3460
  ivinfo.num_heap_tuples = heapRelation->rd_rel->reltuples;
3461
  ivinfo.strategy = NULL;
3462
3463
  /*
3464
   * Encode TIDs as int8 values for the sort, rather than directly sorting
3465
   * item pointers.  This can be significantly faster, primarily because TID
3466
   * is a pass-by-reference type on all platforms, whereas int8 is
3467
   * pass-by-value on most platforms.
3468
   */
3469
  state.tuplesort = tuplesort_begin_datum(INT8OID, Int8LessOperator,
3470
                      InvalidOid, false,
3471
                      maintenance_work_mem,
3472
                      NULL, TUPLESORT_NONE);
3473
  state.htups = state.itups = state.tups_inserted = 0;
3474
3475
  /* ambulkdelete updates progress metrics */
3476
  (void) index_bulk_delete(&ivinfo, NULL,
3477
               validate_index_callback, &state);
3478
3479
  /* Execute the sort */
3480
  {
3481
    const int progress_index[] = {
3482
      PROGRESS_CREATEIDX_PHASE,
3483
      PROGRESS_SCAN_BLOCKS_DONE,
3484
      PROGRESS_SCAN_BLOCKS_TOTAL
3485
    };
3486
    const int64 progress_vals[] = {
3487
      PROGRESS_CREATEIDX_PHASE_VALIDATE_SORT,
3488
      0, 0
3489
    };
3490
3491
    pgstat_progress_update_multi_param(3, progress_index, progress_vals);
3492
  }
3493
  tuplesort_performsort(state.tuplesort);
3494
3495
  /*
3496
   * Now scan the heap and "merge" it with the index
3497
   */
3498
  pgstat_progress_update_param(PROGRESS_CREATEIDX_PHASE,
3499
                 PROGRESS_CREATEIDX_PHASE_VALIDATE_TABLESCAN);
3500
  table_index_validate_scan(heapRelation,
3501
                indexRelation,
3502
                indexInfo,
3503
                snapshot,
3504
                &state);
3505
3506
  /* Done with tuplesort object */
3507
  tuplesort_end(state.tuplesort);
3508
3509
  /* Make sure to release resources cached in indexInfo (if needed). */
3510
  index_insert_cleanup(indexRelation, indexInfo);
3511
3512
  elog(DEBUG2,
3513
     "validate_index found %.0f heap tuples, %.0f index tuples; inserted %.0f missing tuples",
3514
     state.htups, state.itups, state.tups_inserted);
3515
3516
  /* Roll back any GUC changes executed by index functions */
3517
  AtEOXact_GUC(false, save_nestlevel);
3518
3519
  /* Restore userid and security context */
3520
  SetUserIdAndSecContext(save_userid, save_sec_context);
3521
3522
  /* Close rels, but keep locks */
3523
  index_close(indexRelation, NoLock);
3524
  table_close(heapRelation, NoLock);
3525
}
3526
3527
/*
3528
 * validate_index_callback - bulkdelete callback to collect the index TIDs
3529
 */
3530
static bool
3531
validate_index_callback(ItemPointer itemptr, void *opaque)
3532
0
{
3533
0
  ValidateIndexState *state = (ValidateIndexState *) opaque;
3534
0
  int64   encoded = itemptr_encode(itemptr);
3535
3536
0
  tuplesort_putdatum(state->tuplesort, Int64GetDatum(encoded), false);
3537
0
  state->itups += 1;
3538
0
  return false;        /* never actually delete anything */
3539
0
}
3540
3541
/*
3542
 * index_set_state_flags - adjust pg_index state flags
3543
 *
3544
 * This is used during CREATE/DROP INDEX CONCURRENTLY to adjust the pg_index
3545
 * flags that denote the index's state.
3546
 *
3547
 * Note that CatalogTupleUpdate() sends a cache invalidation message for the
3548
 * tuple, so other sessions will hear about the update as soon as we commit.
3549
 */
3550
void
3551
index_set_state_flags(Oid indexId, IndexStateFlagsAction action)
3552
0
{
3553
0
  Relation  pg_index;
3554
0
  HeapTuple indexTuple;
3555
0
  Form_pg_index indexForm;
3556
3557
  /* Open pg_index and fetch a writable copy of the index's tuple */
3558
0
  pg_index = table_open(IndexRelationId, RowExclusiveLock);
3559
3560
0
  indexTuple = SearchSysCacheCopy1(INDEXRELID,
3561
0
                   ObjectIdGetDatum(indexId));
3562
0
  if (!HeapTupleIsValid(indexTuple))
3563
0
    elog(ERROR, "cache lookup failed for index %u", indexId);
3564
0
  indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
3565
3566
  /* Perform the requested state change on the copy */
3567
0
  switch (action)
3568
0
  {
3569
0
    case INDEX_CREATE_SET_READY:
3570
      /* Set indisready during a CREATE INDEX CONCURRENTLY sequence */
3571
0
      Assert(indexForm->indislive);
3572
0
      Assert(!indexForm->indisready);
3573
0
      Assert(!indexForm->indisvalid);
3574
0
      indexForm->indisready = true;
3575
0
      break;
3576
0
    case INDEX_CREATE_SET_VALID:
3577
      /* Set indisvalid during a CREATE INDEX CONCURRENTLY sequence */
3578
0
      Assert(indexForm->indislive);
3579
0
      Assert(indexForm->indisready);
3580
0
      Assert(!indexForm->indisvalid);
3581
0
      indexForm->indisvalid = true;
3582
0
      break;
3583
0
    case INDEX_DROP_CLEAR_VALID:
3584
3585
      /*
3586
       * Clear indisvalid during a DROP INDEX CONCURRENTLY sequence
3587
       *
3588
       * If indisready == true we leave it set so the index still gets
3589
       * maintained by active transactions.  We only need to ensure that
3590
       * indisvalid is false.  (We don't assert that either is initially
3591
       * true, though, since we want to be able to retry a DROP INDEX
3592
       * CONCURRENTLY that failed partway through.)
3593
       *
3594
       * Note: the CLUSTER logic assumes that indisclustered cannot be
3595
       * set on any invalid index, so clear that flag too.  For
3596
       * cleanliness, also clear indisreplident.
3597
       */
3598
0
      indexForm->indisvalid = false;
3599
0
      indexForm->indisclustered = false;
3600
0
      indexForm->indisreplident = false;
3601
0
      break;
3602
0
    case INDEX_DROP_SET_DEAD:
3603
3604
      /*
3605
       * Clear indisready/indislive during DROP INDEX CONCURRENTLY
3606
       *
3607
       * We clear both indisready and indislive, because we not only
3608
       * want to stop updates, we want to prevent sessions from touching
3609
       * the index at all.
3610
       */
3611
0
      Assert(!indexForm->indisvalid);
3612
0
      Assert(!indexForm->indisclustered);
3613
0
      Assert(!indexForm->indisreplident);
3614
0
      indexForm->indisready = false;
3615
0
      indexForm->indislive = false;
3616
0
      break;
3617
0
  }
3618
3619
  /* ... and update it */
3620
0
  CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple);
3621
3622
0
  table_close(pg_index, RowExclusiveLock);
3623
0
}
3624
3625
3626
/*
3627
 * IndexGetRelation: given an index's relation OID, get the OID of the
3628
 * relation it is an index on.  Uses the system cache.
3629
 */
3630
Oid
3631
IndexGetRelation(Oid indexId, bool missing_ok)
3632
0
{
3633
0
  HeapTuple tuple;
3634
0
  Form_pg_index index;
3635
0
  Oid     result;
3636
3637
0
  tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
3638
0
  if (!HeapTupleIsValid(tuple))
3639
0
  {
3640
0
    if (missing_ok)
3641
0
      return InvalidOid;
3642
0
    elog(ERROR, "cache lookup failed for index %u", indexId);
3643
0
  }
3644
0
  index = (Form_pg_index) GETSTRUCT(tuple);
3645
0
  Assert(index->indexrelid == indexId);
3646
3647
0
  result = index->indrelid;
3648
0
  ReleaseSysCache(tuple);
3649
0
  return result;
3650
0
}
3651
3652
/*
3653
 * reindex_index - This routine is used to recreate a single index
3654
 */
3655
void
3656
reindex_index(const ReindexStmt *stmt, Oid indexId,
3657
        bool skip_constraint_checks, char persistence,
3658
        const ReindexParams *params)
3659
0
{
3660
0
  Relation  iRel,
3661
0
        heapRelation;
3662
0
  Oid     heapId;
3663
0
  Oid     save_userid;
3664
0
  int     save_sec_context;
3665
0
  int     save_nestlevel;
3666
0
  IndexInfo  *indexInfo;
3667
0
  bool    skipped_constraint = false;
3668
0
  PGRUsage  ru0;
3669
0
  bool    progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
3670
0
  bool    set_tablespace = false;
3671
3672
0
  pg_rusage_init(&ru0);
3673
3674
  /*
3675
   * Open and lock the parent heap relation.  ShareLock is sufficient since
3676
   * we only need to be sure no schema or data changes are going on.
3677
   */
3678
0
  heapId = IndexGetRelation(indexId,
3679
0
                (params->options & REINDEXOPT_MISSING_OK) != 0);
3680
  /* if relation is missing, leave */
3681
0
  if (!OidIsValid(heapId))
3682
0
    return;
3683
3684
0
  if ((params->options & REINDEXOPT_MISSING_OK) != 0)
3685
0
    heapRelation = try_table_open(heapId, ShareLock);
3686
0
  else
3687
0
    heapRelation = table_open(heapId, ShareLock);
3688
3689
  /* if relation is gone, leave */
3690
0
  if (!heapRelation)
3691
0
    return;
3692
3693
  /*
3694
   * Switch to the table owner's userid, so that any index functions are run
3695
   * as that user.  Also lock down security-restricted operations and
3696
   * arrange to make GUC variable changes local to this command.
3697
   */
3698
0
  GetUserIdAndSecContext(&save_userid, &save_sec_context);
3699
0
  SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
3700
0
               save_sec_context | SECURITY_RESTRICTED_OPERATION);
3701
0
  save_nestlevel = NewGUCNestLevel();
3702
0
  RestrictSearchPath();
3703
3704
0
  if (progress)
3705
0
  {
3706
0
    const int progress_cols[] = {
3707
0
      PROGRESS_CREATEIDX_COMMAND,
3708
0
      PROGRESS_CREATEIDX_INDEX_OID
3709
0
    };
3710
0
    const int64 progress_vals[] = {
3711
0
      PROGRESS_CREATEIDX_COMMAND_REINDEX,
3712
0
      indexId
3713
0
    };
3714
3715
0
    pgstat_progress_start_command(PROGRESS_COMMAND_CREATE_INDEX,
3716
0
                    heapId);
3717
0
    pgstat_progress_update_multi_param(2, progress_cols, progress_vals);
3718
0
  }
3719
3720
  /*
3721
   * Open the target index relation and get an exclusive lock on it, to
3722
   * ensure that no one else is touching this particular index.
3723
   */
3724
0
  if ((params->options & REINDEXOPT_MISSING_OK) != 0)
3725
0
    iRel = try_index_open(indexId, AccessExclusiveLock);
3726
0
  else
3727
0
    iRel = index_open(indexId, AccessExclusiveLock);
3728
3729
  /* if index relation is gone, leave */
3730
0
  if (!iRel)
3731
0
  {
3732
    /* Roll back any GUC changes */
3733
0
    AtEOXact_GUC(false, save_nestlevel);
3734
3735
    /* Restore userid and security context */
3736
0
    SetUserIdAndSecContext(save_userid, save_sec_context);
3737
3738
    /* Close parent heap relation, but keep locks */
3739
0
    table_close(heapRelation, NoLock);
3740
0
    return;
3741
0
  }
3742
3743
0
  if (progress)
3744
0
    pgstat_progress_update_param(PROGRESS_CREATEIDX_ACCESS_METHOD_OID,
3745
0
                   iRel->rd_rel->relam);
3746
3747
  /*
3748
   * If a statement is available, telling that this comes from a REINDEX
3749
   * command, collect the index for event triggers.
3750
   */
3751
0
  if (stmt)
3752
0
  {
3753
0
    ObjectAddress address;
3754
3755
0
    ObjectAddressSet(address, RelationRelationId, indexId);
3756
0
    EventTriggerCollectSimpleCommand(address,
3757
0
                     InvalidObjectAddress,
3758
0
                     (const Node *) stmt);
3759
0
  }
3760
3761
  /*
3762
   * Partitioned indexes should never get processed here, as they have no
3763
   * physical storage.
3764
   */
3765
0
  if (iRel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
3766
0
    elog(ERROR, "cannot reindex partitioned index \"%s.%s\"",
3767
0
       get_namespace_name(RelationGetNamespace(iRel)),
3768
0
       RelationGetRelationName(iRel));
3769
3770
  /*
3771
   * Don't allow reindex on temp tables of other backends ... their local
3772
   * buffer manager is not going to cope.
3773
   */
3774
0
  if (RELATION_IS_OTHER_TEMP(iRel))
3775
0
    ereport(ERROR,
3776
0
        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3777
0
         errmsg("cannot reindex temporary tables of other sessions")));
3778
3779
  /*
3780
   * Don't allow reindex of an invalid index on TOAST table.  This is a
3781
   * leftover from a failed REINDEX CONCURRENTLY, and if rebuilt it would
3782
   * not be possible to drop it anymore.
3783
   */
3784
0
  if (IsToastNamespace(RelationGetNamespace(iRel)) &&
3785
0
    !get_index_isvalid(indexId))
3786
0
    ereport(ERROR,
3787
0
        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3788
0
         errmsg("cannot reindex invalid index on TOAST table")));
3789
3790
  /*
3791
   * System relations cannot be moved even if allow_system_table_mods is
3792
   * enabled to keep things consistent with the concurrent case where all
3793
   * the indexes of a relation are processed in series, including indexes of
3794
   * toast relations.
3795
   *
3796
   * Note that this check is not part of CheckRelationTableSpaceMove() as it
3797
   * gets used for ALTER TABLE SET TABLESPACE that could cascade across
3798
   * toast relations.
3799
   */
3800
0
  if (OidIsValid(params->tablespaceOid) &&
3801
0
    IsSystemRelation(iRel))
3802
0
    ereport(ERROR,
3803
0
        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3804
0
         errmsg("cannot move system relation \"%s\"",
3805
0
            RelationGetRelationName(iRel))));
3806
3807
  /* Check if the tablespace of this index needs to be changed */
3808
0
  if (OidIsValid(params->tablespaceOid) &&
3809
0
    CheckRelationTableSpaceMove(iRel, params->tablespaceOid))
3810
0
    set_tablespace = true;
3811
3812
  /*
3813
   * Also check for active uses of the index in the current transaction; we
3814
   * don't want to reindex underneath an open indexscan.
3815
   */
3816
0
  CheckTableNotInUse(iRel, "REINDEX INDEX");
3817
3818
  /* Set new tablespace, if requested */
3819
0
  if (set_tablespace)
3820
0
  {
3821
    /* Update its pg_class row */
3822
0
    SetRelationTableSpace(iRel, params->tablespaceOid, InvalidOid);
3823
3824
    /*
3825
     * Schedule unlinking of the old index storage at transaction commit.
3826
     */
3827
0
    RelationDropStorage(iRel);
3828
0
    RelationAssumeNewRelfilelocator(iRel);
3829
3830
    /* Make sure the reltablespace change is visible */
3831
0
    CommandCounterIncrement();
3832
0
  }
3833
3834
  /*
3835
   * All predicate locks on the index are about to be made invalid. Promote
3836
   * them to relation locks on the heap.
3837
   */
3838
0
  TransferPredicateLocksToHeapRelation(iRel);
3839
3840
  /* Fetch info needed for index_build */
3841
0
  indexInfo = BuildIndexInfo(iRel);
3842
3843
  /* If requested, skip checking uniqueness/exclusion constraints */
3844
0
  if (skip_constraint_checks)
3845
0
  {
3846
0
    if (indexInfo->ii_Unique || indexInfo->ii_ExclusionOps != NULL)
3847
0
      skipped_constraint = true;
3848
0
    indexInfo->ii_Unique = false;
3849
0
    indexInfo->ii_ExclusionOps = NULL;
3850
0
    indexInfo->ii_ExclusionProcs = NULL;
3851
0
    indexInfo->ii_ExclusionStrats = NULL;
3852
0
  }
3853
3854
  /* Suppress use of the target index while rebuilding it */
3855
0
  SetReindexProcessing(heapId, indexId);
3856
3857
  /* Create a new physical relation for the index */
3858
0
  RelationSetNewRelfilenumber(iRel, persistence);
3859
3860
  /* Initialize the index and rebuild */
3861
  /* Note: we do not need to re-establish pkey setting */
3862
0
  index_build(heapRelation, iRel, indexInfo, true, true, progress);
3863
3864
  /* Re-allow use of target index */
3865
0
  ResetReindexProcessing();
3866
3867
  /*
3868
   * If the index is marked invalid/not-ready/dead (ie, it's from a failed
3869
   * CREATE INDEX CONCURRENTLY, or a DROP INDEX CONCURRENTLY failed midway),
3870
   * and we didn't skip a uniqueness check, we can now mark it valid.  This
3871
   * allows REINDEX to be used to clean up in such cases.
3872
   *
3873
   * We can also reset indcheckxmin, because we have now done a
3874
   * non-concurrent index build, *except* in the case where index_build
3875
   * found some still-broken HOT chains. If it did, and we don't have to
3876
   * change any of the other flags, we just leave indcheckxmin alone (note
3877
   * that index_build won't have changed it, because this is a reindex).
3878
   * This is okay and desirable because not updating the tuple leaves the
3879
   * index's usability horizon (recorded as the tuple's xmin value) the same
3880
   * as it was.
3881
   *
3882
   * But, if the index was invalid/not-ready/dead and there were broken HOT
3883
   * chains, we had better force indcheckxmin true, because the normal
3884
   * argument that the HOT chains couldn't conflict with the index is
3885
   * suspect for an invalid index.  (A conflict is definitely possible if
3886
   * the index was dead.  It probably shouldn't happen otherwise, but let's
3887
   * be conservative.)  In this case advancing the usability horizon is
3888
   * appropriate.
3889
   *
3890
   * Another reason for avoiding unnecessary updates here is that while
3891
   * reindexing pg_index itself, we must not try to update tuples in it.
3892
   * pg_index's indexes should always have these flags in their clean state,
3893
   * so that won't happen.
3894
   */
3895
0
  if (!skipped_constraint)
3896
0
  {
3897
0
    Relation  pg_index;
3898
0
    HeapTuple indexTuple;
3899
0
    Form_pg_index indexForm;
3900
0
    bool    index_bad;
3901
3902
0
    pg_index = table_open(IndexRelationId, RowExclusiveLock);
3903
3904
0
    indexTuple = SearchSysCacheCopy1(INDEXRELID,
3905
0
                     ObjectIdGetDatum(indexId));
3906
0
    if (!HeapTupleIsValid(indexTuple))
3907
0
      elog(ERROR, "cache lookup failed for index %u", indexId);
3908
0
    indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
3909
3910
0
    index_bad = (!indexForm->indisvalid ||
3911
0
           !indexForm->indisready ||
3912
0
           !indexForm->indislive);
3913
0
    if (index_bad ||
3914
0
      (indexForm->indcheckxmin && !indexInfo->ii_BrokenHotChain))
3915
0
    {
3916
0
      if (!indexInfo->ii_BrokenHotChain)
3917
0
        indexForm->indcheckxmin = false;
3918
0
      else if (index_bad)
3919
0
        indexForm->indcheckxmin = true;
3920
0
      indexForm->indisvalid = true;
3921
0
      indexForm->indisready = true;
3922
0
      indexForm->indislive = true;
3923
0
      CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple);
3924
3925
      /*
3926
       * Invalidate the relcache for the table, so that after we commit
3927
       * all sessions will refresh the table's index list.  This ensures
3928
       * that if anyone misses seeing the pg_index row during this
3929
       * update, they'll refresh their list before attempting any update
3930
       * on the table.
3931
       */
3932
0
      CacheInvalidateRelcache(heapRelation);
3933
0
    }
3934
3935
0
    table_close(pg_index, RowExclusiveLock);
3936
0
  }
3937
3938
  /* Log what we did */
3939
0
  if ((params->options & REINDEXOPT_VERBOSE) != 0)
3940
0
    ereport(INFO,
3941
0
        (errmsg("index \"%s\" was reindexed",
3942
0
            get_rel_name(indexId)),
3943
0
         errdetail_internal("%s",
3944
0
                  pg_rusage_show(&ru0))));
3945
3946
  /* Roll back any GUC changes executed by index functions */
3947
0
  AtEOXact_GUC(false, save_nestlevel);
3948
3949
  /* Restore userid and security context */
3950
0
  SetUserIdAndSecContext(save_userid, save_sec_context);
3951
3952
  /* Close rels, but keep locks */
3953
0
  index_close(iRel, NoLock);
3954
0
  table_close(heapRelation, NoLock);
3955
3956
0
  if (progress)
3957
0
    pgstat_progress_end_command();
3958
0
}
3959
3960
/*
3961
 * reindex_relation - This routine is used to recreate all indexes
3962
 * of a relation (and optionally its toast relation too, if any).
3963
 *
3964
 * "flags" is a bitmask that can include any combination of these bits:
3965
 *
3966
 * REINDEX_REL_PROCESS_TOAST: if true, process the toast table too (if any).
3967
 *
3968
 * REINDEX_REL_SUPPRESS_INDEX_USE: if true, the relation was just completely
3969
 * rebuilt by an operation such as VACUUM FULL or CLUSTER, and therefore its
3970
 * indexes are inconsistent with it.  This makes things tricky if the relation
3971
 * is a system catalog that we might consult during the reindexing.  To deal
3972
 * with that case, we mark all of the indexes as pending rebuild so that they
3973
 * won't be trusted until rebuilt.  The caller is required to call us *without*
3974
 * having made the rebuilt table visible by doing CommandCounterIncrement;
3975
 * we'll do CCI after having collected the index list.  (This way we can still
3976
 * use catalog indexes while collecting the list.)
3977
 *
3978
 * REINDEX_REL_CHECK_CONSTRAINTS: if true, recheck unique and exclusion
3979
 * constraint conditions, else don't.  To avoid deadlocks, VACUUM FULL or
3980
 * CLUSTER on a system catalog must omit this flag.  REINDEX should be used to
3981
 * rebuild an index if constraint inconsistency is suspected.  For optimal
3982
 * performance, other callers should include the flag only after transforming
3983
 * the data in a manner that risks a change in constraint validity.
3984
 *
3985
 * REINDEX_REL_FORCE_INDEXES_UNLOGGED: if true, set the persistence of the
3986
 * rebuilt indexes to unlogged.
3987
 *
3988
 * REINDEX_REL_FORCE_INDEXES_PERMANENT: if true, set the persistence of the
3989
 * rebuilt indexes to permanent.
3990
 *
3991
 * Returns true if any indexes were rebuilt (including toast table's index
3992
 * when relevant).  Note that a CommandCounterIncrement will occur after each
3993
 * index rebuild.
3994
 */
3995
bool
3996
reindex_relation(const ReindexStmt *stmt, Oid relid, int flags,
3997
         const ReindexParams *params)
3998
0
{
3999
0
  Relation  rel;
4000
0
  Oid     toast_relid;
4001
0
  List     *indexIds;
4002
0
  char    persistence;
4003
0
  bool    result = false;
4004
0
  ListCell   *indexId;
4005
0
  int     i;
4006
4007
  /*
4008
   * Open and lock the relation.  ShareLock is sufficient since we only need
4009
   * to prevent schema and data changes in it.  The lock level used here
4010
   * should match ReindexTable().
4011
   */
4012
0
  if ((params->options & REINDEXOPT_MISSING_OK) != 0)
4013
0
    rel = try_table_open(relid, ShareLock);
4014
0
  else
4015
0
    rel = table_open(relid, ShareLock);
4016
4017
  /* if relation is gone, leave */
4018
0
  if (!rel)
4019
0
    return false;
4020
4021
  /*
4022
   * Partitioned tables should never get processed here, as they have no
4023
   * physical storage.
4024
   */
4025
0
  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
4026
0
    elog(ERROR, "cannot reindex partitioned table \"%s.%s\"",
4027
0
       get_namespace_name(RelationGetNamespace(rel)),
4028
0
       RelationGetRelationName(rel));
4029
4030
0
  toast_relid = rel->rd_rel->reltoastrelid;
4031
4032
  /*
4033
   * Get the list of index OIDs for this relation.  (We trust the relcache
4034
   * to get this with a sequential scan if ignoring system indexes.)
4035
   */
4036
0
  indexIds = RelationGetIndexList(rel);
4037
4038
0
  if (flags & REINDEX_REL_SUPPRESS_INDEX_USE)
4039
0
  {
4040
    /* Suppress use of all the indexes until they are rebuilt */
4041
0
    SetReindexPending(indexIds);
4042
4043
    /*
4044
     * Make the new heap contents visible --- now things might be
4045
     * inconsistent!
4046
     */
4047
0
    CommandCounterIncrement();
4048
0
  }
4049
4050
  /*
4051
   * Reindex the toast table, if any, before the main table.
4052
   *
4053
   * This helps in cases where a corruption in the toast table's index would
4054
   * otherwise error and stop REINDEX TABLE command when it tries to fetch a
4055
   * toasted datum.  This way. the toast table's index is rebuilt and fixed
4056
   * before it is used for reindexing the main table.
4057
   *
4058
   * It is critical to call reindex_relation() *after* the call to
4059
   * RelationGetIndexList() returning the list of indexes on the relation,
4060
   * because reindex_relation() will call CommandCounterIncrement() after
4061
   * every reindex_index().  See REINDEX_REL_SUPPRESS_INDEX_USE for more
4062
   * details.
4063
   */
4064
0
  if ((flags & REINDEX_REL_PROCESS_TOAST) && OidIsValid(toast_relid))
4065
0
  {
4066
    /*
4067
     * Note that this should fail if the toast relation is missing, so
4068
     * reset REINDEXOPT_MISSING_OK.  Even if a new tablespace is set for
4069
     * the parent relation, the indexes on its toast table are not moved.
4070
     * This rule is enforced by setting tablespaceOid to InvalidOid.
4071
     */
4072
0
    ReindexParams newparams = *params;
4073
4074
0
    newparams.options &= ~(REINDEXOPT_MISSING_OK);
4075
0
    newparams.tablespaceOid = InvalidOid;
4076
0
    result |= reindex_relation(stmt, toast_relid, flags, &newparams);
4077
0
  }
4078
4079
  /*
4080
   * Compute persistence of indexes: same as that of owning rel, unless
4081
   * caller specified otherwise.
4082
   */
4083
0
  if (flags & REINDEX_REL_FORCE_INDEXES_UNLOGGED)
4084
0
    persistence = RELPERSISTENCE_UNLOGGED;
4085
0
  else if (flags & REINDEX_REL_FORCE_INDEXES_PERMANENT)
4086
0
    persistence = RELPERSISTENCE_PERMANENT;
4087
0
  else
4088
0
    persistence = rel->rd_rel->relpersistence;
4089
4090
  /* Reindex all the indexes. */
4091
0
  i = 1;
4092
0
  foreach(indexId, indexIds)
4093
0
  {
4094
0
    Oid     indexOid = lfirst_oid(indexId);
4095
0
    Oid     indexNamespaceId = get_rel_namespace(indexOid);
4096
4097
    /*
4098
     * Skip any invalid indexes on a TOAST table.  These can only be
4099
     * duplicate leftovers from a failed REINDEX CONCURRENTLY, and if
4100
     * rebuilt it would not be possible to drop them anymore.
4101
     */
4102
0
    if (IsToastNamespace(indexNamespaceId) &&
4103
0
      !get_index_isvalid(indexOid))
4104
0
    {
4105
0
      ereport(WARNING,
4106
0
          (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4107
0
           errmsg("cannot reindex invalid index \"%s.%s\" on TOAST table, skipping",
4108
0
              get_namespace_name(indexNamespaceId),
4109
0
              get_rel_name(indexOid))));
4110
4111
      /*
4112
       * Remove this invalid toast index from the reindex pending list,
4113
       * as it is skipped here due to the hard failure that would happen
4114
       * in reindex_index(), should we try to process it.
4115
       */
4116
0
      if (flags & REINDEX_REL_SUPPRESS_INDEX_USE)
4117
0
        RemoveReindexPending(indexOid);
4118
0
      continue;
4119
0
    }
4120
4121
0
    reindex_index(stmt, indexOid, !(flags & REINDEX_REL_CHECK_CONSTRAINTS),
4122
0
            persistence, params);
4123
4124
0
    CommandCounterIncrement();
4125
4126
    /* Index should no longer be in the pending list */
4127
0
    Assert(!ReindexIsProcessingIndex(indexOid));
4128
4129
    /* Set index rebuild count */
4130
0
    pgstat_progress_update_param(PROGRESS_REPACK_INDEX_REBUILD_COUNT,
4131
0
                   i);
4132
0
    i++;
4133
0
  }
4134
4135
  /*
4136
   * Close rel, but continue to hold the lock.
4137
   */
4138
0
  table_close(rel, NoLock);
4139
4140
0
  result |= (indexIds != NIL);
4141
4142
0
  return result;
4143
0
}
4144
4145
4146
/* ----------------------------------------------------------------
4147
 *    System index reindexing support
4148
 *
4149
 * When we are busy reindexing a system index, this code provides support
4150
 * for preventing catalog lookups from using that index.  We also make use
4151
 * of this to catch attempted uses of user indexes during reindexing of
4152
 * those indexes.  This information is propagated to parallel workers;
4153
 * attempting to change it during a parallel operation is not permitted.
4154
 * ----------------------------------------------------------------
4155
 */
4156
4157
static Oid  currentlyReindexedHeap = InvalidOid;
4158
static Oid  currentlyReindexedIndex = InvalidOid;
4159
static List *pendingReindexedIndexes = NIL;
4160
static int  reindexingNestLevel = 0;
4161
4162
/*
4163
 * ReindexIsProcessingHeap
4164
 *    True if heap specified by OID is currently being reindexed.
4165
 */
4166
bool
4167
ReindexIsProcessingHeap(Oid heapOid)
4168
0
{
4169
0
  return heapOid == currentlyReindexedHeap;
4170
0
}
4171
4172
/*
4173
 * ReindexIsCurrentlyProcessingIndex
4174
 *    True if index specified by OID is currently being reindexed.
4175
 */
4176
static bool
4177
ReindexIsCurrentlyProcessingIndex(Oid indexOid)
4178
0
{
4179
0
  return indexOid == currentlyReindexedIndex;
4180
0
}
4181
4182
/*
4183
 * ReindexIsProcessingIndex
4184
 *    True if index specified by OID is currently being reindexed,
4185
 *    or should be treated as invalid because it is awaiting reindex.
4186
 */
4187
bool
4188
ReindexIsProcessingIndex(Oid indexOid)
4189
0
{
4190
0
  return indexOid == currentlyReindexedIndex ||
4191
0
    list_member_oid(pendingReindexedIndexes, indexOid);
4192
0
}
4193
4194
/*
4195
 * SetReindexProcessing
4196
 *    Set flag that specified heap/index are being reindexed.
4197
 */
4198
static void
4199
SetReindexProcessing(Oid heapOid, Oid indexOid)
4200
0
{
4201
0
  Assert(OidIsValid(heapOid) && OidIsValid(indexOid));
4202
  /* Reindexing is not re-entrant. */
4203
0
  if (OidIsValid(currentlyReindexedHeap))
4204
0
    elog(ERROR, "cannot reindex while reindexing");
4205
0
  currentlyReindexedHeap = heapOid;
4206
0
  currentlyReindexedIndex = indexOid;
4207
  /* Index is no longer "pending" reindex. */
4208
0
  RemoveReindexPending(indexOid);
4209
  /* This may have been set already, but in case it isn't, do so now. */
4210
0
  reindexingNestLevel = GetCurrentTransactionNestLevel();
4211
0
}
4212
4213
/*
4214
 * ResetReindexProcessing
4215
 *    Unset reindexing status.
4216
 */
4217
static void
4218
ResetReindexProcessing(void)
4219
0
{
4220
0
  currentlyReindexedHeap = InvalidOid;
4221
0
  currentlyReindexedIndex = InvalidOid;
4222
  /* reindexingNestLevel remains set till end of (sub)transaction */
4223
0
}
4224
4225
/*
4226
 * SetReindexPending
4227
 *    Mark the given indexes as pending reindex.
4228
 *
4229
 * NB: we assume that the current memory context stays valid throughout.
4230
 */
4231
static void
4232
SetReindexPending(List *indexes)
4233
0
{
4234
  /* Reindexing is not re-entrant. */
4235
0
  if (pendingReindexedIndexes)
4236
0
    elog(ERROR, "cannot reindex while reindexing");
4237
0
  if (IsInParallelMode())
4238
0
    elog(ERROR, "cannot modify reindex state during a parallel operation");
4239
0
  pendingReindexedIndexes = list_copy(indexes);
4240
0
  reindexingNestLevel = GetCurrentTransactionNestLevel();
4241
0
}
4242
4243
/*
4244
 * RemoveReindexPending
4245
 *    Remove the given index from the pending list.
4246
 */
4247
static void
4248
RemoveReindexPending(Oid indexOid)
4249
0
{
4250
0
  if (IsInParallelMode())
4251
0
    elog(ERROR, "cannot modify reindex state during a parallel operation");
4252
0
  pendingReindexedIndexes = list_delete_oid(pendingReindexedIndexes,
4253
0
                        indexOid);
4254
0
}
4255
4256
/*
4257
 * ResetReindexState
4258
 *    Clear all reindexing state during (sub)transaction abort.
4259
 */
4260
void
4261
ResetReindexState(int nestLevel)
4262
0
{
4263
  /*
4264
   * Because reindexing is not re-entrant, we don't need to cope with nested
4265
   * reindexing states.  We just need to avoid messing up the outer-level
4266
   * state in case a subtransaction fails within a REINDEX.  So checking the
4267
   * current nest level against that of the reindex operation is sufficient.
4268
   */
4269
0
  if (reindexingNestLevel >= nestLevel)
4270
0
  {
4271
0
    currentlyReindexedHeap = InvalidOid;
4272
0
    currentlyReindexedIndex = InvalidOid;
4273
4274
    /*
4275
     * We needn't try to release the contents of pendingReindexedIndexes;
4276
     * that list should be in a transaction-lifespan context, so it will
4277
     * go away automatically.
4278
     */
4279
0
    pendingReindexedIndexes = NIL;
4280
4281
0
    reindexingNestLevel = 0;
4282
0
  }
4283
0
}
4284
4285
/*
4286
 * EstimateReindexStateSpace
4287
 *    Estimate space needed to pass reindex state to parallel workers.
4288
 */
4289
Size
4290
EstimateReindexStateSpace(void)
4291
0
{
4292
0
  return offsetof(SerializedReindexState, pendingReindexedIndexes)
4293
0
    + mul_size(sizeof(Oid), list_length(pendingReindexedIndexes));
4294
0
}
4295
4296
/*
4297
 * SerializeReindexState
4298
 *    Serialize reindex state for parallel workers.
4299
 */
4300
void
4301
SerializeReindexState(Size maxsize, char *start_address)
4302
0
{
4303
0
  SerializedReindexState *sistate = (SerializedReindexState *) start_address;
4304
0
  int     c = 0;
4305
0
  ListCell   *lc;
4306
4307
0
  sistate->currentlyReindexedHeap = currentlyReindexedHeap;
4308
0
  sistate->currentlyReindexedIndex = currentlyReindexedIndex;
4309
0
  sistate->numPendingReindexedIndexes = list_length(pendingReindexedIndexes);
4310
0
  foreach(lc, pendingReindexedIndexes)
4311
0
    sistate->pendingReindexedIndexes[c++] = lfirst_oid(lc);
4312
0
}
4313
4314
/*
4315
 * RestoreReindexState
4316
 *    Restore reindex state in a parallel worker.
4317
 */
4318
void
4319
RestoreReindexState(const void *reindexstate)
4320
0
{
4321
0
  const SerializedReindexState *sistate = (const SerializedReindexState *) reindexstate;
4322
0
  int     c = 0;
4323
0
  MemoryContext oldcontext;
4324
4325
0
  currentlyReindexedHeap = sistate->currentlyReindexedHeap;
4326
0
  currentlyReindexedIndex = sistate->currentlyReindexedIndex;
4327
4328
0
  Assert(pendingReindexedIndexes == NIL);
4329
0
  oldcontext = MemoryContextSwitchTo(TopMemoryContext);
4330
0
  for (c = 0; c < sistate->numPendingReindexedIndexes; ++c)
4331
0
    pendingReindexedIndexes =
4332
0
      lappend_oid(pendingReindexedIndexes,
4333
0
            sistate->pendingReindexedIndexes[c]);
4334
0
  MemoryContextSwitchTo(oldcontext);
4335
4336
  /* Note the worker has its own transaction nesting level */
4337
0
  reindexingNestLevel = GetCurrentTransactionNestLevel();
4338
0
}