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