]> 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 6c6a135a0b9a0e567d0219f6fbbd5576d39f5bfc..ab250b02ea9aa77246e85f1f05693507e51b0be1 100644 (file)
@@ -3,21 +3,22 @@
  * pg_type.c
  *       routines to support manipulation of the pg_type relation
  *
- * Portions Copyright (c) 1996-2002, 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.79 2002/08/24 15:00:46 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 "utils/builtins.h"
@@ -55,7 +56,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
        /*
         * open pg_type
         */
-       pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
+       pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
        tupDesc = pg_type_desc->rd_att;
 
        /*
@@ -73,8 +74,8 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
        i = 0;
        namestrcpy(&name, typeName);
        values[i++] = NameGetDatum(&name);      /* typname */
-       values[i++] = ObjectIdGetDatum(typeNamespace); /* typnamespace */
-       values[i++] = ObjectIdGetDatum(InvalidOid); /* typowner */
+       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 */
@@ -84,12 +85,15 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
        values[i++] = ObjectIdGetDatum(InvalidOid); /* typelem */
        values[i++] = ObjectIdGetDatum(InvalidOid); /* typinput */
        values[i++] = ObjectIdGetDatum(InvalidOid); /* typoutput */
-       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 */
+       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 */
 
@@ -105,6 +109,25 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
 
        CatalogUpdateIndexes(pg_type_desc, tup);
 
+       /*
+        * Create dependencies.  We can/must skip this in bootstrap mode.
+        */
+       if (!IsBootstrapProcessingMode())
+               GenerateTypeDependencies(typeNamespace,
+                                                                typoid,
+                                                                InvalidOid,
+                                                                0,
+                                                                GetUserId(),
+                                                                InvalidOid,
+                                                                InvalidOid,
+                                                                InvalidOid,
+                                                                InvalidOid,
+                                                                InvalidOid,
+                                                                InvalidOid,
+                                                                InvalidOid,
+                                                                NULL,
+                                                                false);
+
        /*
         * clean up and return the type-oid
         */
@@ -119,46 +142,46 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
  *
  *             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(const char *typeName,
                   Oid typeNamespace,
-                  Oid assignedTypeOid,
-                  Oid relationOid,                     /* only for 'c'atalog typeTypes */
+                  Oid relationOid,             /* only for 'c'atalog types */
+                  char relationKind,   /* ditto */
                   int16 internalSize,
                   char typeType,
                   char typDelim,
                   Oid inputProcedure,
                   Oid outputProcedure,
+                  Oid receiveProcedure,
+                  Oid sendProcedure,
+                  Oid analyzeProcedure,
                   Oid elementType,
                   Oid baseType,
-                  const char *defaultTypeValue,        /* human readable rep */
-                  const char *defaultTypeBin,  /* cooked rep */
+                  const char *defaultTypeValue,                /* human readable rep */
+                  char *defaultTypeBin,        /* cooked rep */
                   bool passedByValue,
                   char alignment,
                   char storage,
                   int32 typeMod,
-                  int32 typNDims,                      /* Array dimensions for baseType */
+                  int32 typNDims,              /* Array dimensions for baseType */
                   bool typeNotNull)
 {
        Relation        pg_type_desc;
        Oid                     typeObjectId;
+       bool            rebuildDeps = false;
        HeapTuple       tup;
        char            nulls[Natts_pg_type];
        char            replaces[Natts_pg_type];
        Datum           values[Natts_pg_type];
        NameData        name;
-       TupleDesc       tupDesc;
        int                     i;
 
        /*
-        * We assume that the caller validated the arguments individually,
-        * but did not check for bad combinations.
+        * 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
@@ -167,16 +190,22 @@ TypeCreate(const char *typeName,
        if (!(internalSize > 0 ||
                  internalSize == -1 ||
                  internalSize == -2))
-               elog(ERROR, "TypeCreate: invalid type internal size %d",
-                        internalSize);
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                errmsg("invalid type internal size %d",
+                                               internalSize)));
        if (passedByValue &&
                (internalSize <= 0 || internalSize > (int16) sizeof(Datum)))
-               elog(ERROR, "TypeCreate: invalid type internal size %d",
-                        internalSize);
+               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)
-               elog(ERROR, "TypeCreate: fixed size types must have storage PLAIN");
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                errmsg("fixed-size types must have storage PLAIN")));
 
        /*
         * initialize arrays needed for heap_formtuple or heap_modifytuple
@@ -194,27 +223,30 @@ TypeCreate(const char *typeName,
        i = 0;
        namestrcpy(&name, typeName);
        values[i++] = NameGetDatum(&name);      /* typname */
-       values[i++] = ObjectIdGetDatum(typeNamespace);  /* typnamespace */
-       values[i++] = Int32GetDatum(GetUserId());       /* typowner */
+       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++] = 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(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 */
+       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,
@@ -239,7 +271,7 @@ TypeCreate(const char *typeName,
         * 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);
+       pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
 
        tup = SearchSysCacheCopy(TYPENAMENSP,
                                                         CStringGetDatum(typeName),
@@ -249,38 +281,34 @@ TypeCreate(const char *typeName,
        {
                /*
                 * check that the type is not already defined.  It may exist as a
-                * shell type, however (but only if assignedTypeOid is not given).
+                * shell type, however.
                 */
-               if (((Form_pg_type) GETSTRUCT(tup))->typisdefined ||
-                       assignedTypeOid != InvalidOid)
-                       elog(ERROR, "type %s already exists", typeName);
+               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);
 
-               AssertTupleDescHasOid(pg_type_desc->rd_att);
                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 */
-               AssertTupleDescHasOid(tupDesc);
-               HeapTupleSetOid(tup, assignedTypeOid);
-
                typeObjectId = simple_heap_insert(pg_type_desc, tup);
        }
 
@@ -291,92 +319,170 @@ TypeCreate(const char *typeName,
         * 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_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))
        {
-               ObjectAddress   myself,
-                                               referenced;
-
-               myself.classId = RelOid_pg_type;
-               myself.objectId = typeObjectId;
-               myself.objectSubId = 0;
-
-               /* dependency on namespace */
-               /* skip for relation rowtype, since we have indirect dependency */
-               if (!OidIsValid(relationOid))
-               {
-                       referenced.classId = get_system_catalog_relid(NamespaceRelationName);
-                       referenced.objectId = typeNamespace;
-                       referenced.objectSubId = 0;
-                       recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
-               }
-
-               /* Normal dependencies on the I/O functions */
-               referenced.classId = RelOid_pg_proc;
+               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);
+       }
 
-               referenced.classId = RelOid_pg_proc;
+       if (OidIsValid(outputProcedure))
+       {
+               referenced.classId = ProcedureRelationId;
                referenced.objectId = outputProcedure;
                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))
-               {
-                       Relation        rel = relation_open(relationOid, AccessShareLock);
-                       char            relkind = rel->rd_rel->relkind;
-                       relation_close(rel, AccessShareLock);
-
-                       referenced.classId = RelOid_pg_class;
-                       referenced.objectId = relationOid;
-                       referenced.objectSubId = 0;
-
-                       if (relkind != RELKIND_COMPOSITE_TYPE)
-                               recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
-                       else
-                               recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
-               }
+       if (OidIsValid(receiveProcedure))
+       {
+               referenced.classId = ProcedureRelationId;
+               referenced.objectId = receiveProcedure;
+               referenced.objectSubId = 0;
+               recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+       }
 
-               /*
-                * 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))
-               {
-                       referenced.classId = RelOid_pg_type;
-                       referenced.objectId = elementType;
-                       referenced.objectSubId = 0;
-                       recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
-               }
-
-               /* Normal dependency from a domain to its base type. */
-               if (OidIsValid(baseType))
-               {
-                       referenced.classId = RelOid_pg_type;
-                       referenced.objectId = baseType;
-                       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);
        }
 
        /*
-        * finish up
+        * 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.
         */
-       heap_close(pg_type_desc, RowExclusiveLock);
+       if (OidIsValid(relationOid))
+       {
+               referenced.classId = RelationRelationId;
+               referenced.objectId = relationOid;
+               referenced.objectSubId = 0;
 
-       return typeObjectId;
+               if (relationKind != RELKIND_COMPOSITE_TYPE)
+                       recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
+               else
+                       recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
+       }
+
+       /*
+        * 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))
+       {
+               referenced.classId = TypeRelationId;
+               referenced.objectId = elementType;
+               referenced.objectSubId = 0;
+               recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
+       }
+
+       /* 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);
+       }
+
+       /* Normal dependency on the default expression. */
+       if (defaultExpr)
+               recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
+
+       /* Shared dependency on owner. */
+       recordDependencyOnOwner(TypeRelationId, typeObjectId, owner);
 }
 
 /*
@@ -394,20 +500,24 @@ TypeRename(const char *oldTypeName, Oid typeNamespace,
        Relation        pg_type_desc;
        HeapTuple       tuple;
 
-       pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
+       pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
 
        tuple = SearchSysCacheCopy(TYPENAMENSP,
                                                           CStringGetDatum(oldTypeName),
                                                           ObjectIdGetDatum(typeNamespace),
                                                           0, 0);
        if (!HeapTupleIsValid(tuple))
-               elog(ERROR, "type %s does not exist", oldTypeName);
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                errmsg("type \"%s\" does not exist", oldTypeName)));
 
        if (SearchSysCacheExists(TYPENAMENSP,
                                                         CStringGetDatum(newTypeName),
                                                         ObjectIdGetDatum(typeNamespace),
                                                         0, 0))
-               elog(ERROR, "type named %s already exists", newTypeName);
+               ereport(ERROR,
+                               (errcode(ERRCODE_DUPLICATE_OBJECT),
+                                errmsg("type \"%s\" already exists", newTypeName)));
 
        namestrcpy(&(((Form_pg_type) GETSTRUCT(tuple))->typname), newTypeName);