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 { ta *** 44,50 **** [ CSV [ HEADER ] [ QUOTE [ AS ] 'quote' ] [ ESCAPE [ AS ] 'escape' ] ! [ FORCE QUOTE column [, ...] ] --- 44,50 ---- [ CSV [ HEADER ] [ QUOTE [ AS ] 'quote' ] [ ESCAPE [ AS ] 'escape' ] ! [ FORCE QUOTE { column [, ...] | * } ] *************** COPY { ta *** 248,254 **** In CSV COPY TO mode, forces quoting to be used for all non-NULL values in each specified column. ! NULL output is never quoted. --- 248,255 ---- In CSV COPY TO mode, forces quoting to be used for all non-NULL values in each specified column. ! NULL output is never quoted. If * is specified, all ! columns of the table will be quoted. 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