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