Re: stand-alone composite types patch (was [HACKERS] Proposal:

Bruce Momjian <pgman@candle.pha.pa.us>

From: Bruce Momjian <pgman@candle.pha.pa.us>
To: Joe Conway <mail@joeconway.com>
Cc: Tom Lane <tgl@sss.pgh.pa.us>, Patches <pgsql-patches@postgresql.org>
Date: 2002-08-11T05:09:17Z
Lists: pgsql-hackers
Your patch has been added to the PostgreSQL unapplied patches list at:

	http://candle.pha.pa.us/cgi-bin/pgpatches

I will try to apply it within the next 48 hours.

---------------------------------------------------------------------------


Joe Conway wrote:
> Tom Lane wrote:
> > If you did it that way then you'd not need that ugly kluge in
> > RemoveType.  What you'd need instead is some smarts (a kluge!?) in
> > setting up the dependency.  Currently that dependency is made in
> > TypeCreate which doesn't know what sort of relation it's creating
> > a type for.  Probably the best answer is to pull that particular
> > dependency out of TypeCreate, and make it (in the proper direction)
> > in AddNewRelationType.
> 
> Fixed.
> 
> > Also, I'm not following the point of the separation between
> > DefineCompositeType and DefineCompositeTypeRelation; nor do I see a need
> > for a CommandCounterIncrement call in there.
> 
> Fixed.
> 
> 
> > You have missed a number of places where this new relkind ought to
> > be special-cased the same way RELKIND_VIEW is --- for example
> > CheckAttributeNames and AddNewAttributeTuples, since a composite type
> > presumably shouldn't have system columns associated.  I'd counsel
> > looking at all references to RELKIND_VIEW to see which places also need
> > to check for RELKIND_COMPOSITE_TYPE.
> 
> Yup, I had missed lots of things, not the least of which was pg_dump. 
> New patch attached includes pg_dump, psql (\dT), docs, and regression 
> support.
> 
> There is also a small adjustment to the expected output file for 
> select-having. I was getting a regression failure based on ordering of 
> the results, so I added ORDER BY clauses.
> 
> Passes all regression tests. If no more objections, please apply.
> 
> Thanks,
> 
> 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	8 Aug 2002 14:49:57 -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.219
> diff -c -r1.219 heap.c
> *** src/backend/catalog/heap.c	6 Aug 2002 02:36:33 -0000	1.219
> --- src/backend/catalog/heap.c	8 Aug 2002 14:49:57 -0000
> ***************
> *** 358,364 ****
>   	 *
>   	 * Skip this for a view, since it doesn't have system attributes.
>   	 */
> ! 	if (relkind != RELKIND_VIEW)
>   	{
>   		for (i = 0; i < natts; i++)
>   		{
> --- 358,364 ----
>   	 *
>   	 * Skip this for a view, since it doesn't have system attributes.
>   	 */
> ! 	if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE)
>   	{
>   		for (i = 0; i < natts; i++)
>   		{
> ***************
> *** 475,481 ****
>   	 * Skip all for a view.  We don't bother with making datatype
>   	 * dependencies here, since presumably all these types are pinned.
>   	 */
> ! 	if (relkind != RELKIND_VIEW)
>   	{
>   		dpp = SysAtt;
>   		for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++)
> --- 475,481 ----
>   	 * Skip all for a view.  We don't bother with making datatype
>   	 * dependencies here, since presumably all these types are pinned.
>   	 */
> ! 	if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE)
>   	{
>   		dpp = SysAtt;
>   		for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++)
> ***************
> *** 764,770 ****
>   	/*
>   	 * We create the disk file for this relation here
>   	 */
> ! 	if (relkind != RELKIND_VIEW)
>   		heap_storage_create(new_rel_desc);
>   
>   	/*
> --- 764,770 ----
>   	/*
>   	 * We create the disk file for this relation here
>   	 */
> ! 	if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE)
>   		heap_storage_create(new_rel_desc);
>   
>   	/*
> ***************
> *** 1135,1141 ****
>   	/*
>   	 * unlink the relation's physical file and finish up.
>   	 */
> ! 	if (rel->rd_rel->relkind != RELKIND_VIEW)
>   		smgrunlink(DEFAULT_SMGR, rel);
>   
>   	/*
> --- 1135,1142 ----
>   	/*
>   	 * unlink the relation's physical file and finish up.
>   	 */
> ! 	if (rel->rd_rel->relkind != RELKIND_VIEW &&
> ! 			rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE)
>   		smgrunlink(DEFAULT_SMGR, rel);
>   
>   	/*
> Index: src/backend/catalog/namespace.c
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/backend/catalog/namespace.c,v
> retrieving revision 1.29
> diff -c -r1.29 namespace.c
> *** src/backend/catalog/namespace.c	8 Aug 2002 01:44:30 -0000	1.29
> --- src/backend/catalog/namespace.c	8 Aug 2002 14:49:57 -0000
> ***************
> *** 1578,1583 ****
> --- 1578,1584 ----
>   			case RELKIND_RELATION:
>   			case RELKIND_SEQUENCE:
>   			case RELKIND_VIEW:
> + 			case RELKIND_COMPOSITE_TYPE:
>   				AssertTupleDescHasOid(pgclass->rd_att);
>   				object.classId = RelOid_pg_class;
>   				object.objectId = HeapTupleGetOid(tuple);
> Index: src/backend/catalog/pg_type.c
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/backend/catalog/pg_type.c,v
> retrieving revision 1.77
> diff -c -r1.77 pg_type.c
> *** src/backend/catalog/pg_type.c	5 Aug 2002 03:29:16 -0000	1.77
> --- src/backend/catalog/pg_type.c	8 Aug 2002 17:30:27 -0000
> ***************
> *** 311,325 ****
>   
>   		/*
>   		 * If the type is a rowtype for a relation, mark it as internally
> ! 		 * dependent on the relation.  This allows it to be auto-dropped
> ! 		 * when the relation is, and not otherwise.
>   		 */
>   		if (OidIsValid(relationOid))
>   		{
>   			referenced.classId = RelOid_pg_class;
>   			referenced.objectId = relationOid;
>   			referenced.objectSubId = 0;
> ! 			recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
>   		}
>   
>   		/*
> --- 311,338 ----
>   
>   		/*
>   		 * If the type is a rowtype for a relation, mark it as internally
> ! 		 * dependent on the relation, *unless* it is a stand-alone composite
> ! 		 * type relation. For the latter case, we have to reverse the
> ! 		 * dependency.
> ! 		 *
> ! 		 * In the former case, this allows the type to be auto-dropped
> ! 		 * when the relation is, and not otherwise. And in the latter,
> ! 		 * of course we get the opposite effect.
>   		 */
>   		if (OidIsValid(relationOid))
>   		{
> + 			Relation	rel = relation_open(relationOid, AccessShareLock);
> + 			char		relkind = rel->rd_rel->relkind;
> + 			relation_close(rel, AccessShareLock);
> + 
>   			referenced.classId = RelOid_pg_class;
>   			referenced.objectId = relationOid;
>   			referenced.objectSubId = 0;
> ! 
> ! 			if (relkind != RELKIND_COMPOSITE_TYPE)
> ! 				recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
> ! 			else
> ! 				recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
>   		}
>   
>   		/*
> Index: src/backend/commands/copy.c
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/backend/commands/copy.c,v
> retrieving revision 1.162
> diff -c -r1.162 copy.c
> *** src/backend/commands/copy.c	2 Aug 2002 18:15:06 -0000	1.162
> --- src/backend/commands/copy.c	8 Aug 2002 14:49:57 -0000
> ***************
> *** 398,403 ****
> --- 398,406 ----
>   			if (rel->rd_rel->relkind == RELKIND_VIEW)
>   				elog(ERROR, "You cannot copy view %s",
>   					 RelationGetRelationName(rel));
> + 			else if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
> + 				elog(ERROR, "You cannot copy type relation %s",
> + 					 RelationGetRelationName(rel));
>   			else if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
>   				elog(ERROR, "You cannot change sequence relation %s",
>   					 RelationGetRelationName(rel));
> ***************
> *** 442,447 ****
> --- 445,453 ----
>   		{
>   			if (rel->rd_rel->relkind == RELKIND_VIEW)
>   				elog(ERROR, "You cannot copy view %s",
> + 					 RelationGetRelationName(rel));
> + 			else if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
> + 				elog(ERROR, "You cannot copy type relation %s",
>   					 RelationGetRelationName(rel));
>   			else if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
>   				elog(ERROR, "You cannot copy sequence %s",
> Index: src/backend/commands/tablecmds.c
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/backend/commands/tablecmds.c,v
> retrieving revision 1.28
> diff -c -r1.28 tablecmds.c
> *** src/backend/commands/tablecmds.c	7 Aug 2002 21:45:01 -0000	1.28
> --- src/backend/commands/tablecmds.c	8 Aug 2002 18:04:58 -0000
> ***************
> *** 345,350 ****
> --- 345,354 ----
>   		elog(ERROR, "TRUNCATE cannot be used on views. '%s' is a view",
>   			 RelationGetRelationName(rel));
>   
> + 	if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
> + 		elog(ERROR, "TRUNCATE cannot be used on type relations. '%s' is a type",
> + 			 RelationGetRelationName(rel));
> + 
>   	if (!allowSystemTableMods && IsSystemRelation(rel))
>   		elog(ERROR, "TRUNCATE cannot be used on system tables. '%s' is a system table",
>   			 RelationGetRelationName(rel));
> ***************
> *** 3210,3221 ****
>   		case RELKIND_RELATION:
>   		case RELKIND_INDEX:
>   		case RELKIND_VIEW:
>   		case RELKIND_SEQUENCE:
>   		case RELKIND_TOASTVALUE:
>   			/* ok to change owner */
>   			break;
>   		default:
> ! 			elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table, TOAST table, index, view, or sequence",
>   				 NameStr(tuple_class->relname));
>   	}
>   }
> --- 3214,3226 ----
>   		case RELKIND_RELATION:
>   		case RELKIND_INDEX:
>   		case RELKIND_VIEW:
> + 		case RELKIND_COMPOSITE_TYPE:
>   		case RELKIND_SEQUENCE:
>   		case RELKIND_TOASTVALUE:
>   			/* ok to change owner */
>   			break;
>   		default:
> ! 			elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table, TOAST table, index, view, type, or sequence",
>   				 NameStr(tuple_class->relname));
>   	}
>   }
> Index: src/backend/commands/typecmds.c
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/backend/commands/typecmds.c,v
> retrieving revision 1.8
> diff -c -r1.8 typecmds.c
> *** src/backend/commands/typecmds.c	24 Jul 2002 19:11:09 -0000	1.8
> --- src/backend/commands/typecmds.c	8 Aug 2002 17:33:43 -0000
> ***************
> *** 38,43 ****
> --- 38,44 ----
>   #include "catalog/namespace.h"
>   #include "catalog/pg_type.h"
>   #include "commands/defrem.h"
> + #include "commands/tablecmds.h"
>   #include "miscadmin.h"
>   #include "parser/parse_func.h"
>   #include "parser/parse_type.h"
> ***************
> *** 50,56 ****
>   
>   static Oid findTypeIOFunction(List *procname, bool isOutput);
>   
> - 
>   /*
>    * DefineType
>    *		Registers a new type.
> --- 51,56 ----
> ***************
> *** 665,668 ****
> --- 665,707 ----
>   	}
>   
>   	return procOid;
> + }
> + 
> + /*-------------------------------------------------------------------
> +  * DefineCompositeType
> +  *
> +  * Create a Composite Type relation.
> +  * `DefineRelation' does all the work, we just provide the correct
> +  * arguments!
> +  *
> +  * If the relation already exists, then 'DefineRelation' will abort
> +  * the xact...
> +  *
> +  * DefineCompositeType returns relid for use when creating
> +  * an implicit composite type during function creation
> +  *-------------------------------------------------------------------
> +  */
> + Oid
> + DefineCompositeType(const RangeVar *typevar, List *coldeflist)
> + {
> + 	CreateStmt *createStmt = makeNode(CreateStmt);
> + 
> + 	if (coldeflist == NIL)
> + 		elog(ERROR, "attempted to define composite type relation with"
> + 					" no attrs");
> + 
> + 	/*
> + 	 * now create the parameters for keys/inheritance etc. All of them are
> + 	 * nil...
> + 	 */
> + 	createStmt->relation = (RangeVar *) typevar;
> + 	createStmt->tableElts = coldeflist;
> + 	createStmt->inhRelations = NIL;
> + 	createStmt->constraints = NIL;
> + 	createStmt->hasoids = false;
> + 
> + 	/*
> + 	 * finally create the relation...
> + 	 */
> + 	return DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE);
>   }
> Index: src/backend/executor/execMain.c
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/backend/executor/execMain.c,v
> retrieving revision 1.173
> diff -c -r1.173 execMain.c
> *** src/backend/executor/execMain.c	7 Aug 2002 21:45:02 -0000	1.173
> --- src/backend/executor/execMain.c	8 Aug 2002 14:49:57 -0000
> ***************
> *** 786,791 ****
> --- 786,795 ----
>   			elog(ERROR, "You can't change view relation %s",
>   				 RelationGetRelationName(resultRelationDesc));
>   			break;
> + 		case RELKIND_COMPOSITE_TYPE:
> + 			elog(ERROR, "You can't change type relation %s",
> + 				 RelationGetRelationName(resultRelationDesc));
> + 			break;
>   	}
>   
>   	MemSet(resultRelInfo, 0, sizeof(ResultRelInfo));
> Index: src/backend/nodes/copyfuncs.c
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/copyfuncs.c,v
> retrieving revision 1.200
> diff -c -r1.200 copyfuncs.c
> *** src/backend/nodes/copyfuncs.c	4 Aug 2002 19:48:09 -0000	1.200
> --- src/backend/nodes/copyfuncs.c	8 Aug 2002 14:49:58 -0000
> ***************
> *** 2233,2238 ****
> --- 2233,2249 ----
>   	return newnode;
>   }
>   
> + static CompositeTypeStmt *
> + _copyCompositeTypeStmt(CompositeTypeStmt *from)
> + {
> + 	CompositeTypeStmt   *newnode = makeNode(CompositeTypeStmt);
> + 
> + 	Node_Copy(from, newnode, typevar);
> + 	Node_Copy(from, newnode, coldeflist);
> + 
> + 	return newnode;
> + }
> + 
>   static ViewStmt *
>   _copyViewStmt(ViewStmt *from)
>   {
> ***************
> *** 2938,2943 ****
> --- 2949,2957 ----
>   			break;
>   		case T_TransactionStmt:
>   			retval = _copyTransactionStmt(from);
> + 			break;
> + 		case T_CompositeTypeStmt:
> + 			retval = _copyCompositeTypeStmt(from);
>   			break;
>   		case T_ViewStmt:
>   			retval = _copyViewStmt(from);
> Index: src/backend/nodes/equalfuncs.c
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/equalfuncs.c,v
> retrieving revision 1.149
> diff -c -r1.149 equalfuncs.c
> *** src/backend/nodes/equalfuncs.c	4 Aug 2002 23:49:59 -0000	1.149
> --- src/backend/nodes/equalfuncs.c	8 Aug 2002 14:49:58 -0000
> ***************
> *** 1062,1067 ****
> --- 1062,1078 ----
>   }
>   
>   static bool
> + _equalCompositeTypeStmt(CompositeTypeStmt *a, CompositeTypeStmt *b)
> + {
> + 	if (!equal(a->typevar, b->typevar))
> + 		return false;
> + 	if (!equal(a->coldeflist, b->coldeflist))
> + 		return false;
> + 
> + 	return true;
> + }
> + 
> + static bool
>   _equalViewStmt(ViewStmt *a, ViewStmt *b)
>   {
>   	if (!equal(a->view, b->view))
> ***************
> *** 2110,2115 ****
> --- 2121,2129 ----
>   			break;
>   		case T_TransactionStmt:
>   			retval = _equalTransactionStmt(a, b);
> + 			break;
> + 		case T_CompositeTypeStmt:
> + 			retval = _equalCompositeTypeStmt(a, b);
>   			break;
>   		case T_ViewStmt:
>   			retval = _equalViewStmt(a, b);
> Index: src/backend/parser/gram.y
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/backend/parser/gram.y,v
> retrieving revision 2.357
> diff -c -r2.357 gram.y
> *** src/backend/parser/gram.y	6 Aug 2002 05:40:45 -0000	2.357
> --- src/backend/parser/gram.y	8 Aug 2002 14:49:58 -0000
> ***************
> *** 205,211 ****
>   
>   %type <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,
> ***************
> *** 2247,2252 ****
> --- 2247,2285 ----
>   					n->definition = $4;
>   					$$ = (Node *)n;
>   				}
> + 			| CREATE TYPE_P any_name AS rowdefinition
> + 				{
> + 					CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
> + 					RangeVar *r = makeNode(RangeVar);
> + 
> + 					switch (length($3))
> + 					{
> + 						case 1:
> + 							r->catalogname = NULL;
> + 							r->schemaname = NULL;
> + 							r->relname = strVal(lfirst($3));
> + 							break;
> + 						case 2:
> + 							r->catalogname = NULL;
> + 							r->schemaname = strVal(lfirst($3));
> + 							r->relname = strVal(lsecond($3));
> + 							break;
> + 						case 3:
> + 							r->catalogname = strVal(lfirst($3));
> + 							r->schemaname = strVal(lsecond($3));
> + 							r->relname = strVal(lfirst(lnext(lnext($3))));
> + 							break;
> + 						default:
> + 							elog(ERROR,
> + 							"Improper qualified name "
> + 							"(too many dotted names): %s",
> + 								 NameListToString($3));
> + 							break;
> + 					}
> + 					n->typevar = r;
> + 					n->coldeflist = $5;
> + 					$$ = (Node *)n;
> + 				}
>   			| CREATE CHARACTER SET opt_as any_name GET definition opt_collate
>   				{
>   					DefineStmt *n = makeNode(DefineStmt);
> ***************
> *** 2255,2260 ****
> --- 2288,2296 ----
>   					n->definition = $7;
>   					$$ = (Node *)n;
>   				}
> + 		;
> + 
> + rowdefinition: '(' TableFuncElementList ')'			{ $$ = $2; }
>   		;
>   
>   definition: '(' def_list ')'						{ $$ = $2; }
> Index: src/backend/storage/buffer/bufmgr.c
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/backend/storage/buffer/bufmgr.c,v
> retrieving revision 1.128
> diff -c -r1.128 bufmgr.c
> *** src/backend/storage/buffer/bufmgr.c	6 Aug 2002 02:36:34 -0000	1.128
> --- src/backend/storage/buffer/bufmgr.c	8 Aug 2002 14:49:58 -0000
> ***************
> *** 1056,1061 ****
> --- 1056,1063 ----
>   	 */
>   	if (relation->rd_rel->relkind == RELKIND_VIEW)
>   		relation->rd_nblocks = 0;
> + 	else if (relation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
> + 		relation->rd_nblocks = 0;
>   	else if (!relation->rd_isnew && !relation->rd_istemp)
>   		relation->rd_nblocks = smgrnblocks(DEFAULT_SMGR, relation);
>   	return relation->rd_nblocks;
> Index: src/backend/storage/smgr/smgr.c
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/backend/storage/smgr/smgr.c,v
> retrieving revision 1.58
> diff -c -r1.58 smgr.c
> *** src/backend/storage/smgr/smgr.c	6 Aug 2002 02:36:34 -0000	1.58
> --- src/backend/storage/smgr/smgr.c	8 Aug 2002 14:49:59 -0000
> ***************
> *** 263,268 ****
> --- 263,270 ----
>   
>   	if (reln->rd_rel->relkind == RELKIND_VIEW)
>   		return -1;
> + 	if (reln->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
> + 		return -1;
>   	if ((fd = (*(smgrsw[which].smgr_open)) (reln)) < 0)
>   		if (!failOK)
>   			elog(ERROR, "cannot open %s: %m", RelationGetRelationName(reln));
> Index: src/backend/tcop/postgres.c
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/backend/tcop/postgres.c,v
> retrieving revision 1.280
> diff -c -r1.280 postgres.c
> *** src/backend/tcop/postgres.c	6 Aug 2002 05:24:04 -0000	1.280
> --- src/backend/tcop/postgres.c	8 Aug 2002 14:49:59 -0000
> ***************
> *** 2264,2269 ****
> --- 2264,2273 ----
>   			}
>   			break;
>   
> + 		case T_CompositeTypeStmt:
> + 			tag = "CREATE TYPE";
> + 			break;
> + 
>   		case T_ViewStmt:
>   			tag = "CREATE VIEW";
>   			break;
> Index: src/backend/tcop/utility.c
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/backend/tcop/utility.c,v
> retrieving revision 1.169
> diff -c -r1.169 utility.c
> *** src/backend/tcop/utility.c	7 Aug 2002 21:45:02 -0000	1.169
> --- src/backend/tcop/utility.c	8 Aug 2002 14:49:59 -0000
> ***************
> *** 70,75 ****
> --- 70,76 ----
>   	{RELKIND_SEQUENCE, "a", "sequence", "SEQUENCE"},
>   	{RELKIND_VIEW, "a", "view", "VIEW"},
>   	{RELKIND_INDEX, "an", "index", "INDEX"},
> + 	{RELKIND_COMPOSITE_TYPE, "a", "type", "TYPE"},
>   	{'\0', "a", "???", "???"}
>   };
>   
> ***************
> *** 570,575 ****
> --- 571,589 ----
>   						DefineAggregate(stmt->defnames, stmt->definition);
>   						break;
>   				}
> + 			}
> + 			break;
> + 
> + 		case T_CompositeTypeStmt:		/* CREATE TYPE (composite) */
> + 			{
> + 				Oid	relid;
> + 				CompositeTypeStmt   *stmt = (CompositeTypeStmt *) parsetree;
> + 
> + 				/*
> + 				 * DefineCompositeType returns relid for use when creating
> + 				 * an implicit composite type during function creation
> + 				 */
> + 				relid = DefineCompositeType(stmt->typevar, stmt->coldeflist);
>   			}
>   			break;
>   
> Index: src/backend/utils/adt/tid.c
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/adt/tid.c,v
> retrieving revision 1.32
> diff -c -r1.32 tid.c
> *** src/backend/utils/adt/tid.c	16 Jul 2002 17:55:25 -0000	1.32
> --- src/backend/utils/adt/tid.c	8 Aug 2002 14:49:59 -0000
> ***************
> *** 226,231 ****
> --- 226,234 ----
>   	if (rel->rd_rel->relkind == RELKIND_VIEW)
>   		return currtid_for_view(rel, tid);
>   
> + 	if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
> + 		elog(ERROR, "currtid can't handle type relations");
> + 
>   	ItemPointerCopy(tid, result);
>   	heap_get_latest_tid(rel, SnapshotNow, result);
>   
> ***************
> *** 248,253 ****
> --- 251,259 ----
>   	rel = heap_openrv(relrv, AccessShareLock);
>   	if (rel->rd_rel->relkind == RELKIND_VIEW)
>   		return currtid_for_view(rel, tid);
> + 
> + 	if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
> + 		elog(ERROR, "currtid can't handle type relations");
>   
>   	result = (ItemPointer) palloc(sizeof(ItemPointerData));
>   	ItemPointerCopy(tid, result);
> Index: src/bin/pg_dump/common.c
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/bin/pg_dump/common.c,v
> retrieving revision 1.67
> diff -c -r1.67 common.c
> *** src/bin/pg_dump/common.c	30 Jul 2002 21:56:04 -0000	1.67
> --- src/bin/pg_dump/common.c	8 Aug 2002 14:49:59 -0000
> ***************
> *** 215,223 ****
>   
>   	for (i = 0; i < numTables; i++)
>   	{
> ! 		/* Sequences and views never have parents */
>   		if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
> ! 			tblinfo[i].relkind == RELKIND_VIEW)
>   			continue;
>   
>   		/* Don't bother computing anything for non-target tables, either */
> --- 215,224 ----
>   
>   	for (i = 0; i < numTables; i++)
>   	{
> ! 		/* Sequences, views, and types never have parents */
>   		if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
> ! 			tblinfo[i].relkind == RELKIND_VIEW ||
> ! 			tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
>   			continue;
>   
>   		/* Don't bother computing anything for non-target tables, either */
> ***************
> *** 269,277 ****
>   
>   	for (i = 0; i < numTables; i++)
>   	{
> ! 		/* Sequences and views never have parents */
>   		if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
> ! 			tblinfo[i].relkind == RELKIND_VIEW)
>   			continue;
>   
>   		/* Don't bother computing anything for non-target tables, either */
> --- 270,279 ----
>   
>   	for (i = 0; i < numTables; i++)
>   	{
> ! 		/* Sequences, views, and types never have parents */
>   		if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
> ! 			tblinfo[i].relkind == RELKIND_VIEW ||
> ! 			tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
>   			continue;
>   
>   		/* Don't bother computing anything for non-target tables, either */
> Index: src/bin/pg_dump/pg_dump.c
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/bin/pg_dump/pg_dump.c,v
> retrieving revision 1.280
> diff -c -r1.280 pg_dump.c
> *** src/bin/pg_dump/pg_dump.c	4 Aug 2002 05:03:29 -0000	1.280
> --- src/bin/pg_dump/pg_dump.c	8 Aug 2002 22:42:58 -0000
> ***************
> *** 95,100 ****
> --- 95,101 ----
>   							FuncInfo *g_finfo, int numFuncs,
>   							TypeInfo *g_tinfo, int numTypes);
>   static void dumpOneDomain(Archive *fout, TypeInfo *tinfo);
> + static void dumpOneCompositeType(Archive *fout, TypeInfo *tinfo);
>   static void dumpOneTable(Archive *fout, TableInfo *tbinfo,
>   						 TableInfo *g_tblinfo);
>   static void dumpOneSequence(Archive *fout, TableInfo *tbinfo,
> ***************
> *** 1178,1183 ****
> --- 1179,1188 ----
>   		if (tblinfo[i].relkind == RELKIND_VIEW)
>   			continue;
>   
> + 		/* Skip TYPE relations */
> + 		if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
> + 			continue;
> + 
>   		if (tblinfo[i].relkind == RELKIND_SEQUENCE)		/* already dumped */
>   			continue;
>   
> ***************
> *** 1582,1587 ****
> --- 1587,1593 ----
>   	int			i_usename;
>   	int			i_typelem;
>   	int			i_typrelid;
> + 	int			i_typrelkind;
>   	int			i_typtype;
>   	int			i_typisdefined;
>   
> ***************
> *** 1602,1608 ****
>   		appendPQExpBuffer(query, "SELECT pg_type.oid, typname, "
>   						  "typnamespace, "
>   						  "(select usename from pg_user where typowner = usesysid) as usename, "
> ! 						  "typelem, typrelid, typtype, typisdefined "
>   						  "FROM pg_type");
>   	}
>   	else
> --- 1608,1616 ----
>   		appendPQExpBuffer(query, "SELECT pg_type.oid, typname, "
>   						  "typnamespace, "
>   						  "(select usename from pg_user where typowner = usesysid) as usename, "
> ! 						  "typelem, typrelid, "
> ! 						  "(select relkind from pg_class where oid = typrelid) as typrelkind, "
> ! 						  "typtype, typisdefined "
>   						  "FROM pg_type");
>   	}
>   	else
> ***************
> *** 1610,1616 ****
>   		appendPQExpBuffer(query, "SELECT pg_type.oid, typname, "
>   						  "0::oid as typnamespace, "
>   						  "(select usename from pg_user where typowner = usesysid) as usename, "
> ! 						  "typelem, typrelid, typtype, typisdefined "
>   						  "FROM pg_type");
>   	}
>   
> --- 1618,1626 ----
>   		appendPQExpBuffer(query, "SELECT pg_type.oid, typname, "
>   						  "0::oid as typnamespace, "
>   						  "(select usename from pg_user where typowner = usesysid) as usename, "
> ! 						  "typelem, typrelid, "
> ! 						  "''::char as typrelkind, "
> ! 						  "typtype, typisdefined "
>   						  "FROM pg_type");
>   	}
>   
> ***************
> *** 1632,1637 ****
> --- 1642,1648 ----
>   	i_usename = PQfnumber(res, "usename");
>   	i_typelem = PQfnumber(res, "typelem");
>   	i_typrelid = PQfnumber(res, "typrelid");
> + 	i_typrelkind = PQfnumber(res, "typrelkind");
>   	i_typtype = PQfnumber(res, "typtype");
>   	i_typisdefined = PQfnumber(res, "typisdefined");
>   
> ***************
> *** 1644,1649 ****
> --- 1655,1661 ----
>   		tinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
>   		tinfo[i].typelem = strdup(PQgetvalue(res, i, i_typelem));
>   		tinfo[i].typrelid = strdup(PQgetvalue(res, i, i_typrelid));
> + 		tinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
>   		tinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
>   
>   		/*
> ***************
> *** 2109,2115 ****
>   		appendPQExpBuffer(query,
>   						  "SELECT pg_class.oid, relname, relacl, relkind, "
>   						  "relnamespace, "
> - 
>   						  "(select usename from pg_user where relowner = usesysid) as usename, "
>   						  "relchecks, reltriggers, "
>   						  "relhasindex, relhasrules, relhasoids "
> --- 2121,2126 ----
> ***************
> *** 2120,2125 ****
> --- 2131,2137 ----
>   	}
>   	else if (g_fout->remoteVersion >= 70200)
>   	{
> + 		/* before 7.3 there were no type relations with relkind 'c' */
>   		appendPQExpBuffer(query,
>   						  "SELECT pg_class.oid, relname, relacl, relkind, "
>   						  "0::oid as relnamespace, "
> ***************
> *** 2363,2368 ****
> --- 2375,2384 ----
>   		if (tblinfo[i].relkind == RELKIND_SEQUENCE)
>   			continue;
>   
> + 		/* Don't bother to collect info for type relations */
> + 		if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
> + 			continue;
> + 
>   		/* Don't bother with uninteresting tables, either */
>   		if (!tblinfo[i].interesting)
>   			continue;
> ***************
> *** 3180,3185 ****
> --- 3196,3300 ----
>   }
>   
>   /*
> +  * dumpOneCompositeType
> +  *    writes out to fout the queries to recreate a user-defined stand-alone
> +  *    composite type as requested by dumpTypes
> +  */
> + static void
> + dumpOneCompositeType(Archive *fout, TypeInfo *tinfo)
> + {
> + 	PQExpBuffer q = createPQExpBuffer();
> + 	PQExpBuffer delq = createPQExpBuffer();
> + 	PQExpBuffer query = createPQExpBuffer();
> + 	PGresult   *res;
> + 	int			ntups;
> + 	char	   *attname;
> + 	char	   *atttypdefn;
> + 	char	   *attbasetype;
> + 	const char *((*deps)[]);
> + 	int			depIdx = 0;
> + 	int			i;
> + 
> + 	deps = malloc(sizeof(char *) * 10);
> + 
> + 	/* Set proper schema search path so type references list correctly */
> + 	selectSourceSchema(tinfo->typnamespace->nspname);
> + 
> + 	/* Fetch type specific details */
> + 	/* We assume here that remoteVersion must be at least 70300 */
> + 
> + 	appendPQExpBuffer(query, "SELECT a.attname, "
> + 					  "pg_catalog.format_type(a.atttypid, a.atttypmod) as atttypdefn, "
> + 					  "a.atttypid as attbasetype "
> + 					  "FROM pg_catalog.pg_type t, pg_catalog.pg_attribute a "
> + 					  "WHERE t.oid = '%s'::pg_catalog.oid "
> + 					  "AND a.attrelid = t.typrelid",
> + 					  tinfo->oid);
> + 
> + 	res = PQexec(g_conn, query->data);
> + 	if (!res ||
> + 		PQresultStatus(res) != PGRES_TUPLES_OK)
> + 	{
> + 		write_msg(NULL, "query to obtain type information failed: %s", PQerrorMessage(g_conn));
> + 		exit_nicely();
> + 	}
> + 
> + 	/* Expecting at least a single result */
> + 	ntups = PQntuples(res);
> + 	if (ntups < 1)
> + 	{
> + 		write_msg(NULL, "Got no rows from: %s", query->data);
> + 		exit_nicely();
> + 	}
> + 
> + 	/* DROP must be fully qualified in case same name appears in pg_catalog */
> + 	appendPQExpBuffer(delq, "DROP TYPE %s.",
> + 					  fmtId(tinfo->typnamespace->nspname, force_quotes));
> + 	appendPQExpBuffer(delq, "%s RESTRICT;\n",
> + 					  fmtId(tinfo->typname, force_quotes));
> + 
> + 	appendPQExpBuffer(q,
> + 					  "CREATE TYPE %s AS (",
> + 					  fmtId(tinfo->typname, force_quotes));
> + 
> + 	for (i = 0; i < ntups; i++)
> + 	{
> + 		attname = PQgetvalue(res, i, PQfnumber(res, "attname"));
> + 		atttypdefn = PQgetvalue(res, i, PQfnumber(res, "atttypdefn"));
> + 		attbasetype = PQgetvalue(res, i, PQfnumber(res, "attbasetype"));
> + 
> + 		if (i > 0)
> + 			appendPQExpBuffer(q, ",\n\t %s %s", attname, atttypdefn);
> + 		else
> + 			appendPQExpBuffer(q, "%s %s", attname, atttypdefn);
> + 
> + 		/* Depends on the base type */
> + 		(*deps)[depIdx++] = strdup(attbasetype);
> + 	}
> + 	appendPQExpBuffer(q, ");\n");
> + 
> + 	(*deps)[depIdx++] = NULL;		/* End of List */
> + 
> + 	ArchiveEntry(fout, tinfo->oid, tinfo->typname,
> + 				 tinfo->typnamespace->nspname,
> + 				 tinfo->usename, "TYPE", deps,
> + 				 q->data, delq->data, NULL, NULL, NULL);
> + 
> + 	/*** Dump Type Comments ***/
> + 	resetPQExpBuffer(q);
> + 
> + 	appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->typname, force_quotes));
> + 	dumpComment(fout, q->data,
> + 				tinfo->typnamespace->nspname, tinfo->usename,
> + 				tinfo->oid, "pg_type", 0, NULL);
> + 
> + 	PQclear(res);
> + 	destroyPQExpBuffer(q);
> + 	destroyPQExpBuffer(delq);
> + 	destroyPQExpBuffer(query);
> + }
> + 
> + /*
>    * dumpTypes
>    *	  writes out to fout the queries to recreate all the user-defined types
>    */
> ***************
> *** 3195,3202 ****
>   		if (!tinfo[i].typnamespace->dump)
>   			continue;
>   
> ! 		/* skip relation types */
> ! 		if (atooid(tinfo[i].typrelid) != 0)
>   			continue;
>   
>   		/* skip undefined placeholder types */
> --- 3310,3317 ----
>   		if (!tinfo[i].typnamespace->dump)
>   			continue;
>   
> ! 		/* skip relation types for non-stand-alone type relations*/
> ! 		if (atooid(tinfo[i].typrelid) != 0 && tinfo[i].typrelkind != 'c')
>   			continue;
>   
>   		/* skip undefined placeholder types */
> ***************
> *** 3214,3219 ****
> --- 3329,3336 ----
>   							finfo, numFuncs, tinfo, numTypes);
>   		else if (tinfo[i].typtype == 'd')
>   			dumpOneDomain(fout, &tinfo[i]);
> + 		else if (tinfo[i].typtype == 'c')
> + 			dumpOneCompositeType(fout, &tinfo[i]);
>   	}
>   }
>   
> ***************
> *** 4839,4844 ****
> --- 4956,4962 ----
>   
>   		if (tbinfo->relkind != RELKIND_SEQUENCE)
>   			continue;
> + 
>   		if (tbinfo->dump)
>   		{
>   			dumpOneSequence(fout, tbinfo, schemaOnly, dataOnly);
> ***************
> *** 4854,4859 ****
> --- 4972,4979 ----
>   			TableInfo	   *tbinfo = &tblinfo[i];
>   
>   			if (tbinfo->relkind == RELKIND_SEQUENCE) /* already dumped */
> + 				continue;
> + 			if (tbinfo->relkind == RELKIND_COMPOSITE_TYPE) /* dumped as a type */
>   				continue;
>   
>   			if (tbinfo->dump)
> Index: src/bin/pg_dump/pg_dump.h
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/bin/pg_dump/pg_dump.h,v
> retrieving revision 1.94
> diff -c -r1.94 pg_dump.h
> *** src/bin/pg_dump/pg_dump.h	2 Aug 2002 18:15:08 -0000	1.94
> --- src/bin/pg_dump/pg_dump.h	8 Aug 2002 18:26:11 -0000
> ***************
> *** 47,52 ****
> --- 47,53 ----
>   	char	   *usename;		/* name of owner, or empty string */
>   	char	   *typelem;		/* OID */
>   	char	   *typrelid;		/* OID */
> + 	char		typrelkind;		/* 'r', 'v', 'c', etc */
>   	char		typtype;		/* 'b', 'c', etc */
>   	bool		isArray;		/* true if user-defined array type */
>   	bool		isDefined;		/* true if typisdefined */
> Index: src/bin/psql/describe.c
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/bin/psql/describe.c,v
> retrieving revision 1.57
> diff -c -r1.57 describe.c
> *** src/bin/psql/describe.c	2 Aug 2002 18:15:08 -0000	1.57
> --- src/bin/psql/describe.c	8 Aug 2002 22:26:38 -0000
> ***************
> *** 168,176 ****
>   
>   	/*
>   	 * do not include array types (start with underscore), do not include
> ! 	 * user relations (typrelid!=0)
>   	 */
> ! 	appendPQExpBuffer(&buf, "FROM pg_type t\nWHERE t.typrelid = 0 AND t.typname !~ '^_.*'\n");
>   
>   	if (name)
>   		/* accept either internal or external type name */
> --- 168,179 ----
>   
>   	/*
>   	 * do not include array types (start with underscore), do not include
> ! 	 * user relations (typrelid!=0) unless they are type relations
>   	 */
> ! 	appendPQExpBuffer(&buf, "FROM pg_type t\nWHERE (t.typrelid = 0 ");
> ! 	appendPQExpBuffer(&buf, "OR (SELECT c.relkind = 'c' FROM pg_class c "
> ! 							  "where c.oid = t.typrelid)) ");
> ! 	appendPQExpBuffer(&buf, "AND t.typname !~ '^_.*'\n");
>   
>   	if (name)
>   		/* accept either internal or external type name */
> Index: src/include/catalog/pg_class.h
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/include/catalog/pg_class.h,v
> retrieving revision 1.70
> diff -c -r1.70 pg_class.h
> *** src/include/catalog/pg_class.h	2 Aug 2002 18:15:09 -0000	1.70
> --- src/include/catalog/pg_class.h	8 Aug 2002 14:49:59 -0000
> ***************
> *** 169,173 ****
> --- 169,174 ----
>   #define		  RELKIND_UNCATALOGED	  'u'		/* temporary heap */
>   #define		  RELKIND_TOASTVALUE	  't'		/* moved off huge values */
>   #define		  RELKIND_VIEW			  'v'		/* view */
> + #define		  RELKIND_COMPOSITE_TYPE  'c'		/* composite type */
>   
>   #endif   /* PG_CLASS_H */
> Index: src/include/commands/defrem.h
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/include/commands/defrem.h,v
> retrieving revision 1.43
> diff -c -r1.43 defrem.h
> *** src/include/commands/defrem.h	29 Jul 2002 22:14:11 -0000	1.43
> --- src/include/commands/defrem.h	8 Aug 2002 14:49:59 -0000
> ***************
> *** 58,63 ****
> --- 58,64 ----
>   extern void RemoveTypeById(Oid typeOid);
>   extern void DefineDomain(CreateDomainStmt *stmt);
>   extern void RemoveDomain(List *names, DropBehavior behavior);
> + extern Oid DefineCompositeType(const RangeVar *typevar, List *coldeflist);
>   
>   extern void DefineOpClass(CreateOpClassStmt *stmt);
>   extern void RemoveOpClass(RemoveOpClassStmt *stmt);
> Index: src/include/nodes/nodes.h
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/include/nodes/nodes.h,v
> retrieving revision 1.114
> diff -c -r1.114 nodes.h
> *** src/include/nodes/nodes.h	29 Jul 2002 22:14:11 -0000	1.114
> --- src/include/nodes/nodes.h	8 Aug 2002 14:49:59 -0000
> ***************
> *** 238,243 ****
> --- 238,244 ----
>   	T_PrivTarget,
>   	T_InsertDefault,
>   	T_CreateOpClassItem,
> + 	T_CompositeTypeStmt,
>   
>   	/*
>   	 * TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h)
> Index: src/include/nodes/parsenodes.h
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/include/nodes/parsenodes.h,v
> retrieving revision 1.198
> diff -c -r1.198 parsenodes.h
> *** src/include/nodes/parsenodes.h	4 Aug 2002 19:48:10 -0000	1.198
> --- src/include/nodes/parsenodes.h	8 Aug 2002 14:49:59 -0000
> ***************
> *** 1402,1407 ****
> --- 1402,1419 ----
>   } TransactionStmt;
>   
>   /* ----------------------
> +  *		Create Type Statement, composite types
> +  * ----------------------
> +  */
> + typedef struct CompositeTypeStmt
> + {
> + 	NodeTag		type;
> + 	RangeVar   *typevar;		/* the composite type to be created */
> + 	List	   *coldeflist;		/* list of ColumnDef nodes */
> + } CompositeTypeStmt;
> + 
> + 
> + /* ----------------------
>    *		Create View Statement
>    * ----------------------
>    */
> Index: src/pl/plpgsql/src/pl_comp.c
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/pl/plpgsql/src/pl_comp.c,v
> retrieving revision 1.44
> diff -c -r1.44 pl_comp.c
> *** src/pl/plpgsql/src/pl_comp.c	8 Aug 2002 01:36:04 -0000	1.44
> --- src/pl/plpgsql/src/pl_comp.c	8 Aug 2002 14:50:00 -0000
> ***************
> *** 1030,1041 ****
>   	}
>   
>   	/*
> ! 	 * It must be a relation, sequence or view
>   	 */
>   	classStruct = (Form_pg_class) GETSTRUCT(classtup);
>   	if (classStruct->relkind != RELKIND_RELATION &&
>   		classStruct->relkind != RELKIND_SEQUENCE &&
> ! 		classStruct->relkind != RELKIND_VIEW)
>   	{
>   		ReleaseSysCache(classtup);
>   		pfree(cp[0]);
> --- 1030,1042 ----
>   	}
>   
>   	/*
> ! 	 * It must be a relation, sequence, view, or type
>   	 */
>   	classStruct = (Form_pg_class) GETSTRUCT(classtup);
>   	if (classStruct->relkind != RELKIND_RELATION &&
>   		classStruct->relkind != RELKIND_SEQUENCE &&
> ! 		classStruct->relkind != RELKIND_VIEW &&
> ! 		classStruct->relkind != RELKIND_COMPOSITE_TYPE)
>   	{
>   		ReleaseSysCache(classtup);
>   		pfree(cp[0]);
> ***************
> *** 1130,1139 ****
>   	if (!HeapTupleIsValid(classtup))
>   		elog(ERROR, "%s: no such class", cp[0]);
>   	classStruct = (Form_pg_class) GETSTRUCT(classtup);
> ! 	/* accept relation, sequence, or view pg_class entries */
>   	if (classStruct->relkind != RELKIND_RELATION &&
>   		classStruct->relkind != RELKIND_SEQUENCE &&
> ! 		classStruct->relkind != RELKIND_VIEW)
>   		elog(ERROR, "%s isn't a table", cp[0]);
>   
>   	/*
> --- 1131,1141 ----
>   	if (!HeapTupleIsValid(classtup))
>   		elog(ERROR, "%s: no such class", cp[0]);
>   	classStruct = (Form_pg_class) GETSTRUCT(classtup);
> ! 	/* accept relation, sequence, view, or type pg_class entries */
>   	if (classStruct->relkind != RELKIND_RELATION &&
>   		classStruct->relkind != RELKIND_SEQUENCE &&
> ! 		classStruct->relkind != RELKIND_VIEW &&
> ! 		classStruct->relkind != RELKIND_COMPOSITE_TYPE)
>   		elog(ERROR, "%s isn't a table", cp[0]);
>   
>   	/*
> Index: src/test/regress/expected/create_type.out
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/test/regress/expected/create_type.out,v
> retrieving revision 1.4
> diff -c -r1.4 create_type.out
> *** src/test/regress/expected/create_type.out	6 Sep 2001 02:07:42 -0000	1.4
> --- src/test/regress/expected/create_type.out	8 Aug 2002 14:50:00 -0000
> ***************
> *** 37,40 ****
> --- 37,53 ----
>    zippo | 42
>   (1 row)
>   
> + -- Test stand-alone composite type
> + CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
> + CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
> +   SELECT * FROM default_test;
> + ' LANGUAGE SQL;
> + SELECT * FROM get_default_test();
> +   f1   | f2 
> + -------+----
> +  zippo | 42
> + (1 row)
> + 
> + DROP TYPE default_test_row CASCADE;
> + NOTICE:  Drop cascades to function get_default_test()
>   DROP TABLE default_test;
> Index: src/test/regress/expected/select_having.out
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/test/regress/expected/select_having.out,v
> retrieving revision 1.7
> diff -c -r1.7 select_having.out
> *** src/test/regress/expected/select_having.out	26 Jun 2002 21:58:56 -0000	1.7
> --- src/test/regress/expected/select_having.out	8 Aug 2002 17:48:10 -0000
> ***************
> *** 14,20 ****
>   INSERT INTO test_having VALUES (8, 4, 'CCCC', 'I');
>   INSERT INTO test_having VALUES (9, 4, 'CCCC', 'j');
>   SELECT b, c FROM test_having
> ! 	GROUP BY b, c HAVING count(*) = 1;
>    b |    c     
>   ---+----------
>    1 | XXXX    
> --- 14,20 ----
>   INSERT INTO test_having VALUES (8, 4, 'CCCC', 'I');
>   INSERT INTO test_having VALUES (9, 4, 'CCCC', 'j');
>   SELECT b, c FROM test_having
> ! 	GROUP BY b, c HAVING count(*) = 1 ORDER BY b, c;
>    b |    c     
>   ---+----------
>    1 | XXXX    
> ***************
> *** 23,37 ****
>   
>   -- HAVING is equivalent to WHERE in this case
>   SELECT b, c FROM test_having
> ! 	GROUP BY b, c HAVING b = 3; 
>    b |    c     
>   ---+----------
> -  3 | BBBB    
>    3 | bbbb    
>   (2 rows)
>   
>   SELECT lower(c), count(c) FROM test_having
> ! 	GROUP BY lower(c) HAVING count(*) > 2 OR min(a) = max(a);
>     lower   | count 
>   ----------+-------
>    bbbb     |     3
> --- 23,37 ----
>   
>   -- HAVING is equivalent to WHERE in this case
>   SELECT b, c FROM test_having
> ! 	GROUP BY b, c HAVING b = 3 ORDER BY b, c; 
>    b |    c     
>   ---+----------
>    3 | bbbb    
> +  3 | BBBB    
>   (2 rows)
>   
>   SELECT lower(c), count(c) FROM test_having
> ! 	GROUP BY lower(c) HAVING count(*) > 2 OR min(a) = max(a) ORDER BY lower(c);
>     lower   | count 
>   ----------+-------
>    bbbb     |     3
> ***************
> *** 40,50 ****
>   (3 rows)
>   
>   SELECT c, max(a) FROM test_having
> ! 	GROUP BY c HAVING count(*) > 2 OR min(a) = max(a);
>       c     | max 
>   ----------+-----
> -  XXXX     |   0
>    bbbb     |   5
>   (2 rows)
>   
>   DROP TABLE test_having;
> --- 40,50 ----
>   (3 rows)
>   
>   SELECT c, max(a) FROM test_having
> ! 	GROUP BY c HAVING count(*) > 2 OR min(a) = max(a) ORDER BY c;
>       c     | max 
>   ----------+-----
>    bbbb     |   5
> +  XXXX     |   0
>   (2 rows)
>   
>   DROP TABLE test_having;
> Index: src/test/regress/sql/create_type.sql
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/test/regress/sql/create_type.sql,v
> retrieving revision 1.4
> diff -c -r1.4 create_type.sql
> *** src/test/regress/sql/create_type.sql	6 Sep 2001 02:07:42 -0000	1.4
> --- src/test/regress/sql/create_type.sql	8 Aug 2002 14:50:00 -0000
> ***************
> *** 41,44 ****
> --- 41,56 ----
>   
>   SELECT * FROM default_test;
>   
> + -- Test stand-alone composite type
> + 
> + CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
> + 
> + CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
> +   SELECT * FROM default_test;
> + ' LANGUAGE SQL;
> + 
> + SELECT * FROM get_default_test();
> + 
> + DROP TYPE default_test_row CASCADE;
> + 
>   DROP TABLE default_test;
> Index: src/test/regress/sql/select_having.sql
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/test/regress/sql/select_having.sql,v
> retrieving revision 1.7
> diff -c -r1.7 select_having.sql
> *** src/test/regress/sql/select_having.sql	26 Jun 2002 21:58:56 -0000	1.7
> --- src/test/regress/sql/select_having.sql	8 Aug 2002 17:43:02 -0000
> ***************
> *** 16,32 ****
>   INSERT INTO test_having VALUES (9, 4, 'CCCC', 'j');
>   
>   SELECT b, c FROM test_having
> ! 	GROUP BY b, c HAVING count(*) = 1;
>   
>   -- HAVING is equivalent to WHERE in this case
>   SELECT b, c FROM test_having
> ! 	GROUP BY b, c HAVING b = 3; 
>   
>   SELECT lower(c), count(c) FROM test_having
> ! 	GROUP BY lower(c) HAVING count(*) > 2 OR min(a) = max(a);
>   
>   SELECT c, max(a) FROM test_having
> ! 	GROUP BY c HAVING count(*) > 2 OR min(a) = max(a);
>   
>   DROP TABLE test_having;
>   
> --- 16,32 ----
>   INSERT INTO test_having VALUES (9, 4, 'CCCC', 'j');
>   
>   SELECT b, c FROM test_having
> ! 	GROUP BY b, c HAVING count(*) = 1 ORDER BY b, c; 
>   
>   -- HAVING is equivalent to WHERE in this case
>   SELECT b, c FROM test_having
> ! 	GROUP BY b, c HAVING b = 3 ORDER BY b, c; 
>   
>   SELECT lower(c), count(c) FROM test_having
> ! 	GROUP BY lower(c) HAVING count(*) > 2 OR min(a) = max(a) ORDER BY lower(c);
>   
>   SELECT c, max(a) FROM test_having
> ! 	GROUP BY c HAVING count(*) > 2 OR min(a) = max(a) ORDER BY c;
>   
>   DROP TABLE test_having;
>   

> 
> ---------------------------(end of broadcast)---------------------------
> TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073