* 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
*/
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;
*
* 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)
{
*/
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.
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);
* the caller is responsible for pfreeing the result
*/
char *
-makeArrayTypeName(char *typeName)
+makeArrayTypeName(const char *typeName)
{
char *arr;