/*-------------------------------------------------------------------------
*
- * 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-2002, 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.11 1997/09/18 20:20:19 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.82 2002/09/04 20:31:14 momjian Exp $
*
*-------------------------------------------------------------------------
*/
-#include <postgres.h>
-
-#include <utils/syscache.h>
-#include <catalog/pg_proc.h>
-#include <access/heapam.h>
-#include <access/relscan.h>
-#include <utils/builtins.h>
-#include <fmgr.h>
-#include <parser/catalog_utils.h>
-#include <catalog/catname.h>
-#include <catalog/indexing.h>
-#include <storage/lmgr.h>
-#include <miscadmin.h>
-#ifndef HAVE_MEMMOVE
-#include <regex/utils.h>
-#else
-#include <string.h>
-#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;
-
- 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;
- }
+#include "access/heapam.h"
+#include "catalog/catname.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_type.h"
+#include "miscadmin.h"
+#include "utils/builtins.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
- /* ----------------
- * 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;
- /* ----------------
- * initialize our nulls[] and values[] arrays
- * ----------------
+ Assert(PointerIsValid(typeName));
+
+ /*
+ * open pg_type
+ */
+ pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
+ tupDesc = pg_type_desc->rd_att;
+
+ /*
+ * initialize our *nulls and *values arrays
*/
for (i = 0; i < Natts_pg_type; ++i)
{
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(InvalidOid); /* 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++] = 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
- * ----------------
- */
- 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;
-
- Assert(PointerIsValid(typeName));
-
- /* ----------------
- * open pg_type
- * ----------------
+ /*
+ * insert the tuple in the relation and get the tuple's oid.
*/
- pg_type_desc = heap_openr(TypeRelationName);
+ typoid = simple_heap_insert(pg_type_desc, tup);
- /* ----------------
- * insert the shell tuple
- * ----------------
- */
- typoid = TypeShellMakeWithOpenRelation(pg_type_desc, typeName);
+ CatalogUpdateIndexes(pg_type_desc, tup);
- /* ----------------
- * 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.
+ *
+ * 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.
* ----------------------------------------------------------------
*/
Oid
-TypeCreate(char *typeName,
- Oid relationOid, /* only for 'c'atalog typeTypes */
+TypeCreate(const char *typeName,
+ Oid typeNamespace,
+ Oid assignedTypeOid,
+ Oid relationOid, /* only for 'c'atalog typeType */
+ 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 elementType,
+ Oid baseType,
+ const char *defaultTypeValue, /* human readable rep */
+ const 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;
-
HeapTuple tup;
char nulls[Natts_pg_type];
char replaces[Natts_pg_type];
Datum values[Natts_pg_type];
-
- Buffer buffer;
- char *procname;
- char *procs[4];
- bool defined;
- ItemPointerData itemPointerData;
+ NameData name;
TupleDesc tupDesc;
+ int i;
- 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))
+ elog(ERROR, "TypeCreate: invalid type internal size %d",
+ internalSize);
+ if (passedByValue &&
+ (internalSize <= 0 || internalSize > (int16) sizeof(Datum)))
+ elog(ERROR, "TypeCreate: invalid type internal size %d",
+ internalSize);
+
+ /* Only varlena types can be toasted */
+ if (storage != 'p' && internalSize != -1)
+ elog(ERROR, "TypeCreate: 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++] = Int32GetDatum(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++] = 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_openr(TypeRelationName, 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 (but only if assignedTypeOid is not given).
+ */
+ if (((Form_pg_type) GETSTRUCT(tup))->typisdefined ||
+ assignedTypeOid != InvalidOid)
+ elog(ERROR, "type %s already exists", typeName);
+
+ /*
+ * Okay to update existing "shell" type tuple
+ */
tup = heap_modifytuple(tup,
- buffer,
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 = tup->t_oid;
+ typeObjectId = HeapTupleGetOid(tup);
}
else
{
values,
nulls);
- heap_insert(pg_type_desc, tup);
+ /* preassign tuple Oid, if one was given */
+ HeapTupleSetOid(tup, assignedTypeOid);
- 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)
+ /*
+ * Create dependencies. We can/must skip this in bootstrap mode.
+ */
+ if (!IsBootstrapProcessingMode())
{
- Relation idescs[Num_pg_type_indices];
+ 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);
+ }
- 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 dependencies on the I/O functions */
+ referenced.classId = RelOid_pg_proc;
+ referenced.objectId = inputProcedure;
+ 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 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 = RelOid_pg_class;
+ referenced.objectId = relationOid;
+ referenced.objectSubId = 0;
+
+ 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 = 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);
+ }
}
- RelationUnsetLockForWrite(pg_type_desc);
- heap_close(pg_type_desc);
+ /*
+ * finish up
+ */
+ heap_close(pg_type_desc, RowExclusiveLock);
- return
- typeObjectId;
+ return typeObjectId;
}
-/* ----------------------------------------------------------------
- * 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(char *oldTypeName, char *newTypeName)
+TypeRename(const char *oldTypeName, Oid typeNamespace,
+ const char *newTypeName)
{
Relation pg_type_desc;
- Relation idescs[Num_pg_type_indices];
- Oid type_oid;
- HeapTuple tup;
- bool defined;
- ItemPointerData itemPointerData;
+ HeapTuple tuple;
- /* check that that the new type is not already defined */
- type_oid = TypeGet(newTypeName, &defined);
- if (OidIsValid(type_oid) && defined)
- {
- elog(WARN, "TypeRename: type %s already defined", newTypeName);
- }
+ pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
- /* get the type tuple from the catalog index scan manager */
- pg_type_desc = heap_openr(TypeRelationName);
- tup = TypeNameIndexScan(pg_type_desc, oldTypeName);
+ tuple = SearchSysCacheCopy(TYPENAMENSP,
+ CStringGetDatum(oldTypeName),
+ ObjectIdGetDatum(typeNamespace),
+ 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "type %s does not exist", oldTypeName);
- /* ----------------
- * change the name of the type
- * ----------------
- */
- if (HeapTupleIsValid(tup))
- {
+ if (SearchSysCacheExists(TYPENAMENSP,
+ CStringGetDatum(newTypeName),
+ ObjectIdGetDatum(typeNamespace),
+ 0, 0))
+ elog(ERROR, "type named %s already exists", newTypeName);
- namestrcpy(&(((TypeTupleForm) GETSTRUCT(tup))->typname), newTypeName);
+ namestrcpy(&(((Form_pg_type) GETSTRUCT(tuple))->typname), newTypeName);
- ItemPointerCopy(&tup->t_ctid, &itemPointerData);
+ simple_heap_update(pg_type_desc, &tuple->t_self, tuple);
- setheapoverride(true);
- heap_replace(pg_type_desc, &itemPointerData, tup);
- setheapoverride(false);
+ /* update the system catalog indexes */
+ CatalogUpdateIndexes(pg_type_desc, 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, tup);
- CatalogCloseIndices(Num_pg_type_indices, idescs);
-
- /* all done */
- pfree(tup);
-
- }
- else
- {
- elog(WARN, "TypeRename: type %s not defined", oldTypeName);
- }
-
- /* finish up */
- heap_close(pg_type_desc);
+ 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;
-
}