* 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.85 2002/12/06 05:00:10 momjian 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"
/*
* open pg_type
*/
- pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
+ pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
tupDesc = pg_type_desc->rd_att;
/*
namestrcpy(&name, typeName);
values[i++] = NameGetDatum(&name); /* typname */
values[i++] = ObjectIdGetDatum(typeNamespace); /* typnamespace */
- values[i++] = ObjectIdGetDatum(InvalidOid); /* typowner */
+ values[i++] = ObjectIdGetDatum(GetUserId()); /* typowner */
values[i++] = Int16GetDatum(0); /* typlen */
values[i++] = BoolGetDatum(false); /* typbyval */
values[i++] = CharGetDatum(0); /* typtype */
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 */
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
*/
*
* 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 typeType */
+ 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 */
{
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
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
namestrcpy(&name, typeName);
values[i++] = NameGetDatum(&name); /* typname */
values[i++] = ObjectIdGetDatum(typeNamespace); /* typnamespace */
- values[i++] = Int32GetDatum(GetUserId()); /* typowner */
+ values[i++] = ObjectIdGetDatum(GetUserId()); /* typowner */
values[i++] = Int16GetDatum(internalSize); /* typlen */
values[i++] = BoolGetDatum(passedByValue); /* typbyval */
values[i++] = CharGetDatum(typeType); /* typtype */
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++] = 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,
*/
if (defaultTypeValue)
values[i] = DirectFunctionCall1(textin,
- CStringGetDatum(defaultTypeValue));
+ CStringGetDatum(defaultTypeValue));
else
nulls[i] = 'n';
i++; /* typdefault */
* 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),
{
/*
* 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);
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 */
- HeapTupleSetOid(tup, assignedTypeOid);
-
typeObjectId = simple_heap_insert(pg_type_desc, tup);
}
* 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,
- false);
- }
+ (defaultTypeBin ?
+ stringToNode(defaultTypeBin) :
+ NULL),
+ rebuildDeps);
/*
* finish up
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 typeType */
- char relationKind,
+ 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,
- char *defaultTypeBin, /* cooked rep */
+ Node *defaultExpr,
bool rebuild)
{
ObjectAddress myself,
referenced;
- /*
- * If true, we need to remove all current dependencies that the type
- * holds, and rebuild them from scratch. This allows us to easily
- * implement alter type, and alter domain statements.
- */
if (rebuild)
- deleteDependencyRecordsFor(RelOid_pg_type,
- typeObjectId);
+ {
+ deleteDependencyRecordsFor(TypeRelationId, typeObjectId);
+ deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId);
+ }
- myself.classId = RelOid_pg_type;
+ myself.classId = TypeRelationId;
myself.objectId = typeObjectId;
myself.objectSubId = 0;
/* skip for relation rowtype, since we have indirect dependency */
if (!OidIsValid(relationOid))
{
- referenced.classId = get_system_catalog_relid(NamespaceRelationName);
+ referenced.classId = NamespaceRelationId;
referenced.objectId = typeNamespace;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
/* Normal dependencies on the I/O functions */
- referenced.classId = RelOid_pg_proc;
- referenced.objectId = inputProcedure;
- referenced.objectSubId = 0;
- recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+ 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);
+ }
- referenced.classId = RelOid_pg_proc;
- 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.
+ * 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.
+ * 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 = RelOid_pg_class;
+ referenced.classId = RelationRelationId;
referenced.objectId = relationOid;
referenced.objectSubId = 0;
}
/*
- * 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 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.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 = RelOid_pg_type;
+ referenced.classId = TypeRelationId;
referenced.objectId = baseType;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
- /* Dependency on the default expression */
- if (defaultTypeBin)
- recordDependencyOnExpr(&myself, stringToNode(defaultTypeBin),
- NIL, DEPENDENCY_NORMAL);
+ /* Normal dependency on the default expression. */
+ if (defaultExpr)
+ recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
+
+ /* Shared dependency on owner. */
+ recordDependencyOnOwner(TypeRelationId, typeObjectId, owner);
}
/*
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);