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.113 2000/05/30 04:24:35 tgl Exp $
15 * index_create() - Create a cataloged index relation
16 * index_drop() - Removes index relation from catalogs
19 *-------------------------------------------------------------------------
24 #include "access/genam.h"
25 #include "access/heapam.h"
26 #include "access/istrat.h"
27 #include "bootstrap/bootstrap.h"
28 #include "catalog/catname.h"
29 #include "catalog/heap.h"
30 #include "catalog/index.h"
31 #include "catalog/indexing.h"
32 #include "catalog/pg_proc.h"
33 #include "catalog/pg_type.h"
34 #include "commands/comment.h"
35 #include "executor/executor.h"
36 #include "miscadmin.h"
37 #include "optimizer/clauses.h"
38 #include "optimizer/prep.h"
39 #include "parser/parse_func.h"
40 #include "storage/smgr.h"
41 #include "utils/builtins.h"
42 #include "utils/catcache.h"
43 #include "utils/fmgroids.h"
44 #include "utils/relcache.h"
45 #include "utils/syscache.h"
46 #include "utils/temprel.h"
47 #include "utils/inval.h"
50 * macros used in guessing how many tuples are on a page.
52 #define AVG_ATTR_SIZE 8
53 #define NTUPLES_PER_PAGE(natts) \
54 ((BLCKSZ - MAXALIGN(sizeof (PageHeaderData))) / \
55 ((natts) * AVG_ATTR_SIZE + MAXALIGN(sizeof(HeapTupleHeaderData))))
57 /* non-export function prototypes */
58 static Oid GetHeapRelationOid(char *heapRelationName, char *indexRelationName,
60 static TupleDesc BuildFuncTupleDesc(FuncIndexInfo *funcInfo);
61 static TupleDesc ConstructTupleDescriptor(Oid heapoid, Relation heapRelation,
62 List *attributeList, int numatts, AttrNumber *attNums);
64 static void ConstructIndexReldesc(Relation indexRelation, Oid amoid);
65 static Oid UpdateRelationRelation(Relation indexRelation, char *temp_relname);
66 static void InitializeAttributeOids(Relation indexRelation,
67 int numatts, Oid indexoid);
68 static void AppendAttributeTuples(Relation indexRelation, int numatts);
69 static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
70 FuncIndexInfo *funcInfo, int natts,
71 AttrNumber *attNums, Oid *classOids, Node *predicate,
72 List *attributeList, bool islossy, bool unique, bool primary);
73 static void DefaultBuild(Relation heapRelation, Relation indexRelation,
74 int numberOfAttributes, AttrNumber *attributeNumber,
75 IndexStrategy indexStrategy, uint16 parameterCount,
76 Datum *parameter, FuncIndexInfoPtr funcInfo, PredInfo *predInfo);
77 static Oid IndexGetRelation(Oid indexId);
79 static bool reindexing = false;
81 SetReindexProcessing(bool reindexmode)
83 bool old = reindexing;
85 reindexing = reindexmode;
89 IsReindexProcessing(void)
94 /* ----------------------------------------------------------------
95 * sysatts is a structure containing attribute tuple forms
96 * for system attributes (numbered -1, -2, ...). This really
97 * should be generated or eliminated or moved elsewhere. -cim 1/19/91
99 * typedef struct FormData_pg_attribute {
114 * } FormData_pg_attribute;
116 * ----------------------------------------------------------------
118 static FormData_pg_attribute sysatts[] = {
119 {0, {"ctid"}, TIDOID, 0, 6, -1, 0, -1, -1, '\0', 'p', '\0', 'i', '\0', '\0'},
120 {0, {"oid"}, OIDOID, 0, 4, -2, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
121 {0, {"xmin"}, XIDOID, 0, 4, -3, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
122 {0, {"cmin"}, CIDOID, 0, 4, -4, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
123 {0, {"xmax"}, XIDOID, 0, 4, -5, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
124 {0, {"cmax"}, CIDOID, 0, 4, -6, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
127 /* ----------------------------------------------------------------
129 * ----------------------------------------------------------------
132 GetHeapRelationOid(char *heapRelationName, char *indexRelationName, bool istemp)
138 indoid = RelnameFindRelid(indexRelationName);
140 if ((!istemp && OidIsValid(indoid)) ||
141 (istemp && get_temp_rel_by_username(indexRelationName) != NULL))
142 elog(ERROR, "Cannot create index: '%s' already exists",
145 heapoid = RelnameFindRelid(heapRelationName);
147 if (!OidIsValid(heapoid))
148 elog(ERROR, "Cannot create index on '%s': relation does not exist",
155 BuildFuncTupleDesc(FuncIndexInfo *funcInfo)
158 TupleDesc funcTupDesc;
165 * Allocate and zero a tuple descriptor.
167 funcTupDesc = CreateTemplateTupleDesc(1);
168 funcTupDesc->attrs[0] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
169 MemSet(funcTupDesc->attrs[0], 0, ATTRIBUTE_TUPLE_SIZE);
172 * Lookup the function for the return type.
174 funcname = FIgetname(funcInfo);
175 nargs = FIgetnArgs(funcInfo);
176 argtypes = FIgetArglist(funcInfo);
177 tuple = SearchSysCacheTuple(PROCNAME,
178 PointerGetDatum(funcname),
179 Int32GetDatum(nargs),
180 PointerGetDatum(argtypes),
183 if (!HeapTupleIsValid(tuple))
184 func_error("BuildFuncTupleDesc", funcname, nargs, argtypes, NULL);
186 retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype;
189 * Look up the return type in pg_type for the type length.
191 tuple = SearchSysCacheTuple(TYPEOID,
192 ObjectIdGetDatum(retType),
194 if (!HeapTupleIsValid(tuple))
195 elog(ERROR, "Function %s return type does not exist", FIgetname(funcInfo));
198 * Assign some of the attributes values. Leave the rest as 0.
200 funcTupDesc->attrs[0]->attlen = ((Form_pg_type) GETSTRUCT(tuple))->typlen;
201 funcTupDesc->attrs[0]->atttypid = retType;
202 funcTupDesc->attrs[0]->attnum = 1;
203 funcTupDesc->attrs[0]->attbyval = ((Form_pg_type) GETSTRUCT(tuple))->typbyval;
204 funcTupDesc->attrs[0]->attcacheoff = -1;
205 funcTupDesc->attrs[0]->atttypmod = -1;
206 funcTupDesc->attrs[0]->attstorage = 'p';
207 funcTupDesc->attrs[0]->attalign = ((Form_pg_type) GETSTRUCT(tuple))->typalign;
210 * make the attributes name the same as the functions
212 namestrcpy(&funcTupDesc->attrs[0]->attname, funcname);
217 /* ----------------------------------------------------------------
218 * ConstructTupleDescriptor
219 * ----------------------------------------------------------------
222 ConstructTupleDescriptor(Oid heapoid,
223 Relation heapRelation,
228 TupleDesc heapTupDesc;
229 TupleDesc indexTupDesc;
231 TypeName *IndexKeyType;
232 AttrNumber atnum; /* attributeNumber[attributeOffset] */
234 int natts; /* Form_pg_class->relnatts */
235 char *from; /* used to simplify memcpy below */
236 char *to; /* used to simplify memcpy below */
240 * allocate the new tuple descriptor
243 natts = RelationGetForm(heapRelation)->relnatts;
245 indexTupDesc = CreateTemplateTupleDesc(numatts);
253 * for each attribute we are indexing, obtain its attribute
254 * tuple form from either the static table of system attribute
255 * tuple forms or the relation tuple descriptor
258 for (i = 0; i < numatts; i += 1)
262 * get the attribute number and make sure it's valid
267 elog(ERROR, "Cannot create index: attribute %d does not exist",
271 IndexKey = (IndexElem *) lfirst(attributeList);
272 IndexKeyType = IndexKey->typename;
273 attributeList = lnext(attributeList);
278 indexTupDesc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
281 * determine which tuple descriptor to copy
284 if (!AttrNumberIsForUserDefinedAttr(atnum))
288 * here we are indexing on a system attribute (-1...-12)
289 * so we convert atnum into a usable index 0...11 so we can
290 * use it to dereference the array sysatts[] which stores
291 * tuple descriptor information for system attributes.
294 if (atnum <= FirstLowInvalidHeapAttributeNumber || atnum >= 0)
295 elog(ERROR, "Cannot create index on system attribute: attribute number out of range (%d)", atnum);
296 atind = (-atnum) - 1;
298 from = (char *) (&sysatts[atind]);
304 * here we are indexing on a normal attribute (1...n)
307 heapTupDesc = RelationGetDescr(heapRelation);
308 atind = AttrNumberGetAttrOffset(atnum);
310 from = (char *) (heapTupDesc->attrs[atind]);
314 * now that we've determined the "from", let's copy
315 * the tuple desc data...
319 to = (char *) (indexTupDesc->attrs[i]);
320 memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);
322 ((Form_pg_attribute) to)->attnum = i + 1;
324 ((Form_pg_attribute) to)->attnotnull = false;
325 ((Form_pg_attribute) to)->atthasdef = false;
326 ((Form_pg_attribute) to)->attcacheoff = -1;
327 ((Form_pg_attribute) to)->atttypmod = -1;
328 ((Form_pg_attribute) to)->attalign = 'i';
331 * if the keytype is defined, we need to change the tuple form's
332 * atttypid & attlen field to match that of the key's type
334 if (IndexKeyType != NULL)
338 tup = SearchSysCacheTuple(TYPENAME,
339 PointerGetDatum(IndexKeyType->name),
341 if (!HeapTupleIsValid(tup))
342 elog(ERROR, "create index: type '%s' undefined",
344 ((Form_pg_attribute) to)->atttypid = tup->t_data->t_oid;
345 ((Form_pg_attribute) to)->attbyval =
346 ((Form_pg_type) GETSTRUCT(tup))->typbyval;
347 ((Form_pg_attribute) to)->attlen =
348 ((Form_pg_type) GETSTRUCT(tup))->typlen;
349 ((Form_pg_attribute) to)->attstorage = 'p';
350 ((Form_pg_attribute) to)->attalign =
351 ((Form_pg_type) GETSTRUCT(tup))->typalign;
352 ((Form_pg_attribute) to)->atttypmod = IndexKeyType->typmod;
357 * now we have to drop in the proper relation descriptor
358 * into the copied tuple form's attrelid and we should be
362 ((Form_pg_attribute) to)->attrelid = heapoid;
368 /* ----------------------------------------------------------------
369 * AccessMethodObjectIdGetForm
370 * Returns the formated access method tuple given its object identifier.
375 * Assumes object identifier is valid.
376 * ----------------------------------------------------------------
379 AccessMethodObjectIdGetForm(Oid accessMethodObjectId)
382 HeapScanDesc pg_am_scan;
383 HeapTuple pg_am_tuple;
388 * form a scan key for the pg_am relation
391 ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
393 ObjectIdGetDatum(accessMethodObjectId));
396 * fetch the desired access method tuple
399 pg_am_desc = heap_openr(AccessMethodRelationName, AccessShareLock);
400 pg_am_scan = heap_beginscan(pg_am_desc, 0, SnapshotNow, 1, &key);
402 pg_am_tuple = heap_getnext(pg_am_scan, 0);
405 * return NULL if not found
408 if (!HeapTupleIsValid(pg_am_tuple))
410 heap_endscan(pg_am_scan);
411 heap_close(pg_am_desc, AccessShareLock);
416 * if found am tuple, then copy the form and return the copy
419 aform = (Form_pg_am) palloc(sizeof *aform);
420 memcpy(aform, GETSTRUCT(pg_am_tuple), sizeof *aform);
422 heap_endscan(pg_am_scan);
423 heap_close(pg_am_desc, AccessShareLock);
428 /* ----------------------------------------------------------------
429 * ConstructIndexReldesc
430 * ----------------------------------------------------------------
433 ConstructIndexReldesc(Relation indexRelation, Oid amoid)
435 MemoryContext oldcxt;
438 * here we make certain to allocate the access method
439 * tuple within the cache context lest it vanish when the
444 CacheCxt = CreateGlobalMemory("Cache");
446 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
448 indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid);
450 MemoryContextSwitchTo(oldcxt);
453 * XXX missing the initialization of some other fields
457 indexRelation->rd_rel->relowner = GetUserId();
459 indexRelation->rd_rel->relam = amoid;
460 indexRelation->rd_rel->reltuples = 1; /* XXX */
461 indexRelation->rd_rel->relkind = RELKIND_INDEX;
464 /* ----------------------------------------------------------------
465 * UpdateRelationRelation
466 * ----------------------------------------------------------------
469 UpdateRelationRelation(Relation indexRelation, char *temp_relname)
474 Relation idescs[Num_pg_class_indices];
476 pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
478 /* XXX Natts_pg_class_fixed is a hack - see pg_class.h */
479 tuple = heap_addheader(Natts_pg_class_fixed,
480 sizeof(*indexRelation->rd_rel),
481 (char *) indexRelation->rd_rel);
484 * the new tuple must have the same oid as the relcache entry for the
485 * index. sure would be embarassing to do this sort of thing in polite
489 tuple->t_data->t_oid = RelationGetRelid(indexRelation);
490 heap_insert(pg_class, tuple);
493 create_temp_relation(temp_relname, tuple);
496 * During normal processing, we need to make sure that the system
497 * catalog indices are correct. Bootstrap (initdb) time doesn't
498 * require this, because we make sure that the indices are correct
499 * just before exiting.
502 if (!IsIgnoringSystemIndexes())
504 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
505 CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, tuple);
506 CatalogCloseIndices(Num_pg_class_indices, idescs);
509 tupleOid = tuple->t_data->t_oid;
510 heap_freetuple(tuple);
511 heap_close(pg_class, RowExclusiveLock);
516 /* ----------------------------------------------------------------
517 * InitializeAttributeOids
518 * ----------------------------------------------------------------
521 InitializeAttributeOids(Relation indexRelation,
525 TupleDesc tupleDescriptor;
528 tupleDescriptor = RelationGetDescr(indexRelation);
530 for (i = 0; i < numatts; i += 1)
531 tupleDescriptor->attrs[i]->attrelid = indexoid;
534 /* ----------------------------------------------------------------
535 * AppendAttributeTuples
537 * XXX For now, only change the ATTNUM attribute value
538 * ----------------------------------------------------------------
541 AppendAttributeTuples(Relation indexRelation, int numatts)
543 Relation pg_attribute;
544 HeapTuple init_tuple,
548 Relation idescs[Num_pg_attr_indices];
550 Datum value[Natts_pg_attribute];
551 char nullv[Natts_pg_attribute];
552 char replace[Natts_pg_attribute];
554 TupleDesc indexTupDesc;
558 * open the attribute relation
562 pg_attribute = heap_openr(AttributeRelationName, RowExclusiveLock);
565 * initialize *null, *replace and *value
568 MemSet(nullv, ' ', Natts_pg_attribute);
569 MemSet(replace, ' ', Natts_pg_attribute);
572 * create the first attribute tuple.
573 * XXX For now, only change the ATTNUM attribute value
576 replace[Anum_pg_attribute_attnum - 1] = 'r';
577 replace[Anum_pg_attribute_attcacheoff - 1] = 'r';
579 value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(1);
580 value[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1);
582 init_tuple = heap_addheader(Natts_pg_attribute,
583 ATTRIBUTE_TUPLE_SIZE,
584 (char *) (indexRelation->rd_att->attrs[0]));
587 if (!IsIgnoringSystemIndexes() && pg_attribute->rd_rel->relhasindex)
590 CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
594 * insert the first attribute tuple.
597 cur_tuple = heap_modifytuple(init_tuple,
602 heap_freetuple(init_tuple);
604 heap_insert(pg_attribute, cur_tuple);
606 CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, cur_tuple);
609 * now we use the information in the index cur_tuple
610 * descriptor to form the remaining attribute tuples.
613 indexTupDesc = RelationGetDescr(indexRelation);
615 for (i = 1; i < numatts; i += 1)
618 * process the remaining attributes...
621 memmove(GETSTRUCT(cur_tuple),
622 (char *) indexTupDesc->attrs[i],
623 ATTRIBUTE_TUPLE_SIZE);
625 value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(i + 1);
627 new_tuple = heap_modifytuple(cur_tuple,
632 heap_freetuple(cur_tuple);
634 heap_insert(pg_attribute, new_tuple);
636 CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, new_tuple);
639 * ModifyHeapTuple returns a new copy of a cur_tuple
640 * so we free the original and use the copy..
643 cur_tuple = new_tuple;
647 heap_freetuple(cur_tuple);
648 heap_close(pg_attribute, RowExclusiveLock);
650 CatalogCloseIndices(Num_pg_attr_indices, idescs);
654 /* ----------------------------------------------------------------
655 * UpdateIndexRelation
656 * ----------------------------------------------------------------
659 UpdateIndexRelation(Oid indexoid,
661 FuncIndexInfo *funcInfo,
671 Form_pg_index indexForm;
680 Relation idescs[Num_pg_index_indices];
683 * allocate an Form_pg_index big enough to hold the
684 * index-predicate (if any) in string form
687 if (predicate != NULL)
689 predString = nodeToString(predicate);
690 predText = textin(predString);
694 predText = textin("");
696 predLen = VARSIZE(predText);
697 itupLen = predLen + sizeof(FormData_pg_index);
698 indexForm = (Form_pg_index) palloc(itupLen);
699 memset(indexForm, 0, sizeof(FormData_pg_index));
701 memmove((char *) &indexForm->indpred, (char *) predText, predLen);
704 * store the oid information into the index tuple form
707 indexForm->indrelid = heapoid;
708 indexForm->indexrelid = indexoid;
709 indexForm->indproc = (PointerIsValid(funcInfo)) ?
710 FIgetProcOid(funcInfo) : InvalidOid;
711 indexForm->indislossy = islossy;
712 indexForm->indisprimary = primary;
713 indexForm->indisunique = unique;
715 indexForm->indhaskeytype = 0;
716 while (attributeList != NIL)
718 IndexKey = (IndexElem *) lfirst(attributeList);
719 if (IndexKey->typename != NULL)
721 indexForm->indhaskeytype = 1;
724 attributeList = lnext(attributeList);
727 MemSet((char *) &indexForm->indkey[0], 0, sizeof indexForm->indkey);
728 MemSet((char *) &indexForm->indclass[0], 0, sizeof indexForm->indclass);
731 * copy index key and op class information
734 for (i = 0; i < natts; i += 1)
736 indexForm->indkey[i] = attNums[i];
737 indexForm->indclass[i] = classOids[i];
741 * If we have a functional index, add all attribute arguments
743 if (PointerIsValid(funcInfo))
745 for (i = 1; i < FIgetnArgs(funcInfo); i++)
746 indexForm->indkey[i] = attNums[i];
749 indexForm->indisclustered = '\0'; /* XXX constant */
752 * open the system catalog index relation
755 pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
758 * form a tuple to insert into pg_index
761 tuple = heap_addheader(Natts_pg_index,
766 * insert the tuple into the pg_index
767 * XXX ADD INDEX TUPLES TOO
770 heap_insert(pg_index, tuple);
773 * insert the index tuple into the pg_index
776 if (!IsIgnoringSystemIndexes())
778 CatalogOpenIndices(Num_pg_index_indices, Name_pg_index_indices, idescs);
779 CatalogIndexInsert(idescs, Num_pg_index_indices, pg_index, tuple);
780 CatalogCloseIndices(Num_pg_index_indices, idescs);
783 * close the relation and free the tuple
786 heap_close(pg_index, RowExclusiveLock);
789 heap_freetuple(tuple);
792 /* ----------------------------------------------------------------
793 * UpdateIndexPredicate
794 * ----------------------------------------------------------------
797 UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
806 Datum values[Natts_pg_index];
807 char nulls[Natts_pg_index];
808 char replace[Natts_pg_index];
811 * Construct newPred as a CNF expression equivalent to the OR of the
812 * original partial-index predicate ("oldPred") and the extension
813 * predicate ("predicate").
815 * This should really try to process the result to change things like
816 * "a>2 OR a>1" to simply "a>1", but for now all it does is make sure
817 * that if the extension predicate is NULL (i.e., it is being extended
818 * to be a complete index), then newPred will be NULL - in effect,
819 * changing "a>2 OR TRUE" to "TRUE". --Nels, Jan '93
822 if (predicate != NULL)
824 newPred = (Node *) make_orclause(lcons(make_andclause((List *) predicate),
825 lcons(make_andclause((List *) oldPred),
827 newPred = (Node *) cnfify((Expr *) newPred, true);
830 /* translate the index-predicate to string form */
833 predString = nodeToString(newPred);
834 predText = textin(predString);
838 predText = textin("");
840 /* open the index system catalog relation */
841 pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
843 tuple = SearchSysCacheTuple(INDEXRELID,
844 ObjectIdGetDatum(indexoid),
846 Assert(HeapTupleIsValid(tuple));
848 for (i = 0; i < Natts_pg_index; i++)
850 nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' ';
852 values[i] = (Datum) NULL;
855 replace[Anum_pg_index_indpred - 1] = 'r';
856 values[Anum_pg_index_indpred - 1] = (Datum) predText;
858 newtup = heap_modifytuple(tuple, pg_index, values, nulls, replace);
860 heap_update(pg_index, &newtup->t_self, newtup, NULL);
862 heap_freetuple(newtup);
863 heap_close(pg_index, RowExclusiveLock);
867 /* ----------------------------------------------------------------
869 * ----------------------------------------------------------------
872 InitIndexStrategy(int numatts,
873 Relation indexRelation,
874 Oid accessMethodObjectId)
876 IndexStrategy strategy;
877 RegProcedure *support;
884 * get information from the index relation descriptor
887 attrelid = indexRelation->rd_att->attrs[0]->attrelid;
888 amstrategies = indexRelation->rd_am->amstrategies;
889 amsupport = indexRelation->rd_am->amsupport;
892 * get the size of the strategy
895 strsize = AttributeNumberGetIndexStrategySize(numatts, amstrategies);
898 * allocate the new index strategy structure
900 * the index strategy has to be allocated in the same
901 * context as the relation descriptor cache or else
902 * it will be lost at the end of the transaction.
906 CacheCxt = CreateGlobalMemory("Cache");
908 strategy = (IndexStrategy)
909 MemoryContextAlloc((MemoryContext) CacheCxt, strsize);
913 strsize = numatts * (amsupport * sizeof(RegProcedure));
914 support = (RegProcedure *) MemoryContextAlloc((MemoryContext) CacheCxt,
918 support = (RegProcedure *) NULL;
921 * fill in the index strategy structure with information
922 * from the catalogs. First we must advance the command counter
923 * so that we will see the newly-entered index catalog tuples.
926 CommandCounterIncrement();
928 IndexSupportInitialize(strategy, support,
929 attrelid, accessMethodObjectId,
930 amstrategies, amsupport, numatts);
933 * store the strategy information in the index reldesc
936 RelationSetIndexSupport(indexRelation, strategy, support);
940 /* ----------------------------------------------------------------
942 * ----------------------------------------------------------------
945 index_create(char *heapRelationName,
946 char *indexRelationName,
947 FuncIndexInfo *funcInfo,
949 Oid accessMethodObjectId,
953 uint16 parameterCount,
960 Relation heapRelation;
961 Relation indexRelation;
962 TupleDesc indexTupDesc;
966 bool istemp = (get_temp_rel_by_username(heapRelationName) != NULL);
967 char *temp_relname = NULL;
973 SetReindexProcessing(false);
975 elog(ERROR, "must index at least one attribute");
978 * get heap relation oid and open the heap relation
982 heapoid = GetHeapRelationOid(heapRelationName, indexRelationName, istemp);
985 * Only SELECT ... FOR UPDATE are allowed while doing this
987 heapRelation = heap_open(heapoid, ShareLock);
990 * construct new tuple descriptor
993 if (PointerIsValid(funcInfo))
994 indexTupDesc = BuildFuncTupleDesc(funcInfo);
996 indexTupDesc = ConstructTupleDescriptor(heapoid,
1002 /* save user relation name because heap_create changes it */
1005 temp_relname = pstrdup(indexRelationName); /* save original value */
1006 indexRelationName = palloc(NAMEDATALEN);
1007 strcpy(indexRelationName, temp_relname); /* heap_create will
1012 * create the index relation
1015 indexRelation = heap_create(indexRelationName,
1016 indexTupDesc, false, istemp, false);
1019 * construct the index relation descriptor
1021 * XXX should have a proper way to create cataloged relations
1024 ConstructIndexReldesc(indexRelation, accessMethodObjectId);
1027 * add index to catalogs
1028 * (append RELATION tuple)
1031 indexoid = UpdateRelationRelation(indexRelation, temp_relname);
1034 * We create the disk file for this relation here
1036 heap_storage_create(indexRelation);
1039 * now update the object id's of all the attribute
1040 * tuple forms in the index relation's tuple descriptor
1043 InitializeAttributeOids(indexRelation, numatts, indexoid);
1046 * append ATTRIBUTE tuples
1049 AppendAttributeTuples(indexRelation, numatts);
1053 * (append INDEX tuple)
1055 * Note that this stows away a representation of "predicate".
1056 * (Or, could define a rule to maintain the predicate) --Nels, Feb '92
1059 UpdateIndexRelation(indexoid, heapoid, funcInfo,
1060 numatts, attNums, classObjectId, predicate,
1061 attributeList, islossy, unique, primary);
1063 predInfo = (PredInfo *) palloc(sizeof(PredInfo));
1064 predInfo->pred = predicate;
1065 predInfo->oldPred = NULL;
1068 * initialize the index strategy
1071 InitIndexStrategy(numatts, indexRelation, accessMethodObjectId);
1074 * If this is bootstrap (initdb) time, then we don't actually fill in
1075 * the index yet. We'll be creating more indices and classes later,
1076 * so we delay filling them in until just before we're done with
1077 * bootstrapping. Otherwise, we call the routine that constructs the
1080 * In normal processing mode, the heap and index relations are closed by
1081 * index_build() --- but we continue to hold the ShareLock on the heap
1082 * that we acquired above, until end of transaction.
1084 if (IsBootstrapProcessingMode())
1086 index_register(heapRelationName, indexRelationName, numatts, attNums,
1087 parameterCount, parameter, funcInfo, predInfo);
1088 /* XXX shouldn't we close the heap and index rels here? */
1092 index_build(heapRelation, indexRelation, numatts, attNums,
1093 parameterCount, parameter, funcInfo, predInfo);
1097 /* ----------------------------------------------------------------
1101 * ----------------------------------------------------------------
1104 index_drop(Oid indexId)
1106 Relation userHeapRelation;
1107 Relation userIndexRelation;
1108 Relation indexRelation;
1109 Relation relationRelation;
1110 Relation attributeRelation;
1114 Assert(OidIsValid(indexId));
1117 * To drop an index safely, we must grab exclusive lock on its parent
1118 * table; otherwise there could be other backends using the index!
1119 * Exclusive lock on the index alone is insufficient because the index
1120 * access routines are a little slipshod about obtaining adequate locking
1121 * (see ExecOpenIndices()). We do grab exclusive lock on the index too,
1122 * just to be safe. Both locks must be held till end of transaction,
1123 * else other backends will still see this index in pg_index.
1126 userHeapRelation = heap_open(IndexGetRelation(indexId),
1127 AccessExclusiveLock);
1129 userIndexRelation = index_open(indexId);
1130 LockRelation(userIndexRelation, AccessExclusiveLock);
1133 * DROP INDEX within a transaction block is dangerous, because
1134 * if the transaction is later rolled back there will be no way to
1135 * undo the unlink of the relation's physical file. For now, allow it
1136 * but emit a warning message.
1137 * Someday we might want to consider postponing the physical unlink
1138 * until transaction commit, but that's a lot of work...
1139 * The only case that actually works right is for relations created
1140 * in the current transaction, since the post-abort state would be that
1141 * they don't exist anyway. So, no warning in that case.
1144 if (IsTransactionBlock() && !userIndexRelation->rd_myxactonly)
1145 elog(NOTICE, "Caution: DROP INDEX cannot be rolled back, so don't abort now");
1148 * fix DESCRIPTION relation
1151 DeleteComments(indexId);
1154 * fix RELATION relation
1157 relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
1159 tuple = SearchSysCacheTupleCopy(RELOID,
1160 ObjectIdGetDatum(indexId),
1163 Assert(HeapTupleIsValid(tuple));
1165 heap_delete(relationRelation, &tuple->t_self, NULL);
1166 heap_freetuple(tuple);
1167 heap_close(relationRelation, RowExclusiveLock);
1170 * fix ATTRIBUTE relation
1173 attributeRelation = heap_openr(AttributeRelationName, RowExclusiveLock);
1175 attnum = 1; /* indexes start at 1 */
1177 while (HeapTupleIsValid(tuple = SearchSysCacheTupleCopy(ATTNUM,
1178 ObjectIdGetDatum(indexId),
1179 Int16GetDatum(attnum),
1182 heap_delete(attributeRelation, &tuple->t_self, NULL);
1183 heap_freetuple(tuple);
1186 heap_close(attributeRelation, RowExclusiveLock);
1189 * fix INDEX relation
1192 indexRelation = heap_openr(IndexRelationName, RowExclusiveLock);
1194 tuple = SearchSysCacheTupleCopy(INDEXRELID,
1195 ObjectIdGetDatum(indexId),
1197 Assert(HeapTupleIsValid(tuple));
1199 heap_delete(indexRelation, &tuple->t_self, NULL);
1200 heap_freetuple(tuple);
1201 heap_close(indexRelation, RowExclusiveLock);
1204 * flush buffer cache and physically remove the file
1206 ReleaseRelationBuffers(userIndexRelation);
1208 if (smgrunlink(DEFAULT_SMGR, userIndexRelation) != SM_SUCCESS)
1209 elog(ERROR, "index_drop: unlink: %m");
1212 * Close rels, but keep locks
1214 index_close(userIndexRelation);
1215 heap_close(userHeapRelation, NoLock);
1217 RelationForgetRelation(indexId);
1219 /* does something only if it is a temp index */
1220 remove_temp_relation(indexId);
1223 /* ----------------------------------------------------------------
1224 * index_build support
1225 * ----------------------------------------------------------------
1232 FormIndexDatum(int numberOfAttributes,
1233 AttrNumber *attributeNumber,
1234 HeapTuple heapTuple,
1235 TupleDesc heapDescriptor,
1238 FuncIndexInfoPtr fInfo)
1245 * for each attribute we need from the heap tuple,
1246 * get the attribute and stick it into the datum and
1251 for (i = 1; i <= numberOfAttributes; i++)
1253 offset = AttrNumberGetAttrOffset(i);
1255 datum[offset] = PointerGetDatum(GetIndexValue(heapTuple,
1262 nullv[offset] = (isNull) ? 'n' : ' ';
1267 /* --------------------------------------------
1268 * Lock class info for update
1269 * --------------------------------------------
1273 LockClassinfoForUpdate(Oid relid, HeapTuple rtup, Buffer *buffer, bool confirmCommitted)
1275 HeapTuple classTuple;
1276 Form_pg_class pgcform;
1278 Relation relationRelation;
1280 classTuple = SearchSysCacheTuple(RELOID, PointerGetDatum(relid),
1282 if (!HeapTupleIsValid(classTuple))
1284 rtup->t_self = classTuple->t_self;
1285 pgcform = (Form_pg_class) GETSTRUCT(classTuple);
1286 relationRelation = heap_openr(RelationRelationName, RowShareLock);
1287 test = heap_mark4update(relationRelation, rtup, buffer);
1290 case HeapTupleSelfUpdated:
1291 case HeapTupleMayBeUpdated:
1294 elog(ERROR, "LockStatsForUpdate couldn't lock relid %u", relid);
1297 RelationInvalidateHeapTuple(relationRelation, rtup);
1298 if (confirmCommitted)
1300 HeapTupleHeader th = rtup->t_data;
1302 if (!(th->t_infomask & HEAP_XMIN_COMMITTED))
1303 elog(ERROR, "The tuple isn't committed");
1304 if (th->t_infomask & HEAP_XMAX_COMMITTED)
1305 if (!(th->t_infomask & HEAP_MARKED_FOR_UPDATE))
1306 elog(ERROR, "The tuple is already deleted");
1308 heap_close(relationRelation, NoLock);
1312 /* ---------------------------------------------
1313 * Indexes of the relation active ?
1314 * ---------------------------------------------
1317 IndexesAreActive(Oid relid, bool confirmCommitted)
1319 HeapTupleData tuple;
1320 Relation indexRelation;
1326 if (!LockClassinfoForUpdate(relid, &tuple, &buffer, confirmCommitted))
1327 elog(ERROR, "IndexesAreActive couldn't lock %u", relid);
1328 if (((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_RELATION)
1329 elog(ERROR, "relation %u isn't an relation", relid);
1330 isactive = ((Form_pg_class) GETSTRUCT(&tuple))->relhasindex;
1331 ReleaseBuffer(buffer);
1334 indexRelation = heap_openr(IndexRelationName, AccessShareLock);
1335 ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid,
1336 F_OIDEQ, ObjectIdGetDatum(relid));
1337 scan = heap_beginscan(indexRelation, false, SnapshotNow,
1339 if (!heap_getnext(scan, 0))
1342 heap_close(indexRelation, NoLock);
1347 * set relhasindex of pg_class in place
1351 setRelhasindexInplace(Oid relid, bool hasindex, bool immediate)
1356 Form_pg_class rd_rel;
1357 HeapScanDesc pg_class_scan = NULL;
1360 * This routine handles updates for only the heap relation
1361 * hasindex. In order to guarantee that we're able to *see* the index
1362 * relation tuple, we bump the command counter id here.
1365 CommandCounterIncrement();
1368 * CommandCounterIncrement() flushes invalid cache entries, including
1369 * those for the heap and index relations for which we're updating
1370 * statistics. Now that the cache is flushed, it's safe to open the
1371 * relation again. We need the relation open in order to figure out
1372 * how many blocks it contains.
1376 whichRel = heap_open(relid, ShareLock);
1378 if (!RelationIsValid(whichRel))
1379 elog(ERROR, "setRelhasindexInplace: cannot open relation id %u", relid);
1382 * Find the RELATION relation tuple for the given relation.
1385 pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
1386 if (!RelationIsValid(pg_class))
1387 elog(ERROR, "setRelhasindexInplace: could not open RELATION relation");
1389 if (!IsIgnoringSystemIndexes())
1391 tuple = SearchSysCacheTupleCopy(RELOID,
1392 ObjectIdGetDatum(relid), 0, 0, 0);
1398 ScanKeyEntryInitialize(&key[0], 0,
1399 ObjectIdAttributeNumber,
1401 ObjectIdGetDatum(relid));
1403 pg_class_scan = heap_beginscan(pg_class, 0, SnapshotNow, 1, key);
1404 tuple = heap_getnext(pg_class_scan, 0);
1407 if (!HeapTupleIsValid(tuple))
1410 heap_endscan(pg_class_scan);
1411 heap_close(pg_class, RowExclusiveLock);
1412 elog(ERROR, "setRelhasindexInplace: cannot scan RELATION relation");
1416 * Confirm that target tuple is locked by this transaction in case of
1417 * immedaite updation.
1421 HeapTupleHeader th = tuple->t_data;
1423 if (!(th->t_infomask & HEAP_XMIN_COMMITTED))
1424 elog(ERROR, "Immediate hasindex updation can be done only for committed tuples %x", th->t_infomask);
1425 if (th->t_infomask & HEAP_XMAX_INVALID)
1426 elog(ERROR, "Immediate hasindex updation can be done only for locked tuples %x", th->t_infomask);
1427 if (th->t_infomask & HEAP_XMAX_COMMITTED)
1428 elog(ERROR, "Immediate hasindex updation can be done only for locked tuples %x", th->t_infomask);
1429 if (!(th->t_infomask & HEAP_MARKED_FOR_UPDATE))
1430 elog(ERROR, "Immediate hasindex updation can be done only for locked tuples %x", th->t_infomask);
1431 if (!(TransactionIdIsCurrentTransactionId(th->t_xmax)))
1432 elog(ERROR, "The updating tuple is already locked by another backend");
1436 * We shouldn't have to do this, but we do... Modify the reldesc in
1437 * place with the new values so that the cache contains the latest
1440 whichRel->rd_rel->relhasindex = hasindex;
1443 * Update hasindex in pg_class.
1449 if (!IsBootstrapProcessingMode())
1450 ImmediateInvalidateSharedHeapTuple(pg_class, tuple);
1451 rd_rel = (Form_pg_class) GETSTRUCT(tuple);
1452 rd_rel->relhasindex = hasindex;
1453 WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
1460 htup.t_self = tuple->t_self;
1461 heap_fetch(pg_class, SnapshotNow, &htup, &buffer);
1462 ImmediateInvalidateSharedHeapTuple(pg_class, tuple);
1463 rd_rel = (Form_pg_class) GETSTRUCT(&htup);
1464 rd_rel->relhasindex = hasindex;
1465 WriteBuffer(buffer);
1469 heap_freetuple(tuple);
1471 heap_endscan(pg_class_scan);
1473 heap_close(pg_class, NoLock);
1474 heap_close(whichRel, NoLock);
1482 UpdateStats(Oid relid, long reltuples, bool inplace)
1490 Form_pg_class rd_rel;
1491 Relation idescs[Num_pg_class_indices];
1492 Datum values[Natts_pg_class];
1493 char nulls[Natts_pg_class];
1494 char replace[Natts_pg_class];
1495 HeapScanDesc pg_class_scan = NULL;
1499 * This routine handles updates for both the heap and index relation
1500 * statistics. In order to guarantee that we're able to *see* the index
1501 * relation tuple, we bump the command counter id here. The index
1502 * relation tuple was created in the current transaction.
1505 CommandCounterIncrement();
1508 * CommandCounterIncrement() flushes invalid cache entries, including
1509 * those for the heap and index relations for which we're updating
1510 * statistics. Now that the cache is flushed, it's safe to open the
1511 * relation again. We need the relation open in order to figure out
1512 * how many blocks it contains.
1517 * Can't use heap_open here since we don't know if it's an index...
1519 whichRel = RelationIdGetRelation(relid);
1521 if (!RelationIsValid(whichRel))
1522 elog(ERROR, "UpdateStats: cannot open relation id %u", relid);
1524 LockRelation(whichRel, ShareLock);
1527 * Find the RELATION relation tuple for the given relation.
1530 pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
1531 if (!RelationIsValid(pg_class))
1532 elog(ERROR, "UpdateStats: could not open RELATION relation");
1534 in_place_upd = (inplace || IsBootstrapProcessingMode());
1537 tuple = SearchSysCacheTupleCopy(RELOID,
1538 ObjectIdGetDatum(relid),
1545 ScanKeyEntryInitialize(&key[0], 0,
1546 ObjectIdAttributeNumber,
1548 ObjectIdGetDatum(relid));
1550 pg_class_scan = heap_beginscan(pg_class, 0, SnapshotNow, 1, key);
1551 tuple = heap_getnext(pg_class_scan, 0);
1554 if (!HeapTupleIsValid(tuple))
1557 heap_endscan(pg_class_scan);
1558 heap_close(pg_class, RowExclusiveLock);
1559 elog(ERROR, "UpdateStats: cannot scan RELATION relation");
1563 * Figure values to insert.
1565 * If we found zero tuples in the scan, do NOT believe it; instead put
1566 * a bogus estimate into the statistics fields. Otherwise, the common
1567 * pattern "CREATE TABLE; CREATE INDEX; insert data" leaves the table
1568 * with zero size statistics until a VACUUM is done. The optimizer will
1569 * generate very bad plans if the stats claim the table is empty when
1570 * it is actually sizable. See also CREATE TABLE in heap.c.
1573 relpages = RelationGetNumberOfBlocks(whichRel);
1579 /* Bogus defaults for a virgin table, same as heap.c */
1583 else if (whichRel->rd_rel->relkind == RELKIND_INDEX && relpages <= 2)
1585 /* Empty index, leave bogus defaults in place */
1589 reltuples = relpages * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
1593 * We shouldn't have to do this, but we do... Modify the reldesc in
1594 * place with the new values so that the cache contains the latest
1597 whichRel->rd_rel->relpages = relpages;
1598 whichRel->rd_rel->reltuples = reltuples;
1601 * Update statistics in pg_class.
1608 * At bootstrap time, we don't need to worry about concurrency or
1609 * visibility of changes, so we cheat.
1611 if (!IsBootstrapProcessingMode())
1612 ImmediateInvalidateSharedHeapTuple(pg_class, tuple);
1613 rd_rel = (Form_pg_class) GETSTRUCT(tuple);
1614 rd_rel->relpages = relpages;
1615 rd_rel->reltuples = reltuples;
1616 WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
1620 /* During normal processing, must work harder. */
1622 for (i = 0; i < Natts_pg_class; i++)
1624 nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' ';
1626 values[i] = (Datum) NULL;
1629 replace[Anum_pg_class_relpages - 1] = 'r';
1630 values[Anum_pg_class_relpages - 1] = (Datum) relpages;
1631 replace[Anum_pg_class_reltuples - 1] = 'r';
1632 values[Anum_pg_class_reltuples - 1] = (Datum) reltuples;
1633 newtup = heap_modifytuple(tuple, pg_class, values, nulls, replace);
1634 heap_update(pg_class, &tuple->t_self, newtup, NULL);
1635 if (!IsIgnoringSystemIndexes())
1637 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
1638 CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, newtup);
1639 CatalogCloseIndices(Num_pg_class_indices, idescs);
1641 heap_freetuple(newtup);
1645 heap_freetuple(tuple);
1647 heap_endscan(pg_class_scan);
1649 heap_close(pg_class, RowExclusiveLock);
1650 /* Cheating a little bit since we didn't open it with heap_open... */
1651 heap_close(whichRel, ShareLock);
1655 /* -------------------------
1656 * FillDummyExprContext
1657 * Sets up dummy ExprContext and TupleTableSlot objects for use
1660 * NOTE: buffer is passed for historical reasons; it should
1661 * almost certainly always be InvalidBuffer.
1662 * -------------------------
1665 FillDummyExprContext(ExprContext *econtext,
1666 TupleTableSlot *slot,
1670 econtext->ecxt_scantuple = slot;
1671 econtext->ecxt_innertuple = NULL;
1672 econtext->ecxt_outertuple = NULL;
1673 econtext->ecxt_param_list_info = NULL;
1674 econtext->ecxt_range_table = NULL;
1676 slot->ttc_tupleDescriptor = tupdesc;
1677 slot->ttc_buffer = buffer;
1678 slot->ttc_shouldFree = false;
1688 DefaultBuild(Relation heapRelation,
1689 Relation indexRelation,
1690 int numberOfAttributes,
1691 AttrNumber *attributeNumber,
1692 IndexStrategy indexStrategy, /* not used */
1693 uint16 parameterCount, /* not used */
1694 Datum *parameter, /* not used */
1695 FuncIndexInfoPtr funcInfo,
1699 HeapTuple heapTuple;
1700 IndexTuple indexTuple;
1701 TupleDesc heapDescriptor;
1702 TupleDesc indexDescriptor;
1708 #ifndef OMIT_PARTIAL_INDEX
1709 ExprContext *econtext;
1710 TupleTable tupleTable;
1711 TupleTableSlot *slot;
1717 InsertIndexResult insertResult;
1720 * more & better checking is needed
1723 Assert(OidIsValid(indexRelation->rd_rel->relam)); /* XXX */
1726 * get the tuple descriptors from the relations so we know
1727 * how to form the index tuples..
1730 heapDescriptor = RelationGetDescr(heapRelation);
1731 indexDescriptor = RelationGetDescr(indexRelation);
1734 * datum and null are arrays in which we collect the index attributes
1735 * when forming a new index tuple.
1738 datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
1739 nullv = (char *) palloc(numberOfAttributes * sizeof *nullv);
1742 * If this is a predicate (partial) index, we will need to evaluate
1743 * the predicate using ExecQual, which requires the current tuple to
1744 * be in a slot of a TupleTable. In addition, ExecQual must have an
1745 * ExprContext referring to that slot. Here, we initialize dummy
1746 * TupleTable and ExprContext objects for this purpose. --Nels, Feb
1750 predicate = predInfo->pred;
1751 oldPred = predInfo->oldPred;
1753 #ifndef OMIT_PARTIAL_INDEX
1754 if (predicate != NULL || oldPred != NULL)
1756 tupleTable = ExecCreateTupleTable(1);
1757 slot = ExecAllocTableSlot(tupleTable);
1758 econtext = makeNode(ExprContext);
1759 FillDummyExprContext(econtext, slot, heapDescriptor, InvalidBuffer);
1767 #endif /* OMIT_PARTIAL_INDEX */
1770 * Ok, begin our scan of the base relation.
1773 scan = heap_beginscan(heapRelation, /* relation */
1774 0, /* start at end */
1775 SnapshotNow, /* seeself */
1776 0, /* number of keys */
1777 (ScanKey) NULL); /* scan key */
1779 reltuples = indtuples = 0;
1782 * for each tuple in the base relation, we create an index
1783 * tuple and add it to the index relation. We keep a running
1784 * count of the number of tuples so that we can update pg_class
1785 * with correct statistics when we're done building the index.
1788 while (HeapTupleIsValid(heapTuple = heap_getnext(scan, 0)))
1792 #ifndef OMIT_PARTIAL_INDEX
1795 * If oldPred != NULL, this is an EXTEND INDEX command, so skip
1796 * this tuple if it was already in the existing partial index
1798 if (oldPred != NULL)
1800 /* SetSlotContents(slot, heapTuple); */
1801 slot->val = heapTuple;
1802 if (ExecQual((List *) oldPred, econtext, false))
1810 * Skip this tuple if it doesn't satisfy the partial-index
1813 if (predicate != NULL)
1815 /* SetSlotContents(slot, heapTuple); */
1816 slot->val = heapTuple;
1817 if (!ExecQual((List *) predicate, econtext, false))
1820 #endif /* OMIT_PARTIAL_INDEX */
1825 * FormIndexDatum fills in its datum and null parameters
1826 * with attribute information taken from the given heap tuple.
1829 FormIndexDatum(numberOfAttributes, /* num attributes */
1830 attributeNumber, /* array of att nums to extract */
1831 heapTuple, /* tuple from base relation */
1832 heapDescriptor, /* heap tuple's descriptor */
1833 datum, /* return: array of attributes */
1834 nullv, /* return: array of char's */
1837 indexTuple = index_formtuple(indexDescriptor,
1841 indexTuple->t_tid = heapTuple->t_self;
1843 insertResult = index_insert(indexRelation, datum, nullv,
1844 &(heapTuple->t_self), heapRelation);
1847 pfree(insertResult);
1853 #ifndef OMIT_PARTIAL_INDEX
1854 if (predicate != NULL || oldPred != NULL)
1856 /* parameter was 'false', almost certainly wrong --- tgl 9/21/99 */
1857 ExecDropTupleTable(tupleTable, true);
1859 #endif /* OMIT_PARTIAL_INDEX */
1865 * Since we just counted the tuples in the heap, we update its stats
1866 * in pg_class to guarantee that the planner takes advantage of the
1867 * index we just created. But, only update statistics during normal
1868 * index definitions, not for indices on system catalogs created
1869 * during bootstrap processing. We must close the relations before
1870 * updating statistics to guarantee that the relcache entries are
1871 * flushed when we increment the command counter in UpdateStats(). But
1872 * we do not release any locks on the relations; those will be held
1873 * until end of transaction.
1875 if (IsNormalProcessingMode())
1877 Oid hrelid = RelationGetRelid(heapRelation);
1878 Oid irelid = RelationGetRelid(indexRelation);
1879 bool inplace = IsReindexProcessing();
1881 heap_close(heapRelation, NoLock);
1882 index_close(indexRelation);
1883 UpdateStats(hrelid, reltuples, inplace);
1884 UpdateStats(irelid, indtuples, inplace);
1885 if (oldPred != NULL)
1887 if (indtuples == reltuples)
1890 UpdateIndexPredicate(irelid, oldPred, predicate);
1900 index_build(Relation heapRelation,
1901 Relation indexRelation,
1902 int numberOfAttributes,
1903 AttrNumber *attributeNumber,
1904 uint16 parameterCount,
1906 FuncIndexInfo *funcInfo,
1909 RegProcedure procedure;
1915 Assert(RelationIsValid(indexRelation));
1916 Assert(PointerIsValid(indexRelation->rd_am));
1918 procedure = indexRelation->rd_am->ambuild;
1921 * use the access method build procedure if supplied..
1924 if (RegProcedureIsValid(procedure))
1925 OidFunctionCall9(procedure,
1926 PointerGetDatum(heapRelation),
1927 PointerGetDatum(indexRelation),
1928 Int32GetDatum(numberOfAttributes),
1929 PointerGetDatum(attributeNumber),
1930 PointerGetDatum(RelationGetIndexStrategy(indexRelation)),
1931 UInt16GetDatum(parameterCount),
1932 PointerGetDatum(parameter),
1933 PointerGetDatum(funcInfo),
1934 PointerGetDatum(predInfo));
1936 DefaultBuild(heapRelation,
1940 RelationGetIndexStrategy(indexRelation),
1948 * IndexGetRelation: given an index's relation OID, get the OID of the
1949 * relation it is an index on. Uses the system cache.
1952 IndexGetRelation(Oid indexId)
1955 Form_pg_index index;
1957 tuple = SearchSysCacheTuple(INDEXRELID,
1958 ObjectIdGetDatum(indexId),
1960 if (!HeapTupleIsValid(tuple))
1962 elog(ERROR, "IndexGetRelation: can't find index id %u",
1965 index = (Form_pg_index) GETSTRUCT(tuple);
1966 Assert(index->indexrelid == indexId);
1968 return index->indrelid;
1972 * IndexIsUnique: given an index's relation OID, see if it
1973 * is unique using the system cache.
1976 IndexIsUnique(Oid indexId)
1979 Form_pg_index index;
1981 tuple = SearchSysCacheTuple(INDEXRELID,
1982 ObjectIdGetDatum(indexId),
1984 if (!HeapTupleIsValid(tuple))
1986 elog(ERROR, "IndexIsUnique: can't find index id %u",
1989 index = (Form_pg_index) GETSTRUCT(tuple);
1990 Assert(index->indexrelid == indexId);
1992 return index->indisunique;
1996 * IndexIsUniqueNoCache: same as above function, but don't use the
1997 * system cache. if we are called from btbuild, the transaction
1998 * that is adding the entry to pg_index has not been committed yet.
1999 * the system cache functions will do a heap scan, but only with
2000 * NowTimeQual, not SelfTimeQual, so it won't find tuples added
2001 * by the current transaction (which is good, because if the transaction
2002 * is aborted, you don't want the tuples sitting around in the cache).
2003 * so anyway, we have to do our own scan with SelfTimeQual.
2004 * this is only called when a new index is created, so it's OK
2008 IndexIsUniqueNoCache(Oid indexId)
2011 ScanKeyData skey[1];
2012 HeapScanDesc scandesc;
2014 Form_pg_index index;
2017 pg_index = heap_openr(IndexRelationName, AccessShareLock);
2019 ScanKeyEntryInitialize(&skey[0], (bits16) 0x0,
2020 Anum_pg_index_indexrelid,
2021 (RegProcedure) F_OIDEQ,
2022 ObjectIdGetDatum(indexId));
2024 scandesc = heap_beginscan(pg_index, 0, SnapshotSelf, 1, skey);
2027 tuple = heap_getnext(scandesc, 0);
2028 if (!HeapTupleIsValid(tuple))
2029 elog(ERROR, "IndexIsUniqueNoCache: can't find index id %u", indexId);
2031 index = (Form_pg_index) GETSTRUCT(tuple);
2032 Assert(index->indexrelid == indexId);
2033 isunique = index->indisunique;
2035 heap_endscan(scandesc);
2036 heap_close(pg_index, AccessShareLock);
2041 /* ---------------------------------
2042 * activate_index -- activate/deactivate the specified index.
2043 * Note that currelntly PostgreSQL doesn't hold the
2045 * ---------------------------------
2048 activate_index(Oid indexId, bool activate)
2050 if (!activate) /* Currently does nothing */
2052 return reindex_index(indexId, false);
2055 /* --------------------------------
2056 * reindex_index - This routine is used to recreate an index
2057 * --------------------------------
2060 reindex_index(Oid indexId, bool force)
2067 HeapTuple indexTuple,
2070 Form_pg_index index;
2074 Node *oldPred = NULL;
2076 AttrNumber *attributeNumberA;
2077 FuncIndexInfo fInfo,
2084 old = SetReindexProcessing(true);
2085 /* Scan pg_index to find indexes on heapRelation */
2086 indexRelation = heap_openr(IndexRelationName, AccessShareLock);
2087 ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indexrelid, F_OIDEQ,
2088 ObjectIdGetDatum(indexId));
2089 scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry);
2090 indexTuple = heap_getnext(scan, 0);
2091 if (!HeapTupleIsValid(indexTuple))
2092 elog(ERROR, "reindex_index index %d tuple is invalid", indexId);
2095 * For the index, fetch index attributes so we can apply index_build
2097 index = (Form_pg_index) GETSTRUCT(indexTuple);
2098 heapId = index->indrelid;
2099 procId = index->indproc;
2101 for (i = 0; i < INDEX_MAX_KEYS; i++)
2103 if (index->indkey[i] == InvalidAttrNumber)
2106 numberOfAttributes = i;
2108 /* If a valid where predicate, compute predicate Node */
2109 if (VARSIZE(&index->indpred) != 0)
2111 predString = textout(&index->indpred);
2112 oldPred = stringToNode(predString);
2115 predInfo = (PredInfo *) palloc(sizeof(PredInfo));
2116 predInfo->pred = (Node *) oldPred;
2117 predInfo->oldPred = NULL;
2119 /* Assign Index keys to attributes array */
2120 attributeNumberA = (AttrNumber *) palloc(numberOfAttributes * sizeof(AttrNumber));
2121 for (i = 0; i < numberOfAttributes; i++)
2122 attributeNumberA[i] = index->indkey[i];
2124 /* If this is a procedural index, initialize our FuncIndexInfo */
2125 if (procId != InvalidOid)
2128 FIsetnArgs(funcInfo, numberOfAttributes);
2129 procTuple = SearchSysCacheTuple(PROCOID, ObjectIdGetDatum(procId),
2131 if (!HeapTupleIsValid(procTuple))
2132 elog(ERROR, "RelationTruncateIndexes: index procedure not found");
2133 namecpy(&(funcInfo->funcName),
2134 &(((Form_pg_proc) GETSTRUCT(procTuple))->proname));
2135 FIsetProcOid(funcInfo, procTuple->t_data->t_oid);
2138 /* Fetch the classTuple associated with this index */
2139 classTuple = SearchSysCacheTupleCopy(RELOID, ObjectIdGetDatum(indexId), 0, 0, 0);
2140 if (!HeapTupleIsValid(classTuple))
2141 elog(ERROR, "RelationTruncateIndexes: index access method not found");
2142 accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam;
2144 /* Open our index relation */
2145 iRel = index_open(indexId);
2147 elog(ERROR, "reindex_index: can't open index relation");
2148 heapRelation = heap_open(heapId, ExclusiveLock);
2149 if (heapRelation == NULL)
2150 elog(ERROR, "reindex_index: can't open heap relation");
2152 /* Obtain exclusive lock on it, just to be sure */
2153 LockRelation(iRel, AccessExclusiveLock);
2156 * Release any buffers associated with this index. If they're dirty,
2157 * they're just dropped without bothering to flush to disk.
2159 ReleaseRelationBuffers(iRel);
2161 /* Now truncate the actual data and set blocks to zero */
2162 smgrtruncate(DEFAULT_SMGR, iRel, 0);
2163 iRel->rd_nblocks = 0;
2165 /* Initialize the index and rebuild */
2166 InitIndexStrategy(numberOfAttributes, iRel, accessMethodId);
2167 index_build(heapRelation, iRel, numberOfAttributes,
2168 attributeNumberA, 0, NULL, funcInfo, predInfo);
2171 * index_build will close both the heap and index relations (but not
2172 * give up the locks we hold on them). That's fine for the index, but
2173 * we need to open the heap again. We need no new lock, since this
2174 * backend still has the exclusive lock grabbed by heap_truncate.
2176 iRel = index_open(indexId);
2177 Assert(iRel != NULL);
2179 /* Complete the scan and close pg_index */
2181 heap_close(indexRelation, AccessShareLock);
2182 SetReindexProcessing(old);
2187 * ----------------------------
2188 * activate_indexes_of_a_table
2189 * activate/deactivate indexes of the specified table.
2190 * ----------------------------
2193 activate_indexes_of_a_table(Oid relid, bool activate)
2195 if (IndexesAreActive(relid, true))
2198 setRelhasindexInplace(relid, false, true);
2205 reindex_relation(relid, false);
2212 /* --------------------------------
2213 * reindex_relation - This routine is used to recreate indexes
2215 * --------------------------------
2218 reindex_relation(Oid relid, bool force)
2220 Relation indexRelation;
2223 HeapTuple indexTuple;
2227 old = SetReindexProcessing(true);
2228 if (IndexesAreActive(relid, true))
2232 SetReindexProcessing(old);
2235 activate_indexes_of_a_table(relid, false);
2238 indexRelation = heap_openr(IndexRelationName, AccessShareLock);
2239 ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid,
2240 F_OIDEQ, ObjectIdGetDatum(relid));
2241 scan = heap_beginscan(indexRelation, false, SnapshotNow,
2244 while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
2246 Form_pg_index index = (Form_pg_index) GETSTRUCT(indexTuple);
2248 if (activate_index(index->indexrelid, true))
2257 heap_close(indexRelation, AccessShareLock);
2259 setRelhasindexInplace(relid, true, false);
2260 SetReindexProcessing(old);