Thread: stand-alone composite types patch (was [HACKERS] Proposal: stand-alone composite types)
stand-alone composite types patch (was [HACKERS] Proposal: stand-alone composite types)
From
Joe Conway
Date:
Joe Conway wrote: > Based on Tom's suggestion, I propose the following: > > 1. Define a new pg_class relkind as 'c' for composite. Currently relkind > can be: 'S' sequence, 'i' index, 'r' relation, 's' special, 't' > toast, and 'v' view. > > 2. Borrow the needed parts from CREATE and DROP VIEW to implement a new > form of the CREATE TYPE command, with syntax something like: > > CREATE TYPE typename AS ( column_name data_type [, ... ] ) > > This would add a pg_class entry of relkind 'c', and add a new > pg_type entry of typtype 'c', with typrelid pointing to the > pg_class entry. Essentially, this new stand-alone composite type > looks a lot like a view without any rules. Items 1 and 2 from the proposal above are implemented in the attached patch. I was able to get rid of the reduce/reduce conflict with Tom's help (thanks Tom!). test=# CREATE TYPE compfoo AS (f1 int, f2 int); CREATE TYPE test=# CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS 'SELECT fooid, foosubid FROM foo' LANGUAGE SQL; CREATE FUNCTION test=# SELECT * FROM getfoo(); f1 | f2 ----+---- 1 | 1 1 | 2 (2 rows) test=# DROP TYPE compfoo; NOTICE: function getfoo() depends on type compfoo ERROR: Cannot drop relation compfoo because other objects depend on it Use DROP ... CASCADE to drop the dependent objects too test=# DROP TYPE compfoo CASCADE; NOTICE: Drop cascades to function getfoo() DROP TYPE Passes all regression tests (well, I'm on RedHat 7.3, so there are three "expected" failures). Doc and regression adjustments included. If there are no objections, please apply. Thanks, Joe Index: doc/src/sgml/ref/create_type.sgml =================================================================== RCS file: /opt/src/cvs/pgsql-server/doc/src/sgml/ref/create_type.sgml,v retrieving revision 1.30 diff -c -r1.30 create_type.sgml *** doc/src/sgml/ref/create_type.sgml 24 Jul 2002 19:11:07 -0000 1.30 --- doc/src/sgml/ref/create_type.sgml 8 Aug 2002 03:54:32 -0000 *************** *** 30,35 **** --- 30,42 ---- [ , 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,143 **** --- 145,169 ---- </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,199 **** </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 <replaceable class="parameter">input_function</replaceable>, which converts the type's external representation to an internal representation usable by the --- 217,225 ---- </para> <para> ! 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,293 **** --- 314,327 ---- <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,375 **** --- 404,418 ---- 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> Index: src/backend/catalog/heap.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/catalog/heap.c,v retrieving revision 1.219 diff -c -r1.219 heap.c *** src/backend/catalog/heap.c 6 Aug 2002 02:36:33 -0000 1.219 --- src/backend/catalog/heap.c 8 Aug 2002 02:49:47 -0000 *************** *** 764,770 **** /* * We create the disk file for this relation here */ ! if (relkind != RELKIND_VIEW) heap_storage_create(new_rel_desc); /* --- 764,770 ---- /* * We create the disk file for this relation here */ ! if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE) heap_storage_create(new_rel_desc); /* *************** *** 1135,1141 **** /* * unlink the relation's physical file and finish up. */ ! if (rel->rd_rel->relkind != RELKIND_VIEW) smgrunlink(DEFAULT_SMGR, rel); /* --- 1135,1142 ---- /* * unlink the relation's physical file and finish up. */ ! if (rel->rd_rel->relkind != RELKIND_VIEW && ! rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE) smgrunlink(DEFAULT_SMGR, rel); /* Index: src/backend/commands/typecmds.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/commands/typecmds.c,v retrieving revision 1.8 diff -c -r1.8 typecmds.c *** src/backend/commands/typecmds.c 24 Jul 2002 19:11:09 -0000 1.8 --- src/backend/commands/typecmds.c 8 Aug 2002 02:49:47 -0000 *************** *** 38,43 **** --- 38,44 ---- #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" *************** *** 49,55 **** static Oid findTypeIOFunction(List *procname, bool isOutput); ! /* * DefineType --- 50,57 ---- static Oid findTypeIOFunction(List *procname, bool isOutput); ! static void DefineCompositeTypeRelation(const RangeVar *typevar, ! List *coldeflist); /* * DefineType *************** *** 251,256 **** --- 253,259 ---- Oid typeoid; HeapTuple tup; ObjectAddress object; + char typtype; /* Make a TypeName so we can use standard type lookup machinery */ typename = makeNode(TypeName); *************** *** 277,289 **** GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, TypeNameToString(typename)); ReleaseSysCache(tup); /* * Do the deletion */ ! object.classId = RelOid_pg_type; ! object.objectId = typeoid; object.objectSubId = 0; performDeletion(&object, behavior); --- 280,317 ---- GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, TypeNameToString(typename)); + typtype = ((Form_pg_type) GETSTRUCT(tup))->typtype; + ReleaseSysCache(tup); /* * Do the deletion */ ! if (typtype != 'c') ! { ! object.classId = RelOid_pg_type; ! object.objectId = typeoid; ! } ! else ! { ! Oid relid = typeidTypeRelid(typeoid); ! Relation rel = relation_open(relid, AccessShareLock); ! char relkind = rel->rd_rel->relkind; ! ! relation_close(rel, AccessShareLock); ! ! if (relkind == RELKIND_COMPOSITE_TYPE) ! { ! object.classId = RelOid_pg_class; ! object.objectId = relid; ! } ! else ! { ! object.classId = RelOid_pg_type; ! object.objectId = typeoid; ! } ! ! } object.objectSubId = 0; performDeletion(&object, behavior); *************** *** 665,668 **** --- 693,758 ---- } return procOid; + } + + /*--------------------------------------------------------------------- + * DefineCompositeTypeRelation + * + * 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... + *--------------------------------------------------------------------- + */ + static void + DefineCompositeTypeRelation(const RangeVar *typevar, List *coldeflist) + { + Oid relid; + 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... + */ + relid = DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE); + } + + /*------------------------------------------------------------------- + * DefineCompositeType + * + * - takes a "typevar", "coldeflist" pair and then + * constructs the "virtual" relation + *------------------------------------------------------------------- + */ + void + DefineCompositeType(const RangeVar *typevar, List *coldeflist) + { + /* + * Create the composite type relation + * + * NOTE: if it already exists, the xact will be aborted. + */ + DefineCompositeTypeRelation(typevar, coldeflist); + + /* + * The relation we have just created is not visible to any other + * commands running with the same transaction & command id. So, + * increment the command id counter (but do NOT pfree any memory!!!!) + */ + CommandCounterIncrement(); } Index: src/backend/nodes/copyfuncs.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/copyfuncs.c,v retrieving revision 1.200 diff -c -r1.200 copyfuncs.c *** src/backend/nodes/copyfuncs.c 4 Aug 2002 19:48:09 -0000 1.200 --- src/backend/nodes/copyfuncs.c 8 Aug 2002 02:49:47 -0000 *************** *** 2233,2238 **** --- 2233,2249 ---- 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) { *************** *** 2938,2943 **** --- 2949,2957 ---- break; case T_TransactionStmt: retval = _copyTransactionStmt(from); + break; + case T_CompositeTypeStmt: + retval = _copyCompositeTypeStmt(from); break; case T_ViewStmt: retval = _copyViewStmt(from); Index: src/backend/nodes/equalfuncs.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/equalfuncs.c,v retrieving revision 1.149 diff -c -r1.149 equalfuncs.c *** src/backend/nodes/equalfuncs.c 4 Aug 2002 23:49:59 -0000 1.149 --- src/backend/nodes/equalfuncs.c 8 Aug 2002 02:49:47 -0000 *************** *** 1062,1067 **** --- 1062,1078 ---- } 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) { if (!equal(a->view, b->view)) *************** *** 2110,2115 **** --- 2121,2129 ---- break; case T_TransactionStmt: retval = _equalTransactionStmt(a, b); + break; + case T_CompositeTypeStmt: + retval = _equalCompositeTypeStmt(a, b); break; case T_ViewStmt: retval = _equalViewStmt(a, b); Index: src/backend/parser/gram.y =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/parser/gram.y,v retrieving revision 2.357 diff -c -r2.357 gram.y *** src/backend/parser/gram.y 6 Aug 2002 05:40:45 -0000 2.357 --- src/backend/parser/gram.y 8 Aug 2002 03:38:46 -0000 *************** *** 205,211 **** %type <list> stmtblock, stmtmulti, OptTableElementList, TableElementList, OptInherit, definition, ! opt_distinct, opt_definition, func_args, func_args_list, func_as, createfunc_opt_list oper_argtypes, RuleActionList, RuleActionMulti, opt_column_list, columnList, opt_name_list, --- 205,211 ---- %type <list> stmtblock, stmtmulti, OptTableElementList, TableElementList, OptInherit, definition, ! 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, *************** *** 2247,2252 **** --- 2247,2285 ---- 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); *************** *** 2255,2260 **** --- 2288,2296 ---- n->definition = $7; $$ = (Node *)n; } + ; + + rowdefinition: '(' TableFuncElementList ')' { $$ = $2; } ; definition: '(' def_list ')' { $$ = $2; } Index: src/backend/tcop/postgres.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/tcop/postgres.c,v retrieving revision 1.280 diff -c -r1.280 postgres.c *** src/backend/tcop/postgres.c 6 Aug 2002 05:24:04 -0000 1.280 --- src/backend/tcop/postgres.c 8 Aug 2002 02:49:47 -0000 *************** *** 2264,2269 **** --- 2264,2273 ---- } break; + case T_CompositeTypeStmt: + tag = "CREATE TYPE"; + break; + case T_ViewStmt: tag = "CREATE VIEW"; break; Index: src/backend/tcop/utility.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/tcop/utility.c,v retrieving revision 1.169 diff -c -r1.169 utility.c *** src/backend/tcop/utility.c 7 Aug 2002 21:45:02 -0000 1.169 --- src/backend/tcop/utility.c 8 Aug 2002 02:49:47 -0000 *************** *** 573,578 **** --- 573,586 ---- } break; + case T_CompositeTypeStmt: /* CREATE TYPE (composite) */ + { + CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree; + + DefineCompositeType(stmt->typevar, stmt->coldeflist); + } + break; + case T_ViewStmt: /* CREATE VIEW */ { ViewStmt *stmt = (ViewStmt *) parsetree; Index: src/include/catalog/pg_class.h =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/include/catalog/pg_class.h,v retrieving revision 1.70 diff -c -r1.70 pg_class.h *** src/include/catalog/pg_class.h 2 Aug 2002 18:15:09 -0000 1.70 --- src/include/catalog/pg_class.h 8 Aug 2002 02:49:47 -0000 *************** *** 169,173 **** --- 169,174 ---- #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 */ Index: src/include/commands/defrem.h =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/include/commands/defrem.h,v retrieving revision 1.43 diff -c -r1.43 defrem.h *** src/include/commands/defrem.h 29 Jul 2002 22:14:11 -0000 1.43 --- src/include/commands/defrem.h 8 Aug 2002 02:49:47 -0000 *************** *** 58,63 **** --- 58,64 ---- extern void RemoveTypeById(Oid typeOid); extern void DefineDomain(CreateDomainStmt *stmt); extern void RemoveDomain(List *names, DropBehavior behavior); + extern void DefineCompositeType(const RangeVar *typevar, List *coldeflist); extern void DefineOpClass(CreateOpClassStmt *stmt); extern void RemoveOpClass(RemoveOpClassStmt *stmt); Index: src/include/nodes/nodes.h =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/include/nodes/nodes.h,v retrieving revision 1.114 diff -c -r1.114 nodes.h *** src/include/nodes/nodes.h 29 Jul 2002 22:14:11 -0000 1.114 --- src/include/nodes/nodes.h 8 Aug 2002 02:49:47 -0000 *************** *** 238,243 **** --- 238,244 ---- T_PrivTarget, T_InsertDefault, T_CreateOpClassItem, + T_CompositeTypeStmt, /* * TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h) Index: src/include/nodes/parsenodes.h =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/include/nodes/parsenodes.h,v retrieving revision 1.198 diff -c -r1.198 parsenodes.h *** src/include/nodes/parsenodes.h 4 Aug 2002 19:48:10 -0000 1.198 --- src/include/nodes/parsenodes.h 8 Aug 2002 02:49:47 -0000 *************** *** 1402,1407 **** --- 1402,1419 ---- } 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 * ---------------------- */ Index: src/test/regress/expected/create_type.out =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/test/regress/expected/create_type.out,v retrieving revision 1.4 diff -c -r1.4 create_type.out *** src/test/regress/expected/create_type.out 6 Sep 2001 02:07:42 -0000 1.4 --- src/test/regress/expected/create_type.out 8 Aug 2002 03:41:27 -0000 *************** *** 37,40 **** --- 37,53 ---- 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; Index: src/test/regress/sql/create_type.sql =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/test/regress/sql/create_type.sql,v retrieving revision 1.4 diff -c -r1.4 create_type.sql *** src/test/regress/sql/create_type.sql 6 Sep 2001 02:07:42 -0000 1.4 --- src/test/regress/sql/create_type.sql 8 Aug 2002 03:09:48 -0000 *************** *** 41,44 **** --- 41,56 ---- 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;
Re: stand-alone composite types patch (was [HACKERS] Proposal: stand-alone composite types)
From
Tom Lane
Date:
Joe Conway <mail@joeconway.com> writes: > Items 1 and 2 from the proposal above are implemented in the attached > patch. Good first cut, but... I don't like the way you did the dependencies. In a normal relation, the type row is internally dependent on the class row. This causes the type to automatically go away if the relation is dropped, and it also prevents an attempt to manually drop the type directly (without dropping the relation). For a composite type, of course we want exactly the opposite behavior: the class row should internally depend on the type, not vice versa. If you did it that way then you'd not need that ugly kluge in RemoveType. What you'd need instead is some smarts (a kluge!?) in setting up the dependency. Currently that dependency is made in TypeCreate which doesn't know what sort of relation it's creating a type for. Probably the best answer is to pull that particular dependency out of TypeCreate, and make it (in the proper direction) in AddNewRelationType. Also, I'm not following the point of the separation between DefineCompositeType and DefineCompositeTypeRelation; nor do I see a need for a CommandCounterIncrement call in there. You have missed a number of places where this new relkind ought to be special-cased the same way RELKIND_VIEW is --- for example CheckAttributeNames and AddNewAttributeTuples, since a composite type presumably shouldn't have system columns associated. I'd counsel looking at all references to RELKIND_VIEW to see which places also need to check for RELKIND_COMPOSITE_TYPE. regards, tom lane
Tom Lane wrote: > If you did it that way then you'd not need that ugly kluge in > RemoveType. What you'd need instead is some smarts (a kluge!?) in > setting up the dependency. Currently that dependency is made in > TypeCreate which doesn't know what sort of relation it's creating > a type for. Probably the best answer is to pull that particular > dependency out of TypeCreate, and make it (in the proper direction) > in AddNewRelationType. OK -- I'll take a look. > Also, I'm not following the point of the separation between > DefineCompositeType and DefineCompositeTypeRelation; nor do I see a need > for a CommandCounterIncrement call in there. Well the next thing I was going to work on after this was an implicitly created composite type when creating a function. I thought maybe the CommandCounterIncrement would be needed so that the type could be created and then immediately used by the function. In any case, I'll combine the two functions. > You have missed a number of places where this new relkind ought to > be special-cased the same way RELKIND_VIEW is --- for example > CheckAttributeNames and AddNewAttributeTuples, since a composite type > presumably shouldn't have system columns associated. I'd counsel > looking at all references to RELKIND_VIEW to see which places also need > to check for RELKIND_COMPOSITE_TYPE. Yeah, after I fired off the post it occurred to me that I had neglected to do that. I was just going through that exercise now. Thanks for the (quick!) review. Round two will be probably sometime tomorrow. Joe
Re: stand-alone composite types patch (was [HACKERS] Proposal: stand-alone composite types)
From
Tom Lane
Date:
Joe Conway <mail@joeconway.com> writes: > Tom Lane wrote: >> Also, I'm not following the point of the separation between >> DefineCompositeType and DefineCompositeTypeRelation; nor do I see a need >> for a CommandCounterIncrement call in there. > Well the next thing I was going to work on after this was an implicitly > created composite type when creating a function. I thought maybe the > CommandCounterIncrement would be needed so that the type could be > created and then immediately used by the function. Hm. Maybe --- it would depend on whether the function-creating code actually tried to look at the type definition, as opposed to just using its OID. (You'll probably want DefineCompositeType to return the type OID, btw.) In any case, I'd be inclined to put the CCI call in the caller not the callee, so it's only done when actually needed. It's surely not needed for a standalone CREATE TYPE command. regards, tom lane
Tom Lane wrote: > You have missed a number of places where this new relkind ought to > be special-cased the same way RELKIND_VIEW is --- for example > CheckAttributeNames and AddNewAttributeTuples, since a composite type > presumably shouldn't have system columns associated. I'd counsel > looking at all references to RELKIND_VIEW to see which places also need > to check for RELKIND_COMPOSITE_TYPE. One of the places I missed was pg_dump.c. In working on pg_dump support, I ran across a problem: test=# CREATE TYPE "MyInt42" (internallength = 4,input = int4in,output = int4out,alignment = int4,default = 42,passedbyvalue); CREATE TYPE test=# CREATE TYPE "compfoo" AS (f1 "MyInt42", f2 integer); CREATE TYPE test=# drop type compfoo; DROP TYPE test=# CREATE TYPE "compfoo" AS (f1 "MyInt42", f2 "integer"); ERROR: Type "integer" does not exist test=# create table tbl_0 (f1 "integer"); ERROR: Type "integer" does not exist test=# create table tbl_0 (f1 "MyInt42"); CREATE TABLE test=# drop table tbl_0 ; DROP TABLE test=# create table tbl_0 (f1 integer); CREATE TABLE Shouldn't "integer" be recognized as a valid type? Thanks, Joe
Tom Lane wrote: > If you did it that way then you'd not need that ugly kluge in > RemoveType. What you'd need instead is some smarts (a kluge!?) in > setting up the dependency. Currently that dependency is made in > TypeCreate which doesn't know what sort of relation it's creating > a type for. Probably the best answer is to pull that particular > dependency out of TypeCreate, and make it (in the proper direction) > in AddNewRelationType. Fixed. > Also, I'm not following the point of the separation between > DefineCompositeType and DefineCompositeTypeRelation; nor do I see a need > for a CommandCounterIncrement call in there. Fixed. > You have missed a number of places where this new relkind ought to > be special-cased the same way RELKIND_VIEW is --- for example > CheckAttributeNames and AddNewAttributeTuples, since a composite type > presumably shouldn't have system columns associated. I'd counsel > looking at all references to RELKIND_VIEW to see which places also need > to check for RELKIND_COMPOSITE_TYPE. Yup, I had missed lots of things, not the least of which was pg_dump. New patch attached includes pg_dump, psql (\dT), docs, and regression support. There is also a small adjustment to the expected output file for select-having. I was getting a regression failure based on ordering of the results, so I added ORDER BY clauses. Passes all regression tests. If no more objections, please apply. Thanks, Joe Index: doc/src/sgml/ref/create_type.sgml =================================================================== RCS file: /opt/src/cvs/pgsql-server/doc/src/sgml/ref/create_type.sgml,v retrieving revision 1.30 diff -c -r1.30 create_type.sgml *** doc/src/sgml/ref/create_type.sgml 24 Jul 2002 19:11:07 -0000 1.30 --- doc/src/sgml/ref/create_type.sgml 8 Aug 2002 14:49:57 -0000 *************** *** 30,35 **** --- 30,42 ---- [ , 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,143 **** --- 145,169 ---- </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,199 **** </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 <replaceable class="parameter">input_function</replaceable>, which converts the type's external representation to an internal representation usable by the --- 217,225 ---- </para> <para> ! 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,293 **** --- 314,327 ---- <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,375 **** --- 404,418 ---- 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> Index: src/backend/catalog/heap.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/catalog/heap.c,v retrieving revision 1.219 diff -c -r1.219 heap.c *** src/backend/catalog/heap.c 6 Aug 2002 02:36:33 -0000 1.219 --- src/backend/catalog/heap.c 8 Aug 2002 14:49:57 -0000 *************** *** 358,364 **** * * Skip this for a view, since it doesn't have system attributes. */ ! if (relkind != RELKIND_VIEW) { for (i = 0; i < natts; i++) { --- 358,364 ---- * * Skip this for a view, since it doesn't have system attributes. */ ! if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE) { for (i = 0; i < natts; i++) { *************** *** 475,481 **** * Skip all for a view. We don't bother with making datatype * dependencies here, since presumably all these types are pinned. */ ! if (relkind != RELKIND_VIEW) { dpp = SysAtt; for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++) --- 475,481 ---- * Skip all for a view. We don't bother with making datatype * dependencies here, since presumably all these types are pinned. */ ! if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE) { dpp = SysAtt; for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++) *************** *** 764,770 **** /* * We create the disk file for this relation here */ ! if (relkind != RELKIND_VIEW) heap_storage_create(new_rel_desc); /* --- 764,770 ---- /* * We create the disk file for this relation here */ ! if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE) heap_storage_create(new_rel_desc); /* *************** *** 1135,1141 **** /* * unlink the relation's physical file and finish up. */ ! if (rel->rd_rel->relkind != RELKIND_VIEW) smgrunlink(DEFAULT_SMGR, rel); /* --- 1135,1142 ---- /* * unlink the relation's physical file and finish up. */ ! if (rel->rd_rel->relkind != RELKIND_VIEW && ! rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE) smgrunlink(DEFAULT_SMGR, rel); /* Index: src/backend/catalog/namespace.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/catalog/namespace.c,v retrieving revision 1.29 diff -c -r1.29 namespace.c *** src/backend/catalog/namespace.c 8 Aug 2002 01:44:30 -0000 1.29 --- src/backend/catalog/namespace.c 8 Aug 2002 14:49:57 -0000 *************** *** 1578,1583 **** --- 1578,1584 ---- 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); Index: src/backend/catalog/pg_type.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/catalog/pg_type.c,v retrieving revision 1.77 diff -c -r1.77 pg_type.c *** src/backend/catalog/pg_type.c 5 Aug 2002 03:29:16 -0000 1.77 --- src/backend/catalog/pg_type.c 8 Aug 2002 17:30:27 -0000 *************** *** 311,325 **** /* * 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. */ if (OidIsValid(relationOid)) { referenced.classId = RelOid_pg_class; referenced.objectId = relationOid; referenced.objectSubId = 0; ! recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); } /* --- 311,338 ---- /* * If the type is a rowtype for a relation, mark it as internally ! * 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; ! ! if (relkind != RELKIND_COMPOSITE_TYPE) ! recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); ! else ! recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL); } /* Index: src/backend/commands/copy.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/commands/copy.c,v retrieving revision 1.162 diff -c -r1.162 copy.c *** src/backend/commands/copy.c 2 Aug 2002 18:15:06 -0000 1.162 --- src/backend/commands/copy.c 8 Aug 2002 14:49:57 -0000 *************** *** 398,403 **** --- 398,406 ---- 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)); *************** *** 442,447 **** --- 445,453 ---- { 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", Index: src/backend/commands/tablecmds.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/commands/tablecmds.c,v retrieving revision 1.28 diff -c -r1.28 tablecmds.c *** src/backend/commands/tablecmds.c 7 Aug 2002 21:45:01 -0000 1.28 --- src/backend/commands/tablecmds.c 8 Aug 2002 18:04:58 -0000 *************** *** 345,350 **** --- 345,354 ---- 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,3221 **** case RELKIND_RELATION: case RELKIND_INDEX: case RELKIND_VIEW: 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", NameStr(tuple_class->relname)); } } --- 3214,3226 ---- 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, type, or sequence", NameStr(tuple_class->relname)); } } Index: src/backend/commands/typecmds.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/commands/typecmds.c,v retrieving revision 1.8 diff -c -r1.8 typecmds.c *** src/backend/commands/typecmds.c 24 Jul 2002 19:11:09 -0000 1.8 --- src/backend/commands/typecmds.c 8 Aug 2002 17:33:43 -0000 *************** *** 38,43 **** --- 38,44 ---- #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,56 **** static Oid findTypeIOFunction(List *procname, bool isOutput); - /* * DefineType * Registers a new type. --- 51,56 ---- *************** *** 665,668 **** --- 665,707 ---- } 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); } Index: src/backend/executor/execMain.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/executor/execMain.c,v retrieving revision 1.173 diff -c -r1.173 execMain.c *** src/backend/executor/execMain.c 7 Aug 2002 21:45:02 -0000 1.173 --- src/backend/executor/execMain.c 8 Aug 2002 14:49:57 -0000 *************** *** 786,791 **** --- 786,795 ---- 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)); Index: src/backend/nodes/copyfuncs.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/copyfuncs.c,v retrieving revision 1.200 diff -c -r1.200 copyfuncs.c *** src/backend/nodes/copyfuncs.c 4 Aug 2002 19:48:09 -0000 1.200 --- src/backend/nodes/copyfuncs.c 8 Aug 2002 14:49:58 -0000 *************** *** 2233,2238 **** --- 2233,2249 ---- 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) { *************** *** 2938,2943 **** --- 2949,2957 ---- break; case T_TransactionStmt: retval = _copyTransactionStmt(from); + break; + case T_CompositeTypeStmt: + retval = _copyCompositeTypeStmt(from); break; case T_ViewStmt: retval = _copyViewStmt(from); Index: src/backend/nodes/equalfuncs.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/equalfuncs.c,v retrieving revision 1.149 diff -c -r1.149 equalfuncs.c *** src/backend/nodes/equalfuncs.c 4 Aug 2002 23:49:59 -0000 1.149 --- src/backend/nodes/equalfuncs.c 8 Aug 2002 14:49:58 -0000 *************** *** 1062,1067 **** --- 1062,1078 ---- } 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) { if (!equal(a->view, b->view)) *************** *** 2110,2115 **** --- 2121,2129 ---- break; case T_TransactionStmt: retval = _equalTransactionStmt(a, b); + break; + case T_CompositeTypeStmt: + retval = _equalCompositeTypeStmt(a, b); break; case T_ViewStmt: retval = _equalViewStmt(a, b); Index: src/backend/parser/gram.y =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/parser/gram.y,v retrieving revision 2.357 diff -c -r2.357 gram.y *** src/backend/parser/gram.y 6 Aug 2002 05:40:45 -0000 2.357 --- src/backend/parser/gram.y 8 Aug 2002 14:49:58 -0000 *************** *** 205,211 **** %type <list> stmtblock, stmtmulti, OptTableElementList, TableElementList, OptInherit, definition, ! opt_distinct, opt_definition, func_args, func_args_list, func_as, createfunc_opt_list oper_argtypes, RuleActionList, RuleActionMulti, opt_column_list, columnList, opt_name_list, --- 205,211 ---- %type <list> stmtblock, stmtmulti, OptTableElementList, TableElementList, OptInherit, definition, ! 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, *************** *** 2247,2252 **** --- 2247,2285 ---- 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); *************** *** 2255,2260 **** --- 2288,2296 ---- n->definition = $7; $$ = (Node *)n; } + ; + + rowdefinition: '(' TableFuncElementList ')' { $$ = $2; } ; definition: '(' def_list ')' { $$ = $2; } Index: src/backend/storage/buffer/bufmgr.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/storage/buffer/bufmgr.c,v retrieving revision 1.128 diff -c -r1.128 bufmgr.c *** src/backend/storage/buffer/bufmgr.c 6 Aug 2002 02:36:34 -0000 1.128 --- src/backend/storage/buffer/bufmgr.c 8 Aug 2002 14:49:58 -0000 *************** *** 1056,1061 **** --- 1056,1063 ---- */ 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; Index: src/backend/storage/smgr/smgr.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/storage/smgr/smgr.c,v retrieving revision 1.58 diff -c -r1.58 smgr.c *** src/backend/storage/smgr/smgr.c 6 Aug 2002 02:36:34 -0000 1.58 --- src/backend/storage/smgr/smgr.c 8 Aug 2002 14:49:59 -0000 *************** *** 263,268 **** --- 263,270 ---- 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)); Index: src/backend/tcop/postgres.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/tcop/postgres.c,v retrieving revision 1.280 diff -c -r1.280 postgres.c *** src/backend/tcop/postgres.c 6 Aug 2002 05:24:04 -0000 1.280 --- src/backend/tcop/postgres.c 8 Aug 2002 14:49:59 -0000 *************** *** 2264,2269 **** --- 2264,2273 ---- } break; + case T_CompositeTypeStmt: + tag = "CREATE TYPE"; + break; + case T_ViewStmt: tag = "CREATE VIEW"; break; Index: src/backend/tcop/utility.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/tcop/utility.c,v retrieving revision 1.169 diff -c -r1.169 utility.c *** src/backend/tcop/utility.c 7 Aug 2002 21:45:02 -0000 1.169 --- src/backend/tcop/utility.c 8 Aug 2002 14:49:59 -0000 *************** *** 70,75 **** --- 70,76 ---- {RELKIND_SEQUENCE, "a", "sequence", "SEQUENCE"}, {RELKIND_VIEW, "a", "view", "VIEW"}, {RELKIND_INDEX, "an", "index", "INDEX"}, + {RELKIND_COMPOSITE_TYPE, "a", "type", "TYPE"}, {'\0', "a", "???", "???"} }; *************** *** 570,575 **** --- 571,589 ---- DefineAggregate(stmt->defnames, stmt->definition); break; } + } + 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; Index: src/backend/utils/adt/tid.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/adt/tid.c,v retrieving revision 1.32 diff -c -r1.32 tid.c *** src/backend/utils/adt/tid.c 16 Jul 2002 17:55:25 -0000 1.32 --- src/backend/utils/adt/tid.c 8 Aug 2002 14:49:59 -0000 *************** *** 226,231 **** --- 226,234 ---- 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); *************** *** 248,253 **** --- 251,259 ---- rel = heap_openrv(relrv, AccessShareLock); 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); Index: src/bin/pg_dump/common.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/bin/pg_dump/common.c,v retrieving revision 1.67 diff -c -r1.67 common.c *** src/bin/pg_dump/common.c 30 Jul 2002 21:56:04 -0000 1.67 --- src/bin/pg_dump/common.c 8 Aug 2002 14:49:59 -0000 *************** *** 215,223 **** for (i = 0; i < numTables; i++) { ! /* Sequences and views never have parents */ if (tblinfo[i].relkind == RELKIND_SEQUENCE || ! tblinfo[i].relkind == RELKIND_VIEW) continue; /* Don't bother computing anything for non-target tables, either */ --- 215,224 ---- for (i = 0; i < numTables; i++) { ! /* Sequences, views, and types never have parents */ if (tblinfo[i].relkind == RELKIND_SEQUENCE || ! tblinfo[i].relkind == RELKIND_VIEW || ! tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE) continue; /* Don't bother computing anything for non-target tables, either */ *************** *** 269,277 **** for (i = 0; i < numTables; i++) { ! /* Sequences and views never have parents */ if (tblinfo[i].relkind == RELKIND_SEQUENCE || ! tblinfo[i].relkind == RELKIND_VIEW) continue; /* Don't bother computing anything for non-target tables, either */ --- 270,279 ---- for (i = 0; i < numTables; i++) { ! /* Sequences, views, and types never have parents */ if (tblinfo[i].relkind == RELKIND_SEQUENCE || ! tblinfo[i].relkind == RELKIND_VIEW || ! tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE) continue; /* Don't bother computing anything for non-target tables, either */ Index: src/bin/pg_dump/pg_dump.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/bin/pg_dump/pg_dump.c,v retrieving revision 1.280 diff -c -r1.280 pg_dump.c *** src/bin/pg_dump/pg_dump.c 4 Aug 2002 05:03:29 -0000 1.280 --- src/bin/pg_dump/pg_dump.c 8 Aug 2002 22:42:58 -0000 *************** *** 95,100 **** --- 95,101 ---- 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, *************** *** 1178,1183 **** --- 1179,1188 ---- 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; *************** *** 1582,1587 **** --- 1587,1593 ---- int i_usename; int i_typelem; int i_typrelid; + int i_typrelkind; int i_typtype; int i_typisdefined; *************** *** 1602,1608 **** appendPQExpBuffer(query, "SELECT pg_type.oid, typname, " "typnamespace, " "(select usename from pg_user where typowner = usesysid) as usename, " ! "typelem, typrelid, typtype, typisdefined " "FROM pg_type"); } else --- 1608,1616 ---- appendPQExpBuffer(query, "SELECT pg_type.oid, typname, " "typnamespace, " "(select usename from pg_user where typowner = usesysid) as usename, " ! "typelem, typrelid, " ! "(select relkind from pg_class where oid = typrelid) as typrelkind, " ! "typtype, typisdefined " "FROM pg_type"); } else *************** *** 1610,1616 **** 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 " "FROM pg_type"); } --- 1618,1626 ---- appendPQExpBuffer(query, "SELECT pg_type.oid, typname, " "0::oid as typnamespace, " "(select usename from pg_user where typowner = usesysid) as usename, " ! "typelem, typrelid, " ! "''::char as typrelkind, " ! "typtype, typisdefined " "FROM pg_type"); } *************** *** 1632,1637 **** --- 1642,1648 ---- 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"); *************** *** 1644,1649 **** --- 1655,1661 ---- 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); /* *************** *** 2109,2115 **** 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 " --- 2121,2126 ---- *************** *** 2120,2125 **** --- 2131,2137 ---- } 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, " *************** *** 2363,2368 **** --- 2375,2384 ---- 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; *************** *** 3180,3185 **** --- 3196,3300 ---- } /* + * 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 */ *************** *** 3195,3202 **** if (!tinfo[i].typnamespace->dump) continue; ! /* skip relation types */ ! if (atooid(tinfo[i].typrelid) != 0) continue; /* skip undefined placeholder types */ --- 3310,3317 ---- if (!tinfo[i].typnamespace->dump) continue; ! /* skip relation types for non-stand-alone type relations*/ ! if (atooid(tinfo[i].typrelid) != 0 && tinfo[i].typrelkind != 'c') continue; /* skip undefined placeholder types */ *************** *** 3214,3219 **** --- 3329,3336 ---- finfo, numFuncs, tinfo, numTypes); else if (tinfo[i].typtype == 'd') dumpOneDomain(fout, &tinfo[i]); + else if (tinfo[i].typtype == 'c') + dumpOneCompositeType(fout, &tinfo[i]); } } *************** *** 4839,4844 **** --- 4956,4962 ---- if (tbinfo->relkind != RELKIND_SEQUENCE) continue; + if (tbinfo->dump) { dumpOneSequence(fout, tbinfo, schemaOnly, dataOnly); *************** *** 4854,4859 **** --- 4972,4979 ---- TableInfo *tbinfo = &tblinfo[i]; if (tbinfo->relkind == RELKIND_SEQUENCE) /* already dumped */ + continue; + if (tbinfo->relkind == RELKIND_COMPOSITE_TYPE) /* dumped as a type */ continue; if (tbinfo->dump) Index: src/bin/pg_dump/pg_dump.h =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/bin/pg_dump/pg_dump.h,v retrieving revision 1.94 diff -c -r1.94 pg_dump.h *** src/bin/pg_dump/pg_dump.h 2 Aug 2002 18:15:08 -0000 1.94 --- src/bin/pg_dump/pg_dump.h 8 Aug 2002 18:26:11 -0000 *************** *** 47,52 **** --- 47,53 ---- 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 */ Index: src/bin/psql/describe.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/bin/psql/describe.c,v retrieving revision 1.57 diff -c -r1.57 describe.c *** src/bin/psql/describe.c 2 Aug 2002 18:15:08 -0000 1.57 --- src/bin/psql/describe.c 8 Aug 2002 22:26:38 -0000 *************** *** 168,176 **** /* * do not include array types (start with underscore), do not include ! * user relations (typrelid!=0) */ ! appendPQExpBuffer(&buf, "FROM pg_type t\nWHERE t.typrelid = 0 AND t.typname !~ '^_.*'\n"); if (name) /* accept either internal or external type name */ --- 168,179 ---- /* * do not include array types (start with underscore), do not include ! * user relations (typrelid!=0) unless they are type relations */ ! appendPQExpBuffer(&buf, "FROM pg_type t\nWHERE (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"); if (name) /* accept either internal or external type name */ Index: src/include/catalog/pg_class.h =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/include/catalog/pg_class.h,v retrieving revision 1.70 diff -c -r1.70 pg_class.h *** src/include/catalog/pg_class.h 2 Aug 2002 18:15:09 -0000 1.70 --- src/include/catalog/pg_class.h 8 Aug 2002 14:49:59 -0000 *************** *** 169,173 **** --- 169,174 ---- #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 */ Index: src/include/commands/defrem.h =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/include/commands/defrem.h,v retrieving revision 1.43 diff -c -r1.43 defrem.h *** src/include/commands/defrem.h 29 Jul 2002 22:14:11 -0000 1.43 --- src/include/commands/defrem.h 8 Aug 2002 14:49:59 -0000 *************** *** 58,63 **** --- 58,64 ---- 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); Index: src/include/nodes/nodes.h =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/include/nodes/nodes.h,v retrieving revision 1.114 diff -c -r1.114 nodes.h *** src/include/nodes/nodes.h 29 Jul 2002 22:14:11 -0000 1.114 --- src/include/nodes/nodes.h 8 Aug 2002 14:49:59 -0000 *************** *** 238,243 **** --- 238,244 ---- T_PrivTarget, T_InsertDefault, T_CreateOpClassItem, + T_CompositeTypeStmt, /* * TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h) Index: src/include/nodes/parsenodes.h =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/include/nodes/parsenodes.h,v retrieving revision 1.198 diff -c -r1.198 parsenodes.h *** src/include/nodes/parsenodes.h 4 Aug 2002 19:48:10 -0000 1.198 --- src/include/nodes/parsenodes.h 8 Aug 2002 14:49:59 -0000 *************** *** 1402,1407 **** --- 1402,1419 ---- } 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 * ---------------------- */ Index: src/pl/plpgsql/src/pl_comp.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/pl/plpgsql/src/pl_comp.c,v retrieving revision 1.44 diff -c -r1.44 pl_comp.c *** src/pl/plpgsql/src/pl_comp.c 8 Aug 2002 01:36:04 -0000 1.44 --- src/pl/plpgsql/src/pl_comp.c 8 Aug 2002 14:50:00 -0000 *************** *** 1030,1041 **** } /* ! * It must be a relation, sequence or view */ classStruct = (Form_pg_class) GETSTRUCT(classtup); if (classStruct->relkind != RELKIND_RELATION && classStruct->relkind != RELKIND_SEQUENCE && ! classStruct->relkind != RELKIND_VIEW) { ReleaseSysCache(classtup); pfree(cp[0]); --- 1030,1042 ---- } /* ! * 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_COMPOSITE_TYPE) { ReleaseSysCache(classtup); pfree(cp[0]); *************** *** 1130,1139 **** if (!HeapTupleIsValid(classtup)) elog(ERROR, "%s: no such class", cp[0]); classStruct = (Form_pg_class) GETSTRUCT(classtup); ! /* accept relation, sequence, or view pg_class entries */ if (classStruct->relkind != RELKIND_RELATION && classStruct->relkind != RELKIND_SEQUENCE && ! classStruct->relkind != RELKIND_VIEW) elog(ERROR, "%s isn't a table", cp[0]); /* --- 1131,1141 ---- if (!HeapTupleIsValid(classtup)) elog(ERROR, "%s: no such class", cp[0]); classStruct = (Form_pg_class) GETSTRUCT(classtup); ! /* 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_COMPOSITE_TYPE) elog(ERROR, "%s isn't a table", cp[0]); /* Index: src/test/regress/expected/create_type.out =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/test/regress/expected/create_type.out,v retrieving revision 1.4 diff -c -r1.4 create_type.out *** src/test/regress/expected/create_type.out 6 Sep 2001 02:07:42 -0000 1.4 --- src/test/regress/expected/create_type.out 8 Aug 2002 14:50:00 -0000 *************** *** 37,40 **** --- 37,53 ---- 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; Index: src/test/regress/expected/select_having.out =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/test/regress/expected/select_having.out,v retrieving revision 1.7 diff -c -r1.7 select_having.out *** src/test/regress/expected/select_having.out 26 Jun 2002 21:58:56 -0000 1.7 --- src/test/regress/expected/select_having.out 8 Aug 2002 17:48:10 -0000 *************** *** 14,20 **** INSERT INTO test_having VALUES (8, 4, 'CCCC', 'I'); INSERT INTO test_having VALUES (9, 4, 'CCCC', 'j'); SELECT b, c FROM test_having ! GROUP BY b, c HAVING count(*) = 1; b | c ---+---------- 1 | XXXX --- 14,20 ---- INSERT INTO test_having VALUES (8, 4, 'CCCC', 'I'); INSERT INTO test_having VALUES (9, 4, 'CCCC', 'j'); SELECT b, c FROM test_having ! GROUP BY b, c HAVING count(*) = 1 ORDER BY b, c; b | c ---+---------- 1 | XXXX *************** *** 23,37 **** -- HAVING is equivalent to WHERE in this case SELECT b, c FROM test_having ! GROUP BY b, c HAVING b = 3; b | c ---+---------- - 3 | BBBB 3 | bbbb (2 rows) SELECT lower(c), count(c) FROM test_having ! GROUP BY lower(c) HAVING count(*) > 2 OR min(a) = max(a); lower | count ----------+------- bbbb | 3 --- 23,37 ---- -- HAVING is equivalent to WHERE in this case SELECT b, c FROM test_having ! GROUP BY b, c HAVING b = 3 ORDER BY b, c; b | c ---+---------- 3 | bbbb + 3 | BBBB (2 rows) SELECT lower(c), count(c) FROM test_having ! GROUP BY lower(c) HAVING count(*) > 2 OR min(a) = max(a) ORDER BY lower(c); lower | count ----------+------- bbbb | 3 *************** *** 40,50 **** (3 rows) SELECT c, max(a) FROM test_having ! GROUP BY c HAVING count(*) > 2 OR min(a) = max(a); c | max ----------+----- - XXXX | 0 bbbb | 5 (2 rows) DROP TABLE test_having; --- 40,50 ---- (3 rows) SELECT c, max(a) FROM test_having ! GROUP BY c HAVING count(*) > 2 OR min(a) = max(a) ORDER BY c; c | max ----------+----- bbbb | 5 + XXXX | 0 (2 rows) DROP TABLE test_having; Index: src/test/regress/sql/create_type.sql =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/test/regress/sql/create_type.sql,v retrieving revision 1.4 diff -c -r1.4 create_type.sql *** src/test/regress/sql/create_type.sql 6 Sep 2001 02:07:42 -0000 1.4 --- src/test/regress/sql/create_type.sql 8 Aug 2002 14:50:00 -0000 *************** *** 41,44 **** --- 41,56 ---- 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; Index: src/test/regress/sql/select_having.sql =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/test/regress/sql/select_having.sql,v retrieving revision 1.7 diff -c -r1.7 select_having.sql *** src/test/regress/sql/select_having.sql 26 Jun 2002 21:58:56 -0000 1.7 --- src/test/regress/sql/select_having.sql 8 Aug 2002 17:43:02 -0000 *************** *** 16,32 **** INSERT INTO test_having VALUES (9, 4, 'CCCC', 'j'); SELECT b, c FROM test_having ! GROUP BY b, c HAVING count(*) = 1; -- HAVING is equivalent to WHERE in this case SELECT b, c FROM test_having ! GROUP BY b, c HAVING b = 3; SELECT lower(c), count(c) FROM test_having ! GROUP BY lower(c) HAVING count(*) > 2 OR min(a) = max(a); SELECT c, max(a) FROM test_having ! GROUP BY c HAVING count(*) > 2 OR min(a) = max(a); DROP TABLE test_having; --- 16,32 ---- INSERT INTO test_having VALUES (9, 4, 'CCCC', 'j'); SELECT b, c FROM test_having ! GROUP BY b, c HAVING count(*) = 1 ORDER BY b, c; -- HAVING is equivalent to WHERE in this case SELECT b, c FROM test_having ! GROUP BY b, c HAVING b = 3 ORDER BY b, c; SELECT lower(c), count(c) FROM test_having ! GROUP BY lower(c) HAVING count(*) > 2 OR min(a) = max(a) ORDER BY lower(c); SELECT c, max(a) FROM test_having ! GROUP BY c HAVING count(*) > 2 OR min(a) = max(a) ORDER BY c; DROP TABLE test_having;
Re: stand-alone composite types patch (was [HACKERS] Proposal: stand-alone composite types)
From
Tom Lane
Date:
Joe Conway <mail@joeconway.com> writes: > Shouldn't "integer" be recognized as a valid type? Not when double-quoted; you are being overzealous about quoting. regards, tom lane
Tom Lane wrote: > Joe Conway <mail@joeconway.com> writes: >>Shouldn't "integer" be recognized as a valid type? > Not when double-quoted; you are being overzealous about quoting. I figured that out (new patch works "correctly"), but it does seem inconsistent: test=# create table tbl_0 (f1 "integer"); ERROR: Type "integer" does not exist test=# create table "tbl_0" ("f1" integer); CREATE TABLE test=# select * from tbl_0 ; f1 ---- (0 rows) test=# select f1 from tbl_0 ; f1 ---- (0 rows) test=# select "f1" from tbl_0 ; f1 ---- (0 rows) For table and column identifiers, if they were defined in all lowercase I can either quote them, or not -- it works either way. Same for *user* defined data types: test=# CREATE TYPE myint42 ( internallength = 4, input = int4in, output = int4out, default = '42', alignment = int4, storage = plain, passedbyvalue); CREATE TYPE test=# create table "tbl_1" ("f1" myint42); CREATE TABLE test=# create table "tbl_2" ("f1" "myint42"); CREATE TABLE test=# \d tbl_2 Table "tbl_2" Column | Type | Modifiers --------+---------+----------- f1 | myint42 | But *internal* data types only work unquoted. Joe
Re: stand-alone composite types patch (was [HACKERS] Proposal: stand-alone composite types)
From
Tom Lane
Date:
Joe Conway <mail@joeconway.com> writes: > Tom Lane wrote: > Shouldn't "integer" be recognized as a valid type? >> Not when double-quoted; you are being overzealous about quoting. > I figured that out (new patch works "correctly"), but it does seem > inconsistent: Would you expect "point[]" and point[] to be the same? The actual type name is int4. int4 and "int4" act the same. Aliases like int and integer are special keywords and so are not recognized when quoted. regards, tom lane
Joe Conway wrote: > There is also a small adjustment to the expected output file for > select-having. I was getting a regression failure based on ordering of > the results, so I added ORDER BY clauses. I now see that the select-having fails differently on my PC at home from the one at work. At home I see in postgresql.conf: LC_MESSAGES = 'C' LC_MONETARY = 'C' LC_NUMERIC = 'C' LC_TIME = 'C' and at work: LC_MESSAGES = 'en_US' LC_MONETARY = 'en_US' LC_NUMERIC = 'en_US' LC_TIME = 'en_US' I have been running `make installcheck` instead of `make check`. I gather that `make installcheck` does not set LOCALE to 'C' (as make check does -- I think). Should it? Please rip the select-having pieces out of this patch when it is applied, or let me know and I'll submit another patch. Thanks, Joe
Joe Conway <mail@joeconway.com> writes: > Joe Conway wrote: >> There is also a small adjustment to the expected output file for >> select-having. I was getting a regression failure based on ordering of >> the results, so I added ORDER BY clauses. > I now see that the select-having fails differently on my PC at home from > the one at work. At home I see in postgresql.conf: > LC_MESSAGES = 'C' > LC_MONETARY = 'C' > LC_NUMERIC = 'C' > LC_TIME = 'C' > and at work: > LC_MESSAGES = 'en_US' > LC_MONETARY = 'en_US' > LC_NUMERIC = 'en_US' > LC_TIME = 'en_US' > I have been running `make installcheck` instead of `make check`. I > gather that `make installcheck` does not set LOCALE to 'C' (as make > check does -- I think). Should it? The problem is that LC_COLLATE is (presumably) also en_US at work; "make installcheck" hasn't got any way of changing the collation of the preinstalled server, because that was frozen at initdb. See the discussion in the regression-test documentation. regards, tom lane
Your patch has been added to the PostgreSQL unapplied patches list at: http://candle.pha.pa.us/cgi-bin/pgpatches I will try to apply it within the next 48 hours. --------------------------------------------------------------------------- Joe Conway wrote: > Tom Lane wrote: > > If you did it that way then you'd not need that ugly kluge in > > RemoveType. What you'd need instead is some smarts (a kluge!?) in > > setting up the dependency. Currently that dependency is made in > > TypeCreate which doesn't know what sort of relation it's creating > > a type for. Probably the best answer is to pull that particular > > dependency out of TypeCreate, and make it (in the proper direction) > > in AddNewRelationType. > > Fixed. > > > Also, I'm not following the point of the separation between > > DefineCompositeType and DefineCompositeTypeRelation; nor do I see a need > > for a CommandCounterIncrement call in there. > > Fixed. > > > > You have missed a number of places where this new relkind ought to > > be special-cased the same way RELKIND_VIEW is --- for example > > CheckAttributeNames and AddNewAttributeTuples, since a composite type > > presumably shouldn't have system columns associated. I'd counsel > > looking at all references to RELKIND_VIEW to see which places also need > > to check for RELKIND_COMPOSITE_TYPE. > > Yup, I had missed lots of things, not the least of which was pg_dump. > New patch attached includes pg_dump, psql (\dT), docs, and regression > support. > > There is also a small adjustment to the expected output file for > select-having. I was getting a regression failure based on ordering of > the results, so I added ORDER BY clauses. > > Passes all regression tests. If no more objections, please apply. > > Thanks, > > Joe > > Index: doc/src/sgml/ref/create_type.sgml > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/doc/src/sgml/ref/create_type.sgml,v > retrieving revision 1.30 > diff -c -r1.30 create_type.sgml > *** doc/src/sgml/ref/create_type.sgml 24 Jul 2002 19:11:07 -0000 1.30 > --- doc/src/sgml/ref/create_type.sgml 8 Aug 2002 14:49:57 -0000 > *************** > *** 30,35 **** > --- 30,42 ---- > [ , 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,143 **** > --- 145,169 ---- > </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,199 **** > </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 > <replaceable class="parameter">input_function</replaceable>, which > converts the type's external representation to an internal > representation usable by the > --- 217,225 ---- > </para> > > <para> > ! 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,293 **** > --- 314,327 ---- > <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,375 **** > --- 404,418 ---- > 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> > Index: src/backend/catalog/heap.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/catalog/heap.c,v > retrieving revision 1.219 > diff -c -r1.219 heap.c > *** src/backend/catalog/heap.c 6 Aug 2002 02:36:33 -0000 1.219 > --- src/backend/catalog/heap.c 8 Aug 2002 14:49:57 -0000 > *************** > *** 358,364 **** > * > * Skip this for a view, since it doesn't have system attributes. > */ > ! if (relkind != RELKIND_VIEW) > { > for (i = 0; i < natts; i++) > { > --- 358,364 ---- > * > * Skip this for a view, since it doesn't have system attributes. > */ > ! if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE) > { > for (i = 0; i < natts; i++) > { > *************** > *** 475,481 **** > * Skip all for a view. We don't bother with making datatype > * dependencies here, since presumably all these types are pinned. > */ > ! if (relkind != RELKIND_VIEW) > { > dpp = SysAtt; > for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++) > --- 475,481 ---- > * Skip all for a view. We don't bother with making datatype > * dependencies here, since presumably all these types are pinned. > */ > ! if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE) > { > dpp = SysAtt; > for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++) > *************** > *** 764,770 **** > /* > * We create the disk file for this relation here > */ > ! if (relkind != RELKIND_VIEW) > heap_storage_create(new_rel_desc); > > /* > --- 764,770 ---- > /* > * We create the disk file for this relation here > */ > ! if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE) > heap_storage_create(new_rel_desc); > > /* > *************** > *** 1135,1141 **** > /* > * unlink the relation's physical file and finish up. > */ > ! if (rel->rd_rel->relkind != RELKIND_VIEW) > smgrunlink(DEFAULT_SMGR, rel); > > /* > --- 1135,1142 ---- > /* > * unlink the relation's physical file and finish up. > */ > ! if (rel->rd_rel->relkind != RELKIND_VIEW && > ! rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE) > smgrunlink(DEFAULT_SMGR, rel); > > /* > Index: src/backend/catalog/namespace.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/catalog/namespace.c,v > retrieving revision 1.29 > diff -c -r1.29 namespace.c > *** src/backend/catalog/namespace.c 8 Aug 2002 01:44:30 -0000 1.29 > --- src/backend/catalog/namespace.c 8 Aug 2002 14:49:57 -0000 > *************** > *** 1578,1583 **** > --- 1578,1584 ---- > 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); > Index: src/backend/catalog/pg_type.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/catalog/pg_type.c,v > retrieving revision 1.77 > diff -c -r1.77 pg_type.c > *** src/backend/catalog/pg_type.c 5 Aug 2002 03:29:16 -0000 1.77 > --- src/backend/catalog/pg_type.c 8 Aug 2002 17:30:27 -0000 > *************** > *** 311,325 **** > > /* > * 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. > */ > if (OidIsValid(relationOid)) > { > referenced.classId = RelOid_pg_class; > referenced.objectId = relationOid; > referenced.objectSubId = 0; > ! recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); > } > > /* > --- 311,338 ---- > > /* > * If the type is a rowtype for a relation, mark it as internally > ! * 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; > ! > ! if (relkind != RELKIND_COMPOSITE_TYPE) > ! recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); > ! else > ! recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL); > } > > /* > Index: src/backend/commands/copy.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/commands/copy.c,v > retrieving revision 1.162 > diff -c -r1.162 copy.c > *** src/backend/commands/copy.c 2 Aug 2002 18:15:06 -0000 1.162 > --- src/backend/commands/copy.c 8 Aug 2002 14:49:57 -0000 > *************** > *** 398,403 **** > --- 398,406 ---- > 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)); > *************** > *** 442,447 **** > --- 445,453 ---- > { > 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", > Index: src/backend/commands/tablecmds.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/commands/tablecmds.c,v > retrieving revision 1.28 > diff -c -r1.28 tablecmds.c > *** src/backend/commands/tablecmds.c 7 Aug 2002 21:45:01 -0000 1.28 > --- src/backend/commands/tablecmds.c 8 Aug 2002 18:04:58 -0000 > *************** > *** 345,350 **** > --- 345,354 ---- > 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,3221 **** > case RELKIND_RELATION: > case RELKIND_INDEX: > case RELKIND_VIEW: > 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", > NameStr(tuple_class->relname)); > } > } > --- 3214,3226 ---- > 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, type, or sequence", > NameStr(tuple_class->relname)); > } > } > Index: src/backend/commands/typecmds.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/commands/typecmds.c,v > retrieving revision 1.8 > diff -c -r1.8 typecmds.c > *** src/backend/commands/typecmds.c 24 Jul 2002 19:11:09 -0000 1.8 > --- src/backend/commands/typecmds.c 8 Aug 2002 17:33:43 -0000 > *************** > *** 38,43 **** > --- 38,44 ---- > #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,56 **** > > static Oid findTypeIOFunction(List *procname, bool isOutput); > > - > /* > * DefineType > * Registers a new type. > --- 51,56 ---- > *************** > *** 665,668 **** > --- 665,707 ---- > } > > 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); > } > Index: src/backend/executor/execMain.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/executor/execMain.c,v > retrieving revision 1.173 > diff -c -r1.173 execMain.c > *** src/backend/executor/execMain.c 7 Aug 2002 21:45:02 -0000 1.173 > --- src/backend/executor/execMain.c 8 Aug 2002 14:49:57 -0000 > *************** > *** 786,791 **** > --- 786,795 ---- > 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)); > Index: src/backend/nodes/copyfuncs.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/copyfuncs.c,v > retrieving revision 1.200 > diff -c -r1.200 copyfuncs.c > *** src/backend/nodes/copyfuncs.c 4 Aug 2002 19:48:09 -0000 1.200 > --- src/backend/nodes/copyfuncs.c 8 Aug 2002 14:49:58 -0000 > *************** > *** 2233,2238 **** > --- 2233,2249 ---- > 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) > { > *************** > *** 2938,2943 **** > --- 2949,2957 ---- > break; > case T_TransactionStmt: > retval = _copyTransactionStmt(from); > + break; > + case T_CompositeTypeStmt: > + retval = _copyCompositeTypeStmt(from); > break; > case T_ViewStmt: > retval = _copyViewStmt(from); > Index: src/backend/nodes/equalfuncs.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/equalfuncs.c,v > retrieving revision 1.149 > diff -c -r1.149 equalfuncs.c > *** src/backend/nodes/equalfuncs.c 4 Aug 2002 23:49:59 -0000 1.149 > --- src/backend/nodes/equalfuncs.c 8 Aug 2002 14:49:58 -0000 > *************** > *** 1062,1067 **** > --- 1062,1078 ---- > } > > 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) > { > if (!equal(a->view, b->view)) > *************** > *** 2110,2115 **** > --- 2121,2129 ---- > break; > case T_TransactionStmt: > retval = _equalTransactionStmt(a, b); > + break; > + case T_CompositeTypeStmt: > + retval = _equalCompositeTypeStmt(a, b); > break; > case T_ViewStmt: > retval = _equalViewStmt(a, b); > Index: src/backend/parser/gram.y > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/parser/gram.y,v > retrieving revision 2.357 > diff -c -r2.357 gram.y > *** src/backend/parser/gram.y 6 Aug 2002 05:40:45 -0000 2.357 > --- src/backend/parser/gram.y 8 Aug 2002 14:49:58 -0000 > *************** > *** 205,211 **** > > %type <list> stmtblock, stmtmulti, > OptTableElementList, TableElementList, OptInherit, definition, > ! opt_distinct, opt_definition, func_args, > func_args_list, func_as, createfunc_opt_list > oper_argtypes, RuleActionList, RuleActionMulti, > opt_column_list, columnList, opt_name_list, > --- 205,211 ---- > > %type <list> stmtblock, stmtmulti, > OptTableElementList, TableElementList, OptInherit, definition, > ! 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, > *************** > *** 2247,2252 **** > --- 2247,2285 ---- > 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); > *************** > *** 2255,2260 **** > --- 2288,2296 ---- > n->definition = $7; > $$ = (Node *)n; > } > + ; > + > + rowdefinition: '(' TableFuncElementList ')' { $$ = $2; } > ; > > definition: '(' def_list ')' { $$ = $2; } > Index: src/backend/storage/buffer/bufmgr.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/storage/buffer/bufmgr.c,v > retrieving revision 1.128 > diff -c -r1.128 bufmgr.c > *** src/backend/storage/buffer/bufmgr.c 6 Aug 2002 02:36:34 -0000 1.128 > --- src/backend/storage/buffer/bufmgr.c 8 Aug 2002 14:49:58 -0000 > *************** > *** 1056,1061 **** > --- 1056,1063 ---- > */ > 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; > Index: src/backend/storage/smgr/smgr.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/storage/smgr/smgr.c,v > retrieving revision 1.58 > diff -c -r1.58 smgr.c > *** src/backend/storage/smgr/smgr.c 6 Aug 2002 02:36:34 -0000 1.58 > --- src/backend/storage/smgr/smgr.c 8 Aug 2002 14:49:59 -0000 > *************** > *** 263,268 **** > --- 263,270 ---- > > 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)); > Index: src/backend/tcop/postgres.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/tcop/postgres.c,v > retrieving revision 1.280 > diff -c -r1.280 postgres.c > *** src/backend/tcop/postgres.c 6 Aug 2002 05:24:04 -0000 1.280 > --- src/backend/tcop/postgres.c 8 Aug 2002 14:49:59 -0000 > *************** > *** 2264,2269 **** > --- 2264,2273 ---- > } > break; > > + case T_CompositeTypeStmt: > + tag = "CREATE TYPE"; > + break; > + > case T_ViewStmt: > tag = "CREATE VIEW"; > break; > Index: src/backend/tcop/utility.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/tcop/utility.c,v > retrieving revision 1.169 > diff -c -r1.169 utility.c > *** src/backend/tcop/utility.c 7 Aug 2002 21:45:02 -0000 1.169 > --- src/backend/tcop/utility.c 8 Aug 2002 14:49:59 -0000 > *************** > *** 70,75 **** > --- 70,76 ---- > {RELKIND_SEQUENCE, "a", "sequence", "SEQUENCE"}, > {RELKIND_VIEW, "a", "view", "VIEW"}, > {RELKIND_INDEX, "an", "index", "INDEX"}, > + {RELKIND_COMPOSITE_TYPE, "a", "type", "TYPE"}, > {'\0', "a", "???", "???"} > }; > > *************** > *** 570,575 **** > --- 571,589 ---- > DefineAggregate(stmt->defnames, stmt->definition); > break; > } > + } > + 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; > > Index: src/backend/utils/adt/tid.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/adt/tid.c,v > retrieving revision 1.32 > diff -c -r1.32 tid.c > *** src/backend/utils/adt/tid.c 16 Jul 2002 17:55:25 -0000 1.32 > --- src/backend/utils/adt/tid.c 8 Aug 2002 14:49:59 -0000 > *************** > *** 226,231 **** > --- 226,234 ---- > 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); > > *************** > *** 248,253 **** > --- 251,259 ---- > rel = heap_openrv(relrv, AccessShareLock); > 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); > Index: src/bin/pg_dump/common.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/bin/pg_dump/common.c,v > retrieving revision 1.67 > diff -c -r1.67 common.c > *** src/bin/pg_dump/common.c 30 Jul 2002 21:56:04 -0000 1.67 > --- src/bin/pg_dump/common.c 8 Aug 2002 14:49:59 -0000 > *************** > *** 215,223 **** > > for (i = 0; i < numTables; i++) > { > ! /* Sequences and views never have parents */ > if (tblinfo[i].relkind == RELKIND_SEQUENCE || > ! tblinfo[i].relkind == RELKIND_VIEW) > continue; > > /* Don't bother computing anything for non-target tables, either */ > --- 215,224 ---- > > for (i = 0; i < numTables; i++) > { > ! /* Sequences, views, and types never have parents */ > if (tblinfo[i].relkind == RELKIND_SEQUENCE || > ! tblinfo[i].relkind == RELKIND_VIEW || > ! tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE) > continue; > > /* Don't bother computing anything for non-target tables, either */ > *************** > *** 269,277 **** > > for (i = 0; i < numTables; i++) > { > ! /* Sequences and views never have parents */ > if (tblinfo[i].relkind == RELKIND_SEQUENCE || > ! tblinfo[i].relkind == RELKIND_VIEW) > continue; > > /* Don't bother computing anything for non-target tables, either */ > --- 270,279 ---- > > for (i = 0; i < numTables; i++) > { > ! /* Sequences, views, and types never have parents */ > if (tblinfo[i].relkind == RELKIND_SEQUENCE || > ! tblinfo[i].relkind == RELKIND_VIEW || > ! tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE) > continue; > > /* Don't bother computing anything for non-target tables, either */ > Index: src/bin/pg_dump/pg_dump.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/bin/pg_dump/pg_dump.c,v > retrieving revision 1.280 > diff -c -r1.280 pg_dump.c > *** src/bin/pg_dump/pg_dump.c 4 Aug 2002 05:03:29 -0000 1.280 > --- src/bin/pg_dump/pg_dump.c 8 Aug 2002 22:42:58 -0000 > *************** > *** 95,100 **** > --- 95,101 ---- > 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, > *************** > *** 1178,1183 **** > --- 1179,1188 ---- > 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; > > *************** > *** 1582,1587 **** > --- 1587,1593 ---- > int i_usename; > int i_typelem; > int i_typrelid; > + int i_typrelkind; > int i_typtype; > int i_typisdefined; > > *************** > *** 1602,1608 **** > appendPQExpBuffer(query, "SELECT pg_type.oid, typname, " > "typnamespace, " > "(select usename from pg_user where typowner = usesysid) as usename, " > ! "typelem, typrelid, typtype, typisdefined " > "FROM pg_type"); > } > else > --- 1608,1616 ---- > appendPQExpBuffer(query, "SELECT pg_type.oid, typname, " > "typnamespace, " > "(select usename from pg_user where typowner = usesysid) as usename, " > ! "typelem, typrelid, " > ! "(select relkind from pg_class where oid = typrelid) as typrelkind, " > ! "typtype, typisdefined " > "FROM pg_type"); > } > else > *************** > *** 1610,1616 **** > 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 " > "FROM pg_type"); > } > > --- 1618,1626 ---- > appendPQExpBuffer(query, "SELECT pg_type.oid, typname, " > "0::oid as typnamespace, " > "(select usename from pg_user where typowner = usesysid) as usename, " > ! "typelem, typrelid, " > ! "''::char as typrelkind, " > ! "typtype, typisdefined " > "FROM pg_type"); > } > > *************** > *** 1632,1637 **** > --- 1642,1648 ---- > 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"); > > *************** > *** 1644,1649 **** > --- 1655,1661 ---- > 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); > > /* > *************** > *** 2109,2115 **** > 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 " > --- 2121,2126 ---- > *************** > *** 2120,2125 **** > --- 2131,2137 ---- > } > 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, " > *************** > *** 2363,2368 **** > --- 2375,2384 ---- > 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; > *************** > *** 3180,3185 **** > --- 3196,3300 ---- > } > > /* > + * 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 > */ > *************** > *** 3195,3202 **** > if (!tinfo[i].typnamespace->dump) > continue; > > ! /* skip relation types */ > ! if (atooid(tinfo[i].typrelid) != 0) > continue; > > /* skip undefined placeholder types */ > --- 3310,3317 ---- > if (!tinfo[i].typnamespace->dump) > continue; > > ! /* skip relation types for non-stand-alone type relations*/ > ! if (atooid(tinfo[i].typrelid) != 0 && tinfo[i].typrelkind != 'c') > continue; > > /* skip undefined placeholder types */ > *************** > *** 3214,3219 **** > --- 3329,3336 ---- > finfo, numFuncs, tinfo, numTypes); > else if (tinfo[i].typtype == 'd') > dumpOneDomain(fout, &tinfo[i]); > + else if (tinfo[i].typtype == 'c') > + dumpOneCompositeType(fout, &tinfo[i]); > } > } > > *************** > *** 4839,4844 **** > --- 4956,4962 ---- > > if (tbinfo->relkind != RELKIND_SEQUENCE) > continue; > + > if (tbinfo->dump) > { > dumpOneSequence(fout, tbinfo, schemaOnly, dataOnly); > *************** > *** 4854,4859 **** > --- 4972,4979 ---- > TableInfo *tbinfo = &tblinfo[i]; > > if (tbinfo->relkind == RELKIND_SEQUENCE) /* already dumped */ > + continue; > + if (tbinfo->relkind == RELKIND_COMPOSITE_TYPE) /* dumped as a type */ > continue; > > if (tbinfo->dump) > Index: src/bin/pg_dump/pg_dump.h > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/bin/pg_dump/pg_dump.h,v > retrieving revision 1.94 > diff -c -r1.94 pg_dump.h > *** src/bin/pg_dump/pg_dump.h 2 Aug 2002 18:15:08 -0000 1.94 > --- src/bin/pg_dump/pg_dump.h 8 Aug 2002 18:26:11 -0000 > *************** > *** 47,52 **** > --- 47,53 ---- > 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 */ > Index: src/bin/psql/describe.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/bin/psql/describe.c,v > retrieving revision 1.57 > diff -c -r1.57 describe.c > *** src/bin/psql/describe.c 2 Aug 2002 18:15:08 -0000 1.57 > --- src/bin/psql/describe.c 8 Aug 2002 22:26:38 -0000 > *************** > *** 168,176 **** > > /* > * do not include array types (start with underscore), do not include > ! * user relations (typrelid!=0) > */ > ! appendPQExpBuffer(&buf, "FROM pg_type t\nWHERE t.typrelid = 0 AND t.typname !~ '^_.*'\n"); > > if (name) > /* accept either internal or external type name */ > --- 168,179 ---- > > /* > * do not include array types (start with underscore), do not include > ! * user relations (typrelid!=0) unless they are type relations > */ > ! appendPQExpBuffer(&buf, "FROM pg_type t\nWHERE (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"); > > if (name) > /* accept either internal or external type name */ > Index: src/include/catalog/pg_class.h > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/include/catalog/pg_class.h,v > retrieving revision 1.70 > diff -c -r1.70 pg_class.h > *** src/include/catalog/pg_class.h 2 Aug 2002 18:15:09 -0000 1.70 > --- src/include/catalog/pg_class.h 8 Aug 2002 14:49:59 -0000 > *************** > *** 169,173 **** > --- 169,174 ---- > #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 */ > Index: src/include/commands/defrem.h > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/include/commands/defrem.h,v > retrieving revision 1.43 > diff -c -r1.43 defrem.h > *** src/include/commands/defrem.h 29 Jul 2002 22:14:11 -0000 1.43 > --- src/include/commands/defrem.h 8 Aug 2002 14:49:59 -0000 > *************** > *** 58,63 **** > --- 58,64 ---- > 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); > Index: src/include/nodes/nodes.h > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/include/nodes/nodes.h,v > retrieving revision 1.114 > diff -c -r1.114 nodes.h > *** src/include/nodes/nodes.h 29 Jul 2002 22:14:11 -0000 1.114 > --- src/include/nodes/nodes.h 8 Aug 2002 14:49:59 -0000 > *************** > *** 238,243 **** > --- 238,244 ---- > T_PrivTarget, > T_InsertDefault, > T_CreateOpClassItem, > + T_CompositeTypeStmt, > > /* > * TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h) > Index: src/include/nodes/parsenodes.h > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/include/nodes/parsenodes.h,v > retrieving revision 1.198 > diff -c -r1.198 parsenodes.h > *** src/include/nodes/parsenodes.h 4 Aug 2002 19:48:10 -0000 1.198 > --- src/include/nodes/parsenodes.h 8 Aug 2002 14:49:59 -0000 > *************** > *** 1402,1407 **** > --- 1402,1419 ---- > } 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 > * ---------------------- > */ > Index: src/pl/plpgsql/src/pl_comp.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/pl/plpgsql/src/pl_comp.c,v > retrieving revision 1.44 > diff -c -r1.44 pl_comp.c > *** src/pl/plpgsql/src/pl_comp.c 8 Aug 2002 01:36:04 -0000 1.44 > --- src/pl/plpgsql/src/pl_comp.c 8 Aug 2002 14:50:00 -0000 > *************** > *** 1030,1041 **** > } > > /* > ! * It must be a relation, sequence or view > */ > classStruct = (Form_pg_class) GETSTRUCT(classtup); > if (classStruct->relkind != RELKIND_RELATION && > classStruct->relkind != RELKIND_SEQUENCE && > ! classStruct->relkind != RELKIND_VIEW) > { > ReleaseSysCache(classtup); > pfree(cp[0]); > --- 1030,1042 ---- > } > > /* > ! * 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_COMPOSITE_TYPE) > { > ReleaseSysCache(classtup); > pfree(cp[0]); > *************** > *** 1130,1139 **** > if (!HeapTupleIsValid(classtup)) > elog(ERROR, "%s: no such class", cp[0]); > classStruct = (Form_pg_class) GETSTRUCT(classtup); > ! /* accept relation, sequence, or view pg_class entries */ > if (classStruct->relkind != RELKIND_RELATION && > classStruct->relkind != RELKIND_SEQUENCE && > ! classStruct->relkind != RELKIND_VIEW) > elog(ERROR, "%s isn't a table", cp[0]); > > /* > --- 1131,1141 ---- > if (!HeapTupleIsValid(classtup)) > elog(ERROR, "%s: no such class", cp[0]); > classStruct = (Form_pg_class) GETSTRUCT(classtup); > ! /* 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_COMPOSITE_TYPE) > elog(ERROR, "%s isn't a table", cp[0]); > > /* > Index: src/test/regress/expected/create_type.out > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/test/regress/expected/create_type.out,v > retrieving revision 1.4 > diff -c -r1.4 create_type.out > *** src/test/regress/expected/create_type.out 6 Sep 2001 02:07:42 -0000 1.4 > --- src/test/regress/expected/create_type.out 8 Aug 2002 14:50:00 -0000 > *************** > *** 37,40 **** > --- 37,53 ---- > 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; > Index: src/test/regress/expected/select_having.out > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/test/regress/expected/select_having.out,v > retrieving revision 1.7 > diff -c -r1.7 select_having.out > *** src/test/regress/expected/select_having.out 26 Jun 2002 21:58:56 -0000 1.7 > --- src/test/regress/expected/select_having.out 8 Aug 2002 17:48:10 -0000 > *************** > *** 14,20 **** > INSERT INTO test_having VALUES (8, 4, 'CCCC', 'I'); > INSERT INTO test_having VALUES (9, 4, 'CCCC', 'j'); > SELECT b, c FROM test_having > ! GROUP BY b, c HAVING count(*) = 1; > b | c > ---+---------- > 1 | XXXX > --- 14,20 ---- > INSERT INTO test_having VALUES (8, 4, 'CCCC', 'I'); > INSERT INTO test_having VALUES (9, 4, 'CCCC', 'j'); > SELECT b, c FROM test_having > ! GROUP BY b, c HAVING count(*) = 1 ORDER BY b, c; > b | c > ---+---------- > 1 | XXXX > *************** > *** 23,37 **** > > -- HAVING is equivalent to WHERE in this case > SELECT b, c FROM test_having > ! GROUP BY b, c HAVING b = 3; > b | c > ---+---------- > - 3 | BBBB > 3 | bbbb > (2 rows) > > SELECT lower(c), count(c) FROM test_having > ! GROUP BY lower(c) HAVING count(*) > 2 OR min(a) = max(a); > lower | count > ----------+------- > bbbb | 3 > --- 23,37 ---- > > -- HAVING is equivalent to WHERE in this case > SELECT b, c FROM test_having > ! GROUP BY b, c HAVING b = 3 ORDER BY b, c; > b | c > ---+---------- > 3 | bbbb > + 3 | BBBB > (2 rows) > > SELECT lower(c), count(c) FROM test_having > ! GROUP BY lower(c) HAVING count(*) > 2 OR min(a) = max(a) ORDER BY lower(c); > lower | count > ----------+------- > bbbb | 3 > *************** > *** 40,50 **** > (3 rows) > > SELECT c, max(a) FROM test_having > ! GROUP BY c HAVING count(*) > 2 OR min(a) = max(a); > c | max > ----------+----- > - XXXX | 0 > bbbb | 5 > (2 rows) > > DROP TABLE test_having; > --- 40,50 ---- > (3 rows) > > SELECT c, max(a) FROM test_having > ! GROUP BY c HAVING count(*) > 2 OR min(a) = max(a) ORDER BY c; > c | max > ----------+----- > bbbb | 5 > + XXXX | 0 > (2 rows) > > DROP TABLE test_having; > Index: src/test/regress/sql/create_type.sql > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/test/regress/sql/create_type.sql,v > retrieving revision 1.4 > diff -c -r1.4 create_type.sql > *** src/test/regress/sql/create_type.sql 6 Sep 2001 02:07:42 -0000 1.4 > --- src/test/regress/sql/create_type.sql 8 Aug 2002 14:50:00 -0000 > *************** > *** 41,44 **** > --- 41,56 ---- > > 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; > Index: src/test/regress/sql/select_having.sql > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/test/regress/sql/select_having.sql,v > retrieving revision 1.7 > diff -c -r1.7 select_having.sql > *** src/test/regress/sql/select_having.sql 26 Jun 2002 21:58:56 -0000 1.7 > --- src/test/regress/sql/select_having.sql 8 Aug 2002 17:43:02 -0000 > *************** > *** 16,32 **** > INSERT INTO test_having VALUES (9, 4, 'CCCC', 'j'); > > SELECT b, c FROM test_having > ! GROUP BY b, c HAVING count(*) = 1; > > -- HAVING is equivalent to WHERE in this case > SELECT b, c FROM test_having > ! GROUP BY b, c HAVING b = 3; > > SELECT lower(c), count(c) FROM test_having > ! GROUP BY lower(c) HAVING count(*) > 2 OR min(a) = max(a); > > SELECT c, max(a) FROM test_having > ! GROUP BY c HAVING count(*) > 2 OR min(a) = max(a); > > DROP TABLE test_having; > > --- 16,32 ---- > INSERT INTO test_having VALUES (9, 4, 'CCCC', 'j'); > > SELECT b, c FROM test_having > ! GROUP BY b, c HAVING count(*) = 1 ORDER BY b, c; > > -- HAVING is equivalent to WHERE in this case > SELECT b, c FROM test_having > ! GROUP BY b, c HAVING b = 3 ORDER BY b, c; > > SELECT lower(c), count(c) FROM test_having > ! GROUP BY lower(c) HAVING count(*) > 2 OR min(a) = max(a) ORDER BY lower(c); > > SELECT c, max(a) FROM test_having > ! GROUP BY c HAVING count(*) > 2 OR min(a) = max(a) ORDER BY c; > > DROP TABLE test_having; > > > ---------------------------(end of broadcast)--------------------------- > TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania 19073
Bruce Momjian <pgman@candle.pha.pa.us> writes: > Your patch has been added to the PostgreSQL unapplied patches list at: >> There is also a small adjustment to the expected output file for >> select-having. I was getting a regression failure based on ordering of >> the results, so I added ORDER BY clauses. Don't forget that that part of the patch was retracted. regards, tom lane
Tom Lane wrote: > Bruce Momjian <pgman@candle.pha.pa.us> writes: > >>Your patch has been added to the PostgreSQL unapplied patches list at: > > >>>There is also a small adjustment to the expected output file for >>>select-having. I was getting a regression failure based on ordering of >>>the results, so I added ORDER BY clauses. >> > > Don't forget that that part of the patch was retracted. You should be able to simply remove the changes to: Index: src/test/regress/expected/select_having.out Index: src/test/regress/sql/select_having.sql from the patch. Or let me know if you want me to do it and resubmit. Thanks, Joe
Retracted part added. [ I hadn't noticed the retraction.] Your patch has been added to the PostgreSQL unapplied patches list at: http://candle.pha.pa.us/cgi-bin/pgpatches I will try to apply it within the next 48 hours. --------------------------------------------------------------------------- Joe Conway wrote: > Tom Lane wrote: > > Bruce Momjian <pgman@candle.pha.pa.us> writes: > > > >>Your patch has been added to the PostgreSQL unapplied patches list at: > > > > > >>>There is also a small adjustment to the expected output file for > >>>select-having. I was getting a regression failure based on ordering of > >>>the results, so I added ORDER BY clauses. > >> > > > > Don't forget that that part of the patch was retracted. > > You should be able to simply remove the changes to: > Index: src/test/regress/expected/select_having.out > Index: src/test/regress/sql/select_having.sql > from the patch. > > Or let me know if you want me to do it and resubmit. > > Thanks, > > Joe > > > -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania 19073
Sorry. this patch fails to apply. A change to catalog/heap.c doesn't seem to fit anywhere. I have attached the reject. --------------------------------------------------------------------------- Joe Conway wrote: > Tom Lane wrote: > > If you did it that way then you'd not need that ugly kluge in > > RemoveType. What you'd need instead is some smarts (a kluge!?) in > > setting up the dependency. Currently that dependency is made in > > TypeCreate which doesn't know what sort of relation it's creating > > a type for. Probably the best answer is to pull that particular > > dependency out of TypeCreate, and make it (in the proper direction) > > in AddNewRelationType. > > Fixed. > > > Also, I'm not following the point of the separation between > > DefineCompositeType and DefineCompositeTypeRelation; nor do I see a need > > for a CommandCounterIncrement call in there. > > Fixed. > > > > You have missed a number of places where this new relkind ought to > > be special-cased the same way RELKIND_VIEW is --- for example > > CheckAttributeNames and AddNewAttributeTuples, since a composite type > > presumably shouldn't have system columns associated. I'd counsel > > looking at all references to RELKIND_VIEW to see which places also need > > to check for RELKIND_COMPOSITE_TYPE. > > Yup, I had missed lots of things, not the least of which was pg_dump. > New patch attached includes pg_dump, psql (\dT), docs, and regression > support. > > There is also a small adjustment to the expected output file for > select-having. I was getting a regression failure based on ordering of > the results, so I added ORDER BY clauses. > > Passes all regression tests. If no more objections, please apply. > > Thanks, > > Joe > -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania 19073 *************** *** 764,770 **** /* * We create the disk file for this relation here */ ! if (relkind != RELKIND_VIEW) heap_storage_create(new_rel_desc); /* --- 764,770 ---- /* * We create the disk file for this relation here */ ! if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE) heap_storage_create(new_rel_desc); /*
Bruce Momjian wrote: > Sorry. this patch fails to apply. A change to catalog/heap.c doesn't > seem to fit anywhere. I have attached the reject. > Lots of code drift in just one week! I'll rework the patch and resend. Joe
Bruce Momjian <pgman@candle.pha.pa.us> writes: > [ this doesn't apply: ] > /* > * We create the disk file for this relation here > */ > ! if (relkind != RELKIND_VIEW) > heap_storage_create(new_rel_desc); > /* > --- 764,770 ---- > /* > * We create the disk file for this relation here > */ > ! if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE) > heap_storage_create(new_rel_desc); > /* There's no longer a separate call to heap_storage_create in that routine --- the right place to make the test is now in the storage_create boolean parameter being passed to heap_create. A simple change, but it passeth patch's understanding ... regards, tom lane
Tom Lane wrote: > There's no longer a separate call to heap_storage_create in that routine > --- the right place to make the test is now in the storage_create > boolean parameter being passed to heap_create. A simple change, but > it passeth patch's understanding ... Thanks. Attached is a patch against cvs tip as of 8:30 PM PST or so. Turned out that even after fixing the failed hunks, there was a new spot in bufmgr.c which needed to be fixed (related to temp relations; RelationUpdateNumberOfBlocks). But thankfully the regression test code caught it :-) Joe Index: doc/src/sgml/ref/create_type.sgml =================================================================== RCS file: /opt/src/cvs/pgsql-server/doc/src/sgml/ref/create_type.sgml,v retrieving revision 1.30 diff -c -r1.30 create_type.sgml *** doc/src/sgml/ref/create_type.sgml 24 Jul 2002 19:11:07 -0000 1.30 --- doc/src/sgml/ref/create_type.sgml 15 Aug 2002 03:06:23 -0000 *************** *** 30,35 **** --- 30,42 ---- [ , 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,143 **** --- 145,169 ---- </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,199 **** </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 <replaceable class="parameter">input_function</replaceable>, which converts the type's external representation to an internal representation usable by the --- 217,225 ---- </para> <para> ! 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,293 **** --- 314,327 ---- <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,375 **** --- 404,418 ---- 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> Index: src/backend/catalog/heap.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/catalog/heap.c,v retrieving revision 1.220 diff -c -r1.220 heap.c *** src/backend/catalog/heap.c 11 Aug 2002 21:17:34 -0000 1.220 --- src/backend/catalog/heap.c 15 Aug 2002 04:21:03 -0000 *************** *** 357,365 **** /* * first check for collision with system attribute names * ! * Skip this for a view, since it doesn't have system attributes. */ ! if (relkind != RELKIND_VIEW) { for (i = 0; i < natts; i++) { --- 357,366 ---- /* * first check for collision with system attribute names * ! * Skip this for a view and type relation, since it doesn't have system ! * attributes. */ ! if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE) { for (i = 0; i < natts; i++) { *************** *** 473,482 **** /* * 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. */ ! if (relkind != RELKIND_VIEW) { dpp = SysAtt; for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++) --- 474,483 ---- /* * Next we add the system attributes. Skip OID if rel has no OIDs. ! * 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 && relkind != RELKIND_COMPOSITE_TYPE) { dpp = SysAtt; for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++) *************** *** 689,701 **** * 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. */ new_rel_desc = heap_create(relname, relnamespace, tupdesc, shared_relation, ! (relkind != RELKIND_VIEW), allow_system_table_mods); /* Fetch the relation OID assigned by heap_create */ --- 690,703 ---- * 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 or type relation. */ new_rel_desc = heap_create(relname, relnamespace, tupdesc, shared_relation, ! (relkind != RELKIND_VIEW && ! relkind != RELKIND_COMPOSITE_TYPE), allow_system_table_mods); /* Fetch the relation OID assigned by heap_create */ *************** *** 1131,1137 **** /* * unlink the relation's physical file and finish up. */ ! if (rel->rd_rel->relkind != RELKIND_VIEW) smgrunlink(DEFAULT_SMGR, rel); /* --- 1133,1140 ---- /* * unlink the relation's physical file and finish up. */ ! if (rel->rd_rel->relkind != RELKIND_VIEW && ! rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE) smgrunlink(DEFAULT_SMGR, rel); /* Index: src/backend/catalog/namespace.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/catalog/namespace.c,v retrieving revision 1.30 diff -c -r1.30 namespace.c *** src/backend/catalog/namespace.c 9 Aug 2002 16:45:14 -0000 1.30 --- src/backend/catalog/namespace.c 15 Aug 2002 03:06:23 -0000 *************** *** 1585,1590 **** --- 1585,1591 ---- 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); Index: src/backend/catalog/pg_type.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/catalog/pg_type.c,v retrieving revision 1.77 diff -c -r1.77 pg_type.c *** src/backend/catalog/pg_type.c 5 Aug 2002 03:29:16 -0000 1.77 --- src/backend/catalog/pg_type.c 15 Aug 2002 03:06:23 -0000 *************** *** 311,325 **** /* * 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. */ if (OidIsValid(relationOid)) { referenced.classId = RelOid_pg_class; referenced.objectId = relationOid; referenced.objectSubId = 0; ! recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); } /* --- 311,338 ---- /* * If the type is a rowtype for a relation, mark it as internally ! * 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; ! ! if (relkind != RELKIND_COMPOSITE_TYPE) ! recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); ! else ! recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL); } /* Index: src/backend/commands/copy.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/commands/copy.c,v retrieving revision 1.162 diff -c -r1.162 copy.c *** src/backend/commands/copy.c 2 Aug 2002 18:15:06 -0000 1.162 --- src/backend/commands/copy.c 15 Aug 2002 03:06:23 -0000 *************** *** 398,403 **** --- 398,406 ---- 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)); *************** *** 442,447 **** --- 445,453 ---- { 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", Index: src/backend/commands/tablecmds.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/commands/tablecmds.c,v retrieving revision 1.28 diff -c -r1.28 tablecmds.c *** src/backend/commands/tablecmds.c 7 Aug 2002 21:45:01 -0000 1.28 --- src/backend/commands/tablecmds.c 15 Aug 2002 03:06:23 -0000 *************** *** 345,350 **** --- 345,354 ---- 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,3221 **** case RELKIND_RELATION: case RELKIND_INDEX: case RELKIND_VIEW: 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", NameStr(tuple_class->relname)); } } --- 3214,3226 ---- 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, type, or sequence", NameStr(tuple_class->relname)); } } Index: src/backend/commands/typecmds.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/commands/typecmds.c,v retrieving revision 1.8 diff -c -r1.8 typecmds.c *** src/backend/commands/typecmds.c 24 Jul 2002 19:11:09 -0000 1.8 --- src/backend/commands/typecmds.c 15 Aug 2002 03:06:23 -0000 *************** *** 38,43 **** --- 38,44 ---- #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,56 **** static Oid findTypeIOFunction(List *procname, bool isOutput); - /* * DefineType * Registers a new type. --- 51,56 ---- *************** *** 665,668 **** --- 665,707 ---- } 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); } Index: src/backend/executor/execMain.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/executor/execMain.c,v retrieving revision 1.173 diff -c -r1.173 execMain.c *** src/backend/executor/execMain.c 7 Aug 2002 21:45:02 -0000 1.173 --- src/backend/executor/execMain.c 15 Aug 2002 03:06:23 -0000 *************** *** 786,791 **** --- 786,795 ---- 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)); Index: src/backend/nodes/copyfuncs.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/copyfuncs.c,v retrieving revision 1.200 diff -c -r1.200 copyfuncs.c *** src/backend/nodes/copyfuncs.c 4 Aug 2002 19:48:09 -0000 1.200 --- src/backend/nodes/copyfuncs.c 15 Aug 2002 03:06:23 -0000 *************** *** 2233,2238 **** --- 2233,2249 ---- 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) { *************** *** 2938,2943 **** --- 2949,2957 ---- break; case T_TransactionStmt: retval = _copyTransactionStmt(from); + break; + case T_CompositeTypeStmt: + retval = _copyCompositeTypeStmt(from); break; case T_ViewStmt: retval = _copyViewStmt(from); Index: src/backend/nodes/equalfuncs.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/equalfuncs.c,v retrieving revision 1.149 diff -c -r1.149 equalfuncs.c *** src/backend/nodes/equalfuncs.c 4 Aug 2002 23:49:59 -0000 1.149 --- src/backend/nodes/equalfuncs.c 15 Aug 2002 03:06:23 -0000 *************** *** 1062,1067 **** --- 1062,1078 ---- } 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) { if (!equal(a->view, b->view)) *************** *** 2110,2115 **** --- 2121,2129 ---- break; case T_TransactionStmt: retval = _equalTransactionStmt(a, b); + break; + case T_CompositeTypeStmt: + retval = _equalCompositeTypeStmt(a, b); break; case T_ViewStmt: retval = _equalViewStmt(a, b); Index: src/backend/parser/gram.y =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/parser/gram.y,v retrieving revision 2.358 diff -c -r2.358 gram.y *** src/backend/parser/gram.y 10 Aug 2002 19:01:53 -0000 2.358 --- src/backend/parser/gram.y 15 Aug 2002 03:06:23 -0000 *************** *** 205,211 **** %type <list> stmtblock, stmtmulti, OptTableElementList, TableElementList, OptInherit, definition, ! opt_distinct, opt_definition, func_args, func_args_list, func_as, createfunc_opt_list oper_argtypes, RuleActionList, RuleActionMulti, opt_column_list, columnList, opt_name_list, --- 205,211 ---- %type <list> stmtblock, stmtmulti, OptTableElementList, TableElementList, OptInherit, definition, ! 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,2238 **** --- 2233,2271 ---- 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); *************** *** 2241,2246 **** --- 2274,2282 ---- n->definition = $7; $$ = (Node *)n; } + ; + + rowdefinition: '(' TableFuncElementList ')' { $$ = $2; } ; definition: '(' def_list ')' { $$ = $2; } Index: src/backend/storage/buffer/bufmgr.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/storage/buffer/bufmgr.c,v retrieving revision 1.129 diff -c -r1.129 bufmgr.c *** src/backend/storage/buffer/bufmgr.c 11 Aug 2002 21:17:34 -0000 1.129 --- src/backend/storage/buffer/bufmgr.c 15 Aug 2002 04:47:07 -0000 *************** *** 1051,1056 **** --- 1051,1058 ---- */ 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; *************** *** 1068,1073 **** --- 1070,1077 ---- 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); Index: src/backend/storage/smgr/smgr.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/storage/smgr/smgr.c,v retrieving revision 1.58 diff -c -r1.58 smgr.c *** src/backend/storage/smgr/smgr.c 6 Aug 2002 02:36:34 -0000 1.58 --- src/backend/storage/smgr/smgr.c 15 Aug 2002 03:06:23 -0000 *************** *** 263,268 **** --- 263,270 ---- 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)); Index: src/backend/tcop/postgres.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/tcop/postgres.c,v retrieving revision 1.281 diff -c -r1.281 postgres.c *** src/backend/tcop/postgres.c 10 Aug 2002 20:29:18 -0000 1.281 --- src/backend/tcop/postgres.c 15 Aug 2002 03:06:23 -0000 *************** *** 2233,2238 **** --- 2233,2242 ---- } break; + case T_CompositeTypeStmt: + tag = "CREATE TYPE"; + break; + case T_ViewStmt: tag = "CREATE VIEW"; break; Index: src/backend/tcop/utility.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/tcop/utility.c,v retrieving revision 1.169 diff -c -r1.169 utility.c *** src/backend/tcop/utility.c 7 Aug 2002 21:45:02 -0000 1.169 --- src/backend/tcop/utility.c 15 Aug 2002 03:06:23 -0000 *************** *** 70,75 **** --- 70,76 ---- {RELKIND_SEQUENCE, "a", "sequence", "SEQUENCE"}, {RELKIND_VIEW, "a", "view", "VIEW"}, {RELKIND_INDEX, "an", "index", "INDEX"}, + {RELKIND_COMPOSITE_TYPE, "a", "type", "TYPE"}, {'\0', "a", "???", "???"} }; *************** *** 570,575 **** --- 571,589 ---- DefineAggregate(stmt->defnames, stmt->definition); break; } + } + 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; Index: src/backend/utils/adt/tid.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/adt/tid.c,v retrieving revision 1.32 diff -c -r1.32 tid.c *** src/backend/utils/adt/tid.c 16 Jul 2002 17:55:25 -0000 1.32 --- src/backend/utils/adt/tid.c 15 Aug 2002 03:06:23 -0000 *************** *** 226,231 **** --- 226,234 ---- 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); *************** *** 248,253 **** --- 251,259 ---- rel = heap_openrv(relrv, AccessShareLock); 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); Index: src/bin/pg_dump/common.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/bin/pg_dump/common.c,v retrieving revision 1.67 diff -c -r1.67 common.c *** src/bin/pg_dump/common.c 30 Jul 2002 21:56:04 -0000 1.67 --- src/bin/pg_dump/common.c 15 Aug 2002 03:06:23 -0000 *************** *** 215,223 **** for (i = 0; i < numTables; i++) { ! /* Sequences and views never have parents */ if (tblinfo[i].relkind == RELKIND_SEQUENCE || ! tblinfo[i].relkind == RELKIND_VIEW) continue; /* Don't bother computing anything for non-target tables, either */ --- 215,224 ---- for (i = 0; i < numTables; i++) { ! /* Sequences, views, and types never have parents */ if (tblinfo[i].relkind == RELKIND_SEQUENCE || ! tblinfo[i].relkind == RELKIND_VIEW || ! tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE) continue; /* Don't bother computing anything for non-target tables, either */ *************** *** 269,277 **** for (i = 0; i < numTables; i++) { ! /* Sequences and views never have parents */ if (tblinfo[i].relkind == RELKIND_SEQUENCE || ! tblinfo[i].relkind == RELKIND_VIEW) continue; /* Don't bother computing anything for non-target tables, either */ --- 270,279 ---- for (i = 0; i < numTables; i++) { ! /* Sequences, views, and types never have parents */ if (tblinfo[i].relkind == RELKIND_SEQUENCE || ! tblinfo[i].relkind == RELKIND_VIEW || ! tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE) continue; /* Don't bother computing anything for non-target tables, either */ Index: src/bin/pg_dump/pg_dump.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/bin/pg_dump/pg_dump.c,v retrieving revision 1.281 diff -c -r1.281 pg_dump.c *** src/bin/pg_dump/pg_dump.c 10 Aug 2002 16:57:31 -0000 1.281 --- src/bin/pg_dump/pg_dump.c 15 Aug 2002 03:06:23 -0000 *************** *** 95,100 **** --- 95,101 ---- 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,1176 **** --- 1172,1181 ---- 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,1580 **** --- 1580,1586 ---- int i_usename; int i_typelem; int i_typrelid; + int i_typrelkind; int i_typtype; int i_typisdefined; *************** *** 1595,1601 **** appendPQExpBuffer(query, "SELECT pg_type.oid, typname, " "typnamespace, " "(select usename from pg_user where typowner = usesysid) as usename, " ! "typelem, typrelid, typtype, typisdefined " "FROM pg_type"); } else --- 1601,1609 ---- appendPQExpBuffer(query, "SELECT pg_type.oid, typname, " "typnamespace, " "(select usename from pg_user where typowner = usesysid) as usename, " ! "typelem, typrelid, " ! "(select relkind from pg_class where oid = typrelid) as typrelkind, " ! "typtype, typisdefined " "FROM pg_type"); } else *************** *** 1603,1609 **** 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 " "FROM pg_type"); } --- 1611,1619 ---- appendPQExpBuffer(query, "SELECT pg_type.oid, typname, " "0::oid as typnamespace, " "(select usename from pg_user where typowner = usesysid) as usename, " ! "typelem, typrelid, " ! "''::char as typrelkind, " ! "typtype, typisdefined " "FROM pg_type"); } *************** *** 1625,1630 **** --- 1635,1641 ---- 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,1642 **** --- 1648,1654 ---- 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,2108 **** 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 " --- 2114,2119 ---- *************** *** 2113,2118 **** --- 2124,2130 ---- } 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,2361 **** --- 2368,2377 ---- 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; *************** *** 3173,3178 **** --- 3189,3293 ---- } /* + * 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,3195 **** if (!tinfo[i].typnamespace->dump) continue; ! /* skip relation types */ ! if (atooid(tinfo[i].typrelid) != 0) continue; /* skip undefined placeholder types */ --- 3303,3310 ---- if (!tinfo[i].typnamespace->dump) continue; ! /* 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,3212 **** --- 3322,3329 ---- 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,4837 **** --- 4949,4955 ---- if (tbinfo->relkind != RELKIND_SEQUENCE) continue; + if (tbinfo->dump) { dumpOneSequence(fout, tbinfo, schemaOnly, dataOnly); *************** *** 4847,4852 **** --- 4965,4972 ---- TableInfo *tbinfo = &tblinfo[i]; if (tbinfo->relkind == RELKIND_SEQUENCE) /* already dumped */ + continue; + if (tbinfo->relkind == RELKIND_COMPOSITE_TYPE) /* dumped as a type */ continue; if (tbinfo->dump) Index: src/bin/pg_dump/pg_dump.h =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/bin/pg_dump/pg_dump.h,v retrieving revision 1.94 diff -c -r1.94 pg_dump.h *** src/bin/pg_dump/pg_dump.h 2 Aug 2002 18:15:08 -0000 1.94 --- src/bin/pg_dump/pg_dump.h 15 Aug 2002 03:06:23 -0000 *************** *** 47,52 **** --- 47,53 ---- 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 */ Index: src/bin/psql/describe.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/bin/psql/describe.c,v retrieving revision 1.60 diff -c -r1.60 describe.c *** src/bin/psql/describe.c 10 Aug 2002 16:01:16 -0000 1.60 --- src/bin/psql/describe.c 15 Aug 2002 04:14:09 -0000 *************** *** 210,218 **** /* * do not include array types (start with underscore), do not include ! * user relations (typrelid!=0) */ ! appendPQExpBuffer(&buf, "WHERE t.typrelid = 0 AND t.typname !~ '^_'\n"); /* Match name pattern against either internal or external name */ processNamePattern(&buf, pattern, true, false, --- 210,221 ---- /* * do not include array types (start with underscore), do not include ! * user relations (typrelid!=0) unless they are type relations */ ! 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, Index: src/include/catalog/pg_class.h =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/include/catalog/pg_class.h,v retrieving revision 1.70 diff -c -r1.70 pg_class.h *** src/include/catalog/pg_class.h 2 Aug 2002 18:15:09 -0000 1.70 --- src/include/catalog/pg_class.h 15 Aug 2002 03:06:23 -0000 *************** *** 169,173 **** --- 169,174 ---- #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 */ Index: src/include/commands/defrem.h =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/include/commands/defrem.h,v retrieving revision 1.43 diff -c -r1.43 defrem.h *** src/include/commands/defrem.h 29 Jul 2002 22:14:11 -0000 1.43 --- src/include/commands/defrem.h 15 Aug 2002 03:06:23 -0000 *************** *** 58,63 **** --- 58,64 ---- 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); Index: src/include/nodes/nodes.h =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/include/nodes/nodes.h,v retrieving revision 1.114 diff -c -r1.114 nodes.h *** src/include/nodes/nodes.h 29 Jul 2002 22:14:11 -0000 1.114 --- src/include/nodes/nodes.h 15 Aug 2002 03:06:23 -0000 *************** *** 238,243 **** --- 238,244 ---- T_PrivTarget, T_InsertDefault, T_CreateOpClassItem, + T_CompositeTypeStmt, /* * TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h) Index: src/include/nodes/parsenodes.h =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/include/nodes/parsenodes.h,v retrieving revision 1.198 diff -c -r1.198 parsenodes.h *** src/include/nodes/parsenodes.h 4 Aug 2002 19:48:10 -0000 1.198 --- src/include/nodes/parsenodes.h 15 Aug 2002 03:06:23 -0000 *************** *** 1402,1407 **** --- 1402,1419 ---- } 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 * ---------------------- */ Index: src/pl/plpgsql/src/pl_comp.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/pl/plpgsql/src/pl_comp.c,v retrieving revision 1.45 diff -c -r1.45 pl_comp.c *** src/pl/plpgsql/src/pl_comp.c 12 Aug 2002 14:25:07 -0000 1.45 --- src/pl/plpgsql/src/pl_comp.c 15 Aug 2002 04:02:53 -0000 *************** *** 1028,1039 **** } /* ! * It must be a relation, sequence or view */ classStruct = (Form_pg_class) GETSTRUCT(classtup); if (classStruct->relkind != RELKIND_RELATION && classStruct->relkind != RELKIND_SEQUENCE && ! classStruct->relkind != RELKIND_VIEW) { ReleaseSysCache(classtup); pfree(cp[0]); --- 1028,1040 ---- } /* ! * 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_COMPOSITE_TYPE) { ReleaseSysCache(classtup); pfree(cp[0]); *************** *** 1145,1154 **** classStruct = (Form_pg_class) GETSTRUCT(classtup); relname = NameStr(classStruct->relname); ! /* accept relation, sequence, or view pg_class entries */ if (classStruct->relkind != RELKIND_RELATION && classStruct->relkind != RELKIND_SEQUENCE && ! classStruct->relkind != RELKIND_VIEW) elog(ERROR, "%s isn't a table", relname); /* --- 1146,1156 ---- classStruct = (Form_pg_class) GETSTRUCT(classtup); relname = NameStr(classStruct->relname); ! /* 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_COMPOSITE_TYPE) elog(ERROR, "%s isn't a table", relname); /* Index: src/test/regress/expected/create_type.out =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/test/regress/expected/create_type.out,v retrieving revision 1.4 diff -c -r1.4 create_type.out *** src/test/regress/expected/create_type.out 6 Sep 2001 02:07:42 -0000 1.4 --- src/test/regress/expected/create_type.out 15 Aug 2002 03:06:23 -0000 *************** *** 37,40 **** --- 37,53 ---- 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; Index: src/test/regress/sql/create_type.sql =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/test/regress/sql/create_type.sql,v retrieving revision 1.4 diff -c -r1.4 create_type.sql *** src/test/regress/sql/create_type.sql 6 Sep 2001 02:07:42 -0000 1.4 --- src/test/regress/sql/create_type.sql 15 Aug 2002 03:06:23 -0000 *************** *** 41,44 **** --- 41,56 ---- 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;
Patch applied. Thanks. --------------------------------------------------------------------------- Joe Conway wrote: > Tom Lane wrote: > > There's no longer a separate call to heap_storage_create in that routine > > --- the right place to make the test is now in the storage_create > > boolean parameter being passed to heap_create. A simple change, but > > it passeth patch's understanding ... > > Thanks. > > Attached is a patch against cvs tip as of 8:30 PM PST or so. Turned out > that even after fixing the failed hunks, there was a new spot in > bufmgr.c which needed to be fixed (related to temp relations; > RelationUpdateNumberOfBlocks). But thankfully the regression test code > caught it :-) > > Joe > > Index: doc/src/sgml/ref/create_type.sgml > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/doc/src/sgml/ref/create_type.sgml,v > retrieving revision 1.30 > diff -c -r1.30 create_type.sgml > *** doc/src/sgml/ref/create_type.sgml 24 Jul 2002 19:11:07 -0000 1.30 > --- doc/src/sgml/ref/create_type.sgml 15 Aug 2002 03:06:23 -0000 > *************** > *** 30,35 **** > --- 30,42 ---- > [ , 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,143 **** > --- 145,169 ---- > </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,199 **** > </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 > <replaceable class="parameter">input_function</replaceable>, which > converts the type's external representation to an internal > representation usable by the > --- 217,225 ---- > </para> > > <para> > ! 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,293 **** > --- 314,327 ---- > <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,375 **** > --- 404,418 ---- > 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> > Index: src/backend/catalog/heap.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/catalog/heap.c,v > retrieving revision 1.220 > diff -c -r1.220 heap.c > *** src/backend/catalog/heap.c 11 Aug 2002 21:17:34 -0000 1.220 > --- src/backend/catalog/heap.c 15 Aug 2002 04:21:03 -0000 > *************** > *** 357,365 **** > /* > * first check for collision with system attribute names > * > ! * Skip this for a view, since it doesn't have system attributes. > */ > ! if (relkind != RELKIND_VIEW) > { > for (i = 0; i < natts; i++) > { > --- 357,366 ---- > /* > * first check for collision with system attribute names > * > ! * Skip this for a view and type relation, since it doesn't have system > ! * attributes. > */ > ! if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE) > { > for (i = 0; i < natts; i++) > { > *************** > *** 473,482 **** > > /* > * 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. > */ > ! if (relkind != RELKIND_VIEW) > { > dpp = SysAtt; > for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++) > --- 474,483 ---- > > /* > * Next we add the system attributes. Skip OID if rel has no OIDs. > ! * 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 && relkind != RELKIND_COMPOSITE_TYPE) > { > dpp = SysAtt; > for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++) > *************** > *** 689,701 **** > * 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. > */ > new_rel_desc = heap_create(relname, > relnamespace, > tupdesc, > shared_relation, > ! (relkind != RELKIND_VIEW), > allow_system_table_mods); > > /* Fetch the relation OID assigned by heap_create */ > --- 690,703 ---- > * 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 or type relation. > */ > new_rel_desc = heap_create(relname, > relnamespace, > tupdesc, > shared_relation, > ! (relkind != RELKIND_VIEW && > ! relkind != RELKIND_COMPOSITE_TYPE), > allow_system_table_mods); > > /* Fetch the relation OID assigned by heap_create */ > *************** > *** 1131,1137 **** > /* > * unlink the relation's physical file and finish up. > */ > ! if (rel->rd_rel->relkind != RELKIND_VIEW) > smgrunlink(DEFAULT_SMGR, rel); > > /* > --- 1133,1140 ---- > /* > * unlink the relation's physical file and finish up. > */ > ! if (rel->rd_rel->relkind != RELKIND_VIEW && > ! rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE) > smgrunlink(DEFAULT_SMGR, rel); > > /* > Index: src/backend/catalog/namespace.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/catalog/namespace.c,v > retrieving revision 1.30 > diff -c -r1.30 namespace.c > *** src/backend/catalog/namespace.c 9 Aug 2002 16:45:14 -0000 1.30 > --- src/backend/catalog/namespace.c 15 Aug 2002 03:06:23 -0000 > *************** > *** 1585,1590 **** > --- 1585,1591 ---- > 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); > Index: src/backend/catalog/pg_type.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/catalog/pg_type.c,v > retrieving revision 1.77 > diff -c -r1.77 pg_type.c > *** src/backend/catalog/pg_type.c 5 Aug 2002 03:29:16 -0000 1.77 > --- src/backend/catalog/pg_type.c 15 Aug 2002 03:06:23 -0000 > *************** > *** 311,325 **** > > /* > * 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. > */ > if (OidIsValid(relationOid)) > { > referenced.classId = RelOid_pg_class; > referenced.objectId = relationOid; > referenced.objectSubId = 0; > ! recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); > } > > /* > --- 311,338 ---- > > /* > * If the type is a rowtype for a relation, mark it as internally > ! * 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; > ! > ! if (relkind != RELKIND_COMPOSITE_TYPE) > ! recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); > ! else > ! recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL); > } > > /* > Index: src/backend/commands/copy.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/commands/copy.c,v > retrieving revision 1.162 > diff -c -r1.162 copy.c > *** src/backend/commands/copy.c 2 Aug 2002 18:15:06 -0000 1.162 > --- src/backend/commands/copy.c 15 Aug 2002 03:06:23 -0000 > *************** > *** 398,403 **** > --- 398,406 ---- > 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)); > *************** > *** 442,447 **** > --- 445,453 ---- > { > 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", > Index: src/backend/commands/tablecmds.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/commands/tablecmds.c,v > retrieving revision 1.28 > diff -c -r1.28 tablecmds.c > *** src/backend/commands/tablecmds.c 7 Aug 2002 21:45:01 -0000 1.28 > --- src/backend/commands/tablecmds.c 15 Aug 2002 03:06:23 -0000 > *************** > *** 345,350 **** > --- 345,354 ---- > 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,3221 **** > case RELKIND_RELATION: > case RELKIND_INDEX: > case RELKIND_VIEW: > 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", > NameStr(tuple_class->relname)); > } > } > --- 3214,3226 ---- > 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, type, or sequence", > NameStr(tuple_class->relname)); > } > } > Index: src/backend/commands/typecmds.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/commands/typecmds.c,v > retrieving revision 1.8 > diff -c -r1.8 typecmds.c > *** src/backend/commands/typecmds.c 24 Jul 2002 19:11:09 -0000 1.8 > --- src/backend/commands/typecmds.c 15 Aug 2002 03:06:23 -0000 > *************** > *** 38,43 **** > --- 38,44 ---- > #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,56 **** > > static Oid findTypeIOFunction(List *procname, bool isOutput); > > - > /* > * DefineType > * Registers a new type. > --- 51,56 ---- > *************** > *** 665,668 **** > --- 665,707 ---- > } > > 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); > } > Index: src/backend/executor/execMain.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/executor/execMain.c,v > retrieving revision 1.173 > diff -c -r1.173 execMain.c > *** src/backend/executor/execMain.c 7 Aug 2002 21:45:02 -0000 1.173 > --- src/backend/executor/execMain.c 15 Aug 2002 03:06:23 -0000 > *************** > *** 786,791 **** > --- 786,795 ---- > 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)); > Index: src/backend/nodes/copyfuncs.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/copyfuncs.c,v > retrieving revision 1.200 > diff -c -r1.200 copyfuncs.c > *** src/backend/nodes/copyfuncs.c 4 Aug 2002 19:48:09 -0000 1.200 > --- src/backend/nodes/copyfuncs.c 15 Aug 2002 03:06:23 -0000 > *************** > *** 2233,2238 **** > --- 2233,2249 ---- > 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) > { > *************** > *** 2938,2943 **** > --- 2949,2957 ---- > break; > case T_TransactionStmt: > retval = _copyTransactionStmt(from); > + break; > + case T_CompositeTypeStmt: > + retval = _copyCompositeTypeStmt(from); > break; > case T_ViewStmt: > retval = _copyViewStmt(from); > Index: src/backend/nodes/equalfuncs.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/equalfuncs.c,v > retrieving revision 1.149 > diff -c -r1.149 equalfuncs.c > *** src/backend/nodes/equalfuncs.c 4 Aug 2002 23:49:59 -0000 1.149 > --- src/backend/nodes/equalfuncs.c 15 Aug 2002 03:06:23 -0000 > *************** > *** 1062,1067 **** > --- 1062,1078 ---- > } > > 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) > { > if (!equal(a->view, b->view)) > *************** > *** 2110,2115 **** > --- 2121,2129 ---- > break; > case T_TransactionStmt: > retval = _equalTransactionStmt(a, b); > + break; > + case T_CompositeTypeStmt: > + retval = _equalCompositeTypeStmt(a, b); > break; > case T_ViewStmt: > retval = _equalViewStmt(a, b); > Index: src/backend/parser/gram.y > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/parser/gram.y,v > retrieving revision 2.358 > diff -c -r2.358 gram.y > *** src/backend/parser/gram.y 10 Aug 2002 19:01:53 -0000 2.358 > --- src/backend/parser/gram.y 15 Aug 2002 03:06:23 -0000 > *************** > *** 205,211 **** > > %type <list> stmtblock, stmtmulti, > OptTableElementList, TableElementList, OptInherit, definition, > ! opt_distinct, opt_definition, func_args, > func_args_list, func_as, createfunc_opt_list > oper_argtypes, RuleActionList, RuleActionMulti, > opt_column_list, columnList, opt_name_list, > --- 205,211 ---- > > %type <list> stmtblock, stmtmulti, > OptTableElementList, TableElementList, OptInherit, definition, > ! 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,2238 **** > --- 2233,2271 ---- > 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); > *************** > *** 2241,2246 **** > --- 2274,2282 ---- > n->definition = $7; > $$ = (Node *)n; > } > + ; > + > + rowdefinition: '(' TableFuncElementList ')' { $$ = $2; } > ; > > definition: '(' def_list ')' { $$ = $2; } > Index: src/backend/storage/buffer/bufmgr.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/storage/buffer/bufmgr.c,v > retrieving revision 1.129 > diff -c -r1.129 bufmgr.c > *** src/backend/storage/buffer/bufmgr.c 11 Aug 2002 21:17:34 -0000 1.129 > --- src/backend/storage/buffer/bufmgr.c 15 Aug 2002 04:47:07 -0000 > *************** > *** 1051,1056 **** > --- 1051,1058 ---- > */ > 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; > *************** > *** 1068,1073 **** > --- 1070,1077 ---- > 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); > Index: src/backend/storage/smgr/smgr.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/storage/smgr/smgr.c,v > retrieving revision 1.58 > diff -c -r1.58 smgr.c > *** src/backend/storage/smgr/smgr.c 6 Aug 2002 02:36:34 -0000 1.58 > --- src/backend/storage/smgr/smgr.c 15 Aug 2002 03:06:23 -0000 > *************** > *** 263,268 **** > --- 263,270 ---- > > 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)); > Index: src/backend/tcop/postgres.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/tcop/postgres.c,v > retrieving revision 1.281 > diff -c -r1.281 postgres.c > *** src/backend/tcop/postgres.c 10 Aug 2002 20:29:18 -0000 1.281 > --- src/backend/tcop/postgres.c 15 Aug 2002 03:06:23 -0000 > *************** > *** 2233,2238 **** > --- 2233,2242 ---- > } > break; > > + case T_CompositeTypeStmt: > + tag = "CREATE TYPE"; > + break; > + > case T_ViewStmt: > tag = "CREATE VIEW"; > break; > Index: src/backend/tcop/utility.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/tcop/utility.c,v > retrieving revision 1.169 > diff -c -r1.169 utility.c > *** src/backend/tcop/utility.c 7 Aug 2002 21:45:02 -0000 1.169 > --- src/backend/tcop/utility.c 15 Aug 2002 03:06:23 -0000 > *************** > *** 70,75 **** > --- 70,76 ---- > {RELKIND_SEQUENCE, "a", "sequence", "SEQUENCE"}, > {RELKIND_VIEW, "a", "view", "VIEW"}, > {RELKIND_INDEX, "an", "index", "INDEX"}, > + {RELKIND_COMPOSITE_TYPE, "a", "type", "TYPE"}, > {'\0', "a", "???", "???"} > }; > > *************** > *** 570,575 **** > --- 571,589 ---- > DefineAggregate(stmt->defnames, stmt->definition); > break; > } > + } > + 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; > > Index: src/backend/utils/adt/tid.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/adt/tid.c,v > retrieving revision 1.32 > diff -c -r1.32 tid.c > *** src/backend/utils/adt/tid.c 16 Jul 2002 17:55:25 -0000 1.32 > --- src/backend/utils/adt/tid.c 15 Aug 2002 03:06:23 -0000 > *************** > *** 226,231 **** > --- 226,234 ---- > 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); > > *************** > *** 248,253 **** > --- 251,259 ---- > rel = heap_openrv(relrv, AccessShareLock); > 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); > Index: src/bin/pg_dump/common.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/bin/pg_dump/common.c,v > retrieving revision 1.67 > diff -c -r1.67 common.c > *** src/bin/pg_dump/common.c 30 Jul 2002 21:56:04 -0000 1.67 > --- src/bin/pg_dump/common.c 15 Aug 2002 03:06:23 -0000 > *************** > *** 215,223 **** > > for (i = 0; i < numTables; i++) > { > ! /* Sequences and views never have parents */ > if (tblinfo[i].relkind == RELKIND_SEQUENCE || > ! tblinfo[i].relkind == RELKIND_VIEW) > continue; > > /* Don't bother computing anything for non-target tables, either */ > --- 215,224 ---- > > for (i = 0; i < numTables; i++) > { > ! /* Sequences, views, and types never have parents */ > if (tblinfo[i].relkind == RELKIND_SEQUENCE || > ! tblinfo[i].relkind == RELKIND_VIEW || > ! tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE) > continue; > > /* Don't bother computing anything for non-target tables, either */ > *************** > *** 269,277 **** > > for (i = 0; i < numTables; i++) > { > ! /* Sequences and views never have parents */ > if (tblinfo[i].relkind == RELKIND_SEQUENCE || > ! tblinfo[i].relkind == RELKIND_VIEW) > continue; > > /* Don't bother computing anything for non-target tables, either */ > --- 270,279 ---- > > for (i = 0; i < numTables; i++) > { > ! /* Sequences, views, and types never have parents */ > if (tblinfo[i].relkind == RELKIND_SEQUENCE || > ! tblinfo[i].relkind == RELKIND_VIEW || > ! tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE) > continue; > > /* Don't bother computing anything for non-target tables, either */ > Index: src/bin/pg_dump/pg_dump.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/bin/pg_dump/pg_dump.c,v > retrieving revision 1.281 > diff -c -r1.281 pg_dump.c > *** src/bin/pg_dump/pg_dump.c 10 Aug 2002 16:57:31 -0000 1.281 > --- src/bin/pg_dump/pg_dump.c 15 Aug 2002 03:06:23 -0000 > *************** > *** 95,100 **** > --- 95,101 ---- > 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,1176 **** > --- 1172,1181 ---- > 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,1580 **** > --- 1580,1586 ---- > int i_usename; > int i_typelem; > int i_typrelid; > + int i_typrelkind; > int i_typtype; > int i_typisdefined; > > *************** > *** 1595,1601 **** > appendPQExpBuffer(query, "SELECT pg_type.oid, typname, " > "typnamespace, " > "(select usename from pg_user where typowner = usesysid) as usename, " > ! "typelem, typrelid, typtype, typisdefined " > "FROM pg_type"); > } > else > --- 1601,1609 ---- > appendPQExpBuffer(query, "SELECT pg_type.oid, typname, " > "typnamespace, " > "(select usename from pg_user where typowner = usesysid) as usename, " > ! "typelem, typrelid, " > ! "(select relkind from pg_class where oid = typrelid) as typrelkind, " > ! "typtype, typisdefined " > "FROM pg_type"); > } > else > *************** > *** 1603,1609 **** > 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 " > "FROM pg_type"); > } > > --- 1611,1619 ---- > appendPQExpBuffer(query, "SELECT pg_type.oid, typname, " > "0::oid as typnamespace, " > "(select usename from pg_user where typowner = usesysid) as usename, " > ! "typelem, typrelid, " > ! "''::char as typrelkind, " > ! "typtype, typisdefined " > "FROM pg_type"); > } > > *************** > *** 1625,1630 **** > --- 1635,1641 ---- > 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,1642 **** > --- 1648,1654 ---- > 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,2108 **** > 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 " > --- 2114,2119 ---- > *************** > *** 2113,2118 **** > --- 2124,2130 ---- > } > 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,2361 **** > --- 2368,2377 ---- > 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; > *************** > *** 3173,3178 **** > --- 3189,3293 ---- > } > > /* > + * 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,3195 **** > if (!tinfo[i].typnamespace->dump) > continue; > > ! /* skip relation types */ > ! if (atooid(tinfo[i].typrelid) != 0) > continue; > > /* skip undefined placeholder types */ > --- 3303,3310 ---- > if (!tinfo[i].typnamespace->dump) > continue; > > ! /* 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,3212 **** > --- 3322,3329 ---- > 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,4837 **** > --- 4949,4955 ---- > > if (tbinfo->relkind != RELKIND_SEQUENCE) > continue; > + > if (tbinfo->dump) > { > dumpOneSequence(fout, tbinfo, schemaOnly, dataOnly); > *************** > *** 4847,4852 **** > --- 4965,4972 ---- > TableInfo *tbinfo = &tblinfo[i]; > > if (tbinfo->relkind == RELKIND_SEQUENCE) /* already dumped */ > + continue; > + if (tbinfo->relkind == RELKIND_COMPOSITE_TYPE) /* dumped as a type */ > continue; > > if (tbinfo->dump) > Index: src/bin/pg_dump/pg_dump.h > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/bin/pg_dump/pg_dump.h,v > retrieving revision 1.94 > diff -c -r1.94 pg_dump.h > *** src/bin/pg_dump/pg_dump.h 2 Aug 2002 18:15:08 -0000 1.94 > --- src/bin/pg_dump/pg_dump.h 15 Aug 2002 03:06:23 -0000 > *************** > *** 47,52 **** > --- 47,53 ---- > 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 */ > Index: src/bin/psql/describe.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/bin/psql/describe.c,v > retrieving revision 1.60 > diff -c -r1.60 describe.c > *** src/bin/psql/describe.c 10 Aug 2002 16:01:16 -0000 1.60 > --- src/bin/psql/describe.c 15 Aug 2002 04:14:09 -0000 > *************** > *** 210,218 **** > > /* > * do not include array types (start with underscore), do not include > ! * user relations (typrelid!=0) > */ > ! appendPQExpBuffer(&buf, "WHERE t.typrelid = 0 AND t.typname !~ '^_'\n"); > > /* Match name pattern against either internal or external name */ > processNamePattern(&buf, pattern, true, false, > --- 210,221 ---- > > /* > * do not include array types (start with underscore), do not include > ! * user relations (typrelid!=0) unless they are type relations > */ > ! 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, > Index: src/include/catalog/pg_class.h > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/include/catalog/pg_class.h,v > retrieving revision 1.70 > diff -c -r1.70 pg_class.h > *** src/include/catalog/pg_class.h 2 Aug 2002 18:15:09 -0000 1.70 > --- src/include/catalog/pg_class.h 15 Aug 2002 03:06:23 -0000 > *************** > *** 169,173 **** > --- 169,174 ---- > #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 */ > Index: src/include/commands/defrem.h > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/include/commands/defrem.h,v > retrieving revision 1.43 > diff -c -r1.43 defrem.h > *** src/include/commands/defrem.h 29 Jul 2002 22:14:11 -0000 1.43 > --- src/include/commands/defrem.h 15 Aug 2002 03:06:23 -0000 > *************** > *** 58,63 **** > --- 58,64 ---- > 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); > Index: src/include/nodes/nodes.h > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/include/nodes/nodes.h,v > retrieving revision 1.114 > diff -c -r1.114 nodes.h > *** src/include/nodes/nodes.h 29 Jul 2002 22:14:11 -0000 1.114 > --- src/include/nodes/nodes.h 15 Aug 2002 03:06:23 -0000 > *************** > *** 238,243 **** > --- 238,244 ---- > T_PrivTarget, > T_InsertDefault, > T_CreateOpClassItem, > + T_CompositeTypeStmt, > > /* > * TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h) > Index: src/include/nodes/parsenodes.h > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/include/nodes/parsenodes.h,v > retrieving revision 1.198 > diff -c -r1.198 parsenodes.h > *** src/include/nodes/parsenodes.h 4 Aug 2002 19:48:10 -0000 1.198 > --- src/include/nodes/parsenodes.h 15 Aug 2002 03:06:23 -0000 > *************** > *** 1402,1407 **** > --- 1402,1419 ---- > } 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 > * ---------------------- > */ > Index: src/pl/plpgsql/src/pl_comp.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/pl/plpgsql/src/pl_comp.c,v > retrieving revision 1.45 > diff -c -r1.45 pl_comp.c > *** src/pl/plpgsql/src/pl_comp.c 12 Aug 2002 14:25:07 -0000 1.45 > --- src/pl/plpgsql/src/pl_comp.c 15 Aug 2002 04:02:53 -0000 > *************** > *** 1028,1039 **** > } > > /* > ! * It must be a relation, sequence or view > */ > classStruct = (Form_pg_class) GETSTRUCT(classtup); > if (classStruct->relkind != RELKIND_RELATION && > classStruct->relkind != RELKIND_SEQUENCE && > ! classStruct->relkind != RELKIND_VIEW) > { > ReleaseSysCache(classtup); > pfree(cp[0]); > --- 1028,1040 ---- > } > > /* > ! * 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_COMPOSITE_TYPE) > { > ReleaseSysCache(classtup); > pfree(cp[0]); > *************** > *** 1145,1154 **** > classStruct = (Form_pg_class) GETSTRUCT(classtup); > relname = NameStr(classStruct->relname); > > ! /* accept relation, sequence, or view pg_class entries */ > if (classStruct->relkind != RELKIND_RELATION && > classStruct->relkind != RELKIND_SEQUENCE && > ! classStruct->relkind != RELKIND_VIEW) > elog(ERROR, "%s isn't a table", relname); > > /* > --- 1146,1156 ---- > classStruct = (Form_pg_class) GETSTRUCT(classtup); > relname = NameStr(classStruct->relname); > > ! /* 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_COMPOSITE_TYPE) > elog(ERROR, "%s isn't a table", relname); > > /* > Index: src/test/regress/expected/create_type.out > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/test/regress/expected/create_type.out,v > retrieving revision 1.4 > diff -c -r1.4 create_type.out > *** src/test/regress/expected/create_type.out 6 Sep 2001 02:07:42 -0000 1.4 > --- src/test/regress/expected/create_type.out 15 Aug 2002 03:06:23 -0000 > *************** > *** 37,40 **** > --- 37,53 ---- > 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; > Index: src/test/regress/sql/create_type.sql > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/test/regress/sql/create_type.sql,v > retrieving revision 1.4 > diff -c -r1.4 create_type.sql > *** src/test/regress/sql/create_type.sql 6 Sep 2001 02:07:42 -0000 1.4 > --- src/test/regress/sql/create_type.sql 15 Aug 2002 03:06:23 -0000 > *************** > *** 41,44 **** > --- 41,56 ---- > > 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; -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania 19073