]> granicus.if.org Git - postgresql/blob - src/backend/catalog/index.c
31eafc5867ecf30fe79dd4c309c295a4322c2d0b
[postgresql] / src / backend / catalog / index.c
1 /*-------------------------------------------------------------------------
2  *
3  * index.c--
4  *        code to create and destroy POSTGRES index relations
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.54 1998/08/26 05:22:34 momjian Exp $
11  *
12  *
13  * INTERFACE ROUTINES
14  *              index_create()                  - Create a cataloged index relation
15  *              index_destroy()                 - Removes index relation from catalogs
16  *
17  * NOTES
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
22  *        caching.
23  *
24  *-------------------------------------------------------------------------
25  */
26 #include "postgres.h"
27
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"
41 #include "fmgr.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"
53
54 #ifndef HAVE_MEMMOVE
55 #include <regex/utils.h>
56 #else
57 #include <string.h>
58 #endif
59
60 /*
61  * macros used in guessing how many tuples are on a page.
62  */
63 #define AVG_TUPLE_SIZE 8
64 #define NTUPLES_PER_PAGE(natts) (BLCKSZ/((natts)*AVG_TUPLE_SIZE))
65
66 /* non-export function prototypes */
67 static Oid
68 RelationNameGetObjectId(char *relationName, Relation pg_class);
69 static Oid      GetHeapRelationOid(char *heapRelationName, char *indexRelationName);
70 static TupleDesc BuildFuncTupleDesc(FuncIndexInfo *funcInfo);
71 static TupleDesc
72 ConstructTupleDescriptor(Oid heapoid, Relation heapRelation,
73                                                  List *attributeList,
74                                                  int numatts, AttrNumber attNums[]);
75
76 static void ConstructIndexReldesc(Relation indexRelation, Oid amoid);
77 static Oid      UpdateRelationRelation(Relation indexRelation);
78 static void
79 InitializeAttributeOids(Relation indexRelation,
80                                                 int numatts,
81                                                 Oid indexoid);
82 static void
83                         AppendAttributeTuples(Relation indexRelation, int numatts);
84 static void
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);
89 static void
90 DefaultBuild(Relation heapRelation, Relation indexRelation,
91                          int numberOfAttributes, AttrNumber attributeNumber[],
92                          IndexStrategy indexStrategy, uint16 parameterCount,
93            Datum parameter[], FuncIndexInfoPtr funcInfo, PredInfo *predInfo);
94
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
99  *
100  * typedef struct FormData_pg_attribute {
101  *              Oid                             attrelid;
102  *              NameData                attname;
103  *              Oid                             atttypid;
104  *              uint32                  attnvals;
105  *              int16                   attlen;
106  *              AttrNumber              attnum;
107  *              uint32                  attnelems;
108  *              int32                   attcacheoff;
109  *              int32                   atttypmod;
110  *              bool                    attbyval;
111  *              bool                    attisset;
112  *              char                    attalign;
113  *              bool                    attnotnull;
114  *              bool                    atthasdef;
115  * } FormData_pg_attribute;
116  *
117  * ----------------------------------------------------------------
118  */
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, '\0', '\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, '\0', '\0', 'i', '\0', '\0'},
125         {0, {"cmax"}, CIDOID, 0, 4, -6, 0, -1, -1, '\001', '\0', 'i', '\0', '\0'},
126 };
127
128 /* ----------------------------------------------------------------
129  * RelationNameGetObjectId --
130  *              Returns the object identifier for a relation given its name.
131  *
132  * ----------------------------------------------------------------
133  */
134 static Oid
135 RelationNameGetObjectId(char *relationName,
136                                                 Relation pg_class)
137 {
138         HeapScanDesc pg_class_scan;
139         HeapTuple       pg_class_tuple;
140         Oid                     relationObjectId;
141         ScanKeyData key;
142
143         /*
144          * If this isn't bootstrap time, we can use the system catalogs to
145          * speed this up.
146          */
147
148         if (!IsBootstrapProcessingMode())
149         {
150                 HeapTuple       tuple;
151         
152                 tuple = SearchSysCacheTuple(RELNAME,
153                                                                         PointerGetDatum(relationName),
154                                                                         0, 0, 0);
155         
156                 if (HeapTupleIsValid(tuple))
157                         return tuple->t_oid;
158                 else
159                         return InvalidOid;
160         }
161
162         /* ----------------
163          *      BOOTSTRAP TIME, do this the hard way.
164          *      begin a scan of pg_class for the named relation
165          * ----------------
166          */
167         ScanKeyEntryInitialize(&key, 0, Anum_pg_class_relname,
168                                                    F_NAMEEQ,
169                                                    PointerGetDatum(relationName));
170
171         pg_class_scan = heap_beginscan(pg_class, 0, SnapshotNow, 1, &key);
172
173         /* ----------------
174          *      if we find the named relation, fetch its relation id
175          *      (the oid of the tuple we found).
176          * ----------------
177          */
178         pg_class_tuple = heap_getnext(pg_class_scan, 0);
179
180         if (!HeapTupleIsValid(pg_class_tuple))
181                 relationObjectId = InvalidOid;
182         else
183                 relationObjectId = pg_class_tuple->t_oid;
184
185         /* ----------------
186          *      cleanup and return results
187          * ----------------
188          */
189         heap_endscan(pg_class_scan);
190
191         return relationObjectId;
192 }
193
194
195 /* ----------------------------------------------------------------
196  *              GetHeapRelationOid
197  * ----------------------------------------------------------------
198  */
199 static Oid
200 GetHeapRelationOid(char *heapRelationName, char *indexRelationName)
201 {
202         Relation        pg_class;
203         Oid                     indoid;
204         Oid                     heapoid;
205
206         /* ----------------
207          *      open pg_class and get the oid of the relation
208          *      corresponding to the name of the index relation.
209          * ----------------
210          */
211         pg_class = heap_openr(RelationRelationName);
212
213         indoid = RelationNameGetObjectId(indexRelationName, pg_class);
214
215         if (OidIsValid(indoid))
216                 elog(ERROR, "Cannot create index: '%s' already exists",
217                          indexRelationName);
218
219         heapoid = RelationNameGetObjectId(heapRelationName, pg_class);
220
221         if (!OidIsValid(heapoid))
222                 elog(ERROR, "Cannot create index on '%s': relation does not exist",
223                          heapRelationName);
224
225         heap_close(pg_class);
226
227         return heapoid;
228 }
229
230 static TupleDesc
231 BuildFuncTupleDesc(FuncIndexInfo *funcInfo)
232 {
233         HeapTuple       tuple;
234         TupleDesc       funcTupDesc;
235         Oid                     retType;
236         char       *funcname;
237         int4            nargs;
238         Oid                *argtypes;
239
240         /*
241          * Allocate and zero a tuple descriptor.
242          */
243         funcTupDesc = CreateTemplateTupleDesc(1);
244         funcTupDesc->attrs[0] = (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
245         MemSet(funcTupDesc->attrs[0], 0, ATTRIBUTE_TUPLE_SIZE);
246
247         /*
248          * Lookup the function for the return type.
249          */
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),
257                                                                 0);
258
259         if (!HeapTupleIsValid(tuple))
260                 func_error("BuildFuncTupleDesc", funcname, nargs, argtypes, NULL);
261
262         retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype;
263
264         /*
265          * Look up the return type in pg_type for the type length.
266          */
267         tuple = SearchSysCacheTuple(TYPOID,
268                                                                 ObjectIdGetDatum(retType),
269                                                                 0, 0, 0);
270         if (!HeapTupleIsValid(tuple))
271                 elog(ERROR, "Function %s return type does not exist", FIgetname(funcInfo));
272
273         /*
274          * Assign some of the attributes values. Leave the rest as 0.
275          */
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;
283
284         /*
285          * make the attributes name the same as the functions
286          */
287         namestrcpy(&funcTupDesc->attrs[0]->attname, funcname);
288
289         return (funcTupDesc);
290 }
291
292 /* ----------------------------------------------------------------
293  *              ConstructTupleDescriptor
294  * ----------------------------------------------------------------
295  */
296 static TupleDesc
297 ConstructTupleDescriptor(Oid heapoid,
298                                                  Relation heapRelation,
299                                                  List *attributeList,
300                                                  int numatts,
301                                                  AttrNumber attNums[])
302 {
303         TupleDesc       heapTupDesc;
304         TupleDesc       indexTupDesc;
305         IndexElem  *IndexKey;
306         TypeName   *IndexKeyType;
307         AttrNumber      atnum;                  /* attributeNumber[attributeOffset] */
308         AttrNumber      atind;
309         int                     natts;                  /* RelationTupleForm->relnatts */
310         char       *from;                       /* used to simplify memcpy below */
311         char       *to;                         /* used to simplify memcpy below */
312         int                     i;
313
314         /* ----------------
315          *      allocate the new tuple descriptor
316          * ----------------
317          */
318         natts = RelationGetRelationTupleForm(heapRelation)->relnatts;
319
320         indexTupDesc = CreateTemplateTupleDesc(numatts);
321
322         /* ----------------
323          *
324          * ----------------
325          */
326
327         /* ----------------
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
331          * ----------------
332          */
333         for (i = 0; i < numatts; i += 1)
334         {
335
336                 /* ----------------
337                  *       get the attribute number and make sure it's valid
338                  * ----------------
339                  */
340                 atnum = attNums[i];
341                 if (atnum > natts)
342                         elog(ERROR, "Cannot create index: attribute %d does not exist",
343                                  atnum);
344                 if (attributeList)
345                 {
346                         IndexKey = (IndexElem *) lfirst(attributeList);
347                         IndexKeyType = IndexKey->typename;
348                         attributeList = lnext(attributeList);
349                 }
350                 else
351                         IndexKeyType = NULL;
352
353                 indexTupDesc->attrs[i] = (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
354
355                 /* ----------------
356                  *       determine which tuple descriptor to copy
357                  * ----------------
358                  */
359                 if (!AttrNumberIsForUserDefinedAttr(atnum))
360                 {
361
362                         /* ----------------
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.
367                          * ----------------
368                          */
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;
372
373                         from = (char *) (&sysatts[atind]);
374
375                 }
376                 else
377                 {
378                         /* ----------------
379                          *        here we are indexing on a normal attribute (1...n)
380                          * ----------------
381                          */
382                         heapTupDesc = RelationGetTupleDescriptor(heapRelation);
383                         atind = AttrNumberGetAttrOffset(atnum);
384
385                         from = (char *) (heapTupDesc->attrs[atind]);
386                 }
387
388                 /* ----------------
389                  *       now that we've determined the "from", let's copy
390                  *       the tuple desc data...
391                  * ----------------
392                  */
393
394                 to = (char *) (indexTupDesc->attrs[i]);
395                 memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);
396
397                 ((AttributeTupleForm) to)->attnum = i + 1;
398
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';
404
405                 /*
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
408                  */
409                 if (IndexKeyType != NULL)
410                 {
411                         HeapTuple       tup;
412
413                         tup = SearchSysCacheTuple(TYPNAME,
414                                                                           PointerGetDatum(IndexKeyType->name),
415                                                                           0, 0, 0);
416                         if (!HeapTupleIsValid(tup))
417                                 elog(ERROR, "create index: type '%s' undefined",
418                                          IndexKeyType->name);
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;
427                 }
428
429
430                 /* ----------------
431                  *        now we have to drop in the proper relation descriptor
432                  *        into the copied tuple form's attrelid and we should be
433                  *        all set.
434                  * ----------------
435                  */
436                 ((AttributeTupleForm) to)->attrelid = heapoid;
437         }
438
439         return indexTupDesc;
440 }
441
442 /* ----------------------------------------------------------------
443  * AccessMethodObjectIdGetAccessMethodTupleForm --
444  *              Returns the formated access method tuple given its object identifier.
445  *
446  * XXX ADD INDEXING
447  *
448  * Note:
449  *              Assumes object identifier is valid.
450  * ----------------------------------------------------------------
451  */
452 Form_pg_am
453 AccessMethodObjectIdGetAccessMethodTupleForm(Oid accessMethodObjectId)
454 {
455         Relation        pg_am_desc;
456         HeapScanDesc pg_am_scan;
457         HeapTuple       pg_am_tuple;
458         ScanKeyData key;
459         Form_pg_am      form;
460
461         /* ----------------
462          *      form a scan key for the pg_am relation
463          * ----------------
464          */
465         ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
466                                                    F_OIDEQ,
467                                                    ObjectIdGetDatum(accessMethodObjectId));
468
469         /* ----------------
470          *      fetch the desired access method tuple
471          * ----------------
472          */
473         pg_am_desc = heap_openr(AccessMethodRelationName);
474         pg_am_scan = heap_beginscan(pg_am_desc, 0, SnapshotNow, 1, &key);
475
476         pg_am_tuple = heap_getnext(pg_am_scan, 0);
477
478         /* ----------------
479          *      return NULL if not found
480          * ----------------
481          */
482         if (!HeapTupleIsValid(pg_am_tuple))
483         {
484                 heap_endscan(pg_am_scan);
485                 heap_close(pg_am_desc);
486                 return (NULL);
487         }
488
489         /* ----------------
490          *      if found am tuple, then copy the form and return the copy
491          * ----------------
492          */
493         form = (Form_pg_am) palloc(sizeof *form);
494         memcpy(form, GETSTRUCT(pg_am_tuple), sizeof *form);
495
496         heap_endscan(pg_am_scan);
497         heap_close(pg_am_desc);
498
499         return (form);
500 }
501
502 /* ----------------------------------------------------------------
503  *              ConstructIndexReldesc
504  * ----------------------------------------------------------------
505  */
506 static void
507 ConstructIndexReldesc(Relation indexRelation, Oid amoid)
508 {
509         extern GlobalMemory CacheCxt;
510         MemoryContext oldcxt;
511
512         /* ----------------
513          *        here we make certain to allocate the access method
514          *        tuple within the cache context lest it vanish when the
515          *        context changes
516          * ----------------
517          */
518         if (!CacheCxt)
519                 CacheCxt = CreateGlobalMemory("Cache");
520
521         oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
522
523         indexRelation->rd_am =
524                 AccessMethodObjectIdGetAccessMethodTupleForm(amoid);
525
526         MemoryContextSwitchTo(oldcxt);
527
528         /* ----------------
529          *       XXX missing the initialization of some other fields
530          * ----------------
531          */
532
533         indexRelation->rd_rel->relowner = GetUserId();
534
535         indexRelation->rd_rel->relam = amoid;
536         indexRelation->rd_rel->reltuples = 1;           /* XXX */
537         indexRelation->rd_rel->relkind = RELKIND_INDEX;
538 }
539
540 /* ----------------------------------------------------------------
541  *              UpdateRelationRelation
542  * ----------------------------------------------------------------
543  */
544 static Oid
545 UpdateRelationRelation(Relation indexRelation)
546 {
547         Relation        pg_class;
548         HeapTuple       tuple;
549         Oid                     tupleOid;
550         Relation        idescs[Num_pg_class_indices];
551
552         pg_class = heap_openr(RelationRelationName);
553
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);
558
559         /* ----------------
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
562          *      company.
563          * ----------------
564          */
565         tuple->t_oid = RelationGetRelid(indexRelation);
566         heap_insert(pg_class, tuple);
567
568         /*
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.
573          */
574
575         if (!IsBootstrapProcessingMode())
576         {
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);
580         }
581
582         tupleOid = tuple->t_oid;
583         pfree(tuple);
584         heap_close(pg_class);
585
586         return (tupleOid);
587 }
588
589 /* ----------------------------------------------------------------
590  *              InitializeAttributeOids
591  * ----------------------------------------------------------------
592  */
593 static void
594 InitializeAttributeOids(Relation indexRelation,
595                                                 int numatts,
596                                                 Oid indexoid)
597 {
598         TupleDesc       tupleDescriptor;
599         int                     i;
600
601         tupleDescriptor = RelationGetTupleDescriptor(indexRelation);
602
603         for (i = 0; i < numatts; i += 1)
604                 tupleDescriptor->attrs[i]->attrelid = indexoid;
605 }
606
607 /* ----------------------------------------------------------------
608  *              AppendAttributeTuples
609  *
610  *              XXX For now, only change the ATTNUM attribute value
611  * ----------------------------------------------------------------
612  */
613 static void
614 AppendAttributeTuples(Relation indexRelation, int numatts)
615 {
616         Relation        pg_attribute;
617         HeapTuple       init_tuple, cur_tuple = NULL, new_tuple;
618         bool            hasind;
619         Relation        idescs[Num_pg_attr_indices];
620
621         Datum           value[Natts_pg_attribute];
622         char            nullv[Natts_pg_attribute];
623         char            replace[Natts_pg_attribute];
624
625         TupleDesc       indexTupDesc;
626         int                     i;
627
628         /* ----------------
629          *      open the attribute relation
630          *      XXX ADD INDEXING
631          * ----------------
632          */
633         pg_attribute = heap_openr(AttributeRelationName);
634
635         /* ----------------
636          *      initialize null[], replace[] and value[]
637          * ----------------
638          */
639         MemSet(nullv, ' ', Natts_pg_attribute);
640         MemSet(replace, ' ', Natts_pg_attribute);
641
642         /* ----------------
643          *      create the first attribute tuple.
644          *      XXX For now, only change the ATTNUM attribute value
645          * ----------------
646          */
647         replace[Anum_pg_attribute_attnum - 1] = 'r';
648         replace[Anum_pg_attribute_attcacheoff - 1] = 'r';
649
650         value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(1);
651         value[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1);
652
653         init_tuple = heap_addheader(Natts_pg_attribute,
654                                                    sizeof *(indexRelation->rd_att->attrs[0]),
655                                                    (char *) (indexRelation->rd_att->attrs[0]));
656
657         hasind = false;
658         if (!IsBootstrapProcessingMode() && pg_attribute->rd_rel->relhasindex)
659         {
660                 hasind = true;
661                 CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
662         }
663
664         /* ----------------
665          *      insert the first attribute tuple.
666          * ----------------
667          */
668         cur_tuple = heap_modifytuple(init_tuple,
669                                                          pg_attribute,
670                                                          value,
671                                                          nullv,
672                                                          replace);
673         pfree(init_tuple);
674         
675         heap_insert(pg_attribute, cur_tuple);
676         if (hasind)
677                 CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, cur_tuple);
678
679         /* ----------------
680          *      now we use the information in the index cur_tuple
681          *      descriptor to form the remaining attribute tuples.
682          * ----------------
683          */
684         indexTupDesc = RelationGetTupleDescriptor(indexRelation);
685
686         for (i = 1; i < numatts; i += 1)
687         {
688                 /* ----------------
689                  *      process the remaining attributes...
690                  * ----------------
691                  */
692                 memmove(GETSTRUCT(cur_tuple),
693                                 (char *) indexTupDesc->attrs[i],
694                                 sizeof(FormData_pg_attribute));
695
696                 value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(i + 1);
697
698                 new_tuple = heap_modifytuple(cur_tuple,
699                                                                         pg_attribute,
700                                                                         value,
701                                                                         nullv,
702                                                                         replace);
703                 pfree(cur_tuple);
704
705                 heap_insert(pg_attribute,new_tuple);
706                 if (hasind)
707                         CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, new_tuple);
708
709                 /* ----------------
710                  *      ModifyHeapTuple returns a new copy of a cur_tuple
711                  *      so we free the original and use the copy..
712                  * ----------------
713                  */
714                  cur_tuple = new_tuple;
715         }
716
717         if (cur_tuple)
718                 pfree(cur_tuple);
719         heap_close(pg_attribute);
720         if (hasind)
721                 CatalogCloseIndices(Num_pg_attr_indices, idescs);
722
723 }
724
725 /* ----------------------------------------------------------------
726  *              UpdateIndexRelation
727  * ----------------------------------------------------------------
728  */
729 static void
730 UpdateIndexRelation(Oid indexoid,
731                                         Oid heapoid,
732                                         FuncIndexInfo *funcInfo,
733                                         int natts,
734                                         AttrNumber attNums[],
735                                         Oid classOids[],
736                                         Node *predicate,
737                                         List *attributeList,
738                                         bool islossy,
739                                         bool unique)
740 {
741         IndexTupleForm indexForm;
742         IndexElem  *IndexKey;
743         char       *predString;
744         text       *predText;
745         int                     predLen,
746                                 itupLen;
747         Relation        pg_index;
748         HeapTuple       tuple;
749         int                     i;
750
751         /* ----------------
752          *      allocate an IndexTupleForm big enough to hold the
753          *      index-predicate (if any) in string form
754          * ----------------
755          */
756         if (predicate != NULL)
757         {
758                 predString = nodeToString(predicate);
759                 predText = (text *) fmgr(F_TEXTIN, predString);
760                 pfree(predString);
761         }
762         else
763                 predText = (text *) fmgr(F_TEXTIN, "");
764         predLen = VARSIZE(predText);
765         itupLen = predLen + sizeof(FormData_pg_index);
766         indexForm = (IndexTupleForm) palloc(itupLen);
767
768         memmove((char *) &indexForm->indpred, (char *) predText, predLen);
769
770         /* ----------------
771          *      store the oid information into the index tuple form
772          * ----------------
773          */
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;
780
781         indexForm->indhaskeytype = 0;
782         while (attributeList != NIL)
783         {
784                 IndexKey = (IndexElem *) lfirst(attributeList);
785                 if (IndexKey->typename != NULL)
786                 {
787                         indexForm->indhaskeytype = 1;
788                         break;
789                 }
790                 attributeList = lnext(attributeList);
791         }
792
793         MemSet((char *) &indexForm->indkey[0], 0, sizeof indexForm->indkey);
794         MemSet((char *) &indexForm->indclass[0], 0, sizeof indexForm->indclass);
795
796         /* ----------------
797          *      copy index key and op class information
798          * ----------------
799          */
800         for (i = 0; i < natts; i += 1)
801         {
802                 indexForm->indkey[i] = attNums[i];
803                 indexForm->indclass[i] = classOids[i];
804         }
805
806         /*
807          * If we have a functional index, add all attribute arguments
808          */
809         if (PointerIsValid(funcInfo))
810         {
811                 for (i = 1; i < FIgetnArgs(funcInfo); i++)
812                         indexForm->indkey[i] = attNums[i];
813         }
814
815         indexForm->indisclustered = '\0';       /* XXX constant */
816
817         /* ----------------
818          *      open the system catalog index relation
819          * ----------------
820          */
821         pg_index = heap_openr(IndexRelationName);
822
823         /* ----------------
824          *      form a tuple to insert into pg_index
825          * ----------------
826          */
827         tuple = heap_addheader(Natts_pg_index,
828                                                    itupLen,
829                                                    (char *) indexForm);
830
831         /* ----------------
832          *      insert the tuple into the pg_index
833          *      XXX ADD INDEX TUPLES TOO
834          * ----------------
835          */
836         heap_insert(pg_index, tuple);
837
838         /* ----------------
839          *      close the relation and free the tuple
840          * ----------------
841          */
842         heap_close(pg_index);
843         pfree(predText);
844         pfree(indexForm);
845         pfree(tuple);
846 }
847
848 /* ----------------------------------------------------------------
849  *              UpdateIndexPredicate
850  * ----------------------------------------------------------------
851  */
852 void
853 UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
854 {
855         Node       *newPred;
856         char       *predString;
857         text       *predText;
858         Relation        pg_index;
859         HeapTuple       tuple;
860         HeapTuple       newtup;
861         int                     i;
862         Datum           values[Natts_pg_index];
863         char            nulls[Natts_pg_index];
864         char            replace[Natts_pg_index];
865
866         /*
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").
870          *
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
876          */
877         newPred = NULL;
878         if (predicate != NULL)
879         {
880                 newPred =
881                         (Node *) make_orclause(lcons(make_andclause((List *) predicate),
882                                                                   lcons(make_andclause((List *) oldPred),
883                                                                                 NIL)));
884                 newPred = (Node *) cnfify((Expr *) newPred, true);
885         }
886
887         /* translate the index-predicate to string form */
888         if (newPred != NULL)
889         {
890                 predString = nodeToString(newPred);
891                 predText = (text *) fmgr(F_TEXTIN, predString);
892                 pfree(predString);
893         }
894         else
895                 predText = (text *) fmgr(F_TEXTIN, "");
896
897         /* open the index system catalog relation */
898         pg_index = heap_openr(IndexRelationName);
899
900         tuple = SearchSysCacheTuple(INDEXRELID,
901                                                                   ObjectIdGetDatum(indexoid),
902                                                                   0, 0, 0);
903         Assert(HeapTupleIsValid(tuple));
904         
905         for (i = 0; i < Natts_pg_index; i++)
906         {
907                 nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' ';
908                 replace[i] = ' ';
909                 values[i] = (Datum) NULL;
910         }
911
912         replace[Anum_pg_index_indpred - 1] = 'r';
913         values[Anum_pg_index_indpred - 1] = (Datum) predText;
914
915         newtup = heap_modifytuple(tuple, pg_index, values, nulls, replace);
916
917         heap_replace(pg_index, &newtup->t_ctid, newtup);
918
919         pfree(newtup);
920         heap_close(pg_index);
921         pfree(predText);
922 }
923
924 /* ----------------------------------------------------------------
925  *              InitIndexStrategy
926  * ----------------------------------------------------------------
927  */
928 void
929 InitIndexStrategy(int numatts,
930                                   Relation indexRelation,
931                                   Oid accessMethodObjectId)
932 {
933         IndexStrategy strategy;
934         RegProcedure *support;
935         uint16          amstrategies;
936         uint16          amsupport;
937         Oid                     attrelid;
938         Size            strsize;
939         extern GlobalMemory CacheCxt;
940
941         /* ----------------
942          *      get information from the index relation descriptor
943          * ----------------
944          */
945         attrelid = indexRelation->rd_att->attrs[0]->attrelid;
946         amstrategies = indexRelation->rd_am->amstrategies;
947         amsupport = indexRelation->rd_am->amsupport;
948
949         /* ----------------
950          *      get the size of the strategy
951          * ----------------
952          */
953         strsize = AttributeNumberGetIndexStrategySize(numatts, amstrategies);
954
955         /* ----------------
956          *      allocate the new index strategy structure
957          *
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.
961          * ----------------
962          */
963         if (!CacheCxt)
964                 CacheCxt = CreateGlobalMemory("Cache");
965
966         strategy = (IndexStrategy)
967                 MemoryContextAlloc((MemoryContext) CacheCxt, strsize);
968
969         if (amsupport > 0)
970         {
971                 strsize = numatts * (amsupport * sizeof(RegProcedure));
972                 support = (RegProcedure *) MemoryContextAlloc((MemoryContext) CacheCxt,
973                                                                                                           strsize);
974         }
975         else
976                 support = (RegProcedure *) NULL;
977
978         /* ----------------
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.
983          * ----------------
984          */
985         setheapoverride(true);
986
987         IndexSupportInitialize(strategy, support,
988                                                    attrelid, accessMethodObjectId,
989                                                    amstrategies, amsupport, numatts);
990
991         setheapoverride(false);
992
993         /* ----------------
994          *      store the strategy information in the index reldesc
995          * ----------------
996          */
997         RelationSetIndexSupport(indexRelation, strategy, support);
998 }
999
1000
1001 /* ----------------------------------------------------------------
1002  *              index_create
1003  * ----------------------------------------------------------------
1004  */
1005 void
1006 index_create(char *heapRelationName,
1007                          char *indexRelationName,
1008                          FuncIndexInfo *funcInfo,
1009                          List *attributeList,
1010                          Oid accessMethodObjectId,
1011                          int numatts,
1012                          AttrNumber attNums[],
1013                          Oid classObjectId[],
1014                          uint16 parameterCount,
1015                          Datum *parameter,
1016                          Node *predicate,
1017                          bool islossy,
1018                          bool unique)
1019 {
1020         Relation        heapRelation;
1021         Relation        indexRelation;
1022         TupleDesc       indexTupDesc;
1023         Oid                     heapoid;
1024         Oid                     indexoid;
1025         PredInfo   *predInfo;
1026
1027         /* ----------------
1028          *      check parameters
1029          * ----------------
1030          */
1031         if (numatts < 1)
1032                 elog(ERROR, "must index at least one attribute");
1033
1034         /* ----------------
1035          *        get heap relation oid and open the heap relation
1036          *        XXX ADD INDEXING
1037          * ----------------
1038          */
1039         heapoid = GetHeapRelationOid(heapRelationName, indexRelationName);
1040
1041         heapRelation = heap_open(heapoid);
1042
1043         /* ----------------
1044          * write lock heap to guarantee exclusive access
1045          * ----------------
1046         RelationSetLockForWrite(heapRelation);
1047          *                                ^^^^^
1048          * Does it have any sense ?             - vadim 10/27/97
1049          */
1050
1051         RelationSetLockForRead(heapRelation);
1052
1053         /* ----------------
1054          *        construct new tuple descriptor
1055          * ----------------
1056          */
1057         if (PointerIsValid(funcInfo))
1058                 indexTupDesc = BuildFuncTupleDesc(funcInfo);
1059         else
1060                 indexTupDesc = ConstructTupleDescriptor(heapoid,
1061                                                                                                 heapRelation,
1062                                                                                                 attributeList,
1063                                                                                                 numatts,
1064                                                                                                 attNums);
1065
1066         /* ----------------
1067          *      create the index relation
1068          * ----------------
1069          */
1070         indexRelation = heap_create(indexRelationName,
1071                                                                 indexTupDesc);
1072
1073         /* ----------------
1074          *        construct the index relation descriptor
1075          *
1076          *        XXX should have a proper way to create cataloged relations
1077          * ----------------
1078          */
1079         ConstructIndexReldesc(indexRelation, accessMethodObjectId);
1080
1081         /* ----------------
1082          *        add index to catalogs
1083          *        (append RELATION tuple)
1084          * ----------------
1085          */
1086         indexoid = UpdateRelationRelation(indexRelation);
1087
1088         /* ----------------
1089          * Now get the index procedure (only relevant for functional indices).
1090          * ----------------
1091          */
1092
1093         if (PointerIsValid(funcInfo))
1094         {
1095                 HeapTuple       proc_tup;
1096
1097                 proc_tup = SearchSysCacheTuple(PRONAME,
1098                                                                         PointerGetDatum(FIgetname(funcInfo)),
1099                                                                          Int32GetDatum(FIgetnArgs(funcInfo)),
1100                                                                  PointerGetDatum(FIgetArglist(funcInfo)),
1101                                                                            0);
1102
1103                 if (!HeapTupleIsValid(proc_tup))
1104                 {
1105                         func_error("index_create", FIgetname(funcInfo),
1106                                            FIgetnArgs(funcInfo), FIgetArglist(funcInfo), NULL);
1107                 }
1108                 FIgetProcOid(funcInfo) = proc_tup->t_oid;
1109         }
1110
1111         /* ----------------
1112          *      now update the object id's of all the attribute
1113          *      tuple forms in the index relation's tuple descriptor
1114          * ----------------
1115          */
1116         InitializeAttributeOids(indexRelation, numatts, indexoid);
1117
1118         /* ----------------
1119          *        append ATTRIBUTE tuples
1120          * ----------------
1121          */
1122         AppendAttributeTuples(indexRelation, numatts);
1123
1124         /* ----------------
1125          *        update pg_index
1126          *        (append INDEX tuple)
1127          *
1128          *        Note that this stows away a representation of "predicate".
1129          *        (Or, could define a rule to maintain the predicate) --Nels, Feb '92
1130          * ----------------
1131          */
1132         UpdateIndexRelation(indexoid, heapoid, funcInfo,
1133                                                 numatts, attNums, classObjectId, predicate,
1134                                                 attributeList, islossy, unique);
1135
1136         predInfo = (PredInfo *) palloc(sizeof(PredInfo));
1137         predInfo->pred = predicate;
1138         predInfo->oldPred = NULL;
1139
1140         /* ----------------
1141          *        initialize the index strategy
1142          * ----------------
1143          */
1144         InitIndexStrategy(numatts, indexRelation, accessMethodObjectId);
1145
1146         /*
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().
1152          */
1153         if (IsBootstrapProcessingMode())
1154         {
1155                 index_register(heapRelationName, indexRelationName, numatts, attNums,
1156                                            parameterCount, parameter, funcInfo, predInfo);
1157         }
1158         else
1159         {
1160                 heapRelation = heap_openr(heapRelationName);
1161                 index_build(heapRelation, indexRelation, numatts, attNums,
1162                                         parameterCount, parameter, funcInfo, predInfo);
1163         }
1164 }
1165
1166 /* ----------------------------------------------------------------
1167  *              index_destroy
1168  *
1169  *              XXX break into modules like index_create
1170  * ----------------------------------------------------------------
1171  */
1172 void
1173 index_destroy(Oid indexId)
1174 {
1175         Relation        userindexRelation;
1176         Relation        indexRelation;
1177         Relation        relationRelation;
1178         Relation        attributeRelation;
1179         HeapTuple       tuple;
1180         int16           attnum;
1181         
1182         Assert(OidIsValid(indexId));
1183
1184         /* why open it here?  bjm 1998/08/20 */
1185         userindexRelation = index_open(indexId);
1186
1187         /* ----------------
1188          * fix RELATION relation
1189          * ----------------
1190          */
1191         relationRelation = heap_openr(RelationRelationName);
1192
1193         tuple = SearchSysCacheTupleCopy(RELOID,
1194                                                                         ObjectIdGetDatum(indexId),
1195                                                                         0, 0, 0);
1196
1197         AssertState(HeapTupleIsValid(tuple));
1198
1199         heap_delete(relationRelation, &tuple->t_ctid);
1200         pfree(tuple);
1201         heap_close(relationRelation);
1202
1203         /* ----------------
1204          * fix ATTRIBUTE relation
1205          * ----------------
1206          */
1207         attributeRelation = heap_openr(AttributeRelationName);
1208
1209         attnum = 1; /* indexes start at 1 */
1210
1211         while (HeapTupleIsValid(tuple = SearchSysCacheTupleCopy(ATTNUM,
1212                                                                         ObjectIdGetDatum(indexId),
1213                                                                         Int16GetDatum(attnum),
1214                                                                         0, 0)))
1215         {
1216                 heap_delete(attributeRelation, &tuple->t_ctid);
1217                 pfree(tuple);
1218                 attnum++;
1219         }
1220         heap_close(attributeRelation);
1221
1222         /* ----------------
1223          * fix INDEX relation
1224          * ----------------
1225          */
1226         tuple = SearchSysCacheTupleCopy(INDEXRELID,
1227                                                                           ObjectIdGetDatum(indexId),
1228                                                                           0, 0, 0);
1229
1230         if (!HeapTupleIsValid(tuple))
1231                 elog(NOTICE, "IndexRelationDestroy: %s's INDEX tuple missing",
1232                          RelationGetRelationName(userindexRelation));
1233
1234         indexRelation = heap_openr(IndexRelationName);
1235                                  
1236         heap_delete(indexRelation, &tuple->t_ctid);
1237         pfree(tuple);
1238         heap_close(indexRelation);
1239
1240         /*
1241          * flush cache and physically remove the file
1242          */
1243         ReleaseRelationBuffers(userindexRelation);
1244
1245         if (FileNameUnlink(relpath(userindexRelation->rd_rel->relname.data)) < 0)
1246                 elog(ERROR, "amdestroyr: unlink: %m");
1247
1248         index_close(userindexRelation);
1249         RelationForgetRelation(RelationGetRelid(userindexRelation));
1250 }
1251
1252 /* ----------------------------------------------------------------
1253  *                                              index_build support
1254  * ----------------------------------------------------------------
1255  */
1256 /* ----------------
1257  *              FormIndexDatum
1258  * ----------------
1259  */
1260 void
1261 FormIndexDatum(int numberOfAttributes,
1262                            AttrNumber attributeNumber[],
1263                            HeapTuple heapTuple,
1264                            TupleDesc heapDescriptor,
1265                            Datum *datum,
1266                            char *nullv,
1267                            FuncIndexInfoPtr fInfo)
1268 {
1269         AttrNumber      i;
1270         int                     offset;
1271         bool            isNull;
1272
1273         /* ----------------
1274          *      for each attribute we need from the heap tuple,
1275          *      get the attribute and stick it into the datum and
1276          *      null arrays.
1277          * ----------------
1278          */
1279
1280         for (i = 1; i <= numberOfAttributes; i++)
1281         {
1282                 offset = AttrNumberGetAttrOffset(i);
1283
1284                 datum[offset] =
1285                         PointerGetDatum(GetIndexValue(heapTuple,
1286                                                                                   heapDescriptor,
1287                                                                                   offset,
1288                                                                                   attributeNumber,
1289                                                                                   fInfo,
1290                                                                                   &isNull));
1291
1292                 nullv[offset] = (isNull) ? 'n' : ' ';
1293         }
1294 }
1295
1296
1297 /* ----------------
1298  *              UpdateStats
1299  * ----------------
1300  */
1301 void
1302 UpdateStats(Oid relid, long reltuples, bool hasindex)
1303 {
1304         Relation        whichRel;
1305         Relation        pg_class;
1306         HeapTuple       tuple;
1307         HeapTuple       newtup;
1308         long            relpages;
1309         int                     i;
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;
1316
1317         /* ----------------
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.
1322          * ----------------
1323          */
1324         CommandCounterIncrement();
1325
1326         /* ----------------
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.
1332          * ----------------
1333          */
1334
1335         whichRel = RelationIdGetRelation(relid);
1336
1337         if (!RelationIsValid(whichRel))
1338                 elog(ERROR, "UpdateStats: cannot open relation id %d", relid);
1339
1340         /* ----------------
1341          * Find the RELATION relation tuple for the given relation.
1342          * ----------------
1343          */
1344         pg_class = heap_openr(RelationRelationName);
1345         if (!RelationIsValid(pg_class))
1346                 elog(ERROR, "UpdateStats: could not open RELATION relation");
1347
1348
1349         if (!IsBootstrapProcessingMode())
1350         {
1351                 tuple = SearchSysCacheTupleCopy(RELOID,
1352                                                                                 ObjectIdGetDatum(relid),
1353                                                                                 0, 0, 0);
1354         }
1355         else
1356         {
1357                 ScanKeyData key[1];
1358
1359                 ScanKeyEntryInitialize(&key[0], 0,
1360                                                                 ObjectIdAttributeNumber,
1361                                                                 F_OIDEQ,
1362                                                                 ObjectIdGetDatum(relid));
1363
1364                 pg_class_scan = heap_beginscan(pg_class, 0, SnapshotNow, 1, key);
1365                 tuple = heap_getnext(pg_class_scan, 0);
1366         }
1367         
1368         if (!HeapTupleIsValid(tuple))
1369         {
1370                 if (IsBootstrapProcessingMode())
1371                         heap_endscan(pg_class_scan);
1372                 heap_close(pg_class);
1373                 elog(ERROR, "UpdateStats: cannot scan RELATION relation");
1374         }
1375
1376         /* ----------------
1377          *      update statistics
1378          * ----------------
1379          */
1380         relpages = RelationGetNumberOfBlocks(whichRel);
1381
1382         /*
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
1385          * copy.
1386          */
1387
1388         whichRel->rd_rel->relhasindex = hasindex;
1389         whichRel->rd_rel->relpages = relpages;
1390         whichRel->rd_rel->reltuples = reltuples;
1391
1392         for (i = 0; i < Natts_pg_class; i++)
1393         {
1394                 nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' ';
1395                 replace[i] = ' ';
1396                 values[i] = (Datum) NULL;
1397         }
1398
1399         /*
1400          * If reltuples wasn't supplied take an educated guess.
1401          */
1402         if (reltuples == 0)
1403                 reltuples = relpages * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
1404
1405         if (IsBootstrapProcessingMode())
1406         {
1407
1408                 /*
1409                  * At bootstrap time, we don't need to worry about concurrency or
1410                  * visibility of changes, so we cheat.
1411                  */
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);
1417         }
1418         else
1419         {
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);
1427
1428                 newtup = heap_modifytuple(tuple, pg_class, values, nulls, replace);
1429                 heap_replace(pg_class, &tuple->t_ctid, newtup);
1430                 pfree(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);
1434         }
1435
1436         if (!IsBootstrapProcessingMode())
1437                 pfree(tuple);
1438         else
1439                 heap_endscan(pg_class_scan);
1440         
1441         heap_close(pg_class);
1442         heap_close(whichRel);
1443 }
1444
1445
1446 /* -------------------------
1447  *              FillDummyExprContext
1448  *                      Sets up dummy ExprContext and TupleTableSlot objects for use
1449  *                      with ExecQual.
1450  * -------------------------
1451  */
1452 void
1453 FillDummyExprContext(ExprContext *econtext,
1454                                          TupleTableSlot *slot,
1455                                          TupleDesc tupdesc,
1456                                          Buffer buffer)
1457 {
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;
1463
1464         slot->ttc_tupleDescriptor = tupdesc;
1465         slot->ttc_buffer = buffer;
1466         slot->ttc_shouldFree = false;
1467
1468 }
1469
1470
1471 /* ----------------
1472  *              DefaultBuild
1473  * ----------------
1474  */
1475 static void
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,
1484                          PredInfo *predInfo)
1485 {
1486         HeapScanDesc scan;
1487         HeapTuple       heapTuple;
1488         IndexTuple      indexTuple;
1489         TupleDesc       heapDescriptor;
1490         TupleDesc       indexDescriptor;
1491         Datum      *datum;
1492         char       *nullv;
1493         long            reltuples,
1494                                 indtuples;
1495
1496 #ifndef OMIT_PARTIAL_INDEX
1497         ExprContext *econtext;
1498         TupleTable      tupleTable;
1499         TupleTableSlot *slot;
1500
1501 #endif
1502         Node       *predicate;
1503         Node       *oldPred;
1504
1505         InsertIndexResult insertResult;
1506
1507         /* ----------------
1508          *      more & better checking is needed
1509          * ----------------
1510          */
1511         Assert(OidIsValid(indexRelation->rd_rel->relam));       /* XXX */
1512
1513         /* ----------------
1514          *      get the tuple descriptors from the relations so we know
1515          *      how to form the index tuples..
1516          * ----------------
1517          */
1518         heapDescriptor = RelationGetTupleDescriptor(heapRelation);
1519         indexDescriptor = RelationGetTupleDescriptor(indexRelation);
1520
1521         /* ----------------
1522          *      datum and null are arrays in which we collect the index attributes
1523          *      when forming a new index tuple.
1524          * ----------------
1525          */
1526         datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
1527         nullv = (char *) palloc(numberOfAttributes * sizeof *nullv);
1528
1529         /*
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
1535          * '92
1536          */
1537
1538         predicate = predInfo->pred;
1539         oldPred = predInfo->oldPred;
1540
1541 #ifndef OMIT_PARTIAL_INDEX
1542         if (predicate != NULL || oldPred != NULL)
1543         {
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);
1549         }
1550         else
1551         {
1552                 econtext = NULL;
1553                 tupleTable = 0;
1554                 slot = NULL;
1555         }
1556 #endif                                                  /* OMIT_PARTIAL_INDEX */
1557
1558         /* ----------------
1559          *      Ok, begin our scan of the base relation.
1560          * ----------------
1561          */
1562         scan = heap_beginscan(heapRelation, /* relation */
1563                                                   0,    /* start at end */
1564                                                   SnapshotNow,/* seeself */
1565                                                   0,    /* number of keys */
1566                                                   (ScanKey) NULL);              /* scan key */
1567
1568         reltuples = indtuples = 0;
1569
1570         /* ----------------
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.
1575          * ----------------
1576          */
1577         while (HeapTupleIsValid(heapTuple = heap_getnext(scan, 0)))
1578         {
1579                 reltuples++;
1580
1581                 /*
1582                  * If oldPred != NULL, this is an EXTEND INDEX command, so skip
1583                  * this tuple if it was already in the existing partial index
1584                  */
1585                 if (oldPred != NULL)
1586                 {
1587 #ifndef OMIT_PARTIAL_INDEX
1588                         /* SetSlotContents(slot, heapTuple); */
1589                         slot->val = heapTuple;
1590                         if (ExecQual((List *) oldPred, econtext) == true)
1591                         {
1592                                 indtuples++;
1593                                 continue;
1594                         }
1595 #endif                                                  /* OMIT_PARTIAL_INDEX */
1596                 }
1597
1598                 /*
1599                  * Skip this tuple if it doesn't satisfy the partial-index
1600                  * predicate
1601                  */
1602                 if (predicate != NULL)
1603                 {
1604 #ifndef OMIT_PARTIAL_INDEX
1605                         /* SetSlotContents(slot, heapTuple); */
1606                         slot->val = heapTuple;
1607                         if (ExecQual((List *) predicate, econtext) == false)
1608                                 continue;
1609 #endif                                                  /* OMIT_PARTIAL_INDEX */
1610                 }
1611
1612                 indtuples++;
1613
1614                 /* ----------------
1615                  *      FormIndexDatum fills in its datum and null parameters
1616                  *      with attribute information taken from the given heap tuple.
1617                  * ----------------
1618                  */
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 */
1625                                            funcInfo);
1626
1627                 indexTuple = index_formtuple(indexDescriptor,
1628                                                                          datum,
1629                                                                          nullv);
1630
1631                 indexTuple->t_tid = heapTuple->t_ctid;
1632
1633                 insertResult = index_insert(indexRelation, datum, nullv,
1634                                                                         &(heapTuple->t_ctid), heapRelation);
1635
1636                 if (insertResult)
1637                         pfree(insertResult);
1638                 pfree(indexTuple);
1639         }
1640
1641         heap_endscan(scan);
1642
1643         if (predicate != NULL || oldPred != NULL)
1644         {
1645 #ifndef OMIT_PARTIAL_INDEX
1646                 ExecDestroyTupleTable(tupleTable, false);
1647 #endif                                                  /* OMIT_PARTIAL_INDEX */
1648         }
1649
1650         pfree(nullv);
1651         pfree(datum);
1652
1653         /*
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.
1659          */
1660         UpdateStats(RelationGetRelid(heapRelation), reltuples, true);
1661         UpdateStats(RelationGetRelid(indexRelation), indtuples, false);
1662         if (oldPred != NULL)
1663         {
1664                 if (indtuples == reltuples)
1665                         predicate = NULL;
1666                 UpdateIndexPredicate(RelationGetRelid(indexRelation),
1667                                                          oldPred, predicate);
1668         }
1669 }
1670
1671 /* ----------------
1672  *              index_build
1673  * ----------------
1674  */
1675 void
1676 index_build(Relation heapRelation,
1677                         Relation indexRelation,
1678                         int numberOfAttributes,
1679                         AttrNumber attributeNumber[],
1680                         uint16 parameterCount,
1681                         Datum *parameter,
1682                         FuncIndexInfo *funcInfo,
1683                         PredInfo *predInfo)
1684 {
1685         RegProcedure procedure;
1686
1687         /* ----------------
1688          *      sanity checks
1689          * ----------------
1690          */
1691         Assert(RelationIsValid(indexRelation));
1692         Assert(PointerIsValid(indexRelation->rd_am));
1693
1694         procedure = indexRelation->rd_am->ambuild;
1695
1696         /* ----------------
1697          *      use the access method build procedure if supplied..
1698          * ----------------
1699          */
1700         if (RegProcedureIsValid(procedure))
1701                 fmgr(procedure,
1702                          heapRelation,
1703                          indexRelation,
1704                          numberOfAttributes,
1705                          attributeNumber,
1706                          RelationGetIndexStrategy(indexRelation),
1707                          parameterCount,
1708                          parameter,
1709                          funcInfo,
1710                          predInfo);
1711         else
1712                 DefaultBuild(heapRelation,
1713                                          indexRelation,
1714                                          numberOfAttributes,
1715                                          attributeNumber,
1716                                          RelationGetIndexStrategy(indexRelation),
1717                                          parameterCount,
1718                                          parameter,
1719                                          funcInfo,
1720                                          predInfo);
1721 }
1722
1723 /*
1724  * IndexIsUnique: given an index's relation OID, see if it
1725  * is unique using the system cache.
1726  */
1727 bool
1728 IndexIsUnique(Oid indexId)
1729 {
1730         HeapTuple       tuple;
1731         IndexTupleForm index;
1732
1733         tuple = SearchSysCacheTuple(INDEXRELID,
1734                                                                 ObjectIdGetDatum(indexId),
1735                                                                 0, 0, 0);
1736         if (!HeapTupleIsValid(tuple))
1737         {
1738                 elog(ERROR, "IndexIsUnique: can't find index id %d",
1739                          indexId);
1740         }
1741         index = (IndexTupleForm) GETSTRUCT(tuple);
1742         Assert(index->indexrelid == indexId);
1743
1744         return index->indisunique;
1745 }
1746
1747 /*
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
1757  * if it's slow.
1758  */
1759 bool
1760 IndexIsUniqueNoCache(Oid indexId)
1761 {
1762         Relation        pg_index;
1763         ScanKeyData skey[1];
1764         HeapScanDesc scandesc;
1765         HeapTuple       tuple;
1766         IndexTupleForm index;
1767         bool            isunique;
1768
1769         pg_index = heap_openr(IndexRelationName);
1770
1771         ScanKeyEntryInitialize(&skey[0], (bits16) 0x0,
1772                                                    Anum_pg_index_indexrelid,
1773                                                    (RegProcedure) F_OIDEQ,
1774                                                    ObjectIdGetDatum(indexId));
1775
1776         scandesc = heap_beginscan(pg_index, 0, SnapshotSelf, 1, skey);
1777
1778         /* NO CACHE */
1779         tuple = heap_getnext(scandesc, 0);
1780         if (!HeapTupleIsValid(tuple))
1781                 elog(ERROR, "IndexIsUniqueNoCache: can't find index id %d", indexId);
1782
1783         index = (IndexTupleForm) GETSTRUCT(tuple);
1784         Assert(index->indexrelid == indexId);
1785         isunique = index->indisunique;
1786
1787         heap_endscan(scandesc);
1788         heap_close(pg_index);
1789         return isunique;
1790 }