diff --git a/doc/src/sgml/ref/allfiles.sgml b/doc/src/sgml/ref/allfiles.sgml
index bd8c3e71f1f12e08ac5fc342753e7353cbc71173..9a06b19d4eeca13cb0f7ddee85ccf94180cc6cfb 100644
--- a/doc/src/sgml/ref/allfiles.sgml
+++ b/doc/src/sgml/ref/allfiles.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.49 2002/09/07 16:49:50 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.50 2002/12/06 03:28:27 momjian Exp $
 PostgreSQL documentation
 Complete list of usable sgml source files in this directory.
 -->
@@ -38,6 +38,7 @@ Complete list of usable sgml source files in this directory.
 <!-- SQL commands -->
 <!entity abort              system "abort.sgml">
 <!entity alterDatabase      system "alter_database.sgml">
+<!entity alterDomain        system "alter_domain.sgml">
 <!entity alterGroup         system "alter_group.sgml">
 <!entity alterTable         system "alter_table.sgml">
 <!entity alterTrigger       system "alter_trigger.sgml">
diff --git a/doc/src/sgml/ref/alter_domain.sgml b/doc/src/sgml/ref/alter_domain.sgml
new file mode 100644
index 0000000000000000000000000000000000000000..8c26e01706f5460f071e974d25a6adee79070b25
--- /dev/null
+++ b/doc/src/sgml/ref/alter_domain.sgml
@@ -0,0 +1,237 @@
+<!--
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_domain.sgml,v 1.1 2002/12/06 03:28:27 momjian Exp $
+PostgreSQL documentation
+-->
+
+<refentry id="SQL-ALTERDOMAIN">
+ <refmeta>
+  <refentrytitle id="sql-alterdomain-title">ALTER DOMAIN</refentrytitle>
+  <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+ <refnamediv>
+  <refname>
+   ALTER DOMAIN
+  </refname>
+  <refpurpose>
+   change the definition of a table
+  </refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+  <refsynopsisdivinfo>
+   <date>2002-11-27</date>
+  </refsynopsisdivinfo>
+  <synopsis>
+ALTER DOMAIN <replaceable class="PARAMETER">domain</replaceable>
+    { SET DEFAULT <replaceable class="PARAMETER">value</replaceable> | DROP DEFAULT }
+ALTER DOMAIN <replaceable class="PARAMETER">domain</replaceable>
+    { SET | DROP } NOT NULL
+ALTER DOMAIN <replaceable class="PARAMETER">domain</replaceable>
+    ADD <replaceable class="PARAMETER">domain_constraint</replaceable>
+ALTER DOMAIN <replaceable class="PARAMETER">domain</replaceable>
+    DROP CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> [ RESTRICT | CASCADE ]
+  </synopsis>
+
+  <refsect2 id="R2-SQL-ALTERDOMAIN-1">
+   <refsect2info>
+    <date>2002-11-27</date>
+   </refsect2info>
+   <title>
+    Inputs
+   </title>
+   <para>
+    <variablelist>
+
+     <varlistentry>
+      <term><replaceable class="PARAMETER"> domain </replaceable></term>
+      <listitem>
+       <para>
+	The name (possibly schema-qualified) of an existing domain to
+	alter.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><replaceable class="PARAMETER"> domain_constraint </replaceable></term>
+      <listitem>
+       <para>
+	New domain constraint for the domain.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><replaceable class="PARAMETER"> constraint_name </replaceable></term>
+      <listitem>
+       <para>
+	Name of an existing constraint to drop.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term>CASCADE</term>
+      <listitem>
+       <para>
+        Automatically drop objects that depend constraint.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term>RESTRICT</term>
+      <listitem>
+       <para>
+        Refuse to drop the constraint if there are any dependent
+	objects. This is the default behavior.
+       </para>
+      </listitem>
+     </varlistentry>
+
+    </variablelist>
+   </para>
+  </refsect2>
+
+  <refsect2 id="R2-SQL-ALTERDOMAIN-2">
+   <refsect2info>
+    <date>1998-04-15</date>
+   </refsect2info>
+   <title>
+    Outputs
+   </title>
+   <para>
+
+    <variablelist>
+     <varlistentry>
+      <term><computeroutput>ALTER DOMAIN</computeroutput></term>
+      <listitem>
+       <para>
+	Message returned from domain alteration.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><computeroutput>ERROR</computeroutput></term>
+      <listitem>
+       <para>
+	Message returned if domain is not available.
+       </para>
+      </listitem>
+     </varlistentry>
+    </variablelist>
+   </para>
+  </refsect2>
+ </refsynopsisdiv>
+
+ <refsect1 id="R1-SQL-ALTERDOMAIN-1">
+  <refsect1info>
+   <date>2002-11-27</date>
+  </refsect1info>
+  <title>
+   Description
+  </title>
+  <para>
+   <command>ALTER DOMAIN</command> changes the definition of an existing domain.
+   There are several sub-forms:
+  </para>
+
+  <variablelist>
+   <varlistentry>
+    <term>SET/DROP DEFAULT</term>
+    <listitem>
+     <para>
+      These forms set or remove the default value for a column. Note
+      that defaults only apply to subsequent <command>INSERT</command>
+      commands; they do not cause rows already in a table using the domain.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term>SET/DROP NOT NULL</term>
+    <listitem>
+     <para>
+      These forms change whether a domain is marked to allow NULL
+      values or to reject NULL values.  You may only <literal>SET NOT NULL</>
+      when the tables using the domain contain no null values in the domain
+      based column.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term>ADD <replaceable class="PARAMETER">domain_constraint</replaceable></term>
+    <listitem>
+     <para>
+      This form adds a new constraint to a table using the same syntax as
+      <xref linkend="SQL-CREATEDOMAIN" endterm="SQL-CREATEDOMAIN-TITLE">. 
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term>DROP CONSTRAINT</term>
+    <listitem>
+     <para>
+      This form drops constraints on a domain.
+     </para>
+    </listitem>
+   </varlistentry>
+
+  </variablelist>
+
+  <para>
+   You must own the domain to use <command>ALTER DOMAIN</>; except for
+   <command>ALTER TABLE OWNER</>, which may only be executed by a superuser.
+  </para>
+ </refsect1>
+
+ <refsect1 id="R1-SQL-ALTERDOMAIN-2">
+  <title>
+   Usage
+  </title>
+  <para>
+   To add a NOT NULL constraint to a column:
+   <programlisting>
+ALTER DOMAIN zipcode SET NOT NULL;
+   </programlisting>
+   To remove a NOT NULL constraint from a column:
+   <programlisting>
+ALTER DOMAIN zipcode DROP NOT NULL;
+   </programlisting>
+  </para>
+
+  <para> 
+   To add a check constraint to a table:
+   <programlisting>
+ALTER DOMAIN zipcode ADD CONSTRAINT zipchk CHECK (char_length(VALUE) = 5);
+   </programlisting>
+  </para>
+
+  <para> 
+   To remove a check constraint from a table and all its children:
+   <programlisting>
+ALTER DOMAIN zipcode DROP CONSTRAINT zipchk;
+   </programlisting>
+  </para>
+ </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:nil
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:1
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:"../reference.ced"
+sgml-exposed-tags:nil
+sgml-local-catalogs:"/usr/lib/sgml/catalog"
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/src/sgml/reference.sgml b/doc/src/sgml/reference.sgml
index 247ce8d8ce0ccfcf906b6640a442b41634838bcf..8709343c3c130a083f6a032923aa87026528309a 100644
--- a/doc/src/sgml/reference.sgml
+++ b/doc/src/sgml/reference.sgml
@@ -1,5 +1,5 @@
 <!-- reference.sgml
-$Header: /cvsroot/pgsql/doc/src/sgml/reference.sgml,v 1.38 2002/09/08 02:33:08 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/reference.sgml,v 1.39 2002/12/06 03:28:27 momjian Exp $
 
 PostgreSQL Reference Manual
 -->
@@ -47,6 +47,7 @@ PostgreSQL Reference Manual
 
    &abort;
    &alterDatabase;
+   &alterDomain;
    &alterGroup;
    &alterTable;
    &alterTrigger;
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index c679c61e12ae2b25134849986e9f4796e259944c..3fb609b3f1b1fa51488f728a20c576db63d43240 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.14 2002/12/04 20:00:37 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.15 2002/12/06 03:28:27 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -36,6 +36,7 @@
 #include "commands/proclang.h"
 #include "commands/schemacmds.h"
 #include "commands/trigger.h"
+#include "commands/typecmds.h"
 #include "lib/stringinfo.h"
 #include "miscadmin.h"
 #include "optimizer/clauses.h"
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 7cd105928c331309c96539c82ef20bbc9a30d3f0..d4e06a17e00cdacdf705c4a366adc1de3a1dc1dc 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_constraint.c,v 1.8 2002/11/15 02:50:05 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_constraint.c,v 1.9 2002/12/06 03:28:27 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -199,6 +199,7 @@ CreateConstraintEntry(const char *constraintName,
 
 		domobject.classId = RelOid_pg_type;
 		domobject.objectId = domainId;
+		domobject.objectSubId = 0;
 
 		recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO);
 	}
@@ -496,15 +497,16 @@ RemoveConstraintById(Oid conId)
 		HeapTuple	typTup;
 		ScanKeyData typKey[1];
 		SysScanDesc typScan;
+		int			nkeys = 0;
 
 		typRel = heap_openr(TypeRelationName, RowExclusiveLock);
 
-		ScanKeyEntryInitialize(&typKey[0], 0x0,
-							   Anum_pg_constraint_contypid, F_OIDEQ,
+		ScanKeyEntryInitialize(&typKey[nkeys++], 0x0,
+							   ObjectIdAttributeNumber, F_OIDEQ,
 							   ObjectIdGetDatum(con->contypid));
 
 		typScan = systable_beginscan(typRel, TypeOidIndex, true,
-									 SnapshotNow, 1, typKey);
+									 SnapshotNow, nkeys, typKey);
 
 		typTup = systable_getnext(typScan);
 
@@ -517,6 +519,11 @@ RemoveConstraintById(Oid conId)
 		/* Keep lock on domain type until end of xact */
 		heap_close(typRel, NoLock);
 	}
+	else
+	{
+		elog(ERROR, "RemoveConstraintById: Constraint %u is not a known type",
+			 conId);
+	}
 
 	/* Fry the constraint itself */
 	simple_heap_delete(conDesc, &tup->t_self);
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index d43c1edeeedd3e831e3c701cfb83f3b9dcc01e63..25721ebd42ef7e85560864f26fe5c92f97c355b9 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.82 2002/09/04 20:31:14 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.83 2002/12/06 03:28:27 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -139,7 +139,7 @@ TypeCreate(const char *typeName,
 		   Oid elementType,
 		   Oid baseType,
 		   const char *defaultTypeValue,		/* human readable rep */
-		   const char *defaultTypeBin,	/* cooked rep */
+		   char *defaultTypeBin,	/* cooked rep */
 		   bool passedByValue,
 		   char alignment,
 		   char storage,
@@ -291,87 +291,125 @@ TypeCreate(const char *typeName,
 	 */
 	if (!IsBootstrapProcessingMode())
 	{
-		ObjectAddress myself,
-					referenced;
-
-		myself.classId = RelOid_pg_type;
-		myself.objectId = typeObjectId;
-		myself.objectSubId = 0;
-
-		/* dependency on namespace */
-		/* skip for relation rowtype, since we have indirect dependency */
-		if (!OidIsValid(relationOid))
-		{
-			referenced.classId = get_system_catalog_relid(NamespaceRelationName);
-			referenced.objectId = typeNamespace;
-			referenced.objectSubId = 0;
-			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
-		}
-
-		/* Normal dependencies on the I/O functions */
-		referenced.classId = RelOid_pg_proc;
-		referenced.objectId = inputProcedure;
-		referenced.objectSubId = 0;
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		GenerateTypeDependencies(typeNamespace,
+								 typeObjectId,
+								 relationOid,
+								 relationKind,
+								 inputProcedure,
+								 outputProcedure,
+								 elementType,
+								 baseType,
+								 defaultTypeBin,
+								 false);
+	}
+
+	/*
+	 * finish up
+	 */
+	heap_close(pg_type_desc, RowExclusiveLock);
+
+	return typeObjectId;
+}
 
-		referenced.classId = RelOid_pg_proc;
-		referenced.objectId = outputProcedure;
+void
+GenerateTypeDependencies(Oid typeNamespace,
+						 Oid typeObjectId,
+						 Oid relationOid,		/* only for 'c'atalog typeType */
+						 char relationKind,
+						 Oid inputProcedure,
+						 Oid outputProcedure,
+						 Oid elementType,
+						 Oid baseType,
+						 char *defaultTypeBin,	/* cooked rep */
+						 bool rebuild)
+{
+	ObjectAddress myself,
+				referenced;
+
+	/*
+	 * If true, we need to remove all current dependencies that the type
+	 * holds, and rebuild them from scratch.  This allows us to easily 
+	 * implement alter type, and alter domain statements.
+	 */
+	if (rebuild)
+		deleteDependencyRecordsFor(RelOid_pg_type,
+								   typeObjectId);
+
+	myself.classId = RelOid_pg_type;
+	myself.objectId = typeObjectId;
+	myself.objectSubId = 0;
+
+	/* dependency on namespace */
+	/* skip for relation rowtype, since we have indirect dependency */
+	if (!OidIsValid(relationOid))
+	{
+		referenced.classId = get_system_catalog_relid(NamespaceRelationName);
+		referenced.objectId = typeNamespace;
 		referenced.objectSubId = 0;
 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	}
 
-		/*
-		 * If the type is a rowtype for a relation, mark it as internally
-		 * dependent on the relation, *unless* it is a stand-alone
-		 * composite type relation. For the latter case, we have to
-		 * reverse the dependency.
-		 *
-		 * In the former case, this allows the type to be auto-dropped when
-		 * the relation is, and not otherwise. And in the latter, of
-		 * course we get the opposite effect.
-		 */
-		if (OidIsValid(relationOid))
-		{
-			referenced.classId = RelOid_pg_class;
-			referenced.objectId = relationOid;
-			referenced.objectSubId = 0;
-
-			if (relationKind != RELKIND_COMPOSITE_TYPE)
-				recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
-			else
-				recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
-		}
+	/* Normal dependencies on the I/O functions */
+	referenced.classId = RelOid_pg_proc;
+	referenced.objectId = inputProcedure;
+	referenced.objectSubId = 0;
+	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
-		/*
-		 * If the type is an array type, mark it auto-dependent on the
-		 * base type.  (This is a compromise between the typical case
-		 * where the array type is automatically generated and the case
-		 * where it is manually created: we'd prefer INTERNAL for the
-		 * former case and NORMAL for the latter.)
-		 */
-		if (OidIsValid(elementType))
-		{
-			referenced.classId = RelOid_pg_type;
-			referenced.objectId = elementType;
-			referenced.objectSubId = 0;
-			recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
-		}
-
-		/* Normal dependency from a domain to its base type. */
-		if (OidIsValid(baseType))
-		{
-			referenced.classId = RelOid_pg_type;
-			referenced.objectId = baseType;
-			referenced.objectSubId = 0;
-			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
-		}
+	referenced.classId = RelOid_pg_proc;
+	referenced.objectId = outputProcedure;
+	referenced.objectSubId = 0;
+	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+	/*
+	 * If the type is a rowtype for a relation, mark it as internally
+	 * dependent on the relation, *unless* it is a stand-alone
+	 * composite type relation. For the latter case, we have to
+	 * reverse the dependency.
+	 *
+	 * In the former case, this allows the type to be auto-dropped when
+	 * the relation is, and not otherwise. And in the latter, of
+	 * course we get the opposite effect.
+	 */
+	if (OidIsValid(relationOid))
+	{
+		referenced.classId = RelOid_pg_class;
+		referenced.objectId = relationOid;
+		referenced.objectSubId = 0;
+
+		if (relationKind != RELKIND_COMPOSITE_TYPE)
+			recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
+		else
+			recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
 	}
 
 	/*
-	 * finish up
+	 * If the type is an array type, mark it auto-dependent on the
+	 * base type.  (This is a compromise between the typical case
+	 * where the array type is automatically generated and the case
+	 * where it is manually created: we'd prefer INTERNAL for the
+	 * former case and NORMAL for the latter.)
 	 */
-	heap_close(pg_type_desc, RowExclusiveLock);
+	if (OidIsValid(elementType))
+	{
+		referenced.classId = RelOid_pg_type;
+		referenced.objectId = elementType;
+		referenced.objectSubId = 0;
+		recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
+	}
 
-	return typeObjectId;
+	/* Normal dependency from a domain to its base type. */
+	if (OidIsValid(baseType))
+	{
+		referenced.classId = RelOid_pg_type;
+		referenced.objectId = baseType;
+		referenced.objectSubId = 0;
+		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	}
+
+	/* Dependency on the default expression */
+	if (defaultTypeBin)
+		recordDependencyOnExpr(&myself, stringToNode(defaultTypeBin),
+							   NIL, DEPENDENCY_NORMAL);
 }
 
 /*
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 3009059549d28e63e4e3ea91229ca2af521d10b2..4822ae4160a0c7f469e61aba9cdf3405b73fbcb1 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.99 2002/12/05 04:04:42 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.100 2002/12/06 03:28:27 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -667,7 +667,7 @@ cluster(ClusterStmt *stmt)
 		tableOid = RangeVarGetRelid(stmt->relation, false);
 		if (!check_cluster_ownership(tableOid))
 			elog(ERROR, "CLUSTER: You do not own relation %s",
-					stmt->relation->relname);
+				 stmt->relation->relname);
 
 		tuple = SearchSysCache(RELOID,
 							   ObjectIdGetDatum(tableOid),
@@ -706,7 +706,7 @@ cluster(ClusterStmt *stmt)
 			}
 			if (indexOid == InvalidOid)
 				elog(ERROR, "CLUSTER: No previously clustered index found on table %s",
-						stmt->relation->relname);
+					 stmt->relation->relname);
 			RelationClose(rel);
 			ReleaseSysCache(ituple);
 			ReleaseSysCache(idxtuple);
@@ -721,7 +721,7 @@ cluster(ClusterStmt *stmt)
 		/* XXX Maybe the namespace should be reported as well */
 		if (!OidIsValid(indexOid))
 			elog(ERROR, "CLUSTER: cannot find index \"%s\" for table \"%s\"",
-					stmt->indexname, stmt->relation->relname);
+				 stmt->indexname, stmt->relation->relname);
 		rvtc.tableOid = tableOid;
 		rvtc.indexOid = indexOid;
 		rvtc.isPrevious = false;
@@ -819,7 +819,7 @@ get_tables_to_cluster(AclId owner)
 	List		   *rvs = NIL;
 
 	/*
-	 * Get all indexes that have indisclustered set.	System
+	 * Get all indexes that have indisclustered set. System
 	 * relations or nailed-in relations cannot ever have
 	 * indisclustered set, because CLUSTER will refuse to
 	 * set it when called with one of them as argument.
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index ab0608a08a9cdeba90c52d98959e2e3a30d6c142..ebae0e272de0149d78bb3f0b85a691cf7035561b 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.17 2002/11/15 02:50:06 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.18 2002/12/06 03:28:27 momjian Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -32,14 +32,18 @@
 #include "postgres.h"
 
 #include "access/heapam.h"
+#include "access/genam.h"
 #include "catalog/catname.h"
 #include "catalog/dependency.h"
 #include "catalog/heap.h"
+#include "catalog/indexing.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_constraint.h"
 #include "catalog/pg_type.h"
 #include "commands/defrem.h"
 #include "commands/tablecmds.h"
+#include "commands/typecmds.h"
+#include "executor/executor.h"
 #include "miscadmin.h"
 #include "nodes/nodes.h"
 #include "optimizer/clauses.h"
@@ -48,6 +52,7 @@
 #include "parser/parse_coerce.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_func.h"
+#include "parser/parse_relation.h"
 #include "parser/parse_type.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
@@ -55,8 +60,21 @@
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
-
 static Oid	findTypeIOFunction(List *procname, Oid typeOid, bool isOutput);
+static List *get_rels_with_domain(Oid domainOid);
+static void domainPermissionCheck(HeapTuple tup, TypeName *typename);
+static void domainCheckForUnsupportedConstraints(Node *newConstraint);
+static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
+								 Oid baseTypeOid,
+								 int typMod, Constraint *constr,
+								 int *counter, char *domainName);
+
+typedef struct
+{
+	Oid		relOid;
+	int		natts;
+	int		*atts;
+} relToCheck;
 
 /*
  * DefineType
@@ -501,12 +519,14 @@ DefineDomain(CreateDomainStmt *stmt)
 		Constraint *colDef;
 		ParseState *pstate;
 
-		/* Prior to processing, confirm that it is not a foreign key constraint */
-		if (nodeTag(newConstraint) == T_FkConstraint)
-			elog(ERROR, "CREATE DOMAIN / FOREIGN KEY constraints not supported");
+		/*
+		 * Check for constraint types which are not supported by
+		 * domains.  Throws an error if it finds one.
+		 */
+		domainCheckForUnsupportedConstraints(newConstraint);
 
+		/* Assume its a CHECK, DEFAULT, NULL or NOT NULL constraint */
 		colDef = (Constraint *) newConstraint;
-
 		switch (colDef->contype)
 		{
 				/*
@@ -560,25 +580,17 @@ DefineDomain(CreateDomainStmt *stmt)
 				nullDefined = true;
 		  		break;
 
-		  	case CONSTR_UNIQUE:
-		  		elog(ERROR, "CREATE DOMAIN / UNIQUE indexes not supported");
-		  		break;
-
-		  	case CONSTR_PRIMARY:
-		  		elog(ERROR, "CREATE DOMAIN / PRIMARY KEY indexes not supported");
-		  		break;
-
-			/* Check constraints are handled after domain creation */
+			/*
+			 * Check constraints are handled after domain creation, as they require
+			 * the Oid of the domain
+			 */
 		  	case CONSTR_CHECK:
 		  		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;
-
+			/*
+			 * If we reach this, then domainCheckForUnsupportedConstraints()
+			 * doesn't have a complete list of unsupported domain constraints
+			 */
 			default:
 				elog(ERROR, "DefineDomain: unrecognized constraint node type");
 				break;
@@ -616,142 +628,26 @@ DefineDomain(CreateDomainStmt *stmt)
 	foreach(listptr, schema)
 	{
 		Constraint *constr = lfirst(listptr);
-		ParseState *pstate;
 
 		switch (constr->contype)
 		{
 		  	case CONSTR_CHECK:
 				{
-					Node	   *expr;
-					char	   *ccsrc;
-					char	   *ccbin;
-					ConstraintTestValue  *domVal;
-
-					/*
-					 * Assign or validate constraint name
-					 */
-					if (constr->name)
-					{
-						if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
-												 domainoid,
-												 domainNamespace,
-												 constr->name))
-							elog(ERROR, "constraint \"%s\" already exists for domain \"%s\"",
-									constr->name,
-									domainName);
-					}
-					else
-						constr->name = GenerateConstraintName(CONSTRAINT_DOMAIN,
-															  domainoid,
-															  domainNamespace,
-															  &counter);
-
-					/*
-					 * Convert the A_EXPR in raw_expr into an
-					 * EXPR
-					 */
-					pstate = make_parsestate(NULL);
-
-					/*
-					 * We want to have the domain VALUE node type filled in so
-					 * that proper casting can occur.
-					 */
-					domVal = makeNode(ConstraintTestValue);
-					domVal->typeId = basetypeoid;
-					domVal->typeMod = stmt->typename->typmod;
-
-					expr = transformExpr(pstate, constr->raw_expr, domVal);
-
-					/*
-					 * Domains don't allow var clauses
-					 */
-					if (contain_var_clause(expr))
-						elog(ERROR, "cannot use column references in domain CHECK clause");
-
-					/*
-					 * Make sure it yields a boolean result.
-					 */
-					expr = coerce_to_boolean(expr, "CHECK");
-
-					/*
-					 * Make sure no outside relations are
-					 * referred to.
-					 */
-					if (length(pstate->p_rtable) != 0)
-						elog(ERROR, "Relations cannot be referenced in domain CHECK constraint");
-
-					/*
-					 * No subplans or aggregates, either...
-					 */
-					if (contain_subplans(expr))
-						elog(ERROR, "cannot use subselect in CHECK constraint expression");
-					if (contain_agg_clause(expr))
-						elog(ERROR, "cannot use aggregate function in CHECK constraint expression");
-
-					/*
-					 * Might as well try to reduce any constant expressions.
-					 */
-					expr = eval_const_expressions(expr);
-
-					/*
-					 * Must fix opids in operator clauses.
-					 */
-					fix_opids(expr);
-
-					ccbin = nodeToString(expr);
-
-					/*
-					 * Deparse it.  Since VARNOs aren't allowed in domain
-					 * constraints, relation context isn't required as anything
-					 * other than a shell.
-					 */
-					ccsrc = deparse_expression(expr,
-								deparse_context_for(domainName,
-													InvalidOid),
-												   false, false);
-
-					/* Write the constraint */
-					CreateConstraintEntry(constr->name,		/* Constraint Name */
-										  domainNamespace,	/* namespace */
-										  CONSTRAINT_CHECK,		/* Constraint Type */
-										  false,	/* Is Deferrable */
-										  false,	/* Is Deferred */
-										  InvalidOid,		/* not a relation constraint */
-										  NULL,	
-										  0,
-										  domainoid,	/* domain constraint */
-										  InvalidOid,	/* Foreign key fields */
-										  NULL,
-										  0,
-										  ' ',
-										  ' ',
-										  ' ',
-										  InvalidOid,
-										  expr, 	/* Tree form check constraint */
-										  ccbin,	/* Binary form check constraint */
-										  ccsrc);	/* Source form check constraint */
+					char   *junk;
+
+					/* Returns the cooked constraint which is not needed during creation */
+					junk = domainAddConstraint(domainoid, domainNamespace,
+											   basetypeoid, stmt->typename->typmod,
+											   constr, &counter, domainName);
 				}
 		  		break;
+
+			/* Errors for other constraints are taken care of prior to domain creation */
 			default:
 		  		break;
 		}
 	}
 
-	/*
-	 * Add any dependencies needed for the default expression.
-	 */
-	if (defaultExpr)
-	{
-		ObjectAddress domobject;
-
-		domobject.classId = RelOid_pg_type;
-		domobject.objectId = domainoid;
-		domobject.objectSubId = 0;
-
-		recordDependencyOnExpr(&domobject, defaultExpr, NIL,
-							   DEPENDENCY_NORMAL);
-	}
-
 	/*
 	 * Now we can clean up.
 	 */
@@ -931,7 +827,8 @@ findTypeIOFunction(List *procname, Oid typeOid, bool isOutput)
 		if (OidIsValid(procOid))
 		{
 			/* Found, but must complain and fix the pg_proc entry */
-			elog(NOTICE, "TypeCreate: changing argument type of function %s from OPAQUE to CSTRING",
+			elog(NOTICE, "TypeCreate: changing argument type of function %s "
+				 "from OPAQUE to CSTRING",
 				 NameListToString(procname));
 			SetFunctionArgType(procOid, 0, CSTRINGOID);
 			/*
@@ -992,3 +889,778 @@ DefineCompositeType(const RangeVar *typevar, List *coldeflist)
 	 */
 	return DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE);
 }
+
+/*
+ * AlterDomainDefault
+ *
+ * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements. 
+ */
+void
+AlterDomainDefault(List *names, Node *defaultRaw)
+{
+	TypeName   *typename;
+	Oid			domainoid;
+	HeapTuple	tup;
+	ParseState *pstate;
+	Relation	rel;
+	char	   *defaultValue;
+	Node	   *defaultExpr = NULL; /* NULL if no default specified */
+	Datum		new_record[Natts_pg_type];
+	char		new_record_nulls[Natts_pg_type];
+	char		new_record_repl[Natts_pg_type];
+	HeapTuple	newtuple;
+	Form_pg_type	typTup;
+
+	/* Make a TypeName so we can use standard type lookup machinery */
+	typename = makeNode(TypeName);
+	typename->names = names;
+	typename->typmod = -1;
+	typename->arrayBounds = NIL;
+
+	/* Lock the domain in the type table */
+	rel = heap_openr(TypeRelationName, RowExclusiveLock);
+
+	/* Use LookupTypeName here so that shell types can be removed. */
+	domainoid = LookupTypeName(typename);
+	if (!OidIsValid(domainoid))
+		elog(ERROR, "Type \"%s\" does not exist",
+			 TypeNameToString(typename));
+
+	tup = SearchSysCacheCopy(TYPEOID,
+							 ObjectIdGetDatum(domainoid),
+							 0, 0, 0);
+
+	if (!HeapTupleIsValid(tup))
+		elog(ERROR, "AlterDomain: type \"%s\" does not exist",
+			 TypeNameToString(typename));
+
+	/* Doesn't return if user isn't allowed to alter the domain */ 
+	domainPermissionCheck(tup, typename);
+
+	/* Setup new tuple */
+	MemSet(new_record, (Datum) 0, sizeof(new_record));
+	MemSet(new_record_nulls, ' ', sizeof(new_record_nulls));
+	MemSet(new_record_repl, ' ', sizeof(new_record_repl));
+
+	/* Useful later */
+	typTup = (Form_pg_type) GETSTRUCT(tup);
+
+	/* Store the new default, if null then skip this step */
+	if (defaultRaw)
+	{
+		/* Create a dummy ParseState for transformExpr */
+		pstate = make_parsestate(NULL);
+		/*
+		 * Cook the colDef->raw_expr into an expression. Note:
+		 * Name is strictly for error message
+		 */
+		defaultExpr = cookDefault(pstate, defaultRaw,
+								  typTup->typbasetype,
+								  typTup->typtypmod,
+								  NameStr(typTup->typname));
+
+		/*
+		 * Expression must be stored as a nodeToString result, but
+		 * we also require a valid textual representation (mainly
+		 * to make life easier for pg_dump).
+		 */
+		defaultValue = deparse_expression(defaultExpr,
+								  deparse_context_for(NameStr(typTup->typname),
+													  InvalidOid),
+										  false, false);
+		/*
+		 * Form an updated tuple with the new default and write it back.
+		 */
+		new_record[Anum_pg_type_typdefaultbin - 1] = DirectFunctionCall1(textin,
+														CStringGetDatum(
+															nodeToString(defaultExpr)));
+
+		new_record_repl[Anum_pg_type_typdefaultbin - 1] = 'r';
+		new_record[Anum_pg_type_typdefault - 1] = DirectFunctionCall1(textin,
+								   					CStringGetDatum(defaultValue));
+		new_record_repl[Anum_pg_type_typdefault - 1] = 'r';
+	}
+	else /* Default is NULL, drop it */
+	{
+		new_record_nulls[Anum_pg_type_typdefaultbin - 1] = 'n';
+		new_record_repl[Anum_pg_type_typdefaultbin - 1] = 'r';
+		new_record_nulls[Anum_pg_type_typdefault - 1] = 'n';
+		new_record_repl[Anum_pg_type_typdefault - 1] = 'r';
+	}
+
+	newtuple = heap_modifytuple(tup, rel,
+								new_record, new_record_nulls, new_record_repl);
+
+	simple_heap_update(rel, &tup->t_self, newtuple);
+
+	CatalogUpdateIndexes(rel, newtuple);
+
+	/* Rebuild dependencies */
+	GenerateTypeDependencies(typTup->typnamespace,
+							 domainoid,
+							 typTup->typrelid,
+							 InvalidOid,
+							 typTup->typinput,
+							 typTup->typoutput,
+							 typTup->typelem,
+							 typTup->typbasetype,
+							 nodeToString(defaultExpr),
+							 true); /* Rebuild is true */
+
+	/* Clean up */
+	heap_close(rel, NoLock);
+	heap_freetuple(newtuple);
+};
+
+/*
+ * AlterDomainNotNull
+ *
+ * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements. 
+ */
+void
+AlterDomainNotNull(List *names, bool notNull)
+{
+	TypeName   *typename;
+	Oid			domainoid;
+	HeapTuple	tup;
+	Relation	rel;
+	Datum		new_record[Natts_pg_type];
+	char		new_record_nulls[Natts_pg_type];
+	char		new_record_repl[Natts_pg_type];
+	HeapTuple	newtuple;
+	Form_pg_type	typTup;
+
+	/* Make a TypeName so we can use standard type lookup machinery */
+	typename = makeNode(TypeName);
+	typename->names = names;
+	typename->typmod = -1;
+	typename->arrayBounds = NIL;
+
+	/* Lock the type table */
+	rel = heap_openr(TypeRelationName, RowExclusiveLock);
+
+	/* Use LookupTypeName here so that shell types can be removed. */
+	domainoid = LookupTypeName(typename);
+	if (!OidIsValid(domainoid))
+		elog(ERROR, "Type \"%s\" does not exist",
+			 TypeNameToString(typename));
+
+	tup = SearchSysCacheCopy(TYPEOID,
+							 ObjectIdGetDatum(domainoid),
+							 0, 0, 0);
+
+	if (!HeapTupleIsValid(tup))
+		elog(ERROR, "AlterDomain: type \"%s\" does not exist",
+			 TypeNameToString(typename));
+
+	/* Doesn't return if user isn't allowed to alter the domain */ 
+	domainPermissionCheck(tup, typename);
+
+	typTup = (Form_pg_type) GETSTRUCT(tup);
+
+	/* Is the domain already set to the destination constraint? */
+	if (typTup->typnotnull == notNull)
+		elog(ERROR, "AlterDomain: %s is already set to %s",
+			 TypeNameToString(typename),
+			 notNull ? "NOT NULL" : "NULL");
+
+	/* Adding a NOT NULL constraint requires checking current domains */
+	if (notNull)
+	{
+		List   *rels;
+		List   *rt;
+
+		/* Fetch relation list with attributes based on this domain */
+		rels = get_rels_with_domain(domainoid);
+
+		foreach (rt, rels)
+		{
+			Relation	typrel;
+			HeapTuple	tuple;
+			HeapScanDesc scan;
+			TupleDesc	tupdesc;
+			relToCheck *rtc = (relToCheck *) lfirst(rt);
+
+			/* Lock relation */
+			typrel = heap_open(rtc->relOid, ExclusiveLock);
+
+			tupdesc = RelationGetDescr(typrel);
+
+			/* Fetch tuples sequentially */
+			scan = heap_beginscan(typrel, SnapshotNow, 0, NULL);
+			while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+			{
+				int		i;
+
+				/* Test attributes */
+				for (i = 0; i < rtc->natts; i++)
+				{
+					Datum	d;
+					bool	isNull;
+
+					d = heap_getattr(tuple, rtc->atts[i], tupdesc, &isNull);
+
+					if (isNull)
+						elog(ERROR, "ALTER DOMAIN: Relation \"%s\" Attribute \"%s\" "
+							 "contains NULL values",
+							 RelationGetRelationName(typrel),
+							 NameStr(*attnumAttName(typrel, rtc->atts[i])));
+				}
+			}
+
+			heap_endscan(scan);
+
+			/* Release lock */
+			heap_close(typrel, NoLock);
+		}
+	}
+
+
+	/* Setup new tuple */
+	MemSet(new_record, (Datum) 0, sizeof(new_record));
+	MemSet(new_record_nulls, ' ', sizeof(new_record_nulls));
+	MemSet(new_record_repl, ' ', sizeof(new_record_repl));
+
+	new_record[Anum_pg_type_typnotnull - 1] = BoolGetDatum(notNull);
+	new_record_repl[Anum_pg_type_typnotnull - 1] = 'r';
+
+	/* Build the new tuple */
+	newtuple = heap_modifytuple(tup, rel,
+								new_record, new_record_nulls, new_record_repl);
+
+	simple_heap_update(rel, &tup->t_self, newtuple);
+
+	CatalogUpdateIndexes(rel, newtuple);
+
+	/* Clean up */
+	heap_close(rel, NoLock);
+	heap_freetuple(newtuple);
+}
+
+/*
+ * AlterDomainDropConstraint
+ *
+ * Implements the ALTER DOMAIN DROP CONSTRAINT statement
+ */
+void
+AlterDomainDropConstraint(List *names, const char *constrName, DropBehavior behavior)
+{
+	TypeName   *typename;
+	Oid			domainoid;
+	HeapTuple	tup;
+	Relation	rel;
+	Form_pg_type	typTup;
+	Relation	conrel;
+	SysScanDesc conscan;
+	ScanKeyData key[1];
+	HeapTuple	contup;
+
+	/* Make a TypeName so we can use standard type lookup machinery */
+	typename = makeNode(TypeName);
+	typename->names = names;
+	typename->typmod = -1;
+	typename->arrayBounds = NIL;
+
+	/* Lock the type table */
+	rel = heap_openr(TypeRelationName, RowExclusiveLock);
+
+	/* Use LookupTypeName here so that shell types can be removed. */
+	domainoid = LookupTypeName(typename);
+	if (!OidIsValid(domainoid))
+		elog(ERROR, "Type \"%s\" does not exist",
+			 TypeNameToString(typename));
+
+	tup = SearchSysCacheCopy(TYPEOID,
+							 ObjectIdGetDatum(domainoid),
+							 0, 0, 0);
+
+	if (!HeapTupleIsValid(tup))
+		elog(ERROR, "AlterDomain: type \"%s\" does not exist",
+			 TypeNameToString(typename));
+
+	/* Doesn't return if user isn't allowed to alter the domain */ 
+	domainPermissionCheck(tup, typename);
+
+	/* Grab an appropriate lock on the pg_constraint relation */
+	conrel = heap_openr(ConstraintRelationName, RowExclusiveLock);
+
+	/* Use the index to scan only constraints of the target relation */
+	ScanKeyEntryInitialize(&key[0], 0x0,
+						   Anum_pg_constraint_contypid, F_OIDEQ,
+						   ObjectIdGetDatum(HeapTupleGetOid(tup)));
+
+	conscan = systable_beginscan(conrel, ConstraintTypidIndex, true,
+								 SnapshotNow, 1, key);
+
+	typTup = (Form_pg_type) GETSTRUCT(tup);
+
+	/*
+	 * Scan over the result set, removing any matching entries.
+	 */
+	while ((contup = systable_getnext(conscan)) != NULL)
+	{
+		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
+
+		if (strcmp(NameStr(con->conname), constrName) == 0)
+		{
+			ObjectAddress conobj;
+
+			conobj.classId = RelationGetRelid(conrel);
+			conobj.objectId = HeapTupleGetOid(contup);
+			conobj.objectSubId = 0;
+
+			performDeletion(&conobj, behavior);
+		}
+	}
+	/* Clean up after the scan */
+	systable_endscan(conscan);
+	heap_close(conrel, RowExclusiveLock);
+
+	heap_close(rel, NoLock);
+};
+
+/*
+ * AlterDomainAddConstraint
+ *
+ * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
+ */
+void
+AlterDomainAddConstraint(List *names, Node *newConstraint)
+{
+	TypeName   *typename;
+	Oid			domainoid;
+	HeapTuple	tup;
+	Relation	rel;
+	List   *rels;
+	List   *rt;
+	Form_pg_type	typTup;
+	char   *ccbin;
+	Node   *expr;
+	int		counter = 0;
+	Constraint *constr;
+
+	/* Make a TypeName so we can use standard type lookup machinery */
+	typename = makeNode(TypeName);
+	typename->names = names;
+	typename->typmod = -1;
+	typename->arrayBounds = NIL;
+
+	/* Lock the type table */
+	rel = heap_openr(TypeRelationName, RowExclusiveLock);
+
+	/* Use LookupTypeName here so that shell types can be removed. */
+	domainoid = LookupTypeName(typename);
+	if (!OidIsValid(domainoid))
+		elog(ERROR, "Type \"%s\" does not exist",
+			 TypeNameToString(typename));
+
+	tup = SearchSysCacheCopy(TYPEOID,
+							 ObjectIdGetDatum(domainoid),
+							 0, 0, 0);
+
+	if (!HeapTupleIsValid(tup))
+		elog(ERROR, "AlterDomain: type \"%s\" does not exist",
+			 TypeNameToString(typename));
+
+
+	/* Doesn't return if user isn't allowed to alter the domain */ 
+	domainPermissionCheck(tup, typename);
+
+	typTup = (Form_pg_type) GETSTRUCT(tup);
+
+
+	/*
+	 * Check for constraint types which are not supported by
+	 * domains.  Throws an error if it finds one.
+	 */
+	domainCheckForUnsupportedConstraints(newConstraint);
+
+	/* Assume its a CHECK, DEFAULT, NULL or NOT NULL constraint */
+	constr = (Constraint *) newConstraint;
+	switch (constr->contype)
+	{
+		case CONSTR_DEFAULT:
+			elog(ERROR, "Use ALTER DOMAIN .. SET DEFAULT instead");
+			break;
+
+		case CONSTR_NOTNULL:
+		case CONSTR_NULL:
+			elog(ERROR, "Use ALTER DOMAIN .. [ SET | DROP ] NOT NULL instead");
+			break;
+
+			/*
+			 * Check constraints are handled after domain creation, as they require
+			 * the Oid of the domain
+			 */
+	  	case CONSTR_CHECK:
+			{
+				/* Returns the cooked constraint which is not needed during creation */
+				ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace,
+											typTup->typbasetype, typTup->typtypmod,
+											constr, &counter, NameStr(typTup->typname));
+			}
+	  		break;
+
+		/*
+		 * If we reach this, then domainCheckForUnsupportedConstraints()
+		 * doesn't have a complete list of unsupported domain constraints
+		 */
+		default:
+			elog(ERROR, "DefineDomain: unrecognized constraint node type");
+			break;
+	}
+
+	/*
+	 * Since all other constraint types throw errors, this must be
+	 * a check constraint, and ccbin must be set.
+	 *
+	 * Test all values stored in the attributes based on the domain
+	 * the constraint is being added to.
+	 */
+	expr = stringToNode(ccbin);
+	rels = get_rels_with_domain(domainoid);
+	foreach (rt, rels)
+	{
+		Relation	typrel;
+		HeapTuple	tuple;
+		HeapScanDesc scan;
+		TupleDesc	tupdesc;
+		ExprContext *econtext;
+		TupleTableSlot *slot;
+		relToCheck *rtc = (relToCheck *) lfirst(rt);
+
+		/* Lock relation */
+		typrel = heap_open(rtc->relOid, ExclusiveLock);
+
+		/* Test attributes */
+		tupdesc = RelationGetDescr(typrel);
+
+		/* Make tuple slot to hold tuples */
+		slot = MakeTupleTableSlot();
+		ExecSetSlotDescriptor(slot, RelationGetDescr(typrel), false);
+
+		/* Make an expression context for ExecQual */
+		econtext = MakeExprContext(slot, CurrentMemoryContext);
+
+		/* Scan through table */
+		scan = heap_beginscan(typrel, SnapshotNow, 0, NULL);
+		while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+		{
+			int		i;
+
+			ExecStoreTuple(tuple, slot, InvalidBuffer, false);
+
+			/* Loop through each attribute of the tuple with a domain */
+			for (i = 0; i < rtc->natts; i++)
+			{
+				Datum	d;
+				bool	isNull;
+				Datum   conResult;
+				ExprDoneCond   isDone;
+
+				d = heap_getattr(tuple, rtc->atts[i], tupdesc, &isNull);
+
+				if (isNull)
+					elog(ERROR, "ALTER DOMAIN: Relation \"%s\" Attribute \"%s\" "
+						 "contains NULL values",
+						 RelationGetRelationName(typrel),
+						 NameStr(*attnumAttName(typrel, rtc->atts[i])));
+
+				econtext->domainValue_datum = d;
+				econtext->domainValue_isNull = isNull;
+
+				conResult = ExecEvalExpr(expr, econtext, &isNull, &isDone);
+
+				if (!DatumGetBool(conResult))
+					elog(ERROR, "AlterDomainAddConstraint: Domain %s constraint %s failed",
+						 NameStr(typTup->typname), constr->name);
+			}
+
+			ResetExprContext(econtext);
+		}
+
+		heap_endscan(scan);
+
+		FreeExprContext(econtext);
+		pfree(slot);
+
+		/* Hold type lock */
+		heap_close(typrel, NoLock);
+	}
+
+	/* Clean up */
+	heap_close(rel, NoLock);
+}
+
+/*
+ * get_rels_with_domain
+ *
+ * Fetch all relations / attributes which are using the domain
+ * while maintaining a RowExclusiveLock on the pg_attribute
+ * entries.
+ *
+ * Generally used for retrieving a list of tests when adding
+ * new constraints to a domain.
+ */
+List *
+get_rels_with_domain(Oid domainOid)
+{
+	Relation	classRel;
+	HeapTuple	classTup;
+	Relation	attRel;
+	HeapScanDesc	classScan;
+	List *rels = NIL;
+
+	/*
+	 * We need to lock the domain rows for the length of the transaction,
+	 * but once all of the tables and the appropriate attributes are
+	 * found we can relese the relation lock.
+	 */
+	classRel = relation_openr(RelationRelationName, ExclusiveLock);
+	attRel = relation_openr(AttributeRelationName, RowExclusiveLock);
+
+	classScan = heap_beginscan(classRel, SnapshotNow, 0, NULL);
+
+	/* Scan through pg_class for tables */
+	while ((classTup = heap_getnext(classScan, ForwardScanDirection)) != NULL)
+	{
+		bool		addToList = true;
+		int			nkeys = 0;
+		HeapTuple	attTup;
+		HeapScanDesc	attScan;
+		ScanKeyData		attKey[2];
+		Form_pg_class	pg_class;
+
+		/* Get our pg_class struct */
+		pg_class = (Form_pg_class) GETSTRUCT(classTup);
+
+		/* Fetch attributes from pg_attribute for the relation of the type domainOid */
+		ScanKeyEntryInitialize(&attKey[nkeys++], 0, Anum_pg_attribute_attrelid,
+						   F_OIDEQ, ObjectIdGetDatum(HeapTupleGetOid(classTup)));
+
+		ScanKeyEntryInitialize(&attKey[nkeys++], 0, Anum_pg_attribute_atttypid,
+						   F_OIDEQ, ObjectIdGetDatum(domainOid));
+
+		/* Setup to scan pg_attribute */
+		attScan = heap_beginscan(attRel, SnapshotNow, nkeys, attKey);
+
+		/* Scan through pg_attribute for attributes based on the domain */
+		while ((attTup = heap_getnext(attScan, ForwardScanDirection)) != NULL)
+		{
+			relToCheck *rtc;
+
+			/* Make the list entries for the relation */
+			if (addToList)
+			{
+				addToList = false;
+
+				rtc = (relToCheck *)palloc(sizeof(relToCheck));
+				rtc->atts = (int *)palloc(sizeof(int) * pg_class->relnatts);
+				rtc->relOid = HeapTupleGetOid(classTup);
+				rtc->natts = 0;
+				rels = lcons((void *)rtc, rels);
+			}
+
+			/* Now add the attribute */
+			rtc->atts[rtc->natts++] = ((Form_pg_attribute) GETSTRUCT(attTup))->attnum;
+		}
+
+		heap_endscan(attScan);
+	}
+
+	heap_endscan(classScan);
+
+	/* Release pg_class, hold pg_attribute for further processing */
+	relation_close(classRel, ExclusiveLock);
+	relation_close(attRel, NoLock);
+
+	return rels;
+}
+
+/*
+ * domainPermissionCheck
+ *
+ * Throw an error if the current user doesn't have permission to modify
+ * the domain in an ALTER DOMAIN statement, or if the type isn't actually
+ * a domain.
+ */
+void
+domainPermissionCheck(HeapTuple tup, TypeName *typename)
+{
+	Form_pg_type	typTup = (Form_pg_type) GETSTRUCT(tup);
+
+	/* Permission check: must own type or its namespace */
+	if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()) &&
+		!pg_namespace_ownercheck(typTup->typnamespace,
+								 GetUserId()))
+		aclcheck_error(ACLCHECK_NOT_OWNER, TypeNameToString(typename));
+
+	/* Check that this is actually a domain */
+	if (typTup->typtype != 'd')
+		elog(ERROR, "%s is not a domain",
+			 TypeNameToString(typename));
+}
+
+
+/*
+ *
+ */
+char *
+domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
+					int typMod, Constraint *constr, int *counter, char *domainName)
+{
+	Node	   *expr;
+	char	   *ccsrc;
+	char	   *ccbin;
+	ParseState *pstate;
+	ConstraintTestValue  *domVal;
+
+	/*
+	 * Assign or validate constraint name
+	 */
+	if (constr->name)
+	{
+		if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
+								 domainOid,
+								 domainNamespace,
+								 constr->name))
+			elog(ERROR, "constraint \"%s\" already exists for domain \"%s\"",
+				 constr->name,
+				 domainName);
+	}
+	else
+		constr->name = GenerateConstraintName(CONSTRAINT_DOMAIN,
+											  domainOid,
+											  domainNamespace,
+											  counter);
+
+	/*
+	 * Convert the A_EXPR in raw_expr into an
+	 * EXPR
+	 */
+	pstate = make_parsestate(NULL);
+
+	/*
+	 * We want to have the domain VALUE node type filled in so
+	 * that proper casting can occur.
+	 */
+	domVal = makeNode(ConstraintTestValue);
+	domVal->typeId = baseTypeOid;
+	domVal->typeMod = typMod;
+
+	expr = transformExpr(pstate, constr->raw_expr, domVal);
+
+	/*
+	 * Domains don't allow var clauses
+	 */
+	if (contain_var_clause(expr))
+		elog(ERROR, "cannot use column references in domain CHECK clause");
+
+	/*
+	 * Make sure it yields a boolean result.
+	 */
+	expr = coerce_to_boolean(expr, "CHECK");
+
+	/*
+	 * Make sure no outside relations are
+	 * referred to.
+	 */
+	if (length(pstate->p_rtable) != 0)
+		elog(ERROR, "Relations cannot be referenced in domain CHECK constraint");
+
+	/*
+	 * No subplans or aggregates, either...
+	 */
+	if (contain_subplans(expr))
+		elog(ERROR, "cannot use subselect in CHECK constraint expression");
+	if (contain_agg_clause(expr))
+		elog(ERROR, "cannot use aggregate function in CHECK constraint expression");
+
+	/*
+	 * Might as well try to reduce any constant expressions.
+	 */
+	expr = eval_const_expressions(expr);
+
+	/*
+	 * Must fix opids in operator clauses.
+	 */
+	fix_opids(expr);
+
+	ccbin = nodeToString(expr);
+
+	/*
+	 * Deparse it.  Since VARNOs aren't allowed in domain
+	 * constraints, relation context isn't required as anything
+	 * other than a shell.
+	 */
+	ccsrc = deparse_expression(expr,
+				deparse_context_for(domainName,
+									InvalidOid),
+								   false, false);
+
+	/* Write the constraint */
+	CreateConstraintEntry(constr->name,		/* Constraint Name */
+						  domainNamespace,	/* namespace */
+						  CONSTRAINT_CHECK,		/* Constraint Type */
+						  false,	/* Is Deferrable */
+						  false,	/* Is Deferred */
+						  InvalidOid,		/* not a relation constraint */
+						  NULL,	
+						  0,
+						  domainOid,	/* domain constraint */
+						  InvalidOid,	/* Foreign key fields */
+						  NULL,
+						  0,
+						  ' ',
+						  ' ',
+						  ' ',
+						  InvalidOid,
+						  expr, 	/* Tree form check constraint */
+						  ccbin,	/* Binary form check constraint */
+						  ccsrc);	/* Source form check constraint */
+
+	/*
+	 * Return the constraint so the calling routine can perform any additional
+	 * required tests.
+	 */
+	return ccbin;
+}
+
+/*
+ * domainCheckForUnsupportedConstraints
+ *
+ * Throws an error on constraints that are unsupported by the
+ * domains.
+ */
+void 
+domainCheckForUnsupportedConstraints(Node *newConstraint)
+{
+	Constraint *colDef;
+
+	if (nodeTag(newConstraint) == T_FkConstraint)
+		elog(ERROR, "CREATE DOMAIN / FOREIGN KEY constraints not supported");
+
+	colDef = (Constraint *) newConstraint;
+
+	switch (colDef->contype)
+		{
+		  	case CONSTR_UNIQUE:
+		  		elog(ERROR, "CREATE DOMAIN / UNIQUE indexes not supported");
+		  		break;
+
+		  	case CONSTR_PRIMARY:
+		  		elog(ERROR, "CREATE DOMAIN / PRIMARY KEY indexes 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;
+
+			default:
+				break;
+		}
+}
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index e7c724c66ed979b3ed1370409cd86652176bc7d1..fd531aaa733b91b4a35a0bab6b7f5cec446d2752 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.113 2002/12/05 15:50:31 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.114 2002/12/06 03:28:27 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1610,8 +1610,8 @@ ExecEvalConstraintTest(ConstraintTest *constraint, ExprContext *econtext,
 				conResult = ExecEvalExpr(constraint->check_expr, econtext, isNull, isDone);
 
 				if (!DatumGetBool(conResult))
-					elog(ERROR, "Domain %s constraint %s failed",
-						 constraint->name, constraint->domname);
+					elog(ERROR, "ExecEvalConstraintTest: Domain %s constraint %s failed",
+						 constraint->domname, constraint->name);
 			}
 			break;
 		default:
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 1fe7efd16368f971c310d6d3d0422ade549ecfbd..01abacfa02a9548d3a7a290ab5bf09172318755d 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.226 2002/12/05 15:50:34 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.227 2002/12/06 03:28:28 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1479,6 +1479,20 @@ _copyAlterTableStmt(AlterTableStmt *from)
 	return newnode;
 }
 
+static AlterDomainStmt *
+_copyAlterDomainStmt(AlterDomainStmt *from)
+{
+	AlterDomainStmt *newnode = makeNode(AlterDomainStmt);
+
+	COPY_SCALAR_FIELD(subtype);
+	COPY_NODE_FIELD(typename);
+	COPY_STRING_FIELD(name);
+	COPY_NODE_FIELD(def);
+	COPY_SCALAR_FIELD(behavior);
+
+	return newnode;
+} 
+
 static GrantStmt *
 _copyGrantStmt(GrantStmt *from)
 {
@@ -2464,6 +2478,9 @@ copyObject(void *from)
 		case T_AlterTableStmt:
 			retval = _copyAlterTableStmt(from);
 			break;
+		case T_AlterDomainStmt:
+			retval = _copyAlterDomainStmt(from);
+			break;
 		case T_GrantStmt:
 			retval = _copyGrantStmt(from);
 			break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index f2cae4c14f4d2c9706a4f7f414ac1a6ca2b4cab1..3c5dc6c03f9b9082ee386a2bf3ee1d129e037f38 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -18,7 +18,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.171 2002/12/05 15:50:34 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.172 2002/12/06 03:28:32 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -525,6 +525,18 @@ _equalAlterTableStmt(AlterTableStmt *a, AlterTableStmt *b)
 	return true;
 }
 
+static bool
+_equalAlterDomainStmt(AlterDomainStmt *a, AlterDomainStmt *b)
+{
+	COMPARE_SCALAR_FIELD(subtype);
+	COMPARE_NODE_FIELD(typename);
+	COMPARE_STRING_FIELD(name);
+	COMPARE_NODE_FIELD(def);
+	COMPARE_SCALAR_FIELD(behavior);
+
+	return true;
+}
+
 static bool
 _equalGrantStmt(GrantStmt *a, GrantStmt *b)
 {
@@ -1621,6 +1633,9 @@ equal(void *a, void *b)
 		case T_AlterTableStmt:
 			retval = _equalAlterTableStmt(a, b);
 			break;
+		case T_AlterDomainStmt:
+			retval = _equalAlterDomainStmt(a, b);
+			break;
 		case T_GrantStmt:
 			retval = _equalGrantStmt(a, b);
 			break;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index d4c879f77027dc054aa50b11b5a9c66764cef7da..e1fad41b0eacb43f0728741dc1d829d7ff46460e 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.383 2002/11/25 21:29:40 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.384 2002/12/06 03:28:33 momjian Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -128,7 +128,7 @@ static void doNegateFloat(Value *v);
 }
 
 %type <node>	stmt schema_stmt
-		AlterDatabaseSetStmt AlterGroupStmt
+		AlterDatabaseSetStmt AlterDomainStmt AlterGroupStmt
 		AlterTableStmt AlterUserStmt AlterUserSetStmt
 		AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
 		ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
@@ -479,6 +479,7 @@ stmtmulti:	stmtmulti ';' stmt
 
 stmt :
 			AlterDatabaseSetStmt
+			| AlterDomainStmt
 			| AlterGroupStmt
 			| AlterTableStmt
 			| AlterUserStmt
@@ -3729,6 +3730,53 @@ CreateDomainStmt:
 				}
 		;
 
+AlterDomainStmt:
+			/* ALTER DOMAIN <domain> {SET DEFAULT <expr>|DROP DEFAULT} */
+			ALTER DOMAIN_P any_name alter_column_default
+				{
+					AlterDomainStmt *n = makeNode(AlterDomainStmt);
+					n->subtype = 'T';
+					n->typename = $3;
+					n->def = $4;
+					$$ = (Node *)n;
+				}
+			/* ALTER DOMAIN <domain> DROP NOT NULL */
+			| ALTER DOMAIN_P any_name DROP NOT NULL_P
+				{
+					AlterDomainStmt *n = makeNode(AlterDomainStmt);
+					n->subtype = 'N';
+					n->typename = $3;
+					$$ = (Node *)n;
+				}
+			/* ALTER DOMAIN <domain> SET NOT NULL */
+			| ALTER DOMAIN_P any_name SET NOT NULL_P
+				{
+					AlterDomainStmt *n = makeNode(AlterDomainStmt);
+					n->subtype = 'O';
+					n->typename = $3;
+					$$ = (Node *)n;
+				}
+			/* ALTER DOMAIN <domain> ADD CONSTRAINT ... */
+			| ALTER DOMAIN_P any_name ADD TableConstraint
+				{
+					AlterDomainStmt *n = makeNode(AlterDomainStmt);
+					n->subtype = 'C';
+					n->typename = $3;
+					n->def = $5;
+					$$ = (Node *)n;
+				}
+			/* ALTER DOMAIN <domain> DROP CONSTRAINT <name> [RESTRICT|CASCADE] */
+			| ALTER DOMAIN_P any_name DROP CONSTRAINT name opt_drop_behavior
+				{
+					AlterDomainStmt *n = makeNode(AlterDomainStmt);
+					n->subtype = 'X';
+					n->typename = $3;
+					n->name = $6;
+					n->behavior = $7;
+					$$ = (Node *)n;
+				}
+			;
+
 opt_as:		AS										{}
 			| /* EMPTY */							{}
 		;
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index b620c7116bc0c56813c7e680ec7ec18605db99df..834cc9c82de31c793e83be10d8ac6dd70e46b7ed 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.132 2002/11/30 21:25:05 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.133 2002/12/06 03:28:33 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -629,6 +629,14 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
 
 		case T_DomainConstraintValue:
 			{
+				/*
+				 * If domVal is NULL, we are not translating an expression that
+				 * can use it
+				 */
+				if (domVal == NULL)
+					elog(ERROR, "VALUE is not allowed in expression for node %d",
+						 nodeTag(expr));
+
 				result = (Node *) copyObject(domVal);
 
 				break;
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 457391b6a999eedd2766fe6bd0f773e626ad8c5a..ac51c0cf34f2541a8834b77e8c16b77d1e440fe9 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.310 2002/11/19 17:21:40 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.311 2002/12/06 03:28:33 momjian Exp $
  *
  * NOTES
  *	  this is the "main" module of the postgres backend and
@@ -1781,7 +1781,7 @@ PostgresMain(int argc, char *argv[], const char *username)
 	if (!IsUnderPostmaster)
 	{
 		puts("\nPOSTGRES backend interactive interface ");
-		puts("$Revision: 1.310 $ $Date: 2002/11/19 17:21:40 $\n");
+		puts("$Revision: 1.311 $ $Date: 2002/12/06 03:28:33 $\n");
 	}
 
 	/*
@@ -2319,6 +2319,10 @@ CreateCommandTag(Node *parsetree)
 			tag = "ALTER TABLE";
 			break;
 
+		case T_AlterDomainStmt:
+			tag = "ALTER DOMAIN";
+			break;
+
 		case T_GrantStmt:
 			{
 				GrantStmt  *stmt = (GrantStmt *) parsetree;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 493dbd7587a51a001718aeec872a9b208a1a4b0a..a45c449535e916beb2d7c25fc80d8ab6d1a7e479 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.182 2002/11/15 03:09:38 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.183 2002/12/06 03:28:33 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -36,6 +36,7 @@
 #include "commands/sequence.h"
 #include "commands/tablecmds.h"
 #include "commands/trigger.h"
+#include "commands/typecmds.h"
 #include "commands/user.h"
 #include "commands/vacuum.h"
 #include "commands/view.h"
@@ -560,6 +561,49 @@ ProcessUtility(Node *parsetree,
 			}
 			break;
 
+		case T_AlterDomainStmt:
+			{
+				AlterDomainStmt *stmt = (AlterDomainStmt *) parsetree;
+
+				/*
+				 * Some or all of these functions are recursive to cover
+				 * inherited things, so permission checks are done there.
+				 */
+				switch (stmt->subtype)
+				{
+					case 'T':	/* ALTER COLUMN DEFAULT */
+
+						/*
+						 * Recursively alter column default for table and,
+						 * if requested, for descendants
+						 */
+						AlterDomainDefault(stmt->typename,
+										   stmt->def);
+						break;
+					case 'N':	/* ALTER COLUMN DROP NOT NULL */
+						AlterDomainNotNull(stmt->typename,
+										   false);
+						break;
+					case 'O':	/* ALTER COLUMN SET NOT NULL */
+						AlterDomainNotNull(stmt->typename,
+										   true);
+						break;
+					case 'C':	/* ADD CONSTRAINT */
+						AlterDomainAddConstraint(stmt->typename,
+												 stmt->def);
+						break;
+					case 'X':	/* DROP CONSTRAINT */
+						AlterDomainDropConstraint(stmt->typename,
+												  stmt->name,
+												  stmt->behavior);
+						break;
+					default:	/* oops */
+						elog(ERROR, "T_AlterDomainStmt: unknown subtype");
+						break;
+				}
+			}
+			break;
+
 
 		case T_GrantStmt:
 			ExecuteGrantStmt((GrantStmt *) parsetree);
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 06ac2f340a6d77dbafcf21e6d9e09dfea4464390..8804e5fe6022429de285aa3781c8428655cc58dc 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_type.h,v 1.134 2002/09/24 21:26:44 tgl Exp $
+ * $Id: pg_type.h,v 1.135 2002/12/06 03:28:33 momjian Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -550,7 +550,7 @@ extern Oid TypeCreate(const char *typeName,
 		   Oid elementType,
 		   Oid baseType,
 		   const char *defaultTypeValue,
-		   const char *defaultTypeBin,
+		   char *defaultTypeBin,
 		   bool passedByValue,
 		   char alignment,
 		   char storage,
@@ -558,6 +558,18 @@ extern Oid TypeCreate(const char *typeName,
 		   int32 typNDims,
 		   bool typeNotNull);
 
+extern void
+GenerateTypeDependencies(Oid typeNamespace,
+						 Oid typeObjectId,
+						 Oid relationOid,		/* only for 'c'atalog typeType */
+						 char relationKind,
+						 Oid inputProcedure,
+						 Oid outputProcedure,
+						 Oid elementType,
+						 Oid baseType,
+						 char *defaultTypeBin,	/* cooked rep */
+						 bool rebuild);
+
 
 extern void TypeRename(const char *oldTypeName, Oid typeNamespace,
 		   const char *newTypeName);
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 401610af6aca074bf8b45cbda5d5689caaaef36c..d098277e7986d9064f82c41221fa83718fbc761f 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: defrem.h,v 1.46 2002/09/21 18:39:26 tgl Exp $
+ * $Id: defrem.h,v 1.47 2002/12/06 03:28:33 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -52,14 +52,6 @@ extern void RemoveOperatorById(Oid operOid);
 extern void DefineAggregate(List *names, List *parameters);
 extern void RemoveAggregate(RemoveAggrStmt *stmt);
 
-/* commands/typecmds.c */
-extern void DefineType(List *names, List *parameters);
-extern void RemoveType(List *names, DropBehavior behavior);
-extern void RemoveTypeById(Oid typeOid);
-extern void DefineDomain(CreateDomainStmt *stmt);
-extern void RemoveDomain(List *names, DropBehavior behavior);
-extern Oid	DefineCompositeType(const RangeVar *typevar, List *coldeflist);
-
 /* commands/opclasscmds.c */
 extern void DefineOpClass(CreateOpClassStmt *stmt);
 extern void RemoveOpClass(RemoveOpClassStmt *stmt);
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index cb16a300442b410464649de50f1abfa82024c9f4..dc1290775d997536e229fe9c8fa57e0bd2f64ada 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodes.h,v 1.126 2002/12/05 15:50:38 tgl Exp $
+ * $Id: nodes.h,v 1.127 2002/12/06 03:28:33 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -157,6 +157,7 @@ typedef enum NodeTag
 	T_UpdateStmt,
 	T_SelectStmt,
 	T_AlterTableStmt,
+	T_AlterDomainStmt,
 	T_SetOperationStmt,
 	T_GrantStmt,
 	T_ClosePortalStmt,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 7ca79b3520fe7a60f7c77e7b182c09c839d85dce..adcb6d9a55120daea994063c7539199026a614c3 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.218 2002/11/25 03:36:50 tgl Exp $
+ * $Id: parsenodes.h,v 1.219 2002/12/06 03:28:33 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -827,6 +827,33 @@ typedef struct AlterTableStmt
 	DropBehavior behavior;		/* RESTRICT or CASCADE for DROP cases */
 } AlterTableStmt;
 
+/* ----------------------
+ *	Alter Domain
+ *
+ * The fields are used in different ways by the different variants of
+ * this command. Subtypes should match AlterTable subtypes
+ * ----------------------
+ */
+typedef struct AlterDomainStmt
+{
+	NodeTag		type;
+	char		subtype;		/*------------
+								 *	T = alter column default
+								 *	N = alter column drop not null
+								 *	O = alter column set not null
+								 *	C = add constraint
+								 *	X = drop constraint
+								 *	U = change owner
+								 *------------
+								 */
+	List	   *typename;		/* table to work on */
+	char	   *name;			/* column or constraint name to act on, or
+								 * new owner */
+	Node	   *def;			/* definition of default or constraint */
+	DropBehavior behavior;		/* RESTRICT or CASCADE for DROP cases */
+} AlterDomainStmt;
+
+
 /* ----------------------
  *		Grant|Revoke Statement
  * ----------------------
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index 92c9cc2cc00d9c7c8201b091d38cc2dfd33526ff..f91191bddb69341fe96af8395240bd107d3c9752 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -115,7 +115,7 @@ INSERT INTO nulltest DEFAULT VALUES;
 ERROR:  Domain dnotnull does not allow NULL values
 INSERT INTO nulltest values ('a', 'b', 'c', 'd', 'c');  -- Good
 insert into nulltest values ('a', 'b', 'c', 'd', NULL);
-ERROR:  Domain $1 constraint dcheck failed
+ERROR:  ExecEvalConstraintTest: Domain dcheck constraint $1 failed
 insert into nulltest values ('a', 'b', 'c', 'd', 'a');
 ERROR:  ExecInsert: rejected due to CHECK constraint "nulltest_col5" on "nulltest"
 INSERT INTO nulltest values (NULL, 'b', 'c', 'd', 'd');
@@ -127,7 +127,7 @@ ERROR:  ExecInsert: Fail to add null value in not null attribute col3
 INSERT INTO nulltest values ('a', 'b', 'c', NULL, 'd'); -- Good
 -- Test copy
 COPY nulltest FROM stdin; --fail
-ERROR:  copy: line 1, Domain $1 constraint dcheck failed
+ERROR:  copy: line 1, ExecEvalConstraintTest: Domain dcheck constraint $1 failed
 lost synchronization with server, resetting connection
 SET autocommit TO 'on';
 -- Last row is bad
@@ -158,6 +158,7 @@ ERROR:  Domain dnotnull does not allow NULL values
 drop table nulltest;
 drop domain dnotnull restrict;
 drop domain dnull restrict;
+drop domain dcheck restrict;
 create domain ddef1 int4 DEFAULT 3;
 create domain ddef2 oid DEFAULT '12';
 -- Type mixing, function returns int8
@@ -191,7 +192,80 @@ select * from defaulttest;
 (4 rows)
 
 drop sequence ddef4_seq;
-drop table defaulttest;
+drop table defaulttest cascade;
+-- Test ALTER DOMAIN .. NOT NULL
+create domain dnotnulltest integer;
+create table domnotnull
+( col1 dnotnulltest
+, col2 dnotnulltest
+);
+insert into domnotnull default values;
+alter domain dnotnulltest set not null; -- fails
+ERROR:  ALTER DOMAIN: Relation "domnotnull" Attribute "col1" contains NULL values
+update domnotnull set col1 = 5;
+alter domain dnotnulltest set not null; -- fails
+ERROR:  ALTER DOMAIN: Relation "domnotnull" Attribute "col2" contains NULL values
+update domnotnull set col2 = 6;
+alter domain dnotnulltest set not null;
+alter domain dnotnulltest set not null; -- fails
+ERROR:  AlterDomain: dnotnulltest is already set to NOT NULL
+update domnotnull set col1 = null; -- fails
+ERROR:  Domain dnotnulltest does not allow NULL values
+alter domain dnotnulltest drop not null;
+alter domain dnotnulltest drop not null; -- fails
+ERROR:  AlterDomain: dnotnulltest is already set to NULL
+update domnotnull set col1 = null;
+drop domain dnotnulltest cascade;
+NOTICE:  Drop cascades to table domnotnull column col2
+NOTICE:  Drop cascades to table domnotnull column col1
+-- Test ALTER DOMAIN .. DEFAULT ..
+create table domdeftest (col1 ddef1);
+insert into domdeftest default values;
+select * from domdeftest;
+ col1 
+------
+ 3
+(1 row)
+
+alter domain ddef1 set default '42';
+insert into domdeftest default values;
+select * from domdeftest;
+ col1 
+------
+ 3
+ 42
+(2 rows)
+
+alter domain ddef1 drop default;
+insert into domdeftest default values;
+select * from domdeftest;
+ col1 
+------
+ 3
+ 42
+ 
+(3 rows)
+
+drop table domdeftest;
+-- Test ALTER DOMAIN .. CONSTRAINT ..
+create domain con as integer;
+create table domcontest (col1 con);
+insert into domcontest values (1);
+insert into domcontest values (2);
+alter domain con add constraint t check (VALUE < 1); -- fails
+ERROR:  AlterDomainAddConstraint: Domain con constraint t failed
+alter domain con add constraint t check (VALUE < 34);
+alter domain con add check (VALUE > 0);
+insert into domcontest values (-5); -- fails
+ERROR:  ExecEvalConstraintTest: Domain con constraint $1 failed
+insert into domcontest values (42); -- fails
+ERROR:  ExecEvalConstraintTest: Domain con constraint t failed
+insert into domcontest values (5);
+alter domain con drop constraint t;
+insert into domcontest values (-5); --fails
+ERROR:  ExecEvalConstraintTest: Domain con constraint $1 failed
+insert into domcontest values (42);
+-- cleanup
 drop domain ddef1 restrict;
 drop domain ddef2 restrict;
 drop domain ddef3 restrict;
diff --git a/src/test/regress/resultmap b/src/test/regress/resultmap
index 0ab2f0e2f71b7bd74d610504568a8b467876eb6e..d4fe5af993030fabf3a7e15c2f984abfcca01b87 100644
--- a/src/test/regress/resultmap
+++ b/src/test/regress/resultmap
@@ -14,8 +14,8 @@ float8/.*-qnx=float8-exp-three-digits
 float8/alpha.*-dec-osf.*:cc=float8-fp-exception
 float8/i.86-pc-cygwin=float8-small-is-zero
 geometry/.*-darwin=geometry-positive-zeros
-geometry/i.86-.*-freebsd4.[0-5]=geometry-positive-zeros
-geometry/alpha.*-freebsd4.[0-5]=geometry-positive-zeros
+geometry/i.86-.*-freebsd4.[0-7]=geometry-positive-zeros
+geometry/alpha.*-freebsd4.[0-7]=geometry-positive-zeros
 geometry/i.86-.*-openbsd=geometry-positive-zeros
 geometry/sparc-.*-openbsd=geometry-positive-zeros
 geometry/.*-netbsd1.[0-5]=geometry-positive-zeros
diff --git a/src/test/regress/sql/domain.sql b/src/test/regress/sql/domain.sql
index 65fba7466fd5bd5f2d58a7bc73b2a0257719cf9a..76060e99c8bd261b7dcf3945c6c8e4873b74daa9 100644
--- a/src/test/regress/sql/domain.sql
+++ b/src/test/regress/sql/domain.sql
@@ -127,6 +127,7 @@ SELECT cast(col4 as dnotnull) from nulltest; -- fail
 drop table nulltest;
 drop domain dnotnull restrict;
 drop domain dnull restrict;
+drop domain dcheck restrict;
 
 
 create domain ddef1 int4 DEFAULT 3;
@@ -159,7 +160,71 @@ COPY defaulttest(col5) FROM stdin;
 select * from defaulttest;
 
 drop sequence ddef4_seq;
-drop table defaulttest;
+drop table defaulttest cascade;
+
+-- Test ALTER DOMAIN .. NOT NULL
+create domain dnotnulltest integer;
+create table domnotnull
+( col1 dnotnulltest
+, col2 dnotnulltest
+);
+
+insert into domnotnull default values;
+alter domain dnotnulltest set not null; -- fails
+
+update domnotnull set col1 = 5;
+alter domain dnotnulltest set not null; -- fails
+
+update domnotnull set col2 = 6;
+
+alter domain dnotnulltest set not null;
+alter domain dnotnulltest set not null; -- fails
+
+update domnotnull set col1 = null; -- fails
+
+alter domain dnotnulltest drop not null;
+alter domain dnotnulltest drop not null; -- fails
+
+update domnotnull set col1 = null;
+
+drop domain dnotnulltest cascade;
+
+-- Test ALTER DOMAIN .. DEFAULT ..
+create table domdeftest (col1 ddef1);
+
+insert into domdeftest default values;
+select * from domdeftest;
+
+alter domain ddef1 set default '42';
+insert into domdeftest default values;
+select * from domdeftest;
+
+alter domain ddef1 drop default;
+insert into domdeftest default values;
+select * from domdeftest;
+
+drop table domdeftest;
+
+-- Test ALTER DOMAIN .. CONSTRAINT ..
+create domain con as integer;
+create table domcontest (col1 con);
+
+insert into domcontest values (1);
+insert into domcontest values (2);
+alter domain con add constraint t check (VALUE < 1); -- fails
+
+alter domain con add constraint t check (VALUE < 34);
+alter domain con add check (VALUE > 0);
+
+insert into domcontest values (-5); -- fails
+insert into domcontest values (42); -- fails
+insert into domcontest values (5);
+
+alter domain con drop constraint t;
+insert into domcontest values (-5); --fails
+insert into domcontest values (42);
+
+-- cleanup
 drop domain ddef1 restrict;
 drop domain ddef2 restrict;
 drop domain ddef3 restrict;