diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index e7f76d3e58112b144e14a1549b824cc89c9396dc..2ea68de912e3ffdcf053c3cfdfd6006749e26f18 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/copy.sgml,v 1.85 2009/02/06 21:22:49 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/copy.sgml,v 1.86 2009/07/25 00:07:10 adunstan Exp $
 PostgreSQL documentation
 -->
 
@@ -44,7 +44,7 @@ COPY { <replaceable class="parameter">tablename</replaceable> [ ( <replaceable c
           [ CSV [ HEADER ]
                 [ QUOTE [ AS ] '<replaceable class="parameter">quote</replaceable>' ] 
                 [ ESCAPE [ AS ] '<replaceable class="parameter">escape</replaceable>' ]
-                [ FORCE QUOTE <replaceable class="parameter">column</replaceable> [, ...] ]
+                [ FORCE QUOTE { <replaceable class="parameter">column</replaceable> [, ...] | * } ]
 </synopsis>
  </refsynopsisdiv>
  
@@ -248,7 +248,9 @@ COPY { <replaceable class="parameter">tablename</replaceable> [ ( <replaceable c
      <para>
       In <literal>CSV</> <command>COPY TO</> mode, forces quoting to be
       used for all non-<literal>NULL</> values in each specified column.
-      <literal>NULL</> output is never quoted.
+      <literal>NULL</> output is never quoted. If <literal>*</> is specified,
+      non-<literal>NULL</> values for all columns of the table will be 
+      quoted.
      </para>
     </listitem>
    </varlistentry>
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index c464ed7f6ce16dfed49104c236cfcfb3f1f59f3e..9048276c5461656ca20ef6e4252ecc617d354f04 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.312 2009/06/11 14:48:55 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.313 2009/07/25 00:07:11 adunstan Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -730,6 +730,9 @@ DoCopy(const CopyStmt *stmt, const char *queryString)
 	int			num_phys_attrs;
 	uint64		processed;
 
+	/* a dummy list that represents 'all-columns' */
+	List		all_columns = { T_List };
+	
 	/* Allocate workspace and zero all fields */
 	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
 
@@ -808,7 +811,11 @@ DoCopy(const CopyStmt *stmt, const char *queryString)
 				ereport(ERROR,
 						(errcode(ERRCODE_SYNTAX_ERROR),
 						 errmsg("conflicting or redundant options")));
-			force_quote = (List *) defel->arg;
+
+			if (IsA(defel->arg, A_Star))
+				force_quote = &all_columns;
+			else
+				force_quote = (List *) defel->arg;
 		}
 		else if (strcmp(defel->defname, "force_notnull") == 0)
 		{
@@ -1092,7 +1099,14 @@ DoCopy(const CopyStmt *stmt, const char *queryString)
 
 	/* Convert FORCE QUOTE name list to per-column flags, check validity */
 	cstate->force_quote_flags = (bool *) palloc0(num_phys_attrs * sizeof(bool));
-	if (force_quote)
+	if (force_quote == &all_columns)
+	{
+		int		i;
+
+		for (i = 0; i < num_phys_attrs; i++)
+			cstate->force_quote_flags[i] = true;
+	}
+	else if (force_quote)
 	{
 		List	   *attnums;
 		ListCell   *cur;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 7e6d55be71274da9c7636270d328e5e8388d783d..c88073d33ddb3d3e8519abc216732f5152460cc4 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.671 2009/07/20 02:42:28 adunstan Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.672 2009/07/25 00:07:11 adunstan Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -2028,6 +2028,10 @@ copy_opt_item:
 				{
 					$$ = makeDefElem("force_quote", (Node *)$3);
 				}
+			| FORCE QUOTE '*'
+				{
+					$$ = makeDefElem("force_quote", (Node *)makeNode(A_Star));
+				}
 			| FORCE NOT NULL_P columnList
 				{
 					$$ = makeDefElem("force_notnull", (Node *)$4);
diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index 7f374ac1a6f79e41dc530501ed85254d0db9864d..5f52d6ee6cf226b65d41e58d1630683107eef2e0 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -191,6 +191,10 @@ COPY y TO stdout WITH CSV FORCE QUOTE col2 ESCAPE E'\\';
 "Jackson, Sam","\\h"
 "It is \"perfect\".","	"
 "",
+COPY y TO stdout WITH CSV FORCE QUOTE *;
+"Jackson, Sam","\h"
+"It is ""perfect"".","	"
+"",
 --test that we read consecutive LFs properly
 CREATE TEMP TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index 7c23ba253c4e28a47af195963ffd3d8094b829da..9dee93c14cd4c73a76644fa5beb386ce89005b10 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -128,6 +128,7 @@ INSERT INTO y VALUES ('', NULL);
 COPY y TO stdout WITH CSV;
 COPY y TO stdout WITH CSV QUOTE '''' DELIMITER '|';
 COPY y TO stdout WITH CSV FORCE QUOTE col2 ESCAPE E'\\';
+COPY y TO stdout WITH CSV FORCE QUOTE *;
 
 --test that we read consecutive LFs properly