diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 26fa62417fed3c1b6a0459c4decb35f2c71328fe..d396f070ddda0e380498238e04f5b0f41f084486 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -829,8 +829,9 @@ dblink_replace_text(PG_FUNCTION_ARGS)
 		left_text = DatumGetTextP(DirectFunctionCall3(text_substr, PointerGetDatum(buf_text), 1, DatumGetInt32(DirectFunctionCall2(textpos, PointerGetDatum(buf_text), PointerGetDatum(from_sub_text))) - 1));
 		right_text = DatumGetTextP(DirectFunctionCall3(text_substr, PointerGetDatum(buf_text), DatumGetInt32(DirectFunctionCall2(textpos, PointerGetDatum(buf_text), PointerGetDatum(from_sub_text))) + from_sub_text_len, -1));
 
-		appendStringInfo(str, DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(left_text))));
-		appendStringInfo(str, to_sub_str);
+		appendStringInfo(str, "%s",
+						 DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(left_text))));
+		appendStringInfo(str, "%s", to_sub_str);
 
 		pfree(buf_text);
 		pfree(left_text);
@@ -838,7 +839,8 @@ dblink_replace_text(PG_FUNCTION_ARGS)
 		curr_posn = DatumGetInt32(DirectFunctionCall2(textpos, PointerGetDatum(buf_text), PointerGetDatum(from_sub_text)));
 	}
 
-	appendStringInfo(str, DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(buf_text))));
+	appendStringInfo(str, "%s",
+					 DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(buf_text))));
 	pfree(buf_text);
 
 	ret_str = pstrdup(str->data);
@@ -1013,10 +1015,11 @@ get_sql_insert(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval
 	TupleDesc		tupdesc;
 	int				natts;
 	StringInfo		str = makeStringInfo();
-	char			*sql = NULL;
-	char			*val = NULL;
+	char			*sql;
+	char			*val;
 	int16			key;
-	unsigned int	i;
+	int				i;
+	bool			needComma;
 
 	/*
 	 * Open relation using relid
@@ -1029,12 +1032,19 @@ get_sql_insert(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval
 	tuple = get_tuple_of_interest(relid, pkattnums, pknumatts, src_pkattvals);
 
 	appendStringInfo(str, "INSERT INTO %s(", quote_ident_cstr(relname));
+
+	needComma = false;
 	for (i = 0; i < natts; i++)
 	{
-		if (i > 0)
+		if (tupdesc->attrs[i]->attisdropped)
+			continue;
+
+		if (needComma)
 			appendStringInfo(str, ",");
 
-		appendStringInfo(str, NameStr(tupdesc->attrs[i]->attname));
+		appendStringInfo(str, "%s",
+						 quote_ident_cstr(NameStr(tupdesc->attrs[i]->attname)));
+		needComma = true;
 	}
 
 	appendStringInfo(str, ") VALUES(");
@@ -1042,9 +1052,13 @@ get_sql_insert(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval
 	/*
 	 * remember attvals are 1 based
 	 */
+	needComma = false;
 	for (i = 0; i < natts; i++)
 	{
-		if (i > 0)
+		if (tupdesc->attrs[i]->attisdropped)
+			continue;
+
+		if (needComma)
 			appendStringInfo(str, ",");
 
 		if (tgt_pkattvals != NULL)
@@ -1059,11 +1073,12 @@ get_sql_insert(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval
 
 		if (val != NULL)
 		{
-			appendStringInfo(str, quote_literal_cstr(val));
+			appendStringInfo(str, "%s", quote_literal_cstr(val));
 			pfree(val);
 		}
 		else
 			appendStringInfo(str, "NULL");
+		needComma = true;
 	}
 	appendStringInfo(str, ")");
 
@@ -1083,9 +1098,9 @@ get_sql_delete(Oid relid, int16 *pkattnums, int16 pknumatts, char **tgt_pkattval
 	TupleDesc		tupdesc;
 	int				natts;
 	StringInfo		str = makeStringInfo();
-	char			*sql = NULL;
-	char			*val = NULL;
-	unsigned int	i;
+	char			*sql;
+	char			*val;
+	int				i;
 
 	/*
 	 * Open relation using relid
@@ -1103,21 +1118,24 @@ get_sql_delete(Oid relid, int16 *pkattnums, int16 pknumatts, char **tgt_pkattval
 		if (i > 0)
 			appendStringInfo(str, " AND ");
 
-		appendStringInfo(str, NameStr(tupdesc->attrs[pkattnum - 1]->attname));
+		appendStringInfo(str, "%s",
+						 quote_ident_cstr(NameStr(tupdesc->attrs[pkattnum - 1]->attname)));
 
 		if (tgt_pkattvals != NULL)
 			val = pstrdup(tgt_pkattvals[i]);
 		else
+		{
 			elog(ERROR, "Target key array must not be NULL");
+			val = NULL;			/* keep compiler quiet */
+		}
 
 		if (val != NULL)
 		{
-			appendStringInfo(str, "=");
-			appendStringInfo(str, quote_literal_cstr(val));
+			appendStringInfo(str, " = %s", quote_literal_cstr(val));
 			pfree(val);
 		}
 		else
-			appendStringInfo(str, "IS NULL");
+			appendStringInfo(str, " IS NULL");
 	}
 
 	sql = pstrdup(str->data);
@@ -1137,10 +1155,11 @@ get_sql_update(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval
 	TupleDesc		tupdesc;
 	int				natts;
 	StringInfo		str = makeStringInfo();
-	char			*sql = NULL;
-	char			*val = NULL;
+	char			*sql;
+	char			*val;
 	int16			key;
 	int				i;
+	bool			needComma;
 
 	/*
 	 * Open relation using relid
@@ -1154,13 +1173,17 @@ get_sql_update(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval
 
 	appendStringInfo(str, "UPDATE %s SET ", quote_ident_cstr(relname));
 
+	needComma = false;
 	for (i = 0; i < natts; i++)
 	{
-		if (i > 0)
-			appendStringInfo(str, ",");
+		if (tupdesc->attrs[i]->attisdropped)
+			continue;
+
+		if (needComma)
+			appendStringInfo(str, ", ");
 
-		appendStringInfo(str, NameStr(tupdesc->attrs[i]->attname));
-		appendStringInfo(str, "=");
+		appendStringInfo(str, "%s = ",
+						 quote_ident_cstr(NameStr(tupdesc->attrs[i]->attname)));
 
 		if (tgt_pkattvals != NULL)
 			key = get_attnum_pk_pos(pkattnums, pknumatts, i + 1);
@@ -1174,11 +1197,12 @@ get_sql_update(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval
 
 		if (val != NULL)
 		{
-			appendStringInfo(str, quote_literal_cstr(val));
+			appendStringInfo(str, "%s", quote_literal_cstr(val));
 			pfree(val);
 		}
 		else
 			appendStringInfo(str, "NULL");
+		needComma = true;
 	}
 
 	appendStringInfo(str, " WHERE ");
@@ -1190,7 +1214,8 @@ get_sql_update(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval
 		if (i > 0)
 			appendStringInfo(str, " AND ");
 
-		appendStringInfo(str, NameStr(tupdesc->attrs[pkattnum - 1]->attname));
+		appendStringInfo(str, "%s",
+						 quote_ident_cstr(NameStr(tupdesc->attrs[pkattnum - 1]->attname)));
 
 		if (tgt_pkattvals != NULL)
 			val = pstrdup(tgt_pkattvals[i]);
@@ -1199,12 +1224,11 @@ get_sql_update(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval
 
 		if (val != NULL)
 		{
-			appendStringInfo(str, "=");
-			appendStringInfo(str, quote_literal_cstr(val));
+			appendStringInfo(str, " = %s", quote_literal_cstr(val));
 			pfree(val);
 		}
 		else
-			appendStringInfo(str, "IS NULL");
+			appendStringInfo(str, " IS NULL");
 	}
 
 	sql = pstrdup(str->data);
@@ -1297,7 +1321,7 @@ get_tuple_of_interest(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_p
 	 * Build sql statement to look up tuple of interest
 	 * Use src_pkattvals as the criteria.
 	 */
-	appendStringInfo(str, "SELECT * from %s WHERE ", relname);
+	appendStringInfo(str, "SELECT * FROM %s WHERE ", quote_ident_cstr(relname));
 
 	for (i = 0; i < pknumatts; i++)
 	{
@@ -1306,17 +1330,17 @@ get_tuple_of_interest(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_p
 		if (i > 0)
 			appendStringInfo(str, " AND ");
 
-		appendStringInfo(str, NameStr(tupdesc->attrs[pkattnum - 1]->attname));
+		appendStringInfo(str, "%s",
+						 quote_ident_cstr(NameStr(tupdesc->attrs[pkattnum - 1]->attname)));
 
 		val = pstrdup(src_pkattvals[i]);
 		if (val != NULL)
 		{
-			appendStringInfo(str, "=");
-			appendStringInfo(str, quote_literal_cstr(val));
+			appendStringInfo(str, " = %s", quote_literal_cstr(val));
 			pfree(val);
 		}
 		else
-			appendStringInfo(str, "IS NULL");
+			appendStringInfo(str, " IS NULL");
 	}
 
 	sql = pstrdup(str->data);
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 8bf4bf816f0ef6ad5dcee0fa6aab964f16a723af..573815388fed56e1a677937fd98047bd3d44007e 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.50 2002/07/31 17:19:49 tgl Exp $
+ $Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.51 2002/08/02 18:15:04 tgl Exp $
  -->
 
 <chapter id="catalogs">
@@ -810,6 +810,17 @@
       </entry>
      </row>
 
+     <row>
+      <entry>attisdropped</entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>
+       This column has been dropped and is no longer valid.  A dropped
+       column is still physically present in the table, but is
+       ignored by the parser and so cannot be accessed via SQL.
+      </entry>
+     </row>
+
     </tbody>
    </tgroup>
   </table>
diff --git a/doc/src/sgml/ref/alter_table.sgml b/doc/src/sgml/ref/alter_table.sgml
index 11da9fdf60c1c952006c86053e8900e7e6e874c0..0bfe88cf54d4d84d587b7ce9bf6c72e7f23d6cc4 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.47 2002/07/31 17:19:50 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.48 2002/08/02 18:15:04 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -23,6 +23,8 @@ PostgreSQL documentation
   <synopsis>
 ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ * ]
     ADD [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> <replaceable class="PARAMETER">type</replaceable> [ <replaceable class="PARAMETER">column_constraint</replaceable> [ ... ] ]
+ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ * ]
+    DROP [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> [ RESTRICT | CASCADE ]
 ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ * ]
     ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> { SET DEFAULT <replaceable class="PARAMETER">value</replaceable> | DROP DEFAULT }
 ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ * ]
@@ -126,6 +128,26 @@ ALTER TABLE <replaceable class="PARAMETER">table</replaceable>
       </listitem>
      </varlistentry>
 
+     <varlistentry>
+      <term>CASCADE</term>
+      <listitem>
+       <para>
+        Automatically drop objects that depend on the dropped column
+	or constraint (for example, views referencing the column).
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term>RESTRICT</term>
+      <listitem>
+       <para>
+        Refuse to drop the column or constraint if there are any dependent
+	objects. This is the default behavior.
+       </para>
+      </listitem>
+     </varlistentry>
+
     </variablelist>
    </para>
   </refsect2>
@@ -186,6 +208,19 @@ ALTER TABLE <replaceable class="PARAMETER">table</replaceable>
     </listitem>
    </varlistentry>
 
+   <varlistentry>
+    <term>DROP COLUMN</term>
+    <listitem>
+     <para>
+      This form drops a column from a table.  Note that indexes and
+      table constraints involving the column will be automatically
+      dropped as well.  You will need to say <literal>CASCADE</> if
+      anything outside the table depends on the column --- for example,
+      foreign key references, views, etc.
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry>
     <term>SET/DROP DEFAULT</term>
     <listitem>
@@ -317,6 +352,22 @@ ALTER TABLE <replaceable class="PARAMETER">table</replaceable>
     form after you've entered non-null values for the column in all rows.
    </para>
 
+   <para>
+    The <literal>DROP COLUMN</literal> command does not physically remove
+    the column, but simply makes it invisible to SQL operations.  Subsequent
+    inserts and updates of the table will store a NULL for the column.
+    Thus, dropping a column is quick but it will not immediately reduce the
+    on-disk size of your table, as the space occupied 
+    by the dropped column is not reclaimed.  The space will be
+    reclaimed over time as existing rows are updated.
+    To reclaim the space at once, do a dummy <command>UPDATE</> of all rows
+    and then vacuum, as in:
+     <programlisting>
+UPDATE table SET col = col;
+VACUUM FULL table;
+    </programlisting>
+   </para>
+
    <para>
     Changing any  part  of  the schema of a system
     catalog is not permitted.
@@ -342,6 +393,13 @@ ALTER TABLE distributors ADD COLUMN address VARCHAR(30);
    </programlisting>
   </para>
 
+  <para>
+   To drop a column from a table:
+   <programlisting>
+ALTER TABLE distributors DROP COLUMN address RESTRICT;
+   </programlisting>
+  </para>
+
   <para>
    To rename an existing column:
    <programlisting>
@@ -420,38 +478,6 @@ ALTER TABLE distributors ADD PRIMARY KEY (dist_id);
      The <literal>ALTER COLUMN</literal> form is in full compliance.
     </para>
 
-    <para>
-     SQL92 specifies some additional capabilities for <command>ALTER TABLE</command>
-     statement which are not yet directly supported by <productname>PostgreSQL</productname>:
-
-    <variablelist>
-    <varlistentry>
-     <term>
-      <synopsis>
-ALTER TABLE <replaceable class="PARAMETER">table</replaceable> DROP [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> { RESTRICT | CASCADE }
-      </synopsis>
-     </term>
-     <listitem>
-      <para>
-       Removes a column from a table.
-       Currently, to remove an existing column the table must be
-       recreated and reloaded:
-       <programlisting>
-CREATE TABLE temp AS SELECT did, city FROM distributors;    
-DROP TABLE distributors;
-CREATE TABLE distributors (
-    did      DECIMAL(3)  DEFAULT 1,
-    name     VARCHAR(40) NOT NULL
-);
-INSERT INTO distributors SELECT * FROM temp;
-DROP TABLE temp;
-       </programlisting>
-      </para>
-     </listitem>
-    </varlistentry>
-   </variablelist>
-   </para>
-
    <para>
     The clauses to rename tables, columns, indexes, and sequences are
     <productname>PostgreSQL</productname> extensions from SQL92.
diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 484b0a620871f07cc3143611749aea6119202d03..d09b6706dd0e8d0f04d14e23a92d220d53406daa 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/copy.sgml,v 1.34 2002/07/30 16:55:05 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/copy.sgml,v 1.35 2002/08/02 18:15:04 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -21,16 +21,14 @@ PostgreSQL documentation
    <date>1999-12-11</date>
   </refsynopsisdivinfo>
   <synopsis>
-COPY <replaceable class="parameter">table</replaceable> 
-    [ ( <replaceable class="parameter">column</replaceable> [, ...] ) ]
+COPY <replaceable class="parameter">table</replaceable> [ ( <replaceable class="parameter">column</replaceable> [, ...] ) ]
     FROM { '<replaceable class="parameter">filename</replaceable>' | <filename>stdin</filename> }
     [ [ WITH ] 
           [ BINARY ] 
           [ OIDS ]
           [ DELIMITER [ AS ] '<replaceable class="parameter">delimiter</replaceable>' ]
           [ NULL [ AS ] '<replaceable class="parameter">null string</replaceable>' ] ]
-COPY <replaceable class="parameter">table</replaceable>
-    [ ( <replaceable class="parameter">column</replaceable> [, ...] ) ]
+COPY <replaceable class="parameter">table</replaceable> [ ( <replaceable class="parameter">column</replaceable> [, ...] ) ]
     TO { '<replaceable class="parameter">filename</replaceable>' | <filename>stdout</filename> }
     [ [ WITH ] 
           [ BINARY ]
@@ -201,10 +199,10 @@ ERROR: <replaceable>reason</replaceable>
 
   <para>
    If a list of columns is specified, <command>COPY</command> will
-   only copy the data in the specified columns to or from the table.
-   If there are any columns in the table that are not in the table,
-   <command>COPY FROM</command> will insert the default value for
-   that column.
+   only copy the data in the specified columns to or from the file.
+   If there are any columns in the table that are not in the file,
+   <command>COPY FROM</command> will insert the default values for
+   those columns.
   </para>
 
   <para>
@@ -266,8 +264,8 @@ ERROR: <replaceable>reason</replaceable>
    </para>
 
    <para>
-    <command>COPY FROM</command> will invoke any triggers or check
-	constraints. However, it will not invoke rules.
+    <command>COPY FROM</command> will invoke any triggers and check
+    constraints on the destination table. However, it will not invoke rules.
    </para>
 
    <para>
@@ -330,12 +328,9 @@ ERROR: <replaceable>reason</replaceable>
     The attribute values themselves are strings generated by the
     output function, or acceptable to the input function, of each
     attribute's data type.  The specified null-value string is used in
-    place of attributes that are NULL.  When using <command>COPY
-	FROM</command> without a column list, each row of the input file
-	must contain data for each attribute in the table: no missing data
-	is allowed.  Similarly, <command>COPY FROM</command> will raise
-	an error if it encounters any data in the input file that would
-	not be inserted into the table: extra data is not allowed.
+    place of attributes that are NULL.
+    <command>COPY FROM</command> will raise an error if any line of the
+    input file contains more or fewer columns than are expected.
    </para>
    <para>
     If OIDS is specified, the OID is read or written as the first column,
diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml
index af82154d8c7a650132fe83999b70e26cbf140d71..0da3d9ef2983e68d53c5d4f8f210552e276a29f9 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.144 2002/07/29 22:14:10 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.145 2002/08/02 18:15:04 tgl Exp $
 -->
 
 <appendix id="release">
@@ -24,6 +24,8 @@ CDATA means the content is "SGML-free", so you can write without
 worries about funny characters.
 -->
 <literallayout><![CDATA[
+COPY accepts a list of columns to copy
+ALTER TABLE DROP COLUMN
 CREATE OPERATOR CLASS/DROP OPERATOR CLASS
 CREATE CAST/DROP CAST
 Sequences created by SERIAL column definitions now auto-drop with the column
diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c
index 1eb62dea91a0d5529dfa59ef8165b90f31a96fb4..249be8700021127f0e927b9f2d84070de87d52e4 100644
--- a/src/backend/access/common/tupdesc.c
+++ b/src/backend/access/common/tupdesc.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.82 2002/07/31 17:19:51 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.83 2002/08/02 18:15:04 tgl Exp $
  *
  * NOTES
  *	  some of the executor utility code such as "ExecTypeFromTL" should be
@@ -111,7 +111,7 @@ CreateTupleDescCopy(TupleDesc tupdesc)
 	for (i = 0; i < desc->natts; i++)
 	{
 		desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
-		memmove(desc->attrs[i],
+		memcpy(desc->attrs[i],
 				tupdesc->attrs[i],
 				ATTRIBUTE_TUPLE_SIZE);
 		desc->attrs[i]->attnotnull = false;
@@ -146,7 +146,7 @@ CreateTupleDescCopyConstr(TupleDesc tupdesc)
 	for (i = 0; i < desc->natts; i++)
 	{
 		desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
-		memmove(desc->attrs[i],
+		memcpy(desc->attrs[i],
 				tupdesc->attrs[i],
 				ATTRIBUTE_TUPLE_SIZE);
 	}
@@ -263,6 +263,8 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
 			return false;
 		if (attr1->attnotnull != attr2->attnotnull)
 			return false;
+		if (attr1->attisdropped != attr2->attisdropped)
+			return false;
 	}
 	if (tupdesc1->constr != NULL)
 	{
@@ -385,6 +387,7 @@ TupleDescInitEntry(TupleDesc desc,
 
 	att->attnotnull = false;
 	att->atthasdef = false;
+	att->attisdropped = false;
 
 	tuple = SearchSysCache(TYPEOID,
 						   ObjectIdGetDatum(oidtypeid),
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 4300c0211dae279c4c59eb7c882258f4e1fa239d..f48c8389ce6227a66d2c352d10bd3494b3e0097b 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.133 2002/07/20 05:16:56 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.134 2002/08/02 18:15:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -522,19 +522,6 @@ boot_openrel(char *relname)
 				(char *) boot_reldesc->rd_att->attrs[i],
 				ATTRIBUTE_TUPLE_SIZE);
 
-		/* Some old pg_attribute tuples might not have attisset. */
-
-		/*
-		 * If the attname is attisset, don't look for it - it may not be
-		 * defined yet.
-		 */
-		if (namestrcmp(&attrtypes[i]->attname, "attisset") == 0)
-			attrtypes[i]->attisset =
-				get_attisset(RelationGetRelid(boot_reldesc),
-							 NameStr(attrtypes[i]->attname));
-		else
-			attrtypes[i]->attisset = false;
-
 		{
 			Form_pg_attribute at = attrtypes[i];
 
@@ -598,15 +585,19 @@ DefineAttr(char *name, char *type, int attnum)
 		closerel(relname);
 	}
 
-	typeoid = gettype(type);
 	if (attrtypes[attnum] == (Form_pg_attribute) NULL)
 		attrtypes[attnum] = AllocateAttribute();
+	MemSet(attrtypes[attnum], 0, ATTRIBUTE_TUPLE_SIZE);
+
+	namestrcpy(&attrtypes[attnum]->attname, name);
+	elog(DEBUG3, "column %s %s", NameStr(attrtypes[attnum]->attname), type);
+	attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */
+
+	typeoid = gettype(type);
+
 	if (Typ != (struct typmap **) NULL)
 	{
 		attrtypes[attnum]->atttypid = Ap->am_oid;
-		namestrcpy(&attrtypes[attnum]->attname, name);
-		elog(DEBUG3, "column %s %s", NameStr(attrtypes[attnum]->attname), type);
-		attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */
 		attlen = attrtypes[attnum]->attlen = Ap->am_typ.typlen;
 		attrtypes[attnum]->attbyval = Ap->am_typ.typbyval;
 		attrtypes[attnum]->attstorage = Ap->am_typ.typstorage;
@@ -615,9 +606,6 @@ DefineAttr(char *name, char *type, int attnum)
 	else
 	{
 		attrtypes[attnum]->atttypid = Procid[typeoid].oid;
-		namestrcpy(&attrtypes[attnum]->attname, name);
-		elog(DEBUG3, "column %s %s", NameStr(attrtypes[attnum]->attname), type);
-		attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */
 		attlen = attrtypes[attnum]->attlen = Procid[typeoid].len;
 
 		/*
@@ -656,6 +644,23 @@ DefineAttr(char *name, char *type, int attnum)
 	}
 	attrtypes[attnum]->attcacheoff = -1;
 	attrtypes[attnum]->atttypmod = -1;
+	/*
+	 * Mark as "not null" if type is fixed-width and prior columns are too.
+	 * This corresponds to case where column can be accessed directly via
+	 * C struct declaration.
+	 */
+	if (attlen > 0)
+	{
+		int		i;
+
+		for (i = 0; i < attnum; i++)
+		{
+			if (attrtypes[i]->attlen <= 0)
+				break;
+		}
+		if (i == attnum)
+			attrtypes[attnum]->attnotnull = true;
+	}
 }
 
 
@@ -896,8 +901,8 @@ gettype(char *type)
  *		AllocateAttribute
  * ----------------
  */
-static Form_pg_attribute		/* XXX */
-AllocateAttribute()
+static Form_pg_attribute
+AllocateAttribute(void)
 {
 	Form_pg_attribute attribute = (Form_pg_attribute) malloc(ATTRIBUTE_TUPLE_SIZE);
 
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index ae88c4bf0551b8e17b93525e4ee8a22c8370f3f0..d51c8d589a944109f4797e7a38a3ed31cb711d17 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.7 2002/07/29 22:14:10 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.8 2002/08/02 18:15:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -567,7 +567,8 @@ doDeletion(const ObjectAddress *object)
 			else
 			{
 				if (object->objectSubId != 0)
-					elog(ERROR, "DROP COLUMN not implemented yet");
+					RemoveAttributeById(object->objectId,
+										object->objectSubId);
 				else
 					heap_drop_with_catalog(object->objectId);
 			}
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 6045c17bb6a16c54d063b1eb33399c0bacb88d16..ec9165c55b18cb0f05e14f6f6988111bf435b68c 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.214 2002/07/31 17:19:51 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.215 2002/08/02 18:15:05 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -97,37 +97,37 @@ static void RemoveStatistics(Relation rel);
 static FormData_pg_attribute a1 = {
 	0, {"ctid"}, TIDOID, 0, sizeof(ItemPointerData),
 	SelfItemPointerAttributeNumber, 0, -1, -1,
-	false, 'p', false, 'i', true, false
+	false, 'p', false, 'i', true, false, false
 };
 
 static FormData_pg_attribute a2 = {
 	0, {"oid"}, OIDOID, 0, sizeof(Oid),
 	ObjectIdAttributeNumber, 0, -1, -1,
-	true, 'p', false, 'i', true, false
+	true, 'p', false, 'i', true, false, false
 };
 
 static FormData_pg_attribute a3 = {
 	0, {"xmin"}, XIDOID, 0, sizeof(TransactionId),
 	MinTransactionIdAttributeNumber, 0, -1, -1,
-	true, 'p', false, 'i', true, false
+	true, 'p', false, 'i', true, false, false
 };
 
 static FormData_pg_attribute a4 = {
 	0, {"cmin"}, CIDOID, 0, sizeof(CommandId),
 	MinCommandIdAttributeNumber, 0, -1, -1,
-	true, 'p', false, 'i', true, false
+	true, 'p', false, 'i', true, false, false
 };
 
 static FormData_pg_attribute a5 = {
 	0, {"xmax"}, XIDOID, 0, sizeof(TransactionId),
 	MaxTransactionIdAttributeNumber, 0, -1, -1,
-	true, 'p', false, 'i', true, false
+	true, 'p', false, 'i', true, false, false
 };
 
 static FormData_pg_attribute a6 = {
 	0, {"cmax"}, CIDOID, 0, sizeof(CommandId),
 	MaxCommandIdAttributeNumber, 0, -1, -1,
-	true, 'p', false, 'i', true, false
+	true, 'p', false, 'i', true, false, false
 };
 
 /*
@@ -139,7 +139,7 @@ static FormData_pg_attribute a6 = {
 static FormData_pg_attribute a7 = {
 	0, {"tableoid"}, OIDOID, 0, sizeof(Oid),
 	TableOidAttributeNumber, 0, -1, -1,
-	true, 'p', false, 'i', true, false
+	true, 'p', false, 'i', true, false, false
 };
 
 static Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7};
@@ -892,6 +892,78 @@ DeleteAttributeTuples(Oid relid)
 	heap_close(attrel, RowExclusiveLock);
 }
 
+/*
+ *		RemoveAttributeById
+ *
+ * This is the guts of ALTER TABLE DROP COLUMN: actually mark the attribute
+ * deleted in pg_attribute.  (Everything else needed, such as getting rid
+ * of any pg_attrdef entry, is handled by dependency.c.)
+ */
+void
+RemoveAttributeById(Oid relid, AttrNumber attnum)
+{
+	Relation	rel;
+	Relation	attr_rel;
+	HeapTuple	tuple;
+	Form_pg_attribute attStruct;
+	char		newattname[NAMEDATALEN];
+
+	/*
+	 * Grab an exclusive lock on the target table, which we will NOT
+	 * release until end of transaction.  (In the simple case where
+	 * we are directly dropping this column, AlterTableDropColumn already
+	 * did this ... but when cascading from a drop of some other object,
+	 * we may not have any lock.)
+	 */
+	rel = heap_open(relid, AccessExclusiveLock);
+
+	attr_rel = heap_openr(AttributeRelationName, RowExclusiveLock);
+
+	tuple = SearchSysCacheCopy(ATTNUM,
+							   ObjectIdGetDatum(relid),
+							   Int16GetDatum(attnum),
+							   0, 0);
+	if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
+		elog(ERROR, "RemoveAttributeById: Failed to find attribute %d in relation %u",
+			 attnum, relid);
+	attStruct = (Form_pg_attribute) GETSTRUCT(tuple);
+
+	/* Mark the attribute as dropped */
+	attStruct->attisdropped = true;
+
+	/* Remove any NOT NULL constraint the column may have */
+	attStruct->attnotnull = false;
+
+	/* We don't want to keep stats for it anymore */
+	attStruct->attstattarget = 0;
+
+	/* Change the column name to something that isn't likely to conflict */
+	snprintf(newattname, NAMEDATALEN, "........pg.dropped.%d........", attnum);
+	namestrcpy(&(attStruct->attname), newattname);
+
+	simple_heap_update(attr_rel, &tuple->t_self, tuple);
+
+	/* keep the system catalog indices current */
+	if (RelationGetForm(attr_rel)->relhasindex)
+	{
+		Relation	idescs[Num_pg_attr_indices];
+
+		CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
+		CatalogIndexInsert(idescs, Num_pg_attr_indices, attr_rel, tuple);
+		CatalogCloseIndices(Num_pg_attr_indices, idescs);
+	}
+
+	/*
+	 * Because updating the pg_attribute row will trigger a relcache flush
+	 * for the target relation, we need not do anything else to notify
+	 * other backends of the change.
+	 */
+
+	heap_close(attr_rel, RowExclusiveLock);
+
+	heap_close(rel, NoLock);
+}
+
 /*
  *		RemoveAttrDefault
  *
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 2a11474e9f5fb26abad98acb37fc610bb8bc4081..2624fdaf25dd5baf43068cb5532b59b1b673897c 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.81 2002/07/24 19:11:09 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.82 2002/08/02 18:15:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -327,9 +327,9 @@ checkretval(Oid rettype, List *queryTreeList)
 	Oid			typerelid;
 	Oid			restype;
 	Relation	reln;
-	Oid			relid;
-	int			relnatts;
-	int			i;
+	int			relnatts;		/* physical number of columns in rel */
+	int			rellogcols;		/* # of nondeleted columns in rel */
+	int			colindex;		/* physical column index */
 
 	/* guard against empty function body; OK only if no return type */
 	if (queryTreeList == NIL)
@@ -404,42 +404,55 @@ checkretval(Oid rettype, List *queryTreeList)
 	/*
 	 * By here, the procedure returns a tuple or set of tuples.  This part
 	 * of the typechecking is a hack. We look up the relation that is the
-	 * declared return type, and be sure that attributes 1 .. n in the
-	 * target list match the declared types.
+	 * declared return type, and scan the non-deleted attributes to ensure
+	 * that they match the datatypes of the non-resjunk columns.
 	 */
 	reln = heap_open(typerelid, AccessShareLock);
-	relid = reln->rd_id;
 	relnatts = reln->rd_rel->relnatts;
+	rellogcols = 0;				/* we'll count nondeleted cols as we go */
+	colindex = 0;
 
-	if (tlistlen != relnatts)
-		elog(ERROR, "function declared to return %s does not SELECT the right number of columns (%d)",
-			 format_type_be(rettype), relnatts);
-
-	/* expect attributes 1 .. n in order */
-	i = 0;
 	foreach(tlistitem, tlist)
 	{
 		TargetEntry *tle = (TargetEntry *) lfirst(tlistitem);
+		Form_pg_attribute attr;
 		Oid			tletype;
 		Oid			atttype;
 
 		if (tle->resdom->resjunk)
 			continue;
+
+		do {
+			colindex++;
+			if (colindex > relnatts)
+				elog(ERROR, "function declared to return %s does not SELECT the right number of columns (%d)",
+					 format_type_be(rettype), rellogcols);
+			attr = reln->rd_att->attrs[colindex - 1];
+		} while (attr->attisdropped);
+		rellogcols++;
+
 		tletype = exprType(tle->expr);
-		atttype = reln->rd_att->attrs[i]->atttypid;
+		atttype = attr->atttypid;
 		if (!IsBinaryCompatible(tletype, atttype))
 			elog(ERROR, "function declared to return %s returns %s instead of %s at column %d",
 				 format_type_be(rettype),
 				 format_type_be(tletype),
 				 format_type_be(atttype),
-				 i + 1);
-		i++;
+				 rellogcols);
+	}
+
+	for (;;)
+	{
+		colindex++;
+		if (colindex > relnatts)
+			break;
+		if (!reln->rd_att->attrs[colindex - 1]->attisdropped)
+			rellogcols++;
 	}
 
-	/* this shouldn't happen, but let's just check... */
-	if (i != relnatts)
+	if (tlistlen != rellogcols)
 		elog(ERROR, "function declared to return %s does not SELECT the right number of columns (%d)",
-			 format_type_be(rettype), relnatts);
+			 format_type_be(rettype), rellogcols);
 
 	heap_close(reln, AccessShareLock);
 }
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 55069aa6feb8b30512e33e44bd17527b9ef46bee..9844a5df0a97e466b1f404e252b85cc1784b946a 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.39 2002/07/31 17:19:51 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.40 2002/08/02 18:15:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,6 +27,7 @@
 #include "commands/vacuum.h"
 #include "miscadmin.h"
 #include "parser/parse_oper.h"
+#include "parser/parse_relation.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/datum.h"
@@ -147,7 +148,6 @@ void
 analyze_rel(Oid relid, VacuumStmt *vacstmt)
 {
 	Relation	onerel;
-	Form_pg_attribute *attr;
 	int			attr_cnt,
 				tcnt,
 				i;
@@ -234,9 +234,6 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
 	 *
 	 * Note that system attributes are never analyzed.
 	 */
-	attr = onerel->rd_att->attrs;
-	attr_cnt = onerel->rd_att->natts;
-
 	if (vacstmt->va_cols != NIL)
 	{
 		List	   *le;
@@ -248,15 +245,8 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
 		{
 			char	   *col = strVal(lfirst(le));
 
-			for (i = 0; i < attr_cnt; i++)
-			{
-				if (namestrcmp(&(attr[i]->attname), col) == 0)
-					break;
-			}
-			if (i >= attr_cnt)
-				elog(ERROR, "ANALYZE: there is no attribute %s in %s",
-					 col, RelationGetRelationName(onerel));
-			vacattrstats[tcnt] = examine_attribute(onerel, i + 1);
+			i = attnameAttNum(onerel, col, false);
+			vacattrstats[tcnt] = examine_attribute(onerel, i);
 			if (vacattrstats[tcnt] != NULL)
 				tcnt++;
 		}
@@ -264,12 +254,13 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
 	}
 	else
 	{
+		attr_cnt = onerel->rd_att->natts;
 		vacattrstats = (VacAttrStats **) palloc(attr_cnt *
 												sizeof(VacAttrStats *));
 		tcnt = 0;
-		for (i = 0; i < attr_cnt; i++)
+		for (i = 1; i <= attr_cnt; i++)
 		{
-			vacattrstats[tcnt] = examine_attribute(onerel, i + 1);
+			vacattrstats[tcnt] = examine_attribute(onerel, i);
 			if (vacattrstats[tcnt] != NULL)
 				tcnt++;
 		}
@@ -388,6 +379,10 @@ examine_attribute(Relation onerel, int attnum)
 	Oid			ltopr = InvalidOid;
 	VacAttrStats *stats;
 
+	/* Don't analyze dropped columns */
+	if (attr->attisdropped)
+		return NULL;
+
 	/* Don't analyze column if user has specified not to */
 	if (attr->attstattarget == 0)
 		return NULL;
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index c5dee8f8af9a65651b5bcd075a7993894e37cf65..118c2c4b777e4fa074450be4c821a34d0d07c276 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.53 2002/07/29 23:46:35 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.54 2002/08/02 18:15:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -382,8 +382,8 @@ CommentAttribute(List *qualname, char *comment)
 
 	attnum = get_attnum(RelationGetRelid(relation), attrname);
 	if (attnum == InvalidAttrNumber)
-		elog(ERROR, "\"%s\" is not an attribute of class \"%s\"",
-			 attrname, RelationGetRelationName(relation));
+		elog(ERROR, "Relation \"%s\" has no column \"%s\"",
+			 RelationGetRelationName(relation), attrname);
 
 	/* Create the comment using the relation's oid */
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 19e17ed2873d81ac0d0d3d7eaddafa4d3acebe26..2529b7282309ad4cab417ea7112379e2a23b8a36 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.161 2002/07/30 16:55:06 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.162 2002/08/02 18:15:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -31,6 +31,7 @@
 #include "rewrite/rewriteHandler.h"
 #include "libpq/libpq.h"
 #include "miscadmin.h"
+#include "parser/parse_relation.h"
 #include "tcop/pquery.h"
 #include "tcop/tcopprot.h"
 #include "utils/acl.h"
@@ -53,13 +54,15 @@ typedef enum CopyReadResult
 } CopyReadResult;
 
 /* non-export function prototypes */
-static void CopyTo(Relation rel, List *attlist, bool binary, bool oids, FILE *fp, char *delim, char *null_print);
-static void CopyFrom(Relation rel, List *attlist, bool binary, bool oids, FILE *fp, char *delim, char *null_print);
+static void CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
+				   FILE *fp, char *delim, char *null_print);
+static void CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
+					 FILE *fp, char *delim, char *null_print);
 static Oid	GetInputFunction(Oid type);
 static Oid	GetTypeElement(Oid type);
 static char *CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result);
 static void CopyAttributeOut(FILE *fp, char *string, char *delim);
-static void CopyCheckAttlist(Relation rel, List *attlist);
+static List *CopyGetAttnums(Relation rel, List *attnamelist);
 
 static const char BinarySignature[12] = "PGBCOPY\n\377\r\n\0";
 
@@ -275,7 +278,8 @@ DoCopy(const CopyStmt *stmt)
 	bool is_from = stmt->is_from;
 	bool pipe = (stmt->filename == NULL);
 	List *option;
-	List *attlist = stmt->attlist;
+	List *attnamelist = stmt->attlist;
+	List *attnumlist;
 	bool binary = false;
 	bool oids = false;
 	char *delim = NULL;
@@ -373,6 +377,11 @@ DoCopy(const CopyStmt *stmt)
 		elog(ERROR, "COPY: table \"%s\" does not have OIDs",
 			 RelationGetRelationName(rel));
 
+	/*
+	 * Generate or convert list of attributes to process
+	 */
+	attnumlist = CopyGetAttnums(rel, attnamelist);
+
 	/*
 	 * Set up variables to avoid per-attribute overhead.
 	 */
@@ -382,26 +391,6 @@ DoCopy(const CopyStmt *stmt)
 	server_encoding = GetDatabaseEncoding();
 #endif
 
-	if (attlist == NIL)
-	{
-		/* get list of attributes in the relation */
- 		TupleDesc desc = RelationGetDescr(rel);
- 		int i;
- 		for (i = 0; i < desc->natts; ++i)
-		{
- 			Ident *id = makeNode(Ident);
- 			id->name = NameStr(desc->attrs[i]->attname);
- 			attlist = lappend(attlist,id);
- 		}
-	}
-	else
-	{
-		if (binary)
-			elog(ERROR,"COPY: BINARY format cannot be used with specific column list");
-
-		CopyCheckAttlist(rel, attlist);
-	}
-	
 	if (is_from)
 	{							/* copy from file to database */
 		if (rel->rd_rel->relkind != RELKIND_RELATION)
@@ -442,10 +431,10 @@ DoCopy(const CopyStmt *stmt)
 			if (S_ISDIR(st.st_mode))
 			{
 				FreeFile(fp);
-				elog(ERROR, "COPY: %s is a directory.", filename);
+				elog(ERROR, "COPY: %s is a directory", filename);
 			}
 		}
-		CopyFrom(rel, attlist, binary, oids, fp, delim, null_print);
+		CopyFrom(rel, attnumlist, binary, oids, fp, delim, null_print);
 	}
 	else
 	{							/* copy from database to file */
@@ -483,7 +472,7 @@ DoCopy(const CopyStmt *stmt)
 			 */
 			if (filename[0] != '/')
 				elog(ERROR, "Relative path not allowed for server side"
-					 " COPY command.");
+					 " COPY command");
 
 			oumask = umask((mode_t) 022);
 			fp = AllocateFile(filename, PG_BINARY_W);
@@ -498,10 +487,10 @@ DoCopy(const CopyStmt *stmt)
 			if (S_ISDIR(st.st_mode))
 			{
 				FreeFile(fp);
-				elog(ERROR, "COPY: %s is a directory.", filename);
+				elog(ERROR, "COPY: %s is a directory", filename);
 			}
 		}
-		CopyTo(rel, attlist, binary, oids, fp, delim, null_print);
+		CopyTo(rel, attnumlist, binary, oids, fp, delim, null_print);
 	}
 
 	if (!pipe)
@@ -529,14 +518,14 @@ DoCopy(const CopyStmt *stmt)
  * Copy from relation TO file.
  */
 static void
-CopyTo(Relation rel, List *attlist, bool binary, bool oids, 
+CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, 
 		 FILE *fp, char *delim, char *null_print)
 {
 	HeapTuple	tuple;
 	TupleDesc	tupDesc;
 	HeapScanDesc scandesc;
-	int			attr_count,
-				i;
+	int			num_phys_attrs;
+	int			attr_count;
 	Form_pg_attribute *attr;
 	FmgrInfo   *out_functions;
 	Oid		   *elements;
@@ -544,48 +533,33 @@ CopyTo(Relation rel, List *attlist, bool binary, bool oids,
 	int16		fld_size;
 	char	   *string;
 	Snapshot	mySnapshot;
-	int			copy_attr_count;
-	int		   *attmap;
-	int			p = 0;
 	List	   *cur;
 
 	tupDesc = rel->rd_att;
-	attr_count = rel->rd_att->natts;
-	attr = rel->rd_att->attrs;
-
-	copy_attr_count = length(attlist);
-	attmap = (int *) palloc(copy_attr_count * sizeof(int));
-
-	foreach(cur, attlist)
-	{
-		const char *currAtt = strVal(lfirst(cur));
-
-		for (i = 0; i < attr_count; i++)
-		{
-			if (namestrcmp(&attr[i]->attname, currAtt) == 0)
-			{
-				attmap[p++] = i;
-				continue;
-			}
-		}
-	}
+	attr = tupDesc->attrs;
+	num_phys_attrs = tupDesc->natts;
+	attr_count = length(attnumlist);
 
 	/*
+	 * Get info about the columns we need to process.
+	 *
 	 * For binary copy we really only need isvarlena, but compute it
 	 * all...
 	 */
-	out_functions = (FmgrInfo *) palloc(attr_count * sizeof(FmgrInfo));
-	elements = (Oid *) palloc(attr_count * sizeof(Oid));
-	isvarlena = (bool *) palloc(attr_count * sizeof(bool));
-	for (i = 0; i < attr_count; i++)
+	out_functions = (FmgrInfo *) palloc(num_phys_attrs * sizeof(FmgrInfo));
+	elements = (Oid *) palloc(num_phys_attrs * sizeof(Oid));
+	isvarlena = (bool *) palloc(num_phys_attrs * sizeof(bool));
+	foreach(cur, attnumlist)
 	{
+		int		attnum = lfirsti(cur);
 		Oid			out_func_oid;
 
-		if (!getTypeOutputInfo(attr[i]->atttypid,
-							 &out_func_oid, &elements[i], &isvarlena[i]))
+		if (!getTypeOutputInfo(attr[attnum-1]->atttypid,
+							   &out_func_oid, &elements[attnum-1],
+							   &isvarlena[attnum-1]))
 			elog(ERROR, "COPY: couldn't lookup info for type %u",
-				 attr[i]->atttypid);
-		fmgr_info(out_func_oid, &out_functions[i]);
+				 attr[attnum-1]->atttypid);
+		fmgr_info(out_func_oid, &out_functions[attnum-1]);
 	}
 
 	if (binary)
@@ -650,14 +624,14 @@ CopyTo(Relation rel, List *attlist, bool binary, bool oids,
 			}
 		}
 
-		for (i = 0; i < copy_attr_count; i++)
+		foreach(cur, attnumlist)
 		{
+			int		attnum = lfirsti(cur);
 			Datum		origvalue,
 						value;
 			bool		isnull;
-			int			mi = attmap[i];
 
-			origvalue = heap_getattr(tuple, mi + 1, tupDesc, &isnull);
+			origvalue = heap_getattr(tuple, attnum, tupDesc, &isnull);
 
 			if (!binary)
 			{
@@ -686,25 +660,25 @@ CopyTo(Relation rel, List *attlist, bool binary, bool oids,
 				 * (or for binary case, becase we must output untoasted
 				 * value).
 				 */
-				if (isvarlena[mi])
+				if (isvarlena[attnum-1])
 					value = PointerGetDatum(PG_DETOAST_DATUM(origvalue));
 				else
 					value = origvalue;
 
 				if (!binary)
 				{
-					string = DatumGetCString(FunctionCall3(&out_functions[mi],
+					string = DatumGetCString(FunctionCall3(&out_functions[attnum-1],
 														   value,
-										   ObjectIdGetDatum(elements[mi]),
-									 Int32GetDatum(attr[mi]->atttypmod)));
+										   ObjectIdGetDatum(elements[attnum-1]),
+									 Int32GetDatum(attr[attnum-1]->atttypmod)));
 					CopyAttributeOut(fp, string, delim);
 					pfree(string);
 				}
 				else
 				{
-					fld_size = attr[mi]->attlen;
+					fld_size = attr[attnum-1]->attlen;
 					CopySendData(&fld_size, sizeof(int16), fp);
-					if (isvarlena[mi])
+					if (isvarlena[attnum-1])
 					{
 						/* varlena */
 						Assert(fld_size == -1);
@@ -712,7 +686,7 @@ CopyTo(Relation rel, List *attlist, bool binary, bool oids,
 									 VARSIZE(value),
 									 fp);
 					}
-					else if (!attr[mi]->attbyval)
+					else if (!attr[attnum-1]->attbyval)
 					{
 						/* fixed-length pass-by-reference */
 						Assert(fld_size > 0);
@@ -767,36 +741,36 @@ CopyTo(Relation rel, List *attlist, bool binary, bool oids,
  * Copy FROM file to relation.
  */
 static void
-CopyFrom(Relation rel, List *attlist, bool binary, bool oids, 
+CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, 
 		 FILE *fp, char *delim, char *null_print)
 {
 	HeapTuple	tuple;
 	TupleDesc	tupDesc;
 	Form_pg_attribute *attr;
-	AttrNumber	attr_count, copy_attr_count, def_attr_count;
+	AttrNumber	num_phys_attrs, attr_count, num_defaults;
 	FmgrInfo   *in_functions;
 	Oid		   *elements;
 	int			i;
+	List	   *cur;
 	Oid			in_func_oid;
 	Datum	   *values;
 	char	   *nulls;
-	int			done = 0;
+	bool		done = false;
 	ResultRelInfo *resultRelInfo;
 	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
 	TupleTable	tupleTable;
 	TupleTableSlot *slot;
 	bool		file_has_oids;
-	int		   *attmap = NULL;
-	int		   *defmap = NULL;
-	Node	  **defexprs = NULL; /* array of default att expressions */
+	int		   *defmap;
+	Node	  **defexprs; /* array of default att expressions */
 	ExprContext *econtext; /* used for ExecEvalExpr for default atts */
-	ExprDoneCond isdone;
+	MemoryContext oldcontext = CurrentMemoryContext;
 
 	tupDesc = RelationGetDescr(rel);
 	attr = tupDesc->attrs;
-	attr_count = tupDesc->natts;
-	copy_attr_count = length(attlist);
-	def_attr_count = 0;
+	num_phys_attrs = tupDesc->natts;
+	attr_count = length(attnumlist);
+	num_defaults = 0;
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -819,50 +793,40 @@ CopyFrom(Relation rel, List *attlist, bool binary, bool oids,
 	slot = ExecAllocTableSlot(tupleTable);
 	ExecSetSlotDescriptor(slot, tupDesc, false);
 
-	if (!binary)
+	/*
+	 * pick up the input function and default expression (if any) for 
+	 * each attribute in the relation.  (We don't actually use the
+	 * input function if it's a binary copy.)
+	 */
+	defmap = (int *) palloc(sizeof(int) * num_phys_attrs);
+	defexprs = (Node **) palloc(sizeof(Node *) * num_phys_attrs);
+	in_functions = (FmgrInfo *) palloc(num_phys_attrs * sizeof(FmgrInfo));
+	elements = (Oid *) palloc(num_phys_attrs * sizeof(Oid));
+
+	for (i = 0; i < num_phys_attrs; i++)
 	{
-		/*
-		 * pick up the input function and default expression (if any) for 
-		 * each attribute in the relation.
-		 */
-		attmap = (int *) palloc(sizeof(int) * attr_count);
-		defmap = (int *) palloc(sizeof(int) * attr_count);
-		defexprs = (Node **) palloc(sizeof(Node *) * attr_count);
-		in_functions = (FmgrInfo *) palloc(attr_count * sizeof(FmgrInfo));
-		elements = (Oid *) palloc(attr_count * sizeof(Oid));
-		for (i = 0; i < attr_count; i++)
-		{
-			List	*l;
-			int		 p = 0;
-			bool	 specified = false;
+		/* We don't need info for dropped attributes */
+		if (attr[i]->attisdropped)
+			continue;
 
-			in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid);
-			fmgr_info(in_func_oid, &in_functions[i]);
-			elements[i] = GetTypeElement(attr[i]->atttypid);
+		in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid);
+		fmgr_info(in_func_oid, &in_functions[i]);
+		elements[i] = GetTypeElement(attr[i]->atttypid);
 
-			foreach(l, attlist)
-			{
-				if (namestrcmp(&attr[i]->attname, strVal(lfirst(l))) == 0)
-				{
-					attmap[p] = i;
-					specified = true;
-					continue;
-				}
-				p++;
-			}
-
-			/* if column not specified, use default value if one exists */
-			if (! specified)
+		/* if column not specified, use default value if one exists */
+		if (!intMember(i + 1, attnumlist))
+		{
+			defexprs[num_defaults] = build_column_default(rel, i + 1);
+			if (defexprs[num_defaults] != NULL)
 			{
-				defexprs[def_attr_count] = build_column_default(rel, i + 1);
-
-				if (defexprs[def_attr_count] != NULL)
-				{
-					defmap[def_attr_count] = i;
-					def_attr_count++;
-				}
+				defmap[num_defaults] = i;
+				num_defaults++;
 			}
 		}
+	}
+
+	if (!binary)
+	{
 		file_has_oids = oids;	/* must rely on user to tell us this... */
 	}
 	else
@@ -898,13 +862,10 @@ CopyFrom(Relation rel, List *attlist, bool binary, bool oids,
 			if (CopyGetEof(fp))
 				elog(ERROR, "COPY BINARY: bogus file header (wrong length)");
 		}
-
-		in_functions = NULL;
-		elements = NULL;
 	}
 
-	values = (Datum *) palloc(attr_count * sizeof(Datum));
-	nulls = (char *) palloc(attr_count * sizeof(char));
+	values = (Datum *) palloc(num_phys_attrs * sizeof(Datum));
+	nulls = (char *) palloc(num_phys_attrs * sizeof(char));
 
 	copy_lineno = 0;
 	fe_eof = false;
@@ -914,58 +875,77 @@ CopyFrom(Relation rel, List *attlist, bool binary, bool oids,
 	while (!done)
 	{
 		bool	skip_tuple;
-		Oid		loaded_oid;
+		Oid		loaded_oid = InvalidOid;
 
 		CHECK_FOR_INTERRUPTS();
 
 		copy_lineno++;
 		
-		/* Reset the per-output-tuple exprcontext */
+		/* Reset the per-tuple exprcontext */
 		ResetPerTupleExprContext(estate);
 
+		/* Switch to and reset per-tuple memory context, too */
+		MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
+		MemoryContextReset(CurrentMemoryContext);
+
 		/* Initialize all values for row to NULL */
-		MemSet(values, 0, attr_count * sizeof(Datum));
-		MemSet(nulls, 'n', attr_count * sizeof(char));
+		MemSet(values, 0, num_phys_attrs * sizeof(Datum));
+		MemSet(nulls, 'n', num_phys_attrs * sizeof(char));
 
 		if (!binary)
 		{
-			CopyReadResult	 result;
+			CopyReadResult	 result = NORMAL_ATTR;
 			char			*string;
 
 			if (file_has_oids)
 			{
 				string = CopyReadAttribute(fp, delim, &result);
 
-				if (result == END_OF_FILE)
-					done = 1;
-				else if (string == NULL || strcmp(string, null_print) == 0)
-					elog(ERROR, "COPY TEXT: NULL Oid");
+				if (result == END_OF_FILE && *string == '\0')
+				{
+					/* EOF at start of line: all is well */
+					done = true;
+					break;
+				}
+
+				if (strcmp(string, null_print) == 0)
+					elog(ERROR, "NULL Oid");
 				else
 				{
 					loaded_oid = DatumGetObjectId(DirectFunctionCall1(oidin,
 											   CStringGetDatum(string)));
 					if (loaded_oid == InvalidOid)
-						elog(ERROR, "COPY TEXT: Invalid Oid");
+						elog(ERROR, "Invalid Oid");
 				}
 			}
       
-			/* 
-			 * here, we only try to read as many attributes as 
-			 * were specified.
+			/*
+			 * Loop to read the user attributes on the line.
 			 */
-			for (i = 0; i < copy_attr_count && !done; i++)
+			foreach(cur, attnumlist)
 			{
-				int m = attmap[i];
+				int		attnum = lfirsti(cur);
+				int		m = attnum - 1;
+
+				/*
+				 * If prior attr on this line was ended by newline or EOF,
+				 * complain.
+				 */
+				if (result != NORMAL_ATTR)
+					elog(ERROR, "Missing data for column \"%s\"",
+						 NameStr(attr[m]->attname));
 
 				string = CopyReadAttribute(fp, delim, &result);
 
-				/* If we got an end-of-line before we expected, bail out */
-				if (result == END_OF_LINE && i < (copy_attr_count - 1))
-					elog(ERROR, "COPY TEXT: Missing data for attribute %d", i + 1);
+				if (result == END_OF_FILE && *string == '\0' &&
+					cur == attnumlist && !file_has_oids)
+				{
+					/* EOF at start of line: all is well */
+					done = true;
+					break;		/* out of per-attr loop */
+				}
 
-				if (result == END_OF_FILE)
-					done = 1;
-				else if (strcmp(string, null_print) == 0)
+				if (strcmp(string, null_print) == 0)
 				{
 					/* we read an SQL NULL, no need to do anything */
 				}
@@ -979,124 +959,149 @@ CopyFrom(Relation rel, List *attlist, bool binary, bool oids,
 				}
 			}
 
-			if (result == NORMAL_ATTR && !done)
-				elog(ERROR, "COPY TEXT: Extra data encountered");
+			if (done)
+				break;			/* out of per-row loop */
+
+			/* Complain if there are more fields on the input line */
+			if (result == NORMAL_ATTR)
+				elog(ERROR, "Extra data after last expected column");
 
 			/*
-			 * as above, we only try a default lookup if one is
-			 * known to be available
+			 * If we got some data on the line, but it was ended by EOF,
+			 * process the line normally but set flag to exit the loop
+			 * when we return to the top.
 			 */
-			for (i = 0; i < def_attr_count && !done; i++)
-			{
-				bool isnull;
-				values[defmap[i]] = ExecEvalExpr(defexprs[i], econtext,
-												 &isnull, &isdone);
-
-				if (! isnull)
-					nulls[defmap[i]] = ' ';
-			}
+			if (result == END_OF_FILE)
+				done = true;
 		}
 		else
-		{						/* binary */
+		{
+			/* binary */
 			int16		fld_count,
 						fld_size;
 
 			CopyGetData(&fld_count, sizeof(int16), fp);
 			if (CopyGetEof(fp) || fld_count == -1)
-				done = 1;
-			else
 			{
-				if (fld_count <= 0 || fld_count > attr_count)
-					elog(ERROR, "COPY BINARY: tuple field count is %d, expected %d",
-						 (int) fld_count, attr_count);
+				done = true;
+				break;
+			}
+
+			if (fld_count != attr_count)
+				elog(ERROR, "COPY BINARY: tuple field count is %d, expected %d",
+					 (int) fld_count, attr_count);
+
+			if (file_has_oids)
+			{
+				CopyGetData(&fld_size, sizeof(int16), fp);
+				if (CopyGetEof(fp))
+					elog(ERROR, "COPY BINARY: unexpected EOF");
+				if (fld_size != (int16) sizeof(Oid))
+					elog(ERROR, "COPY BINARY: sizeof(Oid) is %d, expected %d",
+						 (int) fld_size, (int) sizeof(Oid));
+				CopyGetData(&loaded_oid, sizeof(Oid), fp);
+				if (CopyGetEof(fp))
+					elog(ERROR, "COPY BINARY: unexpected EOF");
+				if (loaded_oid == InvalidOid)
+					elog(ERROR, "COPY BINARY: Invalid Oid");
+			}
 
-				if (file_has_oids)
+			i = 0;
+			foreach(cur, attnumlist)
+			{
+				int		attnum = lfirsti(cur);
+
+				i++;
+
+				CopyGetData(&fld_size, sizeof(int16), fp);
+				if (CopyGetEof(fp))
+					elog(ERROR, "COPY BINARY: unexpected EOF");
+				if (fld_size == 0)
+					continue;	/* it's NULL; nulls[attnum-1] already set */
+				if (fld_size != attr[attnum-1]->attlen)
+					elog(ERROR, "COPY BINARY: sizeof(field %d) is %d, expected %d",
+						 i, (int) fld_size, (int) attr[attnum-1]->attlen);
+				if (fld_size == -1)
 				{
-					CopyGetData(&fld_size, sizeof(int16), fp);
+					/* varlena field */
+					int32		varlena_size;
+					Pointer		varlena_ptr;
+
+					CopyGetData(&varlena_size, sizeof(int32), fp);
 					if (CopyGetEof(fp))
 						elog(ERROR, "COPY BINARY: unexpected EOF");
-					if (fld_size != (int16) sizeof(Oid))
-						elog(ERROR, "COPY BINARY: sizeof(Oid) is %d, expected %d",
-							 (int) fld_size, (int) sizeof(Oid));
-					CopyGetData(&loaded_oid, sizeof(Oid), fp);
+					if (varlena_size < (int32) sizeof(int32))
+						elog(ERROR, "COPY BINARY: bogus varlena length");
+					varlena_ptr = (Pointer) palloc(varlena_size);
+					VARATT_SIZEP(varlena_ptr) = varlena_size;
+					CopyGetData(VARDATA(varlena_ptr),
+								varlena_size - sizeof(int32),
+								fp);
 					if (CopyGetEof(fp))
 						elog(ERROR, "COPY BINARY: unexpected EOF");
-					if (loaded_oid == InvalidOid)
-						elog(ERROR, "COPY BINARY: Invalid Oid");
+					values[attnum-1] = PointerGetDatum(varlena_ptr);
 				}
-
-				for (i = 0; i < (int) fld_count; i++)
+				else if (!attr[attnum-1]->attbyval)
 				{
-					CopyGetData(&fld_size, sizeof(int16), fp);
+					/* fixed-length pass-by-reference */
+					Pointer		refval_ptr;
+
+					Assert(fld_size > 0);
+					refval_ptr = (Pointer) palloc(fld_size);
+					CopyGetData(refval_ptr, fld_size, fp);
 					if (CopyGetEof(fp))
 						elog(ERROR, "COPY BINARY: unexpected EOF");
-					if (fld_size == 0)
-						continue;		/* it's NULL; nulls[i] already set */
-					if (fld_size != attr[i]->attlen)
-						elog(ERROR, "COPY BINARY: sizeof(field %d) is %d, expected %d",
-						   i + 1, (int) fld_size, (int) attr[i]->attlen);
-					if (fld_size == -1)
-					{
-						/* varlena field */
-						int32		varlena_size;
-						Pointer		varlena_ptr;
-
-						CopyGetData(&varlena_size, sizeof(int32), fp);
-						if (CopyGetEof(fp))
-							elog(ERROR, "COPY BINARY: unexpected EOF");
-						if (varlena_size < (int32) sizeof(int32))
-							elog(ERROR, "COPY BINARY: bogus varlena length");
-						varlena_ptr = (Pointer) palloc(varlena_size);
-						VARATT_SIZEP(varlena_ptr) = varlena_size;
-						CopyGetData(VARDATA(varlena_ptr),
-									varlena_size - sizeof(int32),
-									fp);
-						if (CopyGetEof(fp))
-							elog(ERROR, "COPY BINARY: unexpected EOF");
-						values[i] = PointerGetDatum(varlena_ptr);
-					}
-					else if (!attr[i]->attbyval)
-					{
-						/* fixed-length pass-by-reference */
-						Pointer		refval_ptr;
-
-						Assert(fld_size > 0);
-						refval_ptr = (Pointer) palloc(fld_size);
-						CopyGetData(refval_ptr, fld_size, fp);
-						if (CopyGetEof(fp))
-							elog(ERROR, "COPY BINARY: unexpected EOF");
-						values[i] = PointerGetDatum(refval_ptr);
-					}
-					else
-					{
-						/* pass-by-value */
-						Datum		datumBuf;
-
-						/*
-						 * We need this horsing around because we don't
-						 * know how shorter data values are aligned within
-						 * a Datum.
-						 */
-						Assert(fld_size > 0 && fld_size <= sizeof(Datum));
-						CopyGetData(&datumBuf, fld_size, fp);
-						if (CopyGetEof(fp))
-							elog(ERROR, "COPY BINARY: unexpected EOF");
-						values[i] = fetch_att(&datumBuf, true, fld_size);
-					}
+					values[attnum-1] = PointerGetDatum(refval_ptr);
+				}
+				else
+				{
+					/* pass-by-value */
+					Datum		datumBuf;
 
-					nulls[i] = ' ';
+					/*
+					 * We need this horsing around because we don't
+					 * know how shorter data values are aligned within
+					 * a Datum.
+					 */
+					Assert(fld_size > 0 && fld_size <= sizeof(Datum));
+					CopyGetData(&datumBuf, fld_size, fp);
+					if (CopyGetEof(fp))
+						elog(ERROR, "COPY BINARY: unexpected EOF");
+					values[attnum-1] = fetch_att(&datumBuf, true, fld_size);
 				}
+
+				nulls[attnum-1] = ' ';
 			}
 		}
 
-		if (done)
-			break;
+		/*
+		 * Now compute and insert any defaults available for the
+		 * columns not provided by the input data.  Anything not
+		 * processed here or above will remain NULL.
+		 */
+		for (i = 0; i < num_defaults; i++)
+		{
+			bool isnull;
 
+			values[defmap[i]] = ExecEvalExpr(defexprs[i], econtext,
+											 &isnull, NULL);
+			if (!isnull)
+				nulls[defmap[i]] = ' ';
+		}
+
+		/*
+		 * And now we can form the input tuple.
+		 */
 		tuple = heap_formtuple(tupDesc, values, nulls);
   	
 		if (oids && file_has_oids)
 			HeapTupleSetOid(tuple, loaded_oid);
 
+		/*
+		 * Triggers and stuff need to be invoked in query context.
+		 */
+		MemoryContextSwitchTo(oldcontext);
+
 		skip_tuple = false;
 
 		/* BEFORE ROW INSERT Triggers */
@@ -1118,6 +1123,7 @@ CopyFrom(Relation rel, List *attlist, bool binary, bool oids,
 
 		if (!skip_tuple)
 		{
+			/* Place tuple in tuple slot */
 			ExecStoreTuple(tuple, slot, InvalidBuffer, false);
 
 			/*
@@ -1138,8 +1144,6 @@ CopyFrom(Relation rel, List *attlist, bool binary, bool oids,
 			if (resultRelInfo->ri_TrigDesc)
 				ExecARInsertTriggers(estate, resultRelInfo, tuple);
 		}
-
-		heap_freetuple(tuple);
 	}
 
 	/*
@@ -1147,6 +1151,8 @@ CopyFrom(Relation rel, List *attlist, bool binary, bool oids,
 	 */
 	copy_lineno = 0;
 
+	MemoryContextSwitchTo(oldcontext);
+
 	pfree(values);
 	pfree(nulls);
 
@@ -1197,12 +1203,11 @@ GetTypeElement(Oid type)
 /*
  * Read the value of a single attribute.
  *
- * Results are returned in the status indicator, as well as the
- * return value. If a value was successfully read but there is
- * more to read before EOL, NORMAL_ATTR is set and the value read
- * is returned. If a value was read and we hit EOL, END_OF_LINE
- * is set and the value read is returned. If we hit the EOF,
- * END_OF_FILE is set and NULL is returned.
+ * *result is set to indicate what terminated the read:
+ *		NORMAL_ATTR:	column delimiter
+ *		END_OF_LINE:	newline
+ *		END_OF_FILE:	EOF indication
+ * In all cases, the string read up to the terminator is returned.
  *
  * Note: This function does not care about SQL NULL values -- it
  * is the caller's responsibility to check if the returned string
@@ -1215,8 +1220,7 @@ static char *
 CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
 {
 	int			c;
-	int			delimc = (unsigned char)delim[0];
-
+	int			delimc = (unsigned char) delim[0];
 #ifdef MULTIBYTE
 	int			mblen;
 	unsigned char s[2];
@@ -1230,7 +1234,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
 	attribute_buf.len = 0;
 	attribute_buf.data[0] = '\0';
 
-	/* set default */
+	/* set default status */
 	*result = NORMAL_ATTR;
 
 	for (;;)
@@ -1239,7 +1243,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
 		if (c == EOF)
 		{
 			*result = END_OF_FILE;
-			return NULL;
+			goto copy_eof;
 		}
 		if (c == '\n')
 		{
@@ -1254,7 +1258,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
 			if (c == EOF)
 			{
 				*result = END_OF_FILE;
-				return NULL;
+				goto copy_eof;
 			}
 			switch (c)
 			{
@@ -1286,7 +1290,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
 								if (c == EOF)
 								{
 									*result = END_OF_FILE;
-									return NULL;
+									goto copy_eof;
 								}
 								CopyDonePeek(fp, c, false /* put back */ );
 							}
@@ -1296,7 +1300,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
 							if (c == EOF)
 							{
 								*result = END_OF_FILE;
-								return NULL;
+								goto copy_eof;
 							}
 							CopyDonePeek(fp, c, false /* put back */ );
 						}
@@ -1336,7 +1340,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
 					if (c != '\n')
 						elog(ERROR, "CopyReadAttribute: end of record marker corrupted");
 					*result = END_OF_FILE;
-					return NULL;
+					goto copy_eof;
 			}
 		}
 		appendStringInfoCharMacro(&attribute_buf, c);
@@ -1353,7 +1357,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
 				if (c == EOF)
 				{
 					*result = END_OF_FILE;
-					return NULL;
+					goto copy_eof;
 				}
 				appendStringInfoCharMacro(&attribute_buf, c);
 			}
@@ -1361,6 +1365,8 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
 #endif
 	}
 
+copy_eof:
+
 #ifdef MULTIBYTE
 	if (client_encoding != server_encoding)
 	{
@@ -1468,50 +1474,51 @@ CopyAttributeOut(FILE *fp, char *server_string, char *delim)
 }
 
 /*
- * CopyCheckAttlist: elog(ERROR,...) if the specified attlist
- *                    is not valid for the Relation
+ * CopyGetAttnums - build an integer list of attnums to be copied
+ *
+ * The input attnamelist is either the user-specified column list,
+ * or NIL if there was none (in which case we want all the non-dropped
+ * columns).
  */
-static void
-CopyCheckAttlist(Relation rel, List *attlist)
+static List *
+CopyGetAttnums(Relation rel, List *attnamelist)
 {
-	TupleDesc	 tupDesc;
-	int			 attr_count;
-	List		*l;
-
-	if (attlist == NIL)
-		return;
-
-	tupDesc = RelationGetDescr(rel);
-	Assert(tupDesc != NULL);
- 
-	/*
-	 * make sure there aren't more columns specified than are in the table 
-	 */
-	attr_count = tupDesc->natts;
-	if (attr_count < length(attlist))
-		elog(ERROR, "COPY: Too many columns specified");
+	List		*attnums = NIL;
 
-	/* 
-	 * make sure no columns are specified that don't exist in the table 
-	 */
-	foreach(l, attlist)
+	if (attnamelist == NIL)
 	{
-		char	*colName = strVal(lfirst(l));
-		bool	 found = false;
-		int		 i;
+		/* Generate default column list */
+		TupleDesc	 tupDesc = RelationGetDescr(rel);
+		Form_pg_attribute *attr = tupDesc->attrs;
+		int			 attr_count = tupDesc->natts;
+		int			i;
 
 		for (i = 0; i < attr_count; i++)
 		{
-			if (namestrcmp(&tupDesc->attrs[i]->attname, colName) == 0)
-			{
-				found = true;
-				break;
-			}
+			if (attr[i]->attisdropped)
+				continue;
+			attnums = lappendi(attnums, i + 1);
+		}
+	}
+	else
+	{
+		/* Validate the user-supplied list and extract attnums */
+		List	   *l;
+
+		foreach(l, attnamelist)
+		{
+			char	   *name = strVal(lfirst(l));
+			int			attnum;
+
+			/* Lookup column name, elog on failure */
+			/* Note we disallow system columns here */
+			attnum = attnameAttNum(rel, name, false);
+			/* Check for duplicates */
+			if (intMember(attnum, attnums))
+				elog(ERROR, "Attribute \"%s\" specified more than once", name);
+			attnums = lappendi(attnums, attnum);
 		}
-		
-		if (!found)
-			elog(ERROR, "COPY: Specified column \"%s\" does not exist",
-				 colName);
 	}
-}
 
+	return attnums;
+}
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 4049e7435c56a54af4ed4f1e571779b8178d7c66..9edebc1e690e2efbf7877cc89b2b236f399a03c7 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.79 2002/07/29 23:46:35 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.80 2002/08/02 18:15:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -294,10 +294,7 @@ FuncIndexArgs(IndexInfo *indexInfo,
 		HeapTuple	tuple;
 		Form_pg_attribute att;
 
-		tuple = SearchSysCache(ATTNAME,
-							   ObjectIdGetDatum(relId),
-							   PointerGetDatum(arg),
-							   0, 0);
+		tuple = SearchSysCacheAttName(relId, arg);
 		if (!HeapTupleIsValid(tuple))
 			elog(ERROR, "DefineIndex: attribute \"%s\" not found", arg);
 		att = (Form_pg_attribute) GETSTRUCT(tuple);
@@ -387,10 +384,7 @@ NormIndexAttrs(IndexInfo *indexInfo,
 		if (attribute->name == NULL)
 			elog(ERROR, "missing attribute for define index");
 
-		atttuple = SearchSysCache(ATTNAME,
-								  ObjectIdGetDatum(relId),
-								  PointerGetDatum(attribute->name),
-								  0, 0);
+		atttuple = SearchSysCacheAttName(relId, attribute->name);
 		if (!HeapTupleIsValid(atttuple))
 			elog(ERROR, "DefineIndex: attribute \"%s\" not found",
 				 attribute->name);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index cfcf5d5ddfd27f0675b0207c353947bc15926064..4972c09b4a40741a2f0726843c9f4d94da70ec7b 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.25 2002/07/31 17:19:51 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.26 2002/08/02 18:15:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -503,7 +503,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
 		/*
 		 * newattno[] will contain the child-table attribute numbers for
 		 * the attributes of this parent table.  (They are not the same
-		 * for parents after the first one.)
+		 * for parents after the first one, nor if we have dropped columns.)
 		 */
 		newattno = (AttrNumber *) palloc(tupleDesc->natts * sizeof(AttrNumber));
 
@@ -516,6 +516,19 @@ MergeAttributes(List *schema, List *supers, bool istemp,
 			ColumnDef  *def;
 			TypeName   *typename;
 
+			/*
+			 * Ignore dropped columns in the parent.
+			 */
+			if (attribute->attisdropped)
+			{
+				/* 
+				 * change_varattnos_of_a_node asserts that this is greater than
+				 * zero, so if anything tries to use it, we should find out.
+				 */
+				newattno[parent_attno - 1] = 0;
+				continue;
+			}
+
 			/*
 			 * Does it conflict with some previously inherited column?
 			 */
@@ -1062,17 +1075,17 @@ renameatt(Oid relid,
 
 	attrelation = heap_openr(AttributeRelationName, RowExclusiveLock);
 
-	atttup = SearchSysCacheCopy(ATTNAME,
-								ObjectIdGetDatum(relid),
-								PointerGetDatum(oldattname),
-								0, 0);
+	atttup = SearchSysCacheCopyAttName(relid, oldattname);
 	if (!HeapTupleIsValid(atttup))
-		elog(ERROR, "renameatt: attribute \"%s\" does not exist", oldattname);
+		elog(ERROR, "renameatt: attribute \"%s\" does not exist",
+			 oldattname);
 
 	if (((Form_pg_attribute) GETSTRUCT(atttup))->attnum < 0)
-		elog(ERROR, "renameatt: system attribute \"%s\" not renamed", oldattname);
+		elog(ERROR, "renameatt: system attribute \"%s\" may not be renamed",
+			 oldattname);
 
 	/* should not already exist */
+	/* this test is deliberately not attisdropped-aware */
 	if (SearchSysCacheExists(ATTNAME,
 							 ObjectIdGetDatum(relid),
 							 PointerGetDatum(newattname),
@@ -1126,10 +1139,7 @@ renameatt(Oid relid,
 		 * Okay, look to see if any column name of the index matches the
 		 * old attribute name.
 		 */
-		atttup = SearchSysCacheCopy(ATTNAME,
-									ObjectIdGetDatum(indexoid),
-									PointerGetDatum(oldattname),
-									0, 0);
+		atttup = SearchSysCacheCopyAttName(indexoid, oldattname);
 		if (!HeapTupleIsValid(atttup))
 			continue;			/* Nope, so ignore it */
 
@@ -1634,6 +1644,10 @@ AlterTableAddColumn(Oid myrelid,
 		elog(ERROR, "ALTER TABLE: relation \"%s\" not found",
 			 RelationGetRelationName(rel));
 
+	/*
+	 * this test is deliberately not attisdropped-aware, since if one tries
+	 * to add a column matching a dropped column name, it's gonna fail anyway.
+	 */
 	if (SearchSysCacheExists(ATTNAME,
 							 ObjectIdGetDatum(myrelid),
 							 PointerGetDatum(colDef->colname),
@@ -1681,6 +1695,7 @@ AlterTableAddColumn(Oid myrelid,
 	attribute->attnotnull = colDef->is_not_null;
 	attribute->atthasdef = (colDef->raw_default != NULL ||
 							colDef->cooked_default != NULL);
+	attribute->attisdropped = false;
 
 	ReleaseSysCache(typeTuple);
 
@@ -1821,17 +1836,11 @@ AlterTableAlterColumnDropNotNull(Oid myrelid,
 	/*
 	 * get the number of the attribute
 	 */
-	tuple = SearchSysCache(ATTNAME,
-						   ObjectIdGetDatum(myrelid),
-						   PointerGetDatum(colName),
-						   0, 0);
-	if (!HeapTupleIsValid(tuple))
-		elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"",
+	attnum = get_attnum(myrelid, colName);
+	if (attnum == InvalidAttrNumber)
+		elog(ERROR, "Relation \"%s\" has no column \"%s\"",
 			 RelationGetRelationName(rel), colName);
 
-	attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
-	ReleaseSysCache(tuple);
-
 	/* Prevent them from altering a system attribute */
 	if (attnum < 0)
 		elog(ERROR, "ALTER TABLE: Cannot alter system attribute \"%s\"",
@@ -1884,10 +1893,7 @@ AlterTableAlterColumnDropNotNull(Oid myrelid,
 	 */
 	attr_rel = heap_openr(AttributeRelationName, RowExclusiveLock);
 
-	tuple = SearchSysCacheCopy(ATTNAME,
-							   ObjectIdGetDatum(myrelid),
-							   PointerGetDatum(colName),
-							   0, 0);
+	tuple = SearchSysCacheCopyAttName(myrelid, colName);
 	if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
 		elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"",
 			 RelationGetRelationName(rel), colName);
@@ -1971,17 +1977,11 @@ AlterTableAlterColumnSetNotNull(Oid myrelid,
 	/*
 	 * get the number of the attribute
 	 */
-	tuple = SearchSysCache(ATTNAME,
-						   ObjectIdGetDatum(myrelid),
-						   PointerGetDatum(colName),
-						   0, 0);
-	if (!HeapTupleIsValid(tuple))
-		elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"",
+	attnum = get_attnum(myrelid, colName);
+	if (attnum == InvalidAttrNumber)
+		elog(ERROR, "Relation \"%s\" has no column \"%s\"",
 			 RelationGetRelationName(rel), colName);
 
-	attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
-	ReleaseSysCache(tuple);
-
 	/* Prevent them from altering a system attribute */
 	if (attnum < 0)
 		elog(ERROR, "ALTER TABLE: Cannot alter system attribute \"%s\"",
@@ -2014,10 +2014,7 @@ AlterTableAlterColumnSetNotNull(Oid myrelid,
 	 */
 	attr_rel = heap_openr(AttributeRelationName, RowExclusiveLock);
 
-	tuple = SearchSysCacheCopy(ATTNAME,
-							   ObjectIdGetDatum(myrelid),
-							   PointerGetDatum(colName),
-							   0, 0);
+	tuple = SearchSysCacheCopyAttName(myrelid, colName);
 	if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
 		elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"",
 			 RelationGetRelationName(rel), colName);
@@ -2051,7 +2048,6 @@ AlterTableAlterColumnDefault(Oid myrelid,
 							 Node *newDefault)
 {
 	Relation	rel;
-	HeapTuple	tuple;
 	AttrNumber	attnum;
 
 	rel = heap_open(myrelid, AccessExclusiveLock);
@@ -2106,16 +2102,15 @@ AlterTableAlterColumnDefault(Oid myrelid,
 	/*
 	 * get the number of the attribute
 	 */
-	tuple = SearchSysCache(ATTNAME,
-						   ObjectIdGetDatum(myrelid),
-						   PointerGetDatum(colName),
-						   0, 0);
-	if (!HeapTupleIsValid(tuple))
-		elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"",
+	attnum = get_attnum(myrelid, colName);
+	if (attnum == InvalidAttrNumber)
+		elog(ERROR, "Relation \"%s\" has no column \"%s\"",
 			 RelationGetRelationName(rel), colName);
 
-	attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
-	ReleaseSysCache(tuple);
+	/* Prevent them from altering a system attribute */
+	if (attnum < 0)
+		elog(ERROR, "ALTER TABLE: Cannot alter system attribute \"%s\"",
+			 colName);
 
 	/*
 	 * Remove any old default for the column.  We use RESTRICT here for
@@ -2254,10 +2249,7 @@ AlterTableAlterColumnFlags(Oid myrelid,
 
 	attrelation = heap_openr(AttributeRelationName, RowExclusiveLock);
 
-	tuple = SearchSysCacheCopy(ATTNAME,
-							   ObjectIdGetDatum(myrelid),
-							   PointerGetDatum(colName),
-							   0, 0);
+	tuple = SearchSysCacheCopyAttName(myrelid, colName);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"",
 			 RelationGetRelationName(rel), colName);
@@ -2309,7 +2301,99 @@ AlterTableDropColumn(Oid myrelid,
 					 bool inh, const char *colName,
 					 DropBehavior behavior)
 {
-	elog(ERROR, "ALTER TABLE / DROP COLUMN is not implemented");
+	Relation	rel;
+	AttrNumber	attnum;
+	AttrNumber	n;
+	TupleDesc	tupleDesc;
+	bool		success;
+	ObjectAddress	object;
+
+	rel = heap_open(myrelid, AccessExclusiveLock);
+
+	if (rel->rd_rel->relkind != RELKIND_RELATION)
+		elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table",
+			 RelationGetRelationName(rel));
+
+	if (!allowSystemTableMods
+		&& IsSystemRelation(rel))
+		elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
+			 RelationGetRelationName(rel));
+
+	if (!pg_class_ownercheck(myrelid, GetUserId()))
+		aclcheck_error(ACLCHECK_NOT_OWNER, RelationGetRelationName(rel));
+
+	/*
+	 * get the number of the attribute
+	 */
+	attnum = get_attnum(myrelid, colName);
+	if (attnum == InvalidAttrNumber)
+		elog(ERROR, "Relation \"%s\" has no column \"%s\"",
+			 RelationGetRelationName(rel), colName);
+
+	/* Can't drop a system attribute */
+	if (attnum < 0)
+		elog(ERROR, "ALTER TABLE: Cannot drop system attribute \"%s\"",
+			 colName);
+
+	/*
+	 * Make sure there will be at least one user column left in the relation
+	 * after we drop this one.  Zero-length tuples tend to confuse us.
+	 */
+	tupleDesc = RelationGetDescr(rel);
+
+	success = false;
+	for (n = 1; n <= tupleDesc->natts; n++)
+	{
+		Form_pg_attribute attribute = tupleDesc->attrs[n - 1];
+
+		if (!attribute->attisdropped && n != attnum)
+		{
+			success = true;
+			break;
+		}
+	}
+
+	if (!success)
+		elog(ERROR, "ALTER TABLE: Cannot drop last column from table \"%s\"",
+			RelationGetRelationName(rel));
+
+	/*
+	 * Propagate to children if desired
+	 */
+	if (inh)
+	{
+		List	   *child,
+			   *children;
+
+		/* this routine is actually in the planner */
+		children = find_all_inheritors(myrelid);
+
+		/*
+		 * 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);
+
+			if (childrelid == myrelid)
+				continue;
+			AlterTableDropColumn(childrelid,
+								false, colName, behavior);
+		}
+	}
+
+	/*
+	 * Perform the actual deletion
+	 */
+	object.classId = RelOid_pg_class;
+	object.objectId = myrelid;
+	object.objectSubId = attnum;
+
+	performDeletion(&object, behavior);
+
+	heap_close(rel, NoLock);	/* close rel, but keep lock! */
 }
 
 
@@ -2722,8 +2806,13 @@ createForeignKeyConstraint(Relation rel, Relation pkrel,
 	foreach(l, fkconstraint->fk_attrs)
 	{
 		Ident *id = (Ident *) lfirst(l);
+		AttrNumber	attno;
 
-		fkattr[i++] = get_attnum(RelationGetRelid(rel), id->name);
+		attno = get_attnum(RelationGetRelid(rel), id->name);
+		if (attno == InvalidAttrNumber)
+			elog(ERROR, "Relation \"%s\" has no column \"%s\"",
+				 RelationGetRelationName(rel), id->name);
+		fkattr[i++] = attno;
 	}
 
 	/* The same for the referenced primary key attrs */
@@ -2733,8 +2822,13 @@ createForeignKeyConstraint(Relation rel, Relation pkrel,
 	foreach(l, fkconstraint->pk_attrs)
 	{
 		Ident *id = (Ident *) lfirst(l);
+		AttrNumber	attno;
 
-		pkattr[i++] = get_attnum(RelationGetRelid(pkrel), id->name);
+		attno = get_attnum(RelationGetRelid(pkrel), id->name);
+		if (attno == InvalidAttrNumber)
+			elog(ERROR, "Relation \"%s\" has no column \"%s\"",
+				 RelationGetRelationName(pkrel), id->name);
+		pkattr[i++] = attno;
 	}
 
 	/* Now we can make the pg_constraint entry */
diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c
index 1cc9f5af48925cdf8dda0bcf61585798f67b2630..b7c0bac12c8124934344e55d96381df6640015da 100644
--- a/src/backend/optimizer/prep/preptlist.c
+++ b/src/backend/optimizer/prep/preptlist.c
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.53 2002/06/20 20:29:31 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.54 2002/08/02 18:15:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -165,6 +165,8 @@ expand_targetlist(List *tlist, int command_type,
 			 *
 			 * For UPDATE, generate a Var reference to the existing value of
 			 * the attribute, so that it gets copied to the new tuple.
+			 * But generate a NULL for dropped columns (we want to drop any
+			 * old values).
 			 */
 			Oid			atttype = att_tup->atttypid;
 			int32		atttypmod = att_tup->atttypmod;
@@ -182,11 +184,21 @@ expand_targetlist(List *tlist, int command_type,
 												  false);
 					break;
 				case CMD_UPDATE:
-					new_expr = (Node *) makeVar(result_relation,
-												attrno,
-												atttype,
-												atttypmod,
-												0);
+					/* Insert NULLs for dropped columns */
+					if (att_tup->attisdropped)
+						new_expr = (Node *) makeConst(atttype,
+													  att_tup->attlen,
+													  (Datum) 0,
+													  true,		/* isnull */
+													  att_tup->attbyval,
+													  false,	/* not a set */
+													  false);
+					else
+						new_expr = (Node *) makeVar(result_relation,
+													attrno,
+													atttype,
+													atttypmod,
+													0);
 					break;
 				default:
 					elog(ERROR, "expand_targetlist: unexpected command_type");
@@ -210,7 +222,8 @@ expand_targetlist(List *tlist, int command_type,
 	 * the end of the new tlist, making sure they have resnos higher than
 	 * the last real attribute.  (Note: although the rewriter already did
 	 * such renumbering, we have to do it again here in case we are doing
-	 * an UPDATE in an inheritance child table with more columns.)
+	 * an UPDATE in a table with dropped columns, or an inheritance child
+	 * table with extra columns.)
 	 */
 	while (tlist)
 	{
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 367ef4a58a712a14b2250cc3ecb7953251a22532..f41466dbd5c7f3691b9a3fa6ae8a463b43b83bf5 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -14,7 +14,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.74 2002/06/20 20:29:31 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.75 2002/08/02 18:15:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -797,9 +797,16 @@ adjust_inherited_attrs_mutator(Node *node,
 		{
 			var->varno = context->new_rt_index;
 			if (var->varattno > 0)
-				var->varattno = get_attnum(context->new_relid,
-										   get_attname(context->old_relid,
-													   var->varattno));
+			{
+				char *attname = get_attname(context->old_relid,
+											var->varattno);
+
+				var->varattno = get_attnum(context->new_relid, attname);
+				if (var->varattno == InvalidAttrNumber)
+					elog(ERROR, "Relation \"%s\" has no column \"%s\"",
+						 get_rel_name(context->new_relid), attname);
+				pfree(attname);
+			}
 		}
 		return (Node *) var;
 	}
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 6337b61f2acda5ddb1f3e5c54328cc14302e0f8d..e3d8ce070bc4f2530174897bff414a255a995af4 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.239 2002/07/16 22:12:19 tgl Exp $
+ *	$Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.240 2002/08/02 18:15:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1143,6 +1143,8 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
 						Form_pg_attribute inhattr = rel->rd_att->attrs[count];
 						char	   *inhname = NameStr(inhattr->attname);
 
+						if (inhattr->attisdropped)
+							continue;
 						if (strcmp(key->name, inhname) == 0)
 						{
 							found = true;
@@ -1178,10 +1180,7 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
 				/* ALTER TABLE case: does column already exist? */
 				HeapTuple	atttuple;
 
-				atttuple = SearchSysCache(ATTNAME,
-										  ObjectIdGetDatum(cxt->relOid),
-										  PointerGetDatum(key->name),
-										  0, 0);
+				atttuple = SearchSysCacheAttName(cxt->relOid, key->name);
 				if (HeapTupleIsValid(atttuple))
 				{
 					found = true;
@@ -2369,7 +2368,7 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
 		origTarget = (ResTarget *) lfirst(origTargetList);
 		updateTargetListEntry(pstate, tle, origTarget->name,
 							  attnameAttNum(pstate->p_target_relation,
-											origTarget->name),
+											origTarget->name, true),
 							  origTarget->indirection);
 		origTargetList = lnext(origTargetList);
 	}
@@ -2820,11 +2819,14 @@ transformFkeyGetColType(CreateStmtContext *cxt, char *colname)
 				 inh->relname);
 		for (count = 0; count < rel->rd_att->natts; count++)
 		{
-			char	   *name = NameStr(rel->rd_att->attrs[count]->attname);
+			Form_pg_attribute inhattr = rel->rd_att->attrs[count];
+			char	   *inhname = NameStr(inhattr->attname);
 
-			if (strcmp(name, colname) == 0)
+			if (inhattr->attisdropped)
+				continue;
+			if (strcmp(inhname, colname) == 0)
 			{
-				result = rel->rd_att->attrs[count]->atttypid;
+				result = inhattr->atttypid;
 				heap_close(rel, NoLock);
 				return result;
 			}
@@ -2836,10 +2838,7 @@ transformFkeyGetColType(CreateStmtContext *cxt, char *colname)
 	{
 		HeapTuple	atttuple;
 
-		atttuple = SearchSysCache(ATTNAME,
-								  ObjectIdGetDatum(cxt->relOid),
-								  PointerGetDatum(colname),
-								  0, 0);
+		atttuple = SearchSysCacheAttName(cxt->relOid, colname);
 		if (HeapTupleIsValid(atttuple))
 		{
 			result = ((Form_pg_attribute) GETSTRUCT(atttuple))->atttypid;
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index f92bbe8ac5c229de7f56150393d535e39bba7262..677acf9d1a3d0975f7aacefaeb25c7ed67db87c4 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.132 2002/06/20 20:29:32 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.133 2002/08/02 18:15:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1150,6 +1150,9 @@ setup_field_select(Node *input, char *attname, Oid relid)
 	AttrNumber	attno;
 
 	attno = get_attnum(relid, attname);
+	if (attno == InvalidAttrNumber)
+		elog(ERROR, "Relation \"%s\" has no column \"%s\"",
+			 get_rel_name(relid), attname);
 
 	fselect->arg = input;
 	fselect->fieldnum = attno;
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 78a16ea08f8bcceeace8ebb8f57b7add6bedf3df..99b639d73e37be865e2590d6644daec224ed60bd 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.70 2002/06/20 20:29:33 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.71 2002/08/02 18:15:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -37,7 +37,9 @@ static Node *scanNameSpaceForRefname(ParseState *pstate, Node *nsnode,
 static Node *scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte,
 				 char *colname);
 static bool isForUpdate(ParseState *pstate, char *refname);
-static int	specialAttNum(char *a);
+static bool get_rte_attribute_is_dropped(RangeTblEntry *rte,
+										 AttrNumber attnum);
+static int	specialAttNum(const char *attname);
 static void warnAutoRange(ParseState *pstate, RangeVar *relation);
 
 
@@ -267,12 +269,28 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname)
 	/*
 	 * Scan the user column names (or aliases) for a match. Complain if
 	 * multiple matches.
+	 *
+	 * Note: because eref->colnames may include names of dropped columns,
+	 * we need to check for non-droppedness before accepting a match.
+	 * This takes an extra cache lookup, but we can skip the lookup most
+	 * of the time by exploiting the knowledge that dropped columns are
+	 * assigned dummy names starting with '.', which is an unusual choice
+	 * for actual column names.
+	 *
+	 * Should the user try to fool us by altering pg_attribute.attname
+	 * for a dropped column, we'll still catch it by virtue of the checks
+	 * in get_rte_attribute_type(), which is called by make_var().  That
+	 * routine has to do a cache lookup anyway, so the check there is
+	 * cheap.
 	 */
 	foreach(c, rte->eref->colnames)
 	{
 		attnum++;
 		if (strcmp(strVal(lfirst(c)), colname) == 0)
 		{
+			if (colname[0] == '.' && /* see note above */
+				get_rte_attribute_is_dropped(rte, attnum))
+				continue;
 			if (result)
 				elog(ERROR, "Column reference \"%s\" is ambiguous", colname);
 			result = (Node *) make_var(pstate, rte, attnum);
@@ -962,6 +980,9 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte,
 				{
 					Form_pg_attribute attr = rel->rd_att->attrs[varattno];
 
+					if (attr->attisdropped)
+						continue;
+
 					if (colnames)
 					{
 						char	   *label;
@@ -1051,6 +1072,9 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte,
 					{
 						Form_pg_attribute attr = rel->rd_att->attrs[varattno];
 
+						if (attr->attisdropped)
+							continue;
+
 						if (colnames)
 						{
 							char	   *label;
@@ -1246,9 +1270,16 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
 									0, 0);
 				/* this shouldn't happen... */
 				if (!HeapTupleIsValid(tp))
-					elog(ERROR, "Relation %s does not have attribute %d",
+					elog(ERROR, "Relation \"%s\" does not have attribute %d",
 						 get_rel_name(rte->relid), attnum);
 				att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+				/*
+				 * If dropped column, pretend it ain't there.  See notes
+				 * in scanRTEForColumn.
+				 */
+				if (att_tup->attisdropped)
+					elog(ERROR, "Relation \"%s\" has no column \"%s\"",
+						 get_rel_name(rte->relid), NameStr(att_tup->attname));
 				*vartype = att_tup->atttypid;
 				*vartypmod = att_tup->atttypmod;
 				ReleaseSysCache(tp);
@@ -1298,6 +1329,14 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
 						elog(ERROR, "Relation %s does not have attribute %d",
 							 get_rel_name(funcrelid), attnum);
 					att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+					/*
+					 * If dropped column, pretend it ain't there.  See notes
+					 * in scanRTEForColumn.
+					 */
+					if (att_tup->attisdropped)
+						elog(ERROR, "Relation \"%s\" has no column \"%s\"",
+							 get_rel_name(funcrelid),
+							 NameStr(att_tup->attname));
 					*vartype = att_tup->atttypid;
 					*vartypmod = att_tup->atttypmod;
 					ReleaseSysCache(tp);
@@ -1329,6 +1368,86 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
 	}
 }
 
+/*
+ * get_rte_attribute_is_dropped
+ *		Check whether attempted attribute ref is to a dropped column
+ */
+static bool
+get_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum)
+{
+	bool result;
+
+	switch (rte->rtekind)
+	{
+		case RTE_RELATION:
+			{
+				/* Plain relation RTE --- get the attribute's type info */
+				HeapTuple	tp;
+				Form_pg_attribute att_tup;
+
+				tp = SearchSysCache(ATTNUM,
+									ObjectIdGetDatum(rte->relid),
+									Int16GetDatum(attnum),
+									0, 0);
+				/* this shouldn't happen... */
+				if (!HeapTupleIsValid(tp))
+					elog(ERROR, "Relation \"%s\" does not have attribute %d",
+						 get_rel_name(rte->relid), attnum);
+				att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+				result = att_tup->attisdropped;
+				ReleaseSysCache(tp);
+			}
+			break;
+		case RTE_SUBQUERY:
+		case RTE_JOIN:
+			/* Subselect and join RTEs never have dropped columns */
+			result = false;
+			break;
+		case RTE_FUNCTION:
+			{
+				/* Function RTE */
+				Oid			funcrettype = exprType(rte->funcexpr);
+				Oid			funcrelid = typeidTypeRelid(funcrettype);
+
+				if (OidIsValid(funcrelid))
+				{
+					/*
+					 * Composite data type, i.e. a table's row type
+					 * Same as ordinary relation RTE
+					 */
+					HeapTuple			tp;
+					Form_pg_attribute	att_tup;
+
+					tp = SearchSysCache(ATTNUM,
+										ObjectIdGetDatum(funcrelid),
+										Int16GetDatum(attnum),
+										0, 0);
+					/* this shouldn't happen... */
+					if (!HeapTupleIsValid(tp))
+						elog(ERROR, "Relation %s does not have attribute %d",
+							 get_rel_name(funcrelid), attnum);
+					att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+					result = att_tup->attisdropped;
+					ReleaseSysCache(tp);
+				}
+				else
+				{
+					/*
+					 * Must be a base data type, i.e. scalar
+					 */
+					result = false;
+				}
+			}
+			break;
+		default:
+			elog(ERROR, "get_rte_attribute_is_dropped: unsupported RTE kind %d",
+				 (int) rte->rtekind);
+			result = false;		/* keep compiler quiet */
+	}
+
+	return result;
+}
+
 /*
  *	given relation and att name, return id of variable
  *
@@ -1337,23 +1456,30 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
  *	for access to non-opened relations.
  */
 int
-attnameAttNum(Relation rd, char *a)
+attnameAttNum(Relation rd, const char *attname, bool sysColOK)
 {
 	int			i;
 
 	for (i = 0; i < rd->rd_rel->relnatts; i++)
-		if (namestrcmp(&(rd->rd_att->attrs[i]->attname), a) == 0)
+	{
+		Form_pg_attribute	att = rd->rd_att->attrs[i];
+
+		if (namestrcmp(&(att->attname), attname) == 0 && !att->attisdropped)
 			return i + 1;
+	}
 
-	if ((i = specialAttNum(a)) != InvalidAttrNumber)
+	if (sysColOK)
 	{
-		if (i != ObjectIdAttributeNumber || rd->rd_rel->relhasoids)
-			return i;
+		if ((i = specialAttNum(attname)) != InvalidAttrNumber)
+		{
+			if (i != ObjectIdAttributeNumber || rd->rd_rel->relhasoids)
+				return i;
+		}
 	}
 
 	/* on failure */
-	elog(ERROR, "Relation '%s' does not have attribute '%s'",
-		 RelationGetRelationName(rd), a);
+	elog(ERROR, "Relation \"%s\" has no column \"%s\"",
+		 RelationGetRelationName(rd), attname);
 	return InvalidAttrNumber;	/* lint */
 }
 
@@ -1367,11 +1493,12 @@ attnameAttNum(Relation rd, char *a)
  * at least in the case of "oid", which is now optional.
  */
 static int
-specialAttNum(char *a)
+specialAttNum(const char *attname)
 {
 	Form_pg_attribute sysatt;
 
-	sysatt = SystemAttributeByName(a, true /* "oid" will be accepted */ );
+	sysatt = SystemAttributeByName(attname,
+								   true /* "oid" will be accepted */ );
 	if (sysatt != NULL)
 		return sysatt->attnum;
 	return InvalidAttrNumber;
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 608ca7613dc83087fd2a692a6f7e98d639796129..1e51f23d7049823760f019e477e0635c8bb1cce7 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.85 2002/06/20 20:29:33 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.86 2002/08/02 18:15:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -385,8 +385,12 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
 
 		for (i = 0; i < numcol; i++)
 		{
-			ResTarget	   *col = makeNode(ResTarget);
+			ResTarget	   *col;
 
+			if (attr[i]->attisdropped)
+				continue;
+
+			col = makeNode(ResTarget);
 			col->name = pstrdup(NameStr(attr[i]->attname));
 			col->indirection = NIL;
 			col->val = NULL;
@@ -407,7 +411,7 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
 			int			attrno;
 
 			/* Lookup column name, elog on failure */
-			attrno = attnameAttNum(pstate->p_target_relation, name);
+			attrno = attnameAttNum(pstate->p_target_relation, name, false);
 			/* Check for duplicates */
 			if (intMember(attrno, *attrnos))
 				elog(ERROR, "Attribute '%s' specified more than once", name);
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index 159428894e47bf886a4a277e07d481f0aeb0366b..59c534a7ef3161a293642ecf3993a51ef1d0b275 100644
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.46 2002/07/29 23:46:35 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.47 2002/08/02 18:15:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -85,8 +85,8 @@ LookupTypeName(const TypeName *typename)
 		relid = RangeVarGetRelid(rel, false);
 		attnum = get_attnum(relid, field);
 		if (attnum == InvalidAttrNumber)
-			elog(ERROR, "'%s' is not an attribute of class '%s'",
-				 field, rel->relname);
+			elog(ERROR, "Relation \"%s\" has no column \"%s\"",
+				 rel->relname, field);
 		restype = get_atttype(relid, attnum);
 
 		/* this construct should never have an array indicator */
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 59d0744dcee15d7c00a8dabe8d94048769af49fd..577ce2bd52d7c22165323f3bbca3ac5c48936bba 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.75 2002/07/16 05:53:34 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.76 2002/08/02 18:15:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -257,6 +257,16 @@ DefineQueryRewrite(RuleStmt *stmt)
 			attr = event_relation->rd_att->attrs[i - 1];
 			attname = NameStr(attr->attname);
 
+			/*
+			 * Disallow dropped columns in the relation.  This won't happen
+			 * in the cases we actually care about (namely creating a view
+			 * via CREATE TABLE then CREATE RULE).  Trying to cope with it
+			 * is much more trouble than it's worth, because we'd have to
+			 * modify the rule to insert dummy NULLs at the right positions.
+			 */
+			if (attr->attisdropped)
+				elog(ERROR, "cannot convert relation containing dropped columns to view");
+
 			if (strcmp(resdom->resname, attname) != 0)
 				elog(ERROR, "select rule's target entry %d has different column name from %s", i, attname);
 
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 0ae1e223baae20fc71bb1b85c8de49edab7c7817..95ab639d0a7ff6d43e355877c8c1e059329ee29c 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.104 2002/07/18 04:43:50 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.105 2002/08/02 18:15:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -264,6 +264,10 @@ rewriteTargetList(Query *parsetree, Relation target_relation)
 		Form_pg_attribute att_tup = target_relation->rd_att->attrs[attrno-1];
 		TargetEntry *new_tle = NULL;
 
+		/* We can ignore deleted attributes */
+		if (att_tup->attisdropped)
+			continue;
+
 		/*
 		 * Look for targetlist entries matching this attr.  We match by
 		 * resno, but the resname should match too.
diff --git a/src/backend/utils/adt/not_in.c b/src/backend/utils/adt/not_in.c
index 5982e434da39e86dba6137778cd6a28e3d786f0b..7c6be4533eb28090101757964f9e0be6b3f4726e 100644
--- a/src/backend/utils/adt/not_in.c
+++ b/src/backend/utils/adt/not_in.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/not_in.c,v 1.30 2002/06/20 20:29:37 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/not_in.c,v 1.31 2002/08/02 18:15:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,9 +28,9 @@
 
 #include "access/heapam.h"
 #include "catalog/namespace.h"
+#include "parser/parse_relation.h"
 #include "utils/builtins.h"
 
-static int	my_varattno(Relation rd, char *a);
 
 /* ----------------------------------------------------------------
  *
@@ -65,15 +65,10 @@ int4notin(PG_FUNCTION_ARGS)
 	relrv = makeRangeVarFromNameList(names);
 
 	/* Open the relation and get a relation descriptor */
-
 	relation_to_scan = heap_openrv(relrv, AccessShareLock);
 
 	/* Find the column to search */
-
-	attrid = my_varattno(relation_to_scan, attribute);
-	if (attrid < 0)
-		elog(ERROR, "int4notin: unknown attribute %s for relation %s",
-			 attribute, RelationGetRelationName(relation_to_scan));
+	attrid = attnameAttNum(relation_to_scan, attribute, true);
 
 	scan_descriptor = heap_beginscan(relation_to_scan, SnapshotNow,
 									 0, (ScanKey) NULL);
@@ -118,21 +113,3 @@ oidnotin(PG_FUNCTION_ARGS)
 	/* XXX assume oid maps to int4 */
 	return int4notin(fcinfo);
 }
-
-/*
- * XXX
- * If varattno (in parser/catalog_utils.h) ever is added to
- * cinterface.a, this routine should go away
- */
-static int
-my_varattno(Relation rd, char *a)
-{
-	int			i;
-
-	for (i = 0; i < rd->rd_rel->relnatts; i++)
-	{
-		if (namestrcmp(&rd->rd_att->attrs[i]->attname, a) == 0)
-			return i + 1;
-	}
-	return -1;
-}
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index e383ab892d1420b8b695dd1f26a75c3adf252063..9b5b4cd6f13267cdf8ce2343c050edd2bca129a1 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.76 2002/07/12 18:43:18 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.77 2002/08/02 18:15:08 tgl Exp $
  *
  * NOTES
  *	  Eventually, the index information should go through here, too.
@@ -115,16 +115,15 @@ get_attname(Oid relid, AttrNumber attnum)
  *
  *		Given the relation id and the attribute name,
  *		return the "attnum" field from the attribute relation.
+ *
+ *		Returns InvalidAttrNumber if the attr doesn't exist (or is dropped).
  */
 AttrNumber
-get_attnum(Oid relid, char *attname)
+get_attnum(Oid relid, const char *attname)
 {
 	HeapTuple	tp;
 
-	tp = SearchSysCache(ATTNAME,
-						ObjectIdGetDatum(relid),
-						PointerGetDatum(attname),
-						0, 0);
+	tp = SearchSysCacheAttName(relid, attname);
 	if (HeapTupleIsValid(tp))
 	{
 		Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
@@ -166,32 +165,6 @@ get_atttype(Oid relid, AttrNumber attnum)
 		return InvalidOid;
 }
 
-/* This routine uses the attname instead of the attnum because it
- * replaces the routine find_atttype, which is called sometimes when
- * only the attname, not the attno, is available.
- */
-bool
-get_attisset(Oid relid, char *attname)
-{
-	HeapTuple	tp;
-
-	tp = SearchSysCache(ATTNAME,
-						ObjectIdGetDatum(relid),
-						PointerGetDatum(attname),
-						0, 0);
-	if (HeapTupleIsValid(tp))
-	{
-		Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
-		bool		result;
-
-		result = att_tup->attisset;
-		ReleaseSysCache(tp);
-		return result;
-	}
-	else
-		return false;
-}
-
 /*
  * get_atttypmod
  *
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index 0e114f3696828256c892e161a6c06f9af0e02aa9..c9b68b1d8d42c902b21bc8e8f40dcdab444264b0 100644
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.84 2002/07/25 10:07:12 ishii Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.85 2002/08/02 18:15:08 tgl Exp $
  *
  * NOTES
  *	  These routines allow the parser/planner/executor to perform
@@ -622,6 +622,71 @@ GetSysCacheOid(int cacheId,
 	return result;
 }
 
+
+/*
+ * SearchSysCacheAttName
+ *
+ * This routine is equivalent to SearchSysCache on the ATTNAME cache,
+ * except that it will return NULL if the found attribute is marked
+ * attisdropped.  This is convenient for callers that want to act as
+ * though dropped attributes don't exist.
+ */
+HeapTuple
+SearchSysCacheAttName(Oid relid, const char *attname)
+{
+	HeapTuple	tuple;
+
+	tuple = SearchSysCache(ATTNAME,
+						   ObjectIdGetDatum(relid),
+						   CStringGetDatum(attname),
+						   0, 0);
+	if (!HeapTupleIsValid(tuple))
+		return NULL;
+	if (((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped)
+	{
+		ReleaseSysCache(tuple);
+		return NULL;
+	}
+	return tuple;
+}
+
+/*
+ * SearchSysCacheCopyAttName
+ *
+ * As above, an attisdropped-aware version of SearchSysCacheCopy.
+ */
+HeapTuple
+SearchSysCacheCopyAttName(Oid relid, const char *attname)
+{
+	HeapTuple	tuple,
+				newtuple;
+
+	tuple = SearchSysCacheAttName(relid, attname);
+	if (!HeapTupleIsValid(tuple))
+		return tuple;
+	newtuple = heap_copytuple(tuple);
+	ReleaseSysCache(tuple);
+	return newtuple;
+}
+
+/*
+ * SearchSysCacheExistsAttName
+ *
+ * As above, an attisdropped-aware version of SearchSysCacheExists.
+ */
+bool
+SearchSysCacheExistsAttName(Oid relid, const char *attname)
+{
+	HeapTuple	tuple;
+
+	tuple = SearchSysCacheAttName(relid, attname);
+	if (!HeapTupleIsValid(tuple))
+		return false;
+	ReleaseSysCache(tuple);
+	return true;
+}
+
+
 /*
  * SysCacheGetAttr
  *
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 7ca027e010516ccd51e6888cff3aeb309e111f3d..0a44b4cbbcfb4de0dc3a286b536a4837ed759e99 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.278 2002/07/31 17:19:52 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.279 2002/08/02 18:15:08 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -863,13 +863,15 @@ dumpClasses_nodumpData(Archive *fout, char *oid, void *dctxv)
 	{
 		appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
 						  fmtQualifiedId(tbinfo->relnamespace->nspname,
-										 classname),column_list);
+										 classname),
+						  column_list);
 	}
 	else
 	{
 		appendPQExpBuffer(q, "COPY %s %s TO stdout;",
 						  fmtQualifiedId(tbinfo->relnamespace->nspname,
-										 classname), column_list);
+										 classname),
+						  column_list);
 	}
 	res = PQexec(g_conn, q->data);
 	if (!res ||
@@ -1193,10 +1195,13 @@ dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout,
 			if (!dumpData)
 			{
 				/* Dump/restore using COPY */
+				const char *column_list;
+
 				dumpFn = dumpClasses_nodumpData;
+				column_list = fmtCopyColumnList(&(tblinfo[i]));
 				sprintf(copyBuf, "COPY %s %s %sFROM stdin;\n",
-						fmtQualifiedId(tblinfo[i].relnamespace->nspname,tblinfo[i].relname),
-						fmtCopyColumnList(&(tblinfo[i])),
+						fmtId(tblinfo[i].relname, force_quotes),
+						column_list,
 						(oids && tblinfo[i].hasoids) ? "WITH OIDS " : "");
 				copyStmt = copyBuf;
 			}
@@ -2347,6 +2352,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 	int			i_attstattarget;
 	int			i_attnotnull;
 	int			i_atthasdef;
+	int			i_attisdropped;
 	PGresult   *res;
 	int			ntups;
 	bool		hasdefaults;
@@ -2386,7 +2392,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 		if (g_fout->remoteVersion >= 70300)
 		{
 			appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, attstattarget, "
-							  "attnotnull, atthasdef, "
+							  "attnotnull, atthasdef, attisdropped, "
 							  "pg_catalog.format_type(atttypid,atttypmod) as atttypname "
 							  "from pg_catalog.pg_attribute a "
 							  "where attrelid = '%s'::pg_catalog.oid "
@@ -2402,7 +2408,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 			 * explicitly set or was just a default.
 			 */
 			appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, -1 as attstattarget, "
-							  "attnotnull, atthasdef, "
+							  "attnotnull, atthasdef, false as attisdropped, "
 							  "format_type(atttypid,atttypmod) as atttypname "
 							  "from pg_attribute a "
 							  "where attrelid = '%s'::oid "
@@ -2414,7 +2420,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 		{
 			/* format_type not available before 7.1 */
 			appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, -1 as attstattarget, "
-							  "attnotnull, atthasdef, "
+							  "attnotnull, atthasdef, false as attisdropped, "
 							  "(select typname from pg_type where oid = atttypid) as atttypname "
 							  "from pg_attribute a "
 							  "where attrelid = '%s'::oid "
@@ -2439,12 +2445,14 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 		i_attstattarget = PQfnumber(res, "attstattarget");
 		i_attnotnull = PQfnumber(res, "attnotnull");
 		i_atthasdef = PQfnumber(res, "atthasdef");
+		i_attisdropped = PQfnumber(res, "attisdropped");
 
 		tblinfo[i].numatts = ntups;
 		tblinfo[i].attnames = (char **) malloc(ntups * sizeof(char *));
 		tblinfo[i].atttypnames = (char **) malloc(ntups * sizeof(char *));
 		tblinfo[i].atttypmod = (int *) malloc(ntups * sizeof(int));
 		tblinfo[i].attstattarget = (int *) malloc(ntups * sizeof(int));
+		tblinfo[i].attisdropped = (bool *) malloc(ntups * sizeof(bool));
 		tblinfo[i].notnull = (bool *) malloc(ntups * sizeof(bool));
 		tblinfo[i].adef_expr = (char **) malloc(ntups * sizeof(char *));
 		tblinfo[i].inhAttrs = (bool *) malloc(ntups * sizeof(bool));
@@ -2458,6 +2466,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 			tblinfo[i].atttypnames[j] = strdup(PQgetvalue(res, j, i_atttypname));
 			tblinfo[i].atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
 			tblinfo[i].attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
+			tblinfo[i].attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
 			tblinfo[i].notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
 			tblinfo[i].adef_expr[j] = NULL;	/* fix below */
 			if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
@@ -4999,8 +5008,8 @@ dumpOneTable(Archive *fout, TableInfo *tbinfo, TableInfo *g_tblinfo)
 		actual_atts = 0;
 		for (j = 0; j < tbinfo->numatts; j++)
 		{
-			/* Is this one of the table's own attrs ? */
-			if (!tbinfo->inhAttrs[j])
+			/* Is this one of the table's own attrs, and not dropped ? */
+			if (!tbinfo->inhAttrs[j] && !tbinfo->attisdropped[j])
 			{
 				/* Format properly if not first attr */
 				if (actual_atts > 0)
@@ -5161,7 +5170,8 @@ dumpOneTable(Archive *fout, TableInfo *tbinfo, TableInfo *g_tblinfo)
 		 */
 		for (j = 0; j  < tbinfo->numatts; j++)
 		{
-			if (tbinfo->attstattarget[j] >= 0)
+			if (tbinfo->attstattarget[j] >= 0 &&
+				!tbinfo->attisdropped[j])
 			{
 				appendPQExpBuffer(q, "ALTER TABLE %s ",
 								  fmtId(tbinfo->relname, force_quotes));
@@ -6274,7 +6284,7 @@ fmtQualifiedId(const char *schema, const char *id)
 }
 
 /*
- * return a column list clause for the qualified relname.
+ * return a column list clause for the given relation.
  * returns an empty string if the remote server is older than
  * 7.3.
  */
@@ -6284,9 +6294,11 @@ fmtCopyColumnList(const TableInfo* ti)
 	static PQExpBuffer q = NULL;
 	int			numatts = ti->numatts;
 	char**  attnames = ti->attnames;
+	bool*	attisdropped = ti->attisdropped;
+	bool	needComma;
 	int i;
 
-	if (g_fout->remoteVersion < 70300 )
+	if (g_fout->remoteVersion < 70300)
 		return "";
 
 	if (q)				/* first time through? */
@@ -6295,15 +6307,18 @@ fmtCopyColumnList(const TableInfo* ti)
 		q = createPQExpBuffer();
 
 	resetPQExpBuffer(q);
-	
-	appendPQExpBuffer(q,"(");
+
+	appendPQExpBuffer(q, "(");
+	needComma = false;
 	for (i = 0; i < numatts; i++)
 	{
-		if( i > 0 )
-			appendPQExpBuffer(q,",");
-		appendPQExpBuffer(q, fmtId(attnames[i], force_quotes));
+		if (attisdropped[i])
+			continue;
+		if (needComma)
+			appendPQExpBuffer(q, ",");
+		appendPQExpBuffer(q, "%s", fmtId(attnames[i], force_quotes));
+		needComma = true;
 	}
 	appendPQExpBuffer(q, ")");
 	return q->data;
 }
-
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 6a6322c9ca2fb1525fd56a6ea781614da505390d..9a208f1e1475b8726417200bff03bcd3afc6337b 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.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: pg_dump.h,v 1.93 2002/07/31 17:19:53 tgl Exp $
+ * $Id: pg_dump.h,v 1.94 2002/08/02 18:15:08 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -128,6 +128,7 @@ typedef struct _tableInfo
 	 * all interesting tables so that we can tell which constraints were
 	 * inherited.
 	 */
+	bool	   *attisdropped;	/* true if attr is dropped; don't dump it */
 	bool	   *notnull;		/* Not null constraints on attributes */
 	char	  **adef_expr;		/* DEFAULT expressions */
 	bool	   *inhAttrs;		/* true if each attribute is inherited */
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index d60483870a9a55124920653ec351a9556bfa97e9..bff6c5b73d0ad73b1eebf96dbaa6428cddb2f324 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.56 2002/07/20 05:57:31 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.57 2002/08/02 18:15:08 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "describe.h"
@@ -536,7 +536,7 @@ describeTableDetails(const char *name, bool desc)
 	appendPQExpBuffer(&buf, "\nFROM pg_class c, pg_attribute a");
 	if (tableinfo.relkind == 'i')
 		appendPQExpBuffer(&buf, ", pg_index i");
-	appendPQExpBuffer(&buf, "\nWHERE c.relname = '%s'\n  AND a.attnum > 0 AND a.attrelid = c.oid", name);
+	appendPQExpBuffer(&buf, "\nWHERE c.relname = '%s'\n  AND a.attnum > 0 AND NOT a.attisdropped AND a.attrelid = c.oid", name);
 	if (tableinfo.relkind == 'i')
 		appendPQExpBuffer(&buf, " AND a.attrelid = i.indexrelid");
 	appendPQExpBuffer(&buf, "\nORDER BY a.attnum");
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index f60ccae324a45f10a4d0cab63fc825d7c227eb88..3eef1d55eee47ad03f0def166940ed47c0a523c1 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -3,7 +3,7 @@
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.53 2002/07/31 17:19:53 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.54 2002/08/02 18:15:09 tgl Exp $
  */
 
 /*----------------------------------------------------------------------
@@ -156,7 +156,7 @@ pgsql_thing_t words_after_create[] = {
 #define Query_for_list_of_tables words_after_create[9].query
 #define Query_for_list_of_indexes words_after_create[4].query
 #define Query_for_list_of_databases words_after_create[1].query
-#define Query_for_list_of_attributes "SELECT a.attname FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c WHERE c.oid = a.attrelid and a.attnum>0 and substr(a.attname,1,%d)='%s' and c.relname='%s'"
+#define Query_for_list_of_attributes "SELECT a.attname FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c WHERE c.oid = a.attrelid and a.attnum>0 and not a.attisdropped and substr(a.attname,1,%d)='%s' and c.relname='%s'"
 #define Query_for_list_of_users words_after_create[14].query
 
 /* A couple of macros to ease typing. You can use these to complete the given
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 9dcd646e6f37014fb8d061af04b81a1c467f8a5c..f3e36226b015a5dcb1981e2abd63435a8568321a 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.143 2002/07/25 10:07:12 ishii Exp $
+ * $Id: catversion.h,v 1.144 2002/08/02 18:15:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200207251
+#define CATALOG_VERSION_NO	200208011
 
 #endif
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index 3148fd32633c3d3fe7adde956660e161e09e542a..f45c61515adb6dac3a1987967d3f7ba5a6ae33b3 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.54 2002/07/15 16:33:31 tgl Exp $
+ * $Id: heap.h,v 1.55 2002/08/02 18:15:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -63,6 +63,7 @@ extern int	RemoveRelConstraints(Relation rel, const char *constrName,
 
 extern void DeleteRelationTuple(Oid relid);
 extern void DeleteAttributeTuples(Oid relid);
+extern void RemoveAttributeById(Oid relid, AttrNumber attnum);
 extern void RemoveAttrDefault(Oid relid, AttrNumber attnum,
 							  DropBehavior behavior, bool complain);
 extern void RemoveAttrDefaultById(Oid attrdefId);
diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h
index 15945192a00d052953fe52e540801710c8760ab8..a888fcf523c4da5a5e62e7c9af5724396f462b76 100644
--- a/src/include/catalog/pg_attribute.h
+++ b/src/include/catalog/pg_attribute.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_attribute.h,v 1.95 2002/07/31 17:19:54 tgl Exp $
+ * $Id: pg_attribute.h,v 1.96 2002/08/02 18:15:09 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -143,6 +143,9 @@ CATALOG(pg_attribute) BOOTSTRAP BKI_WITHOUT_OIDS
 
 	/* Has DEFAULT value or not */
 	bool		atthasdef;
+
+	/* Is dropped (ie, logically invisible) or not */
+	bool		attisdropped;
 } FormData_pg_attribute;
 
 /*
@@ -151,7 +154,7 @@ CATALOG(pg_attribute) BOOTSTRAP BKI_WITHOUT_OIDS
  * because of alignment padding at the end of the struct.)
  */
 #define ATTRIBUTE_TUPLE_SIZE \
-	(offsetof(FormData_pg_attribute,atthasdef) + sizeof(bool))
+	(offsetof(FormData_pg_attribute,attisdropped) + sizeof(bool))
 
 /* ----------------
  *		Form_pg_attribute corresponds to a pointer to a tuple with
@@ -165,7 +168,7 @@ typedef FormData_pg_attribute *Form_pg_attribute;
  * ----------------
  */
 
-#define Natts_pg_attribute				15
+#define Natts_pg_attribute				16
 #define Anum_pg_attribute_attrelid		1
 #define Anum_pg_attribute_attname		2
 #define Anum_pg_attribute_atttypid		3
@@ -181,6 +184,7 @@ typedef FormData_pg_attribute *Form_pg_attribute;
 #define Anum_pg_attribute_attalign		13
 #define Anum_pg_attribute_attnotnull	14
 #define Anum_pg_attribute_atthasdef		15
+#define Anum_pg_attribute_attisdropped	16
 
 
 
@@ -211,264 +215,266 @@ typedef FormData_pg_attribute *Form_pg_attribute;
  * ----------------
  */
 #define Schema_pg_type \
-{ 1247, {"typname"},	   19, -1, NAMEDATALEN,	1, 0, -1, -1, false, 'p', false, 'i', false, false }, \
-{ 1247, {"typnamespace"},  26, 0,	4,	2, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1247, {"typowner"},	   23, 0,	4,	3, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1247, {"typlen"},		   21, 0,	2,	4, 0, -1, -1, true, 'p', false, 's', false, false }, \
-{ 1247, {"typbyval"},	   16, 0,	1,	5, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1247, {"typtype"},	   18, 0,	1,	6, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1247, {"typisdefined"},  16, 0,	1,	7, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1247, {"typdelim"},	   18, 0,	1,	8, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1247, {"typrelid"},	   26, 0,	4,	9, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1247, {"typelem"},	   26, 0,	4, 10, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1247, {"typinput"},	   24, 0,	4, 11, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1247, {"typoutput"},	   24, 0,	4, 12, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1247, {"typalign"},	   18, 0,	1, 13, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1247, {"typstorage"},    18, 0,	1, 14, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1247, {"typnotnull"},    16, 0,   1, 15, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1247, {"typbasetype"},   26, 0,	4, 16, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1247, {"typtypmod"},     23, 0,	4, 17, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1247, {"typndims"},      23, 0,	4, 18, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1247, {"typdefaultbin"}, 25, 0,  -1, 19, 0, -1, -1, false, 'x', false, 'i', false, false }, \
-{ 1247, {"typdefault"},    25, 0,  -1, 20, 0, -1, -1, false, 'x', false, 'i', false, false }
-
-
-DATA(insert ( 1247 typname			19 -1 NAMEDATALEN   1 0 -1 -1 f p f i f f));
-DATA(insert ( 1247 typnamespace		26 0  4   2 0 -1 -1 t p f i f f));
-DATA(insert ( 1247 typowner			23 0  4   3 0 -1 -1 t p f i f f));
-DATA(insert ( 1247 typlen			21 0  2   4 0 -1 -1 t p f s f f));
-DATA(insert ( 1247 typbyval			16 0  1   5 0 -1 -1 t p f c f f));
-DATA(insert ( 1247 typtype			18 0  1   6 0 -1 -1 t p f c f f));
-DATA(insert ( 1247 typisdefined		16 0  1   7 0 -1 -1 t p f c f f));
-DATA(insert ( 1247 typdelim			18 0  1   8 0 -1 -1 t p f c f f));
-DATA(insert ( 1247 typrelid			26 0  4   9 0 -1 -1 t p f i f f));
-DATA(insert ( 1247 typelem			26 0  4  10 0 -1 -1 t p f i f f));
-DATA(insert ( 1247 typinput			24 0  4  11 0 -1 -1 t p f i f f));
-DATA(insert ( 1247 typoutput		24 0  4  12 0 -1 -1 t p f i f f));
-DATA(insert ( 1247 typalign			18 0  1  13 0 -1 -1 t p f c f f));
-DATA(insert ( 1247 typstorage		18 0  1  14 0 -1 -1 t p f c f f));
-DATA(insert ( 1247 typnotnull		16 0  1  15 0 -1 -1 t p f c f f));
-DATA(insert ( 1247 typbasetype		26 0  4  16 0 -1 -1 t p f i f f));
-DATA(insert ( 1247 typtypmod		23 0  4  17 0 -1 -1 t p f i f f));
-DATA(insert ( 1247 typndims			23 0  4  18 0 -1 -1 t p f i f f));
-DATA(insert ( 1247 typdefaultbin	25 0 -1  19 0 -1 -1 f x f i f f));
-DATA(insert ( 1247 typdefault		25 0 -1  20 0 -1 -1 f x f i f f));
-DATA(insert ( 1247 ctid				27 0  6  -1 0 -1 -1 f p f i f f));
-DATA(insert ( 1247 oid				26 0  4  -2 0 -1 -1 t p f i f f));
-DATA(insert ( 1247 xmin				28 0  4  -3 0 -1 -1 t p f i f f));
-DATA(insert ( 1247 cmin				29 0  4  -4 0 -1 -1 t p f i f f));
-DATA(insert ( 1247 xmax				28 0  4  -5 0 -1 -1 t p f i f f));
-DATA(insert ( 1247 cmax				29 0  4  -6 0 -1 -1 t p f i f f));
-DATA(insert ( 1247 tableoid			26 0  4  -7 0 -1 -1 t p f i f f));
+{ 1247, {"typname"},	   19, -1, NAMEDATALEN,	1, 0, -1, -1, false, 'p', false, 'i', true, false, false }, \
+{ 1247, {"typnamespace"},  26, 0,	4,	2, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1247, {"typowner"},	   23, 0,	4,	3, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1247, {"typlen"},		   21, 0,	2,	4, 0, -1, -1, true, 'p', false, 's', true, false, false }, \
+{ 1247, {"typbyval"},	   16, 0,	1,	5, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1247, {"typtype"},	   18, 0,	1,	6, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1247, {"typisdefined"},  16, 0,	1,	7, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1247, {"typdelim"},	   18, 0,	1,	8, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1247, {"typrelid"},	   26, 0,	4,	9, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1247, {"typelem"},	   26, 0,	4, 10, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1247, {"typinput"},	   24, 0,	4, 11, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1247, {"typoutput"},	   24, 0,	4, 12, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1247, {"typalign"},	   18, 0,	1, 13, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1247, {"typstorage"},    18, 0,	1, 14, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1247, {"typnotnull"},    16, 0,   1, 15, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1247, {"typbasetype"},   26, 0,	4, 16, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1247, {"typtypmod"},     23, 0,	4, 17, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1247, {"typndims"},      23, 0,	4, 18, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1247, {"typdefaultbin"}, 25, 0,  -1, 19, 0, -1, -1, false, 'x', false, 'i', false, false, false }, \
+{ 1247, {"typdefault"},    25, 0,  -1, 20, 0, -1, -1, false, 'x', false, 'i', false, false, false }
+
+
+DATA(insert ( 1247 typname			19 -1 NAMEDATALEN   1 0 -1 -1 f p f i t f f));
+DATA(insert ( 1247 typnamespace		26 0  4   2 0 -1 -1 t p f i t f f));
+DATA(insert ( 1247 typowner			23 0  4   3 0 -1 -1 t p f i t f f));
+DATA(insert ( 1247 typlen			21 0  2   4 0 -1 -1 t p f s t f f));
+DATA(insert ( 1247 typbyval			16 0  1   5 0 -1 -1 t p f c t f f));
+DATA(insert ( 1247 typtype			18 0  1   6 0 -1 -1 t p f c t f f));
+DATA(insert ( 1247 typisdefined		16 0  1   7 0 -1 -1 t p f c t f f));
+DATA(insert ( 1247 typdelim			18 0  1   8 0 -1 -1 t p f c t f f));
+DATA(insert ( 1247 typrelid			26 0  4   9 0 -1 -1 t p f i t f f));
+DATA(insert ( 1247 typelem			26 0  4  10 0 -1 -1 t p f i t f f));
+DATA(insert ( 1247 typinput			24 0  4  11 0 -1 -1 t p f i t f f));
+DATA(insert ( 1247 typoutput		24 0  4  12 0 -1 -1 t p f i t f f));
+DATA(insert ( 1247 typalign			18 0  1  13 0 -1 -1 t p f c t f f));
+DATA(insert ( 1247 typstorage		18 0  1  14 0 -1 -1 t p f c t f f));
+DATA(insert ( 1247 typnotnull		16 0  1  15 0 -1 -1 t p f c t f f));
+DATA(insert ( 1247 typbasetype		26 0  4  16 0 -1 -1 t p f i t f f));
+DATA(insert ( 1247 typtypmod		23 0  4  17 0 -1 -1 t p f i t f f));
+DATA(insert ( 1247 typndims			23 0  4  18 0 -1 -1 t p f i t f f));
+DATA(insert ( 1247 typdefaultbin	25 0 -1  19 0 -1 -1 f x f i f f f));
+DATA(insert ( 1247 typdefault		25 0 -1  20 0 -1 -1 f x f i f f f));
+DATA(insert ( 1247 ctid				27 0  6  -1 0 -1 -1 f p f i t f f));
+DATA(insert ( 1247 oid				26 0  4  -2 0 -1 -1 t p f i t f f));
+DATA(insert ( 1247 xmin				28 0  4  -3 0 -1 -1 t p f i t f f));
+DATA(insert ( 1247 cmin				29 0  4  -4 0 -1 -1 t p f i t f f));
+DATA(insert ( 1247 xmax				28 0  4  -5 0 -1 -1 t p f i t f f));
+DATA(insert ( 1247 cmax				29 0  4  -6 0 -1 -1 t p f i t f f));
+DATA(insert ( 1247 tableoid			26 0  4  -7 0 -1 -1 t p f i t f f));
 
 /* ----------------
  *		pg_database
  * ----------------
  */
-DATA(insert ( 1262 datname			19 0 NAMEDATALEN   1 0 -1 -1 f p f i f f));
-DATA(insert ( 1262 datdba			23 0  4   2 0 -1 -1 t p f i f f));
-DATA(insert ( 1262 encoding			23 0  4   3 0 -1 -1 t p f i f f));
-DATA(insert ( 1262 datistemplate	16 0  1   4 0 -1 -1 t p f c f f));
-DATA(insert ( 1262 datallowconn		16 0  1   5 0 -1 -1 t p f c f f));
-DATA(insert ( 1262 datlastsysoid	26 0  4   6 0 -1 -1 t p f i f f));
-DATA(insert ( 1262 datvacuumxid		28 0  4   7 0 -1 -1 t p f i f f));
-DATA(insert ( 1262 datfrozenxid		28 0  4   8 0 -1 -1 t p f i f f));
+DATA(insert ( 1262 datname			19 0 NAMEDATALEN   1 0 -1 -1 f p f i t f f));
+DATA(insert ( 1262 datdba			23 0  4   2 0 -1 -1 t p f i t f f));
+DATA(insert ( 1262 encoding			23 0  4   3 0 -1 -1 t p f i t f f));
+DATA(insert ( 1262 datistemplate	16 0  1   4 0 -1 -1 t p f c t f f));
+DATA(insert ( 1262 datallowconn		16 0  1   5 0 -1 -1 t p f c t f f));
+DATA(insert ( 1262 datlastsysoid	26 0  4   6 0 -1 -1 t p f i t f f));
+DATA(insert ( 1262 datvacuumxid		28 0  4   7 0 -1 -1 t p f i t f f));
+DATA(insert ( 1262 datfrozenxid		28 0  4   8 0 -1 -1 t p f i t f f));
 /* do not mark datpath as toastable; GetRawDatabaseInfo won't cope */
-DATA(insert ( 1262 datpath			25 0 -1   9 0 -1 -1 f p f i f f));
-DATA(insert ( 1262 datconfig	  1009 0 -1  10 0 -1 -1 f x f i f f));
-DATA(insert ( 1262 datacl		  1034 0 -1  11 0 -1 -1 f x f i f f));
-DATA(insert ( 1262 ctid				27 0  6  -1 0 -1 -1 f p f i f f));
-DATA(insert ( 1262 oid				26 0  4  -2 0 -1 -1 t p f i f f));
-DATA(insert ( 1262 xmin				28 0  4  -3 0 -1 -1 t p f i f f));
-DATA(insert ( 1262 cmin				29 0  4  -4 0 -1 -1 t p f i f f));
-DATA(insert ( 1262 xmax				28 0  4  -5 0 -1 -1 t p f i f f));
-DATA(insert ( 1262 cmax				29 0  4  -6 0 -1 -1 t p f i f f));
-DATA(insert ( 1262 tableoid			26 0  4  -7 0 -1 -1 t p f i f f));
+DATA(insert ( 1262 datpath			25 0 -1   9 0 -1 -1 f p f i t f f));
+DATA(insert ( 1262 datconfig	  1009 0 -1  10 0 -1 -1 f x f i f f f));
+DATA(insert ( 1262 datacl		  1034 0 -1  11 0 -1 -1 f x f i f f f));
+DATA(insert ( 1262 ctid				27 0  6  -1 0 -1 -1 f p f i t f f));
+DATA(insert ( 1262 oid				26 0  4  -2 0 -1 -1 t p f i t f f));
+DATA(insert ( 1262 xmin				28 0  4  -3 0 -1 -1 t p f i t f f));
+DATA(insert ( 1262 cmin				29 0  4  -4 0 -1 -1 t p f i t f f));
+DATA(insert ( 1262 xmax				28 0  4  -5 0 -1 -1 t p f i t f f));
+DATA(insert ( 1262 cmax				29 0  4  -6 0 -1 -1 t p f i t f f));
+DATA(insert ( 1262 tableoid			26 0  4  -7 0 -1 -1 t p f i t f f));
 
 /* ----------------
  *		pg_proc
  * ----------------
  */
 #define Schema_pg_proc \
-{ 1255, {"proname"},			19, -1, NAMEDATALEN,  1, 0, -1, -1, false, 'p', false, 'i', false, false }, \
-{ 1255, {"pronamespace"},		26, 0,	4,	2, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1255, {"proowner"},			23, 0,	4,	3, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1255, {"prolang"},			26, 0,	4,	4, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1255, {"proisagg"},			16, 0,	1,	5, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1255, {"prosecdef"},			16, 0,	1,	6, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1255, {"proisstrict"},		16, 0,	1,	7, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1255, {"proretset"},			16, 0,	1,  8, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1255, {"provolatile"},		18, 0,	1,  9, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1255, {"pronargs"},			21, 0,	2, 10, 0, -1, -1, true, 'p', false, 's', false, false }, \
-{ 1255, {"prorettype"},			26, 0,	4, 11, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1255, {"proargtypes"},		30, 0, INDEX_MAX_KEYS*4, 12, 0, -1, -1, false, 'p', false, 'i', false, false }, \
-{ 1255, {"prosrc"},				25, 0, -1, 13, 0, -1, -1, false, 'x', false, 'i', false, false }, \
-{ 1255, {"probin"},				17, 0, -1, 14, 0, -1, -1, false, 'x', false, 'i', false, false }, \
-{ 1255, {"proacl"},			  1034, 0, -1, 15, 0, -1, -1, false, 'x', false, 'i', false, false }
-
-DATA(insert ( 1255 proname			19 -1 NAMEDATALEN   1 0 -1 -1 f p f i f f));
-DATA(insert ( 1255 pronamespace		26 0  4   2 0 -1 -1 t p f i f f));
-DATA(insert ( 1255 proowner			23 0  4   3 0 -1 -1 t p f i f f));
-DATA(insert ( 1255 prolang			26 0  4   4 0 -1 -1 t p f i f f));
-DATA(insert ( 1255 proisagg			16 0  1   5 0 -1 -1 t p f c f f));
-DATA(insert ( 1255 prosecdef		16 0  1   6 0 -1 -1 t p f c f f));
-DATA(insert ( 1255 proisstrict		16 0  1   7 0 -1 -1 t p f c f f));
-DATA(insert ( 1255 proretset		16 0  1   8 0 -1 -1 t p f c f f));
-DATA(insert ( 1255 provolatile		18 0  1   9 0 -1 -1 t p f c f f));
-DATA(insert ( 1255 pronargs			21 0  2  10 0 -1 -1 t p f s f f));
-DATA(insert ( 1255 prorettype		26 0  4  11 0 -1 -1 t p f i f f));
-DATA(insert ( 1255 proargtypes		30 0 INDEX_MAX_KEYS*4 12 0 -1 -1 f p f i f f));
-DATA(insert ( 1255 prosrc			25 0 -1  13 0 -1 -1 f x f i f f));
-DATA(insert ( 1255 probin			17 0 -1  14 0 -1 -1 f x f i f f));
-DATA(insert ( 1255 proacl		  1034 0 -1  15 0 -1 -1 f x f i f f));
-DATA(insert ( 1255 ctid				27 0  6  -1 0 -1 -1 f p f i f f));
-DATA(insert ( 1255 oid				26 0  4  -2 0 -1 -1 t p f i f f));
-DATA(insert ( 1255 xmin				28 0  4  -3 0 -1 -1 t p f i f f));
-DATA(insert ( 1255 cmin				29 0  4  -4 0 -1 -1 t p f i f f));
-DATA(insert ( 1255 xmax				28 0  4  -5 0 -1 -1 t p f i f f));
-DATA(insert ( 1255 cmax				29 0  4  -6 0 -1 -1 t p f i f f));
-DATA(insert ( 1255 tableoid			26 0  4  -7 0 -1 -1 t p f i f f));
+{ 1255, {"proname"},			19, -1, NAMEDATALEN,  1, 0, -1, -1, false, 'p', false, 'i', true, false, false }, \
+{ 1255, {"pronamespace"},		26, 0,	4,	2, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1255, {"proowner"},			23, 0,	4,	3, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1255, {"prolang"},			26, 0,	4,	4, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1255, {"proisagg"},			16, 0,	1,	5, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1255, {"prosecdef"},			16, 0,	1,	6, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1255, {"proisstrict"},		16, 0,	1,	7, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1255, {"proretset"},			16, 0,	1,  8, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1255, {"provolatile"},		18, 0,	1,  9, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1255, {"pronargs"},			21, 0,	2, 10, 0, -1, -1, true, 'p', false, 's', true, false, false }, \
+{ 1255, {"prorettype"},			26, 0,	4, 11, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1255, {"proargtypes"},		30, 0, INDEX_MAX_KEYS*4, 12, 0, -1, -1, false, 'p', false, 'i', true, false, false }, \
+{ 1255, {"prosrc"},				25, 0, -1, 13, 0, -1, -1, false, 'x', false, 'i', false, false, false }, \
+{ 1255, {"probin"},				17, 0, -1, 14, 0, -1, -1, false, 'x', false, 'i', false, false, false }, \
+{ 1255, {"proacl"},			  1034, 0, -1, 15, 0, -1, -1, false, 'x', false, 'i', false, false, false }
+
+DATA(insert ( 1255 proname			19 -1 NAMEDATALEN   1 0 -1 -1 f p f i t f f));
+DATA(insert ( 1255 pronamespace		26 0  4   2 0 -1 -1 t p f i t f f));
+DATA(insert ( 1255 proowner			23 0  4   3 0 -1 -1 t p f i t f f));
+DATA(insert ( 1255 prolang			26 0  4   4 0 -1 -1 t p f i t f f));
+DATA(insert ( 1255 proisagg			16 0  1   5 0 -1 -1 t p f c t f f));
+DATA(insert ( 1255 prosecdef		16 0  1   6 0 -1 -1 t p f c t f f));
+DATA(insert ( 1255 proisstrict		16 0  1   7 0 -1 -1 t p f c t f f));
+DATA(insert ( 1255 proretset		16 0  1   8 0 -1 -1 t p f c t f f));
+DATA(insert ( 1255 provolatile		18 0  1   9 0 -1 -1 t p f c t f f));
+DATA(insert ( 1255 pronargs			21 0  2  10 0 -1 -1 t p f s t f f));
+DATA(insert ( 1255 prorettype		26 0  4  11 0 -1 -1 t p f i t f f));
+DATA(insert ( 1255 proargtypes		30 0 INDEX_MAX_KEYS*4 12 0 -1 -1 f p f i t f f));
+DATA(insert ( 1255 prosrc			25 0 -1  13 0 -1 -1 f x f i f f f));
+DATA(insert ( 1255 probin			17 0 -1  14 0 -1 -1 f x f i f f f));
+DATA(insert ( 1255 proacl		  1034 0 -1  15 0 -1 -1 f x f i f f f));
+DATA(insert ( 1255 ctid				27 0  6  -1 0 -1 -1 f p f i t f f));
+DATA(insert ( 1255 oid				26 0  4  -2 0 -1 -1 t p f i t f f));
+DATA(insert ( 1255 xmin				28 0  4  -3 0 -1 -1 t p f i t f f));
+DATA(insert ( 1255 cmin				29 0  4  -4 0 -1 -1 t p f i t f f));
+DATA(insert ( 1255 xmax				28 0  4  -5 0 -1 -1 t p f i t f f));
+DATA(insert ( 1255 cmax				29 0  4  -6 0 -1 -1 t p f i t f f));
+DATA(insert ( 1255 tableoid			26 0  4  -7 0 -1 -1 t p f i t f f));
 
 /* ----------------
  *		pg_shadow
  * ----------------
  */
-DATA(insert ( 1260 usename			19	-1 NAMEDATALEN	1 0 -1 -1 f p f i f f));
-DATA(insert ( 1260 usesysid			23	-1	4	2 0 -1 -1 t p f i f f));
-DATA(insert ( 1260 usecreatedb		16	0	1	3 0 -1 -1 t p f c f f));
-DATA(insert ( 1260 usesuper			16	0	1	4 0 -1 -1 t p f c f f));
-DATA(insert ( 1260 usecatupd		16	0	1	5 0 -1 -1 t p f c f f));
-DATA(insert ( 1260 passwd			25	0  -1	6 0 -1 -1 f x f i f f));
-DATA(insert ( 1260 valuntil			702 0	4	7 0 -1 -1 t p f i f f));
-DATA(insert ( 1260 useconfig	  1009  0  -1   8 0 -1 -1 f x f i f f));
-DATA(insert ( 1260 ctid				27 0  6  -1 0 -1 -1 f p f i f f));
+DATA(insert ( 1260 usename			19	-1 NAMEDATALEN	1 0 -1 -1 f p f i t f f));
+DATA(insert ( 1260 usesysid			23	-1	4	2 0 -1 -1 t p f i t f f));
+DATA(insert ( 1260 usecreatedb		16	0	1	3 0 -1 -1 t p f c t f f));
+DATA(insert ( 1260 usesuper			16	0	1	4 0 -1 -1 t p f c t f f));
+DATA(insert ( 1260 usecatupd		16	0	1	5 0 -1 -1 t p f c t f f));
+DATA(insert ( 1260 passwd			25	0  -1	6 0 -1 -1 f x f i f f f));
+DATA(insert ( 1260 valuntil			702 0	4	7 0 -1 -1 t p f i f f f));
+DATA(insert ( 1260 useconfig	  1009  0  -1   8 0 -1 -1 f x f i f f f));
+DATA(insert ( 1260 ctid				27 0  6  -1 0 -1 -1 f p f i t f f));
 /* no OIDs in pg_shadow */
-DATA(insert ( 1260 xmin				28 0  4  -3 0 -1 -1 t p f i f f));
-DATA(insert ( 1260 cmin				29 0  4  -4 0 -1 -1 t p f i f f));
-DATA(insert ( 1260 xmax				28 0  4  -5 0 -1 -1 t p f i f f));
-DATA(insert ( 1260 cmax				29 0  4  -6 0 -1 -1 t p f i f f));
-DATA(insert ( 1260 tableoid			26 0  4  -7 0 -1 -1 t p f i f f));
+DATA(insert ( 1260 xmin				28 0  4  -3 0 -1 -1 t p f i t f f));
+DATA(insert ( 1260 cmin				29 0  4  -4 0 -1 -1 t p f i t f f));
+DATA(insert ( 1260 xmax				28 0  4  -5 0 -1 -1 t p f i t f f));
+DATA(insert ( 1260 cmax				29 0  4  -6 0 -1 -1 t p f i t f f));
+DATA(insert ( 1260 tableoid			26 0  4  -7 0 -1 -1 t p f i t f f));
 
 /* ----------------
  *		pg_group
  * ----------------
  */
-DATA(insert ( 1261 groname			19 -1 NAMEDATALEN  1 0 -1 -1 f p f i f f));
-DATA(insert ( 1261 grosysid			23 -1  4   2 0 -1 -1 t p f i f f));
-DATA(insert ( 1261 grolist		  1007 0 -1   3 0 -1 -1 f x f i f f));
-DATA(insert ( 1261 ctid				27 0  6  -1 0 -1 -1 f p f i f f));
+DATA(insert ( 1261 groname			19 -1 NAMEDATALEN  1 0 -1 -1 f p f i t f f));
+DATA(insert ( 1261 grosysid			23 -1  4   2 0 -1 -1 t p f i t f f));
+DATA(insert ( 1261 grolist		  1007 0 -1   3 0 -1 -1 f x f i f f f));
+DATA(insert ( 1261 ctid				27 0  6  -1 0 -1 -1 f p f i t f f));
 /* no OIDs in pg_group */
-DATA(insert ( 1261 xmin				28 0  4  -3 0 -1 -1 t p f i f f));
-DATA(insert ( 1261 cmin				29 0  4  -4 0 -1 -1 t p f i f f));
-DATA(insert ( 1261 xmax				28 0  4  -5 0 -1 -1 t p f i f f));
-DATA(insert ( 1261 cmax				29 0  4  -6 0 -1 -1 t p f i f f));
-DATA(insert ( 1261 tableoid			26 0  4  -7 0 -1 -1 t p f i f f));
+DATA(insert ( 1261 xmin				28 0  4  -3 0 -1 -1 t p f i t f f));
+DATA(insert ( 1261 cmin				29 0  4  -4 0 -1 -1 t p f i t f f));
+DATA(insert ( 1261 xmax				28 0  4  -5 0 -1 -1 t p f i t f f));
+DATA(insert ( 1261 cmax				29 0  4  -6 0 -1 -1 t p f i t f f));
+DATA(insert ( 1261 tableoid			26 0  4  -7 0 -1 -1 t p f i t f f));
 
 /* ----------------
  *		pg_attribute
  * ----------------
  */
 #define Schema_pg_attribute \
-{ 1249, {"attrelid"},	  26, -1,	4,	1, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1249, {"attname"},	  19, -1, NAMEDATALEN,	2, 0, -1, -1, false, 'p', false, 'i', false, false }, \
-{ 1249, {"atttypid"},	  26, 0,	4,	3, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1249, {"attstattarget"}, 23, 0,	4,	4, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1249, {"attlen"},		  21, 0,	2,	5, 0, -1, -1, true, 'p', false, 's', false, false }, \
-{ 1249, {"attnum"},		  21, 0,	2,	6, 0, -1, -1, true, 'p', false, 's', false, false }, \
-{ 1249, {"attndims"},	  23, 0,	4,	7, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1249, {"attcacheoff"},  23, 0,	4,	8, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1249, {"atttypmod"},	  23, 0,	4,	9, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1249, {"attbyval"},	  16, 0,	1, 10, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1249, {"attstorage"},   18, 0,	1, 11, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1249, {"attisset"},	  16, 0,	1, 12, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1249, {"attalign"},	  18, 0,	1, 13, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1249, {"attnotnull"},  16, 0, 1, 14, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1249, {"atthasdef"},	 16, 0, 1, 15, 0, -1, -1, true, 'p', false, 'c', false, false }
-
-DATA(insert ( 1249 attrelid			26 -1  4   1 0 -1 -1 t p f i f f));
-DATA(insert ( 1249 attname			19 -1 NAMEDATALEN  2 0 -1 -1 f p f i f f));
-DATA(insert ( 1249 atttypid			26 0  4   3 0 -1 -1 t p f i f f));
-DATA(insert ( 1249 attstattarget	23 0  4   4 0 -1 -1 t p f i f f));
-DATA(insert ( 1249 attlen			21 0  2   5 0 -1 -1 t p f s f f));
-DATA(insert ( 1249 attnum			21 0  2   6 0 -1 -1 t p f s f f));
-DATA(insert ( 1249 attndims			23 0  4   7 0 -1 -1 t p f i f f));
-DATA(insert ( 1249 attcacheoff		23 0  4   8 0 -1 -1 t p f i f f));
-DATA(insert ( 1249 atttypmod		23 0  4   9 0 -1 -1 t p f i f f));
-DATA(insert ( 1249 attbyval			16 0  1  10 0 -1 -1 t p f c f f));
-DATA(insert ( 1249 attstorage		18 0  1  11 0 -1 -1 t p f c f f));
-DATA(insert ( 1249 attisset			16 0  1  12 0 -1 -1 t p f c f f));
-DATA(insert ( 1249 attalign			18 0  1  13 0 -1 -1 t p f c f f));
-DATA(insert ( 1249 attnotnull		16 0  1  14 0 -1 -1 t p f c f f));
-DATA(insert ( 1249 atthasdef		16 0  1  15 0 -1 -1 t p f c f f));
-DATA(insert ( 1249 ctid				27 0  6  -1 0 -1 -1 f p f i f f));
+{ 1249, {"attrelid"},	  26, -1,	4,	1, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1249, {"attname"},	  19, -1, NAMEDATALEN,	2, 0, -1, -1, false, 'p', false, 'i', true, false, false }, \
+{ 1249, {"atttypid"},	  26, 0,	4,	3, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1249, {"attstattarget"}, 23, 0,	4,	4, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1249, {"attlen"},		  21, 0,	2,	5, 0, -1, -1, true, 'p', false, 's', true, false, false }, \
+{ 1249, {"attnum"},		  21, 0,	2,	6, 0, -1, -1, true, 'p', false, 's', true, false, false }, \
+{ 1249, {"attndims"},	  23, 0,	4,	7, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1249, {"attcacheoff"},  23, 0,	4,	8, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1249, {"atttypmod"},	  23, 0,	4,	9, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1249, {"attbyval"},	  16, 0,	1, 10, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1249, {"attstorage"},   18, 0,	1, 11, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1249, {"attisset"},	  16, 0,	1, 12, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1249, {"attalign"},	  18, 0,	1, 13, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1249, {"attnotnull"},	  16, 0, 1, 14, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1249, {"atthasdef"},	  16, 0, 1, 15, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1249, {"attisdropped"}, 16, 0, 1, 16, 0, -1, -1, true, 'p', false, 'c', true, false, false }
+
+DATA(insert ( 1249 attrelid			26 -1  4   1 0 -1 -1 t p f i t f f));
+DATA(insert ( 1249 attname			19 -1 NAMEDATALEN  2 0 -1 -1 f p f i t f f));
+DATA(insert ( 1249 atttypid			26 0  4   3 0 -1 -1 t p f i t f f));
+DATA(insert ( 1249 attstattarget	23 0  4   4 0 -1 -1 t p f i t f f));
+DATA(insert ( 1249 attlen			21 0  2   5 0 -1 -1 t p f s t f f));
+DATA(insert ( 1249 attnum			21 0  2   6 0 -1 -1 t p f s t f f));
+DATA(insert ( 1249 attndims			23 0  4   7 0 -1 -1 t p f i t f f));
+DATA(insert ( 1249 attcacheoff		23 0  4   8 0 -1 -1 t p f i t f f));
+DATA(insert ( 1249 atttypmod		23 0  4   9 0 -1 -1 t p f i t f f));
+DATA(insert ( 1249 attbyval			16 0  1  10 0 -1 -1 t p f c t f f));
+DATA(insert ( 1249 attstorage		18 0  1  11 0 -1 -1 t p f c t f f));
+DATA(insert ( 1249 attisset			16 0  1  12 0 -1 -1 t p f c t f f));
+DATA(insert ( 1249 attalign			18 0  1  13 0 -1 -1 t p f c t f f));
+DATA(insert ( 1249 attnotnull		16 0  1  14 0 -1 -1 t p f c t f f));
+DATA(insert ( 1249 atthasdef		16 0  1  15 0 -1 -1 t p f c t f f));
+DATA(insert ( 1249 attisdropped		16 0  1  16 0 -1 -1 t p f c t f f));
+DATA(insert ( 1249 ctid				27 0  6  -1 0 -1 -1 f p f i t f f));
 /* no OIDs in pg_attribute */
-DATA(insert ( 1249 xmin				28 0  4  -3 0 -1 -1 t p f i f f));
-DATA(insert ( 1249 cmin				29 0  4  -4 0 -1 -1 t p f i f f));
-DATA(insert ( 1249 xmax				28 0  4  -5 0 -1 -1 t p f i f f));
-DATA(insert ( 1249 cmax				29 0  4  -6 0 -1 -1 t p f i f f));
-DATA(insert ( 1249 tableoid			26 0  4  -7 0 -1 -1 t p f i f f));
+DATA(insert ( 1249 xmin				28 0  4  -3 0 -1 -1 t p f i t f f));
+DATA(insert ( 1249 cmin				29 0  4  -4 0 -1 -1 t p f i t f f));
+DATA(insert ( 1249 xmax				28 0  4  -5 0 -1 -1 t p f i t f f));
+DATA(insert ( 1249 cmax				29 0  4  -6 0 -1 -1 t p f i t f f));
+DATA(insert ( 1249 tableoid			26 0  4  -7 0 -1 -1 t p f i t f f));
 
 /* ----------------
  *		pg_class
  * ----------------
  */
 #define Schema_pg_class \
-{ 1259, {"relname"},	   19, -1, NAMEDATALEN,	1, 0, -1, -1, false, 'p', false, 'i', false, false }, \
-{ 1259, {"relnamespace"},  26, 0,	4,	2, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1259, {"reltype"},	   26, 0,	4,	3, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1259, {"relowner"},	   23, 0,	4,	4, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1259, {"relam"},		   26, 0,	4,	5, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1259, {"relfilenode"},   26, 0,	4,	6, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1259, {"relpages"},	   23, 0,	4,	7, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1259, {"reltuples"},	   700, 0,	4,	8, 0, -1, -1, false, 'p', false, 'i', false, false }, \
-{ 1259, {"reltoastrelid"}, 26, 0,	4,	9, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1259, {"reltoastidxid"}, 26, 0,	4, 10, 0, -1, -1, true, 'p', false, 'i', false, false }, \
-{ 1259, {"relhasindex"},   16, 0,	1, 11, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1259, {"relisshared"},   16, 0,	1, 12, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1259, {"relkind"},	   18, 0,	1, 13, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1259, {"relnatts"},	   21, 0,	2, 14, 0, -1, -1, true, 'p', false, 's', false, false }, \
-{ 1259, {"relchecks"},	   21, 0,	2, 15, 0, -1, -1, true, 'p', false, 's', false, false }, \
-{ 1259, {"reltriggers"},   21, 0,	2, 16, 0, -1, -1, true, 'p', false, 's', false, false }, \
-{ 1259, {"relukeys"},	   21, 0,	2, 17, 0, -1, -1, true, 'p', false, 's', false, false }, \
-{ 1259, {"relfkeys"},	   21, 0,	2, 18, 0, -1, -1, true, 'p', false, 's', false, false }, \
-{ 1259, {"relrefs"},	   21, 0,	2, 19, 0, -1, -1, true, 'p', false, 's', false, false }, \
-{ 1259, {"relhasoids"},    16, 0,	1, 20, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1259, {"relhaspkey"},    16, 0,	1, 21, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1259, {"relhasrules"},   16, 0,	1, 22, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1259, {"relhassubclass"},16, 0,	1, 23, 0, -1, -1, true, 'p', false, 'c', false, false }, \
-{ 1259, {"relacl"},		 1034, 0,  -1, 24, 0, -1, -1, false, 'x', false, 'i', false, false }
-
-DATA(insert ( 1259 relname			19 -1 NAMEDATALEN   1 0 -1 -1 f p f i f f));
-DATA(insert ( 1259 relnamespace		26 0  4   2 0 -1 -1 t p f i f f));
-DATA(insert ( 1259 reltype			26 0  4   3 0 -1 -1 t p f i f f));
-DATA(insert ( 1259 relowner			23 0  4   4 0 -1 -1 t p f i f f));
-DATA(insert ( 1259 relam			26 0  4   5 0 -1 -1 t p f i f f));
-DATA(insert ( 1259 relfilenode		26 0  4   6 0 -1 -1 t p f i f f));
-DATA(insert ( 1259 relpages			23 0  4   7 0 -1 -1 t p f i f f));
-DATA(insert ( 1259 reltuples	   700 0  4   8 0 -1 -1 f p f i f f));
-DATA(insert ( 1259 reltoastrelid	26 0  4   9 0 -1 -1 t p f i f f));
-DATA(insert ( 1259 reltoastidxid	26 0  4  10 0 -1 -1 t p f i f f));
-DATA(insert ( 1259 relhasindex		16 0  1  11 0 -1 -1 t p f c f f));
-DATA(insert ( 1259 relisshared		16 0  1  12 0 -1 -1 t p f c f f));
-DATA(insert ( 1259 relkind			18 0  1  13 0 -1 -1 t p f c f f));
-DATA(insert ( 1259 relnatts			21 0  2  14 0 -1 -1 t p f s f f));
-DATA(insert ( 1259 relchecks		21 0  2  15 0 -1 -1 t p f s f f));
-DATA(insert ( 1259 reltriggers		21 0  2  16 0 -1 -1 t p f s f f));
-DATA(insert ( 1259 relukeys			21 0  2  17 0 -1 -1 t p f s f f));
-DATA(insert ( 1259 relfkeys			21 0  2  18 0 -1 -1 t p f s f f));
-DATA(insert ( 1259 relrefs			21 0  2  19 0 -1 -1 t p f s f f));
-DATA(insert ( 1259 relhasoids		16 0  1  20 0 -1 -1 t p f c f f));
-DATA(insert ( 1259 relhaspkey		16 0  1  21 0 -1 -1 t p f c f f));
-DATA(insert ( 1259 relhasrules		16 0  1  22 0 -1 -1 t p f c f f));
-DATA(insert ( 1259 relhassubclass	16 0  1  23 0 -1 -1 t p f c f f));
-DATA(insert ( 1259 relacl		  1034 0 -1  24 0 -1 -1 f x f i f f));
-DATA(insert ( 1259 ctid				27 0  6  -1 0 -1 -1 f p f i f f));
-DATA(insert ( 1259 oid				26 0  4  -2 0 -1 -1 t p f i f f));
-DATA(insert ( 1259 xmin				28 0  4  -3 0 -1 -1 t p f i f f));
-DATA(insert ( 1259 cmin				29 0  4  -4 0 -1 -1 t p f i f f));
-DATA(insert ( 1259 xmax				28 0  4  -5 0 -1 -1 t p f i f f));
-DATA(insert ( 1259 cmax				29 0  4  -6 0 -1 -1 t p f i f f));
-DATA(insert ( 1259 tableoid			26 0  4  -7 0 -1 -1 t p f i f f));
+{ 1259, {"relname"},	   19, -1, NAMEDATALEN,	1, 0, -1, -1, false, 'p', false, 'i', true, false, false }, \
+{ 1259, {"relnamespace"},  26, 0,	4,	2, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1259, {"reltype"},	   26, 0,	4,	3, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1259, {"relowner"},	   23, 0,	4,	4, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1259, {"relam"},		   26, 0,	4,	5, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1259, {"relfilenode"},   26, 0,	4,	6, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1259, {"relpages"},	   23, 0,	4,	7, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1259, {"reltuples"},	   700, 0,	4,	8, 0, -1, -1, false, 'p', false, 'i', true, false, false }, \
+{ 1259, {"reltoastrelid"}, 26, 0,	4,	9, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1259, {"reltoastidxid"}, 26, 0,	4, 10, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \
+{ 1259, {"relhasindex"},   16, 0,	1, 11, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1259, {"relisshared"},   16, 0,	1, 12, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1259, {"relkind"},	   18, 0,	1, 13, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1259, {"relnatts"},	   21, 0,	2, 14, 0, -1, -1, true, 'p', false, 's', true, false, false }, \
+{ 1259, {"relchecks"},	   21, 0,	2, 15, 0, -1, -1, true, 'p', false, 's', true, false, false }, \
+{ 1259, {"reltriggers"},   21, 0,	2, 16, 0, -1, -1, true, 'p', false, 's', true, false, false }, \
+{ 1259, {"relukeys"},	   21, 0,	2, 17, 0, -1, -1, true, 'p', false, 's', true, false, false }, \
+{ 1259, {"relfkeys"},	   21, 0,	2, 18, 0, -1, -1, true, 'p', false, 's', true, false, false }, \
+{ 1259, {"relrefs"},	   21, 0,	2, 19, 0, -1, -1, true, 'p', false, 's', true, false, false }, \
+{ 1259, {"relhasoids"},    16, 0,	1, 20, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1259, {"relhaspkey"},    16, 0,	1, 21, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1259, {"relhasrules"},   16, 0,	1, 22, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1259, {"relhassubclass"},16, 0,	1, 23, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \
+{ 1259, {"relacl"},		 1034, 0,  -1, 24, 0, -1, -1, false, 'x', false, 'i', false, false, false }
+
+DATA(insert ( 1259 relname			19 -1 NAMEDATALEN   1 0 -1 -1 f p f i t f f));
+DATA(insert ( 1259 relnamespace		26 0  4   2 0 -1 -1 t p f i t f f));
+DATA(insert ( 1259 reltype			26 0  4   3 0 -1 -1 t p f i t f f));
+DATA(insert ( 1259 relowner			23 0  4   4 0 -1 -1 t p f i t f f));
+DATA(insert ( 1259 relam			26 0  4   5 0 -1 -1 t p f i t f f));
+DATA(insert ( 1259 relfilenode		26 0  4   6 0 -1 -1 t p f i t f f));
+DATA(insert ( 1259 relpages			23 0  4   7 0 -1 -1 t p f i t f f));
+DATA(insert ( 1259 reltuples	   700 0  4   8 0 -1 -1 f p f i t f f));
+DATA(insert ( 1259 reltoastrelid	26 0  4   9 0 -1 -1 t p f i t f f));
+DATA(insert ( 1259 reltoastidxid	26 0  4  10 0 -1 -1 t p f i t f f));
+DATA(insert ( 1259 relhasindex		16 0  1  11 0 -1 -1 t p f c t f f));
+DATA(insert ( 1259 relisshared		16 0  1  12 0 -1 -1 t p f c t f f));
+DATA(insert ( 1259 relkind			18 0  1  13 0 -1 -1 t p f c t f f));
+DATA(insert ( 1259 relnatts			21 0  2  14 0 -1 -1 t p f s t f f));
+DATA(insert ( 1259 relchecks		21 0  2  15 0 -1 -1 t p f s t f f));
+DATA(insert ( 1259 reltriggers		21 0  2  16 0 -1 -1 t p f s t f f));
+DATA(insert ( 1259 relukeys			21 0  2  17 0 -1 -1 t p f s t f f));
+DATA(insert ( 1259 relfkeys			21 0  2  18 0 -1 -1 t p f s t f f));
+DATA(insert ( 1259 relrefs			21 0  2  19 0 -1 -1 t p f s t f f));
+DATA(insert ( 1259 relhasoids		16 0  1  20 0 -1 -1 t p f c t f f));
+DATA(insert ( 1259 relhaspkey		16 0  1  21 0 -1 -1 t p f c t f f));
+DATA(insert ( 1259 relhasrules		16 0  1  22 0 -1 -1 t p f c t f f));
+DATA(insert ( 1259 relhassubclass	16 0  1  23 0 -1 -1 t p f c t f f));
+DATA(insert ( 1259 relacl		  1034 0 -1  24 0 -1 -1 f x f i f f f));
+DATA(insert ( 1259 ctid				27 0  6  -1 0 -1 -1 f p f i t f f));
+DATA(insert ( 1259 oid				26 0  4  -2 0 -1 -1 t p f i t f f));
+DATA(insert ( 1259 xmin				28 0  4  -3 0 -1 -1 t p f i t f f));
+DATA(insert ( 1259 cmin				29 0  4  -4 0 -1 -1 t p f i t f f));
+DATA(insert ( 1259 xmax				28 0  4  -5 0 -1 -1 t p f i t f f));
+DATA(insert ( 1259 cmax				29 0  4  -6 0 -1 -1 t p f i t f f));
+DATA(insert ( 1259 tableoid			26 0  4  -7 0 -1 -1 t p f i t f f));
 
 /* ----------------
  *		pg_xactlock - this is not a real relation, but is a placeholder
@@ -478,6 +484,6 @@ DATA(insert ( 1259 tableoid			26 0  4  -7 0 -1 -1 t p f i f f));
  *				  table; and this entry is just to link to that one.
  * ----------------
  */
-DATA(insert ( 376 xactlockfoo		26 0  4   1 0 -1 -1 t p f i f f));
+DATA(insert ( 376 xactlockfoo		26 0  4   1 0 -1 -1 t p f i t f f));
 
 #endif   /* PG_ATTRIBUTE_H */
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index 827769029f3226748b847aaa928503dd0aacf743..2d5011e6d62c4adf2ebb37457082e3b47facafe8 100644
--- a/src/include/catalog/pg_class.h
+++ b/src/include/catalog/pg_class.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_class.h,v 1.69 2002/07/24 19:11:12 petere Exp $
+ * $Id: pg_class.h,v 1.70 2002/08/02 18:15:09 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -136,7 +136,7 @@ typedef FormData_pg_class *Form_pg_class;
 
 DATA(insert OID = 1247 (  pg_type		PGNSP 71 PGUID 0 1247 0 0 0 0 f f r 20 0 0 0 0 0 t f f f _null_ ));
 DESCR("");
-DATA(insert OID = 1249 (  pg_attribute	PGNSP 75 PGUID 0 1249 0 0 0 0 f f r 15 0 0 0 0 0 f f f f _null_ ));
+DATA(insert OID = 1249 (  pg_attribute	PGNSP 75 PGUID 0 1249 0 0 0 0 f f r 16 0 0 0 0 0 f f f f _null_ ));
 DESCR("");
 DATA(insert OID = 1255 (  pg_proc		PGNSP 81 PGUID 0 1255 0 0 0 0 f f r 15 0 0 0 0 0 t f f f _null_ ));
 DESCR("");
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 9eb7367f2e362b01708324c910f05511a24ff175..2fdb5bc210ca503dae8483334093003efdb4793b 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.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: executor.h,v 1.72 2002/07/20 15:12:55 tgl Exp $
+ * $Id: executor.h,v 1.73 2002/08/02 18:15:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -159,7 +159,6 @@ extern void ExecAssignScanType(CommonScanState *csstate,
 				   TupleDesc tupDesc, bool shouldFree);
 extern void ExecAssignScanTypeFromOuterPlan(Plan *node,
 								CommonScanState *csstate);
-extern Form_pg_attribute ExecGetTypeInfo(Relation relDesc);
 
 extern ExprContext *MakeExprContext(TupleTableSlot *slot,
 				MemoryContext queryContext);
diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h
index 5ff6d74e364a259e4cc4a6ca3aa183be163fadae..a34e2a5619f086cd642fd93a402093cf944319df 100644
--- a/src/include/parser/parse_relation.h
+++ b/src/include/parser/parse_relation.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: parse_relation.h,v 1.34 2002/06/20 20:29:51 momjian Exp $
+ * $Id: parse_relation.h,v 1.35 2002/08/02 18:15:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -58,7 +58,7 @@ extern RangeTblEntry *addImplicitRTE(ParseState *pstate, RangeVar *relation);
 extern void expandRTE(ParseState *pstate, RangeTblEntry *rte,
 		  List **colnames, List **colvars);
 extern List *expandRelAttrs(ParseState *pstate, RangeTblEntry *rte);
-extern int	attnameAttNum(Relation rd, char *a);
+extern int	attnameAttNum(Relation rd, const char *attname, bool sysColOK);
 extern Name attnumAttName(Relation rd, int attid);
 extern Oid	attnumTypeId(Relation rd, int attid);
 
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index dcc310aab5edcee9f9134164aad0cf0af5bb55ce..ab06031b2c6c7a0176f43a557353e635d61251f8 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.55 2002/07/12 18:43:19 tgl Exp $
+ * $Id: lsyscache.h,v 1.56 2002/08/02 18:15:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,9 +18,8 @@
 extern bool op_in_opclass(Oid opno, Oid opclass);
 extern bool op_requires_recheck(Oid opno, Oid opclass);
 extern char *get_attname(Oid relid, AttrNumber attnum);
-extern AttrNumber get_attnum(Oid relid, char *attname);
+extern AttrNumber get_attnum(Oid relid, const char *attname);
 extern Oid	get_atttype(Oid relid, AttrNumber attnum);
-extern bool get_attisset(Oid relid, char *attname);
 extern int32 get_atttypmod(Oid relid, AttrNumber attnum);
 extern void get_atttypetypmod(Oid relid, AttrNumber attnum,
 				  Oid *typid, int32 *typmod);
diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h
index e8c70fa00be193c941c5a70ae621cdb85279b4b2..b9a17c7453eabe9e3010f99b8c2383b6a15fc168 100644
--- a/src/include/utils/syscache.h
+++ b/src/include/utils/syscache.h
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: syscache.h,v 1.51 2002/07/25 10:07:13 ishii Exp $
+ * $Id: syscache.h,v 1.52 2002/08/02 18:15:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -78,6 +78,10 @@ extern bool SearchSysCacheExists(int cacheId,
 extern Oid GetSysCacheOid(int cacheId,
 			   Datum key1, Datum key2, Datum key3, Datum key4);
 
+extern HeapTuple SearchSysCacheAttName(Oid relid, const char *attname);
+extern HeapTuple SearchSysCacheCopyAttName(Oid relid, const char *attname);
+extern bool SearchSysCacheExistsAttName(Oid relid, const char *attname);
+
 extern Datum SysCacheGetAttr(int cacheId, HeapTuple tup,
 				AttrNumber attributeNumber, bool *isNull);
 
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 8f6ff87cf6caca506175b74a58288303c0a333d3..bc95eba1ed193b84412578e00b4a1e2e7b67fa7e 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -3,7 +3,7 @@
  *			  procedural language
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.42 2002/06/15 19:54:24 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.43 2002/08/02 18:15:09 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -1037,10 +1037,7 @@ plpgsql_parse_dblwordtype(char *string)
 	/*
 	 * Fetch the named table field and it's type
 	 */
-	attrtup = SearchSysCache(ATTNAME,
-							 ObjectIdGetDatum(classOid),
-							 PointerGetDatum(word2),
-							 0, 0);
+	attrtup = SearchSysCacheAttName(classOid, word2);
 	if (!HeapTupleIsValid(attrtup))
 	{
 		ReleaseSysCache(classtup);
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 2dc64f3ccfa58d29a85e5bbd05ed97c788a53985..741b012c2896d196d198100f21f14a5f37150dd7 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -635,9 +635,9 @@ delete from atacc1;
 alter table atacc1 alter test set not null;
 -- try altering a non-existent column, should fail
 alter table atacc1 alter bar set not null;
-ERROR:  ALTER TABLE: relation "atacc1" has no column "bar"
+ERROR:  Relation "atacc1" has no column "bar"
 alter table atacc1 alter bar drop not null;
-ERROR:  ALTER TABLE: relation "atacc1" has no column "bar"
+ERROR:  Relation "atacc1" has no column "bar"
 -- try altering the oid column, should fail
 alter table atacc1 alter oid set not null;
 ERROR:  ALTER TABLE: Cannot alter system attribute "oid"
@@ -707,7 +707,7 @@ ERROR:  pg_atoi: error in "wrong_datatype": can't parse "wrong_datatype"
 alter table def_test alter column c2 set default 20;
 -- set defaults on a non-existent column: this should fail
 alter table def_test alter column c3 set default 30;
-ERROR:  ALTER TABLE: relation "def_test" has no column "c3"
+ERROR:  Relation "def_test" has no column "c3"
 -- set defaults on views: we need to create a view, add a rule
 -- to allow insertions into it, and then alter the view to add
 -- a default
@@ -735,3 +735,291 @@ select * from def_view_test;
 drop rule def_view_test_ins on def_view_test;
 drop view def_view_test;
 drop table def_test;
+-- alter table / drop column tests
+-- try altering system catalogs, should fail
+alter table pg_class drop column relname;
+ERROR:  ALTER TABLE: relation "pg_class" is a system catalog
+-- try altering non-existent table, should fail
+alter table foo drop column bar;
+ERROR:  Relation "foo" does not exist
+-- test dropping columns
+create table atacc1 (a int4 not null, b int4, c int4 not null, d int4);
+insert into atacc1 values (1, 2, 3, 4);
+alter table atacc1 drop a;
+alter table atacc1 drop a;
+ERROR:  Relation "atacc1" has no column "a"
+-- SELECTs
+select * from atacc1;
+ b | c | d 
+---+---+---
+ 2 | 3 | 4
+(1 row)
+
+select * from atacc1 order by a;
+ERROR:  Attribute "a" not found
+select * from atacc1 order by "........pg.dropped.1........";
+ERROR:  Attribute "........pg.dropped.1........" not found
+select * from atacc1 group by a;
+ERROR:  Attribute "a" not found
+select * from atacc1 group by "........pg.dropped.1........";
+ERROR:  Attribute "........pg.dropped.1........" not found
+select atacc1.* from atacc1;
+ b | c | d 
+---+---+---
+ 2 | 3 | 4
+(1 row)
+
+select a from atacc1;
+ERROR:  Attribute "a" not found
+select atacc1.a from atacc1;
+ERROR:  No such attribute atacc1.a
+select b,c,d from atacc1;
+ b | c | d 
+---+---+---
+ 2 | 3 | 4
+(1 row)
+
+select a,b,c,d from atacc1;
+ERROR:  Attribute "a" not found
+select * from atacc1 where a = 1;
+ERROR:  Attribute "a" not found
+select "........pg.dropped.1........" from atacc1;
+ERROR:  Attribute "........pg.dropped.1........" not found
+select atacc1."........pg.dropped.1........" from atacc1;
+ERROR:  No such attribute atacc1.........pg.dropped.1........
+select "........pg.dropped.1........",b,c,d from atacc1;
+ERROR:  Attribute "........pg.dropped.1........" not found
+select * from atacc1 where "........pg.dropped.1........" = 1;
+ERROR:  Attribute "........pg.dropped.1........" not found
+-- UPDATEs
+update atacc1 set a = 3;
+ERROR:  Relation "atacc1" has no column "a"
+update atacc1 set b = 2 where a = 3;
+ERROR:  Attribute "a" not found
+update atacc1 set "........pg.dropped.1........" = 3;
+ERROR:  Relation "atacc1" has no column "........pg.dropped.1........"
+update atacc1 set b = 2 where "........pg.dropped.1........" = 3;
+ERROR:  Attribute "........pg.dropped.1........" not found
+-- INSERTs
+insert into atacc1 values (10, 11, 12, 13);
+ERROR:  INSERT has more expressions than target columns
+insert into atacc1 values (default, 11, 12, 13);
+ERROR:  INSERT has more expressions than target columns
+insert into atacc1 values (11, 12, 13);
+insert into atacc1 (a) values (10);
+ERROR:  Relation "atacc1" has no column "a"
+insert into atacc1 (a) values (default);
+ERROR:  Relation "atacc1" has no column "a"
+insert into atacc1 (a,b,c,d) values (10,11,12,13);
+ERROR:  Relation "atacc1" has no column "a"
+insert into atacc1 (a,b,c,d) values (default,11,12,13);
+ERROR:  Relation "atacc1" has no column "a"
+insert into atacc1 (b,c,d) values (11,12,13);
+insert into atacc1 ("........pg.dropped.1........") values (10);
+ERROR:  Relation "atacc1" has no column "........pg.dropped.1........"
+insert into atacc1 ("........pg.dropped.1........") values (default);
+ERROR:  Relation "atacc1" has no column "........pg.dropped.1........"
+insert into atacc1 ("........pg.dropped.1........",b,c,d) values (10,11,12,13);
+ERROR:  Relation "atacc1" has no column "........pg.dropped.1........"
+insert into atacc1 ("........pg.dropped.1........",b,c,d) values (default,11,12,13);
+ERROR:  Relation "atacc1" has no column "........pg.dropped.1........"
+-- DELETEs
+delete from atacc1 where a = 3;
+ERROR:  Attribute "a" not found
+delete from atacc1 where "........pg.dropped.1........" = 3;
+ERROR:  Attribute "........pg.dropped.1........" not found
+delete from atacc1;
+-- try dropping a non-existent column, should fail
+alter table atacc1 drop bar;
+ERROR:  Relation "atacc1" has no column "bar"
+-- try dropping the oid column, should fail
+alter table atacc1 drop oid;
+ERROR:  ALTER TABLE: Cannot drop system attribute "oid"
+-- try creating a view and altering that, should fail
+create view myview as select * from atacc1;
+select * from myview;
+ b | c | d 
+---+---+---
+(0 rows)
+
+alter table myview drop d;
+ERROR:  ALTER TABLE: relation "myview" is not a table
+drop view myview;
+-- test some commands to make sure they fail on the dropped column
+analyze atacc1(a);
+ERROR:  Relation "atacc1" has no column "a"
+analyze atacc1("........pg.dropped.1........");
+ERROR:  Relation "atacc1" has no column "........pg.dropped.1........"
+vacuum analyze atacc1(a);
+ERROR:  Relation "atacc1" has no column "a"
+vacuum analyze atacc1("........pg.dropped.1........");
+ERROR:  Relation "atacc1" has no column "........pg.dropped.1........"
+comment on column atacc1.a is 'testing';
+ERROR:  Relation "atacc1" has no column "a"
+comment on column atacc1."........pg.dropped.1........" is 'testing';
+ERROR:  Relation "atacc1" has no column "........pg.dropped.1........"
+alter table atacc1 alter a set storage plain;
+ERROR:  ALTER TABLE: relation "atacc1" has no column "a"
+alter table atacc1 alter "........pg.dropped.1........" set storage plain;
+ERROR:  ALTER TABLE: relation "atacc1" has no column "........pg.dropped.1........"
+alter table atacc1 alter a set statistics 0;
+ERROR:  ALTER TABLE: relation "atacc1" has no column "a"
+alter table atacc1 alter "........pg.dropped.1........" set statistics 0;
+ERROR:  ALTER TABLE: relation "atacc1" has no column "........pg.dropped.1........"
+alter table atacc1 alter a set default 3;
+ERROR:  Relation "atacc1" has no column "a"
+alter table atacc1 alter "........pg.dropped.1........" set default 3;
+ERROR:  Relation "atacc1" has no column "........pg.dropped.1........"
+alter table atacc1 alter a drop default;
+ERROR:  Relation "atacc1" has no column "a"
+alter table atacc1 alter "........pg.dropped.1........" drop default;
+ERROR:  Relation "atacc1" has no column "........pg.dropped.1........"
+alter table atacc1 alter a set not null;
+ERROR:  Relation "atacc1" has no column "a"
+alter table atacc1 alter "........pg.dropped.1........" set not null;
+ERROR:  Relation "atacc1" has no column "........pg.dropped.1........"
+alter table atacc1 alter a drop not null;
+ERROR:  Relation "atacc1" has no column "a"
+alter table atacc1 alter "........pg.dropped.1........" drop not null;
+ERROR:  Relation "atacc1" has no column "........pg.dropped.1........"
+alter table atacc1 rename a to x;
+ERROR:  renameatt: attribute "a" does not exist
+alter table atacc1 rename "........pg.dropped.1........" to x;
+ERROR:  renameatt: attribute "........pg.dropped.1........" does not exist
+alter table atacc1 add primary key(a);
+ERROR:  ALTER TABLE: column "a" named in key does not exist
+alter table atacc1 add primary key("........pg.dropped.1........");
+ERROR:  ALTER TABLE: column "........pg.dropped.1........" named in key does not exist
+alter table atacc1 add unique(a);
+ERROR:  ALTER TABLE: column "a" named in key does not exist
+alter table atacc1 add unique("........pg.dropped.1........");
+ERROR:  ALTER TABLE: column "........pg.dropped.1........" named in key does not exist
+alter table atacc1 add check (a > 3);
+ERROR:  Attribute "a" not found
+alter table atacc1 add check ("........pg.dropped.1........" > 3);
+ERROR:  Attribute "........pg.dropped.1........" not found
+create table atacc2 (id int4 unique);
+NOTICE:  CREATE TABLE / UNIQUE will create implicit index 'atacc2_id_key' for table 'atacc2'
+alter table atacc1 add foreign key (a) references atacc2(id);
+NOTICE:  ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  ALTER TABLE: column "a" referenced in foreign key constraint does not exist
+alter table atacc1 add foreign key ("........pg.dropped.1........") references atacc2(id);
+NOTICE:  ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  ALTER TABLE: column "........pg.dropped.1........" referenced in foreign key constraint does not exist
+alter table atacc2 add foreign key (id) references atacc1(a);
+NOTICE:  ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  UNIQUE constraint matching given keys for referenced table "atacc1" not found
+alter table atacc2 add foreign key (id) references atacc1("........pg.dropped.1........");
+NOTICE:  ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  UNIQUE constraint matching given keys for referenced table "atacc1" not found
+drop table atacc2;
+create index "testing_idx" on atacc1(a);
+ERROR:  DefineIndex: attribute "a" not found
+create index "testing_idx" on atacc1("........pg.dropped.1........");
+ERROR:  DefineIndex: attribute "........pg.dropped.1........" not found
+-- test create as and select into
+insert into atacc1 values (21, 22, 23);
+create table test1 as select * from atacc1;
+select * from test1;
+ b  | c  | d  
+----+----+----
+ 21 | 22 | 23
+(1 row)
+
+drop table test1;
+select * into test2 from atacc1;
+select * from test2;
+ b  | c  | d  
+----+----+----
+ 21 | 22 | 23
+(1 row)
+
+drop table test2;
+-- try dropping all columns
+alter table atacc1 drop c;
+alter table atacc1 drop d;
+alter table atacc1 drop b;
+ERROR:  ALTER TABLE: Cannot drop last column from table "atacc1"
+select * from atacc1;
+ b  
+----
+ 21
+(1 row)
+
+drop table atacc1;
+-- test inheritance
+create table parent (a int, b int, c int);
+insert into parent values (1, 2, 3);
+alter table parent drop a;
+create table child (d varchar(255)) inherits (parent);
+insert into child values (12, 13, 'testing');
+select * from parent;
+ b  | c  
+----+----
+  2 |  3
+ 12 | 13
+(2 rows)
+
+select * from child;
+ b  | c  |    d    
+----+----+---------
+ 12 | 13 | testing
+(1 row)
+
+alter table parent drop c;
+select * from parent;
+ b  
+----
+  2
+ 12
+(2 rows)
+
+select * from child;
+ b  |    d    
+----+---------
+ 12 | testing
+(1 row)
+
+drop table child;
+drop table parent;
+-- test copy in/out
+create table test (a int4, b int4, c int4);
+insert into test values (1,2,3);
+alter table test drop a;
+copy test to stdout;
+2	3
+copy test(a) to stdout;
+ERROR:  Relation "test" has no column "a"
+copy test("........pg.dropped.1........") to stdout;
+ERROR:  Relation "test" has no column "........pg.dropped.1........"
+copy test from stdin;
+ERROR:  copy: line 1, Extra data after last expected column
+lost synchronization with server, resetting connection
+select * from test;
+ b | c 
+---+---
+ 2 | 3
+(1 row)
+
+copy test from stdin;
+select * from test;
+ b  | c  
+----+----
+  2 |  3
+ 21 | 22
+(2 rows)
+
+copy test(a) from stdin;
+ERROR:  Relation "test" has no column "a"
+copy test("........pg.dropped.1........") from stdin;
+ERROR:  Relation "test" has no column "........pg.dropped.1........"
+copy test(b,c) from stdin;
+select * from test;
+ b  | c  
+----+----
+  2 |  3
+ 21 | 22
+ 31 | 32
+(3 rows)
+
+drop table test;
diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index e4f806c8a56f5978434a70a790624803dc8174d6..58a5b6eb22a20cef58c6b30ffb80d2448867f729 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -29,26 +29,44 @@ COPY x (b, d) from stdin;
 COPY x (a, b, c, d, e) from stdin;
 -- non-existent column in column list: should fail
 COPY x (xyz) from stdin;
-ERROR:  COPY: Specified column "xyz" does not exist
+ERROR:  Relation "x" has no column "xyz"
 -- too many columns in column list: should fail
 COPY x (a, b, c, d, e, d, c) from stdin;
-ERROR:  COPY: Too many columns specified
+ERROR:  Attribute "d" specified more than once
 -- missing data: should fail
 COPY x from stdin;
-ERROR:  copy: line 1, COPY TEXT: Missing data for attribute 1
+ERROR:  copy: line 1, Missing data for column "b"
 lost synchronization with server, resetting connection
 COPY x from stdin;
-ERROR:  copy: line 1, COPY TEXT: Missing data for attribute 4
+ERROR:  copy: line 1, Missing data for column "e"
 lost synchronization with server, resetting connection
 COPY x from stdin;
-ERROR:  copy: line 1, COPY TEXT: Missing data for attribute 4
+ERROR:  copy: line 1, Missing data for column "e"
 lost synchronization with server, resetting connection
 -- extra data: should fail
 COPY x from stdin;
-ERROR:  copy: line 1, COPY TEXT: Extra data encountered
+ERROR:  copy: line 1, Extra data after last expected column
 lost synchronization with server, resetting connection
 -- various COPY options: delimiters, oids, NULL string
 COPY x (b, c, d, e) from stdin with oids delimiter ',' null 'x';
+-- check results of copy in
+SELECT * FROM x;
+   a   | b  |   c   |   d    |          e           
+-------+----+-------+--------+----------------------
+ 10000 | 21 | 31    | 41     | before trigger fired
+ 10001 | 22 | 32    | 42     | before trigger fired
+ 10002 | 23 | 33    | 43     | before trigger fired
+ 10003 | 24 | 34    | 44     | before trigger fired
+ 10004 | 25 | 35    | 45     | before trigger fired
+ 10005 | 26 | 36    | 46     | before trigger fired
+     6 |    | 45    | 80     | before trigger fired
+     1 |  1 | stuff | test_1 | after trigger fired
+     2 |  2 | stuff | test_2 | after trigger fired
+     3 |  3 | stuff | test_3 | after trigger fired
+     4 |  4 | stuff | test_4 | after trigger fired
+     5 |  5 | stuff | test_5 | after trigger fired
+(12 rows)
+
 -- COPY w/ oids on a table w/o oids should fail
 CREATE TABLE no_oids (
 	a	int,
@@ -61,6 +79,7 @@ COPY no_oids FROM stdin WITH OIDS;
 ERROR:  COPY: table "no_oids" does not have OIDs
 COPY no_oids TO stdout WITH OIDS;
 ERROR:  COPY: table "no_oids" does not have OIDs
+-- check copy out
 COPY x TO stdout;
 10000	21	31	41	before trigger fired
 10001	22	32	42	before trigger fired
@@ -87,6 +106,19 @@ stuff	after trigger fired
 stuff	after trigger fired
 stuff	after trigger fired
 stuff	after trigger fired
+COPY x (b, e) TO stdout WITH NULL 'I''m null';
+21	before trigger fired
+22	before trigger fired
+23	before trigger fired
+24	before trigger fired
+25	before trigger fired
+26	before trigger fired
+I'm null	before trigger fired
+1	after trigger fired
+2	after trigger fired
+3	after trigger fired
+4	after trigger fired
+5	after trigger fired
 DROP TABLE x;
 DROP FUNCTION fn_x_before();
 DROP FUNCTION fn_x_after();
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
index f39998073d78e1776e21dd40b7aed6b8ba956d31..8946d2b15b35332becdf06f260076081877daadd 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -571,3 +571,163 @@ select * from def_view_test;
 drop rule def_view_test_ins on def_view_test;
 drop view def_view_test;
 drop table def_test;
+
+-- alter table / drop column tests
+-- try altering system catalogs, should fail
+alter table pg_class drop column relname;
+
+-- try altering non-existent table, should fail
+alter table foo drop column bar;
+
+-- test dropping columns
+create table atacc1 (a int4 not null, b int4, c int4 not null, d int4);
+insert into atacc1 values (1, 2, 3, 4);
+alter table atacc1 drop a;
+alter table atacc1 drop a;
+
+-- SELECTs
+select * from atacc1;
+select * from atacc1 order by a;
+select * from atacc1 order by "........pg.dropped.1........";
+select * from atacc1 group by a;
+select * from atacc1 group by "........pg.dropped.1........";
+select atacc1.* from atacc1;
+select a from atacc1;
+select atacc1.a from atacc1;
+select b,c,d from atacc1;
+select a,b,c,d from atacc1;
+select * from atacc1 where a = 1;
+select "........pg.dropped.1........" from atacc1;
+select atacc1."........pg.dropped.1........" from atacc1;
+select "........pg.dropped.1........",b,c,d from atacc1;
+select * from atacc1 where "........pg.dropped.1........" = 1;
+
+-- UPDATEs
+update atacc1 set a = 3;
+update atacc1 set b = 2 where a = 3;
+update atacc1 set "........pg.dropped.1........" = 3;
+update atacc1 set b = 2 where "........pg.dropped.1........" = 3;
+
+-- INSERTs
+insert into atacc1 values (10, 11, 12, 13);
+insert into atacc1 values (default, 11, 12, 13);
+insert into atacc1 values (11, 12, 13);
+insert into atacc1 (a) values (10);
+insert into atacc1 (a) values (default);
+insert into atacc1 (a,b,c,d) values (10,11,12,13);
+insert into atacc1 (a,b,c,d) values (default,11,12,13);
+insert into atacc1 (b,c,d) values (11,12,13);
+insert into atacc1 ("........pg.dropped.1........") values (10);
+insert into atacc1 ("........pg.dropped.1........") values (default);
+insert into atacc1 ("........pg.dropped.1........",b,c,d) values (10,11,12,13);
+insert into atacc1 ("........pg.dropped.1........",b,c,d) values (default,11,12,13);
+
+-- DELETEs
+delete from atacc1 where a = 3;
+delete from atacc1 where "........pg.dropped.1........" = 3;
+delete from atacc1;
+
+-- try dropping a non-existent column, should fail
+alter table atacc1 drop bar;
+
+-- try dropping the oid column, should fail
+alter table atacc1 drop oid;
+
+-- try creating a view and altering that, should fail
+create view myview as select * from atacc1;
+select * from myview;
+alter table myview drop d;
+drop view myview;
+
+-- test some commands to make sure they fail on the dropped column
+analyze atacc1(a);
+analyze atacc1("........pg.dropped.1........");
+vacuum analyze atacc1(a);
+vacuum analyze atacc1("........pg.dropped.1........");
+comment on column atacc1.a is 'testing';
+comment on column atacc1."........pg.dropped.1........" is 'testing';
+alter table atacc1 alter a set storage plain;
+alter table atacc1 alter "........pg.dropped.1........" set storage plain;
+alter table atacc1 alter a set statistics 0;
+alter table atacc1 alter "........pg.dropped.1........" set statistics 0;
+alter table atacc1 alter a set default 3;
+alter table atacc1 alter "........pg.dropped.1........" set default 3;
+alter table atacc1 alter a drop default;
+alter table atacc1 alter "........pg.dropped.1........" drop default;
+alter table atacc1 alter a set not null;
+alter table atacc1 alter "........pg.dropped.1........" set not null;
+alter table atacc1 alter a drop not null;
+alter table atacc1 alter "........pg.dropped.1........" drop not null;
+alter table atacc1 rename a to x;
+alter table atacc1 rename "........pg.dropped.1........" to x;
+alter table atacc1 add primary key(a);
+alter table atacc1 add primary key("........pg.dropped.1........");
+alter table atacc1 add unique(a);
+alter table atacc1 add unique("........pg.dropped.1........");
+alter table atacc1 add check (a > 3);
+alter table atacc1 add check ("........pg.dropped.1........" > 3);
+create table atacc2 (id int4 unique);
+alter table atacc1 add foreign key (a) references atacc2(id);
+alter table atacc1 add foreign key ("........pg.dropped.1........") references atacc2(id);
+alter table atacc2 add foreign key (id) references atacc1(a);
+alter table atacc2 add foreign key (id) references atacc1("........pg.dropped.1........");
+drop table atacc2;
+create index "testing_idx" on atacc1(a);
+create index "testing_idx" on atacc1("........pg.dropped.1........");
+
+-- test create as and select into
+insert into atacc1 values (21, 22, 23);
+create table test1 as select * from atacc1;
+select * from test1;
+drop table test1;
+select * into test2 from atacc1;
+select * from test2;
+drop table test2;
+
+-- try dropping all columns
+alter table atacc1 drop c;
+alter table atacc1 drop d;
+alter table atacc1 drop b;
+select * from atacc1;
+
+drop table atacc1;
+
+-- test inheritance
+create table parent (a int, b int, c int);
+insert into parent values (1, 2, 3);
+alter table parent drop a;
+create table child (d varchar(255)) inherits (parent);
+insert into child values (12, 13, 'testing');
+
+select * from parent;
+select * from child;
+alter table parent drop c;
+select * from parent;
+select * from child;
+
+drop table child;
+drop table parent;
+
+-- test copy in/out
+create table test (a int4, b int4, c int4);
+insert into test values (1,2,3);
+alter table test drop a;
+copy test to stdout;
+copy test(a) to stdout;
+copy test("........pg.dropped.1........") to stdout;
+copy test from stdin;
+10	11	12
+\.
+select * from test;
+copy test from stdin;
+21	22
+\.
+select * from test;
+copy test(a) from stdin;
+copy test("........pg.dropped.1........") from stdin;
+copy test(b,c) from stdin;
+31	32
+\.
+select * from test;
+drop table test;
+
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index b0ccfe671605c6db6b6fc9116bba90c3229967dd..4f0d50247f182d3fbe3a22ae4d0bdce6f8d29886 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -76,6 +76,9 @@ COPY x (b, c, d, e) from stdin with oids delimiter ',' null 'x';
 500000,x,45,80,90
 \.
 
+-- check results of copy in
+SELECT * FROM x;
+
 -- COPY w/ oids on a table w/o oids should fail
 CREATE TABLE no_oids (
 	a	int,
@@ -89,8 +92,11 @@ INSERT INTO no_oids (a, b) VALUES (20, 30);
 COPY no_oids FROM stdin WITH OIDS;
 COPY no_oids TO stdout WITH OIDS;
 
+-- check copy out
 COPY x TO stdout;
 COPY x (c, e) TO stdout;
+COPY x (b, e) TO stdout WITH NULL 'I''m null';
+
 DROP TABLE x;
 DROP FUNCTION fn_x_before();
 DROP FUNCTION fn_x_after();