1 /*-------------------------------------------------------------------------
4 * code to create and destroy POSTGRES index relations
6 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.180 2002/06/15 19:54:23 momjian Exp $
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
20 *-------------------------------------------------------------------------
26 #include "access/genam.h"
27 #include "access/heapam.h"
28 #include "access/istrat.h"
29 #include "bootstrap/bootstrap.h"
30 #include "catalog/catalog.h"
31 #include "catalog/catname.h"
32 #include "catalog/heap.h"
33 #include "catalog/index.h"
34 #include "catalog/indexing.h"
35 #include "catalog/pg_index.h"
36 #include "catalog/pg_opclass.h"
37 #include "catalog/pg_proc.h"
38 #include "catalog/pg_type.h"
39 #include "commands/comment.h"
40 #include "executor/executor.h"
41 #include "miscadmin.h"
42 #include "optimizer/clauses.h"
43 #include "optimizer/prep.h"
44 #include "parser/parse_func.h"
45 #include "storage/sinval.h"
46 #include "storage/smgr.h"
47 #include "utils/builtins.h"
48 #include "utils/catcache.h"
49 #include "utils/fmgroids.h"
50 #include "utils/inval.h"
51 #include "utils/lsyscache.h"
52 #include "utils/relcache.h"
53 #include "utils/syscache.h"
57 * macros used in guessing how many tuples are on a page.
59 #define AVG_ATTR_SIZE 8
60 #define NTUPLES_PER_PAGE(natts) \
61 ((BLCKSZ - MAXALIGN(sizeof(PageHeaderData))) / \
62 ((natts) * AVG_ATTR_SIZE + MAXALIGN(sizeof(HeapTupleHeaderData))))
64 /* non-export function prototypes */
65 static TupleDesc BuildFuncTupleDesc(Oid funcOid,
67 static TupleDesc ConstructTupleDescriptor(Relation heapRelation,
68 int numatts, AttrNumber *attNums,
70 static void UpdateRelationRelation(Relation indexRelation);
71 static void InitializeAttributeOids(Relation indexRelation,
72 int numatts, Oid indexoid);
73 static void AppendAttributeTuples(Relation indexRelation, int numatts);
74 static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
78 static Oid IndexGetRelation(Oid indexId);
79 static bool activate_index(Oid indexId, bool activate, bool inplace);
82 static bool reindexing = false;
86 SetReindexProcessing(bool reindexmode)
88 bool old = reindexing;
90 reindexing = reindexmode;
95 IsReindexProcessing(void)
101 BuildFuncTupleDesc(Oid funcOid,
104 TupleDesc funcTupDesc;
108 Form_pg_type typeTup;
111 * Allocate and zero a tuple descriptor for a one-column tuple.
113 funcTupDesc = CreateTemplateTupleDesc(1);
114 funcTupDesc->attrs[0] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
115 MemSet(funcTupDesc->attrs[0], 0, ATTRIBUTE_TUPLE_SIZE);
118 * Lookup the function to get its name and return type.
120 tuple = SearchSysCache(PROCOID,
121 ObjectIdGetDatum(funcOid),
123 if (!HeapTupleIsValid(tuple))
124 elog(ERROR, "Function %u does not exist", funcOid);
125 retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype;
128 * make the attributes name the same as the functions
130 namestrcpy(&funcTupDesc->attrs[0]->attname,
131 NameStr(((Form_pg_proc) GETSTRUCT(tuple))->proname));
133 ReleaseSysCache(tuple);
136 * Check the opclass to see if it provides a keytype (overriding the
137 * function result type).
139 tuple = SearchSysCache(CLAOID,
140 ObjectIdGetDatum(classObjectId[0]),
142 if (!HeapTupleIsValid(tuple))
143 elog(ERROR, "Opclass %u does not exist", classObjectId[0]);
144 keyType = ((Form_pg_opclass) GETSTRUCT(tuple))->opckeytype;
145 ReleaseSysCache(tuple);
147 if (!OidIsValid(keyType))
151 * Lookup the key type in pg_type for the type length etc.
153 tuple = SearchSysCache(TYPEOID,
154 ObjectIdGetDatum(keyType),
156 if (!HeapTupleIsValid(tuple))
157 elog(ERROR, "Type %u does not exist", keyType);
158 typeTup = (Form_pg_type) GETSTRUCT(tuple);
161 * Assign some of the attributes values. Leave the rest as 0.
163 funcTupDesc->attrs[0]->attnum = 1;
164 funcTupDesc->attrs[0]->atttypid = keyType;
165 funcTupDesc->attrs[0]->attlen = typeTup->typlen;
166 funcTupDesc->attrs[0]->attbyval = typeTup->typbyval;
167 funcTupDesc->attrs[0]->attcacheoff = -1;
168 funcTupDesc->attrs[0]->atttypmod = -1;
169 funcTupDesc->attrs[0]->attstorage = typeTup->typstorage;
170 funcTupDesc->attrs[0]->attalign = typeTup->typalign;
172 ReleaseSysCache(tuple);
177 /* ----------------------------------------------------------------
178 * ConstructTupleDescriptor
180 * Build an index tuple descriptor for a new index (plain not functional)
181 * ----------------------------------------------------------------
184 ConstructTupleDescriptor(Relation heapRelation,
189 TupleDesc heapTupDesc;
190 TupleDesc indexTupDesc;
191 int natts; /* #atts in heap rel --- for error checks */
194 heapTupDesc = RelationGetDescr(heapRelation);
195 natts = RelationGetForm(heapRelation)->relnatts;
198 * allocate the new tuple descriptor
201 indexTupDesc = CreateTemplateTupleDesc(numatts);
204 * for each attribute we are indexing, obtain its attribute
205 * tuple form from either the static table of system attribute
206 * tuple forms or the relation tuple descriptor
209 for (i = 0; i < numatts; i++)
211 AttrNumber atnum; /* attributeNumber[attributeOffset] */
212 Form_pg_attribute from;
213 Form_pg_attribute to;
218 * get the attribute number and make sure it's valid; determine
219 * which attribute descriptor to copy
223 if (!AttrNumberIsForUserDefinedAttr(atnum))
226 * here we are indexing on a system attribute (-1...-n)
228 from = SystemAttributeDefinition(atnum,
229 heapRelation->rd_rel->relhasoids);
234 * here we are indexing on a normal attribute (1...n)
237 elog(ERROR, "cannot create index: column %d does not exist",
240 from = heapTupDesc->attrs[AttrNumberGetAttrOffset(atnum)];
244 * now that we've determined the "from", let's copy the tuple desc
247 indexTupDesc->attrs[i] = to =
248 (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
249 memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);
252 * Fix the stuff that should not be the same as the underlying
257 to->attstattarget = 0;
258 to->attcacheoff = -1;
259 to->attnotnull = false;
260 to->atthasdef = false;
263 * We do not yet have the correct relation OID for the index, so
264 * just set it invalid for now. InitializeAttributeOids() will
267 to->attrelid = InvalidOid;
270 * Check the opclass to see if it provides a keytype (overriding
271 * the attribute type).
273 tuple = SearchSysCache(CLAOID,
274 ObjectIdGetDatum(classObjectId[i]),
276 if (!HeapTupleIsValid(tuple))
277 elog(ERROR, "Opclass %u does not exist", classObjectId[i]);
278 keyType = ((Form_pg_opclass) GETSTRUCT(tuple))->opckeytype;
279 ReleaseSysCache(tuple);
281 if (OidIsValid(keyType) && keyType != to->atttypid)
283 /* index value and heap value have different types */
284 Form_pg_type typeTup;
286 tuple = SearchSysCache(TYPEOID,
287 ObjectIdGetDatum(keyType),
289 if (!HeapTupleIsValid(tuple))
290 elog(ERROR, "Type %u does not exist", keyType);
291 typeTup = (Form_pg_type) GETSTRUCT(tuple);
293 to->atttypid = keyType;
295 to->attlen = typeTup->typlen;
296 to->attbyval = typeTup->typbyval;
297 to->attalign = typeTup->typalign;
298 to->attstorage = typeTup->typstorage;
300 ReleaseSysCache(tuple);
307 /* ----------------------------------------------------------------
308 * UpdateRelationRelation
309 * ----------------------------------------------------------------
312 UpdateRelationRelation(Relation indexRelation)
316 Relation idescs[Num_pg_class_indices];
318 pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
320 /* XXX Natts_pg_class_fixed is a hack - see pg_class.h */
321 tuple = heap_addheader(Natts_pg_class_fixed,
323 (void *) indexRelation->rd_rel);
326 * the new tuple must have the oid already chosen for the index.
327 * sure would be embarrassing to do this sort of thing in polite company.
329 tuple->t_data->t_oid = RelationGetRelid(indexRelation);
330 simple_heap_insert(pg_class, tuple);
333 * During normal processing, we need to make sure that the system
334 * catalog indices are correct. Bootstrap (initdb) time doesn't
335 * require this, because we make sure that the indices are correct
336 * just before exiting.
338 if (!IsIgnoringSystemIndexes())
340 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
341 CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, tuple);
342 CatalogCloseIndices(Num_pg_class_indices, idescs);
345 heap_freetuple(tuple);
346 heap_close(pg_class, RowExclusiveLock);
349 /* ----------------------------------------------------------------
350 * InitializeAttributeOids
351 * ----------------------------------------------------------------
354 InitializeAttributeOids(Relation indexRelation,
358 TupleDesc tupleDescriptor;
361 tupleDescriptor = RelationGetDescr(indexRelation);
363 for (i = 0; i < numatts; i += 1)
364 tupleDescriptor->attrs[i]->attrelid = indexoid;
367 /* ----------------------------------------------------------------
368 * AppendAttributeTuples
369 * ----------------------------------------------------------------
372 AppendAttributeTuples(Relation indexRelation, int numatts)
374 Relation pg_attribute;
376 Relation idescs[Num_pg_attr_indices];
377 TupleDesc indexTupDesc;
382 * open the attribute relation
384 pg_attribute = heap_openr(AttributeRelationName, RowExclusiveLock);
387 if (!IsIgnoringSystemIndexes() && pg_attribute->rd_rel->relhasindex)
390 CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
394 * insert data from new index's tupdesc into pg_attribute
396 indexTupDesc = RelationGetDescr(indexRelation);
398 for (i = 0; i < numatts; i++)
401 * There used to be very grotty code here to set these fields, but
402 * I think it's unnecessary. They should be set already.
404 Assert(indexTupDesc->attrs[i]->attnum == i + 1);
405 Assert(indexTupDesc->attrs[i]->attcacheoff == -1);
407 new_tuple = heap_addheader(Natts_pg_attribute,
408 ATTRIBUTE_TUPLE_SIZE,
409 (void *) indexTupDesc->attrs[i]);
411 simple_heap_insert(pg_attribute, new_tuple);
414 CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, new_tuple);
416 heap_freetuple(new_tuple);
420 CatalogCloseIndices(Num_pg_attr_indices, idescs);
422 heap_close(pg_attribute, RowExclusiveLock);
425 /* ----------------------------------------------------------------
426 * UpdateIndexRelation
427 * ----------------------------------------------------------------
430 UpdateIndexRelation(Oid indexoid,
432 IndexInfo *indexInfo,
436 Form_pg_index indexForm;
444 Relation idescs[Num_pg_index_indices];
447 * allocate a Form_pg_index big enough to hold the index-predicate (if
448 * any) in string form
450 if (indexInfo->ii_Predicate != NIL)
452 predString = nodeToString(indexInfo->ii_Predicate);
453 predText = DatumGetTextP(DirectFunctionCall1(textin,
454 CStringGetDatum(predString)));
458 predText = DatumGetTextP(DirectFunctionCall1(textin,
459 CStringGetDatum("")));
461 predLen = VARSIZE(predText);
462 itupLen = predLen + sizeof(FormData_pg_index);
463 indexForm = (Form_pg_index) palloc(itupLen);
464 MemSet(indexForm, 0, sizeof(FormData_pg_index));
467 * store information into the index tuple form
469 indexForm->indexrelid = indexoid;
470 indexForm->indrelid = heapoid;
471 indexForm->indproc = indexInfo->ii_FuncOid;
472 indexForm->indisclustered = false; /* not used */
473 indexForm->indisunique = indexInfo->ii_Unique;
474 indexForm->indisprimary = primary;
475 memcpy((char *) &indexForm->indpred, (char *) predText, predLen);
478 * copy index key and op class information
480 * We zeroed the extra slots (if any) above --- that's essential.
482 for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
483 indexForm->indkey[i] = indexInfo->ii_KeyAttrNumbers[i];
485 for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
486 indexForm->indclass[i] = classOids[i];
489 * open the system catalog index relation
491 pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
494 * form a tuple to insert into pg_index
496 tuple = heap_addheader(Natts_pg_index,
501 * insert the tuple into the pg_index
503 simple_heap_insert(pg_index, tuple);
506 * add index tuples for it
508 if (!IsIgnoringSystemIndexes())
510 CatalogOpenIndices(Num_pg_index_indices, Name_pg_index_indices, idescs);
511 CatalogIndexInsert(idescs, Num_pg_index_indices, pg_index, tuple);
512 CatalogCloseIndices(Num_pg_index_indices, idescs);
516 * close the relation and free the tuple
518 heap_close(pg_index, RowExclusiveLock);
521 heap_freetuple(tuple);
525 /* ----------------------------------------------------------------
528 * Returns OID of the created index.
529 * ----------------------------------------------------------------
532 index_create(Oid heapRelationId,
533 const char *indexRelationName,
534 IndexInfo *indexInfo,
535 Oid accessMethodObjectId,
538 bool allow_system_table_mods)
540 Relation heapRelation;
541 Relation indexRelation;
542 TupleDesc indexTupDesc;
543 bool shared_relation;
547 SetReindexProcessing(false);
550 * Only SELECT ... FOR UPDATE are allowed while doing this
552 heapRelation = heap_open(heapRelationId, ShareLock);
555 * The index will be in the same namespace as its parent table,
556 * and is shared across databases if and only if the parent is.
558 namespaceId = RelationGetNamespace(heapRelation);
559 shared_relation = heapRelation->rd_rel->relisshared;
564 if (indexInfo->ii_NumIndexAttrs < 1 ||
565 indexInfo->ii_NumKeyAttrs < 1)
566 elog(ERROR, "must index at least one column");
568 if (!allow_system_table_mods &&
569 IsSystemRelation(heapRelation) &&
570 IsNormalProcessingMode())
571 elog(ERROR, "User-defined indexes on system catalogs are not supported");
574 * We cannot allow indexing a shared relation after initdb (because
575 * there's no way to make the entry in other databases' pg_class).
576 * Unfortunately we can't distinguish initdb from a manually started
577 * standalone backend. However, we can at least prevent this mistake
578 * under normal multi-user operation.
580 if (shared_relation && IsUnderPostmaster)
581 elog(ERROR, "Shared indexes cannot be created after initdb");
583 if (get_relname_relid(indexRelationName, namespaceId))
584 elog(ERROR, "index named \"%s\" already exists",
588 * construct tuple descriptor for index tuples
590 if (OidIsValid(indexInfo->ii_FuncOid))
591 indexTupDesc = BuildFuncTupleDesc(indexInfo->ii_FuncOid,
594 indexTupDesc = ConstructTupleDescriptor(heapRelation,
595 indexInfo->ii_NumKeyAttrs,
596 indexInfo->ii_KeyAttrNumbers,
600 * create the index relation (but don't create storage yet)
602 indexRelation = heap_create(indexRelationName,
607 allow_system_table_mods);
608 indexoid = RelationGetRelid(indexRelation);
611 * Obtain exclusive lock on it. Although no other backends can see it
612 * until we commit, this prevents deadlock-risk complaints from lock
613 * manager in cases such as CLUSTER.
615 LockRelation(indexRelation, AccessExclusiveLock);
618 * Fill in fields of the index's pg_class entry that are not set
619 * correctly by heap_create.
621 * XXX should have a cleaner way to create cataloged indexes
623 indexRelation->rd_rel->relowner = GetUserId();
624 indexRelation->rd_rel->relam = accessMethodObjectId;
625 indexRelation->rd_rel->relkind = RELKIND_INDEX;
626 indexRelation->rd_rel->relhasoids = false;
629 * store index's pg_class entry
631 UpdateRelationRelation(indexRelation);
634 * We create the disk file for this relation here
636 heap_storage_create(indexRelation);
639 * now update the object id's of all the attribute tuple forms in the
640 * index relation's tuple descriptor
642 InitializeAttributeOids(indexRelation,
643 indexInfo->ii_NumIndexAttrs,
647 * append ATTRIBUTE tuples for the index
649 AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs);
653 * (append INDEX tuple)
655 * Note that this stows away a representation of "predicate".
656 * (Or, could define a rule to maintain the predicate) --Nels, Feb '92
659 UpdateIndexRelation(indexoid, heapRelationId, indexInfo,
660 classObjectId, primary);
663 * fill in the index strategy structure with information from the
664 * catalogs. First we must advance the command counter so that we
665 * will see the newly-entered index catalog tuples.
667 CommandCounterIncrement();
669 RelationInitIndexAccessInfo(indexRelation);
672 * If this is bootstrap (initdb) time, then we don't actually fill in
673 * the index yet. We'll be creating more indices and classes later,
674 * so we delay filling them in until just before we're done with
675 * bootstrapping. Otherwise, we call the routine that constructs the
678 * In normal processing mode, the heap and index relations are closed by
679 * index_build() --- but we continue to hold the ShareLock on the heap
680 * and the exclusive lock on the index that we acquired above, until
681 * end of transaction.
683 if (IsBootstrapProcessingMode())
685 index_register(heapRelationId, indexoid, indexInfo);
686 /* XXX shouldn't we close the heap and index rels here? */
689 index_build(heapRelation, indexRelation, indexInfo);
694 /* ----------------------------------------------------------------
698 * ----------------------------------------------------------------
701 index_drop(Oid indexId)
704 Relation userHeapRelation;
705 Relation userIndexRelation;
706 Relation indexRelation;
707 Relation relationRelation;
708 Relation attributeRelation;
713 Assert(OidIsValid(indexId));
716 * To drop an index safely, we must grab exclusive lock on its parent
717 * table; otherwise there could be other backends using the index!
718 * Exclusive lock on the index alone is insufficient because another
719 * backend might be in the midst of devising a query plan that will
720 * use the index. The parser and planner take care to hold an
721 * appropriate lock on the parent table while working, but having them
722 * hold locks on all the indexes too seems overly complex. We do grab
723 * exclusive lock on the index too, just to be safe. Both locks must
724 * be held till end of transaction, else other backends will still see
725 * this index in pg_index.
727 heapId = IndexGetRelation(indexId);
728 userHeapRelation = heap_open(heapId, AccessExclusiveLock);
730 userIndexRelation = index_open(indexId);
731 LockRelation(userIndexRelation, AccessExclusiveLock);
734 * Note: unlike heap_drop_with_catalog, we do not need to prevent
735 * deletion of system indexes here; that's checked for upstream. If we
736 * did check it here, deletion of TOAST tables would fail...
740 * fix DESCRIPTION relation
742 DeleteComments(indexId, RelOid_pg_class);
745 * fix RELATION relation
747 relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
749 /* Remove the pg_class tuple for the index itself */
750 tuple = SearchSysCacheCopy(RELOID,
751 ObjectIdGetDatum(indexId),
753 if (!HeapTupleIsValid(tuple))
754 elog(ERROR, "index_drop: cache lookup failed for index %u",
757 simple_heap_delete(relationRelation, &tuple->t_self);
758 heap_freetuple(tuple);
760 heap_close(relationRelation, RowExclusiveLock);
763 * fix ATTRIBUTE relation
765 attributeRelation = heap_openr(AttributeRelationName, RowExclusiveLock);
767 attnum = 1; /* indexes start at 1 */
769 while (HeapTupleIsValid(tuple = SearchSysCacheCopy(ATTNUM,
770 ObjectIdGetDatum(indexId),
771 Int16GetDatum(attnum),
774 simple_heap_delete(attributeRelation, &tuple->t_self);
775 heap_freetuple(tuple);
778 heap_close(attributeRelation, RowExclusiveLock);
783 indexRelation = heap_openr(IndexRelationName, RowExclusiveLock);
785 tuple = SearchSysCacheCopy(INDEXRELID,
786 ObjectIdGetDatum(indexId),
788 if (!HeapTupleIsValid(tuple))
789 elog(ERROR, "index_drop: cache lookup failed for index %u",
792 simple_heap_delete(indexRelation, &tuple->t_self);
793 heap_freetuple(tuple);
794 heap_close(indexRelation, RowExclusiveLock);
797 * flush buffer cache and physically remove the file
799 i = FlushRelationBuffers(userIndexRelation, (BlockNumber) 0);
801 elog(ERROR, "index_drop: FlushRelationBuffers returned %d", i);
803 smgrunlink(DEFAULT_SMGR, userIndexRelation);
806 * We are presently too lazy to attempt to compute the new correct value
807 * of relhasindex (the next VACUUM will fix it if necessary). So there is
808 * no need to update the pg_class tuple for the owning relation.
809 * But we must send out a shared-cache-inval notice on the owning relation
810 * to ensure other backends update their relcache lists of indexes.
812 CacheInvalidateRelcache(heapId);
815 * Close rels, but keep locks
817 index_close(userIndexRelation);
818 heap_close(userHeapRelation, NoLock);
820 RelationForgetRelation(indexId);
823 /* ----------------------------------------------------------------
824 * index_build support
825 * ----------------------------------------------------------------
830 * Construct an IndexInfo record given the index's pg_index tuple
832 * IndexInfo stores the information about the index that's needed by
833 * FormIndexDatum, which is used for both index_build() and later insertion
834 * of individual index tuples. Normally we build an IndexInfo for an index
835 * just once per command, and then use it for (potentially) many tuples.
839 BuildIndexInfo(Form_pg_index indexStruct)
841 IndexInfo *ii = makeNode(IndexInfo);
846 * count the number of keys, and copy them into the IndexInfo
849 for (i = 0; i < INDEX_MAX_KEYS &&
850 indexStruct->indkey[i] != InvalidAttrNumber; i++)
852 ii->ii_KeyAttrNumbers[i] = indexStruct->indkey[i];
855 ii->ii_NumKeyAttrs = numKeys;
858 * Handle functional index.
860 * If we have a functional index then the number of attributes defined in
861 * the index must be 1 (the function's single return value). Otherwise
862 * it's same as number of keys.
864 ii->ii_FuncOid = indexStruct->indproc;
866 if (OidIsValid(indexStruct->indproc))
868 ii->ii_NumIndexAttrs = 1;
869 /* Do a lookup on the function, too */
870 fmgr_info(indexStruct->indproc, &ii->ii_FuncInfo);
873 ii->ii_NumIndexAttrs = numKeys;
876 * If partial index, convert predicate into expression nodetree
878 if (VARSIZE(&indexStruct->indpred) > VARHDRSZ)
882 predString = DatumGetCString(DirectFunctionCall1(textout,
883 PointerGetDatum(&indexStruct->indpred)));
884 ii->ii_Predicate = stringToNode(predString);
888 ii->ii_Predicate = NIL;
891 ii->ii_Unique = indexStruct->indisunique;
898 * Construct Datum[] and nullv[] arrays for a new index tuple.
900 * indexInfo Info about the index
901 * heapTuple Heap tuple for which we must prepare an index entry
902 * heapDescriptor tupledesc for heap tuple
903 * resultCxt Temporary memory context for any palloc'd datums created
904 * datum Array of index Datums (output area)
905 * nullv Array of is-null indicators (output area)
907 * For largely historical reasons, we don't actually call index_formtuple()
908 * here, we just prepare its input arrays datum[] and nullv[].
912 FormIndexDatum(IndexInfo *indexInfo,
914 TupleDesc heapDescriptor,
915 MemoryContext resultCxt,
919 MemoryContext oldContext;
924 oldContext = MemoryContextSwitchTo(resultCxt);
926 if (OidIsValid(indexInfo->ii_FuncOid))
929 * Functional index --- compute the single index attribute
931 FunctionCallInfoData fcinfo;
932 bool anynull = false;
934 MemSet(&fcinfo, 0, sizeof(fcinfo));
935 fcinfo.flinfo = &indexInfo->ii_FuncInfo;
936 fcinfo.nargs = indexInfo->ii_NumKeyAttrs;
938 for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
940 fcinfo.arg[i] = heap_getattr(heapTuple,
941 indexInfo->ii_KeyAttrNumbers[i],
944 anynull |= fcinfo.argnull[i];
946 if (indexInfo->ii_FuncInfo.fn_strict && anynull)
948 /* force a null result for strict function */
954 iDatum = FunctionCallInvoke(&fcinfo);
955 isNull = fcinfo.isnull;
958 nullv[0] = (isNull) ? 'n' : ' ';
963 * Plain index --- for each attribute we need from the heap tuple,
964 * get the attribute and stick it into the datum and nullv arrays.
966 for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
968 iDatum = heap_getattr(heapTuple,
969 indexInfo->ii_KeyAttrNumbers[i],
973 nullv[i] = (isNull) ? 'n' : ' ';
977 MemoryContextSwitchTo(oldContext);
981 /* --------------------------------------------
982 * Lock class info for update
983 * --------------------------------------------
986 LockClassinfoForUpdate(Oid relid, HeapTuple rtup,
987 Buffer *buffer, bool confirmCommitted)
989 HeapTuple classTuple;
991 Relation relationRelation;
994 * NOTE: get and hold RowExclusiveLock on pg_class, because caller
995 * will probably modify the rel's pg_class tuple later on.
997 relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
998 classTuple = SearchSysCache(RELOID, PointerGetDatum(relid),
1000 if (!HeapTupleIsValid(classTuple))
1002 heap_close(relationRelation, NoLock);
1005 rtup->t_self = classTuple->t_self;
1006 ReleaseSysCache(classTuple);
1010 ItemPointerData tidsave;
1012 ItemPointerCopy(&(rtup->t_self), &tidsave);
1013 test = heap_mark4update(relationRelation, rtup, buffer,
1014 GetCurrentCommandId());
1017 case HeapTupleSelfUpdated:
1018 case HeapTupleMayBeUpdated:
1020 case HeapTupleUpdated:
1021 ReleaseBuffer(*buffer);
1022 if (!ItemPointerEquals(&(rtup->t_self), &tidsave))
1025 elog(ERROR, "LockClassinfoForUpdate couldn't lock relid %u", relid);
1030 CacheInvalidateHeapTuple(relationRelation, rtup);
1031 if (confirmCommitted)
1033 HeapTupleHeader th = rtup->t_data;
1035 if (!(th->t_infomask & HEAP_XMIN_COMMITTED))
1036 elog(ERROR, "The tuple isn't committed");
1037 if (th->t_infomask & HEAP_XMAX_COMMITTED)
1038 if (!(th->t_infomask & HEAP_MARKED_FOR_UPDATE))
1039 elog(ERROR, "The tuple is already deleted");
1041 heap_close(relationRelation, NoLock);
1045 /* ---------------------------------------------
1046 * Indexes of the relation active ?
1047 * ---------------------------------------------
1050 IndexesAreActive(Oid relid, bool confirmCommitted)
1052 HeapTupleData tuple;
1053 Relation indexRelation;
1059 if (!LockClassinfoForUpdate(relid, &tuple, &buffer, confirmCommitted))
1060 elog(ERROR, "IndexesAreActive couldn't lock %u", relid);
1061 if (((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_RELATION &&
1062 ((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_TOASTVALUE)
1063 elog(ERROR, "relation %u isn't an indexable relation", relid);
1064 isactive = ((Form_pg_class) GETSTRUCT(&tuple))->relhasindex;
1065 ReleaseBuffer(buffer);
1068 indexRelation = heap_openr(IndexRelationName, AccessShareLock);
1069 ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid,
1070 F_OIDEQ, ObjectIdGetDatum(relid));
1071 scan = heap_beginscan(indexRelation, SnapshotNow, 1, &entry);
1072 if (heap_getnext(scan, ForwardScanDirection) == NULL)
1073 isactive = true; /* no indexes, so report "active" */
1075 heap_close(indexRelation, AccessShareLock);
1080 * set relhasindex of relation's pg_class entry
1082 * If isprimary is TRUE, we are defining a primary index, so also set
1083 * relhaspkey to TRUE. Otherwise, leave relhaspkey alone.
1085 * If reltoastidxid is not InvalidOid, also set reltoastidxid to that value.
1086 * This is only used for TOAST relations.
1088 * NOTE: an important side-effect of this operation is that an SI invalidation
1089 * message is sent out to all backends --- including me --- causing relcache
1090 * entries to be flushed or updated with the new hasindex data. This must
1091 * happen even if we find that no change is needed in the pg_class row.
1095 setRelhasindex(Oid relid, bool hasindex, bool isprimary, Oid reltoastidxid)
1099 Form_pg_class classtuple;
1101 HeapScanDesc pg_class_scan = NULL;
1104 * Find the tuple to update in pg_class.
1106 pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
1108 if (!IsIgnoringSystemIndexes() &&
1109 (!IsReindexProcessing() || pg_class->rd_rel->relhasindex))
1111 tuple = SearchSysCacheCopy(RELOID,
1112 ObjectIdGetDatum(relid),
1119 ScanKeyEntryInitialize(&key[0], 0,
1120 ObjectIdAttributeNumber,
1122 ObjectIdGetDatum(relid));
1124 pg_class_scan = heap_beginscan(pg_class, SnapshotNow, 1, key);
1125 tuple = heap_getnext(pg_class_scan, ForwardScanDirection);
1128 if (!HeapTupleIsValid(tuple))
1131 heap_endscan(pg_class_scan);
1132 heap_close(pg_class, RowExclusiveLock);
1133 elog(ERROR, "setRelhasindex: cannot find relation %u in pg_class",
1138 * Update fields in the pg_class tuple.
1141 LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
1143 classtuple = (Form_pg_class) GETSTRUCT(tuple);
1145 if (classtuple->relhasindex != hasindex)
1147 classtuple->relhasindex = hasindex;
1152 if (!classtuple->relhaspkey)
1154 classtuple->relhaspkey = true;
1158 if (OidIsValid(reltoastidxid))
1160 Assert(classtuple->relkind == RELKIND_TOASTVALUE);
1161 if (classtuple->reltoastidxid != reltoastidxid)
1163 classtuple->reltoastidxid = reltoastidxid;
1169 LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
1173 /* Write the modified tuple in-place */
1174 WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
1175 /* Send out shared cache inval if necessary */
1176 if (!IsBootstrapProcessingMode())
1177 CacheInvalidateHeapTuple(pg_class, tuple);
1182 simple_heap_update(pg_class, &tuple->t_self, tuple);
1184 /* Keep the catalog indices up to date */
1185 if (!IsIgnoringSystemIndexes())
1187 Relation idescs[Num_pg_class_indices];
1189 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
1191 CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, tuple);
1192 CatalogCloseIndices(Num_pg_class_indices, idescs);
1197 /* no need to change tuple, but force relcache rebuild anyway */
1198 CacheInvalidateRelcache(relid);
1202 heap_freetuple(tuple);
1204 heap_endscan(pg_class_scan);
1206 heap_close(pg_class, RowExclusiveLock);
1210 setNewRelfilenode(Relation relation)
1213 idescs[Num_pg_class_indices];
1215 bool in_place_update = false;
1216 HeapTupleData lockTupleData;
1217 HeapTuple classTuple = NULL;
1219 RelationData workrel;
1221 Assert(!IsSystemRelation(relation) || relation->rd_rel->relkind == RELKIND_INDEX);
1223 pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
1224 /* Fetch and lock the classTuple associated with this relation */
1225 if (!LockClassinfoForUpdate(relation->rd_id, &lockTupleData, &buffer, true))
1226 elog(ERROR, "setNewRelfilenode impossible to lock class tuple");
1227 if (IsIgnoringSystemIndexes())
1228 in_place_update = true;
1229 /* Allocate a new relfilenode */
1230 newrelfilenode = newoid();
1231 /* update pg_class tuple with new relfilenode */
1232 if (!in_place_update)
1234 classTuple = heap_copytuple(&lockTupleData);
1235 ReleaseBuffer(buffer);
1236 ((Form_pg_class) GETSTRUCT(classTuple))->relfilenode = newrelfilenode;
1237 simple_heap_update(pg_class, &classTuple->t_self, classTuple);
1239 /* schedule unlinking old relfilenode */
1240 smgrunlink(DEFAULT_SMGR, relation);
1241 /* create another storage file. Is it a little ugly ? */
1242 memcpy((char *) &workrel, relation, sizeof(RelationData));
1243 workrel.rd_node.relNode = newrelfilenode;
1244 heap_storage_create(&workrel);
1245 smgrclose(DEFAULT_SMGR, &workrel);
1246 /* update pg_class tuple with new relfilenode in place */
1247 if (in_place_update)
1249 classTuple = &lockTupleData;
1250 /* Send out shared cache inval if necessary */
1251 if (!IsBootstrapProcessingMode())
1252 CacheInvalidateHeapTuple(pg_class, classTuple);
1253 /* Update the buffer in-place */
1254 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
1255 ((Form_pg_class) GETSTRUCT(classTuple))->relfilenode = newrelfilenode;
1256 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
1257 WriteBuffer(buffer);
1260 /* Keep the catalog indices up to date */
1261 if (!in_place_update && pg_class->rd_rel->relhasindex)
1263 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
1265 CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, classTuple);
1266 CatalogCloseIndices(Num_pg_class_indices, idescs);
1268 heap_close(pg_class, NoLock);
1269 if (!in_place_update)
1270 heap_freetuple(classTuple);
1271 /* Make sure the relfilenode change */
1272 CommandCounterIncrement();
1279 * Update pg_class' relpages and reltuples statistics for the given relation
1280 * (which can be either a table or an index). Note that this is not used
1281 * in the context of VACUUM.
1285 UpdateStats(Oid relid, double reltuples)
1291 BlockNumber relpages;
1293 Form_pg_class rd_rel;
1294 Relation idescs[Num_pg_class_indices];
1295 Datum values[Natts_pg_class];
1296 char nulls[Natts_pg_class];
1297 char replace[Natts_pg_class];
1298 HeapScanDesc pg_class_scan = NULL;
1302 * This routine handles updates for both the heap and index relation
1303 * statistics. In order to guarantee that we're able to *see* the
1304 * index relation tuple, we bump the command counter id here. The
1305 * index relation tuple was created in the current transaction.
1307 CommandCounterIncrement();
1310 * CommandCounterIncrement() flushes invalid cache entries, including
1311 * those for the heap and index relations for which we're updating
1312 * statistics. Now that the cache is flushed, it's safe to open the
1313 * relation again. We need the relation open in order to figure out
1314 * how many blocks it contains.
1318 * Grabbing lock here is probably redundant ...
1320 whichRel = relation_open(relid, ShareLock);
1323 * Find the RELATION relation tuple for the given relation.
1325 pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
1327 in_place_upd = (IsIgnoringSystemIndexes() || IsReindexProcessing());
1331 tuple = SearchSysCacheCopy(RELOID,
1332 ObjectIdGetDatum(relid),
1339 ScanKeyEntryInitialize(&key[0], 0,
1340 ObjectIdAttributeNumber,
1342 ObjectIdGetDatum(relid));
1344 pg_class_scan = heap_beginscan(pg_class, SnapshotNow, 1, key);
1345 tuple = heap_getnext(pg_class_scan, ForwardScanDirection);
1348 if (!HeapTupleIsValid(tuple))
1351 heap_endscan(pg_class_scan);
1352 heap_close(pg_class, RowExclusiveLock);
1353 elog(ERROR, "UpdateStats: cannot find relation %u in pg_class",
1358 * Figure values to insert.
1360 * If we found zero tuples in the scan, do NOT believe it; instead put a
1361 * bogus estimate into the statistics fields. Otherwise, the common
1362 * pattern "CREATE TABLE; CREATE INDEX; insert data" leaves the table
1363 * with zero size statistics until a VACUUM is done. The optimizer
1364 * will generate very bad plans if the stats claim the table is empty
1365 * when it is actually sizable. See also CREATE TABLE in heap.c.
1367 * Note: this path is also taken during bootstrap, because bootstrap.c
1368 * passes reltuples = 0 after loading a table. We have to estimate
1369 * some number for reltuples based on the actual number of pages.
1371 relpages = RelationGetNumberOfBlocks(whichRel);
1377 /* Bogus defaults for a virgin table, same as heap.c */
1381 else if (whichRel->rd_rel->relkind == RELKIND_INDEX && relpages <= 2)
1383 /* Empty index, leave bogus defaults in place */
1387 reltuples = ((double) relpages) * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
1391 * We shouldn't have to do this, but we do... Modify the reldesc in
1392 * place with the new values so that the cache contains the latest
1395 whichRel->rd_rel->relpages = (int32) relpages;
1396 whichRel->rd_rel->reltuples = reltuples;
1399 * Update statistics in pg_class.
1404 * At bootstrap time, we don't need to worry about concurrency or
1405 * visibility of changes, so we cheat. Also cheat if REINDEX.
1407 rd_rel = (Form_pg_class) GETSTRUCT(tuple);
1408 LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
1409 rd_rel->relpages = (int32) relpages;
1410 rd_rel->reltuples = reltuples;
1411 LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
1412 WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
1413 if (!IsBootstrapProcessingMode())
1414 CacheInvalidateHeapTuple(pg_class, tuple);
1418 /* During normal processing, must work harder. */
1420 for (i = 0; i < Natts_pg_class; i++)
1424 values[i] = (Datum) NULL;
1427 replace[Anum_pg_class_relpages - 1] = 'r';
1428 values[Anum_pg_class_relpages - 1] = Int32GetDatum((int32) relpages);
1429 replace[Anum_pg_class_reltuples - 1] = 'r';
1430 values[Anum_pg_class_reltuples - 1] = Float4GetDatum((float4) reltuples);
1431 newtup = heap_modifytuple(tuple, pg_class, values, nulls, replace);
1432 simple_heap_update(pg_class, &tuple->t_self, newtup);
1433 if (!IsIgnoringSystemIndexes())
1435 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
1436 CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, newtup);
1437 CatalogCloseIndices(Num_pg_class_indices, idescs);
1439 heap_freetuple(newtup);
1443 heap_freetuple(tuple);
1445 heap_endscan(pg_class_scan);
1447 heap_close(pg_class, RowExclusiveLock);
1448 relation_close(whichRel, NoLock);
1453 * index_build - invoke access-method-specific index build procedure
1456 index_build(Relation heapRelation,
1457 Relation indexRelation,
1458 IndexInfo *indexInfo)
1460 RegProcedure procedure;
1465 Assert(RelationIsValid(indexRelation));
1466 Assert(PointerIsValid(indexRelation->rd_am));
1468 procedure = indexRelation->rd_am->ambuild;
1469 Assert(RegProcedureIsValid(procedure));
1472 * Call the access method's build procedure
1474 OidFunctionCall3(procedure,
1475 PointerGetDatum(heapRelation),
1476 PointerGetDatum(indexRelation),
1477 PointerGetDatum(indexInfo));
1482 * IndexBuildHeapScan - scan the heap relation to find tuples to be indexed
1484 * This is called back from an access-method-specific index build procedure
1485 * after the AM has done whatever setup it needs. The parent heap relation
1486 * is scanned to find tuples that should be entered into the index. Each
1487 * such tuple is passed to the AM's callback routine, which does the right
1488 * things to add it to the new index. After we return, the AM's index
1489 * build procedure does whatever cleanup is needed; in particular, it should
1490 * close the heap and index relations.
1492 * The total count of heap tuples is returned. This is for updating pg_class
1493 * statistics. (It's annoying not to be able to do that here, but we can't
1494 * do it until after the relation is closed.) Note that the index AM itself
1495 * must keep track of the number of index tuples; we don't do so here because
1496 * the AM might reject some of the tuples for its own reasons, such as being
1497 * unable to store NULLs.
1500 IndexBuildHeapScan(Relation heapRelation,
1501 Relation indexRelation,
1502 IndexInfo *indexInfo,
1503 IndexBuildCallback callback,
1504 void *callback_state)
1507 HeapTuple heapTuple;
1508 TupleDesc heapDescriptor;
1509 Datum attdata[INDEX_MAX_KEYS];
1510 char nulls[INDEX_MAX_KEYS];
1512 List *predicate = indexInfo->ii_Predicate;
1513 TupleTable tupleTable;
1514 TupleTableSlot *slot;
1515 ExprContext *econtext;
1517 TransactionId OldestXmin;
1522 Assert(OidIsValid(indexRelation->rd_rel->relam));
1524 heapDescriptor = RelationGetDescr(heapRelation);
1527 * If this is a predicate (partial) index, we will need to evaluate
1528 * the predicate using ExecQual, which requires the current tuple to
1529 * be in a slot of a TupleTable. In addition, ExecQual must have an
1530 * ExprContext referring to that slot. Here, we initialize dummy
1531 * TupleTable and ExprContext objects for this purpose. --Nels, Feb 92
1533 * We construct the ExprContext anyway since we need a per-tuple
1534 * temporary memory context for function evaluation -- tgl July 00
1536 if (predicate != NIL)
1538 tupleTable = ExecCreateTupleTable(1);
1539 slot = ExecAllocTableSlot(tupleTable);
1540 ExecSetSlotDescriptor(slot, heapDescriptor, false);
1547 econtext = MakeExprContext(slot, TransactionCommandContext);
1550 * Ok, begin our scan of the base relation. We use SnapshotAny
1551 * because we must retrieve all tuples and do our own time qual
1554 if (IsBootstrapProcessingMode())
1556 snapshot = SnapshotNow;
1557 OldestXmin = InvalidTransactionId;
1561 snapshot = SnapshotAny;
1562 OldestXmin = GetOldestXmin(heapRelation->rd_rel->relisshared);
1565 scan = heap_beginscan(heapRelation, /* relation */
1566 snapshot, /* seeself */
1567 0, /* number of keys */
1568 (ScanKey) NULL); /* scan key */
1573 * Scan all tuples in the base relation.
1575 while ((heapTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1579 CHECK_FOR_INTERRUPTS();
1581 if (snapshot == SnapshotAny)
1583 /* do our own time qual check */
1588 * HeapTupleSatisfiesVacuum may update tuple's hint status
1589 * bits. We could possibly get away with not locking the
1590 * buffer here, since caller should hold ShareLock on the
1591 * relation, but let's be conservative about it.
1593 LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
1594 sv_infomask = heapTuple->t_data->t_infomask;
1596 switch (HeapTupleSatisfiesVacuum(heapTuple->t_data, OldestXmin))
1598 case HEAPTUPLE_DEAD:
1600 tupleIsAlive = false;
1602 case HEAPTUPLE_LIVE:
1604 tupleIsAlive = true;
1606 case HEAPTUPLE_RECENTLY_DEAD:
1609 * If tuple is recently deleted then we must index it
1610 * anyway to keep VACUUM from complaining.
1613 tupleIsAlive = false;
1615 case HEAPTUPLE_INSERT_IN_PROGRESS:
1618 * Since caller should hold ShareLock or better, we
1619 * should not see any tuples inserted by open
1620 * transactions --- unless it's our own transaction.
1621 * (Consider INSERT followed by CREATE INDEX within a
1624 if (!TransactionIdIsCurrentTransactionId(
1625 HeapTupleHeaderGetXmin(heapTuple->t_data)))
1626 elog(ERROR, "IndexBuildHeapScan: concurrent insert in progress");
1628 tupleIsAlive = true;
1630 case HEAPTUPLE_DELETE_IN_PROGRESS:
1633 * Since caller should hold ShareLock or better, we
1634 * should not see any tuples deleted by open
1635 * transactions --- unless it's our own transaction.
1636 * (Consider DELETE followed by CREATE INDEX within a
1639 if (!TransactionIdIsCurrentTransactionId(
1640 HeapTupleHeaderGetXmax(heapTuple->t_data)))
1641 elog(ERROR, "IndexBuildHeapScan: concurrent delete in progress");
1643 tupleIsAlive = false;
1646 elog(ERROR, "Unexpected HeapTupleSatisfiesVacuum result");
1647 indexIt = tupleIsAlive = false; /* keep compiler quiet */
1651 /* check for hint-bit update by HeapTupleSatisfiesVacuum */
1652 if (sv_infomask != heapTuple->t_data->t_infomask)
1653 SetBufferCommitInfoNeedsSave(scan->rs_cbuf);
1655 LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
1662 /* heap_getnext did the time qual check */
1663 tupleIsAlive = true;
1668 MemoryContextReset(econtext->ecxt_per_tuple_memory);
1671 * In a partial index, discard tuples that don't satisfy the
1672 * predicate. We can also discard recently-dead tuples, since
1673 * VACUUM doesn't complain about tuple count mismatch for partial
1676 if (predicate != NIL)
1680 ExecStoreTuple(heapTuple, slot, InvalidBuffer, false);
1681 if (!ExecQual(predicate, econtext, false))
1686 * For the current heap tuple, extract all the attributes we use
1687 * in this index, and note which are null. This also performs
1688 * evaluation of the function, if this is a functional index.
1690 FormIndexDatum(indexInfo,
1693 econtext->ecxt_per_tuple_memory,
1698 * You'd think we should go ahead and build the index tuple here,
1699 * but some index AMs want to do further processing on the data
1700 * first. So pass the attdata and nulls arrays, instead.
1703 /* Call the AM's callback routine to process the tuple */
1704 callback(indexRelation, heapTuple, attdata, nulls, tupleIsAlive,
1710 if (predicate != NIL)
1711 ExecDropTupleTable(tupleTable, true);
1712 FreeExprContext(econtext);
1719 * IndexGetRelation: given an index's relation OID, get the OID of the
1720 * relation it is an index on. Uses the system cache.
1723 IndexGetRelation(Oid indexId)
1726 Form_pg_index index;
1729 tuple = SearchSysCache(INDEXRELID,
1730 ObjectIdGetDatum(indexId),
1732 if (!HeapTupleIsValid(tuple))
1733 elog(ERROR, "IndexGetRelation: can't find index id %u",
1735 index = (Form_pg_index) GETSTRUCT(tuple);
1736 Assert(index->indexrelid == indexId);
1738 result = index->indrelid;
1739 ReleaseSysCache(tuple);
1743 /* ---------------------------------
1744 * activate_index -- activate/deactivate the specified index.
1745 * Note that currently PostgreSQL doesn't hold the
1747 * ---------------------------------
1750 activate_index(Oid indexId, bool activate, bool inplace)
1752 if (!activate) /* Currently does nothing */
1754 return reindex_index(indexId, false, inplace);
1757 /* --------------------------------
1758 * reindex_index - This routine is used to recreate an index
1759 * --------------------------------
1762 reindex_index(Oid indexId, bool force, bool inplace)
1766 IndexInfo *indexInfo;
1771 * REINDEX within a transaction block is dangerous, because if the
1772 * transaction is later rolled back we have no way to undo truncation
1773 * of the index's physical file. Disallow it.
1775 * XXX if we're not doing an inplace rebuild, wouldn't this be okay?
1777 if (IsTransactionBlock())
1778 elog(ERROR, "REINDEX cannot run inside a transaction block");
1781 * Open our index relation and get an exclusive lock on it.
1783 * Note: doing this before opening the parent heap relation means
1784 * there's a possibility for deadlock failure against another xact
1785 * that is doing normal accesses to the heap and index. However,
1786 * it's not real clear why you'd be needing to do REINDEX on a table
1787 * that's in active use, so I'd rather have the protection of making
1788 * sure the index is locked down.
1790 iRel = index_open(indexId);
1792 elog(ERROR, "reindex_index: can't open index relation");
1793 LockRelation(iRel, AccessExclusiveLock);
1795 old = SetReindexProcessing(true);
1797 /* Get OID of index's parent table */
1798 heapId = iRel->rd_index->indrelid;
1799 /* Fetch info needed for index_build */
1800 indexInfo = BuildIndexInfo(iRel->rd_index);
1802 /* Open the parent heap relation */
1803 heapRelation = heap_open(heapId, ExclusiveLock);
1804 if (heapRelation == NULL)
1805 elog(ERROR, "reindex_index: can't open heap relation");
1808 * Force inplace processing if it's a shared index. Necessary because
1809 * we have no way to update relfilenode in other databases.
1811 if (iRel->rd_rel->relisshared)
1817 * Release any buffers associated with this index. If they're
1818 * dirty, they're just dropped without bothering to flush to disk.
1820 DropRelationBuffers(iRel);
1822 /* Now truncate the actual data and set blocks to zero */
1823 smgrtruncate(DEFAULT_SMGR, iRel, 0);
1824 iRel->rd_nblocks = 0;
1825 iRel->rd_targblock = InvalidBlockNumber;
1830 * We'll build a new physical relation for the index.
1832 setNewRelfilenode(iRel);
1835 /* Initialize the index and rebuild */
1836 index_build(heapRelation, iRel, indexInfo);
1839 * index_build will close both the heap and index relations (but not
1840 * give up the locks we hold on them). So we're done.
1843 SetReindexProcessing(old);
1849 * ----------------------------
1850 * activate_indexes_of_a_table
1851 * activate/deactivate indexes of the specified table.
1852 * ----------------------------
1855 activate_indexes_of_a_table(Oid relid, bool activate)
1857 if (IndexesAreActive(relid, true))
1860 setRelhasindex(relid, false, false, InvalidOid);
1867 reindex_relation(relid, false);
1874 /* --------------------------------
1875 * reindex_relation - This routine is used to recreate indexes
1877 * --------------------------------
1880 reindex_relation(Oid relid, bool force)
1882 Relation indexRelation;
1885 HeapTuple indexTuple;
1888 bool deactivate_needed,
1890 upd_pg_class_inplace;
1893 overwrite = upd_pg_class_inplace = deactivate_needed = false;
1896 * avoid heap_update() pg_class tuples while processing reindex for
1899 if (IsIgnoringSystemIndexes())
1900 upd_pg_class_inplace = true;
1903 * Ensure to hold an exclusive lock throughout the transaction. The
1904 * lock could be less intensive but now it's AccessExclusiveLock for
1907 rel = heap_open(relid, AccessExclusiveLock);
1910 * ignore the indexes of the target system relation while processing
1913 if (!IsIgnoringSystemIndexes() && IsSystemRelation(rel))
1914 deactivate_needed = true;
1915 #ifndef ENABLE_REINDEX_NAILED_RELATIONS
1918 * nailed relations are never updated. We couldn't keep the
1919 * consistency between the relation descriptors and pg_class tuples.
1921 if (rel->rd_isnailed)
1923 if (IsIgnoringSystemIndexes())
1926 deactivate_needed = true;
1929 elog(ERROR, "the target relation %u is nailed", relid);
1931 #endif /* ENABLE_REINDEX_NAILED_RELATIONS */
1934 * Shared system indexes must be overwritten because it's impossible
1935 * to update pg_class tuples of all databases.
1937 if (rel->rd_rel->relisshared)
1939 if (IsIgnoringSystemIndexes())
1942 deactivate_needed = true;
1945 elog(ERROR, "the target relation %u is shared", relid);
1949 * Continue to hold the lock.
1951 heap_close(rel, NoLock);
1953 old = SetReindexProcessing(true);
1954 if (deactivate_needed)
1956 if (IndexesAreActive(relid, upd_pg_class_inplace))
1960 SetReindexProcessing(old);
1963 activate_indexes_of_a_table(relid, false);
1964 CommandCounterIncrement();
1968 indexRelation = heap_openr(IndexRelationName, AccessShareLock);
1969 ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid,
1970 F_OIDEQ, ObjectIdGetDatum(relid));
1971 scan = heap_beginscan(indexRelation, SnapshotNow, 1, &entry);
1973 while ((indexTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1975 Form_pg_index index = (Form_pg_index) GETSTRUCT(indexTuple);
1977 if (activate_index(index->indexrelid, true, overwrite))
1986 heap_close(indexRelation, AccessShareLock);
1990 * Ok,we could use the reindexed indexes of the target system
1993 if (deactivate_needed)
1995 if (!overwrite && relid == RelOid_pg_class)
1998 * For pg_class, relhasindex should be set to true here in
2001 setRelhasindex(relid, true, false, InvalidOid);
2002 CommandCounterIncrement();
2005 * However the following setRelhasindex() is needed to
2006 * keep consistency with WAL.
2009 setRelhasindex(relid, true, false, InvalidOid);
2012 SetReindexProcessing(old);