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.6 1996/11/05 11:57:52 scrappy 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 <catalog/pg_proc.h>
29 #include <storage/bufmgr.h>
32 #include "access/genam.h"
33 #include "access/heapam.h"
34 #include "utils/builtins.h"
35 #include "access/xact.h"
36 #include "parser/catalog_utils.h"
38 #include "storage/smgr.h"
39 #include "storage/lmgr.h"
40 #include "miscadmin.h"
41 #include "utils/mcxt.h"
42 #include "utils/palloc.h"
43 #include "utils/relcache.h"
45 #include "bootstrap/bootstrap.h"
47 #include "catalog/catname.h"
48 #include "catalog/catalog.h"
49 #include "utils/syscache.h"
50 #include "catalog/pg_attribute.h"
51 #include "catalog/pg_class.h"
52 #include "catalog/indexing.h"
54 #include "catalog/heap.h"
56 #include "nodes/plannodes.h"
58 #include "catalog/index.h"
60 #include "executor/executor.h"
61 #include "executor/tuptable.h"
63 #include "optimizer/clauses.h"
64 #include "optimizer/prep.h"
66 #include "access/istrat.h"
68 # include <regex/utils.h>
74 * macros used in guessing how many tuples are on a page.
76 #define AVG_TUPLE_SIZE 8
77 #define NTUPLES_PER_PAGE(natts) (BLCKSZ/((natts)*AVG_TUPLE_SIZE))
79 /* non-export function prototypes */
80 static Oid RelationNameGetObjectId(char *relationName, Relation pg_class,
81 bool setHasIndexAttribute);
82 static Oid GetHeapRelationOid(char *heapRelationName, char *indexRelationName);
83 static TupleDesc BuildFuncTupleDesc(FuncIndexInfo *funcInfo);
84 static TupleDesc ConstructTupleDescriptor(Oid heapoid, Relation heapRelation,
85 TypeName *IndexKeyType,
86 int numatts, AttrNumber attNums[]);
88 static void ConstructIndexReldesc(Relation indexRelation, Oid amoid);
89 static Oid UpdateRelationRelation(Relation indexRelation);
90 static void InitializeAttributeOids(Relation indexRelation,
94 AppendAttributeTuples(Relation indexRelation, int numatts);
95 static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
96 FuncIndexInfo *funcInfo, int natts,
97 AttrNumber attNums[], Oid classOids[], Node *predicate,
98 TypeName *indexKeyType, bool islossy);
99 static void DefaultBuild(Relation heapRelation, Relation indexRelation,
100 int numberOfAttributes, AttrNumber attributeNumber[],
101 IndexStrategy indexStrategy, uint16 parameterCount,
102 Datum parameter[], FuncIndexInfoPtr funcInfo, PredInfo *predInfo);
104 /* ----------------------------------------------------------------
105 * sysatts is a structure containing attribute tuple forms
106 * for system attributes (numbered -1, -2, ...). This really
107 * should be generated or eliminated or moved elsewhere. -cim 1/19/91
109 * typedef struct FormData_pg_attribute {
115 * Oid atttyparg; type arg for arrays/spquel/procs
121 * Oid attproc; spquel?
122 * } FormData_pg_attribute;
124 * The data in this table was taken from local1_template.ami
125 * but tmin and tmax were switched because local1 was incorrect.
126 * ----------------------------------------------------------------
128 static FormData_pg_attribute sysatts[] = {
129 { 0l, {"ctid"}, 27l, 0l, 0l, 0l, 6, -1, 0, '\0', '\001', 0l, 'i' },
130 { 0l, {"oid"}, 26l, 0l, 0l, 0l, 4, -2, 0, '\001', '\001', 0l, 'i' },
131 { 0l, {"xmin"}, 28l, 0l, 0l, 0l, 5, -3, 0, '\0', '\001', 0l, 'i' },
132 { 0l, {"cmin"}, 29l, 0l, 0l, 0l, 1, -4, 0, '\001', '\001', 0l, 's' },
133 { 0l, {"xmax"}, 28l, 0l, 0l, 0l, 5, -5, 0, '\0', '\001', 0l, 'i' },
134 { 0l, {"cmax"}, 29l, 0l, 0l, 0l, 1, -6, 0, '\001', '\001', 0l, 's' },
135 { 0l, {"chain"}, 27l, 0l, 0l, 0l, 6, -7, 0, '\0', '\001', 0l, 'i' },
136 { 0l, {"anchor"}, 27l, 0l, 0l, 0l, 6, -8, 0, '\0', '\001', 0l, 'i' },
137 { 0l, {"tmin"}, 20l, 0l, 0l, 0l, 4, -9, 0, '\001', '\001', 0l, 'i' },
138 { 0l, {"tmax"}, 20l, 0l, 0l, 0l, 4, -10, 0, '\001', '\001', 0l, 'i' },
139 { 0l, {"vtype"}, 18l, 0l, 0l, 0l, 1, -11, 0, '\001', '\001', 0l, 'c' },
142 /* ----------------------------------------------------------------
143 * RelationNameGetObjectId --
144 * Returns the object identifier for a relation given its name.
146 * > The HASINDEX attribute for the relation with this name will
147 * > be set if it exists and if it is indicated by the call argument.
148 * What a load of bull. This setHasIndexAttribute is totally ignored.
149 * This is yet another silly routine to scan the catalogs which should
150 * probably be replaced by SearchSysCacheTuple. -cim 1/19/91
153 * Assumes relation name is valid.
154 * Assumes relation descriptor is valid.
155 * ----------------------------------------------------------------
158 RelationNameGetObjectId(char *relationName,
160 bool setHasIndexAttribute)
162 HeapScanDesc pg_class_scan;
163 HeapTuple pg_class_tuple;
164 Oid relationObjectId;
169 * If this isn't bootstrap time, we can use the system catalogs to
173 if (!IsBootstrapProcessingMode()) {
174 pg_class_tuple = ClassNameIndexScan(pg_class, relationName);
175 if (HeapTupleIsValid(pg_class_tuple)) {
176 relationObjectId = pg_class_tuple->t_oid;
177 pfree(pg_class_tuple);
179 relationObjectId = InvalidOid;
181 return (relationObjectId);
185 * Bootstrap time, do this the hard way.
186 * begin a scan of pg_class for the named relation
189 ScanKeyEntryInitialize(&key, 0, Anum_pg_class_relname,
190 NameEqualRegProcedure,
191 PointerGetDatum(relationName));
193 pg_class_scan = heap_beginscan(pg_class, 0, NowTimeQual, 1, &key);
196 * if we find the named relation, fetch its relation id
197 * (the oid of the tuple we found).
200 pg_class_tuple = heap_getnext(pg_class_scan, 0, &buffer);
202 if (! HeapTupleIsValid(pg_class_tuple)) {
203 relationObjectId = InvalidOid;
205 relationObjectId = pg_class_tuple->t_oid;
206 ReleaseBuffer(buffer);
210 * cleanup and return results
213 heap_endscan(pg_class_scan);
220 /* ----------------------------------------------------------------
222 * ----------------------------------------------------------------
225 GetHeapRelationOid(char *heapRelationName, char *indexRelationName)
232 * XXX ADD INDEXING HERE
236 * open pg_class and get the oid of the relation
237 * corresponding to the name of the index relation.
240 pg_class = heap_openr(RelationRelationName);
242 indoid = RelationNameGetObjectId(indexRelationName,
246 if (OidIsValid(indoid))
247 elog(WARN, "Cannot create index: '%s' already exists",
251 * get the object id of the heap relation
254 heapoid = RelationNameGetObjectId(heapRelationName,
259 * check that the heap relation exists..
262 if (! OidIsValid(heapoid))
263 elog(WARN, "Cannot create index on '%s': relation does not exist",
267 * close pg_class and return the heap relation oid
270 heap_close(pg_class);
276 BuildFuncTupleDesc(FuncIndexInfo *funcInfo)
279 TupleDesc funcTupDesc;
286 * Allocate and zero a tuple descriptor.
288 funcTupDesc = CreateTemplateTupleDesc(1);
289 funcTupDesc->attrs[0] = (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
290 memset(funcTupDesc->attrs[0], 0, ATTRIBUTE_TUPLE_SIZE);
293 * Lookup the function for the return type.
295 funcname = FIgetname(funcInfo);
296 nargs = FIgetnArgs(funcInfo);
297 argtypes = FIgetArglist(funcInfo);
298 tuple = SearchSysCacheTuple(PRONAME,
299 PointerGetDatum(funcname),
300 Int32GetDatum(nargs),
301 PointerGetDatum(argtypes),
304 if (!HeapTupleIsValid(tuple))
305 func_error("BuildFuncTupleDesc", funcname, nargs, (int*)argtypes);
307 retType = ((Form_pg_proc)GETSTRUCT(tuple))->prorettype;
310 * Look up the return type in pg_type for the type length.
312 tuple = SearchSysCacheTuple(TYPOID,
313 ObjectIdGetDatum(retType),
315 if (!HeapTupleIsValid(tuple))
316 elog(WARN,"Function %s return type does not exist",FIgetname(funcInfo));
319 * Assign some of the attributes values. Leave the rest as 0.
321 funcTupDesc->attrs[0]->attlen = ((TypeTupleForm)GETSTRUCT(tuple))->typlen;
322 funcTupDesc->attrs[0]->atttypid = retType;
323 funcTupDesc->attrs[0]->attnum = 1;
324 funcTupDesc->attrs[0]->attbyval = ((TypeTupleForm)GETSTRUCT(tuple))->typbyval;
325 funcTupDesc->attrs[0]->attcanindex = 0;
328 * make the attributes name the same as the functions
330 namestrcpy(&funcTupDesc->attrs[0]->attname, funcname);
332 return (funcTupDesc);
335 /* ----------------------------------------------------------------
336 * ConstructTupleDescriptor
337 * ----------------------------------------------------------------
340 ConstructTupleDescriptor(Oid heapoid,
341 Relation heapRelation,
342 TypeName *IndexKeyType,
344 AttrNumber attNums[])
346 TupleDesc heapTupDesc;
347 TupleDesc indexTupDesc;
348 AttrNumber atnum; /* attributeNumber[attributeOffset] */
350 int natts; /* RelationTupleForm->relnatts */
351 char *from; /* used to simplify memcpy below */
352 char *to; /* used to simplify memcpy below */
356 * allocate the new tuple descriptor
359 natts = RelationGetRelationTupleForm(heapRelation)->relnatts;
361 indexTupDesc = CreateTemplateTupleDesc(numatts);
369 * for each attribute we are indexing, obtain its attribute
370 * tuple form from either the static table of system attribute
371 * tuple forms or the relation tuple descriptor
374 for (i = 0; i < numatts; i += 1) {
377 * get the attribute number and make sure it's valid
382 elog(WARN, "Cannot create index: attribute %d does not exist",
385 indexTupDesc->attrs[i] = (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
388 * determine which tuple descriptor to copy
391 if (!AttrNumberIsForUserDefinedAttr(atnum)) {
394 * here we are indexing on a system attribute (-1...-12)
395 * so we convert atnum into a usable index 0...11 so we can
396 * use it to dereference the array sysatts[] which stores
397 * tuple descriptor information for system attributes.
400 if (atnum <= FirstLowInvalidHeapAttributeNumber || atnum >= 0 )
401 elog(WARN, "Cannot create index on system attribute: attribute number out of range (%d)", atnum);
402 atind = (-atnum) - 1;
404 from = (char *) (& sysatts[atind]);
408 * here we are indexing on a normal attribute (1...n)
412 heapTupDesc = RelationGetTupleDescriptor(heapRelation);
413 atind = AttrNumberGetAttrOffset(atnum);
415 from = (char *) (heapTupDesc->attrs[ atind ]);
419 * now that we've determined the "from", let's copy
420 * the tuple desc data...
424 to = (char *) (indexTupDesc->attrs[ i ]);
425 memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);
427 /* if the keytype is defined, we need to change the tuple form's
428 atttypid & attlen field to match that of the key's type */
429 if (IndexKeyType != NULL) {
432 tup = SearchSysCacheTuple(TYPNAME,
433 PointerGetDatum(IndexKeyType->name),
435 if(!HeapTupleIsValid(tup))
436 elog(WARN, "create index: type '%s' undefined",
438 ((AttributeTupleForm) to)->atttypid = tup->t_oid;
439 ((AttributeTupleForm) to)->attbyval =
440 ((TypeTupleForm) ((char *)tup + tup->t_hoff))->typbyval;
441 if (IndexKeyType->typlen > 0)
442 ((AttributeTupleForm) to)->attlen = IndexKeyType->typlen;
443 else ((AttributeTupleForm) to)->attlen =
444 ((TypeTupleForm) ((char *)tup + tup->t_hoff))->typlen;
449 * now we have to drop in the proper relation descriptor
450 * into the copied tuple form's attrelid and we should be
454 ((AttributeTupleForm) to)->attrelid = heapoid;
460 /* ----------------------------------------------------------------
461 * AccessMethodObjectIdGetAccessMethodTupleForm --
462 * Returns the formated access method tuple given its object identifier.
467 * Assumes object identifier is valid.
468 * ----------------------------------------------------------------
471 AccessMethodObjectIdGetAccessMethodTupleForm(Oid accessMethodObjectId)
474 HeapScanDesc pg_am_scan;
475 HeapTuple pg_am_tuple;
480 * form a scan key for the pg_am relation
483 ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
484 ObjectIdEqualRegProcedure,
485 ObjectIdGetDatum(accessMethodObjectId));
488 * fetch the desired access method tuple
491 pg_am_desc = heap_openr(AccessMethodRelationName);
492 pg_am_scan = heap_beginscan(pg_am_desc, 0, NowTimeQual, 1, &key);
494 pg_am_tuple = heap_getnext(pg_am_scan, 0, (Buffer *)NULL);
497 * return NULL if not found
500 if (! HeapTupleIsValid(pg_am_tuple)) {
501 heap_endscan(pg_am_scan);
502 heap_close(pg_am_desc);
507 * if found am tuple, then copy the form and return the copy
510 form = (Form_pg_am)palloc(sizeof *form);
511 memcpy(form, GETSTRUCT(pg_am_tuple), sizeof *form);
513 heap_endscan(pg_am_scan);
514 heap_close(pg_am_desc);
519 /* ----------------------------------------------------------------
520 * ConstructIndexReldesc
521 * ----------------------------------------------------------------
524 ConstructIndexReldesc(Relation indexRelation, Oid amoid)
526 extern GlobalMemory CacheCxt;
527 MemoryContext oldcxt;
530 * here we make certain to allocate the access method
531 * tuple within the cache context lest it vanish when the
536 CacheCxt = CreateGlobalMemory("Cache");
538 oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
540 indexRelation->rd_am =
541 AccessMethodObjectIdGetAccessMethodTupleForm(amoid);
543 MemoryContextSwitchTo(oldcxt);
546 * XXX missing the initialization of some other fields
550 indexRelation->rd_rel->relowner = GetUserId();
552 indexRelation->rd_rel->relam = amoid;
553 indexRelation->rd_rel->reltuples = 1; /* XXX */
554 indexRelation->rd_rel->relexpires = 0; /* XXX */
555 indexRelation->rd_rel->relpreserved = 0; /* XXX */
556 indexRelation->rd_rel->relkind = RELKIND_INDEX;
557 indexRelation->rd_rel->relarch = 'n'; /* XXX */
560 /* ----------------------------------------------------------------
561 * UpdateRelationRelation
562 * ----------------------------------------------------------------
565 UpdateRelationRelation(Relation indexRelation)
570 Relation idescs[Num_pg_class_indices];
572 pg_class = heap_openr(RelationRelationName);
574 /* XXX Natts_pg_class_fixed is a hack - see pg_class.h */
575 tuple = heap_addheader(Natts_pg_class_fixed,
576 sizeof(*indexRelation->rd_rel),
577 (char *) indexRelation->rd_rel);
580 * the new tuple must have the same oid as the relcache entry for the
581 * index. sure would be embarassing to do this sort of thing in polite
585 tuple->t_oid = indexRelation->rd_id;
586 heap_insert(pg_class, tuple);
589 * During normal processing, we need to make sure that the system
590 * catalog indices are correct. Bootstrap (initdb) time doesn't
591 * require this, because we make sure that the indices are correct
592 * just before exiting.
595 if (!IsBootstrapProcessingMode()) {
596 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
597 CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, tuple);
598 CatalogCloseIndices(Num_pg_class_indices, idescs);
601 tupleOid = tuple->t_oid;
603 heap_close(pg_class);
608 /* ----------------------------------------------------------------
609 * InitializeAttributeOids
610 * ----------------------------------------------------------------
613 InitializeAttributeOids(Relation indexRelation,
617 TupleDesc tupleDescriptor;
620 tupleDescriptor = RelationGetTupleDescriptor(indexRelation);
622 for (i = 0; i < numatts; i += 1)
623 tupleDescriptor->attrs[i]->attrelid = indexoid;
626 /* ----------------------------------------------------------------
627 * AppendAttributeTuples
629 * XXX For now, only change the ATTNUM attribute value
630 * ----------------------------------------------------------------
633 AppendAttributeTuples(Relation indexRelation, int numatts)
635 Relation pg_attribute;
639 Relation idescs[Num_pg_attr_indices];
641 Datum value[ Natts_pg_attribute ];
642 char nullv[ Natts_pg_attribute ];
643 char replace[ Natts_pg_attribute ];
645 TupleDesc indexTupDesc;
649 * open the attribute relation
653 pg_attribute = heap_openr(AttributeRelationName);
656 * initialize null[], replace[] and value[]
659 (void) memset(nullv, ' ', Natts_pg_attribute);
660 (void) memset(replace, ' ', Natts_pg_attribute);
663 * create the first attribute tuple.
664 * XXX For now, only change the ATTNUM attribute value
667 replace[ Anum_pg_attribute_attnum - 1 ] = 'r';
669 value[ Anum_pg_attribute_attnum - 1 ] = Int16GetDatum(1);
671 tuple = heap_addheader(Natts_pg_attribute,
672 sizeof *(indexRelation->rd_att->attrs[0]),
673 (char *)(indexRelation->rd_att->attrs[0]));
676 if (!IsBootstrapProcessingMode() && pg_attribute->rd_rel->relhasindex) {
678 CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
682 * insert the first attribute tuple.
685 tuple = heap_modifytuple(tuple,
692 heap_insert(pg_attribute, tuple);
694 CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, tuple);
697 * now we use the information in the index tuple
698 * descriptor to form the remaining attribute tuples.
701 indexTupDesc = RelationGetTupleDescriptor(indexRelation);
703 for (i = 1; i < numatts; i += 1) {
705 * process the remaining attributes...
708 memmove(GETSTRUCT(tuple),
709 (char *)indexTupDesc->attrs[i],
710 sizeof (AttributeTupleForm));
712 value[ Anum_pg_attribute_attnum - 1 ] = Int16GetDatum(i + 1);
714 newtuple = heap_modifytuple(tuple,
721 heap_insert(pg_attribute, newtuple);
723 CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, newtuple);
726 * ModifyHeapTuple returns a new copy of a tuple
727 * so we free the original and use the copy..
735 * close the attribute relation and free the tuple
738 heap_close(pg_attribute);
741 CatalogCloseIndices(Num_pg_attr_indices, idescs);
746 /* ----------------------------------------------------------------
747 * UpdateIndexRelation
748 * ----------------------------------------------------------------
751 UpdateIndexRelation(Oid indexoid,
753 FuncIndexInfo *funcInfo,
755 AttrNumber attNums[],
758 TypeName *indexKeyType,
761 IndexTupleForm indexForm;
764 int predLen, itupLen;
770 * allocate an IndexTupleForm big enough to hold the
771 * index-predicate (if any) in string form
774 if (predicate != NULL) {
775 predString = nodeToString(predicate);
776 predText = (text *)fmgr(F_TEXTIN, predString);
779 predText = (text *)fmgr(F_TEXTIN, "");
781 predLen = VARSIZE(predText);
782 itupLen = predLen + sizeof(FormData_pg_index);
783 indexForm = (IndexTupleForm) palloc(itupLen);
785 memmove((char *)& indexForm->indpred, (char *)predText, predLen);
788 * store the oid information into the index tuple form
791 indexForm->indrelid = heapoid;
792 indexForm->indexrelid = indexoid;
793 indexForm->indproc = (PointerIsValid(funcInfo)) ?
794 FIgetProcOid(funcInfo) : InvalidOid;
795 indexForm->indislossy = islossy;
796 if (indexKeyType != NULL)
797 indexForm->indhaskeytype = 1;
799 indexForm->indhaskeytype = 0;
801 memset((char *)& indexForm->indkey[0], 0, sizeof indexForm->indkey);
802 memset((char *)& indexForm->indclass[0], 0, sizeof indexForm->indclass);
805 * copy index key and op class information
808 for (i = 0; i < natts; i += 1) {
809 indexForm->indkey[i] = attNums[i];
810 indexForm->indclass[i] = classOids[i];
813 * If we have a functional index, add all attribute arguments
815 if (PointerIsValid(funcInfo))
817 for (i=1; i < FIgetnArgs(funcInfo); i++)
818 indexForm->indkey[i] = attNums[i];
821 indexForm->indisclustered = '\0'; /* XXX constant */
822 indexForm->indisarchived = '\0'; /* XXX constant */
825 * open the system catalog index relation
828 pg_index = heap_openr(IndexRelationName);
831 * form a tuple to insert into pg_index
834 tuple = heap_addheader(Natts_pg_index,
839 * insert the tuple into the pg_index
840 * XXX ADD INDEX TUPLES TOO
843 heap_insert(pg_index, tuple);
846 * close the relation and free the tuple
849 heap_close(pg_index);
855 /* ----------------------------------------------------------------
856 * UpdateIndexPredicate
857 * ----------------------------------------------------------------
860 UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
872 Datum values[Natts_pg_index];
873 char nulls[Natts_pg_index];
874 char replace[Natts_pg_index];
877 * Construct newPred as a CNF expression equivalent to the OR of the
878 * original partial-index predicate ("oldPred") and the extension
879 * predicate ("predicate").
881 * This should really try to process the result to change things like
882 * "a>2 OR a>1" to simply "a>1", but for now all it does is make sure
883 * that if the extension predicate is NULL (i.e., it is being extended
884 * to be a complete index), then newPred will be NULL - in effect,
885 * changing "a>2 OR TRUE" to "TRUE". --Nels, Jan '93
888 if (predicate != NULL) {
890 (Node*)make_orclause(lcons(make_andclause((List*)predicate),
891 lcons(make_andclause((List*)oldPred),
893 newPred = (Node*)cnfify((Expr*)newPred, true);
896 /* translate the index-predicate to string form */
897 if (newPred != NULL) {
898 predString = nodeToString(newPred);
899 predText = (text *)fmgr(F_TEXTIN, predString);
902 predText = (text *)fmgr(F_TEXTIN, "");
905 /* open the index system catalog relation */
906 pg_index = heap_openr(IndexRelationName);
908 ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_index_indexrelid,
909 ObjectIdEqualRegProcedure,
910 ObjectIdGetDatum(indexoid));
912 scan = heap_beginscan(pg_index, 0, NowTimeQual, 1, &entry);
913 tuple = heap_getnext(scan, 0, &buffer);
916 for (i = 0; i < Natts_pg_index; i++) {
917 nulls[i] = heap_attisnull(tuple, i+1) ? 'n' : ' ';
919 values[i] = (Datum) NULL;
922 replace[Anum_pg_index_indpred - 1] = 'r';
923 values[Anum_pg_index_indpred - 1] = (Datum) predText;
925 newtup = heap_modifytuple(tuple, buffer, pg_index, values, nulls, replace);
927 (void) heap_replace(pg_index, &(newtup->t_ctid), newtup);
929 heap_close(pg_index);
933 /* ----------------------------------------------------------------
935 * ----------------------------------------------------------------
938 InitIndexStrategy(int numatts,
939 Relation indexRelation,
940 Oid accessMethodObjectId)
942 IndexStrategy strategy;
943 RegProcedure *support;
948 extern GlobalMemory CacheCxt;
951 * get information from the index relation descriptor
954 attrelid = indexRelation->rd_att->attrs[0]->attrelid;
955 amstrategies = indexRelation->rd_am->amstrategies;
956 amsupport = indexRelation->rd_am->amsupport;
959 * get the size of the strategy
962 strsize = AttributeNumberGetIndexStrategySize(numatts, amstrategies);
965 * allocate the new index strategy structure
967 * the index strategy has to be allocated in the same
968 * context as the relation descriptor cache or else
969 * it will be lost at the end of the transaction.
973 CacheCxt = CreateGlobalMemory("Cache");
975 strategy = (IndexStrategy)
976 MemoryContextAlloc((MemoryContext)CacheCxt, strsize);
979 strsize = numatts * (amsupport * sizeof(RegProcedure));
980 support = (RegProcedure *) MemoryContextAlloc((MemoryContext)CacheCxt,
983 support = (RegProcedure *) NULL;
987 * fill in the index strategy structure with information
988 * from the catalogs. Note: we use heap override mode
989 * in order to be allowed to see the correct information in the
990 * catalogs, even though our transaction has not yet committed.
995 IndexSupportInitialize(strategy, support,
996 attrelid, accessMethodObjectId,
997 amstrategies, amsupport, numatts);
1002 * store the strategy information in the index reldesc
1005 RelationSetIndexSupport(indexRelation, strategy, support);
1009 /* ----------------------------------------------------------------
1011 * ----------------------------------------------------------------
1014 index_create(char *heapRelationName,
1015 char *indexRelationName,
1016 FuncIndexInfo *funcInfo,
1017 TypeName *IndexKeyType,
1018 Oid accessMethodObjectId,
1020 AttrNumber attNums[],
1021 Oid classObjectId[],
1022 uint16 parameterCount,
1027 Relation heapRelation;
1028 Relation indexRelation;
1029 TupleDesc indexTupDesc;
1039 elog(WARN, "must index at least one attribute");
1042 * get heap relation oid and open the heap relation
1046 heapoid = GetHeapRelationOid(heapRelationName, indexRelationName);
1048 heapRelation = heap_open(heapoid);
1051 * write lock heap to guarantee exclusive access
1055 RelationSetLockForWrite(heapRelation);
1058 * construct new tuple descriptor
1061 if (PointerIsValid(funcInfo))
1062 indexTupDesc = BuildFuncTupleDesc(funcInfo);
1064 indexTupDesc = ConstructTupleDescriptor(heapoid,
1071 * create the index relation
1074 indexRelation = heap_creatr(indexRelationName,
1079 * construct the index relation descriptor
1081 * XXX should have a proper way to create cataloged relations
1084 ConstructIndexReldesc(indexRelation, accessMethodObjectId);
1087 * add index to catalogs
1088 * (append RELATION tuple)
1091 indexoid = UpdateRelationRelation(indexRelation);
1094 * Now get the index procedure (only relevant for functional indices).
1098 if (PointerIsValid(funcInfo))
1102 proc_tup = SearchSysCacheTuple(PRONAME,
1103 PointerGetDatum(FIgetname(funcInfo)),
1104 Int32GetDatum(FIgetnArgs(funcInfo)),
1105 PointerGetDatum(FIgetArglist(funcInfo)),
1108 if (!HeapTupleIsValid(proc_tup)) {
1109 func_error("index_create", FIgetname(funcInfo),
1110 FIgetnArgs(funcInfo),
1111 (int*) FIgetArglist(funcInfo));
1113 FIgetProcOid(funcInfo) = proc_tup->t_oid;
1117 * now update the object id's of all the attribute
1118 * tuple forms in the index relation's tuple descriptor
1121 InitializeAttributeOids(indexRelation, numatts, indexoid);
1124 * append ATTRIBUTE tuples
1127 AppendAttributeTuples(indexRelation, numatts);
1131 * (append INDEX tuple)
1133 * Note that this stows away a representation of "predicate".
1134 * (Or, could define a rule to maintain the predicate) --Nels, Feb '92
1137 UpdateIndexRelation(indexoid, heapoid, funcInfo,
1138 numatts, attNums, classObjectId, predicate,
1139 IndexKeyType, islossy);
1141 predInfo = (PredInfo*)palloc(sizeof(PredInfo));
1142 predInfo->pred = predicate;
1143 predInfo->oldPred = NULL;
1146 * initialize the index strategy
1149 InitIndexStrategy(numatts, indexRelation, accessMethodObjectId);
1152 * If this is bootstrap (initdb) time, then we don't actually
1153 * fill in the index yet. We'll be creating more indices and classes
1154 * later, so we delay filling them in until just before we're done
1155 * with bootstrapping. Otherwise, we call the routine that constructs
1156 * the index. The heap and index relations are closed by index_build().
1158 if (IsBootstrapProcessingMode()) {
1159 index_register(heapRelationName, indexRelationName, numatts, attNums,
1160 parameterCount, parameter, funcInfo, predInfo);
1162 heapRelation = heap_openr(heapRelationName);
1163 index_build(heapRelation, indexRelation, numatts, attNums,
1164 parameterCount, parameter, funcInfo, predInfo);
1168 /* ----------------------------------------------------------------
1171 * XXX break into modules like index_create
1172 * ----------------------------------------------------------------
1175 index_destroy(Oid indexId)
1177 Relation indexRelation;
1178 Relation catalogRelation;
1183 Assert(OidIsValid(indexId));
1185 indexRelation = index_open(indexId);
1188 * fix RELATION relation
1191 catalogRelation = heap_openr(RelationRelationName);
1193 ScanKeyEntryInitialize(&entry, 0x0, ObjectIdAttributeNumber,
1194 ObjectIdEqualRegProcedure,
1195 ObjectIdGetDatum(indexId));;
1197 scan = heap_beginscan(catalogRelation, 0, NowTimeQual, 1, &entry);
1198 tuple = heap_getnext(scan, 0, (Buffer *)NULL);
1200 AssertState(HeapTupleIsValid(tuple));
1202 heap_delete(catalogRelation, &tuple->t_ctid);
1204 heap_close(catalogRelation);
1207 * fix ATTRIBUTE relation
1210 catalogRelation = heap_openr(AttributeRelationName);
1212 entry.sk_attno = Anum_pg_attribute_attrelid;
1214 scan = heap_beginscan(catalogRelation, 0, NowTimeQual, 1, &entry);
1216 while (tuple = heap_getnext(scan, 0, (Buffer *)NULL),
1217 HeapTupleIsValid(tuple)) {
1219 heap_delete(catalogRelation, &tuple->t_ctid);
1222 heap_close(catalogRelation);
1225 * fix INDEX relation
1228 catalogRelation = heap_openr(IndexRelationName);
1230 entry.sk_attno = Anum_pg_index_indexrelid;
1232 scan = heap_beginscan(catalogRelation, 0, NowTimeQual, 1, &entry);
1233 tuple = heap_getnext(scan, 0, (Buffer *)NULL);
1234 if (! HeapTupleIsValid(tuple)) {
1235 elog(NOTICE, "IndexRelationDestroy: %s's INDEX tuple missing",
1236 RelationGetRelationName(indexRelation));
1238 heap_delete(catalogRelation, &tuple->t_ctid);
1240 heap_close(catalogRelation);
1243 * physically remove the file
1245 if (FileNameUnlink(relpath(indexRelation->rd_rel->relname.data)) < 0)
1246 elog(WARN, "amdestroyr: unlink: %m");
1248 index_close(indexRelation);
1251 /* ----------------------------------------------------------------
1252 * index_build support
1253 * ----------------------------------------------------------------
1260 FormIndexDatum(int numberOfAttributes,
1261 AttrNumber attributeNumber[],
1262 HeapTuple heapTuple,
1263 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 += 1) {
1281 offset = AttrNumberGetAttrOffset(i);
1284 PointerGetDatum( GetIndexValue(heapTuple,
1292 nullv[ offset ] = (isNull) ? 'n' : ' ';
1302 UpdateStats(Oid relid, long reltuples, bool hasindex)
1306 HeapScanDesc pg_class_scan;
1312 Form_pg_class rd_rel;
1313 Relation idescs[Num_pg_class_indices];
1315 static ScanKeyData key[1] = {
1316 { 0, ObjectIdAttributeNumber, ObjectIdEqualRegProcedure }
1318 Datum values[Natts_pg_class];
1319 char nulls[Natts_pg_class];
1320 char replace[Natts_pg_class];
1322 fmgr_info(ObjectIdEqualRegProcedure, (func_ptr *) &key[0].sk_func,
1326 * This routine handles updates for both the heap and index relation
1327 * statistics. In order to guarantee that we're able to *see* the index
1328 * relation tuple, we bump the command counter id here. The index
1329 * relation tuple was created in the current transaction.
1332 CommandCounterIncrement();
1335 * CommandCounterIncrement() flushes invalid cache entries, including
1336 * those for the heap and index relations for which we're updating
1337 * statistics. Now that the cache is flushed, it's safe to open the
1338 * relation again. We need the relation open in order to figure out
1339 * how many blocks it contains.
1343 whichRel = RelationIdGetRelation(relid);
1345 if (!RelationIsValid(whichRel))
1346 elog(WARN, "UpdateStats: cannot open relation id %d", relid);
1349 * Find the RELATION relation tuple for the given relation.
1352 pg_class = heap_openr(RelationRelationName);
1353 if (! RelationIsValid(pg_class)) {
1354 elog(WARN, "UpdateStats: could not open RELATION relation");
1356 key[0].sk_argument = ObjectIdGetDatum(relid);
1359 heap_beginscan(pg_class, 0, NowTimeQual, 1, key);
1361 if (! HeapScanIsValid(pg_class_scan)) {
1362 heap_close(pg_class);
1363 elog(WARN, "UpdateStats: cannot scan RELATION relation");
1366 /* if the heap_open above succeeded, then so will this heap_getnext() */
1367 htup = heap_getnext(pg_class_scan, 0, &buffer);
1368 heap_endscan(pg_class_scan);
1374 relpages = RelationGetNumberOfBlocks(whichRel);
1377 * We shouldn't have to do this, but we do... Modify the reldesc
1378 * in place with the new values so that the cache contains the
1382 whichRel->rd_rel->relhasindex = hasindex;
1383 whichRel->rd_rel->relpages = relpages;
1384 whichRel->rd_rel->reltuples = reltuples;
1386 for (i = 0; i < Natts_pg_class; i++) {
1387 nulls[i] = heap_attisnull(htup, i+1) ? 'n' : ' ';
1389 values[i] = (Datum) NULL;
1393 * If reltuples wasn't supplied take an educated guess.
1396 reltuples = relpages*NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
1398 if (IsBootstrapProcessingMode()) {
1401 * At bootstrap time, we don't need to worry about concurrency
1402 * or visibility of changes, so we cheat.
1405 rd_rel = (Form_pg_class) GETSTRUCT(htup);
1406 rd_rel->relpages = relpages;
1407 rd_rel->reltuples = reltuples;
1408 rd_rel->relhasindex = hasindex;
1410 /* during normal processing, work harder */
1411 replace[Anum_pg_class_relpages - 1] = 'r';
1412 values[Anum_pg_class_relpages - 1] = (Datum)relpages;
1413 replace[Anum_pg_class_reltuples - 1] = 'r';
1414 values[Anum_pg_class_reltuples - 1] = (Datum)reltuples;
1415 replace[Anum_pg_class_relhasindex - 1] = 'r';
1416 values[Anum_pg_class_relhasindex - 1] = CharGetDatum(hasindex);
1418 newtup = heap_modifytuple(htup, buffer, pg_class, values,
1420 (void) heap_replace(pg_class, &(newtup->t_ctid), newtup);
1421 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
1422 CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, newtup);
1423 CatalogCloseIndices(Num_pg_class_indices, idescs);
1426 heap_close(pg_class);
1427 heap_close(whichRel);
1431 /* -------------------------
1432 * FillDummyExprContext
1433 * Sets up dummy ExprContext and TupleTableSlot objects for use
1435 * -------------------------
1438 FillDummyExprContext(ExprContext *econtext,
1439 TupleTableSlot *slot,
1443 econtext->ecxt_scantuple = slot;
1444 econtext->ecxt_innertuple = NULL;
1445 econtext->ecxt_outertuple = NULL;
1446 econtext->ecxt_param_list_info = NULL;
1447 econtext->ecxt_range_table = NULL;
1449 slot->ttc_tupleDescriptor = tupdesc;
1450 slot->ttc_buffer = buffer;
1451 slot->ttc_shouldFree = false;
1461 DefaultBuild(Relation heapRelation,
1462 Relation indexRelation,
1463 int numberOfAttributes,
1464 AttrNumber attributeNumber[],
1465 IndexStrategy indexStrategy, /* not used */
1466 uint16 parameterCount, /* not used */
1467 Datum parameter[], /* not used */
1468 FuncIndexInfoPtr funcInfo,
1472 HeapTuple heapTuple;
1475 IndexTuple indexTuple;
1476 TupleDesc heapDescriptor;
1477 TupleDesc indexDescriptor;
1480 long reltuples, indtuples;
1481 #ifndef OMIT_PARTIAL_INDEX
1482 ExprContext *econtext;
1483 TupleTable tupleTable;
1484 TupleTableSlot *slot;
1489 InsertIndexResult insertResult;
1492 * more & better checking is needed
1495 Assert(OidIsValid(indexRelation->rd_rel->relam)); /* XXX */
1498 * get the tuple descriptors from the relations so we know
1499 * how to form the index tuples..
1502 heapDescriptor = RelationGetTupleDescriptor(heapRelation);
1503 indexDescriptor = RelationGetTupleDescriptor(indexRelation);
1506 * datum and null are arrays in which we collect the index attributes
1507 * when forming a new index tuple.
1510 datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
1511 nullv = (char *) palloc(numberOfAttributes * sizeof *nullv);
1514 * If this is a predicate (partial) index, we will need to evaluate the
1515 * predicate using ExecQual, which requires the current tuple to be in a
1516 * slot of a TupleTable. In addition, ExecQual must have an ExprContext
1517 * referring to that slot. Here, we initialize dummy TupleTable and
1518 * ExprContext objects for this purpose. --Nels, Feb '92
1521 predicate = predInfo->pred;
1522 oldPred = predInfo->oldPred;
1524 #ifndef OMIT_PARTIAL_INDEX
1525 if (predicate != NULL || oldPred != NULL) {
1526 tupleTable = ExecCreateTupleTable(1);
1527 slot = ExecAllocTableSlot(tupleTable);
1528 econtext = makeNode(ExprContext);
1529 FillDummyExprContext(econtext, slot, heapDescriptor, buffer);
1531 #endif /* OMIT_PARTIAL_INDEX */
1534 * Ok, begin our scan of the base relation.
1537 scan = heap_beginscan(heapRelation, /* relation */
1538 0, /* start at end */
1539 NowTimeQual, /* time range */
1540 0, /* number of keys */
1541 (ScanKey) NULL); /* scan key */
1543 reltuples = indtuples = 0;
1546 * for each tuple in the base relation, we create an index
1547 * tuple and add it to the index relation. We keep a running
1548 * count of the number of tuples so that we can update pg_class
1549 * with correct statistics when we're done building the index.
1552 while (heapTuple = heap_getnext(scan, 0, &buffer),
1553 HeapTupleIsValid(heapTuple)) {
1558 * If oldPred != NULL, this is an EXTEND INDEX command, so skip
1559 * this tuple if it was already in the existing partial index
1561 if (oldPred != NULL) {
1562 #ifndef OMIT_PARTIAL_INDEX
1563 /*SetSlotContents(slot, heapTuple); */
1564 slot->val = heapTuple;
1565 if (ExecQual((List*)oldPred, econtext) == true) {
1569 #endif /* OMIT_PARTIAL_INDEX */
1572 /* Skip this tuple if it doesn't satisfy the partial-index predicate */
1573 if (predicate != NULL) {
1574 #ifndef OMIT_PARTIAL_INDEX
1575 /*SetSlotContents(slot, heapTuple); */
1576 slot->val = heapTuple;
1577 if (ExecQual((List*)predicate, econtext) == false)
1579 #endif /* OMIT_PARTIAL_INDEX */
1585 * FormIndexDatum fills in its datum and null parameters
1586 * with attribute information taken from the given heap tuple.
1589 FormIndexDatum(numberOfAttributes, /* num attributes */
1590 attributeNumber, /* array of att nums to extract */
1591 heapTuple, /* tuple from base relation */
1592 heapDescriptor, /* heap tuple's descriptor */
1593 buffer, /* buffer used in the scan */
1594 datum, /* return: array of attributes */
1595 nullv, /* return: array of char's */
1598 indexTuple = index_formtuple(indexDescriptor,
1602 indexTuple->t_tid = heapTuple->t_ctid;
1604 insertResult = index_insert(indexRelation, datum, nullv,
1605 &(heapTuple->t_ctid));
1607 if (insertResult) pfree(insertResult);
1613 if (predicate != NULL || oldPred != NULL) {
1614 #ifndef OMIT_PARTIAL_INDEX
1615 ExecDestroyTupleTable(tupleTable, false);
1616 #endif /* OMIT_PARTIAL_INDEX */
1623 * Okay, now update the reltuples and relpages statistics for both
1624 * the heap relation and the index. These statistics are used by
1625 * the planner to choose a scan type. They are maintained generally
1626 * by the vacuum daemon, but we update them here to make the index
1627 * useful as soon as possible.
1629 UpdateStats(heapRelation->rd_id, reltuples, true);
1630 UpdateStats(indexRelation->rd_id, indtuples, false);
1631 if (oldPred != NULL) {
1632 if (indtuples == reltuples) predicate = NULL;
1633 UpdateIndexPredicate(indexRelation->rd_id, oldPred, predicate);
1642 index_build(Relation heapRelation,
1643 Relation indexRelation,
1644 int numberOfAttributes,
1645 AttrNumber attributeNumber[],
1646 uint16 parameterCount,
1648 FuncIndexInfo *funcInfo,
1651 RegProcedure procedure;
1657 Assert(RelationIsValid(indexRelation));
1658 Assert(PointerIsValid(indexRelation->rd_am));
1660 procedure = indexRelation->rd_am->ambuild;
1663 * use the access method build procedure if supplied..
1666 if (RegProcedureIsValid(procedure))
1667 (void) fmgr(procedure,
1672 RelationGetIndexStrategy(indexRelation),
1678 DefaultBuild(heapRelation,
1682 RelationGetIndexStrategy(indexRelation),