X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Fbackend%2Fcatalog%2Fpg_type.c;h=ab250b02ea9aa77246e85f1f05693507e51b0be1;hb=1dc34982511d91ef8a2b71bdcb870f067c1b3da9;hp=6c6a135a0b9a0e567d0219f6fbbd5576d39f5bfc;hpb=976246cc7e4d8b673fc62fe6daa61c76d94af1af;p=postgresql diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index 6c6a135a0b..ab250b02ea 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -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);