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