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