]> granicus.if.org Git - postgresql/blob - src/backend/catalog/index.c
Makes it compile...still needs work
[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.6 1996/11/05 11:57:52 scrappy 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 <catalog/pg_proc.h>
29 #include <storage/bufmgr.h>
30 #include <fmgr.h>
31
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"
37
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"
44
45 #include "bootstrap/bootstrap.h"
46
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"
53
54 #include "catalog/heap.h"
55
56 #include "nodes/plannodes.h"
57
58 #include "catalog/index.h"
59
60 #include "executor/executor.h"
61 #include "executor/tuptable.h"
62
63 #include "optimizer/clauses.h"
64 #include "optimizer/prep.h"
65
66 #include "access/istrat.h"
67 #ifndef HAVE_MEMMOVE
68 # include <regex/utils.h>
69 #else
70 # include <string.h>
71 #endif
72
73 /*
74  * macros used in guessing how many tuples are on a page.
75  */
76 #define AVG_TUPLE_SIZE 8
77 #define NTUPLES_PER_PAGE(natts) (BLCKSZ/((natts)*AVG_TUPLE_SIZE))
78
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[]);
87
88 static void ConstructIndexReldesc(Relation indexRelation, Oid amoid);
89 static Oid UpdateRelationRelation(Relation indexRelation);
90 static void InitializeAttributeOids(Relation indexRelation,
91                                     int numatts,
92                                     Oid indexoid);
93 static void
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);
103
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
108  *
109  * typedef struct FormData_pg_attribute {
110  *      Oid     attrelid;
111  *      NameData        attname;
112  *      Oid     atttypid;
113  *      Oid     attdefrel;
114  *      uint32          attnvals;
115  *      Oid     atttyparg;      type arg for arrays/spquel/procs
116  *      int16           attlen;
117  *      AttrNumber      attnum;
118  *      uint16          attbound;
119  *      bool            attbyval;
120  *      bool            attcanindex;
121  *      Oid             attproc;        spquel?
122  * } FormData_pg_attribute;
123  *
124  *    The data in this table was taken from local1_template.ami
125  *    but tmin and tmax were switched because local1 was incorrect.
126  * ----------------------------------------------------------------
127  */
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' },
140 };
141
142 /* ----------------------------------------------------------------
143  * RelationNameGetObjectId --
144  *      Returns the object identifier for a relation given its name.
145  *
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
151  *
152  * Note:
153  *      Assumes relation name is valid.
154  *      Assumes relation descriptor is valid.
155  * ----------------------------------------------------------------
156  */
157 static Oid
158 RelationNameGetObjectId(char *relationName,
159                         Relation pg_class,
160                         bool setHasIndexAttribute)
161 {       
162     HeapScanDesc        pg_class_scan;
163     HeapTuple           pg_class_tuple;
164     Oid                 relationObjectId;
165     Buffer              buffer;
166     ScanKeyData         key;
167     
168     /*
169      *  If this isn't bootstrap time, we can use the system catalogs to
170      *  speed this up.
171      */
172     
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);
178         } else
179             relationObjectId = InvalidOid;
180         
181         return (relationObjectId);
182     }
183     
184     /* ----------------
185      *  Bootstrap time, do this the hard way.
186      *  begin a scan of pg_class for the named relation
187      * ----------------
188      */
189     ScanKeyEntryInitialize(&key, 0, Anum_pg_class_relname,
190                            NameEqualRegProcedure,
191                            PointerGetDatum(relationName));
192     
193     pg_class_scan = heap_beginscan(pg_class, 0, NowTimeQual, 1, &key);
194     
195     /* ----------------
196      *  if we find the named relation, fetch its relation id
197      *  (the oid of the tuple we found). 
198      * ----------------
199      */
200     pg_class_tuple = heap_getnext(pg_class_scan, 0, &buffer);
201     
202     if (! HeapTupleIsValid(pg_class_tuple)) {
203         relationObjectId = InvalidOid;
204     } else {
205         relationObjectId = pg_class_tuple->t_oid;
206         ReleaseBuffer(buffer);
207     }
208     
209     /* ----------------
210      *  cleanup and return results
211      * ----------------
212      */
213     heap_endscan(pg_class_scan);
214     
215     return
216         relationObjectId;
217 }
218
219
220 /* ----------------------------------------------------------------
221  *      GetHeapRelationOid
222  * ----------------------------------------------------------------
223  */
224 static Oid
225 GetHeapRelationOid(char *heapRelationName, char *indexRelationName)
226 {
227     Relation    pg_class;
228     Oid         indoid;
229     Oid         heapoid;
230     
231     /* ----------------
232      *  XXX ADD INDEXING HERE
233      * ----------------
234      */
235     /* ----------------
236      *  open pg_class and get the oid of the relation
237      *  corresponding to the name of the index relation.
238      * ----------------
239      */
240     pg_class = heap_openr(RelationRelationName);
241     
242     indoid = RelationNameGetObjectId(indexRelationName,
243                                      pg_class,
244                                      false);
245     
246     if (OidIsValid(indoid))
247         elog(WARN, "Cannot create index: '%s' already exists",
248              indexRelationName);
249     
250     /* ----------------
251      *  get the object id of the heap relation
252      * ----------------
253      */
254     heapoid = RelationNameGetObjectId(heapRelationName,
255                                       pg_class,
256                                       true);
257     
258     /* ----------------
259      *    check that the heap relation exists..
260      * ----------------
261      */
262     if (! OidIsValid(heapoid))
263         elog(WARN, "Cannot create index on '%s': relation does not exist",
264              heapRelationName);
265     
266     /* ----------------
267      *    close pg_class and return the heap relation oid
268      * ----------------
269      */
270     heap_close(pg_class);
271     
272     return heapoid;
273 }
274
275 static TupleDesc
276 BuildFuncTupleDesc(FuncIndexInfo *funcInfo)
277 {
278     HeapTuple           tuple;
279     TupleDesc   funcTupDesc;
280     Oid                 retType;
281     char                *funcname;
282     int4                nargs;
283     Oid         *argtypes;
284     
285     /*
286      * Allocate and zero a tuple descriptor.
287      */
288     funcTupDesc = CreateTemplateTupleDesc(1);
289     funcTupDesc->attrs[0] = (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
290     memset(funcTupDesc->attrs[0], 0, ATTRIBUTE_TUPLE_SIZE);
291     
292     /*
293      * Lookup the function for the return type.
294      */
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),
302                                 0);
303     
304     if (!HeapTupleIsValid(tuple))
305         func_error("BuildFuncTupleDesc", funcname, nargs, (int*)argtypes);
306     
307     retType = ((Form_pg_proc)GETSTRUCT(tuple))->prorettype;
308     
309     /*
310      * Look up the return type in pg_type for the type length.
311      */
312     tuple = SearchSysCacheTuple(TYPOID,
313                                 ObjectIdGetDatum(retType),
314                                 0,0,0);
315     if (!HeapTupleIsValid(tuple))
316         elog(WARN,"Function %s return type does not exist",FIgetname(funcInfo));
317     
318     /*
319      * Assign some of the attributes values. Leave the rest as 0.
320      */
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;
326     
327     /*
328      * make the attributes name the same as the functions
329      */
330     namestrcpy(&funcTupDesc->attrs[0]->attname, funcname);
331     
332     return (funcTupDesc);
333 }
334
335 /* ----------------------------------------------------------------
336  *      ConstructTupleDescriptor
337  * ----------------------------------------------------------------
338  */
339 static TupleDesc
340 ConstructTupleDescriptor(Oid heapoid,
341                          Relation heapRelation,
342                          TypeName *IndexKeyType,
343                          int numatts,
344                          AttrNumber attNums[])
345 {
346     TupleDesc   heapTupDesc;
347     TupleDesc   indexTupDesc;
348     AttrNumber  atnum;          /* attributeNumber[attributeOffset] */
349     AttrNumber  atind;
350     int         natts;          /* RelationTupleForm->relnatts */
351     char        *from;          /* used to simplify memcpy below */
352     char        *to;            /* used to simplify memcpy below */
353     int         i;
354     
355     /* ----------------
356      *  allocate the new tuple descriptor
357      * ----------------
358      */
359     natts = RelationGetRelationTupleForm(heapRelation)->relnatts;
360     
361     indexTupDesc = CreateTemplateTupleDesc(numatts);
362     
363     /* ----------------
364      *  
365      * ----------------
366      */
367     
368     /* ----------------
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
372      * ----------------
373      */
374     for (i = 0; i < numatts; i += 1) {
375         
376         /* ----------------
377          *   get the attribute number and make sure it's valid
378          * ----------------
379          */
380         atnum = attNums[i];
381         if (atnum > natts)
382             elog(WARN, "Cannot create index: attribute %d does not exist",
383                  atnum);
384         
385         indexTupDesc->attrs[i] = (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
386         
387         /* ----------------
388          *   determine which tuple descriptor to copy
389          * ----------------
390          */
391         if (!AttrNumberIsForUserDefinedAttr(atnum)) {
392             
393             /* ----------------
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.
398              * ----------------
399              */
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;
403             
404             from = (char *) (& sysatts[atind]);
405             
406         } else {
407             /* ----------------
408              *    here we are indexing on a normal attribute (1...n)
409              * ----------------
410              */
411             
412             heapTupDesc = RelationGetTupleDescriptor(heapRelation);
413             atind =       AttrNumberGetAttrOffset(atnum);
414             
415             from = (char *) (heapTupDesc->attrs[ atind ]);
416         }
417         
418         /* ----------------
419          *   now that we've determined the "from", let's copy
420          *   the tuple desc data...
421          * ----------------
422          */
423         
424         to =   (char *) (indexTupDesc->attrs[ i ]);
425         memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);
426
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) {
430             HeapTuple tup;
431
432             tup = SearchSysCacheTuple(TYPNAME,
433                                       PointerGetDatum(IndexKeyType->name),
434                                       0,0,0);
435             if(!HeapTupleIsValid(tup))
436                 elog(WARN, "create index: type '%s' undefined",
437                      IndexKeyType->name);
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;
445         }
446            
447
448         /* ----------------
449          *    now we have to drop in the proper relation descriptor
450          *    into the copied tuple form's attrelid and we should be
451          *    all set.
452          * ----------------
453          */
454         ((AttributeTupleForm) to)->attrelid = heapoid;
455     }
456     
457     return indexTupDesc;
458 }
459
460 /* ----------------------------------------------------------------
461  * AccessMethodObjectIdGetAccessMethodTupleForm --
462  *      Returns the formated access method tuple given its object identifier.
463  *
464  * XXX ADD INDEXING
465  *
466  * Note:
467  *      Assumes object identifier is valid.
468  * ----------------------------------------------------------------
469  */
470 Form_pg_am
471 AccessMethodObjectIdGetAccessMethodTupleForm(Oid accessMethodObjectId)
472 {
473     Relation            pg_am_desc;
474     HeapScanDesc        pg_am_scan;
475     HeapTuple           pg_am_tuple;
476     ScanKeyData         key;
477     Form_pg_am          form;
478     
479     /* ----------------
480      *  form a scan key for the pg_am relation
481      * ----------------
482      */
483     ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
484                            ObjectIdEqualRegProcedure,
485                            ObjectIdGetDatum(accessMethodObjectId));
486     
487     /* ----------------
488      *  fetch the desired access method tuple
489      * ----------------
490      */
491     pg_am_desc = heap_openr(AccessMethodRelationName);
492     pg_am_scan = heap_beginscan(pg_am_desc, 0, NowTimeQual, 1, &key);
493     
494     pg_am_tuple = heap_getnext(pg_am_scan, 0, (Buffer *)NULL);
495     
496     /* ----------------
497      *  return NULL if not found
498      * ----------------
499      */
500     if (! HeapTupleIsValid(pg_am_tuple)) {
501         heap_endscan(pg_am_scan);
502         heap_close(pg_am_desc);
503         return (NULL);
504     }
505     
506     /* ----------------
507      *  if found am tuple, then copy the form and return the copy
508      * ----------------
509      */
510     form = (Form_pg_am)palloc(sizeof *form);
511     memcpy(form, GETSTRUCT(pg_am_tuple), sizeof *form);
512     
513     heap_endscan(pg_am_scan);
514     heap_close(pg_am_desc);
515     
516     return (form);
517 }
518
519 /* ----------------------------------------------------------------
520  *      ConstructIndexReldesc
521  * ----------------------------------------------------------------
522  */
523 static void
524 ConstructIndexReldesc(Relation indexRelation, Oid amoid)
525 {
526     extern GlobalMemory  CacheCxt;
527     MemoryContext        oldcxt;
528     
529     /* ----------------
530      *    here we make certain to allocate the access method
531      *    tuple within the cache context lest it vanish when the
532      *    context changes
533      * ----------------
534      */
535     if (!CacheCxt)
536         CacheCxt = CreateGlobalMemory("Cache");
537     
538     oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
539     
540     indexRelation->rd_am =
541         AccessMethodObjectIdGetAccessMethodTupleForm(amoid);
542     
543     MemoryContextSwitchTo(oldcxt);
544     
545     /* ----------------
546      *   XXX missing the initialization of some other fields 
547      * ----------------
548      */
549     
550     indexRelation->rd_rel->relowner =   GetUserId();
551     
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 */
558 }
559
560 /* ----------------------------------------------------------------
561  *      UpdateRelationRelation
562  * ----------------------------------------------------------------
563  */
564 static Oid
565 UpdateRelationRelation(Relation indexRelation)
566 {
567     Relation    pg_class;
568     HeapTuple   tuple;
569     Oid tupleOid;
570     Relation    idescs[Num_pg_class_indices];
571     
572     pg_class = heap_openr(RelationRelationName);
573     
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);
578     
579     /* ----------------
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
582      *  company.
583      * ----------------
584      */
585     tuple->t_oid = indexRelation->rd_id;
586     heap_insert(pg_class, tuple);
587     
588     /*
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.
593      */
594     
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);
599     }
600     
601     tupleOid = tuple->t_oid;
602     pfree(tuple);
603     heap_close(pg_class);
604     
605     return(tupleOid);
606 }
607
608 /* ----------------------------------------------------------------
609  *      InitializeAttributeOids
610  * ----------------------------------------------------------------
611  */
612 static void
613 InitializeAttributeOids(Relation indexRelation,
614                         int numatts,
615                         Oid indexoid)
616 {
617     TupleDesc   tupleDescriptor;
618     int                 i;
619     
620     tupleDescriptor = RelationGetTupleDescriptor(indexRelation);
621     
622     for (i = 0; i < numatts; i += 1)
623         tupleDescriptor->attrs[i]->attrelid = indexoid;
624 }
625
626 /* ----------------------------------------------------------------
627  *      AppendAttributeTuples
628  *
629  *      XXX For now, only change the ATTNUM attribute value
630  * ----------------------------------------------------------------
631  */
632 static void
633 AppendAttributeTuples(Relation indexRelation, int numatts)
634 {
635     Relation    pg_attribute;
636     HeapTuple   tuple;
637     HeapTuple   newtuple;
638     bool        hasind;
639     Relation    idescs[Num_pg_attr_indices];
640     
641     Datum       value[ Natts_pg_attribute ];
642     char        nullv[ Natts_pg_attribute ];
643     char        replace[ Natts_pg_attribute ];
644     
645     TupleDesc   indexTupDesc;
646     int         i;
647     
648     /* ----------------
649      *  open the attribute relation
650      *  XXX ADD INDEXING
651      * ----------------
652      */
653     pg_attribute = heap_openr(AttributeRelationName);
654     
655     /* ----------------
656      *  initialize null[], replace[] and value[]
657      * ----------------
658      */
659     (void) memset(nullv, ' ', Natts_pg_attribute);
660     (void) memset(replace, ' ', Natts_pg_attribute);
661     
662     /* ----------------
663      *  create the first attribute tuple.
664      *  XXX For now, only change the ATTNUM attribute value
665      * ----------------
666      */
667     replace[ Anum_pg_attribute_attnum - 1 ] = 'r';
668     
669     value[ Anum_pg_attribute_attnum - 1 ] = Int16GetDatum(1);
670     
671     tuple = heap_addheader(Natts_pg_attribute,
672                            sizeof *(indexRelation->rd_att->attrs[0]),
673                            (char *)(indexRelation->rd_att->attrs[0]));
674     
675     hasind = false;
676     if (!IsBootstrapProcessingMode() && pg_attribute->rd_rel->relhasindex) {
677         hasind = true;
678         CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
679     }
680     
681     /* ----------------
682      *  insert the first attribute tuple.
683      * ----------------
684      */
685     tuple = heap_modifytuple(tuple,
686                              InvalidBuffer,
687                              pg_attribute,
688                              value,
689                              nullv,
690                              replace);
691     
692     heap_insert(pg_attribute, tuple);
693     if (hasind)
694         CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, tuple);
695     
696     /* ----------------
697      *  now we use the information in the index tuple
698      *  descriptor to form the remaining attribute tuples.
699      * ----------------
700      */
701     indexTupDesc = RelationGetTupleDescriptor(indexRelation);
702     
703     for (i = 1; i < numatts; i += 1) {
704         /* ----------------
705          *  process the remaining attributes...
706          * ----------------
707          */
708         memmove(GETSTRUCT(tuple),
709                (char *)indexTupDesc->attrs[i],
710                sizeof (AttributeTupleForm));
711         
712         value[ Anum_pg_attribute_attnum - 1 ] = Int16GetDatum(i + 1);
713         
714         newtuple = heap_modifytuple(tuple,
715                                     InvalidBuffer,
716                                     pg_attribute,
717                                     value,
718                                     nullv,
719                                     replace);
720         
721         heap_insert(pg_attribute, newtuple);
722         if (hasind)
723             CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, newtuple);
724         
725         /* ----------------
726          *  ModifyHeapTuple returns a new copy of a tuple
727          *  so we free the original and use the copy..
728          * ----------------
729          */
730         pfree(tuple);
731         tuple = newtuple;
732     }
733     
734     /* ----------------
735      *  close the attribute relation and free the tuple
736      * ----------------
737      */
738     heap_close(pg_attribute);
739     
740     if (hasind)
741         CatalogCloseIndices(Num_pg_attr_indices, idescs);
742     
743     pfree(tuple);
744 }
745
746 /* ----------------------------------------------------------------
747  *      UpdateIndexRelation
748  * ----------------------------------------------------------------
749  */
750 static void
751 UpdateIndexRelation(Oid indexoid,
752                     Oid heapoid,
753                     FuncIndexInfo *funcInfo,
754                     int natts,
755                     AttrNumber attNums[],
756                     Oid classOids[],
757                     Node *predicate,
758                     TypeName *indexKeyType,
759                     bool islossy)
760 {
761     IndexTupleForm      indexForm;
762     char                *predString;
763     text                *predText;
764     int                 predLen, itupLen;
765     Relation            pg_index;
766     HeapTuple           tuple;
767     int                 i;
768     
769     /* ----------------
770      *  allocate an IndexTupleForm big enough to hold the
771      *  index-predicate (if any) in string form
772      * ----------------
773      */
774     if (predicate != NULL) {
775         predString = nodeToString(predicate);
776         predText = (text *)fmgr(F_TEXTIN, predString);
777         pfree(predString);
778     } else {
779         predText = (text *)fmgr(F_TEXTIN, "");
780     }
781     predLen = VARSIZE(predText);
782     itupLen = predLen + sizeof(FormData_pg_index);
783     indexForm = (IndexTupleForm) palloc(itupLen);
784     
785     memmove((char *)& indexForm->indpred, (char *)predText, predLen);
786     
787     /* ----------------
788      *  store the oid information into the index tuple form
789      * ----------------
790      */
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;
798     else
799         indexForm->indhaskeytype = 0;
800     
801     memset((char *)& indexForm->indkey[0], 0, sizeof indexForm->indkey);
802     memset((char *)& indexForm->indclass[0], 0, sizeof indexForm->indclass);
803     
804     /* ----------------
805      *  copy index key and op class information
806      * ----------------
807      */
808     for (i = 0; i < natts; i += 1) {
809         indexForm->indkey[i] =   attNums[i];
810         indexForm->indclass[i] = classOids[i];
811     }
812     /*
813      * If we have a functional index, add all attribute arguments
814      */
815     if (PointerIsValid(funcInfo))
816         {
817             for (i=1; i < FIgetnArgs(funcInfo); i++)
818                 indexForm->indkey[i] =   attNums[i];
819         }
820     
821     indexForm->indisclustered = '\0';           /* XXX constant */
822     indexForm->indisarchived = '\0';            /* XXX constant */
823     
824     /* ----------------
825      *  open the system catalog index relation
826      * ----------------
827      */
828     pg_index = heap_openr(IndexRelationName);
829     
830     /* ----------------
831      *  form a tuple to insert into pg_index
832      * ----------------
833      */
834     tuple = heap_addheader(Natts_pg_index,
835                            itupLen,
836                            (char *)indexForm);
837     
838     /* ----------------
839      *  insert the tuple into the pg_index
840      *  XXX ADD INDEX TUPLES TOO
841      * ----------------
842      */
843     heap_insert(pg_index, tuple);
844     
845     /* ----------------
846      *  close the relation and free the tuple
847      * ----------------
848      */
849     heap_close(pg_index);
850     pfree(predText);
851     pfree(indexForm);
852     pfree(tuple);
853 }
854
855 /* ----------------------------------------------------------------
856  *      UpdateIndexPredicate
857  * ----------------------------------------------------------------
858  */
859 void
860 UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
861 {
862     Node                *newPred;
863     char                *predString;
864     text                *predText;
865     Relation            pg_index;
866     HeapTuple           tuple;
867     HeapTuple           newtup;
868     ScanKeyData         entry;
869     HeapScanDesc        scan;
870     Buffer              buffer;
871     int                 i;
872     Datum               values[Natts_pg_index];
873     char                nulls[Natts_pg_index];
874     char                replace[Natts_pg_index];
875     
876     /*
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").
880      *
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
886      */
887     newPred = NULL;
888     if (predicate != NULL) {
889         newPred =
890             (Node*)make_orclause(lcons(make_andclause((List*)predicate),
891                                       lcons(make_andclause((List*)oldPred),
892                                            NIL)));
893         newPred = (Node*)cnfify((Expr*)newPred, true);
894     }
895     
896     /* translate the index-predicate to string form */
897     if (newPred != NULL) {
898         predString = nodeToString(newPred);
899         predText = (text *)fmgr(F_TEXTIN, predString);
900         pfree(predString);
901     } else {
902         predText = (text *)fmgr(F_TEXTIN, "");
903     }
904     
905     /* open the index system catalog relation */
906     pg_index = heap_openr(IndexRelationName);
907     
908     ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_index_indexrelid, 
909                            ObjectIdEqualRegProcedure, 
910                            ObjectIdGetDatum(indexoid));
911     
912     scan = heap_beginscan(pg_index, 0, NowTimeQual, 1, &entry);
913     tuple = heap_getnext(scan, 0, &buffer);
914     heap_endscan(scan);
915     
916     for (i = 0; i < Natts_pg_index; i++) {
917         nulls[i] = heap_attisnull(tuple, i+1) ? 'n' : ' ';
918         replace[i] = ' ';
919         values[i] = (Datum) NULL;
920     }
921     
922     replace[Anum_pg_index_indpred - 1] = 'r';
923     values[Anum_pg_index_indpred - 1] = (Datum) predText;
924     
925     newtup = heap_modifytuple(tuple, buffer, pg_index, values, nulls, replace);
926     
927     (void) heap_replace(pg_index, &(newtup->t_ctid), newtup);
928     
929     heap_close(pg_index);
930     pfree(predText);
931 }
932
933 /* ----------------------------------------------------------------
934  *      InitIndexStrategy
935  * ----------------------------------------------------------------
936  */
937 void
938 InitIndexStrategy(int numatts,
939                   Relation indexRelation,
940                   Oid accessMethodObjectId)
941 {
942     IndexStrategy       strategy;
943     RegProcedure        *support;
944     uint16              amstrategies;
945     uint16              amsupport;
946     Oid         attrelid;
947     Size                strsize;
948     extern GlobalMemory CacheCxt;
949     
950     /* ----------------
951      *  get information from the index relation descriptor
952      * ----------------
953      */
954     attrelid =     indexRelation->rd_att->attrs[0]->attrelid;
955     amstrategies = indexRelation->rd_am->amstrategies;
956     amsupport =    indexRelation->rd_am->amsupport;
957     
958     /* ----------------
959      *  get the size of the strategy
960      * ----------------
961      */
962     strsize =  AttributeNumberGetIndexStrategySize(numatts, amstrategies);
963     
964     /* ----------------
965      *  allocate the new index strategy structure
966      *
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.
970      * ----------------
971      */
972     if (!CacheCxt)
973         CacheCxt = CreateGlobalMemory("Cache");
974     
975     strategy = (IndexStrategy)
976         MemoryContextAlloc((MemoryContext)CacheCxt, strsize);
977     
978     if (amsupport > 0) {
979         strsize = numatts * (amsupport * sizeof(RegProcedure));
980         support = (RegProcedure *) MemoryContextAlloc((MemoryContext)CacheCxt,
981                                                       strsize);
982     } else {
983         support = (RegProcedure *) NULL;
984     }
985     
986     /* ----------------
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.
991      * ----------------
992      */
993     setheapoverride(1);
994     
995     IndexSupportInitialize(strategy, support,
996                            attrelid, accessMethodObjectId,
997                            amstrategies, amsupport, numatts);
998     
999     setheapoverride(0);
1000     
1001     /* ----------------
1002      *  store the strategy information in the index reldesc
1003      * ----------------
1004      */
1005     RelationSetIndexSupport(indexRelation, strategy, support);
1006 }
1007
1008
1009 /* ----------------------------------------------------------------
1010  *      index_create
1011  * ----------------------------------------------------------------
1012  */
1013 void
1014 index_create(char *heapRelationName,
1015              char *indexRelationName,
1016              FuncIndexInfo *funcInfo,
1017              TypeName *IndexKeyType,
1018              Oid accessMethodObjectId,
1019              int numatts,
1020              AttrNumber attNums[],
1021              Oid classObjectId[],
1022              uint16 parameterCount,
1023              Datum *parameter,
1024              Node *predicate,
1025              bool islossy)
1026 {
1027     Relation            heapRelation;
1028     Relation            indexRelation;
1029     TupleDesc           indexTupDesc;
1030     Oid                 heapoid;
1031     Oid                 indexoid;
1032     PredInfo            *predInfo;
1033     
1034     /* ----------------
1035      *  check parameters
1036      * ----------------
1037      */
1038     if (numatts < 1)
1039         elog(WARN, "must index at least one attribute");
1040     
1041     /* ----------------
1042      *    get heap relation oid and open the heap relation
1043      *    XXX ADD INDEXING
1044      * ----------------
1045      */
1046     heapoid = GetHeapRelationOid(heapRelationName, indexRelationName);
1047     
1048     heapRelation = heap_open(heapoid);
1049     
1050     /* ----------------
1051      * write lock heap to guarantee exclusive access
1052      * ---------------- 
1053      */
1054     
1055     RelationSetLockForWrite(heapRelation);
1056     
1057     /* ----------------
1058      *    construct new tuple descriptor
1059      * ----------------
1060      */
1061     if (PointerIsValid(funcInfo))
1062         indexTupDesc = BuildFuncTupleDesc(funcInfo);
1063     else
1064         indexTupDesc = ConstructTupleDescriptor(heapoid,
1065                                                 heapRelation,
1066                                                 IndexKeyType,
1067                                                 numatts,
1068                                                 attNums);
1069     
1070     /* ----------------
1071      *  create the index relation
1072      * ----------------
1073      */
1074     indexRelation = heap_creatr(indexRelationName,
1075                                 DEFAULT_SMGR,
1076                                 indexTupDesc);
1077     
1078     /* ----------------
1079      *    construct the index relation descriptor
1080      *
1081      *    XXX should have a proper way to create cataloged relations
1082      * ----------------
1083      */
1084     ConstructIndexReldesc(indexRelation, accessMethodObjectId);
1085     
1086     /* ----------------
1087      *    add index to catalogs
1088      *    (append RELATION tuple)
1089      * ----------------
1090      */
1091     indexoid = UpdateRelationRelation(indexRelation);
1092     
1093     /* ----------------
1094      * Now get the index procedure (only relevant for functional indices).
1095      * ----------------
1096      */
1097     
1098     if (PointerIsValid(funcInfo))
1099         {
1100             HeapTuple proc_tup;
1101             
1102             proc_tup = SearchSysCacheTuple(PRONAME,
1103                                    PointerGetDatum(FIgetname(funcInfo)),
1104                                    Int32GetDatum(FIgetnArgs(funcInfo)),
1105                                    PointerGetDatum(FIgetArglist(funcInfo)),
1106                                    0);
1107             
1108             if (!HeapTupleIsValid(proc_tup)) {
1109                 func_error("index_create", FIgetname(funcInfo),
1110                            FIgetnArgs(funcInfo), 
1111                            (int*) FIgetArglist(funcInfo));
1112             }
1113             FIgetProcOid(funcInfo) = proc_tup->t_oid;
1114         }
1115     
1116     /* ----------------
1117      *  now update the object id's of all the attribute
1118      *  tuple forms in the index relation's tuple descriptor
1119      * ----------------
1120      */
1121     InitializeAttributeOids(indexRelation, numatts, indexoid);
1122     
1123     /* ----------------
1124      *    append ATTRIBUTE tuples
1125      * ----------------
1126      */
1127     AppendAttributeTuples(indexRelation, numatts);
1128     
1129     /* ----------------
1130      *    update pg_index
1131      *    (append INDEX tuple)
1132      *
1133      *    Note that this stows away a representation of "predicate".
1134      *    (Or, could define a rule to maintain the predicate) --Nels, Feb '92
1135      * ----------------
1136      */
1137     UpdateIndexRelation(indexoid, heapoid, funcInfo,
1138                         numatts, attNums, classObjectId, predicate,
1139                         IndexKeyType, islossy);
1140     
1141     predInfo = (PredInfo*)palloc(sizeof(PredInfo));
1142     predInfo->pred = predicate;
1143     predInfo->oldPred = NULL;
1144     
1145     /* ----------------
1146      *    initialize the index strategy
1147      * ----------------
1148      */
1149     InitIndexStrategy(numatts, indexRelation, accessMethodObjectId);
1150     
1151     /*
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().
1157      */
1158     if (IsBootstrapProcessingMode()) {
1159         index_register(heapRelationName, indexRelationName, numatts, attNums,
1160                        parameterCount, parameter, funcInfo, predInfo);
1161     } else {
1162         heapRelation = heap_openr(heapRelationName);
1163         index_build(heapRelation, indexRelation, numatts, attNums,
1164                     parameterCount, parameter, funcInfo, predInfo);
1165     }
1166 }
1167
1168 /* ----------------------------------------------------------------
1169  *      index_destroy
1170  *
1171  *      XXX break into modules like index_create
1172  * ----------------------------------------------------------------
1173  */
1174 void
1175 index_destroy(Oid indexId)
1176 {
1177     Relation            indexRelation;
1178     Relation            catalogRelation;
1179     HeapTuple           tuple;
1180     HeapScanDesc        scan;
1181     ScanKeyData         entry;
1182     
1183     Assert(OidIsValid(indexId));
1184     
1185     indexRelation = index_open(indexId);
1186     
1187     /* ----------------
1188      * fix RELATION relation
1189      * ----------------
1190      */
1191     catalogRelation = heap_openr(RelationRelationName);
1192     
1193     ScanKeyEntryInitialize(&entry, 0x0, ObjectIdAttributeNumber, 
1194                            ObjectIdEqualRegProcedure, 
1195                            ObjectIdGetDatum(indexId));;
1196     
1197     scan = heap_beginscan(catalogRelation, 0, NowTimeQual, 1, &entry);
1198     tuple = heap_getnext(scan, 0, (Buffer *)NULL);
1199     
1200     AssertState(HeapTupleIsValid(tuple));
1201     
1202     heap_delete(catalogRelation, &tuple->t_ctid);
1203     heap_endscan(scan);
1204     heap_close(catalogRelation);
1205     
1206     /* ----------------
1207      * fix ATTRIBUTE relation
1208      * ----------------
1209      */
1210     catalogRelation = heap_openr(AttributeRelationName);
1211     
1212     entry.sk_attno = Anum_pg_attribute_attrelid;
1213     
1214     scan = heap_beginscan(catalogRelation, 0, NowTimeQual, 1, &entry);
1215     
1216     while (tuple = heap_getnext(scan, 0, (Buffer *)NULL),
1217            HeapTupleIsValid(tuple)) {
1218         
1219         heap_delete(catalogRelation, &tuple->t_ctid);
1220     }
1221     heap_endscan(scan);
1222     heap_close(catalogRelation);
1223     
1224     /* ----------------
1225      * fix INDEX relation
1226      * ----------------
1227      */
1228     catalogRelation = heap_openr(IndexRelationName);
1229     
1230     entry.sk_attno = Anum_pg_index_indexrelid;
1231     
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));
1237     }
1238     heap_delete(catalogRelation, &tuple->t_ctid);
1239     heap_endscan(scan);
1240     heap_close(catalogRelation);
1241     
1242     /*
1243      * physically remove the file
1244      */
1245     if (FileNameUnlink(relpath(indexRelation->rd_rel->relname.data)) < 0)
1246         elog(WARN, "amdestroyr: unlink: %m");
1247     
1248     index_close(indexRelation);
1249 }
1250
1251 /* ----------------------------------------------------------------
1252  *                      index_build support
1253  * ----------------------------------------------------------------
1254  */
1255 /* ----------------
1256  *      FormIndexDatum
1257  * ----------------
1258  */
1259 void
1260 FormIndexDatum(int numberOfAttributes,
1261                AttrNumber attributeNumber[],
1262                HeapTuple heapTuple,
1263                TupleDesc heapDescriptor,
1264                Buffer buffer,
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 += 1) {
1281         offset = AttrNumberGetAttrOffset(i);
1282         
1283         datum[ offset ] =
1284             PointerGetDatum( GetIndexValue(heapTuple,
1285                                            heapDescriptor,
1286                                            offset,
1287                                            attributeNumber,
1288                                            fInfo,
1289                                            &isNull,
1290                                            buffer) );
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     HeapScanDesc pg_class_scan;
1307     HeapTuple   htup;
1308     HeapTuple   newtup;
1309     long        relpages;
1310     Buffer      buffer;
1311     int         i;
1312     Form_pg_class rd_rel;
1313     Relation    idescs[Num_pg_class_indices];
1314     
1315     static ScanKeyData key[1] = {
1316         { 0, ObjectIdAttributeNumber, ObjectIdEqualRegProcedure }
1317     };
1318     Datum       values[Natts_pg_class];
1319     char        nulls[Natts_pg_class];
1320     char        replace[Natts_pg_class];
1321     
1322     fmgr_info(ObjectIdEqualRegProcedure, (func_ptr *) &key[0].sk_func,
1323               &key[0].sk_nargs);
1324     
1325     /* ----------------
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.
1330      * ----------------
1331      */
1332     CommandCounterIncrement();
1333     
1334     /* ----------------
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.
1340      * ----------------
1341      */
1342     
1343     whichRel = RelationIdGetRelation(relid);
1344     
1345     if (!RelationIsValid(whichRel))
1346         elog(WARN, "UpdateStats: cannot open relation id %d", relid);
1347     
1348     /* ----------------
1349      * Find the RELATION relation tuple for the given relation.
1350      * ----------------
1351      */
1352     pg_class = heap_openr(RelationRelationName);
1353     if (! RelationIsValid(pg_class)) {
1354         elog(WARN, "UpdateStats: could not open RELATION relation");
1355     }
1356     key[0].sk_argument = ObjectIdGetDatum(relid);
1357     
1358     pg_class_scan =
1359         heap_beginscan(pg_class, 0, NowTimeQual, 1, key);
1360     
1361     if (! HeapScanIsValid(pg_class_scan)) {
1362         heap_close(pg_class);
1363         elog(WARN, "UpdateStats: cannot scan RELATION relation");
1364     }
1365     
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);
1369     
1370     /* ----------------
1371      *  update statistics
1372      * ----------------
1373      */
1374     relpages = RelationGetNumberOfBlocks(whichRel);
1375     
1376     /*
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
1379      *  latest copy.
1380      */
1381     
1382     whichRel->rd_rel->relhasindex = hasindex;
1383     whichRel->rd_rel->relpages = relpages;
1384     whichRel->rd_rel->reltuples = reltuples;
1385     
1386     for (i = 0; i < Natts_pg_class; i++) {
1387         nulls[i] = heap_attisnull(htup, i+1) ? 'n' : ' ';
1388         replace[i] = ' ';
1389         values[i] = (Datum) NULL;
1390     }
1391     
1392     /*
1393      * If reltuples wasn't supplied take an educated guess.
1394      */
1395     if (reltuples == 0)
1396         reltuples = relpages*NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
1397     
1398     if (IsBootstrapProcessingMode()) {
1399         
1400         /*
1401          *  At bootstrap time, we don't need to worry about concurrency
1402          *  or visibility of changes, so we cheat.
1403          */
1404         
1405         rd_rel = (Form_pg_class) GETSTRUCT(htup);
1406         rd_rel->relpages = relpages;
1407         rd_rel->reltuples = reltuples;
1408         rd_rel->relhasindex = hasindex;
1409     } else {
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);
1417         
1418         newtup = heap_modifytuple(htup, buffer, pg_class, values,
1419                                   nulls, replace);
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);
1424     }
1425     
1426     heap_close(pg_class);
1427     heap_close(whichRel);
1428 }
1429
1430
1431 /* -------------------------
1432  *      FillDummyExprContext
1433  *          Sets up dummy ExprContext and TupleTableSlot objects for use
1434  *          with ExecQual.
1435  * -------------------------
1436  */
1437 void
1438 FillDummyExprContext(ExprContext *econtext,
1439                      TupleTableSlot *slot,
1440                      TupleDesc tupdesc,
1441                      Buffer buffer)
1442 {
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;
1448     
1449     slot->ttc_tupleDescriptor = tupdesc;
1450     slot->ttc_buffer = buffer;
1451     slot->ttc_shouldFree = false;
1452
1453 }
1454
1455
1456 /* ----------------
1457  *      DefaultBuild
1458  * ----------------
1459  */
1460 static void
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,
1469              PredInfo *predInfo)
1470 {
1471     HeapScanDesc        scan;
1472     HeapTuple           heapTuple;
1473     Buffer              buffer;
1474     
1475     IndexTuple          indexTuple;
1476     TupleDesc           heapDescriptor;
1477     TupleDesc           indexDescriptor;
1478     Datum               *datum;
1479     char                *nullv;
1480     long                reltuples, indtuples;
1481 #ifndef OMIT_PARTIAL_INDEX
1482     ExprContext         *econtext;
1483     TupleTable          tupleTable;
1484     TupleTableSlot      *slot;
1485 #endif
1486     Node                *predicate;
1487     Node                *oldPred;
1488     
1489     InsertIndexResult   insertResult;
1490     
1491     /* ----------------
1492      *  more & better checking is needed
1493      * ----------------
1494      */
1495     Assert(OidIsValid(indexRelation->rd_rel->relam));   /* XXX */
1496     
1497     /* ----------------
1498      *  get the tuple descriptors from the relations so we know
1499      *  how to form the index tuples..
1500      * ----------------
1501      */
1502     heapDescriptor =  RelationGetTupleDescriptor(heapRelation);
1503     indexDescriptor = RelationGetTupleDescriptor(indexRelation);
1504     
1505     /* ----------------
1506      *  datum and null are arrays in which we collect the index attributes
1507      *  when forming a new index tuple.
1508      * ----------------
1509      */
1510     datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
1511     nullv =  (char *)  palloc(numberOfAttributes * sizeof *nullv);
1512     
1513     /*
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
1519      */
1520
1521     predicate = predInfo->pred;
1522     oldPred = predInfo->oldPred;
1523
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);
1530     }
1531 #endif /* OMIT_PARTIAL_INDEX */        
1532
1533     /* ----------------
1534      *  Ok, begin our scan of the base relation.
1535      * ----------------
1536      */
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 */
1542     
1543     reltuples = indtuples = 0;
1544     
1545     /* ----------------
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.
1550      * ----------------
1551      */
1552     while (heapTuple = heap_getnext(scan, 0, &buffer),
1553            HeapTupleIsValid(heapTuple)) {
1554         
1555         reltuples++;
1556         
1557         /*
1558          * If oldPred != NULL, this is an EXTEND INDEX command, so skip
1559          * this tuple if it was already in the existing partial index
1560          */
1561         if (oldPred != NULL) {
1562 #ifndef OMIT_PARTIAL_INDEX
1563             /*SetSlotContents(slot, heapTuple); */
1564             slot->val = heapTuple;
1565             if (ExecQual((List*)oldPred, econtext) == true) {
1566                 indtuples++;
1567                 continue;
1568             }
1569 #endif /* OMIT_PARTIAL_INDEX */         
1570         }
1571         
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)
1578                 continue;
1579 #endif /* OMIT_PARTIAL_INDEX */         
1580         }
1581         
1582         indtuples++;
1583         
1584         /* ----------------
1585          *  FormIndexDatum fills in its datum and null parameters
1586          *  with attribute information taken from the given heap tuple.
1587          * ----------------
1588          */
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 */
1596                        funcInfo);
1597         
1598         indexTuple = index_formtuple(indexDescriptor,
1599                                      datum,
1600                                      nullv);
1601         
1602         indexTuple->t_tid = heapTuple->t_ctid;
1603         
1604         insertResult = index_insert(indexRelation, datum, nullv, 
1605                                     &(heapTuple->t_ctid));
1606
1607         if (insertResult) pfree(insertResult);
1608         pfree(indexTuple);
1609     }
1610     
1611     heap_endscan(scan);
1612     
1613     if (predicate != NULL || oldPred != NULL) {
1614 #ifndef OMIT_PARTIAL_INDEX
1615         ExecDestroyTupleTable(tupleTable, false);
1616 #endif /* OMIT_PARTIAL_INDEX */         
1617     }
1618     
1619     pfree(nullv);
1620     pfree(datum);
1621     
1622     /*
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.
1628      */
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);
1634     }
1635 }
1636
1637 /* ----------------
1638  *      index_build
1639  * ----------------
1640  */
1641 void
1642 index_build(Relation heapRelation,
1643             Relation indexRelation,
1644             int numberOfAttributes,
1645             AttrNumber attributeNumber[],
1646             uint16      parameterCount,
1647             Datum       *parameter,
1648             FuncIndexInfo *funcInfo,
1649             PredInfo *predInfo)
1650 {
1651     RegProcedure        procedure;
1652     
1653     /* ----------------
1654      *  sanity checks
1655      * ----------------
1656      */
1657     Assert(RelationIsValid(indexRelation));
1658     Assert(PointerIsValid(indexRelation->rd_am));
1659     
1660     procedure = indexRelation->rd_am->ambuild;
1661     
1662     /* ----------------
1663      *  use the access method build procedure if supplied..
1664      * ----------------
1665      */
1666     if (RegProcedureIsValid(procedure))
1667         (void) fmgr(procedure,
1668                     heapRelation,
1669                     indexRelation,
1670                     numberOfAttributes,
1671                     attributeNumber,
1672                     RelationGetIndexStrategy(indexRelation),
1673                     parameterCount,
1674                     parameter,
1675                     funcInfo,
1676                     predInfo);
1677     else
1678         DefaultBuild(heapRelation,
1679                      indexRelation,
1680                      numberOfAttributes,
1681                      attributeNumber,
1682                      RelationGetIndexStrategy(indexRelation),
1683                      parameterCount,
1684                      parameter,
1685                      funcInfo,
1686                      predInfo);
1687 }
1688
1689