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 = 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.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 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, *************** *** 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;