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	Mon Feb  9 09:25:51 2009
--- force_quote_all/doc/src/sgml/ref/copy.sgml	Tue Jul 14 16:23:12 2009
*************** COPY <replaceable class="parameter">tabl
*** 32,38 ****
            [ CSV [ HEADER ]
                  [ QUOTE [ AS ] '<replaceable class="parameter">quote</replaceable>' ] 
                  [ ESCAPE [ AS ] '<replaceable class="parameter">escape</replaceable>' ]
!                 [ FORCE NOT NULL <replaceable class="parameter">column</replaceable> [, ...] ]
  
  COPY { <replaceable class="parameter">tablename</replaceable> [ ( <replaceable class="parameter">column</replaceable> [, ...] ) ] | ( <replaceable class="parameter">query</replaceable> ) }
      TO { '<replaceable class="parameter">filename</replaceable>' | STDOUT }
--- 32,38 ----
            [ CSV [ HEADER ]
                  [ QUOTE [ AS ] '<replaceable class="parameter">quote</replaceable>' ] 
                  [ ESCAPE [ AS ] '<replaceable class="parameter">escape</replaceable>' ]
!                 [ FORCE NOT NULL { <replaceable class="parameter">column</replaceable> [, ...] | * } ]
  
  COPY { <replaceable class="parameter">tablename</replaceable> [ ( <replaceable class="parameter">column</replaceable> [, ...] ) ] | ( <replaceable class="parameter">query</replaceable> ) }
      TO { '<replaceable class="parameter">filename</replaceable>' | STDOUT }
*************** 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>
*************** COPY { <replaceable class="parameter">ta
*** 261,267 ****
        specified column as though it were quoted and hence not a
        <literal>NULL</> value. For the default null string in
        <literal>CSV</> mode (<literal>''</>), this causes missing
!       values to be input as zero-length strings.
       </para>
      </listitem>
     </varlistentry>
--- 262,269 ----
        specified column as though it were quoted and hence not a
        <literal>NULL</> value. For the default null string in
        <literal>CSV</> mode (<literal>''</>), this causes missing
!       values to be input as zero-length strings. If * is specified,
!       all columns of the table will be not nulls.
       </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 Jun 12 09:52:43 2009
--- force_quote_all/src/backend/commands/copy.c	Tue Jul 14 16:23:12 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 
*** 817,822 ****
--- 824,833 ----
  						(errcode(ERRCODE_SYNTAX_ERROR),
  						 errmsg("conflicting or redundant options")));
  			force_notnull = (List *) defel->arg;
+ 
+ 			/* NIL means all-columns */
+ 			if (force_notnull == NIL)
+ 				force_notnull = &all_columns;
  		}
  		else
  			elog(ERROR, "option \"%s\" not recognized",
*************** 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;
--- 1103,1116 ----
  
  	/* 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;
*************** DoCopy(const CopyStmt *stmt, const char 
*** 1114,1120 ****
  
  	/* Convert FORCE NOT NULL name list to per-column flags, check validity */
  	cstate->force_notnull_flags = (bool *) palloc0(num_phys_attrs * sizeof(bool));
! 	if (force_notnull)
  	{
  		List	   *attnums;
  		ListCell   *cur;
--- 1132,1145 ----
  
  	/* Convert FORCE NOT NULL name list to per-column flags, check validity */
  	cstate->force_notnull_flags = (bool *) palloc0(num_phys_attrs * sizeof(bool));
! 	if (force_notnull == &all_columns)
! 	{
! 		int		i;
! 
! 		for (i = 0; i < num_phys_attrs; i++)
! 			cstate->force_notnull_flags[i] = true;
! 	}
! 	else if (force_notnull)
  	{
  		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	Tue Jul 14 09:36:59 2009
--- force_quote_all/src/backend/parser/gram.y	Tue Jul 14 16:23:12 2009
*************** copy_opt_item:
*** 1995,2003 ****
--- 1995,2011 ----
  				{
  					$$ = makeDefElem("force_quote", (Node *)$3);
  				}
+ 			| FORCE QUOTE '*'
+ 				{
+ 					$$ = makeDefElem("force_quote", NULL);
+ 				}
  			| FORCE NOT NULL_P columnList
  				{
  					$$ = makeDefElem("force_notnull", (Node *)$4);
+ 				}
+ 			| FORCE NOT NULL_P '*'
+ 				{
+ 					$$ = makeDefElem("force_notnull", NULL);
  				}
  		;
  
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	Mon Jun 15 09:50:34 2009
--- force_quote_all/src/test/regress/expected/copy2.out	Tue Jul 14 16:23:12 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	Mon Jun 15 09:50:34 2009
--- force_quote_all/src/test/regress/sql/copy2.sql	Tue Jul 14 16:23:12 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
  
