1 /*-------------------------------------------------------------------------
4 * code to create and destroy POSTGRES index relations
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.55 1998/08/26 17:12:09 momjian Exp $
14 * index_create() - Create a cataloged index relation
15 * index_destroy() - Removes index relation from catalogs
18 * Much of this code uses hardcoded sequential heap relation scans
19 * to fetch information from the catalogs. These should all be
20 * rewritten to use the system caches lookup routines like
21 * SearchSysCacheTuple, which can do efficient lookup and
24 *-------------------------------------------------------------------------
28 #include "access/genam.h"
29 #include "access/heapam.h"
30 #include "access/istrat.h"
31 #include "access/xact.h"
32 #include "bootstrap/bootstrap.h"
33 #include "catalog/catalog.h"
34 #include "catalog/catname.h"
35 #include "catalog/heap.h"
36 #include "catalog/index.h"
37 #include "catalog/indexing.h"
38 #include "catalog/pg_proc.h"
39 #include "catalog/pg_type.h"
40 #include "executor/executor.h"
42 #include "miscadmin.h"
43 #include "optimizer/clauses.h"
44 #include "optimizer/prep.h"
45 #include "parser/parse_func.h"
46 #include "storage/lmgr.h"
47 #include "storage/smgr.h"
48 #include "utils/builtins.h"
49 #include "utils/mcxt.h"
50 #include "utils/relcache.h"
51 #include "utils/syscache.h"
52 #include "utils/tqual.h"
55 #include <regex/utils.h>
61 * macros used in guessing how many tuples are on a page.
63 #define AVG_TUPLE_SIZE 8
64 #define NTUPLES_PER_PAGE(natts) (BLCKSZ/((natts)*AVG_TUPLE_SIZE))
66 /* non-export function prototypes */
68 RelationNameGetObjectId(char *relationName, Relation pg_class);
69 static Oid GetHeapRelationOid(char *heapRelationName, char *indexRelationName);
70 static TupleDesc BuildFuncTupleDesc(FuncIndexInfo *funcInfo);
72 ConstructTupleDescriptor(Oid heapoid, Relation heapRelation,
74 int numatts, AttrNumber attNums[]);
76 static void ConstructIndexReldesc(Relation indexRelation, Oid amoid);
77 static Oid UpdateRelationRelation(Relation indexRelation);
79 InitializeAttributeOids(Relation indexRelation,
83 AppendAttributeTuples(Relation indexRelation, int numatts);
85 UpdateIndexRelation(Oid indexoid, Oid heapoid,
86 FuncIndexInfo *funcInfo, int natts,
87 AttrNumber attNums[], Oid classOids[], Node *predicate,
88 List *attributeList, bool islossy, bool unique);
90 DefaultBuild(Relation heapRelation, Relation indexRelation,
91 int numberOfAttributes, AttrNumber attributeNumber[],
92 IndexStrategy indexStrategy, uint16 parameterCount,
93 Datum parameter[], FuncIndexInfoPtr funcInfo, PredInfo *predInfo);
95 /* ----------------------------------------------------------------
96 * sysatts is a structure containing attribute tuple forms
97 * for system attributes (numbered -1, -2, ...). This really
98 * should be generated or eliminated or moved elsewhere. -cim 1/19/91
100 * typedef struct FormData_pg_attribute {
115 * } FormData_pg_attribute;
117 * ----------------------------------------------------------------
119 static FormData_pg_attribute sysatts[] = {
120 {0, {"ctid"}, TIDOID, 0, 6, -1, 0, -1, -1, '\0', '\0', 'i', '\0', '\0'},
121 {0, {"oid"}, OIDOID, 0, 4, -2, 0, -1, -1, '\001', '\0', 'i', '\0', '\0'},
122 {0, {"xmin"}, XIDOID, 0, 4, -3, 0, -1, -1, '\001', '\0', 'i', '\0', '\0'},
123 {0, {"cmin"}, CIDOID, 0, 4, -4, 0, -1, -1, '\001', '\0', 'i', '\0', '\0'},
124 {0, {"xmax"}, XIDOID, 0, 4, -5, 0, -1, -1, '\001', '\0', 'i', '\0', '\0'},
125 {0, {"cmax"}, CIDOID, 0, 4, -6, 0, -1, -1, '\001', '\0', 'i', '\0', '\0'},
128 /* ----------------------------------------------------------------
129 * RelationNameGetObjectId --
130 * Returns the object identifier for a relation given its name.
132 * ----------------------------------------------------------------
135 RelationNameGetObjectId(char *relationName,
138 HeapScanDesc pg_class_scan;
139 HeapTuple pg_class_tuple;
140 Oid relationObjectId;
144 * If this isn't bootstrap time, we can use the system catalogs to
148 if (!IsBootstrapProcessingMode())
152 tuple = SearchSysCacheTuple(RELNAME,
153 PointerGetDatum(relationName),
156 if (HeapTupleIsValid(tuple))
163 * BOOTSTRAP TIME, do this the hard way.
164 * begin a scan of pg_class for the named relation
167 ScanKeyEntryInitialize(&key, 0, Anum_pg_class_relname,
169 PointerGetDatum(relationName));
171 pg_class_scan = heap_beginscan(pg_class, 0, SnapshotNow, 1, &key);
174 * if we find the named relation, fetch its relation id
175 * (the oid of the tuple we found).
178 pg_class_tuple = heap_getnext(pg_class_scan, 0);
180 if (!HeapTupleIsValid(pg_class_tuple))
181 relationObjectId = InvalidOid;
183 relationObjectId = pg_class_tuple->t_oid;
186 * cleanup and return results
189 heap_endscan(pg_class_scan);
191 return relationObjectId;
195 /* ----------------------------------------------------------------
197 * ----------------------------------------------------------------
200 GetHeapRelationOid(char *heapRelationName, char *indexRelationName)
207 * open pg_class and get the oid of the relation
208 * corresponding to the name of the index relation.
211 pg_class = heap_openr(RelationRelationName);
213 indoid = RelationNameGetObjectId(indexRelationName, pg_class);
215 if (OidIsValid(indoid))
216 elog(ERROR, "Cannot create index: '%s' already exists",
219 heapoid = RelationNameGetObjectId(heapRelationName, pg_class);
221 if (!OidIsValid(heapoid))
222 elog(ERROR, "Cannot create index on '%s': relation does not exist",
225 heap_close(pg_class);
231 BuildFuncTupleDesc(FuncIndexInfo *funcInfo)
234 TupleDesc funcTupDesc;
241 * Allocate and zero a tuple descriptor.
243 funcTupDesc = CreateTemplateTupleDesc(1);
244 funcTupDesc->attrs[0] = (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
245 MemSet(funcTupDesc->attrs[0], 0, ATTRIBUTE_TUPLE_SIZE);
248 * Lookup the function for the return type.
250 funcname = FIgetname(funcInfo);
251 nargs = FIgetnArgs(funcInfo);
252 argtypes = FIgetArglist(funcInfo);
253 tuple = SearchSysCacheTuple(PRONAME,
254 PointerGetDatum(funcname),
255 Int32GetDatum(nargs),
256 PointerGetDatum(argtypes),
259 if (!HeapTupleIsValid(tuple))
260 func_error("BuildFuncTupleDesc", funcname, nargs, argtypes, NULL);
262 retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype;
265 * Look up the return type in pg_type for the type length.
267 tuple = SearchSysCacheTuple(TYPOID,
268 ObjectIdGetDatum(retType),
270 if (!HeapTupleIsValid(tuple))
271 elog(ERROR, "Function %s return type does not exist", FIgetname(funcInfo));
274 * Assign some of the attributes values. Leave the rest as 0.
276 funcTupDesc->attrs[0]->attlen = ((TypeTupleForm) GETSTRUCT(tuple))->typlen;
277 funcTupDesc->attrs[0]->atttypid = retType;
278 funcTupDesc->attrs[0]->attnum = 1;
279 funcTupDesc->attrs[0]->attbyval = ((TypeTupleForm) GETSTRUCT(tuple))->typbyval;
280 funcTupDesc->attrs[0]->attcacheoff = -1;
281 funcTupDesc->attrs[0]->atttypmod = -1;
282 funcTupDesc->attrs[0]->attalign = ((TypeTupleForm) GETSTRUCT(tuple))->typalign;
285 * make the attributes name the same as the functions
287 namestrcpy(&funcTupDesc->attrs[0]->attname, funcname);
289 return (funcTupDesc);
292 /* ----------------------------------------------------------------
293 * ConstructTupleDescriptor
294 * ----------------------------------------------------------------
297 ConstructTupleDescriptor(Oid heapoid,
298 Relation heapRelation,
301 AttrNumber attNums[])
303 TupleDesc heapTupDesc;
304 TupleDesc indexTupDesc;
306 TypeName *IndexKeyType;
307 AttrNumber atnum; /* attributeNumber[attributeOffset] */
309 int natts; /* RelationTupleForm->relnatts */
310 char *from; /* used to simplify memcpy below */
311 char *to; /* used to simplify memcpy below */
315 * allocate the new tuple descriptor
318 natts = RelationGetRelationTupleForm(heapRelation)->relnatts;
320 indexTupDesc = CreateTemplateTupleDesc(numatts);
328 * for each attribute we are indexing, obtain its attribute
329 * tuple form from either the static table of system attribute
330 * tuple forms or the relation tuple descriptor
333 for (i = 0; i < numatts; i += 1)
337 * get the attribute number and make sure it's valid
342 elog(ERROR, "Cannot create index: attribute %d does not exist",
346 IndexKey = (IndexElem *) lfirst(attributeList);
347 IndexKeyType = IndexKey->typename;
348 attributeList = lnext(attributeList);
353 indexTupDesc->attrs[i] = (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
356 * determine which tuple descriptor to copy
359 if (!AttrNumberIsForUserDefinedAttr(atnum))
363 * here we are indexing on a system attribute (-1...-12)
364 * so we convert atnum into a usable index 0...11 so we can
365 * use it to dereference the array sysatts[] which stores
366 * tuple descriptor information for system attributes.
369 if (atnum <= FirstLowInvalidHeapAttributeNumber || atnum >= 0)
370 elog(ERROR, "Cannot create index on system attribute: attribute number out of range (%d)", atnum);
371 atind = (-atnum) - 1;
373 from = (char *) (&sysatts[atind]);
379 * here we are indexing on a normal attribute (1...n)
382 heapTupDesc = RelationGetTupleDescriptor(heapRelation);
383 atind = AttrNumberGetAttrOffset(atnum);
385 from = (char *) (heapTupDesc->attrs[atind]);
389 * now that we've determined the "from", let's copy
390 * the tuple desc data...
394 to = (char *) (indexTupDesc->attrs[i]);
395 memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);
397 ((AttributeTupleForm) to)->attnum = i + 1;
399 ((AttributeTupleForm) to)->attnotnull = false;
400 ((AttributeTupleForm) to)->atthasdef = false;
401 ((AttributeTupleForm) to)->attcacheoff = -1;
402 ((AttributeTupleForm) to)->atttypmod = -1;
403 ((AttributeTupleForm) to)->attalign = 'i';
406 * if the keytype is defined, we need to change the tuple form's
407 * atttypid & attlen field to match that of the key's type
409 if (IndexKeyType != NULL)
413 tup = SearchSysCacheTuple(TYPNAME,
414 PointerGetDatum(IndexKeyType->name),
416 if (!HeapTupleIsValid(tup))
417 elog(ERROR, "create index: type '%s' undefined",
419 ((AttributeTupleForm) to)->atttypid = tup->t_oid;
420 ((AttributeTupleForm) to)->attbyval =
421 ((TypeTupleForm) GETSTRUCT(tup))->typbyval;
422 ((AttributeTupleForm) to)->attlen =
423 ((TypeTupleForm) GETSTRUCT(tup))->typlen;
424 ((AttributeTupleForm) to)->attalign =
425 ((TypeTupleForm) GETSTRUCT(tup))->typalign;
426 ((AttributeTupleForm) to)->atttypmod = IndexKeyType->typmod;
431 * now we have to drop in the proper relation descriptor
432 * into the copied tuple form's attrelid and we should be
436 ((AttributeTupleForm) to)->attrelid = heapoid;
442 /* ----------------------------------------------------------------
443 * AccessMethodObjectIdGetAccessMethodTupleForm --
444 * Returns the formated access method tuple given its object identifier.
449 * Assumes object identifier is valid.
450 * ----------------------------------------------------------------
453 AccessMethodObjectIdGetAccessMethodTupleForm(Oid accessMethodObjectId)
456 HeapScanDesc pg_am_scan;
457 HeapTuple pg_am_tuple;
462 * form a scan key for the pg_am relation
465 ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
467 ObjectIdGetDatum(accessMethodObjectId));
470 * fetch the desired access method tuple
473 pg_am_desc = heap_openr(AccessMethodRelationName);
474 pg_am_scan = heap_beginscan(pg_am_desc, 0, SnapshotNow, 1, &key);
476 pg_am_tuple = heap_getnext(pg_am_scan, 0);
479 * return NULL if not found
482 if (!HeapTupleIsValid(pg_am_tuple))
484 heap_endscan(pg_am_scan);
485 heap_close(pg_am_desc);
490 * if found am tuple, then copy the form and return the copy
493 form = (Form_pg_am) palloc(sizeof *form);
494 memcpy(form, GETSTRUCT(pg_am_tuple), sizeof *form);
496 heap_endscan(pg_am_scan);
497 heap_close(pg_am_desc);
502 /* ----------------------------------------------------------------
503 * ConstructIndexReldesc
504 * ----------------------------------------------------------------
507 ConstructIndexReldesc(Relation indexRelation, Oid amoid)
509 extern GlobalMemory CacheCxt;
510 MemoryContext oldcxt;
513 * here we make certain to allocate the access method
514 * tuple within the cache context lest it vanish when the
519 CacheCxt = CreateGlobalMemory("Cache");
521 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
523 indexRelation->rd_am =
524 AccessMethodObjectIdGetAccessMethodTupleForm(amoid);
526 MemoryContextSwitchTo(oldcxt);
529 * XXX missing the initialization of some other fields
533 indexRelation->rd_rel->relowner = GetUserId();
535 indexRelation->rd_rel->relam = amoid;
536 indexRelation->rd_rel->reltuples = 1; /* XXX */
537 indexRelation->rd_rel->relkind = RELKIND_INDEX;
540 /* ----------------------------------------------------------------
541 * UpdateRelationRelation
542 * ----------------------------------------------------------------
545 UpdateRelationRelation(Relation indexRelation)
550 Relation idescs[Num_pg_class_indices];
552 pg_class = heap_openr(RelationRelationName);
554 /* XXX Natts_pg_class_fixed is a hack - see pg_class.h */
555 tuple = heap_addheader(Natts_pg_class_fixed,
556 sizeof(*indexRelation->rd_rel),
557 (char *) indexRelation->rd_rel);
560 * the new tuple must have the same oid as the relcache entry for the
561 * index. sure would be embarassing to do this sort of thing in polite
565 tuple->t_oid = RelationGetRelid(indexRelation);
566 heap_insert(pg_class, tuple);
569 * During normal processing, we need to make sure that the system
570 * catalog indices are correct. Bootstrap (initdb) time doesn't
571 * require this, because we make sure that the indices are correct
572 * just before exiting.
575 if (!IsBootstrapProcessingMode())
577 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
578 CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, tuple);
579 CatalogCloseIndices(Num_pg_class_indices, idescs);
582 tupleOid = tuple->t_oid;
584 heap_close(pg_class);
589 /* ----------------------------------------------------------------
590 * InitializeAttributeOids
591 * ----------------------------------------------------------------
594 InitializeAttributeOids(Relation indexRelation,
598 TupleDesc tupleDescriptor;
601 tupleDescriptor = RelationGetTupleDescriptor(indexRelation);
603 for (i = 0; i < numatts; i += 1)
604 tupleDescriptor->attrs[i]->attrelid = indexoid;
607 /* ----------------------------------------------------------------
608 * AppendAttributeTuples
610 * XXX For now, only change the ATTNUM attribute value
611 * ----------------------------------------------------------------
614 AppendAttributeTuples(Relation indexRelation, int numatts)
616 Relation pg_attribute;
617 HeapTuple init_tuple, cur_tuple = NULL, new_tuple;
619 Relation idescs[Num_pg_attr_indices];
621 Datum value[Natts_pg_attribute];
622 char nullv[Natts_pg_attribute];
623 char replace[Natts_pg_attribute];
625 TupleDesc indexTupDesc;
629 * open the attribute relation
633 pg_attribute = heap_openr(AttributeRelationName);
636 * initialize null[], replace[] and value[]
639 MemSet(nullv, ' ', Natts_pg_attribute);
640 MemSet(replace, ' ', Natts_pg_attribute);
643 * create the first attribute tuple.
644 * XXX For now, only change the ATTNUM attribute value
647 replace[Anum_pg_attribute_attnum - 1] = 'r';
648 replace[Anum_pg_attribute_attcacheoff - 1] = 'r';
650 value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(1);
651 value[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1);
653 init_tuple = heap_addheader(Natts_pg_attribute,
654 sizeof *(indexRelation->rd_att->attrs[0]),
655 (char *) (indexRelation->rd_att->attrs[0]));
658 if (!IsBootstrapProcessingMode() && pg_attribute->rd_rel->relhasindex)
661 CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
665 * insert the first attribute tuple.
668 cur_tuple = heap_modifytuple(init_tuple,
675 heap_insert(pg_attribute, cur_tuple);
677 CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, cur_tuple);
680 * now we use the information in the index cur_tuple
681 * descriptor to form the remaining attribute tuples.
684 indexTupDesc = RelationGetTupleDescriptor(indexRelation);
686 for (i = 1; i < numatts; i += 1)
689 * process the remaining attributes...
692 memmove(GETSTRUCT(cur_tuple),
693 (char *) indexTupDesc->attrs[i],
694 sizeof(FormData_pg_attribute));
696 value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(i + 1);
698 new_tuple = heap_modifytuple(cur_tuple,
705 heap_insert(pg_attribute,new_tuple);
707 CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, new_tuple);
710 * ModifyHeapTuple returns a new copy of a cur_tuple
711 * so we free the original and use the copy..
714 cur_tuple = new_tuple;
719 heap_close(pg_attribute);
721 CatalogCloseIndices(Num_pg_attr_indices, idescs);
725 /* ----------------------------------------------------------------
726 * UpdateIndexRelation
727 * ----------------------------------------------------------------
730 UpdateIndexRelation(Oid indexoid,
732 FuncIndexInfo *funcInfo,
734 AttrNumber attNums[],
741 IndexTupleForm indexForm;
752 * allocate an IndexTupleForm big enough to hold the
753 * index-predicate (if any) in string form
756 if (predicate != NULL)
758 predString = nodeToString(predicate);
759 predText = (text *) fmgr(F_TEXTIN, predString);
763 predText = (text *) fmgr(F_TEXTIN, "");
764 predLen = VARSIZE(predText);
765 itupLen = predLen + sizeof(FormData_pg_index);
766 indexForm = (IndexTupleForm) palloc(itupLen);
768 memmove((char *) &indexForm->indpred, (char *) predText, predLen);
771 * store the oid information into the index tuple form
774 indexForm->indrelid = heapoid;
775 indexForm->indexrelid = indexoid;
776 indexForm->indproc = (PointerIsValid(funcInfo)) ?
777 FIgetProcOid(funcInfo) : InvalidOid;
778 indexForm->indislossy = islossy;
779 indexForm->indisunique = unique;
781 indexForm->indhaskeytype = 0;
782 while (attributeList != NIL)
784 IndexKey = (IndexElem *) lfirst(attributeList);
785 if (IndexKey->typename != NULL)
787 indexForm->indhaskeytype = 1;
790 attributeList = lnext(attributeList);
793 MemSet((char *) &indexForm->indkey[0], 0, sizeof indexForm->indkey);
794 MemSet((char *) &indexForm->indclass[0], 0, sizeof indexForm->indclass);
797 * copy index key and op class information
800 for (i = 0; i < natts; i += 1)
802 indexForm->indkey[i] = attNums[i];
803 indexForm->indclass[i] = classOids[i];
807 * If we have a functional index, add all attribute arguments
809 if (PointerIsValid(funcInfo))
811 for (i = 1; i < FIgetnArgs(funcInfo); i++)
812 indexForm->indkey[i] = attNums[i];
815 indexForm->indisclustered = '\0'; /* XXX constant */
818 * open the system catalog index relation
821 pg_index = heap_openr(IndexRelationName);
824 * form a tuple to insert into pg_index
827 tuple = heap_addheader(Natts_pg_index,
832 * insert the tuple into the pg_index
833 * XXX ADD INDEX TUPLES TOO
836 heap_insert(pg_index, tuple);
839 * close the relation and free the tuple
842 heap_close(pg_index);
848 /* ----------------------------------------------------------------
849 * UpdateIndexPredicate
850 * ----------------------------------------------------------------
853 UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
862 Datum values[Natts_pg_index];
863 char nulls[Natts_pg_index];
864 char replace[Natts_pg_index];
867 * Construct newPred as a CNF expression equivalent to the OR of the
868 * original partial-index predicate ("oldPred") and the extension
869 * predicate ("predicate").
871 * This should really try to process the result to change things like
872 * "a>2 OR a>1" to simply "a>1", but for now all it does is make sure
873 * that if the extension predicate is NULL (i.e., it is being extended
874 * to be a complete index), then newPred will be NULL - in effect,
875 * changing "a>2 OR TRUE" to "TRUE". --Nels, Jan '93
878 if (predicate != NULL)
881 (Node *) make_orclause(lcons(make_andclause((List *) predicate),
882 lcons(make_andclause((List *) oldPred),
884 newPred = (Node *) cnfify((Expr *) newPred, true);
887 /* translate the index-predicate to string form */
890 predString = nodeToString(newPred);
891 predText = (text *) fmgr(F_TEXTIN, predString);
895 predText = (text *) fmgr(F_TEXTIN, "");
897 /* open the index system catalog relation */
898 pg_index = heap_openr(IndexRelationName);
900 tuple = SearchSysCacheTuple(INDEXRELID,
901 ObjectIdGetDatum(indexoid),
903 Assert(HeapTupleIsValid(tuple));
905 for (i = 0; i < Natts_pg_index; i++)
907 nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' ';
909 values[i] = (Datum) NULL;
912 replace[Anum_pg_index_indpred - 1] = 'r';
913 values[Anum_pg_index_indpred - 1] = (Datum) predText;
915 newtup = heap_modifytuple(tuple, pg_index, values, nulls, replace);
917 heap_replace(pg_index, &newtup->t_ctid, newtup);
920 heap_close(pg_index);
924 /* ----------------------------------------------------------------
926 * ----------------------------------------------------------------
929 InitIndexStrategy(int numatts,
930 Relation indexRelation,
931 Oid accessMethodObjectId)
933 IndexStrategy strategy;
934 RegProcedure *support;
939 extern GlobalMemory CacheCxt;
942 * get information from the index relation descriptor
945 attrelid = indexRelation->rd_att->attrs[0]->attrelid;
946 amstrategies = indexRelation->rd_am->amstrategies;
947 amsupport = indexRelation->rd_am->amsupport;
950 * get the size of the strategy
953 strsize = AttributeNumberGetIndexStrategySize(numatts, amstrategies);
956 * allocate the new index strategy structure
958 * the index strategy has to be allocated in the same
959 * context as the relation descriptor cache or else
960 * it will be lost at the end of the transaction.
964 CacheCxt = CreateGlobalMemory("Cache");
966 strategy = (IndexStrategy)
967 MemoryContextAlloc((MemoryContext) CacheCxt, strsize);
971 strsize = numatts * (amsupport * sizeof(RegProcedure));
972 support = (RegProcedure *) MemoryContextAlloc((MemoryContext) CacheCxt,
976 support = (RegProcedure *) NULL;
979 * fill in the index strategy structure with information
980 * from the catalogs. Note: we use heap override mode
981 * in order to be allowed to see the correct information in the
982 * catalogs, even though our transaction has not yet committed.
985 setheapoverride(true);
987 IndexSupportInitialize(strategy, support,
988 attrelid, accessMethodObjectId,
989 amstrategies, amsupport, numatts);
991 setheapoverride(false);
994 * store the strategy information in the index reldesc
997 RelationSetIndexSupport(indexRelation, strategy, support);
1001 /* ----------------------------------------------------------------
1003 * ----------------------------------------------------------------
1006 index_create(char *heapRelationName,
1007 char *indexRelationName,
1008 FuncIndexInfo *funcInfo,
1009 List *attributeList,
1010 Oid accessMethodObjectId,
1012 AttrNumber attNums[],
1013 Oid classObjectId[],
1014 uint16 parameterCount,
1020 Relation heapRelation;
1021 Relation indexRelation;
1022 TupleDesc indexTupDesc;
1032 elog(ERROR, "must index at least one attribute");
1035 * get heap relation oid and open the heap relation
1039 heapoid = GetHeapRelationOid(heapRelationName, indexRelationName);
1041 heapRelation = heap_open(heapoid);
1044 * write lock heap to guarantee exclusive access
1046 RelationSetLockForWrite(heapRelation);
1048 * Does it have any sense ? - vadim 10/27/97
1051 RelationSetLockForRead(heapRelation);
1054 * construct new tuple descriptor
1057 if (PointerIsValid(funcInfo))
1058 indexTupDesc = BuildFuncTupleDesc(funcInfo);
1060 indexTupDesc = ConstructTupleDescriptor(heapoid,
1067 * create the index relation
1070 indexRelation = heap_create(indexRelationName,
1074 * construct the index relation descriptor
1076 * XXX should have a proper way to create cataloged relations
1079 ConstructIndexReldesc(indexRelation, accessMethodObjectId);
1082 * add index to catalogs
1083 * (append RELATION tuple)
1086 indexoid = UpdateRelationRelation(indexRelation);
1089 * Now get the index procedure (only relevant for functional indices).
1093 if (PointerIsValid(funcInfo))
1097 proc_tup = SearchSysCacheTuple(PRONAME,
1098 PointerGetDatum(FIgetname(funcInfo)),
1099 Int32GetDatum(FIgetnArgs(funcInfo)),
1100 PointerGetDatum(FIgetArglist(funcInfo)),
1103 if (!HeapTupleIsValid(proc_tup))
1105 func_error("index_create", FIgetname(funcInfo),
1106 FIgetnArgs(funcInfo), FIgetArglist(funcInfo), NULL);
1108 FIgetProcOid(funcInfo) = proc_tup->t_oid;
1112 * now update the object id's of all the attribute
1113 * tuple forms in the index relation's tuple descriptor
1116 InitializeAttributeOids(indexRelation, numatts, indexoid);
1119 * append ATTRIBUTE tuples
1122 AppendAttributeTuples(indexRelation, numatts);
1126 * (append INDEX tuple)
1128 * Note that this stows away a representation of "predicate".
1129 * (Or, could define a rule to maintain the predicate) --Nels, Feb '92
1132 UpdateIndexRelation(indexoid, heapoid, funcInfo,
1133 numatts, attNums, classObjectId, predicate,
1134 attributeList, islossy, unique);
1136 predInfo = (PredInfo *) palloc(sizeof(PredInfo));
1137 predInfo->pred = predicate;
1138 predInfo->oldPred = NULL;
1141 * initialize the index strategy
1144 InitIndexStrategy(numatts, indexRelation, accessMethodObjectId);
1147 * If this is bootstrap (initdb) time, then we don't actually fill in
1148 * the index yet. We'll be creating more indices and classes later,
1149 * so we delay filling them in until just before we're done with
1150 * bootstrapping. Otherwise, we call the routine that constructs the
1151 * index. The heap and index relations are closed by index_build().
1153 if (IsBootstrapProcessingMode())
1155 index_register(heapRelationName, indexRelationName, numatts, attNums,
1156 parameterCount, parameter, funcInfo, predInfo);
1160 heapRelation = heap_openr(heapRelationName);
1161 index_build(heapRelation, indexRelation, numatts, attNums,
1162 parameterCount, parameter, funcInfo, predInfo);
1166 /* ----------------------------------------------------------------
1169 * XXX break into modules like index_create
1170 * ----------------------------------------------------------------
1173 index_destroy(Oid indexId)
1175 Relation userindexRelation;
1176 Relation indexRelation;
1177 Relation relationRelation;
1178 Relation attributeRelation;
1182 Assert(OidIsValid(indexId));
1184 /* why open it here? bjm 1998/08/20 */
1185 userindexRelation = index_open(indexId);
1188 * fix RELATION relation
1191 relationRelation = heap_openr(RelationRelationName);
1193 tuple = SearchSysCacheTupleCopy(RELOID,
1194 ObjectIdGetDatum(indexId),
1197 AssertState(HeapTupleIsValid(tuple));
1199 heap_delete(relationRelation, &tuple->t_ctid);
1201 heap_close(relationRelation);
1204 * fix ATTRIBUTE relation
1207 attributeRelation = heap_openr(AttributeRelationName);
1209 attnum = 1; /* indexes start at 1 */
1211 while (HeapTupleIsValid(tuple = SearchSysCacheTupleCopy(ATTNUM,
1212 ObjectIdGetDatum(indexId),
1213 Int16GetDatum(attnum),
1216 heap_delete(attributeRelation, &tuple->t_ctid);
1220 heap_close(attributeRelation);
1223 * fix INDEX relation
1226 tuple = SearchSysCacheTupleCopy(INDEXRELID,
1227 ObjectIdGetDatum(indexId),
1230 if (!HeapTupleIsValid(tuple))
1231 elog(NOTICE, "IndexRelationDestroy: %s's INDEX tuple missing",
1232 RelationGetRelationName(userindexRelation));
1234 indexRelation = heap_openr(IndexRelationName);
1236 heap_delete(indexRelation, &tuple->t_ctid);
1238 heap_close(indexRelation);
1241 * flush cache and physically remove the file
1243 ReleaseRelationBuffers(userindexRelation);
1245 if (FileNameUnlink(relpath(userindexRelation->rd_rel->relname.data)) < 0)
1246 elog(ERROR, "amdestroyr: unlink: %m");
1248 index_close(userindexRelation);
1249 RelationForgetRelation(RelationGetRelid(userindexRelation));
1252 /* ----------------------------------------------------------------
1253 * index_build support
1254 * ----------------------------------------------------------------
1261 FormIndexDatum(int numberOfAttributes,
1262 AttrNumber attributeNumber[],
1263 HeapTuple heapTuple,
1264 TupleDesc heapDescriptor,
1267 FuncIndexInfoPtr fInfo)
1274 * for each attribute we need from the heap tuple,
1275 * get the attribute and stick it into the datum and
1280 for (i = 1; i <= numberOfAttributes; i++)
1282 offset = AttrNumberGetAttrOffset(i);
1285 PointerGetDatum(GetIndexValue(heapTuple,
1292 nullv[offset] = (isNull) ? 'n' : ' ';
1302 UpdateStats(Oid relid, long reltuples, bool hasindex)
1310 Form_pg_class rd_rel;
1311 Relation idescs[Num_pg_class_indices];
1312 Datum values[Natts_pg_class];
1313 char nulls[Natts_pg_class];
1314 char replace[Natts_pg_class];
1315 HeapScanDesc pg_class_scan = NULL;
1318 * This routine handles updates for both the heap and index relation
1319 * statistics. In order to guarantee that we're able to *see* the index
1320 * relation tuple, we bump the command counter id here. The index
1321 * relation tuple was created in the current transaction.
1324 CommandCounterIncrement();
1327 * CommandCounterIncrement() flushes invalid cache entries, including
1328 * those for the heap and index relations for which we're updating
1329 * statistics. Now that the cache is flushed, it's safe to open the
1330 * relation again. We need the relation open in order to figure out
1331 * how many blocks it contains.
1335 whichRel = RelationIdGetRelation(relid);
1337 if (!RelationIsValid(whichRel))
1338 elog(ERROR, "UpdateStats: cannot open relation id %d", relid);
1341 * Find the RELATION relation tuple for the given relation.
1344 pg_class = heap_openr(RelationRelationName);
1345 if (!RelationIsValid(pg_class))
1346 elog(ERROR, "UpdateStats: could not open RELATION relation");
1349 if (!IsBootstrapProcessingMode())
1351 tuple = SearchSysCacheTupleCopy(RELOID,
1352 ObjectIdGetDatum(relid),
1359 ScanKeyEntryInitialize(&key[0], 0,
1360 ObjectIdAttributeNumber,
1362 ObjectIdGetDatum(relid));
1364 pg_class_scan = heap_beginscan(pg_class, 0, SnapshotNow, 1, key);
1365 tuple = heap_getnext(pg_class_scan, 0);
1368 if (!HeapTupleIsValid(tuple))
1370 if (IsBootstrapProcessingMode())
1371 heap_endscan(pg_class_scan);
1372 heap_close(pg_class);
1373 elog(ERROR, "UpdateStats: cannot scan RELATION relation");
1380 relpages = RelationGetNumberOfBlocks(whichRel);
1383 * We shouldn't have to do this, but we do... Modify the reldesc in
1384 * place with the new values so that the cache contains the latest
1388 whichRel->rd_rel->relhasindex = hasindex;
1389 whichRel->rd_rel->relpages = relpages;
1390 whichRel->rd_rel->reltuples = reltuples;
1392 for (i = 0; i < Natts_pg_class; i++)
1394 nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' ';
1396 values[i] = (Datum) NULL;
1400 * If reltuples wasn't supplied take an educated guess.
1403 reltuples = relpages * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
1405 if (IsBootstrapProcessingMode())
1409 * At bootstrap time, we don't need to worry about concurrency or
1410 * visibility of changes, so we cheat.
1412 rd_rel = (Form_pg_class) GETSTRUCT(tuple);
1413 rd_rel->relpages = relpages;
1414 rd_rel->reltuples = reltuples;
1415 rd_rel->relhasindex = hasindex;
1416 WriteBuffer(pg_class_scan->rs_cbuf);
1420 /* during normal processing, work harder */
1421 replace[Anum_pg_class_relpages - 1] = 'r';
1422 values[Anum_pg_class_relpages - 1] = (Datum) relpages;
1423 replace[Anum_pg_class_reltuples - 1] = 'r';
1424 values[Anum_pg_class_reltuples - 1] = (Datum) reltuples;
1425 replace[Anum_pg_class_relhasindex - 1] = 'r';
1426 values[Anum_pg_class_relhasindex - 1] = CharGetDatum(hasindex);
1428 newtup = heap_modifytuple(tuple, pg_class, values, nulls, replace);
1429 heap_replace(pg_class, &tuple->t_ctid, newtup);
1431 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
1432 CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, newtup);
1433 CatalogCloseIndices(Num_pg_class_indices, idescs);
1436 if (!IsBootstrapProcessingMode())
1439 heap_endscan(pg_class_scan);
1441 heap_close(pg_class);
1442 heap_close(whichRel);
1446 /* -------------------------
1447 * FillDummyExprContext
1448 * Sets up dummy ExprContext and TupleTableSlot objects for use
1450 * -------------------------
1453 FillDummyExprContext(ExprContext *econtext,
1454 TupleTableSlot *slot,
1458 econtext->ecxt_scantuple = slot;
1459 econtext->ecxt_innertuple = NULL;
1460 econtext->ecxt_outertuple = NULL;
1461 econtext->ecxt_param_list_info = NULL;
1462 econtext->ecxt_range_table = NULL;
1464 slot->ttc_tupleDescriptor = tupdesc;
1465 slot->ttc_buffer = buffer;
1466 slot->ttc_shouldFree = false;
1476 DefaultBuild(Relation heapRelation,
1477 Relation indexRelation,
1478 int numberOfAttributes,
1479 AttrNumber attributeNumber[],
1480 IndexStrategy indexStrategy, /* not used */
1481 uint16 parameterCount, /* not used */
1482 Datum parameter[], /* not used */
1483 FuncIndexInfoPtr funcInfo,
1487 HeapTuple heapTuple;
1488 IndexTuple indexTuple;
1489 TupleDesc heapDescriptor;
1490 TupleDesc indexDescriptor;
1496 #ifndef OMIT_PARTIAL_INDEX
1497 ExprContext *econtext;
1498 TupleTable tupleTable;
1499 TupleTableSlot *slot;
1505 InsertIndexResult insertResult;
1508 * more & better checking is needed
1511 Assert(OidIsValid(indexRelation->rd_rel->relam)); /* XXX */
1514 * get the tuple descriptors from the relations so we know
1515 * how to form the index tuples..
1518 heapDescriptor = RelationGetTupleDescriptor(heapRelation);
1519 indexDescriptor = RelationGetTupleDescriptor(indexRelation);
1522 * datum and null are arrays in which we collect the index attributes
1523 * when forming a new index tuple.
1526 datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
1527 nullv = (char *) palloc(numberOfAttributes * sizeof *nullv);
1530 * If this is a predicate (partial) index, we will need to evaluate
1531 * the predicate using ExecQual, which requires the current tuple to
1532 * be in a slot of a TupleTable. In addition, ExecQual must have an
1533 * ExprContext referring to that slot. Here, we initialize dummy
1534 * TupleTable and ExprContext objects for this purpose. --Nels, Feb
1538 predicate = predInfo->pred;
1539 oldPred = predInfo->oldPred;
1541 #ifndef OMIT_PARTIAL_INDEX
1542 if (predicate != NULL || oldPred != NULL)
1544 tupleTable = ExecCreateTupleTable(1);
1545 slot = ExecAllocTableSlot(tupleTable);
1546 econtext = makeNode(ExprContext);
1547 /* last parameter was junk being sent bjm 1998/08/17 */
1548 FillDummyExprContext(econtext, slot, heapDescriptor, InvalidBuffer);
1556 #endif /* OMIT_PARTIAL_INDEX */
1559 * Ok, begin our scan of the base relation.
1562 scan = heap_beginscan(heapRelation, /* relation */
1563 0, /* start at end */
1564 SnapshotNow,/* seeself */
1565 0, /* number of keys */
1566 (ScanKey) NULL); /* scan key */
1568 reltuples = indtuples = 0;
1571 * for each tuple in the base relation, we create an index
1572 * tuple and add it to the index relation. We keep a running
1573 * count of the number of tuples so that we can update pg_class
1574 * with correct statistics when we're done building the index.
1577 while (HeapTupleIsValid(heapTuple = heap_getnext(scan, 0)))
1582 * If oldPred != NULL, this is an EXTEND INDEX command, so skip
1583 * this tuple if it was already in the existing partial index
1585 if (oldPred != NULL)
1587 #ifndef OMIT_PARTIAL_INDEX
1588 /* SetSlotContents(slot, heapTuple); */
1589 slot->val = heapTuple;
1590 if (ExecQual((List *) oldPred, econtext) == true)
1595 #endif /* OMIT_PARTIAL_INDEX */
1599 * Skip this tuple if it doesn't satisfy the partial-index
1602 if (predicate != NULL)
1604 #ifndef OMIT_PARTIAL_INDEX
1605 /* SetSlotContents(slot, heapTuple); */
1606 slot->val = heapTuple;
1607 if (ExecQual((List *) predicate, econtext) == false)
1609 #endif /* OMIT_PARTIAL_INDEX */
1615 * FormIndexDatum fills in its datum and null parameters
1616 * with attribute information taken from the given heap tuple.
1619 FormIndexDatum(numberOfAttributes, /* num attributes */
1620 attributeNumber, /* array of att nums to extract */
1621 heapTuple, /* tuple from base relation */
1622 heapDescriptor, /* heap tuple's descriptor */
1623 datum, /* return: array of attributes */
1624 nullv, /* return: array of char's */
1627 indexTuple = index_formtuple(indexDescriptor,
1631 indexTuple->t_tid = heapTuple->t_ctid;
1633 insertResult = index_insert(indexRelation, datum, nullv,
1634 &(heapTuple->t_ctid), heapRelation);
1637 pfree(insertResult);
1643 if (predicate != NULL || oldPred != NULL)
1645 #ifndef OMIT_PARTIAL_INDEX
1646 ExecDestroyTupleTable(tupleTable, false);
1647 #endif /* OMIT_PARTIAL_INDEX */
1654 * Okay, now update the reltuples and relpages statistics for both the
1655 * heap relation and the index. These statistics are used by the
1656 * planner to choose a scan type. They are maintained generally by
1657 * the vacuum daemon, but we update them here to make the index useful
1658 * as soon as possible.
1660 UpdateStats(RelationGetRelid(heapRelation), reltuples, true);
1661 UpdateStats(RelationGetRelid(indexRelation), indtuples, false);
1662 if (oldPred != NULL)
1664 if (indtuples == reltuples)
1666 UpdateIndexPredicate(RelationGetRelid(indexRelation),
1667 oldPred, predicate);
1676 index_build(Relation heapRelation,
1677 Relation indexRelation,
1678 int numberOfAttributes,
1679 AttrNumber attributeNumber[],
1680 uint16 parameterCount,
1682 FuncIndexInfo *funcInfo,
1685 RegProcedure procedure;
1691 Assert(RelationIsValid(indexRelation));
1692 Assert(PointerIsValid(indexRelation->rd_am));
1694 procedure = indexRelation->rd_am->ambuild;
1697 * use the access method build procedure if supplied..
1700 if (RegProcedureIsValid(procedure))
1706 RelationGetIndexStrategy(indexRelation),
1712 DefaultBuild(heapRelation,
1716 RelationGetIndexStrategy(indexRelation),
1724 * IndexIsUnique: given an index's relation OID, see if it
1725 * is unique using the system cache.
1728 IndexIsUnique(Oid indexId)
1731 IndexTupleForm index;
1733 tuple = SearchSysCacheTuple(INDEXRELID,
1734 ObjectIdGetDatum(indexId),
1736 if (!HeapTupleIsValid(tuple))
1738 elog(ERROR, "IndexIsUnique: can't find index id %d",
1741 index = (IndexTupleForm) GETSTRUCT(tuple);
1742 Assert(index->indexrelid == indexId);
1744 return index->indisunique;
1748 * IndexIsUniqueNoCache: same as above function, but don't use the
1749 * system cache. if we are called from btbuild, the transaction
1750 * that is adding the entry to pg_index has not been committed yet.
1751 * the system cache functions will do a heap scan, but only with
1752 * NowTimeQual, not SelfTimeQual, so it won't find tuples added
1753 * by the current transaction (which is good, because if the transaction
1754 * is aborted, you don't want the tuples sitting around in the cache).
1755 * so anyway, we have to do our own scan with SelfTimeQual.
1756 * this is only called when a new index is created, so it's OK
1760 IndexIsUniqueNoCache(Oid indexId)
1763 ScanKeyData skey[1];
1764 HeapScanDesc scandesc;
1766 IndexTupleForm index;
1769 pg_index = heap_openr(IndexRelationName);
1771 ScanKeyEntryInitialize(&skey[0], (bits16) 0x0,
1772 Anum_pg_index_indexrelid,
1773 (RegProcedure) F_OIDEQ,
1774 ObjectIdGetDatum(indexId));
1776 scandesc = heap_beginscan(pg_index, 0, SnapshotSelf, 1, skey);
1779 tuple = heap_getnext(scandesc, 0);
1780 if (!HeapTupleIsValid(tuple))
1781 elog(ERROR, "IndexIsUniqueNoCache: can't find index id %d", indexId);
1783 index = (IndexTupleForm) GETSTRUCT(tuple);
1784 Assert(index->indexrelid == indexId);
1785 isunique = index->indisunique;
1787 heap_endscan(scandesc);
1788 heap_close(pg_index);