diff --git a/doc/src/sgml/ref/create_view.sgml b/doc/src/sgml/ref/create_view.sgml
index 07c8f805b7af34e8b5c53f5b4a5e41517ba78afe..7cbbdbe1ced77d66d9b855ca3e74d211c34c7b79 100644
--- a/doc/src/sgml/ref/create_view.sgml
+++ b/doc/src/sgml/ref/create_view.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_view.sgml,v 1.37 2008/11/14 10:22:46 petere Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_view.sgml,v 1.38 2008/12/06 23:22:46 momjian Exp $
 PostgreSQL documentation
 -->
 
@@ -37,9 +37,10 @@ CREATE [ OR REPLACE ] [ TEMP | TEMPORARY ] VIEW <replaceable class="PARAMETER">n
 
   <para>
    <command>CREATE OR REPLACE VIEW</command> is similar, but if a view
-   of the same name already exists, it is replaced.  You can only replace
-   a view with a new query that generates the identical set of columns
-   (i.e., same column names and data types).
+   of the same name already exists, it is replaced.  The new query must
+   generate all of the same columns that were generated by the original query
+   in the same order and with the same data types, but may add additional
+   columns to the end of the list.
   </para>
 
   <para>
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index d252632ee7e641a474edefa8a75cba13f5a386ef..8e12a77d11c397d65eb56602963600d40e2380bf 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.271 2008/11/19 10:34:51 heikki Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.272 2008/12/06 23:22:46 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2334,6 +2334,12 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
 			ATPrepAddColumn(wqueue, rel, recurse, cmd);
 			pass = AT_PASS_ADD_COL;
 			break;
+		case AT_AddColumnToView:	/* add column via CREATE OR REPLACE VIEW */
+			ATSimplePermissions(rel, true);
+			/* Performs own recursion */
+			ATPrepAddColumn(wqueue, rel, recurse, cmd);
+			pass = AT_PASS_ADD_COL;
+			break;
 		case AT_ColumnDefault:	/* ALTER COLUMN DEFAULT */
 
 			/*
@@ -2555,6 +2561,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
 	switch (cmd->subtype)
 	{
 		case AT_AddColumn:		/* ADD COLUMN */
+		case AT_AddColumnToView: /* add column via CREATE OR REPLACE VIEW */
 			ATExecAddColumn(tab, rel, (ColumnDef *) cmd->def);
 			break;
 		case AT_ColumnDefault:	/* ALTER COLUMN DEFAULT */
@@ -3455,6 +3462,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
 	int			i;
 	int			minattnum,
 				maxatts;
+	char		relkind;
 	HeapTuple	typeTuple;
 	Oid			typeOid;
 	int32		typmod;
@@ -3527,6 +3535,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
 						colDef->colname, RelationGetRelationName(rel))));
 
 	minattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts;
+	relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
 	maxatts = minattnum + 1;
 	if (maxatts > MaxHeapAttributeNumber)
 		ereport(ERROR,
@@ -3625,44 +3634,48 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
 	 * Note: we use build_column_default, and not just the cooked default
 	 * returned by AddRelationNewConstraints, so that the right thing happens
 	 * when a datatype's default applies.
+	 *
+	 * We skip this logic completely for views.
 	 */
-	defval = (Expr *) build_column_default(rel, attribute.attnum);
+	if (relkind != RELKIND_VIEW) {
+		defval = (Expr *) build_column_default(rel, attribute.attnum);
 
-	if (!defval && GetDomainConstraints(typeOid) != NIL)
-	{
-		Oid			baseTypeId;
-		int32		baseTypeMod;
-
-		baseTypeMod = typmod;
-		baseTypeId = getBaseTypeAndTypmod(typeOid, &baseTypeMod);
-		defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod);
-		defval = (Expr *) coerce_to_target_type(NULL,
-												(Node *) defval,
-												baseTypeId,
-												typeOid,
-												typmod,
-												COERCION_ASSIGNMENT,
-												COERCE_IMPLICIT_CAST,
-												-1);
-		if (defval == NULL)		/* should not happen */
-			elog(ERROR, "failed to coerce base type to domain");
-	}
+		if (!defval && GetDomainConstraints(typeOid) != NIL)
+		{
+			Oid			baseTypeId;
+			int32		baseTypeMod;
+
+			baseTypeMod = typmod;
+			baseTypeId = getBaseTypeAndTypmod(typeOid, &baseTypeMod);
+			defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod);
+			defval = (Expr *) coerce_to_target_type(NULL,
+													(Node *) defval,
+													baseTypeId,
+													typeOid,
+													typmod,
+													COERCION_ASSIGNMENT,
+													COERCE_IMPLICIT_CAST,
+													-1);
+			if (defval == NULL)		/* should not happen */
+				elog(ERROR, "failed to coerce base type to domain");
+		}
 
-	if (defval)
-	{
-		NewColumnValue *newval;
+		if (defval)
+		{
+			NewColumnValue *newval;
 
-		newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
-		newval->attnum = attribute.attnum;
-		newval->expr = defval;
+			newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
+			newval->attnum = attribute.attnum;
+			newval->expr = defval;
 
-		tab->newvals = lappend(tab->newvals, newval);
-	}
+			tab->newvals = lappend(tab->newvals, newval);
+		}
 
-	/*
-	 * If the new column is NOT NULL, tell Phase 3 it needs to test that.
-	 */
-	tab->new_notnull |= colDef->is_not_null;
+		/*
+		 * If the new column is NOT NULL, tell Phase 3 it needs to test that.
+		 */
+		tab->new_notnull |= colDef->is_not_null;
+	}
 
 	/*
 	 * Add needed dependency entries for the new column.
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index 5d207861dca17289da3e5f8d9693bc4dfa34b511..23a03d28a9ccc89215d1169353473f4ca9a5f058 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.107 2008/08/25 22:42:32 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.108 2008/12/06 23:22:46 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -172,9 +172,34 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
 		 */
 		Assert(relation->istemp == rel->rd_istemp);
 
+		/*
+ 		 * If new attributes have been added, we must modify the pre-existing
+ 		 * view.
+ 		 */
+		if (list_length(attrList) > rel->rd_att->natts) {
+			List		*atcmds = NIL;
+			ListCell 	*c;
+			int			skip = rel->rd_att->natts;
+
+			foreach(c, attrList) {
+				AlterTableCmd *atcmd;
+
+				if (skip > 0) {
+					--skip;
+					continue;
+				}
+				atcmd = makeNode(AlterTableCmd);
+				atcmd->subtype = AT_AddColumnToView;
+				atcmd->def = lfirst(c);
+				atcmds = lappend(atcmds, atcmd);
+			}
+			AlterTableInternal(viewOid, atcmds, true);
+		}
+
 		/*
 		 * Create a tuple descriptor to compare against the existing view, and
-		 * verify it matches.
+		 * verify that the old column list is an initial prefix of the new
+		 * column list.
 		 */
 		descriptor = BuildDescForRelation(attrList);
 		checkViewTupleDesc(descriptor, rel->rd_att);
@@ -219,13 +244,13 @@ checkViewTupleDesc(TupleDesc newdesc, TupleDesc olddesc)
 {
 	int			i;
 
-	if (newdesc->natts != olddesc->natts)
+	if (newdesc->natts < olddesc->natts)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-				 errmsg("cannot change number of columns in view")));
+				 errmsg("cannot drop columns from view")));
 	/* we can ignore tdhasoid */
 
-	for (i = 0; i < newdesc->natts; i++)
+	for (i = 0; i < olddesc->natts; i++)
 	{
 		Form_pg_attribute newattr = newdesc->attrs[i];
 		Form_pg_attribute oldattr = olddesc->attrs[i];
@@ -234,7 +259,7 @@ checkViewTupleDesc(TupleDesc newdesc, TupleDesc olddesc)
 		if (newattr->attisdropped != oldattr->attisdropped)
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-					 errmsg("cannot change number of columns in view")));
+					 errmsg("cannot drop columns from view")));
 
 		if (strcmp(NameStr(newattr->attname), NameStr(oldattr->attname)) != 0)
 			ereport(ERROR,
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 4e0efe84bbaaf6346af1c5f95fd4e272e79680e2..bb3a9142d6fa18921d7704a5474d9567993ac2d7 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -19,7 +19,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.17 2008/09/01 20:42:45 tgl Exp $
+ *	$PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.18 2008/12/06 23:22:46 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1721,6 +1721,7 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString)
 		switch (cmd->subtype)
 		{
 			case AT_AddColumn:
+			case AT_AddColumnToView:
 				{
 					ColumnDef  *def = (ColumnDef *) cmd->def;
 
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 828c959ef2298e2d0a7e67fcf0d3ddaf4ba82e3a..47e3f37206c1ba392e6f6c8bf0820741bfe8fbc8 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.381 2008/12/04 17:51:27 petere Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.382 2008/12/06 23:22:46 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -989,6 +989,7 @@ typedef struct AlterTableStmt
 typedef enum AlterTableType
 {
 	AT_AddColumn,				/* add column */
+	AT_AddColumnToView,			/* implicitly via CREATE OR REPLACE VIEW */
 	AT_ColumnDefault,			/* alter column default */
 	AT_DropNotNull,				/* alter column drop not null */
 	AT_SetNotNull,				/* alter column set not null */
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index cbee9dceed88f57108bcc441331caede784164e9..e9b6c83e25d883affc095a332b2a83f5ce231029 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -49,15 +49,18 @@ SELECT * FROM viewtest;
 -- should fail
 CREATE OR REPLACE VIEW viewtest AS
 	SELECT a FROM viewtest_tbl WHERE a <> 20;
-ERROR:  cannot change number of columns in view
+ERROR:  cannot drop columns from view
 -- should fail
 CREATE OR REPLACE VIEW viewtest AS
 	SELECT 1, * FROM viewtest_tbl;
-ERROR:  cannot change number of columns in view
+ERROR:  column "b" of relation "viewtest" already exists
 -- should fail
 CREATE OR REPLACE VIEW viewtest AS
 	SELECT a, b::numeric FROM viewtest_tbl;
 ERROR:  cannot change data type of view column "b"
+-- should work 
+CREATE OR REPLACE VIEW viewtest AS
+	SELECT a, b, 0 AS c FROM viewtest_tbl;
 DROP VIEW viewtest;
 DROP TABLE viewtest_tbl;
 -- tests for temporary views
diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql
index 30a9bb1152da9731c2bb2a1af1d4b76439404bee..f8942c93f5ce44b6f43dae451127db8125b16a64 100644
--- a/src/test/regress/sql/create_view.sql
+++ b/src/test/regress/sql/create_view.sql
@@ -61,6 +61,10 @@ CREATE OR REPLACE VIEW viewtest AS
 CREATE OR REPLACE VIEW viewtest AS
 	SELECT a, b::numeric FROM viewtest_tbl;
 
+-- should work 
+CREATE OR REPLACE VIEW viewtest AS
+	SELECT a, b, 0 AS c FROM viewtest_tbl;
+
 DROP VIEW viewtest;
 DROP TABLE viewtest_tbl;