X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Fbackend%2Fcatalog%2Fpg_type.c;h=ab250b02ea9aa77246e85f1f05693507e51b0be1;hb=1dc34982511d91ef8a2b71bdcb870f067c1b3da9;hp=b6fe76bc1f7c53d92907d729ddbbb4c5f7af2f84;hpb=59f6a57e59fe8353f9edaa3703516ea67e06672b;p=postgresql diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index b6fe76bc1f..ab250b02ea 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -1,168 +1,66 @@ /*------------------------------------------------------------------------- * - * pg_type.c-- + * pg_type.c * routines to support manipulation of the pg_type relation * - * Copyright (c) 1994, Regents of the University of California + * 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.10 1997/09/08 21:42:24 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.104 2005/10/15 02:49:14 momjian Exp $ * *------------------------------------------------------------------------- */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef HAVE_MEMMOVE -#include -#else -#include -#endif - -static Oid -TypeShellMakeWithOpenRelation(Relation pg_type_desc, - char *typeName); +#include "postgres.h" -/* ---------------------------------------------------------------- - * 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; +#include "access/heapam.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" +#include "utils/lsyscache.h" +#include "utils/syscache.h" - static ScanKeyData typeKey[1] = { - {0, Anum_pg_type_typname, NameEqualRegProcedure} - }; - - /* ---------------- - * initialize the scan key and begin a scan of pg_type - * ---------------- - */ - fmgr_info(NameEqualRegProcedure, - &typeKey[0].sk_func, &typeKey[0].sk_nargs); - typeKey[0].sk_argument = PointerGetDatum(typeName); - - scan = heap_beginscan(pg_type_desc, - 0, - SelfTimeQual, - 1, - typeKey); - - /* ---------------- - * get the type tuple, if it exists. - * ---------------- - */ - tup = heap_getnext(scan, 0, (Buffer *) 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. - * ---------------- - */ - heap_endscan(scan); - *defined = (bool) ((TypeTupleForm) GETSTRUCT(tup))->typisdefined; - - return - tup->t_oid; -} /* ---------------------------------------------------------------- - * 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); - - /* ---------------- - * 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); - - return - typeoid; -} - -/* ---------------------------------------------------------------- - * TypeShellMakeWithOpenRelation - * - * ---------------------------------------------------------------- - */ -static Oid -TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName) -{ - register int i; + TupleDesc tupDesc; + int i; HeapTuple tup; Datum values[Natts_pg_type]; char nulls[Natts_pg_type]; Oid typoid; - TupleDesc tupDesc; + NameData name; + + 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 - * ---------------- + /* + * initialize our *nulls and *values arrays */ for (i = 0; i < Natts_pg_type; ++i) { @@ -170,450 +68,483 @@ TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName) values[i] = (Datum) NULL; /* redundant, but safe */ } - /* ---------------- - * initialize values[] with the type name and - * ---------------- + /* + * initialize *values with the type name and dummy values */ i = 0; - values[i++] = (Datum) typeName; /* 1 */ - values[i++] = (Datum) InvalidOid; /* 2 */ - values[i++] = (Datum) (int16) 0; /* 3 */ - values[i++] = (Datum) (int16) 0; /* 4 */ - values[i++] = (Datum) (bool) 0; /* 5 */ - values[i++] = (Datum) (bool) 0; /* 6 */ - values[i++] = (Datum) (bool) 0; /* 7 */ - values[i++] = (Datum) (bool) 0; /* 8 */ - values[i++] = (Datum) InvalidOid; /* 9 */ - values[i++] = (Datum) InvalidOid; /* 10 */ - values[i++] = (Datum) InvalidOid; /* 11 */ - values[i++] = (Datum) InvalidOid; /* 12 */ - values[i++] = (Datum) InvalidOid; /* 13 */ - values[i++] = (Datum) InvalidOid; /* 14 */ - values[i++] = (Datum) 'i'; /* 15 */ + namestrcpy(&name, typeName); + 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 */ /* - * ... and fill typdefault with a bogus value - */ - values[i++] = - (Datum) fmgr(TextInRegProcedure, typeName); /* 15 */ - - /* ---------------- - * 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_oid; - - if (RelationGetRelationTupleForm(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 - * ---------------- + /* + * insert the tuple in the relation and get the tuple's oid. */ - pfree(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; + typoid = simple_heap_insert(pg_type_desc, tup); - Assert(PointerIsValid(typeName)); + CatalogUpdateIndexes(pg_type_desc, tup); - /* ---------------- - * open pg_type - * ---------------- - */ - pg_type_desc = heap_openr(TypeRelationName); - - /* ---------------- - * 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_close(pg_type_desc); + heap_freetuple(tup); + heap_close(pg_type_desc, RowExclusiveLock); - return - typoid; + return typoid; } /* ---------------------------------------------------------------- * TypeCreate * * This does all the necessary work needed to define a new type. + * + * Returns the OID assigned to the new type. * ---------------------------------------------------------------- */ Oid -TypeCreate(char *typeName, - 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 *sendProcedure, - char *receiveProcedure, - char *elementTypeName, - char *defaultTypeValue, /* internal 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 alignment, + char storage, + int32 typeMod, + int32 typNDims, /* Array dimensions for baseType */ + bool typeNotNull) { - register i, - j; Relation pg_type_desc; - HeapScanDesc pg_type_scan; - Oid typeObjectId; - Oid elementObjectId = InvalidOid; - + bool rebuildDeps = false; HeapTuple tup; char nulls[Natts_pg_type]; char replaces[Natts_pg_type]; Datum values[Natts_pg_type]; + NameData name; + int i; - Buffer buffer; - char *procname; - char *procs[4]; - bool defined; - ItemPointerData itemPointerData; - TupleDesc tupDesc; - - Oid argList[8]; - - - static ScanKeyData typeKey[1] = { - {0, Anum_pg_type_typname, NameEqualRegProcedure} - }; - - fmgr_info(NameEqualRegProcedure, - &typeKey[0].sk_func, &typeKey[0].sk_nargs); - - /* ---------------- - * check that the type is not already defined. - * ---------------- - */ - typeObjectId = TypeGet(typeName, &defined); - if (OidIsValid(typeObjectId) && defined) - { - elog(WARN, "TypeCreate: type %s already defined", typeName); - } - - /* ---------------- - * if this type has an associated elementType, then we check that - * it is defined. - * ---------------- + /* + * 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 (elementTypeName) - { - elementObjectId = TypeGet(elementTypeName, &defined); - if (!defined) - { - elog(WARN, "TypeCreate: type %s is not defined", elementTypeName); - } - } + 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"))); - /* ---------------- - * XXX comment me - * ---------------- - */ - if (externalSize == 0) - { - externalSize = -1; /* variable length */ - } - - /* ---------------- - * initialize arrays needed by FormHeapTuple - * ---------------- + /* + * initialize arrays needed for heap_formtuple or heap_modifytuple */ for (i = 0; i < Natts_pg_type; ++i) { nulls[i] = ' '; replaces[i] = 'r'; - values[i] = (Datum) NULL; /* redundant, but nice */ + values[i] = (Datum) 0; } /* - * XXX - * - * Do this so that user-defined types have size -1 instead of zero if - * they are variable-length - this is so that everything else in the - * backend works. - */ - - if (internalSize == 0) - internalSize = -1; - - /* ---------------- - * initialize the values[] information - * ---------------- + * initialize the *values information */ i = 0; - values[i++] = PointerGetDatum(typeName); /* 1 */ - values[i++] = (Datum) GetUserId(); /* 2 */ - values[i++] = (Datum) internalSize; /* 3 */ - values[i++] = (Datum) externalSize; /* 4 */ - values[i++] = (Datum) passedByValue; /* 5 */ - values[i++] = (Datum) typeType; /* 6 */ - values[i++] = (Datum) (bool) 1; /* 7 */ - values[i++] = (Datum) typDelim; /* 8 */ - values[i++] = (Datum) (typeType == 'c' ? relationOid : InvalidOid); /* 9 */ - values[i++] = (Datum) elementObjectId; /* 10 */ + namestrcpy(&name, typeName); + 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 */ /* - * arguments to type input and output functions must be 0 + * initialize the default binary value for this type. Check for nulls of + * course. */ - memset(argList, 0, 8 * sizeof(Oid)); - - procs[0] = inputProcedure; - procs[1] = outputProcedure; - procs[2] = (receiveProcedure) ? receiveProcedure : inputProcedure; - procs[3] = (sendProcedure) ? sendProcedure : outputProcedure; - - for (j = 0; j < 4; ++j) - { - procname = procs[j]; - - tup = SearchSysCacheTuple(PRONAME, - PointerGetDatum(procname), - Int32GetDatum(1), - PointerGetDatum(argList), - 0); - - if (!HeapTupleIsValid(tup)) - { - - /* - * it is possible for the input/output procedure to take two - * arguments, where the second argument is the element type - * (eg array_in/array_out) - */ - if (OidIsValid(elementObjectId)) - { - tup = SearchSysCacheTuple(PRONAME, - PointerGetDatum(procname), - Int32GetDatum(2), - PointerGetDatum(argList), - 0); - } - if (!HeapTupleIsValid(tup)) - { - func_error("TypeCreate", procname, 1, argList); - } - } - - values[i++] = (Datum) tup->t_oid; /* 11 - 14 */ - } + if (defaultTypeBin) + values[i] = DirectFunctionCall1(textin, + CStringGetDatum(defaultTypeBin)); + else + nulls[i] = 'n'; + i++; /* typdefaultbin */ - /* ---------------- - * set default alignment - * ---------------- + /* + * initialize the default value for this type. */ - values[i++] = (Datum) alignment; /* 15 */ + if (defaultTypeValue) + values[i] = DirectFunctionCall1(textin, + CStringGetDatum(defaultTypeValue)); + else + nulls[i] = 'n'; + i++; /* typdefault */ - /* ---------------- - * initialize the default value for this type. - * ---------------- - */ - values[i] = (Datum) fmgr(TextInRegProcedure, /* 16 */ - PointerIsValid(defaultTypeValue) - ? defaultTypeValue : "-"); /* XXX default - * 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); + pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock); - /* ----------------- - * Set a write lock initially so as not upgrade a read to a write - * when the heap_insert() or heap_replace() is called. - * ----------------- - */ - RelationSetLockForWrite(pg_type_desc); - - typeKey[0].sk_argument = PointerGetDatum(typeName); - pg_type_scan = heap_beginscan(pg_type_desc, - 0, - SelfTimeQual, - 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, &buffer); + tup = SearchSysCacheCopy(TYPENAMENSP, + CStringGetDatum(typeName), + ObjectIdGetDatum(typeNamespace), + 0, 0); if (HeapTupleIsValid(tup)) { + /* + * 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, - buffer, - pg_type_desc, + RelationGetDescr(pg_type_desc), values, nulls, replaces); - /* XXX may not be necessary */ - ItemPointerCopy(&tup->t_ctid, &itemPointerData); + simple_heap_update(pg_type_desc, &tup->t_self, tup); - setheapoverride(true); - heap_replace(pg_type_desc, &itemPointerData, tup); - setheapoverride(false); + typeObjectId = HeapTupleGetOid(tup); - typeObjectId = tup->t_oid; + 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); - heap_insert(pg_type_desc, tup); - - typeObjectId = tup->t_oid; + typeObjectId = simple_heap_insert(pg_type_desc, tup); } - /* ---------------- - * finish up - * ---------------- - */ - heap_endscan(pg_type_scan); + /* Update indexes */ + CatalogUpdateIndexes(pg_type_desc, tup); - if (RelationGetRelationTupleForm(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); - } - RelationUnsetLockForWrite(pg_type_desc); - heap_close(pg_type_desc); + /* + * 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; + return typeObjectId; } -/* ---------------------------------------------------------------- - * TypeRename +/* + * GenerateTypeDependencies: build the dependencies needed for a type * - * This renames 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 -TypeRename(char *oldTypeName, char *newTypeName) +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) { - Relation pg_type_desc; - Relation idescs[Num_pg_type_indices]; - Oid type_oid; - HeapTuple tup; - bool defined; - ItemPointerData itemPointerData; + ObjectAddress myself, + referenced; - /* check that that the new type is not already defined */ - type_oid = TypeGet(newTypeName, &defined); - if (OidIsValid(type_oid) && defined) + if (rebuild) { - elog(WARN, "TypeRename: type %s already defined", newTypeName); + deleteDependencyRecordsFor(TypeRelationId, typeObjectId); + deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId); } - /* get the type tuple from the catalog index scan manager */ - pg_type_desc = heap_openr(TypeRelationName); - tup = TypeNameIndexScan(pg_type_desc, oldTypeName); + myself.classId = TypeRelationId; + myself.objectId = typeObjectId; + myself.objectSubId = 0; - /* ---------------- - * change the name of the type - * ---------------- - */ - if (HeapTupleIsValid(tup)) + /* 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); + } - namestrcpy(&(((TypeTupleForm) GETSTRUCT(tup))->typname), newTypeName); + /* Normal dependencies on the I/O functions */ + if (OidIsValid(inputProcedure)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = inputProcedure; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } - ItemPointerCopy(&tup->t_ctid, &itemPointerData); + if (OidIsValid(outputProcedure)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = outputProcedure; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } - setheapoverride(true); - heap_replace(pg_type_desc, &itemPointerData, tup); - setheapoverride(false); + if (OidIsValid(receiveProcedure)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = receiveProcedure; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } - /* update the system catalog 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); + if (OidIsValid(sendProcedure)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = sendProcedure; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } - /* all done */ - pfree(tup); + 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); } - else + + /* + * 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)) { - elog(WARN, "TypeRename: type %s not defined", oldTypeName); + referenced.classId = TypeRelationId; + referenced.objectId = elementType; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); } - /* finish up */ - heap_close(pg_type_desc); + /* 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); +} + +/* + * 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, Oid typeNamespace, + const char *newTypeName) +{ + Relation pg_type_desc; + HeapTuple tuple; + + pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock); + + tuple = SearchSysCacheCopy(TYPENAMENSP, + CStringGetDatum(oldTypeName), + ObjectIdGetDatum(typeNamespace), + 0, 0); + if (!HeapTupleIsValid(tuple)) + 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 indexes */ + CatalogUpdateIndexes(pg_type_desc, tuple); + + heap_freetuple(tuple); + heap_close(pg_type_desc, RowExclusiveLock); } /* * makeArrayTypeName(typeName); * - given a base type name, make an array of type name out of it * - * the CALLER is responsible for pfreeing the + * the caller is responsible for pfreeing the result */ - -char * -makeArrayTypeName(char *typeName) +char * +makeArrayTypeName(const char *typeName) { char *arr; if (!typeName) return NULL; - arr = palloc(strlen(typeName) + 2); - arr[0] = '_'; - strcpy(arr + 1, typeName); - + arr = palloc(NAMEDATALEN); + snprintf(arr, NAMEDATALEN, + "_%.*s", NAMEDATALEN - 2, typeName); return arr; - }