diff -cpr HEAD/doc/src/sgml/ref/copy.sgml force_quote_all/doc/src/sgml/ref/copy.sgml
*** HEAD/doc/src/sgml/ref/copy.sgml	Fri Jul 17 12:49:09 2009
--- force_quote_all/doc/src/sgml/ref/copy.sgml	Fri Jul 17 12:49:46 2009
*************** COPY { <replaceable class="parameter">ta
*** 44,50 ****
            [ CSV [ HEADER ]
                  [ QUOTE [ AS ] '<replaceable class="parameter">quote</replaceable>' ] 
                  [ ESCAPE [ AS ] '<replaceable class="parameter">escape</replaceable>' ]
!                 [ FORCE QUOTE <replaceable class="parameter">column</replaceable> [, ...] ]
  </synopsis>
   </refsynopsisdiv>
   
--- 44,50 ----
            [ CSV [ HEADER ]
                  [ QUOTE [ AS ] '<replaceable class="parameter">quote</replaceable>' ] 
                  [ ESCAPE [ AS ] '<replaceable class="parameter">escape</replaceable>' ]
!                 [ FORCE QUOTE { <replaceable class="parameter">column</replaceable> [, ...] | * } ]
  </synopsis>
   </refsynopsisdiv>
   
*************** COPY { <replaceable class="parameter">ta
*** 248,254 ****
       <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.
       </para>
      </listitem>
     </varlistentry>
--- 248,255 ----
       <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. If * is specified, all
!       columns of the table will be quoted.
       </para>
      </listitem>
     </varlistentry>
diff -cpr HEAD/src/backend/commands/copy.c force_quote_all/src/backend/commands/copy.c
*** HEAD/src/backend/commands/copy.c	Fri Jul 17 12:49:09 2009
--- force_quote_all/src/backend/commands/copy.c	Fri Jul 17 12:49:46 2009
*************** DoCopy(const CopyStmt *stmt, const char 
*** 730,735 ****
--- 730,738 ----
  	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));
  
*************** DoCopy(const CopyStmt *stmt, const char 
*** 809,814 ****
--- 812,821 ----
  						(errcode(ERRCODE_SYNTAX_ERROR),
  						 errmsg("conflicting or redundant options")));
  			force_quote = (List *) defel->arg;
+ 
+ 			/* NIL means all-columns */
+ 			if (force_quote == NIL)
+ 				force_quote = &all_columns;
  		}
  		else if (strcmp(defel->defname, "force_notnull") == 0)
  		{
*************** DoCopy(const CopyStmt *stmt, const char 
*** 1092,1098 ****
  
  	/* 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)
  	{
  		List	   *attnums;
  		ListCell   *cur;
--- 1099,1112 ----
  
  	/* 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 == &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 -cpr HEAD/src/backend/parser/gram.y force_quote_all/src/backend/parser/gram.y
*** HEAD/src/backend/parser/gram.y	Fri Jul 17 12:49:09 2009
--- force_quote_all/src/backend/parser/gram.y	Fri Jul 17 12:49:46 2009
*************** copy_opt_item:
*** 2006,2011 ****
--- 2006,2015 ----
  				{
  					$$ = makeDefElem("force_quote", (Node *)$3);
  				}
+ 			| FORCE QUOTE '*'
+ 				{
+ 					$$ = makeDefElem("force_quote", NULL);
+ 				}
  			| FORCE NOT NULL_P columnList
  				{
  					$$ = makeDefElem("force_notnull", (Node *)$4);
diff -cpr HEAD/src/test/regress/expected/copy2.out force_quote_all/src/test/regress/expected/copy2.out
*** HEAD/src/test/regress/expected/copy2.out	Fri Jul 17 12:49:09 2009
--- force_quote_all/src/test/regress/expected/copy2.out	Fri Jul 17 12:49:46 2009
*************** COPY y TO stdout WITH CSV FORCE QUOTE co
*** 191,196 ****
--- 191,200 ----
  "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 -cpr HEAD/src/test/regress/sql/copy2.sql force_quote_all/src/test/regress/sql/copy2.sql
*** HEAD/src/test/regress/sql/copy2.sql	Fri Jul 17 12:49:09 2009
--- force_quote_all/src/test/regress/sql/copy2.sql	Fri Jul 17 12:49:46 2009
*************** INSERT INTO y VALUES ('', NULL);
*** 128,133 ****
--- 128,134 ----
  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
  
