Tom Lane wrote:
authorBruce Momjian
Thu, 15 Aug 2002 16:36:08 +0000 (16:36 +0000)
committerBruce Momjian
Thu, 15 Aug 2002 16:36:08 +0000 (16:36 +0000)
> There's no longer a separate call to heap_storage_create in that routine
> --- the right place to make the test is now in the storage_create
> boolean parameter being passed to heap_create.  A simple change, but
> it passeth patch's understanding ...

Thanks.

Attached is a patch against cvs tip as of 8:30 PM PST or so. Turned out
that even after fixing the failed hunks, there was a new spot in
bufmgr.c which needed to be fixed (related to temp relations;
RelationUpdateNumberOfBlocks). But thankfully the regression test code
caught it :-)

Joe Conway

27 files changed:
doc/src/sgml/ref/create_type.sgml
src/backend/catalog/heap.c
src/backend/catalog/namespace.c
src/backend/catalog/pg_type.c
src/backend/commands/copy.c
src/backend/commands/tablecmds.c
src/backend/commands/typecmds.c
src/backend/executor/execMain.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/parser/gram.y
src/backend/storage/buffer/bufmgr.c
src/backend/storage/smgr/smgr.c
src/backend/tcop/postgres.c
src/backend/tcop/utility.c
src/backend/utils/adt/tid.c
src/bin/pg_dump/common.c
src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h
src/bin/psql/describe.c
src/include/catalog/pg_class.h
src/include/commands/defrem.h
src/include/nodes/nodes.h
src/include/nodes/parsenodes.h
src/pl/plpgsql/src/pl_comp.c
src/test/regress/expected/create_type.out
src/test/regress/sql/create_type.sql

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