OSDN Git Service

Add attisinherited column to pg_attribute; use it to guard against
[pg-rex/syncrep.git] / src / backend / catalog / index.c
index 7b0ca32..bf6608e 100644 (file)
@@ -3,12 +3,12 @@
  * index.c
  *       code to create and destroy POSTGRES index relations
  *
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
+ * 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.134 2001/01/18 04:01:42 inoue Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.192 2002/08/30 19:23:18 tgl 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.
  */
 #define AVG_ATTR_SIZE 8
 #define NTUPLES_PER_PAGE(natts) \
-       ((BLCKSZ - MAXALIGN(sizeof (PageHeaderData))) / \
+       ((BLCKSZ - MAXALIGN(sizeof(PageHeaderData))) / \
        ((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 ConstructTupleDescriptor(Oid heapoid, Relation heapRelation,
-                                                                                 int numatts, AttrNumber *attNums);
-static void ConstructIndexReldesc(Relation indexRelation, Oid amoid);
-static Oid     UpdateRelationRelation(Relation indexRelation, char *temp_relname);
+static TupleDesc BuildFuncTupleDesc(Oid funcOid,
+                                  Oid *classObjectId);
+static TupleDesc ConstructTupleDescriptor(Relation heapRelation,
+                                                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);
+                                       IndexInfo *indexInfo,
+                                       Oid *classOids,
+                                       bool primary);
 static Oid     IndexGetRelation(Oid indexId);
 static bool activate_index(Oid indexId, bool activate, bool inplace);
 
@@ -98,77 +98,20 @@ IsReindexProcessing(void)
        return reindexing;
 }
 
-/* ----------------------------------------------------------------
- *       sysatts is a structure containing attribute tuple forms
- *       for system attributes (numbered -1, -2, ...).  This really
- *       should be generated or eliminated or moved elsewhere. -cim 1/19/91
- *
- * typedef struct FormData_pg_attribute {
- *             Oid                             attrelid;
- *             NameData                attname;
- *             Oid                             atttypid;
- *             uint32                  attnvals;
- *             int16                   attlen;
- *             AttrNumber              attnum;
- *             uint32                  attnelems;
- *             int32                   attcacheoff;
- *             int32                   atttypmod;
- *             bool                    attbyval;
- *             bool                    attisset;
- *             char                    attalign;
- *             bool                    attnotnull;
- *             bool                    atthasdef;
- * } FormData_pg_attribute;
- *
- * ----------------------------------------------------------------
- */
-static FormData_pg_attribute sysatts[] = {
-       {0, {"ctid"}, TIDOID, 0, 6, -1, 0, -1, -1, '\0', 'p', '\0', 'i', '\0', '\0'},
-       {0, {"oid"}, OIDOID, 0, 4, -2, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
-       {0, {"xmin"}, XIDOID, 0, 4, -3, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
-       {0, {"cmin"}, CIDOID, 0, 4, -4, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
-       {0, {"xmax"}, XIDOID, 0, 4, -5, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
-       {0, {"cmax"}, CIDOID, 0, 4, -6, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'},
-};
-
-/* ----------------------------------------------------------------
- *             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.
+        * Allocate and zero a tuple descriptor for a one-column tuple.
         */
-       funcTupDesc = CreateTemplateTupleDesc(1);
+       funcTupDesc = CreateTemplateTupleDesc(1, UNDEFOID);
        funcTupDesc->attrs[0] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
        MemSet(funcTupDesc->attrs[0], 0, ATTRIBUTE_TUPLE_SIZE);
 
@@ -191,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 = 'p';
-       funcTupDesc->attrs[0]->attalign = ((Form_pg_type) GETSTRUCT(tuple))->typalign;
+       funcTupDesc->attrs[0]->attstorage = typeTup->typstorage;
+       funcTupDesc->attrs[0]->attalign = typeTup->typalign;
 
        ReleaseSysCache(tuple);
 
@@ -223,10 +182,10 @@ BuildFuncTupleDesc(Oid funcOid)
  * ----------------------------------------------------------------
  */
 static TupleDesc
-ConstructTupleDescriptor(Oid heapoid,
-                                                Relation heapRelation,
+ConstructTupleDescriptor(Relation heapRelation,
                                                 int numatts,
-                                                AttrNumber *attNums)
+                                                AttrNumber *attNums,
+                                                Oid *classObjectId)
 {
        TupleDesc       heapTupDesc;
        TupleDesc       indexTupDesc;
@@ -236,12 +195,11 @@ ConstructTupleDescriptor(Oid heapoid,
        heapTupDesc = RelationGetDescr(heapRelation);
        natts = RelationGetForm(heapRelation)->relnatts;
 
-       /* ----------------
-        *      allocate the new tuple descriptor
-        * ----------------
+       /*
+        * allocate the new tuple descriptor
         */
 
-       indexTupDesc = CreateTemplateTupleDesc(numatts);
+       indexTupDesc = CreateTemplateTupleDesc(numatts, WITHOUTOID);
 
        /* ----------------
         *        for each attribute we are indexing, obtain its attribute
@@ -252,219 +210,133 @@ ConstructTupleDescriptor(Oid heapoid,
        for (i = 0; i < numatts; i++)
        {
                AttrNumber      atnum;          /* attributeNumber[attributeOffset] */
-               AttrNumber      atind;
-               char       *from;               /* used to simplify memcpy below */
-               char       *to;                 /* used to simplify memcpy below */
+               Form_pg_attribute from;
+               Form_pg_attribute to;
+               HeapTuple       tuple;
+               Oid                     keyType;
 
-               /* ----------------
-                *       get the attribute number and make sure it's valid
-                * ----------------
+               /*
+                * get the attribute number and make sure it's valid; determine
+                * which attribute descriptor to copy
                 */
                atnum = attNums[i];
-               if (atnum > natts)
-                       elog(ERROR, "Cannot create index: attribute %d does not exist",
-                                atnum);
-
-               indexTupDesc->attrs[i] =
-                       (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
 
-               /* ----------------
-                *       determine which tuple descriptor to copy
-                * ----------------
-                */
                if (!AttrNumberIsForUserDefinedAttr(atnum))
                {
-                       /* ----------------
-                        *        here we are indexing on a system attribute (-1...-n)
-                        *        so we convert atnum into a usable index 0...n-1 so we can
-                        *        use it to dereference the array sysatts[] which stores
-                        *        tuple descriptor information for system attributes.
-                        * ----------------
+                       /*
+                        * here we are indexing on a system attribute (-1...-n)
                         */
-                       if (atnum <= FirstLowInvalidHeapAttributeNumber || atnum >= 0)
-                               elog(ERROR, "Cannot create index on system attribute: attribute number out of range (%d)", atnum);
-                       atind = (-atnum) - 1;
-
-                       from = (char *) (&sysatts[atind]);
+                       from = SystemAttributeDefinition(atnum,
+                                                                          heapRelation->rd_rel->relhasoids);
                }
                else
                {
-                       /* ----------------
-                        *        here we are indexing on a normal attribute (1...n)
-                        * ----------------
+                       /*
+                        * here we are indexing on a normal attribute (1...n)
                         */
-                       atind = AttrNumberGetAttrOffset(atnum);
+                       if (atnum > natts)
+                               elog(ERROR, "cannot create index: column %d does not exist",
+                                        atnum);
 
-                       from = (char *) (heapTupDesc->attrs[atind]);
+                       from = heapTupDesc->attrs[AttrNumberGetAttrOffset(atnum)];
                }
 
-               /* ----------------
-                *       now that we've determined the "from", let's copy
-                *       the tuple desc data...
-                * ----------------
+               /*
+                * now that we've determined the "from", let's copy the tuple desc
+                * data...
                 */
-               to = (char *) (indexTupDesc->attrs[i]);
+               indexTupDesc->attrs[i] = to =
+                       (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
                memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);
 
                /*
-                * Fix the stuff that should not be the same as the underlying attr
-                */
-               ((Form_pg_attribute) to)->attnum = i + 1;
-
-               ((Form_pg_attribute) to)->attdispersion = 0.0;
-               ((Form_pg_attribute) to)->attnotnull = false;
-               ((Form_pg_attribute) to)->atthasdef = false;
-               ((Form_pg_attribute) to)->attcacheoff = -1;
-
-               /* ----------------
-                *        now we have to drop in the proper relation descriptor
-                *        into the copied tuple form's attrelid and we should be
-                *        all set.
-                * ----------------
+                * Fix the stuff that should not be the same as the underlying
+                * attr
                 */
-               ((Form_pg_attribute) to)->attrelid = heapoid;
-       }
-
-       return indexTupDesc;
-}
+               to->attnum = i + 1;
 
-/* ----------------------------------------------------------------
- * 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;
+               to->attstattarget = 0;
+               to->attcacheoff = -1;
+               to->attnotnull = false;
+               to->atthasdef = false;
+               to->attisinherited = false;
 
-       /* ----------------
-        *      form a scan key for the pg_am relation
-        * ----------------
-        */
-       ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
-                                                  F_OIDEQ,
-                                                  ObjectIdGetDatum(accessMethodObjectId));
+               /*
+                * We do not yet have the correct relation OID for the index, so
+                * just set it invalid for now.  InitializeAttributeOids() will
+                * fix it later.
+                */
+               to->attrelid = InvalidOid;
 
-       /* ----------------
-        *      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);
-
-       /* ----------------
-        *      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.
-        * ----------------
-        */
-       tuple->t_data->t_oid = RelationGetRelid(indexRelation);
-       heap_insert(pg_class, tuple);
-
-       if (temp_relname)
-               create_temp_relation(temp_relname, tuple);
+                                                  (void *) indexRelation->rd_rel);
 
        /*
-        * 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.
+        * 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.
         */
+       AssertTupleDescHasOid(pg_class->rd_att);
+       HeapTupleSetOid(tuple, RelationGetRelid(indexRelation));
+       simple_heap_insert(pg_class, tuple);
 
-       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);
-       }
+       /* update the system catalog indexes */
+       CatalogUpdateIndexes(pg_class, tuple);
 
-       tupleOid = tuple->t_data->t_oid;
        heap_freetuple(tuple);
        heap_close(pg_class, RowExclusiveLock);
-
-       return tupleOid;
 }
 
 /* ----------------------------------------------------------------
@@ -487,118 +359,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);
+       indstate = CatalogOpenIndexes(pg_attribute);
 
-       /* ----------------
-        *      create the first attribute tuple.
-        *      XXX For now, only change the ATTNUM attribute value
-        * ----------------
+       /*
+        * insert data from new index's tupdesc into pg_attribute
         */
-       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]));
+       indexTupDesc = RelationGetDescr(indexRelation);
 
-       hasind = false;
-       if (!IsIgnoringSystemIndexes() && pg_attribute->rd_rel->relhasindex)
+       for (i = 0; i < numatts; i++)
        {
-               hasind = true;
-               CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
-       }
+               /*
+                * There used to be very grotty code here to set these fields, but
+                * I think it's unnecessary.  They should be set already.
+                */
+               Assert(indexTupDesc->attrs[i]->attnum == i + 1);
+               Assert(indexTupDesc->attrs[i]->attcacheoff == -1);
 
-       /* ----------------
-        *      insert the first attribute tuple.
-        * ----------------
-        */
-       cur_tuple = heap_modifytuple(init_tuple,
-                                                                pg_attribute,
-                                                                value,
-                                                                nullv,
-                                                                replace);
-       heap_freetuple(init_tuple);
+               new_tuple = heap_addheader(Natts_pg_attribute,
+                                          false,
+                                                                  ATTRIBUTE_TUPLE_SIZE,
+                                                                  (void *) indexTupDesc->attrs[i]);
 
-       heap_insert(pg_attribute, cur_tuple);
-       if (hasind)
-               CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, cur_tuple);
+               simple_heap_insert(pg_attribute, new_tuple);
 
-       /* ----------------
-        *      now we use the information in the index cur_tuple
-        *      descriptor to form the remaining attribute tuples.
-        * ----------------
-        */
-       indexTupDesc = RelationGetDescr(indexRelation);
+               CatalogIndexInsert(indstate, new_tuple);
 
-       for (i = 1; i < numatts; i += 1)
-       {
-               /* ----------------
-                *      process the remaining attributes...
-                * ----------------
-                */
-               memmove(GETSTRUCT(cur_tuple),
-                               (char *) indexTupDesc->attrs[i],
-                               ATTRIBUTE_TUPLE_SIZE);
-
-               value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(i + 1);
-
-               new_tuple = heap_modifytuple(cur_tuple,
-                                                                        pg_attribute,
-                                                                        value,
-                                                                        nullv,
-                                                                        replace);
-               heap_freetuple(cur_tuple);
-
-               heap_insert(pg_attribute, new_tuple);
-               if (hasind)
-                       CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, 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);
 }
 
 /* ----------------------------------------------------------------
@@ -610,7 +417,6 @@ UpdateIndexRelation(Oid indexoid,
                                        Oid heapoid,
                                        IndexInfo *indexInfo,
                                        Oid *classOids,
-                                       bool islossy,
                                        bool primary)
 {
        Form_pg_index indexForm;
@@ -621,48 +427,42 @@ 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
-        * ----------------
+       /*
+        * 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,
-                                                                                       CStringGetDatum(predString)));
+                                                                                  CStringGetDatum(predString)));
                pfree(predString);
        }
        else
                predText = DatumGetTextP(DirectFunctionCall1(textin,
-                                                                                                        CStringGetDatum("")));
+                                                                                                  CStringGetDatum("")));
 
        predLen = VARSIZE(predText);
        itupLen = predLen + sizeof(FormData_pg_index);
        indexForm = (Form_pg_index) palloc(itupLen);
        MemSet(indexForm, 0, sizeof(FormData_pg_index));
 
-       /* ----------------
-        *      store information into the index tuple form
-        * ----------------
+       /*
+        * store information into the index tuple form
         */
        indexForm->indexrelid = indexoid;
        indexForm->indrelid = heapoid;
        indexForm->indproc = indexInfo->ii_FuncOid;
-       indexForm->indisclustered = false;
-       indexForm->indislossy = islossy;
-       indexForm->indhaskeytype = true; /* not actually used anymore */
+       indexForm->indisclustered = false;      /* not used */
        indexForm->indisunique = indexInfo->ii_Unique;
        indexForm->indisprimary = primary;
        memcpy((char *) &indexForm->indpred, (char *) predText, predLen);
 
-       /* ----------------
-        *      copy index key and op class information
+       /*
+        * copy index key and op class information
         *
-        *      We zeroed the extra slots (if any) above --- that's essential.
-        * ----------------
+        * We zeroed the extra slots (if any) above --- that's essential.
         */
        for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
                indexForm->indkey[i] = indexInfo->ii_KeyAttrNumbers[i];
@@ -670,40 +470,29 @@ UpdateIndexRelation(Oid indexoid,
        for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
                indexForm->indclass[i] = classOids[i];
 
-       /* ----------------
-        *      open the system catalog index relation
-        * ----------------
+       /*
+        * open the system catalog index relation
         */
        pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
 
-       /* ----------------
-        *      form a tuple to insert into pg_index
-        * ----------------
+       /*
+        * 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
-        * ----------------
+       /*
+        * close the relation and free the tuple
         */
        heap_close(pg_index, RowExclusiveLock);
        pfree(predText);
@@ -711,231 +500,98 @@ 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);
-
-       heap_update(pg_index, &newtup->t_self, newtup, NULL);
-
-       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);
 
-       /* ----------------
-        *      check parameters
-        * ----------------
+       /*
+        * 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");
 
-       /* ----------------
-        *        get heap relation oid and open the heap relation
-        * ----------------
-        */
-       heapoid = GetHeapRelationOid(heapRelationName, indexRelationName, istemp);
+       if (!allow_system_table_mods &&
+               IsSystemRelation(heapRelation) &&
+               IsNormalProcessingMode())
+               elog(ERROR, "User-defined indexes on system catalogs are not supported");
 
        /*
-        * Only SELECT ... FOR UPDATE are allowed while doing this
+        * 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.
         */
-       heapRelation = heap_open(heapoid, ShareLock);
+       if (shared_relation && IsUnderPostmaster)
+               elog(ERROR, "Shared indexes cannot be created after initdb");
 
-       /* ----------------
-        *        construct new tuple descriptor
-        * ----------------
+       if (get_relname_relid(indexRelationName, namespaceId))
+               elog(ERROR, "relation named \"%s\" already exists",
+                        indexRelationName);
+
+       /*
+        * 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(heapoid,
-                                                                                               heapRelation,
+               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 */
-       }
-
-       /* ----------------
-        *      create the index relation
-        * ----------------
+       indexTupDesc->tdhasoid = WITHOUTOID;
+       /*
+        * 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
@@ -944,38 +600,32 @@ 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;  /* WITHOUTOID! */
 
        /*
-        * 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 index relation's tuple descriptor
-        * ----------------
+       /*
+        * now update the object id's of all the attribute tuple forms in the
+        * index relation's tuple descriptor
         */
        InitializeAttributeOids(indexRelation,
                                                        indexInfo->ii_NumIndexAttrs,
                                                        indexoid);
 
-       /* ----------------
-        *        append ATTRIBUTE tuples for the index
-        * ----------------
+       /*
+        * append ATTRIBUTE tuples for the index
         */
        AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs);
 
@@ -987,20 +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);
 
-       /* ----------------
-        *        initialize the index strategy
-        * ----------------
+       /*
+        * 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.
         */
-       InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
-                                         indexRelation,
-                                         accessMethodObjectId);
+       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);
+               }
+       }
+
+       /*
+        * 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();
+
+       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.
@@ -1012,20 +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)
@@ -1034,106 +781,53 @@ index_drop(Oid indexId)
        Relation        userHeapRelation;
        Relation        userIndexRelation;
        Relation        indexRelation;
-       Relation        relationRelation;
-       Relation        attributeRelation;
        HeapTuple       tuple;
-       int16           attnum;
        int                     i;
 
        Assert(OidIsValid(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.
-        * ----------------
+       /*
+        * 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 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);
 
-       userIndexRelation = index_open(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);
-
-       heap_delete(relationRelation, &tuple->t_self, NULL);
-       heap_freetuple(tuple);
+       userIndexRelation = index_open(indexId);
+       LockRelation(userIndexRelation, AccessExclusiveLock);
 
        /*
-        * 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).
+        * fix RELATION relation
         */
-       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)))
-       {
-               heap_delete(attributeRelation, &tuple->t_self, NULL);
-               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);
 
-       heap_delete(indexRelation, &tuple->t_self, NULL);
-       heap_freetuple(tuple);
+       simple_heap_delete(indexRelation, &tuple->t_self);
+
+       ReleaseSysCache(tuple);
        heap_close(indexRelation, RowExclusiveLock);
 
        /*
@@ -1146,15 +840,21 @@ 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);
 }
 
 /* ----------------------------------------------------------------
@@ -1168,21 +868,19 @@ index_drop(Oid indexId)
  *
  * IndexInfo stores the information about the index that's needed by
  * FormIndexDatum, which is used for both index_build() and later insertion
- * of individual index tuples.  Normally we build an IndexInfo for an index
+ * of individual index tuples. Normally we build an IndexInfo for an index
  * just once per command, and then use it for (potentially) many tuples.
  * ----------------
  */
 IndexInfo *
-BuildIndexInfo(HeapTuple indexTuple)
+BuildIndexInfo(Form_pg_index indexStruct)
 {
-       Form_pg_index indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
        IndexInfo  *ii = makeNode(IndexInfo);
        int                     i;
        int                     numKeys;
 
-       /* ----------------
-        *      count the number of keys, and copy them into the IndexInfo
-        * ----------------
+       /*
+        * count the number of keys, and copy them into the IndexInfo
         */
        numKeys = 0;
        for (i = 0; i < INDEX_MAX_KEYS &&
@@ -1193,13 +891,12 @@ BuildIndexInfo(HeapTuple indexTuple)
        }
        ii->ii_NumKeyAttrs = numKeys;
 
-       /* ----------------
-        *      Handle functional index.
+       /*
+        * 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.
-        * ----------------
+        * 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.
         */
        ii->ii_FuncOid = indexStruct->indproc;
 
@@ -1207,26 +904,25 @@ BuildIndexInfo(HeapTuple indexTuple)
        {
                ii->ii_NumIndexAttrs = 1;
                /* Do a lookup on the function, too */
-               fmgr_info(indexStruct->indproc, & ii->ii_FuncInfo);
+               fmgr_info(indexStruct->indproc, &ii->ii_FuncInfo);
        }
        else
                ii->ii_NumIndexAttrs = numKeys;
 
-       /* ----------------
-        *      If partial index, convert predicate into expression nodetree
-        * ----------------
+       /*
+        * If partial index, convert predicate into expression nodetree
         */
-       if (VARSIZE(&indexStruct->indpred) != 0)
+       if (VARSIZE(&indexStruct->indpred) > VARHDRSZ)
        {
                char       *predString;
 
                predString = DatumGetCString(DirectFunctionCall1(textout,
-                                                                        PointerGetDatum(&indexStruct->indpred)));
+                                                               PointerGetDatum(&indexStruct->indpred)));
                ii->ii_Predicate = stringToNode(predString);
                pfree(predString);
        }
        else
-               ii->ii_Predicate = NULL;
+               ii->ii_Predicate = NIL;
 
        /* Other info */
        ii->ii_Unique = indexStruct->indisunique;
@@ -1266,12 +962,11 @@ FormIndexDatum(IndexInfo *indexInfo,
 
        if (OidIsValid(indexInfo->ii_FuncOid))
        {
-               /* ----------------
-                *      Functional index --- compute the single index attribute
-                * ----------------
+               /*
+                * Functional index --- compute the single index attribute
                 */
-               FunctionCallInfoData    fcinfo;
-               bool                                    anynull = false;
+               FunctionCallInfoData fcinfo;
+               bool            anynull = false;
 
                MemSet(&fcinfo, 0, sizeof(fcinfo));
                fcinfo.flinfo = &indexInfo->ii_FuncInfo;
@@ -1301,10 +996,9 @@ 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.
-                * ----------------
+               /*
+                * Plain index --- for each attribute we need from the heap tuple,
+                * get the attribute and stick it into the datum and nullv arrays.
                 */
                for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
                {
@@ -1334,8 +1028,8 @@ LockClassinfoForUpdate(Oid relid, HeapTuple rtup,
        Relation        relationRelation;
 
        /*
-        * NOTE: get and hold RowExclusiveLock on pg_class, because caller will
-        * probably modify the rel's pg_class tuple later on.
+        * NOTE: get and hold RowExclusiveLock on pg_class, because caller
+        * will probably modify the rel's pg_class tuple later on.
         */
        relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
        classTuple = SearchSysCache(RELOID, PointerGetDatum(relid),
@@ -1350,10 +1044,11 @@ LockClassinfoForUpdate(Oid relid, HeapTuple rtup,
 
        while (1)
        {
-               ItemPointerData tidsave;
+               ItemPointerData tidsave;
 
                ItemPointerCopy(&(rtup->t_self), &tidsave);
-               test = heap_mark4update(relationRelation, rtup, buffer);
+               test = heap_mark4update(relationRelation, rtup, buffer,
+                                                               GetCurrentCommandId());
                switch (test)
                {
                        case HeapTupleSelfUpdated:
@@ -1369,7 +1064,7 @@ LockClassinfoForUpdate(Oid relid, HeapTuple rtup,
                }
                break;
        }
-       RelationInvalidateHeapTuple(relationRelation, rtup);
+       CacheInvalidateHeapTuple(relationRelation, rtup);
        if (confirmCommitted)
        {
                HeapTupleHeader th = rtup->t_data;
@@ -1401,7 +1096,7 @@ IndexesAreActive(Oid relid, bool confirmCommitted)
        if (!LockClassinfoForUpdate(relid, &tuple, &buffer, confirmCommitted))
                elog(ERROR, "IndexesAreActive couldn't lock %u", relid);
        if (((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_RELATION &&
-               ((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_TOASTVALUE)
+         ((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_TOASTVALUE)
                elog(ERROR, "relation %u isn't an indexable relation", relid);
        isactive = ((Form_pg_class) GETSTRUCT(&tuple))->relhasindex;
        ReleaseBuffer(buffer);
@@ -1410,10 +1105,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;
@@ -1422,19 +1116,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;
 
        /*
@@ -1442,11 +1142,8 @@ setRelhasindex(Oid relid, bool hasindex)
         */
        pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
 
-#ifdef OLD_FILE_NAMING
-       if (!IsIgnoringSystemIndexes())
-#else
-       if (!IsIgnoringSystemIndexes() && (!IsReindexProcessing() || pg_class->rd_rel->relhasindex))
-#endif /* OLD_FILE_NAMING */
+       if (!IsIgnoringSystemIndexes() &&
+               (!IsReindexProcessing() || pg_class->rd_rel->relhasindex))
        {
                tuple = SearchSysCacheCopy(RELOID,
                                                                   ObjectIdGetDatum(relid),
@@ -1461,8 +1158,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))
@@ -1474,13 +1171,37 @@ setRelhasindex(Oid relid, bool hasindex)
                         relid);
        }
 
-       /* ----------------
-        *      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);
 
@@ -1490,23 +1211,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)
        {
-               heap_update(pg_class, &tuple->t_self, tuple, NULL);
-
-               /* Keep the catalog indices up to date */
-               if (!IsIgnoringSystemIndexes())
-               {
-                       Relation        idescs[Num_pg_class_indices];
+               simple_heap_update(pg_class, &tuple->t_self, tuple);
 
-                       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)
@@ -1517,22 +1235,22 @@ setRelhasindex(Oid relid, bool hasindex)
        heap_close(pg_class, RowExclusiveLock);
 }
 
-#ifndef OLD_FILE_NAMING
 void
 setNewRelfilenode(Relation relation)
 {
-       Relation        pg_class, idescs[Num_pg_class_indices];
-       Oid             newrelfilenode;
+       Relation        pg_class;
+       Oid                     newrelfilenode;
        bool            in_place_update = false;
-       HeapTupleData   lockTupleData;
-       HeapTuple       classTuple = NULL;
+       HeapTupleData lockTupleData;
+       HeapTuple       classTuple = NULL;
        Buffer          buffer;
-       RelationData    workrel;
-       
-       Assert(!IsSystemRelationName(NameStr(relation->rd_rel->relname)) || relation->rd_rel->relkind == RELKIND_INDEX);
+       RelationData workrel;
+
+       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 */
+       /* Fetch and lock the classTuple associated with this relation */
        if (!LockClassinfoForUpdate(relation->rd_id, &lockTupleData, &buffer, true))
                elog(ERROR, "setNewRelfilenode impossible to lock class tuple");
        if (IsIgnoringSystemIndexes())
@@ -1545,25 +1263,22 @@ setNewRelfilenode(Relation relation)
                classTuple = heap_copytuple(&lockTupleData);
                ReleaseBuffer(buffer);
                ((Form_pg_class) GETSTRUCT(classTuple))->relfilenode = newrelfilenode;
-               heap_update(pg_class, &classTuple->t_self, classTuple, NULL);
+               simple_heap_update(pg_class, &classTuple->t_self, classTuple);
        }
-       /* unlink old relfilenode */
-       DropRelationBuffers(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;
        heap_storage_create(&workrel);
+       smgrclose(DEFAULT_SMGR, &workrel);
        /* update pg_class tuple with new relfilenode in place */
        if (in_place_update)
        {
                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;
@@ -1571,82 +1286,69 @@ 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);
-               heap_freetuple(classTuple);
-       }
+       /* 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);
        /* Make sure the relfilenode change */
        CommandCounterIncrement();
 }
-#endif /* OLD_FILE_NAMING */
+
 
 /* ----------------
  *             UpdateStats
+ *
+ * Update pg_class' relpages and reltuples statistics for the given relation
+ * (which can be either a table or an index).  Note that this is not used
+ * in the context of VACUUM.
  * ----------------
  */
 void
-UpdateStats(Oid relid, long reltuples)
+UpdateStats(Oid relid, double reltuples)
 {
        Relation        whichRel;
        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];
        HeapScanDesc pg_class_scan = NULL;
        bool            in_place_upd;
 
-       /* ----------------
+       /*
         * This routine handles updates for both the heap and index relation
-        * statistics.  In order to guarantee that we're able to *see* the index
-        * relation tuple, we bump the command counter id here.  The index
-        * relation tuple was created in the current transaction.
-        * ----------------
+        * statistics.  In order to guarantee that we're able to *see* the
+        * index relation tuple, we bump the command counter id here.  The
+        * index relation tuple was created in the current transaction.
         */
        CommandCounterIncrement();
 
-       /* ----------------
+       /*
         * CommandCounterIncrement() flushes invalid cache entries, including
         * those for the heap and index relations for which we're updating
         * statistics.  Now that the cache is flushed, it's safe to open the
         * relation again.      We need the relation open in order to figure out
         * how many blocks it contains.
-        * ----------------
         */
 
        /*
-        * 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);
+       whichRel = relation_open(relid, ShareLock);
 
-       /* Grab lock to be held till end of xact (probably redundant...) */
-       LockRelation(whichRel, ShareLock);
-
-       /* ----------------
+       /*
         * Find the RELATION relation tuple for the given relation.
-        * ----------------
         */
        pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
 
-#ifdef OLD_FILE_NAMING
-       in_place_upd = (IsReindexProcessing() || IsBootstrapProcessingMode());
-#else
        in_place_upd = (IsIgnoringSystemIndexes() || IsReindexProcessing());
-#endif /* OLD_FILE_NAMING */
 
        if (!in_place_upd)
        {
@@ -1663,8 +1365,8 @@ UpdateStats(Oid relid, long 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))
@@ -1676,16 +1378,19 @@ UpdateStats(Oid relid, long reltuples)
                         relid);
        }
 
-       /* ----------------
+       /*
         * Figure values to insert.
         *
-        * If we found zero tuples in the scan, do NOT believe it; instead put
-        * bogus estimate into the statistics fields.  Otherwise, the common
+        * If we found zero tuples in the scan, do NOT believe it; instead put a
+        * bogus estimate into the statistics fields.  Otherwise, the common
         * pattern "CREATE TABLE; CREATE INDEX; insert data" leaves the table
-        * with zero size statistics until a VACUUM is done.  The optimizer will
-        * generate very bad plans if the stats claim the table is empty when
-        * it is actually sizable.      See also CREATE TABLE in heap.c.
-        * ----------------
+        * with zero size statistics until a VACUUM is done.  The optimizer
+        * will generate very bad plans if the stats claim the table is empty
+        * 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.
         */
        relpages = RelationGetNumberOfBlocks(whichRel);
 
@@ -1703,7 +1408,7 @@ UpdateStats(Oid relid, long reltuples)
                        reltuples = 1000;
                }
                else
-                       reltuples = relpages * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
+                       reltuples = ((double) relpages) * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
        }
 
        /*
@@ -1711,27 +1416,26 @@ UpdateStats(Oid relid, long 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;
 
-       /* ----------------
-        *      Update statistics in pg_class.
-        * ----------------
+       /*
+        * Update statistics in pg_class.
         */
        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.
+                * 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
        {
@@ -1739,23 +1443,18 @@ UpdateStats(Oid relid, long reltuples)
 
                for (i = 0; i < Natts_pg_class; i++)
                {
-                       nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' ';
+                       nulls[i] = ' ';
                        replace[i] = ' ';
                        values[i] = (Datum) NULL;
                }
 
                replace[Anum_pg_class_relpages - 1] = 'r';
-               values[Anum_pg_class_relpages - 1] = (Datum) relpages;
+               values[Anum_pg_class_relpages - 1] = Int32GetDatum((int32) relpages);
                replace[Anum_pg_class_reltuples - 1] = 'r';
-               values[Anum_pg_class_reltuples - 1] = (Datum) reltuples;
+               values[Anum_pg_class_reltuples - 1] = Float4GetDatum((float4) reltuples);
                newtup = heap_modifytuple(tuple, pg_class, values, nulls, replace);
-               heap_update(pg_class, &tuple->t_self, newtup, NULL);
-               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);
-               }
+               simple_heap_update(pg_class, &tuple->t_self, newtup);
+               CatalogUpdateIndexes(pg_class, newtup);
                heap_freetuple(newtup);
        }
 
@@ -1765,47 +1464,81 @@ UpdateStats(Oid relid, long 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];
-       long            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);
 
@@ -1819,12 +1552,11 @@ 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);
-               ExecSetSlotDescriptor(slot, heapDescriptor);
+               ExecSetSlotDescriptor(slot, heapDescriptor, false);
        }
        else
        {
@@ -1832,161 +1564,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;
+       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);
+               bool            tupleIsAlive;
 
-               reltuples++;
+               CHECK_FOR_INTERRUPTS();
 
-#ifndef OMIT_PARTIAL_INDEX
-               /*
-                * 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++;
-                               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++;
 
-               /* ----------------
-                *      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
@@ -2035,90 +1781,82 @@ 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.
-        * ----------------
+       /*
+        * 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 */
+       /* Open the parent heap relation */
        heapRelation = heap_open(heapId, ExclusiveLock);
        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");
 
-#ifndef OLD_FILE_NAMING
-       if (!inplace)
-               setNewRelfilenode(iRel);
-#endif /* OLD_FILE_NAMING */
-       /* 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.
-                */
+                * Release any buffers associated with this index.      If they're
+                * dirty, they're just dropped without bothering to flush to disk.
+                */
                DropRelationBuffers(iRel);
 
                /* 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
-        * give up the locks we hold on them).  So we're done.
+        * give up the locks we hold on them).  So we're done.
         */
 
        SetReindexProcessing(old);
@@ -2138,7 +1876,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;
        }
@@ -2166,32 +1904,40 @@ 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;
 
-       bool    deactivate_needed, overwrite, upd_pg_class_inplace;
-#ifdef OLD_FILE_NAMING
-       overwrite = upd_pg_class_inplace = deactivate_needed = true;    
-#else
-       Relation rel;
-       overwrite = upd_pg_class_inplace = deactivate_needed = false;   
        /*
-        * avoid heap_update() pg_class tuples while processing
-        * reindex for pg_class. 
-        */
+        * avoid heap_update() pg_class tuples while processing reindex for
+        * pg_class.
+        */
        if (IsIgnoringSystemIndexes())
                upd_pg_class_inplace = true;
+
+       /*
+        * Ensure to hold an exclusive lock throughout the transaction. The
+        * lock could be less intensive 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
-       /* 
-        * nailed relations are never updated.
-        * We couldn't keep the consistency between the relation
-        * descriptors and pg_class tuples.
-        */
+#ifndef ENABLE_REINDEX_NAILED_RELATIONS
+
+       /*
+        * nailed relations are never updated. We couldn't keep the
+        * consistency between the relation descriptors and pg_class tuples.
+        */
        if (rel->rd_isnailed)
        {
                if (IsIgnoringSystemIndexes())
@@ -2202,9 +1948,28 @@ reindex_relation(Oid relid, bool force)
                else
                        elog(ERROR, "the target relation %u is nailed", relid);
        }
-#endif /* ENABLE_REINDEX_NAILED_RELATIONS */
-       RelationClose(rel);
-#endif /* OLD_FILE_NAMING */
+#endif   /* ENABLE_REINDEX_NAILED_RELATIONS */
+
+       /*
+        * Shared system indexes must be overwritten because it's impossible
+        * to update pg_class tuples of all databases.
+        */
+       if (rel->rd_rel->relisshared)
+       {
+               if (IsIgnoringSystemIndexes())
+               {
+                       overwrite = true;
+                       deactivate_needed = true;
+               }
+               else
+                       elog(ERROR, "the target relation %u is shared", relid);
+       }
+
+       /*
+        * Continue to hold the lock.
+        */
+       heap_close(rel, NoLock);
+
        old = SetReindexProcessing(true);
        if (deactivate_needed)
        {
@@ -2223,10 +1988,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);
 
@@ -2241,27 +2005,28 @@ reindex_relation(Oid relid, bool force)
        heap_endscan(scan);
        heap_close(indexRelation, AccessShareLock);
        if (reindexed)
-       /*
-        * Ok,we could use the reindexed indexes of the target
-        * system relation now.
-        */
-       { 
+       {
+               /*
+                * Ok,we could use the reindexed indexes of the target system
+                * relation now.
+                */
                if (deactivate_needed)
                {
                        if (!overwrite && relid == RelOid_pg_class)
                        {
-                               /* 
-                                * For pg_class, relhasindex should be set
-                                * to true here in place.
+                               /*
+                                * For pg_class, relhasindex should be set to true here in
+                                * place.
                                 */
-                               setRelhasindex(relid, true);
+                               setRelhasindex(relid, true, false, InvalidOid);
                                CommandCounterIncrement();
-                               /* 
-                                * However the following setRelhasindex()
-                                * is needed to keep consistency with WAL.
+
+                               /*
+                                * However the following setRelhasindex() is needed to
+                                * keep consistency with WAL.
                                 */
                        }
-                       setRelhasindex(relid, true);
+                       setRelhasindex(relid, true, false, InvalidOid);
                }
        }
        SetReindexProcessing(old);