OSDN Git Service

pgindent run.
[pg-rex/syncrep.git] / src / backend / catalog / index.c
index b6420a1..4909c2e 100644 (file)
@@ -3,12 +3,12 @@
  * index.c
  *       code to create and destroy POSTGRES index relations
  *
- * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.152 2001/05/30 20:52:32 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.196 2002/09/04 20:31:14 momjian Exp $
  *
  *
  * INTERFACE ROUTINES
 #include "bootstrap/bootstrap.h"
 #include "catalog/catalog.h"
 #include "catalog/catname.h"
+#include "catalog/dependency.h"
 #include "catalog/heap.h"
 #include "catalog/index.h"
 #include "catalog/indexing.h"
+#include "catalog/pg_constraint.h"
 #include "catalog/pg_index.h"
+#include "catalog/pg_opclass.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
-#include "commands/comment.h"
 #include "executor/executor.h"
 #include "miscadmin.h"
 #include "optimizer/clauses.h"
 #include "optimizer/prep.h"
 #include "parser/parse_func.h"
+#include "storage/sinval.h"
 #include "storage/smgr.h"
 #include "utils/builtins.h"
 #include "utils/catcache.h"
 #include "utils/fmgroids.h"
 #include "utils/inval.h"
+#include "utils/lsyscache.h"
 #include "utils/relcache.h"
 #include "utils/syscache.h"
-#include "utils/temprel.h"
+
 
 /*
  * macros used in guessing how many tuples are on a page.
        ((natts) * AVG_ATTR_SIZE + MAXALIGN(sizeof(HeapTupleHeaderData))))
 
 /* non-export function prototypes */
-static Oid GetHeapRelationOid(char *heapRelationName, char *indexRelationName,
-                                  bool istemp);
-static TupleDesc BuildFuncTupleDesc(Oid funcOid);
+static TupleDesc BuildFuncTupleDesc(Oid funcOid,
+                                  Oid *classObjectId);
 static TupleDesc ConstructTupleDescriptor(Relation heapRelation,
-                                                int numatts, AttrNumber *attNums);
-static void ConstructIndexReldesc(Relation indexRelation, Oid amoid);
-static Oid     UpdateRelationRelation(Relation indexRelation, char *temp_relname);
+                                                int numatts, AttrNumber *attNums,
+                                                Oid *classObjectId);
+static void UpdateRelationRelation(Relation indexRelation);
 static void InitializeAttributeOids(Relation indexRelation,
                                                int numatts, Oid indexoid);
 static void AppendAttributeTuples(Relation indexRelation, int numatts);
 static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
                                        IndexInfo *indexInfo,
                                        Oid *classOids,
-                                       bool islossy, bool primary);
-static void DefaultBuild(Relation heapRelation, Relation indexRelation,
-                        IndexInfo *indexInfo, Node *oldPred,
-                        IndexStrategy indexStrategy);
+                                       bool primary);
 static Oid     IndexGetRelation(Oid indexId);
 static bool activate_index(Oid indexId, bool activate, bool inplace);
 
@@ -98,44 +98,20 @@ IsReindexProcessing(void)
        return reindexing;
 }
 
-/* ----------------------------------------------------------------
- *             GetHeapRelationOid
- * ----------------------------------------------------------------
- */
-static Oid
-GetHeapRelationOid(char *heapRelationName, char *indexRelationName, bool istemp)
-{
-       Oid                     indoid;
-       Oid                     heapoid;
-
-
-       indoid = RelnameFindRelid(indexRelationName);
-
-       if ((!istemp && OidIsValid(indoid)) ||
-               (istemp && is_temp_rel_name(indexRelationName)))
-               elog(ERROR, "Cannot create index: '%s' already exists",
-                        indexRelationName);
-
-       heapoid = RelnameFindRelid(heapRelationName);
-
-       if (!OidIsValid(heapoid))
-               elog(ERROR, "Cannot create index on '%s': relation does not exist",
-                        heapRelationName);
-
-       return heapoid;
-}
-
 static TupleDesc
-BuildFuncTupleDesc(Oid funcOid)
+BuildFuncTupleDesc(Oid funcOid,
+                                  Oid *classObjectId)
 {
        TupleDesc       funcTupDesc;
        HeapTuple       tuple;
+       Oid                     keyType;
        Oid                     retType;
+       Form_pg_type typeTup;
 
        /*
         * Allocate and zero a tuple descriptor for a one-column tuple.
         */
-       funcTupDesc = CreateTemplateTupleDesc(1);
+       funcTupDesc = CreateTemplateTupleDesc(1, false);
        funcTupDesc->attrs[0] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
        MemSet(funcTupDesc->attrs[0], 0, ATTRIBUTE_TUPLE_SIZE);
 
@@ -158,25 +134,41 @@ BuildFuncTupleDesc(Oid funcOid)
        ReleaseSysCache(tuple);
 
        /*
-        * Lookup the return type in pg_type for the type length etc.
+        * Check the opclass to see if it provides a keytype (overriding the
+        * function result type).
+        */
+       tuple = SearchSysCache(CLAOID,
+                                                  ObjectIdGetDatum(classObjectId[0]),
+                                                  0, 0, 0);
+       if (!HeapTupleIsValid(tuple))
+               elog(ERROR, "Opclass %u does not exist", classObjectId[0]);
+       keyType = ((Form_pg_opclass) GETSTRUCT(tuple))->opckeytype;
+       ReleaseSysCache(tuple);
+
+       if (!OidIsValid(keyType))
+               keyType = retType;
+
+       /*
+        * Lookup the key type in pg_type for the type length etc.
         */
        tuple = SearchSysCache(TYPEOID,
-                                                  ObjectIdGetDatum(retType),
+                                                  ObjectIdGetDatum(keyType),
                                                   0, 0, 0);
        if (!HeapTupleIsValid(tuple))
-               elog(ERROR, "Type %u does not exist", retType);
+               elog(ERROR, "Type %u does not exist", keyType);
+       typeTup = (Form_pg_type) GETSTRUCT(tuple);
 
        /*
         * Assign some of the attributes values. Leave the rest as 0.
         */
-       funcTupDesc->attrs[0]->attlen = ((Form_pg_type) GETSTRUCT(tuple))->typlen;
-       funcTupDesc->attrs[0]->atttypid = retType;
        funcTupDesc->attrs[0]->attnum = 1;
-       funcTupDesc->attrs[0]->attbyval = ((Form_pg_type) GETSTRUCT(tuple))->typbyval;
+       funcTupDesc->attrs[0]->atttypid = keyType;
+       funcTupDesc->attrs[0]->attlen = typeTup->typlen;
+       funcTupDesc->attrs[0]->attbyval = typeTup->typbyval;
        funcTupDesc->attrs[0]->attcacheoff = -1;
        funcTupDesc->attrs[0]->atttypmod = -1;
-       funcTupDesc->attrs[0]->attstorage = ((Form_pg_type) GETSTRUCT(tuple))->typstorage;
-       funcTupDesc->attrs[0]->attalign = ((Form_pg_type) GETSTRUCT(tuple))->typalign;
+       funcTupDesc->attrs[0]->attstorage = typeTup->typstorage;
+       funcTupDesc->attrs[0]->attalign = typeTup->typalign;
 
        ReleaseSysCache(tuple);
 
@@ -192,7 +184,8 @@ BuildFuncTupleDesc(Oid funcOid)
 static TupleDesc
 ConstructTupleDescriptor(Relation heapRelation,
                                                 int numatts,
-                                                AttrNumber *attNums)
+                                                AttrNumber *attNums,
+                                                Oid *classObjectId)
 {
        TupleDesc       heapTupDesc;
        TupleDesc       indexTupDesc;
@@ -206,7 +199,7 @@ ConstructTupleDescriptor(Relation heapRelation,
         * allocate the new tuple descriptor
         */
 
-       indexTupDesc = CreateTemplateTupleDesc(numatts);
+       indexTupDesc = CreateTemplateTupleDesc(numatts, false);
 
        /* ----------------
         *        for each attribute we are indexing, obtain its attribute
@@ -219,6 +212,8 @@ ConstructTupleDescriptor(Relation heapRelation,
                AttrNumber      atnum;          /* attributeNumber[attributeOffset] */
                Form_pg_attribute from;
                Form_pg_attribute to;
+               HeapTuple       tuple;
+               Oid                     keyType;
 
                /*
                 * get the attribute number and make sure it's valid; determine
@@ -231,7 +226,8 @@ ConstructTupleDescriptor(Relation heapRelation,
                        /*
                         * here we are indexing on a system attribute (-1...-n)
                         */
-                       from = SystemAttributeDefinition(atnum);
+                       from = SystemAttributeDefinition(atnum,
+                                                                          heapRelation->rd_rel->relhasoids);
                }
                else
                {
@@ -239,7 +235,7 @@ ConstructTupleDescriptor(Relation heapRelation,
                         * here we are indexing on a normal attribute (1...n)
                         */
                        if (atnum > natts)
-                               elog(ERROR, "Cannot create index: attribute %d does not exist",
+                               elog(ERROR, "cannot create index: column %d does not exist",
                                         atnum);
 
                        from = heapTupDesc->attrs[AttrNumberGetAttrOffset(atnum)];
@@ -263,6 +259,7 @@ ConstructTupleDescriptor(Relation heapRelation,
                to->attcacheoff = -1;
                to->attnotnull = false;
                to->atthasdef = false;
+               to->attisinherited = false;
 
                /*
                 * We do not yet have the correct relation OID for the index, so
@@ -270,142 +267,75 @@ ConstructTupleDescriptor(Relation heapRelation,
                 * fix it later.
                 */
                to->attrelid = InvalidOid;
-       }
 
-       return indexTupDesc;
-}
-
-/* ----------------------------------------------------------------
- * AccessMethodObjectIdGetForm
- *             Returns an access method tuple given its object identifier,
- *             or NULL if no such AM tuple can be found.
- *
- * Scanning is done using CurrentMemoryContext as working storage,
- * but the returned tuple will be allocated in resultCxt (which is
- * typically CacheMemoryContext).
- *
- * There was a note here about adding indexing, but I don't see a need
- * for it.     There are so few tuples in pg_am that an indexscan would
- * surely be slower.
- * ----------------------------------------------------------------
- */
-Form_pg_am
-AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
-                                                       MemoryContext resultCxt)
-{
-       Relation        pg_am_desc;
-       HeapScanDesc pg_am_scan;
-       HeapTuple       pg_am_tuple;
-       ScanKeyData key;
-       Form_pg_am      aform;
-
-       /*
-        * form a scan key for the pg_am relation
-        */
-       ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
-                                                  F_OIDEQ,
-                                                  ObjectIdGetDatum(accessMethodObjectId));
-
-       /*
-        * fetch the desired access method tuple
-        */
-       pg_am_desc = heap_openr(AccessMethodRelationName, AccessShareLock);
-       pg_am_scan = heap_beginscan(pg_am_desc, 0, SnapshotNow, 1, &key);
+               /*
+                * Check the opclass to see if it provides a keytype (overriding
+                * the attribute type).
+                */
+               tuple = SearchSysCache(CLAOID,
+                                                          ObjectIdGetDatum(classObjectId[i]),
+                                                          0, 0, 0);
+               if (!HeapTupleIsValid(tuple))
+                       elog(ERROR, "Opclass %u does not exist", classObjectId[i]);
+               keyType = ((Form_pg_opclass) GETSTRUCT(tuple))->opckeytype;
+               ReleaseSysCache(tuple);
 
-       pg_am_tuple = heap_getnext(pg_am_scan, 0);
+               if (OidIsValid(keyType) && keyType != to->atttypid)
+               {
+                       /* index value and heap value have different types */
+                       Form_pg_type typeTup;
 
-       /*
-        * return NULL if not found
-        */
-       if (!HeapTupleIsValid(pg_am_tuple))
-       {
-               heap_endscan(pg_am_scan);
-               heap_close(pg_am_desc, AccessShareLock);
-               return NULL;
+                       tuple = SearchSysCache(TYPEOID,
+                                                                  ObjectIdGetDatum(keyType),
+                                                                  0, 0, 0);
+                       if (!HeapTupleIsValid(tuple))
+                               elog(ERROR, "Type %u does not exist", keyType);
+                       typeTup = (Form_pg_type) GETSTRUCT(tuple);
+
+                       to->atttypid = keyType;
+                       to->atttypmod = -1;
+                       to->attlen = typeTup->typlen;
+                       to->attbyval = typeTup->typbyval;
+                       to->attalign = typeTup->typalign;
+                       to->attstorage = typeTup->typstorage;
+
+                       ReleaseSysCache(tuple);
+               }
        }
 
-       /*
-        * if found AM tuple, then copy it into resultCxt and return the copy
-        */
-       aform = (Form_pg_am) MemoryContextAlloc(resultCxt, sizeof *aform);
-       memcpy(aform, GETSTRUCT(pg_am_tuple), sizeof *aform);
-
-       heap_endscan(pg_am_scan);
-       heap_close(pg_am_desc, AccessShareLock);
-
-       return aform;
-}
-
-/* ----------------------------------------------------------------
- *             ConstructIndexReldesc
- * ----------------------------------------------------------------
- */
-static void
-ConstructIndexReldesc(Relation indexRelation, Oid amoid)
-{
-       indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid,
-                                                                                                        CacheMemoryContext);
-
-       /*
-        * XXX missing the initialization of some other fields
-        */
-
-       indexRelation->rd_rel->relowner = GetUserId();
-
-       indexRelation->rd_rel->relam = amoid;
-       indexRelation->rd_rel->reltuples = 1;           /* XXX */
-       indexRelation->rd_rel->relkind = RELKIND_INDEX;
+       return indexTupDesc;
 }
 
 /* ----------------------------------------------------------------
  *             UpdateRelationRelation
  * ----------------------------------------------------------------
  */
-static Oid
-UpdateRelationRelation(Relation indexRelation, char *temp_relname)
+static void
+UpdateRelationRelation(Relation indexRelation)
 {
        Relation        pg_class;
        HeapTuple       tuple;
-       Oid                     tupleOid;
-       Relation        idescs[Num_pg_class_indices];
 
        pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
 
        /* XXX Natts_pg_class_fixed is a hack - see pg_class.h */
        tuple = heap_addheader(Natts_pg_class_fixed,
+                                                  true,
                                                   CLASS_TUPLE_SIZE,
-                                                  (char *) indexRelation->rd_rel);
+                                                  (void *) indexRelation->rd_rel);
 
        /*
-        * the new tuple must have the same oid as the relcache entry for the
-        * index.  sure would be embarrassing to do this sort of thing in
-        * polite company.
+        * the new tuple must have the oid already chosen for the index. sure
+        * would be embarrassing to do this sort of thing in polite company.
         */
-       tuple->t_data->t_oid = RelationGetRelid(indexRelation);
-       heap_insert(pg_class, tuple);
+       HeapTupleSetOid(tuple, RelationGetRelid(indexRelation));
+       simple_heap_insert(pg_class, tuple);
 
-       if (temp_relname)
-               create_temp_relation(temp_relname, tuple);
+       /* update the system catalog indexes */
+       CatalogUpdateIndexes(pg_class, tuple);
 
-       /*
-        * During normal processing, we need to make sure that the system
-        * catalog indices are correct.  Bootstrap (initdb) time doesn't
-        * require this, because we make sure that the indices are correct
-        * just before exiting.
-        */
-
-       if (!IsIgnoringSystemIndexes())
-       {
-               CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
-               CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, tuple);
-               CatalogCloseIndices(Num_pg_class_indices, idescs);
-       }
-
-       tupleOid = tuple->t_data->t_oid;
        heap_freetuple(tuple);
        heap_close(pg_class, RowExclusiveLock);
-
-       return tupleOid;
 }
 
 /* ----------------------------------------------------------------
@@ -428,113 +358,53 @@ InitializeAttributeOids(Relation indexRelation,
 
 /* ----------------------------------------------------------------
  *             AppendAttributeTuples
- *
- *             XXX For now, only change the ATTNUM attribute value
  * ----------------------------------------------------------------
  */
 static void
 AppendAttributeTuples(Relation indexRelation, int numatts)
 {
        Relation        pg_attribute;
-       HeapTuple       init_tuple,
-                               cur_tuple = NULL,
-                               new_tuple;
-       bool            hasind;
-       Relation        idescs[Num_pg_attr_indices];
-       Datum           value[Natts_pg_attribute];
-       char            nullv[Natts_pg_attribute];
-       char            replace[Natts_pg_attribute];
+       CatalogIndexState indstate;
        TupleDesc       indexTupDesc;
+       HeapTuple       new_tuple;
        int                     i;
 
        /*
-        * open the attribute relation
+        * open the attribute relation and its indexes
         */
        pg_attribute = heap_openr(AttributeRelationName, RowExclusiveLock);
 
-       /*
-        * initialize *null, *replace and *value
-        */
-       MemSet(nullv, ' ', Natts_pg_attribute);
-       MemSet(replace, ' ', Natts_pg_attribute);
-
-       /* ----------
-        *      create the first attribute tuple.
-        *      XXX For now, only change the ATTNUM attribute value
-        * ----------
-        */
-       replace[Anum_pg_attribute_attnum - 1] = 'r';
-       replace[Anum_pg_attribute_attcacheoff - 1] = 'r';
-
-       value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(1);
-       value[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1);
-
-       init_tuple = heap_addheader(Natts_pg_attribute,
-                                                               ATTRIBUTE_TUPLE_SIZE,
-                                                        (char *) (indexRelation->rd_att->attrs[0]));
-
-       hasind = false;
-       if (!IsIgnoringSystemIndexes() && pg_attribute->rd_rel->relhasindex)
-       {
-               hasind = true;
-               CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
-       }
-
-       /*
-        * insert the first attribute tuple.
-        */
-       cur_tuple = heap_modifytuple(init_tuple,
-                                                                pg_attribute,
-                                                                value,
-                                                                nullv,
-                                                                replace);
-       heap_freetuple(init_tuple);
-
-       heap_insert(pg_attribute, cur_tuple);
-       if (hasind)
-               CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, cur_tuple);
+       indstate = CatalogOpenIndexes(pg_attribute);
 
        /*
-        * now we use the information in the index cur_tuple descriptor to
-        * form the remaining attribute tuples.
+        * insert data from new index's tupdesc into pg_attribute
         */
        indexTupDesc = RelationGetDescr(indexRelation);
 
-       for (i = 1; i < numatts; i += 1)
+       for (i = 0; i < numatts; i++)
        {
-
                /*
-                * process the remaining attributes...
+                * There used to be very grotty code here to set these fields, but
+                * I think it's unnecessary.  They should be set already.
                 */
-               memmove(GETSTRUCT(cur_tuple),
-                               (char *) indexTupDesc->attrs[i],
-                               ATTRIBUTE_TUPLE_SIZE);
+               Assert(indexTupDesc->attrs[i]->attnum == i + 1);
+               Assert(indexTupDesc->attrs[i]->attcacheoff == -1);
 
-               value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(i + 1);
+               new_tuple = heap_addheader(Natts_pg_attribute,
+                                                                  false,
+                                                                  ATTRIBUTE_TUPLE_SIZE,
+                                                                  (void *) indexTupDesc->attrs[i]);
 
-               new_tuple = heap_modifytuple(cur_tuple,
-                                                                        pg_attribute,
-                                                                        value,
-                                                                        nullv,
-                                                                        replace);
-               heap_freetuple(cur_tuple);
+               simple_heap_insert(pg_attribute, new_tuple);
 
-               heap_insert(pg_attribute, new_tuple);
-               if (hasind)
-                       CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, new_tuple);
+               CatalogIndexInsert(indstate, new_tuple);
 
-               /*
-                * ModifyHeapTuple returns a new copy of a cur_tuple so we free
-                * the original and use the copy..
-                */
-               cur_tuple = new_tuple;
+               heap_freetuple(new_tuple);
        }
 
-       if (cur_tuple)
-               heap_freetuple(cur_tuple);
+       CatalogCloseIndexes(indstate);
+
        heap_close(pg_attribute, RowExclusiveLock);
-       if (hasind)
-               CatalogCloseIndices(Num_pg_attr_indices, idescs);
 }
 
 /* ----------------------------------------------------------------
@@ -546,7 +416,6 @@ UpdateIndexRelation(Oid indexoid,
                                        Oid heapoid,
                                        IndexInfo *indexInfo,
                                        Oid *classOids,
-                                       bool islossy,
                                        bool primary)
 {
        Form_pg_index indexForm;
@@ -557,13 +426,12 @@ UpdateIndexRelation(Oid indexoid,
        Relation        pg_index;
        HeapTuple       tuple;
        int                     i;
-       Relation        idescs[Num_pg_index_indices];
 
        /*
         * allocate a Form_pg_index big enough to hold the index-predicate (if
         * any) in string form
         */
-       if (indexInfo->ii_Predicate != NULL)
+       if (indexInfo->ii_Predicate != NIL)
        {
                predString = nodeToString(indexInfo->ii_Predicate);
                predText = DatumGetTextP(DirectFunctionCall1(textin,
@@ -585,9 +453,7 @@ UpdateIndexRelation(Oid indexoid,
        indexForm->indexrelid = indexoid;
        indexForm->indrelid = heapoid;
        indexForm->indproc = indexInfo->ii_FuncOid;
-       indexForm->indisclustered = false;                      /* not used */
-       indexForm->indislossy = islossy;
-       indexForm->indhaskeytype = true;                        /* used by GIST */
+       indexForm->indisclustered = false;      /* not clustered, yet */
        indexForm->indisunique = indexInfo->ii_Unique;
        indexForm->indisprimary = primary;
        memcpy((char *) &indexForm->indpred, (char *) predText, predLen);
@@ -612,23 +478,17 @@ UpdateIndexRelation(Oid indexoid,
         * form a tuple to insert into pg_index
         */
        tuple = heap_addheader(Natts_pg_index,
+                                                  false,
                                                   itupLen,
-                                                  (char *) indexForm);
+                                                  (void *) indexForm);
 
        /*
-        * insert the tuple into the pg_index
+        * insert the tuple into the pg_index catalog
         */
-       heap_insert(pg_index, tuple);
+       simple_heap_insert(pg_index, tuple);
 
-       /*
-        * add index tuples for it
-        */
-       if (!IsIgnoringSystemIndexes())
-       {
-               CatalogOpenIndices(Num_pg_index_indices, Name_pg_index_indices, idescs);
-               CatalogIndexInsert(idescs, Num_pg_index_indices, pg_index, tuple);
-               CatalogCloseIndices(Num_pg_index_indices, idescs);
-       }
+       /* update the indexes on pg_index */
+       CatalogUpdateIndexes(pg_index, tuple);
 
        /*
         * close the relation and free the tuple
@@ -639,225 +499,99 @@ UpdateIndexRelation(Oid indexoid,
        heap_freetuple(tuple);
 }
 
-/* ----------------------------------------------------------------
- *             UpdateIndexPredicate
- * ----------------------------------------------------------------
- */
-void
-UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
-{
-       Node       *newPred;
-       char       *predString;
-       text       *predText;
-       Relation        pg_index;
-       HeapTuple       tuple;
-       HeapTuple       newtup;
-       int                     i;
-       Datum           values[Natts_pg_index];
-       char            nulls[Natts_pg_index];
-       char            replace[Natts_pg_index];
-
-       /*
-        * Construct newPred as a CNF expression equivalent to the OR of the
-        * original partial-index predicate ("oldPred") and the extension
-        * predicate ("predicate").
-        *
-        * This should really try to process the result to change things like
-        * "a>2 OR a>1" to simply "a>1", but for now all it does is make sure
-        * that if the extension predicate is NULL (i.e., it is being extended
-        * to be a complete index), then newPred will be NULL - in effect,
-        * changing "a>2 OR TRUE" to "TRUE". --Nels, Jan '93
-        */
-       newPred = NULL;
-       if (predicate != NULL)
-       {
-               newPred = (Node *) make_orclause(lcons(make_andclause((List *) predicate),
-                                                                 lcons(make_andclause((List *) oldPred),
-                                                                               NIL)));
-               newPred = (Node *) cnfify((Expr *) newPred, true);
-       }
-
-       /* translate the index-predicate to string form */
-       if (newPred != NULL)
-       {
-               predString = nodeToString(newPred);
-               predText = DatumGetTextP(DirectFunctionCall1(textin,
-                                                                                  CStringGetDatum(predString)));
-               pfree(predString);
-       }
-       else
-               predText = DatumGetTextP(DirectFunctionCall1(textin,
-                                                                                                  CStringGetDatum("")));
-
-       /* open the index system catalog relation */
-       pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
-
-       tuple = SearchSysCache(INDEXRELID,
-                                                  ObjectIdGetDatum(indexoid),
-                                                  0, 0, 0);
-       if (!HeapTupleIsValid(tuple))
-               elog(ERROR, "UpdateIndexPredicate: cache lookup failed for index %u",
-                        indexoid);
-
-       for (i = 0; i < Natts_pg_index; i++)
-       {
-               nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' ';
-               replace[i] = ' ';
-               values[i] = (Datum) NULL;
-       }
-
-       replace[Anum_pg_index_indpred - 1] = 'r';
-       values[Anum_pg_index_indpred - 1] = (Datum) predText;
-
-       newtup = heap_modifytuple(tuple, pg_index, values, nulls, replace);
-
-       simple_heap_update(pg_index, &newtup->t_self, newtup);
-
-       heap_freetuple(newtup);
-       ReleaseSysCache(tuple);
-
-       heap_close(pg_index, RowExclusiveLock);
-       pfree(predText);
-}
-
-/* ----------------------------------------------------------------
- *             InitIndexStrategy
- * ----------------------------------------------------------------
- */
-void
-InitIndexStrategy(int numatts,
-                                 Relation indexRelation,
-                                 Oid accessMethodObjectId)
-{
-       IndexStrategy strategy;
-       RegProcedure *support;
-       uint16          amstrategies;
-       uint16          amsupport;
-       Oid                     attrelid;
-       Size            strsize;
-
-       /*
-        * get information from the index relation descriptor
-        */
-       attrelid = indexRelation->rd_att->attrs[0]->attrelid;
-       amstrategies = indexRelation->rd_am->amstrategies;
-       amsupport = indexRelation->rd_am->amsupport;
-
-       /*
-        * get the size of the strategy
-        */
-       strsize = AttributeNumberGetIndexStrategySize(numatts, amstrategies);
-
-       /*
-        * allocate the new index strategy structure
-        *
-        * the index strategy has to be allocated in the same context as the
-        * relation descriptor cache or else it will be lost at the end of the
-        * transaction.
-        */
-       if (!CacheMemoryContext)
-               CreateCacheMemoryContext();
-
-       strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
-                                                                                                 strsize);
-
-       if (amsupport > 0)
-       {
-               strsize = numatts * (amsupport * sizeof(RegProcedure));
-               support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext,
-                                                                                                         strsize);
-       }
-       else
-               support = (RegProcedure *) NULL;
-
-       /*
-        * fill in the index strategy structure with information from the
-        * catalogs.  First we must advance the command counter so that we
-        * will see the newly-entered index catalog tuples.
-        */
-       CommandCounterIncrement();
-
-       IndexSupportInitialize(strategy, support,
-                                                  &indexRelation->rd_uniqueindex,
-                                                  attrelid, accessMethodObjectId,
-                                                  amstrategies, amsupport, numatts);
-
-       /*
-        * store the strategy information in the index reldesc
-        */
-       RelationSetIndexSupport(indexRelation, strategy, support);
-}
-
 
 /* ----------------------------------------------------------------
  *             index_create
+ *
+ * Returns OID of the created index.
  * ----------------------------------------------------------------
  */
-void
-index_create(char *heapRelationName,
-                        char *indexRelationName,
+Oid
+index_create(Oid heapRelationId,
+                        const char *indexRelationName,
                         IndexInfo *indexInfo,
                         Oid accessMethodObjectId,
                         Oid *classObjectId,
-                        bool islossy,
                         bool primary,
+                        bool isconstraint,
                         bool allow_system_table_mods)
 {
        Relation        heapRelation;
        Relation        indexRelation;
        TupleDesc       indexTupDesc;
-       Oid                     heapoid;
+       bool            shared_relation;
+       Oid                     namespaceId;
        Oid                     indexoid;
-       bool            istemp = is_temp_rel_name(heapRelationName);
-       char       *temp_relname = NULL;
+       int                     i;
 
        SetReindexProcessing(false);
 
        /*
+        * Only SELECT ... FOR UPDATE are allowed while doing this
+        */
+       heapRelation = heap_open(heapRelationId, ShareLock);
+
+       /*
+        * The index will be in the same namespace as its parent table, and is
+        * shared across databases if and only if the parent is.
+        */
+       namespaceId = RelationGetNamespace(heapRelation);
+       shared_relation = heapRelation->rd_rel->relisshared;
+
+       /*
         * check parameters
         */
        if (indexInfo->ii_NumIndexAttrs < 1 ||
                indexInfo->ii_NumKeyAttrs < 1)
-               elog(ERROR, "must index at least one attribute");
+               elog(ERROR, "must index at least one column");
 
-       if (heapRelationName && !allow_system_table_mods &&
-               IsSystemRelationName(heapRelationName) && IsNormalProcessingMode())
+       if (!allow_system_table_mods &&
+               IsSystemRelation(heapRelation) &&
+               IsNormalProcessingMode())
                elog(ERROR, "User-defined indexes on system catalogs are not supported");
 
        /*
-        * get heap relation oid and open the heap relation
+        * We cannot allow indexing a shared relation after initdb (because
+        * there's no way to make the entry in other databases' pg_class).
+        * Unfortunately we can't distinguish initdb from a manually started
+        * standalone backend.  However, we can at least prevent this mistake
+        * under normal multi-user operation.
         */
-       heapoid = GetHeapRelationOid(heapRelationName, indexRelationName, istemp);
+       if (shared_relation && IsUnderPostmaster)
+               elog(ERROR, "Shared indexes cannot be created after initdb");
 
-       /*
-        * Only SELECT ... FOR UPDATE are allowed while doing this
-        */
-       heapRelation = heap_open(heapoid, ShareLock);
+       if (get_relname_relid(indexRelationName, namespaceId))
+               elog(ERROR, "relation named \"%s\" already exists",
+                        indexRelationName);
 
        /*
-        * construct new tuple descriptor
+        * construct tuple descriptor for index tuples
         */
        if (OidIsValid(indexInfo->ii_FuncOid))
-               indexTupDesc = BuildFuncTupleDesc(indexInfo->ii_FuncOid);
+               indexTupDesc = BuildFuncTupleDesc(indexInfo->ii_FuncOid,
+                                                                                 classObjectId);
        else
                indexTupDesc = ConstructTupleDescriptor(heapRelation,
                                                                                                indexInfo->ii_NumKeyAttrs,
-                                                                                  indexInfo->ii_KeyAttrNumbers);
+                                                                                       indexInfo->ii_KeyAttrNumbers,
+                                                                                               classObjectId);
 
-       if (istemp)
-       {
-               /* save user relation name because heap_create changes it */
-               temp_relname = pstrdup(indexRelationName);              /* save original value */
-               indexRelationName = palloc(NAMEDATALEN);
-               strcpy(indexRelationName, temp_relname);                /* heap_create will
-                                                                                                                * change this */
-       }
+       indexTupDesc->tdhasoid = false;
 
        /*
-        * create the index relation
+        * create the index relation's relcache entry and physical disk file.
+        * (If we fail further down, it's the smgr's responsibility to remove
+        * the disk file again.)
         */
-       indexRelation = heap_create(indexRelationName, indexTupDesc,
-                                                               istemp, false, allow_system_table_mods);
+       indexRelation = heap_create(indexRelationName,
+                                                               namespaceId,
+                                                               indexTupDesc,
+                                                               shared_relation,
+                                                               true,
+                                                               allow_system_table_mods);
+
+       /* Fetch the relation OID assigned by heap_create */
+       indexoid = RelationGetRelid(indexRelation);
 
        /*
         * Obtain exclusive lock on it.  Although no other backends can see it
@@ -867,23 +601,20 @@ index_create(char *heapRelationName,
        LockRelation(indexRelation, AccessExclusiveLock);
 
        /*
-        * construct the index relation descriptor
+        * Fill in fields of the index's pg_class entry that are not set
+        * correctly by heap_create.
         *
-        * XXX should have a proper way to create cataloged relations
+        * XXX should have a cleaner way to create cataloged indexes
         */
-       ConstructIndexReldesc(indexRelation, accessMethodObjectId);
-
-       /* ----------------
-        *        add index to catalogs
-        *        (append RELATION tuple)
-        * ----------------
-        */
-       indexoid = UpdateRelationRelation(indexRelation, temp_relname);
+       indexRelation->rd_rel->relowner = GetUserId();
+       indexRelation->rd_rel->relam = accessMethodObjectId;
+       indexRelation->rd_rel->relkind = RELKIND_INDEX;
+       indexRelation->rd_rel->relhasoids = false;
 
        /*
-        * We create the disk file for this relation here
+        * store index's pg_class entry
         */
-       heap_storage_create(indexRelation);
+       UpdateRelationRelation(indexRelation);
 
        /*
         * now update the object id's of all the attribute tuple forms in the
@@ -906,19 +637,117 @@ index_create(char *heapRelationName,
         *        (Or, could define a rule to maintain the predicate) --Nels, Feb '92
         * ----------------
         */
-       UpdateIndexRelation(indexoid, heapoid, indexInfo,
-                                               classObjectId, islossy, primary);
+       UpdateIndexRelation(indexoid, heapRelationId, indexInfo,
+                                               classObjectId, primary);
+
+       /*
+        * Register constraint and dependencies for the index.
+        *
+        * If the index is from a CONSTRAINT clause, construct a pg_constraint
+        * entry.  The index is then linked to the constraint, which in turn
+        * is linked to the table.      If it's not a CONSTRAINT, make the
+        * dependency directly on the table.
+        *
+        * We don't need a dependency on the namespace, because there'll be an
+        * indirect dependency via our parent table.
+        *
+        * During bootstrap we can't register any dependencies, and we don't try
+        * to make a constraint either.
+        */
+       if (!IsBootstrapProcessingMode())
+       {
+               ObjectAddress myself,
+                                       referenced;
+
+               myself.classId = RelOid_pg_class;
+               myself.objectId = indexoid;
+               myself.objectSubId = 0;
+
+               if (isconstraint)
+               {
+                       char            constraintType;
+                       Oid                     conOid;
+
+                       if (primary)
+                               constraintType = CONSTRAINT_PRIMARY;
+                       else if (indexInfo->ii_Unique)
+                               constraintType = CONSTRAINT_UNIQUE;
+                       else
+                       {
+                               elog(ERROR, "index_create: constraint must be PRIMARY or UNIQUE");
+                               constraintType = 0;             /* keep compiler quiet */
+                       }
+
+                       conOid = CreateConstraintEntry(indexRelationName,
+                                                                                  namespaceId,
+                                                                                  constraintType,
+                                                                                  false,               /* isDeferrable */
+                                                                                  false,               /* isDeferred */
+                                                                                  heapRelationId,
+                                                                                  indexInfo->ii_KeyAttrNumbers,
+                                                                                  indexInfo->ii_NumKeyAttrs,
+                                                                                  InvalidOid,  /* no domain */
+                                                                                  InvalidOid,  /* no foreign key */
+                                                                                  NULL,
+                                                                                  0,
+                                                                                  ' ',
+                                                                                  ' ',
+                                                                                  ' ',
+                                                                                  NULL,                /* no check constraint */
+                                                                                  NULL,
+                                                                                  NULL);
+
+                       referenced.classId = get_system_catalog_relid(ConstraintRelationName);
+                       referenced.objectId = conOid;
+                       referenced.objectSubId = 0;
+
+                       recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
+               }
+               else
+               {
+                       for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
+                       {
+                               referenced.classId = RelOid_pg_class;
+                               referenced.objectId = heapRelationId;
+                               referenced.objectSubId = indexInfo->ii_KeyAttrNumbers[i];
+
+                               recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
+                       }
+               }
+
+               /* Store dependency on operator classes */
+               referenced.classId = get_system_catalog_relid(OperatorClassRelationName);
+               for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
+               {
+                       referenced.objectId = classObjectId[i];
+                       referenced.objectSubId = 0;
+
+                       recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+               }
+
+               /* Store the dependency on the function (if appropriate) */
+               if (OidIsValid(indexInfo->ii_FuncOid))
+               {
+                       referenced.classId = RelOid_pg_proc;
+                       referenced.objectId = indexInfo->ii_FuncOid;
+                       referenced.objectSubId = 0;
+
+                       recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+               }
+       }
 
        /*
-        * initialize the index strategy
+        * Fill in the index strategy structure with information from the
+        * catalogs.  First we must advance the command counter so that we
+        * will see the newly-entered index catalog tuples.
         */
-       InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
-                                         indexRelation,
-                                         accessMethodObjectId);
+       CommandCounterIncrement();
+
+       RelationInitIndexAccessInfo(indexRelation);
 
        /*
         * If this is bootstrap (initdb) time, then we don't actually fill in
-        * the index yet.  We'll be creating more indices and classes later,
+        * the index yet.  We'll be creating more indexes and classes later,
         * so we delay filling them in until just before we're done with
         * bootstrapping.  Otherwise, we call the routine that constructs the
         * index.
@@ -930,18 +759,20 @@ index_create(char *heapRelationName,
         */
        if (IsBootstrapProcessingMode())
        {
-               index_register(heapRelationName, indexRelationName, indexInfo);
+               index_register(heapRelationId, indexoid, indexInfo);
                /* XXX shouldn't we close the heap and index rels here? */
        }
        else
-               index_build(heapRelation, indexRelation, indexInfo, NULL);
+               index_build(heapRelation, indexRelation, indexInfo);
+
+       return indexoid;
 }
 
-/* ----------------------------------------------------------------
- *
+/*
  *             index_drop
  *
- * ----------------------------------------------------------------
+ * NOTE: this routine should now only be called through performDeletion(),
+ * else associated dependencies won't be cleaned up.
  */
 void
 index_drop(Oid indexId)
@@ -950,10 +781,7 @@ index_drop(Oid indexId)
        Relation        userHeapRelation;
        Relation        userIndexRelation;
        Relation        indexRelation;
-       Relation        relationRelation;
-       Relation        attributeRelation;
        HeapTuple       tuple;
-       int16           attnum;
        int                     i;
 
        Assert(OidIsValid(indexId));
@@ -961,12 +789,14 @@ index_drop(Oid indexId)
        /*
         * To drop an index safely, we must grab exclusive lock on its parent
         * table; otherwise there could be other backends using the index!
-        * Exclusive lock on the index alone is insufficient because the index
-        * access routines are a little slipshod about obtaining adequate
-        * locking (see ExecOpenIndices()).  We do grab exclusive lock on the
-        * index too, just to be safe.  Both locks must be held till end of
-        * transaction, else other backends will still see this index in
-        * pg_index.
+        * Exclusive lock on the index alone is insufficient because another
+        * backend might be in the midst of devising a query plan that will
+        * use the index.  The parser and planner take care to hold an
+        * appropriate lock on the parent table while working, but having them
+        * hold locks on all the indexes too seems overly complex.      We do grab
+        * exclusive lock on the index too, just to be safe. Both locks must
+        * be held till end of transaction, else other backends will still see
+        * this index in pg_index.
         */
        heapId = IndexGetRelation(indexId);
        userHeapRelation = heap_open(heapId, AccessExclusiveLock);
@@ -975,76 +805,30 @@ index_drop(Oid indexId)
        LockRelation(userIndexRelation, AccessExclusiveLock);
 
        /*
-        * Note: unlike heap_drop_with_catalog, we do not need to prevent
-        * deletion of system indexes here; that's checked for upstream. If we
-        * did check it here, deletion of TOAST tables would fail...
-        */
-
-       /*
-        * fix DESCRIPTION relation
-        */
-       DeleteComments(indexId);
-
-       /*
         * fix RELATION relation
         */
-       relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
-
-       /* Remove the pg_class tuple for the index itself */
-       tuple = SearchSysCacheCopy(RELOID,
-                                                          ObjectIdGetDatum(indexId),
-                                                          0, 0, 0);
-       if (!HeapTupleIsValid(tuple))
-               elog(ERROR, "index_drop: cache lookup failed for index %u",
-                        indexId);
-
-       simple_heap_delete(relationRelation, &tuple->t_self);
-       heap_freetuple(tuple);
-
-       /*
-        * Update the pg_class tuple for the owning relation.  We are
-        * presently too lazy to attempt to compute the new correct value of
-        * relhasindex (the next VACUUM will fix it if necessary).      But we
-        * must send out a shared-cache-inval notice on the owning relation to
-        * ensure other backends update their relcache lists of indexes.  So,
-        * unconditionally do setRelhasindex(true).
-        */
-       setRelhasindex(heapId, true);
-
-       heap_close(relationRelation, RowExclusiveLock);
+       DeleteRelationTuple(indexId);
 
        /*
         * fix ATTRIBUTE relation
         */
-       attributeRelation = heap_openr(AttributeRelationName, RowExclusiveLock);
-
-       attnum = 1;                                     /* indexes start at 1 */
-
-       while (HeapTupleIsValid(tuple = SearchSysCacheCopy(ATTNUM,
-                                                                                          ObjectIdGetDatum(indexId),
-                                                                                                  Int16GetDatum(attnum),
-                                                                                                          0, 0)))
-       {
-               simple_heap_delete(attributeRelation, &tuple->t_self);
-               heap_freetuple(tuple);
-               attnum++;
-       }
-       heap_close(attributeRelation, RowExclusiveLock);
+       DeleteAttributeTuples(indexId);
 
        /*
         * fix INDEX relation
         */
        indexRelation = heap_openr(IndexRelationName, RowExclusiveLock);
 
-       tuple = SearchSysCacheCopy(INDEXRELID,
-                                                          ObjectIdGetDatum(indexId),
-                                                          0, 0, 0);
+       tuple = SearchSysCache(INDEXRELID,
+                                                  ObjectIdGetDatum(indexId),
+                                                  0, 0, 0);
        if (!HeapTupleIsValid(tuple))
                elog(ERROR, "index_drop: cache lookup failed for index %u",
                         indexId);
 
        simple_heap_delete(indexRelation, &tuple->t_self);
-       heap_freetuple(tuple);
+
+       ReleaseSysCache(tuple);
        heap_close(indexRelation, RowExclusiveLock);
 
        /*
@@ -1057,15 +841,22 @@ index_drop(Oid indexId)
        smgrunlink(DEFAULT_SMGR, userIndexRelation);
 
        /*
+        * We are presently too lazy to attempt to compute the new correct
+        * value of relhasindex (the next VACUUM will fix it if necessary).
+        * So there is no need to update the pg_class tuple for the owning
+        * relation. But we must send out a shared-cache-inval notice on the
+        * owning relation to ensure other backends update their relcache
+        * lists of indexes.
+        */
+       CacheInvalidateRelcache(heapId);
+
+       /*
         * Close rels, but keep locks
         */
        index_close(userIndexRelation);
        heap_close(userHeapRelation, NoLock);
 
        RelationForgetRelation(indexId);
-
-       /* if it's a temp index, clear the temp mapping table entry */
-       remove_temp_rel_by_relid(indexId);
 }
 
 /* ----------------------------------------------------------------
@@ -1083,10 +874,9 @@ index_drop(Oid indexId)
  * just once per command, and then use it for (potentially) many tuples.
  * ----------------
  */
-IndexInfo  *
-BuildIndexInfo(HeapTuple indexTuple)
+IndexInfo *
+BuildIndexInfo(Form_pg_index indexStruct)
 {
-       Form_pg_index indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
        IndexInfo  *ii = makeNode(IndexInfo);
        int                     i;
        int                     numKeys;
@@ -1107,8 +897,8 @@ BuildIndexInfo(HeapTuple indexTuple)
         * Handle functional index.
         *
         * If we have a functional index then the number of attributes defined in
-        * the index must be 1 (the function's single return value).
-        * Otherwise it's same as number of keys.
+        * the index must be 1 (the function's single return value). Otherwise
+        * it's same as number of keys.
         */
        ii->ii_FuncOid = indexStruct->indproc;
 
@@ -1124,7 +914,7 @@ BuildIndexInfo(HeapTuple indexTuple)
        /*
         * If partial index, convert predicate into expression nodetree
         */
-       if (VARSIZE(&indexStruct->indpred) != 0)
+       if (VARSIZE(&indexStruct->indpred) > VARHDRSZ)
        {
                char       *predString;
 
@@ -1134,7 +924,7 @@ BuildIndexInfo(HeapTuple indexTuple)
                pfree(predString);
        }
        else
-               ii->ii_Predicate = NULL;
+               ii->ii_Predicate = NIL;
 
        /* Other info */
        ii->ii_Unique = indexStruct->indisunique;
@@ -1174,7 +964,6 @@ FormIndexDatum(IndexInfo *indexInfo,
 
        if (OidIsValid(indexInfo->ii_FuncOid))
        {
-
                /*
                 * Functional index --- compute the single index attribute
                 */
@@ -1209,7 +998,6 @@ FormIndexDatum(IndexInfo *indexInfo,
        }
        else
        {
-
                /*
                 * Plain index --- for each attribute we need from the heap tuple,
                 * get the attribute and stick it into the datum and nullv arrays.
@@ -1261,7 +1049,8 @@ LockClassinfoForUpdate(Oid relid, HeapTuple rtup,
                ItemPointerData tidsave;
 
                ItemPointerCopy(&(rtup->t_self), &tidsave);
-               test = heap_mark4update(relationRelation, rtup, buffer);
+               test = heap_mark4update(relationRelation, rtup, buffer,
+                                                               GetCurrentCommandId());
                switch (test)
                {
                        case HeapTupleSelfUpdated:
@@ -1277,7 +1066,7 @@ LockClassinfoForUpdate(Oid relid, HeapTuple rtup,
                }
                break;
        }
-       RelationInvalidateHeapTuple(relationRelation, rtup);
+       CacheInvalidateHeapTuple(relationRelation, rtup);
        if (confirmCommitted)
        {
                HeapTupleHeader th = rtup->t_data;
@@ -1318,10 +1107,9 @@ IndexesAreActive(Oid relid, bool confirmCommitted)
        indexRelation = heap_openr(IndexRelationName, AccessShareLock);
        ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid,
                                                   F_OIDEQ, ObjectIdGetDatum(relid));
-       scan = heap_beginscan(indexRelation, false, SnapshotNow,
-                                                 1, &entry);
-       if (!heap_getnext(scan, 0))
-               isactive = true;
+       scan = heap_beginscan(indexRelation, SnapshotNow, 1, &entry);
+       if (heap_getnext(scan, ForwardScanDirection) == NULL)
+               isactive = true;                /* no indexes, so report "active" */
        heap_endscan(scan);
        heap_close(indexRelation, AccessShareLock);
        return isactive;
@@ -1330,19 +1118,25 @@ IndexesAreActive(Oid relid, bool confirmCommitted)
 /* ----------------
  *             set relhasindex of relation's pg_class entry
  *
+ * If isprimary is TRUE, we are defining a primary index, so also set
+ * relhaspkey to TRUE. Otherwise, leave relhaspkey alone.
+ *
+ * If reltoastidxid is not InvalidOid, also set reltoastidxid to that value.
+ * This is only used for TOAST relations.
+ *
  * NOTE: an important side-effect of this operation is that an SI invalidation
  * message is sent out to all backends --- including me --- causing relcache
- * entries to be flushed or updated with the new hasindex data.
- * Therefore, we execute the update even if relhasindex has the right value
- * already.  Possible future improvement: skip the disk update and just send
- * an SI message in that case.
+ * entries to be flushed or updated with the new hasindex data.  This must
+ * happen even if we find that no change is needed in the pg_class row.
  * ----------------
  */
 void
-setRelhasindex(Oid relid, bool hasindex)
+setRelhasindex(Oid relid, bool hasindex, bool isprimary, Oid reltoastidxid)
 {
        Relation        pg_class;
        HeapTuple       tuple;
+       Form_pg_class classtuple;
+       bool            dirty = false;
        HeapScanDesc pg_class_scan = NULL;
 
        /*
@@ -1350,7 +1144,8 @@ setRelhasindex(Oid relid, bool hasindex)
         */
        pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
 
-       if (!IsIgnoringSystemIndexes() && (!IsReindexProcessing() || pg_class->rd_rel->relhasindex))
+       if (!IsIgnoringSystemIndexes() &&
+               (!IsReindexProcessing() || pg_class->rd_rel->relhasindex))
        {
                tuple = SearchSysCacheCopy(RELOID,
                                                                   ObjectIdGetDatum(relid),
@@ -1365,8 +1160,8 @@ setRelhasindex(Oid relid, bool hasindex)
                                                           F_OIDEQ,
                                                           ObjectIdGetDatum(relid));
 
-               pg_class_scan = heap_beginscan(pg_class, 0, SnapshotNow, 1, key);
-               tuple = heap_getnext(pg_class_scan, 0);
+               pg_class_scan = heap_beginscan(pg_class, SnapshotNow, 1, key);
+               tuple = heap_getnext(pg_class_scan, ForwardScanDirection);
        }
 
        if (!HeapTupleIsValid(tuple))
@@ -1379,11 +1174,36 @@ setRelhasindex(Oid relid, bool hasindex)
        }
 
        /*
-        * Update hasindex in pg_class.
+        * Update fields in the pg_class tuple.
         */
        if (pg_class_scan)
                LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
-       ((Form_pg_class) GETSTRUCT(tuple))->relhasindex = hasindex;
+
+       classtuple = (Form_pg_class) GETSTRUCT(tuple);
+
+       if (classtuple->relhasindex != hasindex)
+       {
+               classtuple->relhasindex = hasindex;
+               dirty = true;
+       }
+       if (isprimary)
+       {
+               if (!classtuple->relhaspkey)
+               {
+                       classtuple->relhaspkey = true;
+                       dirty = true;
+               }
+       }
+       if (OidIsValid(reltoastidxid))
+       {
+               Assert(classtuple->relkind == RELKIND_TOASTVALUE);
+               if (classtuple->reltoastidxid != reltoastidxid)
+               {
+                       classtuple->reltoastidxid = reltoastidxid;
+                       dirty = true;
+               }
+       }
+
        if (pg_class_scan)
                LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
 
@@ -1393,23 +1213,20 @@ setRelhasindex(Oid relid, bool hasindex)
                WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
                /* Send out shared cache inval if necessary */
                if (!IsBootstrapProcessingMode())
-                       RelationInvalidateHeapTuple(pg_class, tuple);
+                       CacheInvalidateHeapTuple(pg_class, tuple);
                BufferSync();
        }
-       else
+       else if (dirty)
        {
                simple_heap_update(pg_class, &tuple->t_self, tuple);
 
-               /* Keep the catalog indices up to date */
-               if (!IsIgnoringSystemIndexes())
-               {
-                       Relation        idescs[Num_pg_class_indices];
-
-                       CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
-                                                          idescs);
-                       CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, tuple);
-                       CatalogCloseIndices(Num_pg_class_indices, idescs);
-               }
+               /* Keep the catalog indexes up to date */
+               CatalogUpdateIndexes(pg_class, tuple);
+       }
+       else
+       {
+               /* no need to change tuple, but force relcache rebuild anyway */
+               CacheInvalidateRelcache(relid);
        }
 
        if (!pg_class_scan)
@@ -1423,8 +1240,7 @@ setRelhasindex(Oid relid, bool hasindex)
 void
 setNewRelfilenode(Relation relation)
 {
-       Relation        pg_class,
-                               idescs[Num_pg_class_indices];
+       Relation        pg_class;
        Oid                     newrelfilenode;
        bool            in_place_update = false;
        HeapTupleData lockTupleData;
@@ -1432,7 +1248,8 @@ setNewRelfilenode(Relation relation)
        Buffer          buffer;
        RelationData workrel;
 
-       Assert(!IsSystemRelationName(NameStr(relation->rd_rel->relname)) || relation->rd_rel->relkind == RELKIND_INDEX);
+       Assert(!IsSystemRelation(relation) || IsToastRelation(relation) ||
+                  relation->rd_rel->relkind == RELKIND_INDEX);
 
        pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
        /* Fetch and lock the classTuple associated with this relation */
@@ -1452,9 +1269,6 @@ setNewRelfilenode(Relation relation)
        }
        /* schedule unlinking old relfilenode */
        smgrunlink(DEFAULT_SMGR, relation);
-       /* cleanup pg_internal.init if necessary */
-       if (relation->rd_isnailed)
-               unlink(RELCACHE_INIT_FILENAME);
        /* create another storage file. Is it a little ugly ? */
        memcpy((char *) &workrel, relation, sizeof(RelationData));
        workrel.rd_node.relNode = newrelfilenode;
@@ -1466,7 +1280,7 @@ setNewRelfilenode(Relation relation)
                classTuple = &lockTupleData;
                /* Send out shared cache inval if necessary */
                if (!IsBootstrapProcessingMode())
-                       RelationInvalidateHeapTuple(pg_class, classTuple);
+                       CacheInvalidateHeapTuple(pg_class, classTuple);
                /* Update the buffer in-place */
                LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
                ((Form_pg_class) GETSTRUCT(classTuple))->relfilenode = newrelfilenode;
@@ -1474,14 +1288,10 @@ setNewRelfilenode(Relation relation)
                WriteBuffer(buffer);
                BufferSync();
        }
-       /* Keep the catalog indices up to date */
-       if (!in_place_update && pg_class->rd_rel->relhasindex)
-       {
-               CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
-                                                  idescs);
-               CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, classTuple);
-               CatalogCloseIndices(Num_pg_class_indices, idescs);
-       }
+       /* Keep the catalog indexes up to date */
+       if (!in_place_update)
+               CatalogUpdateIndexes(pg_class, classTuple);
+
        heap_close(pg_class, NoLock);
        if (!in_place_update)
                heap_freetuple(classTuple);
@@ -1505,10 +1315,9 @@ UpdateStats(Oid relid, double reltuples)
        Relation        pg_class;
        HeapTuple       tuple;
        HeapTuple       newtup;
-       long            relpages;
+       BlockNumber relpages;
        int                     i;
        Form_pg_class rd_rel;
-       Relation        idescs[Num_pg_class_indices];
        Datum           values[Natts_pg_class];
        char            nulls[Natts_pg_class];
        char            replace[Natts_pg_class];
@@ -1532,15 +1341,9 @@ UpdateStats(Oid relid, double reltuples)
         */
 
        /*
-        * Can't use heap_open here since we don't know if it's an index...
+        * Grabbing lock here is probably redundant ...
         */
-       whichRel = RelationIdGetRelation(relid);
-
-       if (!RelationIsValid(whichRel))
-               elog(ERROR, "UpdateStats: cannot open relation id %u", relid);
-
-       /* Grab lock to be held till end of xact (probably redundant...) */
-       LockRelation(whichRel, ShareLock);
+       whichRel = relation_open(relid, ShareLock);
 
        /*
         * Find the RELATION relation tuple for the given relation.
@@ -1564,8 +1367,8 @@ UpdateStats(Oid relid, double reltuples)
                                                           F_OIDEQ,
                                                           ObjectIdGetDatum(relid));
 
-               pg_class_scan = heap_beginscan(pg_class, 0, SnapshotNow, 1, key);
-               tuple = heap_getnext(pg_class_scan, 0);
+               pg_class_scan = heap_beginscan(pg_class, SnapshotNow, 1, key);
+               tuple = heap_getnext(pg_class_scan, ForwardScanDirection);
        }
 
        if (!HeapTupleIsValid(tuple))
@@ -1588,8 +1391,8 @@ UpdateStats(Oid relid, double reltuples)
         * when it is actually sizable.  See also CREATE TABLE in heap.c.
         *
         * Note: this path is also taken during bootstrap, because bootstrap.c
-        * passes reltuples = 0 after loading a table.  We have to estimate some
-        * number for reltuples based on the actual number of pages.
+        * passes reltuples = 0 after loading a table.  We have to estimate
+        * some number for reltuples based on the actual number of pages.
         */
        relpages = RelationGetNumberOfBlocks(whichRel);
 
@@ -1607,7 +1410,7 @@ UpdateStats(Oid relid, double reltuples)
                        reltuples = 1000;
                }
                else
-                       reltuples = relpages * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
+                       reltuples = ((double) relpages) * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
        }
 
        /*
@@ -1615,7 +1418,7 @@ UpdateStats(Oid relid, double reltuples)
         * place with the new values so that the cache contains the latest
         * copy.
         */
-       whichRel->rd_rel->relpages = relpages;
+       whichRel->rd_rel->relpages = (int32) relpages;
        whichRel->rd_rel->reltuples = reltuples;
 
        /*
@@ -1623,19 +1426,18 @@ UpdateStats(Oid relid, double reltuples)
         */
        if (in_place_upd)
        {
-
                /*
                 * At bootstrap time, we don't need to worry about concurrency or
                 * visibility of changes, so we cheat.  Also cheat if REINDEX.
                 */
                rd_rel = (Form_pg_class) GETSTRUCT(tuple);
                LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
-               rd_rel->relpages = relpages;
+               rd_rel->relpages = (int32) relpages;
                rd_rel->reltuples = reltuples;
                LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
                WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
                if (!IsBootstrapProcessingMode())
-                       RelationInvalidateHeapTuple(pg_class, tuple);
+                       CacheInvalidateHeapTuple(pg_class, tuple);
        }
        else
        {
@@ -1649,17 +1451,12 @@ UpdateStats(Oid relid, double reltuples)
                }
 
                replace[Anum_pg_class_relpages - 1] = 'r';
-               values[Anum_pg_class_relpages - 1] = Int32GetDatum(relpages);
+               values[Anum_pg_class_relpages - 1] = Int32GetDatum((int32) relpages);
                replace[Anum_pg_class_reltuples - 1] = 'r';
                values[Anum_pg_class_reltuples - 1] = Float4GetDatum((float4) reltuples);
                newtup = heap_modifytuple(tuple, pg_class, values, nulls, replace);
                simple_heap_update(pg_class, &tuple->t_self, newtup);
-               if (!IsIgnoringSystemIndexes())
-               {
-                       CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
-                       CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, newtup);
-                       CatalogCloseIndices(Num_pg_class_indices, idescs);
-               }
+               CatalogUpdateIndexes(pg_class, newtup);
                heap_freetuple(newtup);
        }
 
@@ -1669,48 +1466,81 @@ UpdateStats(Oid relid, double reltuples)
                heap_endscan(pg_class_scan);
 
        heap_close(pg_class, RowExclusiveLock);
-       /* Cheating a little bit since we didn't open it with heap_open... */
-       heap_close(whichRel, NoLock);
+       relation_close(whichRel, NoLock);
 }
 
 
-/* ----------------
- *             DefaultBuild
+/*
+ * index_build - invoke access-method-specific index build procedure
+ */
+void
+index_build(Relation heapRelation,
+                       Relation indexRelation,
+                       IndexInfo *indexInfo)
+{
+       RegProcedure procedure;
+
+       /*
+        * sanity checks
+        */
+       Assert(RelationIsValid(indexRelation));
+       Assert(PointerIsValid(indexRelation->rd_am));
+
+       procedure = indexRelation->rd_am->ambuild;
+       Assert(RegProcedureIsValid(procedure));
+
+       /*
+        * Call the access method's build procedure
+        */
+       OidFunctionCall3(procedure,
+                                        PointerGetDatum(heapRelation),
+                                        PointerGetDatum(indexRelation),
+                                        PointerGetDatum(indexInfo));
+}
+
+
+/*
+ * IndexBuildHeapScan - scan the heap relation to find tuples to be indexed
  *
- * NB: this routine is dead code, and likely always has been, because
- * there are no access methods that don't supply their own ambuild procedure.
+ * This is called back from an access-method-specific index build procedure
+ * after the AM has done whatever setup it needs.  The parent heap relation
+ * is scanned to find tuples that should be entered into the index.  Each
+ * such tuple is passed to the AM's callback routine, which does the right
+ * things to add it to the new index.  After we return, the AM's index
+ * build procedure does whatever cleanup is needed; in particular, it should
+ * close the heap and index relations.
  *
- * Anyone want to wager whether it would actually work if executed?
- * ----------------
+ * The total count of heap tuples is returned. This is for updating pg_class
+ * statistics. (It's annoying not to be able to do that here, but we can't
+ * do it until after the relation is closed.)  Note that the index AM itself
+ * must keep track of the number of index tuples; we don't do so here because
+ * the AM might reject some of the tuples for its own reasons, such as being
+ * unable to store NULLs.
  */
-static void
-DefaultBuild(Relation heapRelation,
-                        Relation indexRelation,
-                        IndexInfo *indexInfo,
-                        Node *oldPred,
-                        IndexStrategy indexStrategy)           /* not used */
+double
+IndexBuildHeapScan(Relation heapRelation,
+                                  Relation indexRelation,
+                                  IndexInfo *indexInfo,
+                                  IndexBuildCallback callback,
+                                  void *callback_state)
 {
        HeapScanDesc scan;
        HeapTuple       heapTuple;
        TupleDesc       heapDescriptor;
-       Datum           datum[INDEX_MAX_KEYS];
-       char            nullv[INDEX_MAX_KEYS];
-       double          reltuples,
-                               indtuples;
-       Node       *predicate = indexInfo->ii_Predicate;
-
-#ifndef OMIT_PARTIAL_INDEX
+       Datum           attdata[INDEX_MAX_KEYS];
+       char            nulls[INDEX_MAX_KEYS];
+       double          reltuples;
+       List       *predicate = indexInfo->ii_Predicate;
        TupleTable      tupleTable;
        TupleTableSlot *slot;
-
-#endif
        ExprContext *econtext;
-       InsertIndexResult insertResult;
+       Snapshot        snapshot;
+       TransactionId OldestXmin;
 
        /*
-        * more & better checking is needed
+        * sanity checks
         */
-       Assert(OidIsValid(indexRelation->rd_rel->relam));       /* XXX */
+       Assert(OidIsValid(indexRelation->rd_rel->relam));
 
        heapDescriptor = RelationGetDescr(heapRelation);
 
@@ -1724,8 +1554,7 @@ DefaultBuild(Relation heapRelation,
         * We construct the ExprContext anyway since we need a per-tuple
         * temporary memory context for function evaluation -- tgl July 00
         */
-#ifndef OMIT_PARTIAL_INDEX
-       if (predicate != NULL || oldPred != NULL)
+       if (predicate != NIL)
        {
                tupleTable = ExecCreateTupleTable(1);
                slot = ExecAllocTableSlot(tupleTable);
@@ -1737,155 +1566,175 @@ DefaultBuild(Relation heapRelation,
                slot = NULL;
        }
        econtext = MakeExprContext(slot, TransactionCommandContext);
-#else
-       econtext = MakeExprContext(NULL, TransactionCommandContext);
-#endif  /* OMIT_PARTIAL_INDEX */
 
        /*
-        * Ok, begin our scan of the base relation.
+        * Ok, begin our scan of the base relation.  We use SnapshotAny
+        * because we must retrieve all tuples and do our own time qual
+        * checks.
         */
+       if (IsBootstrapProcessingMode())
+       {
+               snapshot = SnapshotNow;
+               OldestXmin = InvalidTransactionId;
+       }
+       else
+       {
+               snapshot = SnapshotAny;
+               OldestXmin = GetOldestXmin(heapRelation->rd_rel->relisshared);
+       }
+
        scan = heap_beginscan(heapRelation, /* relation */
-                                                 0,    /* start at end */
-                                                 SnapshotNow,  /* seeself */
+                                                 snapshot,             /* seeself */
                                                  0,    /* number of keys */
                                                  (ScanKey) NULL);              /* scan key */
 
-       reltuples = indtuples = 0.0;
+       reltuples = 0;
 
        /*
-        * for each tuple in the base relation, we create an index tuple and
-        * add it to the index relation.  We keep a running count of the
-        * number of tuples so that we can update pg_class with correct
-        * statistics when we're done building the index.
+        * Scan all tuples in the base relation.
         */
-       while (HeapTupleIsValid(heapTuple = heap_getnext(scan, 0)))
+       while ((heapTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
        {
-               MemoryContextReset(econtext->ecxt_per_tuple_memory);
-
-               reltuples += 1.0;
+               bool            tupleIsAlive;
 
-#ifndef OMIT_PARTIAL_INDEX
+               CHECK_FOR_INTERRUPTS();
 
-               /*
-                * If oldPred != NULL, this is an EXTEND INDEX command, so skip
-                * this tuple if it was already in the existing partial index
-                */
-               if (oldPred != NULL)
+               if (snapshot == SnapshotAny)
                {
-                       slot->val = heapTuple;
-                       if (ExecQual((List *) oldPred, econtext, false))
+                       /* do our own time qual check */
+                       bool            indexIt;
+                       uint16          sv_infomask;
+
+                       /*
+                        * HeapTupleSatisfiesVacuum may update tuple's hint status
+                        * bits. We could possibly get away with not locking the
+                        * buffer here, since caller should hold ShareLock on the
+                        * relation, but let's be conservative about it.
+                        */
+                       LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
+                       sv_infomask = heapTuple->t_data->t_infomask;
+
+                       switch (HeapTupleSatisfiesVacuum(heapTuple->t_data, OldestXmin))
                        {
-                               indtuples += 1.0;
-                               continue;
+                               case HEAPTUPLE_DEAD:
+                                       indexIt = false;
+                                       tupleIsAlive = false;
+                                       break;
+                               case HEAPTUPLE_LIVE:
+                                       indexIt = true;
+                                       tupleIsAlive = true;
+                                       break;
+                               case HEAPTUPLE_RECENTLY_DEAD:
+
+                                       /*
+                                        * If tuple is recently deleted then we must index it
+                                        * anyway to keep VACUUM from complaining.
+                                        */
+                                       indexIt = true;
+                                       tupleIsAlive = false;
+                                       break;
+                               case HEAPTUPLE_INSERT_IN_PROGRESS:
+
+                                       /*
+                                        * Since caller should hold ShareLock or better, we
+                                        * should not see any tuples inserted by open
+                                        * transactions --- unless it's our own transaction.
+                                        * (Consider INSERT followed by CREATE INDEX within a
+                                        * transaction.)
+                                        */
+                                       if (!TransactionIdIsCurrentTransactionId(
+                                                         HeapTupleHeaderGetXmin(heapTuple->t_data)))
+                                               elog(ERROR, "IndexBuildHeapScan: concurrent insert in progress");
+                                       indexIt = true;
+                                       tupleIsAlive = true;
+                                       break;
+                               case HEAPTUPLE_DELETE_IN_PROGRESS:
+
+                                       /*
+                                        * Since caller should hold ShareLock or better, we
+                                        * should not see any tuples deleted by open
+                                        * transactions --- unless it's our own transaction.
+                                        * (Consider DELETE followed by CREATE INDEX within a
+                                        * transaction.)
+                                        */
+                                       if (!TransactionIdIsCurrentTransactionId(
+                                                         HeapTupleHeaderGetXmax(heapTuple->t_data)))
+                                               elog(ERROR, "IndexBuildHeapScan: concurrent delete in progress");
+                                       indexIt = true;
+                                       tupleIsAlive = false;
+                                       break;
+                               default:
+                                       elog(ERROR, "Unexpected HeapTupleSatisfiesVacuum result");
+                                       indexIt = tupleIsAlive = false;         /* keep compiler quiet */
+                                       break;
                        }
+
+                       /* check for hint-bit update by HeapTupleSatisfiesVacuum */
+                       if (sv_infomask != heapTuple->t_data->t_infomask)
+                               SetBufferCommitInfoNeedsSave(scan->rs_cbuf);
+
+                       LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
+
+                       if (!indexIt)
+                               continue;
+               }
+               else
+               {
+                       /* heap_getnext did the time qual check */
+                       tupleIsAlive = true;
                }
 
+               reltuples += 1;
+
+               MemoryContextReset(econtext->ecxt_per_tuple_memory);
+
                /*
-                * Skip this tuple if it doesn't satisfy the partial-index
-                * predicate
+                * In a partial index, discard tuples that don't satisfy the
+                * predicate.  We can also discard recently-dead tuples, since
+                * VACUUM doesn't complain about tuple count mismatch for partial
+                * indexes.
                 */
-               if (predicate != NULL)
+               if (predicate != NIL)
                {
-                       slot->val = heapTuple;
-                       if (!ExecQual((List *) predicate, econtext, false))
+                       if (!tupleIsAlive)
+                               continue;
+                       ExecStoreTuple(heapTuple, slot, InvalidBuffer, false);
+                       if (!ExecQual(predicate, econtext, false))
                                continue;
                }
-#endif  /* OMIT_PARTIAL_INDEX */
-
-               indtuples += 1.0;
 
                /*
-                * FormIndexDatum fills in its datum and null parameters with
-                * attribute information taken from the given heap tuple.
+                * For the current heap tuple, extract all the attributes we use
+                * in this index, and note which are null.      This also performs
+                * evaluation of the function, if this is a functional index.
                 */
                FormIndexDatum(indexInfo,
                                           heapTuple,
                                           heapDescriptor,
                                           econtext->ecxt_per_tuple_memory,
-                                          datum,
-                                          nullv);
+                                          attdata,
+                                          nulls);
 
-               insertResult = index_insert(indexRelation, datum, nullv,
-                                                                       &(heapTuple->t_self), heapRelation);
+               /*
+                * You'd think we should go ahead and build the index tuple here,
+                * but some index AMs want to do further processing on the data
+                * first.  So pass the attdata and nulls arrays, instead.
+                */
 
-               if (insertResult)
-                       pfree(insertResult);
+               /* Call the AM's callback routine to process the tuple */
+               callback(indexRelation, heapTuple, attdata, nulls, tupleIsAlive,
+                                callback_state);
        }
 
        heap_endscan(scan);
 
-#ifndef OMIT_PARTIAL_INDEX
-       if (predicate != NULL || oldPred != NULL)
+       if (predicate != NIL)
                ExecDropTupleTable(tupleTable, true);
-#endif  /* OMIT_PARTIAL_INDEX */
        FreeExprContext(econtext);
 
-       /*
-        * Since we just counted the tuples in the heap, we update its stats
-        * in pg_class to guarantee that the planner takes advantage of the
-        * index we just created.  But, only update statistics during normal
-        * index definitions, not for indices on system catalogs created
-        * during bootstrap processing.  We must close the relations before
-        * updating statistics to guarantee that the relcache entries are
-        * flushed when we increment the command counter in UpdateStats(). But
-        * we do not release any locks on the relations; those will be held
-        * until end of transaction.
-        */
-       if (IsNormalProcessingMode())
-       {
-               Oid                     hrelid = RelationGetRelid(heapRelation);
-               Oid                     irelid = RelationGetRelid(indexRelation);
-
-               heap_close(heapRelation, NoLock);
-               index_close(indexRelation);
-               UpdateStats(hrelid, reltuples);
-               UpdateStats(irelid, indtuples);
-               if (oldPred != NULL)
-               {
-                       if (indtuples == reltuples)
-                               predicate = NULL;
-                       UpdateIndexPredicate(irelid, oldPred, predicate);
-               }
-       }
+       return reltuples;
 }
 
-/* ----------------
- *             index_build
- * ----------------
- */
-void
-index_build(Relation heapRelation,
-                       Relation indexRelation,
-                       IndexInfo *indexInfo,
-                       Node *oldPred)
-{
-       RegProcedure procedure;
-
-       /*
-        * sanity checks
-        */
-       Assert(RelationIsValid(indexRelation));
-       Assert(PointerIsValid(indexRelation->rd_am));
-
-       procedure = indexRelation->rd_am->ambuild;
-
-       /*
-        * use the access method build procedure if supplied, else default.
-        */
-       if (RegProcedureIsValid(procedure))
-               OidFunctionCall5(procedure,
-                                                PointerGetDatum(heapRelation),
-                                                PointerGetDatum(indexRelation),
-                                                PointerGetDatum(indexInfo),
-                                                PointerGetDatum(oldPred),
-                          PointerGetDatum(RelationGetIndexStrategy(indexRelation)));
-       else
-               DefaultBuild(heapRelation,
-                                        indexRelation,
-                                        indexInfo,
-                                        oldPred,
-                                        RelationGetIndexStrategy(indexRelation));
-}
 
 /*
  * IndexGetRelation: given an index's relation OID, get the OID of the
@@ -1934,74 +1783,57 @@ bool
 reindex_index(Oid indexId, bool force, bool inplace)
 {
        Relation        iRel,
-                               indexRelation,
                                heapRelation;
-       ScanKeyData entry;
-       HeapScanDesc scan;
-       HeapTuple       indexTuple,
-                               classTuple;
        IndexInfo  *indexInfo;
-       Oid                     heapId,
-                               accessMethodId;
+       Oid                     heapId;
        bool            old;
 
        /*
         * REINDEX within a transaction block is dangerous, because if the
         * transaction is later rolled back we have no way to undo truncation
         * of the index's physical file.  Disallow it.
+        *
+        * XXX if we're not doing an inplace rebuild, wouldn't this be okay?
         */
        if (IsTransactionBlock())
-               elog(ERROR, "REINDEX cannot run inside a BEGIN/END block");
+               elog(ERROR, "REINDEX cannot run inside a transaction block");
 
-       old = SetReindexProcessing(true);
+       /*
+        * Open our index relation and get an exclusive lock on it.
+        *
+        * Note: doing this before opening the parent heap relation means there's
+        * a possibility for deadlock failure against another xact that is
+        * doing normal accesses to the heap and index.  However, it's not
+        * real clear why you'd be needing to do REINDEX on a table that's in
+        * active use, so I'd rather have the protection of making sure the
+        * index is locked down.
+        */
+       iRel = index_open(indexId);
+       if (iRel == NULL)
+               elog(ERROR, "reindex_index: can't open index relation");
+       LockRelation(iRel, AccessExclusiveLock);
 
-       /* Scan pg_index to find the index's pg_index entry */
-       indexRelation = heap_openr(IndexRelationName, AccessShareLock);
-       ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indexrelid, F_OIDEQ,
-                                                  ObjectIdGetDatum(indexId));
-       scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry);
-       indexTuple = heap_getnext(scan, 0);
-       if (!HeapTupleIsValid(indexTuple))
-               elog(ERROR, "reindex_index: index %u not found in pg_index", indexId);
+       old = SetReindexProcessing(true);
 
        /* Get OID of index's parent table */
-       heapId = ((Form_pg_index) GETSTRUCT(indexTuple))->indrelid;
+       heapId = iRel->rd_index->indrelid;
        /* Fetch info needed for index_build */
-       indexInfo = BuildIndexInfo(indexTuple);
-
-       /* Complete the scan and close pg_index */
-       heap_endscan(scan);
-       heap_close(indexRelation, AccessShareLock);
-
-       /* Fetch the classTuple associated with this index */
-       classTuple = SearchSysCache(RELOID,
-                                                               ObjectIdGetDatum(indexId),
-                                                               0, 0, 0);
-       if (!HeapTupleIsValid(classTuple))
-               elog(ERROR, "reindex_index: index %u not found in pg_class", indexId);
-       accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam;
-       ReleaseSysCache(classTuple);
+       indexInfo = BuildIndexInfo(iRel->rd_index);
 
-       /* Open our index relation */
-       heapRelation = heap_open(heapId, ExclusiveLock);
+       /* Open the parent heap relation */
+       heapRelation = heap_open(heapId, AccessExclusiveLock);
        if (heapRelation == NULL)
                elog(ERROR, "reindex_index: can't open heap relation");
-       iRel = index_open(indexId);
-       if (iRel == NULL)
-               elog(ERROR, "reindex_index: can't open index relation");
 
-       if (!inplace)
-       {
-               inplace = IsSharedSystemRelationName(NameStr(iRel->rd_rel->relname));
-               if (!inplace)
-                       setNewRelfilenode(iRel);
-       }
-       /* Obtain exclusive lock on it, just to be sure */
-       LockRelation(iRel, AccessExclusiveLock);
+       /*
+        * Force inplace processing if it's a shared index.  Necessary because
+        * we have no way to update relfilenode in other databases.
+        */
+       if (iRel->rd_rel->relisshared)
+               inplace = true;
 
        if (inplace)
        {
-
                /*
                 * Release any buffers associated with this index.      If they're
                 * dirty, they're just dropped without bothering to flush to disk.
@@ -2011,11 +1843,18 @@ reindex_index(Oid indexId, bool force, bool inplace)
                /* Now truncate the actual data and set blocks to zero */
                smgrtruncate(DEFAULT_SMGR, iRel, 0);
                iRel->rd_nblocks = 0;
+               iRel->rd_targblock = InvalidBlockNumber;
+       }
+       else
+       {
+               /*
+                * We'll build a new physical relation for the index.
+                */
+               setNewRelfilenode(iRel);
        }
 
        /* Initialize the index and rebuild */
-       InitIndexStrategy(indexInfo->ii_NumIndexAttrs, iRel, accessMethodId);
-       index_build(heapRelation, iRel, indexInfo, NULL);
+       index_build(heapRelation, iRel, indexInfo);
 
        /*
         * index_build will close both the heap and index relations (but not
@@ -2039,7 +1878,7 @@ activate_indexes_of_a_table(Oid relid, bool activate)
        if (IndexesAreActive(relid, true))
        {
                if (!activate)
-                       setRelhasindex(relid, false);
+                       setRelhasindex(relid, false, false, InvalidOid);
                else
                        return false;
        }
@@ -2067,11 +1906,9 @@ reindex_relation(Oid relid, bool force)
        HeapTuple       indexTuple;
        bool            old,
                                reindexed;
-
        bool            deactivate_needed,
                                overwrite,
                                upd_pg_class_inplace;
-
        Relation        rel;
 
        overwrite = upd_pg_class_inplace = deactivate_needed = false;
@@ -2084,11 +1921,18 @@ reindex_relation(Oid relid, bool force)
                upd_pg_class_inplace = true;
 
        /*
+        * Ensure to hold an exclusive lock throughout the transaction. The
+        * lock could be less intensive (in the non-overwrite path) but now
+        * it's AccessExclusiveLock for simplicity.
+        */
+       rel = heap_open(relid, AccessExclusiveLock);
+
+       /*
         * ignore the indexes of the target system relation while processing
         * reindex.
         */
-       rel = RelationIdGetRelation(relid);
-       if (!IsIgnoringSystemIndexes() && IsSystemRelationName(NameStr(rel->rd_rel->relname)))
+       if (!IsIgnoringSystemIndexes() &&
+               IsSystemRelation(rel) && !IsToastRelation(rel))
                deactivate_needed = true;
 #ifndef ENABLE_REINDEX_NAILED_RELATIONS
 
@@ -2106,13 +1950,13 @@ reindex_relation(Oid relid, bool force)
                else
                        elog(ERROR, "the target relation %u is nailed", relid);
        }
-#endif  /* ENABLE_REINDEX_NAILED_RELATIONS */
+#endif   /* ENABLE_REINDEX_NAILED_RELATIONS */
 
        /*
         * Shared system indexes must be overwritten because it's impossible
         * to update pg_class tuples of all databases.
         */
-       if (IsSharedSystemRelationName(NameStr(rel->rd_rel->relname)))
+       if (rel->rd_rel->relisshared)
        {
                if (IsIgnoringSystemIndexes())
                {
@@ -2122,7 +1966,11 @@ reindex_relation(Oid relid, bool force)
                else
                        elog(ERROR, "the target relation %u is shared", relid);
        }
-       RelationClose(rel);
+
+       /*
+        * Continue to hold the lock.
+        */
+       heap_close(rel, NoLock);
 
        old = SetReindexProcessing(true);
        if (deactivate_needed)
@@ -2142,10 +1990,9 @@ reindex_relation(Oid relid, bool force)
        indexRelation = heap_openr(IndexRelationName, AccessShareLock);
        ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid,
                                                   F_OIDEQ, ObjectIdGetDatum(relid));
-       scan = heap_beginscan(indexRelation, false, SnapshotNow,
-                                                 1, &entry);
+       scan = heap_beginscan(indexRelation, SnapshotNow, 1, &entry);
        reindexed = false;
-       while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
+       while ((indexTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
        {
                Form_pg_index index = (Form_pg_index) GETSTRUCT(indexTuple);
 
@@ -2161,7 +2008,6 @@ reindex_relation(Oid relid, bool force)
        heap_close(indexRelation, AccessShareLock);
        if (reindexed)
        {
-
                /*
                 * Ok,we could use the reindexed indexes of the target system
                 * relation now.
@@ -2170,12 +2016,11 @@ reindex_relation(Oid relid, bool force)
                {
                        if (!overwrite && relid == RelOid_pg_class)
                        {
-
                                /*
                                 * For pg_class, relhasindex should be set to true here in
                                 * place.
                                 */
-                               setRelhasindex(relid, true);
+                               setRelhasindex(relid, true, false, InvalidOid);
                                CommandCounterIncrement();
 
                                /*
@@ -2183,7 +2028,7 @@ reindex_relation(Oid relid, bool force)
                                 * keep consistency with WAL.
                                 */
                        }
-                       setRelhasindex(relid, true);
+                       setRelhasindex(relid, true, false, InvalidOid);
                }
        }
        SetReindexProcessing(old);