Domain Support -- another round

Started by Rod Tayloralmost 24 years ago30 messages
#1Rod Taylor
rbt@zort.ca
1 attachment(s)

Ok....

gram.y is fixed (no more %expect usage)

Using the copyCreateDomainStmt in the proper place.

Evolution is the mail client of choice for different (improved?) mime
headers.

And attached is a regular diff -c, rather than a cvs diff -c.

I updated the poor descriptions of MergeDomainAttributes(). Hopefully
its current and future use is more obvious.

Am I getting close?

Attachments:

domain.patchtext/plain; charset=ISO-8859-1Download
diff -rc pgsql.orig/doc/src/sgml/catalogs.sgml pgsqldomain/doc/src/sgml/catalogs.sgml
*** pgsql.orig/doc/src/sgml/catalogs.sgml	Thu Mar  7 11:35:32 2002
--- pgsqldomain/doc/src/sgml/catalogs.sgml	Thu Mar  7 22:24:23 2002
***************
*** 2511,2516 ****
--- 2511,2563 ----
       </row>
  
       <row>
+       <entry>typbasetype</entry>
+       <entry><type>oid</type></entry>
+       <entry></entry>
+       <entry><para>
+        <structfield>typbasetype</structfield> is the type that this one is based
+        off of.  Normally references the domains parent type, and is 0 otherwise.
+       </para></entry>
+      </row>
+ 
+ 	 <row>
+ 	  <entry>typnotnull</entry>
+ 	  <entry><type>boolean</type></entry>
+ 	  <entry></entry>
+ 	  <entry><para>
+ 	   <structfield>typnotnull</structfield> represents a NOT NULL
+ 	   constraint on a type.  Normally used only for domains.
+ 	  </para></entry>
+ 	 </row>
+ 
+      <row>
+       <entry>typmod</entry>
+       <entry><type>integer</type></entry>
+       <entry></entry>
+       <entry><para>
+        <structfield>typmod</structfield> records type-specific data
+        supplied at table creation time (for example, the maximum
+        length of a <type>varchar</type> column).  It is passed to
+        type-specific input and output functions as the third
+        argument. The value will generally be -1 for types that do not
+        need typmod.  This data is copied to
+        <structfield>pg_attribute.atttypmod</structfield> on creation
+        of a table using a domain as it's field type.
+        </para></entry>
+      </row>
+ 
+      <row>
+       <entry>typdefaultbin</entry>
+       <entry><type>text</type></entry>
+       <entry></entry>
+       <entry><para>
+        <structfield>typdefaultbin</structfield> is NULL for types without a
+        default value.  If it's not NULL, it contains the internal string
+        representation of the default expression node.
+       </para></entry>
+      </row>
+ 
+      <row>
        <entry>typdefault</entry>
        <entry><type>text</type></entry>
        <entry></entry>
diff -rc pgsql.orig/doc/src/sgml/ref/allfiles.sgml pgsqldomain/doc/src/sgml/ref/allfiles.sgml
*** pgsql.orig/doc/src/sgml/ref/allfiles.sgml	Thu Mar  7 11:35:32 2002
--- pgsqldomain/doc/src/sgml/ref/allfiles.sgml	Thu Mar  7 22:24:23 2002
***************
*** 52,57 ****
--- 52,58 ----
  <!entity createAggregate    system "create_aggregate.sgml">
  <!entity createConstraint   system "create_constraint.sgml">
  <!entity createDatabase     system "create_database.sgml">
+ <!entity createDomain       system "create_domain.sgml">
  <!entity createFunction     system "create_function.sgml">
  <!entity createGroup        system "create_group.sgml">
  <!entity createIndex        system "create_index.sgml">
***************
*** 69,74 ****
--- 70,76 ----
  <!entity delete             system "delete.sgml">
  <!entity dropAggregate      system "drop_aggregate.sgml">
  <!entity dropDatabase       system "drop_database.sgml">
+ <!entity dropDomain         system "drop_domain.sgml">
  <!entity dropFunction       system "drop_function.sgml">
  <!entity dropGroup          system "drop_group.sgml">
  <!entity dropIndex          system "drop_index.sgml">
diff -rc pgsql.orig/doc/src/sgml/ref/comment.sgml pgsqldomain/doc/src/sgml/ref/comment.sgml
*** pgsql.orig/doc/src/sgml/ref/comment.sgml	Thu Mar  7 11:35:33 2002
--- pgsqldomain/doc/src/sgml/ref/comment.sgml	Thu Mar  7 22:24:23 2002
***************
*** 25,31 ****
    <synopsis>
  COMMENT ON
  [
!   [ DATABASE | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ] <replaceable class="PARAMETER">object_name</replaceable> |
    COLUMN <replaceable class="PARAMETER">table_name</replaceable>.<replaceable class="PARAMETER">column_name</replaceable> |
    AGGREGATE <replaceable class="PARAMETER">agg_name</replaceable> (<replaceable class="PARAMETER">agg_type</replaceable>) |
    FUNCTION <replaceable class="PARAMETER">func_name</replaceable> (<replaceable class="PARAMETER">arg1</replaceable>, <replaceable class="PARAMETER">arg2</replaceable>, ...) |
--- 25,31 ----
    <synopsis>
  COMMENT ON
  [
!   [ DATABASE | DOMAIN | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ] <replaceable class="PARAMETER">object_name</replaceable> |
    COLUMN <replaceable class="PARAMETER">table_name</replaceable>.<replaceable class="PARAMETER">column_name</replaceable> |
    AGGREGATE <replaceable class="PARAMETER">agg_name</replaceable> (<replaceable class="PARAMETER">agg_type</replaceable>) |
    FUNCTION <replaceable class="PARAMETER">func_name</replaceable> (<replaceable class="PARAMETER">arg1</replaceable>, <replaceable class="PARAMETER">arg2</replaceable>, ...) |
***************
*** 33,39 ****
    TRIGGER <replaceable class="PARAMETER">trigger_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable>
  ] IS <replaceable class="PARAMETER">'text'</replaceable>
    </synopsis>
!   
    <refsect2 id="R2-SQL-COMMENT-1">
     <refsect2info>
      <date>1999-10-25</date>
--- 33,39 ----
    TRIGGER <replaceable class="PARAMETER">trigger_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable>
  ] IS <replaceable class="PARAMETER">'text'</replaceable>
    </synopsis>
! 
    <refsect2 id="R2-SQL-COMMENT-1">
     <refsect2info>
      <date>1999-10-25</date>
***************
*** 64,70 ****
      </variablelist>
     </para>
    </refsect2>
!   
    <refsect2 id="R2-SQL-COMMENT-2">
     <refsect2info>
      <date>1998-09-08</date>
--- 64,70 ----
      </variablelist>
     </para>
    </refsect2>
! 
    <refsect2 id="R2-SQL-COMMENT-2">
     <refsect2info>
      <date>1998-09-08</date>
***************
*** 99,105 ****
    </title>
    <para>
     <command>COMMENT</command> stores a comment about a database object.
!     Comments can be 
      easily retrieved with <command>psql</command>'s
      <command>\dd</command>, <command>\d+</command>, or <command>\l+</command>
      commands.  Other user interfaces to retrieve comments can be built atop
--- 99,105 ----
    </title>
    <para>
     <command>COMMENT</command> stores a comment about a database object.
!     Comments can be
      easily retrieved with <command>psql</command>'s
      <command>\dd</command>, <command>\d+</command>, or <command>\l+</command>
      commands.  Other user interfaces to retrieve comments can be built atop
***************
*** 141,146 ****
--- 141,147 ----
  
     <programlisting>
  COMMENT ON DATABASE my_database IS 'Development Database';
+ COMMENT ON DOMAIN my_domain IS 'Domains are like abstracted fields';
  COMMENT ON INDEX my_index IS 'Enforces uniqueness on employee id';
  COMMENT ON RULE my_rule IS 'Logs UPDATES of employee records';
  COMMENT ON SEQUENCE my_sequence IS 'Used to generate primary keys';
***************
*** 155,166 ****
     </programlisting>
    </para>
   </refsect1>
!  
   <refsect1 id="R1-SQL-COMMENT-3">
    <title>
     Compatibility
    </title>
!   
    <refsect2 id="R2-SQL-COMMENT-4">
     <refsect2info>
      <date>1998-09-08</date>
--- 156,167 ----
     </programlisting>
    </para>
   </refsect1>
! 
   <refsect1 id="R1-SQL-COMMENT-3">
    <title>
     Compatibility
    </title>
! 
    <refsect2 id="R2-SQL-COMMENT-4">
     <refsect2info>
      <date>1998-09-08</date>
diff -rc pgsql.orig/doc/src/sgml/reference.sgml pgsqldomain/doc/src/sgml/reference.sgml
*** pgsql.orig/doc/src/sgml/reference.sgml	Thu Mar  7 11:35:32 2002
--- pgsqldomain/doc/src/sgml/reference.sgml	Thu Mar  7 22:24:23 2002
***************
*** 61,66 ****
--- 61,67 ----
     &createAggregate;
     &createConstraint;
     &createDatabase;
+    &createDomain;
     &createFunction;
     &createGroup;
     &createIndex;
***************
*** 78,83 ****
--- 79,85 ----
     &delete;
     &dropAggregate;
     &dropDatabase;
+    &dropDomain;
     &dropFunction;
     &dropGroup;
     &dropIndex;
***************
*** 115,121 ****
     &unlisten;
     &update;
     &vacuum;
!   
   </reference>
  
  <!--
--- 117,123 ----
     &unlisten;
     &update;
     &vacuum;
! 
   </reference>
  
  <!--
Only in pgsqldomain/: log
diff -rc pgsql.orig/src/backend/catalog/heap.c pgsqldomain/src/backend/catalog/heap.c
*** pgsql.orig/src/backend/catalog/heap.c	Thu Mar  7 11:35:33 2002
--- pgsqldomain/src/backend/catalog/heap.c	Thu Mar  7 22:24:23 2002
***************
*** 49,54 ****
--- 49,55 ----
  #include "optimizer/planmain.h"
  #include "optimizer/prep.h"
  #include "optimizer/var.h"
+ #include "parser/parse_coerce.h"
  #include "parser/parse_expr.h"
  #include "parser/parse_relation.h"
  #include "parser/parse_target.h"
***************
*** 698,707 ****
  			   "oidin",			/* receive procedure */
  			   "oidout",		/* send procedure */
  			   NULL,			/* array element type - irrelevant */
  			   NULL,			/* default type value - none */
  			   true,			/* passed by value */
  			   'i',				/* default alignment - same as for OID */
! 			   'p');			/* Not TOASTable */
  }
  
  /* --------------------------------
--- 699,713 ----
  			   "oidin",			/* receive procedure */
  			   "oidout",		/* send procedure */
  			   NULL,			/* array element type - irrelevant */
+ 			   NULL,			/* baseType Name -- typically for domaains */
  			   NULL,			/* default type value - none */
+ 			   NULL,			/* default type binary representation */
  			   true,			/* passed by value */
  			   'i',				/* default alignment - same as for OID */
! 			   'p',				/* Not TOASTable */
! 			   -1,				/* Type mod length */
! 			   0,				/* array dimensions for typBaseType */
! 			   false);			/* Type NOT NULL */
  }
  
  /* --------------------------------
***************
*** 1584,1589 ****
--- 1590,1599 ----
  	int			numchecks;
  	List	   *listptr;
  
+ 	/* Probably shouldn't be null by default */
+ 	Node	   *expr = NULL;
+ 
+ 
  	/*
  	 * Get info about existing constraints.
  	 */
***************
*** 1614,1681 ****
  	foreach(listptr, rawColDefaults)
  	{
  		RawColumnDefault *colDef = (RawColumnDefault *) lfirst(listptr);
- 		Node	   *expr;
- 		Oid			type_id;
  
- 		Assert(colDef->raw_default != NULL);
  
! 		/*
! 		 * Transform raw parsetree to executable expression.
! 		 */
! 		expr = transformExpr(pstate, colDef->raw_default, EXPR_COLUMN_FIRST);
  
! 		/*
! 		 * Make sure default expr does not refer to any vars.
! 		 */
! 		if (contain_var_clause(expr))
! 			elog(ERROR, "cannot use column references in DEFAULT clause");
! 
! 		/*
! 		 * No subplans or aggregates, either...
! 		 */
! 		if (contain_subplans(expr))
! 			elog(ERROR, "cannot use subselects in DEFAULT clause");
! 		if (contain_agg_clause(expr))
! 			elog(ERROR, "cannot use aggregate functions in DEFAULT clause");
! 
! 		/*
! 		 * Check that it will be possible to coerce the expression to the
! 		 * column's type.  We store the expression without coercion,
! 		 * however, to avoid premature coercion in cases like
! 		 *
! 		 * CREATE TABLE tbl (fld datetime DEFAULT 'now'::text);
! 		 *
! 		 * NB: this should match the code in optimizer/prep/preptlist.c that
! 		 * will actually do the coercion, to ensure we don't accept an
! 		 * unusable default expression.
! 		 */
! 		type_id = exprType(expr);
! 		if (type_id != InvalidOid)
! 		{
! 			Form_pg_attribute atp = rel->rd_att->attrs[colDef->attnum - 1];
! 
! 			if (type_id != atp->atttypid)
! 			{
! 				if (CoerceTargetExpr(NULL, expr, type_id,
! 								  atp->atttypid, atp->atttypmod) == NULL)
! 					elog(ERROR, "Column \"%s\" is of type %s"
! 						 " but default expression is of type %s"
! 					"\n\tYou will need to rewrite or cast the expression",
! 						 NameStr(atp->attname),
! 						 format_type_be(atp->atttypid),
! 						 format_type_be(type_id));
! 			}
! 		}
! 
! 		/*
! 		 * Might as well try to reduce any constant expressions.
! 		 */
! 		expr = eval_const_expressions(expr);
! 
! 		/*
! 		 * Must fix opids, in case any operators remain...
! 		 */
! 		fix_opids(expr);
  
  		/*
  		 * OK, store it.
--- 1624,1636 ----
  	foreach(listptr, rawColDefaults)
  	{
  		RawColumnDefault *colDef = (RawColumnDefault *) lfirst(listptr);
  
  
! 		Form_pg_attribute atp = rel->rd_att->attrs[colDef->attnum - 1];
  
! 		expr = cookDefault(pstate, colDef->raw_default
! 						, atp->atttypid, atp->atttypmod
! 						, NameStr(atp->attname));
  
  		/*
  		 * OK, store it.
***************
*** 1891,1896 ****
--- 1846,1933 ----
  	heap_freetuple(reltup);
  	heap_close(relrel, RowExclusiveLock);
  }
+ 
+ /*
+  * Take a raw default and convert it to a cooked format ready for
+  * storage.
+  *
+  * Parse state, attypid, attypmod and attname are required for
+  * CoerceTargetExpr() and more importantly transformExpr().
+  */
+ Node *
+ cookDefault(ParseState *pstate
+ 			, Node *raw_default
+ 			, Oid atttypid
+ 			, int32 atttypmod
+ 			, char *attname) {
+ 
+ 	Oid			type_id;
+ 	Node		*expr;
+ 
+ 	Assert(raw_default != NULL);
+ 
+ 	/*
+ 	 * Transform raw parsetree to executable expression.
+ 	 */
+ 	expr = transformExpr(pstate, raw_default, EXPR_COLUMN_FIRST);
+ 
+ 	/*
+ 	 * Make sure default expr does not refer to any vars.
+ 	 */
+ 	if (contain_var_clause(expr))
+ 		elog(ERROR, "cannot use column references in DEFAULT clause");
+ 
+ 	/*
+ 	 * No subplans or aggregates, either...
+ 	 */
+ 	if (contain_subplans(expr))
+ 		elog(ERROR, "cannot use subselects in DEFAULT clause");
+ 	if (contain_agg_clause(expr))
+ 		elog(ERROR, "cannot use aggregate functions in DEFAULT clause");
+ 
+ 	/*
+ 	 * Check that it will be possible to coerce the expression to the
+ 	 * column's type.  We store the expression without coercion,
+ 	 * however, to avoid premature coercion in cases like
+ 	 *
+ 	 * CREATE TABLE tbl (fld datetime DEFAULT 'now'::text);
+ 	 *
+ 	 * NB: this should match the code in optimizer/prep/preptlist.c that
+ 	 * will actually do the coercion, to ensure we don't accept an
+ 	 * unusable default expression.
+ 	 */
+ 	type_id = exprType(expr);
+ 	if (type_id != InvalidOid && atttypid != InvalidOid) {
+ 		if (type_id != atttypid) {
+ 
+ 			/* Try coercing to the base type of the domain if available */
+ 			if (CoerceTargetExpr(pstate, expr, type_id,
+ 								 getBaseType(atttypid),
+ 								 atttypmod) == NULL) {
+ 
+ 				elog(ERROR, "Column \"%s\" is of type %s"
+ 					" but default expression is of type %s"
+ 					"\n\tYou will need to rewrite or cast the expression",
+ 					 attname,
+ 					 format_type_be(atttypid),
+ 					 format_type_be(type_id));
+ 			}
+ 		}
+ 	}
+ 
+ 	/*
+ 	 * Might as well try to reduce any constant expressions.
+ 	 */
+ 	expr = eval_const_expressions(expr);
+ 
+ 	/*
+ 	 * Must fix opids, in case any operators remain...
+ 	 */
+ 	fix_opids(expr);
+ 
+ 	return(expr);
+ }
+ 
  
  static void
  RemoveAttrDefaults(Relation rel)
diff -rc pgsql.orig/src/backend/catalog/pg_type.c pgsqldomain/src/backend/catalog/pg_type.c
*** pgsql.orig/src/backend/catalog/pg_type.c	Thu Mar  7 11:35:33 2002
--- pgsqldomain/src/backend/catalog/pg_type.c	Thu Mar  7 22:24:23 2002
***************
*** 176,185 ****
  	values[i++] = ObjectIdGetDatum(InvalidOid); /* 12 */
  	values[i++] = ObjectIdGetDatum(InvalidOid); /* 13 */
  	values[i++] = ObjectIdGetDatum(InvalidOid); /* 14 */
! 	values[i++] = CharGetDatum('i');	/* 15 */
! 	values[i++] = CharGetDatum('p');	/* 16 */
  	values[i++] = DirectFunctionCall1(textin,
! 									  CStringGetDatum(typeName));		/* 17 */
  
  	/*
  	 * create a new type tuple with FormHeapTuple
--- 176,191 ----
  	values[i++] = ObjectIdGetDatum(InvalidOid); /* 12 */
  	values[i++] = ObjectIdGetDatum(InvalidOid); /* 13 */
  	values[i++] = ObjectIdGetDatum(InvalidOid); /* 14 */
! 	values[i++] = CharGetDatum('i');			/* 15 */
! 	values[i++] = CharGetDatum('p');			/* 16 */
! 	values[i++] = BoolGetDatum(false);			/* 17 */
! 	values[i++] = Int32GetDatum(-1);			/* 18 */
! 	values[i++] = ObjectIdGetDatum(InvalidOid);	/* 19 */
! 	values[i++] = Int32GetDatum(0);				/* 20 */
  	values[i++] = DirectFunctionCall1(textin,
! 									  CStringGetDatum(typeName));		/* 21 */
! 	values[i++] = DirectFunctionCall1(textin,
! 									  CStringGetDatum(typeName));		/* 22 */
  
  	/*
  	 * create a new type tuple with FormHeapTuple
***************
*** 264,270 ****
  Oid
  TypeCreate(char *typeName,
  		   Oid assignedTypeOid,
! 		   Oid relationOid,		/* only for 'c'atalog typeTypes */
  		   int16 internalSize,
  		   int16 externalSize,
  		   char typeType,
--- 270,276 ----
  Oid
  TypeCreate(char *typeName,
  		   Oid assignedTypeOid,
! 		   Oid relationOid,			/* only for 'c'atalog typeTypes */
  		   int16 internalSize,
  		   int16 externalSize,
  		   char typeType,
***************
*** 274,283 ****
  		   char *receiveProcedure,
  		   char *sendProcedure,
  		   char *elementTypeName,
! 		   char *defaultTypeValue,		/* internal rep */
  		   bool passedByValue,
  		   char alignment,
! 		   char storage)
  {
  	int			i,
  				j;
--- 280,294 ----
  		   char *receiveProcedure,
  		   char *sendProcedure,
  		   char *elementTypeName,
! 		   char *baseTypeName,
! 		   char *defaultTypeValue,	/* human readable rep */
! 		   char *defaultTypeBin,	/* cooked rep */
  		   bool passedByValue,
  		   char alignment,
! 		   char storage,
! 		   int32 typeMod,
! 		   int32 typNDims,			/* Array dimensions for baseTypeName */
! 		   bool typeNotNull)		/* binary default representation (cooked) */
  {
  	int			i,
  				j;
***************
*** 285,290 ****
--- 296,302 ----
  	HeapScanDesc pg_type_scan;
  	Oid			typeObjectId;
  	Oid			elementObjectId = InvalidOid;
+ 	Oid			baseObjectId = InvalidOid;
  	HeapTuple	tup;
  	char		nulls[Natts_pg_type];
  	char		replaces[Natts_pg_type];
***************
*** 318,323 ****
--- 330,346 ----
  	}
  
  	/*
+ 	 * if this type has an associated baseType, then we check that it
+ 	 * is defined.
+ 	 */
+ 	if (baseTypeName)
+ 	{
+ 		baseObjectId = TypeGet(baseTypeName, &defined);
+ 		if (!defined)
+ 			elog(ERROR, "type %s does not exist", baseTypeName);
+ 	}
+ 
+ 	/*
  	 * validate size specifications: either positive (fixed-length) or -1
  	 * (variable-length).
  	 */
***************
*** 388,394 ****
  			 * signature is 0,OIDOID,INT4OID.  The output procedures may
  			 * take 2 args (data value, element OID).
  			 */
! 			if (OidIsValid(elementObjectId))
  			{
  				int			nargs;
  
--- 411,417 ----
  			 * signature is 0,OIDOID,INT4OID.  The output procedures may
  			 * take 2 args (data value, element OID).
  			 */
! 			if (OidIsValid(elementObjectId) || OidIsValid(baseObjectId))
  			{
  				int			nargs;
  
***************
*** 411,416 ****
--- 434,440 ----
  										 PointerGetDatum(argList),
  										 0);
  			}
+ 
  			if (!OidIsValid(procOid))
  				func_error("TypeCreate", procname, 1, argList, NULL);
  		}
***************
*** 429,434 ****
--- 453,486 ----
  	values[i++] = CharGetDatum(storage);		/* 16 */
  
  	/*
+ 	 * set the typenotnull value
+ 	 */
+ 	values[i++] = BoolGetDatum(typeNotNull);	/* 17 */
+ 
+ 	/*
+ 	 * set the typemod value
+ 	 */
+ 	values[i++] = Int32GetDatum(typeMod);			/* 18 */
+ 
+ 	values[i++] = ObjectIdGetDatum(baseObjectId);	/* 19 */
+ 
+ 	/*
+ 	 * Dimension number for an array base type
+ 	 */
+ 	values[i++] = Int32GetDatum(typNDims);			/* 20 */
+ 
+ 	/*
+ 	 * initialize the default binary value for this type.  Check for
+ 	 * nulls of course.
+ 	 */
+ 	if (defaultTypeBin)
+ 		values[i] = DirectFunctionCall1(textin,
+ 									  CStringGetDatum(defaultTypeBin));
+ 	else
+ 		nulls[i] = 'n';
+ 	i++;										/* 21 */
+ 
+ 	/*
  	 * initialize the default value for this type.
  	 */
  	if (defaultTypeValue)
***************
*** 436,442 ****
  									  CStringGetDatum(defaultTypeValue));
  	else
  		nulls[i] = 'n';
! 	i++;						/* 17 */
  
  	/*
  	 * open pg_type and begin a scan for the type name.
--- 488,494 ----
  									  CStringGetDatum(defaultTypeValue));
  	else
  		nulls[i] = 'n';
! 	i++;						/* 22 */
  
  	/*
  	 * open pg_type and begin a scan for the type name.
diff -rc pgsql.orig/src/backend/commands/creatinh.c pgsqldomain/src/backend/commands/creatinh.c
*** pgsql.orig/src/backend/commands/creatinh.c	Thu Mar  7 11:35:34 2002
--- pgsqldomain/src/backend/commands/creatinh.c	Thu Mar  7 23:16:06 2002
***************
*** 39,45 ****
  static void StoreCatalogInheritance(Oid relationId, List *supers);
  static int	findAttrByName(const char *attributeName, List *schema);
  static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass);
! 
  
  /* ----------------------------------------------------------------
   *		DefineRelation
--- 39,45 ----
  static void StoreCatalogInheritance(Oid relationId, List *supers);
  static int	findAttrByName(const char *attributeName, List *schema);
  static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass);
! static List *MergeDomainAttributes(List *schema);
  
  /* ----------------------------------------------------------------
   *		DefineRelation
***************
*** 70,75 ****
--- 70,82 ----
  	StrNCpy(relname, stmt->relname, NAMEDATALEN);
  
  	/*
+ 	 * Inherit domain attributes into the known columns before table inheritance
+ 	 * applies it's changes otherwise we risk adding double constraints
+ 	 * to a domain thats inherited.
+ 	 */
+ 	schema = MergeDomainAttributes(schema);
+ 
+ 	/*
  	 * Look up inheritance ancestors and generate relation schema,
  	 * including inherited attributes.
  	 */
***************
*** 235,240 ****
--- 242,307 ----
  {
  	AssertArg(name);
  	heap_truncate(name);
+ }
+ 
+ 
+ /*
+  * MergeDomainAttributes
+  *      Returns a new table schema with the constraints, types, and other
+  *      attributes of the domain resolved for fields using the domain as
+  *		their type.
+  *
+  * Defaults are pulled out by the table attribute as required, similar to
+  * how all types defaults are processed.
+  */
+ static List *
+ MergeDomainAttributes(List *schema)
+ {
+ 	List	   *entry;
+ 
+ 	/*
+ 	 * Loop through the table elements supplied. These should
+ 	 * never include inherited domains else they'll be
+ 	 * double (or more) processed.
+ 	 */
+ 	foreach(entry, schema)
+ 	{
+ 		ColumnDef  *coldef = lfirst(entry);
+ 		HeapTuple  tuple;
+ 		Form_pg_type typeTup;
+ 
+ 
+ 		tuple = SearchSysCache(TYPENAME,
+ 							   CStringGetDatum(coldef->typename->name),
+ 							   0,0,0);
+ 
+ 		if (!HeapTupleIsValid(tuple))
+ 			elog(ERROR, "MergeDomainAttributes: Type %s does not exist",
+ 				 coldef->typename->name);
+ 
+ 		typeTup = (Form_pg_type) GETSTRUCT(tuple);
+ 		if (typeTup->typtype == 'd') {
+ 			/*
+ 			 * This is a domain, lets force the properties of the domain on to
+ 			 * the new column.
+ 			 */
+ 
+ 			/* Enforce the typmod value */
+ 			coldef->typename->typmod = typeTup->typmod;
+ 
+ 			/* Enforce type NOT NULL || column definition NOT NULL -> NOT NULL */
+ 			coldef->is_not_null |= typeTup->typnotnull;
+ 
+ 			/* Enforce the element type in the event the domain is an array
+ 			 *
+ 			 * BUG: How do we fill out arrayBounds and attrname from typelem and typNDimms?
+ 			 */
+ 
+ 		}
+ 		ReleaseSysCache(tuple);
+ 	}
+ 
+ 	return schema;
  }
  
  /*----------
diff -rc pgsql.orig/src/backend/commands/define.c pgsqldomain/src/backend/commands/define.c
*** pgsql.orig/src/backend/commands/define.c	Thu Mar  7 11:35:34 2002
--- pgsqldomain/src/backend/commands/define.c	Thu Mar  7 22:24:23 2002
***************
*** 40,45 ****
--- 40,46 ----
  
  #include "access/heapam.h"
  #include "catalog/catname.h"
+ #include "catalog/heap.h"
  #include "catalog/pg_aggregate.h"
  #include "catalog/pg_language.h"
  #include "catalog/pg_operator.h"
***************
*** 476,481 ****
--- 477,798 ----
  }
  
  /*
+  * DefineDomain
+  *		Registers a new domain.
+  */
+ void
+ DefineDomain(CreateDomainStmt *stmt)
+ {
+ 	int16		internalLength = -1;	/* int2 */
+ 	int16		externalLength = -1;	/* int2 */
+ 	char	   *inputName = NULL;
+ 	char	   *outputName = NULL;
+ 	char	   *sendName = NULL;
+ 	char	   *receiveName = NULL;
+ 
+ 	/*
+ 	 * Domains store the external representation in defaultValue
+ 	 * and the interal Node representation in defaultValueBin
+ 	 */
+ 	char	   *defaultValue = NULL;
+ 	char	   *defaultValueBin = NULL;
+ 
+ 	bool		byValue = false;
+ 	char		delimiter = DEFAULT_TYPDELIM;
+ 	char		alignment = 'i';	/* default alignment */
+ 	char		storage = 'p';	/* default TOAST storage method */
+ 	char		typtype;
+ 	Datum		datum;
+ 	bool		typNotNull = false;
+ 	char		*elemName = NULL;
+ 	int32		typNDims = 0;	/* No array dimensions by default */
+ 
+ 	bool		isnull;
+ 	Relation	pg_type_rel;
+ 	TupleDesc	pg_type_dsc;
+ 	HeapTuple	typeTup;
+ 	char	   *typeName = stmt->typename->name;
+ 
+ 	List	   *listptr;
+ 	List	   *schema = stmt->constraints;
+ 
+ 	/*
+ 	 * Domainnames, unlike typenames don't need to account for the '_'
+ 	 * prefix.  So they can be one character longer.
+ 	 */
+ 	if (strlen(stmt->domainname) > (NAMEDATALEN - 1))
+ 		elog(ERROR, "CREATE DOMAIN: domain names must be %d characters or less",
+ 			 NAMEDATALEN - 1);
+ 
+ 
+ 	/* Test for existing Domain (or type) of that name */
+ 	typeTup = SearchSysCache( TYPENAME
+ 							, PointerGetDatum(stmt->domainname)
+ 							, 0, 0, 0
+ 							);
+ 
+ 	if (HeapTupleIsValid(typeTup))
+ 	{
+ 		elog(ERROR, "CREATE DOMAIN: domain or type  %s already exists",
+ 			 stmt->domainname);
+ 	}
+ 
+ 	/*
+ 	 * Get the information about old types
+ 	 */
+ 	pg_type_rel = heap_openr(TypeRelationName, RowExclusiveLock);
+ 	pg_type_dsc = RelationGetDescr(pg_type_rel);
+ 
+ 
+ 	/*
+ 	 * When the type is an array for some reason we don't actually receive
+ 	 * the name here.  We receive the base types name.  Lets set Dims while
+ 	 * were at it.
+ 	 */
+ 	if (stmt->typename->arrayBounds > 0) {
+ 		typeName = makeArrayTypeName(stmt->typename->name);
+ 
+ 		typNDims = length(stmt->typename->arrayBounds);
+ 	}
+ 
+ 
+ 	typeTup = SearchSysCache( TYPENAME
+ 							, PointerGetDatum(typeName)
+ 							, 0, 0, 0
+ 							);
+ 
+ 	if (!HeapTupleIsValid(typeTup))
+ 	{
+ 		elog(ERROR, "CREATE DOMAIN: type %s does not exist",
+ 			 stmt->typename->name);
+ 	}
+ 
+ 
+ 	/* Check that this is a basetype */
+ 	typtype = DatumGetChar(heap_getattr(typeTup, Anum_pg_type_typtype, pg_type_dsc, &isnull));
+ 	Assert(!isnull);
+ 
+ 	/*
+ 	 * What we really don't want is domains of domains.  This could cause all sorts
+ 	 * of neat issues if we allow that.
+ 	 *
+ 	 * With testing, we may determine complex types should be allowed
+ 	 */
+ 	if (typtype != 'b') {
+ 		elog(ERROR, "DefineDomain: %s is not a basetype", stmt->typename->name);
+ 	}
+ 
+ 	/* passed by value */
+ 	byValue = 			DatumGetBool(heap_getattr(typeTup, Anum_pg_type_typbyval, pg_type_dsc, &isnull));
+ 	Assert(!isnull);
+ 
+ 	/* Required Alignment */
+ 	alignment = 		DatumGetChar(heap_getattr(typeTup, Anum_pg_type_typalign, pg_type_dsc, &isnull));
+ 	Assert(!isnull);
+ 
+ 	/* Storage Length */
+ 	internalLength = 	DatumGetInt16(heap_getattr(typeTup, Anum_pg_type_typlen, pg_type_dsc, &isnull));
+ 	Assert(!isnull);
+ 
+ 	/* External Length (unused) */
+ 	externalLength = 	DatumGetInt16(heap_getattr(typeTup, Anum_pg_type_typprtlen, pg_type_dsc, &isnull));
+ 	Assert(!isnull);
+ 
+ 	/* Array element Delimiter */
+ 	delimiter = 		DatumGetChar(heap_getattr(typeTup, Anum_pg_type_typdelim, pg_type_dsc, &isnull));
+ 	Assert(!isnull);
+ 
+ 	/* Input Function Name */
+ 	datum = 			heap_getattr(typeTup, Anum_pg_type_typinput, pg_type_dsc, &isnull);
+ 	Assert(!isnull);
+ 
+ 	inputName = 		DatumGetCString(DirectFunctionCall1(regprocout, datum));
+ 
+ 	/* Output Function Name */
+ 	datum = 			heap_getattr(typeTup, Anum_pg_type_typoutput, pg_type_dsc, &isnull);
+ 	Assert(!isnull);
+ 
+ 	outputName = 		DatumGetCString(DirectFunctionCall1(regprocout, datum));
+ 
+ 	/* ReceiveName */
+ 	datum = 			heap_getattr(typeTup, Anum_pg_type_typreceive, pg_type_dsc, &isnull);
+ 	Assert(!isnull);
+ 
+ 	receiveName = 		DatumGetCString(DirectFunctionCall1(regprocout, datum));
+ 
+ 	/* SendName */
+ 	datum = 			heap_getattr(typeTup, Anum_pg_type_typsend, pg_type_dsc, &isnull);
+ 	Assert(!isnull);
+ 
+ 	sendName = 			DatumGetCString(DirectFunctionCall1(regprocout, datum));
+ 
+ 	/* TOAST Strategy */
+ 	storage = 			DatumGetChar(heap_getattr(typeTup, Anum_pg_type_typstorage, pg_type_dsc, &isnull));
+ 	Assert(!isnull);
+ 
+ 	/* Inherited default value */
+ 	datum = 			heap_getattr(typeTup, Anum_pg_type_typdefault, pg_type_dsc, &isnull);
+ 	if (!isnull) {
+ 		defaultValue = 	DatumGetCString(DirectFunctionCall1(textout, datum));
+ 	}
+ 
+ 	/*
+ 	 * Pull out the typelem name of the parent OID.
+ 	 *
+ 	 * This is what enables us to make a domain of an array
+ 	 */
+ 	datum = 			heap_getattr(typeTup, Anum_pg_type_typelem, pg_type_dsc, &isnull);
+ 	Assert(!isnull);
+ 
+ 	if (DatumGetObjectId(datum) != InvalidOid) {
+ 		HeapTuple tup;
+ 
+ 		tup = SearchSysCache( TYPEOID
+ 							, datum
+ 							, 0, 0, 0
+ 							);
+ 
+ 		elemName = NameStr(((Form_pg_type) GETSTRUCT(tup))->typname);
+ 
+ 		ReleaseSysCache(tup);
+ 	}
+ 
+ 
+ 	/*
+ 	 * Run through constraints manually avoids the additional
+ 	 * processing conducted by DefineRelation() and friends.
+ 	 *
+ 	 * Besides, we don't want any constraints to be cooked.  We'll
+ 	 * do that when the table is created via MergeDomainAttributes().
+ 	 */
+ 	foreach(listptr, schema)
+ 	{
+ 		bool nullDefined = false;
+ 		Node	   *expr;
+ 		Constraint *colDef = lfirst(listptr);
+ 
+ 		/* Used for the statement transformation */
+ 		ParseState *pstate;
+ 
+ 		/*
+ 		 * Create a dummy ParseState and insert the target relation as its
+ 		 * sole rangetable entry.  We need a ParseState for transformExpr.
+ 		 */
+ 		pstate = make_parsestate(NULL);
+ 
+ 		switch(colDef->contype) {
+ 			/*
+ 	 		 * The inherited default value may be overridden by the user
+ 			 * with the DEFAULT <expr> statement.
+ 			 *
+ 	 		 * We have to search the entire constraint tree returned as we
+ 			 * don't want to cook or fiddle too much.
+ 			 */
+ 			case CONSTR_DEFAULT:
+ 
+ 				/*
+ 				 * Cook the colDef->raw_expr into an expression to ensure
+ 				 * that it can be done.  We store the text version of the
+ 				 * raw value.
+ 				 *
+ 				 * Note: Name is strictly for error message
+ 				 */
+ 				expr = cookDefault(pstate, colDef->raw_expr
+ 								, typeTup->t_data->t_oid
+ 								, stmt->typename->typmod
+ 								, stmt->typename->name);
+ 
+ 				/* Binary default required */
+ 				defaultValue = deparse_expression(expr,
+ 								deparse_context_for(stmt->domainname,
+ 													InvalidOid),
+ 												   false);
+ 
+ 				defaultValueBin = nodeToString(expr);
+ 
+ 				break;
+ 
+ 			/*
+ 			 * Find the NULL constraint.
+ 			 */
+ 			case CONSTR_NOTNULL:
+ 				if (nullDefined) {
+ 					elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
+ 				} else {
+ 					typNotNull = true;
+ 					nullDefined = true;
+ 				}
+ 
+ 		  		break;
+ 
+ 			case CONSTR_NULL:
+ 				if (nullDefined) {
+ 					elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
+ 				} else {
+ 					typNotNull = false;
+ 					nullDefined = true;
+ 				}
+ 
+ 		  		break;
+ 
+ 		  	case CONSTR_UNIQUE:
+ 		  		elog(ERROR, "CREATE DOMAIN / UNIQUE indecies not supported");
+ 		  		break;
+ 
+ 		  	case CONSTR_PRIMARY:
+ 		  		elog(ERROR, "CREATE DOMAIN / PRIMARY KEY indecies not supported");
+ 		  		break;
+ 
+ 
+ 		  	case CONSTR_CHECK:
+ 
+ 		  		elog(ERROR, "defineDomain: CHECK Constraints not supported");
+ 		  		break;
+ 
+ 		  	case CONSTR_ATTR_DEFERRABLE:
+ 		  	case CONSTR_ATTR_NOT_DEFERRABLE:
+ 		  	case CONSTR_ATTR_DEFERRED:
+ 		  	case CONSTR_ATTR_IMMEDIATE:
+ 		  		elog(ERROR, "defineDomain: DEFERRABLE, NON DEFERRABLE, DEFERRED and IMMEDIATE not supported");
+ 		  		break;
+ 		}
+ 
+ 	}
+ 
+ 	/*
+ 	 * Have TypeCreate do all the real work.
+ 	 */
+ 	TypeCreate(stmt->domainname,	/* type name */
+ 			   InvalidOid,			/* preassigned type oid (not done here) */
+ 			   InvalidOid,			/* relation oid (n/a here) */
+ 			   internalLength,		/* internal size */
+ 			   externalLength,		/* external size */
+ 			   'd',					/* type-type (domain type) */
+ 			   delimiter,			/* array element delimiter */
+ 			   inputName,			/* input procedure */
+ 			   outputName,			/* output procedure */
+ 			   receiveName,			/* receive procedure */
+ 			   sendName,			/* send procedure */
+ 			   elemName,			/* element type name */
+ 			   typeName,			/* base type name */
+ 			   defaultValue,		/* default type value */
+ 			   defaultValueBin,		/* default type value */
+ 			   byValue,				/* passed by value */
+ 			   alignment,			/* required alignment */
+ 			   storage,				/* TOAST strategy */
+ 			   stmt->typename->typmod, /* typeMod value */
+ 			   typNDims,			/* Array dimensions for base type */
+ 			   typNotNull);	/* Type NOT NULL */
+ 
+ 	/*
+ 	 * Now we can clean up.
+ 	 */
+ 	ReleaseSysCache(typeTup);
+ 	heap_close(pg_type_rel, NoLock);
+ }
+ 
+ 
+ /*
   * DefineType
   *		Registers a new type.
   */
***************
*** 490,495 ****
--- 807,814 ----
  	char	   *sendName = NULL;
  	char	   *receiveName = NULL;
  	char	   *defaultValue = NULL;
+ 	char	   *defaultValueBin = NULL;
+ 	Node	   *defaultRaw = (Node *) NULL;
  	bool		byValue = false;
  	char		delimiter = DEFAULT_TYPDELIM;
  	char	   *shadow_type;
***************
*** 531,537 ****
  		else if (strcasecmp(defel->defname, "element") == 0)
  			elemName = defGetString(defel);
  		else if (strcasecmp(defel->defname, "default") == 0)
! 			defaultValue = defGetString(defel);
  		else if (strcasecmp(defel->defname, "passedbyvalue") == 0)
  			byValue = true;
  		else if (strcasecmp(defel->defname, "alignment") == 0)
--- 850,856 ----
  		else if (strcasecmp(defel->defname, "element") == 0)
  			elemName = defGetString(defel);
  		else if (strcasecmp(defel->defname, "default") == 0)
! 			defaultRaw = defel->arg;
  		else if (strcasecmp(defel->defname, "passedbyvalue") == 0)
  			byValue = true;
  		else if (strcasecmp(defel->defname, "alignment") == 0)
***************
*** 591,596 ****
--- 910,941 ----
  	if (outputName == NULL)
  		elog(ERROR, "Define: \"output\" unspecified");
  
+ 
+ 	if (defaultRaw) {
+ 		Node   *expr;
+ 		ParseState *pstate;
+ 
+ 		/*
+ 		 * Create a dummy ParseState and insert the target relation as its
+ 		 * sole rangetable entry.  We need a ParseState for transformExpr.
+ 		 */
+ 		pstate = make_parsestate(NULL);
+ 
+ 		expr = cookDefault(pstate, defaultRaw,
+ 						   InvalidOid,
+ 						   -1,
+ 						   typeName);
+ 
+ 		/* Binary default required */
+ 		defaultValue = deparse_expression(expr,
+ 						deparse_context_for(typeName,
+ 											InvalidOid),
+ 										   false);
+ 
+ 		defaultValueBin = nodeToString(expr);
+ 	}
+ 
+ 
  	/*
  	 * now have TypeCreate do all the real work.
  	 */
***************
*** 606,615 ****
  			   receiveName,		/* receive procedure */
  			   sendName,		/* send procedure */
  			   elemName,		/* element type name */
  			   defaultValue,	/* default type value */
  			   byValue,			/* passed by value */
  			   alignment,		/* required alignment */
! 			   storage);		/* TOAST strategy */
  
  	/*
  	 * When we create a base type (as opposed to a complex type) we need
--- 951,965 ----
  			   receiveName,		/* receive procedure */
  			   sendName,		/* send procedure */
  			   elemName,		/* element type name */
+ 			   NULL,			/* base type name (Non-zero for domains) */
  			   defaultValue,	/* default type value */
+ 			   defaultValueBin,	/* default type value (Binary form) */
  			   byValue,			/* passed by value */
  			   alignment,		/* required alignment */
! 			   storage,			/* TOAST strategy */
! 			   -1,				/* typMod (Domains only) */
! 			   0,				/* Array Dimensions of typbasetype */
! 			   'f');			/* Type NOT NULL */
  
  	/*
  	 * When we create a base type (as opposed to a complex type) we need
***************
*** 632,641 ****
  			   "array_in",		/* receive procedure */
  			   "array_out",		/* send procedure */
  			   typeName,		/* element type name */
  			   NULL,			/* never a default type value */
  			   false,			/* never passed by value */
  			   alignment,		/* see above */
! 			   'x');			/* ARRAY is always toastable */
  
  	pfree(shadow_type);
  }
--- 982,996 ----
  			   "array_in",		/* receive procedure */
  			   "array_out",		/* send procedure */
  			   typeName,		/* element type name */
+ 			   NULL,			/* base type name */
  			   NULL,			/* never a default type value */
+ 			   NULL,			/* binary default isn't sent either */
  			   false,			/* never passed by value */
  			   alignment,		/* see above */
! 			   'x',				/* ARRAY is always toastable */
! 			   -1,				/* typMod (Domains only) */
! 			   0,				/* Array dimensions of typbasetype */
! 			   'f');			/* Type NOT NULL */
  
  	pfree(shadow_type);
  }
diff -rc pgsql.orig/src/backend/commands/remove.c pgsqldomain/src/backend/commands/remove.c
*** pgsql.orig/src/backend/commands/remove.c	Thu Mar  7 11:35:34 2002
--- pgsqldomain/src/backend/commands/remove.c	Thu Mar  7 22:24:23 2002
***************
*** 1,7 ****
  /*-------------------------------------------------------------------------
   *
   * remove.c
!  *	  POSTGRES remove (function | type | operator ) utilty code.
   *
   * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
   * Portions Copyright (c) 1994, Regents of the University of California
--- 1,7 ----
  /*-------------------------------------------------------------------------
   *
   * remove.c
!  *	  POSTGRES remove (domain | function | type | operator ) utilty code.
   *
   * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
   * Portions Copyright (c) 1994, Regents of the University of California
***************
*** 22,27 ****
--- 22,28 ----
  #include "commands/comment.h"
  #include "commands/defrem.h"
  #include "miscadmin.h"
+ #include "parser/parse.h"
  #include "parser/parse_agg.h"
  #include "parser/parse_expr.h"
  #include "parser/parse_func.h"
***************
*** 267,272 ****
--- 268,327 ----
  						 0, 0, 0);
  	if (!HeapTupleIsValid(tup))
  		elog(ERROR, "RemoveType: type '%s' does not exist", shadow_type);
+ 
+ 	simple_heap_delete(relation, &tup->t_self);
+ 
+ 	ReleaseSysCache(tup);
+ 
+ 	heap_close(relation, RowExclusiveLock);
+ }
+ 
+ /*
+  *	RemoveDomain
+  *		Removes the domain 'typeName' and all attributes and relations that
+  *		use it.
+  */
+ void
+ RemoveDomain(char *domainName, int behavior)		/* domain name to be removed */
+ {
+ 	Relation	relation;
+ 	HeapTuple	tup;
+ 	TupleDesc	description;
+ 	char		typtype;
+ 	bool		isnull;
+ 
+ 
+ 	/* Domains are stored as types.  Check for permissions on the type */
+ 	if (!pg_ownercheck(GetUserId(), domainName, TYPENAME))
+ 		elog(ERROR, "RemoveDomain: type '%s': permission denied",
+ 			 domainName);
+ 
+ 
+ 	relation = heap_openr(TypeRelationName, RowExclusiveLock);
+ 	description = RelationGetDescr(relation);
+ 
+ 	tup = SearchSysCache(TYPENAME,
+ 						 PointerGetDatum(domainName),
+ 						 0, 0, 0);
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "RemoveType: type '%s' does not exist", domainName);
+ 
+ 
+ 	/* Check that this is actually a domain */
+ 	typtype = DatumGetChar(heap_getattr(tup, Anum_pg_type_typtype, description, &isnull));
+ 	Assert(!isnull);
+ 
+ 	if (typtype != 'd') {
+ 		elog(ERROR, "%s is not a domain", domainName);
+ 	}
+ 
+ 	/* CASCADE unsupported */
+ 	if (behavior == CASCADE) {
+ 		elog(ERROR, "DROP DOMAIN does not support the CASCADE keyword");
+ 	}
+ 
+ 	/* Delete any comments associated with this type */
+ 	DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation));
  
  	simple_heap_delete(relation, &tup->t_self);
  
diff -rc pgsql.orig/src/backend/nodes/copyfuncs.c pgsqldomain/src/backend/nodes/copyfuncs.c
*** pgsql.orig/src/backend/nodes/copyfuncs.c	Thu Mar  7 11:35:34 2002
--- pgsqldomain/src/backend/nodes/copyfuncs.c	Thu Mar  7 22:53:19 2002
***************
*** 2227,2232 ****
--- 2227,2247 ----
  	return newnode;
  }
  
+ static CreateDomainStmt *
+ _copyCreateDomainStmt(CreateDomainStmt *from)
+ {
+ 	CreateDomainStmt *newnode = makeNode(CreateDomainStmt);
+ 
+ 	if (from->domainname)
+ 		newnode->domainname = pstrdup(from->domainname);
+ 	if (from->typename)
+ 		newnode->typename = from->typename;
+ 	if (from->constraints)
+ 		newnode->constraints = from->constraints;
+ 
+ 	return newnode;
+ }
+ 
  static CreatedbStmt *
  _copyCreatedbStmt(CreatedbStmt *from)
  {
***************
*** 3026,3031 ****
--- 3041,3049 ----
  			break;
  		case T_FuncWithArgs:
  			retval = _copyFuncWithArgs(from);
+ 			break;
+ 		case T_CreateDomainStmt:
+ 			retval = _copyCreateDomainStmt(from);
  			break;
  
  		default:
diff -rc pgsql.orig/src/backend/nodes/equalfuncs.c pgsqldomain/src/backend/nodes/equalfuncs.c
*** pgsql.orig/src/backend/nodes/equalfuncs.c	Thu Mar  7 11:35:34 2002
--- pgsqldomain/src/backend/nodes/equalfuncs.c	Thu Mar  7 22:52:49 2002
***************
*** 1096,1101 ****
--- 1096,1114 ----
  }
  
  static bool
+ _equalCreateDomainStmt(CreateDomainStmt *a, CreateDomainStmt *b)
+ {
+ 	if (!equalstr(a->domainname, b->domainname))
+ 		return false;
+ 	if (!equal(a->typename, b->typename))
+ 		return false;
+ 	if (!equal(a->constraints, b->constraints))
+ 		return false;
+ 
+ 	return true;
+ }
+ 
+ static bool
  _equalCreatedbStmt(CreatedbStmt *a, CreatedbStmt *b)
  {
  	if (!equalstr(a->dbname, b->dbname))
***************
*** 2010,2015 ****
--- 2023,2031 ----
  			break;
  		case T_LoadStmt:
  			retval = _equalLoadStmt(a, b);
+ 			break;
+ 		case T_CreateDomainStmt:
+ 			retval = _equalCreateDomainStmt(a, b);
  			break;
  		case T_CreatedbStmt:
  			retval = _equalCreatedbStmt(a, b);
diff -rc pgsql.orig/src/backend/optimizer/prep/preptlist.c pgsqldomain/src/backend/optimizer/prep/preptlist.c
*** pgsql.orig/src/backend/optimizer/prep/preptlist.c	Thu Mar  7 11:35:35 2002
--- pgsqldomain/src/backend/optimizer/prep/preptlist.c	Thu Mar  7 22:24:23 2002
***************
*** 355,362 ****
  	Form_pg_attribute att_tup = rd_att->attrs[attrno - 1];
  	Oid			atttype = att_tup->atttypid;
  	int32		atttypmod = att_tup->atttypmod;
- 	bool		hasdefault;
- 	Datum		typedefault;
  	int16		typlen;
  	bool		typbyval;
  	Node	   *expr;
--- 355,360 ----
***************
*** 392,398 ****
  				if (type_id != atttype)
  				{
  					expr = CoerceTargetExpr(NULL, expr, type_id,
! 											atttype, atttypmod);
  
  					/*
  					 * This really shouldn't fail; should have checked the
--- 390,396 ----
  				if (type_id != atttype)
  				{
  					expr = CoerceTargetExpr(NULL, expr, type_id,
! 											getBaseType(atttype), atttypmod);
  
  					/*
  					 * This really shouldn't fail; should have checked the
***************
*** 430,470 ****
  		 * element type is, and the element type's default is irrelevant
  		 * too.
  		 */
- 		hasdefault = false;
- 		typedefault = (Datum) 0;
  		typlen = sizeof(Oid);
  		typbyval = true;
  	}
  	else
  	{
  #ifdef	_DROP_COLUMN_HACK__
  		if (COLUMN_IS_DROPPED(att_tup))
  		{
! 			hasdefault = false;
! 			typedefault = (Datum) 0;
  		}
  		else
  #endif   /* _DROP_COLUMN_HACK__ */
! 			hasdefault = get_typdefault(atttype, &typedefault);
  
  		get_typlenbyval(atttype, &typlen, &typbyval);
  	}
  
- 	expr = (Node *) makeConst(atttype,
- 							  typlen,
- 							  typedefault,
- 							  !hasdefault,
- 							  typbyval,
- 							  false,	/* not a set */
- 							  false);
- 
  	/*
  	 * If the column is a fixed-length type, it may need a length coercion
! 	 * as well as a type coercion.	But NULLs don't need that.
  	 */
! 	if (hasdefault)
! 		expr = coerce_type_typmod(NULL, expr,
! 								  atttype, atttypmod);
  
  	return expr;
  }
--- 428,480 ----
  		 * element type is, and the element type's default is irrelevant
  		 * too.
  		 */
  		typlen = sizeof(Oid);
  		typbyval = true;
+ 
+ 		expr = (Node *) makeConst(atttype,
+ 								  typlen,
+ 								  (Datum) 0,
+ 								  true,
+ 								  typbyval,
+ 								  false,           /* not a set */
+ 								  false);
  	}
  	else
  	{
  #ifdef	_DROP_COLUMN_HACK__
  		if (COLUMN_IS_DROPPED(att_tup))
  		{
! 
! 			expr = (Node *) makeConst(atttype,
! 									  typlen,
! 									  (Datum) 0,
! 									  true,
! 									  typbyval,
! 									  false,           /* not a set */
! 									  false);
  		}
  		else
  #endif   /* _DROP_COLUMN_HACK__ */
! 			expr = get_typdefault(atttype, atttypmod);
  
+ 		if (expr == NULL) {
+ 				expr = (Node *) makeConst(atttype,
+ 										  typlen,
+ 										  (Datum) 0,
+ 										  true,
+ 										  typbyval,
+ 										  false,		/* not a set */
+ 										  false);
+ 		}
  		get_typlenbyval(atttype, &typlen, &typbyval);
  	}
  
  	/*
  	 * If the column is a fixed-length type, it may need a length coercion
! 	 * as well as a type coercion, as well as direction to the final type.
  	 */
! 	expr = coerce_type_typmod(NULL, expr,
! 							  atttype, atttypmod);
  
  	return expr;
  }
diff -rc pgsql.orig/src/backend/parser/gram.y pgsqldomain/src/backend/parser/gram.y
*** pgsql.orig/src/backend/parser/gram.y	Thu Mar  7 11:35:35 2002
--- pgsqldomain/src/backend/parser/gram.y	Thu Mar  7 22:34:00 2002
***************
*** 97,103 ****
  
  %}
  
- 
  %union
  {
  	int					ival;
--- 97,102 ----
***************
*** 135,141 ****
  		ClosePortalStmt, ClusterStmt, CommentStmt, ConstraintsSetStmt,
  		CopyStmt, CreateAsStmt, CreateGroupStmt, CreatePLangStmt,
  		CreateSchemaStmt, CreateSeqStmt, CreateStmt, CreateTrigStmt,
! 		CreateUserStmt, CreatedbStmt, CursorStmt, DefineStmt, DeleteStmt,
  		DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropTrigStmt,
  		DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
  		GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt,
--- 134,141 ----
  		ClosePortalStmt, ClusterStmt, CommentStmt, ConstraintsSetStmt,
  		CopyStmt, CreateAsStmt, CreateGroupStmt, CreatePLangStmt,
  		CreateSchemaStmt, CreateSeqStmt, CreateStmt, CreateTrigStmt,
! 		CreateUserStmt, CreateDomainStmt, CreatedbStmt, CursorStmt,
! 		DefineStmt, DeleteStmt,
  		DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropTrigStmt,
  		DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
  		GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt,
***************
*** 289,294 ****
--- 289,296 ----
  %type <list>	constraints_set_namelist
  %type <boolean>	constraints_set_mode
  
+ %type <boolean> opt_as
+ 
  /*
   * If you make any token changes, remember to:
   *		- use "yacc -d" and update parse.h
***************
*** 343,349 ****
  		WITHOUT
  
  /* Keywords (in SQL92 non-reserved words) */
! %token	COMMITTED, SERIALIZABLE, TYPE_P
  
  /* Keywords for Postgres support (not in SQL92 reserved words)
   *
--- 345,351 ----
  		WITHOUT
  
  /* Keywords (in SQL92 non-reserved words) */
! %token	COMMITTED, SERIALIZABLE, TYPE_P, DOMAIN_P
  
  /* Keywords for Postgres support (not in SQL92 reserved words)
   *
***************
*** 446,451 ****
--- 448,454 ----
  		| CopyStmt
  		| CreateStmt
  		| CreateAsStmt
+ 		| CreateDomainStmt
  		| CreateSchemaStmt
  		| CreateGroupStmt
  		| CreateSeqStmt
***************
*** 776,783 ****
--- 779,789 ----
  					n->dbname = $3;
  					$$ = (Node *)n;
  				}
+ 		;
  
  
+  
+ 
  /*****************************************************************************
   *
   * Set PG internal variable
***************
*** 1461,1467 ****
  					n->name = NULL;
  					if (exprIsNullConstant($2))
  					{
! 						/* DEFAULT NULL should be reported as empty expr */
  						n->raw_expr = NULL;
  					}
  					else
--- 1467,1476 ----
  					n->name = NULL;
  					if (exprIsNullConstant($2))
  					{
! 						/*
! 						 * DEFAULT NULL should be reported as empty expr
! 						 * Required for NOT NULL Domain overrides
! 						 */
  						n->raw_expr = NULL;
  					}
  					else
***************
*** 2043,2055 ****
  		| def_list ',' def_elem				{ $$ = lappend($1, $3); }
  		;
  
! def_elem:  ColLabel '=' def_arg
  				{
  					$$ = makeNode(DefElem);
  					$$->defname = $1;
  					$$->arg = (Node *)$3;
  				}
! 		| ColLabel
  				{
  					$$ = makeNode(DefElem);
  					$$->defname = $1;
--- 2052,2073 ----
  		| def_list ',' def_elem				{ $$ = lappend($1, $3); }
  		;
  
! def_elem:  DEFAULT '=' c_expr
! 				{
! 					$$ = makeNode(DefElem);
! 					$$->defname = "default";
! 					if (exprIsNullConstant($3))
! 						$$->arg = (Node *)NULL;
! 					else
! 						$$->arg = $3;
! 				}
! 		| ColId '=' def_arg
  				{
  					$$ = makeNode(DefElem);
  					$$->defname = $1;
  					$$->arg = (Node *)$3;
  				}
! 		| ColId
  				{
  					$$ = makeNode(DefElem);
  					$$->defname = $1;
***************
*** 2078,2083 ****
--- 2096,2110 ----
  					DropStmt *n = makeNode(DropStmt);
  					n->removeType = $2;
  					n->names = $3;
+ 					n->behavior = RESTRICT;		/* Restricted by default */
+ 					$$ = (Node *)n;
+ 				}
+ 		| DROP DOMAIN_P name_list drop_behavior
+ 				{	
+ 					DropStmt *n = makeNode(DropStmt);
+ 					n->removeType = DROP_DOMAIN_P;
+ 					n->names = $3;
+ 					n->behavior = $4;
  					$$ = (Node *)n;
  				}
  		;
***************
*** 2110,2116 ****
   *  The COMMENT ON statement can take different forms based upon the type of
   *  the object associated with the comment. The form of the statement is:
   *
!  *  COMMENT ON [ [ DATABASE | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ] 
   *               <objname> | AGGREGATE <aggname> (<aggtype>) | FUNCTION 
   *		 <funcname> (arg1, arg2, ...) | OPERATOR <op> 
   *		 (leftoperand_typ rightoperand_typ) | TRIGGER <triggername> ON
--- 2137,2143 ----
   *  The COMMENT ON statement can take different forms based upon the type of
   *  the object associated with the comment. The form of the statement is:
   *
!  *  COMMENT ON [ [ DATABASE | DOMAIN | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ] 
   *               <objname> | AGGREGATE <aggname> (<aggtype>) | FUNCTION 
   *		 <funcname> (arg1, arg2, ...) | OPERATOR <op> 
   *		 (leftoperand_typ rightoperand_typ) | TRIGGER <triggername> ON
***************
*** 2196,2201 ****
--- 2223,2229 ----
  		| RULE { $$ = RULE; }
  		| SEQUENCE { $$ = SEQUENCE; }
  		| TABLE { $$ = TABLE; }
+ 		| DOMAIN_P { $$ = TYPE_P; }
  		| TYPE_P { $$ = TYPE_P; }
  		| VIEW { $$ = VIEW; }
  		;		
***************
*** 3178,3183 ****
--- 3206,3227 ----
  				{
  					$$ = lconsi(3, makeListi1(-1));
  				}
+ 		;
+ 
+ 
+ /*****************************************************************************
+  *
+  *		DROP DATABASE
+  *
+  *
+  *****************************************************************************/
+ 
+ DropdbStmt:	DROP DATABASE database_name
+ 				{
+ 					DropdbStmt *n = makeNode(DropdbStmt);
+ 					n->dbname = $3;
+ 					$$ = (Node *)n;
+ 				}
  		| OWNER opt_equal name 
  				{
  					$$ = lconsi(4, makeList1($3));
***************
*** 3222,3243 ****
  				}
  		;
  
- 
  /*****************************************************************************
   *
!  *		DROP DATABASE
   *
   *
   *****************************************************************************/
  
! DropdbStmt:	DROP DATABASE database_name
  				{
! 					DropdbStmt *n = makeNode(DropdbStmt);
! 					n->dbname = $3;
  					$$ = (Node *)n;
  				}
  		;
  
  
  /*****************************************************************************
   *
--- 3266,3295 ----
  				}
  		;
  
  /*****************************************************************************
   *
!  * Manipulate a domain
   *
   *
   *****************************************************************************/
  
! CreateDomainStmt:  CREATE DOMAIN_P name opt_as Typename ColQualList opt_collate
  				{
! 					CreateDomainStmt *n = makeNode(CreateDomainStmt);
! 					n->domainname = $3;
! 					n->typename = $5;
! 					n->constraints = $6;
! 					
! 					if ($7 != NULL)
! 						elog(NOTICE,"CREATE DOMAIN / COLLATE %s not yet "
! 							"implemented; clause ignored", $7);
  					$$ = (Node *)n;
  				}
  		;
  
+ opt_as:	AS	{$$ = TRUE; }
+ 	| /* EMPTY */	{$$ = FALSE; }
+ 	;
  
  /*****************************************************************************
   *
***************
*** 5879,5884 ****
--- 5931,5937 ----
  		| DEFERRED						{ $$ = "deferred"; }
  		| DELETE						{ $$ = "delete"; }
  		| DELIMITERS					{ $$ = "delimiters"; }
+ 		| DOMAIN_P						{ $$ = "domain"; }
  		| DOUBLE						{ $$ = "double"; }
  		| DROP							{ $$ = "drop"; }
  		| EACH							{ $$ = "each"; }
diff -rc pgsql.orig/src/backend/parser/keywords.c pgsqldomain/src/backend/parser/keywords.c
*** pgsql.orig/src/backend/parser/keywords.c	Thu Mar  7 11:35:35 2002
--- pgsqldomain/src/backend/parser/keywords.c	Thu Mar  7 22:24:24 2002
***************
*** 97,102 ****
--- 97,103 ----
  	{"desc", DESC},
  	{"distinct", DISTINCT},
  	{"do", DO},
+ 	{"domain", DOMAIN_P},
  	{"double", DOUBLE},
  	{"drop", DROP},
  	{"each", EACH},
diff -rc pgsql.orig/src/backend/parser/parse_coerce.c pgsqldomain/src/backend/parser/parse_coerce.c
*** pgsql.orig/src/backend/parser/parse_coerce.c	Thu Mar  7 11:35:35 2002
--- pgsqldomain/src/backend/parser/parse_coerce.c	Thu Mar  7 22:24:24 2002
***************
*** 38,43 ****
--- 38,44 ----
  {
  	Node	   *result;
  
+ 
  	if (targetTypeId == inputTypeId ||
  		targetTypeId == InvalidOid ||
  		node == NULL)
***************
*** 605,607 ****
--- 606,637 ----
  	}
  	return result;
  }	/* PreferredType() */
+ 
+ 
+ /*
+  * If the targetTypeId is a domain, we really want to coerce
+  * the tuple to the domain type -- not the domain itself
+  */
+ Oid
+ getBaseType(Oid inType)
+ {
+ 	HeapTuple	tup;
+ 	Form_pg_type typTup;
+ 
+ 	tup = SearchSysCache(TYPEOID,
+ 						 ObjectIdGetDatum(inType),
+ 						 0, 0, 0);
+ 
+ 	typTup = ((Form_pg_type) GETSTRUCT(tup));
+ 
+ 	/*
+ 	 * Assume that typbasetype exists and is a base type, where inType
+ 	 * was a domain
+ 	 */
+ 	if (typTup->typtype == 'd')
+ 		inType = typTup->typbasetype;
+ 
+ 	ReleaseSysCache(tup);
+ 
+ 	return inType;
+ }
diff -rc pgsql.orig/src/backend/parser/parse_expr.c pgsqldomain/src/backend/parser/parse_expr.c
*** pgsql.orig/src/backend/parser/parse_expr.c	Thu Mar  7 11:35:36 2002
--- pgsqldomain/src/backend/parser/parse_expr.c	Thu Mar  7 22:24:24 2002
***************
*** 1027,1033 ****
  	if (inputType != targetType)
  	{
  		expr = CoerceTargetExpr(pstate, expr, inputType,
! 								targetType, typename->typmod);
  		if (expr == NULL)
  			elog(ERROR, "Cannot cast type '%s' to '%s'",
  				 format_type_be(inputType),
--- 1027,1034 ----
  	if (inputType != targetType)
  	{
  		expr = CoerceTargetExpr(pstate, expr, inputType,
! 								getBaseType(targetType),
! 								typename->typmod);
  		if (expr == NULL)
  			elog(ERROR, "Cannot cast type '%s' to '%s'",
  				 format_type_be(inputType),
***************
*** 1039,1045 ****
  	 * as well as a type coercion.
  	 */
  	expr = coerce_type_typmod(pstate, expr,
! 							  targetType, typename->typmod);
  
  	return expr;
  }
--- 1040,1046 ----
  	 * as well as a type coercion.
  	 */
  	expr = coerce_type_typmod(pstate, expr,
! 							  getBaseType(targetType), typename->typmod);
  
  	return expr;
  }
Only in pgsqldomain/src/backend/parser: y.output
diff -rc pgsql.orig/src/backend/tcop/postgres.c pgsqldomain/src/backend/tcop/postgres.c
*** pgsql.orig/src/backend/tcop/postgres.c	Wed Mar  6 01:10:09 2002
--- pgsqldomain/src/backend/tcop/postgres.c	Thu Mar  7 22:24:24 2002
***************
*** 2212,2217 ****
--- 2212,2218 ----
  			}
  			break;
  
+ 		case T_CreateDomainStmt:
  		case T_CreateStmt:
  			tag = "CREATE";
  			break;
diff -rc pgsql.orig/src/backend/tcop/utility.c pgsqldomain/src/backend/tcop/utility.c
*** pgsql.orig/src/backend/tcop/utility.c	Thu Mar  7 11:35:36 2002
--- pgsqldomain/src/backend/tcop/utility.c	Thu Mar  7 22:24:24 2002
***************
*** 282,287 ****
--- 282,292 ----
  							/* RemoveType does its own permissions checks */
  							RemoveType(relname);
  							break;
+ 
+ 						case DROP_DOMAIN_P:
+ 							/* RemoveDomain does its own permissions checks */
+ 							RemoveDomain(relname, stmt->behavior);
+ 							break;
  					}
  
  					/*
***************
*** 725,730 ****
--- 730,748 ----
  		case T_DropPLangStmt:
  			DropProceduralLanguage((DropPLangStmt *) parsetree);
  			break;
+ 
+ 			/*
+ 			 * ******************************** DOMAIN statements ****
+ 			 *
+ 			 */
+ 		case T_CreateDomainStmt:
+ 			DefineDomain((CreateDomainStmt *) parsetree);
+ 			break;
+ 
+ 			/*
+ 			 * ******************************** USER statements ****
+ 			 *
+ 			 */
  
  		case T_CreateUserStmt:
  			CreateUser((CreateUserStmt *) parsetree);
diff -rc pgsql.orig/src/backend/utils/adt/format_type.c pgsqldomain/src/backend/utils/adt/format_type.c
*** pgsql.orig/src/backend/utils/adt/format_type.c	Thu Mar  7 11:35:36 2002
--- pgsqldomain/src/backend/utils/adt/format_type.c	Thu Mar  7 22:24:24 2002
***************
*** 126,131 ****
--- 126,132 ----
  	bool		is_array;
  	char	   *name;
  	char	   *buf;
+ 	char		typtype;
  
  	if (type_oid == InvalidOid && allow_invalid)
  		return pstrdup("-");
***************
*** 144,149 ****
--- 145,175 ----
  
  	array_base_type = ((Form_pg_type) GETSTRUCT(tuple))->typelem;
  	typlen = ((Form_pg_type) GETSTRUCT(tuple))->typlen;
+ 	typtype = ((Form_pg_type) GETSTRUCT(tuple))->typtype;
+ 
+ 	/*
+ 	 * Domains look alot like arrays, so lets process them first, and return
+ 	 * back to avoid the array and 'standard' formatting procedures that are
+ 	 * use for base types.
+ 	 */
+ 	if (typtype == 'd') {
+ 		name = NameStr(((Form_pg_type) GETSTRUCT(tuple))->typname);
+ 
+ 		/*
+ 		 * Double-quote the name if it's not a standard identifier.
+ 		 * Note this is *necessary* for ruleutils.c's use.
+ 		 */
+ 		if (strspn(name, "abcdefghijklmnopqrstuvwxyz0123456789_") != strlen(name)
+ 			|| isdigit((unsigned char) name[0]))
+ 				buf = psnprintf(strlen(name) + 3, "\"%s\"", name);
+ 		else
+ 			buf = pstrdup(name);
+ 
+ 		ReleaseSysCache(tuple);
+ 
+ 		return buf;
+ 	}
+ 
  	if (array_base_type != InvalidOid && typlen < 0)
  	{
  		/* Switch our attention to the array element type */
diff -rc pgsql.orig/src/backend/utils/cache/lsyscache.c pgsqldomain/src/backend/utils/cache/lsyscache.c
*** pgsql.orig/src/backend/utils/cache/lsyscache.c	Thu Mar  7 11:35:36 2002
--- pgsqldomain/src/backend/utils/cache/lsyscache.c	Thu Mar  7 22:24:24 2002
***************
*** 23,28 ****
--- 23,29 ----
  #include "catalog/pg_shadow.h"
  #include "catalog/pg_statistic.h"
  #include "catalog/pg_type.h"
+ #include "parser/parse_coerce.h"
  #include "utils/array.h"
  #include "utils/builtins.h"
  #include "utils/lsyscache.h"
***************
*** 822,837 ****
   *	  Returns FALSE if there is no default (effectively, default is NULL).
   *	  The result points to palloc'd storage for pass-by-reference types.
   */
! bool
! get_typdefault(Oid typid, Datum *defaultValue)
  {
  	HeapTuple	typeTuple;
  	Form_pg_type type;
! 	Oid			typinput,
! 				typelem;
! 	Datum		textDefaultVal;
  	bool		isNull;
! 	char	   *strDefaultVal;
  
  	typeTuple = SearchSysCache(TYPEOID,
  							   ObjectIdGetDatum(typid),
--- 823,839 ----
   *	  Returns FALSE if there is no default (effectively, default is NULL).
   *	  The result points to palloc'd storage for pass-by-reference types.
   */
! Node *
! get_typdefault(Oid typid, int32 atttypmod)
  {
  	HeapTuple	typeTuple;
  	Form_pg_type type;
! 	Oid			typinput;
! 	Oid			typbasetype;
! 	char		typtype;
! 	Datum		datum;
  	bool		isNull;
! 	Node	   *expr;
  
  	typeTuple = SearchSysCache(TYPEOID,
  							   ObjectIdGetDatum(typid),
***************
*** 843,880 ****
  	type = (Form_pg_type) GETSTRUCT(typeTuple);
  
  	typinput = type->typinput;
! 	typelem = type->typelem;
  
  	/*
! 	 * typdefault is potentially null, so don't try to access it as a
  	 * struct field. Must do it the hard way with SysCacheGetAttr.
  	 */
! 	textDefaultVal = SysCacheGetAttr(TYPEOID,
! 									 typeTuple,
! 									 Anum_pg_type_typdefault,
! 									 &isNull);
  
  	if (isNull)
! 	{
! 		ReleaseSysCache(typeTuple);
! 		*defaultValue = (Datum) 0;
! 		return false;
! 	}
  
! 	/* Convert text datum to C string */
! 	strDefaultVal = DatumGetCString(DirectFunctionCall1(textout,
! 														textDefaultVal));
! 
! 	/* Convert C string to a value of the given type */
! 	*defaultValue = OidFunctionCall3(typinput,
! 									 CStringGetDatum(strDefaultVal),
! 									 ObjectIdGetDatum(typelem),
! 									 Int32GetDatum(-1));
  
- 	pfree(strDefaultVal);
- 	ReleaseSysCache(typeTuple);
  
! 	return true;
  }
  
  /*
--- 845,885 ----
  	type = (Form_pg_type) GETSTRUCT(typeTuple);
  
  	typinput = type->typinput;
! 	typbasetype = type->typbasetype;
! 	typtype = type->typtype;
  
  	/*
! 	 * typdefaultbin is potentially null, so don't try to access it as a
  	 * struct field. Must do it the hard way with SysCacheGetAttr.
  	 */
! 	datum = SysCacheGetAttr(TYPEOID,
! 							typeTuple,
! 							Anum_pg_type_typdefaultbin,
! 							&isNull);
  
+ 	ReleaseSysCache(typeTuple);
  	if (isNull)
! 		return (Node *) NULL;
  
! 	/* Convert Datum to a Node */
! 	expr = stringToNode(DatumGetCString(
! 						DirectFunctionCall1(textout, datum)));
! 
! 
! 	/*
! 	 * Ensure we goto the basetype before the domain type.
! 	 *
! 	 * Prevents scenarios like the below from failing:
! 	 * CREATE DOMAIN dom text DEFAULT random();
! 	 *
! 	 */
! 	if (typbasetype != InvalidOid) {
! 		expr = coerce_type(NULL, expr, typid,
! 						  typbasetype, atttypmod);
! 	}
  
  
! 	return expr;
  }
  
  /*
diff -rc pgsql.orig/src/backend/utils/cache/relcache.c pgsqldomain/src/backend/utils/cache/relcache.c
*** pgsql.orig/src/backend/utils/cache/relcache.c	Thu Mar  7 11:35:36 2002
--- pgsqldomain/src/backend/utils/cache/relcache.c	Thu Mar  7 22:24:24 2002
***************
*** 512,519 ****
  			   (char *) attp,
  			   ATTRIBUTE_TUPLE_SIZE);
  
! 		/* Update constraint/default info */
! 		if (attp->attnotnull)
  			constr->has_not_null = true;
  
  		if (attp->atthasdef)
--- 512,523 ----
  			   (char *) attp,
  			   ATTRIBUTE_TUPLE_SIZE);
  
! 
! 
! 		/*
! 		 * Update constraint/default info
! 		 */
!        if (attp->attnotnull)
  			constr->has_not_null = true;
  
  		if (attp->atthasdef)
diff -rc pgsql.orig/src/include/catalog/heap.h pgsqldomain/src/include/catalog/heap.h
*** pgsql.orig/src/include/catalog/heap.h	Thu Mar  7 11:35:38 2002
--- pgsqldomain/src/include/catalog/heap.h	Thu Mar  7 22:24:24 2002
***************
*** 15,20 ****
--- 15,22 ----
  #define HEAP_H
  
  #include "catalog/pg_attribute.h"
+ #include "nodes/parsenodes.h"
+ #include "parser/parse_node.h"
  #include "utils/rel.h"
  
  typedef struct RawColumnDefault
***************
*** 44,49 ****
--- 46,57 ----
  extern void AddRelationRawConstraints(Relation rel,
  						  List *rawColDefaults,
  						  List *rawConstraints);
+ 
+ extern Node *cookDefault(ParseState *pstate
+ 						, Node *raw_default
+ 						, Oid atttypid
+ 						, int32 atttypmod
+ 						, char *attname);
  
  extern int	RemoveCheckConstraint(Relation rel, const char *constrName, bool inh);
  
diff -rc pgsql.orig/src/include/catalog/pg_attribute.h pgsqldomain/src/include/catalog/pg_attribute.h
*** pgsql.orig/src/include/catalog/pg_attribute.h	Thu Mar  7 11:35:38 2002
--- pgsqldomain/src/include/catalog/pg_attribute.h	Thu Mar  7 22:24:24 2002
***************
*** 240,246 ****
  { 1247, {"typsend"},	   24, 0,	4, 14, 0, -1, -1, true, 'p', false, 'i', false, false }, \
  { 1247, {"typalign"},	   18, 0,	1, 15, 0, -1, -1, true, 'p', false, 'c', false, false }, \
  { 1247, {"typstorage"},    18, 0,	1, 16, 0, -1, -1, true, 'p', false, 'c', false, false }, \
! { 1247, {"typdefault"},    25, 0,  -1, 17, 0, -1, -1, false , 'x', false, 'i', false, false }
  
  DATA(insert ( 1247 typname			19 DEFAULT_ATTSTATTARGET NAMEDATALEN   1 0 -1 -1 f p f i f f));
  DATA(insert ( 1247 typowner			23 0  4   2 0 -1 -1 t p f i f f));
--- 240,252 ----
  { 1247, {"typsend"},	   24, 0,	4, 14, 0, -1, -1, true, 'p', false, 'i', false, false }, \
  { 1247, {"typalign"},	   18, 0,	1, 15, 0, -1, -1, true, 'p', false, 'c', false, false }, \
  { 1247, {"typstorage"},    18, 0,	1, 16, 0, -1, -1, true, 'p', false, 'c', false, false }, \
! { 1247, {"typnotnull"},    16, 0,   1, 17, 0, -1, -1, true, 'p', false, 'c', false, false }, \
! { 1247, {"typmod"},        23, 0,	4, 18, 0, -1, -1, true, 'p', false, 'i', false, false }, \
! { 1247, {"typbasetype"},   26, 0,	4, 19, 0, -1, -1, true, 'p', false, 'i', false, false }, \
! { 1247, {"typndims"},      23, 0,	4, 20, 0, -1, -1, true, 'p', false, 'i', false, false }, \
! { 1247, {"typdefaultbin"}, 25, 0,  -1, 21, 0, -1, -1, false, 'x', false, 'i', false, false }, \
! { 1247, {"typdefault"},    25, 0,  -1, 22, 0, -1, -1, false, 'x', false, 'i', false, false }
! 
  
  DATA(insert ( 1247 typname			19 DEFAULT_ATTSTATTARGET NAMEDATALEN   1 0 -1 -1 f p f i f f));
  DATA(insert ( 1247 typowner			23 0  4   2 0 -1 -1 t p f i f f));
***************
*** 258,264 ****
  DATA(insert ( 1247 typsend			24 0  4  14 0 -1 -1 t p f i f f));
  DATA(insert ( 1247 typalign			18 0  1  15 0 -1 -1 t p f c f f));
  DATA(insert ( 1247 typstorage		18 0  1  16 0 -1 -1 t p f c f f));
! DATA(insert ( 1247 typdefault		25 0 -1  17 0 -1 -1 f x f i f f));
  DATA(insert ( 1247 ctid				27 0  6  -1 0 -1 -1 f p f i f f));
  DATA(insert ( 1247 oid				26 0  4  -2 0 -1 -1 t p f i f f));
  DATA(insert ( 1247 xmin				28 0  4  -3 0 -1 -1 t p f i f f));
--- 264,275 ----
  DATA(insert ( 1247 typsend			24 0  4  14 0 -1 -1 t p f i f f));
  DATA(insert ( 1247 typalign			18 0  1  15 0 -1 -1 t p f c f f));
  DATA(insert ( 1247 typstorage		18 0  1  16 0 -1 -1 t p f c f f));
! DATA(insert ( 1247 typnotnull		16 0  1  17 0 -1 -1 t p f c f f));
! DATA(insert ( 1247 typmod			23 0  4  18 0 -1 -1 t p f i f f));
! DATA(insert ( 1247 typbasetype		26 0  4  19 0 -1 -1 t p f i f f));
! DATA(insert ( 1247 typndims			23 0  4  20 0 -1 -1 t p f i f f));
! DATA(insert ( 1247 typdefaultbin	25 0 -1  21 0 -1 -1 f x f i f f));
! DATA(insert ( 1247 typdefault		25 0 -1  22 0 -1 -1 f x f i f f));
  DATA(insert ( 1247 ctid				27 0  6  -1 0 -1 -1 f p f i f f));
  DATA(insert ( 1247 oid				26 0  4  -2 0 -1 -1 t p f i f f));
  DATA(insert ( 1247 xmin				28 0  4  -3 0 -1 -1 t p f i f f));
diff -rc pgsql.orig/src/include/catalog/pg_class.h pgsqldomain/src/include/catalog/pg_class.h
*** pgsql.orig/src/include/catalog/pg_class.h	Thu Mar  7 11:35:38 2002
--- pgsqldomain/src/include/catalog/pg_class.h	Thu Mar  7 22:24:24 2002
***************
*** 132,138 ****
   * ----------------
   */
  
! DATA(insert OID = 1247 (  pg_type		71	PGUID 0 1247 0 0 0 0 f f r 17 0 0 0 0 0 t f f f _null_ ));
  DESCR("");
  DATA(insert OID = 1249 (  pg_attribute	75	PGUID 0 1249 0 0 0 0 f f r 15 0 0 0 0 0 f f f f _null_ ));
  DESCR("");
--- 132,138 ----
   * ----------------
   */
  
! DATA(insert OID = 1247 (  pg_type		71	PGUID 0 1247 0 0 0 0 f f r 22 0 0 0 0 0 t f f f _null_ ));
  DESCR("");
  DATA(insert OID = 1249 (  pg_attribute	75	PGUID 0 1249 0 0 0 0 f f r 15 0 0 0 0 0 f f f f _null_ ));
  DESCR("");
diff -rc pgsql.orig/src/include/catalog/pg_type.h pgsqldomain/src/include/catalog/pg_type.h
*** pgsql.orig/src/include/catalog/pg_type.h	Thu Mar  7 11:35:38 2002
--- pgsqldomain/src/include/catalog/pg_type.h	Thu Mar  7 22:24:24 2002
***************
*** 141,152 ****
  	char		typstorage;
  
  	/*
  	 * typdefault is NULL if the type has no associated default value. If
  	 * it's not NULL, it contains the external representation of the
! 	 * type's default value --- this default is used whenever no
! 	 * per-column default is specified for a column of the datatype.
  	 */
  	text		typdefault;		/* VARIABLE LENGTH FIELD */
  } FormData_pg_type;
  
  /* ----------------
--- 141,189 ----
  	char		typstorage;
  
  	/*
+ 	 * This flag represents a "NOT NULL" constraint against this datatype.
+ 	 *
+ 	 * If true, the attnotnull column for a corresponding table column using
+ 	 * this datatype will always enforce the NOT NULL constraint.
+ 	 *
+ 	 * Used primarily for domain types.
+ 	 */
+ 	bool		typnotnull;
+ 
+ 	/*
+ 	 * typmod records type-specific data supplied at domain creation
+ 	 * time (for example, the max length of a varchar field).  It is
+ 	 * passed to type-specific input and output functions as the third
+ 	 * argument. The value will generally be -1 for types that do not need
+ 	 * typmod.  This value is copied to pg_attribute.atttypmod.
+ 	 */
+ 	int4		typmod;
+ 
+ 	/*
+ 	 * Domains use typbasetype to determine the base (or complex)type that
+ 	 * the domain is based off.  It must be non-zero if the type is a
+ 	 * domain.
+ 	 */
+ 	Oid			typbasetype;
+ 
+ 	/*
+ 	 * typndims is the declared number of dimensions, if an array typbasetype,
+ 	 * otherwise zero.
+ 	 */
+ 	int4		typndims;
+ 
+ 	/*
+ 	 * typdefaultbin is the binary representation of typdefault
+ 	 */
+ 	text		typdefaultbin;	/* VARIABLE LENGTH FIELD */
+ 
+ 	/*
  	 * typdefault is NULL if the type has no associated default value. If
  	 * it's not NULL, it contains the external representation of the
! 	 * type's default value
  	 */
  	text		typdefault;		/* VARIABLE LENGTH FIELD */
+ 
  } FormData_pg_type;
  
  /* ----------------
***************
*** 160,166 ****
   *		compiler constants for pg_type
   * ----------------
   */
! #define Natts_pg_type					17
  #define Anum_pg_type_typname			1
  #define Anum_pg_type_typowner			2
  #define Anum_pg_type_typlen				3
--- 197,203 ----
   *		compiler constants for pg_type
   * ----------------
   */
! #define Natts_pg_type					22
  #define Anum_pg_type_typname			1
  #define Anum_pg_type_typowner			2
  #define Anum_pg_type_typlen				3
***************
*** 177,183 ****
  #define Anum_pg_type_typsend			14
  #define Anum_pg_type_typalign			15
  #define Anum_pg_type_typstorage			16
! #define Anum_pg_type_typdefault			17
  
  /* ----------------
   *		initial contents of pg_type
--- 214,226 ----
  #define Anum_pg_type_typsend			14
  #define Anum_pg_type_typalign			15
  #define Anum_pg_type_typstorage			16
! #define Anum_pg_type_typnotnull			17
! #define Anum_pg_type_typmod				18
! #define Anum_pg_type_typbasetype		19
! #define Anum_pg_type_typndims			20
! #define Anum_pg_type_typdefaultbin		21
! #define Anum_pg_type_typdefault			22
! 
  
  /* ----------------
   *		initial contents of pg_type
***************
*** 192,273 ****
  */
  
  /* OIDS 1 - 99 */
! DATA(insert OID = 16 (	bool	   PGUID  1   1 t b t \054 0   0 boolin boolout boolin boolout c p _null_ ));
  DESCR("boolean, 'true'/'false'");
  #define BOOLOID			16
  
! DATA(insert OID = 17 (	bytea	   PGUID -1  -1 f b t \054 0  0 byteain byteaout byteain byteaout i x _null_ ));
  DESCR("variable-length string, binary values escaped");
  #define BYTEAOID		17
  
! DATA(insert OID = 18 (	char	   PGUID  1   1 t b t \054 0   0 charin charout charin charout c p _null_ ));
  DESCR("single character");
  #define CHAROID			18
  
! DATA(insert OID = 19 (	name	   PGUID NAMEDATALEN NAMEDATALEN  f b t \054 0	18 namein nameout namein nameout i p _null_ ));
  DESCR("31-character type for storing system identifiers");
  #define NAMEOID			19
  
! DATA(insert OID = 20 (	int8	   PGUID  8  20 f b t \054 0   0 int8in int8out int8in int8out d p _null_ ));
  DESCR("~18 digit integer, 8-byte storage");
  #define INT8OID			20
  
! DATA(insert OID = 21 (	int2	   PGUID  2   5 t b t \054 0   0 int2in int2out int2in int2out s p _null_ ));
  DESCR("-32 thousand to 32 thousand, 2-byte storage");
  #define INT2OID			21
  
! DATA(insert OID = 22 (	int2vector PGUID INDEX_MAX_KEYS*2 -1 f b t \054 0  21 int2vectorin int2vectorout int2vectorin int2vectorout i p _null_ ));
  DESCR("array of INDEX_MAX_KEYS int2 integers, used in system tables");
  #define INT2VECTOROID	22
  
! DATA(insert OID = 23 (	int4	   PGUID  4  10 t b t \054 0   0 int4in int4out int4in int4out i p _null_ ));
  DESCR("-2 billion to 2 billion integer, 4-byte storage");
  #define INT4OID			23
  
! DATA(insert OID = 24 (	regproc    PGUID  4  16 t b t \054 0   0 regprocin regprocout regprocin regprocout i p _null_ ));
  DESCR("registered procedure");
  #define REGPROCOID		24
  
! DATA(insert OID = 25 (	text	   PGUID -1  -1 f b t \054 0  0 textin textout textin textout i x _null_ ));
  DESCR("variable-length string, no limit specified");
  #define TEXTOID			25
  
! DATA(insert OID = 26 (	oid		   PGUID  4  10 t b t \054 0   0 oidin oidout oidin oidout i p _null_ ));
  DESCR("object identifier(oid), maximum 4 billion");
  #define OIDOID			26
  
! DATA(insert OID = 27 (	tid		   PGUID  6  19 f b t \054 0   0 tidin tidout tidin tidout i p _null_ ));
  DESCR("(Block, offset), physical location of tuple");
  #define TIDOID		27
  
! DATA(insert OID = 28 (	xid		   PGUID  4  12 t b t \054 0   0 xidin xidout xidin xidout i p _null_ ));
  DESCR("transaction id");
  #define XIDOID 28
  
! DATA(insert OID = 29 (	cid		   PGUID  4  10 t b t \054 0   0 cidin cidout cidin cidout i p _null_ ));
  DESCR("command identifier type, sequence in transaction id");
  #define CIDOID 29
  
! DATA(insert OID = 30 (	oidvector  PGUID INDEX_MAX_KEYS*4 -1 f b t \054 0  26 oidvectorin oidvectorout oidvectorin oidvectorout i p _null_ ));
  DESCR("array of INDEX_MAX_KEYS oids, used in system tables");
  #define OIDVECTOROID	30
  
! DATA(insert OID = 32 (	SET		   PGUID -1  -1 f b t \054 0   0 textin textout textin textout i p _null_ ));
  DESCR("set of tuples");
  
! DATA(insert OID = 71 (	pg_type		 PGUID 4 4 t c t \054 1247 0 int4in int4out int4in int4out i p _null_));
! DATA(insert OID = 75 (	pg_attribute PGUID 4 4 t c t \054 1249 0 int4in int4out int4in int4out i p _null_));
! DATA(insert OID = 81 (	pg_proc		 PGUID 4 4 t c t \054 1255 0 int4in int4out int4in int4out i p _null_));
! DATA(insert OID = 83 (	pg_class	 PGUID 4 4 t c t \054 1259 0 int4in int4out int4in int4out i p _null_));
! DATA(insert OID = 86 (	pg_shadow	 PGUID 4 4 t c t \054 1260 0 int4in int4out int4in int4out i p _null_));
! DATA(insert OID = 87 (	pg_group	 PGUID 4 4 t c t \054 1261 0 int4in int4out int4in int4out i p _null_));
! DATA(insert OID = 88 (	pg_database  PGUID 4 4 t c t \054 1262 0 int4in int4out int4in int4out i p _null_));
  
  /* OIDS 100 - 199 */
  
  /* OIDS 200 - 299 */
  
! DATA(insert OID = 210 (  smgr	   PGUID 2	12 t b t \054 0 0 smgrin smgrout smgrin smgrout s p _null_ ));
  DESCR("storage manager");
  
  /* OIDS 300 - 399 */
--- 235,316 ----
  */
  
  /* OIDS 1 - 99 */
! DATA(insert OID = 16 (	bool	   PGUID  1   1 t b t \054 0   0 boolin boolout boolin boolout c p f -1 0 0 _null_ _null_ ));
  DESCR("boolean, 'true'/'false'");
  #define BOOLOID			16
  
! DATA(insert OID = 17 (	bytea	   PGUID -1  -1 f b t \054 0  0 byteain byteaout byteain byteaout i x f -1 0 0 _null_ _null_ ));
  DESCR("variable-length string, binary values escaped");
  #define BYTEAOID		17
  
! DATA(insert OID = 18 (	char	   PGUID  1   1 t b t \054 0   0 charin charout charin charout c p f -1 0 0 _null_ _null_ ));
  DESCR("single character");
  #define CHAROID			18
  
! DATA(insert OID = 19 (	name	   PGUID NAMEDATALEN NAMEDATALEN  f b t \054 0	18 namein nameout namein nameout i p f -1 0 0 _null_ _null_ ));
  DESCR("31-character type for storing system identifiers");
  #define NAMEOID			19
  
! DATA(insert OID = 20 (	int8	   PGUID  8  20 f b t \054 0   0 int8in int8out int8in int8out d p f -1 0 0 _null_ _null_ ));
  DESCR("~18 digit integer, 8-byte storage");
  #define INT8OID			20
  
! DATA(insert OID = 21 (	int2	   PGUID  2   5 t b t \054 0   0 int2in int2out int2in int2out s p f -1 0 0 _null_ _null_ ));
  DESCR("-32 thousand to 32 thousand, 2-byte storage");
  #define INT2OID			21
  
! DATA(insert OID = 22 (	int2vector PGUID INDEX_MAX_KEYS*2 -1 f b t \054 0  21 int2vectorin int2vectorout int2vectorin int2vectorout i p f -1 0 0 _null_ _null_ ));
  DESCR("array of INDEX_MAX_KEYS int2 integers, used in system tables");
  #define INT2VECTOROID	22
  
! DATA(insert OID = 23 (	int4	   PGUID  4  10 t b t \054 0   0 int4in int4out int4in int4out i p f -1 0 0 _null_ _null_ ));
  DESCR("-2 billion to 2 billion integer, 4-byte storage");
  #define INT4OID			23
  
! DATA(insert OID = 24 (	regproc    PGUID  4  16 t b t \054 0   0 regprocin regprocout regprocin regprocout i p f -1 0 0 _null_ _null_ ));
  DESCR("registered procedure");
  #define REGPROCOID		24
  
! DATA(insert OID = 25 (	text	   PGUID -1  -1 f b t \054 0  0 textin textout textin textout i x f -1 0 0 _null_ _null_ ));
  DESCR("variable-length string, no limit specified");
  #define TEXTOID			25
  
! DATA(insert OID = 26 (	oid		   PGUID  4  10 t b t \054 0   0 oidin oidout oidin oidout i p f -1 0 0 _null_ _null_ ));
  DESCR("object identifier(oid), maximum 4 billion");
  #define OIDOID			26
  
! DATA(insert OID = 27 (	tid		   PGUID  6  19 f b t \054 0   0 tidin tidout tidin tidout i p f -1 0 0 _null_ _null_ ));
  DESCR("(Block, offset), physical location of tuple");
  #define TIDOID		27
  
! DATA(insert OID = 28 (	xid		   PGUID  4  12 t b t \054 0   0 xidin xidout xidin xidout i p f -1 0 0 _null_ _null_ ));
  DESCR("transaction id");
  #define XIDOID 28
  
! DATA(insert OID = 29 (	cid		   PGUID  4  10 t b t \054 0   0 cidin cidout cidin cidout i p f -1 0 0 _null_ _null_ ));
  DESCR("command identifier type, sequence in transaction id");
  #define CIDOID 29
  
! DATA(insert OID = 30 (	oidvector  PGUID INDEX_MAX_KEYS*4 -1 f b t \054 0  26 oidvectorin oidvectorout oidvectorin oidvectorout i p f -1 0 0 _null_ _null_ ));
  DESCR("array of INDEX_MAX_KEYS oids, used in system tables");
  #define OIDVECTOROID	30
  
! DATA(insert OID = 32 (	SET		   PGUID -1  -1 f b t \054 0   0 textin textout textin textout i p f -1 0 0 _null_ _null_ ));
  DESCR("set of tuples");
  
! DATA(insert OID = 71 (	pg_type		 PGUID 4 4 t c t \054 1247 0 int4in int4out int4in int4out i p f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 75 (	pg_attribute PGUID 4 4 t c t \054 1249 0 int4in int4out int4in int4out i p f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 81 (	pg_proc		 PGUID 4 4 t c t \054 1255 0 int4in int4out int4in int4out i p f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 83 (	pg_class	 PGUID 4 4 t c t \054 1259 0 int4in int4out int4in int4out i p f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 86 (	pg_shadow	 PGUID 4 4 t c t \054 1260 0 int4in int4out int4in int4out i p f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 87 (	pg_group	 PGUID 4 4 t c t \054 1261 0 int4in int4out int4in int4out i p f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 88 (	pg_database  PGUID 4 4 t c t \054 1262 0 int4in int4out int4in int4out i p f -1 0 0 _null_ _null_ ));
  
  /* OIDS 100 - 199 */
  
  /* OIDS 200 - 299 */
  
! DATA(insert OID = 210 (  smgr	   PGUID 2	12 t b t \054 0 0 smgrin smgrout smgrin smgrout s p f -1 0 0 _null_ _null_ ));
  DESCR("storage manager");
  
  /* OIDS 300 - 399 */
***************
*** 277,443 ****
  /* OIDS 500 - 599 */
  
  /* OIDS 600 - 699 */
! DATA(insert OID = 600 (  point	   PGUID 16  24 f b t \054 0 701 point_in point_out point_in point_out d p _null_ ));
  DESCR("geometric point '(x, y)'");
  #define POINTOID		600
! DATA(insert OID = 601 (  lseg	   PGUID 32  48 f b t \054 0 600 lseg_in lseg_out lseg_in lseg_out d p _null_ ));
  DESCR("geometric line segment '(pt1,pt2)'");
  #define LSEGOID			601
! DATA(insert OID = 602 (  path	   PGUID -1  -1 f b t \054 0 0 path_in path_out path_in path_out d x _null_ ));
  DESCR("geometric path '(pt1,...)'");
  #define PATHOID			602
! DATA(insert OID = 603 (  box	   PGUID 32 100 f b t \073 0 600 box_in box_out box_in box_out d p _null_ ));
  DESCR("geometric box '(lower left,upper right)'");
  #define BOXOID			603
! DATA(insert OID = 604 (  polygon   PGUID -1  -1 f b t \054 0   0 poly_in poly_out poly_in poly_out d x _null_ ));
  DESCR("geometric polygon '(pt1,...)'");
  #define POLYGONOID		604
  
! DATA(insert OID = 628 (  line	   PGUID 32  48 f b t \054 0 701 line_in line_out line_in line_out d p _null_ ));
  DESCR("geometric line '(pt1,pt2)'");
  #define LINEOID			628
! DATA(insert OID = 629 (  _line	   PGUID  -1 -1 f b t \054 0 628 array_in array_out array_in array_out d x _null_ ));
  DESCR("");
  
  /* OIDS 700 - 799 */
  
! DATA(insert OID = 700 (  float4    PGUID  4  12 f b t \054 0   0 float4in float4out float4in float4out i p _null_ ));
  DESCR("single-precision floating point number, 4-byte storage");
  #define FLOAT4OID 700
! DATA(insert OID = 701 (  float8    PGUID  8  24 f b t \054 0   0 float8in float8out float8in float8out d p _null_ ));
  DESCR("double-precision floating point number, 8-byte storage");
  #define FLOAT8OID 701
! DATA(insert OID = 702 (  abstime   PGUID  4  20 t b t \054 0   0 nabstimein nabstimeout nabstimein nabstimeout i p _null_ ));
  DESCR("absolute, limited-range date and time (Unix system time)");
  #define ABSTIMEOID		702
! DATA(insert OID = 703 (  reltime   PGUID  4  20 t b t \054 0   0 reltimein reltimeout reltimein reltimeout i p _null_ ));
  DESCR("relative, limited-range time interval (Unix delta time)");
  #define RELTIMEOID		703
! DATA(insert OID = 704 (  tinterval PGUID 12  47 f b t \054 0   0 tintervalin tintervalout tintervalin tintervalout i p _null_ ));
  DESCR("(abstime,abstime), time interval");
  #define TINTERVALOID	704
! DATA(insert OID = 705 (  unknown   PGUID -1  -1 f b t \054 0   0 textin textout textin textout i p _null_ ));
  DESCR("");
  #define UNKNOWNOID		705
  
! DATA(insert OID = 718 (  circle    PGUID  24 47 f b t \054 0	0 circle_in circle_out circle_in circle_out d p _null_ ));
  DESCR("geometric circle '(center,radius)'");
  #define CIRCLEOID		718
! DATA(insert OID = 719 (  _circle   PGUID  -1 -1 f b t \054 0  718 array_in array_out array_in array_out d x _null_ ));
! DATA(insert OID = 790 (  money	   PGUID   4 24 f b t \054 0	0 cash_in cash_out cash_in cash_out i p _null_ ));
  DESCR("$d,ddd.cc, money");
  #define CASHOID 790
! DATA(insert OID = 791 (  _money    PGUID  -1 -1 f b t \054 0  790 array_in array_out array_in array_out i x _null_ ));
  
  /* OIDS 800 - 899 */
! DATA(insert OID = 829 ( macaddr    PGUID  6 -1 f b t \054 0 0 macaddr_in macaddr_out macaddr_in macaddr_out i p _null_ ));
  DESCR("XX:XX:XX:XX:XX:XX, MAC address");
  #define MACADDROID 829
! DATA(insert OID = 869 ( inet	   PGUID  -1 -1 f b t \054 0 0 inet_in inet_out inet_in inet_out i p _null_ ));
  DESCR("IP address/netmask, host address, netmask optional");
  #define INETOID 869
! DATA(insert OID = 650 ( cidr	   PGUID  -1 -1 f b t \054 0 0 cidr_in cidr_out cidr_in cidr_out i p _null_ ));
  DESCR("network IP address/netmask, network address");
  #define CIDROID 650
  
  /* OIDS 900 - 999 */
  
  /* OIDS 1000 - 1099 */
! DATA(insert OID = 1000 (  _bool		 PGUID -1  -1 f b t \054 0	16 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1001 (  _bytea	 PGUID -1  -1 f b t \054 0	17 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1002 (  _char		 PGUID -1  -1 f b t \054 0	18 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1003 (  _name		 PGUID -1  -1 f b t \054 0	19 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1005 (  _int2		 PGUID -1  -1 f b t \054 0	21 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1006 (  _int2vector PGUID -1 -1 f b t \054 0	22 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1007 (  _int4		 PGUID -1  -1 f b t \054 0	23 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1008 (  _regproc	 PGUID -1  -1 f b t \054 0	24 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1009 (  _text		 PGUID -1  -1 f b t \054 0	25 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1028 (  _oid		 PGUID -1  -1 f b t \054 0	26 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1010 (  _tid		 PGUID -1  -1 f b t \054 0	27 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1011 (  _xid		 PGUID -1  -1 f b t \054 0	28 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1012 (  _cid		 PGUID -1  -1 f b t \054 0	29 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1013 (  _oidvector PGUID -1  -1 f b t \054 0	30 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1014 (  _bpchar	 PGUID -1  -1 f b t \054 0 1042 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1015 (  _varchar	 PGUID -1  -1 f b t \054 0 1043 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1016 (  _int8		 PGUID -1  -1 f b t \054 0	20 array_in array_out array_in array_out d x _null_ ));
! DATA(insert OID = 1017 (  _point	 PGUID -1  -1 f b t \054 0 600 array_in array_out array_in array_out d x _null_ ));
! DATA(insert OID = 1018 (  _lseg		 PGUID -1  -1 f b t \054 0 601 array_in array_out array_in array_out d x _null_ ));
! DATA(insert OID = 1019 (  _path		 PGUID -1  -1 f b t \054 0 602 array_in array_out array_in array_out d x _null_ ));
! DATA(insert OID = 1020 (  _box		 PGUID -1  -1 f b t \073 0 603 array_in array_out array_in array_out d x _null_ ));
! DATA(insert OID = 1021 (  _float4	 PGUID -1  -1 f b t \054 0 700 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1022 (  _float8	 PGUID -1  -1 f b t \054 0 701 array_in array_out array_in array_out d x _null_ ));
! DATA(insert OID = 1023 (  _abstime	 PGUID -1  -1 f b t \054 0 702 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1024 (  _reltime	 PGUID -1  -1 f b t \054 0 703 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1025 (  _tinterval PGUID -1  -1 f b t \054 0 704 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1027 (  _polygon	 PGUID -1  -1 f b t \054 0 604 array_in array_out array_in array_out d x _null_ ));
  /*
   *	Note: the size of aclitem needs to match sizeof(AclItem) in acl.h.
   *	Thanks to some padding, this will be 8 on all platforms.
   *	We also have an Assert to make sure.
   */
  #define ACLITEMSIZE 8
! DATA(insert OID = 1033 (  aclitem	 PGUID 8   -1 f b t \054 0 0 aclitemin aclitemout aclitemin aclitemout i p _null_ ));
  DESCR("access control list");
! DATA(insert OID = 1034 (  _aclitem	 PGUID -1 -1 f b t \054 0 1033 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1040 (  _macaddr	 PGUID -1 -1 f b t \054 0  829 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1041 (  _inet    PGUID -1 -1 f b t \054 0  869 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 651  (  _cidr    PGUID -1 -1 f b t \054 0  650 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1042 ( bpchar		 PGUID -1  -1 f b t \054 0	0 bpcharin bpcharout bpcharin bpcharout i x _null_ ));
  DESCR("char(length), blank-padded string, fixed storage length");
  #define BPCHAROID		1042
! DATA(insert OID = 1043 ( varchar	 PGUID -1  -1 f b t \054 0	0 varcharin varcharout varcharin varcharout i x _null_ ));
  DESCR("varchar(length), non-blank-padded string, variable storage length");
  #define VARCHAROID		1043
  
! DATA(insert OID = 1082 ( date		 PGUID	4  10 t b t \054 0	0 date_in date_out date_in date_out i p _null_ ));
  DESCR("ANSI SQL date");
  #define DATEOID			1082
! DATA(insert OID = 1083 ( time		 PGUID	8  16 f b t \054 0	0 time_in time_out time_in time_out d p _null_ ));
  DESCR("hh:mm:ss, ANSI SQL time");
  #define TIMEOID			1083
  
  /* OIDS 1100 - 1199 */
! DATA(insert OID = 1114 ( timestamp	 PGUID	8  47 f b t \054 0	0 timestamp_in timestamp_out timestamp_in timestamp_out d p _null_ ));
  DESCR("date and time");
  #define TIMESTAMPOID	1114
! DATA(insert OID = 1115 ( _timestamp  PGUID	-1 -1 f b t \054 0	1184 array_in array_out array_in array_out d x _null_ ));
! DATA(insert OID = 1182 ( _date		 PGUID	-1 -1 f b t \054 0	1082 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1183 ( _time		 PGUID	-1 -1 f b t \054 0	1083 array_in array_out array_in array_out d x _null_ ));
! DATA(insert OID = 1184 ( timestamptz PGUID	8  47 f b t \054 0	0 timestamptz_in timestamptz_out timestamptz_in timestamptz_out d p _null_ ));
  DESCR("date and time with time zone");
  #define TIMESTAMPTZOID	1184
! DATA(insert OID = 1185 ( _timestamptz PGUID -1 -1 f b t \054 0	1184 array_in array_out array_in array_out d x _null_ ));
! DATA(insert OID = 1186 ( interval	 PGUID 12  47 f b t \054 0	0 interval_in interval_out interval_in interval_out d p _null_ ));
  DESCR("@ <number> <units>, time interval");
  #define INTERVALOID		1186
! DATA(insert OID = 1187 ( _interval	 PGUID	-1 -1 f b t \054 0	1186 array_in array_out array_in array_out d x _null_ ));
  
  /* OIDS 1200 - 1299 */
! DATA(insert OID = 1231 (  _numeric	 PGUID -1  -1 f b t \054 0	1700 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1266 ( timetz		 PGUID 12  22 f b t \054 0	0 timetz_in timetz_out timetz_in timetz_out d p _null_ ));
  DESCR("hh:mm:ss, ANSI SQL time");
  #define TIMETZOID		1266
! DATA(insert OID = 1270 ( _timetz	 PGUID	-1 -1 f b t \054 0	1266 array_in array_out array_in array_out d x _null_ ));
  
  /* OIDS 1500 - 1599 */
! DATA(insert OID = 1560 ( bit		 PGUID -1  -1 f b t \054 0	0 bit_in bit_out bit_in bit_out i x _null_ ));
  DESCR("fixed-length bit string");
  #define BITOID	 1560
! DATA(insert OID = 1561 ( _bit		 PGUID	-1 -1 f b t \054 0	1560 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1562 ( varbit		 PGUID -1  -1 f b t \054 0	0 varbit_in varbit_out varbit_in varbit_out i x _null_ ));
  DESCR("variable-length bit string");
  #define VARBITOID	  1562
! DATA(insert OID = 1563 ( _varbit	 PGUID	-1 -1 f b t \054 0	1562 array_in array_out array_in array_out i x _null_ ));
  
  /* OIDS 1600 - 1699 */
  
  /* OIDS 1700 - 1799 */
! DATA(insert OID = 1700 ( numeric	   PGUID -1  -1 f b t \054 0  0 numeric_in numeric_out numeric_in numeric_out i m _null_ ));
  DESCR("numeric(precision, decimal), arbitrary precision number");
  #define NUMERICOID		1700
  
  /* OID 1790 */
! DATA(insert OID = 1790 ( refcursor	   PGUID -1  -1 f b t \054 0  0 textin textout textin textout i x _null_ ));
  DESCR("reference cursor (portal name)");
  #define REFCURSOROID	1790
  
--- 320,486 ----
  /* OIDS 500 - 599 */
  
  /* OIDS 600 - 699 */
! DATA(insert OID = 600 (  point	   PGUID 16  24 f b t \054 0 701 point_in point_out point_in point_out d p f -1 0 0 _null_ _null_ ));
  DESCR("geometric point '(x, y)'");
  #define POINTOID		600
! DATA(insert OID = 601 (  lseg	   PGUID 32  48 f b t \054 0 600 lseg_in lseg_out lseg_in lseg_out d p f -1 0 0 _null_ _null_ ));
  DESCR("geometric line segment '(pt1,pt2)'");
  #define LSEGOID			601
! DATA(insert OID = 602 (  path	   PGUID -1  -1 f b t \054 0 0 path_in path_out path_in path_out d x f -1 0 0 _null_ _null_ ));
  DESCR("geometric path '(pt1,...)'");
  #define PATHOID			602
! DATA(insert OID = 603 (  box	   PGUID 32 100 f b t \073 0 600 box_in box_out box_in box_out d p f -1 0 0 _null_ _null_ ));
  DESCR("geometric box '(lower left,upper right)'");
  #define BOXOID			603
! DATA(insert OID = 604 (  polygon   PGUID -1  -1 f b t \054 0   0 poly_in poly_out poly_in poly_out d x f -1 0 0 _null_ _null_ ));
  DESCR("geometric polygon '(pt1,...)'");
  #define POLYGONOID		604
  
! DATA(insert OID = 628 (  line	   PGUID 32  48 f b t \054 0 701 line_in line_out line_in line_out d p f -1 0 0 _null_ _null_ ));
  DESCR("geometric line '(pt1,pt2)'");
  #define LINEOID			628
! DATA(insert OID = 629 (  _line	   PGUID  -1 -1 f b t \054 0 628 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
  DESCR("");
  
  /* OIDS 700 - 799 */
  
! DATA(insert OID = 700 (  float4    PGUID  4  12 f b t \054 0   0 float4in float4out float4in float4out i p f -1 0 0 _null_ _null_ ));
  DESCR("single-precision floating point number, 4-byte storage");
  #define FLOAT4OID 700
! DATA(insert OID = 701 (  float8    PGUID  8  24 f b t \054 0   0 float8in float8out float8in float8out d p f -1 0 0 _null_ _null_ ));
  DESCR("double-precision floating point number, 8-byte storage");
  #define FLOAT8OID 701
! DATA(insert OID = 702 (  abstime   PGUID  4  20 t b t \054 0   0 nabstimein nabstimeout nabstimein nabstimeout i p f -1 0 0 _null_ _null_ ));
  DESCR("absolute, limited-range date and time (Unix system time)");
  #define ABSTIMEOID		702
! DATA(insert OID = 703 (  reltime   PGUID  4  20 t b t \054 0   0 reltimein reltimeout reltimein reltimeout i p f -1 0 0 _null_ _null_ ));
  DESCR("relative, limited-range time interval (Unix delta time)");
  #define RELTIMEOID		703
! DATA(insert OID = 704 (  tinterval PGUID 12  47 f b t \054 0   0 tintervalin tintervalout tintervalin tintervalout i p f -1 0 0 _null_ _null_ ));
  DESCR("(abstime,abstime), time interval");
  #define TINTERVALOID	704
! DATA(insert OID = 705 (  unknown   PGUID -1  -1 f b t \054 0   0 textin textout textin textout i p f -1 0 0 _null_ _null_ ));
  DESCR("");
  #define UNKNOWNOID		705
  
! DATA(insert OID = 718 (  circle    PGUID  24 47 f b t \054 0	0 circle_in circle_out circle_in circle_out d p f -1 0 0 _null_ _null_ ));
  DESCR("geometric circle '(center,radius)'");
  #define CIRCLEOID		718
! DATA(insert OID = 719 (  _circle   PGUID  -1 -1 f b t \054 0  718 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 790 (  money	   PGUID   4 24 f b t \054 0	0 cash_in cash_out cash_in cash_out i p f -1 0 0 _null_ _null_ ));
  DESCR("$d,ddd.cc, money");
  #define CASHOID 790
! DATA(insert OID = 791 (  _money    PGUID  -1 -1 f b t \054 0  790 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
  
  /* OIDS 800 - 899 */
! DATA(insert OID = 829 ( macaddr    PGUID  6 -1 f b t \054 0 0 macaddr_in macaddr_out macaddr_in macaddr_out i p f -1 0 0 _null_ _null_ ));
  DESCR("XX:XX:XX:XX:XX:XX, MAC address");
  #define MACADDROID 829
! DATA(insert OID = 869 ( inet	   PGUID  -1 -1 f b t \054 0 0 inet_in inet_out inet_in inet_out i p f -1 0 0 _null_ _null_ ));
  DESCR("IP address/netmask, host address, netmask optional");
  #define INETOID 869
! DATA(insert OID = 650 ( cidr	   PGUID  -1 -1 f b t \054 0 0 cidr_in cidr_out cidr_in cidr_out i p f -1 0 0 _null_ _null_ ));
  DESCR("network IP address/netmask, network address");
  #define CIDROID 650
  
  /* OIDS 900 - 999 */
  
  /* OIDS 1000 - 1099 */
! DATA(insert OID = 1000 (  _bool		 PGUID -1  -1 f b t \054 0	16 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1001 (  _bytea	 PGUID -1  -1 f b t \054 0	17 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1002 (  _char		 PGUID -1  -1 f b t \054 0	18 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1003 (  _name		 PGUID -1  -1 f b t \054 0	19 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1005 (  _int2		 PGUID -1  -1 f b t \054 0	21 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1006 (  _int2vector PGUID -1 -1 f b t \054 0	22 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1007 (  _int4		 PGUID -1  -1 f b t \054 0	23 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1008 (  _regproc	 PGUID -1  -1 f b t \054 0	24 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1009 (  _text		 PGUID -1  -1 f b t \054 0	25 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1028 (  _oid		 PGUID -1  -1 f b t \054 0	26 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1010 (  _tid		 PGUID -1  -1 f b t \054 0	27 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1011 (  _xid		 PGUID -1  -1 f b t \054 0	28 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1012 (  _cid		 PGUID -1  -1 f b t \054 0	29 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1013 (  _oidvector PGUID -1  -1 f b t \054 0	30 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1014 (  _bpchar	 PGUID -1  -1 f b t \054 0 1042 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1015 (  _varchar	 PGUID -1  -1 f b t \054 0 1043 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1016 (  _int8		 PGUID -1  -1 f b t \054 0	20 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1017 (  _point	 PGUID -1  -1 f b t \054 0 600 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1018 (  _lseg		 PGUID -1  -1 f b t \054 0 601 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1019 (  _path		 PGUID -1  -1 f b t \054 0 602 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1020 (  _box		 PGUID -1  -1 f b t \073 0 603 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1021 (  _float4	 PGUID -1  -1 f b t \054 0 700 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1022 (  _float8	 PGUID -1  -1 f b t \054 0 701 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1023 (  _abstime	 PGUID -1  -1 f b t \054 0 702 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1024 (  _reltime	 PGUID -1  -1 f b t \054 0 703 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1025 (  _tinterval PGUID -1  -1 f b t \054 0 704 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1027 (  _polygon	 PGUID -1  -1 f b t \054 0 604 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
  /*
   *	Note: the size of aclitem needs to match sizeof(AclItem) in acl.h.
   *	Thanks to some padding, this will be 8 on all platforms.
   *	We also have an Assert to make sure.
   */
  #define ACLITEMSIZE 8
! DATA(insert OID = 1033 (  aclitem	 PGUID 8   -1 f b t \054 0 0 aclitemin aclitemout aclitemin aclitemout i p f -1 0 0 _null_ _null_ ));
  DESCR("access control list");
! DATA(insert OID = 1034 (  _aclitem	 PGUID -1 -1 f b t \054 0 1033 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1040 (  _macaddr	 PGUID -1 -1 f b t \054 0  829 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1041 (  _inet    PGUID -1 -1 f b t \054 0  869 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 651  (  _cidr    PGUID -1 -1 f b t \054 0  650 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1042 ( bpchar		 PGUID -1  -1 f b t \054 0	0 bpcharin bpcharout bpcharin bpcharout i x f -1 0 0 _null_ _null_ ));
  DESCR("char(length), blank-padded string, fixed storage length");
  #define BPCHAROID		1042
! DATA(insert OID = 1043 ( varchar	 PGUID -1  -1 f b t \054 0	0 varcharin varcharout varcharin varcharout i x f -1 0 0 _null_ _null_ ));
  DESCR("varchar(length), non-blank-padded string, variable storage length");
  #define VARCHAROID		1043
  
! DATA(insert OID = 1082 ( date		 PGUID	4  10 t b t \054 0	0 date_in date_out date_in date_out i p f -1 0 0 _null_ _null_ ));
  DESCR("ANSI SQL date");
  #define DATEOID			1082
! DATA(insert OID = 1083 ( time		 PGUID	8  16 f b t \054 0	0 time_in time_out time_in time_out d p f -1 0 0 _null_ _null_ ));
  DESCR("hh:mm:ss, ANSI SQL time");
  #define TIMEOID			1083
  
  /* OIDS 1100 - 1199 */
! DATA(insert OID = 1114 ( timestamp	 PGUID	8  47 f b t \054 0	0 timestamp_in timestamp_out timestamp_in timestamp_out d p f -1 0 0 _null_ _null_ ));
  DESCR("date and time");
  #define TIMESTAMPOID	1114
! DATA(insert OID = 1115 ( _timestamp  PGUID	-1 -1 f b t \054 0	1184 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1182 ( _date		 PGUID	-1 -1 f b t \054 0	1082 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1183 ( _time		 PGUID	-1 -1 f b t \054 0	1083 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1184 ( timestamptz PGUID	8  47 f b t \054 0	0 timestamptz_in timestamptz_out timestamptz_in timestamptz_out d p f -1 0 0 _null_ _null_ ));
  DESCR("date and time with time zone");
  #define TIMESTAMPTZOID	1184
! DATA(insert OID = 1185 ( _timestamptz PGUID -1 -1 f b t \054 0	1184 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1186 ( interval	 PGUID 12  47 f b t \054 0	0 interval_in interval_out interval_in interval_out d p f -1 0 0 _null_ _null_ ));
  DESCR("@ <number> <units>, time interval");
  #define INTERVALOID		1186
! DATA(insert OID = 1187 ( _interval	 PGUID	-1 -1 f b t \054 0	1186 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
  
  /* OIDS 1200 - 1299 */
! DATA(insert OID = 1231 (  _numeric	 PGUID -1  -1 f b t \054 0	1700 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1266 ( timetz		 PGUID 12  22 f b t \054 0	0 timetz_in timetz_out timetz_in timetz_out d p f -1 0 0 _null_ _null_ ));
  DESCR("hh:mm:ss, ANSI SQL time");
  #define TIMETZOID		1266
! DATA(insert OID = 1270 ( _timetz	 PGUID	-1 -1 f b t \054 0	1266 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
  
  /* OIDS 1500 - 1599 */
! DATA(insert OID = 1560 ( bit		 PGUID -1  -1 f b t \054 0	0 bit_in bit_out bit_in bit_out i x f -1 0 0 _null_ _null_ ));
  DESCR("fixed-length bit string");
  #define BITOID	 1560
! DATA(insert OID = 1561 ( _bit		 PGUID	-1 -1 f b t \054 0	1560 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1562 ( varbit		 PGUID -1  -1 f b t \054 0	0 varbit_in varbit_out varbit_in varbit_out i x f -1 0 0 _null_ _null_ ));
  DESCR("variable-length bit string");
  #define VARBITOID	  1562
! DATA(insert OID = 1563 ( _varbit	 PGUID	-1 -1 f b t \054 0	1562 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
  
  /* OIDS 1600 - 1699 */
  
  /* OIDS 1700 - 1799 */
! DATA(insert OID = 1700 ( numeric	   PGUID -1  -1 f b t \054 0  0 numeric_in numeric_out numeric_in numeric_out i m f -1 0 0 _null_ _null_ ));
  DESCR("numeric(precision, decimal), arbitrary precision number");
  #define NUMERICOID		1700
  
  /* OID 1790 */
! DATA(insert OID = 1790 ( refcursor	   PGUID -1  -1 f b t \054 0  0 textin textout textin textout i x f -1 0 0 _null_ _null_ ));
  DESCR("reference cursor (portal name)");
  #define REFCURSOROID	1790
  
***************
*** 447,452 ****
--- 490,496 ----
   */
  extern Oid	TypeGet(char *typeName, bool *defined);
  extern Oid	TypeShellMake(char *typeName);
+ 
  extern Oid TypeCreate(char *typeName,
  		   Oid assignedTypeOid,
  		   Oid relationOid,
***************
*** 459,468 ****
  		   char *receiveProcedure,
  		   char *sendProcedure,
  		   char *elementTypeName,
  		   char *defaultTypeValue,
  		   bool passedByValue,
  		   char alignment,
! 		   char storage);
  extern void TypeRename(const char *oldTypeName, const char *newTypeName);
  extern char *makeArrayTypeName(char *typeName);
  
--- 503,519 ----
  		   char *receiveProcedure,
  		   char *sendProcedure,
  		   char *elementTypeName,
+ 		   char *baseTypeName,
  		   char *defaultTypeValue,
+ 		   char *defaultTypeBin,
  		   bool passedByValue,
  		   char alignment,
! 		   char storage,
! 		   int32 typeMod,
! 		   int32 typNDims,
! 		   bool typeNotNull);
! 
! 
  extern void TypeRename(const char *oldTypeName, const char *newTypeName);
  extern char *makeArrayTypeName(char *typeName);
  
diff -rc pgsql.orig/src/include/commands/defrem.h pgsqldomain/src/include/commands/defrem.h
*** pgsql.orig/src/include/commands/defrem.h	Thu Mar  7 11:35:38 2002
--- pgsqldomain/src/include/commands/defrem.h	Thu Mar  7 22:24:24 2002
***************
*** 39,48 ****
--- 39,50 ----
  extern void DefineOperator(char *name, List *parameters);
  extern void DefineAggregate(char *name, List *parameters);
  extern void DefineType(char *name, List *parameters);
+ extern void DefineDomain(CreateDomainStmt *stmt);
  
  /*
   * prototypes in remove.c
   */
+ extern void RemoveDomain(char *domainName, int behavior);
  extern void RemoveFunction(char *functionName, List *argTypes);
  extern void RemoveOperator(char *operatorName,
  			   char *typeName1, char *typeName2);
diff -rc pgsql.orig/src/include/nodes/nodes.h pgsqldomain/src/include/nodes/nodes.h
*** pgsql.orig/src/include/nodes/nodes.h	Thu Mar  7 11:35:40 2002
--- pgsqldomain/src/include/nodes/nodes.h	Thu Mar  7 22:24:24 2002
***************
*** 172,177 ****
--- 172,178 ----
  	T_TransactionStmt,
  	T_ViewStmt,
  	T_LoadStmt,
+ 	T_CreateDomainStmt,
  	T_CreatedbStmt,
  	T_DropdbStmt,
  	T_VacuumStmt,
diff -rc pgsql.orig/src/include/nodes/parsenodes.h pgsqldomain/src/include/nodes/parsenodes.h
*** pgsql.orig/src/include/nodes/parsenodes.h	Thu Mar  7 11:35:40 2002
--- pgsqldomain/src/include/nodes/parsenodes.h	Thu Mar  7 22:24:24 2002
***************
*** 468,479 ****
--- 468,481 ----
  #define DROP_INDEX	  4
  #define DROP_RULE	  5
  #define DROP_TYPE_P   6
+ #define DROP_DOMAIN_P 7
  
  typedef struct DropStmt
  {
  	NodeTag		type;
  	List	   *names;
  	int			removeType;
+ 	int	   		behavior;		/* CASCADE or RESTRICT drop behavior */
  } DropStmt;
  
  /* ----------------------
***************
*** 682,687 ****
--- 684,690 ----
  	char	   *filename;		/* file to load */
  } LoadStmt;
  
+ 
  /* ----------------------
   *		Createdb Statement
   * ----------------------
***************
*** 1279,1284 ****
--- 1282,1303 ----
  	Node	   *arg;			/* a (Value *) or a (TypeName *) */
  } DefElem;
  
+ 
+ /****************************************************************************
+  *	Nodes for a Domain Creation tree
+  ****************************************************************************/
+ /* ----------------------
+  *		CreateDomain Statement
+  * ----------------------
+  * Down here as it required TypeName to be defined first.
+  */
+ typedef struct CreateDomainStmt
+ {
+ 	NodeTag		type;
+ 	char	   *domainname;			/* name of domain to create */
+ 	TypeName   *typename;			/* the typecast */
+ 	List	   *constraints;		/* constraints (list of Constraint nodes) */
+ } CreateDomainStmt;
  
  /****************************************************************************
   *	Nodes for a Query tree
diff -rc pgsql.orig/src/include/parser/parse_coerce.h pgsqldomain/src/include/parser/parse_coerce.h
*** pgsql.orig/src/include/parser/parse_coerce.h	Thu Mar  7 11:35:40 2002
--- pgsqldomain/src/include/parser/parse_coerce.h	Thu Mar  7 22:24:24 2002
***************
*** 81,85 ****
--- 81,86 ----
  extern Node *coerce_to_common_type(ParseState *pstate, Node *node,
  					  Oid targetTypeId,
  					  const char *context);
+ extern Oid getBaseType(Oid inType);
  
  #endif   /* PARSE_COERCE_H */
diff -rc pgsql.orig/src/include/utils/lsyscache.h pgsqldomain/src/include/utils/lsyscache.h
*** pgsql.orig/src/include/utils/lsyscache.h	Thu Mar  7 11:35:41 2002
--- pgsqldomain/src/include/utils/lsyscache.h	Thu Mar  7 22:24:24 2002
***************
*** 44,50 ****
  extern bool get_typbyval(Oid typid);
  extern void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval);
  extern char get_typstorage(Oid typid);
! extern bool get_typdefault(Oid typid, Datum *defaultValue);
  extern int32 get_typavgwidth(Oid typid, int32 typmod);
  extern int32 get_attavgwidth(Oid relid, AttrNumber attnum);
  extern bool get_attstatsslot(HeapTuple statstuple,
--- 44,50 ----
  extern bool get_typbyval(Oid typid);
  extern void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval);
  extern char get_typstorage(Oid typid);
! extern Node *get_typdefault(Oid typid, int32 atttypmod);
  extern int32 get_typavgwidth(Oid typid, int32 typmod);
  extern int32 get_attavgwidth(Oid relid, AttrNumber attnum);
  extern bool get_attstatsslot(HeapTuple statstuple,
#2Christopher Kings-Lynne
chriskl@familyhealth.com.au
In reply to: Rod Taylor (#1)
Re: Domain Support -- another round

Grr. Figured out why the patch was pooched. Basically SAVING it out of
Outlook adds CR's everywhere! Believe it or not...

BTW, it failed when patching parsenodes.h - you might need to update the
patch against CVS...

Chris

Show quoted text

-----Original Message-----
From: pgsql-patches-owner@postgresql.org
[mailto:pgsql-patches-owner@postgresql.org]On Behalf Of Rod Taylor
Sent: Friday, 8 March 2002 12:21 PM
To: pgsql-patches@postgresql.org
Subject: [PATCHES] Domain Support -- another round

Ok....

gram.y is fixed (no more %expect usage)

Using the copyCreateDomainStmt in the proper place.

Evolution is the mail client of choice for different (improved?) mime
headers.

And attached is a regular diff -c, rather than a cvs diff -c.

I updated the poor descriptions of MergeDomainAttributes(). Hopefully
its current and future use is more obvious.

Am I getting close?

#3Rod Taylor
rbt@zort.ca
In reply to: Rod Taylor (#1)
2 attachment(s)
Re: Domain Support -- another round

Attached is a diff to the patch of the below message to use b_expr
rather than c_expr.

Also includes an improved regress set. Less redundant failures, and
tests numeric types as they're different from the others enough to
warrent it.
--
Rod Taylor

This message represents the official view of the voices in my head

----- Original Message -----
From: "Rod Taylor" <rbt@zort.ca>
To: <pgsql-patches@postgresql.org>
Sent: Thursday, March 07, 2002 11:21 PM
Subject: [PATCHES] Domain Support -- another round

Ok....

gram.y is fixed (no more %expect usage)

Using the copyCreateDomainStmt in the proper place.

Evolution is the mail client of choice for different (improved?)

mime

headers.

And attached is a regular diff -c, rather than a cvs diff -c.

I updated the poor descriptions of MergeDomainAttributes().

Hopefully

its current and future use is more obvious.

Am I getting close?

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

---------------------------(end of

broadcast)---------------------------

TIP 2: you can get off all lists at once with the unregister command
(send "unregister YourEmailAddressHere" to

majordomo@postgresql.org)

Show quoted text

Attachments:

domain.patch.addendumapplication/octet-stream; name=domain.patch.addendumDownload
*** domain.patch	Thu Mar  7 23:17:46 2002
--- domain.patch.2	Fri Mar  8 22:09:18 2002
***************
*** 1627,1633 ****
    		| def_list ',' def_elem				{ $$ = lappend($1, $3); }
    		;
    
! ! def_elem:  DEFAULT '=' c_expr
  ! 				{
  ! 					$$ = makeNode(DefElem);
  ! 					$$->defname = "default";
--- 1627,1633 ----
    		| def_list ',' def_elem				{ $$ = lappend($1, $3); }
    		;
    
! ! def_elem:  DEFAULT '=' b_expr
  ! 				{
  ! 					$$ = makeNode(DefElem);
  ! 					$$->defname = "default";
domainregress.sqlapplication/octet-stream; name=domainregress.sqlDownload
#4Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Rod Taylor (#3)
Re: Domain Support -- another round

Rod indicates this is his final version.

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.

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

Rod Taylor wrote:

Attached is a diff to the patch of the below message to use b_expr
rather than c_expr.

Also includes an improved regress set. Less redundant failures, and
tests numeric types as they're different from the others enough to
warrent it.
--
Rod Taylor

This message represents the official view of the voices in my head

----- Original Message -----
From: "Rod Taylor" <rbt@zort.ca>
To: <pgsql-patches@postgresql.org>
Sent: Thursday, March 07, 2002 11:21 PM
Subject: [PATCHES] Domain Support -- another round

Ok....

gram.y is fixed (no more %expect usage)

Using the copyCreateDomainStmt in the proper place.

Evolution is the mail client of choice for different (improved?)

mime

headers.

And attached is a regular diff -c, rather than a cvs diff -c.

I updated the poor descriptions of MergeDomainAttributes().

Hopefully

its current and future use is more obvious.

Am I getting close?

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

---------------------------(end of

broadcast)---------------------------

TIP 2: you can get off all lists at once with the unregister command
(send "unregister YourEmailAddressHere" to

majordomo@postgresql.org)

[ Attachment, skipping... ]

[ Attachment, skipping... ]

---------------------------(end of broadcast)---------------------------
TIP 2: you can get off all lists at once with the unregister command
(send "unregister YourEmailAddressHere" to majordomo@postgresql.org)

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
#5Peter Eisentraut
peter_e@gmx.net
In reply to: Rod Taylor (#1)
Re: Domain Support -- another round

Random nitpicking below. Also, have you created a regression test?

diff -rc pgsql.orig/doc/src/sgml/catalogs.sgml pgsqldomain/doc/src/sgml/catalogs.sgml
*** pgsql.orig/doc/src/sgml/catalogs.sgml	Thu Mar  7 11:35:32 2002
--- pgsqldomain/doc/src/sgml/catalogs.sgml	Thu Mar  7 22:24:23 2002
***************
*** 2511,2516 ****
--- 2511,2563 ----
</row>
<row>
+       <entry>typbasetype</entry>
+       <entry><type>oid</type></entry>
+       <entry></entry>
+       <entry><para>
+        <structfield>typbasetype</structfield> is the type that this one is based
+        off of.  Normally references the domains parent type, and is 0 otherwise.

"based on"

+       </para></entry>
+      </row>
+
+ 	 <row>
+ 	  <entry>typnotnull</entry>
+ 	  <entry><type>boolean</type></entry>
+ 	  <entry></entry>
+ 	  <entry><para>
+ 	   <structfield>typnotnull</structfield> represents a NOT NULL
+ 	   constraint on a type.  Normally used only for domains.

And unnormally...?

+ 	  </para></entry>
+ 	 </row>
+
+      <row>
+       <entry>typmod</entry>
+       <entry><type>integer</type></entry>
+       <entry></entry>
+       <entry><para>
+        <structfield>typmod</structfield> records type-specific data
+        supplied at table creation time (for example, the maximum
+        length of a <type>varchar</type> column).  It is passed to
+        type-specific input and output functions as the third
+        argument. The value will generally be -1 for types that do not
+        need typmod.  This data is copied to
+        <structfield>pg_attribute.atttypmod</structfield> on creation
+        of a table using a domain as it's field type.
+        </para></entry>
+      </row>
+
+      <row>
+       <entry>typdefaultbin</entry>
+       <entry><type>text</type></entry>
+       <entry></entry>
+       <entry><para>
+        <structfield>typdefaultbin</structfield> is NULL for types without a
+        default value.  If it's not NULL, it contains the internal string
+        representation of the default expression node.
+       </para></entry>
+      </row>
+
+      <row>
<entry>typdefault</entry>
<entry><type>text</type></entry>
<entry></entry>
diff -rc pgsql.orig/doc/src/sgml/ref/allfiles.sgml pgsqldomain/doc/src/sgml/ref/allfiles.sgml
*** pgsql.orig/doc/src/sgml/ref/allfiles.sgml	Thu Mar  7 11:35:32 2002
--- pgsqldomain/doc/src/sgml/ref/allfiles.sgml	Thu Mar  7 22:24:23 2002
***************
*** 52,57 ****
--- 52,58 ----
<!entity createAggregate    system "create_aggregate.sgml">
<!entity createConstraint   system "create_constraint.sgml">
<!entity createDatabase     system "create_database.sgml">
+ <!entity createDomain       system "create_domain.sgml">

I don't see this file included.

<!entity createFunction     system "create_function.sgml">
<!entity createGroup        system "create_group.sgml">
<!entity createIndex        system "create_index.sgml">
***************
*** 69,74 ****
--- 70,76 ----
<!entity delete             system "delete.sgml">
<!entity dropAggregate      system "drop_aggregate.sgml">
<!entity dropDatabase       system "drop_database.sgml">
+ <!entity dropDomain         system "drop_domain.sgml">
<!entity dropFunction       system "drop_function.sgml">
<!entity dropGroup          system "drop_group.sgml">
<!entity dropIndex          system "drop_index.sgml">
diff -rc pgsql.orig/doc/src/sgml/ref/comment.sgml pgsqldomain/doc/src/sgml/ref/comment.sgml
*** pgsql.orig/doc/src/sgml/ref/comment.sgml	Thu Mar  7 11:35:33 2002
--- pgsqldomain/doc/src/sgml/ref/comment.sgml	Thu Mar  7 22:24:23 2002
***************
*** 25,31 ****
<synopsis>
COMMENT ON
[
!   [ DATABASE | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ] <replaceable class="PARAMETER">object_name</replaceable> |
COLUMN <replaceable class="PARAMETER">table_name</replaceable>.<replaceable class="PARAMETER">column_name</replaceable> |
AGGREGATE <replaceable class="PARAMETER">agg_name</replaceable> (<replaceable class="PARAMETER">agg_type</replaceable>) |
FUNCTION <replaceable class="PARAMETER">func_name</replaceable> (<replaceable class="PARAMETER">arg1</replaceable>, <replaceable class="PARAMETER">arg2</replaceable>, ...) |
--- 25,31 ----
<synopsis>
COMMENT ON
[
!   [ DATABASE | DOMAIN | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ] <replaceable class="PARAMETER">object_name</replaceable> |
COLUMN <replaceable class="PARAMETER">table_name</replaceable>.<replaceable class="PARAMETER">column_name</replaceable> |
AGGREGATE <replaceable class="PARAMETER">agg_name</replaceable> (<replaceable class="PARAMETER">agg_type</replaceable>) |
FUNCTION <replaceable class="PARAMETER">func_name</replaceable> (<replaceable class="PARAMETER">arg1</replaceable>, <replaceable class="PARAMETER">arg2</replaceable>, ...) |
***************
*** 33,39 ****
TRIGGER <replaceable class="PARAMETER">trigger_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable>
] IS <replaceable class="PARAMETER">'text'</replaceable>
</synopsis>
!
<refsect2 id="R2-SQL-COMMENT-1">
<refsect2info>
<date>1999-10-25</date>
--- 33,39 ----
TRIGGER <replaceable class="PARAMETER">trigger_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable>
] IS <replaceable class="PARAMETER">'text'</replaceable>
</synopsis>
!
<refsect2 id="R2-SQL-COMMENT-1">
<refsect2info>
<date>1999-10-25</date>
***************
*** 64,70 ****
</variablelist>
</para>
</refsect2>
!
<refsect2 id="R2-SQL-COMMENT-2">
<refsect2info>
<date>1998-09-08</date>
--- 64,70 ----
</variablelist>
</para>
</refsect2>
!
<refsect2 id="R2-SQL-COMMENT-2">
<refsect2info>
<date>1998-09-08</date>
***************
*** 99,105 ****
</title>
<para>
<command>COMMENT</command> stores a comment about a database object.
!     Comments can be
easily retrieved with <command>psql</command>'s
<command>\dd</command>, <command>\d+</command>, or <command>\l+</command>
commands.  Other user interfaces to retrieve comments can be built atop
--- 99,105 ----
</title>
<para>
<command>COMMENT</command> stores a comment about a database object.
!     Comments can be
easily retrieved with <command>psql</command>'s
<command>\dd</command>, <command>\d+</command>, or <command>\l+</command>
commands.  Other user interfaces to retrieve comments can be built atop
***************
*** 141,146 ****
--- 141,147 ----

<programlisting>
COMMENT ON DATABASE my_database IS 'Development Database';
+ COMMENT ON DOMAIN my_domain IS 'Domains are like abstracted fields';

This comment describes domains in general, not a specific domain.

COMMENT ON INDEX my_index IS 'Enforces uniqueness on employee id';
COMMENT ON RULE my_rule IS 'Logs UPDATES of employee records';
COMMENT ON SEQUENCE my_sequence IS 'Used to generate primary keys';
***************
*** 155,166 ****
</programlisting>
</para>
</refsect1>
!
<refsect1 id="R1-SQL-COMMENT-3">
<title>
Compatibility
</title>
!
<refsect2 id="R2-SQL-COMMENT-4">
<refsect2info>
<date>1998-09-08</date>
--- 156,167 ----
</programlisting>
</para>
</refsect1>
!
<refsect1 id="R1-SQL-COMMENT-3">
<title>
Compatibility
</title>
!
<refsect2 id="R2-SQL-COMMENT-4">
<refsect2info>
<date>1998-09-08</date>
diff -rc pgsql.orig/doc/src/sgml/reference.sgml pgsqldomain/doc/src/sgml/reference.sgml
*** pgsql.orig/doc/src/sgml/reference.sgml	Thu Mar  7 11:35:32 2002
--- pgsqldomain/doc/src/sgml/reference.sgml	Thu Mar  7 22:24:23 2002
***************
*** 61,66 ****
--- 61,67 ----
&createAggregate;
&createConstraint;
&createDatabase;
+    &createDomain;
&createFunction;
&createGroup;
&createIndex;
***************
*** 78,83 ****
--- 79,85 ----
&delete;
&dropAggregate;
&dropDatabase;
+    &dropDomain;
&dropFunction;
&dropGroup;
&dropIndex;
***************
*** 115,121 ****
&unlisten;
&update;
&vacuum;
!
</reference>
<!--
--- 117,123 ----
&unlisten;
&update;
&vacuum;
!
</reference>
<!--
diff -rc pgsql.orig/src/backend/catalog/heap.c pgsqldomain/src/backend/catalog/heap.c
*** pgsql.orig/src/backend/catalog/heap.c	Thu Mar  7 11:35:33 2002
--- pgsqldomain/src/backend/catalog/heap.c	Thu Mar  7 22:24:23 2002
***************
*** 49,54 ****
--- 49,55 ----
#include "optimizer/planmain.h"
#include "optimizer/prep.h"
#include "optimizer/var.h"
+ #include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
#include "parser/parse_relation.h"
#include "parser/parse_target.h"
***************
*** 698,707 ****
"oidin",			/* receive procedure */
"oidout",		/* send procedure */
NULL,			/* array element type - irrelevant */
NULL,			/* default type value - none */
true,			/* passed by value */
'i',				/* default alignment - same as for OID */
! 			   'p');			/* Not TOASTable */
}
/* --------------------------------
--- 699,713 ----
"oidin",			/* receive procedure */
"oidout",		/* send procedure */
NULL,			/* array element type - irrelevant */
+ 			   NULL,			/* baseType Name -- typically for domaains */

spello

NULL, /* default type value - none */
+ NULL, /* default type binary representation */
true, /* passed by value */
'i', /* default alignment - same as for OID */
! 'p', /* Not TOASTable */
! -1, /* Type mod length */
! 0, /* array dimensions for typBaseType */
! false); /* Type NOT NULL */
}

/* --------------------------------
***************
*** 1584,1589 ****
--- 1590,1599 ----
int			numchecks;
List	   *listptr;
+ 	/* Probably shouldn't be null by default */
+ 	Node	   *expr = NULL;
+
+
/*
* Get info about existing constraints.
*/
***************
*** 1614,1681 ****
foreach(listptr, rawColDefaults)
{
RawColumnDefault *colDef = (RawColumnDefault *) lfirst(listptr);
- 		Node	   *expr;
- 		Oid			type_id;

- Assert(colDef->raw_default != NULL);

! /*
! * Transform raw parsetree to executable expression.
! */
! expr = transformExpr(pstate, colDef->raw_default, EXPR_COLUMN_FIRST);

! /*
! * Make sure default expr does not refer to any vars.
! */
! if (contain_var_clause(expr))
! elog(ERROR, "cannot use column references in DEFAULT clause");
!
! /*
! * No subplans or aggregates, either...
! */
! if (contain_subplans(expr))
! elog(ERROR, "cannot use subselects in DEFAULT clause");
! if (contain_agg_clause(expr))
! elog(ERROR, "cannot use aggregate functions in DEFAULT clause");
!
! /*
! * Check that it will be possible to coerce the expression to the
! * column's type. We store the expression without coercion,
! * however, to avoid premature coercion in cases like
! *
! * CREATE TABLE tbl (fld datetime DEFAULT 'now'::text);
! *
! * NB: this should match the code in optimizer/prep/preptlist.c that
! * will actually do the coercion, to ensure we don't accept an
! * unusable default expression.
! */
! type_id = exprType(expr);
! if (type_id != InvalidOid)
! {
! Form_pg_attribute atp = rel->rd_att->attrs[colDef->attnum - 1];
!
! if (type_id != atp->atttypid)
! {
! if (CoerceTargetExpr(NULL, expr, type_id,
! atp->atttypid, atp->atttypmod) == NULL)
! elog(ERROR, "Column \"%s\" is of type %s"
! " but default expression is of type %s"
! "\n\tYou will need to rewrite or cast the expression",
! NameStr(atp->attname),
! format_type_be(atp->atttypid),
! format_type_be(type_id));
! }
! }
!
! /*
! * Might as well try to reduce any constant expressions.
! */
! expr = eval_const_expressions(expr);
!
! /*
! * Must fix opids, in case any operators remain...
! */
! fix_opids(expr);

/*
* OK, store it.
--- 1624,1636 ----
foreach(listptr, rawColDefaults)
{
RawColumnDefault *colDef = (RawColumnDefault *) lfirst(listptr);

! Form_pg_attribute atp = rel->rd_att->attrs[colDef->attnum - 1];

! expr = cookDefault(pstate, colDef->raw_default
! , atp->atttypid, atp->atttypmod
! , NameStr(atp->attname));

/*
* OK, store it.
***************
*** 1891,1896 ****
--- 1846,1933 ----
heap_freetuple(reltup);
heap_close(relrel, RowExclusiveLock);
}
+
+ /*
+  * Take a raw default and convert it to a cooked format ready for
+  * storage.
+  *
+  * Parse state, attypid, attypmod and attname are required for
+  * CoerceTargetExpr() and more importantly transformExpr().
+  */
+ Node *
+ cookDefault(ParseState *pstate
+ 			, Node *raw_default
+ 			, Oid atttypid
+ 			, int32 atttypmod
+ 			, char *attname) {

Stick to the formatting please.

+
+ 	Oid			type_id;
+ 	Node		*expr;
+
+ 	Assert(raw_default != NULL);
+
+ 	/*
+ 	 * Transform raw parsetree to executable expression.
+ 	 */
+ 	expr = transformExpr(pstate, raw_default, EXPR_COLUMN_FIRST);
+
+ 	/*
+ 	 * Make sure default expr does not refer to any vars.
+ 	 */
+ 	if (contain_var_clause(expr))
+ 		elog(ERROR, "cannot use column references in DEFAULT clause");
+
+ 	/*
+ 	 * No subplans or aggregates, either...
+ 	 */
+ 	if (contain_subplans(expr))
+ 		elog(ERROR, "cannot use subselects in DEFAULT clause");
+ 	if (contain_agg_clause(expr))
+ 		elog(ERROR, "cannot use aggregate functions in DEFAULT clause");
+
+ 	/*
+ 	 * Check that it will be possible to coerce the expression to the
+ 	 * column's type.  We store the expression without coercion,
+ 	 * however, to avoid premature coercion in cases like
+ 	 *
+ 	 * CREATE TABLE tbl (fld datetime DEFAULT 'now'::text);
+ 	 *
+ 	 * NB: this should match the code in optimizer/prep/preptlist.c that
+ 	 * will actually do the coercion, to ensure we don't accept an
+ 	 * unusable default expression.
+ 	 */
+ 	type_id = exprType(expr);
+ 	if (type_id != InvalidOid && atttypid != InvalidOid) {
+ 		if (type_id != atttypid) {
+
+ 			/* Try coercing to the base type of the domain if available */
+ 			if (CoerceTargetExpr(pstate, expr, type_id,
+ 								 getBaseType(atttypid),
+ 								 atttypmod) == NULL) {
+
+ 				elog(ERROR, "Column \"%s\" is of type %s"
+ 					" but default expression is of type %s"
+ 					"\n\tYou will need to rewrite or cast the expression",
+ 					 attname,
+ 					 format_type_be(atttypid),
+ 					 format_type_be(type_id));
+ 			}
+ 		}
+ 	}
+
+ 	/*
+ 	 * Might as well try to reduce any constant expressions.
+ 	 */
+ 	expr = eval_const_expressions(expr);
+
+ 	/*
+ 	 * Must fix opids, in case any operators remain...
+ 	 */
+ 	fix_opids(expr);
+
+ 	return(expr);
+ }
+

static void
RemoveAttrDefaults(Relation rel)

diff -rc pgsql.orig/src/backend/commands/creatinh.c pgsqldomain/src/backend/commands/creatinh.c
*** pgsql.orig/src/backend/commands/creatinh.c	Thu Mar  7 11:35:34 2002
--- pgsqldomain/src/backend/commands/creatinh.c	Thu Mar  7 23:16:06 2002
***************
*** 39,45 ****
static void StoreCatalogInheritance(Oid relationId, List *supers);
static int	findAttrByName(const char *attributeName, List *schema);
static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass);
!
/* ----------------------------------------------------------------
*		DefineRelation
--- 39,45 ----
static void StoreCatalogInheritance(Oid relationId, List *supers);
static int	findAttrByName(const char *attributeName, List *schema);
static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass);
! static List *MergeDomainAttributes(List *schema);
/* ----------------------------------------------------------------
*		DefineRelation
***************
*** 70,75 ****
--- 70,82 ----
StrNCpy(relname, stmt->relname, NAMEDATALEN);
/*
+ 	 * Inherit domain attributes into the known columns before table inheritance
+ 	 * applies it's changes otherwise we risk adding double constraints
+ 	 * to a domain thats inherited.
+ 	 */
+ 	schema = MergeDomainAttributes(schema);
+
+ 	/*
* Look up inheritance ancestors and generate relation schema,
* including inherited attributes.
*/
***************
*** 235,240 ****
--- 242,307 ----
{
AssertArg(name);
heap_truncate(name);
+ }
+
+
+ /*
+  * MergeDomainAttributes
+  *      Returns a new table schema with the constraints, types, and other
+  *      attributes of the domain resolved for fields using the domain as
+  *		their type.

I didn't know we had schemas yet. You should probably not overload that
term to mean "a list of database objects".

+  *
+  * Defaults are pulled out by the table attribute as required, similar to
+  * how all types defaults are processed.
+  */
+ static List *
+ MergeDomainAttributes(List *schema)
+ {
+ 	List	   *entry;
+
+ 	/*
+ 	 * Loop through the table elements supplied. These should
+ 	 * never include inherited domains else they'll be
+ 	 * double (or more) processed.
+ 	 */
+ 	foreach(entry, schema)
+ 	{
+ 		ColumnDef  *coldef = lfirst(entry);
+ 		HeapTuple  tuple;
+ 		Form_pg_type typeTup;
+
+
+ 		tuple = SearchSysCache(TYPENAME,
+ 							   CStringGetDatum(coldef->typename->name),
+ 							   0,0,0);
+
+ 		if (!HeapTupleIsValid(tuple))
+ 			elog(ERROR, "MergeDomainAttributes: Type %s does not exist",
+ 				 coldef->typename->name);
+
+ 		typeTup = (Form_pg_type) GETSTRUCT(tuple);
+ 		if (typeTup->typtype == 'd') {
+ 			/*
+ 			 * This is a domain, lets force the properties of the domain on to
+ 			 * the new column.
+ 			 */
+
+ 			/* Enforce the typmod value */
+ 			coldef->typename->typmod = typeTup->typmod;
+
+ 			/* Enforce type NOT NULL || column definition NOT NULL -> NOT NULL */
+ 			coldef->is_not_null |= typeTup->typnotnull;
+
+ 			/* Enforce the element type in the event the domain is an array
+ 			 *
+ 			 * BUG: How do we fill out arrayBounds and attrname from typelem and typNDimms?
+ 			 */
+
+ 		}
+ 		ReleaseSysCache(tuple);
+ 	}
+
+ 	return schema;
}
/*----------
diff -rc pgsql.orig/src/backend/commands/define.c pgsqldomain/src/backend/commands/define.c
*** pgsql.orig/src/backend/commands/define.c	Thu Mar  7 11:35:34 2002
--- pgsqldomain/src/backend/commands/define.c	Thu Mar  7 22:24:23 2002
***************
*** 40,45 ****
--- 40,46 ----
#include "access/heapam.h"
#include "catalog/catname.h"
+ #include "catalog/heap.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_language.h"
#include "catalog/pg_operator.h"
***************
*** 476,481 ****
--- 477,798 ----
}
/*
+  * DefineDomain
+  *		Registers a new domain.
+  */
+ void
+ DefineDomain(CreateDomainStmt *stmt)
+ {
+ 	int16		internalLength = -1;	/* int2 */
+ 	int16		externalLength = -1;	/* int2 */
+ 	char	   *inputName = NULL;
+ 	char	   *outputName = NULL;
+ 	char	   *sendName = NULL;
+ 	char	   *receiveName = NULL;
+
+ 	/*
+ 	 * Domains store the external representation in defaultValue
+ 	 * and the interal Node representation in defaultValueBin
+ 	 */
+ 	char	   *defaultValue = NULL;
+ 	char	   *defaultValueBin = NULL;
+
+ 	bool		byValue = false;
+ 	char		delimiter = DEFAULT_TYPDELIM;
+ 	char		alignment = 'i';	/* default alignment */
+ 	char		storage = 'p';	/* default TOAST storage method */
+ 	char		typtype;
+ 	Datum		datum;
+ 	bool		typNotNull = false;
+ 	char		*elemName = NULL;
+ 	int32		typNDims = 0;	/* No array dimensions by default */
+
+ 	bool		isnull;
+ 	Relation	pg_type_rel;
+ 	TupleDesc	pg_type_dsc;
+ 	HeapTuple	typeTup;
+ 	char	   *typeName = stmt->typename->name;
+
+ 	List	   *listptr;
+ 	List	   *schema = stmt->constraints;
+
+ 	/*
+ 	 * Domainnames, unlike typenames don't need to account for the '_'
+ 	 * prefix.  So they can be one character longer.
+ 	 */
+ 	if (strlen(stmt->domainname) > (NAMEDATALEN - 1))
+ 		elog(ERROR, "CREATE DOMAIN: domain names must be %d characters or less",
+ 			 NAMEDATALEN - 1);
+
+
+ 	/* Test for existing Domain (or type) of that name */
+ 	typeTup = SearchSysCache( TYPENAME
+ 							, PointerGetDatum(stmt->domainname)
+ 							, 0, 0, 0
+ 							);
+
+ 	if (HeapTupleIsValid(typeTup))
+ 	{
+ 		elog(ERROR, "CREATE DOMAIN: domain or type  %s already exists",
+ 			 stmt->domainname);
+ 	}
+
+ 	/*
+ 	 * Get the information about old types
+ 	 */
+ 	pg_type_rel = heap_openr(TypeRelationName, RowExclusiveLock);
+ 	pg_type_dsc = RelationGetDescr(pg_type_rel);
+
+
+ 	/*
+ 	 * When the type is an array for some reason we don't actually receive
+ 	 * the name here.  We receive the base types name.  Lets set Dims while
+ 	 * were at it.
+ 	 */
+ 	if (stmt->typename->arrayBounds > 0) {
+ 		typeName = makeArrayTypeName(stmt->typename->name);
+
+ 		typNDims = length(stmt->typename->arrayBounds);
+ 	}
+
+
+ 	typeTup = SearchSysCache( TYPENAME
+ 							, PointerGetDatum(typeName)
+ 							, 0, 0, 0
+ 							);
+
+ 	if (!HeapTupleIsValid(typeTup))
+ 	{
+ 		elog(ERROR, "CREATE DOMAIN: type %s does not exist",
+ 			 stmt->typename->name);
+ 	}
+
+
+ 	/* Check that this is a basetype */
+ 	typtype = DatumGetChar(heap_getattr(typeTup, Anum_pg_type_typtype, pg_type_dsc, &isnull));
+ 	Assert(!isnull);
+
+ 	/*
+ 	 * What we really don't want is domains of domains.  This could cause all sorts
+ 	 * of neat issues if we allow that.
+ 	 *
+ 	 * With testing, we may determine complex types should be allowed
+ 	 */
+ 	if (typtype != 'b') {
+ 		elog(ERROR, "DefineDomain: %s is not a basetype", stmt->typename->name);
+ 	}
+
+ 	/* passed by value */
+ 	byValue = 			DatumGetBool(heap_getattr(typeTup, Anum_pg_type_typbyval, pg_type_dsc, &isnull));
+ 	Assert(!isnull);

You don't have to use heap_getattr here. You can use

byValue = ((Form_pg_type) GETSTRUCT(typeTup))->typbyval

Same for all the other ones that are fixed-length.

+
+ 	/* Required Alignment */
+ 	alignment = 		DatumGetChar(heap_getattr(typeTup, Anum_pg_type_typalign, pg_type_dsc, &isnull));
+ 	Assert(!isnull);
+
+ 	/* Storage Length */
+ 	internalLength = 	DatumGetInt16(heap_getattr(typeTup, Anum_pg_type_typlen, pg_type_dsc, &isnull));
+ 	Assert(!isnull);
+
+ 	/* External Length (unused) */
+ 	externalLength = 	DatumGetInt16(heap_getattr(typeTup, Anum_pg_type_typprtlen, pg_type_dsc, &isnull));
+ 	Assert(!isnull);
+
+ 	/* Array element Delimiter */
+ 	delimiter = 		DatumGetChar(heap_getattr(typeTup, Anum_pg_type_typdelim, pg_type_dsc, &isnull));
+ 	Assert(!isnull);
+
+ 	/* Input Function Name */
+ 	datum = 			heap_getattr(typeTup, Anum_pg_type_typinput, pg_type_dsc, &isnull);
+ 	Assert(!isnull);
+
+ 	inputName = 		DatumGetCString(DirectFunctionCall1(regprocout, datum));
+
+ 	/* Output Function Name */
+ 	datum = 			heap_getattr(typeTup, Anum_pg_type_typoutput, pg_type_dsc, &isnull);
+ 	Assert(!isnull);
+
+ 	outputName = 		DatumGetCString(DirectFunctionCall1(regprocout, datum));
+
+ 	/* ReceiveName */
+ 	datum = 			heap_getattr(typeTup, Anum_pg_type_typreceive, pg_type_dsc, &isnull);
+ 	Assert(!isnull);
+
+ 	receiveName = 		DatumGetCString(DirectFunctionCall1(regprocout, datum));
+
+ 	/* SendName */
+ 	datum = 			heap_getattr(typeTup, Anum_pg_type_typsend, pg_type_dsc, &isnull);
+ 	Assert(!isnull);
+
+ 	sendName = 			DatumGetCString(DirectFunctionCall1(regprocout, datum));
+
+ 	/* TOAST Strategy */
+ 	storage = 			DatumGetChar(heap_getattr(typeTup, Anum_pg_type_typstorage, pg_type_dsc, &isnull));
+ 	Assert(!isnull);
+
+ 	/* Inherited default value */
+ 	datum = 			heap_getattr(typeTup, Anum_pg_type_typdefault, pg_type_dsc, &isnull);
+ 	if (!isnull) {
+ 		defaultValue = 	DatumGetCString(DirectFunctionCall1(textout, datum));
+ 	}
+
+ 	/*
+ 	 * Pull out the typelem name of the parent OID.
+ 	 *
+ 	 * This is what enables us to make a domain of an array
+ 	 */
+ 	datum = 			heap_getattr(typeTup, Anum_pg_type_typelem, pg_type_dsc, &isnull);
+ 	Assert(!isnull);
+
+ 	if (DatumGetObjectId(datum) != InvalidOid) {
+ 		HeapTuple tup;
+
+ 		tup = SearchSysCache( TYPEOID
+ 							, datum
+ 							, 0, 0, 0
+ 							);
+
+ 		elemName = NameStr(((Form_pg_type) GETSTRUCT(tup))->typname);
+
+ 		ReleaseSysCache(tup);
+ 	}
+
+
+ 	/*
+ 	 * Run through constraints manually avoids the additional
+ 	 * processing conducted by DefineRelation() and friends.
+ 	 *
+ 	 * Besides, we don't want any constraints to be cooked.  We'll
+ 	 * do that when the table is created via MergeDomainAttributes().
+ 	 */
+ 	foreach(listptr, schema)
+ 	{
+ 		bool nullDefined = false;
+ 		Node	   *expr;
+ 		Constraint *colDef = lfirst(listptr);
+
+ 		/* Used for the statement transformation */
+ 		ParseState *pstate;
+
+ 		/*
+ 		 * Create a dummy ParseState and insert the target relation as its
+ 		 * sole rangetable entry.  We need a ParseState for transformExpr.
+ 		 */
+ 		pstate = make_parsestate(NULL);
+
+ 		switch(colDef->contype) {
+ 			/*
+ 	 		 * The inherited default value may be overridden by the user
+ 			 * with the DEFAULT <expr> statement.
+ 			 *
+ 	 		 * We have to search the entire constraint tree returned as we
+ 			 * don't want to cook or fiddle too much.
+ 			 */
+ 			case CONSTR_DEFAULT:
+
+ 				/*
+ 				 * Cook the colDef->raw_expr into an expression to ensure
+ 				 * that it can be done.  We store the text version of the
+ 				 * raw value.
+ 				 *
+ 				 * Note: Name is strictly for error message
+ 				 */
+ 				expr = cookDefault(pstate, colDef->raw_expr
+ 								, typeTup->t_data->t_oid
+ 								, stmt->typename->typmod
+ 								, stmt->typename->name);
+
+ 				/* Binary default required */
+ 				defaultValue = deparse_expression(expr,
+ 								deparse_context_for(stmt->domainname,
+ 													InvalidOid),
+ 												   false);
+
+ 				defaultValueBin = nodeToString(expr);
+
+ 				break;
+
+ 			/*
+ 			 * Find the NULL constraint.
+ 			 */
+ 			case CONSTR_NOTNULL:
+ 				if (nullDefined) {
+ 					elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
+ 				} else {
+ 					typNotNull = true;
+ 					nullDefined = true;
+ 				}
+
+ 		  		break;
+
+ 			case CONSTR_NULL:
+ 				if (nullDefined) {
+ 					elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
+ 				} else {
+ 					typNotNull = false;
+ 					nullDefined = true;
+ 				}
+
+ 		  		break;
+
+ 		  	case CONSTR_UNIQUE:
+ 		  		elog(ERROR, "CREATE DOMAIN / UNIQUE indecies not supported");
+ 		  		break;
+
+ 		  	case CONSTR_PRIMARY:
+ 		  		elog(ERROR, "CREATE DOMAIN / PRIMARY KEY indecies not supported");
+ 		  		break;
+
+
+ 		  	case CONSTR_CHECK:
+
+ 		  		elog(ERROR, "defineDomain: CHECK Constraints not supported");
+ 		  		break;
+
+ 		  	case CONSTR_ATTR_DEFERRABLE:
+ 		  	case CONSTR_ATTR_NOT_DEFERRABLE:
+ 		  	case CONSTR_ATTR_DEFERRED:
+ 		  	case CONSTR_ATTR_IMMEDIATE:
+ 		  		elog(ERROR, "defineDomain: DEFERRABLE, NON DEFERRABLE, DEFERRED and IMMEDIATE not supported");
+ 		  		break;
+ 		}
+
+ 	}
+
+ 	/*
+ 	 * Have TypeCreate do all the real work.
+ 	 */
+ 	TypeCreate(stmt->domainname,	/* type name */
+ 			   InvalidOid,			/* preassigned type oid (not done here) */
+ 			   InvalidOid,			/* relation oid (n/a here) */
+ 			   internalLength,		/* internal size */
+ 			   externalLength,		/* external size */
+ 			   'd',					/* type-type (domain type) */
+ 			   delimiter,			/* array element delimiter */
+ 			   inputName,			/* input procedure */
+ 			   outputName,			/* output procedure */
+ 			   receiveName,			/* receive procedure */
+ 			   sendName,			/* send procedure */
+ 			   elemName,			/* element type name */
+ 			   typeName,			/* base type name */
+ 			   defaultValue,		/* default type value */
+ 			   defaultValueBin,		/* default type value */
+ 			   byValue,				/* passed by value */
+ 			   alignment,			/* required alignment */
+ 			   storage,				/* TOAST strategy */
+ 			   stmt->typename->typmod, /* typeMod value */
+ 			   typNDims,			/* Array dimensions for base type */
+ 			   typNotNull);	/* Type NOT NULL */
+
+ 	/*
+ 	 * Now we can clean up.
+ 	 */
+ 	ReleaseSysCache(typeTup);
+ 	heap_close(pg_type_rel, NoLock);
+ }
+
+
+ /*
* DefineType
*		Registers a new type.
*/
***************
*** 490,495 ****
--- 807,814 ----
char	   *sendName = NULL;
char	   *receiveName = NULL;
char	   *defaultValue = NULL;
+ 	char	   *defaultValueBin = NULL;
+ 	Node	   *defaultRaw = (Node *) NULL;
bool		byValue = false;
char		delimiter = DEFAULT_TYPDELIM;
char	   *shadow_type;
***************
*** 531,537 ****
else if (strcasecmp(defel->defname, "element") == 0)
elemName = defGetString(defel);
else if (strcasecmp(defel->defname, "default") == 0)
! 			defaultValue = defGetString(defel);
else if (strcasecmp(defel->defname, "passedbyvalue") == 0)
byValue = true;
else if (strcasecmp(defel->defname, "alignment") == 0)
--- 850,856 ----
else if (strcasecmp(defel->defname, "element") == 0)
elemName = defGetString(defel);
else if (strcasecmp(defel->defname, "default") == 0)
! 			defaultRaw = defel->arg;
else if (strcasecmp(defel->defname, "passedbyvalue") == 0)
byValue = true;
else if (strcasecmp(defel->defname, "alignment") == 0)
***************
*** 591,596 ****
--- 910,941 ----
if (outputName == NULL)
elog(ERROR, "Define: \"output\" unspecified");
+
+ 	if (defaultRaw) {
+ 		Node   *expr;
+ 		ParseState *pstate;
+
+ 		/*
+ 		 * Create a dummy ParseState and insert the target relation as its
+ 		 * sole rangetable entry.  We need a ParseState for transformExpr.
+ 		 */
+ 		pstate = make_parsestate(NULL);
+
+ 		expr = cookDefault(pstate, defaultRaw,
+ 						   InvalidOid,
+ 						   -1,
+ 						   typeName);
+
+ 		/* Binary default required */
+ 		defaultValue = deparse_expression(expr,
+ 						deparse_context_for(typeName,
+ 											InvalidOid),
+ 										   false);
+
+ 		defaultValueBin = nodeToString(expr);
+ 	}
+
+
/*
* now have TypeCreate do all the real work.
*/
***************
*** 606,615 ****
receiveName,		/* receive procedure */
sendName,		/* send procedure */
elemName,		/* element type name */
defaultValue,	/* default type value */
byValue,			/* passed by value */
alignment,		/* required alignment */
! 			   storage);		/* TOAST strategy */
/*
* When we create a base type (as opposed to a complex type) we need
--- 951,965 ----
receiveName,		/* receive procedure */
sendName,		/* send procedure */
elemName,		/* element type name */
+ 			   NULL,			/* base type name (Non-zero for domains) */
defaultValue,	/* default type value */
+ 			   defaultValueBin,	/* default type value (Binary form) */
byValue,			/* passed by value */
alignment,		/* required alignment */
! 			   storage,			/* TOAST strategy */
! 			   -1,				/* typMod (Domains only) */
! 			   0,				/* Array Dimensions of typbasetype */
! 			   'f');			/* Type NOT NULL */

/*
* When we create a base type (as opposed to a complex type) we need
***************
*** 632,641 ****
"array_in", /* receive procedure */
"array_out", /* send procedure */
typeName, /* element type name */
NULL, /* never a default type value */
false, /* never passed by value */
alignment, /* see above */
! 'x'); /* ARRAY is always toastable */

pfree(shadow_type);
}
--- 982,996 ----
"array_in",		/* receive procedure */
"array_out",		/* send procedure */
typeName,		/* element type name */
+ 			   NULL,			/* base type name */
NULL,			/* never a default type value */
+ 			   NULL,			/* binary default isn't sent either */
false,			/* never passed by value */
alignment,		/* see above */
! 			   'x',				/* ARRAY is always toastable */
! 			   -1,				/* typMod (Domains only) */
! 			   0,				/* Array dimensions of typbasetype */
! 			   'f');			/* Type NOT NULL */

pfree(shadow_type);
}

diff -rc pgsql.orig/src/backend/nodes/copyfuncs.c pgsqldomain/src/backend/nodes/copyfuncs.c
*** pgsql.orig/src/backend/nodes/copyfuncs.c	Thu Mar  7 11:35:34 2002
--- pgsqldomain/src/backend/nodes/copyfuncs.c	Thu Mar  7 22:53:19 2002
***************
*** 2227,2232 ****
--- 2227,2247 ----
return newnode;
}
+ static CreateDomainStmt *
+ _copyCreateDomainStmt(CreateDomainStmt *from)
+ {
+ 	CreateDomainStmt *newnode = makeNode(CreateDomainStmt);
+
+ 	if (from->domainname)
+ 		newnode->domainname = pstrdup(from->domainname);
+ 	if (from->typename)
+ 		newnode->typename = from->typename;

That's not a copy.

+ 	if (from->constraints)
+ 		newnode->constraints = from->constraints;
+
+ 	return newnode;
+ }
+
static CreatedbStmt *
_copyCreatedbStmt(CreatedbStmt *from)
{
***************
*** 3026,3031 ****
--- 3041,3049 ----
break;
case T_FuncWithArgs:
retval = _copyFuncWithArgs(from);
+ 			break;
+ 		case T_CreateDomainStmt:
+ 			retval = _copyCreateDomainStmt(from);
break;

default:

diff -rc pgsql.orig/src/backend/parser/gram.y pgsqldomain/src/backend/parser/gram.y
*** pgsql.orig/src/backend/parser/gram.y	Thu Mar  7 11:35:35 2002
--- pgsqldomain/src/backend/parser/gram.y	Thu Mar  7 22:34:00 2002
***************
*** 97,103 ****

%}

-
%union
{
int					ival;
--- 97,102 ----
***************
*** 135,141 ****
ClosePortalStmt, ClusterStmt, CommentStmt, ConstraintsSetStmt,
CopyStmt, CreateAsStmt, CreateGroupStmt, CreatePLangStmt,
CreateSchemaStmt, CreateSeqStmt, CreateStmt, CreateTrigStmt,
! 		CreateUserStmt, CreatedbStmt, CursorStmt, DefineStmt, DeleteStmt,
DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropTrigStmt,
DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt,
--- 134,141 ----
ClosePortalStmt, ClusterStmt, CommentStmt, ConstraintsSetStmt,
CopyStmt, CreateAsStmt, CreateGroupStmt, CreatePLangStmt,
CreateSchemaStmt, CreateSeqStmt, CreateStmt, CreateTrigStmt,
! 		CreateUserStmt, CreateDomainStmt, CreatedbStmt, CursorStmt,

Alphabetical order?

! 		DefineStmt, DeleteStmt,
DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropTrigStmt,
DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt,
***************
*** 289,294 ****
--- 289,296 ----
%type <list>	constraints_set_namelist
%type <boolean>	constraints_set_mode

+ %type <boolean> opt_as
+
/*
* If you make any token changes, remember to:
* - use "yacc -d" and update parse.h
***************
*** 343,349 ****
WITHOUT

/* Keywords (in SQL92 non-reserved words) */
! %token COMMITTED, SERIALIZABLE, TYPE_P

/* Keywords for Postgres support (not in SQL92 reserved words)
*
--- 345,351 ----
WITHOUT

/* Keywords (in SQL92 non-reserved words) */
! %token COMMITTED, SERIALIZABLE, TYPE_P, DOMAIN_P

/* Keywords for Postgres support (not in SQL92 reserved words)
*
***************
*** 446,451 ****
--- 448,454 ----
| CopyStmt
| CreateStmt
| CreateAsStmt
+ 		| CreateDomainStmt
| CreateSchemaStmt
| CreateGroupStmt
| CreateSeqStmt
***************
*** 776,783 ****
--- 779,789 ----
n->dbname = $3;
$$ = (Node *)n;
}
+ 		;
+
+
/*****************************************************************************
*
* Set PG internal variable
***************
*** 1461,1467 ****
n->name = NULL;
if (exprIsNullConstant($2))
{
! 						/* DEFAULT NULL should be reported as empty expr */
n->raw_expr = NULL;
}
else
--- 1467,1476 ----
n->name = NULL;
if (exprIsNullConstant($2))
{
! 						/*
! 						 * DEFAULT NULL should be reported as empty expr
! 						 * Required for NOT NULL Domain overrides
! 						 */
n->raw_expr = NULL;
}
else
***************
*** 2043,2055 ****
| def_list ',' def_elem				{ $$ = lappend($1, $3); }
;
! def_elem:  ColLabel '=' def_arg
{
$$ = makeNode(DefElem);
$$->defname = $1;
$$->arg = (Node *)$3;
}
! 		| ColLabel
{
$$ = makeNode(DefElem);
$$->defname = $1;
--- 2052,2073 ----
| def_list ',' def_elem				{ $$ = lappend($1, $3); }
;
! def_elem:  DEFAULT '=' c_expr
! 				{
! 					$$ = makeNode(DefElem);
! 					$$->defname = "default";
! 					if (exprIsNullConstant($3))
! 						$$->arg = (Node *)NULL;
! 					else
! 						$$->arg = $3;
! 				}
! 		| ColId '=' def_arg
{
$$ = makeNode(DefElem);
$$->defname = $1;
$$->arg = (Node *)$3;
}
! 		| ColId
{
$$ = makeNode(DefElem);
$$->defname = $1;
***************
*** 2078,2083 ****
--- 2096,2110 ----
DropStmt *n = makeNode(DropStmt);
n->removeType = $2;
n->names = $3;
+ 					n->behavior = RESTRICT;		/* Restricted by default */
+ 					$$ = (Node *)n;
+ 				}
+ 		| DROP DOMAIN_P name_list drop_behavior
+ 				{
+ 					DropStmt *n = makeNode(DropStmt);
+ 					n->removeType = DROP_DOMAIN_P;
+ 					n->names = $3;
+ 					n->behavior = $4;
$$ = (Node *)n;
}
;
***************
*** 2110,2116 ****
*  The COMMENT ON statement can take different forms based upon the type of
*  the object associated with the comment. The form of the statement is:
*
!  *  COMMENT ON [ [ DATABASE | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ]
*               <objname> | AGGREGATE <aggname> (<aggtype>) | FUNCTION
*		 <funcname> (arg1, arg2, ...) | OPERATOR <op>
*		 (leftoperand_typ rightoperand_typ) | TRIGGER <triggername> ON
--- 2137,2143 ----
*  The COMMENT ON statement can take different forms based upon the type of
*  the object associated with the comment. The form of the statement is:
*
!  *  COMMENT ON [ [ DATABASE | DOMAIN | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ]
*               <objname> | AGGREGATE <aggname> (<aggtype>) | FUNCTION
*		 <funcname> (arg1, arg2, ...) | OPERATOR <op>
*		 (leftoperand_typ rightoperand_typ) | TRIGGER <triggername> ON
***************
*** 2196,2201 ****
--- 2223,2229 ----
| RULE { $$ = RULE; }
| SEQUENCE { $$ = SEQUENCE; }
| TABLE { $$ = TABLE; }
+ 		| DOMAIN_P { $$ = TYPE_P; }
| TYPE_P { $$ = TYPE_P; }
| VIEW { $$ = VIEW; }
;
***************
*** 3178,3183 ****
--- 3206,3227 ----
{
$$ = lconsi(3, makeListi1(-1));
}
+ 		;
+
+
+ /*****************************************************************************
+  *
+  *		DROP DATABASE
+  *
+  *
+  *****************************************************************************/
+
+ DropdbStmt:	DROP DATABASE database_name
+ 				{
+ 					DropdbStmt *n = makeNode(DropdbStmt);
+ 					n->dbname = $3;
+ 					$$ = (Node *)n;
+ 				}
| OWNER opt_equal name
{
$$ = lconsi(4, makeList1($3));

This doesn't look right.

***************
*** 3222,3243 ****
}
;

-
/*****************************************************************************
*
! * DROP DATABASE
*
*
*****************************************************************************/

! DropdbStmt: DROP DATABASE database_name
{
! DropdbStmt *n = makeNode(DropdbStmt);
! n->dbname = $3;
$$ = (Node *)n;
}
;

/*****************************************************************************
*
--- 3266,3295 ----
}
;

/*****************************************************************************
*
! * Manipulate a domain
*
*
*****************************************************************************/

! CreateDomainStmt: CREATE DOMAIN_P name opt_as Typename ColQualList opt_collate
{
! CreateDomainStmt *n = makeNode(CreateDomainStmt);
! n->domainname = $3;
! n->typename = $5;
! n->constraints = $6;
!
! if ($7 != NULL)
! elog(NOTICE,"CREATE DOMAIN / COLLATE %s not yet "
! "implemented; clause ignored", $7);
$$ = (Node *)n;
}
;

+ opt_as:	AS	{$$ = TRUE; }
+ 	| /* EMPTY */	{$$ = FALSE; }
+ 	;
/*****************************************************************************
*
***************
*** 5879,5884 ****
--- 5931,5937 ----
| DEFERRED						{ $$ = "deferred"; }
| DELETE						{ $$ = "delete"; }
| DELIMITERS					{ $$ = "delimiters"; }
+ 		| DOMAIN_P						{ $$ = "domain"; }
| DOUBLE						{ $$ = "double"; }
| DROP							{ $$ = "drop"; }
| EACH							{ $$ = "each"; }
diff -rc pgsql.orig/src/backend/parser/parse_coerce.c pgsqldomain/src/backend/parser/parse_coerce.c
*** pgsql.orig/src/backend/parser/parse_coerce.c	Thu Mar  7 11:35:35 2002
--- pgsqldomain/src/backend/parser/parse_coerce.c	Thu Mar  7 22:24:24 2002
***************
*** 38,43 ****
--- 38,44 ----
{
Node	   *result;

+

No.

if (targetTypeId == inputTypeId ||
targetTypeId == InvalidOid ||
node == NULL)
***************
*** 605,607 ****
--- 606,637 ----
}
return result;
}	/* PreferredType() */
+
+
+ /*
+  * If the targetTypeId is a domain, we really want to coerce
+  * the tuple to the domain type -- not the domain itself
+  */
+ Oid
+ getBaseType(Oid inType)
+ {
+ 	HeapTuple	tup;
+ 	Form_pg_type typTup;
+
+ 	tup = SearchSysCache(TYPEOID,
+ 						 ObjectIdGetDatum(inType),
+ 						 0, 0, 0);
+
+ 	typTup = ((Form_pg_type) GETSTRUCT(tup));
+
+ 	/*
+ 	 * Assume that typbasetype exists and is a base type, where inType
+ 	 * was a domain
+ 	 */
+ 	if (typTup->typtype == 'd')
+ 		inType = typTup->typbasetype;
+
+ 	ReleaseSysCache(tup);
+
+ 	return inType;
+ }
diff -rc pgsql.orig/src/backend/tcop/postgres.c pgsqldomain/src/backend/tcop/postgres.c
*** pgsql.orig/src/backend/tcop/postgres.c	Wed Mar  6 01:10:09 2002
--- pgsqldomain/src/backend/tcop/postgres.c	Thu Mar  7 22:24:24 2002
***************
*** 2212,2217 ****
--- 2212,2218 ----
}
break;

+ case T_CreateDomainStmt:
case T_CreateStmt:
tag = "CREATE";
break;

The result tag for CREATE DOMAIN is CREATE DOMAIN. (Yes, there's actually
a standard about this.)

--
Peter Eisentraut peter_e@gmx.net

#6Rod Taylor
rbt@zort.ca
In reply to: Peter Eisentraut (#5)
4 attachment(s)
Re: Domain Support -- another round

New set with most of Peters comments corrected. Left the deal about
schema though :) Took nearly an hour to do a cvs diff for some reason
this time (normally a couple of minutes is enough).

Random nitpicking below. Also, have you created a regression test?

They had been posted a few times and haven't changed. (Attached
anyway)

+    <structfield>typnotnull</structfield> represents a NOT NULL
+    constraint on a type.  Normally used only for domains.

And unnormally...?

Unnormally is when someone sets it by hand on a type which isn't a
domain -- I guess. Corrected.

+ <!entity createDomain system "create_domain.sgml">

I don't see this file included.

Other messages. Full package included on this one however.

+  * MergeDomainAttributes
+  *      Returns a new table schema with the constraints, types,

and other

+ * attributes of the domain resolved for fields using the

domain as

+ * their type.

I didn't know we had schemas yet. You should probably not overload

that

term to mean "a list of database objects".

Merge attributes says something very similar about inheritance and
table schemas. Kinda correct considering
the variable used in both cases is *schema.

The diff weirdness in regards to DROP DATABASE is probably because I
started by copying the DROP DATABASE element, then altered it. I
don't know why it chose that method to do the diff though, but it is
accurate. Using -cd flags didn't make it any prettier.

Attachments:

domainregress.sqlapplication/octet-stream; name=domainregress.sqlDownload
create_domain.sgmlapplication/octet-stream; name=create_domain.sgmlDownload
drop_domain.sgmlapplication/octet-stream; name=drop_domain.sgmlDownload
domain.patchapplication/octet-stream; name=domain.patchDownload
? log
? src/backend/parser/y.output
Index: doc/src/sgml/catalogs.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v
retrieving revision 2.33
diff -c -r2.33 catalogs.sgml
*** doc/src/sgml/catalogs.sgml	2002/03/07 16:35:32	2.33
--- doc/src/sgml/catalogs.sgml	2002/03/12 02:35:22
***************
*** 2511,2516 ****
--- 2511,2563 ----
       </row>
  
       <row>
+       <entry>typbasetype</entry>
+       <entry><type>oid</type></entry>
+       <entry></entry>
+       <entry><para>
+        <structfield>typbasetype</structfield> is the type that this one is based
+        on.  Normally references the domains parent type, and is 0 otherwise.
+       </para></entry>
+      </row>
+ 
+ 	 <row>
+ 	  <entry>typnotnull</entry>
+ 	  <entry><type>boolean</type></entry>
+ 	  <entry></entry>
+ 	  <entry><para>
+ 	   <structfield>typnotnull</structfield> represents a NOT NULL
+ 	   constraint on a type.  Used for domains only.
+ 	  </para></entry>
+ 	 </row>
+ 
+      <row>
+       <entry>typmod</entry>
+       <entry><type>integer</type></entry>
+       <entry></entry>
+       <entry><para>
+        <structfield>typmod</structfield> records type-specific data
+        supplied at table creation time (for example, the maximum
+        length of a <type>varchar</type> column).  It is passed to
+        type-specific input and output functions as the third
+        argument. The value will generally be -1 for types that do not
+        need typmod.  This data is copied to
+        <structfield>pg_attribute.atttypmod</structfield> on creation
+        of a table using a domain as it's field type.
+        </para></entry>
+      </row>
+ 
+      <row>
+       <entry>typdefaultbin</entry>
+       <entry><type>text</type></entry>
+       <entry></entry>
+       <entry><para>
+        <structfield>typdefaultbin</structfield> is NULL for types without a
+        default value.  If it's not NULL, it contains the internal string
+        representation of the default expression node.
+       </para></entry>
+      </row>
+ 
+      <row>
        <entry>typdefault</entry>
        <entry><type>text</type></entry>
        <entry></entry>
Index: doc/src/sgml/reference.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/reference.sgml,v
retrieving revision 1.23
diff -c -r1.23 reference.sgml
*** doc/src/sgml/reference.sgml	2002/03/07 16:35:32	1.23
--- doc/src/sgml/reference.sgml	2002/03/12 02:35:48
***************
*** 61,66 ****
--- 61,67 ----
     &createAggregate;
     &createConstraint;
     &createDatabase;
+    &createDomain;
     &createFunction;
     &createGroup;
     &createIndex;
***************
*** 78,83 ****
--- 79,85 ----
     &delete;
     &dropAggregate;
     &dropDatabase;
+    &dropDomain;
     &dropFunction;
     &dropGroup;
     &dropIndex;
***************
*** 115,121 ****
     &unlisten;
     &update;
     &vacuum;
!   
   </reference>
  
  <!--
--- 117,123 ----
     &unlisten;
     &update;
     &vacuum;
! 
   </reference>
  
  <!--
Index: doc/src/sgml/ref/allfiles.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/ref/allfiles.sgml,v
retrieving revision 1.35
diff -c -r1.35 allfiles.sgml
*** doc/src/sgml/ref/allfiles.sgml	2002/03/07 16:35:32	1.35
--- doc/src/sgml/ref/allfiles.sgml	2002/03/12 02:36:02
***************
*** 52,57 ****
--- 52,58 ----
  <!entity createAggregate    system "create_aggregate.sgml">
  <!entity createConstraint   system "create_constraint.sgml">
  <!entity createDatabase     system "create_database.sgml">
+ <!entity createDomain       system "create_domain.sgml">
  <!entity createFunction     system "create_function.sgml">
  <!entity createGroup        system "create_group.sgml">
  <!entity createIndex        system "create_index.sgml">
***************
*** 69,74 ****
--- 70,76 ----
  <!entity delete             system "delete.sgml">
  <!entity dropAggregate      system "drop_aggregate.sgml">
  <!entity dropDatabase       system "drop_database.sgml">
+ <!entity dropDomain         system "drop_domain.sgml">
  <!entity dropFunction       system "drop_function.sgml">
  <!entity dropGroup          system "drop_group.sgml">
  <!entity dropIndex          system "drop_index.sgml">
Index: doc/src/sgml/ref/comment.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/ref/comment.sgml,v
retrieving revision 1.14
diff -c -r1.14 comment.sgml
*** doc/src/sgml/ref/comment.sgml	2002/03/07 16:35:33	1.14
--- doc/src/sgml/ref/comment.sgml	2002/03/12 02:36:03
***************
*** 25,31 ****
    <synopsis>
  COMMENT ON
  [
!   [ DATABASE | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ] <replaceable class="PARAMETER">object_name</replaceable> |
    COLUMN <replaceable class="PARAMETER">table_name</replaceable>.<replaceable class="PARAMETER">column_name</replaceable> |
    AGGREGATE <replaceable class="PARAMETER">agg_name</replaceable> (<replaceable class="PARAMETER">agg_type</replaceable>) |
    FUNCTION <replaceable class="PARAMETER">func_name</replaceable> (<replaceable class="PARAMETER">arg1</replaceable>, <replaceable class="PARAMETER">arg2</replaceable>, ...) |
--- 25,31 ----
    <synopsis>
  COMMENT ON
  [
!   [ DATABASE | DOMAIN | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ] <replaceable class="PARAMETER">object_name</replaceable> |
    COLUMN <replaceable class="PARAMETER">table_name</replaceable>.<replaceable class="PARAMETER">column_name</replaceable> |
    AGGREGATE <replaceable class="PARAMETER">agg_name</replaceable> (<replaceable class="PARAMETER">agg_type</replaceable>) |
    FUNCTION <replaceable class="PARAMETER">func_name</replaceable> (<replaceable class="PARAMETER">arg1</replaceable>, <replaceable class="PARAMETER">arg2</replaceable>, ...) |
***************
*** 33,39 ****
    TRIGGER <replaceable class="PARAMETER">trigger_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable>
  ] IS <replaceable class="PARAMETER">'text'</replaceable>
    </synopsis>
!   
    <refsect2 id="R2-SQL-COMMENT-1">
     <refsect2info>
      <date>1999-10-25</date>
--- 33,39 ----
    TRIGGER <replaceable class="PARAMETER">trigger_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable>
  ] IS <replaceable class="PARAMETER">'text'</replaceable>
    </synopsis>
! 
    <refsect2 id="R2-SQL-COMMENT-1">
     <refsect2info>
      <date>1999-10-25</date>
***************
*** 64,70 ****
      </variablelist>
     </para>
    </refsect2>
!   
    <refsect2 id="R2-SQL-COMMENT-2">
     <refsect2info>
      <date>1998-09-08</date>
--- 64,70 ----
      </variablelist>
     </para>
    </refsect2>
! 
    <refsect2 id="R2-SQL-COMMENT-2">
     <refsect2info>
      <date>1998-09-08</date>
***************
*** 99,105 ****
    </title>
    <para>
     <command>COMMENT</command> stores a comment about a database object.
!     Comments can be 
      easily retrieved with <command>psql</command>'s
      <command>\dd</command>, <command>\d+</command>, or <command>\l+</command>
      commands.  Other user interfaces to retrieve comments can be built atop
--- 99,105 ----
    </title>
    <para>
     <command>COMMENT</command> stores a comment about a database object.
!     Comments can be
      easily retrieved with <command>psql</command>'s
      <command>\dd</command>, <command>\d+</command>, or <command>\l+</command>
      commands.  Other user interfaces to retrieve comments can be built atop
***************
*** 141,146 ****
--- 141,147 ----
  
     <programlisting>
  COMMENT ON DATABASE my_database IS 'Development Database';
+ COMMENT ON DOMAIN my_domain IS 'Email Address Domain';
  COMMENT ON INDEX my_index IS 'Enforces uniqueness on employee id';
  COMMENT ON RULE my_rule IS 'Logs UPDATES of employee records';
  COMMENT ON SEQUENCE my_sequence IS 'Used to generate primary keys';
***************
*** 155,166 ****
     </programlisting>
    </para>
   </refsect1>
!  
   <refsect1 id="R1-SQL-COMMENT-3">
    <title>
     Compatibility
    </title>
!   
    <refsect2 id="R2-SQL-COMMENT-4">
     <refsect2info>
      <date>1998-09-08</date>
--- 156,167 ----
     </programlisting>
    </para>
   </refsect1>
! 
   <refsect1 id="R1-SQL-COMMENT-3">
    <title>
     Compatibility
    </title>
! 
    <refsect2 id="R2-SQL-COMMENT-4">
     <refsect2info>
      <date>1998-09-08</date>
Index: src/backend/catalog/heap.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/catalog/heap.c,v
retrieving revision 1.186
diff -c -r1.186 heap.c
*** src/backend/catalog/heap.c	2002/03/07 16:35:33	1.186
--- src/backend/catalog/heap.c	2002/03/12 02:36:32
***************
*** 49,54 ****
--- 49,55 ----
  #include "optimizer/planmain.h"
  #include "optimizer/prep.h"
  #include "optimizer/var.h"
+ #include "parser/parse_coerce.h"
  #include "parser/parse_expr.h"
  #include "parser/parse_relation.h"
  #include "parser/parse_target.h"
***************
*** 698,707 ****
  			   "oidin",			/* receive procedure */
  			   "oidout",		/* send procedure */
  			   NULL,			/* array element type - irrelevant */
  			   NULL,			/* default type value - none */
  			   true,			/* passed by value */
  			   'i',				/* default alignment - same as for OID */
! 			   'p');			/* Not TOASTable */
  }
  
  /* --------------------------------
--- 699,713 ----
  			   "oidin",			/* receive procedure */
  			   "oidout",		/* send procedure */
  			   NULL,			/* array element type - irrelevant */
+ 			   NULL,			/* baseType Name -- typically for domains */
  			   NULL,			/* default type value - none */
+ 			   NULL,			/* default type binary representation */
  			   true,			/* passed by value */
  			   'i',				/* default alignment - same as for OID */
! 			   'p',				/* Not TOASTable */
! 			   -1,				/* Type mod length */
! 			   0,				/* array dimensions for typBaseType */
! 			   false);			/* Type NOT NULL */
  }
  
  /* --------------------------------
***************
*** 1584,1589 ****
--- 1590,1599 ----
  	int			numchecks;
  	List	   *listptr;
  
+ 	/* Probably shouldn't be null by default */
+ 	Node	   *expr = NULL;
+ 
+ 
  	/*
  	 * Get info about existing constraints.
  	 */
***************
*** 1614,1683 ****
  	foreach(listptr, rawColDefaults)
  	{
  		RawColumnDefault *colDef = (RawColumnDefault *) lfirst(listptr);
- 		Node	   *expr;
- 		Oid			type_id;
  
- 		Assert(colDef->raw_default != NULL);
  
! 		/*
! 		 * Transform raw parsetree to executable expression.
! 		 */
! 		expr = transformExpr(pstate, colDef->raw_default, EXPR_COLUMN_FIRST);
  
! 		/*
! 		 * Make sure default expr does not refer to any vars.
! 		 */
! 		if (contain_var_clause(expr))
! 			elog(ERROR, "cannot use column references in DEFAULT clause");
  
  		/*
- 		 * No subplans or aggregates, either...
- 		 */
- 		if (contain_subplans(expr))
- 			elog(ERROR, "cannot use subselects in DEFAULT clause");
- 		if (contain_agg_clause(expr))
- 			elog(ERROR, "cannot use aggregate functions in DEFAULT clause");
- 
- 		/*
- 		 * Check that it will be possible to coerce the expression to the
- 		 * column's type.  We store the expression without coercion,
- 		 * however, to avoid premature coercion in cases like
- 		 *
- 		 * CREATE TABLE tbl (fld datetime DEFAULT 'now'::text);
- 		 *
- 		 * NB: this should match the code in optimizer/prep/preptlist.c that
- 		 * will actually do the coercion, to ensure we don't accept an
- 		 * unusable default expression.
- 		 */
- 		type_id = exprType(expr);
- 		if (type_id != InvalidOid)
- 		{
- 			Form_pg_attribute atp = rel->rd_att->attrs[colDef->attnum - 1];
- 
- 			if (type_id != atp->atttypid)
- 			{
- 				if (CoerceTargetExpr(NULL, expr, type_id,
- 								  atp->atttypid, atp->atttypmod) == NULL)
- 					elog(ERROR, "Column \"%s\" is of type %s"
- 						 " but default expression is of type %s"
- 					"\n\tYou will need to rewrite or cast the expression",
- 						 NameStr(atp->attname),
- 						 format_type_be(atp->atttypid),
- 						 format_type_be(type_id));
- 			}
- 		}
- 
- 		/*
- 		 * Might as well try to reduce any constant expressions.
- 		 */
- 		expr = eval_const_expressions(expr);
- 
- 		/*
- 		 * Must fix opids, in case any operators remain...
- 		 */
- 		fix_opids(expr);
- 
- 		/*
  		 * OK, store it.
  		 */
  		StoreAttrDefault(rel, colDef->attnum, nodeToString(expr));
--- 1624,1638 ----
  	foreach(listptr, rawColDefaults)
  	{
  		RawColumnDefault *colDef = (RawColumnDefault *) lfirst(listptr);
  
  
! 		Form_pg_attribute atp = rel->rd_att->attrs[colDef->attnum - 1];
  
! 		expr = cookDefault(pstate, colDef->raw_default
! 						, atp->atttypid, atp->atttypmod
! 						, NameStr(atp->attname));
  
  		/*
  		 * OK, store it.
  		 */
  		StoreAttrDefault(rel, colDef->attnum, nodeToString(expr));
***************
*** 1891,1896 ****
--- 1846,1933 ----
  	heap_freetuple(reltup);
  	heap_close(relrel, RowExclusiveLock);
  }
+ 
+ /*
+  * Take a raw default and convert it to a cooked format ready for
+  * storage.
+  *
+  * Parse state, attypid, attypmod and attname are required for
+  * CoerceTargetExpr() and more importantly transformExpr().
+  */
+ Node *
+ cookDefault(ParseState *pstate,
+ 			Node *raw_default,
+ 			Oid atttypid,
+ 			int32 atttypmod,
+ 			char *attname) {
+ 
+ 	Oid			type_id;
+ 	Node		*expr;
+ 
+ 	Assert(raw_default != NULL);
+ 
+ 	/*
+ 	 * Transform raw parsetree to executable expression.
+ 	 */
+ 	expr = transformExpr(pstate, raw_default, EXPR_COLUMN_FIRST);
+ 
+ 	/*
+ 	 * Make sure default expr does not refer to any vars.
+ 	 */
+ 	if (contain_var_clause(expr))
+ 		elog(ERROR, "cannot use column references in DEFAULT clause");
+ 
+ 	/*
+ 	 * No subplans or aggregates, either...
+ 	 */
+ 	if (contain_subplans(expr))
+ 		elog(ERROR, "cannot use subselects in DEFAULT clause");
+ 	if (contain_agg_clause(expr))
+ 		elog(ERROR, "cannot use aggregate functions in DEFAULT clause");
+ 
+ 	/*
+ 	 * Check that it will be possible to coerce the expression to the
+ 	 * column's type.  We store the expression without coercion,
+ 	 * however, to avoid premature coercion in cases like
+ 	 *
+ 	 * CREATE TABLE tbl (fld datetime DEFAULT 'now'::text);
+ 	 *
+ 	 * NB: this should match the code in optimizer/prep/preptlist.c that
+ 	 * will actually do the coercion, to ensure we don't accept an
+ 	 * unusable default expression.
+ 	 */
+ 	type_id = exprType(expr);
+ 	if (type_id != InvalidOid && atttypid != InvalidOid) {
+ 		if (type_id != atttypid) {
+ 
+ 			/* Try coercing to the base type of the domain if available */
+ 			if (CoerceTargetExpr(pstate, expr, type_id,
+ 								 getBaseType(atttypid),
+ 								 atttypmod) == NULL) {
+ 
+ 				elog(ERROR, "Column \"%s\" is of type %s"
+ 					" but default expression is of type %s"
+ 					"\n\tYou will need to rewrite or cast the expression",
+ 					 attname,
+ 					 format_type_be(atttypid),
+ 					 format_type_be(type_id));
+ 			}
+ 		}
+ 	}
+ 
+ 	/*
+ 	 * Might as well try to reduce any constant expressions.
+ 	 */
+ 	expr = eval_const_expressions(expr);
+ 
+ 	/*
+ 	 * Must fix opids, in case any operators remain...
+ 	 */
+ 	fix_opids(expr);
+ 
+ 	return(expr);
+ }
+ 
  
  static void
  RemoveAttrDefaults(Relation rel)
Index: src/backend/catalog/pg_type.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/catalog/pg_type.c,v
retrieving revision 1.67
diff -c -r1.67 pg_type.c
*** src/backend/catalog/pg_type.c	2002/03/07 16:35:33	1.67
--- src/backend/catalog/pg_type.c	2002/03/12 02:36:34
***************
*** 176,185 ****
  	values[i++] = ObjectIdGetDatum(InvalidOid); /* 12 */
  	values[i++] = ObjectIdGetDatum(InvalidOid); /* 13 */
  	values[i++] = ObjectIdGetDatum(InvalidOid); /* 14 */
! 	values[i++] = CharGetDatum('i');	/* 15 */
! 	values[i++] = CharGetDatum('p');	/* 16 */
  	values[i++] = DirectFunctionCall1(textin,
! 									  CStringGetDatum(typeName));		/* 17 */
  
  	/*
  	 * create a new type tuple with FormHeapTuple
--- 176,191 ----
  	values[i++] = ObjectIdGetDatum(InvalidOid); /* 12 */
  	values[i++] = ObjectIdGetDatum(InvalidOid); /* 13 */
  	values[i++] = ObjectIdGetDatum(InvalidOid); /* 14 */
! 	values[i++] = CharGetDatum('i');			/* 15 */
! 	values[i++] = CharGetDatum('p');			/* 16 */
! 	values[i++] = BoolGetDatum(false);			/* 17 */
! 	values[i++] = Int32GetDatum(-1);			/* 18 */
! 	values[i++] = ObjectIdGetDatum(InvalidOid);	/* 19 */
! 	values[i++] = Int32GetDatum(0);				/* 20 */
  	values[i++] = DirectFunctionCall1(textin,
! 									  CStringGetDatum(typeName));		/* 21 */
! 	values[i++] = DirectFunctionCall1(textin,
! 									  CStringGetDatum(typeName));		/* 22 */
  
  	/*
  	 * create a new type tuple with FormHeapTuple
***************
*** 264,270 ****
  Oid
  TypeCreate(char *typeName,
  		   Oid assignedTypeOid,
! 		   Oid relationOid,		/* only for 'c'atalog typeTypes */
  		   int16 internalSize,
  		   int16 externalSize,
  		   char typeType,
--- 270,276 ----
  Oid
  TypeCreate(char *typeName,
  		   Oid assignedTypeOid,
! 		   Oid relationOid,			/* only for 'c'atalog typeTypes */
  		   int16 internalSize,
  		   int16 externalSize,
  		   char typeType,
***************
*** 274,283 ****
  		   char *receiveProcedure,
  		   char *sendProcedure,
  		   char *elementTypeName,
! 		   char *defaultTypeValue,		/* internal rep */
  		   bool passedByValue,
  		   char alignment,
! 		   char storage)
  {
  	int			i,
  				j;
--- 280,294 ----
  		   char *receiveProcedure,
  		   char *sendProcedure,
  		   char *elementTypeName,
! 		   char *baseTypeName,
! 		   char *defaultTypeValue,	/* human readable rep */
! 		   char *defaultTypeBin,	/* cooked rep */
  		   bool passedByValue,
  		   char alignment,
! 		   char storage,
! 		   int32 typeMod,
! 		   int32 typNDims,			/* Array dimensions for baseTypeName */
! 		   bool typeNotNull)		/* binary default representation (cooked) */
  {
  	int			i,
  				j;
***************
*** 285,290 ****
--- 296,302 ----
  	HeapScanDesc pg_type_scan;
  	Oid			typeObjectId;
  	Oid			elementObjectId = InvalidOid;
+ 	Oid			baseObjectId = InvalidOid;
  	HeapTuple	tup;
  	char		nulls[Natts_pg_type];
  	char		replaces[Natts_pg_type];
***************
*** 318,323 ****
--- 330,346 ----
  	}
  
  	/*
+ 	 * if this type has an associated baseType, then we check that it
+ 	 * is defined.
+ 	 */
+ 	if (baseTypeName)
+ 	{
+ 		baseObjectId = TypeGet(baseTypeName, &defined);
+ 		if (!defined)
+ 			elog(ERROR, "type %s does not exist", baseTypeName);
+ 	}
+ 
+ 	/*
  	 * validate size specifications: either positive (fixed-length) or -1
  	 * (variable-length).
  	 */
***************
*** 388,394 ****
  			 * signature is 0,OIDOID,INT4OID.  The output procedures may
  			 * take 2 args (data value, element OID).
  			 */
! 			if (OidIsValid(elementObjectId))
  			{
  				int			nargs;
  
--- 411,417 ----
  			 * signature is 0,OIDOID,INT4OID.  The output procedures may
  			 * take 2 args (data value, element OID).
  			 */
! 			if (OidIsValid(elementObjectId) || OidIsValid(baseObjectId))
  			{
  				int			nargs;
  
***************
*** 411,416 ****
--- 434,440 ----
  										 PointerGetDatum(argList),
  										 0);
  			}
+ 
  			if (!OidIsValid(procOid))
  				func_error("TypeCreate", procname, 1, argList, NULL);
  		}
***************
*** 429,434 ****
--- 453,486 ----
  	values[i++] = CharGetDatum(storage);		/* 16 */
  
  	/*
+ 	 * set the typenotnull value
+ 	 */
+ 	values[i++] = BoolGetDatum(typeNotNull);	/* 17 */
+ 
+ 	/*
+ 	 * set the typemod value
+ 	 */
+ 	values[i++] = Int32GetDatum(typeMod);			/* 18 */
+ 
+ 	values[i++] = ObjectIdGetDatum(baseObjectId);	/* 19 */
+ 
+ 	/*
+ 	 * Dimension number for an array base type
+ 	 */
+ 	values[i++] = Int32GetDatum(typNDims);			/* 20 */
+ 
+ 	/*
+ 	 * initialize the default binary value for this type.  Check for
+ 	 * nulls of course.
+ 	 */
+ 	if (defaultTypeBin)
+ 		values[i] = DirectFunctionCall1(textin,
+ 									  CStringGetDatum(defaultTypeBin));
+ 	else
+ 		nulls[i] = 'n';
+ 	i++;										/* 21 */
+ 
+ 	/*
  	 * initialize the default value for this type.
  	 */
  	if (defaultTypeValue)
***************
*** 436,442 ****
  									  CStringGetDatum(defaultTypeValue));
  	else
  		nulls[i] = 'n';
! 	i++;						/* 17 */
  
  	/*
  	 * open pg_type and begin a scan for the type name.
--- 488,494 ----
  									  CStringGetDatum(defaultTypeValue));
  	else
  		nulls[i] = 'n';
! 	i++;						/* 22 */
  
  	/*
  	 * open pg_type and begin a scan for the type name.
Index: src/backend/commands/creatinh.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/creatinh.c,v
retrieving revision 1.85
diff -c -r1.85 creatinh.c
*** src/backend/commands/creatinh.c	2002/03/07 16:35:34	1.85
--- src/backend/commands/creatinh.c	2002/03/12 02:36:38
***************
*** 39,46 ****
  static void StoreCatalogInheritance(Oid relationId, List *supers);
  static int	findAttrByName(const char *attributeName, List *schema);
  static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass);
  
- 
  /* ----------------------------------------------------------------
   *		DefineRelation
   *				Creates a new relation.
--- 39,46 ----
  static void StoreCatalogInheritance(Oid relationId, List *supers);
  static int	findAttrByName(const char *attributeName, List *schema);
  static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass);
+ static List *MergeDomainAttributes(List *schema);
  
  /* ----------------------------------------------------------------
   *		DefineRelation
   *				Creates a new relation.
***************
*** 70,75 ****
--- 70,82 ----
  	StrNCpy(relname, stmt->relname, NAMEDATALEN);
  
  	/*
+ 	 * Inherit domain attributes into the known columns before table inheritance
+ 	 * applies it's changes otherwise we risk adding double constraints
+ 	 * to a domain thats inherited.
+ 	 */
+ 	schema = MergeDomainAttributes(schema);
+ 
+ 	/*
  	 * Look up inheritance ancestors and generate relation schema,
  	 * including inherited attributes.
  	 */
***************
*** 235,240 ****
--- 242,307 ----
  {
  	AssertArg(name);
  	heap_truncate(name);
+ }
+ 
+ 
+ /*
+  * MergeDomainAttributes
+  *      Returns a new table schema with the constraints, types, and other
+  *      attributes of the domain resolved for fields using the domain as
+  *		their type.
+  *
+  * Defaults are pulled out by the table attribute as required, similar to
+  * how all types defaults are processed.
+  */
+ static List *
+ MergeDomainAttributes(List *schema)
+ {
+ 	List	   *entry;
+ 
+ 	/*
+ 	 * Loop through the table elements supplied. These should
+ 	 * never include inherited domains else they'll be
+ 	 * double (or more) processed.
+ 	 */
+ 	foreach(entry, schema)
+ 	{
+ 		ColumnDef  *coldef = lfirst(entry);
+ 		HeapTuple  tuple;
+ 		Form_pg_type typeTup;
+ 
+ 
+ 		tuple = SearchSysCache(TYPENAME,
+ 							   CStringGetDatum(coldef->typename->name),
+ 							   0,0,0);
+ 
+ 		if (!HeapTupleIsValid(tuple))
+ 			elog(ERROR, "MergeDomainAttributes: Type %s does not exist",
+ 				 coldef->typename->name);
+ 
+ 		typeTup = (Form_pg_type) GETSTRUCT(tuple);
+ 		if (typeTup->typtype == 'd') {
+ 			/*
+ 			 * This is a domain, lets force the properties of the domain on to
+ 			 * the new column.
+ 			 */
+ 
+ 			/* Enforce the typmod value */
+ 			coldef->typename->typmod = typeTup->typmod;
+ 
+ 			/* Enforce type NOT NULL || column definition NOT NULL -> NOT NULL */
+ 			coldef->is_not_null |= typeTup->typnotnull;
+ 
+ 			/* Enforce the element type in the event the domain is an array
+ 			 *
+ 			 * BUG: How do we fill out arrayBounds and attrname from typelem and typNDimms?
+ 			 */
+ 
+ 		}
+ 		ReleaseSysCache(tuple);
+ 	}
+ 
+ 	return schema;
  }
  
  /*----------
Index: src/backend/commands/define.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/define.c,v
retrieving revision 1.69
diff -c -r1.69 define.c
*** src/backend/commands/define.c	2002/03/07 16:35:34	1.69
--- src/backend/commands/define.c	2002/03/12 02:36:39
***************
*** 40,45 ****
--- 40,46 ----
  
  #include "access/heapam.h"
  #include "catalog/catname.h"
+ #include "catalog/heap.h"
  #include "catalog/pg_aggregate.h"
  #include "catalog/pg_language.h"
  #include "catalog/pg_operator.h"
***************
*** 476,481 ****
--- 477,799 ----
  }
  
  /*
+  * DefineDomain
+  *		Registers a new domain.
+  */
+ void
+ DefineDomain(CreateDomainStmt *stmt)
+ {
+ 	int16		internalLength = -1;	/* int2 */
+ 	int16		externalLength = -1;	/* int2 */
+ 	char	   *inputName = NULL;
+ 	char	   *outputName = NULL;
+ 	char	   *sendName = NULL;
+ 	char	   *receiveName = NULL;
+ 
+ 	/*
+ 	 * Domains store the external representation in defaultValue
+ 	 * and the interal Node representation in defaultValueBin
+ 	 */
+ 	char	   *defaultValue = NULL;
+ 	char	   *defaultValueBin = NULL;
+ 
+ 	bool		byValue = false;
+ 	char		delimiter = DEFAULT_TYPDELIM;
+ 	char		alignment = 'i';	/* default alignment */
+ 	char		storage = 'p';	/* default TOAST storage method */
+ 	char		typtype;
+ 	Datum		datum;
+ 	bool		typNotNull = false;
+ 	char		*elemName = NULL;
+ 	int32		typNDims = 0;	/* No array dimensions by default */
+ 
+ 	bool		isnull;
+ 	Relation	pg_type_rel;
+ 	TupleDesc	pg_type_dsc;
+ 	HeapTuple	typeTup;
+ 	char	   *typeName = stmt->typename->name;
+ 
+ 	List	   *listptr;
+ 	List	   *schema = stmt->constraints;
+ 
+ 	/*
+ 	 * Domainnames, unlike typenames don't need to account for the '_'
+ 	 * prefix.  So they can be one character longer.
+ 	 */
+ 	if (strlen(stmt->domainname) > (NAMEDATALEN - 1))
+ 		elog(ERROR, "CREATE DOMAIN: domain names must be %d characters or less",
+ 			 NAMEDATALEN - 1);
+ 
+ 
+ 	/* Test for existing Domain (or type) of that name */
+ 	typeTup = SearchSysCache( TYPENAME
+ 							, PointerGetDatum(stmt->domainname)
+ 							, 0, 0, 0
+ 							);
+ 
+ 	if (HeapTupleIsValid(typeTup))
+ 	{
+ 		elog(ERROR, "CREATE DOMAIN: domain or type  %s already exists",
+ 			 stmt->domainname);
+ 	}
+ 
+ 	/*
+ 	 * Get the information about old types
+ 	 */
+ 	pg_type_rel = heap_openr(TypeRelationName, RowExclusiveLock);
+ 	pg_type_dsc = RelationGetDescr(pg_type_rel);
+ 
+ 
+ 	/*
+ 	 * When the type is an array for some reason we don't actually receive
+ 	 * the name here.  We receive the base types name.  Lets set Dims while
+ 	 * were at it.
+ 	 */
+ 	if (stmt->typename->arrayBounds > 0) {
+ 		typeName = makeArrayTypeName(stmt->typename->name);
+ 
+ 		typNDims = length(stmt->typename->arrayBounds);
+ 	}
+ 
+ 
+ 	typeTup = SearchSysCache( TYPENAME
+ 							, PointerGetDatum(typeName)
+ 							, 0, 0, 0
+ 							);
+ 
+ 	if (!HeapTupleIsValid(typeTup))
+ 	{
+ 		elog(ERROR, "CREATE DOMAIN: type %s does not exist",
+ 			 stmt->typename->name);
+ 	}
+ 
+ 
+ 	/* Check that this is a basetype */
+ 	typtype = DatumGetChar(heap_getattr(typeTup, Anum_pg_type_typtype, pg_type_dsc, &isnull));
+ 	Assert(!isnull);
+ 
+ 	/*
+ 	 * What we really don't want is domains of domains.  This could cause all sorts
+ 	 * of neat issues if we allow that.
+ 	 *
+ 	 * With testing, we may determine complex types should be allowed
+ 	 */
+ 	if (typtype != 'b') {
+ 		elog(ERROR, "DefineDomain: %s is not a basetype", stmt->typename->name);
+ 	}
+ 
+ 	/* passed by value */
+ 	byValue = ((Form_pg_type) GETSTRUCT(typeTup))->typbyval;
+ 
+ 	/* Required Alignment */
+ 	alignment = ((Form_pg_type) GETSTRUCT(typeTup))->typalign;
+ 
+ 	/* Storage Length */
+ 	internalLength = ((Form_pg_type) GETSTRUCT(typeTup))->typlen;
+ 
+ 	/* External Length (unused) */
+ 	externalLength = ((Form_pg_type) GETSTRUCT(typeTup))->typprtlen;
+ 
+ 	/* Array element Delimiter */
+ 	delimiter = ((Form_pg_type) GETSTRUCT(typeTup))->typdelim;
+ 
+ 	/* Input Function Name */
+ 	datum = heap_getattr(typeTup, Anum_pg_type_typinput, pg_type_dsc, &isnull);
+ 	Assert(!isnull);
+ 
+ 	inputName = DatumGetCString(DirectFunctionCall1(regprocout, datum));
+ 
+ 	/* Output Function Name */
+ 	datum = heap_getattr(typeTup, Anum_pg_type_typoutput, pg_type_dsc, &isnull);
+ 	Assert(!isnull);
+ 
+ 	outputName = DatumGetCString(DirectFunctionCall1(regprocout, datum));
+ 
+ 	/* ReceiveName */
+ 	datum = heap_getattr(typeTup, Anum_pg_type_typreceive, pg_type_dsc, &isnull);
+ 	Assert(!isnull);
+ 
+ 	receiveName = DatumGetCString(DirectFunctionCall1(regprocout, datum));
+ 
+ 	/* SendName */
+ 	datum = heap_getattr(typeTup, Anum_pg_type_typsend, pg_type_dsc, &isnull);
+ 	Assert(!isnull);
+ 
+ 	sendName = DatumGetCString(DirectFunctionCall1(regprocout, datum));
+ 
+ 	/* TOAST Strategy */
+ 	storage =  ((Form_pg_type) GETSTRUCT(typeTup))->typstorage;
+ 	Assert(!isnull);
+ 
+ 	/* Inherited default value */
+ 	datum = 			heap_getattr(typeTup, Anum_pg_type_typdefault, pg_type_dsc, &isnull);
+ 	if (!isnull) {
+ 		defaultValue = 	DatumGetCString(DirectFunctionCall1(textout, datum));
+ 	}
+ 
+ 	/* Inherited default binary value */
+ 	datum = 			heap_getattr(typeTup, Anum_pg_type_typdefaultbin, pg_type_dsc, &isnull);
+ 	if (!isnull) {
+ 		defaultValueBin = 	DatumGetCString(DirectFunctionCall1(textout, datum));
+ 	}
+ 
+ 	/*
+ 	 * Pull out the typelem name of the parent OID.
+ 	 *
+ 	 * This is what enables us to make a domain of an array
+ 	 */
+ 	datum = 			heap_getattr(typeTup, Anum_pg_type_typelem, pg_type_dsc, &isnull);
+ 	Assert(!isnull);
+ 
+ 	if (DatumGetObjectId(datum) != InvalidOid) {
+ 		HeapTuple tup;
+ 
+ 		tup = SearchSysCache( TYPEOID
+ 							, datum
+ 							, 0, 0, 0
+ 							);
+ 
+ 		elemName = NameStr(((Form_pg_type) GETSTRUCT(tup))->typname);
+ 
+ 		ReleaseSysCache(tup);
+ 	}
+ 
+ 
+ 	/*
+ 	 * Run through constraints manually avoids the additional
+ 	 * processing conducted by DefineRelation() and friends.
+ 	 *
+ 	 * Besides, we don't want any constraints to be cooked.  We'll
+ 	 * do that when the table is created via MergeDomainAttributes().
+ 	 */
+ 	foreach(listptr, schema)
+ 	{
+ 		bool nullDefined = false;
+ 		Node	   *expr;
+ 		Constraint *colDef = lfirst(listptr);
+ 
+ 		/* Used for the statement transformation */
+ 		ParseState *pstate;
+ 
+ 		/*
+ 		 * Create a dummy ParseState and insert the target relation as its
+ 		 * sole rangetable entry.  We need a ParseState for transformExpr.
+ 		 */
+ 		pstate = make_parsestate(NULL);
+ 
+ 		switch(colDef->contype) {
+ 			/*
+ 	 		 * The inherited default value may be overridden by the user
+ 			 * with the DEFAULT <expr> statement.
+ 			 *
+ 	 		 * We have to search the entire constraint tree returned as we
+ 			 * don't want to cook or fiddle too much.
+ 			 */
+ 			case CONSTR_DEFAULT:
+ 
+ 				/*
+ 				 * Cook the colDef->raw_expr into an expression to ensure
+ 				 * that it can be done.  We store the text version of the
+ 				 * raw value.
+ 				 *
+ 				 * Note: Name is strictly for error message
+ 				 */
+ 				expr = cookDefault(pstate, colDef->raw_expr
+ 								, typeTup->t_data->t_oid
+ 								, stmt->typename->typmod
+ 								, stmt->typename->name);
+ 
+ 				/* Binary default required */
+ 				defaultValue = deparse_expression(expr,
+ 								deparse_context_for(stmt->domainname,
+ 													InvalidOid),
+ 												   false);
+ 
+ 				defaultValueBin = nodeToString(expr);
+ 
+ 				break;
+ 
+ 			/*
+ 			 * Find the NULL constraint.
+ 			 */
+ 			case CONSTR_NOTNULL:
+ 				if (nullDefined) {
+ 					elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
+ 				} else {
+ 					typNotNull = true;
+ 					nullDefined = true;
+ 				}
+ 
+ 		  		break;
+ 
+ 			case CONSTR_NULL:
+ 				if (nullDefined) {
+ 					elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
+ 				} else {
+ 					typNotNull = false;
+ 					nullDefined = true;
+ 				}
+ 
+ 		  		break;
+ 
+ 		  	case CONSTR_UNIQUE:
+ 		  		elog(ERROR, "CREATE DOMAIN / UNIQUE indecies not supported");
+ 		  		break;
+ 
+ 		  	case CONSTR_PRIMARY:
+ 		  		elog(ERROR, "CREATE DOMAIN / PRIMARY KEY indecies not supported");
+ 		  		break;
+ 
+ 
+ 		  	case CONSTR_CHECK:
+ 
+ 		  		elog(ERROR, "defineDomain: CHECK Constraints not supported");
+ 		  		break;
+ 
+ 		  	case CONSTR_ATTR_DEFERRABLE:
+ 		  	case CONSTR_ATTR_NOT_DEFERRABLE:
+ 		  	case CONSTR_ATTR_DEFERRED:
+ 		  	case CONSTR_ATTR_IMMEDIATE:
+ 		  		elog(ERROR, "defineDomain: DEFERRABLE, NON DEFERRABLE, DEFERRED and IMMEDIATE not supported");
+ 		  		break;
+ 		}
+ 
+ 	}
+ 
+ 	/*
+ 	 * Have TypeCreate do all the real work.
+ 	 */
+ 	TypeCreate(stmt->domainname,	/* type name */
+ 			   InvalidOid,			/* preassigned type oid (not done here) */
+ 			   InvalidOid,			/* relation oid (n/a here) */
+ 			   internalLength,		/* internal size */
+ 			   externalLength,		/* external size */
+ 			   'd',					/* type-type (domain type) */
+ 			   delimiter,			/* array element delimiter */
+ 			   inputName,			/* input procedure */
+ 			   outputName,			/* output procedure */
+ 			   receiveName,			/* receive procedure */
+ 			   sendName,			/* send procedure */
+ 			   elemName,			/* element type name */
+ 			   typeName,			/* base type name */
+ 			   defaultValue,		/* default type value */
+ 			   defaultValueBin,		/* default type value */
+ 			   byValue,				/* passed by value */
+ 			   alignment,			/* required alignment */
+ 			   storage,				/* TOAST strategy */
+ 			   stmt->typename->typmod, /* typeMod value */
+ 			   typNDims,			/* Array dimensions for base type */
+ 			   typNotNull);	/* Type NOT NULL */
+ 
+ 	/*
+ 	 * Now we can clean up.
+ 	 */
+ 	ReleaseSysCache(typeTup);
+ 	heap_close(pg_type_rel, NoLock);
+ }
+ 
+ 
+ /*
   * DefineType
   *		Registers a new type.
   */
***************
*** 490,495 ****
--- 808,815 ----
  	char	   *sendName = NULL;
  	char	   *receiveName = NULL;
  	char	   *defaultValue = NULL;
+ 	char	   *defaultValueBin = NULL;
+ 	Node	   *defaultRaw = (Node *) NULL;
  	bool		byValue = false;
  	char		delimiter = DEFAULT_TYPDELIM;
  	char	   *shadow_type;
***************
*** 531,537 ****
  		else if (strcasecmp(defel->defname, "element") == 0)
  			elemName = defGetString(defel);
  		else if (strcasecmp(defel->defname, "default") == 0)
! 			defaultValue = defGetString(defel);
  		else if (strcasecmp(defel->defname, "passedbyvalue") == 0)
  			byValue = true;
  		else if (strcasecmp(defel->defname, "alignment") == 0)
--- 851,857 ----
  		else if (strcasecmp(defel->defname, "element") == 0)
  			elemName = defGetString(defel);
  		else if (strcasecmp(defel->defname, "default") == 0)
! 			defaultRaw = defel->arg;
  		else if (strcasecmp(defel->defname, "passedbyvalue") == 0)
  			byValue = true;
  		else if (strcasecmp(defel->defname, "alignment") == 0)
***************
*** 591,596 ****
--- 911,942 ----
  	if (outputName == NULL)
  		elog(ERROR, "Define: \"output\" unspecified");
  
+ 
+ 	if (defaultRaw) {
+ 		Node   *expr;
+ 		ParseState *pstate;
+ 
+ 		/*
+ 		 * Create a dummy ParseState and insert the target relation as its
+ 		 * sole rangetable entry.  We need a ParseState for transformExpr.
+ 		 */
+ 		pstate = make_parsestate(NULL);
+ 
+ 		expr = cookDefault(pstate, defaultRaw,
+ 						   InvalidOid,
+ 						   -1,
+ 						   typeName);
+ 
+ 		/* Binary default required */
+ 		defaultValue = deparse_expression(expr,
+ 						deparse_context_for(typeName,
+ 											InvalidOid),
+ 										   false);
+ 
+ 		defaultValueBin = nodeToString(expr);
+ 	}
+ 
+ 
  	/*
  	 * now have TypeCreate do all the real work.
  	 */
***************
*** 606,615 ****
  			   receiveName,		/* receive procedure */
  			   sendName,		/* send procedure */
  			   elemName,		/* element type name */
  			   defaultValue,	/* default type value */
  			   byValue,			/* passed by value */
  			   alignment,		/* required alignment */
! 			   storage);		/* TOAST strategy */
  
  	/*
  	 * When we create a base type (as opposed to a complex type) we need
--- 952,966 ----
  			   receiveName,		/* receive procedure */
  			   sendName,		/* send procedure */
  			   elemName,		/* element type name */
+ 			   NULL,			/* base type name (Non-zero for domains) */
  			   defaultValue,	/* default type value */
+ 			   defaultValueBin,	/* default type value (Binary form) */
  			   byValue,			/* passed by value */
  			   alignment,		/* required alignment */
! 			   storage,			/* TOAST strategy */
! 			   -1,				/* typMod (Domains only) */
! 			   0,				/* Array Dimensions of typbasetype */
! 			   'f');			/* Type NOT NULL */
  
  	/*
  	 * When we create a base type (as opposed to a complex type) we need
***************
*** 632,641 ****
  			   "array_in",		/* receive procedure */
  			   "array_out",		/* send procedure */
  			   typeName,		/* element type name */
  			   NULL,			/* never a default type value */
  			   false,			/* never passed by value */
  			   alignment,		/* see above */
! 			   'x');			/* ARRAY is always toastable */
  
  	pfree(shadow_type);
  }
--- 983,997 ----
  			   "array_in",		/* receive procedure */
  			   "array_out",		/* send procedure */
  			   typeName,		/* element type name */
+ 			   NULL,			/* base type name */
  			   NULL,			/* never a default type value */
+ 			   NULL,			/* binary default isn't sent either */
  			   false,			/* never passed by value */
  			   alignment,		/* see above */
! 			   'x',				/* ARRAY is always toastable */
! 			   -1,				/* typMod (Domains only) */
! 			   0,				/* Array dimensions of typbasetype */
! 			   'f');			/* Type NOT NULL */
  
  	pfree(shadow_type);
  }
Index: src/backend/commands/remove.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/remove.c,v
retrieving revision 1.68
diff -c -r1.68 remove.c
*** src/backend/commands/remove.c	2002/03/07 16:35:34	1.68
--- src/backend/commands/remove.c	2002/03/12 02:36:40
***************
*** 1,7 ****
  /*-------------------------------------------------------------------------
   *
   * remove.c
!  *	  POSTGRES remove (function | type | operator ) utilty code.
   *
   * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
   * Portions Copyright (c) 1994, Regents of the University of California
--- 1,7 ----
  /*-------------------------------------------------------------------------
   *
   * remove.c
!  *	  POSTGRES remove (domain | function | type | operator ) utilty code.
   *
   * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
   * Portions Copyright (c) 1994, Regents of the University of California
***************
*** 22,27 ****
--- 22,28 ----
  #include "commands/comment.h"
  #include "commands/defrem.h"
  #include "miscadmin.h"
+ #include "parser/parse.h"
  #include "parser/parse_agg.h"
  #include "parser/parse_expr.h"
  #include "parser/parse_func.h"
***************
*** 267,272 ****
--- 268,327 ----
  						 0, 0, 0);
  	if (!HeapTupleIsValid(tup))
  		elog(ERROR, "RemoveType: type '%s' does not exist", shadow_type);
+ 
+ 	simple_heap_delete(relation, &tup->t_self);
+ 
+ 	ReleaseSysCache(tup);
+ 
+ 	heap_close(relation, RowExclusiveLock);
+ }
+ 
+ /*
+  *	RemoveDomain
+  *		Removes the domain 'typeName' and all attributes and relations that
+  *		use it.
+  */
+ void
+ RemoveDomain(char *domainName, int behavior)		/* domain name to be removed */
+ {
+ 	Relation	relation;
+ 	HeapTuple	tup;
+ 	TupleDesc	description;
+ 	char		typtype;
+ 	bool		isnull;
+ 
+ 
+ 	/* Domains are stored as types.  Check for permissions on the type */
+ 	if (!pg_ownercheck(GetUserId(), domainName, TYPENAME))
+ 		elog(ERROR, "RemoveDomain: type '%s': permission denied",
+ 			 domainName);
+ 
+ 
+ 	relation = heap_openr(TypeRelationName, RowExclusiveLock);
+ 	description = RelationGetDescr(relation);
+ 
+ 	tup = SearchSysCache(TYPENAME,
+ 						 PointerGetDatum(domainName),
+ 						 0, 0, 0);
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "RemoveType: type '%s' does not exist", domainName);
+ 
+ 
+ 	/* Check that this is actually a domain */
+ 	typtype = DatumGetChar(heap_getattr(tup, Anum_pg_type_typtype, description, &isnull));
+ 	Assert(!isnull);
+ 
+ 	if (typtype != 'd') {
+ 		elog(ERROR, "%s is not a domain", domainName);
+ 	}
+ 
+ 	/* CASCADE unsupported */
+ 	if (behavior == CASCADE) {
+ 		elog(ERROR, "DROP DOMAIN does not support the CASCADE keyword");
+ 	}
+ 
+ 	/* Delete any comments associated with this type */
+ 	DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation));
  
  	simple_heap_delete(relation, &tup->t_self);
  
Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.167
diff -c -r1.167 copyfuncs.c
*** src/backend/nodes/copyfuncs.c	2002/03/07 16:35:34	1.167
--- src/backend/nodes/copyfuncs.c	2002/03/12 02:36:58
***************
*** 2227,2232 ****
--- 2227,2246 ----
  	return newnode;
  }
  
+ static CreateDomainStmt *
+ _copyCreateDomainStmt(CreateDomainStmt *from)
+ {
+ 	CreateDomainStmt *newnode = makeNode(CreateDomainStmt);
+ 
+ 	if (from->domainname)
+ 		newnode->domainname = pstrdup(from->domainname);
+ 
+ 	Node_Copy(from, newnode, typename);
+ 	Node_Copy(from, newnode, constraints);
+ 
+ 	return newnode;
+ }
+ 
  static CreatedbStmt *
  _copyCreatedbStmt(CreatedbStmt *from)
  {
***************
*** 3026,3031 ****
--- 3040,3048 ----
  			break;
  		case T_FuncWithArgs:
  			retval = _copyFuncWithArgs(from);
+ 			break;
+ 		case T_CreateDomainStmt:
+ 			retval = _copyCreateDomainStmt(from);
  			break;
  
  		default:
Index: src/backend/nodes/equalfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v
retrieving revision 1.115
diff -c -r1.115 equalfuncs.c
*** src/backend/nodes/equalfuncs.c	2002/03/07 16:35:34	1.115
--- src/backend/nodes/equalfuncs.c	2002/03/12 02:36:58
***************
*** 1096,1101 ****
--- 1096,1114 ----
  }
  
  static bool
+ _equalCreateDomainStmt(CreateDomainStmt *a, CreateDomainStmt *b)
+ {
+ 	if (!equalstr(a->domainname, b->domainname))
+ 		return false;
+ 	if (!equal(a->typename, b->typename))
+ 		return false;
+ 	if (!equal(a->constraints, b->constraints))
+ 		return false;
+ 
+ 	return true;
+ }
+ 
+ static bool
  _equalCreatedbStmt(CreatedbStmt *a, CreatedbStmt *b)
  {
  	if (!equalstr(a->dbname, b->dbname))
***************
*** 2010,2015 ****
--- 2023,2031 ----
  			break;
  		case T_LoadStmt:
  			retval = _equalLoadStmt(a, b);
+ 			break;
+ 		case T_CreateDomainStmt:
+ 			retval = _equalCreateDomainStmt(a, b);
  			break;
  		case T_CreatedbStmt:
  			retval = _equalCreatedbStmt(a, b);
Index: src/backend/optimizer/prep/preptlist.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v
retrieving revision 1.48
diff -c -r1.48 preptlist.c
*** src/backend/optimizer/prep/preptlist.c	2002/03/07 16:35:35	1.48
--- src/backend/optimizer/prep/preptlist.c	2002/03/12 02:37:11
***************
*** 355,362 ****
  	Form_pg_attribute att_tup = rd_att->attrs[attrno - 1];
  	Oid			atttype = att_tup->atttypid;
  	int32		atttypmod = att_tup->atttypmod;
- 	bool		hasdefault;
- 	Datum		typedefault;
  	int16		typlen;
  	bool		typbyval;
  	Node	   *expr;
--- 355,360 ----
***************
*** 392,398 ****
  				if (type_id != atttype)
  				{
  					expr = CoerceTargetExpr(NULL, expr, type_id,
! 											atttype, atttypmod);
  
  					/*
  					 * This really shouldn't fail; should have checked the
--- 390,396 ----
  				if (type_id != atttype)
  				{
  					expr = CoerceTargetExpr(NULL, expr, type_id,
! 											getBaseType(atttype), atttypmod);
  
  					/*
  					 * This really shouldn't fail; should have checked the
***************
*** 430,470 ****
  		 * element type is, and the element type's default is irrelevant
  		 * too.
  		 */
- 		hasdefault = false;
- 		typedefault = (Datum) 0;
  		typlen = sizeof(Oid);
  		typbyval = true;
  	}
  	else
  	{
  #ifdef	_DROP_COLUMN_HACK__
  		if (COLUMN_IS_DROPPED(att_tup))
  		{
! 			hasdefault = false;
! 			typedefault = (Datum) 0;
  		}
  		else
  #endif   /* _DROP_COLUMN_HACK__ */
! 			hasdefault = get_typdefault(atttype, &typedefault);
  
  		get_typlenbyval(atttype, &typlen, &typbyval);
  	}
  
- 	expr = (Node *) makeConst(atttype,
- 							  typlen,
- 							  typedefault,
- 							  !hasdefault,
- 							  typbyval,
- 							  false,	/* not a set */
- 							  false);
- 
  	/*
  	 * If the column is a fixed-length type, it may need a length coercion
! 	 * as well as a type coercion.	But NULLs don't need that.
  	 */
! 	if (hasdefault)
! 		expr = coerce_type_typmod(NULL, expr,
! 								  atttype, atttypmod);
  
  	return expr;
  }
--- 428,480 ----
  		 * element type is, and the element type's default is irrelevant
  		 * too.
  		 */
  		typlen = sizeof(Oid);
  		typbyval = true;
+ 
+ 		expr = (Node *) makeConst(atttype,
+ 								  typlen,
+ 								  (Datum) 0,
+ 								  true,
+ 								  typbyval,
+ 								  false,           /* not a set */
+ 								  false);
  	}
  	else
  	{
  #ifdef	_DROP_COLUMN_HACK__
  		if (COLUMN_IS_DROPPED(att_tup))
  		{
! 
! 			expr = (Node *) makeConst(atttype,
! 									  typlen,
! 									  (Datum) 0,
! 									  true,
! 									  typbyval,
! 									  false,           /* not a set */
! 									  false);
  		}
  		else
  #endif   /* _DROP_COLUMN_HACK__ */
! 			expr = get_typdefault(atttype, atttypmod);
  
+ 		if (expr == NULL) {
+ 				expr = (Node *) makeConst(atttype,
+ 										  typlen,
+ 										  (Datum) 0,
+ 										  true,
+ 										  typbyval,
+ 										  false,		/* not a set */
+ 										  false);
+ 		}
  		get_typlenbyval(atttype, &typlen, &typbyval);
  	}
  
  	/*
  	 * If the column is a fixed-length type, it may need a length coercion
! 	 * as well as a type coercion, as well as direction to the final type.
  	 */
! 	expr = coerce_type_typmod(NULL, expr,
! 							  atttype, atttypmod);
  
  	return expr;
  }
Index: src/backend/parser/gram.y
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.287
diff -c -r2.287 gram.y
*** src/backend/parser/gram.y	2002/03/07 16:35:35	2.287
--- src/backend/parser/gram.y	2002/03/12 02:37:18
***************
*** 97,103 ****
  
  %}
  
- 
  %union
  {
  	int					ival;
--- 97,102 ----
***************
*** 133,141 ****
  		AlterDatabaseSetStmt, AlterGroupStmt, AlterSchemaStmt, AlterTableStmt,
  		AlterUserStmt, AlterUserSetStmt, AnalyzeStmt,
  		ClosePortalStmt, ClusterStmt, CommentStmt, ConstraintsSetStmt,
! 		CopyStmt, CreateAsStmt, CreateGroupStmt, CreatePLangStmt,
  		CreateSchemaStmt, CreateSeqStmt, CreateStmt, CreateTrigStmt,
! 		CreateUserStmt, CreatedbStmt, CursorStmt, DefineStmt, DeleteStmt,
  		DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropTrigStmt,
  		DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
  		GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt,
--- 132,141 ----
  		AlterDatabaseSetStmt, AlterGroupStmt, AlterSchemaStmt, AlterTableStmt,
  		AlterUserStmt, AlterUserSetStmt, AnalyzeStmt,
  		ClosePortalStmt, ClusterStmt, CommentStmt, ConstraintsSetStmt,
! 		CopyStmt, CreateAsStmt, CreateDomainStmt, CreateGroupStmt, CreatePLangStmt,
  		CreateSchemaStmt, CreateSeqStmt, CreateStmt, CreateTrigStmt,
! 		CreateUserStmt, CreatedbStmt, CursorStmt,
! 		DefineStmt, DeleteStmt,
  		DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropTrigStmt,
  		DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
  		GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt,
***************
*** 289,294 ****
--- 289,296 ----
  %type <list>	constraints_set_namelist
  %type <boolean>	constraints_set_mode
  
+ %type <boolean> opt_as
+ 
  /*
   * If you make any token changes, remember to:
   *		- use "yacc -d" and update parse.h
***************
*** 343,349 ****
  		WITHOUT
  
  /* Keywords (in SQL92 non-reserved words) */
! %token	COMMITTED, SERIALIZABLE, TYPE_P
  
  /* Keywords for Postgres support (not in SQL92 reserved words)
   *
--- 345,351 ----
  		WITHOUT
  
  /* Keywords (in SQL92 non-reserved words) */
! %token	COMMITTED, SERIALIZABLE, TYPE_P, DOMAIN_P
  
  /* Keywords for Postgres support (not in SQL92 reserved words)
   *
***************
*** 446,451 ****
--- 448,454 ----
  		| CopyStmt
  		| CreateStmt
  		| CreateAsStmt
+ 		| CreateDomainStmt
  		| CreateSchemaStmt
  		| CreateGroupStmt
  		| CreateSeqStmt
***************
*** 776,783 ****
--- 779,789 ----
  					n->dbname = $3;
  					$$ = (Node *)n;
  				}
+ 		;
  
  
+  
+ 
  /*****************************************************************************
   *
   * Set PG internal variable
***************
*** 1461,1467 ****
  					n->name = NULL;
  					if (exprIsNullConstant($2))
  					{
! 						/* DEFAULT NULL should be reported as empty expr */
  						n->raw_expr = NULL;
  					}
  					else
--- 1467,1476 ----
  					n->name = NULL;
  					if (exprIsNullConstant($2))
  					{
! 						/*
! 						 * DEFAULT NULL should be reported as empty expr
! 						 * Required for NOT NULL Domain overrides
! 						 */
  						n->raw_expr = NULL;
  					}
  					else
***************
*** 2043,2055 ****
  		| def_list ',' def_elem				{ $$ = lappend($1, $3); }
  		;
  
! def_elem:  ColLabel '=' def_arg
  				{
  					$$ = makeNode(DefElem);
  					$$->defname = $1;
  					$$->arg = (Node *)$3;
  				}
! 		| ColLabel
  				{
  					$$ = makeNode(DefElem);
  					$$->defname = $1;
--- 2052,2073 ----
  		| def_list ',' def_elem				{ $$ = lappend($1, $3); }
  		;
  
! def_elem:  DEFAULT '=' b_expr
! 				{
! 					$$ = makeNode(DefElem);
! 					$$->defname = "default";
! 					if (exprIsNullConstant($3))
! 						$$->arg = (Node *)NULL;
! 					else
! 						$$->arg = $3;
! 				}
! 		| ColId '=' def_arg
  				{
  					$$ = makeNode(DefElem);
  					$$->defname = $1;
  					$$->arg = (Node *)$3;
  				}
! 		| ColId
  				{
  					$$ = makeNode(DefElem);
  					$$->defname = $1;
***************
*** 2078,2083 ****
--- 2096,2110 ----
  					DropStmt *n = makeNode(DropStmt);
  					n->removeType = $2;
  					n->names = $3;
+ 					n->behavior = RESTRICT;		/* Restricted by default */
+ 					$$ = (Node *)n;
+ 				}
+ 		| DROP DOMAIN_P name_list drop_behavior
+ 				{	
+ 					DropStmt *n = makeNode(DropStmt);
+ 					n->removeType = DROP_DOMAIN_P;
+ 					n->names = $3;
+ 					n->behavior = $4;
  					$$ = (Node *)n;
  				}
  		;
***************
*** 2110,2116 ****
   *  The COMMENT ON statement can take different forms based upon the type of
   *  the object associated with the comment. The form of the statement is:
   *
!  *  COMMENT ON [ [ DATABASE | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ] 
   *               <objname> | AGGREGATE <aggname> (<aggtype>) | FUNCTION 
   *		 <funcname> (arg1, arg2, ...) | OPERATOR <op> 
   *		 (leftoperand_typ rightoperand_typ) | TRIGGER <triggername> ON
--- 2137,2143 ----
   *  The COMMENT ON statement can take different forms based upon the type of
   *  the object associated with the comment. The form of the statement is:
   *
!  *  COMMENT ON [ [ DATABASE | DOMAIN | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ] 
   *               <objname> | AGGREGATE <aggname> (<aggtype>) | FUNCTION 
   *		 <funcname> (arg1, arg2, ...) | OPERATOR <op> 
   *		 (leftoperand_typ rightoperand_typ) | TRIGGER <triggername> ON
***************
*** 2196,2201 ****
--- 2223,2229 ----
  		| RULE { $$ = RULE; }
  		| SEQUENCE { $$ = SEQUENCE; }
  		| TABLE { $$ = TABLE; }
+ 		| DOMAIN_P { $$ = TYPE_P; }
  		| TYPE_P { $$ = TYPE_P; }
  		| VIEW { $$ = VIEW; }
  		;		
***************
*** 3178,3183 ****
--- 3206,3227 ----
  				{
  					$$ = lconsi(3, makeListi1(-1));
  				}
+ 		;
+ 
+ 
+ /*****************************************************************************
+  *
+  *		DROP DATABASE
+  *
+  *
+  *****************************************************************************/
+ 
+ DropdbStmt:	DROP DATABASE database_name
+ 				{
+ 					DropdbStmt *n = makeNode(DropdbStmt);
+ 					n->dbname = $3;
+ 					$$ = (Node *)n;
+ 				}
  		| OWNER opt_equal name 
  				{
  					$$ = lconsi(4, makeList1($3));
***************
*** 3222,3243 ****
  				}
  		;
  
- 
  /*****************************************************************************
   *
!  *		DROP DATABASE
   *
   *
   *****************************************************************************/
  
! DropdbStmt:	DROP DATABASE database_name
  				{
! 					DropdbStmt *n = makeNode(DropdbStmt);
! 					n->dbname = $3;
  					$$ = (Node *)n;
  				}
  		;
  
  
  /*****************************************************************************
   *
--- 3266,3295 ----
  				}
  		;
  
  /*****************************************************************************
   *
!  * Manipulate a domain
   *
   *
   *****************************************************************************/
  
! CreateDomainStmt:  CREATE DOMAIN_P name opt_as Typename ColQualList opt_collate
  				{
! 					CreateDomainStmt *n = makeNode(CreateDomainStmt);
! 					n->domainname = $3;
! 					n->typename = $5;
! 					n->constraints = $6;
! 					
! 					if ($7 != NULL)
! 						elog(NOTICE,"CREATE DOMAIN / COLLATE %s not yet "
! 							"implemented; clause ignored", $7);
  					$$ = (Node *)n;
  				}
  		;
  
+ opt_as:	AS	{$$ = TRUE; }
+ 	| /* EMPTY */	{$$ = FALSE; }
+ 	;
  
  /*****************************************************************************
   *
***************
*** 5879,5884 ****
--- 5931,5937 ----
  		| DEFERRED						{ $$ = "deferred"; }
  		| DELETE						{ $$ = "delete"; }
  		| DELIMITERS					{ $$ = "delimiters"; }
+ 		| DOMAIN_P						{ $$ = "domain"; }
  		| DOUBLE						{ $$ = "double"; }
  		| DROP							{ $$ = "drop"; }
  		| EACH							{ $$ = "each"; }
Index: src/backend/parser/keywords.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/keywords.c,v
retrieving revision 1.103
diff -c -r1.103 keywords.c
*** src/backend/parser/keywords.c	2002/03/07 16:35:35	1.103
--- src/backend/parser/keywords.c	2002/03/12 02:37:18
***************
*** 97,102 ****
--- 97,103 ----
  	{"desc", DESC},
  	{"distinct", DISTINCT},
  	{"do", DO},
+ 	{"domain", DOMAIN_P},
  	{"double", DOUBLE},
  	{"drop", DROP},
  	{"each", EACH},
Index: src/backend/parser/parse_coerce.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/parse_coerce.c,v
retrieving revision 2.66
diff -c -r2.66 parse_coerce.c
*** src/backend/parser/parse_coerce.c	2002/03/07 16:35:35	2.66
--- src/backend/parser/parse_coerce.c	2002/03/12 02:37:20
***************
*** 605,607 ****
--- 605,636 ----
  	}
  	return result;
  }	/* PreferredType() */
+ 
+ 
+ /*
+  * If the targetTypeId is a domain, we really want to coerce
+  * the tuple to the domain type -- not the domain itself
+  */
+ Oid
+ getBaseType(Oid inType)
+ {
+ 	HeapTuple	tup;
+ 	Form_pg_type typTup;
+ 
+ 	tup = SearchSysCache(TYPEOID,
+ 						 ObjectIdGetDatum(inType),
+ 						 0, 0, 0);
+ 
+ 	typTup = ((Form_pg_type) GETSTRUCT(tup));
+ 
+ 	/*
+ 	 * Assume that typbasetype exists and is a base type, where inType
+ 	 * was a domain
+ 	 */
+ 	if (typTup->typtype == 'd')
+ 		inType = typTup->typbasetype;
+ 
+ 	ReleaseSysCache(tup);
+ 
+ 	return inType;
+ }
Index: src/backend/parser/parse_expr.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/parse_expr.c,v
retrieving revision 1.107
diff -c -r1.107 parse_expr.c
*** src/backend/parser/parse_expr.c	2002/03/07 16:35:36	1.107
--- src/backend/parser/parse_expr.c	2002/03/12 02:37:20
***************
*** 1027,1033 ****
  	if (inputType != targetType)
  	{
  		expr = CoerceTargetExpr(pstate, expr, inputType,
! 								targetType, typename->typmod);
  		if (expr == NULL)
  			elog(ERROR, "Cannot cast type '%s' to '%s'",
  				 format_type_be(inputType),
--- 1027,1034 ----
  	if (inputType != targetType)
  	{
  		expr = CoerceTargetExpr(pstate, expr, inputType,
! 								getBaseType(targetType),
! 								typename->typmod);
  		if (expr == NULL)
  			elog(ERROR, "Cannot cast type '%s' to '%s'",
  				 format_type_be(inputType),
***************
*** 1039,1045 ****
  	 * as well as a type coercion.
  	 */
  	expr = coerce_type_typmod(pstate, expr,
! 							  targetType, typename->typmod);
  
  	return expr;
  }
--- 1040,1046 ----
  	 * as well as a type coercion.
  	 */
  	expr = coerce_type_typmod(pstate, expr,
! 							  getBaseType(targetType), typename->typmod);
  
  	return expr;
  }
Index: src/backend/tcop/postgres.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/tcop/postgres.c,v
retrieving revision 1.254
diff -c -r1.254 postgres.c
*** src/backend/tcop/postgres.c	2002/03/06 06:10:09	1.254
--- src/backend/tcop/postgres.c	2002/03/12 02:38:04
***************
*** 2212,2219 ****
  			}
  			break;
  
  		case T_CreateStmt:
! 			tag = "CREATE";
  			break;
  
  		case T_DropStmt:
--- 2212,2220 ----
  			}
  			break;
  
+ 		case T_CreateDomainStmt:
  		case T_CreateStmt:
! 			tag = "CREATE DOMAIN";
  			break;
  
  		case T_DropStmt:
Index: src/backend/tcop/utility.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/tcop/utility.c,v
retrieving revision 1.132
diff -c -r1.132 utility.c
*** src/backend/tcop/utility.c	2002/03/07 16:35:36	1.132
--- src/backend/tcop/utility.c	2002/03/12 02:38:05
***************
*** 282,287 ****
--- 282,292 ----
  							/* RemoveType does its own permissions checks */
  							RemoveType(relname);
  							break;
+ 
+ 						case DROP_DOMAIN_P:
+ 							/* RemoveDomain does its own permissions checks */
+ 							RemoveDomain(relname, stmt->behavior);
+ 							break;
  					}
  
  					/*
***************
*** 725,730 ****
--- 730,748 ----
  		case T_DropPLangStmt:
  			DropProceduralLanguage((DropPLangStmt *) parsetree);
  			break;
+ 
+ 			/*
+ 			 * ******************************** DOMAIN statements ****
+ 			 *
+ 			 */
+ 		case T_CreateDomainStmt:
+ 			DefineDomain((CreateDomainStmt *) parsetree);
+ 			break;
+ 
+ 			/*
+ 			 * ******************************** USER statements ****
+ 			 *
+ 			 */
  
  		case T_CreateUserStmt:
  			CreateUser((CreateUserStmt *) parsetree);
Index: src/backend/utils/adt/format_type.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/format_type.c,v
retrieving revision 1.26
diff -c -r1.26 format_type.c
*** src/backend/utils/adt/format_type.c	2002/03/07 16:35:36	1.26
--- src/backend/utils/adt/format_type.c	2002/03/12 02:38:10
***************
*** 126,131 ****
--- 126,132 ----
  	bool		is_array;
  	char	   *name;
  	char	   *buf;
+ 	char		typtype;
  
  	if (type_oid == InvalidOid && allow_invalid)
  		return pstrdup("-");
***************
*** 144,149 ****
--- 145,175 ----
  
  	array_base_type = ((Form_pg_type) GETSTRUCT(tuple))->typelem;
  	typlen = ((Form_pg_type) GETSTRUCT(tuple))->typlen;
+ 	typtype = ((Form_pg_type) GETSTRUCT(tuple))->typtype;
+ 
+ 	/*
+ 	 * Domains look alot like arrays, so lets process them first, and return
+ 	 * back to avoid the array and 'standard' formatting procedures that are
+ 	 * use for base types.
+ 	 */
+ 	if (typtype == 'd') {
+ 		name = NameStr(((Form_pg_type) GETSTRUCT(tuple))->typname);
+ 
+ 		/*
+ 		 * Double-quote the name if it's not a standard identifier.
+ 		 * Note this is *necessary* for ruleutils.c's use.
+ 		 */
+ 		if (strspn(name, "abcdefghijklmnopqrstuvwxyz0123456789_") != strlen(name)
+ 			|| isdigit((unsigned char) name[0]))
+ 				buf = psnprintf(strlen(name) + 3, "\"%s\"", name);
+ 		else
+ 			buf = pstrdup(name);
+ 
+ 		ReleaseSysCache(tuple);
+ 
+ 		return buf;
+ 	}
+ 
  	if (array_base_type != InvalidOid && typlen < 0)
  	{
  		/* Switch our attention to the array element type */
Index: src/backend/utils/cache/lsyscache.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v
retrieving revision 1.62
diff -c -r1.62 lsyscache.c
*** src/backend/utils/cache/lsyscache.c	2002/03/07 16:35:36	1.62
--- src/backend/utils/cache/lsyscache.c	2002/03/12 02:38:25
***************
*** 23,28 ****
--- 23,29 ----
  #include "catalog/pg_shadow.h"
  #include "catalog/pg_statistic.h"
  #include "catalog/pg_type.h"
+ #include "parser/parse_coerce.h"
  #include "utils/array.h"
  #include "utils/builtins.h"
  #include "utils/lsyscache.h"
***************
*** 822,837 ****
   *	  Returns FALSE if there is no default (effectively, default is NULL).
   *	  The result points to palloc'd storage for pass-by-reference types.
   */
! bool
! get_typdefault(Oid typid, Datum *defaultValue)
  {
  	HeapTuple	typeTuple;
  	Form_pg_type type;
! 	Oid			typinput,
! 				typelem;
! 	Datum		textDefaultVal;
  	bool		isNull;
! 	char	   *strDefaultVal;
  
  	typeTuple = SearchSysCache(TYPEOID,
  							   ObjectIdGetDatum(typid),
--- 823,839 ----
   *	  Returns FALSE if there is no default (effectively, default is NULL).
   *	  The result points to palloc'd storage for pass-by-reference types.
   */
! Node *
! get_typdefault(Oid typid, int32 atttypmod)
  {
  	HeapTuple	typeTuple;
  	Form_pg_type type;
! 	Oid			typinput;
! 	Oid			typbasetype;
! 	char		typtype;
! 	Datum		datum;
  	bool		isNull;
! 	Node	   *expr;
  
  	typeTuple = SearchSysCache(TYPEOID,
  							   ObjectIdGetDatum(typid),
***************
*** 843,880 ****
  	type = (Form_pg_type) GETSTRUCT(typeTuple);
  
  	typinput = type->typinput;
! 	typelem = type->typelem;
  
  	/*
! 	 * typdefault is potentially null, so don't try to access it as a
  	 * struct field. Must do it the hard way with SysCacheGetAttr.
  	 */
! 	textDefaultVal = SysCacheGetAttr(TYPEOID,
! 									 typeTuple,
! 									 Anum_pg_type_typdefault,
! 									 &isNull);
  
  	if (isNull)
! 	{
! 		ReleaseSysCache(typeTuple);
! 		*defaultValue = (Datum) 0;
! 		return false;
! 	}
  
! 	/* Convert text datum to C string */
! 	strDefaultVal = DatumGetCString(DirectFunctionCall1(textout,
! 														textDefaultVal));
! 
! 	/* Convert C string to a value of the given type */
! 	*defaultValue = OidFunctionCall3(typinput,
! 									 CStringGetDatum(strDefaultVal),
! 									 ObjectIdGetDatum(typelem),
! 									 Int32GetDatum(-1));
  
! 	pfree(strDefaultVal);
! 	ReleaseSysCache(typeTuple);
  
! 	return true;
  }
  
  /*
--- 845,885 ----
  	type = (Form_pg_type) GETSTRUCT(typeTuple);
  
  	typinput = type->typinput;
! 	typbasetype = type->typbasetype;
! 	typtype = type->typtype;
  
  	/*
! 	 * typdefaultbin is potentially null, so don't try to access it as a
  	 * struct field. Must do it the hard way with SysCacheGetAttr.
  	 */
! 	datum = SysCacheGetAttr(TYPEOID,
! 							typeTuple,
! 							Anum_pg_type_typdefaultbin,
! 							&isNull);
  
+ 	ReleaseSysCache(typeTuple);
  	if (isNull)
! 		return (Node *) NULL;
  
! 	/* Convert Datum to a Node */
! 	expr = stringToNode(DatumGetCString(
! 						DirectFunctionCall1(textout, datum)));
  
! 
! 	/*
! 	 * Ensure we goto the basetype before the domain type.
! 	 *
! 	 * Prevents scenarios like the below from failing:
! 	 * CREATE DOMAIN dom text DEFAULT random();
! 	 *
! 	 */
! 	if (typbasetype != InvalidOid) {
! 		expr = coerce_type(NULL, expr, typid,
! 						  typbasetype, atttypmod);
! 	}
! 
  
! 	return expr;
  }
  
  /*
Index: src/backend/utils/cache/relcache.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/cache/relcache.c,v
retrieving revision 1.156
diff -c -r1.156 relcache.c
*** src/backend/utils/cache/relcache.c	2002/03/07 16:35:36	1.156
--- src/backend/utils/cache/relcache.c	2002/03/12 02:38:27
***************
*** 512,519 ****
  			   (char *) attp,
  			   ATTRIBUTE_TUPLE_SIZE);
  
! 		/* Update constraint/default info */
! 		if (attp->attnotnull)
  			constr->has_not_null = true;
  
  		if (attp->atthasdef)
--- 512,523 ----
  			   (char *) attp,
  			   ATTRIBUTE_TUPLE_SIZE);
  
! 
! 
! 		/*
! 		 * Update constraint/default info
! 		 */
!        if (attp->attnotnull)
  			constr->has_not_null = true;
  
  		if (attp->atthasdef)
Index: src/include/catalog/heap.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/heap.h,v
retrieving revision 1.43
diff -c -r1.43 heap.h
*** src/include/catalog/heap.h	2002/03/07 16:35:38	1.43
--- src/include/catalog/heap.h	2002/03/12 02:41:03
***************
*** 15,20 ****
--- 15,22 ----
  #define HEAP_H
  
  #include "catalog/pg_attribute.h"
+ #include "nodes/parsenodes.h"
+ #include "parser/parse_node.h"
  #include "utils/rel.h"
  
  typedef struct RawColumnDefault
***************
*** 44,49 ****
--- 46,57 ----
  extern void AddRelationRawConstraints(Relation rel,
  						  List *rawColDefaults,
  						  List *rawConstraints);
+ 
+ extern Node *cookDefault(ParseState *pstate
+ 						, Node *raw_default
+ 						, Oid atttypid
+ 						, int32 atttypmod
+ 						, char *attname);
  
  extern int	RemoveCheckConstraint(Relation rel, const char *constrName, bool inh);
  
Index: src/include/catalog/pg_attribute.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_attribute.h,v
retrieving revision 1.83
diff -c -r1.83 pg_attribute.h
*** src/include/catalog/pg_attribute.h	2002/03/07 16:35:38	1.83
--- src/include/catalog/pg_attribute.h	2002/03/12 02:41:04
***************
*** 240,247 ****
  { 1247, {"typsend"},	   24, 0,	4, 14, 0, -1, -1, true, 'p', false, 'i', false, false }, \
  { 1247, {"typalign"},	   18, 0,	1, 15, 0, -1, -1, true, 'p', false, 'c', false, false }, \
  { 1247, {"typstorage"},    18, 0,	1, 16, 0, -1, -1, true, 'p', false, 'c', false, false }, \
! { 1247, {"typdefault"},    25, 0,  -1, 17, 0, -1, -1, false , 'x', false, 'i', false, false }
  
  DATA(insert ( 1247 typname			19 DEFAULT_ATTSTATTARGET NAMEDATALEN   1 0 -1 -1 f p f i f f));
  DATA(insert ( 1247 typowner			23 0  4   2 0 -1 -1 t p f i f f));
  DATA(insert ( 1247 typlen			21 0  2   3 0 -1 -1 t p f s f f));
--- 240,253 ----
  { 1247, {"typsend"},	   24, 0,	4, 14, 0, -1, -1, true, 'p', false, 'i', false, false }, \
  { 1247, {"typalign"},	   18, 0,	1, 15, 0, -1, -1, true, 'p', false, 'c', false, false }, \
  { 1247, {"typstorage"},    18, 0,	1, 16, 0, -1, -1, true, 'p', false, 'c', false, false }, \
! { 1247, {"typnotnull"},    16, 0,   1, 17, 0, -1, -1, true, 'p', false, 'c', false, false }, \
! { 1247, {"typmod"},        23, 0,	4, 18, 0, -1, -1, true, 'p', false, 'i', false, false }, \
! { 1247, {"typbasetype"},   26, 0,	4, 19, 0, -1, -1, true, 'p', false, 'i', false, false }, \
! { 1247, {"typndims"},      23, 0,	4, 20, 0, -1, -1, true, 'p', false, 'i', false, false }, \
! { 1247, {"typdefaultbin"}, 25, 0,  -1, 21, 0, -1, -1, false, 'x', false, 'i', false, false }, \
! { 1247, {"typdefault"},    25, 0,  -1, 22, 0, -1, -1, false, 'x', false, 'i', false, false }
  
+ 
  DATA(insert ( 1247 typname			19 DEFAULT_ATTSTATTARGET NAMEDATALEN   1 0 -1 -1 f p f i f f));
  DATA(insert ( 1247 typowner			23 0  4   2 0 -1 -1 t p f i f f));
  DATA(insert ( 1247 typlen			21 0  2   3 0 -1 -1 t p f s f f));
***************
*** 258,264 ****
  DATA(insert ( 1247 typsend			24 0  4  14 0 -1 -1 t p f i f f));
  DATA(insert ( 1247 typalign			18 0  1  15 0 -1 -1 t p f c f f));
  DATA(insert ( 1247 typstorage		18 0  1  16 0 -1 -1 t p f c f f));
! DATA(insert ( 1247 typdefault		25 0 -1  17 0 -1 -1 f x f i f f));
  DATA(insert ( 1247 ctid				27 0  6  -1 0 -1 -1 f p f i f f));
  DATA(insert ( 1247 oid				26 0  4  -2 0 -1 -1 t p f i f f));
  DATA(insert ( 1247 xmin				28 0  4  -3 0 -1 -1 t p f i f f));
--- 264,275 ----
  DATA(insert ( 1247 typsend			24 0  4  14 0 -1 -1 t p f i f f));
  DATA(insert ( 1247 typalign			18 0  1  15 0 -1 -1 t p f c f f));
  DATA(insert ( 1247 typstorage		18 0  1  16 0 -1 -1 t p f c f f));
! DATA(insert ( 1247 typnotnull		16 0  1  17 0 -1 -1 t p f c f f));
! DATA(insert ( 1247 typmod			23 0  4  18 0 -1 -1 t p f i f f));
! DATA(insert ( 1247 typbasetype		26 0  4  19 0 -1 -1 t p f i f f));
! DATA(insert ( 1247 typndims			23 0  4  20 0 -1 -1 t p f i f f));
! DATA(insert ( 1247 typdefaultbin	25 0 -1  21 0 -1 -1 f x f i f f));
! DATA(insert ( 1247 typdefault		25 0 -1  22 0 -1 -1 f x f i f f));
  DATA(insert ( 1247 ctid				27 0  6  -1 0 -1 -1 f p f i f f));
  DATA(insert ( 1247 oid				26 0  4  -2 0 -1 -1 t p f i f f));
  DATA(insert ( 1247 xmin				28 0  4  -3 0 -1 -1 t p f i f f));
Index: src/include/catalog/pg_class.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_class.h,v
retrieving revision 1.61
diff -c -r1.61 pg_class.h
*** src/include/catalog/pg_class.h	2002/03/07 16:35:38	1.61
--- src/include/catalog/pg_class.h	2002/03/12 02:41:04
***************
*** 132,138 ****
   * ----------------
   */
  
! DATA(insert OID = 1247 (  pg_type		71	PGUID 0 1247 0 0 0 0 f f r 17 0 0 0 0 0 t f f f _null_ ));
  DESCR("");
  DATA(insert OID = 1249 (  pg_attribute	75	PGUID 0 1249 0 0 0 0 f f r 15 0 0 0 0 0 f f f f _null_ ));
  DESCR("");
--- 132,138 ----
   * ----------------
   */
  
! DATA(insert OID = 1247 (  pg_type		71	PGUID 0 1247 0 0 0 0 f f r 22 0 0 0 0 0 t f f f _null_ ));
  DESCR("");
  DATA(insert OID = 1249 (  pg_attribute	75	PGUID 0 1249 0 0 0 0 f f r 15 0 0 0 0 0 f f f f _null_ ));
  DESCR("");
Index: src/include/catalog/pg_type.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_type.h,v
retrieving revision 1.116
diff -c -r1.116 pg_type.h
*** src/include/catalog/pg_type.h	2002/03/07 16:35:38	1.116
--- src/include/catalog/pg_type.h	2002/03/12 02:41:08
***************
*** 141,152 ****
  	char		typstorage;
  
  	/*
  	 * typdefault is NULL if the type has no associated default value. If
  	 * it's not NULL, it contains the external representation of the
! 	 * type's default value --- this default is used whenever no
! 	 * per-column default is specified for a column of the datatype.
  	 */
  	text		typdefault;		/* VARIABLE LENGTH FIELD */
  } FormData_pg_type;
  
  /* ----------------
--- 141,189 ----
  	char		typstorage;
  
  	/*
+ 	 * This flag represents a "NOT NULL" constraint against this datatype.
+ 	 *
+ 	 * If true, the attnotnull column for a corresponding table column using
+ 	 * this datatype will always enforce the NOT NULL constraint.
+ 	 *
+ 	 * Used primarily for domain types.
+ 	 */
+ 	bool		typnotnull;
+ 
+ 	/*
+ 	 * typmod records type-specific data supplied at domain creation
+ 	 * time (for example, the max length of a varchar field).  It is
+ 	 * passed to type-specific input and output functions as the third
+ 	 * argument. The value will generally be -1 for types that do not need
+ 	 * typmod.  This value is copied to pg_attribute.atttypmod.
+ 	 */
+ 	int4		typmod;
+ 
+ 	/*
+ 	 * Domains use typbasetype to determine the base (or complex)type that
+ 	 * the domain is based off.  It must be non-zero if the type is a
+ 	 * domain.
+ 	 */
+ 	Oid			typbasetype;
+ 
+ 	/*
+ 	 * typndims is the declared number of dimensions, if an array typbasetype,
+ 	 * otherwise zero.
+ 	 */
+ 	int4		typndims;
+ 
+ 	/*
+ 	 * typdefaultbin is the binary representation of typdefault
+ 	 */
+ 	text		typdefaultbin;	/* VARIABLE LENGTH FIELD */
+ 
+ 	/*
  	 * typdefault is NULL if the type has no associated default value. If
  	 * it's not NULL, it contains the external representation of the
! 	 * type's default value
  	 */
  	text		typdefault;		/* VARIABLE LENGTH FIELD */
+ 
  } FormData_pg_type;
  
  /* ----------------
***************
*** 160,166 ****
   *		compiler constants for pg_type
   * ----------------
   */
! #define Natts_pg_type					17
  #define Anum_pg_type_typname			1
  #define Anum_pg_type_typowner			2
  #define Anum_pg_type_typlen				3
--- 197,203 ----
   *		compiler constants for pg_type
   * ----------------
   */
! #define Natts_pg_type					22
  #define Anum_pg_type_typname			1
  #define Anum_pg_type_typowner			2
  #define Anum_pg_type_typlen				3
***************
*** 177,183 ****
  #define Anum_pg_type_typsend			14
  #define Anum_pg_type_typalign			15
  #define Anum_pg_type_typstorage			16
! #define Anum_pg_type_typdefault			17
  
  /* ----------------
   *		initial contents of pg_type
--- 214,226 ----
  #define Anum_pg_type_typsend			14
  #define Anum_pg_type_typalign			15
  #define Anum_pg_type_typstorage			16
! #define Anum_pg_type_typnotnull			17
! #define Anum_pg_type_typmod				18
! #define Anum_pg_type_typbasetype		19
! #define Anum_pg_type_typndims			20
! #define Anum_pg_type_typdefaultbin		21
! #define Anum_pg_type_typdefault			22
! 
  
  /* ----------------
   *		initial contents of pg_type
***************
*** 192,273 ****
  */
  
  /* OIDS 1 - 99 */
! DATA(insert OID = 16 (	bool	   PGUID  1   1 t b t \054 0   0 boolin boolout boolin boolout c p _null_ ));
  DESCR("boolean, 'true'/'false'");
  #define BOOLOID			16
  
! DATA(insert OID = 17 (	bytea	   PGUID -1  -1 f b t \054 0  0 byteain byteaout byteain byteaout i x _null_ ));
  DESCR("variable-length string, binary values escaped");
  #define BYTEAOID		17
  
! DATA(insert OID = 18 (	char	   PGUID  1   1 t b t \054 0   0 charin charout charin charout c p _null_ ));
  DESCR("single character");
  #define CHAROID			18
  
! DATA(insert OID = 19 (	name	   PGUID NAMEDATALEN NAMEDATALEN  f b t \054 0	18 namein nameout namein nameout i p _null_ ));
  DESCR("31-character type for storing system identifiers");
  #define NAMEOID			19
  
! DATA(insert OID = 20 (	int8	   PGUID  8  20 f b t \054 0   0 int8in int8out int8in int8out d p _null_ ));
  DESCR("~18 digit integer, 8-byte storage");
  #define INT8OID			20
  
! DATA(insert OID = 21 (	int2	   PGUID  2   5 t b t \054 0   0 int2in int2out int2in int2out s p _null_ ));
  DESCR("-32 thousand to 32 thousand, 2-byte storage");
  #define INT2OID			21
  
! DATA(insert OID = 22 (	int2vector PGUID INDEX_MAX_KEYS*2 -1 f b t \054 0  21 int2vectorin int2vectorout int2vectorin int2vectorout i p _null_ ));
  DESCR("array of INDEX_MAX_KEYS int2 integers, used in system tables");
  #define INT2VECTOROID	22
  
! DATA(insert OID = 23 (	int4	   PGUID  4  10 t b t \054 0   0 int4in int4out int4in int4out i p _null_ ));
  DESCR("-2 billion to 2 billion integer, 4-byte storage");
  #define INT4OID			23
  
! DATA(insert OID = 24 (	regproc    PGUID  4  16 t b t \054 0   0 regprocin regprocout regprocin regprocout i p _null_ ));
  DESCR("registered procedure");
  #define REGPROCOID		24
  
! DATA(insert OID = 25 (	text	   PGUID -1  -1 f b t \054 0  0 textin textout textin textout i x _null_ ));
  DESCR("variable-length string, no limit specified");
  #define TEXTOID			25
  
! DATA(insert OID = 26 (	oid		   PGUID  4  10 t b t \054 0   0 oidin oidout oidin oidout i p _null_ ));
  DESCR("object identifier(oid), maximum 4 billion");
  #define OIDOID			26
  
! DATA(insert OID = 27 (	tid		   PGUID  6  19 f b t \054 0   0 tidin tidout tidin tidout i p _null_ ));
  DESCR("(Block, offset), physical location of tuple");
  #define TIDOID		27
  
! DATA(insert OID = 28 (	xid		   PGUID  4  12 t b t \054 0   0 xidin xidout xidin xidout i p _null_ ));
  DESCR("transaction id");
  #define XIDOID 28
  
! DATA(insert OID = 29 (	cid		   PGUID  4  10 t b t \054 0   0 cidin cidout cidin cidout i p _null_ ));
  DESCR("command identifier type, sequence in transaction id");
  #define CIDOID 29
  
! DATA(insert OID = 30 (	oidvector  PGUID INDEX_MAX_KEYS*4 -1 f b t \054 0  26 oidvectorin oidvectorout oidvectorin oidvectorout i p _null_ ));
  DESCR("array of INDEX_MAX_KEYS oids, used in system tables");
  #define OIDVECTOROID	30
  
! DATA(insert OID = 32 (	SET		   PGUID -1  -1 f b t \054 0   0 textin textout textin textout i p _null_ ));
  DESCR("set of tuples");
  
! DATA(insert OID = 71 (	pg_type		 PGUID 4 4 t c t \054 1247 0 int4in int4out int4in int4out i p _null_));
! DATA(insert OID = 75 (	pg_attribute PGUID 4 4 t c t \054 1249 0 int4in int4out int4in int4out i p _null_));
! DATA(insert OID = 81 (	pg_proc		 PGUID 4 4 t c t \054 1255 0 int4in int4out int4in int4out i p _null_));
! DATA(insert OID = 83 (	pg_class	 PGUID 4 4 t c t \054 1259 0 int4in int4out int4in int4out i p _null_));
! DATA(insert OID = 86 (	pg_shadow	 PGUID 4 4 t c t \054 1260 0 int4in int4out int4in int4out i p _null_));
! DATA(insert OID = 87 (	pg_group	 PGUID 4 4 t c t \054 1261 0 int4in int4out int4in int4out i p _null_));
! DATA(insert OID = 88 (	pg_database  PGUID 4 4 t c t \054 1262 0 int4in int4out int4in int4out i p _null_));
  
  /* OIDS 100 - 199 */
  
  /* OIDS 200 - 299 */
  
! DATA(insert OID = 210 (  smgr	   PGUID 2	12 t b t \054 0 0 smgrin smgrout smgrin smgrout s p _null_ ));
  DESCR("storage manager");
  
  /* OIDS 300 - 399 */
--- 235,316 ----
  */
  
  /* OIDS 1 - 99 */
! DATA(insert OID = 16 (	bool	   PGUID  1   1 t b t \054 0   0 boolin boolout boolin boolout c p f -1 0 0 _null_ _null_ ));
  DESCR("boolean, 'true'/'false'");
  #define BOOLOID			16
  
! DATA(insert OID = 17 (	bytea	   PGUID -1  -1 f b t \054 0  0 byteain byteaout byteain byteaout i x f -1 0 0 _null_ _null_ ));
  DESCR("variable-length string, binary values escaped");
  #define BYTEAOID		17
  
! DATA(insert OID = 18 (	char	   PGUID  1   1 t b t \054 0   0 charin charout charin charout c p f -1 0 0 _null_ _null_ ));
  DESCR("single character");
  #define CHAROID			18
  
! DATA(insert OID = 19 (	name	   PGUID NAMEDATALEN NAMEDATALEN  f b t \054 0	18 namein nameout namein nameout i p f -1 0 0 _null_ _null_ ));
  DESCR("31-character type for storing system identifiers");
  #define NAMEOID			19
  
! DATA(insert OID = 20 (	int8	   PGUID  8  20 f b t \054 0   0 int8in int8out int8in int8out d p f -1 0 0 _null_ _null_ ));
  DESCR("~18 digit integer, 8-byte storage");
  #define INT8OID			20
  
! DATA(insert OID = 21 (	int2	   PGUID  2   5 t b t \054 0   0 int2in int2out int2in int2out s p f -1 0 0 _null_ _null_ ));
  DESCR("-32 thousand to 32 thousand, 2-byte storage");
  #define INT2OID			21
  
! DATA(insert OID = 22 (	int2vector PGUID INDEX_MAX_KEYS*2 -1 f b t \054 0  21 int2vectorin int2vectorout int2vectorin int2vectorout i p f -1 0 0 _null_ _null_ ));
  DESCR("array of INDEX_MAX_KEYS int2 integers, used in system tables");
  #define INT2VECTOROID	22
  
! DATA(insert OID = 23 (	int4	   PGUID  4  10 t b t \054 0   0 int4in int4out int4in int4out i p f -1 0 0 _null_ _null_ ));
  DESCR("-2 billion to 2 billion integer, 4-byte storage");
  #define INT4OID			23
  
! DATA(insert OID = 24 (	regproc    PGUID  4  16 t b t \054 0   0 regprocin regprocout regprocin regprocout i p f -1 0 0 _null_ _null_ ));
  DESCR("registered procedure");
  #define REGPROCOID		24
  
! DATA(insert OID = 25 (	text	   PGUID -1  -1 f b t \054 0  0 textin textout textin textout i x f -1 0 0 _null_ _null_ ));
  DESCR("variable-length string, no limit specified");
  #define TEXTOID			25
  
! DATA(insert OID = 26 (	oid		   PGUID  4  10 t b t \054 0   0 oidin oidout oidin oidout i p f -1 0 0 _null_ _null_ ));
  DESCR("object identifier(oid), maximum 4 billion");
  #define OIDOID			26
  
! DATA(insert OID = 27 (	tid		   PGUID  6  19 f b t \054 0   0 tidin tidout tidin tidout i p f -1 0 0 _null_ _null_ ));
  DESCR("(Block, offset), physical location of tuple");
  #define TIDOID		27
  
! DATA(insert OID = 28 (	xid		   PGUID  4  12 t b t \054 0   0 xidin xidout xidin xidout i p f -1 0 0 _null_ _null_ ));
  DESCR("transaction id");
  #define XIDOID 28
  
! DATA(insert OID = 29 (	cid		   PGUID  4  10 t b t \054 0   0 cidin cidout cidin cidout i p f -1 0 0 _null_ _null_ ));
  DESCR("command identifier type, sequence in transaction id");
  #define CIDOID 29
  
! DATA(insert OID = 30 (	oidvector  PGUID INDEX_MAX_KEYS*4 -1 f b t \054 0  26 oidvectorin oidvectorout oidvectorin oidvectorout i p f -1 0 0 _null_ _null_ ));
  DESCR("array of INDEX_MAX_KEYS oids, used in system tables");
  #define OIDVECTOROID	30
  
! DATA(insert OID = 32 (	SET		   PGUID -1  -1 f b t \054 0   0 textin textout textin textout i p f -1 0 0 _null_ _null_ ));
  DESCR("set of tuples");
  
! DATA(insert OID = 71 (	pg_type		 PGUID 4 4 t c t \054 1247 0 int4in int4out int4in int4out i p f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 75 (	pg_attribute PGUID 4 4 t c t \054 1249 0 int4in int4out int4in int4out i p f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 81 (	pg_proc		 PGUID 4 4 t c t \054 1255 0 int4in int4out int4in int4out i p f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 83 (	pg_class	 PGUID 4 4 t c t \054 1259 0 int4in int4out int4in int4out i p f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 86 (	pg_shadow	 PGUID 4 4 t c t \054 1260 0 int4in int4out int4in int4out i p f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 87 (	pg_group	 PGUID 4 4 t c t \054 1261 0 int4in int4out int4in int4out i p f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 88 (	pg_database  PGUID 4 4 t c t \054 1262 0 int4in int4out int4in int4out i p f -1 0 0 _null_ _null_ ));
  
  /* OIDS 100 - 199 */
  
  /* OIDS 200 - 299 */
  
! DATA(insert OID = 210 (  smgr	   PGUID 2	12 t b t \054 0 0 smgrin smgrout smgrin smgrout s p f -1 0 0 _null_ _null_ ));
  DESCR("storage manager");
  
  /* OIDS 300 - 399 */
***************
*** 277,443 ****
  /* OIDS 500 - 599 */
  
  /* OIDS 600 - 699 */
! DATA(insert OID = 600 (  point	   PGUID 16  24 f b t \054 0 701 point_in point_out point_in point_out d p _null_ ));
  DESCR("geometric point '(x, y)'");
  #define POINTOID		600
! DATA(insert OID = 601 (  lseg	   PGUID 32  48 f b t \054 0 600 lseg_in lseg_out lseg_in lseg_out d p _null_ ));
  DESCR("geometric line segment '(pt1,pt2)'");
  #define LSEGOID			601
! DATA(insert OID = 602 (  path	   PGUID -1  -1 f b t \054 0 0 path_in path_out path_in path_out d x _null_ ));
  DESCR("geometric path '(pt1,...)'");
  #define PATHOID			602
! DATA(insert OID = 603 (  box	   PGUID 32 100 f b t \073 0 600 box_in box_out box_in box_out d p _null_ ));
  DESCR("geometric box '(lower left,upper right)'");
  #define BOXOID			603
! DATA(insert OID = 604 (  polygon   PGUID -1  -1 f b t \054 0   0 poly_in poly_out poly_in poly_out d x _null_ ));
  DESCR("geometric polygon '(pt1,...)'");
  #define POLYGONOID		604
  
! DATA(insert OID = 628 (  line	   PGUID 32  48 f b t \054 0 701 line_in line_out line_in line_out d p _null_ ));
  DESCR("geometric line '(pt1,pt2)'");
  #define LINEOID			628
! DATA(insert OID = 629 (  _line	   PGUID  -1 -1 f b t \054 0 628 array_in array_out array_in array_out d x _null_ ));
  DESCR("");
  
  /* OIDS 700 - 799 */
  
! DATA(insert OID = 700 (  float4    PGUID  4  12 f b t \054 0   0 float4in float4out float4in float4out i p _null_ ));
  DESCR("single-precision floating point number, 4-byte storage");
  #define FLOAT4OID 700
! DATA(insert OID = 701 (  float8    PGUID  8  24 f b t \054 0   0 float8in float8out float8in float8out d p _null_ ));
  DESCR("double-precision floating point number, 8-byte storage");
  #define FLOAT8OID 701
! DATA(insert OID = 702 (  abstime   PGUID  4  20 t b t \054 0   0 nabstimein nabstimeout nabstimein nabstimeout i p _null_ ));
  DESCR("absolute, limited-range date and time (Unix system time)");
  #define ABSTIMEOID		702
! DATA(insert OID = 703 (  reltime   PGUID  4  20 t b t \054 0   0 reltimein reltimeout reltimein reltimeout i p _null_ ));
  DESCR("relative, limited-range time interval (Unix delta time)");
  #define RELTIMEOID		703
! DATA(insert OID = 704 (  tinterval PGUID 12  47 f b t \054 0   0 tintervalin tintervalout tintervalin tintervalout i p _null_ ));
  DESCR("(abstime,abstime), time interval");
  #define TINTERVALOID	704
! DATA(insert OID = 705 (  unknown   PGUID -1  -1 f b t \054 0   0 textin textout textin textout i p _null_ ));
  DESCR("");
  #define UNKNOWNOID		705
  
! DATA(insert OID = 718 (  circle    PGUID  24 47 f b t \054 0	0 circle_in circle_out circle_in circle_out d p _null_ ));
  DESCR("geometric circle '(center,radius)'");
  #define CIRCLEOID		718
! DATA(insert OID = 719 (  _circle   PGUID  -1 -1 f b t \054 0  718 array_in array_out array_in array_out d x _null_ ));
! DATA(insert OID = 790 (  money	   PGUID   4 24 f b t \054 0	0 cash_in cash_out cash_in cash_out i p _null_ ));
  DESCR("$d,ddd.cc, money");
  #define CASHOID 790
! DATA(insert OID = 791 (  _money    PGUID  -1 -1 f b t \054 0  790 array_in array_out array_in array_out i x _null_ ));
  
  /* OIDS 800 - 899 */
! DATA(insert OID = 829 ( macaddr    PGUID  6 -1 f b t \054 0 0 macaddr_in macaddr_out macaddr_in macaddr_out i p _null_ ));
  DESCR("XX:XX:XX:XX:XX:XX, MAC address");
  #define MACADDROID 829
! DATA(insert OID = 869 ( inet	   PGUID  -1 -1 f b t \054 0 0 inet_in inet_out inet_in inet_out i p _null_ ));
  DESCR("IP address/netmask, host address, netmask optional");
  #define INETOID 869
! DATA(insert OID = 650 ( cidr	   PGUID  -1 -1 f b t \054 0 0 cidr_in cidr_out cidr_in cidr_out i p _null_ ));
  DESCR("network IP address/netmask, network address");
  #define CIDROID 650
  
  /* OIDS 900 - 999 */
  
  /* OIDS 1000 - 1099 */
! DATA(insert OID = 1000 (  _bool		 PGUID -1  -1 f b t \054 0	16 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1001 (  _bytea	 PGUID -1  -1 f b t \054 0	17 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1002 (  _char		 PGUID -1  -1 f b t \054 0	18 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1003 (  _name		 PGUID -1  -1 f b t \054 0	19 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1005 (  _int2		 PGUID -1  -1 f b t \054 0	21 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1006 (  _int2vector PGUID -1 -1 f b t \054 0	22 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1007 (  _int4		 PGUID -1  -1 f b t \054 0	23 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1008 (  _regproc	 PGUID -1  -1 f b t \054 0	24 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1009 (  _text		 PGUID -1  -1 f b t \054 0	25 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1028 (  _oid		 PGUID -1  -1 f b t \054 0	26 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1010 (  _tid		 PGUID -1  -1 f b t \054 0	27 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1011 (  _xid		 PGUID -1  -1 f b t \054 0	28 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1012 (  _cid		 PGUID -1  -1 f b t \054 0	29 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1013 (  _oidvector PGUID -1  -1 f b t \054 0	30 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1014 (  _bpchar	 PGUID -1  -1 f b t \054 0 1042 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1015 (  _varchar	 PGUID -1  -1 f b t \054 0 1043 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1016 (  _int8		 PGUID -1  -1 f b t \054 0	20 array_in array_out array_in array_out d x _null_ ));
! DATA(insert OID = 1017 (  _point	 PGUID -1  -1 f b t \054 0 600 array_in array_out array_in array_out d x _null_ ));
! DATA(insert OID = 1018 (  _lseg		 PGUID -1  -1 f b t \054 0 601 array_in array_out array_in array_out d x _null_ ));
! DATA(insert OID = 1019 (  _path		 PGUID -1  -1 f b t \054 0 602 array_in array_out array_in array_out d x _null_ ));
! DATA(insert OID = 1020 (  _box		 PGUID -1  -1 f b t \073 0 603 array_in array_out array_in array_out d x _null_ ));
! DATA(insert OID = 1021 (  _float4	 PGUID -1  -1 f b t \054 0 700 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1022 (  _float8	 PGUID -1  -1 f b t \054 0 701 array_in array_out array_in array_out d x _null_ ));
! DATA(insert OID = 1023 (  _abstime	 PGUID -1  -1 f b t \054 0 702 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1024 (  _reltime	 PGUID -1  -1 f b t \054 0 703 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1025 (  _tinterval PGUID -1  -1 f b t \054 0 704 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1027 (  _polygon	 PGUID -1  -1 f b t \054 0 604 array_in array_out array_in array_out d x _null_ ));
  /*
   *	Note: the size of aclitem needs to match sizeof(AclItem) in acl.h.
   *	Thanks to some padding, this will be 8 on all platforms.
   *	We also have an Assert to make sure.
   */
  #define ACLITEMSIZE 8
! DATA(insert OID = 1033 (  aclitem	 PGUID 8   -1 f b t \054 0 0 aclitemin aclitemout aclitemin aclitemout i p _null_ ));
  DESCR("access control list");
! DATA(insert OID = 1034 (  _aclitem	 PGUID -1 -1 f b t \054 0 1033 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1040 (  _macaddr	 PGUID -1 -1 f b t \054 0  829 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1041 (  _inet    PGUID -1 -1 f b t \054 0  869 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 651  (  _cidr    PGUID -1 -1 f b t \054 0  650 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1042 ( bpchar		 PGUID -1  -1 f b t \054 0	0 bpcharin bpcharout bpcharin bpcharout i x _null_ ));
  DESCR("char(length), blank-padded string, fixed storage length");
  #define BPCHAROID		1042
! DATA(insert OID = 1043 ( varchar	 PGUID -1  -1 f b t \054 0	0 varcharin varcharout varcharin varcharout i x _null_ ));
  DESCR("varchar(length), non-blank-padded string, variable storage length");
  #define VARCHAROID		1043
  
! DATA(insert OID = 1082 ( date		 PGUID	4  10 t b t \054 0	0 date_in date_out date_in date_out i p _null_ ));
  DESCR("ANSI SQL date");
  #define DATEOID			1082
! DATA(insert OID = 1083 ( time		 PGUID	8  16 f b t \054 0	0 time_in time_out time_in time_out d p _null_ ));
  DESCR("hh:mm:ss, ANSI SQL time");
  #define TIMEOID			1083
  
  /* OIDS 1100 - 1199 */
! DATA(insert OID = 1114 ( timestamp	 PGUID	8  47 f b t \054 0	0 timestamp_in timestamp_out timestamp_in timestamp_out d p _null_ ));
  DESCR("date and time");
  #define TIMESTAMPOID	1114
! DATA(insert OID = 1115 ( _timestamp  PGUID	-1 -1 f b t \054 0	1184 array_in array_out array_in array_out d x _null_ ));
! DATA(insert OID = 1182 ( _date		 PGUID	-1 -1 f b t \054 0	1082 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1183 ( _time		 PGUID	-1 -1 f b t \054 0	1083 array_in array_out array_in array_out d x _null_ ));
! DATA(insert OID = 1184 ( timestamptz PGUID	8  47 f b t \054 0	0 timestamptz_in timestamptz_out timestamptz_in timestamptz_out d p _null_ ));
  DESCR("date and time with time zone");
  #define TIMESTAMPTZOID	1184
! DATA(insert OID = 1185 ( _timestamptz PGUID -1 -1 f b t \054 0	1184 array_in array_out array_in array_out d x _null_ ));
! DATA(insert OID = 1186 ( interval	 PGUID 12  47 f b t \054 0	0 interval_in interval_out interval_in interval_out d p _null_ ));
  DESCR("@ <number> <units>, time interval");
  #define INTERVALOID		1186
! DATA(insert OID = 1187 ( _interval	 PGUID	-1 -1 f b t \054 0	1186 array_in array_out array_in array_out d x _null_ ));
  
  /* OIDS 1200 - 1299 */
! DATA(insert OID = 1231 (  _numeric	 PGUID -1  -1 f b t \054 0	1700 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1266 ( timetz		 PGUID 12  22 f b t \054 0	0 timetz_in timetz_out timetz_in timetz_out d p _null_ ));
  DESCR("hh:mm:ss, ANSI SQL time");
  #define TIMETZOID		1266
! DATA(insert OID = 1270 ( _timetz	 PGUID	-1 -1 f b t \054 0	1266 array_in array_out array_in array_out d x _null_ ));
  
  /* OIDS 1500 - 1599 */
! DATA(insert OID = 1560 ( bit		 PGUID -1  -1 f b t \054 0	0 bit_in bit_out bit_in bit_out i x _null_ ));
  DESCR("fixed-length bit string");
  #define BITOID	 1560
! DATA(insert OID = 1561 ( _bit		 PGUID	-1 -1 f b t \054 0	1560 array_in array_out array_in array_out i x _null_ ));
! DATA(insert OID = 1562 ( varbit		 PGUID -1  -1 f b t \054 0	0 varbit_in varbit_out varbit_in varbit_out i x _null_ ));
  DESCR("variable-length bit string");
  #define VARBITOID	  1562
! DATA(insert OID = 1563 ( _varbit	 PGUID	-1 -1 f b t \054 0	1562 array_in array_out array_in array_out i x _null_ ));
  
  /* OIDS 1600 - 1699 */
  
  /* OIDS 1700 - 1799 */
! DATA(insert OID = 1700 ( numeric	   PGUID -1  -1 f b t \054 0  0 numeric_in numeric_out numeric_in numeric_out i m _null_ ));
  DESCR("numeric(precision, decimal), arbitrary precision number");
  #define NUMERICOID		1700
  
  /* OID 1790 */
! DATA(insert OID = 1790 ( refcursor	   PGUID -1  -1 f b t \054 0  0 textin textout textin textout i x _null_ ));
  DESCR("reference cursor (portal name)");
  #define REFCURSOROID	1790
  
--- 320,486 ----
  /* OIDS 500 - 599 */
  
  /* OIDS 600 - 699 */
! DATA(insert OID = 600 (  point	   PGUID 16  24 f b t \054 0 701 point_in point_out point_in point_out d p f -1 0 0 _null_ _null_ ));
  DESCR("geometric point '(x, y)'");
  #define POINTOID		600
! DATA(insert OID = 601 (  lseg	   PGUID 32  48 f b t \054 0 600 lseg_in lseg_out lseg_in lseg_out d p f -1 0 0 _null_ _null_ ));
  DESCR("geometric line segment '(pt1,pt2)'");
  #define LSEGOID			601
! DATA(insert OID = 602 (  path	   PGUID -1  -1 f b t \054 0 0 path_in path_out path_in path_out d x f -1 0 0 _null_ _null_ ));
  DESCR("geometric path '(pt1,...)'");
  #define PATHOID			602
! DATA(insert OID = 603 (  box	   PGUID 32 100 f b t \073 0 600 box_in box_out box_in box_out d p f -1 0 0 _null_ _null_ ));
  DESCR("geometric box '(lower left,upper right)'");
  #define BOXOID			603
! DATA(insert OID = 604 (  polygon   PGUID -1  -1 f b t \054 0   0 poly_in poly_out poly_in poly_out d x f -1 0 0 _null_ _null_ ));
  DESCR("geometric polygon '(pt1,...)'");
  #define POLYGONOID		604
  
! DATA(insert OID = 628 (  line	   PGUID 32  48 f b t \054 0 701 line_in line_out line_in line_out d p f -1 0 0 _null_ _null_ ));
  DESCR("geometric line '(pt1,pt2)'");
  #define LINEOID			628
! DATA(insert OID = 629 (  _line	   PGUID  -1 -1 f b t \054 0 628 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
  DESCR("");
  
  /* OIDS 700 - 799 */
  
! DATA(insert OID = 700 (  float4    PGUID  4  12 f b t \054 0   0 float4in float4out float4in float4out i p f -1 0 0 _null_ _null_ ));
  DESCR("single-precision floating point number, 4-byte storage");
  #define FLOAT4OID 700
! DATA(insert OID = 701 (  float8    PGUID  8  24 f b t \054 0   0 float8in float8out float8in float8out d p f -1 0 0 _null_ _null_ ));
  DESCR("double-precision floating point number, 8-byte storage");
  #define FLOAT8OID 701
! DATA(insert OID = 702 (  abstime   PGUID  4  20 t b t \054 0   0 nabstimein nabstimeout nabstimein nabstimeout i p f -1 0 0 _null_ _null_ ));
  DESCR("absolute, limited-range date and time (Unix system time)");
  #define ABSTIMEOID		702
! DATA(insert OID = 703 (  reltime   PGUID  4  20 t b t \054 0   0 reltimein reltimeout reltimein reltimeout i p f -1 0 0 _null_ _null_ ));
  DESCR("relative, limited-range time interval (Unix delta time)");
  #define RELTIMEOID		703
! DATA(insert OID = 704 (  tinterval PGUID 12  47 f b t \054 0   0 tintervalin tintervalout tintervalin tintervalout i p f -1 0 0 _null_ _null_ ));
  DESCR("(abstime,abstime), time interval");
  #define TINTERVALOID	704
! DATA(insert OID = 705 (  unknown   PGUID -1  -1 f b t \054 0   0 textin textout textin textout i p f -1 0 0 _null_ _null_ ));
  DESCR("");
  #define UNKNOWNOID		705
  
! DATA(insert OID = 718 (  circle    PGUID  24 47 f b t \054 0	0 circle_in circle_out circle_in circle_out d p f -1 0 0 _null_ _null_ ));
  DESCR("geometric circle '(center,radius)'");
  #define CIRCLEOID		718
! DATA(insert OID = 719 (  _circle   PGUID  -1 -1 f b t \054 0  718 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 790 (  money	   PGUID   4 24 f b t \054 0	0 cash_in cash_out cash_in cash_out i p f -1 0 0 _null_ _null_ ));
  DESCR("$d,ddd.cc, money");
  #define CASHOID 790
! DATA(insert OID = 791 (  _money    PGUID  -1 -1 f b t \054 0  790 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
  
  /* OIDS 800 - 899 */
! DATA(insert OID = 829 ( macaddr    PGUID  6 -1 f b t \054 0 0 macaddr_in macaddr_out macaddr_in macaddr_out i p f -1 0 0 _null_ _null_ ));
  DESCR("XX:XX:XX:XX:XX:XX, MAC address");
  #define MACADDROID 829
! DATA(insert OID = 869 ( inet	   PGUID  -1 -1 f b t \054 0 0 inet_in inet_out inet_in inet_out i p f -1 0 0 _null_ _null_ ));
  DESCR("IP address/netmask, host address, netmask optional");
  #define INETOID 869
! DATA(insert OID = 650 ( cidr	   PGUID  -1 -1 f b t \054 0 0 cidr_in cidr_out cidr_in cidr_out i p f -1 0 0 _null_ _null_ ));
  DESCR("network IP address/netmask, network address");
  #define CIDROID 650
  
  /* OIDS 900 - 999 */
  
  /* OIDS 1000 - 1099 */
! DATA(insert OID = 1000 (  _bool		 PGUID -1  -1 f b t \054 0	16 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1001 (  _bytea	 PGUID -1  -1 f b t \054 0	17 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1002 (  _char		 PGUID -1  -1 f b t \054 0	18 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1003 (  _name		 PGUID -1  -1 f b t \054 0	19 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1005 (  _int2		 PGUID -1  -1 f b t \054 0	21 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1006 (  _int2vector PGUID -1 -1 f b t \054 0	22 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1007 (  _int4		 PGUID -1  -1 f b t \054 0	23 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1008 (  _regproc	 PGUID -1  -1 f b t \054 0	24 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1009 (  _text		 PGUID -1  -1 f b t \054 0	25 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1028 (  _oid		 PGUID -1  -1 f b t \054 0	26 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1010 (  _tid		 PGUID -1  -1 f b t \054 0	27 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1011 (  _xid		 PGUID -1  -1 f b t \054 0	28 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1012 (  _cid		 PGUID -1  -1 f b t \054 0	29 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1013 (  _oidvector PGUID -1  -1 f b t \054 0	30 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1014 (  _bpchar	 PGUID -1  -1 f b t \054 0 1042 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1015 (  _varchar	 PGUID -1  -1 f b t \054 0 1043 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1016 (  _int8		 PGUID -1  -1 f b t \054 0	20 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1017 (  _point	 PGUID -1  -1 f b t \054 0 600 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1018 (  _lseg		 PGUID -1  -1 f b t \054 0 601 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1019 (  _path		 PGUID -1  -1 f b t \054 0 602 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1020 (  _box		 PGUID -1  -1 f b t \073 0 603 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1021 (  _float4	 PGUID -1  -1 f b t \054 0 700 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1022 (  _float8	 PGUID -1  -1 f b t \054 0 701 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1023 (  _abstime	 PGUID -1  -1 f b t \054 0 702 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1024 (  _reltime	 PGUID -1  -1 f b t \054 0 703 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1025 (  _tinterval PGUID -1  -1 f b t \054 0 704 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1027 (  _polygon	 PGUID -1  -1 f b t \054 0 604 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
  /*
   *	Note: the size of aclitem needs to match sizeof(AclItem) in acl.h.
   *	Thanks to some padding, this will be 8 on all platforms.
   *	We also have an Assert to make sure.
   */
  #define ACLITEMSIZE 8
! DATA(insert OID = 1033 (  aclitem	 PGUID 8   -1 f b t \054 0 0 aclitemin aclitemout aclitemin aclitemout i p f -1 0 0 _null_ _null_ ));
  DESCR("access control list");
! DATA(insert OID = 1034 (  _aclitem	 PGUID -1 -1 f b t \054 0 1033 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1040 (  _macaddr	 PGUID -1 -1 f b t \054 0  829 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1041 (  _inet    PGUID -1 -1 f b t \054 0  869 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 651  (  _cidr    PGUID -1 -1 f b t \054 0  650 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1042 ( bpchar		 PGUID -1  -1 f b t \054 0	0 bpcharin bpcharout bpcharin bpcharout i x f -1 0 0 _null_ _null_ ));
  DESCR("char(length), blank-padded string, fixed storage length");
  #define BPCHAROID		1042
! DATA(insert OID = 1043 ( varchar	 PGUID -1  -1 f b t \054 0	0 varcharin varcharout varcharin varcharout i x f -1 0 0 _null_ _null_ ));
  DESCR("varchar(length), non-blank-padded string, variable storage length");
  #define VARCHAROID		1043
  
! DATA(insert OID = 1082 ( date		 PGUID	4  10 t b t \054 0	0 date_in date_out date_in date_out i p f -1 0 0 _null_ _null_ ));
  DESCR("ANSI SQL date");
  #define DATEOID			1082
! DATA(insert OID = 1083 ( time		 PGUID	8  16 f b t \054 0	0 time_in time_out time_in time_out d p f -1 0 0 _null_ _null_ ));
  DESCR("hh:mm:ss, ANSI SQL time");
  #define TIMEOID			1083
  
  /* OIDS 1100 - 1199 */
! DATA(insert OID = 1114 ( timestamp	 PGUID	8  47 f b t \054 0	0 timestamp_in timestamp_out timestamp_in timestamp_out d p f -1 0 0 _null_ _null_ ));
  DESCR("date and time");
  #define TIMESTAMPOID	1114
! DATA(insert OID = 1115 ( _timestamp  PGUID	-1 -1 f b t \054 0	1184 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1182 ( _date		 PGUID	-1 -1 f b t \054 0	1082 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1183 ( _time		 PGUID	-1 -1 f b t \054 0	1083 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1184 ( timestamptz PGUID	8  47 f b t \054 0	0 timestamptz_in timestamptz_out timestamptz_in timestamptz_out d p f -1 0 0 _null_ _null_ ));
  DESCR("date and time with time zone");
  #define TIMESTAMPTZOID	1184
! DATA(insert OID = 1185 ( _timestamptz PGUID -1 -1 f b t \054 0	1184 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1186 ( interval	 PGUID 12  47 f b t \054 0	0 interval_in interval_out interval_in interval_out d p f -1 0 0 _null_ _null_ ));
  DESCR("@ <number> <units>, time interval");
  #define INTERVALOID		1186
! DATA(insert OID = 1187 ( _interval	 PGUID	-1 -1 f b t \054 0	1186 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
  
  /* OIDS 1200 - 1299 */
! DATA(insert OID = 1231 (  _numeric	 PGUID -1  -1 f b t \054 0	1700 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1266 ( timetz		 PGUID 12  22 f b t \054 0	0 timetz_in timetz_out timetz_in timetz_out d p f -1 0 0 _null_ _null_ ));
  DESCR("hh:mm:ss, ANSI SQL time");
  #define TIMETZOID		1266
! DATA(insert OID = 1270 ( _timetz	 PGUID	-1 -1 f b t \054 0	1266 array_in array_out array_in array_out d x f -1 0 0 _null_ _null_ ));
  
  /* OIDS 1500 - 1599 */
! DATA(insert OID = 1560 ( bit		 PGUID -1  -1 f b t \054 0	0 bit_in bit_out bit_in bit_out i x f -1 0 0 _null_ _null_ ));
  DESCR("fixed-length bit string");
  #define BITOID	 1560
! DATA(insert OID = 1561 ( _bit		 PGUID	-1 -1 f b t \054 0	1560 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
! DATA(insert OID = 1562 ( varbit		 PGUID -1  -1 f b t \054 0	0 varbit_in varbit_out varbit_in varbit_out i x f -1 0 0 _null_ _null_ ));
  DESCR("variable-length bit string");
  #define VARBITOID	  1562
! DATA(insert OID = 1563 ( _varbit	 PGUID	-1 -1 f b t \054 0	1562 array_in array_out array_in array_out i x f -1 0 0 _null_ _null_ ));
  
  /* OIDS 1600 - 1699 */
  
  /* OIDS 1700 - 1799 */
! DATA(insert OID = 1700 ( numeric	   PGUID -1  -1 f b t \054 0  0 numeric_in numeric_out numeric_in numeric_out i m f -1 0 0 _null_ _null_ ));
  DESCR("numeric(precision, decimal), arbitrary precision number");
  #define NUMERICOID		1700
  
  /* OID 1790 */
! DATA(insert OID = 1790 ( refcursor	   PGUID -1  -1 f b t \054 0  0 textin textout textin textout i x f -1 0 0 _null_ _null_ ));
  DESCR("reference cursor (portal name)");
  #define REFCURSOROID	1790
  
***************
*** 447,452 ****
--- 490,496 ----
   */
  extern Oid	TypeGet(char *typeName, bool *defined);
  extern Oid	TypeShellMake(char *typeName);
+ 
  extern Oid TypeCreate(char *typeName,
  		   Oid assignedTypeOid,
  		   Oid relationOid,
***************
*** 459,468 ****
  		   char *receiveProcedure,
  		   char *sendProcedure,
  		   char *elementTypeName,
  		   char *defaultTypeValue,
  		   bool passedByValue,
  		   char alignment,
! 		   char storage);
  extern void TypeRename(const char *oldTypeName, const char *newTypeName);
  extern char *makeArrayTypeName(char *typeName);
  
--- 503,519 ----
  		   char *receiveProcedure,
  		   char *sendProcedure,
  		   char *elementTypeName,
+ 		   char *baseTypeName,
  		   char *defaultTypeValue,
+ 		   char *defaultTypeBin,
  		   bool passedByValue,
  		   char alignment,
! 		   char storage,
! 		   int32 typeMod,
! 		   int32 typNDims,
! 		   bool typeNotNull);
! 
! 
  extern void TypeRename(const char *oldTypeName, const char *newTypeName);
  extern char *makeArrayTypeName(char *typeName);
  
Index: src/include/commands/defrem.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/commands/defrem.h,v
retrieving revision 1.30
diff -c -r1.30 defrem.h
*** src/include/commands/defrem.h	2002/03/07 16:35:38	1.30
--- src/include/commands/defrem.h	2002/03/12 02:41:08
***************
*** 39,48 ****
--- 39,50 ----
  extern void DefineOperator(char *name, List *parameters);
  extern void DefineAggregate(char *name, List *parameters);
  extern void DefineType(char *name, List *parameters);
+ extern void DefineDomain(CreateDomainStmt *stmt);
  
  /*
   * prototypes in remove.c
   */
+ extern void RemoveDomain(char *domainName, int behavior);
  extern void RemoveFunction(char *functionName, List *argTypes);
  extern void RemoveOperator(char *operatorName,
  			   char *typeName1, char *typeName2);
Index: src/include/nodes/nodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/nodes.h,v
retrieving revision 1.100
diff -c -r1.100 nodes.h
*** src/include/nodes/nodes.h	2002/03/07 16:35:40	1.100
--- src/include/nodes/nodes.h	2002/03/12 02:41:10
***************
*** 172,177 ****
--- 172,178 ----
  	T_TransactionStmt,
  	T_ViewStmt,
  	T_LoadStmt,
+ 	T_CreateDomainStmt,
  	T_CreatedbStmt,
  	T_DropdbStmt,
  	T_VacuumStmt,
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.158
diff -c -r1.158 parsenodes.h
*** src/include/nodes/parsenodes.h	2002/03/07 16:35:40	1.158
--- src/include/nodes/parsenodes.h	2002/03/12 02:41:11
***************
*** 468,479 ****
--- 468,481 ----
  #define DROP_INDEX	  4
  #define DROP_RULE	  5
  #define DROP_TYPE_P   6
+ #define DROP_DOMAIN_P 7
  
  typedef struct DropStmt
  {
  	NodeTag		type;
  	List	   *names;
  	int			removeType;
+ 	int	   		behavior;		/* CASCADE or RESTRICT drop behavior */
  } DropStmt;
  
  /* ----------------------
***************
*** 682,687 ****
--- 684,690 ----
  	char	   *filename;		/* file to load */
  } LoadStmt;
  
+ 
  /* ----------------------
   *		Createdb Statement
   * ----------------------
***************
*** 1279,1284 ****
--- 1282,1303 ----
  	Node	   *arg;			/* a (Value *) or a (TypeName *) */
  } DefElem;
  
+ 
+ /****************************************************************************
+  *	Nodes for a Domain Creation tree
+  ****************************************************************************/
+ /* ----------------------
+  *		CreateDomain Statement
+  * ----------------------
+  * Down here as it required TypeName to be defined first.
+  */
+ typedef struct CreateDomainStmt
+ {
+ 	NodeTag		type;
+ 	char	   *domainname;			/* name of domain to create */
+ 	TypeName   *typename;			/* the typecast */
+ 	List	   *constraints;		/* constraints (list of Constraint nodes) */
+ } CreateDomainStmt;
  
  /****************************************************************************
   *	Nodes for a Query tree
Index: src/include/parser/parse_coerce.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/parser/parse_coerce.h,v
retrieving revision 1.39
diff -c -r1.39 parse_coerce.h
*** src/include/parser/parse_coerce.h	2002/03/07 16:35:40	1.39
--- src/include/parser/parse_coerce.h	2002/03/12 02:41:13
***************
*** 81,85 ****
--- 81,86 ----
  extern Node *coerce_to_common_type(ParseState *pstate, Node *node,
  					  Oid targetTypeId,
  					  const char *context);
+ extern Oid getBaseType(Oid inType);
  
  #endif   /* PARSE_COERCE_H */
Index: src/include/utils/lsyscache.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/utils/lsyscache.h,v
retrieving revision 1.42
diff -c -r1.42 lsyscache.h
*** src/include/utils/lsyscache.h	2002/03/07 16:35:41	1.42
--- src/include/utils/lsyscache.h	2002/03/12 02:41:17
***************
*** 44,50 ****
  extern bool get_typbyval(Oid typid);
  extern void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval);
  extern char get_typstorage(Oid typid);
! extern bool get_typdefault(Oid typid, Datum *defaultValue);
  extern int32 get_typavgwidth(Oid typid, int32 typmod);
  extern int32 get_attavgwidth(Oid relid, AttrNumber attnum);
  extern bool get_attstatsslot(HeapTuple statstuple,
--- 44,50 ----
  extern bool get_typbyval(Oid typid);
  extern void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval);
  extern char get_typstorage(Oid typid);
! extern Node *get_typdefault(Oid typid, int32 atttypmod);
  extern int32 get_typavgwidth(Oid typid, int32 typmod);
  extern int32 get_attavgwidth(Oid relid, AttrNumber attnum);
  extern bool get_attstatsslot(HeapTuple statstuple,
#7Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Rod Taylor (#3)
Re: Domain Support -- another round

Removed, superceeded by new versions.

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

Rod Taylor wrote:

Attached is a diff to the patch of the below message to use b_expr
rather than c_expr.

Also includes an improved regress set. Less redundant failures, and
tests numeric types as they're different from the others enough to
warrent it.
--
Rod Taylor

This message represents the official view of the voices in my head

----- Original Message -----
From: "Rod Taylor" <rbt@zort.ca>
To: <pgsql-patches@postgresql.org>
Sent: Thursday, March 07, 2002 11:21 PM
Subject: [PATCHES] Domain Support -- another round

Ok....

gram.y is fixed (no more %expect usage)

Using the copyCreateDomainStmt in the proper place.

Evolution is the mail client of choice for different (improved?)

mime

headers.

And attached is a regular diff -c, rather than a cvs diff -c.

I updated the poor descriptions of MergeDomainAttributes().

Hopefully

its current and future use is more obvious.

Am I getting close?

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

---------------------------(end of

broadcast)---------------------------

TIP 2: you can get off all lists at once with the unregister command
(send "unregister YourEmailAddressHere" to

majordomo@postgresql.org)

[ Attachment, skipping... ]

[ Attachment, skipping... ]

---------------------------(end of broadcast)---------------------------
TIP 2: you can get off all lists at once with the unregister command
(send "unregister YourEmailAddressHere" to majordomo@postgresql.org)

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
#8Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Rod Taylor (#6)
Re: Domain Support -- another round

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.

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

Rod Taylor wrote:

New set with most of Peters comments corrected. Left the deal about
schema though :) Took nearly an hour to do a cvs diff for some reason
this time (normally a couple of minutes is enough).

Random nitpicking below. Also, have you created a regression test?

They had been posted a few times and haven't changed. (Attached
anyway)

+    <structfield>typnotnull</structfield> represents a NOT NULL
+    constraint on a type.  Normally used only for domains.

And unnormally...?

Unnormally is when someone sets it by hand on a type which isn't a
domain -- I guess. Corrected.

+ <!entity createDomain system "create_domain.sgml">

I don't see this file included.

Other messages. Full package included on this one however.

+  * MergeDomainAttributes
+  *      Returns a new table schema with the constraints, types,

and other

+ * attributes of the domain resolved for fields using the

domain as

+ * their type.

I didn't know we had schemas yet. You should probably not overload

that

term to mean "a list of database objects".

Merge attributes says something very similar about inheritance and
table schemas. Kinda correct considering
the variable used in both cases is *schema.

The diff weirdness in regards to DROP DATABASE is probably because I
started by copying the DROP DATABASE element, then altered it. I
don't know why it chose that method to do the diff though, but it is
accurate. Using -cd flags didn't make it any prettier.

[ Attachment, skipping... ]

[ Attachment, skipping... ]

[ Attachment, skipping... ]

[ Attachment, skipping... ]

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
#9Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Rod Taylor (#6)
1 attachment(s)
Re: Domain Support -- another round

Patch applied. I am attaching the expected/domain.out file that I
generated when I added your domain test file to the regression tests.
Please verify that the output is correct. Thanks.

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

Rod Taylor wrote:

New set with most of Peters comments corrected. Left the deal about
schema though :) Took nearly an hour to do a cvs diff for some reason
this time (normally a couple of minutes is enough).

Random nitpicking below. Also, have you created a regression test?

They had been posted a few times and haven't changed. (Attached
anyway)

+    <structfield>typnotnull</structfield> represents a NOT NULL
+    constraint on a type.  Normally used only for domains.

And unnormally...?

Unnormally is when someone sets it by hand on a type which isn't a
domain -- I guess. Corrected.

+ <!entity createDomain system "create_domain.sgml">

I don't see this file included.

Other messages. Full package included on this one however.

+  * MergeDomainAttributes
+  *      Returns a new table schema with the constraints, types,

and other

+ * attributes of the domain resolved for fields using the

domain as

+ * their type.

I didn't know we had schemas yet. You should probably not overload

that

term to mean "a list of database objects".

Merge attributes says something very similar about inheritance and
table schemas. Kinda correct considering
the variable used in both cases is *schema.

The diff weirdness in regards to DROP DATABASE is probably because I
started by copying the DROP DATABASE element, then altered it. I
don't know why it chose that method to do the diff though, but it is
accurate. Using -cd flags didn't make it any prettier.

[ Attachment, skipping... ]

[ Attachment, skipping... ]

[ Attachment, skipping... ]

[ Attachment, skipping... ]

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Attachments:

/pg/test/regress/expected/domain.outtext/plainDownload
#10Rod Taylor
rbt@barchord.com
In reply to: Bruce Momjian (#9)
Re: Domain Support -- another round

Output looks good, but I always got a bunch of NOTICE statements.

I'll assume the lack of those is related to the logging changes that
have been going on?
--
Rod Taylor

This message represents the official view of the voices in my head

----- Original Message -----
From: "Bruce Momjian" <pgman@candle.pha.pa.us>
To: "Rod Taylor" <rbt@zort.ca>
Cc: "Peter Eisentraut" <peter_e@gmx.net>;
<pgsql-patches@postgresql.org>
Sent: Monday, March 18, 2002 9:16 PM
Subject: Re: [PATCHES] Domain Support -- another round

Patch applied. I am attaching the expected/domain.out file that I
generated when I added your domain test file to the regression

tests.

Please verify that the output is correct. Thanks.

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

-------

Rod Taylor wrote:

New set with most of Peters comments corrected. Left the deal

about

schema though :) Took nearly an hour to do a cvs diff for some

reason

this time (normally a couple of minutes is enough).

Random nitpicking below. Also, have you created a regression

test?

They had been posted a few times and haven't changed. (Attached
anyway)

+ <structfield>typnotnull</structfield> represents a NOT

NULL

+ constraint on a type. Normally used only for domains.

And unnormally...?

Unnormally is when someone sets it by hand on a type which isn't a
domain -- I guess. Corrected.

+ <!entity createDomain system "create_domain.sgml">

I don't see this file included.

Other messages. Full package included on this one however.

+  * MergeDomainAttributes
+  *      Returns a new table schema with the constraints,

types,

and other

+ * attributes of the domain resolved for fields using

the

domain as

+ * their type.

I didn't know we had schemas yet. You should probably not

overload

that

term to mean "a list of database objects".

Merge attributes says something very similar about inheritance and
table schemas. Kinda correct considering
the variable used in both cases is *schema.

The diff weirdness in regards to DROP DATABASE is probably because

I

started by copying the DROP DATABASE element, then altered it. I
don't know why it chose that method to do the diff though, but it

is

accurate. Using -cd flags didn't make it any prettier.

[ Attachment, skipping... ]

[ Attachment, skipping... ]

[ Attachment, skipping... ]

[ Attachment, skipping... ]

--
Bruce Momjian                        |  http://candle.pha.pa.us
pgman@candle.pha.pa.us               |  (610) 853-3000
+  If your life is a hard drive,     |  830 Blythe Avenue
+  Christ can be your backup.        |  Drexel Hill, Pennsylvania

19026

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

-- Test Comment / Drop
create domain domaindroptest int4;
comment on domain domaindroptest is 'About to drop this..';
create domain basetypetest domaindroptest;
ERROR: DefineDomain: domaindroptest is not a basetype
drop domain domaindroptest;
ERROR: parser: parse error at or near ";"
drop domain domaindroptest restrict;
-- TEST Domains.
create domain domainvarchar varchar(5);
create domain domainnumeric numeric(8,2);
create domain domainint4 int4;
create domain domaintext text;
-- Test tables using domains
create table basictest
( testint4 domainint4
, testtext domaintext
, testvarchar domainvarchar
, testnumeric domainnumeric
);
INSERT INTO basictest values ('88', 'haha', 'short',

12'); -- Good

INSERT INTO basictest values ('88', 'haha', 'short text',

'123.12'); -- Bad varchar

ERROR: value too long for type character varying(5)
INSERT INTO basictest values ('88', 'haha', 'short',

3.1212'); -- Truncate numeric

select * from basictest;
testint4 | testtext | testvarchar | testnumeric
----------+----------+-------------+-------------
88 | haha | short | 123.12
88 | haha | short | 123.12
(2 rows)

drop table basictest;
drop domain domainvarchar restrict;
drop domain domainnumeric restrict;
drop domain domainint4 restrict;
drop domain domaintext restrict;
-- Array Test
create domain domainint4arr int4[1];
create domain domaintextarr text[2][3];
create table domarrtest
( testint4arr domainint4arr
, testtextarr domaintextarr
);
INSERT INTO domarrtest values ('{2,2}', '{{"a","b"}{"c","d"}}');
INSERT INTO domarrtest values ('{{2,2}{2,2}}', '{{"a","b"}}');
INSERT INTO domarrtest values ('{2,2}',

'{{"a","b"}{"c","d"}{"e"}}');

INSERT INTO domarrtest values ('{2,2}', '{{"a"}{"c"}}');
INSERT INTO domarrtest values (NULL, '{{"a","b"}{"c","d","e"}}');
drop table domarrtest;
drop domain domainint4arr restrict;
drop domain domaintextarr restrict;
create domain dnotnull varchar(15) NOT NULL;
create domain dnull varchar(15) NULL;
create table nulltest
( col1 dnotnull
, col2 dnotnull NULL -- NOT NULL in the domain cannot be

overridden

, col3 dnull NOT NULL
, col4 dnull
);
INSERT INTO nulltest DEFAULT VALUES;
ERROR: ExecAppend: Fail to add null value in not null attribute

col1

INSERT INTO nulltest values ('a', 'b', 'c', 'd'); -- Good
INSERT INTO nulltest values (NULL, 'b', 'c', 'd');
ERROR: ExecAppend: Fail to add null value in not null attribute

col1

INSERT INTO nulltest values ('a', NULL, 'c', 'd');
ERROR: ExecAppend: Fail to add null value in not null attribute

col2

INSERT INTO nulltest values ('a', 'b', NULL, 'd');
ERROR: ExecAppend: Fail to add null value in not null attribute

col3

Show quoted text

INSERT INTO nulltest values ('a', 'b', 'c', NULL); -- Good
select * from nulltest;
col1 | col2 | col3 | col4
------+------+------+------
a | b | c | d
a | b | c |
(2 rows)

drop table nulltest;
drop domain dnotnull restrict;
drop domain dnull restrict;
create domain ddef1 int4 DEFAULT 3;
create domain ddef2 oid DEFAULT '12';
-- Type mixing, function returns int8
create domain ddef3 text DEFAULT 5;
create sequence ddef4_seq;
create domain ddef4 int4 DEFAULT nextval(cast('ddef4_seq' as text));
create domain ddef5 numeric(8,2) NOT NULL DEFAULT '12.12';
create table defaulttest
( col1 ddef1
, col2 ddef2
, col3 ddef3
, col4 ddef4
, col5 ddef1 NOT NULL DEFAULT NULL
, col6 ddef2 DEFAULT '88'
, col7 ddef4 DEFAULT 8000
, col8 ddef5
);
insert into defaulttest default values;
insert into defaulttest default values;
insert into defaulttest default values;
select * from defaulttest;
col1 | col2 | col3 | col4 | col5 | col6 | col7 | col8
------+------+------+------+------+------+------+-------
3 | 12 | 5 | 1 | 3 | 88 | 8000 | 12.12
3 | 12 | 5 | 2 | 3 | 88 | 8000 | 12.12
3 | 12 | 5 | 3 | 3 | 88 | 8000 | 12.12
(3 rows)

drop sequence ddef4_seq;
drop table defaulttest;
drop domain ddef1 restrict;
drop domain ddef2 restrict;
drop domain ddef3 restrict;
drop domain ddef4 restrict;
drop domain ddef5 restrict;

#11Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Rod Taylor (#10)
Re: Domain Support -- another round

Rod Taylor wrote:

Output looks good, but I always got a bunch of NOTICE statements.

I'll assume the lack of those is related to the logging changes that
have been going on?

Uh, that is very possible, though the messages would now be INFO
perhaps. I don't think we actually removed messages in the default
install.

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
#12Tom Lane
tgl@sss.pgh.pa.us
In reply to: Rod Taylor (#6)
Re: Domain Support -- another round

I've committed a bunch of changes after code review of your DOMAIN
patch. There were a number of minor bugs as well as some stylistic
things I didn't like.

Probably the largest change was that I concluded we had to revert the
handling of default values for base types to the old way: simple literal
stored as a string. You can't meaningfully deal with an expression that
represents a value of a type you haven't defined yet --- since you
surely haven't defined any functions or operators that yield it, either.
Therefore the apparent flexibility is illusory. Also, the code just
plain didn't work: after I fixed preptlist.c to do what it should be
doing, I was getting "can't coerce" failures in the create_type
regression test. (For example, it didn't believe that an int4 literal
"42" was a valid default for the test's type int42, which is correct
given that the test doesn't define any conversion function...) So all
in all I just don't see any way that can work. I've set it up so that
you can have *either* an expression default (if typdefaultbin is not
null) *or* a simple literal default (if typdefaultbin is null but
typdefault isn't). The former case will work for domains, the latter
for base types.

There are still some things that need to be worked on:

1. pg_dump. We *cannot* release this feature in 7.3 if there's not
pg_dump support for it.

2. Arrays. I don't much care for the fact that arrays of domain-type
values aren't supported. The handling of domains that are themselves
arrays seems a tad odd as well: the array-ish nature of the domain is
exposed, which doesn't make a lot of sense to me. Perhaps we'd be
better off to forbid array domains.

3. Domains on domains. Why shouldn't I be able to make a domain that's
a further restriction of another domain?

4. CHECK constraints for domains (which after all is the real point,
no?)

regards, tom lane

#13Fernando Nasser
fnasser@redhat.com
In reply to: Peter Eisentraut (#5)
Re: Domain Support -- another round

Tom Lane wrote:

2. Arrays. I don't much care for the fact that arrays of domain-type
values aren't supported. The handling of domains that are themselves
arrays seems a tad odd as well: the array-ish nature of the domain is
exposed, which doesn't make a lot of sense to me. Perhaps we'd be
better off to forbid array domains.

From SQL99 11.23 Syntax Rule 6)

"<data type> should not specify a reference type, user-defined type,
or an array type."
==========

--
Fernando Nasser
Red Hat - Toronto E-Mail: fnasser@redhat.com
2323 Yonge Street, Suite #300
Toronto, Ontario M4P 2C9

#14Rod Taylor
rbt@zort.ca
In reply to: Peter Eisentraut (#5)
Re: Domain Support -- another round

There are still some things that need to be worked on:

1. pg_dump. We *cannot* release this feature in 7.3 if there's not
pg_dump support for it.

I intend to try to do this next week.

2. Arrays. I don't much care for the fact that arrays of

domain-type

values aren't supported. The handling of domains that are

themselves

arrays seems a tad odd as well: the array-ish nature of the domain

is

exposed, which doesn't make a lot of sense to me. Perhaps we'd be
better off to forbid array domains.

The reason I didn't make array types for domains is that I have
absolutly no idea how to manage the below case once point 4 is
implemented.

create domain dom as int4 check (VALUE > 5);
create table tab (col1 dom[2][3]);

3. Domains on domains. Why shouldn't I be able to make a domain

that's

a further restriction of another domain?

Not entirely sure, except the book I had (SQL99 Complete, Really)
specifically forbids it.

4. CHECK constraints for domains (which after all is the real point,
no?)

Yes, I'm slow and only capable of one step at a time. Foreign key
constraints are the other real point.

#15Fernando Nasser
fnasser@redhat.com
In reply to: Peter Eisentraut (#5)
Re: Domain Support -- another round

Rod Taylor wrote:

2. Arrays. I don't much care for the fact that arrays of

domain-type

values aren't supported. The handling of domains that are

themselves

arrays seems a tad odd as well: the array-ish nature of the domain

is

exposed, which doesn't make a lot of sense to me. Perhaps we'd be
better off to forbid array domains.

The reason I didn't make array types for domains is that I have
absolutly no idea how to manage the below case once point 4 is
implemented.

create domain dom as int4 check (VALUE > 5);
create table tab (col1 dom[2][3]);

SQL'99 explicitly forbids it. Please refer to my posting to HACKERS
for the SQL document reference.

3. Domains on domains. Why shouldn't I be able to make a domain

that's

a further restriction of another domain?

Not entirely sure, except the book I had (SQL99 Complete, Really)
specifically forbids it.

Yes, but this is their interpretation of the standard. There is an
error in that page anyway, as the standard explicitly forbids
arrays and UDTs and they list REF and ARRAY as valid data types.
(they also get confused with SESSION_USER and CURENT_USER on page
281, so it does not surprise me).

I couldn't find anything in the standard explicitly forbidden it.
But I don't think this is a very useful feature anyway. As one is
creating another domain, he /she can as well specify constraints
that represent a further reduction of the valid values range.

--
Fernando Nasser
Red Hat Canada Ltd. E-Mail: fnasser@redhat.com
2323 Yonge Street, Suite #300
Toronto, Ontario M4P 2C9

#16Rod Taylor
rbt@zort.ca
In reply to: Peter Eisentraut (#5)
Re: [PATCHES] Domain Support -- another round

Not entirely sure, except the book I had (SQL99 Complete, Really)
specifically forbids it.

Yes, but this is their interpretation of the standard. There is an

Understood. It's the best that I had on me.

I've not found a cheap resource for the real one. Ie. priced suitably
to fit a hobby project :)

Show quoted text

error in that page anyway, as the standard explicitly forbids
arrays and UDTs and they list REF and ARRAY as valid data types.
(they also get confused with SESSION_USER and CURENT_USER on page
281, so it does not surprise me).

#17Thomas Lockhart
thomas@fourpalms.org
In reply to: Peter Eisentraut (#5)
Re: Domain Support -- another round

SQL'99 explicitly forbids it. Please refer to my posting to HACKERS
for the SQL document reference.

The fact that a standard "forbids" something does not necessarily mean
it is a bad idea, as I'm sure you know. Is there any reason that the
standard forbids using domains inside arrays, other than someone on the
standards committee realized that it would be hard for their company to
implement it? That is, does allowing domains in arrays lead to
inconsistancies or fundamental issues with relational algebra or other
set logic that should keep it out of the next set of standards?

If Postgres was developed to only the current standard, it would never
have been written. And since the start of the open source days, if we
had worked solely to get it to conform to the current standard we'd be
starting at ground zero for implementing SQL99, since many of our
features now appear in that standard. Someone cheated and looked at what
we could already do... ;)

- Thomas

#18Fernando Nasser
fnasser@redhat.com
In reply to: Peter Eisentraut (#5)
Re: Domain Support -- another round

Thomas Lockhart wrote:

SQL'99 explicitly forbids it. Please refer to my posting to HACKERS
for the SQL document reference.

The fact that a standard "forbids" something does not necessarily mean
it is a bad idea, as I'm sure you know. Is there any reason that the
standard forbids using domains inside arrays, other than someone on the
standards committee realized that it would be hard for their company to
implement it? That is, does allowing domains in arrays lead to
inconsistancies or fundamental issues with relational algebra or other
set logic that should keep it out of the next set of standards?

I partially agree, but I guess Tom has already given some of the reasons
not to do it.

If Postgres was developed to only the current standard, it would never
have been written. And since the start of the open source days, if we
had worked solely to get it to conform to the current standard we'd be
starting at ground zero for implementing SQL99, since many of our
features now appear in that standard. Someone cheated and looked at what
we could already do... ;)

Again, I only partially agree with that, Adding significant features
that
will allow people to solve significantly different problems that can not
be solved with the vanilla standard is a good think. And I believe it
is
acknowledged in many places that many SQL3 features were inspired on
Postgres.

However, adding extensions to the SQL standard otherwise is a bad thing.
If affects portability. Actually, "extending" standards has been a
weapon
used by some proprietary companies to hurt the competition. Standards
are
friends of Open Source software and we should try to stick to them
whenever possible.

In the case of DOMAINS, which are already considered by some as not very
useful and passive of removal from next editions of the standard (by one
SQL editor, at least -- I can give you the book reference this
afternoon),
adding extension to the SQL to it would just aggravate the issue.

So, although I agree with you in principle, I believe that in these
cases
we should stick to the standard and avoid gratuitous extensions.

--
Fernando Nasser
Red Hat Canada Ltd. E-Mail: fnasser@redhat.com
2323 Yonge Street, Suite #300
Toronto, Ontario M4P 2C9

#19Thomas Lockhart
thomas@fourpalms.org
In reply to: Peter Eisentraut (#5)
Re: Domain Support -- another round

...

So, although I agree with you in principle, I believe that in these
cases we should stick to the standard and avoid gratuitous extensions.

Hmm. In any case, supporting arrays (esp. if it is not allowed in the
standard) should not be a requirement for implementing the DOMAIN
functionality. No point in arguing principles on just, uh, principles,
when we could actually be getting something good done ;)

- Thomas

#20Fernando Nasser
fnasser@redhat.com
In reply to: Peter Eisentraut (#5)
Re: Domain Support -- another round

Thomas Lockhart wrote:

...

So, although I agree with you in principle, I believe that in these
cases we should stick to the standard and avoid gratuitous extensions.

Hmm. In any case, supporting arrays (esp. if it is not allowed in the
standard) should not be a requirement for implementing the DOMAIN
functionality. No point in arguing principles on just, uh, principles,
when we could actually be getting something good done ;)

I couldn't agree more.

Cheers,
Fernando

--
Fernando Nasser
Red Hat Canada Ltd. E-Mail: fnasser@redhat.com
2323 Yonge Street, Suite #300
Toronto, Ontario M4P 2C9

#21Tom Lane
tgl@sss.pgh.pa.us
In reply to: Rod Taylor (#16)
Where to get official SQL spec (was Re: Domain Support)

"Rod Taylor" <rbt@zort.ca> writes:

I've not found a cheap resource for the real one. Ie. priced suitably
to fit a hobby project :)

Try ANSI's electronic standards store: they'll sell you PDFs of ANSI's
printing of the spec at a reasonable price.

http://webstore.ansi.org/ansidocstore/default.asp

Go to the "search" page and enter "9075" (the IS number for SQL).
Along with the overpriced ISO offerings, there are:

ANSI X3.135-1992 SQL92

ANSI/ISO/IEC 9075-n-1999 SQL99, parts 1-5

Each of these is $18 US. You don't really need all five parts of
SQL99; I've seldom found any use for anything but part 2. It is
worth having SQL92, mainly because it's so much more readable
than the 99 spec :-(

regards, tom lane

#22Christopher Kings-Lynne
chriskl@familyhealth.com.au
In reply to: Tom Lane (#21)
Re: Where to get official SQL spec (was Re: Domain Support)

"Rod Taylor" <rbt@zort.ca> writes:

I've not found a cheap resource for the real one. Ie. priced suitably
to fit a hobby project :)

I seem to have parts 1-5 .txt of sql99 on my computer here. I ftp'd them
off some ftp site yonks ago. Anyone want them? Is it legal for me to have
them or distribute them?

Chris

#23Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Christopher Kings-Lynne (#22)
Re: Where to get official SQL spec (was Re: Domain Support)

Christopher Kings-Lynne wrote:

"Rod Taylor" <rbt@zort.ca> writes:

I've not found a cheap resource for the real one. Ie. priced suitably
to fit a hobby project :)

I seem to have parts 1-5 .txt of sql99 on my computer here. I ftp'd them
off some ftp site yonks ago. Anyone want them? Is it legal for me to have
them or distribute them?

I have these URL's:

http://www.ansi.org
http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt
ftp://gatekeeper.dec.com/pub/standards/sql
ftp://jerry.ece.umassd.edu/isowg3/x3h2/Standards/

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
#24Tom Lane
tgl@sss.pgh.pa.us
In reply to: Christopher Kings-Lynne (#22)
Re: Where to get official SQL spec (was Re: Domain Support)

"Christopher Kings-Lynne" <chriskl@familyhealth.com.au> writes:

I seem to have parts 1-5 .txt of sql99 on my computer here. I ftp'd them
off some ftp site yonks ago. Anyone want them? Is it legal for me to have
them or distribute them?

My understanding of the legal situation is that what's circulating
around the net in plain text form is *draft* versions of the spec.
It is okay to redistribute these freely. The *official* version
you are supposed to pay for.

No, I don't know how close the drafts really are to the final.

Personally I tend to consult the draft versions more than the PDF
versions anyway, because it's vastly easier to search flat ASCII
files than PDFs ... so I sure hope they're pretty close ...

regards, tom lane

#25Nicolas Bazin
nbazin@ingenico.com.au
In reply to: Christopher Kings-Lynne (#22)
Re: Where to get official SQL spec (was Re: Domain Support)

It would be nice to add it to the docs of the project.
----- Original Message -----
From: "Tom Lane" <tgl@sss.pgh.pa.us>
To: "Christopher Kings-Lynne" <chriskl@familyhealth.com.au>
Cc: "Rod Taylor" <rbt@zort.ca>; "Hackers List"
<pgsql-hackers@postgresql.org>
Sent: Friday, March 22, 2002 1:29 PM
Subject: Re: [HACKERS] Where to get official SQL spec (was Re: Domain
Support)

"Christopher Kings-Lynne" <chriskl@familyhealth.com.au> writes:

I seem to have parts 1-5 .txt of sql99 on my computer here. I ftp'd

them

off some ftp site yonks ago. Anyone want them? Is it legal for me to

have

Show quoted text

them or distribute them?

My understanding of the legal situation is that what's circulating
around the net in plain text form is *draft* versions of the spec.
It is okay to redistribute these freely. The *official* version
you are supposed to pay for.

No, I don't know how close the drafts really are to the final.

Personally I tend to consult the draft versions more than the PDF
versions anyway, because it's vastly easier to search flat ASCII
files than PDFs ... so I sure hope they're pretty close ...

regards, tom lane

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

#26Thomas Lockhart
thomas@fourpalms.org
In reply to: Christopher Kings-Lynne (#22)
Re: Where to get official SQL spec (was Re: Domain Support)

It would be nice to add it to the docs of the project.

If anyone wants a copy, just holler. A bunch of us have exchanged those
drafts over the years so speak up and someone will forward you a copy...

I'm sure we stumbled on them via google or somesuch so a quick search
would get you an independent copy too...

- Thomas

#27Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Thomas Lockhart (#26)
Re: Where to get official SQL spec (was Re: Domain Support)

Thomas Lockhart wrote:

It would be nice to add it to the docs of the project.

If anyone wants a copy, just holler. A bunch of us have exchanged those
drafts over the years so speak up and someone will forward you a copy...

I'm sure we stumbled on them via google or somesuch so a quick search
would get you an independent copy too...

Should I add the URL's to the developer's FAQ?

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
#28Nicolas Bazin
nbazin@ingenico.com.au
In reply to: Christopher Kings-Lynne (#22)
Re: Where to get official SQL spec (was Re: Domain Support)

Does it mean that we are not 100% sure they are open documents?
----- Original Message -----
From: "Thomas Lockhart" <thomas@fourpalms.org>
To: "Nicolas Bazin" <nbazin@ingenico.com.au>
Cc: "Christopher Kings-Lynne" <chriskl@familyhealth.com.au>; "Tom Lane"
<tgl@sss.pgh.pa.us>; "Rod Taylor" <rbt@zort.ca>; "Hackers List"
<pgsql-hackers@postgresql.org>
Sent: Friday, March 22, 2002 3:36 PM
Subject: Re: Where to get official SQL spec (was Re: Domain Support)

Show quoted text

It would be nice to add it to the docs of the project.

If anyone wants a copy, just holler. A bunch of us have exchanged those
drafts over the years so speak up and someone will forward you a copy...

I'm sure we stumbled on them via google or somesuch so a quick search
would get you an independent copy too...

- Thomas

#29Thomas Lockhart
thomas@fourpalms.org
In reply to: Christopher Kings-Lynne (#22)
Re: Where to get official SQL spec (was Re: Domain Support)

Does it mean that we are not 100% sure they are open documents?

Hmm. Yeah, though afaics there is no copyright inside the docs.

- Thomas

#30Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Tom Lane (#21)
Re: Where to get official SQL spec (was Re: Domain Support)

I have updated the developer's FAQ with this information:

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

1.12) Where can I get a copy of the SQL standards?

There are two pertinent standards, SQL92 and SQL99. These standards are
endorsed by ANSI and ISO. A draft of the SQL92 standard is available at
http://www.contrib.andrew.cmu.edu/~shadow/. The SQL99 standard must be
purchased from ANSI at
http://webstore.ansi.org/ansidocstore/default.asp. The main standards
documents are ANSI X3.135-1992 for SQL92 and ANSI/ISO/IEC 9075-2-1999
for SQL99.

A summary of these standards is at
http://dbs.uni-leipzig.de/en/lokal/standards.pdf and
http://db.konkuk.ac.kr/present/SQL3.pdf.

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

Tom Lane wrote:

"Rod Taylor" <rbt@zort.ca> writes:

I've not found a cheap resource for the real one. Ie. priced suitably
to fit a hobby project :)

Try ANSI's electronic standards store: they'll sell you PDFs of ANSI's
printing of the spec at a reasonable price.

http://webstore.ansi.org/ansidocstore/default.asp

Go to the "search" page and enter "9075" (the IS number for SQL).
Along with the overpriced ISO offerings, there are:

ANSI X3.135-1992 SQL92

ANSI/ISO/IEC 9075-n-1999 SQL99, parts 1-5

Each of these is $18 US. You don't really need all five parts of
SQL99; I've seldom found any use for anything but part 2. It is
worth having SQL92, mainly because it's so much more readable
than the 99 spec :-(

regards, tom lane

---------------------------(end of broadcast)---------------------------
TIP 5: Have you checked our extensive FAQ?

http://www.postgresql.org/users-lounge/docs/faq.html

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026