diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index cf4b86e2e82cca3dfe0df06020584ccb2bb01b54..68bb8276981568f3c9ed3c4cded35f1ba725d309 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.142 2000/08/03 19:19:08 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.143 2000/09/12 04:49:06 momjian Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -842,7 +842,9 @@ heap_create_with_catalog(char *relname,
 	/*
 	 * We create the disk file for this relation here
 	 */
-	heap_storage_create(new_rel_desc);
+	if (relkind != RELKIND_VIEW)
+		heap_storage_create(new_rel_desc);
+
 	/* ----------------
 	 *	ok, the relation has been cataloged, so close our relations
 	 *	and return the oid of the newly created relation.
@@ -1468,7 +1470,7 @@ heap_drop_with_catalog(const char *relname,
 	 *	unlink the relation's physical file and finish up.
 	 * ----------------
 	 */
-	if (! rel->rd_unlinked)
+	if (rel->rd_rel->relkind != RELKIND_VIEW && ! rel->rd_unlinked)
 		smgrunlink(DEFAULT_SMGR, rel);
 	rel->rd_unlinked = true;
 
diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c
index d0de9e2e4de68b9181de841319e5475d77dfbd59..d0faa943cfd620047e0b8d293ea3ad3abbeacd68 100644
--- a/src/backend/commands/command.c
+++ b/src/backend/commands/command.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.100 2000/09/12 04:33:18 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.101 2000/09/12 04:49:06 momjian Exp $
  *
  * NOTES
  *	  The PerformAddAttribute() code, like most of the relation
@@ -533,6 +533,9 @@ AlterTableAlterColumn(const char *relationName,
 #endif
 
 	rel = heap_openr(relationName, AccessExclusiveLock);
+	if ( rel->rd_rel->relkind == RELKIND_VIEW )
+		elog(ERROR, "ALTER TABLE: %s is a view", relationName);
+
 	myrelid = RelationGetRelid(rel);
 	heap_close(rel, NoLock);
 
@@ -1133,6 +1136,10 @@ AlterTableAddConstraint(char *relationName,
 
 						rel = heap_openr(relationName, AccessExclusiveLock);
 
+						/* make sure it is not a view */
+						if (rel->rd_rel->relkind == RELKIND_VIEW)
+						   elog(ERROR, "ALTER TABLE: cannot add constraint to a view");
+
 						/*
 						 * Scan all of the rows, looking for a false match
 						 */
@@ -1251,19 +1258,20 @@ AlterTableAddConstraint(char *relationName,
 					elog(ERROR, "ALTER TABLE / ADD CONSTRAINT: Unable to reference temporary table from permanent table constraint.");
 				}
 
-				/* check to see if the referenced table is a view. */
-				if (is_viewr(fkconstraint->pktable_name))
-				 elog(ERROR, "ALTER TABLE: Cannot add constraints to views.");
-
 				/*
 				 * Grab an exclusive lock on the pk table, so that someone
 				 * doesn't delete rows out from under us.
 				 */
 
 				pkrel = heap_openr(fkconstraint->pktable_name, AccessExclusiveLock);
-			        if (pkrel == NULL)
-                			elog(ERROR, "referenced table \"%s\" not found",
+				if (pkrel == NULL)
+						elog(ERROR, "referenced table \"%s\" not found",
+							 fkconstraint->pktable_name);
+
+				if (pkrel->rd_rel->relkind != RELKIND_RELATION)
+					elog(ERROR, "referenced table \"%s\" not a relation", 
 		                         fkconstraint->pktable_name);
+				
 
 				/*
 				 * Grab an exclusive lock on the fk table, and then scan
@@ -1277,6 +1285,9 @@ AlterTableAddConstraint(char *relationName,
 					elog(ERROR, "table \"%s\" not found",
 						relationName);
 
+				if (rel->rd_rel->relkind != RELKIND_RELATION)
+					elog(ERROR, "referencing table \"%s\" not a relation", relationName);
+
 				/* First we check for limited correctness of the constraint */
 
 			        rel_attrs = pkrel->rd_att->attrs;
@@ -1503,6 +1514,7 @@ AlterTableCreateToastTable(const char *relationName, bool silent)
 	 * allow to create TOAST tables for views. But why not - someone
 	 * can insert into a view, so it shouldn't be impossible to hide
 	 * huge data there :-)
+	 * Not any more.
 	 */
 	if (((Form_pg_class) GETSTRUCT(reltup))->relkind != RELKIND_RELATION)
 	{
@@ -1702,6 +1714,9 @@ LockTableCommand(LockStmt *lockstmt)
 
 	rel = heap_openr(lockstmt->relname, NoLock);
 
+	if (rel->rd_rel->relkind != RELKIND_RELATION)
+			elog(ERROR, "LOCK TABLE: %s is not a table", lockstmt->relname);
+
 	if (is_view(rel)) 
 			elog(ERROR, "LOCK TABLE: cannot lock a view");
 
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index 87c7d84727ddb1b0d0ff0282e31dbbdec8cd0617..51832bc2c7bb442a78f261801d130ee8d37dc9fc 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -21,6 +21,7 @@
 #include "catalog/pg_shadow.h"
 #include "catalog/pg_trigger.h"
 #include "catalog/pg_type.h"
+#include "catalog/pg_class.h"
 #include "commands/comment.h"
 #include "miscadmin.h"
 #include "parser/parse.h"
@@ -301,19 +302,19 @@ CommentRelation(int reltype, char *relname, char *comment)
 	switch (reltype)
 	{
 		case (INDEX):
-			if (relkind != 'i')
+			if (relkind != RELKIND_INDEX)
 				elog(ERROR, "relation '%s' is not an index", relname);
 			break;
 		case (TABLE):
-			if (relkind != 'r')
+			if (relkind != RELKIND_RELATION)
 				elog(ERROR, "relation '%s' is not a table", relname);
 			break;
 		case (VIEW):
-			if (relkind != 'r')
+			if (relkind != RELKIND_VIEW)
 				elog(ERROR, "relation '%s' is not a view", relname);
 			break;
 		case (SEQUENCE):
-			if (relkind != 'S')
+			if (relkind != RELKIND_SEQUENCE)
 				elog(ERROR, "relation '%s' is not a sequence", relname);
 			break;
 	}
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 398d002ffcd2ad28460add27af2c528a7e77261a..7d4005d21d5b5d953cc4a4cacafa547f10fd1591 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.164 2000/09/06 14:15:16 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.165 2000/09/12 04:49:07 momjian Exp $
  *
 
  *-------------------------------------------------------------------------
@@ -306,7 +306,7 @@ getrels(NameData *VacRelP)
 
 		if (rkind != RELKIND_RELATION)
 		{
-			elog(NOTICE, "Vacuum: can not process index and certain system tables");
+			elog(NOTICE, "Vacuum: can not process indecies, views and certain system tables");
 			continue;
 		}
 
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index 01e23d13150268d811efd2a2d0396a1ac59a45da..af10805b71f39f28ff843257c21217c60cfe8970 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Id: view.c,v 1.46 2000/09/12 04:15:56 momjian Exp $
+ *	$Id: view.c,v 1.47 2000/09/12 04:49:07 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -102,7 +102,7 @@ DefineVirtualRelation(char *relname, List *tlist)
 	/*
 	 * finally create the relation...
 	 */
-	DefineRelation(&createStmt, RELKIND_RELATION);
+	DefineRelation(&createStmt, RELKIND_VIEW);
 }
 
 /*------------------------------------------------------------------
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index c6571279e1f418fbbe045d21c0ee26b57ff13481..d25530b44fb9d0e7219f828cd443b5c346676b00 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -27,7 +27,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.125 2000/09/06 14:15:17 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.126 2000/09/12 04:49:08 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -720,6 +720,10 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
 			elog(ERROR, "You can't change toast relation %s",
 				 RelationGetRelationName(resultRelationDesc));
 
+		if (resultRelationDesc->rd_rel->relkind == RELKIND_VIEW)
+			elog(ERROR, "You can't change view relation %s",
+				 RelationGetRelationName(resultRelationDesc));
+
 		resultRelationInfo = makeNode(RelationInfo);
 		resultRelationInfo->ri_RangeTableIndex = resultRelationIndex;
 		resultRelationInfo->ri_RelationDesc = resultRelationDesc;
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index c9315f6d338fc79d2cca32da0509c6901a47077e..8444bd9138423c985097d50837ba4087c393507a 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.50 2000/09/12 04:15:57 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.51 2000/09/12 04:49:09 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,6 +23,8 @@
 #include "parser/parse_relation.h"
 #include "rewrite/rewriteDefine.h"
 #include "rewrite/rewriteSupport.h"
+#include "utils/syscache.h"
+#include "storage/smgr.h"
 #include "commands/view.h"
 
 
@@ -162,6 +164,7 @@ DefineQueryRewrite(RuleStmt *stmt)
 			   *event_qualP;
 	List	   *l;
 	Query	   *query;
+	bool		RelisBecomingView = false;
 
 	/*
 	 * If we are installing an ON SELECT rule, we had better grab
@@ -207,6 +210,30 @@ DefineQueryRewrite(RuleStmt *stmt)
 			elog(ERROR, "rule actions on NEW currently not supported"
 				 "\n\tuse triggers instead");
 		}
+
+		if (event_relation->rd_rel->relkind != RELKIND_VIEW)
+		{
+			HeapScanDesc  scanDesc;
+			HeapTuple	  tuple;
+			/*
+			 * A relation is about to become a view.
+			 * check that the relation is empty because
+			 * the storage for the relation is going to
+			 * be deleted.
+			 */
+
+			scanDesc = heap_beginscan(event_relation, 0, SnapshotNow, 0, NULL);
+			tuple = heap_getnext(scanDesc, 0);
+			if (HeapTupleIsValid(tuple))
+				elog(ERROR, "relation %s is not empty. Cannot convert to view", event_obj->relname);
+
+			/* don't need heap_freetuple because we never got a valid tuple */
+			heap_endscan(scanDesc);
+
+
+			RelisBecomingView = true;
+		}
+
 	}
 
 	/*
@@ -338,6 +365,10 @@ DefineQueryRewrite(RuleStmt *stmt)
 	/* discard rule if it's null action and not INSTEAD; it's a no-op */
 	if (action != NULL || is_instead)
 	{
+		Relation	relationRelation;
+		HeapTuple	tuple;
+		Relation	idescs[Num_pg_class_indices];
+
 		event_qualP = nodeToString(event_qual);
 		actionP = nodeToString(action);
 
@@ -351,14 +382,50 @@ DefineQueryRewrite(RuleStmt *stmt)
 
 		/*
 		 * Set pg_class 'relhasrules' field TRUE for event relation.
+		 * Also modify the 'relkind' field to show that the relation is
+		 * now a view.
 		 *
 		 * Important side effect: an SI notice is broadcast to force all
 		 * backends (including me!) to update relcache entries with the new
 		 * rule.
+		 *
+		 * NOTE : Used to call setRelhasrulesInRelation. The code
+		 * was inlined so that two updates were not needed. mhh 31-aug-2000
+		 */
+
+		/*
+		 * Find the tuple to update in pg_class, using syscache for the lookup.
 		 */
-		setRelhasrulesInRelation(ev_relid, true);
+		relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
+		tuple = SearchSysCacheTupleCopy(RELOID,
+									ObjectIdGetDatum(ev_relid),
+									0, 0, 0);
+		Assert(HeapTupleIsValid(tuple));
+
+		/* Do the update */
+		((Form_pg_class) GETSTRUCT(tuple))->relhasrules = true;
+		if (RelisBecomingView)
+			((Form_pg_class) GETSTRUCT(tuple))->relkind = RELKIND_VIEW;
+
+		heap_update(relationRelation, &tuple->t_self, tuple, NULL);
+
+		/* Keep the catalog indices up to date */
+		CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
+		CatalogIndexInsert(idescs, Num_pg_class_indices, relationRelation, tuple);
+		CatalogCloseIndices(Num_pg_class_indices, idescs);
+
+		heap_freetuple(tuple);
+		heap_close(relationRelation, RowExclusiveLock);
 	}
 
+	/*
+	 * IF the relation is becoming a view, delete the storage
+	 * files associated with it.
+	 */
+	if (RelisBecomingView)
+		smgrunlink(DEFAULT_SMGR, event_relation);
+
+
 	/* Close rel, but keep lock till commit... */
 	heap_close(event_relation, NoLock);
 }
diff --git a/src/backend/rewrite/rewriteRemove.c b/src/backend/rewrite/rewriteRemove.c
index d50e1049097bbe006df356f111b38e0dd71214eb..2af77853c467a46add7bdcb54ee6c8c525479212 100644
--- a/src/backend/rewrite/rewriteRemove.c
+++ b/src/backend/rewrite/rewriteRemove.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.38 2000/06/30 07:04:23 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.39 2000/09/12 04:49:09 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -103,6 +103,11 @@ RemoveRewriteRule(char *ruleName)
 	 */
 	event_relation = heap_open(eventRelationOid, AccessExclusiveLock);
 
+	/* do not allow the removal of a view's SELECT rule */
+	if (event_relation->rd_rel->relkind == RELKIND_VIEW &&
+			((Form_pg_rewrite) GETSTRUCT(tuple))->ev_type == '1' )
+		elog(ERROR, "Cannot remove a view's SELECT rule");
+
 	hasMoreRules = event_relation->rd_rules != NULL &&
 		event_relation->rd_rules->numLocks > 1;
 
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 558f678430ff71d35cfacab9e7900b2a312f273e..d603914c514a65f46e13436b258ad59260621b22 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.92 2000/09/06 14:15:21 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.93 2000/09/12 04:49:11 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -228,6 +228,9 @@ ProcessUtility(Node *parsetree,
 				if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
 					elog(ERROR, "TRUNCATE cannot be used on sequences. '%s' is a sequence",
 						 relname);
+				if (rel->rd_rel->relkind == RELKIND_VIEW)
+					elog(ERROR, "TRUNCATE cannot be used on views. '%s' is a sequence",
+						 relname);
 				heap_close(rel, NoLock);
 
 #ifndef NO_SECURITY
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 013ade75288000c6332d49da1eca616989d39c9c..e39f1cfd12d4b7b71ccf7763f368342b0cd8f6ed 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.110 2000/08/30 08:48:55 inoue Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.111 2000/09/12 04:49:13 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1022,14 +1022,18 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
 	 *	by the storage manager code to rd_fd.
 	 * ----------------
 	 */
-	fd = smgropen(DEFAULT_SMGR, relation);
+	if (relation->rd_rel->relkind != RELKIND_VIEW) {
+		fd = smgropen(DEFAULT_SMGR, relation);
 
-	Assert(fd >= -1);
-	if (fd == -1)
-		elog(NOTICE, "RelationIdBuildRelation: smgropen(%s): %m",
-			 NameStr(relation->rd_rel->relname));
+		Assert(fd >= -1);
+		if (fd == -1)
+			elog(NOTICE, "RelationBuildDesc: smgropen(%s): %m",
+				 NameStr(relation->rd_rel->relname));
 
-	relation->rd_fd = fd;
+		relation->rd_fd = fd;
+	} else {
+		relation->rd_fd = -1;
+	}
 
 	/* ----------------
 	 *	insert newly created relation into proper relcaches,
@@ -1279,7 +1283,7 @@ RelationIdCacheGetRelation(Oid relationId)
 
 	if (RelationIsValid(rd))
 	{
-		if (rd->rd_fd == -1)
+		if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
 		{
 			rd->rd_fd = smgropen(DEFAULT_SMGR, rd);
 			Assert(rd->rd_fd != -1 || rd->rd_unlinked);
@@ -1313,7 +1317,7 @@ RelationNameCacheGetRelation(const char *relationName)
 
 	if (RelationIsValid(rd))
 	{
-		if (rd->rd_fd == -1)
+		if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
 		{
 			rd->rd_fd = smgropen(DEFAULT_SMGR, rd);
 			Assert(rd->rd_fd != -1 || rd->rd_unlinked);
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 22b3cb7354ede6ca351367a7f1289d284f5577f7..b73ea0e6136e105db47812d3f8c3471aa10fea39 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.43 2000/08/23 06:04:43 thomas Exp $
+ * $Id: catversion.h,v 1.44 2000/09/12 04:49:15 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200008221
+#define CATALOG_VERSION_NO	200009111
 
 #endif
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index 1ea5b7b7792f96781d0518a788f8eaf4af420a65..3fc4a7fd76cc3febf1df81be65eff4a43b25491b 100644
--- a/src/include/catalog/pg_class.h
+++ b/src/include/catalog/pg_class.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_class.h,v 1.39 2000/07/03 23:10:05 wieck Exp $
+ * $Id: pg_class.h,v 1.40 2000/09/12 04:49:15 momjian Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -178,5 +178,6 @@ DESCR("");
 #define		  RELKIND_SEQUENCE		  'S'		/* SEQUENCE relation */
 #define		  RELKIND_UNCATALOGED	  'u'		/* temporary heap */
 #define		  RELKIND_TOASTVALUE	  't'		/* moved off huge values */
+#define		  RELKIND_VIEW				'v'	/* view */
 
 #endif	 /* PG_CLASS_H */
diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out
index 38eaf0b21dad6d544f6e7ade125c559944996a51..4f388b0e456016de12e5594d4947d7da5a5456a0 100644
--- a/src/test/regress/expected/type_sanity.out
+++ b/src/test/regress/expected/type_sanity.out
@@ -111,7 +111,7 @@ WHERE p1.typsend = p2.oid AND p1.typtype = 'b' AND
 -- Look for illegal values in pg_class fields
 SELECT p1.oid, p1.relname
 FROM pg_class as p1
-WHERE p1.relkind NOT IN ('r', 'i', 's', 'S', 't');
+WHERE p1.relkind NOT IN ('r', 'i', 's', 'S', 't', 'v');
  oid | relname 
 -----+---------
 (0 rows)
diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql
index 106a86b87c8c9df9ccbe844d39bc1c52fa74ee72..dbd6d0af409695b7f1a2fa7c5240aa52a4f53be8 100644
--- a/src/test/regress/sql/type_sanity.sql
+++ b/src/test/regress/sql/type_sanity.sql
@@ -99,7 +99,7 @@ WHERE p1.typsend = p2.oid AND p1.typtype = 'b' AND
 
 SELECT p1.oid, p1.relname
 FROM pg_class as p1
-WHERE p1.relkind NOT IN ('r', 'i', 's', 'S', 't');
+WHERE p1.relkind NOT IN ('r', 'i', 's', 'S', 't', 'v');
 
 -- Indexes should have an access method, others not.