diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml index d4860cff80d3a5f3139af0db040f796426fc9eb3..9da93a42d289ac0e52a05e4c945566d65126f953 100644 --- a/doc/src/sgml/ref/create_type.sgml +++ b/doc/src/sgml/ref/create_type.sgml @@ -1,5 +1,5 @@ <!-- -$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_type.sgml,v 1.30 2002/07/24 19:11:07 petere Exp $ +$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_type.sgml,v 1.31 2002/08/15 16:36:00 momjian Exp $ PostgreSQL documentation --> @@ -30,6 +30,13 @@ CREATE TYPE <replaceable class="parameter">typename</replaceable> ( INPUT = <rep [ , ALIGNMENT = <replaceable class="parameter">alignment</replaceable> ] [ , STORAGE = <replaceable class="parameter">storage</replaceable> ] ) + +CREATE TYPE <replaceable class="parameter">typename</replaceable> AS + ( <replaceable class="PARAMETER">column_definition_list</replaceable> ) + +where <replaceable class="PARAMETER">column_definition_list</replaceable> can be: + +( <replaceable class="PARAMETER">column_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [, ... ] ) </synopsis> <refsect2 id="R2-SQL-CREATETYPE-1"> @@ -138,6 +145,25 @@ CREATE TYPE <replaceable class="parameter">typename</replaceable> ( INPUT = <rep </para> </listitem> </varlistentry> + + <varlistentry> + <term><replaceable class="PARAMETER">column_name</replaceable></term> + <listitem> + <para> + The name of a column of the composite type. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><replaceable class="PARAMETER">data_type</replaceable></term> + <listitem> + <para> + The name of an existing data type. + </para> + </listitem> + </varlistentry> + </variablelist> </para> </refsect2> @@ -191,9 +217,9 @@ CREATE TYPE </para> <para> - <command>CREATE TYPE</command> requires the registration of two functions - (using CREATE FUNCTION) before defining the type. The - representation of a new base type is determined by + The first form of <command>CREATE TYPE</command> requires the + registration of two functions (using CREATE FUNCTION) before defining the + type. The representation of a new base type is determined by <replaceable class="parameter">input_function</replaceable>, which converts the type's external representation to an internal representation usable by the @@ -288,6 +314,14 @@ CREATE TYPE <literal>extended</literal> and <literal>external</literal> items.) </para> + <para> + The second form of <command>CREATE TYPE</command> requires a column + definition list in the form ( <replaceable class="PARAMETER">column_name</replaceable> + <replaceable class="PARAMETER">data_type</replaceable> [, ... ] ). This + creates a composite type, similar to that of a TABLE or VIEW relation. + A stand-alone composite type is useful as the return type of FUNCTION. + </para> + <refsect2> <title>Array Types</title> @@ -370,6 +404,15 @@ CREATE TYPE box (INTERNALLENGTH = 16, CREATE TYPE bigobj (INPUT = lo_filein, OUTPUT = lo_fileout, INTERNALLENGTH = VARIABLE); CREATE TABLE big_objs (id int4, obj bigobj); +</programlisting> + </para> + + <para> + This example creates a composite type and uses it in + a table function definition: +<programlisting> +CREATE TYPE compfoo AS (f1 int, f2 int); +CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS 'SELECT fooid, foorefid FROM foo' LANGUAGE SQL; </programlisting> </para> </refsect1> diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 747dcb9ae5395df706dea234dcfc8a4eefa00f4e..0c21400ca1db0face1a80d63f3c7ed6b030c2835 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.220 2002/08/11 21:17:34 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.221 2002/08/15 16:36:00 momjian Exp $ * * * INTERFACE ROUTINES @@ -357,9 +357,10 @@ CheckAttributeNames(TupleDesc tupdesc, bool relhasoids, char relkind) /* * first check for collision with system attribute names * - * Skip this for a view, since it doesn't have system attributes. + * Skip this for a view and type relation, since it doesn't have system + * attributes. */ - if (relkind != RELKIND_VIEW) + if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE) { for (i = 0; i < natts; i++) { @@ -473,10 +474,10 @@ AddNewAttributeTuples(Oid new_rel_oid, /* * Next we add the system attributes. Skip OID if rel has no OIDs. - * Skip all for a view. We don't bother with making datatype - * dependencies here, since presumably all these types are pinned. + * Skip all for a view or type relation. We don't bother with making + * datatype dependencies here, since presumably all these types are pinned. */ - if (relkind != RELKIND_VIEW) + if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE) { dpp = SysAtt; for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++) @@ -689,13 +690,14 @@ heap_create_with_catalog(const char *relname, * physical disk file. (If we fail further down, it's the smgr's * responsibility to remove the disk file again.) * - * NB: create a physical file only if it's not a view. + * NB: create a physical file only if it's not a view or type relation. */ new_rel_desc = heap_create(relname, relnamespace, tupdesc, shared_relation, - (relkind != RELKIND_VIEW), + (relkind != RELKIND_VIEW && + relkind != RELKIND_COMPOSITE_TYPE), allow_system_table_mods); /* Fetch the relation OID assigned by heap_create */ @@ -1131,7 +1133,8 @@ heap_drop_with_catalog(Oid rid) /* * unlink the relation's physical file and finish up. */ - if (rel->rd_rel->relkind != RELKIND_VIEW) + if (rel->rd_rel->relkind != RELKIND_VIEW && + rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE) smgrunlink(DEFAULT_SMGR, rel); /* diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index 1aab73279faff3c539491e31609a2159869a6727..8f6caa5d4d9e688136f7658e8e74ee4420165095 100644 --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@ -13,7 +13,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.30 2002/08/09 16:45:14 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.31 2002/08/15 16:36:01 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1585,6 +1585,7 @@ RemoveTempRelations(Oid tempNamespaceId) case RELKIND_RELATION: case RELKIND_SEQUENCE: case RELKIND_VIEW: + case RELKIND_COMPOSITE_TYPE: AssertTupleDescHasOid(pgclass->rd_att); object.classId = RelOid_pg_class; object.objectId = HeapTupleGetOid(tuple); diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index d1e90c6173220e32fe418e09f2c2334d0b59cbee..8482c43ca278629b3d6275873550cafe390ecac0 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.77 2002/08/05 03:29:16 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.78 2002/08/15 16:36:01 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -311,15 +311,28 @@ TypeCreate(const char *typeName, /* * If the type is a rowtype for a relation, mark it as internally - * dependent on the relation. This allows it to be auto-dropped - * when the relation is, and not otherwise. + * dependent on the relation, *unless* it is a stand-alone composite + * type relation. For the latter case, we have to reverse the + * dependency. + * + * In the former case, this allows the type to be auto-dropped + * when the relation is, and not otherwise. And in the latter, + * of course we get the opposite effect. */ if (OidIsValid(relationOid)) { + Relation rel = relation_open(relationOid, AccessShareLock); + char relkind = rel->rd_rel->relkind; + relation_close(rel, AccessShareLock); + referenced.classId = RelOid_pg_class; referenced.objectId = relationOid; referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); + + if (relkind != RELKIND_COMPOSITE_TYPE) + recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); + else + recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL); } /* diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 2529b7282309ad4cab417ea7112379e2a23b8a36..890ef6f6768d8db0da53cdc431c46d62f2ad2073 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.162 2002/08/02 18:15:06 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.163 2002/08/15 16:36:02 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -398,6 +398,9 @@ DoCopy(const CopyStmt *stmt) if (rel->rd_rel->relkind == RELKIND_VIEW) elog(ERROR, "You cannot copy view %s", RelationGetRelationName(rel)); + else if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE) + elog(ERROR, "You cannot copy type relation %s", + RelationGetRelationName(rel)); else if (rel->rd_rel->relkind == RELKIND_SEQUENCE) elog(ERROR, "You cannot change sequence relation %s", RelationGetRelationName(rel)); @@ -443,6 +446,9 @@ DoCopy(const CopyStmt *stmt) if (rel->rd_rel->relkind == RELKIND_VIEW) elog(ERROR, "You cannot copy view %s", RelationGetRelationName(rel)); + else if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE) + elog(ERROR, "You cannot copy type relation %s", + RelationGetRelationName(rel)); else if (rel->rd_rel->relkind == RELKIND_SEQUENCE) elog(ERROR, "You cannot copy sequence %s", RelationGetRelationName(rel)); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index d40122cdf5450f56b8de7dc8def5b23483b40f3f..72ecd6d0ce4e1c83c3d9fbd56fd411ab67a47bc7 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.28 2002/08/07 21:45:01 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.29 2002/08/15 16:36:02 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -345,6 +345,10 @@ TruncateRelation(const RangeVar *relation) elog(ERROR, "TRUNCATE cannot be used on views. '%s' is a view", RelationGetRelationName(rel)); + if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE) + elog(ERROR, "TRUNCATE cannot be used on type relations. '%s' is a type", + RelationGetRelationName(rel)); + if (!allowSystemTableMods && IsSystemRelation(rel)) elog(ERROR, "TRUNCATE cannot be used on system tables. '%s' is a system table", RelationGetRelationName(rel)); @@ -3210,12 +3214,13 @@ CheckTupleType(Form_pg_class tuple_class) case RELKIND_RELATION: case RELKIND_INDEX: case RELKIND_VIEW: + case RELKIND_COMPOSITE_TYPE: case RELKIND_SEQUENCE: case RELKIND_TOASTVALUE: /* ok to change owner */ break; default: - elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table, TOAST table, index, view, or sequence", + elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table, TOAST table, index, view, type, or sequence", NameStr(tuple_class->relname)); } } diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index a27babb32e33e55912b6f121631c85d6fd347a37..f9f27d5867625d031edaebdf9fa7a7c9bfba0d2e 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.8 2002/07/24 19:11:09 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.9 2002/08/15 16:36:02 momjian Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -38,6 +38,7 @@ #include "catalog/namespace.h" #include "catalog/pg_type.h" #include "commands/defrem.h" +#include "commands/tablecmds.h" #include "miscadmin.h" #include "parser/parse_func.h" #include "parser/parse_type.h" @@ -50,7 +51,6 @@ static Oid findTypeIOFunction(List *procname, bool isOutput); - /* * DefineType * Registers a new type. @@ -666,3 +666,42 @@ findTypeIOFunction(List *procname, bool isOutput) return procOid; } + +/*------------------------------------------------------------------- + * DefineCompositeType + * + * Create a Composite Type relation. + * `DefineRelation' does all the work, we just provide the correct + * arguments! + * + * If the relation already exists, then 'DefineRelation' will abort + * the xact... + * + * DefineCompositeType returns relid for use when creating + * an implicit composite type during function creation + *------------------------------------------------------------------- + */ +Oid +DefineCompositeType(const RangeVar *typevar, List *coldeflist) +{ + CreateStmt *createStmt = makeNode(CreateStmt); + + if (coldeflist == NIL) + elog(ERROR, "attempted to define composite type relation with" + " no attrs"); + + /* + * now create the parameters for keys/inheritance etc. All of them are + * nil... + */ + createStmt->relation = (RangeVar *) typevar; + createStmt->tableElts = coldeflist; + createStmt->inhRelations = NIL; + createStmt->constraints = NIL; + createStmt->hasoids = false; + + /* + * finally create the relation... + */ + return DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE); +} diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 7e50ca4f9e628bcdd9fc4f94c39a8388ef3c768c..0b9bb86578a14d8d3d0b65ccd37b6bfe48635b4d 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -27,7 +27,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.173 2002/08/07 21:45:02 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.174 2002/08/15 16:36:02 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -786,6 +786,10 @@ initResultRelInfo(ResultRelInfo *resultRelInfo, elog(ERROR, "You can't change view relation %s", RelationGetRelationName(resultRelationDesc)); break; + case RELKIND_COMPOSITE_TYPE: + elog(ERROR, "You can't change type relation %s", + RelationGetRelationName(resultRelationDesc)); + break; } MemSet(resultRelInfo, 0, sizeof(ResultRelInfo)); diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 954a372181a927691d0eb18676138915f9f0d8f9..6caceb7311ca9e46b91a828d773784ecf12c6563 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.200 2002/08/04 19:48:09 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.201 2002/08/15 16:36:02 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -2233,6 +2233,17 @@ _copyTransactionStmt(TransactionStmt *from) return newnode; } +static CompositeTypeStmt * +_copyCompositeTypeStmt(CompositeTypeStmt *from) +{ + CompositeTypeStmt *newnode = makeNode(CompositeTypeStmt); + + Node_Copy(from, newnode, typevar); + Node_Copy(from, newnode, coldeflist); + + return newnode; +} + static ViewStmt * _copyViewStmt(ViewStmt *from) { @@ -2939,6 +2950,9 @@ copyObject(void *from) case T_TransactionStmt: retval = _copyTransactionStmt(from); break; + case T_CompositeTypeStmt: + retval = _copyCompositeTypeStmt(from); + break; case T_ViewStmt: retval = _copyViewStmt(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index e87e9f4f94acd39ad9f3e34369fc13e42ca6e8e5..7eda9e377f0b4d746dd0474beae71a9db9623b60 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -20,7 +20,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.149 2002/08/04 23:49:59 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.150 2002/08/15 16:36:03 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1061,6 +1061,17 @@ _equalTransactionStmt(TransactionStmt *a, TransactionStmt *b) return true; } +static bool +_equalCompositeTypeStmt(CompositeTypeStmt *a, CompositeTypeStmt *b) +{ + if (!equal(a->typevar, b->typevar)) + return false; + if (!equal(a->coldeflist, b->coldeflist)) + return false; + + return true; +} + static bool _equalViewStmt(ViewStmt *a, ViewStmt *b) { @@ -2111,6 +2122,9 @@ equal(void *a, void *b) case T_TransactionStmt: retval = _equalTransactionStmt(a, b); break; + case T_CompositeTypeStmt: + retval = _equalCompositeTypeStmt(a, b); + break; case T_ViewStmt: retval = _equalViewStmt(a, b); break; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 98acc050d56ab71d02bad375db2687fa0382087c..a56f7d41b99b30a3df9740d8340f30ce3108f46f 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.358 2002/08/10 19:01:53 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.359 2002/08/15 16:36:03 momjian Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -205,7 +205,7 @@ static void doNegateFloat(Value *v); %type <list> stmtblock, stmtmulti, OptTableElementList, TableElementList, OptInherit, definition, - opt_distinct, opt_definition, func_args, + opt_distinct, opt_definition, func_args, rowdefinition func_args_list, func_as, createfunc_opt_list oper_argtypes, RuleActionList, RuleActionMulti, opt_column_list, columnList, opt_name_list, @@ -2233,6 +2233,39 @@ DefineStmt: n->definition = $4; $$ = (Node *)n; } + | CREATE TYPE_P any_name AS rowdefinition + { + CompositeTypeStmt *n = makeNode(CompositeTypeStmt); + RangeVar *r = makeNode(RangeVar); + + switch (length($3)) + { + case 1: + r->catalogname = NULL; + r->schemaname = NULL; + r->relname = strVal(lfirst($3)); + break; + case 2: + r->catalogname = NULL; + r->schemaname = strVal(lfirst($3)); + r->relname = strVal(lsecond($3)); + break; + case 3: + r->catalogname = strVal(lfirst($3)); + r->schemaname = strVal(lsecond($3)); + r->relname = strVal(lfirst(lnext(lnext($3)))); + break; + default: + elog(ERROR, + "Improper qualified name " + "(too many dotted names): %s", + NameListToString($3)); + break; + } + n->typevar = r; + n->coldeflist = $5; + $$ = (Node *)n; + } | CREATE CHARACTER SET opt_as any_name GET definition opt_collate { DefineStmt *n = makeNode(DefineStmt); @@ -2243,6 +2276,9 @@ DefineStmt: } ; +rowdefinition: '(' TableFuncElementList ')' { $$ = $2; } + ; + definition: '(' def_list ')' { $$ = $2; } ; diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 11df91c25cf31fba8c57bf5451187cdd1efe7f59..550bd6e70d5b548de45f108c7d694ebc7f33f4c1 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.129 2002/08/11 21:17:34 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.130 2002/08/15 16:36:04 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1051,6 +1051,8 @@ RelationGetNumberOfBlocks(Relation relation) */ if (relation->rd_rel->relkind == RELKIND_VIEW) relation->rd_nblocks = 0; + else if (relation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE) + relation->rd_nblocks = 0; else if (!relation->rd_isnew && !relation->rd_istemp) relation->rd_nblocks = smgrnblocks(DEFAULT_SMGR, relation); return relation->rd_nblocks; @@ -1069,6 +1071,8 @@ RelationUpdateNumberOfBlocks(Relation relation) { if (relation->rd_rel->relkind == RELKIND_VIEW) relation->rd_nblocks = 0; + else if (relation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE) + relation->rd_nblocks = 0; else relation->rd_nblocks = smgrnblocks(DEFAULT_SMGR, relation); } diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c index 252781d9c3fbbccf436e953980635a3b2fcd4cfb..dab9b5dcbb2fe777b0a1933ff950c9ecef42fb2e 100644 --- a/src/backend/storage/smgr/smgr.c +++ b/src/backend/storage/smgr/smgr.c @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgr.c,v 1.58 2002/08/06 02:36:34 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgr.c,v 1.59 2002/08/15 16:36:04 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -263,6 +263,8 @@ smgropen(int16 which, Relation reln, bool failOK) if (reln->rd_rel->relkind == RELKIND_VIEW) return -1; + if (reln->rd_rel->relkind == RELKIND_COMPOSITE_TYPE) + return -1; if ((fd = (*(smgrsw[which].smgr_open)) (reln)) < 0) if (!failOK) elog(ERROR, "cannot open %s: %m", RelationGetRelationName(reln)); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6c5e17b48f61f2a8dc3d3c16fccadf6a173e3168..5c0a07bfaa9fff315d9883803bca6846c9f14b27 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.281 2002/08/10 20:29:18 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.282 2002/08/15 16:36:05 momjian Exp $ * * NOTES * this is the "main" module of the postgres backend and @@ -1674,7 +1674,7 @@ PostgresMain(int argc, char *argv[], const char *username) if (!IsUnderPostmaster) { puts("\nPOSTGRES backend interactive interface "); - puts("$Revision: 1.281 $ $Date: 2002/08/10 20:29:18 $\n"); + puts("$Revision: 1.282 $ $Date: 2002/08/15 16:36:05 $\n"); } /* @@ -2233,6 +2233,10 @@ CreateCommandTag(Node *parsetree) } break; + case T_CompositeTypeStmt: + tag = "CREATE TYPE"; + break; + case T_ViewStmt: tag = "CREATE VIEW"; break; diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 2ef3ff8a3f41485b798ab31f94909bd74d0ab77e..e75b52b6702943dcbbd4b85a75747cc3fd3e09db 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.169 2002/08/07 21:45:02 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.170 2002/08/15 16:36:05 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -70,6 +70,7 @@ static struct kindstrings kindstringarray[] = { {RELKIND_SEQUENCE, "a", "sequence", "SEQUENCE"}, {RELKIND_VIEW, "a", "view", "VIEW"}, {RELKIND_INDEX, "an", "index", "INDEX"}, + {RELKIND_COMPOSITE_TYPE, "a", "type", "TYPE"}, {'\0', "a", "???", "???"} }; @@ -573,6 +574,19 @@ ProcessUtility(Node *parsetree, } break; + case T_CompositeTypeStmt: /* CREATE TYPE (composite) */ + { + Oid relid; + CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree; + + /* + * DefineCompositeType returns relid for use when creating + * an implicit composite type during function creation + */ + relid = DefineCompositeType(stmt->typevar, stmt->coldeflist); + } + break; + case T_ViewStmt: /* CREATE VIEW */ { ViewStmt *stmt = (ViewStmt *) parsetree; diff --git a/src/backend/utils/adt/tid.c b/src/backend/utils/adt/tid.c index e81248a6db08078e399128c8dfad57abda304ecc..5a784a4476869c9a2f718fe596e9b7ec3f464122 100644 --- a/src/backend/utils/adt/tid.c +++ b/src/backend/utils/adt/tid.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/tid.c,v 1.32 2002/07/16 17:55:25 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/tid.c,v 1.33 2002/08/15 16:36:05 momjian Exp $ * * NOTES * input routine largely stolen from boxin(). @@ -226,6 +226,9 @@ currtid_byreloid(PG_FUNCTION_ARGS) if (rel->rd_rel->relkind == RELKIND_VIEW) return currtid_for_view(rel, tid); + if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE) + elog(ERROR, "currtid can't handle type relations"); + ItemPointerCopy(tid, result); heap_get_latest_tid(rel, SnapshotNow, result); @@ -249,6 +252,9 @@ currtid_byrelname(PG_FUNCTION_ARGS) if (rel->rd_rel->relkind == RELKIND_VIEW) return currtid_for_view(rel, tid); + if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE) + elog(ERROR, "currtid can't handle type relations"); + result = (ItemPointer) palloc(sizeof(ItemPointerData)); ItemPointerCopy(tid, result); diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c index 0e3ffe91e5ce03ac5cd011dffd01b83aa6e234c9..4f33ff4e4fd46f85f3d7ad46b355b1af007cc7de 100644 --- a/src/bin/pg_dump/common.c +++ b/src/bin/pg_dump/common.c @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.67 2002/07/30 21:56:04 tgl Exp $ + * $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.68 2002/08/15 16:36:06 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -215,9 +215,10 @@ flagInhTables(TableInfo *tblinfo, int numTables, for (i = 0; i < numTables; i++) { - /* Sequences and views never have parents */ + /* Sequences, views, and types never have parents */ if (tblinfo[i].relkind == RELKIND_SEQUENCE || - tblinfo[i].relkind == RELKIND_VIEW) + tblinfo[i].relkind == RELKIND_VIEW || + tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE) continue; /* Don't bother computing anything for non-target tables, either */ @@ -269,9 +270,10 @@ flagInhAttrs(TableInfo *tblinfo, int numTables, for (i = 0; i < numTables; i++) { - /* Sequences and views never have parents */ + /* Sequences, views, and types never have parents */ if (tblinfo[i].relkind == RELKIND_SEQUENCE || - tblinfo[i].relkind == RELKIND_VIEW) + tblinfo[i].relkind == RELKIND_VIEW || + tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE) continue; /* Don't bother computing anything for non-target tables, either */ diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 0397320a73574dc4063be0ba026082badc8d6354..22dfa23a965e73e1f4df3da5591afaddcae54758 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -22,7 +22,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.281 2002/08/10 16:57:31 petere Exp $ + * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.282 2002/08/15 16:36:06 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -95,6 +95,7 @@ static void dumpOneBaseType(Archive *fout, TypeInfo *tinfo, FuncInfo *g_finfo, int numFuncs, TypeInfo *g_tinfo, int numTypes); static void dumpOneDomain(Archive *fout, TypeInfo *tinfo); +static void dumpOneCompositeType(Archive *fout, TypeInfo *tinfo); static void dumpOneTable(Archive *fout, TableInfo *tbinfo, TableInfo *g_tblinfo); static void dumpOneSequence(Archive *fout, TableInfo *tbinfo, @@ -1171,6 +1172,10 @@ dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout, if (tblinfo[i].relkind == RELKIND_VIEW) continue; + /* Skip TYPE relations */ + if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE) + continue; + if (tblinfo[i].relkind == RELKIND_SEQUENCE) /* already dumped */ continue; @@ -1575,6 +1580,7 @@ getTypes(int *numTypes) int i_usename; int i_typelem; int i_typrelid; + int i_typrelkind; int i_typtype; int i_typisdefined; @@ -1595,7 +1601,9 @@ getTypes(int *numTypes) appendPQExpBuffer(query, "SELECT pg_type.oid, typname, " "typnamespace, " "(select usename from pg_user where typowner = usesysid) as usename, " - "typelem, typrelid, typtype, typisdefined " + "typelem, typrelid, " + "(select relkind from pg_class where oid = typrelid) as typrelkind, " + "typtype, typisdefined " "FROM pg_type"); } else @@ -1603,7 +1611,9 @@ getTypes(int *numTypes) appendPQExpBuffer(query, "SELECT pg_type.oid, typname, " "0::oid as typnamespace, " "(select usename from pg_user where typowner = usesysid) as usename, " - "typelem, typrelid, typtype, typisdefined " + "typelem, typrelid, " + "''::char as typrelkind, " + "typtype, typisdefined " "FROM pg_type"); } @@ -1625,6 +1635,7 @@ getTypes(int *numTypes) i_usename = PQfnumber(res, "usename"); i_typelem = PQfnumber(res, "typelem"); i_typrelid = PQfnumber(res, "typrelid"); + i_typrelkind = PQfnumber(res, "typrelkind"); i_typtype = PQfnumber(res, "typtype"); i_typisdefined = PQfnumber(res, "typisdefined"); @@ -1637,6 +1648,7 @@ getTypes(int *numTypes) tinfo[i].usename = strdup(PQgetvalue(res, i, i_usename)); tinfo[i].typelem = strdup(PQgetvalue(res, i, i_typelem)); tinfo[i].typrelid = strdup(PQgetvalue(res, i, i_typrelid)); + tinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind); tinfo[i].typtype = *PQgetvalue(res, i, i_typtype); /* @@ -2102,7 +2114,6 @@ getTables(int *numTables) appendPQExpBuffer(query, "SELECT pg_class.oid, relname, relacl, relkind, " "relnamespace, " - "(select usename from pg_user where relowner = usesysid) as usename, " "relchecks, reltriggers, " "relhasindex, relhasrules, relhasoids " @@ -2113,6 +2124,7 @@ getTables(int *numTables) } else if (g_fout->remoteVersion >= 70200) { + /* before 7.3 there were no type relations with relkind 'c' */ appendPQExpBuffer(query, "SELECT pg_class.oid, relname, relacl, relkind, " "0::oid as relnamespace, " @@ -2356,6 +2368,10 @@ getTableAttrs(TableInfo *tblinfo, int numTables) if (tblinfo[i].relkind == RELKIND_SEQUENCE) continue; + /* Don't bother to collect info for type relations */ + if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE) + continue; + /* Don't bother with uninteresting tables, either */ if (!tblinfo[i].interesting) continue; @@ -3172,6 +3188,105 @@ dumpOneDomain(Archive *fout, TypeInfo *tinfo) destroyPQExpBuffer(query); } +/* + * dumpOneCompositeType + * writes out to fout the queries to recreate a user-defined stand-alone + * composite type as requested by dumpTypes + */ +static void +dumpOneCompositeType(Archive *fout, TypeInfo *tinfo) +{ + PQExpBuffer q = createPQExpBuffer(); + PQExpBuffer delq = createPQExpBuffer(); + PQExpBuffer query = createPQExpBuffer(); + PGresult *res; + int ntups; + char *attname; + char *atttypdefn; + char *attbasetype; + const char *((*deps)[]); + int depIdx = 0; + int i; + + deps = malloc(sizeof(char *) * 10); + + /* Set proper schema search path so type references list correctly */ + selectSourceSchema(tinfo->typnamespace->nspname); + + /* Fetch type specific details */ + /* We assume here that remoteVersion must be at least 70300 */ + + appendPQExpBuffer(query, "SELECT a.attname, " + "pg_catalog.format_type(a.atttypid, a.atttypmod) as atttypdefn, " + "a.atttypid as attbasetype " + "FROM pg_catalog.pg_type t, pg_catalog.pg_attribute a " + "WHERE t.oid = '%s'::pg_catalog.oid " + "AND a.attrelid = t.typrelid", + tinfo->oid); + + res = PQexec(g_conn, query->data); + if (!res || + PQresultStatus(res) != PGRES_TUPLES_OK) + { + write_msg(NULL, "query to obtain type information failed: %s", PQerrorMessage(g_conn)); + exit_nicely(); + } + + /* Expecting at least a single result */ + ntups = PQntuples(res); + if (ntups < 1) + { + write_msg(NULL, "Got no rows from: %s", query->data); + exit_nicely(); + } + + /* DROP must be fully qualified in case same name appears in pg_catalog */ + appendPQExpBuffer(delq, "DROP TYPE %s.", + fmtId(tinfo->typnamespace->nspname, force_quotes)); + appendPQExpBuffer(delq, "%s RESTRICT;\n", + fmtId(tinfo->typname, force_quotes)); + + appendPQExpBuffer(q, + "CREATE TYPE %s AS (", + fmtId(tinfo->typname, force_quotes)); + + for (i = 0; i < ntups; i++) + { + attname = PQgetvalue(res, i, PQfnumber(res, "attname")); + atttypdefn = PQgetvalue(res, i, PQfnumber(res, "atttypdefn")); + attbasetype = PQgetvalue(res, i, PQfnumber(res, "attbasetype")); + + if (i > 0) + appendPQExpBuffer(q, ",\n\t %s %s", attname, atttypdefn); + else + appendPQExpBuffer(q, "%s %s", attname, atttypdefn); + + /* Depends on the base type */ + (*deps)[depIdx++] = strdup(attbasetype); + } + appendPQExpBuffer(q, ");\n"); + + (*deps)[depIdx++] = NULL; /* End of List */ + + ArchiveEntry(fout, tinfo->oid, tinfo->typname, + tinfo->typnamespace->nspname, + tinfo->usename, "TYPE", deps, + q->data, delq->data, NULL, NULL, NULL); + + /*** Dump Type Comments ***/ + resetPQExpBuffer(q); + + appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->typname, force_quotes)); + dumpComment(fout, q->data, + tinfo->typnamespace->nspname, tinfo->usename, + tinfo->oid, "pg_type", 0, NULL); + + PQclear(res); + destroyPQExpBuffer(q); + destroyPQExpBuffer(delq); + destroyPQExpBuffer(query); +} + /* * dumpTypes * writes out to fout the queries to recreate all the user-defined types @@ -3188,8 +3303,8 @@ dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs, if (!tinfo[i].typnamespace->dump) continue; - /* skip relation types */ - if (atooid(tinfo[i].typrelid) != 0) + /* skip relation types for non-stand-alone type relations*/ + if (atooid(tinfo[i].typrelid) != 0 && tinfo[i].typrelkind != 'c') continue; /* skip undefined placeholder types */ @@ -3207,6 +3322,8 @@ dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs, finfo, numFuncs, tinfo, numTypes); else if (tinfo[i].typtype == 'd') dumpOneDomain(fout, &tinfo[i]); + else if (tinfo[i].typtype == 'c') + dumpOneCompositeType(fout, &tinfo[i]); } } @@ -4832,6 +4949,7 @@ dumpTables(Archive *fout, TableInfo tblinfo[], int numTables, if (tbinfo->relkind != RELKIND_SEQUENCE) continue; + if (tbinfo->dump) { dumpOneSequence(fout, tbinfo, schemaOnly, dataOnly); @@ -4848,6 +4966,8 @@ dumpTables(Archive *fout, TableInfo tblinfo[], int numTables, if (tbinfo->relkind == RELKIND_SEQUENCE) /* already dumped */ continue; + if (tbinfo->relkind == RELKIND_COMPOSITE_TYPE) /* dumped as a type */ + continue; if (tbinfo->dump) { diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 9a208f1e1475b8726417200bff03bcd3afc6337b..02415a794dece25518f187e77de990717c5db105 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_dump.h,v 1.94 2002/08/02 18:15:08 tgl Exp $ + * $Id: pg_dump.h,v 1.95 2002/08/15 16:36:06 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -47,6 +47,7 @@ typedef struct _typeInfo char *usename; /* name of owner, or empty string */ char *typelem; /* OID */ char *typrelid; /* OID */ + char typrelkind; /* 'r', 'v', 'c', etc */ char typtype; /* 'b', 'c', etc */ bool isArray; /* true if user-defined array type */ bool isDefined; /* true if typisdefined */ diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index dc37b9b7ba4b01661f06a3409ed57c9a282b1111..5b446e673d7a498f854816ec644f271bc9cfbc7c 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -3,7 +3,7 @@ * * Copyright 2000-2002 by PostgreSQL Global Development Group * - * $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.60 2002/08/10 16:01:16 tgl Exp $ + * $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.61 2002/08/15 16:36:06 momjian Exp $ */ #include "postgres_fe.h" #include "describe.h" @@ -210,9 +210,12 @@ describeTypes(const char *pattern, bool verbose) /* * do not include array types (start with underscore), do not include - * user relations (typrelid!=0) + * user relations (typrelid!=0) unless they are type relations */ - appendPQExpBuffer(&buf, "WHERE t.typrelid = 0 AND t.typname !~ '^_'\n"); + appendPQExpBuffer(&buf, "WHERE (t.typrelid = 0 "); + appendPQExpBuffer(&buf, "OR (SELECT c.relkind = 'c' FROM pg_class c " + "where c.oid = t.typrelid)) "); + appendPQExpBuffer(&buf, "AND t.typname !~ '^_'\n"); /* Match name pattern against either internal or external name */ processNamePattern(&buf, pattern, true, false, diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index 2d5011e6d62c4adf2ebb37457082e3b47facafe8..fd4ffac9c07b6f368075fde0c0227be3896b3da4 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_class.h,v 1.70 2002/08/02 18:15:09 tgl Exp $ + * $Id: pg_class.h,v 1.71 2002/08/15 16:36:07 momjian Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -169,5 +169,6 @@ DESCR(""); #define RELKIND_UNCATALOGED 'u' /* temporary heap */ #define RELKIND_TOASTVALUE 't' /* moved off huge values */ #define RELKIND_VIEW 'v' /* view */ +#define RELKIND_COMPOSITE_TYPE 'c' /* composite type */ #endif /* PG_CLASS_H */ diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index a4af74ac5c5c64fbbf525df3e5451de86804d6ca..3de3390dbf4ce68887bd491e5c4388ec039d2b74 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: defrem.h,v 1.43 2002/07/29 22:14:11 tgl Exp $ + * $Id: defrem.h,v 1.44 2002/08/15 16:36:07 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -58,6 +58,7 @@ extern void RemoveType(List *names, DropBehavior behavior); extern void RemoveTypeById(Oid typeOid); extern void DefineDomain(CreateDomainStmt *stmt); extern void RemoveDomain(List *names, DropBehavior behavior); +extern Oid DefineCompositeType(const RangeVar *typevar, List *coldeflist); extern void DefineOpClass(CreateOpClassStmt *stmt); extern void RemoveOpClass(RemoveOpClassStmt *stmt); diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 93a020a12e9e309e8b36df2e300d5edb58e9c0a7..0e3922ec37ade569950520726be8be1b556f3838 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: nodes.h,v 1.114 2002/07/29 22:14:11 tgl Exp $ + * $Id: nodes.h,v 1.115 2002/08/15 16:36:07 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -238,6 +238,7 @@ typedef enum NodeTag T_PrivTarget, T_InsertDefault, T_CreateOpClassItem, + T_CompositeTypeStmt, /* * TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h) diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 765d1ca0514795c7498737b8647b87b9a1447240..8c356a55976350f9ddaed13d2fdb58789f2dcc89 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: parsenodes.h,v 1.198 2002/08/04 19:48:10 momjian Exp $ + * $Id: parsenodes.h,v 1.199 2002/08/15 16:36:07 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1401,6 +1401,18 @@ typedef struct TransactionStmt List *options; } TransactionStmt; +/* ---------------------- + * Create Type Statement, composite types + * ---------------------- + */ +typedef struct CompositeTypeStmt +{ + NodeTag type; + RangeVar *typevar; /* the composite type to be created */ + List *coldeflist; /* list of ColumnDef nodes */ +} CompositeTypeStmt; + + /* ---------------------- * Create View Statement * ---------------------- diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 00edb1abf93e1a2f3e6945794893997f8ab41ec5..ebb2312dae4a847ac61a750df023eb1b6db77539 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -3,7 +3,7 @@ * procedural language * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.45 2002/08/12 14:25:07 tgl Exp $ + * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.46 2002/08/15 16:36:08 momjian Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -1028,12 +1028,13 @@ plpgsql_parse_dblwordtype(char *word) } /* - * It must be a relation, sequence or view + * It must be a relation, sequence, view, or type */ classStruct = (Form_pg_class) GETSTRUCT(classtup); if (classStruct->relkind != RELKIND_RELATION && classStruct->relkind != RELKIND_SEQUENCE && - classStruct->relkind != RELKIND_VIEW) + classStruct->relkind != RELKIND_VIEW && + classStruct->relkind != RELKIND_COMPOSITE_TYPE) { ReleaseSysCache(classtup); pfree(cp[0]); @@ -1145,10 +1146,11 @@ build_rowtype(Oid classOid) classStruct = (Form_pg_class) GETSTRUCT(classtup); relname = NameStr(classStruct->relname); - /* accept relation, sequence, or view pg_class entries */ + /* accept relation, sequence, view, or type pg_class entries */ if (classStruct->relkind != RELKIND_RELATION && classStruct->relkind != RELKIND_SEQUENCE && - classStruct->relkind != RELKIND_VIEW) + classStruct->relkind != RELKIND_VIEW && + classStruct->relkind != RELKIND_COMPOSITE_TYPE) elog(ERROR, "%s isn't a table", relname); /* diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out index 06b992280b110c8638334589adf1ed59895b268d..68dc8fbd5e57be55c90c2b0488781091c44ee59d 100644 --- a/src/test/regress/expected/create_type.out +++ b/src/test/regress/expected/create_type.out @@ -37,4 +37,17 @@ SELECT * FROM default_test; zippo | 42 (1 row) +-- Test stand-alone composite type +CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42); +CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS ' + SELECT * FROM default_test; +' LANGUAGE SQL; +SELECT * FROM get_default_test(); + f1 | f2 +-------+---- + zippo | 42 +(1 row) + +DROP TYPE default_test_row CASCADE; +NOTICE: Drop cascades to function get_default_test() DROP TABLE default_test; diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql index a728bbd8b9db796a8a6825553b3ba63334c38bce..9b37981bd49c0e56fc46daaa48839ec0d18106fe 100644 --- a/src/test/regress/sql/create_type.sql +++ b/src/test/regress/sql/create_type.sql @@ -41,4 +41,16 @@ INSERT INTO default_test DEFAULT VALUES; SELECT * FROM default_test; +-- Test stand-alone composite type + +CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42); + +CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS ' + SELECT * FROM default_test; +' LANGUAGE SQL; + +SELECT * FROM get_default_test(); + +DROP TYPE default_test_row CASCADE; + DROP TABLE default_test;