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"> <sect1 id="arrays">
<title>Arrays</title> <title>Arrays</title>
...@@ -10,8 +10,9 @@ ...@@ -10,8 +10,9 @@
<para> <para>
<productname>PostgreSQL</productname> allows columns of a table to be <productname>PostgreSQL</productname> allows columns of a table to be
defined as variable-length multidimensional arrays. Arrays of any defined as variable-length multidimensional arrays. Arrays of any
built-in or user-defined base type or enum type can be created. built-in or user-defined base type, enum type, or composite type
(Arrays of composite types or domains are not yet supported, however.) can be created.
Arrays of domains are not yet supported.
</para> </para>
<sect2> <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 Documentation of the system catalogs, directed toward PostgreSQL developers
--> -->
...@@ -4524,6 +4524,17 @@ ...@@ -4524,6 +4524,17 @@
</entry> </entry>
</row> </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> <row>
<entry><structfield>typinput</structfield></entry> <entry><structfield>typinput</structfield></entry>
<entry><type>regproc</type></entry> <entry><type>regproc</type></entry>
...@@ -4686,9 +4697,10 @@ ...@@ -4686,9 +4697,10 @@
<entry></entry> <entry></entry>
<entry><para> <entry><para>
<structfield>typndims</structfield> is the number of array dimensions <structfield>typndims</structfield> is the number of array dimensions
for a domain that is an array (that is, <structfield>typbasetype</> is an array type; for a domain that is an array (that is, <structfield>typbasetype</> is
the domain's <structfield>typelem</> will match the base type's <structfield>typelem</structfield>). an array type; the domain's <structfield>typelem</> will match the base
Zero for types other than array domains type's <structfield>typelem</structfield>).
Zero for types other than domains over array types
</para></entry> </para></entry>
</row> </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 PostgreSQL documentation
--> -->
...@@ -312,15 +312,17 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> ...@@ -312,15 +312,17 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
<title>Array Types</title> <title>Array Types</title>
<para> <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 <productname>PostgreSQL</productname> automatically creates an
associated array type, whose name consists of the base type's associated array type, whose name consists of the base type's
name prepended with an underscore. The parser understands this name prepended with an underscore, and truncated if necessary to keep
naming convention, and translates requests for columns of type it less than <symbol>NAMEDATALEN</symbol> bytes long. (If the name
<literal>foo[]</> into requests for type <literal>_foo</>. so generated collides with an existing type name, the process is
The implicitly-created array type is variable length and uses the 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 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>
<para> <para>
...@@ -330,10 +332,9 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> ...@@ -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 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 identical things, and you want to allow these things to be accessed
directly by subscripting, in addition to whatever operations you plan directly by subscripting, in addition to whatever operations you plan
to provide for the type as a whole. For example, type <type>name</> to provide for the type as a whole. For example, type <type>point</>
allows its constituent <type>char</> elements to be accessed this way. is represented as just two floating-point numbers, which it allows to be
A 2-D <type>point</> type could allow its two component numbers to be accessed as <literal>point[0]</> and <literal>point[1]</>.
accessed like <literal>point[0]</> and <literal>point[1]</>.
Note that Note that
this facility only works for fixed-length types whose internal form this facility only works for fixed-length types whose internal form
is exactly a sequence of identical fixed-length fields. A subscriptable is exactly a sequence of identical fixed-length fields. A subscriptable
...@@ -529,12 +530,15 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> ...@@ -529,12 +530,15 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
<title>Notes</title> <title>Notes</title>
<para> <para>
User-defined type names should not begin with the underscore character It is best to avoid using type names that begin with the underscore
(<literal>_</literal>) and should only be 62 characters character (<literal>_</literal>). <productname>PostgreSQL</productname>
long (or in general <symbol>NAMEDATALEN</symbol> - 2, rather than forms the name of an array type by prepending one or more underscores
the <symbol>NAMEDATALEN</symbol> - 1 characters allowed for other to the element type's name, and these names may collide with user-defined
names). Type names beginning with underscore are reserved for type names that begin with underscore. While the system will modify
internally-created array type names. 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>
<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"> <chapter id="sql-syntax">
<title>SQL Syntax</title> <title>SQL Syntax</title>
...@@ -131,10 +131,10 @@ INSERT INTO MY_TABLE VALUES (3, 'hi there'); ...@@ -131,10 +131,10 @@ INSERT INTO MY_TABLE VALUES (3, 'hi there');
<para> <para>
<indexterm><primary>identifier</primary><secondary>length</secondary></indexterm> <indexterm><primary>identifier</primary><secondary>length</secondary></indexterm>
The system uses no more than <symbol>NAMEDATALEN</symbol>-1 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, commands, but they will be truncated. By default,
<symbol>NAMEDATALEN</symbol> is 64 so the maximum identifier <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 changing the <symbol>NAMEDATALEN</symbol> constant in
<filename>src/include/pg_config_manual.h</filename>. <filename>src/include/pg_config_manual.h</filename>.
</para> </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; This directory contains .c files that manipulate the system catalogs;
src/include/catalog contains the .h files that define the structure 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 ...@@ -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 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 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 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 NULL. For example, if you set pg_type.typrelid to be NULL, a
piece of code will likely perform "typetup->typdelim" (or, worse, piece of code will likely perform "typetup->typrelid" (or, worse,
"typetyp->typelem", which follows typdelim). This will result in "typetyp->typelem", which follows typrelid). This will result in
random errors or even segmentation violations. Hence, do NOT insert random errors or even segmentation violations. Hence, do NOT insert
catalog tuples that contain NULL attributes except in their catalog tuples that contain NULL attributes except in their
variable-length portions! (The bootstrapping code is fairly good about variable-length portions! (The bootstrapping code is fairly good about
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#include "catalog/pg_statistic.h" #include "catalog/pg_statistic.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "commands/tablecmds.h" #include "commands/tablecmds.h"
#include "commands/typecmds.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "optimizer/var.h" #include "optimizer/var.h"
...@@ -69,7 +70,8 @@ static void AddNewRelationTuple(Relation pg_class_desc, ...@@ -69,7 +70,8 @@ static void AddNewRelationTuple(Relation pg_class_desc,
static Oid AddNewRelationType(const char *typeName, static Oid AddNewRelationType(const char *typeName,
Oid typeNamespace, Oid typeNamespace,
Oid new_rel_oid, Oid new_rel_oid,
char new_rel_kind); char new_rel_kind,
Oid new_array_type);
static void RelationRemoveInheritance(Oid relid); static void RelationRemoveInheritance(Oid relid);
static void StoreRelCheck(Relation rel, char *ccname, char *ccbin); static void StoreRelCheck(Relation rel, char *ccname, char *ccbin);
static void StoreConstraints(Relation rel, TupleDesc tupdesc); static void StoreConstraints(Relation rel, TupleDesc tupdesc);
...@@ -401,26 +403,55 @@ CheckAttributeType(const char *attname, Oid atttypid) ...@@ -401,26 +403,55 @@ CheckAttributeType(const char *attname, Oid atttypid)
{ {
char att_typtype = get_typtype(atttypid); char att_typtype = get_typtype(atttypid);
if (atttypid == UNKNOWNOID)
{
/* /*
* Warn user, but don't fail, if column to be created has UNKNOWN type * Warn user, but don't fail, if column to be created has UNKNOWN type
* (usually as a result of a 'retrieve into' - jolly) * (usually as a result of a 'retrieve into' - jolly)
*
* Refuse any attempt to create a pseudo-type column.
*/ */
if (atttypid == UNKNOWNOID)
ereport(WARNING, ereport(WARNING,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION), (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("column \"%s\" has type \"unknown\"", attname), errmsg("column \"%s\" has type \"unknown\"", attname),
errdetail("Proceeding with relation creation anyway."))); errdetail("Proceeding with relation creation anyway.")));
}
else if (att_typtype == TYPTYPE_PSEUDO) 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) if (atttypid != ANYARRAYOID || IsUnderPostmaster)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION), (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("column \"%s\" has pseudo-type %s", errmsg("column \"%s\" has pseudo-type %s",
attname, format_type_be(atttypid)))); 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 ...@@ -710,16 +741,18 @@ static Oid
AddNewRelationType(const char *typeName, AddNewRelationType(const char *typeName,
Oid typeNamespace, Oid typeNamespace,
Oid new_rel_oid, Oid new_rel_oid,
char new_rel_kind) char new_rel_kind,
Oid new_array_type)
{ {
return return
TypeCreate(typeName, /* type name */ TypeCreate(InvalidOid, /* no predetermined OID */
typeName, /* type name */
typeNamespace, /* type namespace */ typeNamespace, /* type namespace */
new_rel_oid, /* relation oid */ new_rel_oid, /* relation oid */
new_rel_kind, /* relation kind */ new_rel_kind, /* relation kind */
-1, /* internal size (varlena) */ -1, /* internal size (varlena) */
TYPTYPE_COMPOSITE, /* type-type (composite) */ TYPTYPE_COMPOSITE, /* type-type (composite) */
',', /* default array delimiter */ DEFAULT_TYPDELIM, /* default array delimiter */
F_RECORD_IN, /* input procedure */ F_RECORD_IN, /* input procedure */
F_RECORD_OUT, /* output procedure */ F_RECORD_OUT, /* output procedure */
F_RECORD_RECV, /* receive procedure */ F_RECORD_RECV, /* receive procedure */
...@@ -728,6 +761,8 @@ AddNewRelationType(const char *typeName, ...@@ -728,6 +761,8 @@ AddNewRelationType(const char *typeName,
InvalidOid, /* typmodout procedure - none */ InvalidOid, /* typmodout procedure - none */
InvalidOid, /* analyze procedure - default */ InvalidOid, /* analyze procedure - default */
InvalidOid, /* array element type - irrelevant */ InvalidOid, /* array element type - irrelevant */
false, /* this is not an array type */
new_array_type, /* array type if any */
InvalidOid, /* domain base type - irrelevant */ InvalidOid, /* domain base type - irrelevant */
NULL, /* default value - none */ NULL, /* default value - none */
NULL, /* default binary representation */ NULL, /* default binary representation */
...@@ -763,6 +798,7 @@ heap_create_with_catalog(const char *relname, ...@@ -763,6 +798,7 @@ heap_create_with_catalog(const char *relname,
Relation pg_class_desc; Relation pg_class_desc;
Relation new_rel_desc; Relation new_rel_desc;
Oid new_type_oid; Oid new_type_oid;
Oid new_array_oid = InvalidOid;
pg_class_desc = heap_open(RelationRelationId, RowExclusiveLock); pg_class_desc = heap_open(RelationRelationId, RowExclusiveLock);
...@@ -805,7 +841,24 @@ heap_create_with_catalog(const char *relname, ...@@ -805,7 +841,24 @@ heap_create_with_catalog(const char *relname,
Assert(relid == RelationGetRelid(new_rel_desc)); 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. * system type corresponding to the new relation.
* *
* NOTE: we could get a unique-index failure here, in case the same name * 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, ...@@ -814,7 +867,47 @@ heap_create_with_catalog(const char *relname,
new_type_oid = AddNewRelationType(relname, new_type_oid = AddNewRelationType(relname,
relnamespace, relnamespace,
relid, 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. * now create an entry in pg_class for the relation.
...@@ -838,13 +931,15 @@ heap_create_with_catalog(const char *relname, ...@@ -838,13 +931,15 @@ heap_create_with_catalog(const char *relname,
oidislocal, oidinhcount); oidislocal, oidinhcount);
/* /*
* make a dependency link to force the relation to be deleted if its * 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 * namespace is. Also make a dependency link to its owner.
* dependencies while bootstrapping.
* *
* 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, ObjectAddress myself,
referenced; referenced;
...@@ -857,12 +952,6 @@ heap_create_with_catalog(const char *relname, ...@@ -857,12 +952,6 @@ heap_create_with_catalog(const char *relname,
referenced.objectSubId = 0; referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); 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 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -1254,7 +1254,7 @@ shdepReassignOwned(List *roleids, Oid newrole)
break; break;
case TypeRelationId: case TypeRelationId:
AlterTypeOwnerInternal(sdepForm->objid, newrole); AlterTypeOwnerInternal(sdepForm->objid, newrole, true);
break; break;
case OperatorRelationId: case OperatorRelationId:
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -22,6 +22,7 @@
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "commands/typecmds.h" #include "commands/typecmds.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "parser/scansup.h"
#include "utils/acl.h" #include "utils/acl.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
...@@ -90,6 +91,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace) ...@@ -90,6 +91,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
values[i++] = CharGetDatum(DEFAULT_TYPDELIM); /* typdelim */ values[i++] = CharGetDatum(DEFAULT_TYPDELIM); /* typdelim */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typrelid */ values[i++] = ObjectIdGetDatum(InvalidOid); /* typrelid */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typelem */ values[i++] = ObjectIdGetDatum(InvalidOid); /* typelem */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typarray */
values[i++] = ObjectIdGetDatum(F_SHELL_IN); /* typinput */ values[i++] = ObjectIdGetDatum(F_SHELL_IN); /* typinput */
values[i++] = ObjectIdGetDatum(F_SHELL_OUT); /* typoutput */ values[i++] = ObjectIdGetDatum(F_SHELL_OUT); /* typoutput */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typreceive */ values[i++] = ObjectIdGetDatum(InvalidOid); /* typreceive */
...@@ -135,6 +137,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace) ...@@ -135,6 +137,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
InvalidOid, InvalidOid,
InvalidOid, InvalidOid,
InvalidOid, InvalidOid,
false,
InvalidOid, InvalidOid,
NULL, NULL,
false); false);
...@@ -153,13 +156,16 @@ TypeShellMake(const char *typeName, Oid typeNamespace) ...@@ -153,13 +156,16 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
* *
* This does all the necessary work needed to define a new type. * 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 Oid
TypeCreate(const char *typeName, TypeCreate(Oid newTypeOid,
const char *typeName,
Oid typeNamespace, Oid typeNamespace,
Oid relationOid, /* only for composite types */ Oid relationOid, /* only for relation rowtypes */
char relationKind, /* ditto */ char relationKind, /* ditto */
int16 internalSize, int16 internalSize,
char typeType, char typeType,
...@@ -172,6 +178,8 @@ TypeCreate(const char *typeName, ...@@ -172,6 +178,8 @@ TypeCreate(const char *typeName,
Oid typmodoutProcedure, Oid typmodoutProcedure,
Oid analyzeProcedure, Oid analyzeProcedure,
Oid elementType, Oid elementType,
bool isImplicitArray,
Oid arrayType,
Oid baseType, Oid baseType,
const char *defaultTypeValue, /* human readable rep */ const char *defaultTypeValue, /* human readable rep */
char *defaultTypeBin, /* cooked rep */ char *defaultTypeBin, /* cooked rep */
...@@ -243,9 +251,9 @@ TypeCreate(const char *typeName, ...@@ -243,9 +251,9 @@ TypeCreate(const char *typeName,
values[i++] = CharGetDatum(typeType); /* typtype */ values[i++] = CharGetDatum(typeType); /* typtype */
values[i++] = BoolGetDatum(true); /* typisdefined */ values[i++] = BoolGetDatum(true); /* typisdefined */
values[i++] = CharGetDatum(typDelim); /* typdelim */ values[i++] = CharGetDatum(typDelim); /* typdelim */
values[i++] = ObjectIdGetDatum(typeType == TYPTYPE_COMPOSITE ? values[i++] = ObjectIdGetDatum(relationOid); /* typrelid */
relationOid : InvalidOid); /* typrelid */
values[i++] = ObjectIdGetDatum(elementType); /* typelem */ values[i++] = ObjectIdGetDatum(elementType); /* typelem */
values[i++] = ObjectIdGetDatum(arrayType); /* typarray */
values[i++] = ObjectIdGetDatum(inputProcedure); /* typinput */ values[i++] = ObjectIdGetDatum(inputProcedure); /* typinput */
values[i++] = ObjectIdGetDatum(outputProcedure); /* typoutput */ values[i++] = ObjectIdGetDatum(outputProcedure); /* typoutput */
values[i++] = ObjectIdGetDatum(receiveProcedure); /* typreceive */ values[i++] = ObjectIdGetDatum(receiveProcedure); /* typreceive */
...@@ -310,6 +318,10 @@ TypeCreate(const char *typeName, ...@@ -310,6 +318,10 @@ TypeCreate(const char *typeName,
if (((Form_pg_type) GETSTRUCT(tup))->typowner != GetUserId()) if (((Form_pg_type) GETSTRUCT(tup))->typowner != GetUserId())
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, typeName); 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 * Okay to update existing shell type tuple
*/ */
...@@ -331,6 +343,10 @@ TypeCreate(const char *typeName, ...@@ -331,6 +343,10 @@ TypeCreate(const char *typeName,
values, values,
nulls); 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); typeObjectId = simple_heap_insert(pg_type_desc, tup);
} }
...@@ -354,6 +370,7 @@ TypeCreate(const char *typeName, ...@@ -354,6 +370,7 @@ TypeCreate(const char *typeName,
typmodoutProcedure, typmodoutProcedure,
analyzeProcedure, analyzeProcedure,
elementType, elementType,
isImplicitArray,
baseType, baseType,
(defaultTypeBin ? (defaultTypeBin ?
stringToNode(defaultTypeBin) : stringToNode(defaultTypeBin) :
...@@ -378,7 +395,7 @@ TypeCreate(const char *typeName, ...@@ -378,7 +395,7 @@ TypeCreate(const char *typeName,
void void
GenerateTypeDependencies(Oid typeNamespace, GenerateTypeDependencies(Oid typeNamespace,
Oid typeObjectId, Oid typeObjectId,
Oid relationOid, /* only for composite types */ Oid relationOid, /* only for relation rowtypes */
char relationKind, /* ditto */ char relationKind, /* ditto */
Oid owner, Oid owner,
Oid inputProcedure, Oid inputProcedure,
...@@ -389,6 +406,7 @@ GenerateTypeDependencies(Oid typeNamespace, ...@@ -389,6 +406,7 @@ GenerateTypeDependencies(Oid typeNamespace,
Oid typmodoutProcedure, Oid typmodoutProcedure,
Oid analyzeProcedure, Oid analyzeProcedure,
Oid elementType, Oid elementType,
bool isImplicitArray,
Oid baseType, Oid baseType,
Node *defaultExpr, Node *defaultExpr,
bool rebuild) bool rebuild)
...@@ -406,14 +424,23 @@ GenerateTypeDependencies(Oid typeNamespace, ...@@ -406,14 +424,23 @@ GenerateTypeDependencies(Oid typeNamespace,
myself.objectId = typeObjectId; myself.objectId = typeObjectId;
myself.objectSubId = 0; myself.objectSubId = 0;
/* dependency on namespace */ /*
/* skip for relation rowtype, since we have indirect dependency */ * Make dependency on namespace and shared dependency on owner.
if (!OidIsValid(relationOid)) *
* 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.classId = NamespaceRelationId;
referenced.objectId = typeNamespace; referenced.objectId = typeNamespace;
referenced.objectSubId = 0; referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
recordDependencyOnOwner(TypeRelationId, typeObjectId, owner);
} }
/* Normal dependencies on the I/O functions */ /* Normal dependencies on the I/O functions */
...@@ -495,17 +522,17 @@ GenerateTypeDependencies(Oid typeNamespace, ...@@ -495,17 +522,17 @@ GenerateTypeDependencies(Oid typeNamespace,
} }
/* /*
* If the type is an array type, mark it auto-dependent on the base type. * If the type is an implicitly-created array type, mark it as internally
* (This is a compromise between the typical case where the array type is * dependent on the element type. Otherwise, if it has an element type,
* automatically generated and the case where it is manually created: we'd * the dependency is a normal one.
* prefer INTERNAL for the former case and NORMAL for the latter.)
*/ */
if (OidIsValid(elementType)) if (OidIsValid(elementType))
{ {
referenced.classId = TypeRelationId; referenced.classId = TypeRelationId;
referenced.objectId = elementType; referenced.objectId = elementType;
referenced.objectSubId = 0; 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. */ /* Normal dependency from a domain to its base type. */
...@@ -520,9 +547,6 @@ GenerateTypeDependencies(Oid typeNamespace, ...@@ -520,9 +547,6 @@ GenerateTypeDependencies(Oid typeNamespace,
/* Normal dependency on the default expression. */ /* Normal dependency on the default expression. */
if (defaultExpr) if (defaultExpr)
recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL); recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
/* Shared dependency on owner. */
recordDependencyOnOwner(TypeRelationId, typeObjectId, owner);
} }
/* /*
...@@ -570,21 +594,47 @@ TypeRename(const char *oldTypeName, Oid typeNamespace, ...@@ -570,21 +594,47 @@ TypeRename(const char *oldTypeName, Oid typeNamespace,
heap_close(pg_type_desc, RowExclusiveLock); heap_close(pg_type_desc, RowExclusiveLock);
} }
/* /*
* makeArrayTypeName(typeName); * makeArrayTypeName(typeName)
* - given a base type name, make an array of type name out of it * - given a base type name, make an array type name for it
* *
* the caller is responsible for pfreeing the result * the caller is responsible for pfreeing the result
*/ */
char * char *
makeArrayTypeName(const char *typeName) makeArrayTypeName(const char *typeName, Oid typeNamespace)
{ {
char *arr; 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); 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; return arr;
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -2827,6 +2827,7 @@ find_composite_type_dependencies(Oid typeOid, const char *origTblName)
ScanKeyData key[2]; ScanKeyData key[2];
SysScanDesc depScan; SysScanDesc depScan;
HeapTuple depTup; HeapTuple depTup;
Oid arrayOid;
/* /*
* We scan pg_depend to find those things that depend on the rowtype. (We * 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) ...@@ -2886,6 +2887,14 @@ find_composite_type_dependencies(Oid typeOid, const char *origTblName)
systable_endscan(depScan); systable_endscan(depScan);
relation_close(depRel, AccessShareLock); 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) ...@@ -5299,6 +5308,9 @@ ATPostAlterTypeParse(char *cmd, List **wqueue)
* be changed separately from the parent table. Also, we can skip permission * 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 * checks (this is necessary not just an optimization, else we'd fail to
* handle toast tables properly). * handle toast tables properly).
*
* recursing is also true if ALTER TYPE OWNER is calling us to fix up a
* free-standing composite type.
*/ */
void void
ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing) ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing)
...@@ -5370,6 +5382,7 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing) ...@@ -5370,6 +5382,7 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing)
} }
break; break;
case RELKIND_TOASTVALUE: case RELKIND_TOASTVALUE:
case RELKIND_COMPOSITE_TYPE:
if (recursing) if (recursing)
break; break;
/* FALL THRU */ /* FALL THRU */
...@@ -5448,14 +5461,22 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing) ...@@ -5448,14 +5461,22 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing)
heap_freetuple(newtuple); 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 * Also change the ownership of the table's rowtype, if it has one
*/ */
if (tuple_class->relkind != RELKIND_INDEX) 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 * If we are operating on a table, also change the ownership of any
...@@ -6462,7 +6483,7 @@ AlterTableNamespace(RangeVar *relation, const char *newschema) ...@@ -6462,7 +6483,7 @@ AlterTableNamespace(RangeVar *relation, const char *newschema)
AlterRelationNamespaceInternal(classRel, relid, oldNspOid, nspOid, true); AlterRelationNamespaceInternal(classRel, relid, oldNspOid, nspOid, true);
/* Fix the table's rowtype too */ /* 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 */ /* Fix other dependent stuff */
if (rel->rd_rel->relkind == RELKIND_RELATION) if (rel->rd_rel->relkind == RELKIND_RELATION)
...@@ -6625,7 +6646,7 @@ AlterSeqNamespaces(Relation classRel, Relation rel, ...@@ -6625,7 +6646,7 @@ AlterSeqNamespaces(Relation classRel, Relation rel,
* them to the new namespace, too. * them to the new namespace, too.
*/ */
AlterTypeNamespaceInternal(RelationGetForm(seqRel)->reltype, AlterTypeNamespaceInternal(RelationGetForm(seqRel)->reltype,
newNspOid, false); newNspOid, false, false);
/* Now we can close it. Keep the lock till end of transaction. */ /* Now we can close it. Keep the lock till end of transaction. */
relation_close(seqRel, NoLock); relation_close(seqRel, NoLock);
......
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -116,10 +116,6 @@ LookupTypeName(ParseState *pstate, const TypeName *typename)
/* deconstruct the name list */ /* deconstruct the name list */
DeconstructQualifiedName(typename->names, &schemaname, &typname); DeconstructQualifiedName(typename->names, &schemaname, &typname);
/* If an array reference, look up the array type instead */
if (typename->arrayBounds != NIL)
typname = makeArrayTypeName(typname);
if (schemaname) if (schemaname)
{ {
/* Look in specific schema only */ /* Look in specific schema only */
...@@ -136,6 +132,10 @@ LookupTypeName(ParseState *pstate, const TypeName *typename) ...@@ -136,6 +132,10 @@ LookupTypeName(ParseState *pstate, const TypeName *typename)
/* Unqualified type name, so search the search path */ /* Unqualified type name, so search the search path */
restype = TypenameGetTypid(typname); restype = TypenameGetTypid(typname);
} }
/* If an array reference, return the array type instead */
if (typename->arrayBounds != NIL)
restype = get_array_type(restype);
} }
return restype; return restype;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 * NOTES
* Eventually, the index information should go through here, too. * Eventually, the index information should go through here, too.
...@@ -2203,50 +2203,24 @@ get_element_type(Oid typid) ...@@ -2203,50 +2203,24 @@ get_element_type(Oid typid)
/* /*
* get_array_type * 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. * Returns InvalidOid if no array type can be found.
*
* NB: this only considers varlena arrays to be true arrays.
*/ */
Oid Oid
get_array_type(Oid typid) get_array_type(Oid typid)
{ {
HeapTuple tp; HeapTuple tp;
Oid result = InvalidOid;
tp = SearchSysCache(TYPEOID, tp = SearchSysCache(TYPEOID,
ObjectIdGetDatum(typid), ObjectIdGetDatum(typid),
0, 0, 0); 0, 0, 0);
if (HeapTupleIsValid(tp)) if (HeapTupleIsValid(tp))
{ {
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp); result = ((Form_pg_type) GETSTRUCT(tp))->typarray;
char *array_typename;
Oid namespaceId;
array_typename = makeArrayTypeName(NameStr(typtup->typname));
namespaceId = typtup->typnamespace;
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); ReleaseSysCache(tp);
return result;
}
} }
return InvalidOid; return result;
} }
/* /*
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* by PostgreSQL * by PostgreSQL
* *
* IDENTIFICATION * 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) ...@@ -963,9 +963,8 @@ selectDumpableType(TypeInfo *tinfo)
else if (!tinfo->isDefined) else if (!tinfo->isDefined)
tinfo->dobj.dump = false; tinfo->dobj.dump = false;
/* skip all array types that start w/ underscore */ /* skip auto-generated array types */
else if ((tinfo->dobj.name[0] == '_') && else if (tinfo->isArray)
OidIsValid(tinfo->typelem))
tinfo->dobj.dump = false; tinfo->dobj.dump = false;
else else
...@@ -1963,6 +1962,7 @@ getTypes(int *numTypes) ...@@ -1963,6 +1962,7 @@ getTypes(int *numTypes)
int i_typrelkind; int i_typrelkind;
int i_typtype; int i_typtype;
int i_typisdefined; int i_typisdefined;
int i_isarray;
/* /*
* we include even the built-in types because those may be used as array * we include even the built-in types because those may be used as array
...@@ -1970,13 +1970,20 @@ getTypes(int *numTypes) ...@@ -1970,13 +1970,20 @@ getTypes(int *numTypes)
* *
* we filter out the built-in types when we dump out the types * 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 */ /* Make sure we are in proper schema */
selectSourceSchema("pg_catalog"); selectSourceSchema("pg_catalog");
if (g_fout->remoteVersion >= 70300) if (g_fout->remoteVersion >= 80300)
{ {
appendPQExpBuffer(query, "SELECT tableoid, oid, typname, " appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
"typnamespace, " "typnamespace, "
...@@ -1985,7 +1992,23 @@ getTypes(int *numTypes) ...@@ -1985,7 +1992,23 @@ getTypes(int *numTypes)
"typoutput::oid as typoutput, typelem, typrelid, " "typoutput::oid as typoutput, typelem, typrelid, "
"CASE WHEN typrelid = 0 THEN ' '::\"char\" " "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
"ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END as typrelkind, " "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", "FROM pg_type",
username_subquery); username_subquery);
} }
...@@ -1998,7 +2021,8 @@ getTypes(int *numTypes) ...@@ -1998,7 +2021,8 @@ getTypes(int *numTypes)
"typoutput::oid as typoutput, typelem, typrelid, " "typoutput::oid as typoutput, typelem, typrelid, "
"CASE WHEN typrelid = 0 THEN ' '::\"char\" " "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
"ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END as typrelkind, " "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", "FROM pg_type",
username_subquery); username_subquery);
} }
...@@ -2013,7 +2037,8 @@ getTypes(int *numTypes) ...@@ -2013,7 +2037,8 @@ getTypes(int *numTypes)
"typoutput::oid as typoutput, typelem, typrelid, " "typoutput::oid as typoutput, typelem, typrelid, "
"CASE WHEN typrelid = 0 THEN ' '::\"char\" " "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
"ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END as typrelkind, " "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", "FROM pg_type",
username_subquery); username_subquery);
} }
...@@ -2037,6 +2062,7 @@ getTypes(int *numTypes) ...@@ -2037,6 +2062,7 @@ getTypes(int *numTypes)
i_typrelkind = PQfnumber(res, "typrelkind"); i_typrelkind = PQfnumber(res, "typrelkind");
i_typtype = PQfnumber(res, "typtype"); i_typtype = PQfnumber(res, "typtype");
i_typisdefined = PQfnumber(res, "typisdefined"); i_typisdefined = PQfnumber(res, "typisdefined");
i_isarray = PQfnumber(res, "isarray");
for (i = 0; i < ntups; i++) for (i = 0; i < ntups; i++)
{ {
...@@ -2064,20 +2090,16 @@ getTypes(int *numTypes) ...@@ -2064,20 +2090,16 @@ getTypes(int *numTypes)
tinfo[i].typrelkind != RELKIND_COMPOSITE_TYPE) tinfo[i].typrelkind != RELKIND_COMPOSITE_TYPE)
tinfo[i].dobj.objType = DO_TABLE_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) if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
tinfo[i].isDefined = true; tinfo[i].isDefined = true;
else else
tinfo[i].isDefined = false; 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 */ /* Decide whether we want to dump it */
selectDumpableType(&tinfo[i]); selectDumpableType(&tinfo[i]);
...@@ -3894,7 +3916,7 @@ getTriggers(TableInfo tblinfo[], int numTables) ...@@ -3894,7 +3916,7 @@ getTriggers(TableInfo tblinfo[], int numTables)
else if (g_fout->remoteVersion >= 70100) else if (g_fout->remoteVersion >= 70100)
{ {
appendPQExpBuffer(query, appendPQExpBuffer(query,
"SELECT tgname, tgfoid::pg_catalog.regproc as tgfname, " "SELECT tgname, tgfoid::regproc as tgfname, "
"tgtype, tgnargs, tgargs, tgenabled, " "tgtype, tgnargs, tgargs, tgenabled, "
"tgisconstraint, tgconstrname, tgdeferrable, " "tgisconstraint, tgconstrname, tgdeferrable, "
"tgconstrrelid, tginitdeferred, tableoid, oid, " "tgconstrrelid, tginitdeferred, tableoid, oid, "
...@@ -3907,7 +3929,7 @@ getTriggers(TableInfo tblinfo[], int numTables) ...@@ -3907,7 +3929,7 @@ getTriggers(TableInfo tblinfo[], int numTables)
else else
{ {
appendPQExpBuffer(query, appendPQExpBuffer(query,
"SELECT tgname, tgfoid::pg_catalog.regproc as tgfname, " "SELECT tgname, tgfoid::regproc as tgfname, "
"tgtype, tgnargs, tgargs, tgenabled, " "tgtype, tgnargs, tgargs, tgenabled, "
"tgisconstraint, tgconstrname, tgdeferrable, " "tgisconstraint, tgconstrname, tgdeferrable, "
"tgconstrrelid, tginitdeferred, " "tgconstrrelid, tginitdeferred, "
...@@ -5473,7 +5495,7 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) ...@@ -5473,7 +5495,7 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo)
appendPQExpBufferStr(q, typdefault); appendPQExpBufferStr(q, typdefault);
} }
if (tinfo->isArray) if (OidIsValid(tinfo->typelem))
{ {
char *elemType; char *elemType;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 ...@@ -164,7 +164,7 @@ typedef struct _typeInfo
Oid typrelid; Oid typrelid;
char typrelkind; /* 'r', 'v', 'c', etc */ char typrelkind; /* 'r', 'v', 'c', etc */
char typtype; /* 'b', '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 */ bool isDefined; /* true if typisdefined */
/* If it's a dumpable base type, we create a "shell type" entry for it */ /* If it's a dumpable base type, we create a "shell type" entry for it */
struct _shellTypeInfo *shellType; /* shell-type entry, or NULL */ struct _shellTypeInfo *shellType; /* shell-type entry, or NULL */
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200705081 #define CATALOG_VERSION_NO 200705111
#endif #endif
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
...@@ -232,21 +232,22 @@ typedef FormData_pg_attribute *Form_pg_attribute; ...@@ -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, {"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, {"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, {"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, {"typarray"}, 26, -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, {"typinput"}, 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, {"typoutput"}, 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, {"typreceive"}, 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, {"typsend"}, 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, {"typmodin"}, 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, {"typmodout"}, 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, {"typanalyze"}, 24, -1, 4, 18, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typstorage"}, 18, -1, 1, 19, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ { 1247, {"typalign"}, 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, {"typstorage"}, 18, -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, {"typnotnull"}, 16, -1, 1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typtypmod"}, 23, -1, 4, 22, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ { 1247, {"typbasetype"}, 26, -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, {"typtypmod"}, 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, {"typndims"}, 23, -1, 4, 24, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typdefault"}, 25, -1, -1, 25, 0, -1, -1, false, 'x', 'i', false, 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 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)); 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)); ...@@ -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 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 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 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 typarray 26 -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 typinput 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 typoutput 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 typreceive 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 typsend 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 typmodin 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 typmodout 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 typanalyze 24 -1 4 18 0 -1 -1 t p i 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 typalign 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 typstorage 18 -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 typnotnull 16 -1 1 21 0 -1 -1 t p c 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 typbasetype 26 -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 typtypmod 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 typndims 23 -1 4 24 0 -1 -1 t p i t 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 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 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 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)); DATA(insert ( 1247 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0));
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
...@@ -132,7 +132,7 @@ typedef FormData_pg_class *Form_pg_class; ...@@ -132,7 +132,7 @@ typedef FormData_pg_class *Form_pg_class;
*/ */
/* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */ /* 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(""); 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_ )); 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(""); DESCR("");
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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, ...@@ -36,9 +36,11 @@ extern void AlterDomainDropConstraint(List *names, const char *constrName,
extern List *GetDomainConstraints(Oid typeOid); extern List *GetDomainConstraints(Oid typeOid);
extern void AlterTypeOwner(List *names, Oid newOwnerId); 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 AlterTypeNamespace(List *names, const char *newschema);
extern void AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, extern void AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
bool isImplicitArray,
bool errorOnTableType); bool errorOnTableType);
#endif /* TYPECMDS_H */ #endif /* TYPECMDS_H */
...@@ -1456,7 +1456,6 @@ select alter2.plus1(41); ...@@ -1456,7 +1456,6 @@ select alter2.plus1(41);
-- clean up -- clean up
drop schema alter2 cascade; 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.ctype
NOTICE: drop cascades to type alter2.posint NOTICE: drop cascades to type alter2.posint
NOTICE: drop cascades to function alter2.plus1(integer) NOTICE: drop cascades to function alter2.plus1(integer)
......
...@@ -409,6 +409,14 @@ WHERE indrelid != 0 AND ...@@ -409,6 +409,14 @@ WHERE indrelid != 0 AND
------+---------- ------+----------
(0 rows) (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 SELECT ctid, lanvalidator
FROM pg_catalog.pg_language fk FROM pg_catalog.pg_language fk
WHERE lanvalidator != 0 AND WHERE lanvalidator != 0 AND
...@@ -721,6 +729,14 @@ WHERE typelem != 0 AND ...@@ -721,6 +729,14 @@ WHERE typelem != 0 AND
------+--------- ------+---------
(0 rows) (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 SELECT ctid, typinput
FROM pg_catalog.pg_type fk FROM pg_catalog.pg_type fk
WHERE typinput != 0 AND WHERE typinput != 0 AND
......
...@@ -69,6 +69,16 @@ WHERE p1.typtype in ('b','e') AND p1.typname NOT LIKE E'\\_%' AND NOT EXISTS ...@@ -69,6 +69,16 @@ WHERE p1.typtype in ('b','e') AND p1.typname NOT LIKE E'\\_%' AND NOT EXISTS
705 | unknown 705 | unknown
(2 rows) (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. -- Text conversion routines must be provided.
SELECT p1.oid, p1.typname SELECT p1.oid, p1.typname
FROM pg_type as p1 FROM pg_type as p1
......
...@@ -205,6 +205,10 @@ SELECT ctid, indrelid ...@@ -205,6 +205,10 @@ SELECT ctid, indrelid
FROM pg_catalog.pg_index fk FROM pg_catalog.pg_index fk
WHERE indrelid != 0 AND WHERE indrelid != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.indrelid); 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 SELECT ctid, lanvalidator
FROM pg_catalog.pg_language fk FROM pg_catalog.pg_language fk
WHERE lanvalidator != 0 AND WHERE lanvalidator != 0 AND
...@@ -361,6 +365,10 @@ SELECT ctid, typelem ...@@ -361,6 +365,10 @@ SELECT ctid, typelem
FROM pg_catalog.pg_type fk FROM pg_catalog.pg_type fk
WHERE typelem != 0 AND WHERE typelem != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typelem); 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 SELECT ctid, typinput
FROM pg_catalog.pg_type fk FROM pg_catalog.pg_type fk
WHERE typinput != 0 AND WHERE typinput != 0 AND
......
...@@ -59,6 +59,13 @@ WHERE p1.typtype in ('b','e') AND p1.typname NOT LIKE E'\\_%' AND NOT EXISTS ...@@ -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 WHERE p2.typname = ('_' || p1.typname)::name AND
p2.typelem = p1.oid); 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. -- Text conversion routines must be provided.
SELECT p1.oid, p1.typname SELECT p1.oid, p1.typname
......
$PostgreSQL: pgsql/src/tools/findoidjoins/README,v 1.4 2007/05/11 17:57:14 tgl Exp $
findoidjoins findoidjoins
...@@ -87,6 +88,7 @@ Join pg_catalog.pg_depend.refclassid => pg_catalog.pg_class.oid ...@@ -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_description.classoid => pg_catalog.pg_class.oid
Join pg_catalog.pg_index.indexrelid => 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_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_language.lanvalidator => pg_catalog.pg_proc.oid
Join pg_catalog.pg_namespace.nspowner => pg_catalog.pg_authid.oid Join pg_catalog.pg_namespace.nspowner => pg_catalog.pg_authid.oid
Join pg_catalog.pg_opclass.opcmethod => pg_catalog.pg_am.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 ...@@ -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.typowner => pg_catalog.pg_authid.oid
Join pg_catalog.pg_type.typrelid => pg_catalog.pg_class.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.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.typinput => pg_catalog.pg_proc.oid
Join pg_catalog.pg_type.typoutput => 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 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