Commit bc8036fc authored by Tom Lane's avatar Tom Lane

Support arrays of composite types, including the rowtypes of regular tables

and views (but not system catalogs, nor sequences or toast tables).  Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage.  (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)

Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.

David Fetter, Andrew Dunstan, Tom Lane
parent b1110aaa
<!-- $PostgreSQL: pgsql/doc/src/sgml/array.sgml,v 1.60 2007/04/06 19:22:38 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/array.sgml,v 1.61 2007/05/11 17:57:11 tgl Exp $ -->
<sect1 id="arrays">
<title>Arrays</title>
......@@ -10,8 +10,9 @@
<para>
<productname>PostgreSQL</productname> allows columns of a table to be
defined as variable-length multidimensional arrays. Arrays of any
built-in or user-defined base type or enum type can be created.
(Arrays of composite types or domains are not yet supported, however.)
built-in or user-defined base type, enum type, or composite type
can be created.
Arrays of domains are not yet supported.
</para>
<sect2>
......
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.150 2007/04/06 22:33:41 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.151 2007/05/11 17:57:11 tgl Exp $ -->
<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
-->
......@@ -4524,6 +4524,17 @@
</entry>
</row>
<row>
<entry><structfield>typarray</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
<entry>
If <structfield>typarray</structfield> is not 0 then it
identifies another row in <structname>pg_type</structname>, which
is the <quote>true</quote> array type having this type as element
</entry>
</row>
<row>
<entry><structfield>typinput</structfield></entry>
<entry><type>regproc</type></entry>
......@@ -4686,9 +4697,10 @@
<entry></entry>
<entry><para>
<structfield>typndims</structfield> is the number of array dimensions
for a domain that is an array (that is, <structfield>typbasetype</> is an array type;
the domain's <structfield>typelem</> will match the base type's <structfield>typelem</structfield>).
Zero for types other than array domains
for a domain that is an array (that is, <structfield>typbasetype</> is
an array type; the domain's <structfield>typelem</> will match the base
type's <structfield>typelem</structfield>).
Zero for types other than domains over array types
</para></entry>
</row>
......
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_type.sgml,v 1.69 2007/04/02 03:49:37 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/create_type.sgml,v 1.70 2007/05/11 17:57:11 tgl Exp $
PostgreSQL documentation
-->
......@@ -312,15 +312,17 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
<title>Array Types</title>
<para>
Whenever a user-defined base or enum data type is created,
Whenever a user-defined type is created,
<productname>PostgreSQL</productname> automatically creates an
associated array type, whose name consists of the base type's
name prepended with an underscore. The parser understands this
naming convention, and translates requests for columns of type
<literal>foo[]</> into requests for type <literal>_foo</>.
The implicitly-created array type is variable length and uses the
name prepended with an underscore, and truncated if necessary to keep
it less than <symbol>NAMEDATALEN</symbol> bytes long. (If the name
so generated collides with an existing type name, the process is
repeated until a non-colliding name is found.)
This implicitly-created array type is variable length and uses the
built-in input and output functions <literal>array_in</> and
<literal>array_out</>.
<literal>array_out</>. The array type tracks any changes in its
element type's owner or schema, and is dropped if the element type is.
</para>
<para>
......@@ -330,10 +332,9 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
making a fixed-length type that happens to be internally an array of a number of
identical things, and you want to allow these things to be accessed
directly by subscripting, in addition to whatever operations you plan
to provide for the type as a whole. For example, type <type>name</>
allows its constituent <type>char</> elements to be accessed this way.
A 2-D <type>point</> type could allow its two component numbers to be
accessed like <literal>point[0]</> and <literal>point[1]</>.
to provide for the type as a whole. For example, type <type>point</>
is represented as just two floating-point numbers, which it allows to be
accessed as <literal>point[0]</> and <literal>point[1]</>.
Note that
this facility only works for fixed-length types whose internal form
is exactly a sequence of identical fixed-length fields. A subscriptable
......@@ -529,12 +530,15 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
<title>Notes</title>
<para>
User-defined type names should not begin with the underscore character
(<literal>_</literal>) and should only be 62 characters
long (or in general <symbol>NAMEDATALEN</symbol> - 2, rather than
the <symbol>NAMEDATALEN</symbol> - 1 characters allowed for other
names). Type names beginning with underscore are reserved for
internally-created array type names.
It is best to avoid using type names that begin with the underscore
character (<literal>_</literal>). <productname>PostgreSQL</productname>
forms the name of an array type by prepending one or more underscores
to the element type's name, and these names may collide with user-defined
type names that begin with underscore. While the system will modify
generated array type names to avoid collisions, this does not help if the
conflicting array type already exists when you try to create your type.
Also, various old client software may assume that names beginning with
underscores always represent arrays.
</para>
<para>
......
<!-- $PostgreSQL: pgsql/doc/src/sgml/syntax.sgml,v 1.117 2007/02/20 14:04:50 momjian Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/syntax.sgml,v 1.118 2007/05/11 17:57:11 tgl Exp $ -->
<chapter id="sql-syntax">
<title>SQL Syntax</title>
......@@ -131,10 +131,10 @@ INSERT INTO MY_TABLE VALUES (3, 'hi there');
<para>
<indexterm><primary>identifier</primary><secondary>length</secondary></indexterm>
The system uses no more than <symbol>NAMEDATALEN</symbol>-1
characters of an identifier; longer names can be written in
bytes of an identifier; longer names can be written in
commands, but they will be truncated. By default,
<symbol>NAMEDATALEN</symbol> is 64 so the maximum identifier
length is 63. If this limit is problematic, it can be raised by
length is 63 bytes. If this limit is problematic, it can be raised by
changing the <symbol>NAMEDATALEN</symbol> constant in
<filename>src/include/pg_config_manual.h</filename>.
</para>
......
$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
......
......@@ -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);
}
/*
......
......@@ -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:
......
......@@ -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;
}
......@@ -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);
......
This diff is collapsed.
......@@ -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;
......
......@@ -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;
}
/*
......
......@@ -12,7 +12,7 @@
* by PostgreSQL
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.467 2007/04/16 18:42:10 tgl Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.468 2007/05/11 17:57:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -963,9 +963,8 @@ selectDumpableType(TypeInfo *tinfo)
else if (!tinfo->isDefined)
tinfo->dobj.dump = false;
/* skip all array types that start w/ underscore */
else if ((tinfo->dobj.name[0] == '_') &&
OidIsValid(tinfo->typelem))
/* skip auto-generated array types */
else if (tinfo->isArray)
tinfo->dobj.dump = false;
else
......@@ -1963,6 +1962,7 @@ getTypes(int *numTypes)
int i_typrelkind;
int i_typtype;
int i_typisdefined;
int i_isarray;
/*
* we include even the built-in types because those may be used as array
......@@ -1970,13 +1970,20 @@ getTypes(int *numTypes)
*
* we filter out the built-in types when we dump out the types
*
* same approach for undefined (shell) types
* same approach for undefined (shell) types and array types
*
* Note: as of 8.3 we can reliably detect whether a type is an
* auto-generated array type by checking the element type's typarray.
* (Before that the test is capable of generating false positives.)
* We still check for name beginning with '_', though, so as to avoid
* the cost of the subselect probe for all standard types. This would
* have to be revisited if the backend ever allows renaming of array types.
*/
/* Make sure we are in proper schema */
selectSourceSchema("pg_catalog");
if (g_fout->remoteVersion >= 70300)
if (g_fout->remoteVersion >= 80300)
{
appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
"typnamespace, "
......@@ -1985,7 +1992,23 @@ getTypes(int *numTypes)
"typoutput::oid as typoutput, typelem, typrelid, "
"CASE WHEN typrelid = 0 THEN ' '::\"char\" "
"ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END as typrelkind, "
"typtype, typisdefined "
"typtype, typisdefined, "
"typname[0] = '_' AND typelem != 0 AND "
"(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
"FROM pg_type",
username_subquery);
}
else if (g_fout->remoteVersion >= 70300)
{
appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
"typnamespace, "
"(%s typowner) as rolname, "
"typinput::oid as typinput, "
"typoutput::oid as typoutput, typelem, typrelid, "
"CASE WHEN typrelid = 0 THEN ' '::\"char\" "
"ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END as typrelkind, "
"typtype, typisdefined, "
"typname[0] = '_' AND typelem != 0 AS isarray "
"FROM pg_type",
username_subquery);
}
......@@ -1998,7 +2021,8 @@ getTypes(int *numTypes)
"typoutput::oid as typoutput, typelem, typrelid, "
"CASE WHEN typrelid = 0 THEN ' '::\"char\" "
"ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END as typrelkind, "
"typtype, typisdefined "
"typtype, typisdefined, "
"typname[0] = '_' AND typelem != 0 AS isarray "
"FROM pg_type",
username_subquery);
}
......@@ -2013,7 +2037,8 @@ getTypes(int *numTypes)
"typoutput::oid as typoutput, typelem, typrelid, "
"CASE WHEN typrelid = 0 THEN ' '::\"char\" "
"ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END as typrelkind, "
"typtype, typisdefined "
"typtype, typisdefined, "
"typname[0] = '_' AND typelem != 0 AS isarray "
"FROM pg_type",
username_subquery);
}
......@@ -2037,6 +2062,7 @@ getTypes(int *numTypes)
i_typrelkind = PQfnumber(res, "typrelkind");
i_typtype = PQfnumber(res, "typtype");
i_typisdefined = PQfnumber(res, "typisdefined");
i_isarray = PQfnumber(res, "isarray");
for (i = 0; i < ntups; i++)
{
......@@ -2064,20 +2090,16 @@ getTypes(int *numTypes)
tinfo[i].typrelkind != RELKIND_COMPOSITE_TYPE)
tinfo[i].dobj.objType = DO_TABLE_TYPE;
/*
* check for user-defined array types, omit system generated ones
*/
if (OidIsValid(tinfo[i].typelem) &&
tinfo[i].dobj.name[0] != '_')
tinfo[i].isArray = true;
else
tinfo[i].isArray = false;
if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
tinfo[i].isDefined = true;
else
tinfo[i].isDefined = false;
if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
tinfo[i].isArray = true;
else
tinfo[i].isArray = false;
/* Decide whether we want to dump it */
selectDumpableType(&tinfo[i]);
......@@ -3894,7 +3916,7 @@ getTriggers(TableInfo tblinfo[], int numTables)
else if (g_fout->remoteVersion >= 70100)
{
appendPQExpBuffer(query,
"SELECT tgname, tgfoid::pg_catalog.regproc as tgfname, "
"SELECT tgname, tgfoid::regproc as tgfname, "
"tgtype, tgnargs, tgargs, tgenabled, "
"tgisconstraint, tgconstrname, tgdeferrable, "
"tgconstrrelid, tginitdeferred, tableoid, oid, "
......@@ -3907,7 +3929,7 @@ getTriggers(TableInfo tblinfo[], int numTables)
else
{
appendPQExpBuffer(query,
"SELECT tgname, tgfoid::pg_catalog.regproc as tgfname, "
"SELECT tgname, tgfoid::regproc as tgfname, "
"tgtype, tgnargs, tgargs, tgenabled, "
"tgisconstraint, tgconstrname, tgdeferrable, "
"tgconstrrelid, tginitdeferred, "
......@@ -5473,7 +5495,7 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo)
appendPQExpBufferStr(q, typdefault);
}
if (tinfo->isArray)
if (OidIsValid(tinfo->typelem))
{
char *elemType;
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.134 2007/03/19 23:38:30 wieck Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.135 2007/05/11 17:57:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -164,7 +164,7 @@ typedef struct _typeInfo
Oid typrelid;
char typrelkind; /* 'r', 'v', 'c', etc */
char typtype; /* 'b', 'c', etc */
bool isArray; /* true if user-defined array type */
bool isArray; /* true if auto-generated array type */
bool isDefined; /* true if typisdefined */
/* If it's a dumpable base type, we create a "shell type" entry for it */
struct _shellTypeInfo *shellType; /* shell-type entry, or NULL */
......
......@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.405 2007/05/08 18:56:47 neilc Exp $
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.406 2007/05/11 17:57:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200705081
#define CATALOG_VERSION_NO 200705111
#endif
......@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.130 2007/01/22 01:35:21 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.131 2007/05/11 17:57:13 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
......@@ -232,21 +232,22 @@ typedef FormData_pg_attribute *Form_pg_attribute;
{ 1247, {"typdelim"}, 18, -1, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typrelid"}, 26, -1, 4, 9, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typelem"}, 26, -1, 4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typinput"}, 24, -1, 4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typoutput"}, 24, -1, 4, 12, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typreceive"}, 24, -1, 4, 13, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typsend"}, 24, -1, 4, 14, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typmodin"}, 24, -1, 4, 15, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typmodout"}, 24, -1, 4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typanalyze"}, 24, -1, 4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typalign"}, 18, -1, 1, 18, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typstorage"}, 18, -1, 1, 19, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typnotnull"}, 16, -1, 1, 20, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typbasetype"}, 26, -1, 4, 21, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typtypmod"}, 23, -1, 4, 22, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typndims"}, 23, -1, 4, 23, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typdefaultbin"}, 25, -1, -1, 24, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1247, {"typdefault"}, 25, -1, -1, 25, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
{ 1247, {"typarray"}, 26, -1, 4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typinput"}, 24, -1, 4, 12, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typoutput"}, 24, -1, 4, 13, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typreceive"}, 24, -1, 4, 14, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typsend"}, 24, -1, 4, 15, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typmodin"}, 24, -1, 4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typmodout"}, 24, -1, 4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typanalyze"}, 24, -1, 4, 18, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typalign"}, 18, -1, 1, 19, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typstorage"}, 18, -1, 1, 20, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typnotnull"}, 16, -1, 1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typbasetype"}, 26, -1, 4, 22, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typtypmod"}, 23, -1, 4, 23, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typndims"}, 23, -1, 4, 24, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typdefaultbin"}, 25, -1, -1, 25, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1247, {"typdefault"}, 25, -1, -1, 26, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
DATA(insert ( 1247 typname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0));
DATA(insert ( 1247 typnamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0));
......@@ -258,21 +259,22 @@ DATA(insert ( 1247 typisdefined 16 -1 1 7 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typdelim 18 -1 1 8 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typrelid 26 -1 4 9 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typelem 26 -1 4 10 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typinput 24 -1 4 11 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typoutput 24 -1 4 12 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typreceive 24 -1 4 13 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typsend 24 -1 4 14 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typmodin 24 -1 4 15 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typmodout 24 -1 4 16 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typanalyze 24 -1 4 17 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typalign 18 -1 1 18 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typstorage 18 -1 1 19 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typnotnull 16 -1 1 20 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typbasetype 26 -1 4 21 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typtypmod 23 -1 4 22 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typndims 23 -1 4 23 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typdefaultbin 25 -1 -1 24 0 -1 -1 f x i f f f t 0));
DATA(insert ( 1247 typdefault 25 -1 -1 25 0 -1 -1 f x i f f f t 0));
DATA(insert ( 1247 typarray 26 -1 4 11 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typinput 24 -1 4 12 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typoutput 24 -1 4 13 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typreceive 24 -1 4 14 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typsend 24 -1 4 15 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typmodin 24 -1 4 16 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typmodout 24 -1 4 17 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typanalyze 24 -1 4 18 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typalign 18 -1 1 19 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typstorage 18 -1 1 20 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typnotnull 16 -1 1 21 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typbasetype 26 -1 4 22 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typtypmod 23 -1 4 23 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typndims 23 -1 4 24 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typdefaultbin 25 -1 -1 25 0 -1 -1 f x i f f f t 0));
DATA(insert ( 1247 typdefault 25 -1 -1 26 0 -1 -1 f x i f f f t 0));
DATA(insert ( 1247 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0));
DATA(insert ( 1247 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0));
......
......@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.100 2007/01/22 01:35:22 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.101 2007/05/11 17:57:13 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
......@@ -132,7 +132,7 @@ typedef FormData_pg_class *Form_pg_class;
*/
/* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f r 25 0 0 0 0 0 t f f f 3 _null_ _null_ ));
DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f r 26 0 0 0 0 0 t f f f 3 _null_ _null_ ));
DESCR("");
DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 17 0 0 0 0 0 f f f f 3 _null_ _null_ ));
DESCR("");
......
This diff is collapsed.
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/commands/typecmds.h,v 1.18 2007/04/02 03:49:41 tgl Exp $
* $PostgreSQL: pgsql/src/include/commands/typecmds.h,v 1.19 2007/05/11 17:57:14 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -36,9 +36,11 @@ extern void AlterDomainDropConstraint(List *names, const char *constrName,
extern List *GetDomainConstraints(Oid typeOid);
extern void AlterTypeOwner(List *names, Oid newOwnerId);
extern void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId);
extern void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
bool hasDependEntry);
extern void AlterTypeNamespace(List *names, const char *newschema);
extern void AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
bool errorOnTableType);
bool isImplicitArray,
bool errorOnTableType);
#endif /* TYPECMDS_H */
......@@ -1456,7 +1456,6 @@ select alter2.plus1(41);
-- clean up
drop schema alter2 cascade;
NOTICE: drop cascades to composite type alter2.ctype
NOTICE: drop cascades to type alter2.ctype
NOTICE: drop cascades to type alter2.posint
NOTICE: drop cascades to function alter2.plus1(integer)
......
......@@ -409,6 +409,14 @@ WHERE indrelid != 0 AND
------+----------
(0 rows)
SELECT ctid, lanowner
FROM pg_catalog.pg_language fk
WHERE lanowner != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.lanowner);
ctid | lanowner
------+----------
(0 rows)
SELECT ctid, lanvalidator
FROM pg_catalog.pg_language fk
WHERE lanvalidator != 0 AND
......@@ -721,6 +729,14 @@ WHERE typelem != 0 AND
------+---------
(0 rows)
SELECT ctid, typarray
FROM pg_catalog.pg_type fk
WHERE typarray != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typarray);
ctid | typarray
------+----------
(0 rows)
SELECT ctid, typinput
FROM pg_catalog.pg_type fk
WHERE typinput != 0 AND
......
......@@ -69,6 +69,16 @@ WHERE p1.typtype in ('b','e') AND p1.typname NOT LIKE E'\\_%' AND NOT EXISTS
705 | unknown
(2 rows)
-- Make sure typarray points to a varlena array type of our own base
SELECT p1.oid, p1.typname as basetype, p2.typname as arraytype,
p2.typelem, p2.typlen
FROM pg_type p1 LEFT JOIN pg_type p2 ON (p1.typarray = p2.oid)
WHERE p1.typarray <> 0 AND
(p2.oid IS NULL OR p2.typelem <> p1.oid OR p2.typlen <> -1);
oid | basetype | arraytype | typelem | typlen
-----+----------+-----------+---------+--------
(0 rows)
-- Text conversion routines must be provided.
SELECT p1.oid, p1.typname
FROM pg_type as p1
......
......@@ -205,6 +205,10 @@ SELECT ctid, indrelid
FROM pg_catalog.pg_index fk
WHERE indrelid != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.indrelid);
SELECT ctid, lanowner
FROM pg_catalog.pg_language fk
WHERE lanowner != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.lanowner);
SELECT ctid, lanvalidator
FROM pg_catalog.pg_language fk
WHERE lanvalidator != 0 AND
......@@ -361,6 +365,10 @@ SELECT ctid, typelem
FROM pg_catalog.pg_type fk
WHERE typelem != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typelem);
SELECT ctid, typarray
FROM pg_catalog.pg_type fk
WHERE typarray != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typarray);
SELECT ctid, typinput
FROM pg_catalog.pg_type fk
WHERE typinput != 0 AND
......
......@@ -59,6 +59,13 @@ WHERE p1.typtype in ('b','e') AND p1.typname NOT LIKE E'\\_%' AND NOT EXISTS
WHERE p2.typname = ('_' || p1.typname)::name AND
p2.typelem = p1.oid);
-- Make sure typarray points to a varlena array type of our own base
SELECT p1.oid, p1.typname as basetype, p2.typname as arraytype,
p2.typelem, p2.typlen
FROM pg_type p1 LEFT JOIN pg_type p2 ON (p1.typarray = p2.oid)
WHERE p1.typarray <> 0 AND
(p2.oid IS NULL OR p2.typelem <> p1.oid OR p2.typlen <> -1);
-- Text conversion routines must be provided.
SELECT p1.oid, p1.typname
......
$PostgreSQL: pgsql/src/tools/findoidjoins/README,v 1.4 2007/05/11 17:57:14 tgl Exp $
findoidjoins
......@@ -87,6 +88,7 @@ Join pg_catalog.pg_depend.refclassid => pg_catalog.pg_class.oid
Join pg_catalog.pg_description.classoid => pg_catalog.pg_class.oid
Join pg_catalog.pg_index.indexrelid => pg_catalog.pg_class.oid
Join pg_catalog.pg_index.indrelid => pg_catalog.pg_class.oid
Join pg_catalog.pg_language.lanowner => pg_catalog.pg_authid.oid
Join pg_catalog.pg_language.lanvalidator => pg_catalog.pg_proc.oid
Join pg_catalog.pg_namespace.nspowner => pg_catalog.pg_authid.oid
Join pg_catalog.pg_opclass.opcmethod => pg_catalog.pg_am.oid
......@@ -126,6 +128,7 @@ Join pg_catalog.pg_type.typnamespace => pg_catalog.pg_namespace.oid
Join pg_catalog.pg_type.typowner => pg_catalog.pg_authid.oid
Join pg_catalog.pg_type.typrelid => pg_catalog.pg_class.oid
Join pg_catalog.pg_type.typelem => pg_catalog.pg_type.oid
Join pg_catalog.pg_type.typarray => pg_catalog.pg_type.oid
Join pg_catalog.pg_type.typinput => pg_catalog.pg_proc.oid
Join pg_catalog.pg_type.typoutput => pg_catalog.pg_proc.oid
Join pg_catalog.pg_type.typreceive => pg_catalog.pg_proc.oid
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment