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 = alignment ] [ , STORAGE = storage ] ) + + CREATE TYPE typename AS + ( column_definition_list ) + + where column_definition_list can be: + + ( column_name data_type [, ... ] ) *************** *** 138,143 **** --- 145,169 ---- + + + column_name + + + The name of a column of the composite type. + + + + + + data_type + + + The name of an existing data type. + + + + *************** *** 191,199 **** ! CREATE TYPE requires the registration of two functions ! (using CREATE FUNCTION) before defining the type. The ! representation of a new base type is determined by input_function, which converts the type's external representation to an internal representation usable by the --- 217,225 ---- ! The first form of CREATE TYPE requires the ! registration of two functions (using CREATE FUNCTION) before defining the ! type. The representation of a new base type is determined by input_function, which converts the type's external representation to an internal representation usable by the *************** *** 288,293 **** --- 314,327 ---- extended and external items.) + + The second form of CREATE TYPE requires a column + definition list in the form ( column_name + data_type [, ... ] ). 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. + + Array Types *************** *** 370,375 **** --- 404,418 ---- CREATE TYPE bigobj (INPUT = lo_filein, OUTPUT = lo_fileout, INTERNALLENGTH = VARIABLE); CREATE TABLE big_objs (id int4, obj bigobj); + + + + + This example creates a composite type and uses it in + a table function definition: + + CREATE TYPE compfoo AS (f1 int, f2 int); + CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS 'SELECT fooid, foorefid FROM foo' LANGUAGE SQL; 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 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 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;