Re: stand-alone composite types patch (was [HACKERS] Proposal: - Mailing list pgsql-patches

From Joe Conway
Subject Re: stand-alone composite types patch (was [HACKERS] Proposal:
Date
Msg-id 3D5B39D7.6010709@joeconway.com
Whole thread Raw
In response to Re: stand-alone composite types patch (was [HACKERS] Proposal:  (Bruce Momjian <pgman@candle.pha.pa.us>)
Responses Re: stand-alone composite types patch (was [HACKERS] Proposal:
List pgsql-patches
Tom Lane wrote:
> There's no longer a separate call to heap_storage_create in that routine
> --- the right place to make the test is now in the storage_create
> boolean parameter being passed to heap_create.  A simple change, but
> it passeth patch's understanding ...

Thanks.

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

Joe

Index: doc/src/sgml/ref/create_type.sgml
===================================================================
RCS file: /opt/src/cvs/pgsql-server/doc/src/sgml/ref/create_type.sgml,v
retrieving revision 1.30
diff -c -r1.30 create_type.sgml
*** doc/src/sgml/ref/create_type.sgml    24 Jul 2002 19:11:07 -0000    1.30
--- doc/src/sgml/ref/create_type.sgml    15 Aug 2002 03:06:23 -0000
***************
*** 30,35 ****
--- 30,42 ----
      [ , ALIGNMENT = <replaceable class="parameter">alignment</replaceable> ]
      [ , STORAGE = <replaceable class="parameter">storage</replaceable> ]
  )
+
+ CREATE TYPE <replaceable class="parameter">typename</replaceable> AS
+       ( <replaceable class="PARAMETER">column_definition_list</replaceable> )
+
+ where <replaceable class="PARAMETER">column_definition_list</replaceable> can be:
+
+ ( <replaceable class="PARAMETER">column_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [,
...] ) 
    </synopsis>

    <refsect2 id="R2-SQL-CREATETYPE-1">
***************
*** 138,143 ****
--- 145,169 ----
         </para>
        </listitem>
       </varlistentry>
+
+      <varlistentry>
+       <term><replaceable class="PARAMETER">column_name</replaceable></term>
+       <listitem>
+        <para>
+         The name of a column of the composite type.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term><replaceable class="PARAMETER">data_type</replaceable></term>
+       <listitem>
+        <para>
+         The name of an existing data type.
+        </para>
+       </listitem>
+      </varlistentry>
+
      </variablelist>
     </para>
    </refsect2>
***************
*** 191,199 ****
    </para>

    <para>
!    <command>CREATE TYPE</command>  requires  the  registration of two functions
!    (using CREATE FUNCTION) before defining the type.   The
!    representation  of  a  new  base  type  is  determined  by
     <replaceable class="parameter">input_function</replaceable>, which
     converts the type's external  representation  to  an  internal
     representation  usable by the
--- 217,225 ----
    </para>

    <para>
!    The first form of <command>CREATE TYPE</command>  requires  the
!    registration of two functions (using CREATE FUNCTION) before defining the
!    type. The representation of a new base type is determined by
     <replaceable class="parameter">input_function</replaceable>, which
     converts the type's external  representation  to  an  internal
     representation  usable by the
***************
*** 288,293 ****
--- 314,327 ----
     <literal>extended</literal> and <literal>external</literal> items.)
    </para>

+   <para>
+    The second form of <command>CREATE TYPE</command> requires a column
+    definition list in the form ( <replaceable class="PARAMETER">column_name</replaceable>
+    <replaceable class="PARAMETER">data_type</replaceable> [, ... ] ). This
+    creates a composite type, similar to that of a TABLE or VIEW relation.
+    A stand-alone composite type is useful as the return type of FUNCTION.
+   </para>
+
    <refsect2>
     <title>Array Types</title>

***************
*** 370,375 ****
--- 404,418 ----
  CREATE TYPE bigobj (INPUT = lo_filein, OUTPUT = lo_fileout,
      INTERNALLENGTH = VARIABLE);
  CREATE TABLE big_objs (id int4, obj bigobj);
+ </programlisting>
+   </para>
+
+   <para>
+    This example creates a composite type and uses it in
+    a table function definition:
+ <programlisting>
+ CREATE TYPE compfoo AS (f1 int, f2 int);
+ CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS 'SELECT fooid, foorefid FROM foo' LANGUAGE SQL;
  </programlisting>
    </para>
   </refsect1>
Index: src/backend/catalog/heap.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/catalog/heap.c,v
retrieving revision 1.220
diff -c -r1.220 heap.c
*** src/backend/catalog/heap.c    11 Aug 2002 21:17:34 -0000    1.220
--- src/backend/catalog/heap.c    15 Aug 2002 04:21:03 -0000
***************
*** 357,365 ****
      /*
       * first check for collision with system attribute names
       *
!      * Skip this for a view, since it doesn't have system attributes.
       */
!     if (relkind != RELKIND_VIEW)
      {
          for (i = 0; i < natts; i++)
          {
--- 357,366 ----
      /*
       * first check for collision with system attribute names
       *
!      * Skip this for a view and type relation, since it doesn't have system
!      * attributes.
       */
!     if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE)
      {
          for (i = 0; i < natts; i++)
          {
***************
*** 473,482 ****

      /*
       * Next we add the system attributes.  Skip OID if rel has no OIDs.
!      * Skip all for a view.  We don't bother with making datatype
!      * dependencies here, since presumably all these types are pinned.
       */
!     if (relkind != RELKIND_VIEW)
      {
          dpp = SysAtt;
          for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++)
--- 474,483 ----

      /*
       * Next we add the system attributes.  Skip OID if rel has no OIDs.
!      * Skip all for a view or type relation.  We don't bother with making
!      * datatype dependencies here, since presumably all these types are pinned.
       */
!     if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE)
      {
          dpp = SysAtt;
          for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++)
***************
*** 689,701 ****
       * physical disk file.  (If we fail further down, it's the smgr's
       * responsibility to remove the disk file again.)
       *
!      * NB: create a physical file only if it's not a view.
       */
      new_rel_desc = heap_create(relname,
                                 relnamespace,
                                 tupdesc,
                                 shared_relation,
!                                (relkind != RELKIND_VIEW),
                                 allow_system_table_mods);

      /* Fetch the relation OID assigned by heap_create */
--- 690,703 ----
       * physical disk file.  (If we fail further down, it's the smgr's
       * responsibility to remove the disk file again.)
       *
!      * NB: create a physical file only if it's not a view or type relation.
       */
      new_rel_desc = heap_create(relname,
                                 relnamespace,
                                 tupdesc,
                                 shared_relation,
!                                (relkind != RELKIND_VIEW &&
!                                 relkind != RELKIND_COMPOSITE_TYPE),
                                 allow_system_table_mods);

      /* Fetch the relation OID assigned by heap_create */
***************
*** 1131,1137 ****
      /*
       * unlink the relation's physical file and finish up.
       */
!     if (rel->rd_rel->relkind != RELKIND_VIEW)
          smgrunlink(DEFAULT_SMGR, rel);

      /*
--- 1133,1140 ----
      /*
       * unlink the relation's physical file and finish up.
       */
!     if (rel->rd_rel->relkind != RELKIND_VIEW &&
!             rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE)
          smgrunlink(DEFAULT_SMGR, rel);

      /*
Index: src/backend/catalog/namespace.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/catalog/namespace.c,v
retrieving revision 1.30
diff -c -r1.30 namespace.c
*** src/backend/catalog/namespace.c    9 Aug 2002 16:45:14 -0000    1.30
--- src/backend/catalog/namespace.c    15 Aug 2002 03:06:23 -0000
***************
*** 1585,1590 ****
--- 1585,1591 ----
              case RELKIND_RELATION:
              case RELKIND_SEQUENCE:
              case RELKIND_VIEW:
+             case RELKIND_COMPOSITE_TYPE:
                  AssertTupleDescHasOid(pgclass->rd_att);
                  object.classId = RelOid_pg_class;
                  object.objectId = HeapTupleGetOid(tuple);
Index: src/backend/catalog/pg_type.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/catalog/pg_type.c,v
retrieving revision 1.77
diff -c -r1.77 pg_type.c
*** src/backend/catalog/pg_type.c    5 Aug 2002 03:29:16 -0000    1.77
--- src/backend/catalog/pg_type.c    15 Aug 2002 03:06:23 -0000
***************
*** 311,325 ****

          /*
           * If the type is a rowtype for a relation, mark it as internally
!          * dependent on the relation.  This allows it to be auto-dropped
!          * when the relation is, and not otherwise.
           */
          if (OidIsValid(relationOid))
          {
              referenced.classId = RelOid_pg_class;
              referenced.objectId = relationOid;
              referenced.objectSubId = 0;
!             recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
          }

          /*
--- 311,338 ----

          /*
           * If the type is a rowtype for a relation, mark it as internally
!          * dependent on the relation, *unless* it is a stand-alone composite
!          * type relation. For the latter case, we have to reverse the
!          * dependency.
!          *
!          * In the former case, this allows the type to be auto-dropped
!          * when the relation is, and not otherwise. And in the latter,
!          * of course we get the opposite effect.
           */
          if (OidIsValid(relationOid))
          {
+             Relation    rel = relation_open(relationOid, AccessShareLock);
+             char        relkind = rel->rd_rel->relkind;
+             relation_close(rel, AccessShareLock);
+
              referenced.classId = RelOid_pg_class;
              referenced.objectId = relationOid;
              referenced.objectSubId = 0;
!
!             if (relkind != RELKIND_COMPOSITE_TYPE)
!                 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
!             else
!                 recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
          }

          /*
Index: src/backend/commands/copy.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/commands/copy.c,v
retrieving revision 1.162
diff -c -r1.162 copy.c
*** src/backend/commands/copy.c    2 Aug 2002 18:15:06 -0000    1.162
--- src/backend/commands/copy.c    15 Aug 2002 03:06:23 -0000
***************
*** 398,403 ****
--- 398,406 ----
              if (rel->rd_rel->relkind == RELKIND_VIEW)
                  elog(ERROR, "You cannot copy view %s",
                       RelationGetRelationName(rel));
+             else if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
+                 elog(ERROR, "You cannot copy type relation %s",
+                      RelationGetRelationName(rel));
              else if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
                  elog(ERROR, "You cannot change sequence relation %s",
                       RelationGetRelationName(rel));
***************
*** 442,447 ****
--- 445,453 ----
          {
              if (rel->rd_rel->relkind == RELKIND_VIEW)
                  elog(ERROR, "You cannot copy view %s",
+                      RelationGetRelationName(rel));
+             else if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
+                 elog(ERROR, "You cannot copy type relation %s",
                       RelationGetRelationName(rel));
              else if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
                  elog(ERROR, "You cannot copy sequence %s",
Index: src/backend/commands/tablecmds.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/commands/tablecmds.c,v
retrieving revision 1.28
diff -c -r1.28 tablecmds.c
*** src/backend/commands/tablecmds.c    7 Aug 2002 21:45:01 -0000    1.28
--- src/backend/commands/tablecmds.c    15 Aug 2002 03:06:23 -0000
***************
*** 345,350 ****
--- 345,354 ----
          elog(ERROR, "TRUNCATE cannot be used on views. '%s' is a view",
               RelationGetRelationName(rel));

+     if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
+         elog(ERROR, "TRUNCATE cannot be used on type relations. '%s' is a type",
+              RelationGetRelationName(rel));
+
      if (!allowSystemTableMods && IsSystemRelation(rel))
          elog(ERROR, "TRUNCATE cannot be used on system tables. '%s' is a system table",
               RelationGetRelationName(rel));
***************
*** 3210,3221 ****
          case RELKIND_RELATION:
          case RELKIND_INDEX:
          case RELKIND_VIEW:
          case RELKIND_SEQUENCE:
          case RELKIND_TOASTVALUE:
              /* ok to change owner */
              break;
          default:
!             elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table, TOAST table, index, view, or sequence",
                   NameStr(tuple_class->relname));
      }
  }
--- 3214,3226 ----
          case RELKIND_RELATION:
          case RELKIND_INDEX:
          case RELKIND_VIEW:
+         case RELKIND_COMPOSITE_TYPE:
          case RELKIND_SEQUENCE:
          case RELKIND_TOASTVALUE:
              /* ok to change owner */
              break;
          default:
!             elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table, TOAST table, index, view, type, or sequence",
                   NameStr(tuple_class->relname));
      }
  }
Index: src/backend/commands/typecmds.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/commands/typecmds.c,v
retrieving revision 1.8
diff -c -r1.8 typecmds.c
*** src/backend/commands/typecmds.c    24 Jul 2002 19:11:09 -0000    1.8
--- src/backend/commands/typecmds.c    15 Aug 2002 03:06:23 -0000
***************
*** 38,43 ****
--- 38,44 ----
  #include "catalog/namespace.h"
  #include "catalog/pg_type.h"
  #include "commands/defrem.h"
+ #include "commands/tablecmds.h"
  #include "miscadmin.h"
  #include "parser/parse_func.h"
  #include "parser/parse_type.h"
***************
*** 50,56 ****

  static Oid findTypeIOFunction(List *procname, bool isOutput);

-
  /*
   * DefineType
   *        Registers a new type.
--- 51,56 ----
***************
*** 665,668 ****
--- 665,707 ----
      }

      return procOid;
+ }
+
+ /*-------------------------------------------------------------------
+  * DefineCompositeType
+  *
+  * Create a Composite Type relation.
+  * `DefineRelation' does all the work, we just provide the correct
+  * arguments!
+  *
+  * If the relation already exists, then 'DefineRelation' will abort
+  * the xact...
+  *
+  * DefineCompositeType returns relid for use when creating
+  * an implicit composite type during function creation
+  *-------------------------------------------------------------------
+  */
+ Oid
+ DefineCompositeType(const RangeVar *typevar, List *coldeflist)
+ {
+     CreateStmt *createStmt = makeNode(CreateStmt);
+
+     if (coldeflist == NIL)
+         elog(ERROR, "attempted to define composite type relation with"
+                     " no attrs");
+
+     /*
+      * now create the parameters for keys/inheritance etc. All of them are
+      * nil...
+      */
+     createStmt->relation = (RangeVar *) typevar;
+     createStmt->tableElts = coldeflist;
+     createStmt->inhRelations = NIL;
+     createStmt->constraints = NIL;
+     createStmt->hasoids = false;
+
+     /*
+      * finally create the relation...
+      */
+     return DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE);
  }
Index: src/backend/executor/execMain.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/executor/execMain.c,v
retrieving revision 1.173
diff -c -r1.173 execMain.c
*** src/backend/executor/execMain.c    7 Aug 2002 21:45:02 -0000    1.173
--- src/backend/executor/execMain.c    15 Aug 2002 03:06:23 -0000
***************
*** 786,791 ****
--- 786,795 ----
              elog(ERROR, "You can't change view relation %s",
                   RelationGetRelationName(resultRelationDesc));
              break;
+         case RELKIND_COMPOSITE_TYPE:
+             elog(ERROR, "You can't change type relation %s",
+                  RelationGetRelationName(resultRelationDesc));
+             break;
      }

      MemSet(resultRelInfo, 0, sizeof(ResultRelInfo));
Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.200
diff -c -r1.200 copyfuncs.c
*** src/backend/nodes/copyfuncs.c    4 Aug 2002 19:48:09 -0000    1.200
--- src/backend/nodes/copyfuncs.c    15 Aug 2002 03:06:23 -0000
***************
*** 2233,2238 ****
--- 2233,2249 ----
      return newnode;
  }

+ static CompositeTypeStmt *
+ _copyCompositeTypeStmt(CompositeTypeStmt *from)
+ {
+     CompositeTypeStmt   *newnode = makeNode(CompositeTypeStmt);
+
+     Node_Copy(from, newnode, typevar);
+     Node_Copy(from, newnode, coldeflist);
+
+     return newnode;
+ }
+
  static ViewStmt *
  _copyViewStmt(ViewStmt *from)
  {
***************
*** 2938,2943 ****
--- 2949,2957 ----
              break;
          case T_TransactionStmt:
              retval = _copyTransactionStmt(from);
+             break;
+         case T_CompositeTypeStmt:
+             retval = _copyCompositeTypeStmt(from);
              break;
          case T_ViewStmt:
              retval = _copyViewStmt(from);
Index: src/backend/nodes/equalfuncs.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/equalfuncs.c,v
retrieving revision 1.149
diff -c -r1.149 equalfuncs.c
*** src/backend/nodes/equalfuncs.c    4 Aug 2002 23:49:59 -0000    1.149
--- src/backend/nodes/equalfuncs.c    15 Aug 2002 03:06:23 -0000
***************
*** 1062,1067 ****
--- 1062,1078 ----
  }

  static bool
+ _equalCompositeTypeStmt(CompositeTypeStmt *a, CompositeTypeStmt *b)
+ {
+     if (!equal(a->typevar, b->typevar))
+         return false;
+     if (!equal(a->coldeflist, b->coldeflist))
+         return false;
+
+     return true;
+ }
+
+ static bool
  _equalViewStmt(ViewStmt *a, ViewStmt *b)
  {
      if (!equal(a->view, b->view))
***************
*** 2110,2115 ****
--- 2121,2129 ----
              break;
          case T_TransactionStmt:
              retval = _equalTransactionStmt(a, b);
+             break;
+         case T_CompositeTypeStmt:
+             retval = _equalCompositeTypeStmt(a, b);
              break;
          case T_ViewStmt:
              retval = _equalViewStmt(a, b);
Index: src/backend/parser/gram.y
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/parser/gram.y,v
retrieving revision 2.358
diff -c -r2.358 gram.y
*** src/backend/parser/gram.y    10 Aug 2002 19:01:53 -0000    2.358
--- src/backend/parser/gram.y    15 Aug 2002 03:06:23 -0000
***************
*** 205,211 ****

  %type <list>    stmtblock, stmtmulti,
                  OptTableElementList, TableElementList, OptInherit, definition,
!                 opt_distinct, opt_definition, func_args,
                  func_args_list, func_as, createfunc_opt_list
                  oper_argtypes, RuleActionList, RuleActionMulti,
                  opt_column_list, columnList, opt_name_list,
--- 205,211 ----

  %type <list>    stmtblock, stmtmulti,
                  OptTableElementList, TableElementList, OptInherit, definition,
!                 opt_distinct, opt_definition, func_args, rowdefinition
                  func_args_list, func_as, createfunc_opt_list
                  oper_argtypes, RuleActionList, RuleActionMulti,
                  opt_column_list, columnList, opt_name_list,
***************
*** 2233,2238 ****
--- 2233,2271 ----
                      n->definition = $4;
                      $$ = (Node *)n;
                  }
+             | CREATE TYPE_P any_name AS rowdefinition
+                 {
+                     CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
+                     RangeVar *r = makeNode(RangeVar);
+
+                     switch (length($3))
+                     {
+                         case 1:
+                             r->catalogname = NULL;
+                             r->schemaname = NULL;
+                             r->relname = strVal(lfirst($3));
+                             break;
+                         case 2:
+                             r->catalogname = NULL;
+                             r->schemaname = strVal(lfirst($3));
+                             r->relname = strVal(lsecond($3));
+                             break;
+                         case 3:
+                             r->catalogname = strVal(lfirst($3));
+                             r->schemaname = strVal(lsecond($3));
+                             r->relname = strVal(lfirst(lnext(lnext($3))));
+                             break;
+                         default:
+                             elog(ERROR,
+                             "Improper qualified name "
+                             "(too many dotted names): %s",
+                                  NameListToString($3));
+                             break;
+                     }
+                     n->typevar = r;
+                     n->coldeflist = $5;
+                     $$ = (Node *)n;
+                 }
              | CREATE CHARACTER SET opt_as any_name GET definition opt_collate
                  {
                      DefineStmt *n = makeNode(DefineStmt);
***************
*** 2241,2246 ****
--- 2274,2282 ----
                      n->definition = $7;
                      $$ = (Node *)n;
                  }
+         ;
+
+ rowdefinition: '(' TableFuncElementList ')'            { $$ = $2; }
          ;

  definition: '(' def_list ')'                        { $$ = $2; }
Index: src/backend/storage/buffer/bufmgr.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/storage/buffer/bufmgr.c,v
retrieving revision 1.129
diff -c -r1.129 bufmgr.c
*** src/backend/storage/buffer/bufmgr.c    11 Aug 2002 21:17:34 -0000    1.129
--- src/backend/storage/buffer/bufmgr.c    15 Aug 2002 04:47:07 -0000
***************
*** 1051,1056 ****
--- 1051,1058 ----
       */
      if (relation->rd_rel->relkind == RELKIND_VIEW)
          relation->rd_nblocks = 0;
+     else if (relation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
+         relation->rd_nblocks = 0;
      else if (!relation->rd_isnew && !relation->rd_istemp)
          relation->rd_nblocks = smgrnblocks(DEFAULT_SMGR, relation);
      return relation->rd_nblocks;
***************
*** 1068,1073 ****
--- 1070,1077 ----
  RelationUpdateNumberOfBlocks(Relation relation)
  {
      if (relation->rd_rel->relkind == RELKIND_VIEW)
+         relation->rd_nblocks = 0;
+     else if (relation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
          relation->rd_nblocks = 0;
      else
          relation->rd_nblocks = smgrnblocks(DEFAULT_SMGR, relation);
Index: src/backend/storage/smgr/smgr.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/storage/smgr/smgr.c,v
retrieving revision 1.58
diff -c -r1.58 smgr.c
*** src/backend/storage/smgr/smgr.c    6 Aug 2002 02:36:34 -0000    1.58
--- src/backend/storage/smgr/smgr.c    15 Aug 2002 03:06:23 -0000
***************
*** 263,268 ****
--- 263,270 ----

      if (reln->rd_rel->relkind == RELKIND_VIEW)
          return -1;
+     if (reln->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
+         return -1;
      if ((fd = (*(smgrsw[which].smgr_open)) (reln)) < 0)
          if (!failOK)
              elog(ERROR, "cannot open %s: %m", RelationGetRelationName(reln));
Index: src/backend/tcop/postgres.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/tcop/postgres.c,v
retrieving revision 1.281
diff -c -r1.281 postgres.c
*** src/backend/tcop/postgres.c    10 Aug 2002 20:29:18 -0000    1.281
--- src/backend/tcop/postgres.c    15 Aug 2002 03:06:23 -0000
***************
*** 2233,2238 ****
--- 2233,2242 ----
              }
              break;

+         case T_CompositeTypeStmt:
+             tag = "CREATE TYPE";
+             break;
+
          case T_ViewStmt:
              tag = "CREATE VIEW";
              break;
Index: src/backend/tcop/utility.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/tcop/utility.c,v
retrieving revision 1.169
diff -c -r1.169 utility.c
*** src/backend/tcop/utility.c    7 Aug 2002 21:45:02 -0000    1.169
--- src/backend/tcop/utility.c    15 Aug 2002 03:06:23 -0000
***************
*** 70,75 ****
--- 70,76 ----
      {RELKIND_SEQUENCE, "a", "sequence", "SEQUENCE"},
      {RELKIND_VIEW, "a", "view", "VIEW"},
      {RELKIND_INDEX, "an", "index", "INDEX"},
+     {RELKIND_COMPOSITE_TYPE, "a", "type", "TYPE"},
      {'\0', "a", "???", "???"}
  };

***************
*** 570,575 ****
--- 571,589 ----
                          DefineAggregate(stmt->defnames, stmt->definition);
                          break;
                  }
+             }
+             break;
+
+         case T_CompositeTypeStmt:        /* CREATE TYPE (composite) */
+             {
+                 Oid    relid;
+                 CompositeTypeStmt   *stmt = (CompositeTypeStmt *) parsetree;
+
+                 /*
+                  * DefineCompositeType returns relid for use when creating
+                  * an implicit composite type during function creation
+                  */
+                 relid = DefineCompositeType(stmt->typevar, stmt->coldeflist);
              }
              break;

Index: src/backend/utils/adt/tid.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/adt/tid.c,v
retrieving revision 1.32
diff -c -r1.32 tid.c
*** src/backend/utils/adt/tid.c    16 Jul 2002 17:55:25 -0000    1.32
--- src/backend/utils/adt/tid.c    15 Aug 2002 03:06:23 -0000
***************
*** 226,231 ****
--- 226,234 ----
      if (rel->rd_rel->relkind == RELKIND_VIEW)
          return currtid_for_view(rel, tid);

+     if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
+         elog(ERROR, "currtid can't handle type relations");
+
      ItemPointerCopy(tid, result);
      heap_get_latest_tid(rel, SnapshotNow, result);

***************
*** 248,253 ****
--- 251,259 ----
      rel = heap_openrv(relrv, AccessShareLock);
      if (rel->rd_rel->relkind == RELKIND_VIEW)
          return currtid_for_view(rel, tid);
+
+     if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
+         elog(ERROR, "currtid can't handle type relations");

      result = (ItemPointer) palloc(sizeof(ItemPointerData));
      ItemPointerCopy(tid, result);
Index: src/bin/pg_dump/common.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/bin/pg_dump/common.c,v
retrieving revision 1.67
diff -c -r1.67 common.c
*** src/bin/pg_dump/common.c    30 Jul 2002 21:56:04 -0000    1.67
--- src/bin/pg_dump/common.c    15 Aug 2002 03:06:23 -0000
***************
*** 215,223 ****

      for (i = 0; i < numTables; i++)
      {
!         /* Sequences and views never have parents */
          if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
!             tblinfo[i].relkind == RELKIND_VIEW)
              continue;

          /* Don't bother computing anything for non-target tables, either */
--- 215,224 ----

      for (i = 0; i < numTables; i++)
      {
!         /* Sequences, views, and types never have parents */
          if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
!             tblinfo[i].relkind == RELKIND_VIEW ||
!             tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
              continue;

          /* Don't bother computing anything for non-target tables, either */
***************
*** 269,277 ****

      for (i = 0; i < numTables; i++)
      {
!         /* Sequences and views never have parents */
          if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
!             tblinfo[i].relkind == RELKIND_VIEW)
              continue;

          /* Don't bother computing anything for non-target tables, either */
--- 270,279 ----

      for (i = 0; i < numTables; i++)
      {
!         /* Sequences, views, and types never have parents */
          if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
!             tblinfo[i].relkind == RELKIND_VIEW ||
!             tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
              continue;

          /* Don't bother computing anything for non-target tables, either */
Index: src/bin/pg_dump/pg_dump.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/bin/pg_dump/pg_dump.c,v
retrieving revision 1.281
diff -c -r1.281 pg_dump.c
*** src/bin/pg_dump/pg_dump.c    10 Aug 2002 16:57:31 -0000    1.281
--- src/bin/pg_dump/pg_dump.c    15 Aug 2002 03:06:23 -0000
***************
*** 95,100 ****
--- 95,101 ----
                              FuncInfo *g_finfo, int numFuncs,
                              TypeInfo *g_tinfo, int numTypes);
  static void dumpOneDomain(Archive *fout, TypeInfo *tinfo);
+ static void dumpOneCompositeType(Archive *fout, TypeInfo *tinfo);
  static void dumpOneTable(Archive *fout, TableInfo *tbinfo,
                           TableInfo *g_tblinfo);
  static void dumpOneSequence(Archive *fout, TableInfo *tbinfo,
***************
*** 1171,1176 ****
--- 1172,1181 ----
          if (tblinfo[i].relkind == RELKIND_VIEW)
              continue;

+         /* Skip TYPE relations */
+         if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
+             continue;
+
          if (tblinfo[i].relkind == RELKIND_SEQUENCE)        /* already dumped */
              continue;

***************
*** 1575,1580 ****
--- 1580,1586 ----
      int            i_usename;
      int            i_typelem;
      int            i_typrelid;
+     int            i_typrelkind;
      int            i_typtype;
      int            i_typisdefined;

***************
*** 1595,1601 ****
          appendPQExpBuffer(query, "SELECT pg_type.oid, typname, "
                            "typnamespace, "
                            "(select usename from pg_user where typowner = usesysid) as usename, "
!                           "typelem, typrelid, typtype, typisdefined "
                            "FROM pg_type");
      }
      else
--- 1601,1609 ----
          appendPQExpBuffer(query, "SELECT pg_type.oid, typname, "
                            "typnamespace, "
                            "(select usename from pg_user where typowner = usesysid) as usename, "
!                           "typelem, typrelid, "
!                           "(select relkind from pg_class where oid = typrelid) as typrelkind, "
!                           "typtype, typisdefined "
                            "FROM pg_type");
      }
      else
***************
*** 1603,1609 ****
          appendPQExpBuffer(query, "SELECT pg_type.oid, typname, "
                            "0::oid as typnamespace, "
                            "(select usename from pg_user where typowner = usesysid) as usename, "
!                           "typelem, typrelid, typtype, typisdefined "
                            "FROM pg_type");
      }

--- 1611,1619 ----
          appendPQExpBuffer(query, "SELECT pg_type.oid, typname, "
                            "0::oid as typnamespace, "
                            "(select usename from pg_user where typowner = usesysid) as usename, "
!                           "typelem, typrelid, "
!                           "''::char as typrelkind, "
!                           "typtype, typisdefined "
                            "FROM pg_type");
      }

***************
*** 1625,1630 ****
--- 1635,1641 ----
      i_usename = PQfnumber(res, "usename");
      i_typelem = PQfnumber(res, "typelem");
      i_typrelid = PQfnumber(res, "typrelid");
+     i_typrelkind = PQfnumber(res, "typrelkind");
      i_typtype = PQfnumber(res, "typtype");
      i_typisdefined = PQfnumber(res, "typisdefined");

***************
*** 1637,1642 ****
--- 1648,1654 ----
          tinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
          tinfo[i].typelem = strdup(PQgetvalue(res, i, i_typelem));
          tinfo[i].typrelid = strdup(PQgetvalue(res, i, i_typrelid));
+         tinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
          tinfo[i].typtype = *PQgetvalue(res, i, i_typtype);

          /*
***************
*** 2102,2108 ****
          appendPQExpBuffer(query,
                            "SELECT pg_class.oid, relname, relacl, relkind, "
                            "relnamespace, "
-
                            "(select usename from pg_user where relowner = usesysid) as usename, "
                            "relchecks, reltriggers, "
                            "relhasindex, relhasrules, relhasoids "
--- 2114,2119 ----
***************
*** 2113,2118 ****
--- 2124,2130 ----
      }
      else if (g_fout->remoteVersion >= 70200)
      {
+         /* before 7.3 there were no type relations with relkind 'c' */
          appendPQExpBuffer(query,
                            "SELECT pg_class.oid, relname, relacl, relkind, "
                            "0::oid as relnamespace, "
***************
*** 2356,2361 ****
--- 2368,2377 ----
          if (tblinfo[i].relkind == RELKIND_SEQUENCE)
              continue;

+         /* Don't bother to collect info for type relations */
+         if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
+             continue;
+
          /* Don't bother with uninteresting tables, either */
          if (!tblinfo[i].interesting)
              continue;
***************
*** 3173,3178 ****
--- 3189,3293 ----
  }

  /*
+  * dumpOneCompositeType
+  *    writes out to fout the queries to recreate a user-defined stand-alone
+  *    composite type as requested by dumpTypes
+  */
+ static void
+ dumpOneCompositeType(Archive *fout, TypeInfo *tinfo)
+ {
+     PQExpBuffer q = createPQExpBuffer();
+     PQExpBuffer delq = createPQExpBuffer();
+     PQExpBuffer query = createPQExpBuffer();
+     PGresult   *res;
+     int            ntups;
+     char       *attname;
+     char       *atttypdefn;
+     char       *attbasetype;
+     const char *((*deps)[]);
+     int            depIdx = 0;
+     int            i;
+
+     deps = malloc(sizeof(char *) * 10);
+
+     /* Set proper schema search path so type references list correctly */
+     selectSourceSchema(tinfo->typnamespace->nspname);
+
+     /* Fetch type specific details */
+     /* We assume here that remoteVersion must be at least 70300 */
+
+     appendPQExpBuffer(query, "SELECT a.attname, "
+                       "pg_catalog.format_type(a.atttypid, a.atttypmod) as atttypdefn, "
+                       "a.atttypid as attbasetype "
+                       "FROM pg_catalog.pg_type t, pg_catalog.pg_attribute a "
+                       "WHERE t.oid = '%s'::pg_catalog.oid "
+                       "AND a.attrelid = t.typrelid",
+                       tinfo->oid);
+
+     res = PQexec(g_conn, query->data);
+     if (!res ||
+         PQresultStatus(res) != PGRES_TUPLES_OK)
+     {
+         write_msg(NULL, "query to obtain type information failed: %s", PQerrorMessage(g_conn));
+         exit_nicely();
+     }
+
+     /* Expecting at least a single result */
+     ntups = PQntuples(res);
+     if (ntups < 1)
+     {
+         write_msg(NULL, "Got no rows from: %s", query->data);
+         exit_nicely();
+     }
+
+     /* DROP must be fully qualified in case same name appears in pg_catalog */
+     appendPQExpBuffer(delq, "DROP TYPE %s.",
+                       fmtId(tinfo->typnamespace->nspname, force_quotes));
+     appendPQExpBuffer(delq, "%s RESTRICT;\n",
+                       fmtId(tinfo->typname, force_quotes));
+
+     appendPQExpBuffer(q,
+                       "CREATE TYPE %s AS (",
+                       fmtId(tinfo->typname, force_quotes));
+
+     for (i = 0; i < ntups; i++)
+     {
+         attname = PQgetvalue(res, i, PQfnumber(res, "attname"));
+         atttypdefn = PQgetvalue(res, i, PQfnumber(res, "atttypdefn"));
+         attbasetype = PQgetvalue(res, i, PQfnumber(res, "attbasetype"));
+
+         if (i > 0)
+             appendPQExpBuffer(q, ",\n\t %s %s", attname, atttypdefn);
+         else
+             appendPQExpBuffer(q, "%s %s", attname, atttypdefn);
+
+         /* Depends on the base type */
+         (*deps)[depIdx++] = strdup(attbasetype);
+     }
+     appendPQExpBuffer(q, ");\n");
+
+     (*deps)[depIdx++] = NULL;        /* End of List */
+
+     ArchiveEntry(fout, tinfo->oid, tinfo->typname,
+                  tinfo->typnamespace->nspname,
+                  tinfo->usename, "TYPE", deps,
+                  q->data, delq->data, NULL, NULL, NULL);
+
+     /*** Dump Type Comments ***/
+     resetPQExpBuffer(q);
+
+     appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->typname, force_quotes));
+     dumpComment(fout, q->data,
+                 tinfo->typnamespace->nspname, tinfo->usename,
+                 tinfo->oid, "pg_type", 0, NULL);
+
+     PQclear(res);
+     destroyPQExpBuffer(q);
+     destroyPQExpBuffer(delq);
+     destroyPQExpBuffer(query);
+ }
+
+ /*
   * dumpTypes
   *      writes out to fout the queries to recreate all the user-defined types
   */
***************
*** 3188,3195 ****
          if (!tinfo[i].typnamespace->dump)
              continue;

!         /* skip relation types */
!         if (atooid(tinfo[i].typrelid) != 0)
              continue;

          /* skip undefined placeholder types */
--- 3303,3310 ----
          if (!tinfo[i].typnamespace->dump)
              continue;

!         /* skip relation types for non-stand-alone type relations*/
!         if (atooid(tinfo[i].typrelid) != 0 && tinfo[i].typrelkind != 'c')
              continue;

          /* skip undefined placeholder types */
***************
*** 3207,3212 ****
--- 3322,3329 ----
                              finfo, numFuncs, tinfo, numTypes);
          else if (tinfo[i].typtype == 'd')
              dumpOneDomain(fout, &tinfo[i]);
+         else if (tinfo[i].typtype == 'c')
+             dumpOneCompositeType(fout, &tinfo[i]);
      }
  }

***************
*** 4832,4837 ****
--- 4949,4955 ----

          if (tbinfo->relkind != RELKIND_SEQUENCE)
              continue;
+
          if (tbinfo->dump)
          {
              dumpOneSequence(fout, tbinfo, schemaOnly, dataOnly);
***************
*** 4847,4852 ****
--- 4965,4972 ----
              TableInfo       *tbinfo = &tblinfo[i];

              if (tbinfo->relkind == RELKIND_SEQUENCE) /* already dumped */
+                 continue;
+             if (tbinfo->relkind == RELKIND_COMPOSITE_TYPE) /* dumped as a type */
                  continue;

              if (tbinfo->dump)
Index: src/bin/pg_dump/pg_dump.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/bin/pg_dump/pg_dump.h,v
retrieving revision 1.94
diff -c -r1.94 pg_dump.h
*** src/bin/pg_dump/pg_dump.h    2 Aug 2002 18:15:08 -0000    1.94
--- src/bin/pg_dump/pg_dump.h    15 Aug 2002 03:06:23 -0000
***************
*** 47,52 ****
--- 47,53 ----
      char       *usename;        /* name of owner, or empty string */
      char       *typelem;        /* OID */
      char       *typrelid;        /* OID */
+     char        typrelkind;        /* 'r', 'v', 'c', etc */
      char        typtype;        /* 'b', 'c', etc */
      bool        isArray;        /* true if user-defined array type */
      bool        isDefined;        /* true if typisdefined */
Index: src/bin/psql/describe.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/bin/psql/describe.c,v
retrieving revision 1.60
diff -c -r1.60 describe.c
*** src/bin/psql/describe.c    10 Aug 2002 16:01:16 -0000    1.60
--- src/bin/psql/describe.c    15 Aug 2002 04:14:09 -0000
***************
*** 210,218 ****

      /*
       * do not include array types (start with underscore), do not include
!      * user relations (typrelid!=0)
       */
!     appendPQExpBuffer(&buf, "WHERE t.typrelid = 0 AND t.typname !~ '^_'\n");

      /* Match name pattern against either internal or external name */
      processNamePattern(&buf, pattern, true, false,
--- 210,221 ----

      /*
       * do not include array types (start with underscore), do not include
!      * user relations (typrelid!=0) unless they are type relations
       */
!     appendPQExpBuffer(&buf, "WHERE (t.typrelid = 0 ");
!     appendPQExpBuffer(&buf, "OR (SELECT c.relkind = 'c' FROM pg_class c "
!                               "where c.oid = t.typrelid)) ");
!     appendPQExpBuffer(&buf, "AND t.typname !~ '^_'\n");

      /* Match name pattern against either internal or external name */
      processNamePattern(&buf, pattern, true, false,
Index: src/include/catalog/pg_class.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/catalog/pg_class.h,v
retrieving revision 1.70
diff -c -r1.70 pg_class.h
*** src/include/catalog/pg_class.h    2 Aug 2002 18:15:09 -0000    1.70
--- src/include/catalog/pg_class.h    15 Aug 2002 03:06:23 -0000
***************
*** 169,173 ****
--- 169,174 ----
  #define          RELKIND_UNCATALOGED      'u'        /* temporary heap */
  #define          RELKIND_TOASTVALUE      't'        /* moved off huge values */
  #define          RELKIND_VIEW              'v'        /* view */
+ #define          RELKIND_COMPOSITE_TYPE  'c'        /* composite type */

  #endif   /* PG_CLASS_H */
Index: src/include/commands/defrem.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/commands/defrem.h,v
retrieving revision 1.43
diff -c -r1.43 defrem.h
*** src/include/commands/defrem.h    29 Jul 2002 22:14:11 -0000    1.43
--- src/include/commands/defrem.h    15 Aug 2002 03:06:23 -0000
***************
*** 58,63 ****
--- 58,64 ----
  extern void RemoveTypeById(Oid typeOid);
  extern void DefineDomain(CreateDomainStmt *stmt);
  extern void RemoveDomain(List *names, DropBehavior behavior);
+ extern Oid DefineCompositeType(const RangeVar *typevar, List *coldeflist);

  extern void DefineOpClass(CreateOpClassStmt *stmt);
  extern void RemoveOpClass(RemoveOpClassStmt *stmt);
Index: src/include/nodes/nodes.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/nodes/nodes.h,v
retrieving revision 1.114
diff -c -r1.114 nodes.h
*** src/include/nodes/nodes.h    29 Jul 2002 22:14:11 -0000    1.114
--- src/include/nodes/nodes.h    15 Aug 2002 03:06:23 -0000
***************
*** 238,243 ****
--- 238,244 ----
      T_PrivTarget,
      T_InsertDefault,
      T_CreateOpClassItem,
+     T_CompositeTypeStmt,

      /*
       * TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h)
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/nodes/parsenodes.h,v
retrieving revision 1.198
diff -c -r1.198 parsenodes.h
*** src/include/nodes/parsenodes.h    4 Aug 2002 19:48:10 -0000    1.198
--- src/include/nodes/parsenodes.h    15 Aug 2002 03:06:23 -0000
***************
*** 1402,1407 ****
--- 1402,1419 ----
  } TransactionStmt;

  /* ----------------------
+  *        Create Type Statement, composite types
+  * ----------------------
+  */
+ typedef struct CompositeTypeStmt
+ {
+     NodeTag        type;
+     RangeVar   *typevar;        /* the composite type to be created */
+     List       *coldeflist;        /* list of ColumnDef nodes */
+ } CompositeTypeStmt;
+
+
+ /* ----------------------
   *        Create View Statement
   * ----------------------
   */
Index: src/pl/plpgsql/src/pl_comp.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/pl/plpgsql/src/pl_comp.c,v
retrieving revision 1.45
diff -c -r1.45 pl_comp.c
*** src/pl/plpgsql/src/pl_comp.c    12 Aug 2002 14:25:07 -0000    1.45
--- src/pl/plpgsql/src/pl_comp.c    15 Aug 2002 04:02:53 -0000
***************
*** 1028,1039 ****
      }

      /*
!      * It must be a relation, sequence or view
       */
      classStruct = (Form_pg_class) GETSTRUCT(classtup);
      if (classStruct->relkind != RELKIND_RELATION &&
          classStruct->relkind != RELKIND_SEQUENCE &&
!         classStruct->relkind != RELKIND_VIEW)
      {
          ReleaseSysCache(classtup);
          pfree(cp[0]);
--- 1028,1040 ----
      }

      /*
!      * It must be a relation, sequence, view, or type
       */
      classStruct = (Form_pg_class) GETSTRUCT(classtup);
      if (classStruct->relkind != RELKIND_RELATION &&
          classStruct->relkind != RELKIND_SEQUENCE &&
!         classStruct->relkind != RELKIND_VIEW &&
!         classStruct->relkind != RELKIND_COMPOSITE_TYPE)
      {
          ReleaseSysCache(classtup);
          pfree(cp[0]);
***************
*** 1145,1154 ****
      classStruct = (Form_pg_class) GETSTRUCT(classtup);
      relname = NameStr(classStruct->relname);

!     /* accept relation, sequence, or view pg_class entries */
      if (classStruct->relkind != RELKIND_RELATION &&
          classStruct->relkind != RELKIND_SEQUENCE &&
!         classStruct->relkind != RELKIND_VIEW)
          elog(ERROR, "%s isn't a table", relname);

      /*
--- 1146,1156 ----
      classStruct = (Form_pg_class) GETSTRUCT(classtup);
      relname = NameStr(classStruct->relname);

!     /* accept relation, sequence, view, or type pg_class entries */
      if (classStruct->relkind != RELKIND_RELATION &&
          classStruct->relkind != RELKIND_SEQUENCE &&
!         classStruct->relkind != RELKIND_VIEW &&
!         classStruct->relkind != RELKIND_COMPOSITE_TYPE)
          elog(ERROR, "%s isn't a table", relname);

      /*
Index: src/test/regress/expected/create_type.out
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/test/regress/expected/create_type.out,v
retrieving revision 1.4
diff -c -r1.4 create_type.out
*** src/test/regress/expected/create_type.out    6 Sep 2001 02:07:42 -0000    1.4
--- src/test/regress/expected/create_type.out    15 Aug 2002 03:06:23 -0000
***************
*** 37,40 ****
--- 37,53 ----
   zippo | 42
  (1 row)

+ -- Test stand-alone composite type
+ CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+ CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
+   SELECT * FROM default_test;
+ ' LANGUAGE SQL;
+ SELECT * FROM get_default_test();
+   f1   | f2
+ -------+----
+  zippo | 42
+ (1 row)
+
+ DROP TYPE default_test_row CASCADE;
+ NOTICE:  Drop cascades to function get_default_test()
  DROP TABLE default_test;
Index: src/test/regress/sql/create_type.sql
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/test/regress/sql/create_type.sql,v
retrieving revision 1.4
diff -c -r1.4 create_type.sql
*** src/test/regress/sql/create_type.sql    6 Sep 2001 02:07:42 -0000    1.4
--- src/test/regress/sql/create_type.sql    15 Aug 2002 03:06:23 -0000
***************
*** 41,44 ****
--- 41,56 ----

  SELECT * FROM default_test;

+ -- Test stand-alone composite type
+
+ CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+
+ CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
+   SELECT * FROM default_test;
+ ' LANGUAGE SQL;
+
+ SELECT * FROM get_default_test();
+
+ DROP TYPE default_test_row CASCADE;
+
  DROP TABLE default_test;

pgsql-patches by date:

Previous
From: Rod Taylor
Date:
Subject: Docbook 4.2 support
Next
From: "Ulrich Neumann"
Date:
Subject: Antw: Re: File for /src/backend/port/netware