diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index c3ed19e4b2a7d31de1d089399e5110918fa42fc2..602680aaacb2019d3346bf62d50a2ac43935d657 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -1,6 +1,6 @@
 <!--
  Documentation of the system catalogs, directed toward PostgreSQL developers
- $Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.44 2002/06/20 15:44:06 momjian Exp $
+ $Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.45 2002/07/12 18:43:12 tgl Exp $
  -->
 
 <chapter id="catalogs">
@@ -71,11 +71,21 @@
       <entry>tables, indexes, sequences (<quote>relations</quote>)</entry>
      </row>
 
+     <row>
+      <entry>pg_constraint</entry>
+      <entry>check constraints, unique / primary key constraints, foreign key constraints</entry>
+     </row>
+
      <row>
       <entry>pg_database</entry>
       <entry>databases within this database cluster</entry>
      </row>
 
+     <row>
+      <entry>pg_depend</entry>
+      <entry>dependencies between database objects</entry>
+     </row>
+
      <row>
       <entry>pg_description</entry>
       <entry>descriptions or comments on database objects</entry>
@@ -131,11 +141,6 @@
       <entry>functions and procedures</entry>
      </row>
 
-     <row>
-      <entry>pg_relcheck</entry>
-      <entry>check constraints</entry>
-     </row>
-
      <row>
       <entry>pg_rewrite</entry>
       <entry>query rewriter rules</entry>
@@ -680,7 +685,7 @@
       <entry></entry>
       <entry>
        Number of check constraints on the table; see
-       <structname>pg_relcheck</structname> catalog
+       <structname>pg_constraint</structname> catalog
       </entry>
      </row>
 
@@ -764,6 +769,167 @@
   </table>
  </sect1>
 
+ <sect1 id="catalog-pg-constraint">
+  <title>pg_constraint</title>
+
+  <para>
+   This system catalog stores CHECK, PRIMARY KEY, UNIQUE, and FOREIGN KEY
+   constraints on tables.  (Column
+   constraints are not treated specially.  Every column constraint is
+   equivalent to some table constraint.)  See under <command>CREATE
+   TABLE</command> for more information.
+  </para>
+
+  <note>
+   <para>
+    NOT NULL constraints are represented in the <structname>pg_attribute</>
+    catalog.
+   </para>
+  </note>
+
+  <para>
+   CHECK constraints on domains are stored here, too.  Global ASSERTIONS
+   (a currently-unsupported SQL feature) may someday appear here as well.
+  </para>
+
+  <table>
+   <title>pg_constraint Columns</title>
+
+   <tgroup cols=4>
+    <thead>
+     <row>
+      <entry>Name</entry>
+      <entry>Type</entry>
+      <entry>References</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+
+    <tbody>
+     <row>
+      <entry>conname</entry>
+      <entry><type>name</type></entry>
+      <entry></entry>
+      <entry>Constraint name (not necessarily unique!)</entry>
+     </row>
+
+     <row>
+      <entry>connamespace</entry>
+      <entry><type>oid</type></entry>
+      <entry>pg_namespace.oid</entry>
+      <entry>
+       The OID of the namespace that contains this constraint
+      </entry>
+     </row>
+
+     <row>
+      <entry>contype</entry>
+      <entry><type>char</type></entry>
+      <entry></entry>
+      <entry>
+        'c' = check constraint,
+	'f' = foreign key constraint,
+	'p' = primary key constraint,
+        'u' = unique constraint
+      </entry>
+     </row>
+
+     <row>
+      <entry>condeferrable</entry>
+      <entry><type>boolean</type></entry>
+      <entry></entry>
+      <entry>Is the constraint deferrable?</entry>
+     </row>
+
+     <row>
+      <entry>condeferred</entry>
+      <entry><type>boolean</type></entry>
+      <entry></entry>
+      <entry>Is the constraint deferred by default?</entry>
+     </row>
+
+     <row>
+      <entry>conrelid</entry>
+      <entry><type>oid</type></entry>
+      <entry>pg_class.oid</entry>
+      <entry>The table this constraint is on; 0 if not a table constraint</entry>
+     </row>
+
+     <row>
+      <entry>contypid</entry>
+      <entry><type>oid</type></entry>
+      <entry>pg_type.oid</entry>
+      <entry>The domain this constraint is on; 0 if not a domain constraint</entry>
+     </row>
+
+     <row>
+      <entry>confrelid</entry>
+      <entry><type>oid</type></entry>
+      <entry>pg_class.oid</entry>
+      <entry>If a foreign key, the referenced table; else 0</entry>
+     </row>
+
+     <row>
+      <entry>confupdtype</entry>
+      <entry><type>char</type></entry>
+      <entry></entry>
+      <entry>Foreign key update action code</entry>
+     </row>
+
+     <row>
+      <entry>confdeltype</entry>
+      <entry><type>char</type></entry>
+      <entry></entry>
+      <entry>Foreign key deletion action code</entry>
+     </row>
+
+     <row>
+      <entry>confmatchtype</entry>
+      <entry><type>char</type></entry>
+      <entry></entry>
+      <entry>Foreign key match type</entry>
+     </row>
+
+     <row>
+      <entry>conkey</entry>
+      <entry><type>smallint[]</type></entry>
+      <entry>pg_attribute.attnum</entry>
+      <entry>If a table constraint, list of columns which the constraint constrains</entry>
+     </row>
+
+     <row>
+      <entry>confkey</entry>
+      <entry><type>smallint[]</type></entry>
+      <entry>pg_attribute.attnum</entry>
+      <entry>If a foreign key, list of the referenced columns</entry>
+     </row>
+
+     <row>
+      <entry>conbin</entry>
+      <entry><type>text</type></entry>
+      <entry></entry>
+      <entry>If a check constraint, an internal representation of the expression</entry>
+     </row>
+
+     <row>
+      <entry>consrc</entry>
+      <entry><type>text</type></entry>
+      <entry></entry>
+      <entry>If a check constraint, a human-readable representation of the expression</entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+  <note>
+   <para>
+    <structname>pg_class</structname>.<structfield>relchecks</structfield>
+    needs to agree with the number of check-constraint entries found in this
+    table for the given relation.
+   </para>
+  </note>
+
+ </sect1>
 
  <sect1 id="catalog-pg-database">
   <title>pg_database</title>
@@ -903,6 +1069,151 @@
  </sect1>
 
 
+ <sect1 id="catalog-pg-depend">
+  <title>pg_depend</title>
+
+  <para>
+   The <structname>pg_depend</structname> table records the dependency
+   relationships between database objects.  This information allows
+   <command>DROP</> commands to find which other objects must be dropped
+   by <command>DROP CASCADE</>, or prevent dropping in the <command>DROP
+   RESTRICT</> case.
+  </para>
+
+  <table>
+   <title>pg_depend Columns</title>
+
+   <tgroup cols=4>
+    <thead>
+     <row>
+      <entry>Name</entry>
+      <entry>Type</entry>
+      <entry>References</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+
+    <tbody>
+     <row>
+      <entry>classid</entry>
+      <entry><type>oid</type></entry>
+      <entry>pg_class.oid</entry>
+      <entry>The oid of the system catalog the dependent object is in</entry>
+     </row>
+
+     <row>
+      <entry>objid</entry>
+      <entry><type>oid</type></entry>
+      <entry>any oid attribute</entry>
+      <entry>The oid of the specific dependent object</entry>
+     </row>
+
+     <row>
+      <entry>objsubid</entry>
+      <entry><type>integer</type></entry>
+      <entry></entry>
+      <entry>For a table attribute, this is the attribute's
+       column number (the objid and classid refer to the table itself).
+       For all other object types, this field is presently zero.
+      </entry>
+     </row>
+
+     <row>
+      <entry>refclassid</entry>
+      <entry><type>oid</type></entry>
+      <entry>pg_class.oid</entry>
+      <entry>The oid of the system catalog the referenced object is in</entry>
+     </row>
+
+     <row>
+      <entry>refobjid</entry>
+      <entry><type>oid</type></entry>
+      <entry>any oid attribute</entry>
+      <entry>The oid of the specific referenced object</entry>
+     </row>
+
+     <row>
+      <entry>refobjsubid</entry>
+      <entry><type>integer</type></entry>
+      <entry></entry>
+      <entry>For a table attribute, this is the attribute's
+       column number (the objid and classid refer to the table itself).
+       For all other object types, this field is presently zero.
+      </entry>
+     </row>
+
+     <row>
+      <entry>deptype</entry>
+      <entry><type>char</type></entry>
+      <entry></entry>
+      <entry>
+       A code defining the specific semantics of this dependency relationship.
+      </entry>
+     </row>
+
+    </tbody>
+   </tgroup>
+  </table>
+
+  <para>
+   In all cases, a <structname>pg_depend</structname> entry indicates that the
+   referenced object may not be dropped without also dropping the dependent
+   object.  However, there are several subflavors identified by
+   <structfield>deptype</>:
+
+   <itemizedlist>
+    <listitem>
+     <para>
+      DEPENDENCY_NORMAL ('n'): normal relationship between separately-created
+      objects.  The dependent object may be dropped without affecting the
+      referenced object.  The referenced object may only be dropped by
+      specifying CASCADE, in which case the dependent object is dropped too.
+      Example: a table column has a normal dependency on its datatype.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      DEPENDENCY_AUTO ('a'): the dependent object can be dropped separately
+      from the referenced object, and should be automatically dropped
+      (regardless of RESTRICT or CASCADE mode) if the referenced object
+      is dropped.
+      Example: a named constraint on a table is made auto-dependent on
+      the table, so that it will go away if the table is dropped.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      DEPENDENCY_INTERNAL ('i'): the dependent object was created as part
+      of creation of the referenced object, and is really just a part of
+      its internal implementation.  A DROP of the dependent object will be
+      disallowed outright (we'll tell the user to issue a DROP against the
+      referenced object, instead).  A DROP of the referenced object will be
+      propagated through to drop the dependent object whether CASCADE is
+      specified or not.
+      Example: a trigger that's created to enforce a foreign-key constraint
+      is made internally dependent on the constraint's pg_constraint entry.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      DEPENDENCY_PIN ('p'): there is no dependent object; this type of entry
+      is a signal that the system itself depends on the referenced object,
+      and so that object must never be deleted.  Entries of this type are
+      created only during initdb.  The fields for the dependent object
+      contain zeroes.
+     </para>
+    </listitem>
+   </itemizedlist>
+
+   Other dependency flavors may be needed in future.
+  </para>
+
+ </sect1>
+
+
  <sect1 id="catalog-pg-description">
   <title>pg_description</title>
 
@@ -1866,72 +2177,6 @@
 
  </sect1>
 
-
- <sect1 id="catalog-pg-relcheck">
-  <title>pg_relcheck</title>
-
-  <para>
-   This system catalog stores CHECK constraints on tables.  (Column
-   constraints are not treated specially.  Every column constraint is
-   equivalent to some table constraint.)  See under <command>CREATE
-   TABLE</command> for more information.
-  </para>
-
-  <table>
-   <title>pg_relcheck Columns</title>
-
-   <tgroup cols=4>
-    <thead>
-     <row>
-      <entry>Name</entry>
-      <entry>Type</entry>
-      <entry>References</entry>
-      <entry>Description</entry>
-     </row>
-    </thead>
-
-    <tbody>
-     <row>
-      <entry>rcrelid</entry>
-      <entry><type>oid</type></entry>
-      <entry>pg_class.oid</entry>
-      <entry>The table this check constraint is on</entry>
-     </row>
-
-     <row>
-      <entry>rcname</entry>
-      <entry><type>name</type></entry>
-      <entry></entry>
-      <entry>Constraint name</entry>
-     </row>
-
-     <row>
-      <entry>rcbin</entry>
-      <entry><type>text</type></entry>
-      <entry></entry>
-      <entry>An internal representation of the constraint expression</entry>
-     </row>
-
-     <row>
-      <entry>rcsrc</entry>
-      <entry><type>text</type></entry>
-      <entry></entry>
-      <entry>A human-readable representation of the constraint expression</entry>
-     </row>
-    </tbody>
-   </tgroup>
-  </table>
-
-  <note>
-   <para>
-    <structname>pg_class</structname>.<structfield>relchecks</structfield>
-    needs to match up with the entries in this table.
-   </para>
-  </note>
-
- </sect1>
-
-
  <sect1 id="catalog-pg-rewrite">
   <title>pg_rewrite</title>
 
diff --git a/doc/src/sgml/ref/alter_table.sgml b/doc/src/sgml/ref/alter_table.sgml
index 4966eb757b8c527da568b9892ef5c781f987d124..9acd474203cce3384b25972de8bbdebfabe0b796 100644
--- a/doc/src/sgml/ref/alter_table.sgml
+++ b/doc/src/sgml/ref/alter_table.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.45 2002/05/18 15:44:47 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.46 2002/07/12 18:43:12 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -39,7 +39,7 @@ ALTER TABLE <replaceable class="PARAMETER">table</replaceable>
 ALTER TABLE <replaceable class="PARAMETER">table</replaceable>
     ADD <replaceable class="PARAMETER">table_constraint_definition</replaceable>
 ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> 
-	DROP CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> { RESTRICT | CASCADE }
+	DROP CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> [ RESTRICT | CASCADE ]
 ALTER TABLE <replaceable class="PARAMETER">table</replaceable>
 	OWNER TO <replaceable class="PARAMETER">new_owner</replaceable> 
   </synopsis>
@@ -315,26 +315,6 @@ ALTER TABLE <replaceable class="PARAMETER">table</replaceable>
     form after you've entered non-null values for the column in all rows.
    </para>
 
-   <para>
-    In DROP CONSTRAINT, the RESTRICT keyword is required, although
-    dependencies are not yet checked.  The CASCADE option is unsupported.  
-    Currently DROP CONSTRAINT only handles CHECK constraints.
-    To remove a PRIMARY or UNIQUE constraint, drop the 
-    relevant index using the <xref linkend="SQL-DROPINDEX" endterm="sql-dropindex-title"> command.
-    To remove FOREIGN KEY constraints you need to recreate
-    and reload the table, using other parameters to the
-    <xref linkend="SQL-CREATETABLE" endterm="sql-createtable-title"> command.
-   </para>
-   <para>
-    For example, to drop all constraints on a table <literal>distributors</literal>:
-    <programlisting>
-CREATE TABLE temp AS SELECT * FROM distributors;
-DROP TABLE distributors;
-CREATE TABLE distributors AS SELECT * FROM temp;
-DROP TABLE temp;
-    </programlisting>
-   </para>
-
    <para>
     Changing any  part  of  the schema of a system
     catalog is not permitted.
@@ -395,7 +375,7 @@ ALTER TABLE distributors ADD CONSTRAINT zipchk CHECK (char_length(zipcode) = 5);
   <para> 
    To remove a check constraint from a table and all its children:
    <programlisting>
-ALTER TABLE distributors DROP CONSTRAINT zipchk RESTRICT;
+ALTER TABLE distributors DROP CONSTRAINT zipchk;
    </programlisting>
   </para>
 
diff --git a/doc/src/sgml/ref/comment.sgml b/doc/src/sgml/ref/comment.sgml
index 3d4041ba8eead3f8ebc7c0959c6017fae037189a..ea173e1741a28c47a5ea647d0921be915bb2c5ab 100644
--- a/doc/src/sgml/ref/comment.sgml
+++ b/doc/src/sgml/ref/comment.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/comment.sgml,v 1.19 2002/05/13 17:45:30 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/comment.sgml,v 1.20 2002/07/12 18:43:12 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -26,6 +26,7 @@ COMMENT ON
   TABLE <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>) |
+  CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> |
   DATABASE <replaceable class="PARAMETER">object_name</replaceable> |
   DOMAIN <replaceable class="PARAMETER">object_name</replaceable> |
   FUNCTION <replaceable class="PARAMETER">func_name</replaceable> (<replaceable class="PARAMETER">arg1_type</replaceable>, <replaceable class="PARAMETER">arg2_type</replaceable>, ...) |
@@ -52,7 +53,7 @@ COMMENT ON
     <variablelist>
      <varlistentry>
       <term><replaceable class="PARAMETER">object_name,
-      table_name.column_name, agg_name, func_name, op, rule_name, trigger_name</replaceable></term>
+      table_name.column_name, agg_name, constraint_name, func_name, op, rule_name, trigger_name</replaceable></term>
       <listitem>
        <para>
 	The name of the object to be be commented.  Names of tables,
diff --git a/doc/src/sgml/ref/drop_aggregate.sgml b/doc/src/sgml/ref/drop_aggregate.sgml
index 857a7f10f48c7fb16b82a984de1e34f274813ab5..9913e5d8ed363cc30da2c1e9fc8310cb4ecd1c4b 100644
--- a/doc/src/sgml/ref/drop_aggregate.sgml
+++ b/doc/src/sgml/ref/drop_aggregate.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_aggregate.sgml,v 1.18 2002/05/18 15:44:47 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_aggregate.sgml,v 1.19 2002/07/12 18:43:12 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -21,7 +21,7 @@ PostgreSQL documentation
    <date>1999-07-20</date>
   </refsynopsisdivinfo>
   <synopsis>
-DROP AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceable class="PARAMETER">type</replaceable> )
+DROP AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceable class="PARAMETER">type</replaceable> ) [ CASCADE | RESTRICT ]
   </synopsis>
 
   <refsect2 id="R2-SQL-DROPAGGREGATE-1">
@@ -54,6 +54,23 @@ DROP AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceable
        </para>
       </listitem>
      </varlistentry>
+     <varlistentry>
+      <term>CASCADE</term>
+      <listitem>
+       <para>
+        Automatically drop objects that depend on the aggregate.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term>RESTRICT</term>
+      <listitem>
+       <para>
+        Refuse to drop the aggregate if there are any dependent objects.
+	This is the default.
+       </para>
+      </listitem>
+     </varlistentry>
     </variablelist>
    </para>
   </refsect2>
diff --git a/doc/src/sgml/ref/drop_domain.sgml b/doc/src/sgml/ref/drop_domain.sgml
index 5bc73a065fab389c2436f6c0d5d13556cb3ed728..b39e249302111ed49f2f8f188e054c45e15a6741 100644
--- a/doc/src/sgml/ref/drop_domain.sgml
+++ b/doc/src/sgml/ref/drop_domain.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_domain.sgml,v 1.6 2002/05/18 15:44:47 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_domain.sgml,v 1.7 2002/07/12 18:43:13 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -48,8 +48,8 @@ DROP DOMAIN <replaceable class="PARAMETER">domainname</replaceable> [, ...]  [ C
       <term><literal>CASCADE</></term>
       <listitem>
        <para>
-        Automatically drop objects that depend on the domain.  This
-	behavior is not currently supported.
+        Automatically drop objects that depend on the domain
+	(such as table columns).
        </para>
       </listitem>
      </varlistentry>
@@ -58,7 +58,8 @@ DROP DOMAIN <replaceable class="PARAMETER">domainname</replaceable> [, ...]  [ C
       <term><literal>RESTRICT</></term>
       <listitem>
        <para>
-        Do not drop dependent objects.  This is the default.
+        Refuse to drop the domain if there are any dependent objects.
+	This is the default.
        </para>
       </listitem>
      </varlistentry>
@@ -143,19 +144,14 @@ DROP DOMAIN box;
 
  <refsect1 id="SQL-DROPDOMAIN-compatibility">
   <title>Compatibility</title>
+  
+  <refsect2 id="R2-SQL-DROPDOMAIN-sql92">
+   <title>
+    SQL92
+   </title>
 
-  <para>
-   A <command>DROP DOMAIN</command> statement exists in SQL99.  As with
-   most other <quote>drop</quote> commands, <command>DROP
-   DOMAIN</command> in SQL99 requires a <quote>drop behavior</quote>
-   clause to select between dropping all dependent objects or refusing
-   to drop if dependent objects exist:
-<synopsis>
-DROP DOMAIN <replaceable>name</replaceable> { CASCADE | RESTRICT }
-</synopsis>
-   <productname>PostgreSQL</productname> accepts only the RESTRICT
-   option, and currently does not check for existence of dependent objects.
-  </para>
+   <para></para>
+  </refsect2>
  </refsect1>
 
  <refsect1 id="SQL-DROPDOMAIN-see-also">
diff --git a/doc/src/sgml/ref/drop_function.sgml b/doc/src/sgml/ref/drop_function.sgml
index 268d8c66e8c60d67d529be55d365ceca9dfebfa7..5aa1b141badd767642995c87fba0a7466634b416 100644
--- a/doc/src/sgml/ref/drop_function.sgml
+++ b/doc/src/sgml/ref/drop_function.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_function.sgml,v 1.20 2002/05/18 15:44:47 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_function.sgml,v 1.21 2002/07/12 18:43:13 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -21,7 +21,7 @@ PostgreSQL documentation
    <date>1999-07-20</date>
   </refsynopsisdivinfo>
   <synopsis>
-DROP FUNCTION <replaceable class="parameter">name</replaceable> ( [ <replaceable class="parameter">type</replaceable> [, ...] ] )
+DROP FUNCTION <replaceable class="parameter">name</replaceable> ( [ <replaceable class="parameter">type</replaceable> [, ...] ] ) [ CASCADE | RESTRICT ]
   </synopsis>
 
   <refsect2 id="R2-SQL-DROPFUNCTION-1">
@@ -49,6 +49,24 @@ DROP FUNCTION <replaceable class="parameter">name</replaceable> ( [ <replaceable
        </para>
       </listitem>
      </varlistentry>
+     <varlistentry>
+      <term>CASCADE</term>
+      <listitem>
+       <para>
+        Automatically drop objects that depend on the function
+	(such as operators or triggers).
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term>RESTRICT</term>
+      <listitem>
+       <para>
+        Refuse to drop the function if there are any dependent objects.
+	This is the default.
+       </para>
+      </listitem>
+     </varlistentry>
     </variablelist>
    </para>
   </refsect2>
@@ -136,15 +154,8 @@ DROP FUNCTION sqrt(integer);
   <title>Compatibility</title>
   
   <para>
-   A <command>DROP FUNCTION</command> statement is defined in SQL99.  One of its syntax forms is:
-
-<synopsis>
-DROP FUNCTION <replaceable class="parameter">name</replaceable> (<replaceable>arg</>, ...) { RESTRICT | CASCADE }
-</synopsis>
-
-   where <literal>CASCADE</> specifies dropping all objects that
-   depend on the function and <literal>RESTRICT</literal> refuses to
-   drop the function if dependent objects exist.
+   A <command>DROP FUNCTION</command> statement is defined in SQL99.  One of
+   its syntax forms is similar to PostgreSQL's.
   </para>
  </refsect1>
 
diff --git a/doc/src/sgml/ref/drop_index.sgml b/doc/src/sgml/ref/drop_index.sgml
index 0db2c6094613c6676df662757f72a7ab9f6a633d..149afff0779fd15121f4ac9609bc818c03ba626a 100644
--- a/doc/src/sgml/ref/drop_index.sgml
+++ b/doc/src/sgml/ref/drop_index.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_index.sgml,v 1.15 2002/05/18 15:44:47 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_index.sgml,v 1.16 2002/07/12 18:43:13 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -21,7 +21,7 @@ PostgreSQL documentation
    <date>1999-07-20</date>
   </refsynopsisdivinfo>
   <synopsis>
-DROP INDEX <replaceable class="PARAMETER">index_name</replaceable> [, ...]
+DROP INDEX <replaceable class="PARAMETER">index_name</replaceable> [, ...] [ CASCADE | RESTRICT ]
   </synopsis>
 
   <refsect2 id="R2-SQL-DROPINDEX-1">
@@ -41,6 +41,23 @@ DROP INDEX <replaceable class="PARAMETER">index_name</replaceable> [, ...]
        </para>
       </listitem>
      </varlistentry>
+     <varlistentry>
+      <term>CASCADE</term>
+      <listitem>
+       <para>
+        Automatically drop objects that depend on the index.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term>RESTRICT</term>
+      <listitem>
+       <para>
+        Refuse to drop the index if there are any dependent objects.
+	This is the default.
+       </para>
+      </listitem>
+     </varlistentry>
     </variablelist>
    </para>
   </refsect2>
diff --git a/doc/src/sgml/ref/drop_language.sgml b/doc/src/sgml/ref/drop_language.sgml
index 08badab80832ae78602e61e6c9d90cf8b091e42e..e0690a88ac69c30b36015076d9cc46a358109018 100644
--- a/doc/src/sgml/ref/drop_language.sgml
+++ b/doc/src/sgml/ref/drop_language.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_language.sgml,v 1.14 2002/05/18 15:44:47 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_language.sgml,v 1.15 2002/07/12 18:43:13 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -21,7 +21,7 @@ PostgreSQL documentation
    <date>1999-07-20</date>
   </refsynopsisdivinfo>
   <synopsis>
-DROP [ PROCEDURAL ] LANGUAGE <replaceable class="PARAMETER">name</replaceable>
+DROP [ PROCEDURAL ] LANGUAGE <replaceable class="PARAMETER">name</replaceable> [ CASCADE | RESTRICT ]
   </synopsis>
   
   <refsect2 id="R2-SQL-DROPLANGUAGE-1">
@@ -43,7 +43,26 @@ DROP [ PROCEDURAL ] LANGUAGE <replaceable class="PARAMETER">name</replaceable>
        </para>
       </listitem>
      </varlistentry>
+     <varlistentry>
+      <term>CASCADE</term>
+      <listitem>
+       <para>
+        Automatically drop objects that depend on the language
+	(such as functions in the language).
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term>RESTRICT</term>
+      <listitem>
+       <para>
+        Refuse to drop the language if there are any dependent objects.
+	This is the default.
+       </para>
+      </listitem>
+     </varlistentry>
     </variablelist>
+
    </para>
   </refsect2>
   
@@ -112,14 +131,6 @@ ERROR: Language "<replaceable class="parameter">name</replaceable>" doesn't exis
     <xref linkend="sql-createlanguage" endterm="sql-createlanguage-title">
     for information on how to create procedural languages.
    </para>
-
-   <para>
-    No checks are made if functions or trigger procedures registered
-    in this language still exist. To re-enable them without having
-    to drop and recreate all the functions, the pg_proc's prolang
-    attribute of the functions must be adjusted to the new object
-    ID of the recreated pg_language entry for the PL.
-   </para>
   </refsect2>
  </refsect1>
  
diff --git a/doc/src/sgml/ref/drop_operator.sgml b/doc/src/sgml/ref/drop_operator.sgml
index bc4657038fdbb42058e4ef0812a6217a3349e14a..1cfb824090c89b1f3e35ac1bbd46ad959693d4c0 100644
--- a/doc/src/sgml/ref/drop_operator.sgml
+++ b/doc/src/sgml/ref/drop_operator.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_operator.sgml,v 1.16 2002/05/18 15:44:47 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_operator.sgml,v 1.17 2002/07/12 18:43:13 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -22,7 +22,7 @@ PostgreSQL documentation
    <date>1999-07-20</date>
   </refsynopsisdivinfo>
   <synopsis>
-DROP OPERATOR <replaceable class="PARAMETER">id</replaceable> ( <replaceable class="PARAMETER">lefttype</replaceable> | NONE , <replaceable class="PARAMETER">righttype</replaceable> | NONE )
+DROP OPERATOR <replaceable class="PARAMETER">id</replaceable> ( <replaceable class="PARAMETER">lefttype</replaceable> | NONE , <replaceable class="PARAMETER">righttype</replaceable> | NONE ) [ CASCADE | RESTRICT ]
   </synopsis>
   
   <refsect2 id="R2-SQL-DROPOPERATOR-1">
@@ -60,6 +60,23 @@ DROP OPERATOR <replaceable class="PARAMETER">id</replaceable> ( <replaceable cla
        </para>
       </listitem>
      </varlistentry>
+     <varlistentry>
+      <term>CASCADE</term>
+      <listitem>
+       <para>
+        Automatically drop objects that depend on the operator.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term>RESTRICT</term>
+      <listitem>
+       <para>
+        Refuse to drop the operator if there are any dependent objects.
+	This is the default.
+       </para>
+      </listitem>
+     </varlistentry>
     </variablelist>
    </para>
   </refsect2>
diff --git a/doc/src/sgml/ref/drop_rule.sgml b/doc/src/sgml/ref/drop_rule.sgml
index 4f8ea97f88d324287cc3eaa668af759e5275638a..afb1b6a874bf954d161a4a414159dead3419188d 100644
--- a/doc/src/sgml/ref/drop_rule.sgml
+++ b/doc/src/sgml/ref/drop_rule.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_rule.sgml,v 1.15 2002/05/18 15:44:47 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_rule.sgml,v 1.16 2002/07/12 18:43:13 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -21,7 +21,7 @@ PostgreSQL documentation
    <date>1998-09-22</date>
   </refsynopsisdivinfo>
   <synopsis>
-DROP RULE <replaceable class="PARAMETER">name</replaceable> ON <replaceable class="PARAMETER">relation</replaceable>
+DROP RULE <replaceable class="PARAMETER">name</replaceable> ON <replaceable class="PARAMETER">relation</replaceable> [ CASCADE | RESTRICT ]
   </synopsis>
   
   <refsect2 id="R2-SQL-DROPRULE-1">
@@ -50,7 +50,25 @@ DROP RULE <replaceable class="PARAMETER">name</replaceable> ON <replaceable clas
        </para>
       </listitem>
      </varlistentry>
+     <varlistentry>
+      <term>CASCADE</term>
+      <listitem>
+       <para>
+        Automatically drop objects that depend on the rule.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term>RESTRICT</term>
+      <listitem>
+       <para>
+        Refuse to drop the rule if there are any dependent objects.
+	This is the default.
+       </para>
+      </listitem>
+     </varlistentry>
     </variablelist>
+
    </para>
   </refsect2>
 
diff --git a/doc/src/sgml/ref/drop_sequence.sgml b/doc/src/sgml/ref/drop_sequence.sgml
index 4c371164e1e9f784f441197bf2157835d9f8373a..50623849342cce2eec68727550b7c6016a9a7f2a 100644
--- a/doc/src/sgml/ref/drop_sequence.sgml
+++ b/doc/src/sgml/ref/drop_sequence.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_sequence.sgml,v 1.14 2002/05/18 15:44:47 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_sequence.sgml,v 1.15 2002/07/12 18:43:13 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -21,7 +21,8 @@ PostgreSQL documentation
    <date>1999-07-20</date>
   </refsynopsisdivinfo>
   <synopsis>
-DROP SEQUENCE <replaceable class="PARAMETER">name</replaceable> [, ...]
+DROP SEQUENCE <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | RESTRICT ]
+
   </synopsis>
   
   <refsect2 id="R2-SQL-DROPSEQUENCE-1">
@@ -75,7 +76,25 @@ ERROR: sequence "<replaceable class="parameter">name</replaceable>" does not exi
        </para>
       </listitem>
      </varlistentry>
+     <varlistentry>
+      <term>CASCADE</term>
+      <listitem>
+       <para>
+        Automatically drop objects that depend on the sequence.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term>RESTRICT</term>
+      <listitem>
+       <para>
+        Refuse to drop the sequence if there are any dependent objects.
+	This is the default.
+       </para>
+      </listitem>
+     </varlistentry>
     </variablelist>
+
    </para>
   </refsect2>
  </refsynopsisdiv>
diff --git a/doc/src/sgml/ref/drop_table.sgml b/doc/src/sgml/ref/drop_table.sgml
index cae3275067d4785da8dd9eff5aa5eaf4e0f5eae2..23148ff827d54bd41b5b93b16901a7713943297f 100644
--- a/doc/src/sgml/ref/drop_table.sgml
+++ b/doc/src/sgml/ref/drop_table.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_table.sgml,v 1.15 2002/05/18 15:44:47 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_table.sgml,v 1.16 2002/07/12 18:43:13 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -21,7 +21,8 @@ PostgreSQL documentation
    <date>1999-07-20</date>
   </refsynopsisdivinfo>
   <synopsis>
-DROP TABLE <replaceable class="PARAMETER">name</replaceable> [, ...]
+DROP TABLE <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | RESTRICT ]
+
   </synopsis>
   
   <refsect2 id="R2-SQL-DROPTABLE-1">
@@ -41,6 +42,24 @@ DROP TABLE <replaceable class="PARAMETER">name</replaceable> [, ...]
        </para>
       </listitem>
      </varlistentry>
+     <varlistentry>
+      <term>CASCADE</term>
+      <listitem>
+       <para>
+        Automatically drop objects that depend on the table
+	(such as views).
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term>RESTRICT</term>
+      <listitem>
+       <para>
+        Refuse to drop the table if there are any dependent objects.
+	This is the default.
+       </para>
+      </listitem>
+     </varlistentry>
     </variablelist>
    </para>
   </refsect2>
@@ -136,44 +155,11 @@ DROP TABLE films, distributors;
   </title>
   
   <refsect2 id="R2-SQL-DROPTABLE-4">
-   <refsect2info>
-    <date>1998-09-22</date>
-   </refsect2info>
    <title>
     SQL92
    </title>
    <para>
-    SQL92 specifies some additional capabilities for DROP TABLE:
    </para>
-   <synopsis>
-DROP TABLE <replaceable class="parameter">table</replaceable> { RESTRICT | CASCADE }
-   </synopsis>
-   <variablelist>
-    <varlistentry>
-     <term>RESTRICT</term>
-     <listitem>
-      <para>
-       Ensures that only a table with no dependent views or
-       integrity constraints can be destroyed.
-      </para>
-     </listitem>
-    </varlistentry>
-    <varlistentry>
-     <term>CASCADE</term>
-     <listitem>
-      <para>
-       Any referencing views or integrity constraints
-       will also be dropped.
-      </para>
-     </listitem>
-    </varlistentry>
-   </variablelist>
-    <tip>
-    <para>
-     At present, to remove a referencing view you must drop
-     it explicitly.
-    </para>
-   </tip>
    </refsect2>
  </refsect1>
 </refentry>
diff --git a/doc/src/sgml/ref/drop_trigger.sgml b/doc/src/sgml/ref/drop_trigger.sgml
index e4f157b1d7c0d8c23ed9c32145a80c38b25f5e91..c154d8117db751170a879a0b1fcfd6f5260e63a9 100644
--- a/doc/src/sgml/ref/drop_trigger.sgml
+++ b/doc/src/sgml/ref/drop_trigger.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_trigger.sgml,v 1.12 2002/05/18 15:44:47 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_trigger.sgml,v 1.13 2002/07/12 18:43:13 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -21,7 +21,7 @@ PostgreSQL documentation
    <date>1998-09-22</date>
   </refsynopsisdivinfo>
   <synopsis>
-DROP TRIGGER <replaceable class="PARAMETER">name</replaceable> ON <replaceable class="PARAMETER">table</replaceable>
+DROP TRIGGER <replaceable class="PARAMETER">name</replaceable> ON <replaceable class="PARAMETER">table</replaceable> [ CASCADE | RESTRICT ]
   </synopsis>
 
   <refsect2 id="R2-SQL-DROPTRIGGER-1">
@@ -50,6 +50,23 @@ DROP TRIGGER <replaceable class="PARAMETER">name</replaceable> ON <replaceable c
        </para>
       </listitem>
      </varlistentry>
+     <varlistentry>
+      <term>CASCADE</term>
+      <listitem>
+       <para>
+        Automatically drop objects that depend on the trigger.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term>RESTRICT</term>
+      <listitem>
+       <para>
+        Refuse to drop the trigger if there are any dependent objects.
+	This is the default.
+       </para>
+      </listitem>
+     </varlistentry>
     </variablelist>
    </para>
   </refsect2>
diff --git a/doc/src/sgml/ref/drop_type.sgml b/doc/src/sgml/ref/drop_type.sgml
index 3ac0f17ae9fee5f6f630add5ca91161afb9a9140..81cf010bb00e6d6f2ad2e3ec4a88b3f263ef7af6 100644
--- a/doc/src/sgml/ref/drop_type.sgml
+++ b/doc/src/sgml/ref/drop_type.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_type.sgml,v 1.17 2002/05/18 15:44:47 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_type.sgml,v 1.18 2002/07/12 18:43:13 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -21,7 +21,8 @@ PostgreSQL documentation
    <date>1999-07-20</date>
   </refsynopsisdivinfo>
   <synopsis>
-DROP TYPE <replaceable class="PARAMETER">typename</replaceable> [, ...]
+DROP TYPE <replaceable class="PARAMETER">typename</replaceable> [, ...] [ CASCADE | RESTRICT ]
+
   </synopsis>
   
   <refsect2 id="R2-SQL-DROPTYPE-1">
@@ -41,6 +42,24 @@ DROP TYPE <replaceable class="PARAMETER">typename</replaceable> [, ...]
        </para>
       </listitem>
      </varlistentry>
+     <varlistentry>
+      <term>CASCADE</term>
+      <listitem>
+       <para>
+        Automatically drop objects that depend on the type
+	(such as table columns, functions, operators, etc).
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term>RESTRICT</term>
+      <listitem>
+       <para>
+        Refuse to drop the type if there are any dependent objects.
+	This is the default.
+       </para>
+      </listitem>
+     </varlistentry>
     </variablelist>
    </para>
   </refsect2>
@@ -75,6 +94,7 @@ ERROR:  RemoveType: type '<replaceable class="parameter">typename</replaceable>'
       </listitem>
      </varlistentry>
     </variablelist>
+
    </para>
   </refsect2>
  </refsynopsisdiv>
@@ -132,19 +152,6 @@ DROP TYPE box;
  <refsect1 id="SQL-DROPTYPE-compatibility">
   <title>Compatibility</title>
 
-  <para>
-   A <command>DROP TYPE</command> statement exists in SQL99.  As with
-   most other <quote>drop</quote> commands, <command>DROP
-   TYPE</command> in SQL99 requires a <quote>drop behavior</quote>
-   clause to select between dropping all dependent objects or refusing
-   to drop if dependent objects exist:
-<synopsis>
-DROP TYPE <replaceable>name</replaceable> { CASCADE | RESTRICT }
-</synopsis>
-   <productname>PostgreSQL</productname> currently ignores
-   dependencies altogether.
-  </para>
-
   <para>
    Note that the <command>CREATE TYPE</command> command and the data
    type extension mechanisms in <productname>PostgreSQL</productname>
diff --git a/doc/src/sgml/ref/drop_view.sgml b/doc/src/sgml/ref/drop_view.sgml
index a789e38c4ce1c2ce07ba3c5a6c61a3eb8da96cbf..52711d984ef5e3a8371161f193033d7ea5ff11a6 100644
--- a/doc/src/sgml/ref/drop_view.sgml
+++ b/doc/src/sgml/ref/drop_view.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_view.sgml,v 1.14 2002/05/18 15:44:47 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_view.sgml,v 1.15 2002/07/12 18:43:13 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -21,7 +21,7 @@ PostgreSQL documentation
    <date>1999-07-20</date>
   </refsynopsisdivinfo>
   <synopsis>
-DROP VIEW <replaceable class="PARAMETER">name</replaceable> [, ...]
+DROP VIEW <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | RESTRICT ]
   </synopsis>
   
   <refsect2 id="R2-SQL-DROPVIEW-1">
@@ -42,7 +42,26 @@ DROP VIEW <replaceable class="PARAMETER">name</replaceable> [, ...]
        </para>
       </listitem>
      </varlistentry>
+     <varlistentry>
+      <term>CASCADE</term>
+      <listitem>
+       <para>
+        Automatically drop objects that depend on the view
+	(such as other views).
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term>RESTRICT</term>
+      <listitem>
+       <para>
+        Refuse to drop the view if there are any dependent objects.
+	This is the default.
+       </para>
+      </listitem>
+     </varlistentry>
     </variablelist>
+
    </para>
   </refsect2>
 
@@ -134,58 +153,7 @@ DROP VIEW kinds;
     SQL92
    </title>
    <para>
-    <acronym>SQL92</acronym> specifies some additional capabilities for
-    <command>DROP VIEW</command>:
-   
-    <synopsis>
-DROP VIEW <replaceable class="parameter">view</replaceable> { RESTRICT | CASCADE }
-    </synopsis>
    </para>
-
-   <refsect3 id="R3-SQL-DROPVIEW-1">
-    <refsect3info>
-     <date>1998-09-22</date>
-    </refsect3info>
-    <title>
-     Inputs
-    </title>
-    <para>
-     <variablelist>
-      <varlistentry>
-       <term>RESTRICT</term>
-       <listitem>
-	<para>
-	 Ensures that only a view with no dependent views or
-	 integrity constraints can be destroyed.
-	</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term>CASCADE</term>
-       <listitem>
-	<para>
-	 Any referencing views and integrity constraints
-	 will be dropped as well.
-	</para>
-       </listitem>
-      </varlistentry>
-     </variablelist>
-    </para>
-   </refsect3>
-
-  <refsect3 id="R3-SQL-DROPVIEW-2">
-   <refsect3info>
-    <date>1998-09-22</date>
-   </refsect3info>
-   <title>
-    Notes
-    </title>
-    <para>
-     At present, to remove a referencing view from a
-     <productname>PostgreSQL</productname> database, 
-     you must drop it explicitly.
-    </para>
-   </refsect3>
   </refsect2>
  </refsect1>
 </refentry>
diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml
index 9cd74fae205ed68057c9eb24f02477cc54fb659c..7fd8c92e371b85bd131d6376f7d9993bb5291694 100644
--- a/doc/src/sgml/release.sgml
+++ b/doc/src/sgml/release.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.139 2002/06/11 15:32:33 thomas Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.140 2002/07/12 18:43:12 tgl Exp $
 -->
 
 <appendix id="release">
@@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without
 worries about funny characters.
 -->
 <literallayout><![CDATA[
+Most forms of DROP now support RESTRICT and CASCADE options
 Recursive SQL functions can be defined
 User-defined procedural languages can register a validator function to check new functions as they are created
 Functions can be executed with the privileges of the owner
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index 3039f49725cd841e8738844ad0a139fc4a9f2ccc..705a2b1fe80e98544f7d40f0d3b08cafcb0b5f7f 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.48 2002/06/20 20:29:25 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.49 2002/07/12 18:43:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -240,7 +240,8 @@ Boot_DeclareIndexStmt:
 					DefineIndex(makeRangeVar(NULL, LexIDStr($5)),
 								LexIDStr($3),
 								LexIDStr($7),
-								$9, false, false, NULL, NIL);
+								$9,
+								false, false, false, NULL, NIL);
 					do_end();
 				}
 		;
@@ -253,7 +254,8 @@ Boot_DeclareUniqueIndexStmt:
 					DefineIndex(makeRangeVar(NULL, LexIDStr($6)),
 								LexIDStr($4),
 								LexIDStr($8),
-								$10, true, false, NULL, NIL);
+								$10,
+								true, false, false, NULL, NIL);
 					do_end();
 				}
 		;
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index 0d021964b7a48a2dc3e8813e023e4914c4d1ee78..22e033524eeffe232e104533bac37837056026c1 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -2,7 +2,7 @@
 #
 # Makefile for backend/catalog
 #
-# $Header: /cvsroot/pgsql/src/backend/catalog/Makefile,v 1.40 2002/07/11 07:39:27 ishii Exp $
+# $Header: /cvsroot/pgsql/src/backend/catalog/Makefile,v 1.41 2002/07/12 18:43:13 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -10,9 +10,9 @@ subdir = src/backend/catalog
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-OBJS = catalog.o heap.o index.o indexing.o namespace.o aclchk.o \
-       pg_aggregate.o pg_largeobject.o pg_namespace.o \
-       pg_operator.o pg_proc.o pg_type.o pg_conversion.o
+OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
+       pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o \
+       pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_type.o
 
 BKIFILES = postgres.bki postgres.description
 
@@ -27,12 +27,12 @@ SUBSYS.o: $(OBJS)
 
 POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/,\
 	pg_proc.h pg_type.h pg_attribute.h pg_class.h \
-	pg_attrdef.h pg_relcheck.h pg_inherits.h pg_index.h \
+	pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h \
 	pg_operator.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
 	pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
 	pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h \
 	pg_namespace.h pg_conversion.h pg_database.h pg_shadow.h pg_group.h \
-	indexing.h \
+	pg_depend.h indexing.h \
     )
 
 pg_includes := $(sort -I$(top_srcdir)/src/include -I$(top_builddir)/src/include)
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
new file mode 100644
index 0000000000000000000000000000000000000000..b7c431d3727232c4cbff26be43f98efec0f1e606
--- /dev/null
+++ b/src/backend/catalog/dependency.c
@@ -0,0 +1,731 @@
+/*-------------------------------------------------------------------------
+ *
+ * dependency.c
+ *	  Routines to support inter-object dependencies.
+ *
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.1 2002/07/12 18:43:13 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "catalog/catname.h"
+#include "catalog/dependency.h"
+#include "catalog/heap.h"
+#include "catalog/index.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_constraint.h"
+#include "catalog/pg_depend.h"
+#include "catalog/pg_language.h"
+#include "catalog/pg_rewrite.h"
+#include "catalog/pg_trigger.h"
+#include "catalog/pg_type.h"
+#include "commands/comment.h"
+#include "commands/defrem.h"
+#include "commands/proclang.h"
+#include "commands/trigger.h"
+#include "lib/stringinfo.h"
+#include "miscadmin.h"
+#include "rewrite/rewriteRemove.h"
+#include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
+
+
+/* This enum covers all system catalogs whose OIDs can appear in classid. */
+typedef enum ObjectClasses
+{
+	OCLASS_CLASS,				/* pg_class */
+	OCLASS_PROC,				/* pg_proc */
+	OCLASS_TYPE,				/* pg_type */
+	OCLASS_CONSTRAINT,			/* pg_constraint */
+	OCLASS_LANGUAGE,			/* pg_language */
+	OCLASS_OPERATOR,			/* pg_operator */
+	OCLASS_REWRITE,				/* pg_rewrite */
+	OCLASS_TRIGGER				/* pg_trigger */
+} ObjectClasses;
+
+static bool recursiveDeletion(const ObjectAddress *object,
+							  DropBehavior behavior,
+							  int recursionLevel,
+							  Relation depRel);
+static void doDeletion(const ObjectAddress *object);
+static ObjectClasses getObjectClass(const ObjectAddress *object);
+static char *getObjectDescription(const ObjectAddress *object);
+
+
+/*
+ * performDeletion: attempt to drop the specified object.  If CASCADE
+ * behavior is specified, also drop any dependent objects (recursively).
+ * If RESTRICT behavior is specified, error out if there are any dependent
+ * objects, except for those that should be implicitly dropped anyway
+ * according to the dependency type.
+ *
+ * This is the outer control routine for all forms of DROP that drop objects
+ * that can participate in dependencies.
+ */
+void
+performDeletion(const ObjectAddress *object,
+				DropBehavior behavior)
+{
+	char		   *objDescription;
+	Relation		depRel;
+
+	/*
+	 * Get object description for possible use in failure message.
+	 * Must do this before deleting it ...
+	 */
+	objDescription = getObjectDescription(object);
+
+	/*
+	 * We save some cycles by opening pg_depend just once and passing the
+	 * Relation pointer down to all the recursive deletion steps.
+	 */
+	depRel = heap_openr(DependRelationName, RowExclusiveLock);
+
+	if (!recursiveDeletion(object, behavior, 0, depRel))
+		elog(ERROR, "Cannot drop %s because other objects depend on it"
+			 "\n\tUse DROP ... CASCADE to drop the dependent objects too",
+			 objDescription);
+
+	heap_close(depRel, RowExclusiveLock);
+
+	pfree(objDescription);
+}
+
+
+/*
+ * recursiveDeletion: delete a single object for performDeletion.
+ *
+ * Returns TRUE if successful, FALSE if not.  recursionLevel is 0 at the
+ * outer level, >0 when deleting a dependent object.
+ *
+ * In RESTRICT mode, we perform all the deletions anyway, but elog a NOTICE
+ * and return FALSE if we find a restriction violation.  performDeletion
+ * will then abort the transaction to nullify the deletions.  We have to
+ * do it this way to (a) report all the direct and indirect dependencies
+ * while (b) not going into infinite recursion if there's a cycle.
+ */
+static bool
+recursiveDeletion(const ObjectAddress *object,
+				  DropBehavior behavior,
+				  int recursionLevel,
+				  Relation depRel)
+{
+	bool			ok = true;
+	char		   *objDescription;
+	ScanKeyData		key[3];
+	int				nkeys;
+	SysScanDesc		scan;
+	HeapTuple		tup;
+	ObjectAddress	otherObject;
+
+	/*
+	 * Get object description for possible use in messages.  Must do this
+	 * before deleting it ...
+	 */
+	objDescription = getObjectDescription(object);
+
+	/*
+	 * Step 1: find and remove pg_depend records that link from this
+	 * object to others.  We have to do this anyway, and doing it first
+	 * ensures that we avoid infinite recursion in the case of cycles.
+	 * Also, some dependency types require an error here.
+	 *
+	 * When dropping a whole object (subId = 0), remove all pg_depend
+	 * records for its sub-objects too.
+	 */
+	ScanKeyEntryInitialize(&key[0], 0x0,
+						   Anum_pg_depend_classid, F_OIDEQ,
+						   ObjectIdGetDatum(object->classId));
+	ScanKeyEntryInitialize(&key[1], 0x0,
+						   Anum_pg_depend_objid, F_OIDEQ,
+						   ObjectIdGetDatum(object->objectId));
+	if (object->objectSubId != 0)
+	{
+		ScanKeyEntryInitialize(&key[2], 0x0,
+							   Anum_pg_depend_objsubid, F_INT4EQ,
+							   Int32GetDatum(object->objectSubId));
+		nkeys = 3;
+	}
+	else
+		nkeys = 2;
+
+	scan = systable_beginscan(depRel, DependDependerIndex, true,
+							  SnapshotNow, nkeys, key);
+
+	while (HeapTupleIsValid(tup = systable_getnext(scan)))
+	{
+		Form_pg_depend	foundDep = (Form_pg_depend) GETSTRUCT(tup);
+
+		otherObject.classId = foundDep->refclassid;
+		otherObject.objectId = foundDep->refobjid;
+		otherObject.objectSubId = foundDep->refobjsubid;
+
+		switch (foundDep->deptype)
+		{
+			case DEPENDENCY_NORMAL:
+			case DEPENDENCY_AUTO:
+				/* no problem */
+				break;
+			case DEPENDENCY_INTERNAL:
+				/*
+				 * Disallow direct DROP of an object that is part of the
+				 * implementation of another object.  (We just elog here,
+				 * rather than issuing a notice and continuing, since
+				 * no other dependencies are likely to be interesting.)
+				 */
+				if (recursionLevel == 0)
+					elog(ERROR, "Cannot drop %s because %s requires it"
+						 "\n\tYou may DROP the other object instead",
+						 objDescription,
+						 getObjectDescription(&otherObject));
+				break;
+			case DEPENDENCY_PIN:
+				/*
+				 * Should not happen; PIN dependencies should have zeroes
+				 * in the depender fields...
+				 */
+				elog(ERROR, "recursiveDeletion: incorrect use of PIN dependency with %s",
+					 objDescription);
+				break;
+			default:
+				elog(ERROR, "recursiveDeletion: unknown dependency type '%c' for %s",
+					 foundDep->deptype, objDescription);
+				break;
+		}
+
+		simple_heap_delete(depRel, &tup->t_self);
+	}
+
+	systable_endscan(scan);
+
+	/*
+	 * CommandCounterIncrement here to ensure that preceding changes
+	 * are all visible; in particular, that the above deletions of pg_depend
+	 * entries are visible.  That prevents infinite recursion in case of
+	 * a dependency loop (which is perfectly legal).
+	 */
+	CommandCounterIncrement();
+
+	/*
+	 * Step 2: scan pg_depend records that link to this object, showing
+	 * the things that depend on it.  Recursively delete those things.
+	 * (We don't delete the pg_depend records here, as the recursive call
+	 * will do that.)  Note it's important to delete the dependent objects
+	 * before the referenced one, since the deletion routines might do
+	 * things like try to update the pg_class record when deleting a
+	 * check constraint.
+	 *
+	 * Again, when dropping a whole object (subId = 0), find pg_depend
+	 * records for its sub-objects too.
+	 *
+	 * NOTE: because we are using SnapshotNow, if a recursive call deletes
+	 * any pg_depend tuples that our scan hasn't yet visited, we will not see
+	 * them as good when we do visit them.  This is essential for correct
+	 * behavior if there are multiple dependency paths between two objects
+	 * --- else we might try to delete an already-deleted object.
+	 */
+	ScanKeyEntryInitialize(&key[0], 0x0,
+						   Anum_pg_depend_refclassid, F_OIDEQ,
+						   ObjectIdGetDatum(object->classId));
+	ScanKeyEntryInitialize(&key[1], 0x0,
+						   Anum_pg_depend_refobjid, F_OIDEQ,
+						   ObjectIdGetDatum(object->objectId));
+	if (object->objectSubId != 0)
+	{
+		ScanKeyEntryInitialize(&key[2], 0x0,
+							   Anum_pg_depend_refobjsubid, F_INT4EQ,
+							   Int32GetDatum(object->objectSubId));
+		nkeys = 3;
+	}
+	else
+		nkeys = 2;
+
+	scan = systable_beginscan(depRel, DependReferenceIndex, true,
+							  SnapshotNow, nkeys, key);
+
+	while (HeapTupleIsValid(tup = systable_getnext(scan)))
+	{
+		Form_pg_depend	foundDep = (Form_pg_depend) GETSTRUCT(tup);
+
+		otherObject.classId = foundDep->classid;
+		otherObject.objectId = foundDep->objid;
+		otherObject.objectSubId = foundDep->objsubid;
+
+		switch (foundDep->deptype)
+		{
+			case DEPENDENCY_NORMAL:
+				if (behavior == DROP_RESTRICT)
+				{
+					elog(NOTICE, "%s depends on %s",
+						 getObjectDescription(&otherObject),
+						 objDescription);
+					ok = false;
+				}
+				else
+					elog(NOTICE, "Drop cascades to %s",
+						 getObjectDescription(&otherObject));
+
+				if (!recursiveDeletion(&otherObject, behavior,
+									   recursionLevel + 1, depRel))
+					ok = false;
+				break;
+			case DEPENDENCY_AUTO:
+			case DEPENDENCY_INTERNAL:
+				/*
+				 * We propagate the DROP without complaint even in the
+				 * RESTRICT case.  (However, normal dependencies on the
+				 * component object could still cause failure.)
+				 */
+				elog(DEBUG1, "Drop internally cascades to %s",
+					 getObjectDescription(&otherObject));
+
+				if (!recursiveDeletion(&otherObject, behavior,
+									   recursionLevel + 1, depRel))
+					ok = false;
+				break;
+			case DEPENDENCY_PIN:
+				/*
+				 * For a PIN dependency we just elog immediately; there
+				 * won't be any others to report.
+				 */
+				elog(ERROR, "Cannot drop %s because it is required by the database system",
+					 objDescription);
+				break;
+			default:
+				elog(ERROR, "recursiveDeletion: unknown dependency type '%c' for %s",
+					 foundDep->deptype, objDescription);
+				break;
+		}
+	}
+
+	systable_endscan(scan);
+
+	/*
+	 * We do not need CommandCounterIncrement here, since if step 2 did
+	 * anything then each recursive call will have ended with one.
+	 */
+
+	/*
+	 * Step 3: delete the object itself.
+	 */
+	doDeletion(object);
+
+	/*
+	 * Delete any comments associated with this object.  (This is a convenient
+	 * place to do it instead of having every object type know to do it.)
+	 */
+	DeleteComments(object->objectId, object->classId, object->objectSubId);
+
+	/*
+	 * CommandCounterIncrement here to ensure that preceding changes
+	 * are all visible.
+	 */
+	CommandCounterIncrement();
+
+	/*
+	 * And we're done!
+	 */
+	pfree(objDescription);
+
+	return ok;
+}
+
+
+/*
+ * doDeletion: actually delete a single object
+ */
+static void
+doDeletion(const ObjectAddress *object)
+{
+	switch (getObjectClass(object))
+	{
+		case OCLASS_CLASS:
+		{
+			HeapTuple	relTup;
+			char		relKind;
+
+			/*
+			 * Need the relkind to figure out how to drop.
+			 */
+			relTup = SearchSysCache(RELOID,
+									ObjectIdGetDatum(object->objectId),
+									0, 0, 0);
+			if (!HeapTupleIsValid(relTup))
+				elog(ERROR, "doDeletion: Relation %u does not exist",
+					 object->objectId);
+			relKind = ((Form_pg_class) GETSTRUCT(relTup))->relkind;
+			ReleaseSysCache(relTup);
+
+			if (relKind == RELKIND_INDEX)
+			{
+				Assert(object->objectSubId == 0);
+				index_drop(object->objectId);
+			}
+			else
+			{
+				if (object->objectSubId != 0)
+					elog(ERROR, "DROP COLUMN not implemented yet");
+				else
+					heap_drop_with_catalog(object->objectId);
+			}
+			break;
+		}
+
+		case OCLASS_PROC:
+			RemoveFunctionById(object->objectId);
+			break;
+
+		case OCLASS_TYPE:
+			RemoveTypeById(object->objectId);
+			break;
+
+		case OCLASS_CONSTRAINT:
+			RemoveConstraintById(object->objectId);
+			break;
+
+		case OCLASS_LANGUAGE:
+			DropProceduralLanguageById(object->objectId);
+			break;
+
+		case OCLASS_OPERATOR:
+			RemoveOperatorById(object->objectId);
+			break;
+
+		case OCLASS_REWRITE:
+			RemoveRewriteRuleById(object->objectId);
+			break;
+
+		case OCLASS_TRIGGER:
+			RemoveTriggerById(object->objectId);
+			break;
+
+		default:
+			elog(ERROR, "doDeletion: Unsupported object class %u",
+				 object->classId);
+	}
+}
+
+/*
+ * Determine the class of a given object identified by objectAddress.
+ *
+ * This function is needed just because some of the system catalogs do
+ * not have hardwired-at-compile-time OIDs.
+ */
+static ObjectClasses
+getObjectClass(const ObjectAddress *object)
+{
+	static bool reloids_initialized = false;
+	static Oid	reloid_pg_constraint;
+	static Oid	reloid_pg_language;
+	static Oid	reloid_pg_operator;
+	static Oid	reloid_pg_rewrite;
+	static Oid	reloid_pg_trigger;
+
+	/* Easy for the bootstrapped catalogs... */
+	switch (object->classId)
+	{
+		case RelOid_pg_class:
+			/* caller must check objectSubId */
+			return OCLASS_CLASS;
+
+		case RelOid_pg_proc:
+			Assert(object->objectSubId == 0);
+			return OCLASS_PROC;
+
+		case RelOid_pg_type:
+			Assert(object->objectSubId == 0);
+			return OCLASS_TYPE;
+	}
+
+	/*
+	 * Handle cases where catalog's OID is not hardwired.
+	 *
+	 * Although these OIDs aren't compile-time constants, they surely
+	 * shouldn't change during a backend's run.  So, look them up the
+	 * first time through and then cache them.
+	 */
+	if (!reloids_initialized)
+	{
+		reloid_pg_constraint = get_system_catalog_relid(ConstraintRelationName);
+		reloid_pg_language = get_system_catalog_relid(LanguageRelationName);
+		reloid_pg_operator = get_system_catalog_relid(OperatorRelationName);
+		reloid_pg_rewrite = get_system_catalog_relid(RewriteRelationName);
+		reloid_pg_trigger = get_system_catalog_relid(TriggerRelationName);
+		reloids_initialized = true;
+	}
+
+	if (object->classId == reloid_pg_constraint)
+	{
+		Assert(object->objectSubId == 0);
+		return OCLASS_CONSTRAINT;
+	}
+	if (object->classId == reloid_pg_language)
+	{
+		Assert(object->objectSubId == 0);
+		return OCLASS_LANGUAGE;
+	}
+	if (object->classId == reloid_pg_operator)
+	{
+		Assert(object->objectSubId == 0);
+		return OCLASS_OPERATOR;
+	}
+	if (object->classId == reloid_pg_rewrite)
+	{
+		Assert(object->objectSubId == 0);
+		return OCLASS_REWRITE;
+	}
+	if (object->classId == reloid_pg_trigger)
+	{
+		Assert(object->objectSubId == 0);
+		return OCLASS_TRIGGER;
+	}
+
+	elog(ERROR, "getObjectClass: Unknown object class %u",
+		 object->classId);
+	return OCLASS_CLASS;		/* keep compiler quiet */
+}
+
+/*
+ * getObjectDescription: build an object description for messages
+ *
+ * The result is a palloc'd string.
+ */
+static char *
+getObjectDescription(const ObjectAddress *object)
+{
+	StringInfoData buffer;
+
+	initStringInfo(&buffer);
+
+	switch (getObjectClass(object))
+	{
+		case OCLASS_CLASS:
+		{
+			HeapTuple	relTup;
+			Form_pg_class	relForm;
+
+			relTup = SearchSysCache(RELOID,
+									ObjectIdGetDatum(object->objectId),
+									0, 0, 0);
+			if (!HeapTupleIsValid(relTup))
+				elog(ERROR, "getObjectDescription: Relation %u does not exist",
+					 object->objectId);
+			relForm = (Form_pg_class) GETSTRUCT(relTup);
+
+			switch (relForm->relkind)
+			{
+				case RELKIND_RELATION:
+					appendStringInfo(&buffer, "table %s",
+									 NameStr(relForm->relname));
+					break;
+				case RELKIND_INDEX:
+					appendStringInfo(&buffer, "index %s",
+									 NameStr(relForm->relname));
+					break;
+				case RELKIND_SPECIAL:
+					appendStringInfo(&buffer, "special system relation %s",
+									 NameStr(relForm->relname));
+					break;
+				case RELKIND_SEQUENCE:
+					appendStringInfo(&buffer, "sequence %s",
+									 NameStr(relForm->relname));
+					break;
+				case RELKIND_UNCATALOGED:
+					appendStringInfo(&buffer, "uncataloged table %s",
+									 NameStr(relForm->relname));
+					break;
+				case RELKIND_TOASTVALUE:
+					appendStringInfo(&buffer, "toast table %s",
+									 NameStr(relForm->relname));
+					break;
+				case RELKIND_VIEW:
+					appendStringInfo(&buffer, "view %s",
+									 NameStr(relForm->relname));
+					break;
+				default:
+					/* shouldn't get here */
+					appendStringInfo(&buffer, "relation %s",
+									 NameStr(relForm->relname));
+					break;
+			}
+
+			if (object->objectSubId != 0)
+				appendStringInfo(&buffer, " column %s",
+								 get_attname(object->objectId,
+											 object->objectSubId));
+
+			ReleaseSysCache(relTup);
+			break;
+		}
+
+		case OCLASS_PROC:
+			/* XXX could improve on this */
+			appendStringInfo(&buffer, "function %s",
+							 get_func_name(object->objectId));
+			break;
+
+		case OCLASS_TYPE:
+		{
+			HeapTuple		typeTup;
+
+			typeTup = SearchSysCache(TYPEOID,
+									 ObjectIdGetDatum(object->objectId),
+									 0, 0, 0);
+			if (!HeapTupleIsValid(typeTup))
+				elog(ERROR, "getObjectDescription: Type %u does not exist",
+					 object->objectId);
+			appendStringInfo(&buffer, "type %s",
+							 NameStr(((Form_pg_type) GETSTRUCT(typeTup))->typname));
+			ReleaseSysCache(typeTup);
+			break;
+		}
+
+		case OCLASS_CONSTRAINT:
+		{
+			Relation		conDesc;
+			ScanKeyData		skey[1];
+			SysScanDesc		rcscan;
+			HeapTuple		tup;
+			Form_pg_constraint con;
+
+			conDesc = heap_openr(ConstraintRelationName, AccessShareLock);
+
+			ScanKeyEntryInitialize(&skey[0], 0x0,
+								   ObjectIdAttributeNumber, F_OIDEQ,
+								   ObjectIdGetDatum(object->objectId));
+
+			rcscan = systable_beginscan(conDesc, ConstraintOidIndex, true,
+										SnapshotNow, 1, skey);
+
+			tup = systable_getnext(rcscan);
+
+			if (!HeapTupleIsValid(tup))
+				elog(ERROR, "getObjectDescription: Constraint %u does not exist",
+					 object->objectId);
+
+			con = (Form_pg_constraint) GETSTRUCT(tup);
+
+			appendStringInfo(&buffer, "constraint %s",
+							 NameStr(con->conname));
+			if (OidIsValid(con->conrelid))
+				appendStringInfo(&buffer, " on table %s",
+								 get_rel_name(con->conrelid));
+
+			systable_endscan(rcscan);
+			heap_close(conDesc, AccessShareLock);
+			break;
+		}
+
+		case OCLASS_LANGUAGE:
+		{
+			HeapTuple		langTup;
+
+			langTup = SearchSysCache(LANGOID,
+									 ObjectIdGetDatum(object->objectId),
+									 0, 0, 0);
+			if (!HeapTupleIsValid(langTup))
+				elog(ERROR, "getObjectDescription: Language %u does not exist",
+					 object->objectId);
+			appendStringInfo(&buffer, "language %s",
+							 NameStr(((Form_pg_language) GETSTRUCT(langTup))->lanname));
+			ReleaseSysCache(langTup);
+			break;
+		}
+
+		case OCLASS_OPERATOR:
+			/* XXX could improve on this */
+			appendStringInfo(&buffer, "operator %s",
+							 get_opname(object->objectId));
+			break;
+
+		case OCLASS_REWRITE:
+		{
+			Relation		ruleDesc;
+			ScanKeyData		skey[1];
+			SysScanDesc		rcscan;
+			HeapTuple		tup;
+			Form_pg_rewrite	rule;
+
+			ruleDesc = heap_openr(RewriteRelationName, AccessShareLock);
+
+			ScanKeyEntryInitialize(&skey[0], 0x0,
+								   ObjectIdAttributeNumber, F_OIDEQ,
+								   ObjectIdGetDatum(object->objectId));
+
+			rcscan = systable_beginscan(ruleDesc, RewriteOidIndex, true,
+										SnapshotNow, 1, skey);
+
+			tup = systable_getnext(rcscan);
+
+			if (!HeapTupleIsValid(tup))
+				elog(ERROR, "getObjectDescription: Rule %u does not exist",
+					 object->objectId);
+
+			rule = (Form_pg_rewrite) GETSTRUCT(tup);
+
+			appendStringInfo(&buffer, "rule %s",
+							 NameStr(rule->rulename));
+			if (OidIsValid(rule->ev_class))
+				appendStringInfo(&buffer, " on table %s",
+								 get_rel_name(rule->ev_class));
+
+			systable_endscan(rcscan);
+			heap_close(ruleDesc, AccessShareLock);
+			break;
+		}
+
+		case OCLASS_TRIGGER:
+		{
+			Relation		trigDesc;
+			ScanKeyData		skey[1];
+			SysScanDesc		tgscan;
+			HeapTuple		tup;
+			Form_pg_trigger	trig;
+
+			trigDesc = heap_openr(TriggerRelationName, AccessShareLock);
+
+			ScanKeyEntryInitialize(&skey[0], 0x0,
+								   ObjectIdAttributeNumber, F_OIDEQ,
+								   ObjectIdGetDatum(object->objectId));
+
+			tgscan = systable_beginscan(trigDesc, TriggerOidIndex, true,
+										SnapshotNow, 1, skey);
+
+			tup = systable_getnext(tgscan);
+
+			if (!HeapTupleIsValid(tup))
+				elog(ERROR, "getObjectDescription: Trigger %u does not exist",
+					 object->objectId);
+
+			trig = (Form_pg_trigger) GETSTRUCT(tup);
+
+			appendStringInfo(&buffer, "trigger %s",
+							 NameStr(trig->tgname));
+			if (OidIsValid(trig->tgrelid))
+				appendStringInfo(&buffer, " on table %s",
+								 get_rel_name(trig->tgrelid));
+
+			systable_endscan(tgscan);
+			heap_close(trigDesc, AccessShareLock);
+			break;
+		}
+
+		default:
+			appendStringInfo(&buffer, "unknown object %u %u %d",
+							 object->classId,
+							 object->objectId,
+							 object->objectSubId);
+			break;
+	}
+
+	return buffer.data;
+}
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 81fbee1fa583265ded15af57ddd9db6d91e7188c..207090ae70aba4e6df8f7196eba6f74776d5bd64 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.204 2002/06/20 20:29:26 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.205 2002/07/12 18:43:13 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -33,21 +33,20 @@
 #include "access/genam.h"
 #include "catalog/catalog.h"
 #include "catalog/catname.h"
+#include "catalog/dependency.h"
 #include "catalog/heap.h"
 #include "catalog/index.h"
 #include "catalog/indexing.h"
 #include "catalog/pg_attrdef.h"
+#include "catalog/pg_constraint.h"
 #include "catalog/pg_inherits.h"
-#include "catalog/pg_relcheck.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
-#include "commands/comment.h"
 #include "commands/trigger.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/planmain.h"
-#include "optimizer/prep.h"
 #include "optimizer/var.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_expr.h"
@@ -69,8 +68,6 @@ static void AddNewRelationTuple(Relation pg_class_desc,
 					char relkind, bool relhasoids);
 static void DeleteAttributeTuples(Relation rel);
 static void DeleteRelationTuple(Relation rel);
-static void DeleteTypeTuple(Relation rel);
-static void RelationRemoveIndexes(Relation relation);
 static void RelationRemoveInheritance(Relation relation);
 static void AddNewRelationType(const char *typeName,
 							   Oid typeNamespace,
@@ -80,7 +77,7 @@ static void StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin);
 static void StoreRelCheck(Relation rel, char *ccname, char *ccbin);
 static void StoreConstraints(Relation rel, TupleDesc tupdesc);
 static void SetRelationNumChecks(Relation rel, int numchecks);
-static void RemoveConstraints(Relation rel);
+static void RemoveDefaults(Relation rel);
 static void RemoveStatistics(Relation rel);
 
 
@@ -760,106 +757,42 @@ heap_create_with_catalog(const char *relname,
 }
 
 
-/* --------------------------------
+/*
  *		RelationRemoveInheritance
  *
- *		Note: for now, we cause an exception if relation is a
- *		superclass.  Someday, we may want to allow this and merge
- *		the type info into subclass procedures....	this seems like
- *		lots of work.
- * --------------------------------
+ * Formerly, this routine checked for child relations and aborted the
+ * deletion if any were found.  Now we rely on the dependency mechanism
+ * to check for or delete child relations.  By the time we get here,
+ * there are no children and we need only remove the pg_inherits rows.
  */
 static void
 RelationRemoveInheritance(Relation relation)
 {
 	Relation	catalogRelation;
 	HeapTuple	tuple;
-	HeapScanDesc scan;
+	SysScanDesc scan;
 	ScanKeyData entry;
-	bool		found = false;
 
-	/*
-	 * open pg_inherits
-	 */
 	catalogRelation = heap_openr(InheritsRelationName, RowExclusiveLock);
 
-	/*
-	 * form a scan key for the subclasses of this class and begin scanning
-	 */
-	ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_inherits_inhparent,
-						   F_OIDEQ,
+	ScanKeyEntryInitialize(&entry, 0x0,
+						   Anum_pg_inherits_inhrelid, F_OIDEQ,
 						   ObjectIdGetDatum(RelationGetRelid(relation)));
 
-	scan = heap_beginscan(catalogRelation,
-						  SnapshotNow,
-						  1,
-						  &entry);
-
-	/*
-	 * if any subclasses exist, then we disallow the deletion.
-	 */
-	if ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
-	{
-		Oid			subclass = ((Form_pg_inherits) GETSTRUCT(tuple))->inhrelid;
-		char	   *subclassname;
-
-		subclassname = get_rel_name(subclass);
-		/* Just in case get_rel_name fails... */
-		if (subclassname)
-			elog(ERROR, "Relation \"%s\" inherits from \"%s\"",
-				 subclassname, RelationGetRelationName(relation));
-		else
-			elog(ERROR, "Relation %u inherits from \"%s\"",
-				 subclass, RelationGetRelationName(relation));
-	}
-	heap_endscan(scan);
-
-	/*
-	 * If we get here, it means the relation has no subclasses so we can
-	 * trash it.  First we remove dead INHERITS tuples.
-	 */
-	entry.sk_attno = Anum_pg_inherits_inhrelid;
-
-	scan = heap_beginscan(catalogRelation,
-						  SnapshotNow,
-						  1,
-						  &entry);
+	scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndex, true,
+							  SnapshotNow, 1, &entry);
 
-	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
 	{
 		simple_heap_delete(catalogRelation, &tuple->t_self);
-		found = true;
 	}
 
-	heap_endscan(scan);
+	systable_endscan(scan);
 	heap_close(catalogRelation, RowExclusiveLock);
 }
 
 /*
- *		RelationRemoveIndexes
- */
-static void
-RelationRemoveIndexes(Relation relation)
-{
-	List	   *indexoidlist,
-			   *indexoidscan;
-
-	indexoidlist = RelationGetIndexList(relation);
-
-	foreach(indexoidscan, indexoidlist)
-	{
-		Oid			indexoid = lfirsti(indexoidscan);
-
-		index_drop(indexoid);
-	}
-
-	freeList(indexoidlist);
-}
-
-/* --------------------------------
  *		DeleteRelationTuple
- *
- * --------------------------------
  */
 static void
 DeleteRelationTuple(Relation rel)
@@ -1049,163 +982,34 @@ DeleteAttributeTuples(Relation rel)
 	heap_close(pg_attribute_desc, RowExclusiveLock);
 }
 
-/* --------------------------------
- *		DeleteTypeTuple
- *
- *		If the user attempts to destroy a relation and there
- *		exists attributes in other relations of type
- *		"relation we are deleting", then we have to do something
- *		special.  presently we disallow the destroy.
- * --------------------------------
- */
-static void
-DeleteTypeTuple(Relation rel)
-{
-	Relation	pg_type_desc;
-	HeapScanDesc pg_type_scan;
-	Relation	pg_attribute_desc;
-	HeapScanDesc pg_attribute_scan;
-	ScanKeyData key;
-	ScanKeyData attkey;
-	HeapTuple	tup;
-	HeapTuple	atttup;
-	Oid			typoid;
-
-	/*
-	 * open pg_type
-	 */
-	pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
-
-	/*
-	 * create a scan key to locate the type tuple corresponding to this
-	 * relation.
-	 */
-	ScanKeyEntryInitialize(&key, 0,
-						   Anum_pg_type_typrelid,
-						   F_OIDEQ,
-						   ObjectIdGetDatum(RelationGetRelid(rel)));
-
-	pg_type_scan = heap_beginscan(pg_type_desc,
-								  SnapshotNow,
-								  1,
-								  &key);
-
-	/*
-	 * use heap_getnext() to fetch the pg_type tuple.  If this tuple is
-	 * not valid then something's wrong.
-	 */
-	tup = heap_getnext(pg_type_scan, ForwardScanDirection);
-
-	if (!HeapTupleIsValid(tup))
-	{
-		heap_endscan(pg_type_scan);
-		heap_close(pg_type_desc, RowExclusiveLock);
-		elog(ERROR, "DeleteTypeTuple: type \"%s\" does not exist",
-			 RelationGetRelationName(rel));
-	}
-
-	/*
-	 * now scan pg_attribute.  if any other relations have attributes of
-	 * the type of the relation we are deleteing then we have to disallow
-	 * the deletion.  should talk to stonebraker about this.  -cim 6/19/90
-	 */
-	typoid = tup->t_data->t_oid;
-
-	pg_attribute_desc = heap_openr(AttributeRelationName, RowExclusiveLock);
-
-	ScanKeyEntryInitialize(&attkey,
-						   0,
-						   Anum_pg_attribute_atttypid,
-						   F_OIDEQ,
-						   ObjectIdGetDatum(typoid));
-
-	pg_attribute_scan = heap_beginscan(pg_attribute_desc,
-									   SnapshotNow,
-									   1,
-									   &attkey);
-
-	/*
-	 * try and get a pg_attribute tuple.  if we succeed it means we can't
-	 * delete the relation because something depends on the schema.
-	 */
-	atttup = heap_getnext(pg_attribute_scan, ForwardScanDirection);
-
-	if (HeapTupleIsValid(atttup))
-	{
-		Oid			relid = ((Form_pg_attribute) GETSTRUCT(atttup))->attrelid;
-
-		heap_endscan(pg_attribute_scan);
-		heap_close(pg_attribute_desc, RowExclusiveLock);
-		heap_endscan(pg_type_scan);
-		heap_close(pg_type_desc, RowExclusiveLock);
-
-		elog(ERROR, "DeleteTypeTuple: column of type %s exists in relation %u",
-			 RelationGetRelationName(rel), relid);
-	}
-	heap_endscan(pg_attribute_scan);
-	heap_close(pg_attribute_desc, RowExclusiveLock);
-
-	/*
-	 * Ok, it's safe so we delete the relation tuple from pg_type and
-	 * finish up.
-	 */
-	simple_heap_delete(pg_type_desc, &tup->t_self);
-
-	heap_endscan(pg_type_scan);
-	heap_close(pg_type_desc, RowExclusiveLock);
-}
-
 /* ----------------------------------------------------------------
- *		heap_drop_with_catalog	- removes all record of named relation from catalogs
+ *		heap_drop_with_catalog	- removes specified relation from catalogs
  *
- *		1)	open relation, check for existence, etc.
- *		2)	remove inheritance information
- *		3)	remove indexes
- *		4)	remove pg_class tuple
- *		5)	remove pg_attribute tuples and related descriptions
- *		6)	remove pg_description tuples
- *		7)	remove pg_type tuples
- *		8)	RemoveConstraints ()
- *		9)	unlink relation
+ *		1)	open relation, acquire exclusive lock.
+ *		2)	flush relation buffers from bufmgr
+ *		3)	remove inheritance information
+ *		4)	remove pg_statistic tuples
+ *		5)	remove pg_attribute tuples and related items
+ *		6)	remove pg_class tuple
+ *		7)	unlink relation file
  *
- * old comments
- *		Except for vital relations, removes relation from
- *		relation catalog, and related attributes from
- *		attribute catalog (needed?).  (Anything else?)
- *
- *		get proper relation from relation catalog (if not arg)
- *		scan attribute catalog deleting attributes of reldesc
- *				(necessary?)
- *		delete relation from relation catalog
- *		(How are the tuples of the relation discarded?)
- *
- *		XXX Must fix to work with indexes.
- *		There may be a better order for doing things.
- *		Problems with destroying a deleted database--cannot create
- *		a struct reldesc without having an open file descriptor.
+ * Note that this routine is not responsible for dropping objects that are
+ * linked to the pg_class entry via dependencies (for example, indexes and
+ * constraints).  Those are deleted by the dependency-tracing logic in
+ * dependency.c before control gets here.  In general, therefore, this routine
+ * should never be called directly; go through performDeletion() instead.
  * ----------------------------------------------------------------
  */
 void
-heap_drop_with_catalog(Oid rid,
-					   bool allow_system_table_mods)
+heap_drop_with_catalog(Oid rid)
 {
 	Relation	rel;
-	Oid			toasttableOid;
 	int			i;
 
 	/*
 	 * Open and lock the relation.
 	 */
 	rel = heap_open(rid, AccessExclusiveLock);
-	toasttableOid = rel->rd_rel->reltoastrelid;
-
-	/*
-	 * prevent deletion of system relations
-	 */
-	if (!allow_system_table_mods &&
-		IsSystemRelation(rel))
-		elog(ERROR, "System relation \"%s\" may not be dropped",
-			 RelationGetRelationName(rel));
 
 	/*
 	 * Release all buffers that belong to this relation, after writing any
@@ -1216,43 +1020,22 @@ heap_drop_with_catalog(Oid rid,
 		elog(ERROR, "heap_drop_with_catalog: FlushRelationBuffers returned %d",
 			 i);
 
-	/*
-	 * remove rules if necessary
-	 */
-	if (rel->rd_rules != NULL)
-		RelationRemoveRules(rid);
-
-	/* triggers */
-	RelationRemoveTriggers(rel);
-
 	/*
 	 * remove inheritance information
 	 */
 	RelationRemoveInheritance(rel);
 
 	/*
-	 * remove indexes if necessary
+	 * delete statistics
 	 */
-	RelationRemoveIndexes(rel);
+	RemoveStatistics(rel);
 
 	/*
-	 * delete attribute tuples
+	 * delete attribute tuples and associated defaults
 	 */
 	DeleteAttributeTuples(rel);
 
-	/*
-	 * delete comments, statistics, and constraints
-	 */
-	DeleteComments(rid, RelOid_pg_class);
-
-	RemoveStatistics(rel);
-
-	RemoveConstraints(rel);
-
-	/*
-	 * delete type tuple
-	 */
-	DeleteTypeTuple(rel);
+	RemoveDefaults(rel);
 
 	/*
 	 * delete relation tuple
@@ -1276,10 +1059,6 @@ heap_drop_with_catalog(Oid rid,
 	 * flush the relation from the relcache
 	 */
 	RelationForgetRelation(rid);
-
-	/* If it has a toast table, recurse to get rid of that too */
-	if (OidIsValid(toasttableOid))
-		heap_drop_with_catalog(toasttableOid, true);
 }
 
 
@@ -1374,11 +1153,9 @@ StoreRelCheck(Relation rel, char *ccname, char *ccbin)
 {
 	Node	   *expr;
 	char	   *ccsrc;
-	Relation	rcrel;
-	Relation	idescs[Num_pg_relcheck_indices];
-	HeapTuple	tuple;
-	Datum		values[4];
-	static char nulls[4] = {' ', ' ', ' ', ' '};
+	List	   *varList;
+	int			keycount;
+	int16	   *attNos;
 
 	/*
 	 * Convert condition to a normal boolean expression tree.
@@ -1394,26 +1171,55 @@ StoreRelCheck(Relation rel, char *ccname, char *ccbin)
 											RelationGetRelid(rel)),
 							   false);
 
-	values[Anum_pg_relcheck_rcrelid - 1] = RelationGetRelid(rel);
-	values[Anum_pg_relcheck_rcname - 1] = DirectFunctionCall1(namein,
-												CStringGetDatum(ccname));
-	values[Anum_pg_relcheck_rcbin - 1] = DirectFunctionCall1(textin,
-												 CStringGetDatum(ccbin));
-	values[Anum_pg_relcheck_rcsrc - 1] = DirectFunctionCall1(textin,
-												 CStringGetDatum(ccsrc));
-	rcrel = heap_openr(RelCheckRelationName, RowExclusiveLock);
-	tuple = heap_formtuple(rcrel->rd_att, values, nulls);
-	simple_heap_insert(rcrel, tuple);
-	CatalogOpenIndices(Num_pg_relcheck_indices, Name_pg_relcheck_indices,
-					   idescs);
-	CatalogIndexInsert(idescs, Num_pg_relcheck_indices, rcrel, tuple);
-	CatalogCloseIndices(Num_pg_relcheck_indices, idescs);
-	heap_close(rcrel, RowExclusiveLock);
+	/*
+	 * Find columns of rel that are used in ccbin
+	 */
+	varList = pull_var_clause(expr, false);
+	keycount = length(varList);
+
+	if (keycount > 0)
+	{
+		List	   *vl;
+		int			i = 0;
+
+		attNos = (int16 *) palloc(keycount * sizeof(int16));
+		foreach(vl, varList)
+		{
+			Var	   *var = (Var *) lfirst(vl);
+			int		j;
+
+			for (j = 0; j < i; j++)
+				if (attNos[j] == var->varattno)
+					break;
+			if (j == i)
+				attNos[i++] = var->varattno;
+		}
+		keycount = i;
+	}
+	else
+		attNos = NULL;
+
+	/*
+	 * Create the Check Constraint
+	 */
+	CreateConstraintEntry(ccname, 	/* Constraint Name */
+						  RelationGetNamespace(rel), /* namespace */
+						  CONSTRAINT_CHECK, /* Constraint Type */
+						  false, 	/* Is Deferrable */
+						  false,	/* Is Deferred */
+						  RelationGetRelid(rel), /* relation */
+						  attNos,	/* List of attributes in the constraint */
+						  keycount,	/* # attributes in the constraint */
+						  InvalidOid, /* not a domain constraint */
+						  InvalidOid, /* Foreign key fields */
+						  NULL,
+						  0,
+						  ' ',
+						  ' ',
+						  ' ',
+						  ccbin,	/* Binary form check constraint */
+						  ccsrc);	/* Source form check constraint */
 
-	pfree(DatumGetPointer(values[Anum_pg_relcheck_rcname - 1]));
-	pfree(DatumGetPointer(values[Anum_pg_relcheck_rcbin - 1]));
-	pfree(DatumGetPointer(values[Anum_pg_relcheck_rcsrc - 1]));
-	heap_freetuple(tuple);
 	pfree(ccsrc);
 }
 
@@ -1488,6 +1294,7 @@ AddRelationRawConstraints(Relation rel,
 	ParseState *pstate;
 	RangeTblEntry *rte;
 	int			numchecks;
+	int			constr_name_ctr = 0;
 	List	   *listptr;
 	Node	   *expr;
 
@@ -1549,18 +1356,17 @@ AddRelationRawConstraints(Relation rel,
 		/* Check name uniqueness, or generate a new name */
 		if (cdef->name != NULL)
 		{
-			int			i;
 			List	   *listptr2;
 
 			ccname = cdef->name;
-			/* Check against old constraints */
-			for (i = 0; i < numoldchecks; i++)
-			{
-				if (strcmp(oldchecks[i].ccname, ccname) == 0)
-					elog(ERROR, "Duplicate CHECK constraint name: '%s'",
-						 ccname);
-			}
+			/* Check against pre-existing constraints */
+			if (ConstraintNameIsUsed(RelationGetRelid(rel),
+									 RelationGetNamespace(rel),
+									 ccname))
+				elog(ERROR, "constraint \"%s\" already exists for relation \"%s\"",
+					 ccname, RelationGetRelationName(rel));
 			/* Check against other new constraints */
+			/* Needed because we don't do CommandCounterIncrement in loop */
 			foreach(listptr2, rawConstraints)
 			{
 				Constraint *cdef2 = (Constraint *) lfirst(listptr2);
@@ -1577,55 +1383,40 @@ AddRelationRawConstraints(Relation rel,
 		}
 		else
 		{
-			int			i;
-			int			j;
 			bool		success;
-			List	   *listptr2;
 
-			ccname = (char *) palloc(NAMEDATALEN);
-
-			/* Loop until we find a non-conflicting constraint name */
-			/* What happens if this loops forever? */
-			j = numchecks + 1;
 			do
 			{
-				success = true;
-				snprintf(ccname, NAMEDATALEN, "$%d", j);
-
-				/* Check against old constraints */
-				for (i = 0; i < numoldchecks; i++)
-				{
-					if (strcmp(oldchecks[i].ccname, ccname) == 0)
-					{
-						success = false;
-						break;
-					}
-				}
+				List	   *listptr2;
 
 				/*
-				 * Check against other new constraints, if the check
-				 * hasn't already failed
+				 * Generate a name that does not conflict with pre-existing
+				 * constraints, nor with any auto-generated names so far.
+				 */
+				ccname = GenerateConstraintName(RelationGetRelid(rel),
+												RelationGetNamespace(rel),
+												&constr_name_ctr);
+				/*
+				 * Check against other new constraints, in case the user
+				 * has specified a name that looks like an auto-generated
+				 * name.
 				 */
-				if (success)
+				success = true;
+				foreach(listptr2, rawConstraints)
 				{
-					foreach(listptr2, rawConstraints)
+					Constraint *cdef2 = (Constraint *) lfirst(listptr2);
+
+					if (cdef2 == cdef ||
+						cdef2->contype != CONSTR_CHECK ||
+						cdef2->raw_expr == NULL ||
+						cdef2->name == NULL)
+						continue;
+					if (strcmp(cdef2->name, ccname) == 0)
 					{
-						Constraint *cdef2 = (Constraint *) lfirst(listptr2);
-
-						if (cdef2 == cdef ||
-							cdef2->contype != CONSTR_CHECK ||
-							cdef2->raw_expr == NULL ||
-							cdef2->name == NULL)
-							continue;
-						if (strcmp(cdef2->name, ccname) == 0)
-						{
-							success = false;
-							break;
-						}
+						success = false;
+						break;
 					}
 				}
-
-				++j;
 			} while (!success);
 		}
 
@@ -1852,157 +1643,74 @@ RemoveAttrDefaults(Relation rel)
 	heap_close(adrel, RowExclusiveLock);
 }
 
-static void
-RemoveRelChecks(Relation rel)
-{
-	Relation	rcrel;
-	HeapScanDesc rcscan;
-	ScanKeyData key;
-	HeapTuple	tup;
-
-	rcrel = heap_openr(RelCheckRelationName, RowExclusiveLock);
-
-	ScanKeyEntryInitialize(&key, 0, Anum_pg_relcheck_rcrelid,
-						   F_OIDEQ,
-						   ObjectIdGetDatum(RelationGetRelid(rel)));
-
-	rcscan = heap_beginscan(rcrel, SnapshotNow, 1, &key);
-
-	while ((tup = heap_getnext(rcscan, ForwardScanDirection)) != NULL)
-		simple_heap_delete(rcrel, &tup->t_self);
-
-	heap_endscan(rcscan);
-	heap_close(rcrel, RowExclusiveLock);
-
-}
-
 /*
- * Removes all CHECK constraints on a relation that match the given name.
- * It is the responsibility of the calling function to acquire a lock on
- * the relation.
- * Returns: The number of CHECK constraints removed.
+ * Removes all constraints on a relation that match the given name.
+ *
+ * It is the responsibility of the calling function to acquire a suitable
+ * lock on the relation.
+ *
+ * Returns: The number of constraints removed.
  */
 int
-RemoveCheckConstraint(Relation rel, const char *constrName, bool inh)
+RemoveRelConstraints(Relation rel, const char *constrName,
+					 DropBehavior behavior)
 {
-	Oid			relid;
-	Relation	rcrel;
-	TupleDesc	tupleDesc;
-	TupleConstr *oldconstr;
-	int			numoldchecks;
-	int			numchecks;
-	HeapScanDesc rcscan;
-	ScanKeyData key[2];
-	HeapTuple	rctup;
-	int			rel_deleted = 0;
-	int			all_deleted = 0;
+	int			ndeleted = 0;
+	Relation	conrel;
+	SysScanDesc	conscan;
+	ScanKeyData key[1];
+	HeapTuple	contup;
+
+	/* 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_conrelid, F_OIDEQ,
+						   ObjectIdGetDatum(RelationGetRelid(rel)));
 
-	/* Find id of the relation */
-	relid = RelationGetRelid(rel);
+	conscan = systable_beginscan(conrel, ConstraintRelidIndex, true,
+								 SnapshotNow, 1, key);
 
 	/*
-	 * Process child tables and remove constraints of the same name.
+	 * Scan over the result set, removing any matching entries.
 	 */
-	if (inh)
+	while ((contup = systable_getnext(conscan)) != NULL)
 	{
-		List	   *child,
-				   *children;
-
-		/* This routine is actually in the planner */
-		children = find_all_inheritors(relid);
+		Form_pg_constraint	con = (Form_pg_constraint) GETSTRUCT(contup);
 
-		/*
-		 * find_all_inheritors does the recursive search of the
-		 * inheritance hierarchy, so all we have to do is process all of
-		 * the relids in the list that it returns.
-		 */
-		foreach(child, children)
+		if (strcmp(NameStr(con->conname), constrName) == 0)
 		{
-			Oid			childrelid = lfirsti(child);
-			Relation	inhrel;
-
-			if (childrelid == relid)
-				continue;
-			inhrel = heap_open(childrelid, AccessExclusiveLock);
-			all_deleted += RemoveCheckConstraint(inhrel, constrName, false);
-			heap_close(inhrel, NoLock);
-		}
-	}
-
-	/*
-	 * Get number of existing constraints.
-	 */
-	tupleDesc = RelationGetDescr(rel);
-	oldconstr = tupleDesc->constr;
-	if (oldconstr)
-		numoldchecks = oldconstr->num_check;
-	else
-		numoldchecks = 0;
+			ObjectAddress	conobj;
 
-	/* Grab an appropriate lock on the pg_relcheck relation */
-	rcrel = heap_openr(RelCheckRelationName, RowExclusiveLock);
+			conobj.classId = RelationGetRelid(conrel);
+			conobj.objectId = contup->t_data->t_oid;
+			conobj.objectSubId = 0;
 
-	/*
-	 * Create two scan keys.  We need to match on the oid of the table the
-	 * CHECK is in and also we need to match the name of the CHECK
-	 * constraint.
-	 */
-	ScanKeyEntryInitialize(&key[0], 0, Anum_pg_relcheck_rcrelid,
-						   F_OIDEQ,
-						   ObjectIdGetDatum(RelationGetRelid(rel)));
+			performDeletion(&conobj, behavior);
 
-	ScanKeyEntryInitialize(&key[1], 0, Anum_pg_relcheck_rcname,
-						   F_NAMEEQ,
-						   PointerGetDatum(constrName));
-
-	/* Begin scanning the heap */
-	rcscan = heap_beginscan(rcrel, SnapshotNow, 2, key);
-
-	/*
-	 * Scan over the result set, removing any matching entries.  Note that
-	 * this has the side-effect of removing ALL CHECK constraints that
-	 * share the specified constraint name.
-	 */
-	while ((rctup = heap_getnext(rcscan, ForwardScanDirection)) != NULL)
-	{
-		simple_heap_delete(rcrel, &rctup->t_self);
-		++rel_deleted;
-		++all_deleted;
+			ndeleted++;
+		}
 	}
 
 	/* Clean up after the scan */
-	heap_endscan(rcscan);
-	heap_close(rcrel, RowExclusiveLock);
+	systable_endscan(conscan);
+	heap_close(conrel, RowExclusiveLock);
 
-	if (rel_deleted)
-	{
-		/*
-		 * Update the count of constraints in the relation's pg_class tuple.
-		 */
-		numchecks = numoldchecks - rel_deleted;
-		if (numchecks < 0)
-			elog(ERROR, "check count became negative");
-
-		SetRelationNumChecks(rel, numchecks);
-	}
-
-	/* Return the number of tuples deleted, including all children */
-	return all_deleted;
+	return ndeleted;
 }
 
 static void
-RemoveConstraints(Relation rel)
+RemoveDefaults(Relation rel)
 {
 	TupleConstr *constr = rel->rd_att->constr;
 
-	if (!constr)
-		return;
-
-	if (constr->num_defval > 0)
+	/*
+	 * We can skip looking at pg_attrdef if there are no defaults recorded
+	 * in the Relation.
+	 */
+	if (constr && constr->num_defval > 0)
 		RemoveAttrDefaults(rel);
-
-	if (constr->num_check > 0)
-		RemoveRelChecks(rel);
 }
 
 static void
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 2b6f77594c6e788d38e690048d2127787a934ac1..30cef89feff6f7aa17a4bcfbf2198aeed62ffa5c 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.181 2002/06/20 20:29:26 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.182 2002/07/12 18:43:13 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -29,14 +29,15 @@
 #include "bootstrap/bootstrap.h"
 #include "catalog/catalog.h"
 #include "catalog/catname.h"
+#include "catalog/dependency.h"
 #include "catalog/heap.h"
 #include "catalog/index.h"
 #include "catalog/indexing.h"
+#include "catalog/pg_constraint.h"
 #include "catalog/pg_index.h"
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
-#include "commands/comment.h"
 #include "executor/executor.h"
 #include "miscadmin.h"
 #include "optimizer/clauses.h"
@@ -535,6 +536,7 @@ index_create(Oid heapRelationId,
 			 Oid accessMethodObjectId,
 			 Oid *classObjectId,
 			 bool primary,
+			 bool isconstraint,
 			 bool allow_system_table_mods)
 {
 	Relation	heapRelation;
@@ -543,6 +545,7 @@ index_create(Oid heapRelationId,
 	bool		shared_relation;
 	Oid			namespaceId;
 	Oid			indexoid;
+	int			i;
 
 	SetReindexProcessing(false);
 
@@ -660,7 +663,89 @@ index_create(Oid heapRelationId,
 						classObjectId, primary);
 
 	/*
-	 * fill in the index strategy structure with information from the
+	 * Register constraint and dependencies for the index.
+	 *
+	 * If the index is from a CONSTRAINT clause, construct a pg_constraint
+	 * entry.  The index is then linked to the constraint, which in turn is
+	 * linked to the table.  If it's not a CONSTRAINT, make the dependency
+	 * directly on the table.
+	 *
+	 * During bootstrap we can't register any dependencies, and we don't
+	 * try to make a constraint either.
+	 */
+	if (!IsBootstrapProcessingMode())
+	{
+		ObjectAddress	myself,
+						referenced;
+
+		myself.classId = RelOid_pg_class;
+		myself.objectId = indexoid;
+		myself.objectSubId = 0;
+
+		if (isconstraint)
+		{
+			char		constraintType;
+			Oid			conOid;
+
+			if (primary)
+				constraintType = CONSTRAINT_PRIMARY;
+			else if (indexInfo->ii_Unique)
+				constraintType = CONSTRAINT_UNIQUE;
+			else
+			{
+				elog(ERROR, "index_create: constraint must be PRIMARY or UNIQUE");
+				constraintType = 0;	/* keep compiler quiet */
+			}
+
+			conOid = CreateConstraintEntry(indexRelationName,
+										   namespaceId,
+										   constraintType,
+										   false, /* isDeferrable */
+										   false, /* isDeferred */
+										   heapRelationId,
+										   indexInfo->ii_KeyAttrNumbers,
+										   indexInfo->ii_NumIndexAttrs,
+										   InvalidOid, /* no domain */
+										   InvalidOid, /* no foreign key */
+										   NULL,
+										   0,
+										   ' ',
+										   ' ',
+										   ' ',
+										   NULL, /* Constraint Bin & Src */
+										   NULL);
+
+			referenced.classId = get_system_catalog_relid(ConstraintRelationName);
+			referenced.objectId = conOid;
+			referenced.objectSubId = 0;
+
+			recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
+		}
+		else
+		{
+			for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
+			{
+				referenced.classId = RelOid_pg_class;
+				referenced.objectId = heapRelationId;
+				referenced.objectSubId = indexInfo->ii_KeyAttrNumbers[i];
+
+				recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
+			}
+		}
+
+		/* Store the dependency on the function (if appropriate) */
+		if (OidIsValid(indexInfo->ii_FuncOid))
+		{
+			referenced.classId = RelOid_pg_proc;
+			referenced.objectId = indexInfo->ii_FuncOid;
+			referenced.objectSubId = 0;
+
+			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		}
+	}
+
+	/*
+	 * Fill in the index strategy structure with information from the
 	 * catalogs.  First we must advance the command counter so that we
 	 * will see the newly-entered index catalog tuples.
 	 */
@@ -691,11 +776,11 @@ index_create(Oid heapRelationId,
 	return indexoid;
 }
 
-/* ----------------------------------------------------------------
- *
+/*
  *		index_drop
  *
- * ----------------------------------------------------------------
+ * NOTE: this routine should now only be called through performDeletion(),
+ * else associated dependencies won't be cleaned up.
  */
 void
 index_drop(Oid indexId)
@@ -730,17 +815,6 @@ index_drop(Oid indexId)
 	userIndexRelation = index_open(indexId);
 	LockRelation(userIndexRelation, AccessExclusiveLock);
 
-	/*
-	 * Note: unlike heap_drop_with_catalog, we do not need to prevent
-	 * deletion of system indexes here; that's checked for upstream. If we
-	 * did check it here, deletion of TOAST tables would fail...
-	 */
-
-	/*
-	 * fix DESCRIPTION relation
-	 */
-	DeleteComments(indexId, RelOid_pg_class);
-
 	/*
 	 * fix RELATION relation
 	 */
diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c
index 5611edda85343827176b48aa1353bce71607dbcd..9925c39af1e1cac39d7b31d3c4d2e88763129f45 100644
--- a/src/backend/catalog/indexing.c
+++ b/src/backend/catalog/indexing.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.95 2002/07/11 07:39:27 ishii Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.96 2002/07/12 18:43:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -45,10 +45,14 @@ char	   *Name_pg_attrdef_indices[Num_pg_attrdef_indices] =
 {AttrDefaultIndex};
 char	   *Name_pg_class_indices[Num_pg_class_indices] =
 {ClassNameNspIndex, ClassOidIndex};
+char	   *Name_pg_constraint_indices[Num_pg_constraint_indices] =
+{ConstraintNameNspIndex, ConstraintOidIndex, ConstraintRelidIndex};
 char	   *Name_pg_conversion_indices[Num_pg_conversion_indices] =
 {ConversionNameNspIndex, ConversionDefaultIndex};
 char	   *Name_pg_database_indices[Num_pg_database_indices] =
 {DatabaseNameIndex, DatabaseOidIndex};
+char	   *Name_pg_depend_indices[Num_pg_depend_indices] =
+{DependDependerIndex, DependReferenceIndex};
 char	   *Name_pg_group_indices[Num_pg_group_indices] =
 {GroupNameIndex, GroupSysidIndex};
 char	   *Name_pg_index_indices[Num_pg_index_indices] =
@@ -67,8 +71,6 @@ char	   *Name_pg_operator_indices[Num_pg_operator_indices] =
 {OperatorOidIndex, OperatorNameNspIndex};
 char	   *Name_pg_proc_indices[Num_pg_proc_indices] =
 {ProcedureOidIndex, ProcedureNameNspIndex};
-char	   *Name_pg_relcheck_indices[Num_pg_relcheck_indices] =
-{RelCheckIndex};
 char	   *Name_pg_rewrite_indices[Num_pg_rewrite_indices] =
 {RewriteOidIndex, RewriteRelRulenameIndex};
 char	   *Name_pg_shadow_indices[Num_pg_shadow_indices] =
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 2af7e1d00f00bae79babf221df2c40719b7ad7d7..ad5a0c0d6a3aedb9c982dd3efce3760e74d9c8b8 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.23 2002/06/20 20:29:26 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.24 2002/07/12 18:43:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,6 +23,7 @@
 #include "access/xact.h"
 #include "catalog/catalog.h"
 #include "catalog/catname.h"
+#include "catalog/dependency.h"
 #include "catalog/heap.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_inherits.h"
@@ -128,25 +129,10 @@ static Oid	mySpecialNamespace = InvalidOid;
 char *namespace_search_path = NULL;
 
 
-/*
- * Deletion ordering constraint item.
- */
-typedef struct DelConstraint
-{
-	Oid			referencer;		/* table to delete first */
-	Oid			referencee;		/* table to delete second */
-	int			pred;			/* workspace for TopoSortRels */
-	struct DelConstraint *link;	/* workspace for TopoSortRels */
-} DelConstraint;
-
-
 /* Local functions */
 static void recomputeNamespacePath(void);
 static void InitTempTableNamespace(void);
 static void RemoveTempRelations(Oid tempNamespaceId);
-static List *FindTempRelations(Oid tempNamespaceId);
-static List *FindDeletionConstraints(List *relOids);
-static List *TopoSortRels(List *relOids, List *constraintList);
 static void RemoveTempRelationsCallback(void);
 static void NamespaceCallback(Datum arg, Oid relid);
 
@@ -1531,56 +1517,22 @@ AtEOXact_Namespace(bool isCommit)
 static void
 RemoveTempRelations(Oid tempNamespaceId)
 {
-	List	   *tempRelList;
-	List	   *constraintList;
-	List	   *lptr;
-
-	/* Get a list of relations to delete */
-	tempRelList = FindTempRelations(tempNamespaceId);
-
-	if (tempRelList == NIL)
-		return;					/* nothing to do */
-
-	/* If more than one, sort them to respect any deletion-order constraints */
-	if (length(tempRelList) > 1)
-	{
-		constraintList = FindDeletionConstraints(tempRelList);
-		if (constraintList != NIL)
-			tempRelList = TopoSortRels(tempRelList, constraintList);
-	}
-
-	/* Scan the list and delete all entries */
-	foreach(lptr, tempRelList)
-	{
-		Oid			reloid = (Oid) lfirsti(lptr);
-
-		heap_drop_with_catalog(reloid, true);
-		/*
-		 * Advance cmd counter to make catalog changes visible, in case
-		 * a later entry depends on this one.
-		 */
-		CommandCounterIncrement();
-	}
-}
-
-/*
- * Find all relations in the specified temp namespace.
- *
- * Returns a list of relation OIDs.
- */
-static List *
-FindTempRelations(Oid tempNamespaceId)
-{
-	List	   *tempRelList = NIL;
 	Relation	pgclass;
 	HeapScanDesc scan;
 	HeapTuple	tuple;
 	ScanKeyData key;
+	ObjectAddress object;
 
 	/*
 	 * Scan pg_class to find all the relations in the target namespace.
 	 * Ignore indexes, though, on the assumption that they'll go away
 	 * when their tables are deleted.
+	 *
+	 * NOTE: if there are deletion constraints between temp relations,
+	 * then our CASCADE delete call may cause as-yet-unvisited objects
+	 * to go away.  This is okay because we are using SnapshotNow; when
+	 * the scan does reach those pg_class tuples, they'll be ignored as
+	 * already deleted.
 	 */
 	ScanKeyEntryInitialize(&key, 0x0,
 						   Anum_pg_class_relnamespace,
@@ -1597,7 +1549,10 @@ FindTempRelations(Oid tempNamespaceId)
 			case RELKIND_RELATION:
 			case RELKIND_SEQUENCE:
 			case RELKIND_VIEW:
-				tempRelList = lconsi(tuple->t_data->t_oid, tempRelList);
+				object.classId = RelOid_pg_class;
+				object.objectId = tuple->t_data->t_oid;
+				object.objectSubId = 0;
+				performDeletion(&object, DROP_CASCADE);
 				break;
 			default:
 				break;
@@ -1606,164 +1561,6 @@ FindTempRelations(Oid tempNamespaceId)
 
 	heap_endscan(scan);
 	heap_close(pgclass, AccessShareLock);
-
-	return tempRelList;
-}
-
-/*
- * Find deletion-order constraints involving the given relation OIDs.
- *
- * Returns a list of DelConstraint objects.
- */
-static List *
-FindDeletionConstraints(List *relOids)
-{
-	List	   *constraintList = NIL;
-	Relation	inheritsrel;
-	HeapScanDesc scan;
-	HeapTuple	tuple;
-
-	/*
-	 * Scan pg_inherits to find parents and children that are in the list.
-	 */
-	inheritsrel = heap_openr(InheritsRelationName, AccessShareLock);
-	scan = heap_beginscan(inheritsrel, SnapshotNow, 0, NULL);
-
-	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
-	{
-		Oid		inhrelid = ((Form_pg_inherits) GETSTRUCT(tuple))->inhrelid;
-		Oid		inhparent = ((Form_pg_inherits) GETSTRUCT(tuple))->inhparent;
-
-		if (intMember(inhrelid, relOids) && intMember(inhparent, relOids))
-		{
-			DelConstraint  *item;
-
-			item = (DelConstraint *) palloc(sizeof(DelConstraint));
-			item->referencer = inhrelid;
-			item->referencee = inhparent;
-			constraintList = lcons(item, constraintList);
-		}
-	}
-
-	heap_endscan(scan);
-	heap_close(inheritsrel, AccessShareLock);
-
-	return constraintList;
-}
-
-/*
- * TopoSortRels -- topological sort of a list of rels to delete
- *
- * This is a lot simpler and slower than, for example, the topological sort
- * algorithm shown in Knuth's Volume 1.  However, we are not likely to be
- * working with more than a few constraints, so the apparent slowness of the
- * algorithm won't really matter.
- */
-static List *
-TopoSortRels(List *relOids, List *constraintList)
-{
-	int			queue_size = length(relOids);
-	Oid		   *rels;
-	int		   *beforeConstraints;
-	DelConstraint **afterConstraints;
-	List	   *resultList = NIL;
-	List	   *lptr;
-	int			i,
-				j,
-				k,
-				last;
-
-	/* Allocate workspace */
-	rels = (Oid *) palloc(queue_size * sizeof(Oid));
-	beforeConstraints = (int *) palloc(queue_size * sizeof(int));
-	afterConstraints = (DelConstraint **)
-		palloc(queue_size * sizeof(DelConstraint*));
-
-	/* Build an array of the target relation OIDs */
-	i = 0;
-	foreach(lptr, relOids)
-	{
-		rels[i++] = (Oid) lfirsti(lptr);
-	}
-
-	/*
-	 * Scan the constraints, and for each rel in the array, generate a
-	 * count of the number of constraints that say it must be before
-	 * something else, plus a list of the constraints that say it must be
-	 * after something else. The count for the j'th rel is stored in
-	 * beforeConstraints[j], and the head of its list in
-	 * afterConstraints[j].  Each constraint stores its list link in
-	 * its link field (note any constraint will be in just one list).
-	 * The array index for the before-rel of each constraint is
-	 * remembered in the constraint's pred field.
-	 */
-	MemSet(beforeConstraints, 0, queue_size * sizeof(int));
-	MemSet(afterConstraints, 0, queue_size * sizeof(DelConstraint*));
-	foreach(lptr, constraintList)
-	{
-		DelConstraint  *constraint = (DelConstraint *) lfirst(lptr);
-		Oid			rel;
-
-		/* Find the referencer rel in the array */
-		rel = constraint->referencer;
-		for (j = queue_size; --j >= 0;)
-		{
-			if (rels[j] == rel)
-				break;
-		}
-		Assert(j >= 0);			/* should have found a match */
-		/* Find the referencee rel in the array */
-		rel = constraint->referencee;
-		for (k = queue_size; --k >= 0;)
-		{
-			if (rels[k] == rel)
-				break;
-		}
-		Assert(k >= 0);			/* should have found a match */
-		beforeConstraints[j]++; /* referencer must come before */
-		/* add this constraint to list of after-constraints for referencee */
-		constraint->pred = j;
-		constraint->link = afterConstraints[k];
-		afterConstraints[k] = constraint;
-	}
-	/*--------------------
-	 * Now scan the rels array backwards.	At each step, output the
-	 * last rel that has no remaining before-constraints, and decrease
-	 * the beforeConstraints count of each of the rels it was constrained
-	 * against.  (This is the right order since we are building the result
-	 * list back-to-front.)
-	 * i = counter for number of rels left to output
-	 * j = search index for rels[]
-	 * dc = temp for scanning constraint list for rel j
-	 * last = last valid index in rels (avoid redundant searches)
-	 *--------------------
-	 */
-	last = queue_size - 1;
-	for (i = queue_size; --i >= 0;)
-	{
-		DelConstraint  *dc;
-
-		/* Find next candidate to output */
-		while (rels[last] == InvalidOid)
-			last--;
-		for (j = last; j >= 0; j--)
-		{
-			if (rels[j] != InvalidOid && beforeConstraints[j] == 0)
-				break;
-		}
-		/* If no available candidate, topological sort fails */
-		if (j < 0)
-			elog(ERROR, "TopoSortRels: failed to find a workable deletion ordering");
-		/* Output candidate, and mark it done by zeroing rels[] entry */
-		resultList = lconsi(rels[j], resultList);
-		rels[j] = InvalidOid;
-		/* Update beforeConstraints counts of its predecessors */
-		for (dc = afterConstraints[j]; dc; dc = dc->link)
-			beforeConstraints[dc->pred]--;
-	}
-
-	/* Done */
-	return resultList;
 }
 
 /*
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
new file mode 100644
index 0000000000000000000000000000000000000000..47712dde1d66997d855a613f0e8ba57a665a8eea
--- /dev/null
+++ b/src/backend/catalog/pg_constraint.c
@@ -0,0 +1,453 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_constraint.c
+ *	  routines to support manipulation of the pg_constraint relation
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_constraint.c,v 1.1 2002/07/12 18:43:15 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "access/genam.h"
+#include "catalog/catalog.h"
+#include "catalog/catname.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_constraint.h"
+#include "miscadmin.h"
+#include "utils/array.h"
+#include "utils/builtins.h"
+#include "utils/fmgroids.h"
+#include "utils/syscache.h"
+
+
+/*
+ * CreateConstraintEntry
+ *	Create a constraint table entry.
+ *
+ * Subsidiary records (such as triggers or indexes to implement the
+ * constraint) are *not* created here.  But we do make dependency links
+ * from the constraint to the things it depends on.
+ */
+Oid
+CreateConstraintEntry(const char *constraintName,
+					  Oid constraintNamespace,
+					  char constraintType,
+					  bool isDeferrable,
+					  bool isDeferred,
+					  Oid relId,
+					  const int16 *constraintKey,
+					  int constraintNKeys,
+					  Oid domainId,
+					  Oid foreignRelId,
+					  const int16 *foreignKey,
+					  int foreignNKeys,
+					  char foreignUpdateType,
+					  char foreignDeleteType,
+					  char foreignMatchType,
+					  const char *conBin,
+					  const char *conSrc)
+{
+	Relation	conDesc;
+	Oid			conOid;
+	HeapTuple	tup;
+	char		nulls[Natts_pg_constraint];
+	Datum		values[Natts_pg_constraint];
+	ArrayType  *conkeyArray;
+	ArrayType  *confkeyArray;
+	NameData	cname;
+	int			i;
+	ObjectAddress conobject;
+
+	conDesc = heap_openr(ConstraintRelationName, RowExclusiveLock);
+
+	Assert(constraintName);
+	namestrcpy(&cname, constraintName);
+
+	/*
+	 * Convert C arrays into Postgres arrays.
+	 */
+	if (constraintNKeys > 0)
+	{
+		Datum	   *conkey;
+
+		conkey = (Datum *) palloc(constraintNKeys * sizeof(Datum));
+		for (i = 0; i < constraintNKeys; i++)
+			conkey[i] = Int16GetDatum(constraintKey[i]);
+		conkeyArray = construct_array(conkey, constraintNKeys,
+									  true, 2, 's');
+	}
+	else
+		conkeyArray = NULL;
+
+	if (foreignNKeys > 0)
+	{
+		Datum	   *confkey;
+
+		confkey = (Datum *) palloc(foreignNKeys * sizeof(Datum));
+		for (i = 0; i < foreignNKeys; i++)
+			confkey[i] = Int16GetDatum(foreignKey[i]);
+		confkeyArray = construct_array(confkey, foreignNKeys,
+									   true, 2, 's');
+	}
+	else
+		confkeyArray = NULL;
+
+	/* initialize nulls and values */
+	for (i = 0; i < Natts_pg_constraint; i++)
+	{
+		nulls[i] = ' ';
+		values[i] = (Datum) NULL;
+	}
+
+	values[Anum_pg_constraint_conname - 1] = NameGetDatum(&cname);
+	values[Anum_pg_constraint_connamespace - 1] = ObjectIdGetDatum(constraintNamespace);
+	values[Anum_pg_constraint_contype - 1] = CharGetDatum(constraintType);
+	values[Anum_pg_constraint_condeferrable - 1] = BoolGetDatum(isDeferrable);
+	values[Anum_pg_constraint_condeferred - 1] = BoolGetDatum(isDeferred);
+	values[Anum_pg_constraint_conrelid - 1] = ObjectIdGetDatum(relId);
+	values[Anum_pg_constraint_contypid - 1] = ObjectIdGetDatum(domainId);
+	values[Anum_pg_constraint_confrelid - 1] = ObjectIdGetDatum(foreignRelId);
+	values[Anum_pg_constraint_confupdtype - 1] = CharGetDatum(foreignUpdateType);
+	values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType);
+	values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
+
+	if (conkeyArray)
+		values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
+	else
+		nulls[Anum_pg_constraint_conkey - 1] = 'n';
+
+	if (confkeyArray)
+		values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray);
+	else
+		nulls[Anum_pg_constraint_confkey - 1] = 'n';
+
+	/*
+	 * initialize the binary form of the check constraint.
+	 */
+	if (conBin)
+		values[Anum_pg_constraint_conbin - 1] = DirectFunctionCall1(textin,
+										CStringGetDatum(conBin));
+	else
+		nulls[Anum_pg_constraint_conbin - 1] = 'n';
+
+	/*
+	 * initialize the text form of the check constraint
+	 */
+	if (conSrc)
+		values[Anum_pg_constraint_consrc - 1] = DirectFunctionCall1(textin,
+										CStringGetDatum(conSrc));	
+	else
+		nulls[Anum_pg_constraint_consrc - 1] = 'n';
+
+	tup = heap_formtuple(RelationGetDescr(conDesc), values, nulls);
+
+	conOid = simple_heap_insert(conDesc, tup);
+
+	/* Handle Indices */
+	if (RelationGetForm(conDesc)->relhasindex)
+	{
+		Relation	idescs[Num_pg_constraint_indices];
+
+		CatalogOpenIndices(Num_pg_constraint_indices, Name_pg_constraint_indices, idescs);
+		CatalogIndexInsert(idescs, Num_pg_constraint_indices, conDesc, tup);
+		CatalogCloseIndices(Num_pg_constraint_indices, idescs);
+	}
+
+	conobject.classId = RelationGetRelid(conDesc);
+	conobject.objectId = conOid;
+	conobject.objectSubId = 0;
+
+	heap_close(conDesc, RowExclusiveLock);
+
+	if (OidIsValid(relId))
+	{
+		/*
+		 * Register auto dependency from constraint to owning relation,
+		 * or to specific column(s) if any are mentioned.
+		 */
+		ObjectAddress	relobject;
+
+		relobject.classId = RelOid_pg_class;
+		relobject.objectId = relId;
+		if (constraintNKeys > 0)
+		{
+			for (i = 0; i < constraintNKeys; i++)
+			{
+				relobject.objectSubId = constraintKey[i];
+
+				recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
+			}
+		}
+		else
+		{
+			relobject.objectSubId = 0;
+
+			recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
+		}
+	}
+
+	if (OidIsValid(foreignRelId))
+	{
+		/*
+		 * Register dependency from constraint to foreign relation,
+		 * or to specific column(s) if any are mentioned.
+		 *
+		 * In normal case of two separate relations, make this a NORMAL
+		 * dependency (so dropping the FK table would require CASCADE).
+		 * However, for a self-reference just make it AUTO.
+		 */
+		DependencyType	deptype;
+		ObjectAddress	relobject;
+
+		deptype = (foreignRelId == relId) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL;
+		relobject.classId = RelOid_pg_class;
+		relobject.objectId = foreignRelId;
+		if (foreignNKeys > 0)
+		{
+			for (i = 0; i < foreignNKeys; i++)
+			{
+				relobject.objectSubId = foreignKey[i];
+
+				recordDependencyOn(&conobject, &relobject, deptype);
+			}
+		}
+		else
+		{
+			relobject.objectSubId = 0;
+
+			recordDependencyOn(&conobject, &relobject, deptype);
+		}
+	}
+
+	return conOid;
+}
+
+
+/*
+ * Test whether given name is currently used as a constraint name
+ * for the given relation.
+ *
+ * NB: Caller should hold exclusive lock on the given relation, else
+ * this test is not very meaningful.
+ */
+bool
+ConstraintNameIsUsed(Oid relId, Oid relNamespace, const char *cname)
+{
+	bool		found;
+	Relation	conDesc;
+	SysScanDesc conscan;
+	ScanKeyData skey[2];
+	HeapTuple	tup;
+
+	conDesc = heap_openr(ConstraintRelationName, RowExclusiveLock);
+
+	found = false;
+
+	ScanKeyEntryInitialize(&skey[0], 0x0,
+						   Anum_pg_constraint_conname, F_NAMEEQ,
+						   CStringGetDatum(cname));
+
+	ScanKeyEntryInitialize(&skey[1], 0x0,
+						   Anum_pg_constraint_connamespace, F_OIDEQ,
+						   ObjectIdGetDatum(relNamespace));
+
+	conscan = systable_beginscan(conDesc, ConstraintNameNspIndex, true,
+								 SnapshotNow, 2, skey);
+
+	while (HeapTupleIsValid(tup = systable_getnext(conscan)))
+	{
+		Form_pg_constraint	con = (Form_pg_constraint) GETSTRUCT(tup);
+
+		if (con->conrelid == relId)
+		{
+			found = true;
+			break;
+		}
+	}
+
+	systable_endscan(conscan);
+	heap_close(conDesc, RowExclusiveLock);
+
+	return found;
+}
+
+/*
+ * Generate a currently-unused constraint name for the given relation.
+ *
+ * The passed counter should be initialized to 0 the first time through.
+ * If multiple constraint names are to be generated in a single command,
+ * pass the new counter value to each successive call, else the same
+ * name will be generated each time.
+ *
+ * NB: Caller should hold exclusive lock on the given relation, else
+ * someone else might choose the same name concurrently!
+ */
+char *
+GenerateConstraintName(Oid relId, Oid relNamespace, int *counter)
+{
+	bool		found;
+	Relation	conDesc;
+	char	   *cname;
+
+	cname = (char *) palloc(NAMEDATALEN * sizeof(char));
+
+	conDesc = heap_openr(ConstraintRelationName, RowExclusiveLock);
+
+	/* Loop until we find a non-conflicting constraint name */
+	/* We assume there will be one eventually ... */
+	do
+	{
+		SysScanDesc conscan;
+		ScanKeyData skey[2];
+		HeapTuple	tup;
+
+		++(*counter);
+		snprintf(cname, NAMEDATALEN, "$%d", *counter);
+
+		/*
+		 * This duplicates ConstraintNameIsUsed() so that we can avoid
+		 * re-opening pg_constraint for each iteration.
+		 */
+		found = false;
+
+		ScanKeyEntryInitialize(&skey[0], 0x0,
+							   Anum_pg_constraint_conname, F_NAMEEQ,
+							   CStringGetDatum(cname));
+
+		ScanKeyEntryInitialize(&skey[1], 0x0,
+							   Anum_pg_constraint_connamespace, F_OIDEQ,
+							   ObjectIdGetDatum(relNamespace));
+
+		conscan = systable_beginscan(conDesc, ConstraintNameNspIndex, true,
+									 SnapshotNow, 2, skey);
+
+		while (HeapTupleIsValid(tup = systable_getnext(conscan)))
+		{
+			Form_pg_constraint	con = (Form_pg_constraint) GETSTRUCT(tup);
+
+			if (con->conrelid == relId)
+			{
+				found = true;
+				break;
+			}
+		}
+
+		systable_endscan(conscan);
+	} while (found);
+
+	heap_close(conDesc, RowExclusiveLock);
+
+	return cname;
+}
+
+/*
+ * Does the given name look like a generated constraint name?
+ *
+ * This is a test on the form of the name, *not* on whether it has
+ * actually been assigned.
+ */
+bool
+ConstraintNameIsGenerated(const char *cname)
+{
+	if (cname[0] != '$')
+		return false;
+	if (strspn(cname+1, "0123456789") != strlen(cname+1))
+		return false;
+	return true;
+}
+
+/*
+ * Delete a single constraint record.
+ */
+void
+RemoveConstraintById(Oid conId)
+{
+	Relation		conDesc;
+	ScanKeyData		skey[1];
+	SysScanDesc 	conscan;
+	HeapTuple		tup;
+	Form_pg_constraint	con;
+
+	conDesc = heap_openr(ConstraintRelationName, RowExclusiveLock);
+
+	ScanKeyEntryInitialize(&skey[0], 0x0,
+						   ObjectIdAttributeNumber, F_OIDEQ,
+						   ObjectIdGetDatum(conId));
+
+	conscan = systable_beginscan(conDesc, ConstraintOidIndex, true,
+								 SnapshotNow, 1, skey);
+
+	tup = systable_getnext(conscan);
+	if (!HeapTupleIsValid(tup))
+		elog(ERROR, "RemoveConstraintById: constraint %u not found",
+			 conId);
+	con = (Form_pg_constraint) GETSTRUCT(tup);
+
+	/*
+	 * If the constraint is for a relation, open and exclusive-lock
+	 * the relation it's for.
+	 *
+	 * XXX not clear what we should lock, if anything, for other constraints.
+	 */
+	if (OidIsValid(con->conrelid))
+	{
+		Relation	rel;
+
+		rel = heap_open(con->conrelid, AccessExclusiveLock);
+
+		/*
+		 * We need to update the relcheck count if it is a check constraint
+		 * being dropped.  This update will force backends to rebuild
+		 * relcache entries when we commit.
+		 */
+		if (con->contype == CONSTRAINT_CHECK)
+		{
+			Relation		pgrel;
+			HeapTuple		relTup;
+			Form_pg_class	classForm;
+			Relation		ridescs[Num_pg_class_indices];
+		
+			pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
+			relTup = SearchSysCacheCopy(RELOID,
+										ObjectIdGetDatum(con->conrelid),
+										0, 0, 0);
+			if (!HeapTupleIsValid(relTup))
+				elog(ERROR, "cache lookup of relation %u failed",
+					 con->conrelid);
+			classForm = (Form_pg_class) GETSTRUCT(relTup);
+
+			if (classForm->relchecks == 0)
+				elog(ERROR, "RemoveConstraintById: relation %s has relchecks = 0",
+					 RelationGetRelationName(rel));
+			classForm->relchecks--;
+
+			simple_heap_update(pgrel, &relTup->t_self, relTup);
+
+			CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
+			CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, relTup);
+			CatalogCloseIndices(Num_pg_class_indices, ridescs);
+
+			heap_freetuple(relTup);
+
+			heap_close(pgrel, RowExclusiveLock);
+		}
+
+		/* Keep lock on constraint's rel until end of xact */
+		heap_close(rel, NoLock);
+	}
+
+	/* Fry the constraint itself */
+	simple_heap_delete(conDesc, &tup->t_self);
+
+	/* Clean up */
+	systable_endscan(conscan);
+	heap_close(conDesc, RowExclusiveLock);
+}
diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c
new file mode 100644
index 0000000000000000000000000000000000000000..4057374069ae17482a7bc001b8633c4a8ab942a3
--- /dev/null
+++ b/src/backend/catalog/pg_depend.c
@@ -0,0 +1,147 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_depend.c
+ *	  routines to support manipulation of the pg_depend relation
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_depend.c,v 1.1 2002/07/12 18:43:15 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "catalog/catname.h"
+#include "catalog/indexing.h"
+#include "catalog/dependency.h"
+#include "catalog/pg_depend.h"
+#include "miscadmin.h"
+#include "utils/fmgroids.h"
+
+
+static bool isObjectPinned(const ObjectAddress *object, Relation rel);
+
+
+/*
+ * Record a dependency between 2 objects via their respective objectAddress.
+ * The first argument is the dependent object, the second the one it
+ * references.
+ *
+ * This simply creates an entry in pg_depend, without any other processing.
+ */
+void
+recordDependencyOn(const ObjectAddress *depender,
+				   const ObjectAddress *referenced,
+				   DependencyType behavior)
+{
+	Relation	dependDesc;
+	HeapTuple	tup;
+	int			i;
+	char		nulls[Natts_pg_depend];
+	Datum		values[Natts_pg_depend];
+	Relation	idescs[Num_pg_depend_indices];
+
+	/*
+	 * During bootstrap, do nothing since pg_depend may not exist yet.
+	 * initdb will fill in appropriate pg_depend entries after bootstrap.
+	 */
+	if (IsBootstrapProcessingMode())
+		return;
+
+	dependDesc = heap_openr(DependRelationName, RowExclusiveLock);
+
+	/*
+	 * If the referenced object is pinned by the system, there's no real
+	 * need to record dependencies on it.  This saves lots of space in
+	 * pg_depend, so it's worth the time taken to check.
+	 */
+	if (!isObjectPinned(referenced, dependDesc))
+	{
+		/*
+		 * Record the Dependency.  Note we don't bother to check for
+		 * duplicate dependencies; there's no harm in them.
+		 */
+		for (i = 0; i < Natts_pg_depend; ++i)
+		{
+			nulls[i] = ' ';
+			values[i] = (Datum) 0;
+		}
+
+		values[Anum_pg_depend_classid - 1]	= ObjectIdGetDatum(depender->classId);
+		values[Anum_pg_depend_objid - 1]	= ObjectIdGetDatum(depender->objectId);
+		values[Anum_pg_depend_objsubid - 1]	= Int32GetDatum(depender->objectSubId);
+
+		values[Anum_pg_depend_refclassid - 1]	= ObjectIdGetDatum(referenced->classId);
+		values[Anum_pg_depend_refobjid - 1]		= ObjectIdGetDatum(referenced->objectId);
+		values[Anum_pg_depend_refobjsubid - 1]	= Int32GetDatum(referenced->objectSubId);
+
+		values[Anum_pg_depend_deptype -1] = CharGetDatum((char) behavior);
+
+		tup = heap_formtuple(dependDesc->rd_att, values, nulls);
+
+		simple_heap_insert(dependDesc, tup);
+
+		/*
+		 * Keep indices current
+		 */
+		CatalogOpenIndices(Num_pg_depend_indices, Name_pg_depend_indices, idescs);
+		CatalogIndexInsert(idescs, Num_pg_depend_indices, dependDesc, tup);
+		CatalogCloseIndices(Num_pg_depend_indices, idescs);
+	}
+
+	heap_close(dependDesc, RowExclusiveLock);
+}
+
+
+/*
+ * isObjectPinned()
+ *
+ * Test if an object is required for basic database functionality.
+ * Caller must already have opened pg_depend.
+ *
+ * The passed subId, if any, is ignored; we assume that only whole objects
+ * are pinned (and that this implies pinning their components).
+ */
+static bool
+isObjectPinned(const ObjectAddress *object, Relation rel)
+{
+	bool		ret = false;
+	SysScanDesc	scan;
+	HeapTuple	tup;
+	ScanKeyData key[2];
+
+	ScanKeyEntryInitialize(&key[0], 0x0,
+						   Anum_pg_depend_refclassid, F_OIDEQ,
+						   ObjectIdGetDatum(object->classId));
+
+	ScanKeyEntryInitialize(&key[1], 0x0,
+						   Anum_pg_depend_refobjid, F_OIDEQ,
+						   ObjectIdGetDatum(object->objectId));
+
+	scan = systable_beginscan(rel, DependReferenceIndex, true,
+							  SnapshotNow, 2, key);
+
+	/*
+	 * Since we won't generate additional pg_depend entries for pinned
+	 * objects, there can be at most one entry referencing a pinned
+	 * object.  Hence, it's sufficient to look at the first returned
+	 * tuple; we don't need to loop.
+	 */
+	tup = systable_getnext(scan);
+	if (HeapTupleIsValid(tup))
+	{
+		Form_pg_depend	foundDep = (Form_pg_depend) GETSTRUCT(tup);
+
+		if (foundDep->deptype == DEPENDENCY_PIN)
+			ret = true;
+	}
+
+	systable_endscan(scan);
+
+	return ret;
+}
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 5b8b9a88c223bd310d94a9d1654853ef4d346852..88f113beb01c6c645e8f7c4b2b9880d80e2bca53 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.72 2002/06/20 20:29:26 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.73 2002/07/12 18:43:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,6 +16,7 @@
 
 #include "access/heapam.h"
 #include "catalog/catname.h"
+#include "catalog/dependency.h"
 #include "catalog/indexing.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
@@ -166,6 +167,8 @@ TypeCreate(const char *typeName,
 	NameData	name;
 	TupleDesc	tupDesc;
 	int			i;
+	ObjectAddress	myself,
+					referenced;
 
 	/*
 	 * validate size specifications: either positive (fixed-length) or -1
@@ -298,6 +301,77 @@ TypeCreate(const char *typeName,
 		CatalogCloseIndices(Num_pg_type_indices, idescs);
 	}
 
+	/*
+	 * Create dependencies
+	 */
+	myself.classId = RelOid_pg_type;
+	myself.objectId = typeObjectId;
+	myself.objectSubId = 0;
+
+	/* Normal dependencies on the I/O functions */
+	referenced.classId = RelOid_pg_proc;
+	referenced.objectId = inputProcedure;
+	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 (receiveProcedure != inputProcedure)
+	{
+		referenced.classId = RelOid_pg_proc;
+		referenced.objectId = receiveProcedure;
+		referenced.objectSubId = 0;
+		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	}
+
+	if (sendProcedure != outputProcedure)
+	{
+		referenced.classId = RelOid_pg_proc;
+		referenced.objectId = sendProcedure;
+		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.  This allows it to be auto-dropped
+	 * when the relation is, and not otherwise.
+	 */
+	if (OidIsValid(relationOid))
+	{
+		referenced.classId = RelOid_pg_class;
+		referenced.objectId = relationOid;
+		referenced.objectSubId = 0;
+		recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
+	}
+
+	/*
+	 * 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);
+	}
+
 	/*
 	 * finish up
 	 */
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index c3c1ed16dfc4ea2680bbd0a6bfe126c76cb36089..1b83f03f48136b7b31995147322f77e409f8a701 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v 1.2 2002/04/27 03:45:00 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v 1.3 2002/07/12 18:43:15 tgl Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -24,10 +24,10 @@
 
 #include "access/heapam.h"
 #include "catalog/catname.h"
+#include "catalog/dependency.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_aggregate.h"
 #include "catalog/pg_proc.h"
-#include "commands/comment.h"
 #include "commands/defrem.h"
 #include "miscadmin.h"
 #include "parser/parse_func.h"
@@ -141,13 +141,19 @@ DefineAggregate(List *names, List *parameters)
 }
 
 
+/*
+ * RemoveAggregate
+ *		Deletes an aggregate.
+ */
 void
-RemoveAggregate(List *aggName, TypeName *aggType)
+RemoveAggregate(RemoveAggrStmt *stmt)
 {
-	Relation	relation;
-	HeapTuple	tup;
+	List	   *aggName = stmt->aggname;
+	TypeName   *aggType = stmt->aggtype;
 	Oid			basetypeID;
 	Oid			procOid;
+	HeapTuple	tup;
+	ObjectAddress object;
 
 	/*
 	 * if a basetype is passed in, then attempt to find an aggregate for
@@ -164,8 +170,9 @@ RemoveAggregate(List *aggName, TypeName *aggType)
 
 	procOid = find_aggregate_func("RemoveAggregate", aggName, basetypeID);
 
-	relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
-
+	/*
+	 * Find the function tuple, do permissions and validity checks
+	 */
 	tup = SearchSysCache(PROCOID,
 						 ObjectIdGetDatum(procOid),
 						 0, 0, 0);
@@ -179,30 +186,16 @@ RemoveAggregate(List *aggName, TypeName *aggType)
 								 GetUserId()))
 		aclcheck_error(ACLCHECK_NOT_OWNER, NameListToString(aggName));
 
-	/* Delete any comments associated with this function */
-	DeleteComments(procOid, RelationGetRelid(relation));
-
-	/* Remove the pg_proc tuple */
-	simple_heap_delete(relation, &tup->t_self);
+	/* find_aggregate_func already checked it is an aggregate */
 
 	ReleaseSysCache(tup);
 
-	heap_close(relation, RowExclusiveLock);
-
-	/* Remove the pg_aggregate tuple */
-
-	relation = heap_openr(AggregateRelationName, RowExclusiveLock);
-
-	tup = SearchSysCache(AGGFNOID,
-						 ObjectIdGetDatum(procOid),
-						 0, 0, 0);
-	if (!HeapTupleIsValid(tup))	/* should not happen */
-		elog(ERROR, "RemoveAggregate: couldn't find pg_aggregate tuple for %s",
-			 NameListToString(aggName));
-
-	simple_heap_delete(relation, &tup->t_self);
-
-	ReleaseSysCache(tup);
+	/*
+	 * Do the deletion
+	 */
+	object.classId = RelOid_pg_proc;
+	object.objectId = procOid;
+	object.objectSubId = 0;
 
-	heap_close(relation, RowExclusiveLock);
+	performDeletion(&object, stmt->behavior);
 }
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 3306943fb04875971f65c266547fe0204bf974c7..837390744fbee37b1e972401b499b87bdb6cca2f 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.82 2002/06/20 20:29:26 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.83 2002/07/12 18:43:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -24,6 +24,7 @@
 
 #include "access/genam.h"
 #include "access/heapam.h"
+#include "catalog/dependency.h"
 #include "catalog/heap.h"
 #include "catalog/index.h"
 #include "catalog/pg_index.h"
@@ -64,6 +65,7 @@ cluster(RangeVar *oldrelation, char *oldindexname)
 				OldIndex;
 	char		NewHeapName[NAMEDATALEN];
 	char		NewIndexName[NAMEDATALEN];
+	ObjectAddress object;
 
 	/*
 	 * We grab exclusive access to the target rel and index for the
@@ -119,9 +121,14 @@ cluster(RangeVar *oldrelation, char *oldindexname)
 	CommandCounterIncrement();
 
 	/* Destroy old heap (along with its index) and rename new. */
-	heap_drop_with_catalog(OIDOldHeap, allowSystemTableMods);
+	object.classId = RelOid_pg_class;
+	object.objectId = OIDOldHeap;
+	object.objectSubId = 0;
 
-	CommandCounterIncrement();
+	/* XXX better to use DROP_CASCADE here? */
+	performDeletion(&object, DROP_RESTRICT);
+
+	/* performDeletion does CommandCounterIncrement at end */
 
 	renamerel(OIDNewHeap, oldrelation->relname);
 
@@ -198,6 +205,7 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap, const char *NewIndexName)
 							   OldIndex->rd_rel->relam,
 							   OldIndex->rd_index->indclass,
 							   OldIndex->rd_index->indisprimary,
+							   false, /* XXX losing constraint status */
 							   allowSystemTableMods);
 
 	setRelhasindex(OIDNewHeap, true,
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index 160a52246a165ba40dddad798e6c0b3003550979..b1ce1b2ce65b84323f31e0747b20bc946dc36d32 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -7,7 +7,7 @@
  * Copyright (c) 1996-2001, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.49 2002/06/20 20:51:45 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.50 2002/07/12 18:43:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -225,38 +225,45 @@ CreateComments(Oid oid, Oid classoid, int32 subid, char *comment)
 }
 
 /*
- * DeleteComments --
+ * DeleteComments -- remove comments for an object
  *
- * This routine is used to purge all comments associated with an object,
- * regardless of their objsubid.  It is called, for example, when a relation
- * is destroyed.
+ * If subid is nonzero then only comments matching it will be removed.
+ * If subid is zero, all comments matching the oid/classoid will be removed
+ * (this corresponds to deleting a whole object).
  */
 void
-DeleteComments(Oid oid, Oid classoid)
+DeleteComments(Oid oid, Oid classoid, int32 subid)
 {
 	Relation	description;
-	ScanKeyData skey[2];
+	ScanKeyData skey[3];
+	int			nkeys;
 	SysScanDesc	sd;
 	HeapTuple	oldtuple;
 
 	/* Use the index to search for all matching old tuples */
 
-	ScanKeyEntryInitialize(&skey[0],
-						   (bits16) 0x0,
-						   (AttrNumber) 1,
-						   (RegProcedure) F_OIDEQ,
+	ScanKeyEntryInitialize(&skey[0], 0x0,
+						   Anum_pg_description_objoid, F_OIDEQ,
 						   ObjectIdGetDatum(oid));
 
-	ScanKeyEntryInitialize(&skey[1],
-						   (bits16) 0x0,
-						   (AttrNumber) 2,
-						   (RegProcedure) F_OIDEQ,
+	ScanKeyEntryInitialize(&skey[1], 0x0,
+						   Anum_pg_description_classoid, F_OIDEQ,
 						   ObjectIdGetDatum(classoid));
 
+	if (subid != 0)
+	{
+		ScanKeyEntryInitialize(&skey[2], 0x0,
+							   Anum_pg_description_objsubid, F_INT4EQ,
+							   Int32GetDatum(subid));
+		nkeys = 3;
+	}
+	else
+		nkeys = 2;
+
 	description = heap_openr(DescriptionRelationName, RowExclusiveLock);
 
 	sd = systable_beginscan(description, DescriptionObjIndex, true,
-							SnapshotNow, 2, skey);
+							SnapshotNow, nkeys, skey);
 
 	while ((oldtuple = systable_getnext(sd)) != NULL)
 	{
@@ -266,7 +273,7 @@ DeleteComments(Oid oid, Oid classoid)
 	/* Done */
 
 	systable_endscan(sd);
-	heap_close(description, NoLock);
+	heap_close(description, RowExclusiveLock);
 }
 
 /*
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 3526b91b997d28a749336751b746fad9f56288e5..c6bbb37186098cb49da25b13e1f9d32881e1edf6 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.95 2002/06/20 20:29:27 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.96 2002/07/12 18:43:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -456,8 +456,13 @@ dropdb(const char *dbname)
 
 	heap_endscan(pgdbscan);
 
-	/* Delete any comments associated with the database */
-	DeleteComments(db_id, RelationGetRelid(pgdbrel));
+	/*
+	 * Delete any comments associated with the database
+	 *
+	 * NOTE: this is probably dead code since any such comments should have
+	 * been in that database, not mine.
+	 */
+	DeleteComments(db_id, RelationGetRelid(pgdbrel), 0);
 
 	/*
 	 * Close pg_database, but keep exclusive lock till commit to ensure
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 638fd19a8ebba8f4c9ded5867e61a99a3c98c810..9a33810b07351dac3d2c2281b3d41efb78bf2955 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.7 2002/06/20 20:29:27 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.8 2002/07/12 18:43:16 tgl Exp $
  *
  * DESCRIPTION
  *	  These routines take the parse tree and pick out the
@@ -33,11 +33,11 @@
 
 #include "access/heapam.h"
 #include "catalog/catname.h"
+#include "catalog/dependency.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
-#include "commands/comment.h"
 #include "commands/defrem.h"
 #include "miscadmin.h"
 #include "optimizer/cost.h"
@@ -532,25 +532,22 @@ CreateFunction(CreateFunctionStmt *stmt)
 /*
  * RemoveFunction
  *		Deletes a function.
- *
- * Exceptions:
- *		BadArg if name is invalid.
- *		"ERROR" if function nonexistent.
- *		...
  */
 void
-RemoveFunction(List *functionName,		/* function name to be removed */
-			   List *argTypes)	/* list of TypeName nodes */
+RemoveFunction(RemoveFuncStmt *stmt)
 {
+	List	   *functionName = stmt->funcname;
+	List	   *argTypes = stmt->args; /* list of TypeName nodes */
 	Oid			funcOid;
-	Relation	relation;
 	HeapTuple	tup;
+	ObjectAddress object;
 
+	/*
+	 * Find the function, do permissions and validity checks
+	 */
 	funcOid = LookupFuncNameTypeNames(functionName, argTypes, 
 									  true, "RemoveFunction");
 
-	relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
-
 	tup = SearchSysCache(PROCOID,
 						 ObjectIdGetDatum(funcOid),
 						 0, 0, 0);
@@ -576,12 +573,69 @@ RemoveFunction(List *functionName,		/* function name to be removed */
 			 NameListToString(functionName));
 	}
 
-	/* Delete any comments associated with this function */
-	DeleteComments(funcOid, RelationGetRelid(relation));
+	ReleaseSysCache(tup);
+
+	/*
+	 * Do the deletion
+	 */
+	object.classId = RelOid_pg_proc;
+	object.objectId = funcOid;
+	object.objectSubId = 0;
+
+	performDeletion(&object, stmt->behavior);
+}
+
+/*
+ * Guts of function deletion.
+ *
+ * Note: this is also used for aggregate deletion, since the OIDs of
+ * both functions and aggregates point to pg_proc.
+ */
+void
+RemoveFunctionById(Oid funcOid)
+{
+	Relation	relation;
+	HeapTuple	tup;
+	bool		isagg;
+
+	/*
+	 * Delete the pg_proc tuple.
+	 */
+	relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
+
+	tup = SearchSysCache(PROCOID,
+						 ObjectIdGetDatum(funcOid),
+						 0, 0, 0);
+	if (!HeapTupleIsValid(tup))	/* should not happen */
+		elog(ERROR, "RemoveFunctionById: couldn't find tuple for function %u",
+			 funcOid);
+
+	isagg = ((Form_pg_proc) GETSTRUCT(tup))->proisagg;
 
 	simple_heap_delete(relation, &tup->t_self);
 
 	ReleaseSysCache(tup);
 
 	heap_close(relation, RowExclusiveLock);
+
+	/*
+	 * If there's a pg_aggregate tuple, delete that too.
+	 */
+	if (isagg)
+	{
+		relation = heap_openr(AggregateRelationName, RowExclusiveLock);
+
+		tup = SearchSysCache(AGGFNOID,
+							 ObjectIdGetDatum(funcOid),
+							 0, 0, 0);
+		if (!HeapTupleIsValid(tup))	/* should not happen */
+			elog(ERROR, "RemoveFunctionById: couldn't find pg_aggregate tuple for %u",
+				 funcOid);
+
+		simple_heap_delete(relation, &tup->t_self);
+
+		ReleaseSysCache(tup);
+
+		heap_close(relation, RowExclusiveLock);
+	}
 }
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 1338f16bb59b5236a21e964915e51c17703b0b19..5cf03bd11aa4262c2665fcd54e671f6e79f978ea 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.76 2002/07/01 15:27:45 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.77 2002/07/12 18:43:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,7 @@
 #include "access/heapam.h"
 #include "catalog/catalog.h"
 #include "catalog/catname.h"
+#include "catalog/dependency.h"
 #include "catalog/index.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_opclass.h"
@@ -68,6 +69,7 @@ DefineIndex(RangeVar *heapRelation,
 			List *attributeList,
 			bool unique,
 			bool primary,
+			bool isconstraint,
 			Expr *predicate,
 			List *rangetable)
 {
@@ -208,7 +210,7 @@ DefineIndex(RangeVar *heapRelation,
 
 	index_create(relationId, indexRelationName,
 				 indexInfo, accessMethodId, classObjectId,
-				 primary, allowSystemTableMods);
+				 primary, isconstraint, allowSystemTableMods);
 
 	/*
 	 * We update the relation's pg_class tuple even if it already has
@@ -566,6 +568,7 @@ RemoveIndex(RangeVar *relation, DropBehavior behavior)
 {
 	Oid			indOid;
 	HeapTuple	tuple;
+	ObjectAddress object;
 
 	indOid = RangeVarGetRelid(relation, false);
 	tuple = SearchSysCache(RELOID,
@@ -580,7 +583,11 @@ RemoveIndex(RangeVar *relation, DropBehavior behavior)
 
 	ReleaseSysCache(tuple);
 
-	index_drop(indOid);
+	object.classId = RelOid_pg_class;
+	object.objectId = indOid;
+	object.objectSubId = 0;
+
+	performDeletion(&object, behavior);
 }
 
 /*
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index fcf96c5e9c17d58c3ce29ebde573cdeb5443eb4e..1c4e5f3bee324a9d75c4f9808e9aadc92af5eb2c 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/operatorcmds.c,v 1.4 2002/07/01 15:27:46 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/operatorcmds.c,v 1.5 2002/07/12 18:43:16 tgl Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -36,9 +36,9 @@
 
 #include "access/heapam.h"
 #include "catalog/catname.h"
+#include "catalog/dependency.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_operator.h"
-#include "commands/comment.h"
 #include "commands/defrem.h"
 #include "miscadmin.h"
 #include "parser/parse_oper.h"
@@ -217,17 +217,15 @@ RemoveOperator(RemoveOperStmt *stmt)
 	TypeName *typeName1 = (TypeName *) lfirst(stmt->args);
 	TypeName *typeName2 = (TypeName *) lsecond(stmt->args);
 	Oid			operOid;
-	Relation	relation;
 	HeapTuple	tup;
+	ObjectAddress object;
 
 	operOid = LookupOperNameTypeNames(operatorName, typeName1, typeName2,
 									  "RemoveOperator");
 
-	relation = heap_openr(OperatorRelationName, RowExclusiveLock);
-
-	tup = SearchSysCacheCopy(OPEROID,
-							 ObjectIdGetDatum(operOid),
-							 0, 0, 0);
+	tup = SearchSysCache(OPEROID,
+						 ObjectIdGetDatum(operOid),
+						 0, 0, 0);
 	if (!HeapTupleIsValid(tup))	/* should not happen */
 		elog(ERROR, "RemoveOperator: failed to find tuple for operator '%s'",
 			 NameListToString(operatorName));
@@ -238,11 +236,39 @@ RemoveOperator(RemoveOperStmt *stmt)
 								 GetUserId()))
 		aclcheck_error(ACLCHECK_NOT_OWNER, NameListToString(operatorName));
 
-	/* Delete any comments associated with this operator */
-	DeleteComments(operOid, RelationGetRelid(relation));
+	ReleaseSysCache(tup);
+
+	/*
+	 * Do the deletion
+	 */
+	object.classId = get_system_catalog_relid(OperatorRelationName);
+	object.objectId = operOid;
+	object.objectSubId = 0;
+
+	performDeletion(&object, stmt->behavior);
+}
+
+/*
+ * Guts of operator deletion.
+ */
+void
+RemoveOperatorById(Oid operOid)
+{
+	Relation	relation;
+	HeapTuple	tup;
+
+	relation = heap_openr(OperatorRelationName, RowExclusiveLock);
+
+	tup = SearchSysCache(OPEROID,
+						 ObjectIdGetDatum(operOid),
+						 0, 0, 0);
+	if (!HeapTupleIsValid(tup))	/* should not happen */
+		elog(ERROR, "RemoveOperatorById: failed to find tuple for operator %u",
+			 operOid);
 
 	simple_heap_delete(relation, &tup->t_self);
 
-	heap_freetuple(tup);
+	ReleaseSysCache(tup);
+
 	heap_close(relation, RowExclusiveLock);
 }
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index 158927067f110eddb20f33a921350675444fe007..56dc320e2ef4416db7fce6b742ee2365c8b9de38 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.34 2002/06/20 20:29:27 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.35 2002/07/12 18:43:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,6 +17,7 @@
 
 #include "access/heapam.h"
 #include "catalog/catname.h"
+#include "catalog/dependency.h"
 #include "catalog/indexing.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_language.h"
@@ -140,7 +141,7 @@ DropProceduralLanguage(DropPLangStmt *stmt)
 {
 	char		languageName[NAMEDATALEN];
 	HeapTuple	langTup;
-	Relation	rel;
+	ObjectAddress object;
 
 	/*
 	 * Check permission
@@ -155,11 +156,9 @@ DropProceduralLanguage(DropPLangStmt *stmt)
 	 */
 	case_translate_language_name(stmt->plname, languageName);
 
-	rel = heap_openr(LanguageRelationName, RowExclusiveLock);
-
-	langTup = SearchSysCacheCopy(LANGNAME,
-								 PointerGetDatum(languageName),
-								 0, 0, 0);
+	langTup = SearchSysCache(LANGNAME,
+							 CStringGetDatum(languageName),
+							 0, 0, 0);
 	if (!HeapTupleIsValid(langTup))
 		elog(ERROR, "Language %s doesn't exist", languageName);
 
@@ -167,8 +166,39 @@ DropProceduralLanguage(DropPLangStmt *stmt)
 		elog(ERROR, "Language %s isn't a created procedural language",
 			 languageName);
 
+	object.classId = get_system_catalog_relid(LanguageRelationName);
+	object.objectId = langTup->t_data->t_oid;
+	object.objectSubId = 0;
+
+	ReleaseSysCache(langTup);
+
+	/*
+	 * Do the deletion
+	 */
+	performDeletion(&object, stmt->behavior);
+}
+
+/*
+ * Guts of language dropping.
+ */
+void
+DropProceduralLanguageById(Oid langOid)
+{
+	Relation	rel;
+	HeapTuple	langTup;
+
+	rel = heap_openr(LanguageRelationName, RowExclusiveLock);
+
+	langTup = SearchSysCache(LANGOID,
+							 ObjectIdGetDatum(langOid),
+							 0, 0, 0);
+	if (!HeapTupleIsValid(langTup))
+		elog(ERROR, "DropProceduralLanguageById: language %u not found",
+			 langOid);
+
 	simple_heap_delete(rel, &langTup->t_self);
 
-	heap_freetuple(langTup);
+	ReleaseSysCache(langTup);
+
 	heap_close(rel, RowExclusiveLock);
 }
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 901090c70aca49f97db348352835b57039a2346d..0d4d277bae4e6faa10102e912018314b6853d4e1 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.19 2002/07/06 20:16:35 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.20 2002/07/12 18:43:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,11 +18,13 @@
 #include "access/tuptoaster.h"
 #include "catalog/catalog.h"
 #include "catalog/catname.h"
+#include "catalog/dependency.h"
 #include "catalog/heap.h"
 #include "catalog/index.h"
 #include "catalog/indexing.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_attrdef.h"
+#include "catalog/pg_constraint.h"
 #include "catalog/pg_inherits.h"
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_opclass.h"
@@ -36,6 +38,7 @@
 #include "optimizer/clauses.h"
 #include "optimizer/planmain.h"
 #include "optimizer/prep.h"
+#include "parser/gramparse.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
@@ -57,6 +60,13 @@ static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass);
 static void drop_default(Oid relid, int16 attnum);
 static void CheckTupleType(Form_pg_class tuple_class);
 static bool needs_toast_table(Relation rel);
+static void validateForeignKeyConstraint(FkConstraint *fkconstraint,
+										 Relation rel, Relation pkrel);
+static Oid	createForeignKeyConstraint(Relation rel, Relation pkrel,
+									   FkConstraint *fkconstraint);
+static void createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint,
+									 Oid constrOid);
+static char *fkMatchTypeToString(char match_type);
 
 /* Used by attribute and relation renaming routines: */
 
@@ -147,6 +157,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
 		ConstrCheck *check = (ConstrCheck *) palloc(length(old_constraints) *
 													sizeof(ConstrCheck));
 		int			ncheck = 0;
+		int			constr_name_ctr = 0;
 
 		foreach(listptr, old_constraints)
 		{
@@ -167,8 +178,16 @@ DefineRelation(CreateStmt *stmt, char relkind)
 			}
 			else
 			{
+				/*
+				 * Generate a constraint name.  NB: this should match the
+				 * form of names that GenerateConstraintName() may produce
+				 * for names added later.  We are assured that there is
+				 * no name conflict, because MergeAttributes() did not pass
+				 * back any names of this form.
+				 */
 				check[ncheck].ccname = (char *) palloc(NAMEDATALEN);
-				snprintf(check[ncheck].ccname, NAMEDATALEN, "$%d", ncheck + 1);
+				snprintf(check[ncheck].ccname, NAMEDATALEN, "$%d",
+						 ++constr_name_ctr);
 			}
 			Assert(cdef->raw_expr == NULL && cdef->cooked_expr != NULL);
 			check[ncheck].ccbin = pstrdup(cdef->cooked_expr);
@@ -262,21 +281,20 @@ DefineRelation(CreateStmt *stmt, char relkind)
 /*
  * RemoveRelation
  *		Deletes a relation.
- *
- * Exceptions:
- *		BadArg if name is invalid.
- *
- * Note:
- *		If the relation has indices defined on it, then the index relations
- * themselves will be destroyed, too.
  */
 void
 RemoveRelation(const RangeVar *relation, DropBehavior behavior)
 {
 	Oid			relOid;
+	ObjectAddress object;
 
 	relOid = RangeVarGetRelid(relation, false);
-	heap_drop_with_catalog(relOid, allowSystemTableMods);
+
+	object.classId = RelOid_pg_class;
+	object.objectId = relOid;
+	object.objectSubId = 0;
+
+	performDeletion(&object, behavior);
 }
 
 /*
@@ -580,7 +598,13 @@ MergeAttributes(List *schema, List *supers, bool istemp,
 				Node	   *expr;
 
 				cdef->contype = CONSTR_CHECK;
-				if (check[i].ccname[0] == '$')
+				/*
+				 * Do not inherit generated constraint names, since they
+				 * might conflict across multiple inheritance parents.
+				 * (But conflicts between user-assigned names will cause
+				 * an error.)
+				 */
+				if (ConstraintNameIsGenerated(check[i].ccname))
 					cdef->name = NULL;
 				else
 					cdef->name = pstrdup(check[i].ccname);
@@ -684,7 +708,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
 /*
  * complementary static functions for MergeAttributes().
  *
- * Varattnos of pg_relcheck.rcbin must be rewritten when subclasses inherit
+ * Varattnos of pg_constraint.conbin must be rewritten when subclasses inherit
  * constraints from parent classes, since the inherited attributes could
  * be given different column numbers in multiple-inheritance cases.
  *
@@ -747,7 +771,8 @@ StoreCatalogInheritance(Oid relationId, List *supers)
 		return;
 
 	/*
-	 * Catalog INHERITS information using direct ancestors only.
+	 * Store INHERITS information in pg_inherits using direct ancestors only.
+	 * Also enter dependencies on the direct ancestors.
 	 */
 	relation = heap_openr(InheritsRelationName, RowExclusiveLock);
 	desc = RelationGetDescr(relation);
@@ -758,6 +783,8 @@ StoreCatalogInheritance(Oid relationId, List *supers)
 		Oid			entryOid = lfirsti(entry);
 		Datum		datum[Natts_pg_inherits];
 		char		nullarr[Natts_pg_inherits];
+		ObjectAddress childobject,
+					parentobject;
 
 		datum[0] = ObjectIdGetDatum(relationId);		/* inhrel */
 		datum[1] = ObjectIdGetDatum(entryOid);	/* inhparent */
@@ -782,6 +809,18 @@ StoreCatalogInheritance(Oid relationId, List *supers)
 
 		heap_freetuple(tuple);
 
+		/*
+		 * Store a dependency too
+		 */
+		parentobject.classId = RelOid_pg_class;
+		parentobject.objectId = entryOid;
+		parentobject.objectSubId = 0;
+		childobject.classId = RelOid_pg_class;
+		childobject.objectId = relationId;
+		childobject.objectSubId = 0;
+
+		recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL);
+
 		seqNumber += 1;
 	}
 
@@ -2299,6 +2338,7 @@ AlterTableAddConstraint(Oid myrelid,
 {
 	Relation	rel;
 	List	   *listptr;
+	int			counter = 0;
 
 	/*
 	 * Grab an exclusive lock on the target table, which we will NOT
@@ -2343,7 +2383,12 @@ AlterTableAddConstraint(Oid myrelid,
 
 	foreach(listptr, newConstraints)
 	{
-		Node	   *newConstraint = lfirst(listptr);
+		/*
+		 * copy is because we may destructively alter the node below
+		 * by inserting a generated name; this name is not necessarily
+		 * correct for children or parents.
+		 */
+		Node	   *newConstraint = copyObject(lfirst(listptr));
 
 		switch (nodeTag(newConstraint))
 		{
@@ -2370,12 +2415,23 @@ AlterTableAddConstraint(Oid myrelid,
 								RangeTblEntry *rte;
 								List	   *qual;
 								Node	   *expr;
-								char	   *name;
 
+								/*
+								 * Assign or validate constraint name
+								 */
 								if (constr->name)
-									name = constr->name;
+								{
+									if (ConstraintNameIsUsed(RelationGetRelid(rel),
+															 RelationGetNamespace(rel),
+															 constr->name))
+										elog(ERROR, "constraint \"%s\" already exists for relation \"%s\"",
+											 constr->name,
+											 RelationGetRelationName(rel));
+								}
 								else
-									name = "<unnamed>";
+									constr->name = GenerateConstraintName(RelationGetRelid(rel),
+																		  RelationGetNamespace(rel),
+																		  &counter);
 
 								/*
 								 * We need to make a parse state and range
@@ -2458,7 +2514,8 @@ AlterTableAddConstraint(Oid myrelid,
 								pfree(slot);
 
 								if (!successful)
-									elog(ERROR, "AlterTableAddConstraint: rejected due to CHECK constraint %s", name);
+									elog(ERROR, "AlterTableAddConstraint: rejected due to CHECK constraint %s",
+										 constr->name);
 
 								/*
 								 * Call AddRelationRawConstraints to do
@@ -2481,17 +2538,32 @@ AlterTableAddConstraint(Oid myrelid,
 				{
 					FkConstraint *fkconstraint = (FkConstraint *) newConstraint;
 					Relation	pkrel;
-					HeapScanDesc scan;
-					HeapTuple	tuple;
-					Trigger		trig;
-					List	   *list;
-					int			count;
+					Oid			constrOid;
+
+					/*
+					 * Assign or validate constraint name
+					 */
+					if (fkconstraint->constr_name)
+					{
+						if (ConstraintNameIsUsed(RelationGetRelid(rel),
+												 RelationGetNamespace(rel),
+												 fkconstraint->constr_name))
+							elog(ERROR, "constraint \"%s\" already exists for relation \"%s\"",
+								 fkconstraint->constr_name,
+								 RelationGetRelationName(rel));
+					}
+					else
+						fkconstraint->constr_name = GenerateConstraintName(RelationGetRelid(rel),
+																		   RelationGetNamespace(rel),
+																		   &counter);
 
 					/*
 					 * Grab an exclusive lock on the pk table, so that
 					 * someone doesn't delete rows out from under us.
-					 *
-					 * XXX wouldn't a lesser lock be sufficient?
+					 * (Although a lesser lock would do for that purpose,
+					 * we'll need exclusive lock anyway to add triggers
+					 * to the pk table; trying to start with a lesser lock
+					 * will just create a risk of deadlock.)
 					 */
 					pkrel = heap_openrv(fkconstraint->pktable,
 										AccessExclusiveLock);
@@ -2500,119 +2572,471 @@ AlterTableAddConstraint(Oid myrelid,
 					 * Validity checks
 					 */
 					if (pkrel->rd_rel->relkind != RELKIND_RELATION)
-						elog(ERROR, "referenced table \"%s\" not a relation",
-							 fkconstraint->pktable->relname);
+						elog(ERROR, "referenced relation \"%s\" is not a table",
+							 RelationGetRelationName(pkrel));
+
+					if (!allowSystemTableMods
+						&& IsSystemRelation(pkrel))
+						elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
+							 RelationGetRelationName(pkrel));
+
+					/* XXX shouldn't there be a permission check too? */
 
 					if (isTempNamespace(RelationGetNamespace(pkrel)) &&
 						!isTempNamespace(RelationGetNamespace(rel)))
-						elog(ERROR, "ALTER TABLE / ADD CONSTRAINT: Unable to reference temporary table from permanent table constraint.");
+						elog(ERROR, "ALTER TABLE / ADD CONSTRAINT: Unable to reference temporary table from permanent table constraint");
 
 					/*
-					 * First we check for limited correctness of the
-					 * constraint.
+					 * Check that the constraint is satisfied by existing
+					 * rows (we can skip this during table creation).
 					 *
 					 * NOTE: we assume parser has already checked for
 					 * existence of an appropriate unique index on the
 					 * referenced relation, and that the column datatypes
 					 * are comparable.
-					 *
-					 * Scan through each tuple, calling RI_FKey_check_ins
-					 * (insert trigger) as if that tuple had just been
-					 * inserted.  If any of those fail, it should
-					 * elog(ERROR) and that's that.
 					 */
-					MemSet(&trig, 0, sizeof(trig));
-					trig.tgoid = InvalidOid;
-					if (fkconstraint->constr_name)
-						trig.tgname = fkconstraint->constr_name;
-					else
-						trig.tgname = "<unknown>";
-					trig.tgenabled = TRUE;
-					trig.tgisconstraint = TRUE;
-					trig.tgconstrrelid = RelationGetRelid(pkrel);
-					trig.tgdeferrable = FALSE;
-					trig.tginitdeferred = FALSE;
-
-					trig.tgargs = (char **) palloc(
-					 sizeof(char *) * (4 + length(fkconstraint->fk_attrs)
-									   + length(fkconstraint->pk_attrs)));
-
-					trig.tgargs[0] = trig.tgname;
-					trig.tgargs[1] = RelationGetRelationName(rel);
-					trig.tgargs[2] = RelationGetRelationName(pkrel);
-					trig.tgargs[3] = fkconstraint->match_type;
-					count = 4;
-					foreach(list, fkconstraint->fk_attrs)
-					{
-						Ident	   *fk_at = lfirst(list);
+					if (!fkconstraint->skip_validation)
+						validateForeignKeyConstraint(fkconstraint, rel, pkrel);
 
-						trig.tgargs[count] = fk_at->name;
-						count += 2;
-					}
-					count = 5;
-					foreach(list, fkconstraint->pk_attrs)
-					{
-						Ident	   *pk_at = lfirst(list);
+					/*
+					 * Record the FK constraint in pg_constraint.
+					 */
+					constrOid = createForeignKeyConstraint(rel, pkrel,
+														   fkconstraint);
 
-						trig.tgargs[count] = pk_at->name;
-						count += 2;
-					}
-					trig.tgnargs = count - 1;
+					/*
+					 * Create the triggers that will enforce the constraint.
+					 */
+					createForeignKeyTriggers(rel, fkconstraint, constrOid);
 
-					scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
+					/*
+					 * Close pk table, but keep lock until we've committed.
+					 */
+					heap_close(pkrel, NoLock);
 
-					while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
-					{
-						/* Make a call to the check function */
+					break;
+				}
+			default:
+				elog(ERROR, "ALTER TABLE / ADD CONSTRAINT unable to determine type of constraint passed");
+		}
+	}
 
-						/*
-						 * No parameters are passed, but we do set a
-						 * context
-						 */
-						FunctionCallInfoData fcinfo;
-						TriggerData trigdata;
+	/* Close rel, but keep lock till commit */
+	heap_close(rel, NoLock);
+}
 
-						MemSet(&fcinfo, 0, sizeof(fcinfo));
+/*
+ * Scan the existing rows in a table to verify they meet a proposed FK
+ * constraint.
+ *
+ * Caller must have opened and locked both relations.
+ */
+static void
+validateForeignKeyConstraint(FkConstraint *fkconstraint,
+							 Relation rel,
+							 Relation pkrel)
+{
+	HeapScanDesc scan;
+	HeapTuple	tuple;
+	Trigger		trig;
+	List	   *list;
+	int			count;
+
+	/*
+	 * Scan through each tuple, calling RI_FKey_check_ins
+	 * (insert trigger) as if that tuple had just been
+	 * inserted.  If any of those fail, it should
+	 * elog(ERROR) and that's that.
+	 */
+	MemSet(&trig, 0, sizeof(trig));
+	trig.tgoid = InvalidOid;
+	trig.tgname = fkconstraint->constr_name;
+	trig.tgenabled = TRUE;
+	trig.tgisconstraint = TRUE;
+	trig.tgconstrrelid = RelationGetRelid(pkrel);
+	trig.tgdeferrable = FALSE;
+	trig.tginitdeferred = FALSE;
+
+	trig.tgargs = (char **) palloc(sizeof(char *) *
+								   (4 + length(fkconstraint->fk_attrs)
+									+ length(fkconstraint->pk_attrs)));
+
+	trig.tgargs[0] = trig.tgname;
+	trig.tgargs[1] = RelationGetRelationName(rel);
+	trig.tgargs[2] = RelationGetRelationName(pkrel);
+	trig.tgargs[3] = fkMatchTypeToString(fkconstraint->fk_matchtype);
+	count = 4;
+	foreach(list, fkconstraint->fk_attrs)
+	{
+		Ident	   *fk_at = lfirst(list);
 
-						/*
-						 * We assume RI_FKey_check_ins won't look at
-						 * flinfo...
-						 */
+		trig.tgargs[count] = fk_at->name;
+		count += 2;
+	}
+	count = 5;
+	foreach(list, fkconstraint->pk_attrs)
+	{
+		Ident	   *pk_at = lfirst(list);
 
-						trigdata.type = T_TriggerData;
-						trigdata.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW;
-						trigdata.tg_relation = rel;
-						trigdata.tg_trigtuple = tuple;
-						trigdata.tg_newtuple = NULL;
-						trigdata.tg_trigger = &trig;
+		trig.tgargs[count] = pk_at->name;
+		count += 2;
+	}
+	trig.tgnargs = count - 1;
 
-						fcinfo.context = (Node *) &trigdata;
+	scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
 
-						RI_FKey_check_ins(&fcinfo);
-					}
-					heap_endscan(scan);
+	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	{
+		FunctionCallInfoData fcinfo;
+		TriggerData trigdata;
 
-					pfree(trig.tgargs);
+		/*
+		 * Make a call to the trigger function
+		 *
+		 * No parameters are passed, but we do set a context
+		 */
+		MemSet(&fcinfo, 0, sizeof(fcinfo));
 
-					heap_close(pkrel, NoLock);
+		/*
+		 * We assume RI_FKey_check_ins won't look at flinfo...
+		 */
+		trigdata.type = T_TriggerData;
+		trigdata.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW;
+		trigdata.tg_relation = rel;
+		trigdata.tg_trigtuple = tuple;
+		trigdata.tg_newtuple = NULL;
+		trigdata.tg_trigger = &trig;
 
-					break;
-				}
-			default:
-				elog(ERROR, "ALTER TABLE / ADD CONSTRAINT unable to determine type of constraint passed");
-		}
+		fcinfo.context = (Node *) &trigdata;
+
+		RI_FKey_check_ins(&fcinfo);
 	}
 
-	/* Close rel, but keep lock till commit */
-	heap_close(rel, NoLock);
+	heap_endscan(scan);
+
+	pfree(trig.tgargs);
 }
 
+/*
+ * Record an FK constraint in pg_constraint.
+ */
+static Oid
+createForeignKeyConstraint(Relation rel, Relation pkrel,
+						   FkConstraint *fkconstraint)
+{
+	int16	   *fkattr;
+	int16	   *pkattr;
+	int			fkcount;
+	int			pkcount;
+	List	   *l;
+	int			i;
+
+	/* Convert foreign-key attr names to attr number array */
+	fkcount = length(fkconstraint->fk_attrs);
+	fkattr = (int16 *) palloc(fkcount * sizeof(int16));
+	i = 0;
+	foreach(l, fkconstraint->fk_attrs)
+	{
+		Ident *id = (Ident *) lfirst(l);
+
+		fkattr[i++] = get_attnum(RelationGetRelid(rel), id->name);
+	}
+
+	/* The same for the referenced primary key attrs */
+	pkcount = length(fkconstraint->pk_attrs);
+	pkattr = (int16 *) palloc(pkcount * sizeof(int16));
+	i = 0;
+	foreach(l, fkconstraint->pk_attrs)
+	{
+		Ident *id = (Ident *) lfirst(l);
+
+		pkattr[i++] = get_attnum(RelationGetRelid(pkrel), id->name);
+	}
+
+	/* Now we can make the pg_constraint entry */
+	return CreateConstraintEntry(fkconstraint->constr_name,
+								 RelationGetNamespace(rel),
+								 CONSTRAINT_FOREIGN,
+								 fkconstraint->deferrable,
+								 fkconstraint->initdeferred,
+								 RelationGetRelid(rel),
+								 fkattr,
+								 fkcount,
+								 InvalidOid, /* not a domain constraint */
+								 RelationGetRelid(pkrel),
+								 pkattr,
+								 pkcount,
+								 fkconstraint->fk_upd_action,
+								 fkconstraint->fk_del_action,
+								 fkconstraint->fk_matchtype,
+								 NULL,
+								 NULL);
+}
+
+/*
+ * Create the triggers that implement an FK constraint.
+ */
+static void
+createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint,
+						 Oid constrOid)
+{
+	RangeVar   *myRel;
+	CreateTrigStmt *fk_trigger;
+	List	   *fk_attr;
+	List	   *pk_attr;
+	Ident	   *id;
+	ObjectAddress trigobj,
+				constrobj;
+
+	/*
+	 * Reconstruct a RangeVar for my relation (not passed in, unfortunately).
+	 */
+	myRel = makeRangeVar(get_namespace_name(RelationGetNamespace(rel)),
+						 RelationGetRelationName(rel));
+
+	/*
+	 * Preset objectAddress fields
+	 */
+	constrobj.classId = get_system_catalog_relid(ConstraintRelationName);
+	constrobj.objectId = constrOid;
+	constrobj.objectSubId = 0;
+	trigobj.classId = get_system_catalog_relid(TriggerRelationName);
+	trigobj.objectSubId = 0;
+
+	/* Make changes-so-far visible */
+	CommandCounterIncrement();
+
+	/*
+	 * Build and execute a CREATE CONSTRAINT TRIGGER statement for the
+	 * CHECK action.
+	 */
+	fk_trigger = makeNode(CreateTrigStmt);
+	fk_trigger->trigname = fkconstraint->constr_name;
+	fk_trigger->relation = myRel;
+	fk_trigger->funcname = SystemFuncName("RI_FKey_check_ins");
+	fk_trigger->before = false;
+	fk_trigger->row = true;
+	fk_trigger->actions[0] = 'i';
+	fk_trigger->actions[1] = 'u';
+	fk_trigger->actions[2] = '\0';
+	fk_trigger->lang = NULL;
+	fk_trigger->text = NULL;
+
+	fk_trigger->attr = NIL;
+	fk_trigger->when = NULL;
+	fk_trigger->isconstraint = true;
+	fk_trigger->deferrable = fkconstraint->deferrable;
+	fk_trigger->initdeferred = fkconstraint->initdeferred;
+	fk_trigger->constrrel = fkconstraint->pktable;
+
+	fk_trigger->args = NIL;
+	fk_trigger->args = lappend(fk_trigger->args,
+							   makeString(fkconstraint->constr_name));
+	fk_trigger->args = lappend(fk_trigger->args,
+							   makeString(myRel->relname));
+	fk_trigger->args = lappend(fk_trigger->args,
+							   makeString(fkconstraint->pktable->relname));
+	fk_trigger->args = lappend(fk_trigger->args,
+							   makeString(fkMatchTypeToString(fkconstraint->fk_matchtype)));
+	fk_attr = fkconstraint->fk_attrs;
+	pk_attr = fkconstraint->pk_attrs;
+	if (length(fk_attr) != length(pk_attr))
+		elog(ERROR, "number of key attributes in referenced table must be equal to foreign key"
+			 "\n\tIllegal FOREIGN KEY definition references \"%s\"",
+			 fkconstraint->pktable->relname);
+
+	while (fk_attr != NIL)
+	{
+		id = (Ident *) lfirst(fk_attr);
+		fk_trigger->args = lappend(fk_trigger->args, makeString(id->name));
+
+		id = (Ident *) lfirst(pk_attr);
+		fk_trigger->args = lappend(fk_trigger->args, makeString(id->name));
+
+		fk_attr = lnext(fk_attr);
+		pk_attr = lnext(pk_attr);
+	}
+
+	trigobj.objectId = CreateTrigger(fk_trigger, true);
+
+	/* Register dependency from trigger to constraint */
+	recordDependencyOn(&trigobj, &constrobj, DEPENDENCY_INTERNAL);
+
+	/* Make changes-so-far visible */
+	CommandCounterIncrement();
+
+	/*
+	 * Build and execute a CREATE CONSTRAINT TRIGGER statement for the
+	 * ON DELETE action on the referenced table.
+	 */
+	fk_trigger = makeNode(CreateTrigStmt);
+	fk_trigger->trigname = fkconstraint->constr_name;
+	fk_trigger->relation = fkconstraint->pktable;
+	fk_trigger->before = false;
+	fk_trigger->row = true;
+	fk_trigger->actions[0] = 'd';
+	fk_trigger->actions[1] = '\0';
+	fk_trigger->lang = NULL;
+	fk_trigger->text = NULL;
+
+	fk_trigger->attr = NIL;
+	fk_trigger->when = NULL;
+	fk_trigger->isconstraint = true;
+	fk_trigger->deferrable = fkconstraint->deferrable;
+	fk_trigger->initdeferred = fkconstraint->initdeferred;
+	fk_trigger->constrrel = myRel;
+	switch (fkconstraint->fk_del_action)
+	{
+		case FKCONSTR_ACTION_NOACTION:
+			fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_del");
+			break;
+		case FKCONSTR_ACTION_RESTRICT:
+			fk_trigger->deferrable = false;
+			fk_trigger->initdeferred = false;
+			fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_del");
+			break;
+		case FKCONSTR_ACTION_CASCADE:
+			fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_del");
+			break;
+		case FKCONSTR_ACTION_SETNULL:
+			fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_del");
+			break;
+		case FKCONSTR_ACTION_SETDEFAULT:
+			fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_del");
+			break;
+		default:
+			elog(ERROR, "Unrecognized ON DELETE action for FOREIGN KEY constraint");
+			break;
+	}
+
+	fk_trigger->args = NIL;
+	fk_trigger->args = lappend(fk_trigger->args,
+							   makeString(fkconstraint->constr_name));
+	fk_trigger->args = lappend(fk_trigger->args,
+							   makeString(myRel->relname));
+	fk_trigger->args = lappend(fk_trigger->args,
+							   makeString(fkconstraint->pktable->relname));
+	fk_trigger->args = lappend(fk_trigger->args,
+							   makeString(fkMatchTypeToString(fkconstraint->fk_matchtype)));
+	fk_attr = fkconstraint->fk_attrs;
+	pk_attr = fkconstraint->pk_attrs;
+	while (fk_attr != NIL)
+	{
+		id = (Ident *) lfirst(fk_attr);
+		fk_trigger->args = lappend(fk_trigger->args, makeString(id->name));
+
+		id = (Ident *) lfirst(pk_attr);
+		fk_trigger->args = lappend(fk_trigger->args, makeString(id->name));
+
+		fk_attr = lnext(fk_attr);
+		pk_attr = lnext(pk_attr);
+	}
+
+	trigobj.objectId = CreateTrigger(fk_trigger, true);
+
+	/* Register dependency from trigger to constraint */
+	recordDependencyOn(&trigobj, &constrobj, DEPENDENCY_INTERNAL);
+
+	/* Make changes-so-far visible */
+	CommandCounterIncrement();
+
+	/*
+	 * Build and execute a CREATE CONSTRAINT TRIGGER statement for the
+	 * ON UPDATE action on the referenced table.
+	 */
+	fk_trigger = makeNode(CreateTrigStmt);
+	fk_trigger->trigname = fkconstraint->constr_name;
+	fk_trigger->relation = fkconstraint->pktable;
+	fk_trigger->before = false;
+	fk_trigger->row = true;
+	fk_trigger->actions[0] = 'u';
+	fk_trigger->actions[1] = '\0';
+	fk_trigger->lang = NULL;
+	fk_trigger->text = NULL;
+
+	fk_trigger->attr = NIL;
+	fk_trigger->when = NULL;
+	fk_trigger->isconstraint = true;
+	fk_trigger->deferrable = fkconstraint->deferrable;
+	fk_trigger->initdeferred = fkconstraint->initdeferred;
+	fk_trigger->constrrel = myRel;
+	switch (fkconstraint->fk_upd_action)
+	{
+		case FKCONSTR_ACTION_NOACTION:
+			fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_upd");
+			break;
+		case FKCONSTR_ACTION_RESTRICT:
+			fk_trigger->deferrable = false;
+			fk_trigger->initdeferred = false;
+			fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_upd");
+			break;
+		case FKCONSTR_ACTION_CASCADE:
+			fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_upd");
+			break;
+		case FKCONSTR_ACTION_SETNULL:
+			fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_upd");
+			break;
+		case FKCONSTR_ACTION_SETDEFAULT:
+			fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_upd");
+			break;
+		default:
+			elog(ERROR, "Unrecognized ON UPDATE action for FOREIGN KEY constraint");
+			break;
+	}
+
+	fk_trigger->args = NIL;
+	fk_trigger->args = lappend(fk_trigger->args,
+							   makeString(fkconstraint->constr_name));
+	fk_trigger->args = lappend(fk_trigger->args,
+							   makeString(myRel->relname));
+	fk_trigger->args = lappend(fk_trigger->args,
+							   makeString(fkconstraint->pktable->relname));
+	fk_trigger->args = lappend(fk_trigger->args,
+							   makeString(fkMatchTypeToString(fkconstraint->fk_matchtype)));
+	fk_attr = fkconstraint->fk_attrs;
+	pk_attr = fkconstraint->pk_attrs;
+	while (fk_attr != NIL)
+	{
+		id = (Ident *) lfirst(fk_attr);
+		fk_trigger->args = lappend(fk_trigger->args, makeString(id->name));
+
+		id = (Ident *) lfirst(pk_attr);
+		fk_trigger->args = lappend(fk_trigger->args, makeString(id->name));
+
+		fk_attr = lnext(fk_attr);
+		pk_attr = lnext(pk_attr);
+	}
+
+	trigobj.objectId = CreateTrigger(fk_trigger, true);
+
+	/* Register dependency from trigger to constraint */
+	recordDependencyOn(&trigobj, &constrobj, DEPENDENCY_INTERNAL);
+}
+
+/*
+ * fkMatchTypeToString -
+ *	  convert FKCONSTR_MATCH_xxx code to string to use in trigger args
+ */
+static char *
+fkMatchTypeToString(char match_type)
+{
+	switch (match_type) 
+	{
+		case FKCONSTR_MATCH_FULL:
+			return pstrdup("FULL");
+		case FKCONSTR_MATCH_PARTIAL:
+			return pstrdup("PARTIAL");
+		case FKCONSTR_MATCH_UNSPECIFIED:
+			return pstrdup("UNSPECIFIED");
+		default:
+			elog(ERROR, "fkMatchTypeToString: Unknown MATCH TYPE '%c'",
+				 match_type);
+	}
+	return NULL;				/* can't get here */
+}
 
 /*
  * ALTER TABLE DROP CONSTRAINT
- * Note: It is legal to remove a constraint with name "" as it is possible
- * to add a constraint with name "".
- * Christopher Kings-Lynne
  */
 void
 AlterTableDropConstraint(Oid myrelid,
@@ -2620,14 +3044,7 @@ AlterTableDropConstraint(Oid myrelid,
 						 DropBehavior behavior)
 {
 	Relation	rel;
-	int			deleted;
-
-	/*
-	 * We don't support CASCADE yet  - in fact, RESTRICT doesn't work to
-	 * the spec either!
-	 */
-	if (behavior == DROP_CASCADE)
-		elog(ERROR, "ALTER TABLE / DROP CONSTRAINT does not support the CASCADE keyword");
+	int			deleted = 0;
 
 	/*
 	 * Acquire an exclusive lock on the target relation for the duration
@@ -2649,26 +3066,39 @@ AlterTableDropConstraint(Oid myrelid,
 		aclcheck_error(ACLCHECK_NOT_OWNER, RelationGetRelationName(rel));
 
 	/*
-	 * Since all we have is the name of the constraint, we have to look
-	 * through all catalogs that could possibly contain a constraint for
-	 * this relation. We also keep a count of the number of constraints
-	 * removed.
+	 * Process child tables if requested.
 	 */
+	if (inh)
+	{
+		List	   *child,
+				   *children;
 
-	deleted = 0;
+		/* This routine is actually in the planner */
+		children = find_all_inheritors(myrelid);
 
-	/*
-	 * First, we remove all CHECK constraints with the given name
-	 */
+		/*
+		 * find_all_inheritors does the recursive search of the
+		 * inheritance hierarchy, so all we have to do is process all of
+		 * the relids in the list that it returns.
+		 */
+		foreach(child, children)
+		{
+			Oid			childrelid = lfirsti(child);
+			Relation	inhrel;
 
-	deleted += RemoveCheckConstraint(rel, constrName, inh);
+			if (childrelid == myrelid)
+				continue;
+			inhrel = heap_open(childrelid, AccessExclusiveLock);
+			/* do NOT count child constraints in deleted. */
+			RemoveRelConstraints(inhrel, constrName, behavior);
+			heap_close(inhrel, NoLock);
+		}
+	}
 
 	/*
-	 * Now we remove NULL, UNIQUE, PRIMARY KEY and FOREIGN KEY
-	 * constraints.
-	 *
-	 * Unimplemented.
+	 * Now do the thing on this relation.
 	 */
+	deleted += RemoveRelConstraints(rel, constrName, behavior);
 
 	/* Close the target relation */
 	heap_close(rel, NoLock);
@@ -2797,6 +3227,8 @@ AlterTableCreateToastTable(Oid relOid, bool silent)
 	char		toast_idxname[NAMEDATALEN];
 	IndexInfo  *indexInfo;
 	Oid			classObjectId[2];
+	ObjectAddress baseobject,
+				toastobject;
 
 	/*
 	 * Grab an exclusive lock on the target table, which we will NOT
@@ -2957,7 +3389,7 @@ AlterTableCreateToastTable(Oid relOid, bool silent)
 
 	toast_idxid = index_create(toast_relid, toast_idxname, indexInfo,
 							   BTREE_AM_OID, classObjectId,
-							   true, true);
+							   true, false, true);
 
 	/*
 	 * Update toast rel's pg_class entry to show that it has an index. The
@@ -2981,6 +3413,19 @@ AlterTableCreateToastTable(Oid relOid, bool silent)
 
 	heap_freetuple(reltup);
 
+	/*
+	 * Register dependency from the toast table to the master, so that
+	 * the toast table will be deleted if the master is.
+	 */
+	baseobject.classId = RelOid_pg_class;
+	baseobject.objectId = relOid;
+	baseobject.objectSubId = 0;
+	toastobject.classId = RelOid_pg_class;
+	toastobject.objectId = toast_relid;
+	toastobject.objectSubId = 0;
+
+	recordDependencyOn(&toastobject, &baseobject, DEPENDENCY_INTERNAL);
+
 	/*
 	 * Close relations and make changes visible
 	 */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 18484372ed5e8d35127b880997df78a784f2c428..b27dd0f4380f5aa56b1ab2c9a450e90f4dc53306 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.120 2002/06/20 20:29:27 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.121 2002/07/12 18:43:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,12 +17,12 @@
 #include "access/heapam.h"
 #include "catalog/catalog.h"
 #include "catalog/catname.h"
+#include "catalog/dependency.h"
 #include "catalog/indexing.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_trigger.h"
-#include "commands/comment.h"
 #include "commands/trigger.h"
 #include "executor/executor.h"
 #include "miscadmin.h"
@@ -50,8 +50,8 @@ static void DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
 					   MemoryContext per_tuple_context);
 
 
-void
-CreateTrigger(CreateTrigStmt *stmt)
+Oid
+CreateTrigger(CreateTrigStmt *stmt, bool forConstraint)
 {
 	int16		tgtype;
 	int16		tgattr[FUNC_MAX_ARGS];
@@ -69,11 +69,15 @@ CreateTrigger(CreateTrigStmt *stmt)
 	Oid			fargtypes[FUNC_MAX_ARGS];
 	Oid			funcoid;
 	Oid			funclang;
+	Oid			trigoid;
 	int			found = 0;
 	int			i;
 	char		constrtrigname[NAMEDATALEN];
-	char	   *constrname = "";
-	Oid			constrrelid = InvalidOid;
+	char	   *trigname;
+	char	   *constrname;
+	Oid			constrrelid;
+	ObjectAddress	myself,
+					referenced;
 
 	rel = heap_openrv(stmt->relation, AccessExclusiveLock);
 
@@ -91,21 +95,28 @@ CreateTrigger(CreateTrigStmt *stmt)
 		aclcheck_error(aclresult, RelationGetRelationName(rel));
 
 	/*
-	 * If trigger is an RI constraint, use trigger name as constraint name
-	 * and build a unique trigger name instead.
+	 * If trigger is an RI constraint, use specified trigger name as
+	 * constraint name and build a unique trigger name instead.
+	 * This is mainly for backwards compatibility with CREATE CONSTRAINT
+	 * TRIGGER commands.
 	 */
 	if (stmt->isconstraint)
 	{
-		constrname = stmt->trigname;
 		snprintf(constrtrigname, sizeof(constrtrigname),
 				 "RI_ConstraintTrigger_%u", newoid());
-		stmt->trigname = constrtrigname;
-
-		if (stmt->constrrel != NULL)
-			constrrelid = RangeVarGetRelid(stmt->constrrel, false);
-		else
-			constrrelid = InvalidOid;
+		trigname = constrtrigname;
+		constrname = stmt->trigname;
 	}
+	else
+	{
+		trigname = stmt->trigname;
+		constrname = "";
+	}
+
+	if (stmt->constrrel != NULL)
+		constrrelid = RangeVarGetRelid(stmt->constrrel, false);
+	else
+		constrrelid = InvalidOid;
 
 	TRIGGER_CLEAR_TYPE(tgtype);
 	if (stmt->before)
@@ -160,9 +171,9 @@ CreateTrigger(CreateTrigStmt *stmt)
 	{
 		Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
 
-		if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0)
+		if (namestrcmp(&(pg_trigger->tgname), trigname) == 0)
 			elog(ERROR, "CreateTrigger: trigger %s already defined on relation %s",
-				 stmt->trigname, stmt->relation->relname);
+				 trigname, stmt->relation->relname);
 		found++;
 	}
 	systable_endscan(tgscan);
@@ -209,12 +220,13 @@ CreateTrigger(CreateTrigStmt *stmt)
 
 	values[Anum_pg_trigger_tgrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
 	values[Anum_pg_trigger_tgname - 1] = DirectFunctionCall1(namein,
-										CStringGetDatum(stmt->trigname));
+										CStringGetDatum(trigname));
 	values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
 	values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
 	values[Anum_pg_trigger_tgenabled - 1] = BoolGetDatum(true);
 	values[Anum_pg_trigger_tgisconstraint - 1] = BoolGetDatum(stmt->isconstraint);
-	values[Anum_pg_trigger_tgconstrname - 1] = PointerGetDatum(constrname);
+	values[Anum_pg_trigger_tgconstrname - 1] = DirectFunctionCall1(namein,
+																   CStringGetDatum(constrname));
 	values[Anum_pg_trigger_tgconstrrelid - 1] = ObjectIdGetDatum(constrrelid);
 	values[Anum_pg_trigger_tgdeferrable - 1] = BoolGetDatum(stmt->deferrable);
 	values[Anum_pg_trigger_tginitdeferred - 1] = BoolGetDatum(stmt->initdeferred);
@@ -270,10 +282,16 @@ CreateTrigger(CreateTrigStmt *stmt)
 	/*
 	 * Insert tuple into pg_trigger.
 	 */
-	simple_heap_insert(tgrel, tuple);
+	trigoid = simple_heap_insert(tgrel, tuple);
+
 	CatalogOpenIndices(Num_pg_trigger_indices, Name_pg_trigger_indices, idescs);
 	CatalogIndexInsert(idescs, Num_pg_trigger_indices, tgrel, tuple);
 	CatalogCloseIndices(Num_pg_trigger_indices, idescs);
+
+	myself.classId = RelationGetRelid(tgrel);
+	myself.objectId = trigoid;
+	myself.objectSubId = 0;
+
 	heap_freetuple(tuple);
 	heap_close(tgrel, RowExclusiveLock);
 
@@ -294,10 +312,13 @@ CreateTrigger(CreateTrigStmt *stmt)
 			 stmt->relation->relname);
 
 	((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found + 1;
+
 	simple_heap_update(pgrel, &tuple->t_self, tuple);
+
 	CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
 	CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple);
 	CatalogCloseIndices(Num_pg_class_indices, ridescs);
+
 	heap_freetuple(tuple);
 	heap_close(pgrel, RowExclusiveLock);
 
@@ -307,25 +328,129 @@ CreateTrigger(CreateTrigStmt *stmt)
 	 * upcoming CommandCounterIncrement...
 	 */
 
+	/*
+	 * Record dependencies for trigger.  Always place a normal dependency
+	 * on the function.  If we are doing this in response to an explicit
+	 * CREATE TRIGGER command, also make trigger be auto-dropped if its
+	 * relation is dropped or if the FK relation is dropped.  (Auto drop
+	 * is compatible with our pre-7.3 behavior.)  If the trigger is being
+	 * made for a constraint, we can skip the relation links; the dependency
+	 * on the constraint will indirectly depend on the relations.
+	 */
+	referenced.classId = RelOid_pg_proc;
+	referenced.objectId = funcoid;
+	referenced.objectSubId = 0;
+	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+	if (!forConstraint)
+	{
+		referenced.classId = RelOid_pg_class;
+		referenced.objectId = RelationGetRelid(rel);
+		referenced.objectSubId = 0;
+		recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
+		if (constrrelid != InvalidOid)
+		{
+			referenced.classId = RelOid_pg_class;
+			referenced.objectId = constrrelid;
+			referenced.objectSubId = 0;
+			recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
+		}
+	}
+
 	/* Keep lock on target rel until end of xact */
 	heap_close(rel, NoLock);
+
+	return trigoid;
 }
 
 /*
  * DropTrigger - drop an individual trigger by name
  */
 void
-DropTrigger(Oid relid, const char *trigname)
+DropTrigger(Oid relid, const char *trigname, DropBehavior behavior)
+{
+	Relation		tgrel;
+	ScanKeyData		skey[2];
+	SysScanDesc		tgscan;
+	HeapTuple		tup;
+	ObjectAddress object;
+
+	/*
+	 * Find the trigger, verify permissions, set up object address
+	 */
+	tgrel = heap_openr(TriggerRelationName, AccessShareLock);
+
+	ScanKeyEntryInitialize(&skey[0], 0x0,
+						   Anum_pg_trigger_tgrelid, F_OIDEQ,
+						   ObjectIdGetDatum(relid));
+
+	ScanKeyEntryInitialize(&skey[1], 0x0,
+						   Anum_pg_trigger_tgname, F_NAMEEQ,
+						   CStringGetDatum(trigname));
+
+	tgscan = systable_beginscan(tgrel, TriggerRelidNameIndex, true,
+								SnapshotNow, 2, skey);
+
+	tup = systable_getnext(tgscan);
+
+	if (!HeapTupleIsValid(tup))
+		elog(ERROR, "DropTrigger: there is no trigger %s on relation %s",
+			 trigname, get_rel_name(relid));
+
+	if (!pg_class_ownercheck(relid, GetUserId()))
+		aclcheck_error(ACLCHECK_NOT_OWNER, get_rel_name(relid));
+
+	object.classId = RelationGetRelid(tgrel);
+	object.objectId = tup->t_data->t_oid;
+	object.objectSubId = 0;
+
+	systable_endscan(tgscan);
+	heap_close(tgrel, AccessShareLock);
+
+	/*
+	 * Do the deletion
+	 */
+	performDeletion(&object, behavior);
+}
+
+/*
+ * Guts of trigger deletion.
+ */
+void
+RemoveTriggerById(Oid trigOid)
 {
-	Relation	rel;
 	Relation	tgrel;
 	SysScanDesc	tgscan;
-	ScanKeyData key;
+	ScanKeyData	skey[1];
+	HeapTuple	tup;
+	Oid			relid;
+	Relation	rel;
 	Relation	pgrel;
 	HeapTuple	tuple;
+	Form_pg_class	classForm;
 	Relation	ridescs[Num_pg_class_indices];
-	int			remaining = 0;
-	int			found = 0;
+
+	tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
+
+	/*
+	 * Find the trigger to delete.
+	 */
+	ScanKeyEntryInitialize(&skey[0], 0x0,
+						   ObjectIdAttributeNumber, F_OIDEQ,
+						   ObjectIdGetDatum(trigOid));
+
+	tgscan = systable_beginscan(tgrel, TriggerOidIndex, true,
+								SnapshotNow, 1, skey);
+
+	tup = systable_getnext(tgscan);
+	if (!HeapTupleIsValid(tup))
+		elog(ERROR, "RemoveTriggerById: Trigger %u does not exist",
+			 trigOid);
+
+	/*
+	 * Open and exclusive-lock the relation the trigger belongs to.
+	 */
+	relid = ((Form_pg_trigger) GETSTRUCT(tup))->tgrelid;
 
 	rel = heap_open(relid, AccessExclusiveLock);
 
@@ -337,55 +462,22 @@ DropTrigger(Oid relid, const char *trigname)
 		elog(ERROR, "DropTrigger: can't drop trigger for system relation %s",
 			 RelationGetRelationName(rel));
 
-	if (!pg_class_ownercheck(relid, GetUserId()))
-		aclcheck_error(ACLCHECK_NOT_OWNER, RelationGetRelationName(rel));
-
 	/*
-	 * Search pg_trigger, delete target trigger, count remaining triggers
-	 * for relation.  (Although we could fetch and delete the target
-	 * trigger directly, we'd still have to scan the remaining triggers,
-	 * so we may as well do both in one indexscan.)
-	 *
-	 * Note this is OK only because we have AccessExclusiveLock on the rel,
-	 * so no one else is creating/deleting triggers on this rel at the same
-	 * time.
+	 * Delete the pg_trigger tuple.
 	 */
-	tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
-	ScanKeyEntryInitialize(&key, 0,
-						   Anum_pg_trigger_tgrelid,
-						   F_OIDEQ,
-						   ObjectIdGetDatum(relid));
-	tgscan = systable_beginscan(tgrel, TriggerRelidNameIndex, true,
-								SnapshotNow, 1, &key);
-	while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
-	{
-		Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
+	simple_heap_delete(tgrel, &tup->t_self);
 
-		if (namestrcmp(&(pg_trigger->tgname), trigname) == 0)
-		{
-			/* Delete any comments associated with this trigger */
-			DeleteComments(tuple->t_data->t_oid, RelationGetRelid(tgrel));
-
-			simple_heap_delete(tgrel, &tuple->t_self);
-			found++;
-		}
-		else
-			remaining++;
-	}
 	systable_endscan(tgscan);
 	heap_close(tgrel, RowExclusiveLock);
 
-	if (found == 0)
-		elog(ERROR, "DropTrigger: there is no trigger %s on relation %s",
-			 trigname, RelationGetRelationName(rel));
-	if (found > 1)				/* shouldn't happen */
-		elog(NOTICE, "DropTrigger: found (and deleted) %d triggers %s on relation %s",
-			 found, trigname, RelationGetRelationName(rel));
-
 	/*
 	 * Update relation's pg_class entry.  Crucial side-effect: other
 	 * backends (and this one too!) are sent SI message to make them
 	 * rebuild relcache entries.
+	 *
+	 * Note this is OK only because we have AccessExclusiveLock on the rel,
+	 * so no one else is creating/deleting triggers on this rel at the same
+	 * time.
 	 */
 	pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
 	tuple = SearchSysCacheCopy(RELOID,
@@ -394,115 +486,27 @@ DropTrigger(Oid relid, const char *trigname)
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "DropTrigger: relation %s not found in pg_class",
 			 RelationGetRelationName(rel));
+	classForm = (Form_pg_class) GETSTRUCT(tuple);
+
+	if (classForm->reltriggers == 0)
+		elog(ERROR, "DropTrigger: relation %s has reltriggers = 0",
+			 RelationGetRelationName(rel));
+	classForm->reltriggers--;
 
-	((Form_pg_class) GETSTRUCT(tuple))->reltriggers = remaining;
 	simple_heap_update(pgrel, &tuple->t_self, tuple);
+
 	CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
 	CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple);
 	CatalogCloseIndices(Num_pg_class_indices, ridescs);
+
 	heap_freetuple(tuple);
+
 	heap_close(pgrel, RowExclusiveLock);
 
-	/* Keep lock on target rel until end of xact */
+	/* Keep lock on trigger's rel until end of xact */
 	heap_close(rel, NoLock);
 }
 
-/*
- * Remove all triggers for a relation that's being deleted.
- */
-void
-RelationRemoveTriggers(Relation rel)
-{
-	Relation	tgrel;
-	SysScanDesc	tgscan;
-	ScanKeyData key;
-	HeapTuple	tup;
-	bool		found = false;
-
-	tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
-	ScanKeyEntryInitialize(&key, 0,
-						   Anum_pg_trigger_tgrelid,
-						   F_OIDEQ,
-						   ObjectIdGetDatum(RelationGetRelid(rel)));
-	tgscan = systable_beginscan(tgrel, TriggerRelidNameIndex, true,
-								SnapshotNow, 1, &key);
-
-	while (HeapTupleIsValid(tup = systable_getnext(tgscan)))
-	{
-		/* Delete any comments associated with this trigger */
-		DeleteComments(tup->t_data->t_oid, RelationGetRelid(tgrel));
-
-		simple_heap_delete(tgrel, &tup->t_self);
-
-		found = true;
-	}
-
-	systable_endscan(tgscan);
-
-	/*
-	 * If we deleted any triggers, must update pg_class entry and advance
-	 * command counter to make the updated entry visible. This is fairly
-	 * annoying, since we'e just going to drop the durn thing later, but
-	 * it's necessary to have a consistent state in case we do
-	 * CommandCounterIncrement() below --- if RelationBuildTriggers()
-	 * runs, it will complain otherwise. Perhaps RelationBuildTriggers()
-	 * shouldn't be so picky...
-	 */
-	if (found)
-	{
-		Relation	pgrel;
-		Relation	ridescs[Num_pg_class_indices];
-
-		pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
-		tup = SearchSysCacheCopy(RELOID,
-								 ObjectIdGetDatum(RelationGetRelid(rel)),
-								 0, 0, 0);
-		if (!HeapTupleIsValid(tup))
-			elog(ERROR, "RelationRemoveTriggers: relation %u not found in pg_class",
-				 RelationGetRelid(rel));
-
-		((Form_pg_class) GETSTRUCT(tup))->reltriggers = 0;
-		simple_heap_update(pgrel, &tup->t_self, tup);
-		CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
-		CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tup);
-		CatalogCloseIndices(Num_pg_class_indices, ridescs);
-		heap_freetuple(tup);
-		heap_close(pgrel, RowExclusiveLock);
-		CommandCounterIncrement();
-	}
-
-	/*
-	 * Also drop all constraint triggers referencing this relation
-	 */
-	ScanKeyEntryInitialize(&key, 0,
-						   Anum_pg_trigger_tgconstrrelid,
-						   F_OIDEQ,
-						   ObjectIdGetDatum(RelationGetRelid(rel)));
-	tgscan = systable_beginscan(tgrel, TriggerConstrRelidIndex, true,
-								SnapshotNow, 1, &key);
-
-	while (HeapTupleIsValid(tup = systable_getnext(tgscan)))
-	{
-		Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tup);
-
-		elog(NOTICE, "DROP TABLE implicitly drops referential integrity trigger from table \"%s\"",
-			 get_rel_name(pg_trigger->tgrelid));
-
-		DropTrigger(pg_trigger->tgrelid, NameStr(pg_trigger->tgname));
-
-		/*
-		 * Need to do a command counter increment here to show up new
-		 * pg_class.reltriggers in the next loop iteration (in case there
-		 * are multiple referential integrity action triggers for the same
-		 * FK table defined on the PK table).
-		 */
-		CommandCounterIncrement();
-	}
-	systable_endscan(tgscan);
-
-	heap_close(tgrel, RowExclusiveLock);
-}
-
 /*
  *		renametrig		- changes the name of a trigger on a relation
  *
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index a9b468558107807c82b37e4466db8cf2c59465a9..f148ff658918db7401d530d87d1f4cc65f492d0e 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.4 2002/07/01 15:27:48 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.5 2002/07/12 18:43:16 tgl Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -33,10 +33,10 @@
 
 #include "access/heapam.h"
 #include "catalog/catname.h"
+#include "catalog/dependency.h"
 #include "catalog/heap.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_type.h"
-#include "commands/comment.h"
 #include "commands/defrem.h"
 #include "miscadmin.h"
 #include "parser/parse_func.h"
@@ -262,17 +262,14 @@ DefineType(List *names, List *parameters)
 /*
  *	RemoveType
  *		Removes a datatype.
- *
- * NOTE: since this tries to remove the associated array type too, it'll
- * only work on scalar types.
  */
 void
 RemoveType(List *names, DropBehavior behavior)
 {
 	TypeName   *typename;
-	Relation	relation;
 	Oid			typeoid;
 	HeapTuple	tup;
+	ObjectAddress object;
 
 	/* Make a TypeName so we can use standard type lookup machinery */
 	typename = makeNode(TypeName);
@@ -280,8 +277,6 @@ RemoveType(List *names, DropBehavior behavior)
 	typename->typmod = -1;
 	typename->arrayBounds = NIL;
 
-	relation = heap_openr(TypeRelationName, RowExclusiveLock);
-
 	/* Use LookupTypeName here so that shell types can be removed. */
 	typeoid = LookupTypeName(typename);
 	if (!OidIsValid(typeoid))
@@ -301,30 +296,36 @@ RemoveType(List *names, DropBehavior behavior)
 								 GetUserId()))
 		aclcheck_error(ACLCHECK_NOT_OWNER, TypeNameToString(typename));
 
-	/* Delete any comments associated with this type */
-	DeleteComments(typeoid, RelationGetRelid(relation));
+	ReleaseSysCache(tup);
 
-	/* Remove the type tuple from pg_type */
-	simple_heap_delete(relation, &tup->t_self);
+	/*
+	 * Do the deletion
+	 */
+	object.classId = RelOid_pg_type;
+	object.objectId = typeoid;
+	object.objectSubId = 0;
 
-	ReleaseSysCache(tup);
+	performDeletion(&object, behavior);
+}
 
-	/* Now, delete the "array of" that type */
-	typename->arrayBounds = makeList1(makeInteger(1));
 
-	typeoid = LookupTypeName(typename);
-	if (!OidIsValid(typeoid))
-		elog(ERROR, "Type \"%s\" does not exist",
-			 TypeNameToString(typename));
+/*
+ * Guts of type deletion.
+ */
+void
+RemoveTypeById(Oid typeOid)
+{
+	Relation	relation;
+	HeapTuple	tup;
+
+	relation = heap_openr(TypeRelationName, RowExclusiveLock);
 
 	tup = SearchSysCache(TYPEOID,
-						 ObjectIdGetDatum(typeoid),
+						 ObjectIdGetDatum(typeOid),
 						 0, 0, 0);
 	if (!HeapTupleIsValid(tup))
-		elog(ERROR, "Type \"%s\" does not exist",
-			 TypeNameToString(typename));
-
-	DeleteComments(typeoid, RelationGetRelid(relation));
+		elog(ERROR, "RemoveTypeById: type %u not found",
+			 typeOid);
 
 	simple_heap_delete(relation, &tup->t_self);
 
@@ -365,6 +366,8 @@ DefineDomain(CreateDomainStmt *stmt)
 	HeapTuple	typeTup;
 	List	   *schema = stmt->constraints;
 	List	   *listptr;
+	Oid			basetypeoid;
+	Form_pg_type	baseType;
 
 	/* Convert list of names to a name and namespace */
 	domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
@@ -389,40 +392,43 @@ DefineDomain(CreateDomainStmt *stmt)
 	 */
 	typeTup = typenameType(stmt->typename);
 
+	baseType = (Form_pg_type) GETSTRUCT(typeTup);
+	basetypeoid = typeTup->t_data->t_oid;
+
 	/*
 	 * 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
 	 */
-	typtype = ((Form_pg_type) GETSTRUCT(typeTup))->typtype;
+	typtype = baseType->typtype;
 	if (typtype != 'b')
 		elog(ERROR, "DefineDomain: %s is not a basetype",
 			 TypeNameToString(stmt->typename));
 
 	/* passed by value */
-	byValue = ((Form_pg_type) GETSTRUCT(typeTup))->typbyval;
+	byValue = baseType->typbyval;
 
 	/* Required Alignment */
-	alignment = ((Form_pg_type) GETSTRUCT(typeTup))->typalign;
+	alignment = baseType->typalign;
 
 	/* TOAST Strategy */
-	storage = ((Form_pg_type) GETSTRUCT(typeTup))->typstorage;
+	storage = baseType->typstorage;
 
 	/* Storage Length */
-	internalLength = ((Form_pg_type) GETSTRUCT(typeTup))->typlen;
+	internalLength = baseType->typlen;
 
 	/* External Length (unused) */
-	externalLength = ((Form_pg_type) GETSTRUCT(typeTup))->typprtlen;
+	externalLength = baseType->typprtlen;
 
 	/* Array element Delimiter */
-	delimiter = ((Form_pg_type) GETSTRUCT(typeTup))->typdelim;
+	delimiter = baseType->typdelim;
 
 	/* I/O Functions */
-	inputProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typinput;
-	outputProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typoutput;
-	receiveProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typreceive;
-	sendProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typsend;
+	inputProcedure = baseType->typinput;
+	outputProcedure = baseType->typoutput;
+	receiveProcedure = baseType->typreceive;
+	sendProcedure = baseType->typsend;
 
 	/* Inherited default value */
 	datum =	SysCacheGetAttr(TYPEOID, typeTup,
@@ -441,7 +447,7 @@ DefineDomain(CreateDomainStmt *stmt)
 	 *
 	 * This is what enables us to make a domain of an array
 	 */
-	basetypelem = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;
+	basetypelem = baseType->typelem;
 
 	/*
 	 * Run through constraints manually to avoid the additional
@@ -474,7 +480,7 @@ DefineDomain(CreateDomainStmt *stmt)
 				 * Note: Name is strictly for error message
 				 */
 				expr = cookDefault(pstate, colDef->raw_expr,
-								   typeTup->t_data->t_oid,
+								   basetypeoid,
 								   stmt->typename->typmod,
 								   domainName);
 				/*
@@ -540,7 +546,7 @@ DefineDomain(CreateDomainStmt *stmt)
 	 */
 	TypeCreate(domainName,			/* type name */
 			   domainNamespace,		/* namespace */
-			   InvalidOid,			/* preassigned type oid (not done here) */
+			   InvalidOid,			/* preassigned type oid (none here) */
 			   InvalidOid,			/* relation oid (n/a here) */
 			   internalLength,		/* internal size */
 			   externalLength,		/* external size */
@@ -551,7 +557,7 @@ DefineDomain(CreateDomainStmt *stmt)
 			   receiveProcedure,	/* receive procedure */
 			   sendProcedure,		/* send procedure */
 			   basetypelem,			/* element type ID */
-			   typeTup->t_data->t_oid,	/* base type ID */
+			   basetypeoid,			/* base type ID */
 			   defaultValue,		/* default type value (text) */
 			   defaultValueBin,		/* default type value (binary) */
 			   byValue,				/* passed by value */
@@ -571,19 +577,17 @@ DefineDomain(CreateDomainStmt *stmt)
 /*
  *	RemoveDomain
  *		Removes a domain.
+ *
+ * This is identical to RemoveType except we insist it be a domain.
  */
 void
 RemoveDomain(List *names, DropBehavior behavior)
 {
 	TypeName   *typename;
-	Relation	relation;
 	Oid			typeoid;
 	HeapTuple	tup;
 	char		typtype;
-
-	/* CASCADE unsupported */
-	if (behavior == DROP_CASCADE)
-		elog(ERROR, "DROP DOMAIN does not support the CASCADE keyword");
+	ObjectAddress object;
 
 	/* Make a TypeName so we can use standard type lookup machinery */
 	typename = makeNode(TypeName);
@@ -591,15 +595,17 @@ RemoveDomain(List *names, DropBehavior behavior)
 	typename->typmod = -1;
 	typename->arrayBounds = NIL;
 
-	relation = heap_openr(TypeRelationName, RowExclusiveLock);
-
-	typeoid = typenameTypeId(typename);
+	/* Use LookupTypeName here so that shell types can be removed. */
+	typeoid = LookupTypeName(typename);
+	if (!OidIsValid(typeoid))
+		elog(ERROR, "Type \"%s\" does not exist",
+			 TypeNameToString(typename));
 
 	tup = SearchSysCache(TYPEOID,
 						 ObjectIdGetDatum(typeoid),
 						 0, 0, 0);
 	if (!HeapTupleIsValid(tup))
-		elog(ERROR, "RemoveDomain: type '%s' does not exist",
+		elog(ERROR, "RemoveDomain: type \"%s\" does not exist",
 			 TypeNameToString(typename));
 
 	/* Permission check: must own type or its namespace */
@@ -615,17 +621,16 @@ RemoveDomain(List *names, DropBehavior behavior)
 		elog(ERROR, "%s is not a domain",
 			 TypeNameToString(typename));
 
-	/* Delete any comments associated with this type */
-	DeleteComments(typeoid, RelationGetRelid(relation));
-
-	/* Remove the type tuple from pg_type */
-	simple_heap_delete(relation, &tup->t_self);
-
 	ReleaseSysCache(tup);
 
-	/* At present, domains don't have associated array types */
+	/*
+	 * Do the deletion
+	 */
+	object.classId = RelOid_pg_type;
+	object.objectId = typeoid;
+	object.objectSubId = 0;
 
-	heap_close(relation, RowExclusiveLock);
+	performDeletion(&object, behavior);
 }
 
 
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index d27350fd4677d11b288ced85e3697b251f8aa674..519df157184960b1192f06be935e5db9e0393ae9 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -6,13 +6,14 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Id: view.c,v 1.65 2002/07/01 15:27:49 tgl Exp $
+ *	$Id: view.c,v 1.66 2002/07/12 18:43:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/xact.h"
+#include "catalog/dependency.h"
 #include "catalog/heap.h"
 #include "catalog/namespace.h"
 #include "commands/tablecmds.h"
@@ -252,16 +253,21 @@ DefineView(const RangeVar *view, Query *viewParse)
  * RemoveView
  *
  * Remove a view given its name
+ *
+ * We just have to drop the relation; the associated rules will be
+ * cleaned up automatically.
  */
 void
 RemoveView(const RangeVar *view, DropBehavior behavior)
 {
 	Oid			viewOid;
+	ObjectAddress object;
 
 	viewOid = RangeVarGetRelid(view, false);
-	/*
-	 * We just have to drop the relation; the associated rules will be
-	 * cleaned up automatically.
-	 */
-	heap_drop_with_catalog(viewOid, allowSystemTableMods);
+
+	object.classId = RelOid_pg_class;
+	object.objectId = viewOid;
+	object.objectSubId = 0;
+
+	performDeletion(&object, behavior);
 }
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 739161b17919f3f88318e7c11ccd4ee46e645198..4e568a3c531ba5daa9bbb13a6b55d631dfe51dd4 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.192 2002/07/01 15:27:51 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.193 2002/07/12 18:43:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1505,11 +1505,12 @@ _copyFkConstraint(FkConstraint *from)
 	Node_Copy(from, newnode, pktable);
 	Node_Copy(from, newnode, fk_attrs);
 	Node_Copy(from, newnode, pk_attrs);
-	if (from->match_type)
-		newnode->match_type = pstrdup(from->match_type);
-	newnode->actions = from->actions;
+	newnode->fk_matchtype = from->fk_matchtype;
+	newnode->fk_upd_action = from->fk_upd_action;
+	newnode->fk_del_action = from->fk_del_action;
 	newnode->deferrable = from->deferrable;
 	newnode->initdeferred = from->initdeferred;
+	newnode->skip_validation = from->skip_validation;
 
 	return newnode;
 }
@@ -2089,6 +2090,7 @@ _copyIndexStmt(IndexStmt *from)
 	Node_Copy(from, newnode, rangetable);
 	newnode->unique = from->unique;
 	newnode->primary = from->primary;
+	newnode->isconstraint = from->isconstraint;
 
 	return newnode;
 }
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 214493449b96c9ab678be81d0f2fb3ac5af84eaf..e15870b2c800b4f4fc4534317e51a59136a4e0bb 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -20,7 +20,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.139 2002/07/01 15:27:52 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.140 2002/07/12 18:43:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -912,6 +912,8 @@ _equalIndexStmt(IndexStmt *a, IndexStmt *b)
 		return false;
 	if (a->primary != b->primary)
 		return false;
+	if (a->isconstraint != b->isconstraint)
+		return false;
 
 	return true;
 }
@@ -1734,14 +1736,18 @@ _equalFkConstraint(FkConstraint *a, FkConstraint *b)
 		return false;
 	if (!equal(a->pk_attrs, b->pk_attrs))
 		return false;
-	if (!equalstr(a->match_type, b->match_type))
+	if (a->fk_matchtype != b->fk_matchtype)
 		return false;
-	if (a->actions != b->actions)
+	if (a->fk_upd_action != b->fk_upd_action)
+		return false;
+	if (a->fk_del_action != b->fk_del_action)
 		return false;
 	if (a->deferrable != b->deferrable)
 		return false;
 	if (a->initdeferred != b->initdeferred)
 		return false;
+	if (a->skip_validation != b->skip_validation)
+		return false;
 
 	return true;
 }
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 2b292635186a5e98b76939e396416dba5a9e37a8..ae3139a6ea65e06f396b25ff5958b90a3b25bd5d 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.161 2002/07/04 15:23:53 thomas Exp $
+ *	$Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.162 2002/07/12 18:43:16 tgl Exp $
  *
  * NOTES
  *	  Every (plan) node in POSTGRES has an associated "out" routine which
@@ -136,9 +136,10 @@ _outIndexStmt(StringInfo str, IndexStmt *node)
 	_outNode(str, node->whereClause);
 	appendStringInfo(str, " :rangetable ");
 	_outNode(str, node->rangetable);
-	appendStringInfo(str, " :unique %s :primary %s ",
+	appendStringInfo(str, " :unique %s :primary %s :isconstraint %s ",
 					 booltostr(node->unique),
-					 booltostr(node->primary));
+					 booltostr(node->primary),
+					 booltostr(node->isconstraint));
 }
 
 static void
@@ -1447,12 +1448,13 @@ _outFkConstraint(StringInfo str, FkConstraint *node)
 	_outNode(str, node->fk_attrs);
 	appendStringInfo(str, " :pk_attrs ");
 	_outNode(str, node->pk_attrs);
-	appendStringInfo(str, " :match_type ");
-	_outToken(str, node->match_type);
-	appendStringInfo(str, " :actions %d :deferrable %s :initdeferred %s",
-					 node->actions,
+	appendStringInfo(str, " :fk_matchtype %c :fk_upd_action %c :fk_del_action %c :deferrable %s :initdeferred %s :skip_validation %s",
+					 node->fk_matchtype,
+					 node->fk_upd_action,
+					 node->fk_del_action,
 					 booltostr(node->deferrable),
-					 booltostr(node->initdeferred));
+					 booltostr(node->initdeferred),
+					 booltostr(node->skip_validation));
 }
 
 static void
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index b1b94dc6fdacb85abe40dd2b06f5c61ae6b040e2..2fbca505987b7b84e164d526cdb9dd717cb14e0b 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.237 2002/06/20 20:29:31 momjian Exp $
+ *	$Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.238 2002/07/12 18:43:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,7 +47,7 @@
 /* State shared by transformCreateSchemaStmt and its subroutines */
 typedef struct
 {
-	const char *stmtType;		/* "CREATE TABLE" or "ALTER TABLE" */
+	const char *stmtType;		/* "CREATE SCHEMA" or "ALTER SCHEMA" */
 	char	   *schemaname;		/* name of schema */
 	char	   *authid;			/* owner of schema */
 	List	   *tables;			/* CREATE TABLE items */
@@ -1066,6 +1066,7 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
 					 cxt->stmtType, (cxt->relation)->relname);
 			cxt->pkey = index;
 		}
+		index->isconstraint = true;
 
 		if (constraint->name != NULL)
 			index->idxname = pstrdup(constraint->name);
@@ -1304,15 +1305,8 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
 static void
 transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
 {
-	CreateTrigStmt *fk_trigger;
 	List	   *fkactions = NIL;
 	List	   *fkclist;
-	List	   *fk_attr;
-	List	   *pk_attr;
-	Ident	   *id;
-	Oid			pktypoid[INDEX_MAX_KEYS];
-	Oid			fktypoid[INDEX_MAX_KEYS];
-	int			i;
 
 	if (cxt->fkconstraints == NIL)
 		return;
@@ -1323,15 +1317,12 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
 	foreach(fkclist, cxt->fkconstraints)
 	{
 		FkConstraint *fkconstraint = (FkConstraint *) lfirst(fkclist);
+		Oid			pktypoid[INDEX_MAX_KEYS];
+		Oid			fktypoid[INDEX_MAX_KEYS];
+		int			i;
 		int			attnum;
 		List	   *fkattrs;
 
-		/*
-		 * If the constraint has no name, set it to <unnamed>
-		 */
-		if (fkconstraint->constr_name == NULL)
-			fkconstraint->constr_name = "<unnamed>";
-
 		for (attnum = 0; attnum < INDEX_MAX_KEYS; attnum++)
 			pktypoid[attnum] = fktypoid[attnum] = InvalidOid;
 
@@ -1473,203 +1464,24 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
 		}
 
 		/*
-		 * Build a CREATE CONSTRAINT TRIGGER statement for the CHECK
-		 * action.
+		 * For ALTER TABLE ADD CONSTRAINT, we're done.  For CREATE TABLE,
+		 * gin up an ALTER TABLE ADD CONSTRAINT command to execute after
+		 * the basic CREATE TABLE is complete.
 		 */
-		fk_trigger = (CreateTrigStmt *) makeNode(CreateTrigStmt);
-		fk_trigger->trigname = fkconstraint->constr_name;
-		fk_trigger->relation = cxt->relation;
-		fk_trigger->funcname = SystemFuncName("RI_FKey_check_ins");
-		fk_trigger->before = false;
-		fk_trigger->row = true;
-		fk_trigger->actions[0] = 'i';
-		fk_trigger->actions[1] = 'u';
-		fk_trigger->actions[2] = '\0';
-		fk_trigger->lang = NULL;
-		fk_trigger->text = NULL;
-
-		fk_trigger->attr = NIL;
-		fk_trigger->when = NULL;
-		fk_trigger->isconstraint = true;
-		fk_trigger->deferrable = fkconstraint->deferrable;
-		fk_trigger->initdeferred = fkconstraint->initdeferred;
-		fk_trigger->constrrel = fkconstraint->pktable;
-
-		fk_trigger->args = NIL;
-		fk_trigger->args = lappend(fk_trigger->args,
-								   makeString(fkconstraint->constr_name));
-		fk_trigger->args = lappend(fk_trigger->args,
-								   makeString((cxt->relation)->relname));
-		fk_trigger->args = lappend(fk_trigger->args,
-								 makeString(fkconstraint->pktable->relname));
-		fk_trigger->args = lappend(fk_trigger->args,
-								   makeString(fkconstraint->match_type));
-		fk_attr = fkconstraint->fk_attrs;
-		pk_attr = fkconstraint->pk_attrs;
-		if (length(fk_attr) != length(pk_attr))
-			elog(ERROR, "number of key attributes in referenced table must be equal to foreign key"
-				 "\n\tIllegal FOREIGN KEY definition references \"%s\"",
-				 fkconstraint->pktable->relname);
-
-		while (fk_attr != NIL)
+		if (strcmp(cxt->stmtType, "CREATE TABLE") == 0)
 		{
-			id = (Ident *) lfirst(fk_attr);
-			fk_trigger->args = lappend(fk_trigger->args,
-									   makeString(id->name));
-
-			id = (Ident *) lfirst(pk_attr);
-			fk_trigger->args = lappend(fk_trigger->args,
-									   makeString(id->name));
+			AlterTableStmt *alterstmt = makeNode(AlterTableStmt);
 
-			fk_attr = lnext(fk_attr);
-			pk_attr = lnext(pk_attr);
-		}
+			alterstmt->subtype = 'c'; /* preprocessed add constraint */
+			alterstmt->relation = cxt->relation;
+			alterstmt->name = NULL;
+			alterstmt->def = (Node *) makeList1(fkconstraint);
 
-		fkactions = lappend(fkactions, (Node *) fk_trigger);
+			/* Don't need to scan the table contents in this case */
+			fkconstraint->skip_validation = true;
 
-		/*
-		 * Build a CREATE CONSTRAINT TRIGGER statement for the ON DELETE
-		 * action fired on the PK table !!!
-		 */
-		fk_trigger = (CreateTrigStmt *) makeNode(CreateTrigStmt);
-		fk_trigger->trigname = fkconstraint->constr_name;
-		fk_trigger->relation = fkconstraint->pktable;
-		fk_trigger->before = false;
-		fk_trigger->row = true;
-		fk_trigger->actions[0] = 'd';
-		fk_trigger->actions[1] = '\0';
-		fk_trigger->lang = NULL;
-		fk_trigger->text = NULL;
-
-		fk_trigger->attr = NIL;
-		fk_trigger->when = NULL;
-		fk_trigger->isconstraint = true;
-		fk_trigger->deferrable = fkconstraint->deferrable;
-		fk_trigger->initdeferred = fkconstraint->initdeferred;
-		fk_trigger->constrrel = cxt->relation;
-		switch ((fkconstraint->actions & FKCONSTR_ON_DELETE_MASK)
-				>> FKCONSTR_ON_DELETE_SHIFT)
-		{
-			case FKCONSTR_ON_KEY_NOACTION:
-				fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_del");
-				break;
-			case FKCONSTR_ON_KEY_RESTRICT:
-				fk_trigger->deferrable = false;
-				fk_trigger->initdeferred = false;
-				fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_del");
-				break;
-			case FKCONSTR_ON_KEY_CASCADE:
-				fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_del");
-				break;
-			case FKCONSTR_ON_KEY_SETNULL:
-				fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_del");
-				break;
-			case FKCONSTR_ON_KEY_SETDEFAULT:
-				fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_del");
-				break;
-			default:
-				elog(ERROR, "Only one ON DELETE action can be specified for FOREIGN KEY constraint");
-				break;
+			fkactions = lappend(fkactions, (Node *) alterstmt);
 		}
-
-		fk_trigger->args = NIL;
-		fk_trigger->args = lappend(fk_trigger->args,
-								   makeString(fkconstraint->constr_name));
-		fk_trigger->args = lappend(fk_trigger->args,
-								   makeString((cxt->relation)->relname));
-		fk_trigger->args = lappend(fk_trigger->args,
-								 makeString(fkconstraint->pktable->relname));
-		fk_trigger->args = lappend(fk_trigger->args,
-								   makeString(fkconstraint->match_type));
-		fk_attr = fkconstraint->fk_attrs;
-		pk_attr = fkconstraint->pk_attrs;
-		while (fk_attr != NIL)
-		{
-			id = (Ident *) lfirst(fk_attr);
-			fk_trigger->args = lappend(fk_trigger->args,
-									   makeString(id->name));
-
-			id = (Ident *) lfirst(pk_attr);
-			fk_trigger->args = lappend(fk_trigger->args,
-									   makeString(id->name));
-
-			fk_attr = lnext(fk_attr);
-			pk_attr = lnext(pk_attr);
-		}
-
-		fkactions = lappend(fkactions, (Node *) fk_trigger);
-
-		/*
-		 * Build a CREATE CONSTRAINT TRIGGER statement for the ON UPDATE
-		 * action fired on the PK table !!!
-		 */
-		fk_trigger = (CreateTrigStmt *) makeNode(CreateTrigStmt);
-		fk_trigger->trigname = fkconstraint->constr_name;
-		fk_trigger->relation = fkconstraint->pktable;
-		fk_trigger->before = false;
-		fk_trigger->row = true;
-		fk_trigger->actions[0] = 'u';
-		fk_trigger->actions[1] = '\0';
-		fk_trigger->lang = NULL;
-		fk_trigger->text = NULL;
-
-		fk_trigger->attr = NIL;
-		fk_trigger->when = NULL;
-		fk_trigger->isconstraint = true;
-		fk_trigger->deferrable = fkconstraint->deferrable;
-		fk_trigger->initdeferred = fkconstraint->initdeferred;
-		fk_trigger->constrrel = cxt->relation;
-		switch ((fkconstraint->actions & FKCONSTR_ON_UPDATE_MASK)
-				>> FKCONSTR_ON_UPDATE_SHIFT)
-		{
-			case FKCONSTR_ON_KEY_NOACTION:
-				fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_upd");
-				break;
-			case FKCONSTR_ON_KEY_RESTRICT:
-				fk_trigger->deferrable = false;
-				fk_trigger->initdeferred = false;
-				fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_upd");
-				break;
-			case FKCONSTR_ON_KEY_CASCADE:
-				fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_upd");
-				break;
-			case FKCONSTR_ON_KEY_SETNULL:
-				fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_upd");
-				break;
-			case FKCONSTR_ON_KEY_SETDEFAULT:
-				fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_upd");
-				break;
-			default:
-				elog(ERROR, "Only one ON UPDATE action can be specified for FOREIGN KEY constraint");
-				break;
-		}
-
-		fk_trigger->args = NIL;
-		fk_trigger->args = lappend(fk_trigger->args,
-								   makeString(fkconstraint->constr_name));
-		fk_trigger->args = lappend(fk_trigger->args,
-								   makeString((cxt->relation)->relname));
-		fk_trigger->args = lappend(fk_trigger->args,
-								 makeString(fkconstraint->pktable->relname));
-		fk_trigger->args = lappend(fk_trigger->args,
-								   makeString(fkconstraint->match_type));
-		fk_attr = fkconstraint->fk_attrs;
-		pk_attr = fkconstraint->pk_attrs;
-		while (fk_attr != NIL)
-		{
-			id = (Ident *) lfirst(fk_attr);
-			fk_trigger->args = lappend(fk_trigger->args,
-									   makeString(id->name));
-
-			id = (Ident *) lfirst(pk_attr);
-			fk_trigger->args = lappend(fk_trigger->args,
-									   makeString(id->name));
-
-			fk_attr = lnext(fk_attr);
-			pk_attr = lnext(pk_attr);
-		}
-
-		fkactions = lappend(fkactions, (Node *) fk_trigger);
 	}
 
 	/*
@@ -2642,6 +2454,14 @@ transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt,
 			*extras_after = nconc(cxt.alist, *extras_after);
 			break;
 
+		case 'c':
+			/*
+			 * Already-transformed ADD CONSTRAINT, so just make it look
+			 * like the standard case.
+			 */
+			stmt->subtype = 'C';
+			break;
+
 		default:
 			break;
 	}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 18b349c4ee2f211cc18ba29813ec7f12113fba28..17128a814e534411613e99244e9d411ad4334c4a 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.338 2002/07/11 07:39:25 ishii Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.339 2002/07/12 18:43:17 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -309,8 +309,7 @@ static void doNegateFloat(Value *v);
 %type <node>	TableConstraint, TableLikeClause
 %type <list>	ColQualList
 %type <node>	ColConstraint, ColConstraintElem, ConstraintAttr
-%type <ival>	key_actions, key_delete, key_update, key_reference
-%type <str>		key_match
+%type <ival>	key_actions, key_delete, key_match, key_update, key_action
 %type <ival>	ConstraintAttributeSpec, ConstraintDeferrabilitySpec,
 				ConstraintTimeSpec
 
@@ -1594,8 +1593,9 @@ ColConstraintElem:
 					n->pktable			= $2;
 					n->fk_attrs			= NIL;
 					n->pk_attrs			= $3;
-					n->match_type		= $4;
-					n->actions			= $5;
+					n->fk_matchtype		= $4;
+					n->fk_upd_action	= (char) ($5 >> 8);
+					n->fk_del_action	= (char) ($5 & 0xFF);
 					n->deferrable		= FALSE;
 					n->initdeferred		= FALSE;
 					$$ = (Node *)n;
@@ -1714,16 +1714,16 @@ ConstraintElem:
 					$$ = (Node *)n;
 				}
 			| FOREIGN KEY '(' columnList ')' REFERENCES qualified_name
-			opt_column_list
-				key_match key_actions ConstraintAttributeSpec
+				opt_column_list key_match key_actions ConstraintAttributeSpec
 				{
 					FkConstraint *n = makeNode(FkConstraint);
 					n->constr_name		= NULL;
 					n->pktable			= $7;
 					n->fk_attrs			= $4;
 					n->pk_attrs			= $8;
-					n->match_type		= $9;
-					n->actions			= $10;
+					n->fk_matchtype		= $9;
+					n->fk_upd_action	= (char) ($10 >> 8);
+					n->fk_del_action	= (char) ($10 & 0xFF);
 					n->deferrable		= ($11 & 1) != 0;
 					n->initdeferred		= ($11 & 2) != 0;
 					$$ = (Node *)n;
@@ -1750,45 +1750,54 @@ columnElem: ColId
 
 key_match:  MATCH FULL
 			{
-				$$ = "FULL";
+				$$ = FKCONSTR_MATCH_FULL;
 			}
 		| MATCH PARTIAL
 			{
 				elog(ERROR, "FOREIGN KEY/MATCH PARTIAL not yet implemented");
-				$$ = "PARTIAL";
+				$$ = FKCONSTR_MATCH_PARTIAL;
 			}
 		| MATCH SIMPLE
 			{
-				$$ = "UNSPECIFIED";
+				$$ = FKCONSTR_MATCH_UNSPECIFIED;
 			}
 		| /*EMPTY*/
 			{
-				$$ = "UNSPECIFIED";
+				$$ = FKCONSTR_MATCH_UNSPECIFIED;
 			}
 		;
 
+/*
+ * We combine the update and delete actions into one value temporarily
+ * for simplicity of parsing, and then break them down again in the
+ * calling production.  update is in the left 8 bits, delete in the right.
+ * Note that NOACTION is the default.
+ */
 key_actions:
-			key_delete								{ $$ = $1; }
-			| key_update							{ $$ = $1; }
-			| key_delete key_update					{ $$ = $1 | $2; }
-			| key_update key_delete					{ $$ = $1 | $2; }
-			| /*EMPTY*/								{ $$ = 0; }
+			key_update
+				{ $$ = ($1 << 8) | (FKCONSTR_ACTION_NOACTION & 0xFF); }
+			| key_delete
+				{ $$ = (FKCONSTR_ACTION_NOACTION << 8) | ($1 & 0xFF); }
+			| key_update key_delete
+				{ $$ = ($1 << 8) | ($2 & 0xFF); }
+			| key_delete key_update
+				{ $$ = ($2 << 8) | ($1 & 0xFF); }
+			| /*EMPTY*/
+				{ $$ = (FKCONSTR_ACTION_NOACTION << 8) | (FKCONSTR_ACTION_NOACTION & 0xFF); }
 		;
 
-key_delete: ON DELETE_P key_reference
-								{ $$ = $3 << FKCONSTR_ON_DELETE_SHIFT; }
+key_update: ON UPDATE key_action		{ $$ = $3; }
 		;
 
-key_update: ON UPDATE key_reference
-								{ $$ = $3 << FKCONSTR_ON_UPDATE_SHIFT; }
+key_delete: ON DELETE_P key_action		{ $$ = $3; }
 		;
 
-key_reference:
-			NO ACTION					{ $$ = FKCONSTR_ON_KEY_NOACTION; }
-			| RESTRICT					{ $$ = FKCONSTR_ON_KEY_RESTRICT; }
-			| CASCADE					{ $$ = FKCONSTR_ON_KEY_CASCADE; }
-			| SET NULL_P				{ $$ = FKCONSTR_ON_KEY_SETNULL; }
-			| SET DEFAULT				{ $$ = FKCONSTR_ON_KEY_SETDEFAULT; }
+key_action:
+			NO ACTION					{ $$ = FKCONSTR_ACTION_NOACTION; }
+			| RESTRICT					{ $$ = FKCONSTR_ACTION_RESTRICT; }
+			| CASCADE					{ $$ = FKCONSTR_ACTION_CASCADE; }
+			| SET NULL_P				{ $$ = FKCONSTR_ACTION_SETNULL; }
+			| SET DEFAULT				{ $$ = FKCONSTR_ACTION_SETDEFAULT; }
 		;
 
 OptInherit: INHERITS '(' qualified_name_list ')'	{ $$ = $3; }
@@ -2300,7 +2309,7 @@ drop_type:	TABLE									{ $$ = DROP_TABLE; }
 			| INDEX									{ $$ = DROP_INDEX; }
 			| TYPE_P								{ $$ = DROP_TYPE; }
 			| DOMAIN_P								{ $$ = DROP_DOMAIN; }
-			| CONVERSION_P								{ $$ = DROP_CONVERSION; }
+			| CONVERSION_P							{ $$ = DROP_CONVERSION; }
 		;
 
 any_name_list:
@@ -6673,6 +6682,7 @@ unreserved_keyword:
 			| COMMIT
 			| COMMITTED
 			| CONSTRAINTS
+			| CONVERSION_P
 			| COPY
 			| CREATEDB
 			| CREATEUSER
@@ -6857,6 +6867,7 @@ col_name_keyword:
 			| SUBSTRING
 			| TIME
 			| TIMESTAMP
+			| TREAT
 			| TRIM
 			| VARCHAR
 		;
@@ -6963,7 +6974,6 @@ reserved_keyword:
 			| THEN
 			| TO
 			| TRAILING
-			| TREAT
 			| TRUE_P
 			| UNION
 			| UNIQUE
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 43f8ffd6f1f8f1bb5cf5cb1d569cd4c2e05caecd..5922cb4ab5b67ff1766ab780aaf0b740fc068924 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.73 2002/06/20 20:29:33 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.74 2002/07/12 18:43:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,6 +16,7 @@
 
 #include "access/heapam.h"
 #include "catalog/catname.h"
+#include "catalog/dependency.h"
 #include "catalog/indexing.h"
 #include "catalog/pg_rewrite.h"
 #include "commands/view.h"
@@ -57,6 +58,8 @@ InsertRule(char *rulname,
 	TupleDesc	tupDesc;
 	HeapTuple	tup;
 	Oid			rewriteObjectId;
+	ObjectAddress	myself,
+					referenced;
 
 	if (IsDefinedRewriteRule(eventrel_oid, rulname))
 		elog(ERROR, "Attempt to insert rule \"%s\" failed: already exists",
@@ -103,6 +106,23 @@ InsertRule(char *rulname,
 
 	heap_freetuple(tup);
 
+	/*
+	 * Install dependency on rule's relation to ensure it will go away
+	 * on relation deletion.  If the rule is ON SELECT, make the dependency
+	 * implicit --- this prevents deleting a view's SELECT rule.  Other
+	 * kinds of rules can be AUTO.
+	 */
+	myself.classId = RelationGetRelid(pg_rewrite_desc);
+	myself.objectId = rewriteObjectId;
+	myself.objectSubId = 0;
+
+	referenced.classId = RelOid_pg_class;
+	referenced.objectId = eventrel_oid;
+	referenced.objectSubId = 0;
+
+	recordDependencyOn(&myself, &referenced,
+		(evtype == CMD_SELECT) ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
+
 	heap_close(pg_rewrite_desc, RowExclusiveLock);
 
 	return rewriteObjectId;
diff --git a/src/backend/rewrite/rewriteRemove.c b/src/backend/rewrite/rewriteRemove.c
index 71fd4d5ac407c7bd9ad0f112442393d86cda86b8..4ce9f3f2b908aa605648cf31746ae57404eaf0ed 100644
--- a/src/backend/rewrite/rewriteRemove.c
+++ b/src/backend/rewrite/rewriteRemove.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.50 2002/06/20 20:29:34 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.51 2002/07/12 18:43:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,14 +17,15 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "catalog/catname.h"
+#include "catalog/dependency.h"
 #include "catalog/indexing.h"
 #include "catalog/pg_rewrite.h"
-#include "commands/comment.h"
 #include "miscadmin.h"
 #include "rewrite/rewriteRemove.h"
 #include "rewrite/rewriteSupport.h"
 #include "utils/acl.h"
 #include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
 
@@ -34,77 +35,102 @@
  * Delete a rule given its name.
  */
 void
-RemoveRewriteRule(Oid owningRel, const char *ruleName)
+RemoveRewriteRule(Oid owningRel, const char *ruleName, DropBehavior behavior)
 {
-	Relation	RewriteRelation;
-	Relation	event_relation;
 	HeapTuple	tuple;
-	Oid			ruleId;
 	Oid			eventRelationOid;
-	bool		hasMoreRules;
 	AclResult	aclresult;
-
-	/*
-	 * Open the pg_rewrite relation.
-	 */
-	RewriteRelation = heap_openr(RewriteRelationName, RowExclusiveLock);
+	ObjectAddress object;
 
 	/*
 	 * Find the tuple for the target rule.
 	 */
-	tuple = SearchSysCacheCopy(RULERELNAME,
-							   ObjectIdGetDatum(owningRel),
-							   PointerGetDatum(ruleName),
-							   0, 0);
+	tuple = SearchSysCache(RULERELNAME,
+						   ObjectIdGetDatum(owningRel),
+						   PointerGetDatum(ruleName),
+						   0, 0);
 
 	/*
-	 * complain if no rule with such name existed
+	 * complain if no rule with such name exists
 	 */
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "Rule \"%s\" not found", ruleName);
 
 	/*
-	 * Save the OID of the rule (i.e. the tuple's OID) and the event
-	 * relation's OID
+	 * Verify user has appropriate permissions.
 	 */
-	ruleId = tuple->t_data->t_oid;
 	eventRelationOid = ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_class;
 	Assert(eventRelationOid == owningRel);
+	aclresult = pg_class_aclcheck(eventRelationOid, GetUserId(), ACL_RULE);
+	if (aclresult != ACLCHECK_OK)
+		aclcheck_error(aclresult, get_rel_name(eventRelationOid));
 
 	/*
-	 * We had better grab AccessExclusiveLock so that we know no other
-	 * rule additions/deletions are going on for this relation.  Else we
-	 * cannot set relhasrules correctly.  Besides, we don't want to be
-	 * changing the ruleset while queries are executing on the rel.
+	 * Do the deletion
 	 */
-	event_relation = heap_open(eventRelationOid, AccessExclusiveLock);
+	object.classId = get_system_catalog_relid(RewriteRelationName);
+	object.objectId = tuple->t_data->t_oid;
+	object.objectSubId = 0;
+
+	ReleaseSysCache(tuple);
+
+	performDeletion(&object, behavior);
+}
+
+
+/*
+ * Guts of rule deletion.
+ */
+void
+RemoveRewriteRuleById(Oid ruleOid)
+{
+	Relation	RewriteRelation;
+	ScanKeyData		skey[1];
+	SysScanDesc		rcscan;
+	Relation	event_relation;
+	HeapTuple	tuple;
+	Oid			eventRelationOid;
+	bool		hasMoreRules;
 
 	/*
-	 * Verify user has appropriate permissions.
+	 * Open the pg_rewrite relation.
 	 */
-	aclresult = pg_class_aclcheck(eventRelationOid, GetUserId(), ACL_RULE);
-	if (aclresult != ACLCHECK_OK)
-		aclcheck_error(aclresult, RelationGetRelationName(event_relation));
+	RewriteRelation = heap_openr(RewriteRelationName, RowExclusiveLock);
+
+	/*
+	 * Find the tuple for the target rule.
+	 */
+	ScanKeyEntryInitialize(&skey[0], 0x0,
+						   ObjectIdAttributeNumber, F_OIDEQ,
+						   ObjectIdGetDatum(ruleOid));
 
-	/* do not allow the removal of a view's SELECT rule */
-	if (event_relation->rd_rel->relkind == RELKIND_VIEW &&
-		((Form_pg_rewrite) GETSTRUCT(tuple))->ev_type == '1')
-		elog(ERROR, "Cannot remove a view's SELECT rule");
+	rcscan = systable_beginscan(RewriteRelation, RewriteOidIndex, true,
+								SnapshotNow, 1, skey);
 
-	hasMoreRules = event_relation->rd_rules != NULL &&
-		event_relation->rd_rules->numLocks > 1;
+	tuple = systable_getnext(rcscan);
+
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "RemoveRewriteRuleById: Rule %u does not exist",
+			 ruleOid);
 
 	/*
-	 * Delete any comments associated with this rule
+	 * We had better grab AccessExclusiveLock so that we know no other
+	 * rule additions/deletions are going on for this relation.  Else we
+	 * cannot set relhasrules correctly.  Besides, we don't want to be
+	 * changing the ruleset while queries are executing on the rel.
 	 */
-	DeleteComments(ruleId, RelationGetRelid(RewriteRelation));
+	eventRelationOid = ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_class;
+	event_relation = heap_open(eventRelationOid, AccessExclusiveLock);
+
+	hasMoreRules = event_relation->rd_rules != NULL &&
+		event_relation->rd_rules->numLocks > 1;
 
 	/*
 	 * Now delete the pg_rewrite tuple for the rule
 	 */
 	simple_heap_delete(RewriteRelation, &tuple->t_self);
 
-	heap_freetuple(tuple);
+	systable_endscan(rcscan);
 
 	heap_close(RewriteRelation, RowExclusiveLock);
 
@@ -120,49 +146,3 @@ RemoveRewriteRule(Oid owningRel, const char *ruleName)
 	/* Close rel, but keep lock till commit... */
 	heap_close(event_relation, NoLock);
 }
-
-/*
- * RelationRemoveRules -
- *	  removes all rules associated with the relation when the relation is
- *	  being removed.
- */
-void
-RelationRemoveRules(Oid relid)
-{
-	Relation	RewriteRelation;
-	SysScanDesc scanDesc;
-	ScanKeyData scanKeyData;
-	HeapTuple	tuple;
-
-	/*
-	 * Open the pg_rewrite relation.
-	 */
-	RewriteRelation = heap_openr(RewriteRelationName, RowExclusiveLock);
-
-	/*
-	 * Scan pg_rewrite for all the tuples that have the same ev_class
-	 * as relid (the relation to be removed).
-	 */
-	ScanKeyEntryInitialize(&scanKeyData,
-						   0,
-						   Anum_pg_rewrite_ev_class,
-						   F_OIDEQ,
-						   ObjectIdGetDatum(relid));
-
-	scanDesc = systable_beginscan(RewriteRelation,
-								  RewriteRelRulenameIndex,
-								  true, SnapshotNow,
-								  1, &scanKeyData);
-
-	while (HeapTupleIsValid(tuple = systable_getnext(scanDesc)))
-	{
-		/* Delete any comments associated with this rule */
-		DeleteComments(tuple->t_data->t_oid, RelationGetRelid(RewriteRelation));
-
-		simple_heap_delete(RewriteRelation, &tuple->t_self);
-	}
-
-	systable_endscan(scanDesc);
-
-	heap_close(RewriteRelation, RowExclusiveLock);
-}
diff --git a/src/backend/rewrite/rewriteSupport.c b/src/backend/rewrite/rewriteSupport.c
index ba590b8cc6693a856f684b4c73b1aace2f46b343..3f4c7f23871962a7b587a40982d0f784a7f5fe75 100644
--- a/src/backend/rewrite/rewriteSupport.c
+++ b/src/backend/rewrite/rewriteSupport.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.52 2002/06/20 20:29:34 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.53 2002/07/12 18:43:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,7 @@
 #include "catalog/catname.h"
 #include "catalog/indexing.h"
 #include "rewrite/rewriteSupport.h"
+#include "utils/inval.h"
 #include "utils/syscache.h"
 
 
@@ -44,9 +45,8 @@ IsDefinedRewriteRule(Oid owningRel, const char *ruleName)
  * NOTE: an important side-effect of this operation is that an SI invalidation
  * message is sent out to all backends --- including me --- causing relcache
  * entries to be flushed or updated with the new set of rules for the table.
- * Therefore, we execute the update even if relhasrules has the right value
- * already.  Possible future improvement: skip the disk update and just send
- * an SI message in that case.
+ * This must happen even if we find that no change is needed in the pg_class
+ * row.
  */
 void
 SetRelationRuleStatus(Oid relationId, bool relHasRules,
@@ -54,6 +54,7 @@ SetRelationRuleStatus(Oid relationId, bool relHasRules,
 {
 	Relation	relationRelation;
 	HeapTuple	tuple;
+	Form_pg_class classForm;
 	Relation	idescs[Num_pg_class_indices];
 
 	/*
@@ -66,18 +67,28 @@ SetRelationRuleStatus(Oid relationId, bool relHasRules,
 							   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "SetRelationRuleStatus: cache lookup failed for relation %u", relationId);
+	classForm = (Form_pg_class) GETSTRUCT(tuple);
 
-	/* Do the update */
-	((Form_pg_class) GETSTRUCT(tuple))->relhasrules = relHasRules;
-	if (relIsBecomingView)
-		((Form_pg_class) GETSTRUCT(tuple))->relkind = RELKIND_VIEW;
+	if (classForm->relhasrules != relHasRules ||
+		(relIsBecomingView && classForm->relkind != RELKIND_VIEW))
+	{
+		/* Do the update */
+		classForm->relhasrules = relHasRules;
+		if (relIsBecomingView)
+			classForm->relkind = RELKIND_VIEW;
 
-	simple_heap_update(relationRelation, &tuple->t_self, tuple);
+		simple_heap_update(relationRelation, &tuple->t_self, tuple);
 
-	/* Keep the catalog indices up to date */
-	CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
-	CatalogIndexInsert(idescs, Num_pg_class_indices, relationRelation, tuple);
-	CatalogCloseIndices(Num_pg_class_indices, idescs);
+		/* Keep the catalog indices up to date */
+		CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
+		CatalogIndexInsert(idescs, Num_pg_class_indices, relationRelation, tuple);
+		CatalogCloseIndices(Num_pg_class_indices, idescs);
+	}
+	else
+	{
+		/* no need to change tuple, but force relcache rebuild anyway */
+		CacheInvalidateRelcache(relationId);
+	}
 
 	heap_freetuple(tuple);
 	heap_close(relationRelation, RowExclusiveLock);
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index e5e57d4a6de8ce8f6685ba12e242a283f0e9af22..8637394366703bee1a5a7d8459c90f832eeda8b7 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.161 2002/07/11 07:39:26 ishii Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.162 2002/07/12 18:43:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -582,6 +582,7 @@ ProcessUtility(Node *parsetree,
 							stmt->indexParams,			/* parameters */
 							stmt->unique,
 							stmt->primary,
+							stmt->isconstraint,
 							(Expr *) stmt->whereClause,
 							stmt->rangetable);
 			}
@@ -596,19 +597,11 @@ ProcessUtility(Node *parsetree,
 			break;
 
 		case T_RemoveAggrStmt:
-			{
-				RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;
-
-				RemoveAggregate(stmt->aggname, stmt->aggtype);
-			}
+			RemoveAggregate((RemoveAggrStmt *) parsetree);
 			break;
 
 		case T_RemoveFuncStmt:
-			{
-				RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
-
-				RemoveFunction(stmt->funcname, stmt->args);
-			}
+			RemoveFunction((RemoveFuncStmt *) parsetree);
 			break;
 
 		case T_RemoveOperStmt:
@@ -719,7 +712,7 @@ ProcessUtility(Node *parsetree,
 			break;
 
 		case T_CreateTrigStmt:
-			CreateTrigger((CreateTrigStmt *) parsetree);
+			CreateTrigger((CreateTrigStmt *) parsetree, false);
 			break;
 
 		case T_DropPropertyStmt:
@@ -733,11 +726,13 @@ ProcessUtility(Node *parsetree,
 				{
 					case DROP_RULE:
 						/* RemoveRewriteRule checks permissions */
-						RemoveRewriteRule(relId, stmt->property);
+						RemoveRewriteRule(relId, stmt->property,
+										  stmt->behavior);
 						break;
 					case DROP_TRIGGER:
 						/* DropTrigger checks permissions */
-						DropTrigger(relId, stmt->property);
+						DropTrigger(relId, stmt->property,
+									stmt->behavior);
 						break;
 				}
 			}
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 5063225afce29cd00eaad96f08248726d850d54c..e383ab892d1420b8b695dd1f26a75c3adf252063 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.75 2002/07/06 20:16:36 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.76 2002/07/12 18:43:18 tgl Exp $
  *
  * NOTES
  *	  Eventually, the index information should go through here, too.
@@ -671,6 +671,25 @@ get_relname_relid(const char *relname, Oid relnamespace)
 						  0, 0);
 }
 
+/*
+ * get_system_catalog_relid
+ *		Get the OID of a system catalog identified by name.
+ */
+Oid
+get_system_catalog_relid(const char *catname)
+{
+	Oid		relid;
+
+	relid = GetSysCacheOid(RELNAMENSP,
+						   PointerGetDatum(catname),
+						   ObjectIdGetDatum(PG_CATALOG_NAMESPACE),
+						   0, 0);
+	if (!OidIsValid(relid))
+		elog(ERROR, "get_system_catalog_relid: cannot find %s", catname);
+
+	return relid;
+}
+
 #ifdef NOT_USED
 /*
  * get_relnatts
@@ -1060,7 +1079,7 @@ getBaseType(Oid typid)
 /*
  * getBaseTypeTypeMod
  *		If the given type is a domain, return its base type;
- *		otherwise return the type's own OID.
+ *		otherwise return the type's own OID.  Also return base typmod.
  */
 Oid
 getBaseTypeTypeMod(Oid typid, int32 *typmod)
@@ -1077,7 +1096,7 @@ getBaseTypeTypeMod(Oid typid, int32 *typmod)
 							 ObjectIdGetDatum(typid),
 							 0, 0, 0);
 		if (!HeapTupleIsValid(tup))
-			elog(ERROR, "getBaseType: failed to lookup type %u", typid);
+			elog(ERROR, "getBaseTypeTypeMod: failed to lookup type %u", typid);
 		typTup = (Form_pg_type) GETSTRUCT(tup);
 		if (typTup->typtype != 'd')
 		{
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index ec70be31b6742e9387ed35e07e982c9a5131e09f..9714f4ba3aa7ea4596c6446d8d27075f6b6c2737 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.165 2002/06/20 20:29:39 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.166 2002/07/12 18:43:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -43,11 +43,11 @@
 #include "catalog/pg_amproc.h"
 #include "catalog/pg_attrdef.h"
 #include "catalog/pg_attribute.h"
+#include "catalog/pg_constraint.h"
 #include "catalog/pg_index.h"
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_proc.h"
-#include "catalog/pg_relcheck.h"
 #include "catalog/pg_rewrite.h"
 #include "catalog/pg_type.h"
 #include "commands/trigger.h"
@@ -296,7 +296,7 @@ static void RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
 static Relation RelationBuildDesc(RelationBuildDescInfo buildinfo,
 				  Relation oldrelation);
 static void AttrDefaultFetch(Relation relation);
-static void RelCheckFetch(Relation relation);
+static void CheckConstraintFetch(Relation relation);
 static List *insert_ordered_oid(List *list, Oid datum);
 static void IndexSupportInitialize(Form_pg_index iform,
 								   IndexStrategy indexStrategy,
@@ -451,7 +451,7 @@ AllocateRelationDesc(Relation relation, Form_pg_class relp)
  *		RelationBuildTupleDesc
  *
  *		Form the relation's tuple descriptor from information in
- *		the pg_attribute, pg_attrdef & pg_relcheck system catalogs.
+ *		the pg_attribute, pg_attrdef & pg_constraint system catalogs.
  */
 static void
 RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
@@ -603,7 +603,7 @@ RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
 				MemoryContextAlloc(CacheMemoryContext,
 								constr->num_check * sizeof(ConstrCheck));
 			MemSet(constr->check, 0, constr->num_check * sizeof(ConstrCheck));
-			RelCheckFetch(relation);
+			CheckConstraintFetch(relation);
 		}
 		else
 			constr->num_check = 0;
@@ -2483,62 +2483,60 @@ AttrDefaultFetch(Relation relation)
 }
 
 static void
-RelCheckFetch(Relation relation)
+CheckConstraintFetch(Relation relation)
 {
 	ConstrCheck *check = relation->rd_att->constr->check;
 	int			ncheck = relation->rd_att->constr->num_check;
-	Relation	rcrel;
-	SysScanDesc rcscan;
-	ScanKeyData skey;
+	Relation	conrel;
+	SysScanDesc conscan;
+	ScanKeyData skey[1];
 	HeapTuple	htup;
-	Name		rcname;
 	Datum		val;
 	bool		isnull;
-	int			found;
+	int			found = 0;
 
-	ScanKeyEntryInitialize(&skey,
-						   (bits16) 0x0,
-						   (AttrNumber) Anum_pg_relcheck_rcrelid,
-						   (RegProcedure) F_OIDEQ,
+	ScanKeyEntryInitialize(&skey[0], 0x0,
+						   Anum_pg_constraint_conrelid, F_OIDEQ,
 						   ObjectIdGetDatum(RelationGetRelid(relation)));
 
-	rcrel = heap_openr(RelCheckRelationName, AccessShareLock);
-	rcscan = systable_beginscan(rcrel, RelCheckIndex, true,
-								SnapshotNow,
-								1, &skey);
-	found = 0;
+	conrel = heap_openr(ConstraintRelationName, AccessShareLock);
+	conscan = systable_beginscan(conrel, ConstraintRelidIndex, true,
+								 SnapshotNow, 1, skey);
 
-	while (HeapTupleIsValid(htup = systable_getnext(rcscan)))
+	while (HeapTupleIsValid(htup = systable_getnext(conscan)))
 	{
+		Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(htup);
+
+		/* We want check constraints only */
+		if (conform->contype != CONSTRAINT_CHECK)
+			continue;
+
 		if (found == ncheck)
-			elog(ERROR, "RelCheckFetch: unexpected record found for rel %s",
+			elog(ERROR, "CheckConstraintFetch: unexpected record found for rel %s",
 				 RelationGetRelationName(relation));
 
-		rcname = (Name) fastgetattr(htup,
-									Anum_pg_relcheck_rcname,
-									rcrel->rd_att, &isnull);
-		if (isnull)
-			elog(ERROR, "RelCheckFetch: rcname IS NULL for rel %s",
-				 RelationGetRelationName(relation));
 		check[found].ccname = MemoryContextStrdup(CacheMemoryContext,
-												  NameStr(*rcname));
+												  NameStr(conform->conname));
+
+		/* Grab and test conbin is actually set */
 		val = fastgetattr(htup,
-						  Anum_pg_relcheck_rcbin,
-						  rcrel->rd_att, &isnull);
+						  Anum_pg_constraint_conbin,
+						  conrel->rd_att, &isnull);
 		if (isnull)
-			elog(ERROR, "RelCheckFetch: rcbin IS NULL for rel %s",
+			elog(ERROR, "CheckConstraintFetch: conbin IS NULL for rel %s",
 				 RelationGetRelationName(relation));
+
 		check[found].ccbin = MemoryContextStrdup(CacheMemoryContext,
 							 DatumGetCString(DirectFunctionCall1(textout,
 																 val)));
 		found++;
 	}
 
-	systable_endscan(rcscan);
-	heap_close(rcrel, AccessShareLock);
+	systable_endscan(conscan);
+	heap_close(conrel, AccessShareLock);
 
 	if (found != ncheck)
-		elog(ERROR, "RelCheckFetch: %d record(s) not found for rel %s",
+		elog(ERROR, "CheckConstraintFetch: %d record(s) not found for rel %s",
 			 ncheck - found, RelationGetRelationName(relation));
 }
 
diff --git a/src/bin/initdb/initdb.sh b/src/bin/initdb/initdb.sh
index 3e7ccceae9c2fb43ecdb221826bb325f2e10a103..144dad4dbab9ac19a129ee999d904886263f144c 100644
--- a/src/bin/initdb/initdb.sh
+++ b/src/bin/initdb/initdb.sh
@@ -27,7 +27,7 @@
 # Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
 # Portions Copyright (c) 1994, Regents of the University of California
 #
-# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.156 2002/06/20 20:29:41 momjian Exp $
+# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.157 2002/07/12 18:43:18 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -682,11 +682,11 @@ $ECHO_N "enabling unlimited row size for system tables... "$ECHO_C
 
 "$PGPATH"/postgres $PGSQL_OPT template1 >/dev/null <<EOF
 ALTER TABLE pg_attrdef CREATE TOAST TABLE;
+ALTER TABLE pg_constraint CREATE TOAST TABLE;
 ALTER TABLE pg_database CREATE TOAST TABLE;
 ALTER TABLE pg_description CREATE TOAST TABLE;
 ALTER TABLE pg_group CREATE TOAST TABLE;
 ALTER TABLE pg_proc CREATE TOAST TABLE;
-ALTER TABLE pg_relcheck CREATE TOAST TABLE;
 ALTER TABLE pg_rewrite CREATE TOAST TABLE;
 ALTER TABLE pg_shadow CREATE TOAST TABLE;
 ALTER TABLE pg_statistic CREATE TOAST TABLE;
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 01ec480e3f1089cd6bf5532a555ac1fa98343611..dd6aad5503df8dc10e0a2d7ac30d14baf9eafff4 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -22,7 +22,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.270 2002/07/04 15:35:07 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.271 2002/07/12 18:43:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -4656,8 +4656,8 @@ dumpOneTable(Archive *fout, TableInfo *tbinfo, TableInfo *g_tblinfo)
 		if (tbinfo->ncheck > 0)
 		{
 			PGresult   *res2;
-			int			i_rcname,
-						i_rcsrc;
+			int			i_conname,
+						i_consrc;
 			int			ntups2;
 
 			if (g_verbose)
@@ -4666,24 +4666,25 @@ dumpOneTable(Archive *fout, TableInfo *tbinfo, TableInfo *g_tblinfo)
 
 			resetPQExpBuffer(query);
 			if (g_fout->remoteVersion >= 70300)
-				appendPQExpBuffer(query, "SELECT rcname, rcsrc"
-								  " from pg_catalog.pg_relcheck c1"
-								  " where rcrelid = '%s'::pg_catalog.oid "
+				appendPQExpBuffer(query, "SELECT conname, consrc"
+								  " from pg_catalog.pg_constraint c1"
+								  " where conrelid = '%s'::pg_catalog.oid "
+								  "   and contype = 'c' "
 								  "   and not exists "
 								  "  (select 1 from "
-								  "    pg_catalog.pg_relcheck c2, "
+								  "    pg_catalog.pg_constraint c2, "
 								  "    pg_catalog.pg_inherits i "
-								  "    where i.inhrelid = c1.rcrelid "
-								  "      and (c2.rcname = c1.rcname "
-								  "          or (c2.rcname[0] = '$' "
-								  "              and c1.rcname[0] = '$')"
+								  "    where i.inhrelid = c1.conrelid "
+								  "      and (c2.conname = c1.conname "
+								  "          or (c2.conname[0] = '$' "
+								  "              and c1.conname[0] = '$')"
 								  "          )"
-								  "      and c2.rcsrc = c1.rcsrc "
-								  "      and c2.rcrelid = i.inhparent) "
-								  " order by rcname ",
+								  "      and c2.consrc = c1.consrc "
+								  "      and c2.conrelid = i.inhparent) "
+								  " order by conname ",
 								  tbinfo->oid);
 			else
-				appendPQExpBuffer(query, "SELECT rcname, rcsrc"
+				appendPQExpBuffer(query, "SELECT rcname as conname, rcsrc as consrc"
 								  " from pg_relcheck c1"
 								  " where rcrelid = '%s'::oid "
 								  "   and not exists "
@@ -4714,13 +4715,13 @@ dumpOneTable(Archive *fout, TableInfo *tbinfo, TableInfo *g_tblinfo)
 				exit_nicely();
 			}
 
-			i_rcname = PQfnumber(res2, "rcname");
-			i_rcsrc = PQfnumber(res2, "rcsrc");
+			i_conname = PQfnumber(res2, "conname");
+			i_consrc = PQfnumber(res2, "consrc");
 
 			for (j = 0; j < ntups2; j++)
 			{
-				const char *name = PQgetvalue(res2, j, i_rcname);
-				const char *expr = PQgetvalue(res2, j, i_rcsrc);
+				const char *name = PQgetvalue(res2, j, i_conname);
+				const char *expr = PQgetvalue(res2, j, i_consrc);
 
 				if (actual_atts + j > 0)
 					appendPQExpBuffer(q, ",\n\t");
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 297875e0becaab36eaca1e780a432bfc8c96dd78..d3c386284b42fc36cde9d0dcd815b03217934f91 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -3,7 +3,7 @@
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.54 2002/05/13 17:45:30 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.55 2002/07/12 18:43:19 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "describe.h"
@@ -747,7 +747,7 @@ describeTableDetails(const char *name, bool desc)
 				   *result3 = NULL,
 				   *result4 = NULL;
 		int			index_count = 0,
-					constr_count = 0,
+					check_count = 0,
 					rule_count = 0,
 					trigger_count = 0;
 		int			count_footers = 0;
@@ -770,19 +770,20 @@ describeTableDetails(const char *name, bool desc)
 				index_count = PQntuples(result1);
 		}
 
-		/* count table (and column) constraints */
+		/* count table (and column) check constraints */
 		if (tableinfo.checks)
 		{
 			printfPQExpBuffer(&buf,
-					"SELECT rcsrc, rcname\n"
-					"FROM pg_relcheck r, pg_class c\n"
-					"WHERE c.relname='%s' AND c.oid = r.rcrelid",
+					"SELECT consrc, conname\n"
+					"FROM pg_constraint r, pg_class c\n"
+					"WHERE c.relname='%s' AND c.oid = r.conrelid\n"
+					"AND r.contype = 'c'",
 					name);
 			result2 = PSQLexec(buf.data);
 			if (!result2)
 				goto error_return;
 			else
-				constr_count = PQntuples(result2);
+				check_count = PQntuples(result2);
 		}
 
 		/* count rules */
@@ -815,7 +816,7 @@ describeTableDetails(const char *name, bool desc)
 				trigger_count = PQntuples(result4);
 		}
 
-		footers = xmalloc((index_count + constr_count + rule_count + trigger_count + 1)
+		footers = xmalloc((index_count + check_count + rule_count + trigger_count + 1)
 						  * sizeof(*footers));
 
 		/* print indexes */
@@ -846,8 +847,8 @@ describeTableDetails(const char *name, bool desc)
 		}
 
 
-		/* print constraints */
-		for (i = 0; i < constr_count; i++)
+		/* print check constraints */
+		for (i = 0; i < check_count; i++)
 		{
 			char	   *s = _("Check constraints");
 
diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h
index e6e0b1aaebb846b96d120b3d12ca0e803273e8fd..0f277d1c9e8ebaa859a4c8710c347c30930d00ef 100644
--- a/src/include/access/tupdesc.h
+++ b/src/include/access/tupdesc.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: tupdesc.h,v 1.35 2002/06/20 20:29:43 momjian Exp $
+ * $Id: tupdesc.h,v 1.36 2002/07/12 18:43:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -43,7 +43,7 @@ typedef struct tupleConstr
 
 /*
  * This structure contains all information (i.e. from Classes
- * pg_attribute, pg_attrdef, pg_relcheck) for a tuple.
+ * pg_attribute, pg_attrdef, pg_constraint) for a tuple.
  */
 typedef struct tupleDesc
 {
diff --git a/src/include/catalog/catname.h b/src/include/catalog/catname.h
index 6f755c9f9dc77302d845db3274cdaf10260abf1f..0e452a9ca3e7c3f27fac9ac3e96b5487fd74158d 100644
--- a/src/include/catalog/catname.h
+++ b/src/include/catalog/catname.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: catname.h,v 1.27 2002/07/11 07:39:27 ishii Exp $
+ * $Id: catname.h,v 1.28 2002/07/12 18:43:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,8 +20,10 @@
 #define  AccessMethodOperatorRelationName "pg_amop"
 #define  AccessMethodProcedureRelationName "pg_amproc"
 #define  AttributeRelationName "pg_attribute"
+#define  ConstraintRelationName "pg_constraint"
 #define  ConversionRelationName "pg_conversion"
 #define  DatabaseRelationName "pg_database"
+#define  DependRelationName "pg_depend"
 #define  DescriptionRelationName "pg_description"
 #define  GroupRelationName "pg_group"
 #define  IndexRelationName "pg_index"
@@ -40,7 +42,6 @@
 #define  TypeRelationName "pg_type"
 #define  VersionRelationName "pg_version"
 #define  AttrDefaultRelationName "pg_attrdef"
-#define  RelCheckRelationName "pg_relcheck"
 #define  TriggerRelationName "pg_trigger"
 
 #endif   /* CATNAME_H */
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 81f52bd9b34565ea2aaf031840ff6ba1ade38733..9d3acbe35f558ebbf77884997d6af9c5fb69a9e5 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.138 2002/07/11 07:39:27 ishii Exp $
+ * $Id: catversion.h,v 1.139 2002/07/12 18:43:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200207111
+#define CATALOG_VERSION_NO	200207112
 
 #endif
diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h
new file mode 100644
index 0000000000000000000000000000000000000000..c890acb687a9ca7b56cf8b7bcc10d23319d47808
--- /dev/null
+++ b/src/include/catalog/dependency.h
@@ -0,0 +1,92 @@
+/*-------------------------------------------------------------------------
+ *
+ * dependency.h
+ *	  Routines to support inter-object dependencies.
+ *
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: dependency.h,v 1.1 2002/07/12 18:43:19 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef DEPENDENCY_H
+#define DEPENDENCY_H
+
+#include "nodes/parsenodes.h"	/* for DropBehavior */
+
+
+/*
+ * Precise semantics of a dependency relationship are specified by the
+ * DependencyType code (which is stored in a "char" field in pg_depend,
+ * so we assign ASCII-code values to the enumeration members).
+ *
+ * In all cases, a dependency relationship indicates that the referenced
+ * object may not be dropped without also dropping the dependent object.
+ * However, there are several subflavors:
+ *
+ * DEPENDENCY_NORMAL ('n'): normal relationship between separately-created
+ * objects.  The dependent object may be dropped without affecting the
+ * referenced object.  The referenced object may only be dropped by
+ * specifying CASCADE, in which case the dependent object is dropped too.
+ * Example: a table column has a normal dependency on its datatype.
+ *
+ * DEPENDENCY_AUTO ('a'): the dependent object can be dropped separately
+ * from the referenced object, and should be automatically dropped
+ * (regardless of RESTRICT or CASCADE mode) if the referenced object
+ * is dropped.
+ * Example: a named constraint on a table is made auto-dependent on
+ * the table, so that it will go away if the table is dropped.
+ *
+ * DEPENDENCY_INTERNAL ('i'): the dependent object was created as part
+ * of creation of the referenced object, and is really just a part of
+ * its internal implementation.  A DROP of the dependent object will be
+ * disallowed outright (we'll tell the user to issue a DROP against the
+ * referenced object, instead).  A DROP of the referenced object will be
+ * propagated through to drop the dependent object whether CASCADE is
+ * specified or not.
+ * Example: a trigger that's created to enforce a foreign-key constraint
+ * is made internally dependent on the constraint's pg_constraint entry.
+ *
+ * DEPENDENCY_PIN ('p'): there is no dependent object; this type of entry
+ * is a signal that the system itself depends on the referenced object,
+ * and so that object must never be deleted.  Entries of this type are
+ * created only during initdb.  The fields for the dependent object
+ * contain zeroes.
+ *
+ * Other dependency flavors may be needed in future.
+ */
+
+typedef enum DependencyType
+{
+	DEPENDENCY_NORMAL	= 'n',
+	DEPENDENCY_AUTO		= 'a',
+	DEPENDENCY_INTERNAL	= 'i',
+	DEPENDENCY_PIN		= 'p'
+} DependencyType;
+
+
+/*
+ * The two objects related by a dependency are identified by ObjectAddresses.
+ */
+typedef struct ObjectAddress
+{
+	Oid		classId;		/* Class Id from pg_class */
+	Oid		objectId;		/* OID of the object */
+	int32	objectSubId;	/* Subitem within the object (column of table) */
+} ObjectAddress;
+
+
+/* in dependency.c */
+
+extern void performDeletion(const ObjectAddress *object,
+							DropBehavior behavior);
+
+/* in pg_depend.c */
+
+extern void recordDependencyOn(const ObjectAddress *depender,
+							   const ObjectAddress *referenced,
+							   DependencyType behavior);
+
+#endif   /* DEPENDENCY_H */
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index a9570dd3ab510c367fb969dd3d0af1a30f0ecf33..5cf87e2631f4af9f95822ede4351fec3c8668c1c 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.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: heap.h,v 1.51 2002/06/20 20:29:43 momjian Exp $
+ * $Id: heap.h,v 1.52 2002/07/12 18:43:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -44,7 +44,7 @@ extern Oid heap_create_with_catalog(const char *relname,
 						 bool relhasoids,
 						 bool allow_system_table_mods);
 
-extern void heap_drop_with_catalog(Oid rid, bool allow_system_table_mods);
+extern void heap_drop_with_catalog(Oid rid);
 
 extern void heap_truncate(Oid rid);
 
@@ -58,7 +58,8 @@ extern Node *cookDefault(ParseState *pstate,
 						 int32 atttypmod,
 						 char *attname);
 
-extern int	RemoveCheckConstraint(Relation rel, const char *constrName, bool inh);
+extern int	RemoveRelConstraints(Relation rel, const char *constrName,
+								 DropBehavior behavior);
 
 extern Form_pg_attribute SystemAttributeDefinition(AttrNumber attno,
 						  bool relhasoids);
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index fb4afac8a2d4a4eff3167c7eb3e9cee3d0e89009..738f1079dc27c9b8542ff8be8513983363737015 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.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: index.h,v 1.48 2002/06/20 20:29:43 momjian Exp $
+ * $Id: index.h,v 1.49 2002/07/12 18:43:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -35,6 +35,7 @@ extern Oid index_create(Oid heapRelationId,
 			 Oid accessMethodObjectId,
 			 Oid *classObjectId,
 			 bool primary,
+			 bool isconstraint,
 			 bool allow_system_table_mods);
 
 extern void index_drop(Oid indexId);
diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h
index 9413e5c8586dd27a7ed006e6bd575848c7b438fd..d4ca744172b621279ac10331b7ffa37008db20b6 100644
--- a/src/include/catalog/indexing.h
+++ b/src/include/catalog/indexing.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: indexing.h,v 1.68 2002/07/11 07:39:27 ishii Exp $
+ * $Id: indexing.h,v 1.69 2002/07/12 18:43:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,8 +27,10 @@
 #define Num_pg_attr_indices			2
 #define Num_pg_attrdef_indices		1
 #define Num_pg_class_indices		2
+#define Num_pg_constraint_indices	3
 #define Num_pg_conversion_indices	2
 #define Num_pg_database_indices		2
+#define Num_pg_depend_indices		2
 #define Num_pg_description_indices	1
 #define Num_pg_group_indices		2
 #define Num_pg_index_indices		2
@@ -39,7 +41,6 @@
 #define Num_pg_opclass_indices		2
 #define Num_pg_operator_indices		2
 #define Num_pg_proc_indices			2
-#define Num_pg_relcheck_indices		1
 #define Num_pg_rewrite_indices		2
 #define Num_pg_shadow_indices		2
 #define Num_pg_statistic_indices	1
@@ -60,10 +61,15 @@
 #define AttributeRelidNumIndex		"pg_attribute_relid_attnum_index"
 #define ClassNameNspIndex			"pg_class_relname_nsp_index"
 #define ClassOidIndex				"pg_class_oid_index"
+#define ConstraintNameNspIndex		"pg_constraint_conname_nsp_index"
+#define ConstraintOidIndex			"pg_constraint_oid_index"
+#define ConstraintRelidIndex		"pg_constraint_conrelid_index"
 #define ConversionDefaultIndex		"pg_conversion_default_index"
 #define ConversionNameNspIndex		"pg_conversion_name_nsp_index"
 #define DatabaseNameIndex			"pg_database_datname_index"
 #define DatabaseOidIndex			"pg_database_oid_index"
+#define DependDependerIndex			"pg_depend_depender_index"
+#define DependReferenceIndex		"pg_depend_reference_index"
 #define DescriptionObjIndex			"pg_description_o_c_o_index"
 #define GroupNameIndex				"pg_group_name_index"
 #define GroupSysidIndex				"pg_group_sysid_index"
@@ -81,7 +87,6 @@
 #define OperatorOidIndex			"pg_operator_oid_index"
 #define ProcedureNameNspIndex		"pg_proc_proname_args_nsp_index"
 #define ProcedureOidIndex			"pg_proc_oid_index"
-#define RelCheckIndex				"pg_relcheck_rcrelid_index"
 #define RewriteOidIndex				"pg_rewrite_oid_index"
 #define RewriteRelRulenameIndex		"pg_rewrite_rel_rulename_index"
 #define ShadowNameIndex				"pg_shadow_usename_index"
@@ -102,8 +107,10 @@ extern char *Name_pg_amproc_indices[];
 extern char *Name_pg_attr_indices[];
 extern char *Name_pg_attrdef_indices[];
 extern char *Name_pg_class_indices[];
+extern char *Name_pg_constraint_indices[];
 extern char *Name_pg_conversion_indices[];
 extern char *Name_pg_database_indices[];
+extern char *Name_pg_depend_indices[];
 extern char *Name_pg_description_indices[];
 extern char *Name_pg_group_indices[];
 extern char *Name_pg_index_indices[];
@@ -114,7 +121,6 @@ extern char *Name_pg_namespace_indices[];
 extern char *Name_pg_opclass_indices[];
 extern char *Name_pg_operator_indices[];
 extern char *Name_pg_proc_indices[];
-extern char *Name_pg_relcheck_indices[];
 extern char *Name_pg_rewrite_indices[];
 extern char *Name_pg_shadow_indices[];
 extern char *Name_pg_statistic_indices[];
@@ -160,10 +166,19 @@ DECLARE_UNIQUE_INDEX(pg_attribute_relid_attnum_index on pg_attribute using btree
 DECLARE_UNIQUE_INDEX(pg_class_oid_index on pg_class using btree(oid oid_ops));
 DECLARE_UNIQUE_INDEX(pg_class_relname_nsp_index on pg_class using btree(relname name_ops, relnamespace oid_ops));
 /* This following index is not used for a cache and is not unique */
+DECLARE_INDEX(pg_constraint_conname_nsp_index on pg_constraint using btree(conname name_ops, connamespace oid_ops));
+/* This following index is not used for a cache and is not unique */
+DECLARE_INDEX(pg_constraint_conrelid_index on pg_constraint using btree(conrelid oid_ops));
+DECLARE_UNIQUE_INDEX(pg_constraint_oid_index on pg_constraint using btree(oid oid_ops));
+/* This following index is not used for a cache and is not unique */
 DECLARE_INDEX(pg_conversion_default_index on pg_conversion using btree(connamespace oid_ops, conforencoding int4_ops, contoencoding int4_ops));
 DECLARE_UNIQUE_INDEX(pg_conversion_name_nsp_index on pg_conversion using btree(conname name_ops, connamespace oid_ops));
 DECLARE_UNIQUE_INDEX(pg_database_datname_index on pg_database using btree(datname name_ops));
 DECLARE_UNIQUE_INDEX(pg_database_oid_index on pg_database using btree(oid oid_ops));
+/* This following index is not used for a cache and is not unique */
+DECLARE_INDEX(pg_depend_depender_index on pg_depend using btree(classid oid_ops, objid oid_ops, objsubid int4_ops));
+/* This following index is not used for a cache and is not unique */
+DECLARE_INDEX(pg_depend_reference_index on pg_depend using btree(refclassid oid_ops, refobjid oid_ops, refobjsubid int4_ops));
 DECLARE_UNIQUE_INDEX(pg_description_o_c_o_index on pg_description using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops));
 DECLARE_UNIQUE_INDEX(pg_group_name_index on pg_group using btree(groname name_ops));
 DECLARE_UNIQUE_INDEX(pg_group_sysid_index on pg_group using btree(grosysid int4_ops));
@@ -183,7 +198,6 @@ DECLARE_UNIQUE_INDEX(pg_operator_oprname_l_r_n_index on pg_operator using btree(
 DECLARE_UNIQUE_INDEX(pg_proc_oid_index on pg_proc using btree(oid oid_ops));
 DECLARE_UNIQUE_INDEX(pg_proc_proname_args_nsp_index on pg_proc using btree(proname name_ops, pronargs int2_ops, proargtypes oidvector_ops, pronamespace oid_ops));
 /* This following index is not used for a cache and is not unique */
-DECLARE_INDEX(pg_relcheck_rcrelid_index on pg_relcheck using btree(rcrelid oid_ops));
 DECLARE_UNIQUE_INDEX(pg_rewrite_oid_index on pg_rewrite using btree(oid oid_ops));
 DECLARE_UNIQUE_INDEX(pg_rewrite_rel_rulename_index on pg_rewrite using btree(ev_class oid_ops, rulename name_ops));
 DECLARE_UNIQUE_INDEX(pg_shadow_usename_index on pg_shadow using btree(usename name_ops));
diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h
new file mode 100644
index 0000000000000000000000000000000000000000..ec493146524662f750f51c01644bc476eaee8794
--- /dev/null
+++ b/src/include/catalog/pg_constraint.h
@@ -0,0 +1,172 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_constraint.h
+ *	  definition of the system "constraint" relation (pg_constraint)
+ *	  along with the relation's initial contents.
+ *
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: pg_constraint.h,v 1.1 2002/07/12 18:43:19 tgl Exp $
+ *
+ * NOTES
+ *	  the genbki.sh script reads this file and generates .bki
+ *	  information from the DATA() statements.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_CONSTRAINT_H
+#define PG_CONSTRAINT_H
+
+/* ----------------
+ *		postgres.h contains the system type definintions and the
+ *		CATALOG(), BOOTSTRAP and DATA() sugar words so this file
+ *		can be read by both genbki.sh and the C compiler.
+ * ----------------
+ */
+
+/* ----------------
+ *		pg_constraint definition.  cpp turns this into
+ *		typedef struct FormData_pg_constraint
+ * ----------------
+ */
+CATALOG(pg_constraint)
+{
+	/*
+	 * conname + connamespace is deliberately not unique; we allow, for
+	 * example, the same name to be used for constraints of different
+	 * relations.  This is partly for backwards compatibility with past
+	 * Postgres practice, and partly because we don't want to have to obtain
+	 * a global lock to generate a globally unique name for a nameless
+	 * constraint.  We associate a namespace with constraint names only
+	 * for SQL92 compatibility.
+	 */
+	NameData	conname;		/* name of this constraint */
+	Oid			connamespace;	/* OID of namespace containing constraint */
+	char		contype;		/* constraint type; see codes below */
+	bool		condeferrable;	/* deferrable constraint? */
+	bool		condeferred;	/* deferred by default? */
+
+	/*
+	 * conrelid and conkey are only meaningful if the constraint applies
+	 * to a specific relation (this excludes domain constraints and
+	 * assertions).  Otherwise conrelid is 0 and conkey is NULL.
+	 */
+	Oid			conrelid;		/* relation this constraint constrains */
+
+	/*
+	 * contypid links to the pg_type row for a domain if this is a domain
+	 * constraint.  Otherwise it's 0.
+	 *
+	 * For SQL-style global ASSERTIONs, both conrelid and contypid would
+	 * be zero.  This is not presently supported, however.
+	 */
+	Oid			contypid;		/* domain this constraint constrains */
+
+	/*
+	 * These fields, plus confkey, are only meaningful for a foreign-key
+	 * constraint.  Otherwise confrelid is 0 and the char fields are spaces.
+	 */
+	Oid			confrelid;		/* relation referenced by foreign key */
+	char		confupdtype;	/* foreign key's ON UPDATE action */
+	char		confdeltype;	/* foreign key's ON DELETE action */
+	char		confmatchtype;	/* foreign key's match type */
+
+	/*
+	 * VARIABLE LENGTH FIELDS start here.  These fields may be NULL, too.
+	 */
+
+	/*
+	 * Columns of conrelid that the constraint applies to
+	 */
+	int2		conkey[1];
+
+	/*
+	 * If a foreign key, the referenced columns of confrelid
+	 */
+	int2		confkey[1];
+
+	/*
+	 * If a check constraint, nodeToString representation of expression
+	 */
+	text		conbin;
+
+	/*
+	 * If a check constraint, source-text representation of expression
+	 */
+	text		consrc;
+} FormData_pg_constraint;
+
+/* ----------------
+ *		Form_pg_constraint corresponds to a pointer to a tuple with
+ *		the format of pg_constraint relation.
+ * ----------------
+ */
+typedef FormData_pg_constraint *Form_pg_constraint;
+
+/* ----------------
+ *		compiler constants for pg_constraint
+ * ----------------
+ */
+#define Natts_pg_constraint					15
+#define Anum_pg_constraint_conname			1
+#define Anum_pg_constraint_connamespace		2
+#define Anum_pg_constraint_contype			3
+#define Anum_pg_constraint_condeferrable	4
+#define Anum_pg_constraint_condeferred		5
+#define Anum_pg_constraint_conrelid			6
+#define Anum_pg_constraint_contypid			7
+#define Anum_pg_constraint_confrelid		8
+#define Anum_pg_constraint_confupdtype		9
+#define Anum_pg_constraint_confdeltype		10
+#define Anum_pg_constraint_confmatchtype	11
+#define Anum_pg_constraint_conkey			12
+#define Anum_pg_constraint_confkey			13
+#define Anum_pg_constraint_conbin			14
+#define Anum_pg_constraint_consrc			15
+
+
+/* Valid values for contype */
+#define CONSTRAINT_CHECK			'c'
+#define CONSTRAINT_FOREIGN			'f'
+#define CONSTRAINT_PRIMARY			'p'
+#define CONSTRAINT_UNIQUE			'u'
+
+/*
+ * Valid values for confupdtype and confdeltype are the FKCONSTR_ACTION_xxx
+ * constants defined in parsenodes.h.  Valid values for confmatchtype are
+ * the FKCONSTR_MATCH_xxx constants defined in parsenodes.h.
+ */
+
+
+/*
+ * prototypes for functions in pg_constraint.c
+ */
+extern Oid	CreateConstraintEntry(const char *constraintName,
+								  Oid constraintNamespace,
+								  char constraintType,
+								  bool isDeferrable,
+								  bool isDeferred,
+								  Oid relId,
+								  const int16 *constraintKey,
+								  int constraintNKeys,
+								  Oid domainId,
+								  Oid foreignRelId,
+								  const int16 *foreignKey,
+								  int foreignNKeys,
+								  char foreignUpdateType,
+								  char foreignDeleteType,
+								  char foreignMatchType,
+								  const char *conBin,
+								  const char *conSrc);
+
+extern void RemoveConstraintById(Oid conId);
+
+extern bool ConstraintNameIsUsed(Oid relId, Oid relNamespace,
+								 const char *cname);
+extern char *GenerateConstraintName(Oid relId, Oid relNamespace,
+									int *counter);
+extern bool ConstraintNameIsGenerated(const char *cname);
+
+#endif   /* PG_CONSTRAINT_H */
diff --git a/src/include/catalog/pg_depend.h b/src/include/catalog/pg_depend.h
new file mode 100644
index 0000000000000000000000000000000000000000..169a98fc2cce219593c295eff52588721655aba9
--- /dev/null
+++ b/src/include/catalog/pg_depend.h
@@ -0,0 +1,93 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_depend.h
+ *	  definition of the system "dependency" relation (pg_depend)
+ *	  along with the relation's initial contents.
+ *
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: pg_depend.h,v 1.1 2002/07/12 18:43:19 tgl Exp $
+ *
+ * NOTES
+ *	  the genbki.sh script reads this file and generates .bki
+ *	  information from the DATA() statements.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_DEPEND_H
+#define PG_DEPEND_H
+
+/* ----------------
+ *		postgres.h contains the system type definitions and the
+ *		CATALOG(), BOOTSTRAP and DATA() sugar words so this file
+ *		can be read by both genbki.sh and the C compiler.
+ * ----------------
+ */
+
+/* ----------------
+ *		pg_depend definition.  cpp turns this into
+ *		typedef struct FormData_pg_depend
+ * ----------------
+ */
+CATALOG(pg_depend) BKI_WITHOUT_OIDS
+{
+	/*
+	 * Identification of the dependent (referencing) object.
+	 *
+	 * These fields are all zeroes for a DEPENDENCY_PIN entry.
+	 */
+	Oid			classid;		/* OID of table containing object */
+	Oid			objid;			/* OID of object itself */
+	int4		objsubid;		/* column number, or 0 if not used */
+
+	/*
+	 * Identification of the independent (referenced) object.
+	 */
+	Oid			refclassid;		/* OID of table containing object */
+	Oid			refobjid;		/* OID of object itself */
+	int4		refobjsubid;	/* column number, or 0 if not used */
+
+	/*
+	 * Precise semantics of the relationship are specified by the deptype
+	 * field.  See DependencyType in catalog/dependency.h.
+	 */
+	char		deptype;		/* see codes in dependency.h */
+} FormData_pg_depend;
+
+/* ----------------
+ *		Form_pg_depend corresponds to a pointer to a row with
+ *		the format of pg_depend relation.
+ * ----------------
+ */
+typedef FormData_pg_depend *Form_pg_depend;
+
+/* ----------------
+ *		compiler constants for pg_depend
+ * ----------------
+ */
+#define Natts_pg_depend				7
+#define Anum_pg_depend_classid		1
+#define Anum_pg_depend_objid		2
+#define Anum_pg_depend_objsubid		3
+#define Anum_pg_depend_refclassid	4
+#define Anum_pg_depend_refobjid		5
+#define Anum_pg_depend_refobjsubid	6
+#define Anum_pg_depend_deptype		7
+
+
+/*
+ * pg_depend has no preloaded contents; system-defined dependencies are
+ * loaded into it during a late stage of the initdb process.
+ *
+ * NOTE: we do not represent all possible dependency pairs in pg_depend;
+ * for example, there's not much value in creating an explicit dependency
+ * from an attribute to its relation.  Usually we make a dependency for
+ * cases where the relationship is conditional rather than essential
+ * (for example, not all triggers are dependent on constraints, but all
+ * attributes are dependent on relations) or where the dependency is not
+ * convenient to find from the contents of other catalogs.
+ */
+
+#endif   /* PG_DEPEND_H */
diff --git a/src/include/catalog/pg_relcheck.h b/src/include/catalog/pg_relcheck.h
deleted file mode 100644
index f37cbe85b08bdf3de2b625bc383d682d36f7f1ea..0000000000000000000000000000000000000000
--- a/src/include/catalog/pg_relcheck.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * pg_relcheck.h
- *
- *
- * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * NOTES
- *	  the genbki.sh script reads this file and generates .bki
- *	  information from the DATA() statements.
- *
- *-------------------------------------------------------------------------
- */
-#ifndef PG_RELCHECK_H
-#define PG_RELCHECK_H
-
-/* ----------------
- *		postgres.h contains the system type definintions and the
- *		CATALOG(), BOOTSTRAP and DATA() sugar words so this file
- *		can be read by both genbki.sh and the C compiler.
- * ----------------
- */
-
-/* ----------------
- *		pg_relcheck definition.  cpp turns this into
- *		typedef struct FormData_pg_relcheck
- * ----------------
- */
-CATALOG(pg_relcheck) BKI_WITHOUT_OIDS
-{
-	Oid			rcrelid;
-	NameData	rcname;
-	text		rcbin;
-	text		rcsrc;
-} FormData_pg_relcheck;
-
-/* ----------------
- *		Form_pg_relcheck corresponds to a pointer to a tuple with
- *		the format of pg_relcheck relation.
- * ----------------
- */
-typedef FormData_pg_relcheck *Form_pg_relcheck;
-
-/* ----------------
- *		compiler constants for pg_relcheck
- * ----------------
- */
-#define Natts_pg_relcheck				4
-#define Anum_pg_relcheck_rcrelid		1
-#define Anum_pg_relcheck_rcname			2
-#define Anum_pg_relcheck_rcbin			3
-#define Anum_pg_relcheck_rcsrc			4
-
-#endif   /* PG_RELCHECK_H */
diff --git a/src/include/commands/comment.h b/src/include/commands/comment.h
index bf2acfcfa0ed9479f862b2247b0749b179c4a09f..0972c13486a0441db966aee733fdcd516495956a 100644
--- a/src/include/commands/comment.h
+++ b/src/include/commands/comment.h
@@ -27,7 +27,7 @@
 
 extern void CommentObject(CommentStmt *stmt);
 
-extern void DeleteComments(Oid oid, Oid classoid);
+extern void DeleteComments(Oid oid, Oid classoid, int32 subid);
 
 extern void CreateComments(Oid oid, Oid classoid, int32 subid, char *comment);
 
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 551deae0956d811be8cc1799faeb5660e0ce7242..169ec3f3dff1dc132428a0600ac5ceaa750c32c1 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.40 2002/07/01 15:27:56 tgl Exp $
+ * $Id: defrem.h,v 1.41 2002/07/12 18:43:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,6 +27,7 @@ extern void DefineIndex(RangeVar *heapRelation,
 			List *attributeList,
 			bool unique,
 			bool primary,
+			bool isconstraint,
 			Expr *predicate,
 			List *rangetable);
 extern void RemoveIndex(RangeVar *relation, DropBehavior behavior);
@@ -39,16 +40,19 @@ extern void ReindexDatabase(const char *databaseName, bool force, bool all);
  */
 
 extern void CreateFunction(CreateFunctionStmt *stmt);
-extern void RemoveFunction(List *functionName, List *argTypes);
+extern void RemoveFunction(RemoveFuncStmt *stmt);
+extern void RemoveFunctionById(Oid funcOid);
 
 extern void DefineOperator(List *names, List *parameters);
 extern void RemoveOperator(RemoveOperStmt *stmt);
+extern void RemoveOperatorById(Oid operOid);
 
 extern void DefineAggregate(List *names, List *parameters);
-extern void RemoveAggregate(List *aggName, TypeName *aggType);
+extern void RemoveAggregate(RemoveAggrStmt *stmt);
 
 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);
 
diff --git a/src/include/commands/proclang.h b/src/include/commands/proclang.h
index 25cf7ab5ef8d590471e50215022235daebd6f5dc..f4fde9b1083eb5907d4d7ee2e63244b47b137afd 100644
--- a/src/include/commands/proclang.h
+++ b/src/include/commands/proclang.h
@@ -13,5 +13,6 @@
 
 extern void CreateProceduralLanguage(CreatePLangStmt *stmt);
 extern void DropProceduralLanguage(DropPLangStmt *stmt);
+extern void DropProceduralLanguageById(Oid langOid);
 
 #endif   /* PROCLANG_H */
diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h
index 9ff6c8e1eac8a451bd5661d640a6c81dc6e82c99..b9308cd57f3b7b1e54ed24e5264ad0ec14707632 100644
--- a/src/include/commands/trigger.h
+++ b/src/include/commands/trigger.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: trigger.h,v 1.36 2002/06/20 20:29:49 momjian Exp $
+ * $Id: trigger.h,v 1.37 2002/07/12 18:43:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -101,9 +101,11 @@ typedef struct TriggerData
 #define RI_MAX_ARGUMENTS		(RI_FIRST_ATTNAME_ARGNO + (RI_MAX_NUMKEYS * 2))
 
 
-extern void CreateTrigger(CreateTrigStmt *stmt);
-extern void DropTrigger(Oid relid, const char *trigname);
-extern void RelationRemoveTriggers(Relation rel);
+extern Oid	CreateTrigger(CreateTrigStmt *stmt, bool forConstraint);
+
+extern void DropTrigger(Oid relid, const char *trigname,
+						DropBehavior behavior);
+extern void RemoveTriggerById(Oid trigOid);
 
 extern void renametrig(Oid relid, const char *oldname, const char *newname);
 
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 19693d57b3affbd60f91e1c79d09cffd1108ea6b..2fec7f66fbd9defc694620bcce3df2c212d7f5b2 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.184 2002/07/11 07:39:27 ishii Exp $
+ * $Id: parsenodes.h,v 1.185 2002/07/12 18:43:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -762,6 +762,8 @@ typedef struct AlterTableStmt
 								 *  M = alter column storage
 								 *	D = drop column
 								 *	C = add constraint
+								 *	c = pre-processed add constraint
+								 *		(local in parser/analyze.c)
 								 *	X = drop constraint
 								 *	E = create toast table
 								 *	U = change owner
@@ -929,31 +931,41 @@ typedef struct Constraint
 
 /* ----------
  * Definitions for FOREIGN KEY constraints in CreateStmt
+ *
+ * Note: FKCONSTR_ACTION_xxx values are stored into pg_constraint.confupdtype
+ * and pg_constraint.confdeltype columns; FKCONSTR_MATCH_xxx values are
+ * stored into pg_constraint.confmatchtype.  Changing the code values may
+ * require an initdb!
+ *
+ * If skip_validation is true then we skip checking that the existing rows
+ * in the table satisfy the constraint, and just install the catalog entries
+ * for the constraint.  This is currently used only during CREATE TABLE
+ * (when we know the table must be empty).
  * ----------
  */
-#define FKCONSTR_ON_KEY_NOACTION		0x0000
-#define FKCONSTR_ON_KEY_RESTRICT		0x0001
-#define FKCONSTR_ON_KEY_CASCADE			0x0002
-#define FKCONSTR_ON_KEY_SETNULL			0x0004
-#define FKCONSTR_ON_KEY_SETDEFAULT		0x0008
-
-#define FKCONSTR_ON_DELETE_MASK			0x000F
-#define FKCONSTR_ON_DELETE_SHIFT		0
+#define FKCONSTR_ACTION_NOACTION	'a'
+#define FKCONSTR_ACTION_RESTRICT	'r'
+#define FKCONSTR_ACTION_CASCADE		'c'
+#define FKCONSTR_ACTION_SETNULL		'n'
+#define FKCONSTR_ACTION_SETDEFAULT	'd'
 
-#define FKCONSTR_ON_UPDATE_MASK			0x00F0
-#define FKCONSTR_ON_UPDATE_SHIFT		4
+#define FKCONSTR_MATCH_FULL			'f'
+#define FKCONSTR_MATCH_PARTIAL		'p'
+#define FKCONSTR_MATCH_UNSPECIFIED	'u'
 
 typedef struct FkConstraint
 {
 	NodeTag		type;
-	char	   *constr_name;	/* Constraint name */
+	char	   *constr_name;	/* Constraint name, or NULL if unnamed */
 	RangeVar   *pktable;		/* Primary key table */
 	List	   *fk_attrs;		/* Attributes of foreign key */
 	List	   *pk_attrs;		/* Corresponding attrs in PK table */
-	char	   *match_type;		/* FULL or PARTIAL */
-	int32		actions;		/* ON DELETE/UPDATE actions */
+	char		fk_matchtype;	/* FULL, PARTIAL, UNSPECIFIED */
+	char		fk_upd_action;	/* ON UPDATE action */
+	char		fk_del_action;	/* ON DELETE action */
 	bool		deferrable;		/* DEFERRABLE */
 	bool		initdeferred;	/* INITIALLY DEFERRED */
+	bool		skip_validation; /* skip validation of existing rows? */
 } FkConstraint;
 
 /* ----------------------
@@ -1201,6 +1213,7 @@ typedef struct IndexStmt
 								 * transformStmt() */
 	bool		unique;			/* is index unique? */
 	bool		primary;		/* is index on primary key? */
+	bool		isconstraint;	/* is it from a CONSTRAINT clause? */
 } IndexStmt;
 
 /* ----------------------
diff --git a/src/include/rewrite/rewriteRemove.h b/src/include/rewrite/rewriteRemove.h
index 3af9c15048173d9afb63bdda3a8210f121fde063..664625982d51d863ad686a35dadf84083be2f7b1 100644
--- a/src/include/rewrite/rewriteRemove.h
+++ b/src/include/rewrite/rewriteRemove.h
@@ -7,14 +7,18 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: rewriteRemove.h,v 1.14 2002/06/20 20:29:52 momjian Exp $
+ * $Id: rewriteRemove.h,v 1.15 2002/07/12 18:43:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef REWRITEREMOVE_H
 #define REWRITEREMOVE_H
 
-extern void RemoveRewriteRule(Oid owningRel, const char *ruleName);
-extern void RelationRemoveRules(Oid relid);
+#include "nodes/parsenodes.h"
+
+
+extern void RemoveRewriteRule(Oid owningRel, const char *ruleName,
+							  DropBehavior behavior);
+extern void RemoveRewriteRuleById(Oid ruleOid);
 
 #endif   /* REWRITEREMOVE_H */
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index ca361ebc2cca1339d9e7a5d410e9b1848078fbfd..dcc310aab5edcee9f9134164aad0cf0af5bb55ce 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: lsyscache.h,v 1.54 2002/07/06 20:16:36 momjian Exp $
+ * $Id: lsyscache.h,v 1.55 2002/07/12 18:43:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,6 +42,7 @@ extern Oid	get_func_rettype(Oid funcid);
 extern bool	get_func_retset(Oid funcid);
 extern char func_volatile(Oid funcid);
 extern Oid	get_relname_relid(const char *relname, Oid relnamespace);
+extern Oid	get_system_catalog_relid(const char *catname);
 extern char *get_rel_name(Oid relid);
 extern Oid	get_rel_namespace(Oid relid);
 extern Oid	get_rel_type_id(Oid relid);
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index f2e31919cc5e1556ed555e767bf52e98d4bee729..2dc64f3ccfa58d29a85e5bbd05ed97c788a53985 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -340,8 +340,6 @@ ERROR:  UNIQUE constraint matching given keys for referenced table "tmp4" not fo
 DROP TABLE tmp5;
 DROP TABLE tmp4;
 DROP TABLE tmp3;
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "tmp2"
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "tmp2"
 DROP TABLE tmp2;
 -- Foreign key adding test with mixed types
 -- Note: these tables are TEMP to avoid name conflicts when this test
@@ -369,9 +367,9 @@ NOTICE:  ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
 -- As should this
 ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable(ptest1);
 NOTICE:  ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
-DROP TABLE pktable;
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "fktable"
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "fktable"
+DROP TABLE pktable cascade;
+NOTICE:  Drop cascades to constraint $2 on table fktable
+NOTICE:  Drop cascades to constraint $1 on table fktable
 DROP TABLE fktable;
 CREATE TEMP TABLE PKTABLE (ptest1 int, ptest2 inet,
                            PRIMARY KEY(ptest1, ptest2));
@@ -382,16 +380,16 @@ ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2) references pktable;
 NOTICE:  ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
 ERROR:  Unable to identify an operator '=' for types 'cidr' and 'integer'
 	You will have to retype this query using an explicit cast
--- Again, so should this...
 DROP TABLE FKTABLE;
+-- Again, so should this...
 CREATE TEMP TABLE FKTABLE (ftest1 cidr, ftest2 timestamp);
 ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2)
      references pktable(ptest1, ptest2);
 NOTICE:  ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
 ERROR:  Unable to identify an operator '=' for types 'cidr' and 'integer'
 	You will have to retype this query using an explicit cast
--- This fails because we mixed up the column ordering
 DROP TABLE FKTABLE;
+-- This fails because we mixed up the column ordering
 CREATE TEMP TABLE FKTABLE (ftest1 int, ftest2 inet);
 ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2)
      references pktable(ptest2, ptest1);
@@ -445,7 +443,7 @@ create table atacc1 (test int check (test>3), test2 int);
 alter table atacc1 add check (test2>test);
 -- should fail for $2
 insert into atacc1 (test2, test) values (3, 4);
-ERROR:  ExecInsert: rejected due to CHECK constraint $2
+ERROR:  ExecInsert: rejected due to CHECK constraint $1
 drop table atacc1;
 -- inheritance related tests
 create table atacc1 (test int);
@@ -628,7 +626,7 @@ alter table atacc1 add constraint "atacc1_pkey" primary key (test);
 NOTICE:  ALTER TABLE / ADD PRIMARY KEY will create implicit index 'atacc1_pkey' for table 'atacc1'
 alter table atacc1 alter column test drop not null;
 ERROR:  ALTER TABLE: Attribute "test" is in a primary key
-drop index atacc1_pkey;
+alter table atacc1 drop constraint "atacc1_pkey";
 alter table atacc1 alter column test drop not null;
 insert into atacc1 values (null);
 alter table atacc1 alter test set not null;
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index 75c83fc7ebf6c24dff7978215c507ef23586b744..915b420b9a28f2e69740af85feb714a1a480457d 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -1,11 +1,13 @@
 -- Test Comment / Drop
 create domain domaindroptest int4;
 comment on domain domaindroptest is 'About to drop this..';
+-- currently this will be disallowed
 create domain basetypetest domaindroptest;
 ERROR:  DefineDomain: domaindroptest is not a basetype
-drop domain domaindroptest cascade;
-ERROR:  DROP DOMAIN does not support the CASCADE keyword
 drop domain domaindroptest;
+-- this should fail because already gone
+drop domain domaindroptest cascade;
+ERROR:  Type "domaindroptest" does not exist
 -- TEST Domains.
 create domain domainvarchar varchar(5);
 create domain domainnumeric numeric(8,2);
diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out
index b8be87228bba5eca3c7e457f62fae8482d3e4c29..f5272891b9f1fae1e133c6fd1de62793696d6942 100644
--- a/src/test/regress/expected/foreign_key.out
+++ b/src/test/regress/expected/foreign_key.out
@@ -22,7 +22,7 @@ INSERT INTO FKTABLE VALUES (3, 4);
 INSERT INTO FKTABLE VALUES (NULL, 1);
 -- Insert a failed row into FK TABLE
 INSERT INTO FKTABLE VALUES (100, 2);
-ERROR:  <unnamed> referential integrity violation - key referenced from fktable not found in pktable
+ERROR:  $1 referential integrity violation - key referenced from fktable not found in pktable
 -- Check FKTABLE
 SELECT * FROM FKTABLE;
  ftest1 | ftest2 
@@ -55,9 +55,8 @@ SELECT * FROM FKTABLE;
       1 |      3
 (3 rows)
 
-DROP TABLE PKTABLE;
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "fktable"
 DROP TABLE FKTABLE;
+DROP TABLE PKTABLE;
 --
 -- check set NULL and table constraint on multiple columns
 --
@@ -138,8 +137,8 @@ SELECT * FROM FKTABLE;
         |        |      8
 (5 rows)
 
-DROP TABLE PKTABLE;
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "fktable"
+DROP TABLE PKTABLE CASCADE;
+NOTICE:  Drop cascades to constraint constrname on table fktable
 DROP TABLE FKTABLE;
 --
 -- check set default and table constraint on multiple columns
@@ -223,8 +222,13 @@ SELECT * FROM FKTABLE;
      -1 |     -2 |      8
 (5 rows)
 
+-- this should fail for lack of CASCADE
 DROP TABLE PKTABLE;
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "fktable"
+NOTICE:  constraint constrname2 on table fktable depends on table pktable
+ERROR:  Cannot drop table pktable because other objects depend on it
+	Use DROP ... CASCADE to drop the dependent objects too
+DROP TABLE PKTABLE CASCADE;
+NOTICE:  Drop cascades to constraint constrname2 on table fktable
 DROP TABLE FKTABLE;
 --
 -- First test, check with no on delete or on update
@@ -246,7 +250,7 @@ INSERT INTO FKTABLE VALUES (3, 4);
 INSERT INTO FKTABLE VALUES (NULL, 1);
 -- Insert a failed row into FK TABLE
 INSERT INTO FKTABLE VALUES (100, 2);
-ERROR:  <unnamed> referential integrity violation - key referenced from fktable not found in pktable
+ERROR:  $1 referential integrity violation - key referenced from fktable not found in pktable
 -- Check FKTABLE
 SELECT * FROM FKTABLE;
  ftest1 | ftest2 
@@ -270,7 +274,7 @@ SELECT * FROM PKTABLE;
 
 -- Delete a row from PK TABLE (should fail)
 DELETE FROM PKTABLE WHERE ptest1=1;
-ERROR:  <unnamed> referential integrity violation - key in pktable still referenced from fktable
+ERROR:  $1 referential integrity violation - key in pktable still referenced from fktable
 -- Delete a row from PK TABLE (should succeed)
 DELETE FROM PKTABLE WHERE ptest1=5;
 -- Check PKTABLE for deletes
@@ -285,7 +289,7 @@ SELECT * FROM PKTABLE;
 
 -- Update a row from PK TABLE (should fail)
 UPDATE PKTABLE SET ptest1=0 WHERE ptest1=2;
-ERROR:  <unnamed> referential integrity violation - key in pktable still referenced from fktable
+ERROR:  $1 referential integrity violation - key in pktable still referenced from fktable
 -- Update a row from PK TABLE (should succeed)
 UPDATE PKTABLE SET ptest1=0 WHERE ptest1=4;
 -- Check PKTABLE for updates
@@ -298,9 +302,8 @@ SELECT * FROM PKTABLE;
       0 | Test4
 (4 rows)
 
-DROP TABLE PKTABLE;
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "fktable"
 DROP TABLE FKTABLE;
+DROP TABLE PKTABLE;
 -- MATCH unspecified
 -- Base test restricting update/delete
 CREATE TABLE PKTABLE ( ptest1 int, ptest2 int, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2, ptest3) );
@@ -363,8 +366,6 @@ SELECT * from FKTABLE;
 (5 rows)
 
 DROP TABLE FKTABLE;
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
 DROP TABLE PKTABLE;
 -- cascade update/delete
 CREATE TABLE PKTABLE ( ptest1 int, ptest2 int, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2, ptest3) );
@@ -462,8 +463,6 @@ SELECT * from FKTABLE;
 (4 rows)
 
 DROP TABLE FKTABLE;
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
 DROP TABLE PKTABLE;
 -- set null update / set default delete
 CREATE TABLE PKTABLE ( ptest1 int, ptest2 int, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2, ptest3) );
@@ -568,8 +567,6 @@ SELECT * from FKTABLE;
 (6 rows)
 
 DROP TABLE FKTABLE;
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
 DROP TABLE PKTABLE;
 -- set default update / set null delete
 CREATE TABLE PKTABLE ( ptest1 int, ptest2 int, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2, ptest3) );
@@ -687,8 +684,6 @@ SELECT * from FKTABLE;
 (7 rows)
 
 DROP TABLE FKTABLE;
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
 DROP TABLE PKTABLE;
 CREATE TABLE PKTABLE (ptest1 int PRIMARY KEY);
 NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
@@ -734,14 +729,10 @@ ERROR:  Unable to identify an operator '=' for types 'inet' and 'integer'
 CREATE TABLE FKTABLE (ftest1 varchar REFERENCES pktable);
 NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
 DROP TABLE FKTABLE;
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
 -- As should this
 CREATE TABLE FKTABLE (ftest1 varchar REFERENCES pktable(ptest1));
 NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
 DROP TABLE FKTABLE;
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
 DROP TABLE PKTABLE;
 -- Two columns, two tables
 CREATE TABLE PKTABLE (ptest1 int, ptest2 inet, PRIMARY KEY(ptest1, ptest2));
@@ -775,14 +766,10 @@ ERROR:  Unable to identify an operator '=' for types 'integer' and 'inet'
 CREATE TABLE FKTABLE (ftest1 int, ftest2 inet, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable(ptest2, ptest1));
 NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
 DROP TABLE FKTABLE;
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
 -- As does this
 CREATE TABLE FKTABLE (ftest1 int, ftest2 inet, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable(ptest1, ptest2));
 NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
 DROP TABLE FKTABLE;
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
 DROP TABLE PKTABLE;
 -- Two columns, same table
 -- Make sure this still works...
@@ -832,25 +819,23 @@ insert into pktable(base1) values (1);
 insert into pktable(base1) values (2);
 --  let's insert a non-existant fktable value
 insert into fktable(ftest1) values (3);
-ERROR:  <unnamed> referential integrity violation - key referenced from fktable not found in pktable
+ERROR:  $1 referential integrity violation - key referenced from fktable not found in pktable
 --  let's make a valid row for that
 insert into pktable(base1) values (3);
 insert into fktable(ftest1) values (3);
 -- let's try removing a row that should fail from pktable
 delete from pktable where base1>2;
-ERROR:  <unnamed> referential integrity violation - key in pktable still referenced from fktable
+ERROR:  $1 referential integrity violation - key in pktable still referenced from fktable
 -- okay, let's try updating all of the base1 values to *4
 -- which should fail.
 update pktable set base1=base1*4;
-ERROR:  <unnamed> referential integrity violation - key in pktable still referenced from fktable
+ERROR:  $1 referential integrity violation - key in pktable still referenced from fktable
 -- okay, let's try an update that should work.
 update pktable set base1=base1*4 where base1<3;
 -- and a delete that should work
 delete from pktable where base1>3;
 -- cleanup
 drop table fktable;
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
 delete from pktable;
 -- Now 2 columns 2 tables, matching types
 create table fktable (ftest1 int, ftest2 int, foreign key(ftest1, ftest2) references pktable(base1, ptest1));
@@ -860,25 +845,23 @@ insert into pktable(base1, ptest1) values (1, 1);
 insert into pktable(base1, ptest1) values (2, 2);
 --  let's insert a non-existant fktable value
 insert into fktable(ftest1, ftest2) values (3, 1);
-ERROR:  <unnamed> referential integrity violation - key referenced from fktable not found in pktable
+ERROR:  $1 referential integrity violation - key referenced from fktable not found in pktable
 --  let's make a valid row for that
 insert into pktable(base1,ptest1) values (3, 1);
 insert into fktable(ftest1, ftest2) values (3, 1);
 -- let's try removing a row that should fail from pktable
 delete from pktable where base1>2;
-ERROR:  <unnamed> referential integrity violation - key in pktable still referenced from fktable
+ERROR:  $1 referential integrity violation - key in pktable still referenced from fktable
 -- okay, let's try updating all of the base1 values to *4
 -- which should fail.
 update pktable set base1=base1*4;
-ERROR:  <unnamed> referential integrity violation - key in pktable still referenced from fktable
+ERROR:  $1 referential integrity violation - key in pktable still referenced from fktable
 -- okay, let's try an update that should work.
 update pktable set base1=base1*4 where base1<3;
 -- and a delete that should work
 delete from pktable where base1>3;
 -- cleanup
 drop table fktable;
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
-NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
 drop table pktable;
 drop table pktable_base;
 -- Now we'll do one all in 1 table with 2 columns of matching types
@@ -893,13 +876,13 @@ insert into pktable (base1, ptest1, base2, ptest2) values (2, 2, 2, 1);
 insert into pktable (base1, ptest1, base2, ptest2) values (1, 3, 2, 2);
 -- fails (3,2) isn't in base1, ptest1
 insert into pktable (base1, ptest1, base2, ptest2) values (2, 3, 3, 2);
-ERROR:  <unnamed> referential integrity violation - key referenced from pktable not found in pktable
+ERROR:  $1 referential integrity violation - key referenced from pktable not found in pktable
 -- fails (2,2) is being referenced
 delete from pktable where base1=2;
-ERROR:  <unnamed> referential integrity violation - key in pktable still referenced from pktable
+ERROR:  $1 referential integrity violation - key in pktable still referenced from pktable
 -- fails (1,1) is being referenced (twice)
 update pktable set base1=3 where base1=1;
-ERROR:  <unnamed> referential integrity violation - key referenced from pktable not found in pktable
+ERROR:  $1 referential integrity violation - key referenced from pktable not found in pktable
 -- this sequence of two deletes will work, since after the first there will be no (2,*) references
 delete from pktable where base2=2;
 delete from pktable where base1=2;
diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out
index 37544dd0ccb1f1956d212145cd8c60506f12668a..2e0cf3a03300daa482a2aba217aa99510c74f103 100644
--- a/src/test/regress/expected/sanity_check.out
+++ b/src/test/regress/expected/sanity_check.out
@@ -38,8 +38,10 @@ SELECT relname, relhasindex
  pg_attrdef          | t
  pg_attribute        | t
  pg_class            | t
+ pg_constraint       | t
  pg_conversion       | t
  pg_database         | t
+ pg_depend           | t
  pg_description      | t
  pg_group            | t
  pg_index            | t
@@ -50,7 +52,6 @@ SELECT relname, relhasindex
  pg_opclass          | t
  pg_operator         | t
  pg_proc             | t
- pg_relcheck         | t
  pg_rewrite          | t
  pg_shadow           | t
  pg_statistic        | t
@@ -61,5 +62,5 @@ SELECT relname, relhasindex
  shighway            | t
  tenk1               | t
  tenk2               | t
-(51 rows)
+(52 rows)
 
diff --git a/src/test/regress/output/constraints.source b/src/test/regress/output/constraints.source
index 3dafd9a87719bcc26895f6ffd05d4869c5d24830..8935dae873468b710d4107d17a5f90a488e879a1 100644
--- a/src/test/regress/output/constraints.source
+++ b/src/test/regress/output/constraints.source
@@ -123,7 +123,7 @@ INSERT INTO INSERT_TBL(y) VALUES ('Y');
 ERROR:  ExecInsert: rejected due to CHECK constraint insert_con
 INSERT INTO INSERT_TBL(y) VALUES ('Y');
 INSERT INTO INSERT_TBL(x,z) VALUES (1, -2);
-ERROR:  ExecInsert: rejected due to CHECK constraint $2
+ERROR:  ExecInsert: rejected due to CHECK constraint $1
 INSERT INTO INSERT_TBL(z,x) VALUES (-7,  7);
 INSERT INTO INSERT_TBL VALUES (5, 'check failed', -5);
 ERROR:  ExecInsert: rejected due to CHECK constraint insert_con
@@ -139,7 +139,7 @@ SELECT '' AS four, * FROM INSERT_TBL;
 (4 rows)
 
 INSERT INTO INSERT_TBL(y,z) VALUES ('check failed', 4);
-ERROR:  ExecInsert: rejected due to CHECK constraint $2
+ERROR:  ExecInsert: rejected due to CHECK constraint $1
 INSERT INTO INSERT_TBL(x,y) VALUES (5, 'check failed');
 ERROR:  ExecInsert: rejected due to CHECK constraint insert_con
 INSERT INTO INSERT_TBL(x,y) VALUES (5, '!check failed');
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
index a46e5aaa22fe94229871fe959866b3e2623c73fe..f39998073d78e1776e21dd40b7aed6b8ba956d31 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -250,7 +250,7 @@ CREATE TEMP TABLE FKTABLE (ftest1 varchar);
 ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable;
 -- As should this
 ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable(ptest1);
-DROP TABLE pktable;
+DROP TABLE pktable cascade;
 DROP TABLE fktable;
 
 CREATE TEMP TABLE PKTABLE (ptest1 int, ptest2 inet,
@@ -258,13 +258,13 @@ CREATE TEMP TABLE PKTABLE (ptest1 int, ptest2 inet,
 -- This should fail, because we just chose really odd types
 CREATE TEMP TABLE FKTABLE (ftest1 cidr, ftest2 timestamp);
 ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2) references pktable;
--- Again, so should this...
 DROP TABLE FKTABLE;
+-- Again, so should this...
 CREATE TEMP TABLE FKTABLE (ftest1 cidr, ftest2 timestamp);
 ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2)
      references pktable(ptest1, ptest2);
--- This fails because we mixed up the column ordering
 DROP TABLE FKTABLE;
+-- This fails because we mixed up the column ordering
 CREATE TEMP TABLE FKTABLE (ftest1 int, ftest2 inet);
 ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2)
      references pktable(ptest2, ptest1);
@@ -486,7 +486,7 @@ alter table foo alter column bar drop not null;
 create table atacc1 (test int not null);
 alter table atacc1 add constraint "atacc1_pkey" primary key (test);
 alter table atacc1 alter column test drop not null;
-drop index atacc1_pkey;
+alter table atacc1 drop constraint "atacc1_pkey";
 alter table atacc1 alter column test drop not null;
 insert into atacc1 values (null);
 alter table atacc1 alter test set not null;
diff --git a/src/test/regress/sql/domain.sql b/src/test/regress/sql/domain.sql
index 055c377decb872883f2ce60c19be3864b07d7afa..77dccb2aaca430888010c763b9c9dfc9452e3223 100644
--- a/src/test/regress/sql/domain.sql
+++ b/src/test/regress/sql/domain.sql
@@ -4,11 +4,14 @@
 create domain domaindroptest int4;
 comment on domain domaindroptest is 'About to drop this..';
 
+-- currently this will be disallowed
 create domain basetypetest domaindroptest;
 
-drop domain domaindroptest cascade;
 drop domain domaindroptest;
 
+-- this should fail because already gone
+drop domain domaindroptest cascade;
+
 
 -- TEST Domains.
 
diff --git a/src/test/regress/sql/foreign_key.sql b/src/test/regress/sql/foreign_key.sql
index a7cb5842233a92827414c477a29f91c4168ce02a..c6b50e4b32edd1316bb16243d75ab8a3692da881 100644
--- a/src/test/regress/sql/foreign_key.sql
+++ b/src/test/regress/sql/foreign_key.sql
@@ -40,8 +40,8 @@ UPDATE PKTABLE SET ptest1=1 WHERE ptest1=2;
 -- Check FKTABLE for update of matched row
 SELECT * FROM FKTABLE;
 
-DROP TABLE PKTABLE;
 DROP TABLE FKTABLE;
+DROP TABLE PKTABLE;
 
 --
 -- check set NULL and table constraint on multiple columns
@@ -92,7 +92,7 @@ UPDATE PKTABLE SET ptest1=1 WHERE ptest1=2;
 -- Check FKTABLE for update of matched row
 SELECT * FROM FKTABLE;
 
-DROP TABLE PKTABLE;
+DROP TABLE PKTABLE CASCADE;
 DROP TABLE FKTABLE;
 
 --
@@ -147,7 +147,9 @@ UPDATE PKTABLE SET ptest1=1 WHERE ptest1=2;
 -- Check FKTABLE for update of matched row
 SELECT * FROM FKTABLE;
 
+-- this should fail for lack of CASCADE
 DROP TABLE PKTABLE;
+DROP TABLE PKTABLE CASCADE;
 DROP TABLE FKTABLE;
 
 
@@ -197,8 +199,8 @@ UPDATE PKTABLE SET ptest1=0 WHERE ptest1=4;
 -- Check PKTABLE for updates
 SELECT * FROM PKTABLE;
 
-DROP TABLE PKTABLE;
 DROP TABLE FKTABLE;
+DROP TABLE PKTABLE;
 
 
 -- MATCH unspecified