1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* pg_type.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* routines to support manipulation of the pg_type relation
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2004-12-31 23:04:05 +01:00
|
|
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2006-02-28 23:37:27 +01:00
|
|
|
* $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.105 2006/02/28 22:37:25 tgl Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1998-04-27 06:08:07 +02:00
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
#include "access/heapam.h"
|
2002-07-12 20:43:19 +02:00
|
|
|
#include "catalog/dependency.h"
|
1998-04-27 06:08:07 +02:00
|
|
|
#include "catalog/indexing.h"
|
2005-04-14 22:03:27 +02:00
|
|
|
#include "catalog/pg_namespace.h"
|
2005-04-14 03:38:22 +02:00
|
|
|
#include "catalog/pg_proc.h"
|
1998-04-27 06:08:07 +02:00
|
|
|
#include "catalog/pg_type.h"
|
2006-02-28 23:37:27 +01:00
|
|
|
#include "commands/typecmds.h"
|
1998-04-27 06:08:07 +02:00
|
|
|
#include "miscadmin.h"
|
2006-02-28 23:37:27 +01:00
|
|
|
#include "utils/acl.h"
|
1998-04-27 06:08:07 +02:00
|
|
|
#include "utils/builtins.h"
|
2006-02-28 23:37:27 +01:00
|
|
|
#include "utils/fmgroids.h"
|
2002-07-18 18:47:26 +02:00
|
|
|
#include "utils/lsyscache.h"
|
1998-04-27 06:08:07 +02:00
|
|
|
#include "utils/syscache.h"
|
|
|
|
|
1996-11-04 00:27:08 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------------------------------------------------------
|
2002-03-29 20:06:29 +01:00
|
|
|
* TypeShellMake
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2006-02-28 23:37:27 +01:00
|
|
|
* This procedure inserts a "shell" tuple into the pg_type relation.
|
|
|
|
* The type tuple inserted has valid but dummy values, and its
|
|
|
|
* "typisdefined" field is false indicating it's not really defined.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2006-02-28 23:37:27 +01:00
|
|
|
* This is used so that a tuple exists in the catalogs. The I/O
|
|
|
|
* functions for the type will link to this tuple. When the full
|
|
|
|
* CREATE TYPE command is issued, the bogus values will be replaced
|
|
|
|
* with correct ones, and "typisdefined" will be set to true.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
Oid
|
2002-03-29 20:06:29 +01:00
|
|
|
TypeShellMake(const char *typeName, Oid typeNamespace)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation pg_type_desc;
|
2002-03-29 20:06:29 +01:00
|
|
|
TupleDesc tupDesc;
|
1998-02-26 05:46:47 +01:00
|
|
|
int i;
|
1997-09-08 04:41:22 +02:00
|
|
|
HeapTuple tup;
|
|
|
|
Datum values[Natts_pg_type];
|
|
|
|
char nulls[Natts_pg_type];
|
|
|
|
Oid typoid;
|
1998-04-01 17:35:33 +02:00
|
|
|
NameData name;
|
2002-03-29 20:06:29 +01:00
|
|
|
|
|
|
|
Assert(PointerIsValid(typeName));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* open pg_type
|
|
|
|
*/
|
2005-04-14 22:03:27 +02:00
|
|
|
pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
|
2002-03-29 20:06:29 +01:00
|
|
|
tupDesc = pg_type_desc->rd_att;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* initialize our *nulls and *values arrays
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
for (i = 0; i < Natts_pg_type; ++i)
|
|
|
|
{
|
|
|
|
nulls[i] = ' ';
|
|
|
|
values[i] = (Datum) NULL; /* redundant, but safe */
|
|
|
|
}
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* initialize *values with the type name and dummy values
|
2006-02-28 23:37:27 +01:00
|
|
|
*
|
|
|
|
* The representational details are the same as int4 ... it doesn't
|
|
|
|
* really matter what they are so long as they are consistent. Also
|
|
|
|
* note that we give it typtype = 'p' (pseudotype) as extra insurance
|
|
|
|
* that it won't be mistaken for a usable type.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
i = 0;
|
1998-04-01 17:35:33 +02:00
|
|
|
namestrcpy(&name, typeName);
|
2002-03-29 20:06:29 +01:00
|
|
|
values[i++] = NameGetDatum(&name); /* typname */
|
2002-09-04 22:31:48 +02:00
|
|
|
values[i++] = ObjectIdGetDatum(typeNamespace); /* typnamespace */
|
2005-10-15 04:49:52 +02:00
|
|
|
values[i++] = ObjectIdGetDatum(GetUserId()); /* typowner */
|
2006-02-28 23:37:27 +01:00
|
|
|
values[i++] = Int16GetDatum(sizeof(int4)); /* typlen */
|
|
|
|
values[i++] = BoolGetDatum(true); /* typbyval */
|
|
|
|
values[i++] = CharGetDatum('p'); /* typtype */
|
|
|
|
values[i++] = BoolGetDatum(false); /* typisdefined */
|
|
|
|
values[i++] = CharGetDatum(DEFAULT_TYPDELIM); /* typdelim */
|
|
|
|
values[i++] = ObjectIdGetDatum(InvalidOid); /* typrelid */
|
|
|
|
values[i++] = ObjectIdGetDatum(InvalidOid); /* typelem */
|
|
|
|
values[i++] = ObjectIdGetDatum(F_SHELL_IN); /* typinput */
|
|
|
|
values[i++] = ObjectIdGetDatum(F_SHELL_OUT); /* 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 */
|
2002-03-29 20:06:29 +01:00
|
|
|
nulls[i++] = 'n'; /* typdefaultbin */
|
|
|
|
nulls[i++] = 'n'; /* typdefault */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2002-03-29 20:06:29 +01:00
|
|
|
* create a new type tuple
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
tup = heap_formtuple(tupDesc, values, nulls);
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* insert the tuple in the relation and get the tuple's oid.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2002-05-22 00:05:55 +02:00
|
|
|
typoid = simple_heap_insert(pg_type_desc, tup);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-08-05 05:29:17 +02:00
|
|
|
CatalogUpdateIndexes(pg_type_desc, tup);
|
2001-03-22 07:16:21 +01:00
|
|
|
|
2003-01-08 22:40:39 +01:00
|
|
|
/*
|
|
|
|
* Create dependencies. We can/must skip this in bootstrap mode.
|
|
|
|
*/
|
|
|
|
if (!IsBootstrapProcessingMode())
|
|
|
|
GenerateTypeDependencies(typeNamespace,
|
|
|
|
typoid,
|
|
|
|
InvalidOid,
|
|
|
|
0,
|
2005-07-07 22:40:02 +02:00
|
|
|
GetUserId(),
|
2006-02-28 23:37:27 +01:00
|
|
|
F_SHELL_IN,
|
|
|
|
F_SHELL_OUT,
|
2003-01-08 22:40:39 +01:00
|
|
|
InvalidOid,
|
|
|
|
InvalidOid,
|
2003-05-09 00:19:58 +02:00
|
|
|
InvalidOid,
|
|
|
|
InvalidOid,
|
2004-02-13 00:41:04 +01:00
|
|
|
InvalidOid,
|
2003-01-08 22:40:39 +01:00
|
|
|
NULL,
|
|
|
|
false);
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2002-03-29 20:06:29 +01:00
|
|
|
* clean up and return the type-oid
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1999-12-16 23:20:03 +01:00
|
|
|
heap_freetuple(tup);
|
1999-09-18 21:08:25 +02:00
|
|
|
heap_close(pg_type_desc, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-02-03 22:18:02 +01:00
|
|
|
return typoid;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* TypeCreate
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* This does all the necessary work needed to define a new type.
|
2001-02-12 21:07:21 +01:00
|
|
|
*
|
2005-08-12 03:36:05 +02:00
|
|
|
* Returns the OID assigned to the new type.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
Oid
|
2002-03-29 20:06:29 +01:00
|
|
|
TypeCreate(const char *typeName,
|
|
|
|
Oid typeNamespace,
|
2003-01-08 22:40:39 +01:00
|
|
|
Oid relationOid, /* only for 'c'atalog types */
|
2002-09-04 22:31:48 +02:00
|
|
|
char relationKind, /* ditto */
|
1997-09-07 07:04:48 +02:00
|
|
|
int16 internalSize,
|
|
|
|
char typeType,
|
|
|
|
char typDelim,
|
2002-03-29 20:06:29 +01:00
|
|
|
Oid inputProcedure,
|
|
|
|
Oid outputProcedure,
|
2003-05-09 00:19:58 +02:00
|
|
|
Oid receiveProcedure,
|
|
|
|
Oid sendProcedure,
|
2004-02-13 00:41:04 +01:00
|
|
|
Oid analyzeProcedure,
|
2002-03-29 20:06:29 +01:00
|
|
|
Oid elementType,
|
|
|
|
Oid baseType,
|
2002-09-04 22:31:48 +02:00
|
|
|
const char *defaultTypeValue, /* human readable rep */
|
2002-12-06 06:00:34 +01:00
|
|
|
char *defaultTypeBin, /* cooked rep */
|
1997-09-07 07:04:48 +02:00
|
|
|
bool passedByValue,
|
2000-07-04 01:10:14 +02:00
|
|
|
char alignment,
|
2002-03-19 03:18:25 +01:00
|
|
|
char storage,
|
|
|
|
int32 typeMod,
|
2002-09-04 22:31:48 +02:00
|
|
|
int32 typNDims, /* Array dimensions for baseType */
|
2002-03-20 20:45:13 +01:00
|
|
|
bool typeNotNull)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation pg_type_desc;
|
|
|
|
Oid typeObjectId;
|
2003-01-08 22:40:39 +01:00
|
|
|
bool rebuildDeps = false;
|
1997-09-08 04:41:22 +02:00
|
|
|
HeapTuple tup;
|
|
|
|
char nulls[Natts_pg_type];
|
|
|
|
char replaces[Natts_pg_type];
|
|
|
|
Datum values[Natts_pg_type];
|
1998-04-01 17:35:33 +02:00
|
|
|
NameData name;
|
2002-03-29 20:06:29 +01:00
|
|
|
int i;
|
2002-03-19 03:18:25 +01:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* We assume that the caller validated the arguments individually, but did
|
|
|
|
* not check for bad combinations.
|
2002-08-24 17:00:47 +02:00
|
|
|
*
|
|
|
|
* 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).
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2002-08-24 17:00:47 +02:00
|
|
|
if (!(internalSize > 0 ||
|
|
|
|
internalSize == -1 ||
|
|
|
|
internalSize == -2))
|
2003-07-21 03:59:11 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
errmsg("invalid type internal size %d",
|
|
|
|
internalSize)));
|
2002-08-24 17:00:47 +02:00
|
|
|
if (passedByValue &&
|
|
|
|
(internalSize <= 0 || internalSize > (int16) sizeof(Datum)))
|
2003-07-21 03:59:11 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("internal size %d is invalid for passed-by-value type",
|
|
|
|
internalSize)));
|
2001-09-06 04:07:42 +02:00
|
|
|
|
2002-08-24 17:00:47 +02:00
|
|
|
/* Only varlena types can be toasted */
|
|
|
|
if (storage != 'p' && internalSize != -1)
|
2003-07-21 03:59:11 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
errmsg("fixed-size types must have storage PLAIN")));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2002-03-29 20:06:29 +01:00
|
|
|
* initialize arrays needed for heap_formtuple or heap_modifytuple
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
for (i = 0; i < Natts_pg_type; ++i)
|
|
|
|
{
|
|
|
|
nulls[i] = ' ';
|
|
|
|
replaces[i] = 'r';
|
2001-09-06 04:07:42 +02:00
|
|
|
values[i] = (Datum) 0;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* initialize the *values information
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
i = 0;
|
1998-09-01 06:40:42 +02:00
|
|
|
namestrcpy(&name, typeName);
|
2002-03-29 20:06:29 +01:00
|
|
|
values[i++] = NameGetDatum(&name); /* typname */
|
2002-09-04 22:31:48 +02:00
|
|
|
values[i++] = ObjectIdGetDatum(typeNamespace); /* typnamespace */
|
2005-10-15 04:49:52 +02:00
|
|
|
values[i++] = ObjectIdGetDatum(GetUserId()); /* typowner */
|
2002-03-29 20:06:29 +01:00
|
|
|
values[i++] = Int16GetDatum(internalSize); /* typlen */
|
|
|
|
values[i++] = BoolGetDatum(passedByValue); /* typbyval */
|
|
|
|
values[i++] = CharGetDatum(typeType); /* typtype */
|
2002-09-04 22:31:48 +02:00
|
|
|
values[i++] = BoolGetDatum(true); /* typisdefined */
|
2002-03-29 20:06:29 +01:00
|
|
|
values[i++] = CharGetDatum(typDelim); /* typdelim */
|
|
|
|
values[i++] = ObjectIdGetDatum(typeType == 'c' ? relationOid : InvalidOid); /* typrelid */
|
2002-09-04 22:31:48 +02:00
|
|
|
values[i++] = ObjectIdGetDatum(elementType); /* typelem */
|
|
|
|
values[i++] = ObjectIdGetDatum(inputProcedure); /* typinput */
|
|
|
|
values[i++] = ObjectIdGetDatum(outputProcedure); /* typoutput */
|
2003-05-09 00:19:58 +02:00
|
|
|
values[i++] = ObjectIdGetDatum(receiveProcedure); /* typreceive */
|
|
|
|
values[i++] = ObjectIdGetDatum(sendProcedure); /* typsend */
|
2004-02-13 00:41:04 +01:00
|
|
|
values[i++] = ObjectIdGetDatum(analyzeProcedure); /* typanalyze */
|
2002-03-29 20:06:29 +01:00
|
|
|
values[i++] = CharGetDatum(alignment); /* typalign */
|
|
|
|
values[i++] = CharGetDatum(storage); /* typstorage */
|
2002-09-04 22:31:48 +02:00
|
|
|
values[i++] = BoolGetDatum(typeNotNull); /* typnotnull */
|
|
|
|
values[i++] = ObjectIdGetDatum(baseType); /* typbasetype */
|
|
|
|
values[i++] = Int32GetDatum(typeMod); /* typtypmod */
|
|
|
|
values[i++] = Int32GetDatum(typNDims); /* typndims */
|
2002-03-19 03:18:25 +01:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* initialize the default binary value for this type. Check for nulls of
|
|
|
|
* course.
|
2002-03-19 03:18:25 +01:00
|
|
|
*/
|
|
|
|
if (defaultTypeBin)
|
|
|
|
values[i] = DirectFunctionCall1(textin,
|
2002-03-20 20:45:13 +01:00
|
|
|
CStringGetDatum(defaultTypeBin));
|
2002-03-19 03:18:25 +01:00
|
|
|
else
|
|
|
|
nulls[i] = 'n';
|
2002-03-29 20:06:29 +01:00
|
|
|
i++; /* typdefaultbin */
|
2002-03-19 03:18:25 +01:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* initialize the default value for this type.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2001-09-06 04:07:42 +02:00
|
|
|
if (defaultTypeValue)
|
|
|
|
values[i] = DirectFunctionCall1(textin,
|
2005-10-15 04:49:52 +02:00
|
|
|
CStringGetDatum(defaultTypeValue));
|
2001-09-06 04:07:42 +02:00
|
|
|
else
|
|
|
|
nulls[i] = 'n';
|
2002-03-29 20:06:29 +01:00
|
|
|
i++; /* typdefault */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2002-03-29 20:06:29 +01:00
|
|
|
* 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.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2005-04-14 22:03:27 +02:00
|
|
|
pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-03-29 20:06:29 +01:00
|
|
|
tup = SearchSysCacheCopy(TYPENAMENSP,
|
|
|
|
CStringGetDatum(typeName),
|
|
|
|
ObjectIdGetDatum(typeNamespace),
|
|
|
|
0, 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
if (HeapTupleIsValid(tup))
|
|
|
|
{
|
2002-03-29 20:06:29 +01:00
|
|
|
/*
|
|
|
|
* check that the type is not already defined. It may exist as a
|
2005-08-12 03:36:05 +02:00
|
|
|
* shell type, however.
|
2002-03-29 20:06:29 +01:00
|
|
|
*/
|
2005-08-12 03:36:05 +02:00
|
|
|
if (((Form_pg_type) GETSTRUCT(tup))->typisdefined)
|
2003-07-21 03:59:11 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
|
|
|
errmsg("type \"%s\" already exists", typeName)));
|
2001-02-12 21:07:21 +01:00
|
|
|
|
2002-03-29 20:06:29 +01:00
|
|
|
/*
|
2006-02-28 23:37:27 +01:00
|
|
|
* shell type must have been created by same owner
|
|
|
|
*/
|
|
|
|
if (((Form_pg_type) GETSTRUCT(tup))->typowner != GetUserId())
|
|
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, typeName);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Okay to update existing shell type tuple
|
2002-03-29 20:06:29 +01:00
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
tup = heap_modifytuple(tup,
|
2005-01-28 00:24:11 +01:00
|
|
|
RelationGetDescr(pg_type_desc),
|
1997-09-07 07:04:48 +02:00
|
|
|
values,
|
|
|
|
nulls,
|
|
|
|
replaces);
|
|
|
|
|
2001-01-23 05:32:23 +01:00
|
|
|
simple_heap_update(pg_type_desc, &tup->t_self, tup);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-07-20 07:16:59 +02:00
|
|
|
typeObjectId = HeapTupleGetOid(tup);
|
2003-01-08 22:40:39 +01:00
|
|
|
|
|
|
|
rebuildDeps = true; /* get rid of shell type's dependencies */
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-01-28 00:24:11 +01:00
|
|
|
tup = heap_formtuple(RelationGetDescr(pg_type_desc),
|
1997-09-07 07:04:48 +02:00
|
|
|
values,
|
|
|
|
nulls);
|
|
|
|
|
2002-05-22 00:05:55 +02:00
|
|
|
typeObjectId = simple_heap_insert(pg_type_desc, tup);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2002-08-05 05:29:17 +02:00
|
|
|
/* Update indexes */
|
|
|
|
CatalogUpdateIndexes(pg_type_desc, tup);
|
1999-09-18 21:08:25 +02:00
|
|
|
|
2002-07-12 20:43:19 +02:00
|
|
|
/*
|
2002-07-18 18:47:26 +02:00
|
|
|
* Create dependencies. We can/must skip this in bootstrap mode.
|
2002-07-12 20:43:19 +02:00
|
|
|
*/
|
2002-07-18 18:47:26 +02:00
|
|
|
if (!IsBootstrapProcessingMode())
|
2002-12-06 06:00:34 +01:00
|
|
|
GenerateTypeDependencies(typeNamespace,
|
|
|
|
typeObjectId,
|
|
|
|
relationOid,
|
|
|
|
relationKind,
|
2005-07-07 22:40:02 +02:00
|
|
|
GetUserId(),
|
2002-12-06 06:00:34 +01:00
|
|
|
inputProcedure,
|
|
|
|
outputProcedure,
|
2003-05-09 00:19:58 +02:00
|
|
|
receiveProcedure,
|
|
|
|
sendProcedure,
|
2004-02-13 00:41:04 +01:00
|
|
|
analyzeProcedure,
|
2002-12-06 06:00:34 +01:00
|
|
|
elementType,
|
|
|
|
baseType,
|
2003-01-08 22:40:39 +01:00
|
|
|
(defaultTypeBin ?
|
|
|
|
stringToNode(defaultTypeBin) :
|
2004-01-07 19:56:30 +01:00
|
|
|
NULL),
|
2003-01-08 22:40:39 +01:00
|
|
|
rebuildDeps);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* finish up
|
|
|
|
*/
|
|
|
|
heap_close(pg_type_desc, RowExclusiveLock);
|
|
|
|
|
|
|
|
return typeObjectId;
|
|
|
|
}
|
2002-07-12 20:43:19 +02:00
|
|
|
|
2003-01-08 22:40:39 +01:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2002-12-06 06:00:34 +01:00
|
|
|
void
|
|
|
|
GenerateTypeDependencies(Oid typeNamespace,
|
|
|
|
Oid typeObjectId,
|
2005-10-15 04:49:52 +02:00
|
|
|
Oid relationOid, /* only for 'c'atalog types */
|
2003-01-08 22:40:39 +01:00
|
|
|
char relationKind, /* ditto */
|
2005-07-07 22:40:02 +02:00
|
|
|
Oid owner,
|
2002-12-06 06:00:34 +01:00
|
|
|
Oid inputProcedure,
|
|
|
|
Oid outputProcedure,
|
2003-05-09 00:19:58 +02:00
|
|
|
Oid receiveProcedure,
|
|
|
|
Oid sendProcedure,
|
2004-02-13 00:41:04 +01:00
|
|
|
Oid analyzeProcedure,
|
2002-12-06 06:00:34 +01:00
|
|
|
Oid elementType,
|
|
|
|
Oid baseType,
|
2003-01-08 22:40:39 +01:00
|
|
|
Node *defaultExpr,
|
2002-12-06 06:00:34 +01:00
|
|
|
bool rebuild)
|
|
|
|
{
|
|
|
|
ObjectAddress myself,
|
|
|
|
referenced;
|
|
|
|
|
|
|
|
if (rebuild)
|
2005-07-07 22:40:02 +02:00
|
|
|
{
|
2005-04-14 03:38:22 +02:00
|
|
|
deleteDependencyRecordsFor(TypeRelationId, typeObjectId);
|
2005-07-07 22:40:02 +02:00
|
|
|
deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId);
|
|
|
|
}
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2005-04-14 03:38:22 +02:00
|
|
|
myself.classId = TypeRelationId;
|
2002-12-06 06:00:34 +01:00
|
|
|
myself.objectId = typeObjectId;
|
|
|
|
myself.objectSubId = 0;
|
|
|
|
|
|
|
|
/* dependency on namespace */
|
|
|
|
/* skip for relation rowtype, since we have indirect dependency */
|
|
|
|
if (!OidIsValid(relationOid))
|
|
|
|
{
|
2005-04-14 22:03:27 +02:00
|
|
|
referenced.classId = NamespaceRelationId;
|
2002-12-06 06:00:34 +01:00
|
|
|
referenced.objectId = typeNamespace;
|
2002-12-06 04:28:34 +01:00
|
|
|
referenced.objectSubId = 0;
|
2002-12-06 04:43:35 +01:00
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
|
2002-12-06 06:00:34 +01:00
|
|
|
}
|
2002-12-06 04:28:34 +01:00
|
|
|
|
2002-12-06 06:00:34 +01:00
|
|
|
/* Normal dependencies on the I/O functions */
|
2003-01-08 22:40:39 +01:00
|
|
|
if (OidIsValid(inputProcedure))
|
|
|
|
{
|
2005-04-14 03:38:22 +02:00
|
|
|
referenced.classId = ProcedureRelationId;
|
2003-01-08 22:40:39 +01:00
|
|
|
referenced.objectId = inputProcedure;
|
|
|
|
referenced.objectSubId = 0;
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
|
|
|
|
}
|
2002-12-06 04:43:35 +01:00
|
|
|
|
2003-01-08 22:40:39 +01:00
|
|
|
if (OidIsValid(outputProcedure))
|
|
|
|
{
|
2005-04-14 03:38:22 +02:00
|
|
|
referenced.classId = ProcedureRelationId;
|
2003-01-08 22:40:39 +01:00
|
|
|
referenced.objectId = outputProcedure;
|
|
|
|
referenced.objectSubId = 0;
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
|
|
|
|
}
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-05-09 00:19:58 +02:00
|
|
|
if (OidIsValid(receiveProcedure))
|
|
|
|
{
|
2005-04-14 03:38:22 +02:00
|
|
|
referenced.classId = ProcedureRelationId;
|
2003-05-09 00:19:58 +02:00
|
|
|
referenced.objectId = receiveProcedure;
|
|
|
|
referenced.objectSubId = 0;
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (OidIsValid(sendProcedure))
|
|
|
|
{
|
2005-04-14 03:38:22 +02:00
|
|
|
referenced.classId = ProcedureRelationId;
|
2003-05-09 00:19:58 +02:00
|
|
|
referenced.objectId = sendProcedure;
|
|
|
|
referenced.objectSubId = 0;
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
|
|
|
|
}
|
|
|
|
|
2004-02-13 00:41:04 +01:00
|
|
|
if (OidIsValid(analyzeProcedure))
|
|
|
|
{
|
2005-04-14 03:38:22 +02:00
|
|
|
referenced.classId = ProcedureRelationId;
|
2004-02-13 00:41:04 +01:00
|
|
|
referenced.objectId = analyzeProcedure;
|
|
|
|
referenced.objectSubId = 0;
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
|
|
|
|
}
|
|
|
|
|
2002-12-06 06:00:34 +01:00
|
|
|
/*
|
|
|
|
* If the type is a rowtype for a relation, mark it as internally
|
2005-10-15 04:49:52 +02:00
|
|
|
* dependent on the relation, *unless* it is a stand-alone composite type
|
|
|
|
* relation. For the latter case, we have to reverse the dependency.
|
2002-12-06 06:00:34 +01:00
|
|
|
*
|
2003-08-04 02:43:34 +02:00
|
|
|
* In the former case, this allows the type to be auto-dropped when the
|
2005-10-15 04:49:52 +02:00
|
|
|
* relation is, and not otherwise. And in the latter, of course we get the
|
|
|
|
* opposite effect.
|
2002-12-06 06:00:34 +01:00
|
|
|
*/
|
|
|
|
if (OidIsValid(relationOid))
|
|
|
|
{
|
2005-04-14 03:38:22 +02:00
|
|
|
referenced.classId = RelationRelationId;
|
2002-12-06 06:00:34 +01:00
|
|
|
referenced.objectId = relationOid;
|
|
|
|
referenced.objectSubId = 0;
|
|
|
|
|
|
|
|
if (relationKind != RELKIND_COMPOSITE_TYPE)
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
|
|
|
|
else
|
|
|
|
recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
|
2002-07-12 20:43:19 +02:00
|
|
|
}
|
|
|
|
|
2002-03-29 20:06:29 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* 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.)
|
2002-03-29 20:06:29 +01:00
|
|
|
*/
|
2002-12-06 06:00:34 +01:00
|
|
|
if (OidIsValid(elementType))
|
|
|
|
{
|
2005-04-14 03:38:22 +02:00
|
|
|
referenced.classId = TypeRelationId;
|
2002-12-06 06:00:34 +01:00
|
|
|
referenced.objectId = elementType;
|
|
|
|
referenced.objectSubId = 0;
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
|
|
|
|
}
|
2002-12-06 04:28:34 +01:00
|
|
|
|
2002-12-06 06:00:34 +01:00
|
|
|
/* Normal dependency from a domain to its base type. */
|
|
|
|
if (OidIsValid(baseType))
|
|
|
|
{
|
2005-04-14 03:38:22 +02:00
|
|
|
referenced.classId = TypeRelationId;
|
2002-12-06 06:00:34 +01:00
|
|
|
referenced.objectId = baseType;
|
|
|
|
referenced.objectSubId = 0;
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
|
|
|
|
}
|
|
|
|
|
2003-01-08 22:40:39 +01:00
|
|
|
/* Normal dependency on the default expression. */
|
|
|
|
if (defaultExpr)
|
|
|
|
recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
|
2005-07-07 22:40:02 +02:00
|
|
|
|
|
|
|
/* Shared dependency on owner. */
|
|
|
|
recordDependencyOnOwner(TypeRelationId, typeObjectId, owner);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2002-03-29 20:06:29 +01:00
|
|
|
/*
|
|
|
|
* TypeRename
|
1997-09-07 07:04:48 +02:00
|
|
|
* This renames a type
|
2002-03-29 20:06:29 +01:00
|
|
|
*
|
|
|
|
* 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.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
void
|
2002-03-29 20:06:29 +01:00
|
|
|
TypeRename(const char *oldTypeName, Oid typeNamespace,
|
|
|
|
const char *newTypeName)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation pg_type_desc;
|
2000-11-16 23:30:52 +01:00
|
|
|
HeapTuple tuple;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-03-29 20:06:29 +01:00
|
|
|
tuple = SearchSysCacheCopy(TYPENAMENSP,
|
|
|
|
CStringGetDatum(oldTypeName),
|
|
|
|
ObjectIdGetDatum(typeNamespace),
|
|
|
|
0, 0);
|
2000-11-16 23:30:52 +01:00
|
|
|
if (!HeapTupleIsValid(tuple))
|
2003-07-21 03:59:11 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
|
|
errmsg("type \"%s\" does not exist", oldTypeName)));
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2002-03-29 20:06:29 +01:00
|
|
|
if (SearchSysCacheExists(TYPENAMENSP,
|
|
|
|
CStringGetDatum(newTypeName),
|
|
|
|
ObjectIdGetDatum(typeNamespace),
|
|
|
|
0, 0))
|
2003-07-21 03:59:11 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
|
|
|
errmsg("type \"%s\" already exists", newTypeName)));
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2000-11-16 23:30:52 +01:00
|
|
|
namestrcpy(&(((Form_pg_type) GETSTRUCT(tuple))->typname), newTypeName);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-01-23 05:32:23 +01:00
|
|
|
simple_heap_update(pg_type_desc, &tuple->t_self, tuple);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-08-05 05:29:17 +02:00
|
|
|
/* update the system catalog indexes */
|
|
|
|
CatalogUpdateIndexes(pg_type_desc, tuple);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-11-16 23:30:52 +01:00
|
|
|
heap_freetuple(tuple);
|
1999-09-18 21:08:25 +02:00
|
|
|
heap_close(pg_type_desc, RowExclusiveLock);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* makeArrayTypeName(typeName);
|
1997-09-07 07:04:48 +02:00
|
|
|
* - given a base type name, make an array of type name out of it
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2001-10-12 02:07:15 +02:00
|
|
|
* the caller is responsible for pfreeing the result
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1998-02-26 05:46:47 +01:00
|
|
|
char *
|
2002-03-29 20:06:29 +01:00
|
|
|
makeArrayTypeName(const char *typeName)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
char *arr;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
if (!typeName)
|
|
|
|
return NULL;
|
2001-10-12 02:07:15 +02:00
|
|
|
arr = palloc(NAMEDATALEN);
|
|
|
|
snprintf(arr, NAMEDATALEN,
|
|
|
|
"_%.*s", NAMEDATALEN - 2, typeName);
|
1997-09-07 07:04:48 +02:00
|
|
|
return arr;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|