1 /*-------------------------------------------------------------------------
4 * code to create and destroy POSTGRES index relations
6 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.131 2000/12/08 06:17:57 inoue 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 *-------------------------------------------------------------------------
25 #include "access/genam.h"
26 #include "access/heapam.h"
27 #include "access/istrat.h"
28 #include "bootstrap/bootstrap.h"
29 #include "catalog/catalog.h"
30 #include "catalog/catname.h"
31 #include "catalog/heap.h"
32 #include "catalog/index.h"
33 #include "catalog/indexing.h"
34 #include "catalog/pg_index.h"
35 #include "catalog/pg_proc.h"
36 #include "catalog/pg_type.h"
37 #include "commands/comment.h"
38 #include "executor/executor.h"
39 #include "miscadmin.h"
40 #include "optimizer/clauses.h"
41 #include "optimizer/prep.h"
42 #include "parser/parse_func.h"
43 #include "storage/smgr.h"
44 #include "utils/builtins.h"
45 #include "utils/catcache.h"
46 #include "utils/fmgroids.h"
47 #include "utils/inval.h"
48 #include "utils/relcache.h"
49 #include "utils/syscache.h"
50 #include "utils/temprel.h"
53 * macros used in guessing how many tuples are on a page.
55 #define AVG_ATTR_SIZE 8
56 #define NTUPLES_PER_PAGE(natts) \
57 ((BLCKSZ - MAXALIGN(sizeof (PageHeaderData))) / \
58 ((natts) * AVG_ATTR_SIZE + MAXALIGN(sizeof(HeapTupleHeaderData))))
60 /* non-export function prototypes */
61 static Oid GetHeapRelationOid(char *heapRelationName, char *indexRelationName,
63 static TupleDesc BuildFuncTupleDesc(Oid funcOid);
64 static TupleDesc ConstructTupleDescriptor(Oid heapoid, Relation heapRelation,
65 int numatts, AttrNumber *attNums);
66 static void ConstructIndexReldesc(Relation indexRelation, Oid amoid);
67 static Oid UpdateRelationRelation(Relation indexRelation, char *temp_relname);
68 static void InitializeAttributeOids(Relation indexRelation,
69 int numatts, Oid indexoid);
70 static void AppendAttributeTuples(Relation indexRelation, int numatts);
71 static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
74 bool islossy, bool primary);
75 static void DefaultBuild(Relation heapRelation, Relation indexRelation,
76 IndexInfo *indexInfo, Node *oldPred,
77 IndexStrategy indexStrategy);
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)
100 /* ----------------------------------------------------------------
101 * sysatts is a structure containing attribute tuple forms
102 * for system attributes (numbered -1, -2, ...). This really
103 * should be generated or eliminated or moved elsewhere. -cim 1/19/91
105 * typedef struct FormData_pg_attribute {
120 * } FormData_pg_attribute;
122 * ----------------------------------------------------------------
124 static FormData_pg_attribute sysatts[] = {
125 {0, {"ctid"}, TIDOID, 0, 6, -1, 0, -1, -1, '\0', 'p', '\0', 'i', '\0', '\0'},
126 {0, {"oid"}, OIDOID, 0, 4, -2, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
127 {0, {"xmin"}, XIDOID, 0, 4, -3, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
128 {0, {"cmin"}, CIDOID, 0, 4, -4, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
129 {0, {"xmax"}, XIDOID, 0, 4, -5, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
130 {0, {"cmax"}, CIDOID, 0, 4, -6, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
133 /* ----------------------------------------------------------------
135 * ----------------------------------------------------------------
138 GetHeapRelationOid(char *heapRelationName, char *indexRelationName, bool istemp)
144 indoid = RelnameFindRelid(indexRelationName);
146 if ((!istemp && OidIsValid(indoid)) ||
147 (istemp && get_temp_rel_by_username(indexRelationName) != NULL))
148 elog(ERROR, "Cannot create index: '%s' already exists",
151 heapoid = RelnameFindRelid(heapRelationName);
153 if (!OidIsValid(heapoid))
154 elog(ERROR, "Cannot create index on '%s': relation does not exist",
161 BuildFuncTupleDesc(Oid funcOid)
163 TupleDesc funcTupDesc;
168 * Allocate and zero a tuple descriptor.
170 funcTupDesc = CreateTemplateTupleDesc(1);
171 funcTupDesc->attrs[0] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
172 MemSet(funcTupDesc->attrs[0], 0, ATTRIBUTE_TUPLE_SIZE);
175 * Lookup the function to get its name and return type.
177 tuple = SearchSysCache(PROCOID,
178 ObjectIdGetDatum(funcOid),
180 if (!HeapTupleIsValid(tuple))
181 elog(ERROR, "Function %u does not exist", funcOid);
182 retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype;
185 * make the attributes name the same as the functions
187 namestrcpy(&funcTupDesc->attrs[0]->attname,
188 NameStr(((Form_pg_proc) GETSTRUCT(tuple))->proname));
190 ReleaseSysCache(tuple);
193 * Lookup the return type in pg_type for the type length etc.
195 tuple = SearchSysCache(TYPEOID,
196 ObjectIdGetDatum(retType),
198 if (!HeapTupleIsValid(tuple))
199 elog(ERROR, "Type %u does not exist", retType);
202 * Assign some of the attributes values. Leave the rest as 0.
204 funcTupDesc->attrs[0]->attlen = ((Form_pg_type) GETSTRUCT(tuple))->typlen;
205 funcTupDesc->attrs[0]->atttypid = retType;
206 funcTupDesc->attrs[0]->attnum = 1;
207 funcTupDesc->attrs[0]->attbyval = ((Form_pg_type) GETSTRUCT(tuple))->typbyval;
208 funcTupDesc->attrs[0]->attcacheoff = -1;
209 funcTupDesc->attrs[0]->atttypmod = -1;
210 funcTupDesc->attrs[0]->attstorage = 'p';
211 funcTupDesc->attrs[0]->attalign = ((Form_pg_type) GETSTRUCT(tuple))->typalign;
213 ReleaseSysCache(tuple);
218 /* ----------------------------------------------------------------
219 * ConstructTupleDescriptor
221 * Build an index tuple descriptor for a new index (plain not functional)
222 * ----------------------------------------------------------------
225 ConstructTupleDescriptor(Oid heapoid,
226 Relation heapRelation,
230 TupleDesc heapTupDesc;
231 TupleDesc indexTupDesc;
232 int natts; /* #atts in heap rel --- for error checks */
235 heapTupDesc = RelationGetDescr(heapRelation);
236 natts = RelationGetForm(heapRelation)->relnatts;
239 * allocate the new tuple descriptor
243 indexTupDesc = CreateTemplateTupleDesc(numatts);
246 * for each attribute we are indexing, obtain its attribute
247 * tuple form from either the static table of system attribute
248 * tuple forms or the relation tuple descriptor
251 for (i = 0; i < numatts; i++)
253 AttrNumber atnum; /* attributeNumber[attributeOffset] */
255 char *from; /* used to simplify memcpy below */
256 char *to; /* used to simplify memcpy below */
259 * get the attribute number and make sure it's valid
264 elog(ERROR, "Cannot create index: attribute %d does not exist",
267 indexTupDesc->attrs[i] =
268 (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
271 * determine which tuple descriptor to copy
274 if (!AttrNumberIsForUserDefinedAttr(atnum))
277 * here we are indexing on a system attribute (-1...-n)
278 * so we convert atnum into a usable index 0...n-1 so we can
279 * use it to dereference the array sysatts[] which stores
280 * tuple descriptor information for system attributes.
283 if (atnum <= FirstLowInvalidHeapAttributeNumber || atnum >= 0)
284 elog(ERROR, "Cannot create index on system attribute: attribute number out of range (%d)", atnum);
285 atind = (-atnum) - 1;
287 from = (char *) (&sysatts[atind]);
292 * here we are indexing on a normal attribute (1...n)
295 atind = AttrNumberGetAttrOffset(atnum);
297 from = (char *) (heapTupDesc->attrs[atind]);
301 * now that we've determined the "from", let's copy
302 * the tuple desc data...
305 to = (char *) (indexTupDesc->attrs[i]);
306 memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);
309 * Fix the stuff that should not be the same as the underlying attr
311 ((Form_pg_attribute) to)->attnum = i + 1;
313 ((Form_pg_attribute) to)->attdispersion = 0.0;
314 ((Form_pg_attribute) to)->attnotnull = false;
315 ((Form_pg_attribute) to)->atthasdef = false;
316 ((Form_pg_attribute) to)->attcacheoff = -1;
319 * now we have to drop in the proper relation descriptor
320 * into the copied tuple form's attrelid and we should be
324 ((Form_pg_attribute) to)->attrelid = heapoid;
330 /* ----------------------------------------------------------------
331 * AccessMethodObjectIdGetForm
332 * Returns an access method tuple given its object identifier,
333 * or NULL if no such AM tuple can be found.
335 * Scanning is done using CurrentMemoryContext as working storage,
336 * but the returned tuple will be allocated in resultCxt (which is
337 * typically CacheMemoryContext).
339 * There was a note here about adding indexing, but I don't see a need
340 * for it. There are so few tuples in pg_am that an indexscan would
342 * ----------------------------------------------------------------
345 AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
346 MemoryContext resultCxt)
349 HeapScanDesc pg_am_scan;
350 HeapTuple pg_am_tuple;
355 * form a scan key for the pg_am relation
358 ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
360 ObjectIdGetDatum(accessMethodObjectId));
363 * fetch the desired access method tuple
366 pg_am_desc = heap_openr(AccessMethodRelationName, AccessShareLock);
367 pg_am_scan = heap_beginscan(pg_am_desc, 0, SnapshotNow, 1, &key);
369 pg_am_tuple = heap_getnext(pg_am_scan, 0);
372 * return NULL if not found
375 if (!HeapTupleIsValid(pg_am_tuple))
377 heap_endscan(pg_am_scan);
378 heap_close(pg_am_desc, AccessShareLock);
383 * if found AM tuple, then copy it into resultCxt and return the copy
386 aform = (Form_pg_am) MemoryContextAlloc(resultCxt, sizeof *aform);
387 memcpy(aform, GETSTRUCT(pg_am_tuple), sizeof *aform);
389 heap_endscan(pg_am_scan);
390 heap_close(pg_am_desc, AccessShareLock);
395 /* ----------------------------------------------------------------
396 * ConstructIndexReldesc
397 * ----------------------------------------------------------------
400 ConstructIndexReldesc(Relation indexRelation, Oid amoid)
402 indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid,
406 * XXX missing the initialization of some other fields
410 indexRelation->rd_rel->relowner = GetUserId();
412 indexRelation->rd_rel->relam = amoid;
413 indexRelation->rd_rel->reltuples = 1; /* XXX */
414 indexRelation->rd_rel->relkind = RELKIND_INDEX;
417 /* ----------------------------------------------------------------
418 * UpdateRelationRelation
419 * ----------------------------------------------------------------
422 UpdateRelationRelation(Relation indexRelation, char *temp_relname)
427 Relation idescs[Num_pg_class_indices];
429 pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
431 /* XXX Natts_pg_class_fixed is a hack - see pg_class.h */
432 tuple = heap_addheader(Natts_pg_class_fixed,
434 (char *) indexRelation->rd_rel);
437 * the new tuple must have the same oid as the relcache entry for the
438 * index. sure would be embarrassing to do this sort of thing in
442 tuple->t_data->t_oid = RelationGetRelid(indexRelation);
443 heap_insert(pg_class, tuple);
446 create_temp_relation(temp_relname, tuple);
449 * During normal processing, we need to make sure that the system
450 * catalog indices are correct. Bootstrap (initdb) time doesn't
451 * require this, because we make sure that the indices are correct
452 * just before exiting.
455 if (!IsIgnoringSystemIndexes())
457 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
458 CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, tuple);
459 CatalogCloseIndices(Num_pg_class_indices, idescs);
462 tupleOid = tuple->t_data->t_oid;
463 heap_freetuple(tuple);
464 heap_close(pg_class, RowExclusiveLock);
469 /* ----------------------------------------------------------------
470 * InitializeAttributeOids
471 * ----------------------------------------------------------------
474 InitializeAttributeOids(Relation indexRelation,
478 TupleDesc tupleDescriptor;
481 tupleDescriptor = RelationGetDescr(indexRelation);
483 for (i = 0; i < numatts; i += 1)
484 tupleDescriptor->attrs[i]->attrelid = indexoid;
487 /* ----------------------------------------------------------------
488 * AppendAttributeTuples
490 * XXX For now, only change the ATTNUM attribute value
491 * ----------------------------------------------------------------
494 AppendAttributeTuples(Relation indexRelation, int numatts)
496 Relation pg_attribute;
497 HeapTuple init_tuple,
501 Relation idescs[Num_pg_attr_indices];
502 Datum value[Natts_pg_attribute];
503 char nullv[Natts_pg_attribute];
504 char replace[Natts_pg_attribute];
505 TupleDesc indexTupDesc;
509 * open the attribute relation
512 pg_attribute = heap_openr(AttributeRelationName, RowExclusiveLock);
515 * initialize *null, *replace and *value
518 MemSet(nullv, ' ', Natts_pg_attribute);
519 MemSet(replace, ' ', Natts_pg_attribute);
522 * create the first attribute tuple.
523 * XXX For now, only change the ATTNUM attribute value
526 replace[Anum_pg_attribute_attnum - 1] = 'r';
527 replace[Anum_pg_attribute_attcacheoff - 1] = 'r';
529 value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(1);
530 value[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1);
532 init_tuple = heap_addheader(Natts_pg_attribute,
533 ATTRIBUTE_TUPLE_SIZE,
534 (char *) (indexRelation->rd_att->attrs[0]));
537 if (!IsIgnoringSystemIndexes() && pg_attribute->rd_rel->relhasindex)
540 CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
544 * insert the first attribute tuple.
547 cur_tuple = heap_modifytuple(init_tuple,
552 heap_freetuple(init_tuple);
554 heap_insert(pg_attribute, cur_tuple);
556 CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, cur_tuple);
559 * now we use the information in the index cur_tuple
560 * descriptor to form the remaining attribute tuples.
563 indexTupDesc = RelationGetDescr(indexRelation);
565 for (i = 1; i < numatts; i += 1)
568 * process the remaining attributes...
571 memmove(GETSTRUCT(cur_tuple),
572 (char *) indexTupDesc->attrs[i],
573 ATTRIBUTE_TUPLE_SIZE);
575 value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(i + 1);
577 new_tuple = heap_modifytuple(cur_tuple,
582 heap_freetuple(cur_tuple);
584 heap_insert(pg_attribute, new_tuple);
586 CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, new_tuple);
589 * ModifyHeapTuple returns a new copy of a cur_tuple
590 * so we free the original and use the copy..
593 cur_tuple = new_tuple;
597 heap_freetuple(cur_tuple);
598 heap_close(pg_attribute, RowExclusiveLock);
600 CatalogCloseIndices(Num_pg_attr_indices, idescs);
603 /* ----------------------------------------------------------------
604 * UpdateIndexRelation
605 * ----------------------------------------------------------------
608 UpdateIndexRelation(Oid indexoid,
610 IndexInfo *indexInfo,
615 Form_pg_index indexForm;
623 Relation idescs[Num_pg_index_indices];
626 * allocate a Form_pg_index big enough to hold the
627 * index-predicate (if any) in string form
630 if (indexInfo->ii_Predicate != NULL)
632 predString = nodeToString(indexInfo->ii_Predicate);
633 predText = DatumGetTextP(DirectFunctionCall1(textin,
634 CStringGetDatum(predString)));
638 predText = DatumGetTextP(DirectFunctionCall1(textin,
639 CStringGetDatum("")));
641 predLen = VARSIZE(predText);
642 itupLen = predLen + sizeof(FormData_pg_index);
643 indexForm = (Form_pg_index) palloc(itupLen);
644 MemSet(indexForm, 0, sizeof(FormData_pg_index));
647 * store information into the index tuple form
650 indexForm->indexrelid = indexoid;
651 indexForm->indrelid = heapoid;
652 indexForm->indproc = indexInfo->ii_FuncOid;
653 indexForm->indisclustered = false;
654 indexForm->indislossy = islossy;
655 indexForm->indhaskeytype = true; /* not actually used anymore */
656 indexForm->indisunique = indexInfo->ii_Unique;
657 indexForm->indisprimary = primary;
658 memcpy((char *) &indexForm->indpred, (char *) predText, predLen);
661 * copy index key and op class information
663 * We zeroed the extra slots (if any) above --- that's essential.
666 for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
667 indexForm->indkey[i] = indexInfo->ii_KeyAttrNumbers[i];
669 for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
670 indexForm->indclass[i] = classOids[i];
673 * open the system catalog index relation
676 pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
679 * form a tuple to insert into pg_index
682 tuple = heap_addheader(Natts_pg_index,
687 * insert the tuple into the pg_index
690 heap_insert(pg_index, tuple);
693 * add index tuples for it
696 if (!IsIgnoringSystemIndexes())
698 CatalogOpenIndices(Num_pg_index_indices, Name_pg_index_indices, idescs);
699 CatalogIndexInsert(idescs, Num_pg_index_indices, pg_index, tuple);
700 CatalogCloseIndices(Num_pg_index_indices, idescs);
704 * close the relation and free the tuple
707 heap_close(pg_index, RowExclusiveLock);
710 heap_freetuple(tuple);
713 /* ----------------------------------------------------------------
714 * UpdateIndexPredicate
715 * ----------------------------------------------------------------
718 UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
727 Datum values[Natts_pg_index];
728 char nulls[Natts_pg_index];
729 char replace[Natts_pg_index];
732 * Construct newPred as a CNF expression equivalent to the OR of the
733 * original partial-index predicate ("oldPred") and the extension
734 * predicate ("predicate").
736 * This should really try to process the result to change things like
737 * "a>2 OR a>1" to simply "a>1", but for now all it does is make sure
738 * that if the extension predicate is NULL (i.e., it is being extended
739 * to be a complete index), then newPred will be NULL - in effect,
740 * changing "a>2 OR TRUE" to "TRUE". --Nels, Jan '93
743 if (predicate != NULL)
745 newPred = (Node *) make_orclause(lcons(make_andclause((List *) predicate),
746 lcons(make_andclause((List *) oldPred),
748 newPred = (Node *) cnfify((Expr *) newPred, true);
751 /* translate the index-predicate to string form */
754 predString = nodeToString(newPred);
755 predText = DatumGetTextP(DirectFunctionCall1(textin,
756 CStringGetDatum(predString)));
760 predText = DatumGetTextP(DirectFunctionCall1(textin,
761 CStringGetDatum("")));
763 /* open the index system catalog relation */
764 pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
766 tuple = SearchSysCache(INDEXRELID,
767 ObjectIdGetDatum(indexoid),
769 if (!HeapTupleIsValid(tuple))
770 elog(ERROR, "UpdateIndexPredicate: cache lookup failed for index %u",
773 for (i = 0; i < Natts_pg_index; i++)
775 nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' ';
777 values[i] = (Datum) NULL;
780 replace[Anum_pg_index_indpred - 1] = 'r';
781 values[Anum_pg_index_indpred - 1] = (Datum) predText;
783 newtup = heap_modifytuple(tuple, pg_index, values, nulls, replace);
785 heap_update(pg_index, &newtup->t_self, newtup, NULL);
787 heap_freetuple(newtup);
788 ReleaseSysCache(tuple);
790 heap_close(pg_index, RowExclusiveLock);
794 /* ----------------------------------------------------------------
796 * ----------------------------------------------------------------
799 InitIndexStrategy(int numatts,
800 Relation indexRelation,
801 Oid accessMethodObjectId)
803 IndexStrategy strategy;
804 RegProcedure *support;
811 * get information from the index relation descriptor
814 attrelid = indexRelation->rd_att->attrs[0]->attrelid;
815 amstrategies = indexRelation->rd_am->amstrategies;
816 amsupport = indexRelation->rd_am->amsupport;
819 * get the size of the strategy
822 strsize = AttributeNumberGetIndexStrategySize(numatts, amstrategies);
825 * allocate the new index strategy structure
827 * the index strategy has to be allocated in the same
828 * context as the relation descriptor cache or else
829 * it will be lost at the end of the transaction.
832 if (!CacheMemoryContext)
833 CreateCacheMemoryContext();
835 strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
840 strsize = numatts * (amsupport * sizeof(RegProcedure));
841 support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext,
845 support = (RegProcedure *) NULL;
848 * fill in the index strategy structure with information
849 * from the catalogs. First we must advance the command counter
850 * so that we will see the newly-entered index catalog tuples.
853 CommandCounterIncrement();
855 IndexSupportInitialize(strategy, support,
856 &indexRelation->rd_uniqueindex,
857 attrelid, accessMethodObjectId,
858 amstrategies, amsupport, numatts);
861 * store the strategy information in the index reldesc
864 RelationSetIndexSupport(indexRelation, strategy, support);
868 /* ----------------------------------------------------------------
870 * ----------------------------------------------------------------
873 index_create(char *heapRelationName,
874 char *indexRelationName,
875 IndexInfo *indexInfo,
876 Oid accessMethodObjectId,
880 bool allow_system_table_mods)
882 Relation heapRelation;
883 Relation indexRelation;
884 TupleDesc indexTupDesc;
887 bool istemp = (get_temp_rel_by_username(heapRelationName) != NULL);
888 char *temp_relname = NULL;
890 SetReindexProcessing(false);
896 if (indexInfo->ii_NumIndexAttrs < 1 ||
897 indexInfo->ii_NumKeyAttrs < 1)
898 elog(ERROR, "must index at least one attribute");
901 * get heap relation oid and open the heap relation
904 heapoid = GetHeapRelationOid(heapRelationName, indexRelationName, istemp);
907 * Only SELECT ... FOR UPDATE are allowed while doing this
909 heapRelation = heap_open(heapoid, ShareLock);
912 * construct new tuple descriptor
915 if (OidIsValid(indexInfo->ii_FuncOid))
916 indexTupDesc = BuildFuncTupleDesc(indexInfo->ii_FuncOid);
918 indexTupDesc = ConstructTupleDescriptor(heapoid,
920 indexInfo->ii_NumKeyAttrs,
921 indexInfo->ii_KeyAttrNumbers);
925 /* save user relation name because heap_create changes it */
926 temp_relname = pstrdup(indexRelationName); /* save original value */
927 indexRelationName = palloc(NAMEDATALEN);
928 strcpy(indexRelationName, temp_relname); /* heap_create will
933 * create the index relation
936 indexRelation = heap_create(indexRelationName, indexTupDesc,
937 istemp, false, allow_system_table_mods);
940 * Obtain exclusive lock on it. Although no other backends can see it
941 * until we commit, this prevents deadlock-risk complaints from lock
942 * manager in cases such as CLUSTER.
944 LockRelation(indexRelation, AccessExclusiveLock);
947 * construct the index relation descriptor
949 * XXX should have a proper way to create cataloged relations
952 ConstructIndexReldesc(indexRelation, accessMethodObjectId);
955 * add index to catalogs
956 * (append RELATION tuple)
959 indexoid = UpdateRelationRelation(indexRelation, temp_relname);
962 * We create the disk file for this relation here
964 heap_storage_create(indexRelation);
967 * now update the object id's of all the attribute
968 * tuple forms in the index relation's tuple descriptor
971 InitializeAttributeOids(indexRelation,
972 indexInfo->ii_NumIndexAttrs,
976 * append ATTRIBUTE tuples for the index
979 AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs);
983 * (append INDEX tuple)
985 * Note that this stows away a representation of "predicate".
986 * (Or, could define a rule to maintain the predicate) --Nels, Feb '92
989 UpdateIndexRelation(indexoid, heapoid, indexInfo,
990 classObjectId, islossy, primary);
993 * initialize the index strategy
996 InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
998 accessMethodObjectId);
1001 * If this is bootstrap (initdb) time, then we don't actually fill in
1002 * the index yet. We'll be creating more indices and classes later,
1003 * so we delay filling them in until just before we're done with
1004 * bootstrapping. Otherwise, we call the routine that constructs the
1007 * In normal processing mode, the heap and index relations are closed by
1008 * index_build() --- but we continue to hold the ShareLock on the heap
1009 * and the exclusive lock on the index that we acquired above, until
1010 * end of transaction.
1012 if (IsBootstrapProcessingMode())
1014 index_register(heapRelationName, indexRelationName, indexInfo);
1015 /* XXX shouldn't we close the heap and index rels here? */
1019 index_build(heapRelation, indexRelation, indexInfo, NULL);
1023 /* ----------------------------------------------------------------
1027 * ----------------------------------------------------------------
1030 index_drop(Oid indexId)
1033 Relation userHeapRelation;
1034 Relation userIndexRelation;
1035 Relation indexRelation;
1036 Relation relationRelation;
1037 Relation attributeRelation;
1042 Assert(OidIsValid(indexId));
1045 * To drop an index safely, we must grab exclusive lock on its parent
1046 * table; otherwise there could be other backends using the index!
1047 * Exclusive lock on the index alone is insufficient because the index
1048 * access routines are a little slipshod about obtaining adequate locking
1049 * (see ExecOpenIndices()). We do grab exclusive lock on the index too,
1050 * just to be safe. Both locks must be held till end of transaction,
1051 * else other backends will still see this index in pg_index.
1054 heapId = IndexGetRelation(indexId);
1055 userHeapRelation = heap_open(heapId, AccessExclusiveLock);
1057 userIndexRelation = index_open(indexId);
1058 LockRelation(userIndexRelation, AccessExclusiveLock);
1061 * Note: unlike heap_drop_with_catalog, we do not need to prevent
1062 * deletion of system indexes here; that's checked for upstream.
1063 * If we did check it here, deletion of TOAST tables would fail...
1068 * fix DESCRIPTION relation
1071 DeleteComments(indexId);
1074 * fix RELATION relation
1077 relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
1079 /* Remove the pg_class tuple for the index itself */
1080 tuple = SearchSysCacheCopy(RELOID,
1081 ObjectIdGetDatum(indexId),
1083 if (!HeapTupleIsValid(tuple))
1084 elog(ERROR, "index_drop: cache lookup failed for index %u",
1087 heap_delete(relationRelation, &tuple->t_self, NULL);
1088 heap_freetuple(tuple);
1091 * Update the pg_class tuple for the owning relation. We are presently
1092 * too lazy to attempt to compute the new correct value of relhasindex
1093 * (the next VACUUM will fix it if necessary). But we must send out a
1094 * shared-cache-inval notice on the owning relation to ensure other
1095 * backends update their relcache lists of indexes. So, unconditionally
1096 * do setRelhasindex(true).
1098 setRelhasindex(heapId, true);
1100 heap_close(relationRelation, RowExclusiveLock);
1103 * fix ATTRIBUTE relation
1106 attributeRelation = heap_openr(AttributeRelationName, RowExclusiveLock);
1108 attnum = 1; /* indexes start at 1 */
1110 while (HeapTupleIsValid(tuple = SearchSysCacheCopy(ATTNUM,
1111 ObjectIdGetDatum(indexId),
1112 Int16GetDatum(attnum),
1115 heap_delete(attributeRelation, &tuple->t_self, NULL);
1116 heap_freetuple(tuple);
1119 heap_close(attributeRelation, RowExclusiveLock);
1122 * fix INDEX relation
1125 indexRelation = heap_openr(IndexRelationName, RowExclusiveLock);
1127 tuple = SearchSysCacheCopy(INDEXRELID,
1128 ObjectIdGetDatum(indexId),
1130 if (!HeapTupleIsValid(tuple))
1131 elog(ERROR, "index_drop: cache lookup failed for index %u",
1134 heap_delete(indexRelation, &tuple->t_self, NULL);
1135 heap_freetuple(tuple);
1136 heap_close(indexRelation, RowExclusiveLock);
1139 * flush buffer cache and physically remove the file
1141 i = FlushRelationBuffers(userIndexRelation, (BlockNumber) 0);
1143 elog(ERROR, "index_drop: FlushRelationBuffers returned %d", i);
1145 smgrunlink(DEFAULT_SMGR, userIndexRelation);
1148 * Close rels, but keep locks
1150 index_close(userIndexRelation);
1151 heap_close(userHeapRelation, NoLock);
1153 RelationForgetRelation(indexId);
1155 /* if it's a temp index, clear the temp mapping table entry */
1156 remove_temp_rel_by_relid(indexId);
1159 /* ----------------------------------------------------------------
1160 * index_build support
1161 * ----------------------------------------------------------------
1166 * Construct an IndexInfo record given the index's pg_index tuple
1168 * IndexInfo stores the information about the index that's needed by
1169 * FormIndexDatum, which is used for both index_build() and later insertion
1170 * of individual index tuples. Normally we build an IndexInfo for an index
1171 * just once per command, and then use it for (potentially) many tuples.
1175 BuildIndexInfo(HeapTuple indexTuple)
1177 Form_pg_index indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
1178 IndexInfo *ii = makeNode(IndexInfo);
1183 * count the number of keys, and copy them into the IndexInfo
1187 for (i = 0; i < INDEX_MAX_KEYS &&
1188 indexStruct->indkey[i] != InvalidAttrNumber; i++)
1190 ii->ii_KeyAttrNumbers[i] = indexStruct->indkey[i];
1193 ii->ii_NumKeyAttrs = numKeys;
1196 * Handle functional index.
1198 * If we have a functional index then the number of
1199 * attributes defined in the index must be 1 (the function's
1200 * single return value). Otherwise it's same as number of keys.
1203 ii->ii_FuncOid = indexStruct->indproc;
1205 if (OidIsValid(indexStruct->indproc))
1207 ii->ii_NumIndexAttrs = 1;
1208 /* Do a lookup on the function, too */
1209 fmgr_info(indexStruct->indproc, & ii->ii_FuncInfo);
1212 ii->ii_NumIndexAttrs = numKeys;
1215 * If partial index, convert predicate into expression nodetree
1218 if (VARSIZE(&indexStruct->indpred) != 0)
1222 predString = DatumGetCString(DirectFunctionCall1(textout,
1223 PointerGetDatum(&indexStruct->indpred)));
1224 ii->ii_Predicate = stringToNode(predString);
1228 ii->ii_Predicate = NULL;
1231 ii->ii_Unique = indexStruct->indisunique;
1238 * Construct Datum[] and nullv[] arrays for a new index tuple.
1240 * indexInfo Info about the index
1241 * heapTuple Heap tuple for which we must prepare an index entry
1242 * heapDescriptor tupledesc for heap tuple
1243 * resultCxt Temporary memory context for any palloc'd datums created
1244 * datum Array of index Datums (output area)
1245 * nullv Array of is-null indicators (output area)
1247 * For largely historical reasons, we don't actually call index_formtuple()
1248 * here, we just prepare its input arrays datum[] and nullv[].
1252 FormIndexDatum(IndexInfo *indexInfo,
1253 HeapTuple heapTuple,
1254 TupleDesc heapDescriptor,
1255 MemoryContext resultCxt,
1259 MemoryContext oldContext;
1264 oldContext = MemoryContextSwitchTo(resultCxt);
1266 if (OidIsValid(indexInfo->ii_FuncOid))
1269 * Functional index --- compute the single index attribute
1272 FunctionCallInfoData fcinfo;
1273 bool anynull = false;
1275 MemSet(&fcinfo, 0, sizeof(fcinfo));
1276 fcinfo.flinfo = &indexInfo->ii_FuncInfo;
1277 fcinfo.nargs = indexInfo->ii_NumKeyAttrs;
1279 for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
1281 fcinfo.arg[i] = heap_getattr(heapTuple,
1282 indexInfo->ii_KeyAttrNumbers[i],
1284 &fcinfo.argnull[i]);
1285 anynull |= fcinfo.argnull[i];
1287 if (indexInfo->ii_FuncInfo.fn_strict && anynull)
1289 /* force a null result for strict function */
1295 iDatum = FunctionCallInvoke(&fcinfo);
1296 isNull = fcinfo.isnull;
1299 nullv[0] = (isNull) ? 'n' : ' ';
1304 * Plain index --- for each attribute we need from the heap tuple,
1305 * get the attribute and stick it into the datum and nullv arrays.
1308 for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
1310 iDatum = heap_getattr(heapTuple,
1311 indexInfo->ii_KeyAttrNumbers[i],
1315 nullv[i] = (isNull) ? 'n' : ' ';
1319 MemoryContextSwitchTo(oldContext);
1323 /* --------------------------------------------
1324 * Lock class info for update
1325 * --------------------------------------------
1328 LockClassinfoForUpdate(Oid relid, HeapTuple rtup,
1329 Buffer *buffer, bool confirmCommitted)
1331 HeapTuple classTuple;
1333 Relation relationRelation;
1336 * NOTE: get and hold RowExclusiveLock on pg_class, because caller will
1337 * probably modify the rel's pg_class tuple later on.
1339 relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
1340 classTuple = SearchSysCache(RELOID, PointerGetDatum(relid),
1342 if (!HeapTupleIsValid(classTuple))
1344 heap_close(relationRelation, NoLock);
1347 rtup->t_self = classTuple->t_self;
1348 ReleaseSysCache(classTuple);
1350 test = heap_mark4update(relationRelation, rtup, buffer);
1353 case HeapTupleSelfUpdated:
1354 case HeapTupleMayBeUpdated:
1357 elog(ERROR, "LockStatsForUpdate couldn't lock relid %u", relid);
1360 RelationInvalidateHeapTuple(relationRelation, rtup);
1361 if (confirmCommitted)
1363 HeapTupleHeader th = rtup->t_data;
1365 if (!(th->t_infomask & HEAP_XMIN_COMMITTED))
1366 elog(ERROR, "The tuple isn't committed");
1367 if (th->t_infomask & HEAP_XMAX_COMMITTED)
1368 if (!(th->t_infomask & HEAP_MARKED_FOR_UPDATE))
1369 elog(ERROR, "The tuple is already deleted");
1371 heap_close(relationRelation, NoLock);
1375 /* ---------------------------------------------
1376 * Indexes of the relation active ?
1377 * ---------------------------------------------
1380 IndexesAreActive(Oid relid, bool confirmCommitted)
1382 HeapTupleData tuple;
1383 Relation indexRelation;
1389 if (!LockClassinfoForUpdate(relid, &tuple, &buffer, confirmCommitted))
1390 elog(ERROR, "IndexesAreActive couldn't lock %u", relid);
1391 if (((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_RELATION &&
1392 ((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_TOASTVALUE)
1393 elog(ERROR, "relation %u isn't an indexable relation", relid);
1394 isactive = ((Form_pg_class) GETSTRUCT(&tuple))->relhasindex;
1395 ReleaseBuffer(buffer);
1398 indexRelation = heap_openr(IndexRelationName, AccessShareLock);
1399 ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid,
1400 F_OIDEQ, ObjectIdGetDatum(relid));
1401 scan = heap_beginscan(indexRelation, false, SnapshotNow,
1403 if (!heap_getnext(scan, 0))
1406 heap_close(indexRelation, AccessShareLock);
1411 * set relhasindex of relation's pg_class entry
1413 * NOTE: an important side-effect of this operation is that an SI invalidation
1414 * message is sent out to all backends --- including me --- causing relcache
1415 * entries to be flushed or updated with the new hasindex data.
1416 * Therefore, we execute the update even if relhasindex has the right value
1417 * already. Possible future improvement: skip the disk update and just send
1418 * an SI message in that case.
1422 setRelhasindex(Oid relid, bool hasindex)
1426 HeapScanDesc pg_class_scan = NULL;
1429 * Find the tuple to update in pg_class.
1431 pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
1433 #ifdef OLD_FILE_NAMING
1434 if (!IsIgnoringSystemIndexes())
1436 if (!IsIgnoringSystemIndexes() && (!IsReindexProcessing() || pg_class->rd_rel->relhasindex))
1437 #endif /* OLD_FILE_NAMING */
1439 tuple = SearchSysCacheCopy(RELOID,
1440 ObjectIdGetDatum(relid),
1447 ScanKeyEntryInitialize(&key[0], 0,
1448 ObjectIdAttributeNumber,
1450 ObjectIdGetDatum(relid));
1452 pg_class_scan = heap_beginscan(pg_class, 0, SnapshotNow, 1, key);
1453 tuple = heap_getnext(pg_class_scan, 0);
1456 if (!HeapTupleIsValid(tuple))
1459 heap_endscan(pg_class_scan);
1460 heap_close(pg_class, RowExclusiveLock);
1461 elog(ERROR, "setRelhasindex: cannot find relation %u in pg_class",
1466 * Update hasindex in pg_class.
1470 LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
1471 ((Form_pg_class) GETSTRUCT(tuple))->relhasindex = hasindex;
1473 LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
1477 /* Write the modified tuple in-place */
1478 WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
1479 /* Send out shared cache inval if necessary */
1480 if (!IsBootstrapProcessingMode())
1481 RelationInvalidateHeapTuple(pg_class, tuple);
1486 heap_update(pg_class, &tuple->t_self, tuple, NULL);
1488 /* Keep the catalog indices up to date */
1489 if (!IsIgnoringSystemIndexes())
1491 Relation idescs[Num_pg_class_indices];
1493 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
1495 CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, tuple);
1496 CatalogCloseIndices(Num_pg_class_indices, idescs);
1501 heap_freetuple(tuple);
1503 heap_endscan(pg_class_scan);
1505 heap_close(pg_class, RowExclusiveLock);
1508 #ifndef OLD_FILE_NAMING
1510 setNewRelfilenode(Relation relation)
1512 Relation pg_class, idescs[Num_pg_class_indices];
1514 bool in_place_update = false;
1515 HeapTupleData lockTupleData;
1516 HeapTuple classTuple;
1518 RelationData workrel;
1520 Assert(!IsSystemRelationName(NameStr(relation->rd_rel->relname)) || relation->rd_rel->relkind == RELKIND_INDEX);
1522 pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
1523 /* Fetch and lock the classTuple associated with this relation */
1524 if (!LockClassinfoForUpdate(relation->rd_id, &lockTupleData, &buffer, true))
1525 elog(ERROR, "setNewRelfilenode impossible to lock class tuple");
1526 if (IsIgnoringSystemIndexes())
1527 in_place_update = true;
1528 /* Allocate a new relfilenode */
1529 newrelfilenode = newoid();
1530 /* update pg_class tuple with new relfilenode */
1531 if (!in_place_update)
1533 classTuple = heap_copytuple(&lockTupleData);
1534 ReleaseBuffer(buffer);
1535 ((Form_pg_class) GETSTRUCT(classTuple))->relfilenode = newrelfilenode;
1536 heap_update(pg_class, &classTuple->t_self, classTuple, NULL);
1538 /* unlink old relfilenode */
1539 DropRelationBuffers(relation);
1540 smgrunlink(DEFAULT_SMGR, relation);
1541 /* cleanup pg_internal.init if necessary */
1542 if (relation->rd_isnailed)
1543 unlink(RELCACHE_INIT_FILENAME);
1544 /* create another storage file. Is it a little ugly ? */
1545 memcpy((char *) &workrel, relation, sizeof(RelationData));
1546 workrel.rd_node.relNode = newrelfilenode;
1547 heap_storage_create(&workrel);
1548 /* update pg_class tuple with new relfilenode in place */
1549 if (in_place_update)
1551 classTuple = &lockTupleData;
1552 /* Send out shared cache inval if necessary */
1553 if (!IsBootstrapProcessingMode())
1554 RelationInvalidateHeapTuple(pg_class, classTuple);
1555 /* Update the buffer in-place */
1556 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
1557 ((Form_pg_class) GETSTRUCT(classTuple))->relfilenode = newrelfilenode;
1558 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
1559 WriteBuffer(buffer);
1562 /* Keep the catalog indices up to date */
1563 if (!in_place_update && pg_class->rd_rel->relhasindex)
1565 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
1567 CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, classTuple);
1568 CatalogCloseIndices(Num_pg_class_indices, idescs);
1569 heap_freetuple(classTuple);
1571 heap_close(pg_class, NoLock);
1572 /* Make sure the relfilenode change */
1573 CommandCounterIncrement();
1575 #endif /* OLD_FILE_NAMING */
1582 UpdateStats(Oid relid, long reltuples)
1590 Form_pg_class rd_rel;
1591 Relation idescs[Num_pg_class_indices];
1592 Datum values[Natts_pg_class];
1593 char nulls[Natts_pg_class];
1594 char replace[Natts_pg_class];
1595 HeapScanDesc pg_class_scan = NULL;
1599 * This routine handles updates for both the heap and index relation
1600 * statistics. In order to guarantee that we're able to *see* the index
1601 * relation tuple, we bump the command counter id here. The index
1602 * relation tuple was created in the current transaction.
1605 CommandCounterIncrement();
1608 * CommandCounterIncrement() flushes invalid cache entries, including
1609 * those for the heap and index relations for which we're updating
1610 * statistics. Now that the cache is flushed, it's safe to open the
1611 * relation again. We need the relation open in order to figure out
1612 * how many blocks it contains.
1617 * Can't use heap_open here since we don't know if it's an index...
1619 whichRel = RelationIdGetRelation(relid);
1621 if (!RelationIsValid(whichRel))
1622 elog(ERROR, "UpdateStats: cannot open relation id %u", relid);
1624 /* Grab lock to be held till end of xact (probably redundant...) */
1625 LockRelation(whichRel, ShareLock);
1628 * Find the RELATION relation tuple for the given relation.
1631 pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
1633 #ifdef OLD_FILE_NAMING
1634 in_place_upd = (IsReindexProcessing() || IsBootstrapProcessingMode());
1636 in_place_upd = (IsIgnoringSystemIndexes() || (IsReindexProcessing() &&
1637 relid == RelOid_pg_class));
1638 #endif /* OLD_FILE_NAMING */
1642 tuple = SearchSysCacheCopy(RELOID,
1643 ObjectIdGetDatum(relid),
1650 ScanKeyEntryInitialize(&key[0], 0,
1651 ObjectIdAttributeNumber,
1653 ObjectIdGetDatum(relid));
1655 pg_class_scan = heap_beginscan(pg_class, 0, SnapshotNow, 1, key);
1656 tuple = heap_getnext(pg_class_scan, 0);
1659 if (!HeapTupleIsValid(tuple))
1662 heap_endscan(pg_class_scan);
1663 heap_close(pg_class, RowExclusiveLock);
1664 elog(ERROR, "UpdateStats: cannot find relation %u in pg_class",
1669 * Figure values to insert.
1671 * If we found zero tuples in the scan, do NOT believe it; instead put
1672 * a bogus estimate into the statistics fields. Otherwise, the common
1673 * pattern "CREATE TABLE; CREATE INDEX; insert data" leaves the table
1674 * with zero size statistics until a VACUUM is done. The optimizer will
1675 * generate very bad plans if the stats claim the table is empty when
1676 * it is actually sizable. See also CREATE TABLE in heap.c.
1679 relpages = RelationGetNumberOfBlocks(whichRel);
1685 /* Bogus defaults for a virgin table, same as heap.c */
1689 else if (whichRel->rd_rel->relkind == RELKIND_INDEX && relpages <= 2)
1691 /* Empty index, leave bogus defaults in place */
1695 reltuples = relpages * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
1699 * We shouldn't have to do this, but we do... Modify the reldesc in
1700 * place with the new values so that the cache contains the latest
1703 whichRel->rd_rel->relpages = relpages;
1704 whichRel->rd_rel->reltuples = reltuples;
1707 * Update statistics in pg_class.
1713 * At bootstrap time, we don't need to worry about concurrency or
1714 * visibility of changes, so we cheat. Also cheat if REINDEX.
1716 rd_rel = (Form_pg_class) GETSTRUCT(tuple);
1717 LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
1718 rd_rel->relpages = relpages;
1719 rd_rel->reltuples = reltuples;
1720 LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
1721 WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
1722 if (!IsBootstrapProcessingMode())
1723 RelationInvalidateHeapTuple(pg_class, tuple);
1727 /* During normal processing, must work harder. */
1729 for (i = 0; i < Natts_pg_class; i++)
1731 nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' ';
1733 values[i] = (Datum) NULL;
1736 replace[Anum_pg_class_relpages - 1] = 'r';
1737 values[Anum_pg_class_relpages - 1] = (Datum) relpages;
1738 replace[Anum_pg_class_reltuples - 1] = 'r';
1739 values[Anum_pg_class_reltuples - 1] = (Datum) reltuples;
1740 newtup = heap_modifytuple(tuple, pg_class, values, nulls, replace);
1741 heap_update(pg_class, &tuple->t_self, newtup, NULL);
1742 if (!IsIgnoringSystemIndexes())
1744 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
1745 CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, newtup);
1746 CatalogCloseIndices(Num_pg_class_indices, idescs);
1748 heap_freetuple(newtup);
1752 heap_freetuple(tuple);
1754 heap_endscan(pg_class_scan);
1756 heap_close(pg_class, RowExclusiveLock);
1757 /* Cheating a little bit since we didn't open it with heap_open... */
1758 heap_close(whichRel, NoLock);
1765 * NB: this routine is dead code, and likely always has been, because
1766 * there are no access methods that don't supply their own ambuild procedure.
1768 * Anyone want to wager whether it would actually work if executed?
1772 DefaultBuild(Relation heapRelation,
1773 Relation indexRelation,
1774 IndexInfo *indexInfo,
1776 IndexStrategy indexStrategy) /* not used */
1779 HeapTuple heapTuple;
1780 TupleDesc heapDescriptor;
1781 Datum datum[INDEX_MAX_KEYS];
1782 char nullv[INDEX_MAX_KEYS];
1785 Node *predicate = indexInfo->ii_Predicate;
1786 #ifndef OMIT_PARTIAL_INDEX
1787 TupleTable tupleTable;
1788 TupleTableSlot *slot;
1790 ExprContext *econtext;
1791 InsertIndexResult insertResult;
1794 * more & better checking is needed
1797 Assert(OidIsValid(indexRelation->rd_rel->relam)); /* XXX */
1799 heapDescriptor = RelationGetDescr(heapRelation);
1802 * If this is a predicate (partial) index, we will need to evaluate
1803 * the predicate using ExecQual, which requires the current tuple to
1804 * be in a slot of a TupleTable. In addition, ExecQual must have an
1805 * ExprContext referring to that slot. Here, we initialize dummy
1806 * TupleTable and ExprContext objects for this purpose. --Nels, Feb 92
1808 * We construct the ExprContext anyway since we need a per-tuple
1809 * temporary memory context for function evaluation -- tgl July 00
1811 #ifndef OMIT_PARTIAL_INDEX
1812 if (predicate != NULL || oldPred != NULL)
1814 tupleTable = ExecCreateTupleTable(1);
1815 slot = ExecAllocTableSlot(tupleTable);
1816 ExecSetSlotDescriptor(slot, heapDescriptor);
1823 econtext = MakeExprContext(slot, TransactionCommandContext);
1825 econtext = MakeExprContext(NULL, TransactionCommandContext);
1826 #endif /* OMIT_PARTIAL_INDEX */
1829 * Ok, begin our scan of the base relation.
1832 scan = heap_beginscan(heapRelation, /* relation */
1833 0, /* start at end */
1834 SnapshotNow, /* seeself */
1835 0, /* number of keys */
1836 (ScanKey) NULL); /* scan key */
1838 reltuples = indtuples = 0;
1841 * for each tuple in the base relation, we create an index
1842 * tuple and add it to the index relation. We keep a running
1843 * count of the number of tuples so that we can update pg_class
1844 * with correct statistics when we're done building the index.
1847 while (HeapTupleIsValid(heapTuple = heap_getnext(scan, 0)))
1849 MemoryContextReset(econtext->ecxt_per_tuple_memory);
1853 #ifndef OMIT_PARTIAL_INDEX
1855 * If oldPred != NULL, this is an EXTEND INDEX command, so skip
1856 * this tuple if it was already in the existing partial index
1858 if (oldPred != NULL)
1860 slot->val = heapTuple;
1861 if (ExecQual((List *) oldPred, econtext, false))
1869 * Skip this tuple if it doesn't satisfy the partial-index
1872 if (predicate != NULL)
1874 slot->val = heapTuple;
1875 if (!ExecQual((List *) predicate, econtext, false))
1878 #endif /* OMIT_PARTIAL_INDEX */
1883 * FormIndexDatum fills in its datum and null parameters
1884 * with attribute information taken from the given heap tuple.
1887 FormIndexDatum(indexInfo,
1890 econtext->ecxt_per_tuple_memory,
1894 insertResult = index_insert(indexRelation, datum, nullv,
1895 &(heapTuple->t_self), heapRelation);
1898 pfree(insertResult);
1903 #ifndef OMIT_PARTIAL_INDEX
1904 if (predicate != NULL || oldPred != NULL)
1906 ExecDropTupleTable(tupleTable, true);
1908 #endif /* OMIT_PARTIAL_INDEX */
1909 FreeExprContext(econtext);
1912 * Since we just counted the tuples in the heap, we update its stats
1913 * in pg_class to guarantee that the planner takes advantage of the
1914 * index we just created. But, only update statistics during normal
1915 * index definitions, not for indices on system catalogs created
1916 * during bootstrap processing. We must close the relations before
1917 * updating statistics to guarantee that the relcache entries are
1918 * flushed when we increment the command counter in UpdateStats(). But
1919 * we do not release any locks on the relations; those will be held
1920 * until end of transaction.
1922 if (IsNormalProcessingMode())
1924 Oid hrelid = RelationGetRelid(heapRelation);
1925 Oid irelid = RelationGetRelid(indexRelation);
1927 heap_close(heapRelation, NoLock);
1928 index_close(indexRelation);
1929 UpdateStats(hrelid, reltuples);
1930 UpdateStats(irelid, indtuples);
1931 if (oldPred != NULL)
1933 if (indtuples == reltuples)
1935 UpdateIndexPredicate(irelid, oldPred, predicate);
1945 index_build(Relation heapRelation,
1946 Relation indexRelation,
1947 IndexInfo *indexInfo,
1950 RegProcedure procedure;
1956 Assert(RelationIsValid(indexRelation));
1957 Assert(PointerIsValid(indexRelation->rd_am));
1959 procedure = indexRelation->rd_am->ambuild;
1962 * use the access method build procedure if supplied, else default.
1965 if (RegProcedureIsValid(procedure))
1966 OidFunctionCall5(procedure,
1967 PointerGetDatum(heapRelation),
1968 PointerGetDatum(indexRelation),
1969 PointerGetDatum(indexInfo),
1970 PointerGetDatum(oldPred),
1971 PointerGetDatum(RelationGetIndexStrategy(indexRelation)));
1973 DefaultBuild(heapRelation,
1977 RelationGetIndexStrategy(indexRelation));
1981 * IndexGetRelation: given an index's relation OID, get the OID of the
1982 * relation it is an index on. Uses the system cache.
1985 IndexGetRelation(Oid indexId)
1988 Form_pg_index index;
1991 tuple = SearchSysCache(INDEXRELID,
1992 ObjectIdGetDatum(indexId),
1994 if (!HeapTupleIsValid(tuple))
1995 elog(ERROR, "IndexGetRelation: can't find index id %u",
1997 index = (Form_pg_index) GETSTRUCT(tuple);
1998 Assert(index->indexrelid == indexId);
2000 result = index->indrelid;
2001 ReleaseSysCache(tuple);
2005 /* ---------------------------------
2006 * activate_index -- activate/deactivate the specified index.
2007 * Note that currently PostgreSQL doesn't hold the
2009 * ---------------------------------
2012 activate_index(Oid indexId, bool activate, bool inplace)
2014 if (!activate) /* Currently does nothing */
2016 return reindex_index(indexId, false, inplace);
2019 /* --------------------------------
2020 * reindex_index - This routine is used to recreate an index
2021 * --------------------------------
2024 reindex_index(Oid indexId, bool force, bool inplace)
2031 HeapTuple indexTuple,
2033 IndexInfo *indexInfo;
2039 * REINDEX within a transaction block is dangerous, because
2040 * if the transaction is later rolled back we have no way to
2041 * undo truncation of the index's physical file. Disallow it.
2044 if (IsTransactionBlock())
2045 elog(ERROR, "REINDEX cannot run inside a BEGIN/END block");
2047 old = SetReindexProcessing(true);
2049 /* Scan pg_index to find the index's pg_index entry */
2050 indexRelation = heap_openr(IndexRelationName, AccessShareLock);
2051 ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indexrelid, F_OIDEQ,
2052 ObjectIdGetDatum(indexId));
2053 scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry);
2054 indexTuple = heap_getnext(scan, 0);
2055 if (!HeapTupleIsValid(indexTuple))
2056 elog(ERROR, "reindex_index: index %u not found in pg_index", indexId);
2058 /* Get OID of index's parent table */
2059 heapId = ((Form_pg_index) GETSTRUCT(indexTuple))->indrelid;
2060 /* Fetch info needed for index_build */
2061 indexInfo = BuildIndexInfo(indexTuple);
2063 /* Complete the scan and close pg_index */
2065 heap_close(indexRelation, AccessShareLock);
2067 /* Fetch the classTuple associated with this index */
2068 classTuple = SearchSysCache(RELOID,
2069 ObjectIdGetDatum(indexId),
2071 if (!HeapTupleIsValid(classTuple))
2072 elog(ERROR, "reindex_index: index %u not found in pg_class", indexId);
2073 accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam;
2074 ReleaseSysCache(classTuple);
2076 /* Open our index relation */
2077 heapRelation = heap_open(heapId, ExclusiveLock);
2078 if (heapRelation == NULL)
2079 elog(ERROR, "reindex_index: can't open heap relation");
2080 iRel = index_open(indexId);
2082 elog(ERROR, "reindex_index: can't open index relation");
2084 #ifndef OLD_FILE_NAMING
2086 setNewRelfilenode(iRel);
2087 #endif /* OLD_FILE_NAMING */
2088 /* Obtain exclusive lock on it, just to be sure */
2089 LockRelation(iRel, AccessExclusiveLock);
2094 * Release any buffers associated with this index. If they're dirty,
2095 * they're just dropped without bothering to flush to disk.
2097 DropRelationBuffers(iRel);
2099 /* Now truncate the actual data and set blocks to zero */
2100 smgrtruncate(DEFAULT_SMGR, iRel, 0);
2101 iRel->rd_nblocks = 0;
2104 /* Initialize the index and rebuild */
2105 InitIndexStrategy(indexInfo->ii_NumIndexAttrs, iRel, accessMethodId);
2106 index_build(heapRelation, iRel, indexInfo, NULL);
2109 * index_build will close both the heap and index relations (but not
2110 * give up the locks we hold on them). So we're done.
2113 SetReindexProcessing(old);
2119 * ----------------------------
2120 * activate_indexes_of_a_table
2121 * activate/deactivate indexes of the specified table.
2122 * ----------------------------
2125 activate_indexes_of_a_table(Oid relid, bool activate)
2127 if (IndexesAreActive(relid, true))
2130 setRelhasindex(relid, false);
2137 reindex_relation(relid, false);
2144 /* --------------------------------
2145 * reindex_relation - This routine is used to recreate indexes
2147 * --------------------------------
2150 reindex_relation(Oid relid, bool force)
2152 Relation indexRelation;
2155 HeapTuple indexTuple;
2159 bool deactivate_needed, overwrite, upd_pg_class_inplace;
2160 #ifdef OLD_FILE_NAMING
2161 overwrite = upd_pg_class_inplace = deactivate_needed = true;
2164 overwrite = upd_pg_class_inplace = deactivate_needed = false;
2166 * avoid heap_update() pg_class tuples while processing
2167 * reindex for pg_class.
2169 if (IsIgnoringSystemIndexes())
2170 upd_pg_class_inplace = true;
2172 * ignore the indexes of the target system relation while processing
2175 rel = RelationIdGetRelation(relid);
2176 if (!IsIgnoringSystemIndexes() && IsSystemRelationName(NameStr(rel->rd_rel->relname)))
2177 deactivate_needed = true;
2178 #ifndef ENABLE_REINDEX_NAILED_RELATIONS
2180 * nailed relations are never updated.
2181 * We couldn't keep the consistency between the relation
2182 * descriptors and pg_class tuples.
2184 if (rel->rd_isnailed)
2186 if (IsIgnoringSystemIndexes())
2189 deactivate_needed = true;
2192 elog(ERROR, "the target relation %u is nailed", relid);
2194 #endif /* ENABLE_REINDEX_NAILED_RELATIONS */
2196 #endif /* OLD_FILE_NAMING */
2197 old = SetReindexProcessing(true);
2198 if (deactivate_needed)
2200 if (IndexesAreActive(relid, upd_pg_class_inplace))
2204 SetReindexProcessing(old);
2207 activate_indexes_of_a_table(relid, false);
2208 CommandCounterIncrement();
2212 indexRelation = heap_openr(IndexRelationName, AccessShareLock);
2213 ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid,
2214 F_OIDEQ, ObjectIdGetDatum(relid));
2215 scan = heap_beginscan(indexRelation, false, SnapshotNow,
2218 while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
2220 Form_pg_index index = (Form_pg_index) GETSTRUCT(indexTuple);
2222 if (activate_index(index->indexrelid, true, overwrite))
2231 heap_close(indexRelation, AccessShareLock);
2234 * Ok,we could use the reindexed indexes of the target
2235 * system relation now.
2238 if (deactivate_needed)
2240 if (!overwrite && relid == RelOid_pg_class)
2243 * For pg_class, relhasindex should be set
2244 * to true here in place.
2246 setRelhasindex(relid, true);
2247 CommandCounterIncrement();
2249 * However the following setRelhasindex()
2250 * is needed to keep consistency with WAL.
2253 setRelhasindex(relid, true);
2256 SetReindexProcessing(old);