]> granicus.if.org Git - postgresql/blobdiff - src/backend/catalog/pg_type.c
Standard pgindent run for 8.1.
[postgresql] / src / backend / catalog / pg_type.c
index 6878691241d10ef9327e35389e7e62e00afa4540..ab250b02ea9aa77246e85f1f05693507e51b0be1 100644 (file)
  * pg_type.c
  *       routines to support manipulation of the pg_type relation
  *
- * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.69 2002/03/20 19:43:38 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.104 2005/10/15 02:49:14 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/heapam.h"
-#include "catalog/catname.h"
+#include "catalog/dependency.h"
 #include "catalog/indexing.h"
+#include "catalog/pg_namespace.h"
+#include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
-#include "parser/parse_func.h"
 #include "utils/builtins.h"
-#include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
 
-static Oid TypeShellMakeWithOpenRelation(Relation pg_type_desc,
-                                                         char *typeName);
-
-/* ----------------------------------------------------------------
- *             TypeGetWithOpenRelation
- *
- *             preforms a scan on pg_type for a type tuple with the
- *             given type name.
- * ----------------------------------------------------------------
- *             pg_type_desc                     -- reldesc for pg_type
- *             typeName                                 -- name of type to be fetched
- *             defined                                  -- has the type been defined?
- */
-static Oid
-TypeGetWithOpenRelation(Relation pg_type_desc,
-                                               char *typeName,
-                                               bool *defined)
-{
-       HeapScanDesc scan;
-       HeapTuple       tup;
-       Oid                     typoid;
-       ScanKeyData typeKey[1];
-
-       /*
-        * initialize the scan key and begin a scan of pg_type
-        */
-       ScanKeyEntryInitialize(&typeKey[0],
-                                                  0,
-                                                  Anum_pg_type_typname,
-                                                  F_NAMEEQ,
-                                                  PointerGetDatum(typeName));
-
-       scan = heap_beginscan(pg_type_desc,
-                                                 0,
-                                                 SnapshotSelf, /* cache? */
-                                                 1,
-                                                 typeKey);
-
-       /*
-        * get the type tuple, if it exists.
-        */
-       tup = heap_getnext(scan, 0);
-
-       /*
-        * if no type tuple exists for the given type name, then end the scan
-        * and return appropriate information.
-        */
-       if (!HeapTupleIsValid(tup))
-       {
-               heap_endscan(scan);
-               *defined = false;
-               return InvalidOid;
-       }
-
-       /*
-        * here, the type tuple does exist so we pull information from the
-        * typisdefined field of the tuple and return the tuple's oid, which
-        * is the oid of the type.
-        */
-       *defined = (bool) ((Form_pg_type) GETSTRUCT(tup))->typisdefined;
-       typoid = tup->t_data->t_oid;
-
-       heap_endscan(scan);
-
-       return typoid;
-}
-
 /* ----------------------------------------------------------------
- *             TypeGet
- *
- *             Finds the ObjectId of a type, even if uncommitted; "defined"
- *             is only set if the type has actually been defined, i.e., if
- *             the type tuple is not a shell.
+ *             TypeShellMake
  *
- *             Note: the meat of this function is now in the function
- *                       TypeGetWithOpenRelation().  -cim 6/15/90
+ *             This procedure inserts a "shell" tuple into the type
+ *             relation.  The type tuple inserted has invalid values
+ *             and in particular, the "typisdefined" field is false.
  *
- *             Also called from util/remove.c
+ *             This is used so that a tuple exists in the catalogs.
+ *             The invalid fields should be fixed up sometime after
+ *             this routine is called, and then the "typeisdefined"
+ *             field is set to true. -cim 6/15/90
  * ----------------------------------------------------------------
  */
 Oid
-TypeGet(char *typeName,                        /* name of type to be fetched */
-               bool *defined)                  /* has the type been defined? */
+TypeShellMake(const char *typeName, Oid typeNamespace)
 {
        Relation        pg_type_desc;
-       Oid                     typeoid;
-
-       /*
-        * open the pg_type relation
-        */
-       pg_type_desc = heap_openr(TypeRelationName, AccessShareLock);
-
-       /*
-        * scan the type relation for the information we want
-        */
-       typeoid = TypeGetWithOpenRelation(pg_type_desc,
-                                                                         typeName,
-                                                                         defined);
-
-       /*
-        * close the type relation and return the type oid.
-        */
-       heap_close(pg_type_desc, AccessShareLock);
-
-       return typeoid;
-}
-
-/* ----------------------------------------------------------------
- *             TypeShellMakeWithOpenRelation
- *
- * ----------------------------------------------------------------
- */
-static Oid
-TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName)
-{
+       TupleDesc       tupDesc;
        int                     i;
        HeapTuple       tup;
        Datum           values[Natts_pg_type];
        char            nulls[Natts_pg_type];
        Oid                     typoid;
        NameData        name;
-       TupleDesc       tupDesc;
+
+       Assert(PointerIsValid(typeName));
+
+       /*
+        * open pg_type
+        */
+       pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
+       tupDesc = pg_type_desc->rd_att;
 
        /*
         * initialize our *nulls and *values arrays
@@ -162,93 +73,65 @@ TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName)
         */
        i = 0;
        namestrcpy(&name, typeName);
-       values[i++] = NameGetDatum(&name);      /* 1 */
-       values[i++] = ObjectIdGetDatum(InvalidOid); /* 2 */
-       values[i++] = Int16GetDatum(0);         /* 3 */
-       values[i++] = Int16GetDatum(0);         /* 4 */
-       values[i++] = BoolGetDatum(false);      /* 5 */
-       values[i++] = CharGetDatum(0);          /* 6 */
-       values[i++] = BoolGetDatum(false);      /* 7 */
-       values[i++] = CharGetDatum(0);          /* 8 */
-       values[i++] = ObjectIdGetDatum(InvalidOid); /* 9 */
-       values[i++] = ObjectIdGetDatum(InvalidOid); /* 10 */
-       values[i++] = ObjectIdGetDatum(InvalidOid); /* 11 */
-       values[i++] = ObjectIdGetDatum(InvalidOid); /* 12 */
-       values[i++] = ObjectIdGetDatum(InvalidOid); /* 13 */
-       values[i++] = ObjectIdGetDatum(InvalidOid); /* 14 */
-       values[i++] = CharGetDatum('i');                        /* 15 */
-       values[i++] = CharGetDatum('p');                        /* 16 */
-       values[i++] = BoolGetDatum(false);                      /* 17 */
-       values[i++] = ObjectIdGetDatum(InvalidOid);     /* 18 */
-       values[i++] = Int32GetDatum(-1);                        /* 19 */
-       values[i++] = Int32GetDatum(0);                         /* 20 */
-       nulls[i++] = 'n';                       /* 21 */
-       nulls[i++] = 'n';                       /* 22 */
+       values[i++] = NameGetDatum(&name);      /* typname */
+       values[i++] = ObjectIdGetDatum(typeNamespace);          /* typnamespace */
+       values[i++] = ObjectIdGetDatum(GetUserId());            /* typowner */
+       values[i++] = Int16GetDatum(0);         /* typlen */
+       values[i++] = BoolGetDatum(false);      /* typbyval */
+       values[i++] = CharGetDatum(0);          /* typtype */
+       values[i++] = BoolGetDatum(false);      /* typisdefined */
+       values[i++] = CharGetDatum(0);          /* typdelim */
+       values[i++] = ObjectIdGetDatum(InvalidOid); /* typrelid */
+       values[i++] = ObjectIdGetDatum(InvalidOid); /* typelem */
+       values[i++] = ObjectIdGetDatum(InvalidOid); /* typinput */
+       values[i++] = ObjectIdGetDatum(InvalidOid); /* typoutput */
+       values[i++] = ObjectIdGetDatum(InvalidOid); /* typreceive */
+       values[i++] = ObjectIdGetDatum(InvalidOid); /* typsend */
+       values[i++] = ObjectIdGetDatum(InvalidOid); /* typanalyze */
+       values[i++] = CharGetDatum('i');        /* typalign */
+       values[i++] = CharGetDatum('p');        /* typstorage */
+       values[i++] = BoolGetDatum(false);      /* typnotnull */
+       values[i++] = ObjectIdGetDatum(InvalidOid); /* typbasetype */
+       values[i++] = Int32GetDatum(-1);        /* typtypmod */
+       values[i++] = Int32GetDatum(0);         /* typndims */
+       nulls[i++] = 'n';                       /* typdefaultbin */
+       nulls[i++] = 'n';                       /* typdefault */
 
        /*
-        * create a new type tuple with FormHeapTuple
+        * create a new type tuple
         */
-       tupDesc = pg_type_desc->rd_att;
-
        tup = heap_formtuple(tupDesc, values, nulls);
 
        /*
         * insert the tuple in the relation and get the tuple's oid.
         */
-       heap_insert(pg_type_desc, tup);
-       typoid = tup->t_data->t_oid;
-
-       if (RelationGetForm(pg_type_desc)->relhasindex)
-       {
-               Relation        idescs[Num_pg_type_indices];
-
-               CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
-               CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
-               CatalogCloseIndices(Num_pg_type_indices, idescs);
-       }
-
-       /*
-        * free the tuple and return the type-oid
-        */
-       heap_freetuple(tup);
+       typoid = simple_heap_insert(pg_type_desc, tup);
 
-       return typoid;
-}
-
-/* ----------------------------------------------------------------
- *             TypeShellMake
- *
- *             This procedure inserts a "shell" tuple into the type
- *             relation.  The type tuple inserted has invalid values
- *             and in particular, the "typisdefined" field is false.
- *
- *             This is used so that a tuple exists in the catalogs.
- *             The invalid fields should be fixed up sometime after
- *             this routine is called, and then the "typeisdefined"
- *             field is set to true. -cim 6/15/90
- * ----------------------------------------------------------------
- */
-Oid
-TypeShellMake(char *typeName)
-{
-       Relation        pg_type_desc;
-       Oid                     typoid;
-
-       Assert(PointerIsValid(typeName));
-
-       /*
-        * open pg_type
-        */
-       pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
+       CatalogUpdateIndexes(pg_type_desc, tup);
 
        /*
-        * insert the shell tuple
+        * Create dependencies.  We can/must skip this in bootstrap mode.
         */
-       typoid = TypeShellMakeWithOpenRelation(pg_type_desc, typeName);
+       if (!IsBootstrapProcessingMode())
+               GenerateTypeDependencies(typeNamespace,
+                                                                typoid,
+                                                                InvalidOid,
+                                                                0,
+                                                                GetUserId(),
+                                                                InvalidOid,
+                                                                InvalidOid,
+                                                                InvalidOid,
+                                                                InvalidOid,
+                                                                InvalidOid,
+                                                                InvalidOid,
+                                                                InvalidOid,
+                                                                NULL,
+                                                                false);
 
        /*
-        * close pg_type and return the tuple's oid.
+        * clean up and return the type-oid
         */
+       heap_freetuple(tup);
        heap_close(pg_type_desc, RowExclusiveLock);
 
        return typoid;
@@ -259,101 +142,73 @@ TypeShellMake(char *typeName)
  *
  *             This does all the necessary work needed to define a new type.
  *
- * NOTE: if assignedTypeOid is not InvalidOid, then that OID is assigned to
- * the new type (which, therefore, cannot already exist as a shell type).
- * This hack is only intended for use in creating a relation's associated
- * type, where we need to have created the relation tuple already.
+ *             Returns the OID assigned to the new type.
  * ----------------------------------------------------------------
  */
 Oid
-TypeCreate(char *typeName,
-                  Oid assignedTypeOid,
-                  Oid relationOid,                     /* only for 'c'atalog typeTypes */
+TypeCreate(const char *typeName,
+                  Oid typeNamespace,
+                  Oid relationOid,             /* only for 'c'atalog types */
+                  char relationKind,   /* ditto */
                   int16 internalSize,
-                  int16 externalSize,
                   char typeType,
                   char typDelim,
-                  char *inputProcedure,
-                  char *outputProcedure,
-                  char *receiveProcedure,
-                  char *sendProcedure,
-                  char *elementTypeName,
-                  char *baseTypeName,
-                  char *defaultTypeValue,      /* human readable rep */
+                  Oid inputProcedure,
+                  Oid outputProcedure,
+                  Oid receiveProcedure,
+                  Oid sendProcedure,
+                  Oid analyzeProcedure,
+                  Oid elementType,
+                  Oid baseType,
+                  const char *defaultTypeValue,                /* human readable rep */
                   char *defaultTypeBin,        /* cooked rep */
                   bool passedByValue,
                   char alignment,
                   char storage,
                   int32 typeMod,
-                  int32 typNDims,                      /* Array dimensions for baseTypeName */
+                  int32 typNDims,              /* Array dimensions for baseType */
                   bool typeNotNull)
 {
-       int                     i,
-                               j;
        Relation        pg_type_desc;
-       HeapScanDesc pg_type_scan;
        Oid                     typeObjectId;
-       Oid                     elementObjectId = InvalidOid;
-       Oid                     baseObjectId = InvalidOid;
+       bool            rebuildDeps = false;
        HeapTuple       tup;
        char            nulls[Natts_pg_type];
        char            replaces[Natts_pg_type];
        Datum           values[Natts_pg_type];
-       char       *procname;
-       char       *procs[4];
-       bool            defined;
        NameData        name;
-       TupleDesc       tupDesc;
-       Oid                     argList[FUNC_MAX_ARGS];
-       ScanKeyData typeKey[1];
-
-       /*
-        * check that the type is not already defined.  It might exist as a
-        * shell type, however (but only if assignedTypeOid is not given).
-        */
-       typeObjectId = TypeGet(typeName, &defined);
-       if (OidIsValid(typeObjectId) &&
-               (defined || assignedTypeOid != InvalidOid))
-               elog(ERROR, "type named %s already exists", typeName);
-
-       /*
-        * if this type has an associated elementType, then we check that it
-        * is defined.
-        */
-       if (elementTypeName)
-       {
-               elementObjectId = TypeGet(elementTypeName, &defined);
-               if (!defined)
-                       elog(ERROR, "type %s does not exist", elementTypeName);
-       }
-
-       /*
-        * if this type has an associated baseType, then we check that it
-        * is defined.
-        */
-       if (baseTypeName)
-       {
-               baseObjectId = TypeGet(baseTypeName, &defined);
-               if (!defined)
-                       elog(ERROR, "type %s does not exist", baseTypeName);
-       }
+       int                     i;
 
        /*
-        * validate size specifications: either positive (fixed-length) or -1
-        * (variable-length).
+        * We assume that the caller validated the arguments individually, but did
+        * not check for bad combinations.
+        *
+        * Validate size specifications: either positive (fixed-length) or -1
+        * (varlena) or -2 (cstring).  Pass-by-value types must have a fixed
+        * length not more than sizeof(Datum).
         */
-       if (!(internalSize > 0 || internalSize == -1))
-               elog(ERROR, "TypeCreate: invalid type internal size %d",
-                        internalSize);
-       if (!(externalSize > 0 || externalSize == -1))
-               elog(ERROR, "TypeCreate: invalid type external size %d",
-                        externalSize);
-
-       if (internalSize != -1 && storage != 'p')
-               elog(ERROR, "TypeCreate: fixed size types must have storage PLAIN");
+       if (!(internalSize > 0 ||
+                 internalSize == -1 ||
+                 internalSize == -2))
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                errmsg("invalid type internal size %d",
+                                               internalSize)));
+       if (passedByValue &&
+               (internalSize <= 0 || internalSize > (int16) sizeof(Datum)))
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                          errmsg("internal size %d is invalid for passed-by-value type",
+                                         internalSize)));
+
+       /* Only varlena types can be toasted */
+       if (storage != 'p' && internalSize != -1)
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                errmsg("fixed-size types must have storage PLAIN")));
 
        /*
-        * initialize arrays needed by FormHeapTuple
+        * initialize arrays needed for heap_formtuple or heap_modifytuple
         */
        for (i = 0; i < Natts_pg_type; ++i)
        {
@@ -367,105 +222,38 @@ TypeCreate(char *typeName,
         */
        i = 0;
        namestrcpy(&name, typeName);
-       values[i++] = NameGetDatum(&name);      /* 1 */
-       values[i++] = Int32GetDatum(GetUserId());       /* 2 */
-       values[i++] = Int16GetDatum(internalSize);      /* 3 */
-       values[i++] = Int16GetDatum(externalSize);      /* 4 */
-       values[i++] = BoolGetDatum(passedByValue);      /* 5 */
-       values[i++] = CharGetDatum(typeType);           /* 6 */
-       values[i++] = BoolGetDatum(true);       /* 7 */
-       values[i++] = CharGetDatum(typDelim);           /* 8 */
-       values[i++] = ObjectIdGetDatum(typeType == 'c' ? relationOid : InvalidOid); /* 9 */
-       values[i++] = ObjectIdGetDatum(elementObjectId);        /* 10 */
-
-       procs[0] = inputProcedure;
-       procs[1] = outputProcedure;
-       procs[2] = (receiveProcedure) ? receiveProcedure : inputProcedure;
-       procs[3] = (sendProcedure) ? sendProcedure : outputProcedure;
-
-       for (j = 0; j < 4; ++j)
-       {
-               Oid                     procOid;
-
-               procname = procs[j];
-
-               /*
-                * First look for a 1-argument func with all argtypes 0. This is
-                * valid for all four kinds of procedure.
-                */
-               MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
-
-               procOid = GetSysCacheOid(PROCNAME,
-                                                                PointerGetDatum(procname),
-                                                                Int32GetDatum(1),
-                                                                PointerGetDatum(argList),
-                                                                0);
-
-               if (!OidIsValid(procOid))
-               {
-                       /*
-                        * For array types, the input procedures may take 3 args (data
-                        * value, element OID, atttypmod); the pg_proc argtype
-                        * signature is 0,OIDOID,INT4OID.  The output procedures may
-                        * take 2 args (data value, element OID).
-                        */
-                       if (OidIsValid(elementObjectId) || OidIsValid(baseObjectId))
-                       {
-                               int                     nargs;
-
-                               if (j % 2)
-                               {
-                                       /* output proc */
-                                       nargs = 2;
-                                       argList[1] = OIDOID;
-                               }
-                               else
-                               {
-                                       /* input proc */
-                                       nargs = 3;
-                                       argList[1] = OIDOID;
-                                       argList[2] = INT4OID;
-                               }
-                               procOid = GetSysCacheOid(PROCNAME,
-                                                                                PointerGetDatum(procname),
-                                                                                Int32GetDatum(nargs),
-                                                                                PointerGetDatum(argList),
-                                                                                0);
-                       }
-
-                       if (!OidIsValid(procOid))
-                               func_error("TypeCreate", procname, 1, argList, NULL);
-               }
-
-               values[i++] = ObjectIdGetDatum(procOid);                /* 11 - 14 */
-       }
-
-       /*
-        * set default alignment
-        */
-       values[i++] = CharGetDatum(alignment);          /* 15 */
-
-       /*
-        * set default storage for TOAST
-        */
-       values[i++] = CharGetDatum(storage);            /* 16 */
-
-       /* set typnotnull, typbasetype, typtypmod, typndims */
-       values[i++] = BoolGetDatum(typeNotNull);                /* 17 */
-       values[i++] = ObjectIdGetDatum(baseObjectId);   /* 18 */
-       values[i++] = Int32GetDatum(typeMod);                   /* 19 */
-       values[i++] = Int32GetDatum(typNDims);                  /* 20 */
+       values[i++] = NameGetDatum(&name);      /* typname */
+       values[i++] = ObjectIdGetDatum(typeNamespace);          /* typnamespace */
+       values[i++] = ObjectIdGetDatum(GetUserId());            /* typowner */
+       values[i++] = Int16GetDatum(internalSize);      /* typlen */
+       values[i++] = BoolGetDatum(passedByValue);      /* typbyval */
+       values[i++] = CharGetDatum(typeType);           /* typtype */
+       values[i++] = BoolGetDatum(true);       /* typisdefined */
+       values[i++] = CharGetDatum(typDelim);           /* typdelim */
+       values[i++] = ObjectIdGetDatum(typeType == 'c' ? relationOid : InvalidOid); /* typrelid */
+       values[i++] = ObjectIdGetDatum(elementType);            /* typelem */
+       values[i++] = ObjectIdGetDatum(inputProcedure);         /* typinput */
+       values[i++] = ObjectIdGetDatum(outputProcedure);        /* typoutput */
+       values[i++] = ObjectIdGetDatum(receiveProcedure);       /* typreceive */
+       values[i++] = ObjectIdGetDatum(sendProcedure);          /* typsend */
+       values[i++] = ObjectIdGetDatum(analyzeProcedure);       /* typanalyze */
+       values[i++] = CharGetDatum(alignment);          /* typalign */
+       values[i++] = CharGetDatum(storage);            /* typstorage */
+       values[i++] = BoolGetDatum(typeNotNull);        /* typnotnull */
+       values[i++] = ObjectIdGetDatum(baseType);       /* typbasetype */
+       values[i++] = Int32GetDatum(typeMod);           /* typtypmod */
+       values[i++] = Int32GetDatum(typNDims);          /* typndims */
 
        /*
-        * initialize the default binary value for this type.  Check for
-        * nulls of course.
+        * initialize the default binary value for this type.  Check for nulls of
+        * course.
         */
        if (defaultTypeBin)
                values[i] = DirectFunctionCall1(textin,
                                                                                CStringGetDatum(defaultTypeBin));
        else
                nulls[i] = 'n';
-       i++;                                            /* 21 */
+       i++;                                            /* typdefaultbin */
 
        /*
         * initialize the default value for this type.
@@ -475,115 +263,268 @@ TypeCreate(char *typeName,
                                                                                CStringGetDatum(defaultTypeValue));
        else
                nulls[i] = 'n';
-       i++;                                            /* 22 */
+       i++;                                            /* typdefault */
 
        /*
-        * open pg_type and begin a scan for the type name.
+        * open pg_type and prepare to insert or update a row.
+        *
+        * NOTE: updating will not work correctly in bootstrap mode; but we don't
+        * expect to be overwriting any shell types in bootstrap mode.
         */
-       pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
-
-       ScanKeyEntryInitialize(&typeKey[0],
-                                                  0,
-                                                  Anum_pg_type_typname,
-                                                  F_NAMEEQ,
-                                                  PointerGetDatum(typeName));
+       pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
 
-       pg_type_scan = heap_beginscan(pg_type_desc,
-                                                                 0,
-                                                                 SnapshotSelf, /* cache? */
-                                                                 1,
-                                                                 typeKey);
-
-       /*
-        * define the type either by adding a tuple to the type relation, or
-        * by updating the fields of the "shell" tuple already there.
-        */
-       tup = heap_getnext(pg_type_scan, 0);
+       tup = SearchSysCacheCopy(TYPENAMENSP,
+                                                        CStringGetDatum(typeName),
+                                                        ObjectIdGetDatum(typeNamespace),
+                                                        0, 0);
        if (HeapTupleIsValid(tup))
        {
-               /* should not happen given prior test? */
-               if (assignedTypeOid != InvalidOid)
-                       elog(ERROR, "type %s already exists", typeName);
+               /*
+                * check that the type is not already defined.  It may exist as a
+                * shell type, however.
+                */
+               if (((Form_pg_type) GETSTRUCT(tup))->typisdefined)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_DUPLICATE_OBJECT),
+                                        errmsg("type \"%s\" already exists", typeName)));
 
+               /*
+                * Okay to update existing "shell" type tuple
+                */
                tup = heap_modifytuple(tup,
-                                                          pg_type_desc,
+                                                          RelationGetDescr(pg_type_desc),
                                                           values,
                                                           nulls,
                                                           replaces);
 
                simple_heap_update(pg_type_desc, &tup->t_self, tup);
 
-               typeObjectId = tup->t_data->t_oid;
+               typeObjectId = HeapTupleGetOid(tup);
+
+               rebuildDeps = true;             /* get rid of shell type's dependencies */
        }
        else
        {
-               tupDesc = pg_type_desc->rd_att;
-
-               tup = heap_formtuple(tupDesc,
+               tup = heap_formtuple(RelationGetDescr(pg_type_desc),
                                                         values,
                                                         nulls);
 
-               /* preassign tuple Oid, if one was given */
-               tup->t_data->t_oid = assignedTypeOid;
+               typeObjectId = simple_heap_insert(pg_type_desc, tup);
+       }
 
-               heap_insert(pg_type_desc, tup);
+       /* Update indexes */
+       CatalogUpdateIndexes(pg_type_desc, tup);
 
-               typeObjectId = tup->t_data->t_oid;
-       }
+       /*
+        * Create dependencies.  We can/must skip this in bootstrap mode.
+        */
+       if (!IsBootstrapProcessingMode())
+               GenerateTypeDependencies(typeNamespace,
+                                                                typeObjectId,
+                                                                relationOid,
+                                                                relationKind,
+                                                                GetUserId(),
+                                                                inputProcedure,
+                                                                outputProcedure,
+                                                                receiveProcedure,
+                                                                sendProcedure,
+                                                                analyzeProcedure,
+                                                                elementType,
+                                                                baseType,
+                                                                (defaultTypeBin ?
+                                                                 stringToNode(defaultTypeBin) :
+                                                                 NULL),
+                                                                rebuildDeps);
 
        /*
         * finish up
         */
-       heap_endscan(pg_type_scan);
+       heap_close(pg_type_desc, RowExclusiveLock);
+
+       return typeObjectId;
+}
+
+/*
+ * GenerateTypeDependencies: build the dependencies needed for a type
+ *
+ * If rebuild is true, we remove existing dependencies and rebuild them
+ * from scratch.  This is needed for ALTER TYPE, and also when replacing
+ * a shell type.
+ *
+ * NOTE: a shell type will have a dependency to its namespace, and no others.
+ */
+void
+GenerateTypeDependencies(Oid typeNamespace,
+                                                Oid typeObjectId,
+                                                Oid relationOid,               /* only for 'c'atalog types */
+                                                char relationKind,             /* ditto */
+                                                Oid owner,
+                                                Oid inputProcedure,
+                                                Oid outputProcedure,
+                                                Oid receiveProcedure,
+                                                Oid sendProcedure,
+                                                Oid analyzeProcedure,
+                                                Oid elementType,
+                                                Oid baseType,
+                                                Node *defaultExpr,
+                                                bool rebuild)
+{
+       ObjectAddress myself,
+                               referenced;
+
+       if (rebuild)
+       {
+               deleteDependencyRecordsFor(TypeRelationId, typeObjectId);
+               deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId);
+       }
+
+       myself.classId = TypeRelationId;
+       myself.objectId = typeObjectId;
+       myself.objectSubId = 0;
+
+       /* dependency on namespace */
+       /* skip for relation rowtype, since we have indirect dependency */
+       if (!OidIsValid(relationOid))
+       {
+               referenced.classId = NamespaceRelationId;
+               referenced.objectId = typeNamespace;
+               referenced.objectSubId = 0;
+               recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+       }
+
+       /* Normal dependencies on the I/O functions */
+       if (OidIsValid(inputProcedure))
+       {
+               referenced.classId = ProcedureRelationId;
+               referenced.objectId = inputProcedure;
+               referenced.objectSubId = 0;
+               recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+       }
+
+       if (OidIsValid(outputProcedure))
+       {
+               referenced.classId = ProcedureRelationId;
+               referenced.objectId = outputProcedure;
+               referenced.objectSubId = 0;
+               recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+       }
+
+       if (OidIsValid(receiveProcedure))
+       {
+               referenced.classId = ProcedureRelationId;
+               referenced.objectId = receiveProcedure;
+               referenced.objectSubId = 0;
+               recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+       }
+
+       if (OidIsValid(sendProcedure))
+       {
+               referenced.classId = ProcedureRelationId;
+               referenced.objectId = sendProcedure;
+               referenced.objectSubId = 0;
+               recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+       }
+
+       if (OidIsValid(analyzeProcedure))
+       {
+               referenced.classId = ProcedureRelationId;
+               referenced.objectId = analyzeProcedure;
+               referenced.objectSubId = 0;
+               recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+       }
+
+       /*
+        * If the type is a rowtype for a relation, mark it as internally
+        * dependent on the relation, *unless* it is a stand-alone composite type
+        * relation. For the latter case, we have to reverse the dependency.
+        *
+        * In the former case, this allows the type to be auto-dropped when the
+        * relation is, and not otherwise. And in the latter, of course we get the
+        * opposite effect.
+        */
+       if (OidIsValid(relationOid))
+       {
+               referenced.classId = RelationRelationId;
+               referenced.objectId = relationOid;
+               referenced.objectSubId = 0;
+
+               if (relationKind != RELKIND_COMPOSITE_TYPE)
+                       recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
+               else
+                       recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
+       }
 
-       if (RelationGetForm(pg_type_desc)->relhasindex)
+       /*
+        * If the type is an array type, mark it auto-dependent on the base type.
+        * (This is a compromise between the typical case where the array type is
+        * automatically generated and the case where it is manually created: we'd
+        * prefer INTERNAL for the former case and NORMAL for the latter.)
+        */
+       if (OidIsValid(elementType))
        {
-               Relation        idescs[Num_pg_type_indices];
+               referenced.classId = TypeRelationId;
+               referenced.objectId = elementType;
+               referenced.objectSubId = 0;
+               recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
+       }
 
-               CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
-               CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
-               CatalogCloseIndices(Num_pg_type_indices, idescs);
+       /* Normal dependency from a domain to its base type. */
+       if (OidIsValid(baseType))
+       {
+               referenced.classId = TypeRelationId;
+               referenced.objectId = baseType;
+               referenced.objectSubId = 0;
+               recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
        }
 
-       heap_close(pg_type_desc, RowExclusiveLock);
+       /* Normal dependency on the default expression. */
+       if (defaultExpr)
+               recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
 
-       return typeObjectId;
+       /* Shared dependency on owner. */
+       recordDependencyOnOwner(TypeRelationId, typeObjectId, owner);
 }
 
-/* ----------------------------------------------------------------
- *             TypeRename
- *
+/*
+ * TypeRename
  *             This renames a type
- * ----------------------------------------------------------------
+ *
+ * Note: any associated array type is *not* renamed; caller must make
+ * another call to handle that case.  Currently this is only used for
+ * renaming types associated with tables, for which there are no arrays.
  */
 void
-TypeRename(const char *oldTypeName, const char *newTypeName)
+TypeRename(const char *oldTypeName, Oid typeNamespace,
+                  const char *newTypeName)
 {
        Relation        pg_type_desc;
-       Relation        idescs[Num_pg_type_indices];
        HeapTuple       tuple;
 
-       pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
+       pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
 
-       tuple = SearchSysCacheCopy(TYPENAME,
-                                                          PointerGetDatum(oldTypeName),
-                                                          0, 0, 0);
+       tuple = SearchSysCacheCopy(TYPENAMENSP,
+                                                          CStringGetDatum(oldTypeName),
+                                                          ObjectIdGetDatum(typeNamespace),
+                                                          0, 0);
        if (!HeapTupleIsValid(tuple))
-               elog(ERROR, "type %s does not exist", oldTypeName);
-
-       if (SearchSysCacheExists(TYPENAME,
-                                                        PointerGetDatum(newTypeName),
-                                                        0, 0, 0))
-               elog(ERROR, "type named %s already exists", newTypeName);
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                errmsg("type \"%s\" does not exist", oldTypeName)));
+
+       if (SearchSysCacheExists(TYPENAMENSP,
+                                                        CStringGetDatum(newTypeName),
+                                                        ObjectIdGetDatum(typeNamespace),
+                                                        0, 0))
+               ereport(ERROR,
+                               (errcode(ERRCODE_DUPLICATE_OBJECT),
+                                errmsg("type \"%s\" already exists", newTypeName)));
 
        namestrcpy(&(((Form_pg_type) GETSTRUCT(tuple))->typname), newTypeName);
 
        simple_heap_update(pg_type_desc, &tuple->t_self, tuple);
 
-       /* update the system catalog indices */
-       CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
-       CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tuple);
-       CatalogCloseIndices(Num_pg_type_indices, idescs);
+       /* update the system catalog indexes */
+       CatalogUpdateIndexes(pg_type_desc, tuple);
 
        heap_freetuple(tuple);
        heap_close(pg_type_desc, RowExclusiveLock);
@@ -596,7 +537,7 @@ TypeRename(const char *oldTypeName, const char *newTypeName)
  * the caller is responsible for pfreeing the result
  */
 char *
-makeArrayTypeName(char *typeName)
+makeArrayTypeName(const char *typeName)
 {
        char       *arr;