OSDN Git Service

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