aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/catalog/README8
-rw-r--r--src/backend/catalog/heap.c141
-rw-r--r--src/backend/catalog/pg_shdepend.c4
-rw-r--r--src/backend/catalog/pg_type.c102
-rw-r--r--src/backend/commands/tablecmds.c33
-rw-r--r--src/backend/commands/typecmds.c218
-rw-r--r--src/backend/parser/parse_type.c10
-rw-r--r--src/backend/utils/cache/lsyscache.c36
8 files changed, 373 insertions, 179 deletions
diff --git a/src/backend/catalog/README b/src/backend/catalog/README
index 3cbcc3d45ee..89c6e0305ae 100644
--- a/src/backend/catalog/README
+++ b/src/backend/catalog/README
@@ -1,4 +1,4 @@
-$PostgreSQL: pgsql/src/backend/catalog/README,v 1.10 2006/07/31 01:16:36 tgl Exp $
+$PostgreSQL: pgsql/src/backend/catalog/README,v 1.11 2007/05/11 17:57:11 tgl Exp $
This directory contains .c files that manipulate the system catalogs;
src/include/catalog contains the .h files that define the structure
@@ -86,9 +86,9 @@ general) assumes that the fixed-length portions of all system catalog
tuples are in fact present, because it maps C struct declarations onto
them. Thus, the variable-length fields must all be at the end, and
only the variable-length fields of a catalog tuple are permitted to be
-NULL. For example, if you set pg_type.typdelim to be NULL, a
-piece of code will likely perform "typetup->typdelim" (or, worse,
-"typetyp->typelem", which follows typdelim). This will result in
+NULL. For example, if you set pg_type.typrelid to be NULL, a
+piece of code will likely perform "typetup->typrelid" (or, worse,
+"typetyp->typelem", which follows typrelid). This will result in
random errors or even segmentation violations. Hence, do NOT insert
catalog tuples that contain NULL attributes except in their
variable-length portions! (The bootstrapping code is fairly good about
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index e6404ecd0b5..8b34d685d85 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.318 2007/04/02 03:49:37 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.319 2007/05/11 17:57:11 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -45,6 +45,7 @@
#include "catalog/pg_statistic.h"
#include "catalog/pg_type.h"
#include "commands/tablecmds.h"
+#include "commands/typecmds.h"
#include "miscadmin.h"
#include "optimizer/clauses.h"
#include "optimizer/var.h"
@@ -69,7 +70,8 @@ static void AddNewRelationTuple(Relation pg_class_desc,
static Oid AddNewRelationType(const char *typeName,
Oid typeNamespace,
Oid new_rel_oid,
- char new_rel_kind);
+ char new_rel_kind,
+ Oid new_array_type);
static void RelationRemoveInheritance(Oid relid);
static void StoreRelCheck(Relation rel, char *ccname, char *ccbin);
static void StoreConstraints(Relation rel, TupleDesc tupdesc);
@@ -401,26 +403,55 @@ CheckAttributeType(const char *attname, Oid atttypid)
{
char att_typtype = get_typtype(atttypid);
- /*
- * Warn user, but don't fail, if column to be created has UNKNOWN type
- * (usually as a result of a 'retrieve into' - jolly)
- *
- * Refuse any attempt to create a pseudo-type column.
- */
if (atttypid == UNKNOWNOID)
+ {
+ /*
+ * Warn user, but don't fail, if column to be created has UNKNOWN type
+ * (usually as a result of a 'retrieve into' - jolly)
+ */
ereport(WARNING,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("column \"%s\" has type \"unknown\"", attname),
errdetail("Proceeding with relation creation anyway.")));
+ }
else if (att_typtype == TYPTYPE_PSEUDO)
{
- /* Special hack for pg_statistic: allow ANYARRAY during initdb */
+ /*
+ * Refuse any attempt to create a pseudo-type column, except for
+ * a special hack for pg_statistic: allow ANYARRAY during initdb
+ */
if (atttypid != ANYARRAYOID || IsUnderPostmaster)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("column \"%s\" has pseudo-type %s",
attname, format_type_be(atttypid))));
}
+ else if (att_typtype == TYPTYPE_COMPOSITE)
+ {
+ /*
+ * For a composite type, recurse into its attributes. You might
+ * think this isn't necessary, but since we allow system catalogs
+ * to break the rule, we have to guard against the case.
+ */
+ Relation relation;
+ TupleDesc tupdesc;
+ int i;
+
+ relation = relation_open(get_typ_typrelid(atttypid), AccessShareLock);
+
+ tupdesc = RelationGetDescr(relation);
+
+ for (i = 0; i < tupdesc->natts; i++)
+ {
+ Form_pg_attribute attr = tupdesc->attrs[i];
+
+ if (attr->attisdropped)
+ continue;
+ CheckAttributeType(NameStr(attr->attname), attr->atttypid);
+ }
+
+ relation_close(relation, AccessShareLock);
+ }
}
/* --------------------------------
@@ -710,16 +741,18 @@ static Oid
AddNewRelationType(const char *typeName,
Oid typeNamespace,
Oid new_rel_oid,
- char new_rel_kind)
+ char new_rel_kind,
+ Oid new_array_type)
{
return
- TypeCreate(typeName, /* type name */
+ TypeCreate(InvalidOid, /* no predetermined OID */
+ typeName, /* type name */
typeNamespace, /* type namespace */
new_rel_oid, /* relation oid */
new_rel_kind, /* relation kind */
-1, /* internal size (varlena) */
TYPTYPE_COMPOSITE, /* type-type (composite) */
- ',', /* default array delimiter */
+ DEFAULT_TYPDELIM, /* default array delimiter */
F_RECORD_IN, /* input procedure */
F_RECORD_OUT, /* output procedure */
F_RECORD_RECV, /* receive procedure */
@@ -728,6 +761,8 @@ AddNewRelationType(const char *typeName,
InvalidOid, /* typmodout procedure - none */
InvalidOid, /* analyze procedure - default */
InvalidOid, /* array element type - irrelevant */
+ false, /* this is not an array type */
+ new_array_type, /* array type if any */
InvalidOid, /* domain base type - irrelevant */
NULL, /* default value - none */
NULL, /* default binary representation */
@@ -763,6 +798,7 @@ heap_create_with_catalog(const char *relname,
Relation pg_class_desc;
Relation new_rel_desc;
Oid new_type_oid;
+ Oid new_array_oid = InvalidOid;
pg_class_desc = heap_open(RelationRelationId, RowExclusiveLock);
@@ -805,7 +841,24 @@ heap_create_with_catalog(const char *relname,
Assert(relid == RelationGetRelid(new_rel_desc));
/*
- * since defining a relation also defines a complex type, we add a new
+ * Decide whether to create an array type over the relation's rowtype.
+ * We do not create any array types for system catalogs (ie, those made
+ * during initdb). We create array types for regular relations, views,
+ * and composite types ... but not, eg, for toast tables or sequences.
+ */
+ if (IsUnderPostmaster && (relkind == RELKIND_RELATION ||
+ relkind == RELKIND_VIEW ||
+ relkind == RELKIND_COMPOSITE_TYPE))
+ {
+ /* OK, so pre-assign a type OID for the array type */
+ Relation pg_type = heap_open(TypeRelationId, AccessShareLock);
+
+ new_array_oid = GetNewOid(pg_type);
+ heap_close(pg_type, AccessShareLock);
+ }
+
+ /*
+ * Since defining a relation also defines a complex type, we add a new
* system type corresponding to the new relation.
*
* NOTE: we could get a unique-index failure here, in case the same name
@@ -814,7 +867,47 @@ heap_create_with_catalog(const char *relname,
new_type_oid = AddNewRelationType(relname,
relnamespace,
relid,
- relkind);
+ relkind,
+ new_array_oid);
+ /*
+ * Now make the array type if wanted.
+ */
+ if (OidIsValid(new_array_oid))
+ {
+ char *relarrayname;
+
+ relarrayname = makeArrayTypeName(relname, relnamespace);
+
+ TypeCreate(new_array_oid, /* force the type's OID to this */
+ relarrayname, /* Array type name */
+ relnamespace, /* Same namespace as parent */
+ InvalidOid, /* Not composite, no relationOid */
+ 0, /* relkind, also N/A here */
+ -1, /* Internal size (varlena) */
+ TYPTYPE_BASE, /* Not composite - typelem is */
+ DEFAULT_TYPDELIM, /* default array delimiter */
+ F_ARRAY_IN, /* array input proc */
+ F_ARRAY_OUT, /* array output proc */
+ F_ARRAY_RECV, /* array recv (bin) proc */
+ F_ARRAY_SEND, /* array send (bin) proc */
+ InvalidOid, /* typmodin procedure - none */
+ InvalidOid, /* typmodout procedure - none */
+ InvalidOid, /* analyze procedure - default */
+ new_type_oid, /* array element type - the rowtype */
+ true, /* yes, this is an array type */
+ InvalidOid, /* this has no array type */
+ InvalidOid, /* domain base type - irrelevant */
+ NULL, /* default value - none */
+ NULL, /* default binary representation */
+ false, /* passed by reference */
+ 'd', /* alignment - must be the largest! */
+ 'x', /* fully TOASTable */
+ -1, /* typmod */
+ 0, /* array dimensions for typBaseType */
+ false); /* Type NOT NULL */
+
+ pfree(relarrayname);
+ }
/*
* now create an entry in pg_class for the relation.
@@ -838,13 +931,15 @@ heap_create_with_catalog(const char *relname,
oidislocal, oidinhcount);
/*
- * make a dependency link to force the relation to be deleted if its
- * namespace is. Skip this in bootstrap mode, since we don't make
- * dependencies while bootstrapping.
+ * Make a dependency link to force the relation to be deleted if its
+ * namespace is. Also make a dependency link to its owner.
*
- * Also make a dependency link to its owner.
+ * For composite types, these dependencies are tracked for the pg_type
+ * entry, so we needn't record them here. Also, skip this in bootstrap
+ * mode, since we don't make dependencies while bootstrapping.
*/
- if (!IsBootstrapProcessingMode())
+ if (relkind != RELKIND_COMPOSITE_TYPE &&
+ !IsBootstrapProcessingMode())
{
ObjectAddress myself,
referenced;
@@ -857,13 +952,7 @@ heap_create_with_catalog(const char *relname,
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
- /*
- * For composite types, the dependency on owner is tracked for the
- * pg_type entry, so don't record it here. All other relkinds need
- * their ownership tracked.
- */
- if (relkind != RELKIND_COMPOSITE_TYPE)
- recordDependencyOnOwner(RelationRelationId, relid, ownerid);
+ recordDependencyOnOwner(RelationRelationId, relid, ownerid);
}
/*
diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c
index 9ad012db49f..e3de61344bb 100644
--- a/src/backend/catalog/pg_shdepend.c
+++ b/src/backend/catalog/pg_shdepend.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.17 2007/03/03 19:32:54 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.18 2007/05/11 17:57:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1254,7 +1254,7 @@ shdepReassignOwned(List *roleids, Oid newrole)
break;
case TypeRelationId:
- AlterTypeOwnerInternal(sdepForm->objid, newrole);
+ AlterTypeOwnerInternal(sdepForm->objid, newrole, true);
break;
case OperatorRelationId:
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index efc3b8de099..83601496043 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.111 2007/04/02 03:49:37 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.112 2007/05/11 17:57:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -22,6 +22,7 @@
#include "catalog/pg_type.h"
#include "commands/typecmds.h"
#include "miscadmin.h"
+#include "parser/scansup.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
@@ -90,6 +91,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
values[i++] = CharGetDatum(DEFAULT_TYPDELIM); /* typdelim */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typrelid */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typelem */
+ values[i++] = ObjectIdGetDatum(InvalidOid); /* typarray */
values[i++] = ObjectIdGetDatum(F_SHELL_IN); /* typinput */
values[i++] = ObjectIdGetDatum(F_SHELL_OUT); /* typoutput */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typreceive */
@@ -135,6 +137,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
InvalidOid,
InvalidOid,
InvalidOid,
+ false,
InvalidOid,
NULL,
false);
@@ -153,13 +156,16 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
*
* This does all the necessary work needed to define a new type.
*
- * Returns the OID assigned to the new type.
+ * Returns the OID assigned to the new type. If newTypeOid is
+ * zero (the normal case), a new OID is created; otherwise we
+ * use exactly that OID.
* ----------------------------------------------------------------
*/
Oid
-TypeCreate(const char *typeName,
+TypeCreate(Oid newTypeOid,
+ const char *typeName,
Oid typeNamespace,
- Oid relationOid, /* only for composite types */
+ Oid relationOid, /* only for relation rowtypes */
char relationKind, /* ditto */
int16 internalSize,
char typeType,
@@ -172,6 +178,8 @@ TypeCreate(const char *typeName,
Oid typmodoutProcedure,
Oid analyzeProcedure,
Oid elementType,
+ bool isImplicitArray,
+ Oid arrayType,
Oid baseType,
const char *defaultTypeValue, /* human readable rep */
char *defaultTypeBin, /* cooked rep */
@@ -243,9 +251,9 @@ TypeCreate(const char *typeName,
values[i++] = CharGetDatum(typeType); /* typtype */
values[i++] = BoolGetDatum(true); /* typisdefined */
values[i++] = CharGetDatum(typDelim); /* typdelim */
- values[i++] = ObjectIdGetDatum(typeType == TYPTYPE_COMPOSITE ?
- relationOid : InvalidOid); /* typrelid */
+ values[i++] = ObjectIdGetDatum(relationOid); /* typrelid */
values[i++] = ObjectIdGetDatum(elementType); /* typelem */
+ values[i++] = ObjectIdGetDatum(arrayType); /* typarray */
values[i++] = ObjectIdGetDatum(inputProcedure); /* typinput */
values[i++] = ObjectIdGetDatum(outputProcedure); /* typoutput */
values[i++] = ObjectIdGetDatum(receiveProcedure); /* typreceive */
@@ -310,6 +318,10 @@ TypeCreate(const char *typeName,
if (((Form_pg_type) GETSTRUCT(tup))->typowner != GetUserId())
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, typeName);
+ /* trouble if caller wanted to force the OID */
+ if (OidIsValid(newTypeOid))
+ elog(ERROR, "cannot assign new OID to existing shell type");
+
/*
* Okay to update existing shell type tuple
*/
@@ -331,6 +343,10 @@ TypeCreate(const char *typeName,
values,
nulls);
+ /* Force the OID if requested by caller, else heap_insert does it */
+ if (OidIsValid(newTypeOid))
+ HeapTupleSetOid(tup, newTypeOid);
+
typeObjectId = simple_heap_insert(pg_type_desc, tup);
}
@@ -354,6 +370,7 @@ TypeCreate(const char *typeName,
typmodoutProcedure,
analyzeProcedure,
elementType,
+ isImplicitArray,
baseType,
(defaultTypeBin ?
stringToNode(defaultTypeBin) :
@@ -378,8 +395,8 @@ TypeCreate(const char *typeName,
void
GenerateTypeDependencies(Oid typeNamespace,
Oid typeObjectId,
- Oid relationOid, /* only for composite types */
- char relationKind, /* ditto */
+ Oid relationOid, /* only for relation rowtypes */
+ char relationKind, /* ditto */
Oid owner,
Oid inputProcedure,
Oid outputProcedure,
@@ -389,6 +406,7 @@ GenerateTypeDependencies(Oid typeNamespace,
Oid typmodoutProcedure,
Oid analyzeProcedure,
Oid elementType,
+ bool isImplicitArray,
Oid baseType,
Node *defaultExpr,
bool rebuild)
@@ -406,14 +424,23 @@ GenerateTypeDependencies(Oid typeNamespace,
myself.objectId = typeObjectId;
myself.objectSubId = 0;
- /* dependency on namespace */
- /* skip for relation rowtype, since we have indirect dependency */
- if (!OidIsValid(relationOid))
+ /*
+ * Make dependency on namespace and shared dependency on owner.
+ *
+ * For a relation rowtype (that's not a composite type), we should skip
+ * these because we'll depend on them indirectly through the pg_class
+ * entry. Likewise, skip for implicit arrays since we'll depend on them
+ * through the element type.
+ */
+ if ((!OidIsValid(relationOid) || relationKind == RELKIND_COMPOSITE_TYPE) &&
+ !isImplicitArray)
{
referenced.classId = NamespaceRelationId;
referenced.objectId = typeNamespace;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+ recordDependencyOnOwner(TypeRelationId, typeObjectId, owner);
}
/* Normal dependencies on the I/O functions */
@@ -495,17 +522,17 @@ GenerateTypeDependencies(Oid typeNamespace,
}
/*
- * 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 the type is an implicitly-created array type, mark it as internally
+ * dependent on the element type. Otherwise, if it has an element type,
+ * the dependency is a normal one.
*/
if (OidIsValid(elementType))
{
referenced.classId = TypeRelationId;
referenced.objectId = elementType;
referenced.objectSubId = 0;
- recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
+ recordDependencyOn(&myself, &referenced,
+ isImplicitArray ? DEPENDENCY_INTERNAL : DEPENDENCY_NORMAL);
}
/* Normal dependency from a domain to its base type. */
@@ -520,9 +547,6 @@ GenerateTypeDependencies(Oid typeNamespace,
/* Normal dependency on the default expression. */
if (defaultExpr)
recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
-
- /* Shared dependency on owner. */
- recordDependencyOnOwner(TypeRelationId, typeObjectId, owner);
}
/*
@@ -570,21 +594,47 @@ TypeRename(const char *oldTypeName, Oid typeNamespace,
heap_close(pg_type_desc, RowExclusiveLock);
}
+
/*
- * makeArrayTypeName(typeName);
- * - given a base type name, make an array of type name out of it
+ * makeArrayTypeName(typeName)
+ * - given a base type name, make an array type name for it
*
* the caller is responsible for pfreeing the result
*/
char *
-makeArrayTypeName(const char *typeName)
+makeArrayTypeName(const char *typeName, Oid typeNamespace)
{
char *arr;
+ int i;
+ Relation pg_type_desc;
- if (!typeName)
- return NULL;
+ /*
+ * The idea is to prepend underscores as needed until we make a name
+ * that doesn't collide with anything...
+ */
arr = palloc(NAMEDATALEN);
- snprintf(arr, NAMEDATALEN,
- "_%.*s", NAMEDATALEN - 2, typeName);
+
+ pg_type_desc = heap_open(TypeRelationId, AccessShareLock);
+
+ for (i = 1; i < NAMEDATALEN - 1; i++)
+ {
+ arr[i - 1] = '_';
+ strlcpy(arr + i, typeName, NAMEDATALEN - i);
+ truncate_identifier(arr, strlen(arr), false);
+ if (!SearchSysCacheExists(TYPENAMENSP,
+ CStringGetDatum(arr),
+ ObjectIdGetDatum(typeNamespace),
+ 0, 0))
+ break;
+ }
+
+ heap_close(pg_type_desc, AccessShareLock);
+
+ if (i >= NAMEDATALEN-1)
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("could not form array type name for type \"%s\"",
+ typeName)));
+
return arr;
}
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 8043799b887..a1bbf177893 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.219 2007/04/08 01:26:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.220 2007/05/11 17:57:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2827,6 +2827,7 @@ find_composite_type_dependencies(Oid typeOid, const char *origTblName)
ScanKeyData key[2];
SysScanDesc depScan;
HeapTuple depTup;
+ Oid arrayOid;
/*
* We scan pg_depend to find those things that depend on the rowtype. (We
@@ -2886,6 +2887,14 @@ find_composite_type_dependencies(Oid typeOid, const char *origTblName)
systable_endscan(depScan);
relation_close(depRel, AccessShareLock);
+
+ /*
+ * If there's an array type for the rowtype, must check for uses of it,
+ * too.
+ */
+ arrayOid = get_array_type(typeOid);
+ if (OidIsValid(arrayOid))
+ find_composite_type_dependencies(arrayOid, origTblName);
}
@@ -5299,6 +5308,9 @@ ATPostAlterTypeParse(char *cmd, List **wqueue)
* be changed separately from the parent table. Also, we can skip permission
* checks (this is necessary not just an optimization, else we'd fail to
* handle toast tables properly).
+ *
+ * recursing is also true if ALTER TYPE OWNER is calling us to fix up a
+ * free-standing composite type.
*/
void
ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing)
@@ -5370,6 +5382,7 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing)
}
break;
case RELKIND_TOASTVALUE:
+ case RELKIND_COMPOSITE_TYPE:
if (recursing)
break;
/* FALL THRU */
@@ -5448,14 +5461,22 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing)
heap_freetuple(newtuple);
- /* Update owner dependency reference */
- changeDependencyOnOwner(RelationRelationId, relationOid, newOwnerId);
+ /*
+ * Update owner dependency reference, if any. A composite type has
+ * none, because it's tracked for the pg_type entry instead of here;
+ * indexes don't have their own entries either.
+ */
+ if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
+ tuple_class->relkind != RELKIND_INDEX)
+ changeDependencyOnOwner(RelationRelationId, relationOid,
+ newOwnerId);
/*
* Also change the ownership of the table's rowtype, if it has one
*/
if (tuple_class->relkind != RELKIND_INDEX)
- AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
+ AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId,
+ tuple_class->relkind == RELKIND_COMPOSITE_TYPE);
/*
* If we are operating on a table, also change the ownership of any
@@ -6462,7 +6483,7 @@ AlterTableNamespace(RangeVar *relation, const char *newschema)
AlterRelationNamespaceInternal(classRel, relid, oldNspOid, nspOid, true);
/* Fix the table's rowtype too */
- AlterTypeNamespaceInternal(rel->rd_rel->reltype, nspOid, false);
+ AlterTypeNamespaceInternal(rel->rd_rel->reltype, nspOid, false, false);
/* Fix other dependent stuff */
if (rel->rd_rel->relkind == RELKIND_RELATION)
@@ -6625,7 +6646,7 @@ AlterSeqNamespaces(Relation classRel, Relation rel,
* them to the new namespace, too.
*/
AlterTypeNamespaceInternal(RelationGetForm(seqRel)->reltype,
- newNspOid, false);
+ newNspOid, false, false);
/* Now we can close it. Keep the lock till end of transaction. */
relation_close(seqRel, NoLock);
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 5c1b9f6f0e6..7911f6df3a5 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.101 2007/04/02 03:49:38 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.102 2007/05/11 17:57:12 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@@ -34,6 +34,7 @@
#include "access/genam.h"
#include "access/heapam.h"
#include "access/xact.h"
+#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/indexing.h"
@@ -118,10 +119,12 @@ DefineType(List *names, List *parameters)
Oid typmodinOid = InvalidOid;
Oid typmodoutOid = InvalidOid;
Oid analyzeOid = InvalidOid;
- char *shadow_type;
+ char *array_type;
+ Oid array_oid;
ListCell *pl;
Oid typoid;
Oid resulttype;
+ Relation pg_type;
/* Convert list of names to a name and namespace */
typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
@@ -133,16 +136,6 @@ DefineType(List *names, List *parameters)
get_namespace_name(typeNamespace));
/*
- * Type names must be one character shorter than other names, allowing
- * room to create the corresponding array type name with prepended "_".
- */
- if (strlen(typeName) > (NAMEDATALEN - 2))
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_NAME),
- errmsg("type names must be %d characters or less",
- NAMEDATALEN - 2)));
-
- /*
* Look to see if type already exists (presumably as a shell; if not,
* TypeCreate will complain). If it doesn't, create it as a shell, so
* that the OID is known for use in the I/O function definitions.
@@ -396,11 +389,17 @@ DefineType(List *names, List *parameters)
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
NameListToString(analyzeName));
+ /* Preassign array type OID so we can insert it in pg_type.typarray */
+ pg_type = heap_open(TypeRelationId, AccessShareLock);
+ array_oid = GetNewOid(pg_type);
+ heap_close(pg_type, AccessShareLock);
+
/*
* now have TypeCreate do all the real work.
*/
typoid =
- TypeCreate(typeName, /* type name */
+ TypeCreate(InvalidOid, /* no predetermined type OID */
+ typeName, /* type name */
typeNamespace, /* namespace */
InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */
@@ -415,6 +414,8 @@ DefineType(List *names, List *parameters)
typmodoutOid,/* typmodout procedure */
analyzeOid, /* analyze procedure */
elemType, /* element type ID */
+ false, /* this is not an array type */
+ array_oid, /* array type we are about to create */
InvalidOid, /* base type ID (only for domains) */
defaultValue, /* default type value */
NULL, /* no binary form available */
@@ -426,19 +427,19 @@ DefineType(List *names, List *parameters)
false); /* Type NOT NULL */
/*
- * When we create a base type (as opposed to a complex type) we need to
- * have an array entry for it in pg_type as well.
+ * Create the array type that goes with it.
*/
- shadow_type = makeArrayTypeName(typeName);
+ array_type = makeArrayTypeName(typeName, typeNamespace);
/* alignment must be 'i' or 'd' for arrays */
alignment = (alignment == 'd') ? 'd' : 'i';
- TypeCreate(shadow_type, /* type name */
+ TypeCreate(array_oid, /* force assignment of this type OID */
+ array_type, /* type name */
typeNamespace, /* namespace */
InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */
- -1, /* internal size */
+ -1, /* internal size (always varlena) */
TYPTYPE_BASE, /* type-type (base type) */
DEFAULT_TYPDELIM, /* array element delimiter */
F_ARRAY_IN, /* input procedure */
@@ -449,6 +450,8 @@ DefineType(List *names, List *parameters)
typmodoutOid, /* typmodout procedure */
InvalidOid, /* analyze procedure - default */
typoid, /* element type ID */
+ true, /* yes this is an array type */
+ InvalidOid, /* no further array type */
InvalidOid, /* base type ID */
NULL, /* never a default type value */
NULL, /* binary default isn't sent either */
@@ -459,7 +462,7 @@ DefineType(List *names, List *parameters)
0, /* Array dimensions of typbasetype */
false); /* Type NOT NULL */
- pfree(shadow_type);
+ pfree(array_type);
}
@@ -474,6 +477,7 @@ RemoveType(List *names, DropBehavior behavior, bool missing_ok)
Oid typeoid;
HeapTuple tup;
ObjectAddress object;
+ Form_pg_type typ;
/* Make a TypeName so we can use standard type lookup machinery */
typename = makeTypeNameFromNameList(names);
@@ -504,14 +508,19 @@ RemoveType(List *names, DropBehavior behavior, bool missing_ok)
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for type %u", typeoid);
+ typ = (Form_pg_type) GETSTRUCT(tup);
/* Permission check: must own type or its namespace */
if (!pg_type_ownercheck(typeoid, GetUserId()) &&
- !pg_namespace_ownercheck(((Form_pg_type) GETSTRUCT(tup))->typnamespace,
- GetUserId()))
+ !pg_namespace_ownercheck(typ->typnamespace, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
TypeNameToString(typename));
+ /*
+ * Note: we need no special check for array types here, as the normal
+ * treatment of internal dependencies handles it just fine
+ */
+
ReleaseSysCache(tup);
/*
@@ -608,19 +617,6 @@ DefineDomain(CreateDomainStmt *stmt)
get_namespace_name(domainNamespace));
/*
- * Domainnames, unlike typenames don't need to account for the '_' prefix.
- * So they can be one character longer. (This test is presently useless
- * since the parser will have truncated the name to fit. But leave it
- * here since we may someday support arrays of domains, in which case
- * we'll be back to needing to enforce NAMEDATALEN-2.)
- */
- if (strlen(domainName) > (NAMEDATALEN - 1))
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_NAME),
- errmsg("domain names must be %d characters or less",
- NAMEDATALEN - 1)));
-
- /*
* Look up the base type.
*/
typeTup = typenameType(NULL, stmt->typename);
@@ -805,7 +801,8 @@ DefineDomain(CreateDomainStmt *stmt)
* Have TypeCreate do all the real work.
*/
domainoid =
- TypeCreate(domainName, /* type name */
+ TypeCreate(InvalidOid, /* no predetermined type OID */
+ domainName, /* type name */
domainNamespace, /* namespace */
InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */
@@ -820,6 +817,8 @@ DefineDomain(CreateDomainStmt *stmt)
InvalidOid, /* typmodout procedure - none */
analyzeProcedure, /* analyze procedure */
typelem, /* element type ID */
+ false, /* this isn't an array */
+ InvalidOid, /* no arrays for domains (yet) */
basetypeoid, /* base type ID */
defaultValue, /* default type value (text) */
defaultValueBin, /* default type value (binary) */
@@ -949,6 +948,8 @@ DefineEnum(CreateEnumStmt *stmt)
Oid enumNamespace;
Oid enumTypeOid;
AclResult aclresult;
+ Oid enumArrayOid;
+ Relation pg_type;
/* Convert list of names to a name and namespace */
enumNamespace = QualifiedNameGetCreationNamespace(stmt->typename,
@@ -960,19 +961,15 @@ DefineEnum(CreateEnumStmt *stmt)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(enumNamespace));
- /*
- * Type names must be one character shorter than other names, allowing
- * room to create the corresponding array type name with prepended "_".
- */
- if (strlen(enumName) > (NAMEDATALEN - 2))
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_NAME),
- errmsg("type names must be %d characters or less",
- NAMEDATALEN - 2)));
+ /* Preassign array type OID so we can insert it in pg_type.typarray */
+ pg_type = heap_open(TypeRelationId, AccessShareLock);
+ enumArrayOid = GetNewOid(pg_type);
+ heap_close(pg_type, AccessShareLock);
/* Create the pg_type entry */
enumTypeOid =
- TypeCreate(enumName, /* type name */
+ TypeCreate(InvalidOid, /* no predetermined type OID */
+ enumName, /* type name */
enumNamespace, /* namespace */
InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */
@@ -987,6 +984,8 @@ DefineEnum(CreateEnumStmt *stmt)
InvalidOid, /* typmodout procedure - none */
InvalidOid, /* analyze procedure - default */
InvalidOid, /* element type ID */
+ false, /* this is not an array type */
+ enumArrayOid, /* array type we are about to create */
InvalidOid, /* base type ID (only for domains) */
NULL, /* never a default type value */
NULL, /* binary default isn't sent either */
@@ -1000,14 +999,17 @@ DefineEnum(CreateEnumStmt *stmt)
/* Enter the enum's values into pg_enum */
EnumValuesCreate(enumTypeOid, stmt->vals);
- /* Create array type for enum */
- enumArrayName = makeArrayTypeName(enumName);
+ /*
+ * Create the array type that goes with it.
+ */
+ enumArrayName = makeArrayTypeName(enumName, enumNamespace);
- TypeCreate(enumArrayName, /* type name */
+ TypeCreate(enumArrayOid, /* force assignment of this type OID */
+ enumArrayName, /* type name */
enumNamespace, /* namespace */
InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */
- -1, /* internal size */
+ -1, /* internal size (always varlena) */
TYPTYPE_BASE, /* type-type (base type) */
DEFAULT_TYPDELIM, /* array element delimiter */
F_ARRAY_IN, /* input procedure */
@@ -1018,6 +1020,8 @@ DefineEnum(CreateEnumStmt *stmt)
InvalidOid, /* typmodout procedure - none */
InvalidOid, /* analyze procedure - default */
enumTypeOid, /* element type ID */
+ true, /* yes this is an array type */
+ InvalidOid, /* no further array type */
InvalidOid, /* base type ID */
NULL, /* never a default type value */
NULL, /* binary default isn't sent either */
@@ -1026,7 +1030,7 @@ DefineEnum(CreateEnumStmt *stmt)
'x', /* ARRAY is always toastable */
-1, /* typMod (Domains only) */
0, /* Array dimensions of typbasetype */
- false); /* Type NOT NULL */
+ false); /* Type NOT NULL */
pfree(enumArrayName);
}
@@ -1435,7 +1439,7 @@ AlterDomainDefault(List *names, Node *defaultRaw)
/* Rebuild dependencies */
GenerateTypeDependencies(typTup->typnamespace,
domainoid,
- typTup->typrelid,
+ InvalidOid, /* typrelid is n/a */
0, /* relation kind is n/a */
typTup->typowner,
typTup->typinput,
@@ -1446,6 +1450,7 @@ AlterDomainDefault(List *names, Node *defaultRaw)
typTup->typmodout,
typTup->typanalyze,
typTup->typelem,
+ false, /* a domain isn't an implicit array */
typTup->typbasetype,
defaultExpr,
true); /* Rebuild is true */
@@ -2251,7 +2256,7 @@ AlterTypeOwner(List *names, Oid newOwnerId)
/*
* If it's a composite type, we need to check that it really is a
- * free-standing composite type, and not a table's underlying type. We
+ * free-standing composite type, and not a table's rowtype. We
* want people to use ALTER TABLE not ALTER TYPE for that case.
*/
if (typTup->typtype == TYPTYPE_COMPOSITE &&
@@ -2261,6 +2266,16 @@ AlterTypeOwner(List *names, Oid newOwnerId)
errmsg("\"%s\" is a table's row type",
TypeNameToString(typename))));
+ /* don't allow direct alteration of array types, either */
+ if (OidIsValid(typTup->typelem) &&
+ get_array_type(typTup->typelem) == typeOid)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("cannot alter array type %s",
+ format_type_be(typeOid)),
+ errhint("You can alter type %s, which will alter the array type as well.",
+ format_type_be(typTup->typelem))));
+
/*
* If the new owner is the same as the existing owner, consider the
* command to have succeeded. This is for dump restoration purposes.
@@ -2288,16 +2303,32 @@ AlterTypeOwner(List *names, Oid newOwnerId)
}
/*
- * Modify the owner --- okay to scribble on typTup because it's a copy
+ * If it's a composite type, invoke ATExecChangeOwner so that we
+ * fix up the pg_class entry properly. That will call back to
+ * AlterTypeOwnerInternal to take care of the pg_type entry(s).
*/
- typTup->typowner = newOwnerId;
+ if (typTup->typtype == TYPTYPE_COMPOSITE)
+ ATExecChangeOwner(typTup->typrelid, newOwnerId, true);
+ else
+ {
+ /*
+ * We can just apply the modification directly.
+ *
+ * okay to scribble on typTup because it's a copy
+ */
+ typTup->typowner = newOwnerId;
- simple_heap_update(rel, &tup->t_self, tup);
+ simple_heap_update(rel, &tup->t_self, tup);
- CatalogUpdateIndexes(rel, tup);
+ CatalogUpdateIndexes(rel, tup);
- /* Update owner dependency reference */
- changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
+ /* Update owner dependency reference */
+ changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
+
+ /* If it has an array type, update that too */
+ if (OidIsValid(typTup->typarray))
+ AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
+ }
}
/* Clean up */
@@ -2307,12 +2338,17 @@ AlterTypeOwner(List *names, Oid newOwnerId)
/*
* AlterTypeOwnerInternal - change type owner unconditionally
*
- * This is currently only used to propagate ALTER TABLE OWNER to the
- * table's rowtype, and to implement REASSIGN OWNED BY. It assumes the
- * caller has done all needed checks.
+ * This is currently only used to propagate ALTER TABLE/TYPE OWNER to a
+ * table's rowtype or an array type, and to implement REASSIGN OWNED BY.
+ * It assumes the caller has done all needed checks. The function will
+ * automatically recurse to an array type if the type has one.
+ *
+ * hasDependEntry should be TRUE if type is expected to have a pg_shdepend
+ * entry (ie, it's not a table rowtype nor an array type).
*/
void
-AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
+AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
+ bool hasDependEntry)
{
Relation rel;
HeapTuple tup;
@@ -2336,8 +2372,13 @@ AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
CatalogUpdateIndexes(rel, tup);
- /* Update owner dependency reference */
- changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
+ /* Update owner dependency reference, if it has one */
+ if (hasDependEntry)
+ changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
+
+ /* If it has an array type, update that too */
+ if (OidIsValid(typTup->typarray))
+ AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
/* Clean up */
heap_close(rel, RowExclusiveLock);
@@ -2352,6 +2393,7 @@ AlterTypeNamespace(List *names, const char *newschema)
TypeName *typename;
Oid typeOid;
Oid nspOid;
+ Oid elemOid;
/* Make a TypeName so we can use standard type lookup machinery */
typename = makeTypeNameFromNameList(names);
@@ -2365,8 +2407,18 @@ AlterTypeNamespace(List *names, const char *newschema)
/* get schema OID and check its permissions */
nspOid = LookupCreationNamespace(newschema);
+ /* don't allow direct alteration of array types */
+ elemOid = get_element_type(typeOid);
+ if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("cannot alter array type %s",
+ format_type_be(typeOid)),
+ errhint("You can alter type %s, which will alter the array type as well.",
+ format_type_be(elemOid))));
+
/* and do the work */
- AlterTypeNamespaceInternal(typeOid, nspOid, true);
+ AlterTypeNamespaceInternal(typeOid, nspOid, false, true);
}
/*
@@ -2374,18 +2426,24 @@ AlterTypeNamespace(List *names, const char *newschema)
*
* Caller must have already checked privileges.
*
+ * The function automatically recurses to process the type's array type,
+ * if any. isImplicitArray should be TRUE only when doing this internal
+ * recursion (outside callers must never try to move an array type directly).
+ *
* If errorOnTableType is TRUE, the function errors out if the type is
* a table type. ALTER TABLE has to be used to move a table to a new
* namespace.
*/
void
AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
+ bool isImplicitArray,
bool errorOnTableType)
{
Relation rel;
HeapTuple tup;
Form_pg_type typform;
Oid oldNspOid;
+ Oid arrayOid;
bool isCompositeType;
rel = heap_open(TypeRelationId, RowExclusiveLock);
@@ -2398,6 +2456,7 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
typform = (Form_pg_type) GETSTRUCT(tup);
oldNspOid = typform->typnamespace;
+ arrayOid = typform->typarray;
if (oldNspOid == nspOid)
ereport(ERROR,
@@ -2463,13 +2522,9 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
classRel = heap_open(RelationRelationId, RowExclusiveLock);
- /*
- * The dependency on the schema is listed under the pg_class entry, so
- * tell AlterRelationNamespaceInternal to fix it.
- */
AlterRelationNamespaceInternal(classRel, typform->typrelid,
oldNspOid, nspOid,
- true);
+ false);
heap_close(classRel, RowExclusiveLock);
@@ -2485,19 +2540,24 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
/* If it's a domain, it might have constraints */
if (typform->typtype == TYPTYPE_DOMAIN)
AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true);
+ }
- /*
- * Update dependency on schema, if any --- a table rowtype has not got
- * one.
- */
- if (typform->typtype != TYPTYPE_COMPOSITE)
- if (changeDependencyFor(TypeRelationId, typeOid,
+ /*
+ * Update dependency on schema, if any --- a table rowtype has not got
+ * one, and neither does an implicit array.
+ */
+ if ((isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
+ !isImplicitArray)
+ if (changeDependencyFor(TypeRelationId, typeOid,
NamespaceRelationId, oldNspOid, nspOid) != 1)
- elog(ERROR, "failed to change schema dependency for type %s",
- format_type_be(typeOid));
- }
+ elog(ERROR, "failed to change schema dependency for type %s",
+ format_type_be(typeOid));
heap_freetuple(tup);
heap_close(rel, RowExclusiveLock);
+
+ /* Recursively alter the associated array type, if any */
+ if (OidIsValid(arrayOid))
+ AlterTypeNamespaceInternal(arrayOid, nspOid, true, true);
}
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index 0263386d2a2..d3198f0496a 100644
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.89 2007/04/27 22:05:48 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.90 2007/05/11 17:57:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -116,10 +116,6 @@ LookupTypeName(ParseState *pstate, const TypeName *typename)
/* deconstruct the name list */
DeconstructQualifiedName(typename->names, &schemaname, &typname);
- /* If an array reference, look up the array type instead */
- if (typename->arrayBounds != NIL)
- typname = makeArrayTypeName(typname);
-
if (schemaname)
{
/* Look in specific schema only */
@@ -136,6 +132,10 @@ LookupTypeName(ParseState *pstate, const TypeName *typename)
/* Unqualified type name, so search the search path */
restype = TypenameGetTypid(typname);
}
+
+ /* If an array reference, return the array type instead */
+ if (typename->arrayBounds != NIL)
+ restype = get_array_type(restype);
}
return restype;
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 391870c3a69..d86a70521e3 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.151 2007/04/02 03:49:39 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.152 2007/05/11 17:57:12 tgl Exp $
*
* NOTES
* Eventually, the index information should go through here, too.
@@ -2203,50 +2203,24 @@ get_element_type(Oid typid)
/*
* get_array_type
*
- * Given the type OID, get the corresponding array type.
+ * Given the type OID, get the corresponding "true" array type.
* Returns InvalidOid if no array type can be found.
- *
- * NB: this only considers varlena arrays to be true arrays.
*/
Oid
get_array_type(Oid typid)
{
HeapTuple tp;
+ Oid result = InvalidOid;
tp = SearchSysCache(TYPEOID,
ObjectIdGetDatum(typid),
0, 0, 0);
if (HeapTupleIsValid(tp))
{
- Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
- char *array_typename;
- Oid namespaceId;
-
- array_typename = makeArrayTypeName(NameStr(typtup->typname));
- namespaceId = typtup->typnamespace;
+ result = ((Form_pg_type) GETSTRUCT(tp))->typarray;
ReleaseSysCache(tp);
-
- tp = SearchSysCache(TYPENAMENSP,
- PointerGetDatum(array_typename),
- ObjectIdGetDatum(namespaceId),
- 0, 0);
-
- pfree(array_typename);
-
- if (HeapTupleIsValid(tp))
- {
- Oid result;
-
- typtup = (Form_pg_type) GETSTRUCT(tp);
- if (typtup->typlen == -1 && typtup->typelem == typid)
- result = HeapTupleGetOid(tp);
- else
- result = InvalidOid;
- ReleaseSysCache(tp);
- return result;
- }
}
- return InvalidOid;
+ return result;
}
/*