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 = 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 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 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/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;