]> granicus.if.org Git - postgresql/blob - src/backend/catalog/index.c
REINDEX under WAL.
[postgresql] / src / backend / catalog / index.c
1 /*-------------------------------------------------------------------------
2  *
3  * index.c
4  *        code to create and destroy POSTGRES index relations
5  *
6  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.131 2000/12/08 06:17:57 inoue Exp $
12  *
13  *
14  * INTERFACE ROUTINES
15  *              index_create()                  - Create a cataloged index relation
16  *              index_drop()                    - Removes index relation from catalogs
17  *              BuildIndexInfo()                - Prepare to insert index tuples
18  *              FormIndexDatum()                - Construct datum vector for one index tuple
19  *
20  *-------------------------------------------------------------------------
21  */
22 #include "postgres.h"
23
24
25 #include "access/genam.h"
26 #include "access/heapam.h"
27 #include "access/istrat.h"
28 #include "bootstrap/bootstrap.h"
29 #include "catalog/catalog.h"
30 #include "catalog/catname.h"
31 #include "catalog/heap.h"
32 #include "catalog/index.h"
33 #include "catalog/indexing.h"
34 #include "catalog/pg_index.h"
35 #include "catalog/pg_proc.h"
36 #include "catalog/pg_type.h"
37 #include "commands/comment.h"
38 #include "executor/executor.h"
39 #include "miscadmin.h"
40 #include "optimizer/clauses.h"
41 #include "optimizer/prep.h"
42 #include "parser/parse_func.h"
43 #include "storage/smgr.h"
44 #include "utils/builtins.h"
45 #include "utils/catcache.h"
46 #include "utils/fmgroids.h"
47 #include "utils/inval.h"
48 #include "utils/relcache.h"
49 #include "utils/syscache.h"
50 #include "utils/temprel.h"
51
52 /*
53  * macros used in guessing how many tuples are on a page.
54  */
55 #define AVG_ATTR_SIZE 8
56 #define NTUPLES_PER_PAGE(natts) \
57         ((BLCKSZ - MAXALIGN(sizeof (PageHeaderData))) / \
58         ((natts) * AVG_ATTR_SIZE + MAXALIGN(sizeof(HeapTupleHeaderData))))
59
60 /* non-export function prototypes */
61 static Oid GetHeapRelationOid(char *heapRelationName, char *indexRelationName,
62                                    bool istemp);
63 static TupleDesc BuildFuncTupleDesc(Oid funcOid);
64 static TupleDesc ConstructTupleDescriptor(Oid heapoid, Relation heapRelation,
65                                                                                   int numatts, AttrNumber *attNums);
66 static void ConstructIndexReldesc(Relation indexRelation, Oid amoid);
67 static Oid      UpdateRelationRelation(Relation indexRelation, char *temp_relname);
68 static void InitializeAttributeOids(Relation indexRelation,
69                                                 int numatts, Oid indexoid);
70 static void AppendAttributeTuples(Relation indexRelation, int numatts);
71 static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
72                                                                 IndexInfo *indexInfo,
73                                                                 Oid *classOids,
74                                                                 bool islossy, bool primary);
75 static void DefaultBuild(Relation heapRelation, Relation indexRelation,
76                                                  IndexInfo *indexInfo, Node *oldPred,
77                                                  IndexStrategy indexStrategy);
78 static Oid      IndexGetRelation(Oid indexId);
79 static bool activate_index(Oid indexId, bool activate, bool inplace);
80
81
82 static bool reindexing = false;
83
84
85 bool
86 SetReindexProcessing(bool reindexmode)
87 {
88         bool            old = reindexing;
89
90         reindexing = reindexmode;
91         return old;
92 }
93
94 bool
95 IsReindexProcessing(void)
96 {
97         return reindexing;
98 }
99
100 /* ----------------------------------------------------------------
101  *        sysatts is a structure containing attribute tuple forms
102  *        for system attributes (numbered -1, -2, ...).  This really
103  *        should be generated or eliminated or moved elsewhere. -cim 1/19/91
104  *
105  * typedef struct FormData_pg_attribute {
106  *              Oid                             attrelid;
107  *              NameData                attname;
108  *              Oid                             atttypid;
109  *              uint32                  attnvals;
110  *              int16                   attlen;
111  *              AttrNumber              attnum;
112  *              uint32                  attnelems;
113  *              int32                   attcacheoff;
114  *              int32                   atttypmod;
115  *              bool                    attbyval;
116  *              bool                    attisset;
117  *              char                    attalign;
118  *              bool                    attnotnull;
119  *              bool                    atthasdef;
120  * } FormData_pg_attribute;
121  *
122  * ----------------------------------------------------------------
123  */
124 static FormData_pg_attribute sysatts[] = {
125         {0, {"ctid"}, TIDOID, 0, 6, -1, 0, -1, -1, '\0', 'p', '\0', 'i', '\0', '\0'},
126         {0, {"oid"}, OIDOID, 0, 4, -2, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
127         {0, {"xmin"}, XIDOID, 0, 4, -3, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
128         {0, {"cmin"}, CIDOID, 0, 4, -4, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
129         {0, {"xmax"}, XIDOID, 0, 4, -5, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
130         {0, {"cmax"}, CIDOID, 0, 4, -6, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
131 };
132
133 /* ----------------------------------------------------------------
134  *              GetHeapRelationOid
135  * ----------------------------------------------------------------
136  */
137 static Oid
138 GetHeapRelationOid(char *heapRelationName, char *indexRelationName, bool istemp)
139 {
140         Oid                     indoid;
141         Oid                     heapoid;
142
143
144         indoid = RelnameFindRelid(indexRelationName);
145
146         if ((!istemp && OidIsValid(indoid)) ||
147                 (istemp && get_temp_rel_by_username(indexRelationName) != NULL))
148                 elog(ERROR, "Cannot create index: '%s' already exists",
149                          indexRelationName);
150
151         heapoid = RelnameFindRelid(heapRelationName);
152
153         if (!OidIsValid(heapoid))
154                 elog(ERROR, "Cannot create index on '%s': relation does not exist",
155                          heapRelationName);
156
157         return heapoid;
158 }
159
160 static TupleDesc
161 BuildFuncTupleDesc(Oid funcOid)
162 {
163         TupleDesc       funcTupDesc;
164         HeapTuple       tuple;
165         Oid                     retType;
166
167         /*
168          * Allocate and zero a tuple descriptor.
169          */
170         funcTupDesc = CreateTemplateTupleDesc(1);
171         funcTupDesc->attrs[0] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
172         MemSet(funcTupDesc->attrs[0], 0, ATTRIBUTE_TUPLE_SIZE);
173
174         /*
175          * Lookup the function to get its name and return type.
176          */
177         tuple = SearchSysCache(PROCOID,
178                                                    ObjectIdGetDatum(funcOid),
179                                                    0, 0, 0);
180         if (!HeapTupleIsValid(tuple))
181                 elog(ERROR, "Function %u does not exist", funcOid);
182         retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype;
183
184         /*
185          * make the attributes name the same as the functions
186          */
187         namestrcpy(&funcTupDesc->attrs[0]->attname,
188                            NameStr(((Form_pg_proc) GETSTRUCT(tuple))->proname));
189
190         ReleaseSysCache(tuple);
191
192         /*
193          * Lookup the return type in pg_type for the type length etc.
194          */
195         tuple = SearchSysCache(TYPEOID,
196                                                    ObjectIdGetDatum(retType),
197                                                    0, 0, 0);
198         if (!HeapTupleIsValid(tuple))
199                 elog(ERROR, "Type %u does not exist", retType);
200
201         /*
202          * Assign some of the attributes values. Leave the rest as 0.
203          */
204         funcTupDesc->attrs[0]->attlen = ((Form_pg_type) GETSTRUCT(tuple))->typlen;
205         funcTupDesc->attrs[0]->atttypid = retType;
206         funcTupDesc->attrs[0]->attnum = 1;
207         funcTupDesc->attrs[0]->attbyval = ((Form_pg_type) GETSTRUCT(tuple))->typbyval;
208         funcTupDesc->attrs[0]->attcacheoff = -1;
209         funcTupDesc->attrs[0]->atttypmod = -1;
210         funcTupDesc->attrs[0]->attstorage = 'p';
211         funcTupDesc->attrs[0]->attalign = ((Form_pg_type) GETSTRUCT(tuple))->typalign;
212
213         ReleaseSysCache(tuple);
214
215         return funcTupDesc;
216 }
217
218 /* ----------------------------------------------------------------
219  *              ConstructTupleDescriptor
220  *
221  * Build an index tuple descriptor for a new index (plain not functional)
222  * ----------------------------------------------------------------
223  */
224 static TupleDesc
225 ConstructTupleDescriptor(Oid heapoid,
226                                                  Relation heapRelation,
227                                                  int numatts,
228                                                  AttrNumber *attNums)
229 {
230         TupleDesc       heapTupDesc;
231         TupleDesc       indexTupDesc;
232         int                     natts;                  /* #atts in heap rel --- for error checks */
233         int                     i;
234
235         heapTupDesc = RelationGetDescr(heapRelation);
236         natts = RelationGetForm(heapRelation)->relnatts;
237
238         /* ----------------
239          *      allocate the new tuple descriptor
240          * ----------------
241          */
242
243         indexTupDesc = CreateTemplateTupleDesc(numatts);
244
245         /* ----------------
246          *        for each attribute we are indexing, obtain its attribute
247          *        tuple form from either the static table of system attribute
248          *        tuple forms or the relation tuple descriptor
249          * ----------------
250          */
251         for (i = 0; i < numatts; i++)
252         {
253                 AttrNumber      atnum;          /* attributeNumber[attributeOffset] */
254                 AttrNumber      atind;
255                 char       *from;               /* used to simplify memcpy below */
256                 char       *to;                 /* used to simplify memcpy below */
257
258                 /* ----------------
259                  *       get the attribute number and make sure it's valid
260                  * ----------------
261                  */
262                 atnum = attNums[i];
263                 if (atnum > natts)
264                         elog(ERROR, "Cannot create index: attribute %d does not exist",
265                                  atnum);
266
267                 indexTupDesc->attrs[i] =
268                         (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
269
270                 /* ----------------
271                  *       determine which tuple descriptor to copy
272                  * ----------------
273                  */
274                 if (!AttrNumberIsForUserDefinedAttr(atnum))
275                 {
276                         /* ----------------
277                          *        here we are indexing on a system attribute (-1...-n)
278                          *        so we convert atnum into a usable index 0...n-1 so we can
279                          *        use it to dereference the array sysatts[] which stores
280                          *        tuple descriptor information for system attributes.
281                          * ----------------
282                          */
283                         if (atnum <= FirstLowInvalidHeapAttributeNumber || atnum >= 0)
284                                 elog(ERROR, "Cannot create index on system attribute: attribute number out of range (%d)", atnum);
285                         atind = (-atnum) - 1;
286
287                         from = (char *) (&sysatts[atind]);
288                 }
289                 else
290                 {
291                         /* ----------------
292                          *        here we are indexing on a normal attribute (1...n)
293                          * ----------------
294                          */
295                         atind = AttrNumberGetAttrOffset(atnum);
296
297                         from = (char *) (heapTupDesc->attrs[atind]);
298                 }
299
300                 /* ----------------
301                  *       now that we've determined the "from", let's copy
302                  *       the tuple desc data...
303                  * ----------------
304                  */
305                 to = (char *) (indexTupDesc->attrs[i]);
306                 memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);
307
308                 /*
309                  * Fix the stuff that should not be the same as the underlying attr
310                  */
311                 ((Form_pg_attribute) to)->attnum = i + 1;
312
313                 ((Form_pg_attribute) to)->attdispersion = 0.0;
314                 ((Form_pg_attribute) to)->attnotnull = false;
315                 ((Form_pg_attribute) to)->atthasdef = false;
316                 ((Form_pg_attribute) to)->attcacheoff = -1;
317
318                 /* ----------------
319                  *        now we have to drop in the proper relation descriptor
320                  *        into the copied tuple form's attrelid and we should be
321                  *        all set.
322                  * ----------------
323                  */
324                 ((Form_pg_attribute) to)->attrelid = heapoid;
325         }
326
327         return indexTupDesc;
328 }
329
330 /* ----------------------------------------------------------------
331  * AccessMethodObjectIdGetForm
332  *              Returns an access method tuple given its object identifier,
333  *              or NULL if no such AM tuple can be found.
334  *
335  * Scanning is done using CurrentMemoryContext as working storage,
336  * but the returned tuple will be allocated in resultCxt (which is
337  * typically CacheMemoryContext).
338  *
339  * There was a note here about adding indexing, but I don't see a need
340  * for it.  There are so few tuples in pg_am that an indexscan would
341  * surely be slower.
342  * ----------------------------------------------------------------
343  */
344 Form_pg_am
345 AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
346                                                         MemoryContext resultCxt)
347 {
348         Relation        pg_am_desc;
349         HeapScanDesc pg_am_scan;
350         HeapTuple       pg_am_tuple;
351         ScanKeyData key;
352         Form_pg_am      aform;
353
354         /* ----------------
355          *      form a scan key for the pg_am relation
356          * ----------------
357          */
358         ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
359                                                    F_OIDEQ,
360                                                    ObjectIdGetDatum(accessMethodObjectId));
361
362         /* ----------------
363          *      fetch the desired access method tuple
364          * ----------------
365          */
366         pg_am_desc = heap_openr(AccessMethodRelationName, AccessShareLock);
367         pg_am_scan = heap_beginscan(pg_am_desc, 0, SnapshotNow, 1, &key);
368
369         pg_am_tuple = heap_getnext(pg_am_scan, 0);
370
371         /* ----------------
372          *      return NULL if not found
373          * ----------------
374          */
375         if (!HeapTupleIsValid(pg_am_tuple))
376         {
377                 heap_endscan(pg_am_scan);
378                 heap_close(pg_am_desc, AccessShareLock);
379                 return NULL;
380         }
381
382         /* ----------------
383          *      if found AM tuple, then copy it into resultCxt and return the copy
384          * ----------------
385          */
386         aform = (Form_pg_am) MemoryContextAlloc(resultCxt, sizeof *aform);
387         memcpy(aform, GETSTRUCT(pg_am_tuple), sizeof *aform);
388
389         heap_endscan(pg_am_scan);
390         heap_close(pg_am_desc, AccessShareLock);
391
392         return aform;
393 }
394
395 /* ----------------------------------------------------------------
396  *              ConstructIndexReldesc
397  * ----------------------------------------------------------------
398  */
399 static void
400 ConstructIndexReldesc(Relation indexRelation, Oid amoid)
401 {
402         indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid,
403                                                                                                            CacheMemoryContext);
404
405         /* ----------------
406          *       XXX missing the initialization of some other fields
407          * ----------------
408          */
409
410         indexRelation->rd_rel->relowner = GetUserId();
411
412         indexRelation->rd_rel->relam = amoid;
413         indexRelation->rd_rel->reltuples = 1;           /* XXX */
414         indexRelation->rd_rel->relkind = RELKIND_INDEX;
415 }
416
417 /* ----------------------------------------------------------------
418  *              UpdateRelationRelation
419  * ----------------------------------------------------------------
420  */
421 static Oid
422 UpdateRelationRelation(Relation indexRelation, char *temp_relname)
423 {
424         Relation        pg_class;
425         HeapTuple       tuple;
426         Oid                     tupleOid;
427         Relation        idescs[Num_pg_class_indices];
428
429         pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
430
431         /* XXX Natts_pg_class_fixed is a hack - see pg_class.h */
432         tuple = heap_addheader(Natts_pg_class_fixed,
433                                                    CLASS_TUPLE_SIZE,
434                                                    (char *) indexRelation->rd_rel);
435
436         /* ----------------
437          *      the new tuple must have the same oid as the relcache entry for the
438          *      index.  sure would be embarrassing to do this sort of thing in
439          *      polite company.
440          * ----------------
441          */
442         tuple->t_data->t_oid = RelationGetRelid(indexRelation);
443         heap_insert(pg_class, tuple);
444
445         if (temp_relname)
446                 create_temp_relation(temp_relname, tuple);
447
448         /*
449          * During normal processing, we need to make sure that the system
450          * catalog indices are correct.  Bootstrap (initdb) time doesn't
451          * require this, because we make sure that the indices are correct
452          * just before exiting.
453          */
454
455         if (!IsIgnoringSystemIndexes())
456         {
457                 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
458                 CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, tuple);
459                 CatalogCloseIndices(Num_pg_class_indices, idescs);
460         }
461
462         tupleOid = tuple->t_data->t_oid;
463         heap_freetuple(tuple);
464         heap_close(pg_class, RowExclusiveLock);
465
466         return tupleOid;
467 }
468
469 /* ----------------------------------------------------------------
470  *              InitializeAttributeOids
471  * ----------------------------------------------------------------
472  */
473 static void
474 InitializeAttributeOids(Relation indexRelation,
475                                                 int numatts,
476                                                 Oid indexoid)
477 {
478         TupleDesc       tupleDescriptor;
479         int                     i;
480
481         tupleDescriptor = RelationGetDescr(indexRelation);
482
483         for (i = 0; i < numatts; i += 1)
484                 tupleDescriptor->attrs[i]->attrelid = indexoid;
485 }
486
487 /* ----------------------------------------------------------------
488  *              AppendAttributeTuples
489  *
490  *              XXX For now, only change the ATTNUM attribute value
491  * ----------------------------------------------------------------
492  */
493 static void
494 AppendAttributeTuples(Relation indexRelation, int numatts)
495 {
496         Relation        pg_attribute;
497         HeapTuple       init_tuple,
498                                 cur_tuple = NULL,
499                                 new_tuple;
500         bool            hasind;
501         Relation        idescs[Num_pg_attr_indices];
502         Datum           value[Natts_pg_attribute];
503         char            nullv[Natts_pg_attribute];
504         char            replace[Natts_pg_attribute];
505         TupleDesc       indexTupDesc;
506         int                     i;
507
508         /* ----------------
509          *      open the attribute relation
510          * ----------------
511          */
512         pg_attribute = heap_openr(AttributeRelationName, RowExclusiveLock);
513
514         /* ----------------
515          *      initialize *null, *replace and *value
516          * ----------------
517          */
518         MemSet(nullv, ' ', Natts_pg_attribute);
519         MemSet(replace, ' ', Natts_pg_attribute);
520
521         /* ----------------
522          *      create the first attribute tuple.
523          *      XXX For now, only change the ATTNUM attribute value
524          * ----------------
525          */
526         replace[Anum_pg_attribute_attnum - 1] = 'r';
527         replace[Anum_pg_attribute_attcacheoff - 1] = 'r';
528
529         value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(1);
530         value[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1);
531
532         init_tuple = heap_addheader(Natts_pg_attribute,
533                                                                 ATTRIBUTE_TUPLE_SIZE,
534                                                          (char *) (indexRelation->rd_att->attrs[0]));
535
536         hasind = false;
537         if (!IsIgnoringSystemIndexes() && pg_attribute->rd_rel->relhasindex)
538         {
539                 hasind = true;
540                 CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
541         }
542
543         /* ----------------
544          *      insert the first attribute tuple.
545          * ----------------
546          */
547         cur_tuple = heap_modifytuple(init_tuple,
548                                                                  pg_attribute,
549                                                                  value,
550                                                                  nullv,
551                                                                  replace);
552         heap_freetuple(init_tuple);
553
554         heap_insert(pg_attribute, cur_tuple);
555         if (hasind)
556                 CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, cur_tuple);
557
558         /* ----------------
559          *      now we use the information in the index cur_tuple
560          *      descriptor to form the remaining attribute tuples.
561          * ----------------
562          */
563         indexTupDesc = RelationGetDescr(indexRelation);
564
565         for (i = 1; i < numatts; i += 1)
566         {
567                 /* ----------------
568                  *      process the remaining attributes...
569                  * ----------------
570                  */
571                 memmove(GETSTRUCT(cur_tuple),
572                                 (char *) indexTupDesc->attrs[i],
573                                 ATTRIBUTE_TUPLE_SIZE);
574
575                 value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(i + 1);
576
577                 new_tuple = heap_modifytuple(cur_tuple,
578                                                                          pg_attribute,
579                                                                          value,
580                                                                          nullv,
581                                                                          replace);
582                 heap_freetuple(cur_tuple);
583
584                 heap_insert(pg_attribute, new_tuple);
585                 if (hasind)
586                         CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, new_tuple);
587
588                 /* ----------------
589                  *      ModifyHeapTuple returns a new copy of a cur_tuple
590                  *      so we free the original and use the copy..
591                  * ----------------
592                  */
593                 cur_tuple = new_tuple;
594         }
595
596         if (cur_tuple)
597                 heap_freetuple(cur_tuple);
598         heap_close(pg_attribute, RowExclusiveLock);
599         if (hasind)
600                 CatalogCloseIndices(Num_pg_attr_indices, idescs);
601 }
602
603 /* ----------------------------------------------------------------
604  *              UpdateIndexRelation
605  * ----------------------------------------------------------------
606  */
607 static void
608 UpdateIndexRelation(Oid indexoid,
609                                         Oid heapoid,
610                                         IndexInfo *indexInfo,
611                                         Oid *classOids,
612                                         bool islossy,
613                                         bool primary)
614 {
615         Form_pg_index indexForm;
616         char       *predString;
617         text       *predText;
618         int                     predLen,
619                                 itupLen;
620         Relation        pg_index;
621         HeapTuple       tuple;
622         int                     i;
623         Relation        idescs[Num_pg_index_indices];
624
625         /* ----------------
626          *      allocate a Form_pg_index big enough to hold the
627          *      index-predicate (if any) in string form
628          * ----------------
629          */
630         if (indexInfo->ii_Predicate != NULL)
631         {
632                 predString = nodeToString(indexInfo->ii_Predicate);
633                 predText = DatumGetTextP(DirectFunctionCall1(textin,
634                                                                                         CStringGetDatum(predString)));
635                 pfree(predString);
636         }
637         else
638                 predText = DatumGetTextP(DirectFunctionCall1(textin,
639                                                                                                          CStringGetDatum("")));
640
641         predLen = VARSIZE(predText);
642         itupLen = predLen + sizeof(FormData_pg_index);
643         indexForm = (Form_pg_index) palloc(itupLen);
644         MemSet(indexForm, 0, sizeof(FormData_pg_index));
645
646         /* ----------------
647          *      store information into the index tuple form
648          * ----------------
649          */
650         indexForm->indexrelid = indexoid;
651         indexForm->indrelid = heapoid;
652         indexForm->indproc = indexInfo->ii_FuncOid;
653         indexForm->indisclustered = false;
654         indexForm->indislossy = islossy;
655         indexForm->indhaskeytype = true; /* not actually used anymore */
656         indexForm->indisunique = indexInfo->ii_Unique;
657         indexForm->indisprimary = primary;
658         memcpy((char *) &indexForm->indpred, (char *) predText, predLen);
659
660         /* ----------------
661          *      copy index key and op class information
662          *
663          *      We zeroed the extra slots (if any) above --- that's essential.
664          * ----------------
665          */
666         for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
667                 indexForm->indkey[i] = indexInfo->ii_KeyAttrNumbers[i];
668
669         for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
670                 indexForm->indclass[i] = classOids[i];
671
672         /* ----------------
673          *      open the system catalog index relation
674          * ----------------
675          */
676         pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
677
678         /* ----------------
679          *      form a tuple to insert into pg_index
680          * ----------------
681          */
682         tuple = heap_addheader(Natts_pg_index,
683                                                    itupLen,
684                                                    (char *) indexForm);
685
686         /* ----------------
687          *      insert the tuple into the pg_index
688          * ----------------
689          */
690         heap_insert(pg_index, tuple);
691
692         /* ----------------
693          *      add index tuples for it
694          * ----------------
695          */
696         if (!IsIgnoringSystemIndexes())
697         {
698                 CatalogOpenIndices(Num_pg_index_indices, Name_pg_index_indices, idescs);
699                 CatalogIndexInsert(idescs, Num_pg_index_indices, pg_index, tuple);
700                 CatalogCloseIndices(Num_pg_index_indices, idescs);
701         }
702
703         /* ----------------
704          *      close the relation and free the tuple
705          * ----------------
706          */
707         heap_close(pg_index, RowExclusiveLock);
708         pfree(predText);
709         pfree(indexForm);
710         heap_freetuple(tuple);
711 }
712
713 /* ----------------------------------------------------------------
714  *              UpdateIndexPredicate
715  * ----------------------------------------------------------------
716  */
717 void
718 UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
719 {
720         Node       *newPred;
721         char       *predString;
722         text       *predText;
723         Relation        pg_index;
724         HeapTuple       tuple;
725         HeapTuple       newtup;
726         int                     i;
727         Datum           values[Natts_pg_index];
728         char            nulls[Natts_pg_index];
729         char            replace[Natts_pg_index];
730
731         /*
732          * Construct newPred as a CNF expression equivalent to the OR of the
733          * original partial-index predicate ("oldPred") and the extension
734          * predicate ("predicate").
735          *
736          * This should really try to process the result to change things like
737          * "a>2 OR a>1" to simply "a>1", but for now all it does is make sure
738          * that if the extension predicate is NULL (i.e., it is being extended
739          * to be a complete index), then newPred will be NULL - in effect,
740          * changing "a>2 OR TRUE" to "TRUE". --Nels, Jan '93
741          */
742         newPred = NULL;
743         if (predicate != NULL)
744         {
745                 newPred = (Node *) make_orclause(lcons(make_andclause((List *) predicate),
746                                                                   lcons(make_andclause((List *) oldPred),
747                                                                                 NIL)));
748                 newPred = (Node *) cnfify((Expr *) newPred, true);
749         }
750
751         /* translate the index-predicate to string form */
752         if (newPred != NULL)
753         {
754                 predString = nodeToString(newPred);
755                 predText = DatumGetTextP(DirectFunctionCall1(textin,
756                                                                                         CStringGetDatum(predString)));
757                 pfree(predString);
758         }
759         else
760                 predText = DatumGetTextP(DirectFunctionCall1(textin,
761                                                                                                          CStringGetDatum("")));
762
763         /* open the index system catalog relation */
764         pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
765
766         tuple = SearchSysCache(INDEXRELID,
767                                                    ObjectIdGetDatum(indexoid),
768                                                    0, 0, 0);
769         if (!HeapTupleIsValid(tuple))
770                 elog(ERROR, "UpdateIndexPredicate: cache lookup failed for index %u",
771                          indexoid);
772
773         for (i = 0; i < Natts_pg_index; i++)
774         {
775                 nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' ';
776                 replace[i] = ' ';
777                 values[i] = (Datum) NULL;
778         }
779
780         replace[Anum_pg_index_indpred - 1] = 'r';
781         values[Anum_pg_index_indpred - 1] = (Datum) predText;
782
783         newtup = heap_modifytuple(tuple, pg_index, values, nulls, replace);
784
785         heap_update(pg_index, &newtup->t_self, newtup, NULL);
786
787         heap_freetuple(newtup);
788         ReleaseSysCache(tuple);
789
790         heap_close(pg_index, RowExclusiveLock);
791         pfree(predText);
792 }
793
794 /* ----------------------------------------------------------------
795  *              InitIndexStrategy
796  * ----------------------------------------------------------------
797  */
798 void
799 InitIndexStrategy(int numatts,
800                                   Relation indexRelation,
801                                   Oid accessMethodObjectId)
802 {
803         IndexStrategy strategy;
804         RegProcedure *support;
805         uint16          amstrategies;
806         uint16          amsupport;
807         Oid                     attrelid;
808         Size            strsize;
809
810         /* ----------------
811          *      get information from the index relation descriptor
812          * ----------------
813          */
814         attrelid = indexRelation->rd_att->attrs[0]->attrelid;
815         amstrategies = indexRelation->rd_am->amstrategies;
816         amsupport = indexRelation->rd_am->amsupport;
817
818         /* ----------------
819          *      get the size of the strategy
820          * ----------------
821          */
822         strsize = AttributeNumberGetIndexStrategySize(numatts, amstrategies);
823
824         /* ----------------
825          *      allocate the new index strategy structure
826          *
827          *      the index strategy has to be allocated in the same
828          *      context as the relation descriptor cache or else
829          *      it will be lost at the end of the transaction.
830          * ----------------
831          */
832         if (!CacheMemoryContext)
833                 CreateCacheMemoryContext();
834
835         strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
836                                                                                                   strsize);
837
838         if (amsupport > 0)
839         {
840                 strsize = numatts * (amsupport * sizeof(RegProcedure));
841                 support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext,
842                                                                                                           strsize);
843         }
844         else
845                 support = (RegProcedure *) NULL;
846
847         /* ----------------
848          *      fill in the index strategy structure with information
849          *      from the catalogs.      First we must advance the command counter
850          *      so that we will see the newly-entered index catalog tuples.
851          * ----------------
852          */
853         CommandCounterIncrement();
854
855         IndexSupportInitialize(strategy, support,
856                                                    &indexRelation->rd_uniqueindex,
857                                                    attrelid, accessMethodObjectId,
858                                                    amstrategies, amsupport, numatts);
859
860         /* ----------------
861          *      store the strategy information in the index reldesc
862          * ----------------
863          */
864         RelationSetIndexSupport(indexRelation, strategy, support);
865 }
866
867
868 /* ----------------------------------------------------------------
869  *              index_create
870  * ----------------------------------------------------------------
871  */
872 void
873 index_create(char *heapRelationName,
874                          char *indexRelationName,
875                          IndexInfo *indexInfo,
876                          Oid accessMethodObjectId,
877                          Oid *classObjectId,
878                          bool islossy,
879                          bool primary,
880                          bool allow_system_table_mods)
881 {
882         Relation        heapRelation;
883         Relation        indexRelation;
884         TupleDesc       indexTupDesc;
885         Oid                     heapoid;
886         Oid                     indexoid;
887         bool            istemp = (get_temp_rel_by_username(heapRelationName) != NULL);
888         char       *temp_relname = NULL;
889
890         SetReindexProcessing(false);
891
892         /* ----------------
893          *      check parameters
894          * ----------------
895          */
896         if (indexInfo->ii_NumIndexAttrs < 1 ||
897                 indexInfo->ii_NumKeyAttrs < 1)
898                 elog(ERROR, "must index at least one attribute");
899
900         /* ----------------
901          *        get heap relation oid and open the heap relation
902          * ----------------
903          */
904         heapoid = GetHeapRelationOid(heapRelationName, indexRelationName, istemp);
905
906         /*
907          * Only SELECT ... FOR UPDATE are allowed while doing this
908          */
909         heapRelation = heap_open(heapoid, ShareLock);
910
911         /* ----------------
912          *        construct new tuple descriptor
913          * ----------------
914          */
915         if (OidIsValid(indexInfo->ii_FuncOid))
916                 indexTupDesc = BuildFuncTupleDesc(indexInfo->ii_FuncOid);
917         else
918                 indexTupDesc = ConstructTupleDescriptor(heapoid,
919                                                                                                 heapRelation,
920                                                                                                 indexInfo->ii_NumKeyAttrs,
921                                                                                                 indexInfo->ii_KeyAttrNumbers);
922
923         if (istemp)
924         {
925                 /* save user relation name because heap_create changes it */
926                 temp_relname = pstrdup(indexRelationName);      /* save original value */
927                 indexRelationName = palloc(NAMEDATALEN);
928                 strcpy(indexRelationName, temp_relname);        /* heap_create will
929                                                                                                          * change this */
930         }
931
932         /* ----------------
933          *      create the index relation
934          * ----------------
935          */
936         indexRelation = heap_create(indexRelationName, indexTupDesc,
937                                                                 istemp, false, allow_system_table_mods);
938
939         /*
940          * Obtain exclusive lock on it.  Although no other backends can see it
941          * until we commit, this prevents deadlock-risk complaints from lock
942          * manager in cases such as CLUSTER.
943          */
944         LockRelation(indexRelation, AccessExclusiveLock);
945
946         /* ----------------
947          *        construct the index relation descriptor
948          *
949          *        XXX should have a proper way to create cataloged relations
950          * ----------------
951          */
952         ConstructIndexReldesc(indexRelation, accessMethodObjectId);
953
954         /* ----------------
955          *        add index to catalogs
956          *        (append RELATION tuple)
957          * ----------------
958          */
959         indexoid = UpdateRelationRelation(indexRelation, temp_relname);
960
961         /*
962          * We create the disk file for this relation here
963          */
964         heap_storage_create(indexRelation);
965
966         /* ----------------
967          *      now update the object id's of all the attribute
968          *      tuple forms in the index relation's tuple descriptor
969          * ----------------
970          */
971         InitializeAttributeOids(indexRelation,
972                                                         indexInfo->ii_NumIndexAttrs,
973                                                         indexoid);
974
975         /* ----------------
976          *        append ATTRIBUTE tuples for the index
977          * ----------------
978          */
979         AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs);
980
981         /* ----------------
982          *        update pg_index
983          *        (append INDEX tuple)
984          *
985          *        Note that this stows away a representation of "predicate".
986          *        (Or, could define a rule to maintain the predicate) --Nels, Feb '92
987          * ----------------
988          */
989         UpdateIndexRelation(indexoid, heapoid, indexInfo,
990                                                 classObjectId, islossy, primary);
991
992         /* ----------------
993          *        initialize the index strategy
994          * ----------------
995          */
996         InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
997                                           indexRelation,
998                                           accessMethodObjectId);
999
1000         /*
1001          * If this is bootstrap (initdb) time, then we don't actually fill in
1002          * the index yet.  We'll be creating more indices and classes later,
1003          * so we delay filling them in until just before we're done with
1004          * bootstrapping.  Otherwise, we call the routine that constructs the
1005          * index.
1006          *
1007          * In normal processing mode, the heap and index relations are closed by
1008          * index_build() --- but we continue to hold the ShareLock on the heap
1009          * and the exclusive lock on the index that we acquired above, until
1010          * end of transaction.
1011          */
1012         if (IsBootstrapProcessingMode())
1013         {
1014                 index_register(heapRelationName, indexRelationName, indexInfo);
1015                 /* XXX shouldn't we close the heap and index rels here? */
1016         }
1017         else
1018         {
1019                 index_build(heapRelation, indexRelation, indexInfo, NULL);
1020         }
1021 }
1022
1023 /* ----------------------------------------------------------------
1024  *
1025  *              index_drop
1026  *
1027  * ----------------------------------------------------------------
1028  */
1029 void
1030 index_drop(Oid indexId)
1031 {
1032         Oid                     heapId;
1033         Relation        userHeapRelation;
1034         Relation        userIndexRelation;
1035         Relation        indexRelation;
1036         Relation        relationRelation;
1037         Relation        attributeRelation;
1038         HeapTuple       tuple;
1039         int16           attnum;
1040         int                     i;
1041
1042         Assert(OidIsValid(indexId));
1043
1044         /* ----------------
1045          *      To drop an index safely, we must grab exclusive lock on its parent
1046          *      table; otherwise there could be other backends using the index!
1047          *      Exclusive lock on the index alone is insufficient because the index
1048          *      access routines are a little slipshod about obtaining adequate locking
1049          *      (see ExecOpenIndices()).  We do grab exclusive lock on the index too,
1050          *      just to be safe.  Both locks must be held till end of transaction,
1051          *      else other backends will still see this index in pg_index.
1052          * ----------------
1053          */
1054         heapId = IndexGetRelation(indexId);
1055         userHeapRelation = heap_open(heapId, AccessExclusiveLock);
1056
1057         userIndexRelation = index_open(indexId);
1058         LockRelation(userIndexRelation, AccessExclusiveLock);
1059
1060         /* ----------------
1061          *      Note: unlike heap_drop_with_catalog, we do not need to prevent
1062          *      deletion of system indexes here; that's checked for upstream.
1063          *      If we did check it here, deletion of TOAST tables would fail...
1064          * ----------------
1065          */
1066
1067         /* ----------------
1068          * fix DESCRIPTION relation
1069          * ----------------
1070          */
1071         DeleteComments(indexId);
1072
1073         /* ----------------
1074          * fix RELATION relation
1075          * ----------------
1076          */
1077         relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
1078
1079         /* Remove the pg_class tuple for the index itself */
1080         tuple = SearchSysCacheCopy(RELOID,
1081                                                            ObjectIdGetDatum(indexId),
1082                                                            0, 0, 0);
1083         if (!HeapTupleIsValid(tuple))
1084                 elog(ERROR, "index_drop: cache lookup failed for index %u",
1085                          indexId);
1086
1087         heap_delete(relationRelation, &tuple->t_self, NULL);
1088         heap_freetuple(tuple);
1089
1090         /*
1091          * Update the pg_class tuple for the owning relation.  We are presently
1092          * too lazy to attempt to compute the new correct value of relhasindex
1093          * (the next VACUUM will fix it if necessary).  But we must send out a
1094          * shared-cache-inval notice on the owning relation to ensure other
1095          * backends update their relcache lists of indexes.  So, unconditionally
1096          * do setRelhasindex(true).
1097          */
1098         setRelhasindex(heapId, true);
1099
1100         heap_close(relationRelation, RowExclusiveLock);
1101
1102         /* ----------------
1103          * fix ATTRIBUTE relation
1104          * ----------------
1105          */
1106         attributeRelation = heap_openr(AttributeRelationName, RowExclusiveLock);
1107
1108         attnum = 1;                                     /* indexes start at 1 */
1109
1110         while (HeapTupleIsValid(tuple = SearchSysCacheCopy(ATTNUM,
1111                                                                                            ObjectIdGetDatum(indexId),
1112                                                                                                    Int16GetDatum(attnum),
1113                                                                                                            0, 0)))
1114         {
1115                 heap_delete(attributeRelation, &tuple->t_self, NULL);
1116                 heap_freetuple(tuple);
1117                 attnum++;
1118         }
1119         heap_close(attributeRelation, RowExclusiveLock);
1120
1121         /* ----------------
1122          * fix INDEX relation
1123          * ----------------
1124          */
1125         indexRelation = heap_openr(IndexRelationName, RowExclusiveLock);
1126
1127         tuple = SearchSysCacheCopy(INDEXRELID,
1128                                                            ObjectIdGetDatum(indexId),
1129                                                            0, 0, 0);
1130         if (!HeapTupleIsValid(tuple))
1131                 elog(ERROR, "index_drop: cache lookup failed for index %u",
1132                          indexId);
1133
1134         heap_delete(indexRelation, &tuple->t_self, NULL);
1135         heap_freetuple(tuple);
1136         heap_close(indexRelation, RowExclusiveLock);
1137
1138         /*
1139          * flush buffer cache and physically remove the file
1140          */
1141         i = FlushRelationBuffers(userIndexRelation, (BlockNumber) 0);
1142         if (i < 0)
1143                 elog(ERROR, "index_drop: FlushRelationBuffers returned %d", i);
1144
1145         smgrunlink(DEFAULT_SMGR, userIndexRelation);
1146
1147         /*
1148          * Close rels, but keep locks
1149          */
1150         index_close(userIndexRelation);
1151         heap_close(userHeapRelation, NoLock);
1152
1153         RelationForgetRelation(indexId);
1154
1155         /* if it's a temp index, clear the temp mapping table entry */
1156         remove_temp_rel_by_relid(indexId);
1157 }
1158
1159 /* ----------------------------------------------------------------
1160  *                                              index_build support
1161  * ----------------------------------------------------------------
1162  */
1163
1164 /* ----------------
1165  *              BuildIndexInfo
1166  *                      Construct an IndexInfo record given the index's pg_index tuple
1167  *
1168  * IndexInfo stores the information about the index that's needed by
1169  * FormIndexDatum, which is used for both index_build() and later insertion
1170  * of individual index tuples.  Normally we build an IndexInfo for an index
1171  * just once per command, and then use it for (potentially) many tuples.
1172  * ----------------
1173  */
1174 IndexInfo *
1175 BuildIndexInfo(HeapTuple indexTuple)
1176 {
1177         Form_pg_index indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
1178         IndexInfo  *ii = makeNode(IndexInfo);
1179         int                     i;
1180         int                     numKeys;
1181
1182         /* ----------------
1183          *      count the number of keys, and copy them into the IndexInfo
1184          * ----------------
1185          */
1186         numKeys = 0;
1187         for (i = 0; i < INDEX_MAX_KEYS &&
1188                  indexStruct->indkey[i] != InvalidAttrNumber; i++)
1189         {
1190                 ii->ii_KeyAttrNumbers[i] = indexStruct->indkey[i];
1191                 numKeys++;
1192         }
1193         ii->ii_NumKeyAttrs = numKeys;
1194
1195         /* ----------------
1196          *      Handle functional index.
1197          *
1198          *      If we have a functional index then the number of
1199          *      attributes defined in the index must be 1 (the function's
1200          *      single return value).  Otherwise it's same as number of keys.
1201          * ----------------
1202          */
1203         ii->ii_FuncOid = indexStruct->indproc;
1204
1205         if (OidIsValid(indexStruct->indproc))
1206         {
1207                 ii->ii_NumIndexAttrs = 1;
1208                 /* Do a lookup on the function, too */
1209                 fmgr_info(indexStruct->indproc, & ii->ii_FuncInfo);
1210         }
1211         else
1212                 ii->ii_NumIndexAttrs = numKeys;
1213
1214         /* ----------------
1215          *      If partial index, convert predicate into expression nodetree
1216          * ----------------
1217          */
1218         if (VARSIZE(&indexStruct->indpred) != 0)
1219         {
1220                 char       *predString;
1221
1222                 predString = DatumGetCString(DirectFunctionCall1(textout,
1223                                                                          PointerGetDatum(&indexStruct->indpred)));
1224                 ii->ii_Predicate = stringToNode(predString);
1225                 pfree(predString);
1226         }
1227         else
1228                 ii->ii_Predicate = NULL;
1229
1230         /* Other info */
1231         ii->ii_Unique = indexStruct->indisunique;
1232
1233         return ii;
1234 }
1235
1236 /* ----------------
1237  *              FormIndexDatum
1238  *                      Construct Datum[] and nullv[] arrays for a new index tuple.
1239  *
1240  *      indexInfo               Info about the index
1241  *      heapTuple               Heap tuple for which we must prepare an index entry
1242  *      heapDescriptor  tupledesc for heap tuple
1243  *      resultCxt               Temporary memory context for any palloc'd datums created
1244  *      datum                   Array of index Datums (output area)
1245  *      nullv                   Array of is-null indicators (output area)
1246  *
1247  * For largely historical reasons, we don't actually call index_formtuple()
1248  * here, we just prepare its input arrays datum[] and nullv[].
1249  * ----------------
1250  */
1251 void
1252 FormIndexDatum(IndexInfo *indexInfo,
1253                            HeapTuple heapTuple,
1254                            TupleDesc heapDescriptor,
1255                            MemoryContext resultCxt,
1256                            Datum *datum,
1257                            char *nullv)
1258 {
1259         MemoryContext oldContext;
1260         int                     i;
1261         Datum           iDatum;
1262         bool            isNull;
1263
1264         oldContext = MemoryContextSwitchTo(resultCxt);
1265
1266         if (OidIsValid(indexInfo->ii_FuncOid))
1267         {
1268                 /* ----------------
1269                  *      Functional index --- compute the single index attribute
1270                  * ----------------
1271                  */
1272                 FunctionCallInfoData    fcinfo;
1273                 bool                                    anynull = false;
1274
1275                 MemSet(&fcinfo, 0, sizeof(fcinfo));
1276                 fcinfo.flinfo = &indexInfo->ii_FuncInfo;
1277                 fcinfo.nargs = indexInfo->ii_NumKeyAttrs;
1278
1279                 for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
1280                 {
1281                         fcinfo.arg[i] = heap_getattr(heapTuple,
1282                                                                                  indexInfo->ii_KeyAttrNumbers[i],
1283                                                                                  heapDescriptor,
1284                                                                                  &fcinfo.argnull[i]);
1285                         anynull |= fcinfo.argnull[i];
1286                 }
1287                 if (indexInfo->ii_FuncInfo.fn_strict && anynull)
1288                 {
1289                         /* force a null result for strict function */
1290                         iDatum = (Datum) 0;
1291                         isNull = true;
1292                 }
1293                 else
1294                 {
1295                         iDatum = FunctionCallInvoke(&fcinfo);
1296                         isNull = fcinfo.isnull;
1297                 }
1298                 datum[0] = iDatum;
1299                 nullv[0] = (isNull) ? 'n' : ' ';
1300         }
1301         else
1302         {
1303                 /* ----------------
1304                  *      Plain index --- for each attribute we need from the heap tuple,
1305                  *      get the attribute and stick it into the datum and nullv arrays.
1306                  * ----------------
1307                  */
1308                 for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
1309                 {
1310                         iDatum = heap_getattr(heapTuple,
1311                                                                   indexInfo->ii_KeyAttrNumbers[i],
1312                                                                   heapDescriptor,
1313                                                                   &isNull);
1314                         datum[i] = iDatum;
1315                         nullv[i] = (isNull) ? 'n' : ' ';
1316                 }
1317         }
1318
1319         MemoryContextSwitchTo(oldContext);
1320 }
1321
1322
1323 /* --------------------------------------------
1324  *              Lock class info for update
1325  * --------------------------------------------
1326  */
1327 static bool
1328 LockClassinfoForUpdate(Oid relid, HeapTuple rtup,
1329                                            Buffer *buffer, bool confirmCommitted)
1330 {
1331         HeapTuple       classTuple;
1332         bool            test;
1333         Relation        relationRelation;
1334
1335         /*
1336          * NOTE: get and hold RowExclusiveLock on pg_class, because caller will
1337          * probably modify the rel's pg_class tuple later on.
1338          */
1339         relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
1340         classTuple = SearchSysCache(RELOID, PointerGetDatum(relid),
1341                                                                 0, 0, 0);
1342         if (!HeapTupleIsValid(classTuple))
1343         {
1344                 heap_close(relationRelation, NoLock);
1345                 return false;
1346         }
1347         rtup->t_self = classTuple->t_self;
1348         ReleaseSysCache(classTuple);
1349
1350         test = heap_mark4update(relationRelation, rtup, buffer);
1351         switch (test)
1352         {
1353                 case HeapTupleSelfUpdated:
1354                 case HeapTupleMayBeUpdated:
1355                         break;
1356                 default:
1357                         elog(ERROR, "LockStatsForUpdate couldn't lock relid %u", relid);
1358                         return false;
1359         }
1360         RelationInvalidateHeapTuple(relationRelation, rtup);
1361         if (confirmCommitted)
1362         {
1363                 HeapTupleHeader th = rtup->t_data;
1364
1365                 if (!(th->t_infomask & HEAP_XMIN_COMMITTED))
1366                         elog(ERROR, "The tuple isn't committed");
1367                 if (th->t_infomask & HEAP_XMAX_COMMITTED)
1368                         if (!(th->t_infomask & HEAP_MARKED_FOR_UPDATE))
1369                                 elog(ERROR, "The tuple is already deleted");
1370         }
1371         heap_close(relationRelation, NoLock);
1372         return true;
1373 }
1374
1375 /* ---------------------------------------------
1376  *              Indexes of the relation active ?
1377  * ---------------------------------------------
1378  */
1379 bool
1380 IndexesAreActive(Oid relid, bool confirmCommitted)
1381 {
1382         HeapTupleData tuple;
1383         Relation        indexRelation;
1384         Buffer          buffer;
1385         HeapScanDesc scan;
1386         ScanKeyData entry;
1387         bool            isactive;
1388
1389         if (!LockClassinfoForUpdate(relid, &tuple, &buffer, confirmCommitted))
1390                 elog(ERROR, "IndexesAreActive couldn't lock %u", relid);
1391         if (((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_RELATION &&
1392                 ((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_TOASTVALUE)
1393                 elog(ERROR, "relation %u isn't an indexable relation", relid);
1394         isactive = ((Form_pg_class) GETSTRUCT(&tuple))->relhasindex;
1395         ReleaseBuffer(buffer);
1396         if (isactive)
1397                 return isactive;
1398         indexRelation = heap_openr(IndexRelationName, AccessShareLock);
1399         ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid,
1400                                                    F_OIDEQ, ObjectIdGetDatum(relid));
1401         scan = heap_beginscan(indexRelation, false, SnapshotNow,
1402                                                   1, &entry);
1403         if (!heap_getnext(scan, 0))
1404                 isactive = true;
1405         heap_endscan(scan);
1406         heap_close(indexRelation, AccessShareLock);
1407         return isactive;
1408 }
1409
1410 /* ----------------
1411  *              set relhasindex of relation's pg_class entry
1412  *
1413  * NOTE: an important side-effect of this operation is that an SI invalidation
1414  * message is sent out to all backends --- including me --- causing relcache
1415  * entries to be flushed or updated with the new hasindex data.
1416  * Therefore, we execute the update even if relhasindex has the right value
1417  * already.  Possible future improvement: skip the disk update and just send
1418  * an SI message in that case.
1419  * ----------------
1420  */
1421 void
1422 setRelhasindex(Oid relid, bool hasindex)
1423 {
1424         Relation        pg_class;
1425         HeapTuple       tuple;
1426         HeapScanDesc pg_class_scan = NULL;
1427
1428         /*
1429          * Find the tuple to update in pg_class.
1430          */
1431         pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
1432
1433 #ifdef  OLD_FILE_NAMING
1434         if (!IsIgnoringSystemIndexes())
1435 #else
1436         if (!IsIgnoringSystemIndexes() && (!IsReindexProcessing() || pg_class->rd_rel->relhasindex))
1437 #endif /* OLD_FILE_NAMING */
1438         {
1439                 tuple = SearchSysCacheCopy(RELOID,
1440                                                                    ObjectIdGetDatum(relid),
1441                                                                    0, 0, 0);
1442         }
1443         else
1444         {
1445                 ScanKeyData key[1];
1446
1447                 ScanKeyEntryInitialize(&key[0], 0,
1448                                                            ObjectIdAttributeNumber,
1449                                                            F_OIDEQ,
1450                                                            ObjectIdGetDatum(relid));
1451
1452                 pg_class_scan = heap_beginscan(pg_class, 0, SnapshotNow, 1, key);
1453                 tuple = heap_getnext(pg_class_scan, 0);
1454         }
1455
1456         if (!HeapTupleIsValid(tuple))
1457         {
1458                 if (pg_class_scan)
1459                         heap_endscan(pg_class_scan);
1460                 heap_close(pg_class, RowExclusiveLock);
1461                 elog(ERROR, "setRelhasindex: cannot find relation %u in pg_class",
1462                          relid);
1463         }
1464
1465         /* ----------------
1466          *      Update hasindex in pg_class.
1467          * ----------------
1468          */
1469         if (pg_class_scan)
1470                 LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
1471         ((Form_pg_class) GETSTRUCT(tuple))->relhasindex = hasindex;
1472         if (pg_class_scan)
1473                 LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
1474
1475         if (pg_class_scan)
1476         {
1477                 /* Write the modified tuple in-place */
1478                 WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
1479                 /* Send out shared cache inval if necessary */
1480                 if (!IsBootstrapProcessingMode())
1481                         RelationInvalidateHeapTuple(pg_class, tuple);
1482                 BufferSync();
1483         }
1484         else
1485         {
1486                 heap_update(pg_class, &tuple->t_self, tuple, NULL);
1487
1488                 /* Keep the catalog indices up to date */
1489                 if (!IsIgnoringSystemIndexes())
1490                 {
1491                         Relation        idescs[Num_pg_class_indices];
1492
1493                         CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
1494                                                            idescs);
1495                         CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, tuple);
1496                         CatalogCloseIndices(Num_pg_class_indices, idescs);
1497                 }
1498         }
1499
1500         if (!pg_class_scan)
1501                 heap_freetuple(tuple);
1502         else
1503                 heap_endscan(pg_class_scan);
1504
1505         heap_close(pg_class, RowExclusiveLock);
1506 }
1507
1508 #ifndef OLD_FILE_NAMING
1509 void
1510 setNewRelfilenode(Relation relation)
1511 {
1512         Relation        pg_class, idescs[Num_pg_class_indices];
1513         Oid             newrelfilenode;
1514         bool            in_place_update = false;
1515         HeapTupleData   lockTupleData;
1516         HeapTuple       classTuple;
1517         Buffer          buffer;
1518         RelationData    workrel;
1519         
1520         Assert(!IsSystemRelationName(NameStr(relation->rd_rel->relname)) || relation->rd_rel->relkind == RELKIND_INDEX);
1521
1522         pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
1523          /* Fetch and lock the classTuple associated with this relation */
1524         if (!LockClassinfoForUpdate(relation->rd_id, &lockTupleData, &buffer, true))
1525                 elog(ERROR, "setNewRelfilenode impossible to lock class tuple");
1526         if (IsIgnoringSystemIndexes())
1527                 in_place_update = true;
1528         /* Allocate a new relfilenode */
1529         newrelfilenode = newoid();
1530         /* update pg_class tuple with new relfilenode */
1531         if (!in_place_update)
1532         {
1533                 classTuple = heap_copytuple(&lockTupleData);
1534                 ReleaseBuffer(buffer);
1535                 ((Form_pg_class) GETSTRUCT(classTuple))->relfilenode = newrelfilenode;
1536                 heap_update(pg_class, &classTuple->t_self, classTuple, NULL);
1537         }
1538         /* unlink old relfilenode */
1539         DropRelationBuffers(relation);
1540         smgrunlink(DEFAULT_SMGR, relation);
1541         /* cleanup pg_internal.init if necessary */
1542         if (relation->rd_isnailed)
1543                 unlink(RELCACHE_INIT_FILENAME);
1544         /* create another storage file. Is it a little ugly ? */
1545         memcpy((char *) &workrel, relation, sizeof(RelationData));
1546         workrel.rd_node.relNode = newrelfilenode;
1547         heap_storage_create(&workrel);
1548         /* update pg_class tuple with new relfilenode in place */
1549         if (in_place_update)
1550         {
1551                 classTuple = &lockTupleData;
1552                 /* Send out shared cache inval if necessary */
1553                 if (!IsBootstrapProcessingMode())
1554                         RelationInvalidateHeapTuple(pg_class, classTuple);
1555                 /* Update the buffer in-place */
1556                 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
1557                 ((Form_pg_class) GETSTRUCT(classTuple))->relfilenode = newrelfilenode;
1558                 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
1559                 WriteBuffer(buffer);
1560                 BufferSync();
1561         }
1562         /* Keep the catalog indices up to date */
1563         if (!in_place_update && pg_class->rd_rel->relhasindex)
1564         {
1565                 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
1566                                                            idescs);
1567                 CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, classTuple);
1568                 CatalogCloseIndices(Num_pg_class_indices, idescs);
1569                 heap_freetuple(classTuple);
1570         }
1571         heap_close(pg_class, NoLock);
1572         /* Make sure the relfilenode change */
1573         CommandCounterIncrement();
1574 }
1575 #endif /* OLD_FILE_NAMING */
1576
1577 /* ----------------
1578  *              UpdateStats
1579  * ----------------
1580  */
1581 void
1582 UpdateStats(Oid relid, long reltuples)
1583 {
1584         Relation        whichRel;
1585         Relation        pg_class;
1586         HeapTuple       tuple;
1587         HeapTuple       newtup;
1588         long            relpages;
1589         int                     i;
1590         Form_pg_class rd_rel;
1591         Relation        idescs[Num_pg_class_indices];
1592         Datum           values[Natts_pg_class];
1593         char            nulls[Natts_pg_class];
1594         char            replace[Natts_pg_class];
1595         HeapScanDesc pg_class_scan = NULL;
1596         bool            in_place_upd;
1597
1598         /* ----------------
1599          * This routine handles updates for both the heap and index relation
1600          * statistics.  In order to guarantee that we're able to *see* the index
1601          * relation tuple, we bump the command counter id here.  The index
1602          * relation tuple was created in the current transaction.
1603          * ----------------
1604          */
1605         CommandCounterIncrement();
1606
1607         /* ----------------
1608          * CommandCounterIncrement() flushes invalid cache entries, including
1609          * those for the heap and index relations for which we're updating
1610          * statistics.  Now that the cache is flushed, it's safe to open the
1611          * relation again.      We need the relation open in order to figure out
1612          * how many blocks it contains.
1613          * ----------------
1614          */
1615
1616         /*
1617          * Can't use heap_open here since we don't know if it's an index...
1618          */
1619         whichRel = RelationIdGetRelation(relid);
1620
1621         if (!RelationIsValid(whichRel))
1622                 elog(ERROR, "UpdateStats: cannot open relation id %u", relid);
1623
1624         /* Grab lock to be held till end of xact (probably redundant...) */
1625         LockRelation(whichRel, ShareLock);
1626
1627         /* ----------------
1628          * Find the RELATION relation tuple for the given relation.
1629          * ----------------
1630          */
1631         pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
1632
1633 #ifdef  OLD_FILE_NAMING
1634         in_place_upd = (IsReindexProcessing() || IsBootstrapProcessingMode());
1635 #else
1636         in_place_upd = (IsIgnoringSystemIndexes() || (IsReindexProcessing() &&
1637                         relid == RelOid_pg_class));
1638 #endif /* OLD_FILE_NAMING */
1639
1640         if (!in_place_upd)
1641         {
1642                 tuple = SearchSysCacheCopy(RELOID,
1643                                                                    ObjectIdGetDatum(relid),
1644                                                                    0, 0, 0);
1645         }
1646         else
1647         {
1648                 ScanKeyData key[1];
1649
1650                 ScanKeyEntryInitialize(&key[0], 0,
1651                                                            ObjectIdAttributeNumber,
1652                                                            F_OIDEQ,
1653                                                            ObjectIdGetDatum(relid));
1654
1655                 pg_class_scan = heap_beginscan(pg_class, 0, SnapshotNow, 1, key);
1656                 tuple = heap_getnext(pg_class_scan, 0);
1657         }
1658
1659         if (!HeapTupleIsValid(tuple))
1660         {
1661                 if (pg_class_scan)
1662                         heap_endscan(pg_class_scan);
1663                 heap_close(pg_class, RowExclusiveLock);
1664                 elog(ERROR, "UpdateStats: cannot find relation %u in pg_class",
1665                          relid);
1666         }
1667
1668         /* ----------------
1669          * Figure values to insert.
1670          *
1671          * If we found zero tuples in the scan, do NOT believe it; instead put
1672          * a bogus estimate into the statistics fields.  Otherwise, the common
1673          * pattern "CREATE TABLE; CREATE INDEX; insert data" leaves the table
1674          * with zero size statistics until a VACUUM is done.  The optimizer will
1675          * generate very bad plans if the stats claim the table is empty when
1676          * it is actually sizable.      See also CREATE TABLE in heap.c.
1677          * ----------------
1678          */
1679         relpages = RelationGetNumberOfBlocks(whichRel);
1680
1681         if (reltuples == 0)
1682         {
1683                 if (relpages == 0)
1684                 {
1685                         /* Bogus defaults for a virgin table, same as heap.c */
1686                         reltuples = 1000;
1687                         relpages = 10;
1688                 }
1689                 else if (whichRel->rd_rel->relkind == RELKIND_INDEX && relpages <= 2)
1690                 {
1691                         /* Empty index, leave bogus defaults in place */
1692                         reltuples = 1000;
1693                 }
1694                 else
1695                         reltuples = relpages * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
1696         }
1697
1698         /*
1699          * We shouldn't have to do this, but we do...  Modify the reldesc in
1700          * place with the new values so that the cache contains the latest
1701          * copy.
1702          */
1703         whichRel->rd_rel->relpages = relpages;
1704         whichRel->rd_rel->reltuples = reltuples;
1705
1706         /* ----------------
1707          *      Update statistics in pg_class.
1708          * ----------------
1709          */
1710         if (in_place_upd)
1711         {
1712                 /*
1713                  * At bootstrap time, we don't need to worry about concurrency or
1714                  * visibility of changes, so we cheat.  Also cheat if REINDEX.
1715                  */
1716                 rd_rel = (Form_pg_class) GETSTRUCT(tuple);
1717                 LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
1718                 rd_rel->relpages = relpages;
1719                 rd_rel->reltuples = reltuples;
1720                 LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
1721                 WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
1722                 if (!IsBootstrapProcessingMode())
1723                         RelationInvalidateHeapTuple(pg_class, tuple);
1724         }
1725         else
1726         {
1727                 /* During normal processing, must work harder. */
1728
1729                 for (i = 0; i < Natts_pg_class; i++)
1730                 {
1731                         nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' ';
1732                         replace[i] = ' ';
1733                         values[i] = (Datum) NULL;
1734                 }
1735
1736                 replace[Anum_pg_class_relpages - 1] = 'r';
1737                 values[Anum_pg_class_relpages - 1] = (Datum) relpages;
1738                 replace[Anum_pg_class_reltuples - 1] = 'r';
1739                 values[Anum_pg_class_reltuples - 1] = (Datum) reltuples;
1740                 newtup = heap_modifytuple(tuple, pg_class, values, nulls, replace);
1741                 heap_update(pg_class, &tuple->t_self, newtup, NULL);
1742                 if (!IsIgnoringSystemIndexes())
1743                 {
1744                         CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
1745                         CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, newtup);
1746                         CatalogCloseIndices(Num_pg_class_indices, idescs);
1747                 }
1748                 heap_freetuple(newtup);
1749         }
1750
1751         if (!pg_class_scan)
1752                 heap_freetuple(tuple);
1753         else
1754                 heap_endscan(pg_class_scan);
1755
1756         heap_close(pg_class, RowExclusiveLock);
1757         /* Cheating a little bit since we didn't open it with heap_open... */
1758         heap_close(whichRel, NoLock);
1759 }
1760
1761
1762 /* ----------------
1763  *              DefaultBuild
1764  *
1765  * NB: this routine is dead code, and likely always has been, because
1766  * there are no access methods that don't supply their own ambuild procedure.
1767  *
1768  * Anyone want to wager whether it would actually work if executed?
1769  * ----------------
1770  */
1771 static void
1772 DefaultBuild(Relation heapRelation,
1773                          Relation indexRelation,
1774                          IndexInfo *indexInfo,
1775                          Node *oldPred,
1776                          IndexStrategy indexStrategy) /* not used */
1777 {
1778         HeapScanDesc scan;
1779         HeapTuple       heapTuple;
1780         TupleDesc       heapDescriptor;
1781         Datum           datum[INDEX_MAX_KEYS];
1782         char            nullv[INDEX_MAX_KEYS];
1783         long            reltuples,
1784                                 indtuples;
1785         Node       *predicate = indexInfo->ii_Predicate;
1786 #ifndef OMIT_PARTIAL_INDEX
1787         TupleTable      tupleTable;
1788         TupleTableSlot *slot;
1789 #endif
1790         ExprContext *econtext;
1791         InsertIndexResult insertResult;
1792
1793         /* ----------------
1794          *      more & better checking is needed
1795          * ----------------
1796          */
1797         Assert(OidIsValid(indexRelation->rd_rel->relam));       /* XXX */
1798
1799         heapDescriptor = RelationGetDescr(heapRelation);
1800
1801         /*
1802          * If this is a predicate (partial) index, we will need to evaluate
1803          * the predicate using ExecQual, which requires the current tuple to
1804          * be in a slot of a TupleTable.  In addition, ExecQual must have an
1805          * ExprContext referring to that slot.  Here, we initialize dummy
1806          * TupleTable and ExprContext objects for this purpose. --Nels, Feb 92
1807          *
1808          * We construct the ExprContext anyway since we need a per-tuple
1809          * temporary memory context for function evaluation -- tgl July 00
1810          */
1811 #ifndef OMIT_PARTIAL_INDEX
1812         if (predicate != NULL || oldPred != NULL)
1813         {
1814                 tupleTable = ExecCreateTupleTable(1);
1815                 slot = ExecAllocTableSlot(tupleTable);
1816                 ExecSetSlotDescriptor(slot, heapDescriptor);
1817         }
1818         else
1819         {
1820                 tupleTable = NULL;
1821                 slot = NULL;
1822         }
1823         econtext = MakeExprContext(slot, TransactionCommandContext);
1824 #else
1825         econtext = MakeExprContext(NULL, TransactionCommandContext);
1826 #endif   /* OMIT_PARTIAL_INDEX */
1827
1828         /* ----------------
1829          *      Ok, begin our scan of the base relation.
1830          * ----------------
1831          */
1832         scan = heap_beginscan(heapRelation, /* relation */
1833                                                   0,    /* start at end */
1834                                                   SnapshotNow,  /* seeself */
1835                                                   0,    /* number of keys */
1836                                                   (ScanKey) NULL);              /* scan key */
1837
1838         reltuples = indtuples = 0;
1839
1840         /* ----------------
1841          *      for each tuple in the base relation, we create an index
1842          *      tuple and add it to the index relation.  We keep a running
1843          *      count of the number of tuples so that we can update pg_class
1844          *      with correct statistics when we're done building the index.
1845          * ----------------
1846          */
1847         while (HeapTupleIsValid(heapTuple = heap_getnext(scan, 0)))
1848         {
1849                 MemoryContextReset(econtext->ecxt_per_tuple_memory);
1850
1851                 reltuples++;
1852
1853 #ifndef OMIT_PARTIAL_INDEX
1854                 /*
1855                  * If oldPred != NULL, this is an EXTEND INDEX command, so skip
1856                  * this tuple if it was already in the existing partial index
1857                  */
1858                 if (oldPred != NULL)
1859                 {
1860                         slot->val = heapTuple;
1861                         if (ExecQual((List *) oldPred, econtext, false))
1862                         {
1863                                 indtuples++;
1864                                 continue;
1865                         }
1866                 }
1867
1868                 /*
1869                  * Skip this tuple if it doesn't satisfy the partial-index
1870                  * predicate
1871                  */
1872                 if (predicate != NULL)
1873                 {
1874                         slot->val = heapTuple;
1875                         if (!ExecQual((List *) predicate, econtext, false))
1876                                 continue;
1877                 }
1878 #endif   /* OMIT_PARTIAL_INDEX */
1879
1880                 indtuples++;
1881
1882                 /* ----------------
1883                  *      FormIndexDatum fills in its datum and null parameters
1884                  *      with attribute information taken from the given heap tuple.
1885                  * ----------------
1886                  */
1887                 FormIndexDatum(indexInfo,
1888                                            heapTuple,
1889                                            heapDescriptor,
1890                                            econtext->ecxt_per_tuple_memory,
1891                                            datum,
1892                                            nullv);
1893
1894                 insertResult = index_insert(indexRelation, datum, nullv,
1895                                                                         &(heapTuple->t_self), heapRelation);
1896
1897                 if (insertResult)
1898                         pfree(insertResult);
1899         }
1900
1901         heap_endscan(scan);
1902
1903 #ifndef OMIT_PARTIAL_INDEX
1904         if (predicate != NULL || oldPred != NULL)
1905         {
1906                 ExecDropTupleTable(tupleTable, true);
1907         }
1908 #endif   /* OMIT_PARTIAL_INDEX */
1909         FreeExprContext(econtext);
1910
1911         /*
1912          * Since we just counted the tuples in the heap, we update its stats
1913          * in pg_class to guarantee that the planner takes advantage of the
1914          * index we just created.  But, only update statistics during normal
1915          * index definitions, not for indices on system catalogs created
1916          * during bootstrap processing.  We must close the relations before
1917          * updating statistics to guarantee that the relcache entries are
1918          * flushed when we increment the command counter in UpdateStats(). But
1919          * we do not release any locks on the relations; those will be held
1920          * until end of transaction.
1921          */
1922         if (IsNormalProcessingMode())
1923         {
1924                 Oid                     hrelid = RelationGetRelid(heapRelation);
1925                 Oid                     irelid = RelationGetRelid(indexRelation);
1926
1927                 heap_close(heapRelation, NoLock);
1928                 index_close(indexRelation);
1929                 UpdateStats(hrelid, reltuples);
1930                 UpdateStats(irelid, indtuples);
1931                 if (oldPred != NULL)
1932                 {
1933                         if (indtuples == reltuples)
1934                                 predicate = NULL;
1935                         UpdateIndexPredicate(irelid, oldPred, predicate);
1936                 }
1937         }
1938 }
1939
1940 /* ----------------
1941  *              index_build
1942  * ----------------
1943  */
1944 void
1945 index_build(Relation heapRelation,
1946                         Relation indexRelation,
1947                         IndexInfo *indexInfo,
1948                         Node *oldPred)
1949 {
1950         RegProcedure procedure;
1951
1952         /* ----------------
1953          *      sanity checks
1954          * ----------------
1955          */
1956         Assert(RelationIsValid(indexRelation));
1957         Assert(PointerIsValid(indexRelation->rd_am));
1958
1959         procedure = indexRelation->rd_am->ambuild;
1960
1961         /* ----------------
1962          *      use the access method build procedure if supplied, else default.
1963          * ----------------
1964          */
1965         if (RegProcedureIsValid(procedure))
1966                 OidFunctionCall5(procedure,
1967                                                  PointerGetDatum(heapRelation),
1968                                                  PointerGetDatum(indexRelation),
1969                                                  PointerGetDatum(indexInfo),
1970                                                  PointerGetDatum(oldPred),
1971                                                  PointerGetDatum(RelationGetIndexStrategy(indexRelation)));
1972         else
1973                 DefaultBuild(heapRelation,
1974                                          indexRelation,
1975                                          indexInfo,
1976                                          oldPred,
1977                                          RelationGetIndexStrategy(indexRelation));
1978 }
1979
1980 /*
1981  * IndexGetRelation: given an index's relation OID, get the OID of the
1982  * relation it is an index on.  Uses the system cache.
1983  */
1984 static Oid
1985 IndexGetRelation(Oid indexId)
1986 {
1987         HeapTuple       tuple;
1988         Form_pg_index index;
1989         Oid                     result;
1990
1991         tuple = SearchSysCache(INDEXRELID,
1992                                                    ObjectIdGetDatum(indexId),
1993                                                    0, 0, 0);
1994         if (!HeapTupleIsValid(tuple))
1995                 elog(ERROR, "IndexGetRelation: can't find index id %u",
1996                          indexId);
1997         index = (Form_pg_index) GETSTRUCT(tuple);
1998         Assert(index->indexrelid == indexId);
1999
2000         result = index->indrelid;
2001         ReleaseSysCache(tuple);
2002         return result;
2003 }
2004
2005 /* ---------------------------------
2006  * activate_index -- activate/deactivate the specified index.
2007  *              Note that currently PostgreSQL doesn't hold the
2008  *              status per index
2009  * ---------------------------------
2010  */
2011 static bool
2012 activate_index(Oid indexId, bool activate, bool inplace)
2013 {
2014         if (!activate)                          /* Currently does nothing */
2015                 return true;
2016         return reindex_index(indexId, false, inplace);
2017 }
2018
2019 /* --------------------------------
2020  * reindex_index - This routine is used to recreate an index
2021  * --------------------------------
2022  */
2023 bool
2024 reindex_index(Oid indexId, bool force, bool inplace)
2025 {
2026         Relation        iRel,
2027                                 indexRelation,
2028                                 heapRelation;
2029         ScanKeyData entry;
2030         HeapScanDesc scan;
2031         HeapTuple       indexTuple,
2032                                 classTuple;
2033         IndexInfo  *indexInfo;
2034         Oid                     heapId,
2035                                 accessMethodId;
2036         bool            old;
2037
2038         /* ----------------
2039          *      REINDEX within a transaction block is dangerous, because
2040          *      if the transaction is later rolled back we have no way to
2041          *      undo truncation of the index's physical file.  Disallow it.
2042          * ----------------
2043          */
2044         if (IsTransactionBlock())
2045                 elog(ERROR, "REINDEX cannot run inside a BEGIN/END block");
2046
2047         old = SetReindexProcessing(true);
2048
2049         /* Scan pg_index to find the index's pg_index entry */
2050         indexRelation = heap_openr(IndexRelationName, AccessShareLock);
2051         ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indexrelid, F_OIDEQ,
2052                                                    ObjectIdGetDatum(indexId));
2053         scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry);
2054         indexTuple = heap_getnext(scan, 0);
2055         if (!HeapTupleIsValid(indexTuple))
2056                 elog(ERROR, "reindex_index: index %u not found in pg_index", indexId);
2057
2058         /* Get OID of index's parent table */
2059         heapId = ((Form_pg_index) GETSTRUCT(indexTuple))->indrelid;
2060         /* Fetch info needed for index_build */
2061         indexInfo = BuildIndexInfo(indexTuple);
2062
2063         /* Complete the scan and close pg_index */
2064         heap_endscan(scan);
2065         heap_close(indexRelation, AccessShareLock);
2066
2067         /* Fetch the classTuple associated with this index */
2068         classTuple = SearchSysCache(RELOID,
2069                                                                 ObjectIdGetDatum(indexId),
2070                                                                 0, 0, 0);
2071         if (!HeapTupleIsValid(classTuple))
2072                 elog(ERROR, "reindex_index: index %u not found in pg_class", indexId);
2073         accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam;
2074         ReleaseSysCache(classTuple);
2075
2076         /* Open our index relation */
2077         heapRelation = heap_open(heapId, ExclusiveLock);
2078         if (heapRelation == NULL)
2079                 elog(ERROR, "reindex_index: can't open heap relation");
2080         iRel = index_open(indexId);
2081         if (iRel == NULL)
2082                 elog(ERROR, "reindex_index: can't open index relation");
2083
2084 #ifndef OLD_FILE_NAMING
2085         if (!inplace)
2086                 setNewRelfilenode(iRel);
2087 #endif /* OLD_FILE_NAMING */
2088         /* Obtain exclusive lock on it, just to be sure */
2089         LockRelation(iRel, AccessExclusiveLock);
2090
2091         if (inplace)
2092         {
2093                 /*
2094                  * Release any buffers associated with this index.      If they're dirty,
2095                  * they're just dropped without bothering to flush to disk.
2096                  */
2097                 DropRelationBuffers(iRel);
2098
2099                 /* Now truncate the actual data and set blocks to zero */
2100                 smgrtruncate(DEFAULT_SMGR, iRel, 0);
2101                 iRel->rd_nblocks = 0;
2102         }
2103
2104         /* Initialize the index and rebuild */
2105         InitIndexStrategy(indexInfo->ii_NumIndexAttrs, iRel, accessMethodId);
2106         index_build(heapRelation, iRel, indexInfo, NULL);
2107
2108         /*
2109          * index_build will close both the heap and index relations (but not
2110          * give up the locks we hold on them).  So we're done.
2111          */
2112
2113         SetReindexProcessing(old);
2114
2115         return true;
2116 }
2117
2118 /*
2119  * ----------------------------
2120  * activate_indexes_of_a_table
2121  *      activate/deactivate indexes of the specified table.
2122  * ----------------------------
2123  */
2124 bool
2125 activate_indexes_of_a_table(Oid relid, bool activate)
2126 {
2127         if (IndexesAreActive(relid, true))
2128         {
2129                 if (!activate)
2130                         setRelhasindex(relid, false);
2131                 else
2132                         return false;
2133         }
2134         else
2135         {
2136                 if (activate)
2137                         reindex_relation(relid, false);
2138                 else
2139                         return false;
2140         }
2141         return true;
2142 }
2143
2144 /* --------------------------------
2145  * reindex_relation - This routine is used to recreate indexes
2146  * of a relation.
2147  * --------------------------------
2148  */
2149 bool
2150 reindex_relation(Oid relid, bool force)
2151 {
2152         Relation        indexRelation;
2153         ScanKeyData entry;
2154         HeapScanDesc scan;
2155         HeapTuple       indexTuple;
2156         bool            old,
2157                                 reindexed;
2158
2159         bool    deactivate_needed, overwrite, upd_pg_class_inplace;
2160 #ifdef OLD_FILE_NAMING
2161         overwrite = upd_pg_class_inplace = deactivate_needed = true;    
2162 #else
2163         Relation rel;
2164         overwrite = upd_pg_class_inplace = deactivate_needed = false;   
2165         /*
2166          * avoid heap_update() pg_class tuples while processing
2167          * reindex for pg_class. 
2168          */
2169         if (IsIgnoringSystemIndexes())
2170                 upd_pg_class_inplace = true;
2171         /*
2172          * ignore the indexes of the target system relation while processing
2173          * reindex.
2174          */ 
2175         rel = RelationIdGetRelation(relid);
2176         if (!IsIgnoringSystemIndexes() && IsSystemRelationName(NameStr(rel->rd_rel->relname)))
2177                 deactivate_needed = true;
2178 #ifndef ENABLE_REINDEX_NAILED_RELATIONS
2179         /* 
2180          * nailed relations are never updated.
2181          * We couldn't keep the consistency between the relation
2182          * descriptors and pg_class tuples.
2183          */
2184         if (rel->rd_isnailed)
2185         {
2186                 if (IsIgnoringSystemIndexes())
2187                 {
2188                         overwrite = true;
2189                         deactivate_needed = true;
2190                 }
2191                 else
2192                         elog(ERROR, "the target relation %u is nailed", relid);
2193         }
2194 #endif /* ENABLE_REINDEX_NAILED_RELATIONS */
2195         RelationClose(rel);
2196 #endif /* OLD_FILE_NAMING */
2197         old = SetReindexProcessing(true);
2198         if (deactivate_needed)
2199         {
2200                 if (IndexesAreActive(relid, upd_pg_class_inplace))
2201                 {
2202                         if (!force)
2203                         {
2204                                 SetReindexProcessing(old);
2205                                 return false;
2206                         }
2207                         activate_indexes_of_a_table(relid, false);
2208                         CommandCounterIncrement();
2209                 }
2210         }
2211
2212         indexRelation = heap_openr(IndexRelationName, AccessShareLock);
2213         ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid,
2214                                                    F_OIDEQ, ObjectIdGetDatum(relid));
2215         scan = heap_beginscan(indexRelation, false, SnapshotNow,
2216                                                   1, &entry);
2217         reindexed = false;
2218         while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
2219         {
2220                 Form_pg_index index = (Form_pg_index) GETSTRUCT(indexTuple);
2221
2222                 if (activate_index(index->indexrelid, true, overwrite))
2223                         reindexed = true;
2224                 else
2225                 {
2226                         reindexed = false;
2227                         break;
2228                 }
2229         }
2230         heap_endscan(scan);
2231         heap_close(indexRelation, AccessShareLock);
2232         if (reindexed)
2233         /*
2234          * Ok,we could use the reindexed indexes of the target
2235          * system relation now.
2236          */
2237         { 
2238                 if (deactivate_needed)
2239                 {
2240                         if (!overwrite && relid == RelOid_pg_class)
2241                         {
2242                                 /* 
2243                                  * For pg_class, relhasindex should be set
2244                                  * to true here in place.
2245                                  */
2246                                 setRelhasindex(relid, true);
2247                                 CommandCounterIncrement();
2248                                 /* 
2249                                  * However the following setRelhasindex()
2250                                  * is needed to keep consistency with WAL.
2251                                  */
2252                         }
2253                         setRelhasindex(relid, true);
2254                 }
2255         }
2256         SetReindexProcessing(old);
2257
2258         return reindexed;
2259 }