Commit 49d3d9cf authored by Bruce Momjian's avatar Bruce Momjian

Change COPY CSV keyword to be:

	FORCE QUOTE to force quotes
	FORCE NOT NULL to quote null input values
parent 2d1221bf
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/copy.sgml,v 1.56 2004/04/19 17:22:30 momjian Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/copy.sgml,v 1.57 2004/04/21 00:34:18 momjian Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -29,7 +29,7 @@ COPY <replaceable class="parameter">tablename</replaceable> [ ( <replaceable cla ...@@ -29,7 +29,7 @@ COPY <replaceable class="parameter">tablename</replaceable> [ ( <replaceable cla
[ NULL [ AS ] '<replaceable class="parameter">null string</replaceable>' ] [ NULL [ AS ] '<replaceable class="parameter">null string</replaceable>' ]
[ CSV [ QUOTE [ AS ] '<replaceable class="parameter">quote</replaceable>' ] [ CSV [ QUOTE [ AS ] '<replaceable class="parameter">quote</replaceable>' ]
[ ESCAPE [ AS ] '<replaceable class="parameter">escape</replaceable>' ] [ ESCAPE [ AS ] '<replaceable class="parameter">escape</replaceable>' ]
[ LITERAL <replaceable class="parameter">column</replaceable> [, ...] ] [ FORCE NOT NULL <replaceable class="parameter">column</replaceable> [, ...] ]
COPY <replaceable class="parameter">tablename</replaceable> [ ( <replaceable class="parameter">column</replaceable> [, ...] ) ] COPY <replaceable class="parameter">tablename</replaceable> [ ( <replaceable class="parameter">column</replaceable> [, ...] ) ]
TO { '<replaceable class="parameter">filename</replaceable>' | STDOUT } TO { '<replaceable class="parameter">filename</replaceable>' | STDOUT }
...@@ -40,7 +40,7 @@ COPY <replaceable class="parameter">tablename</replaceable> [ ( <replaceable cla ...@@ -40,7 +40,7 @@ COPY <replaceable class="parameter">tablename</replaceable> [ ( <replaceable cla
[ NULL [ AS ] '<replaceable class="parameter">null string</replaceable>' ] [ NULL [ AS ] '<replaceable class="parameter">null string</replaceable>' ]
[ CSV [ QUOTE [ AS ] '<replaceable class="parameter">quote</replaceable>' ] [ CSV [ QUOTE [ AS ] '<replaceable class="parameter">quote</replaceable>' ]
[ ESCAPE [ AS ] '<replaceable class="parameter">escape</replaceable>' ] [ ESCAPE [ AS ] '<replaceable class="parameter">escape</replaceable>' ]
[ FORCE <replaceable class="parameter">column</replaceable> [, ...] ] [ FORCE QUOTE <replaceable class="parameter">column</replaceable> [, ...] ]
</synopsis> </synopsis>
</refsynopsisdiv> </refsynopsisdiv>
...@@ -185,10 +185,10 @@ COPY <replaceable class="parameter">tablename</replaceable> [ ( <replaceable cla ...@@ -185,10 +185,10 @@ COPY <replaceable class="parameter">tablename</replaceable> [ ( <replaceable cla
<term><literal>CSV</literal></term> <term><literal>CSV</literal></term>
<listitem> <listitem>
<para> <para>
Enables Comma Separated Variable (<literal>CSV</>) mode. (Also called Enables Comma Separated Variable (<literal>CSV</>) mode. (Also
Comma Separated Value). It sets the default <literal>DELIMITER</> to called Comma Separated Value). It sets the default
comma, and <literal>QUOTE</> and <literal>ESCAPE</> values to <literal>DELIMITER</> to comma, and <literal>QUOTE</> and
double-quote. <literal>ESCAPE</> values to double-quote.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -207,38 +207,33 @@ COPY <replaceable class="parameter">tablename</replaceable> [ ( <replaceable cla ...@@ -207,38 +207,33 @@ COPY <replaceable class="parameter">tablename</replaceable> [ ( <replaceable cla
<term><replaceable class="parameter">escape</replaceable></term> <term><replaceable class="parameter">escape</replaceable></term>
<listitem> <listitem>
<para> <para>
Specifies the character that should appear before a <literal>QUOTE</> Specifies the character that should appear before a
data character value in <literal>CSV</> mode. The default is the <literal>QUOTE</> data character value in <literal>CSV</> mode.
<literal>QUOTE</> value (usually double-quote). The default is the <literal>QUOTE</> value (usually double-quote).
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><literal>FORCE</></term> <term><literal>FORCE QUOTE</></term>
<listitem> <listitem>
<para> <para>
In <literal>CSV</> <command>COPY TO</> mode, forces quoting In <literal>CSV</> <command>COPY TO</> mode, forces quoting to be
to be used for all non-<literal>NULL</> values in each specified used for all non-<literal>NULL</> values in each specified column.
column. <literal>NULL</> output is never quoted. <literal>NULL</> output is never quoted.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><literal>LITERAL</></term> <term><literal>FORCE NOT NULL</></term>
<listitem> <listitem>
<para> <para>
In <literal>CSV</> <command>COPY FROM</> mode, for each column specified, In <literal>CSV</> <command>COPY FROM</> mode, process each
do not do a <literal>null string</> comparison; instead load the value specified column as though it were quoted and hance not a
literally. <literal>QUOTE</> and <literal>ESCAPE</> processing are still <literal>NULL</> value. For the default <literal>null string</> in
performed. <literal>CSV</> mode (<literal>''</>), this causes a missing
</para> values to be input as a zero-length strings.
<para>
If the <literal>null string</> is <literal>''</> (the default
in <literal>CSV</> mode), a missing input value (<literal>delimiter,
delimiter</>), will load as a zero-length string. <literal>Delimiter, quote,
quote, delimiter</> is always treated as a zero-length string on input.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -483,7 +478,7 @@ COPY <replaceable class="parameter">tablename</replaceable> [ ( <replaceable cla ...@@ -483,7 +478,7 @@ COPY <replaceable class="parameter">tablename</replaceable> [ ( <replaceable cla
suffixed by the <literal>QUOTE</> character, and any occurrence suffixed by the <literal>QUOTE</> character, and any occurrence
within the value of a <literal>QUOTE</> character or the within the value of a <literal>QUOTE</> character or the
<literal>ESCAPE</> character is preceded by the escape character. <literal>ESCAPE</> character is preceded by the escape character.
You can also use <literal>FORCE</> to force quotes when outputting You can also use <literal>FORCE QUOTE</> to force quotes when outputting
non-<literal>NULL</> values in specific columns. non-<literal>NULL</> values in specific columns.
</para> </para>
...@@ -496,7 +491,7 @@ COPY <replaceable class="parameter">tablename</replaceable> [ ( <replaceable cla ...@@ -496,7 +491,7 @@ COPY <replaceable class="parameter">tablename</replaceable> [ ( <replaceable cla
is quoted. Therefore, using the default settings, a <literal>NULL</> is is quoted. Therefore, using the default settings, a <literal>NULL</> is
written as an unquoted empty string, while an empty string is written as an unquoted empty string, while an empty string is
written with double quotes (<literal>""</>). Reading values follows written with double quotes (<literal>""</>). Reading values follows
similar rules. You can use <literal>LITERAL</> to prevent <literal>NULL</> similar rules. You can use <literal>FORCE NOT NULL</> to prevent <literal>NULL</>
input comparisons for specific columns. input comparisons for specific columns.
</para> </para>
......
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.111 2004/04/19 17:22:30 momjian Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.112 2004/04/21 00:34:18 momjian Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -713,8 +713,8 @@ testdb=> ...@@ -713,8 +713,8 @@ testdb=>
[ <literal>null [as] </literal> '<replaceable class="parameter">string</replaceable>' ]</literal> [ <literal>null [as] </literal> '<replaceable class="parameter">string</replaceable>' ]</literal>
[ <literal>csv [ quote [as] </literal> '<replaceable class="parameter">character</replaceable>' ] [ <literal>csv [ quote [as] </literal> '<replaceable class="parameter">character</replaceable>' ]
[ <literal>escape [as] </literal> '<replaceable class="parameter">character</replaceable>' ] [ <literal>escape [as] </literal> '<replaceable class="parameter">character</replaceable>' ]
[ <literal>force</> <replaceable class="parameter">column_list</replaceable> ] [ <literal>force quote</> <replaceable class="parameter">column_list</replaceable> ]
[ <literal>literal</> <replaceable class="parameter">column_list</replaceable> ] ] [ <literal>force not null</> <replaceable class="parameter">column_list</replaceable> ] ]
</term> </term>
<listitem> <listitem>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.222 2004/04/19 21:58:02 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.223 2004/04/21 00:34:18 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -132,10 +132,10 @@ static bool line_buf_converted; ...@@ -132,10 +132,10 @@ static bool line_buf_converted;
/* non-export function prototypes */ /* non-export function prototypes */
static void CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, static void CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
char *delim, char *null_print, bool csv_mode, char *quote, char *escape, char *delim, char *null_print, bool csv_mode, char *quote, char *escape,
List *force_atts); List *force_quote_atts);
static void CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, static void CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
char *delim, char *null_print, bool csv_mode, char *quote, char *escape, char *delim, char *null_print, bool csv_mode, char *quote, char *escape,
List *literal_atts); List *force_notnull_atts);
static bool CopyReadLine(void); static bool CopyReadLine(void);
static char *CopyReadAttribute(const char *delim, const char *null_print, static char *CopyReadAttribute(const char *delim, const char *null_print,
CopyReadResult *result, bool *isnull); CopyReadResult *result, bool *isnull);
...@@ -695,10 +695,10 @@ DoCopy(const CopyStmt *stmt) ...@@ -695,10 +695,10 @@ DoCopy(const CopyStmt *stmt)
char *quote = NULL; char *quote = NULL;
char *escape = NULL; char *escape = NULL;
char *null_print = NULL; char *null_print = NULL;
List *force = NIL; List *force_quote = NIL;
List *literal = NIL; List *force_notnull = NIL;
List *force_atts = NIL; List *force_quote_atts = NIL;
List *literal_atts = NIL; List *force_notnull_atts = NIL;
Relation rel; Relation rel;
AclMode required_access = (is_from ? ACL_INSERT : ACL_SELECT); AclMode required_access = (is_from ? ACL_INSERT : ACL_SELECT);
AclResult aclresult; AclResult aclresult;
...@@ -764,21 +764,21 @@ DoCopy(const CopyStmt *stmt) ...@@ -764,21 +764,21 @@ DoCopy(const CopyStmt *stmt)
errmsg("conflicting or redundant options"))); errmsg("conflicting or redundant options")));
escape = strVal(defel->arg); escape = strVal(defel->arg);
} }
else if (strcmp(defel->defname, "force") == 0) else if (strcmp(defel->defname, "force_quote") == 0)
{ {
if (force) if (force_quote)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options"))); errmsg("conflicting or redundant options")));
force = (List *)defel->arg; force_quote = (List *)defel->arg;
} }
else if (strcmp(defel->defname, "literal") == 0) else if (strcmp(defel->defname, "force_notnull") == 0)
{ {
if (literal) if (force_notnull)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options"))); errmsg("conflicting or redundant options")));
literal = (List *)defel->arg; force_notnull = (List *)defel->arg;
} }
else else
elog(ERROR, "option \"%s\" not recognized", elog(ERROR, "option \"%s\" not recognized",
...@@ -850,28 +850,28 @@ DoCopy(const CopyStmt *stmt) ...@@ -850,28 +850,28 @@ DoCopy(const CopyStmt *stmt)
errmsg("COPY escape must be a single character"))); errmsg("COPY escape must be a single character")));
/* /*
* Check force * Check force_quote
*/ */
if (!csv_mode && force != NIL) if (!csv_mode && force_quote != NIL)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("COPY force available only in CSV mode"))); errmsg("COPY force quote available only in CSV mode")));
if (force != NIL && is_from) if (force_quote != NIL && is_from)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("COPY force only available using COPY TO"))); errmsg("COPY force quote only available using COPY TO")));
/* /*
* Check literal * Check force_notnull
*/ */
if (!csv_mode && literal != NIL) if (!csv_mode && force_notnull != NIL)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("COPY literal available only in CSV mode"))); errmsg("COPY force not null available only in CSV mode")));
if (literal != NIL && !is_from) if (force_notnull != NIL && !is_from)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("COPY literal only available using COPY FROM"))); errmsg("COPY force not null only available using COPY FROM")));
/* /*
* Don't allow the delimiter to appear in the null string. * Don't allow the delimiter to appear in the null string.
...@@ -928,47 +928,47 @@ DoCopy(const CopyStmt *stmt) ...@@ -928,47 +928,47 @@ DoCopy(const CopyStmt *stmt)
attnumlist = CopyGetAttnums(rel, attnamelist); attnumlist = CopyGetAttnums(rel, attnamelist);
/* /*
* Check that FORCE references valid COPY columns * Check that FORCE QUOTE references valid COPY columns
*/ */
if (force) if (force_quote)
{ {
TupleDesc tupDesc = RelationGetDescr(rel); TupleDesc tupDesc = RelationGetDescr(rel);
Form_pg_attribute *attr = tupDesc->attrs; Form_pg_attribute *attr = tupDesc->attrs;
List *cur; List *cur;
force_atts = CopyGetAttnums(rel, force); force_quote_atts = CopyGetAttnums(rel, force_quote);
foreach(cur, force_atts) foreach(cur, force_quote_atts)
{ {
int attnum = lfirsti(cur); int attnum = lfirsti(cur);
if (!intMember(attnum, attnumlist)) if (!intMember(attnum, attnumlist))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE), (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("FORCE column \"%s\" not referenced by COPY", errmsg("FORCE QUOTE column \"%s\" not referenced by COPY",
NameStr(attr[attnum - 1]->attname)))); NameStr(attr[attnum - 1]->attname))));
} }
} }
/* /*
* Check that LITERAL references valid COPY columns * Check that FORCE NOT NULL references valid COPY columns
*/ */
if (literal) if (force_notnull)
{ {
List *cur; List *cur;
TupleDesc tupDesc = RelationGetDescr(rel); TupleDesc tupDesc = RelationGetDescr(rel);
Form_pg_attribute *attr = tupDesc->attrs; Form_pg_attribute *attr = tupDesc->attrs;
literal_atts = CopyGetAttnums(rel, literal); force_notnull_atts = CopyGetAttnums(rel, force_notnull);
foreach(cur, literal_atts) foreach(cur, force_notnull_atts)
{ {
int attnum = lfirsti(cur); int attnum = lfirsti(cur);
if (!intMember(attnum, attnumlist)) if (!intMember(attnum, attnumlist))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE), (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("LITERAL column \"%s\" not referenced by COPY", errmsg("FORCE NOT NULL column \"%s\" not referenced by COPY",
NameStr(attr[attnum - 1]->attname)))); NameStr(attr[attnum - 1]->attname))));
} }
} }
...@@ -1037,7 +1037,7 @@ DoCopy(const CopyStmt *stmt) ...@@ -1037,7 +1037,7 @@ DoCopy(const CopyStmt *stmt)
} }
} }
CopyFrom(rel, attnumlist, binary, oids, delim, null_print, csv_mode, CopyFrom(rel, attnumlist, binary, oids, delim, null_print, csv_mode,
quote, escape, literal_atts); quote, escape, force_notnull_atts);
} }
else else
{ /* copy from database to file */ { /* copy from database to file */
...@@ -1100,7 +1100,7 @@ DoCopy(const CopyStmt *stmt) ...@@ -1100,7 +1100,7 @@ DoCopy(const CopyStmt *stmt)
} }
} }
CopyTo(rel, attnumlist, binary, oids, delim, null_print, csv_mode, CopyTo(rel, attnumlist, binary, oids, delim, null_print, csv_mode,
quote, escape, force_atts); quote, escape, force_quote_atts);
} }
if (!pipe) if (!pipe)
...@@ -1133,7 +1133,7 @@ DoCopy(const CopyStmt *stmt) ...@@ -1133,7 +1133,7 @@ DoCopy(const CopyStmt *stmt)
static void static void
CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
char *delim, char *null_print, bool csv_mode, char *quote, char *delim, char *null_print, bool csv_mode, char *quote,
char *escape, List *force_atts) char *escape, List *force_quote_atts)
{ {
HeapTuple tuple; HeapTuple tuple;
TupleDesc tupDesc; TupleDesc tupDesc;
...@@ -1180,7 +1180,7 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, ...@@ -1180,7 +1180,7 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
&isvarlena[attnum - 1]); &isvarlena[attnum - 1]);
fmgr_info(out_func_oid, &out_functions[attnum - 1]); fmgr_info(out_func_oid, &out_functions[attnum - 1]);
if (intMember(attnum, force_atts)) if (intMember(attnum, force_quote_atts))
force_quote[attnum - 1] = true; force_quote[attnum - 1] = true;
else else
force_quote[attnum - 1] = false; force_quote[attnum - 1] = false;
...@@ -1434,7 +1434,7 @@ limit_printout_length(StringInfo buf) ...@@ -1434,7 +1434,7 @@ limit_printout_length(StringInfo buf)
static void static void
CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
char *delim, char *null_print, bool csv_mode, char *quote, char *delim, char *null_print, bool csv_mode, char *quote,
char *escape, List *literal_atts) char *escape, List *force_notnull_atts)
{ {
HeapTuple tuple; HeapTuple tuple;
TupleDesc tupDesc; TupleDesc tupDesc;
...@@ -1447,7 +1447,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, ...@@ -1447,7 +1447,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
Oid *elements; Oid *elements;
Oid oid_in_element; Oid oid_in_element;
ExprState **constraintexprs; ExprState **constraintexprs;
bool *literal_nullstr; bool *force_notnull;
bool hasConstraints = false; bool hasConstraints = false;
int attnum; int attnum;
int i; int i;
...@@ -1509,7 +1509,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, ...@@ -1509,7 +1509,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
defmap = (int *) palloc((num_phys_attrs + 1) * sizeof(int)); defmap = (int *) palloc((num_phys_attrs + 1) * sizeof(int));
defexprs = (ExprState **) palloc((num_phys_attrs + 1) * sizeof(ExprState *)); defexprs = (ExprState **) palloc((num_phys_attrs + 1) * sizeof(ExprState *));
constraintexprs = (ExprState **) palloc0((num_phys_attrs + 1) * sizeof(ExprState *)); constraintexprs = (ExprState **) palloc0((num_phys_attrs + 1) * sizeof(ExprState *));
literal_nullstr = (bool *) palloc((num_phys_attrs + 1) * sizeof(bool)); force_notnull = (bool *) palloc((num_phys_attrs + 1) * sizeof(bool));
for (attnum = 1; attnum <= num_phys_attrs; attnum++) for (attnum = 1; attnum <= num_phys_attrs; attnum++)
{ {
...@@ -1526,10 +1526,10 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, ...@@ -1526,10 +1526,10 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
&in_func_oid, &elements[attnum - 1]); &in_func_oid, &elements[attnum - 1]);
fmgr_info(in_func_oid, &in_functions[attnum - 1]); fmgr_info(in_func_oid, &in_functions[attnum - 1]);
if (intMember(attnum, literal_atts)) if (intMember(attnum, force_notnull_atts))
literal_nullstr[attnum - 1] = true; force_notnull[attnum - 1] = true;
else else
literal_nullstr[attnum - 1] = false; force_notnull[attnum - 1] = false;
/* Get default info if needed */ /* Get default info if needed */
if (!intMember(attnum, attnumlist)) if (!intMember(attnum, attnumlist))
...@@ -1748,7 +1748,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, ...@@ -1748,7 +1748,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
string = CopyReadAttribute(delim, null_print, string = CopyReadAttribute(delim, null_print,
&result, &isnull); &result, &isnull);
if (csv_mode && isnull && literal_nullstr[m]) if (csv_mode && isnull && force_notnull[m])
{ {
string = null_print; /* set to NULL string */ string = null_print; /* set to NULL string */
isnull = false; isnull = false;
...@@ -1947,7 +1947,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, ...@@ -1947,7 +1947,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
pfree(defmap); pfree(defmap);
pfree(defexprs); pfree(defexprs);
pfree(constraintexprs); pfree(constraintexprs);
pfree(literal_nullstr); pfree(force_notnull);
ExecDropTupleTable(tupleTable, true); ExecDropTupleTable(tupleTable, true);
...@@ -2558,14 +2558,13 @@ CopyAttributeOut(char *server_string, char *delim) ...@@ -2558,14 +2558,13 @@ CopyAttributeOut(char *server_string, char *delim)
*/ */
static void static void
CopyAttributeOutCSV(char *server_string, char *delim, char *quote, CopyAttributeOutCSV(char *server_string, char *delim, char *quote,
char *escape, bool force_quote) char *escape, bool use_quote)
{ {
char *string; char *string;
char c; char c;
char delimc = delim[0]; char delimc = delim[0];
char quotec = quote[0]; char quotec = quote[0];
char escapec = escape[0]; char escapec = escape[0];
bool need_quote = force_quote;
char *test_string; char *test_string;
bool same_encoding; bool same_encoding;
int mblen; int mblen;
...@@ -2583,23 +2582,23 @@ CopyAttributeOutCSV(char *server_string, char *delim, char *quote, ...@@ -2583,23 +2582,23 @@ CopyAttributeOutCSV(char *server_string, char *delim, char *quote,
*/ */
for(test_string = string; for(test_string = string;
!need_quote && (c = *test_string) != '\0'; !use_quote && (c = *test_string) != '\0';
test_string += mblen) test_string += mblen)
{ {
if (c == delimc || c == quotec || c == '\n' || c == '\r') if (c == delimc || c == quotec || c == '\n' || c == '\r')
need_quote = true; use_quote = true;
if (!same_encoding) if (!same_encoding)
mblen = pg_encoding_mblen(client_encoding, test_string); mblen = pg_encoding_mblen(client_encoding, test_string);
else else
mblen = 1; mblen = 1;
} }
if (need_quote) if (use_quote)
CopySendChar(quotec); CopySendChar(quotec);
for (; (c = *string) != '\0'; string += mblen) for (; (c = *string) != '\0'; string += mblen)
{ {
if (need_quote && (c == quotec || c == escapec)) if (use_quote && (c == quotec || c == escapec))
CopySendChar(escapec); CopySendChar(escapec);
CopySendChar(c); CopySendChar(c);
...@@ -2615,7 +2614,7 @@ CopyAttributeOutCSV(char *server_string, char *delim, char *quote, ...@@ -2615,7 +2614,7 @@ CopyAttributeOutCSV(char *server_string, char *delim, char *quote,
mblen = 1; mblen = 1;
} }
if (need_quote) if (use_quote)
CopySendChar(quotec); CopySendChar(quotec);
} }
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.451 2004/04/19 17:22:30 momjian Exp $ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.452 2004/04/21 00:34:18 momjian Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -370,7 +370,7 @@ static void doNegateFloat(Value *v); ...@@ -370,7 +370,7 @@ static void doNegateFloat(Value *v);
KEY KEY
LANCOMPILER LANGUAGE LARGE_P LAST_P LEADING LEFT LEVEL LIKE LIMIT LANCOMPILER LANGUAGE LARGE_P LAST_P LEADING LEFT LEVEL LIKE LIMIT
LISTEN LITERAL LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
LOCK_P LOCK_P
MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
...@@ -1374,13 +1374,13 @@ copy_opt_item: ...@@ -1374,13 +1374,13 @@ copy_opt_item:
{ {
$$ = makeDefElem("escape", (Node *)makeString($3)); $$ = makeDefElem("escape", (Node *)makeString($3));
} }
| FORCE columnList | FORCE QUOTE columnList
{ {
$$ = makeDefElem("force", (Node *)$2); $$ = makeDefElem("force_quote", (Node *)$3);
} }
| LITERAL columnList | FORCE NOT NULL_P columnList
{ {
$$ = makeDefElem("literal", (Node *)$2); $$ = makeDefElem("force_notnull", (Node *)$4);
} }
; ;
...@@ -7496,7 +7496,6 @@ unreserved_keyword: ...@@ -7496,7 +7496,6 @@ unreserved_keyword:
| LAST_P | LAST_P
| LEVEL | LEVEL
| LISTEN | LISTEN
| LITERAL
| LOAD | LOAD
| LOCAL | LOCAL
| LOCATION | LOCATION
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.148 2004/04/19 17:22:31 momjian Exp $ * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.149 2004/04/21 00:34:18 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -187,7 +187,6 @@ static const ScanKeyword ScanKeywords[] = { ...@@ -187,7 +187,6 @@ static const ScanKeyword ScanKeywords[] = {
{"like", LIKE}, {"like", LIKE},
{"limit", LIMIT}, {"limit", LIMIT},
{"listen", LISTEN}, {"listen", LISTEN},
{"literal", LITERAL},
{"load", LOAD}, {"load", LOAD},
{"local", LOCAL}, {"local", LOCAL},
{"localtime", LOCALTIME}, {"localtime", LOCALTIME},
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Copyright (c) 2000-2003, PostgreSQL Global Development Group * Copyright (c) 2000-2003, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/bin/psql/copy.c,v 1.45 2004/04/19 17:42:58 momjian Exp $ * $PostgreSQL: pgsql/src/bin/psql/copy.c,v 1.46 2004/04/21 00:34:18 momjian Exp $
*/ */
#include "postgres_fe.h" #include "postgres_fe.h"
#include "copy.h" #include "copy.h"
...@@ -71,8 +71,8 @@ struct copy_options ...@@ -71,8 +71,8 @@ struct copy_options
char *null; char *null;
char *quote; char *quote;
char *escape; char *escape;
char *force_list; char *force_quote_list;
char *literal_list; char *force_notnull_list;
}; };
...@@ -88,8 +88,8 @@ free_copy_options(struct copy_options * ptr) ...@@ -88,8 +88,8 @@ free_copy_options(struct copy_options * ptr)
free(ptr->null); free(ptr->null);
free(ptr->quote); free(ptr->quote);
free(ptr->escape); free(ptr->escape);
free(ptr->force_list); free(ptr->force_quote_list);
free(ptr->literal_list); free(ptr->force_notnull_list);
free(ptr); free(ptr);
} }
...@@ -344,45 +344,56 @@ parse_slash_copy(const char *args) ...@@ -344,45 +344,56 @@ parse_slash_copy(const char *args)
} }
else if (strcasecmp(token, "force") == 0) else if (strcasecmp(token, "force") == 0)
{ {
/* handle column list */ token = strtokx(NULL, whitespace, ",", "\"",
fetch_next = false; 0, false, pset.encoding);
for (;;) if (strcasecmp(token, "quote") == 0)
{ {
token = strtokx(NULL, whitespace, ",", "\"", /* handle column list */
0, false, pset.encoding); fetch_next = false;
if (!token || strchr(",", token[0])) for (;;)
goto error; {
if (!result->force_list) token = strtokx(NULL, whitespace, ",", "\"",
result->force_list = pg_strdup(token); 0, false, pset.encoding);
else if (!token || strchr(",", token[0]))
xstrcat(&result->force_list, token); goto error;
token = strtokx(NULL, whitespace, ",", "\"", if (!result->force_quote_list)
0, false, pset.encoding); result->force_quote_list = pg_strdup(token);
if (!token || token[0] != ',') else
break; xstrcat(&result->force_quote_list, token);
xstrcat(&result->force_list, token); token = strtokx(NULL, whitespace, ",", "\"",
0, false, pset.encoding);
if (!token || token[0] != ',')
break;
xstrcat(&result->force_quote_list, token);
}
} }
} else if (strcasecmp(token, "not") == 0)
else if (strcasecmp(token, "literal") == 0)
{
/* handle column list */
fetch_next = false;
for (;;)
{ {
token = strtokx(NULL, whitespace, ",", "\"", token = strtokx(NULL, whitespace, ",", "\"",
0, false, pset.encoding); 0, false, pset.encoding);
if (!token || strchr(",", token[0])) if (strcasecmp(token, "null") != 0)
goto error; goto error;
if (!result->literal_list) /* handle column list */
result->literal_list = pg_strdup(token); fetch_next = false;
else for (;;)
xstrcat(&result->literal_list, token); {
token = strtokx(NULL, whitespace, ",", "\"", token = strtokx(NULL, whitespace, ",", "\"",
0, false, pset.encoding); 0, false, pset.encoding);
if (!token || token[0] != ',') if (!token || strchr(",", token[0]))
break; goto error;
xstrcat(&result->literal_list, token); if (!result->force_notnull_list)
result->force_notnull_list = pg_strdup(token);
else
xstrcat(&result->force_notnull_list, token);
token = strtokx(NULL, whitespace, ",", "\"",
0, false, pset.encoding);
if (!token || token[0] != ',')
break;
xstrcat(&result->force_notnull_list, token);
}
} }
else
goto error;
} }
else else
goto error; goto error;
...@@ -493,14 +504,14 @@ do_copy(const char *args) ...@@ -493,14 +504,14 @@ do_copy(const char *args)
appendPQExpBuffer(&query, " ESCAPE AS '%s'", options->escape); appendPQExpBuffer(&query, " ESCAPE AS '%s'", options->escape);
} }
if (options->force_list) if (options->force_quote_list)
{ {
appendPQExpBuffer(&query, " FORCE %s", options->force_list); appendPQExpBuffer(&query, " FORCE QUOTE %s", options->force_quote_list);
} }
if (options->literal_list) if (options->force_notnull_list)
{ {
appendPQExpBuffer(&query, " LITERAL %s", options->literal_list); appendPQExpBuffer(&query, " FORCE NOT NULL %s", options->force_notnull_list);
} }
if (options->from) if (options->from)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment