CSV keyword change - Mailing list pgsql-patches
From | Bruce Momjian |
---|---|
Subject | CSV keyword change |
Date | |
Msg-id | 200404210035.i3L0ZaC10890@candle.pha.pa.us Whole thread Raw |
List | pgsql-patches |
I just changed the COPY CSV keywords: FORCE QUOTE to force quotes FORCE NOT NULL to quote null input values Patch attached. -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania 19073 Index: doc/src/sgml/ref/copy.sgml =================================================================== RCS file: /cvsroot/pgsql-server/doc/src/sgml/ref/copy.sgml,v retrieving revision 1.56 diff -c -c -r1.56 copy.sgml *** doc/src/sgml/ref/copy.sgml 19 Apr 2004 17:22:30 -0000 1.56 --- doc/src/sgml/ref/copy.sgml 21 Apr 2004 00:17:51 -0000 *************** *** 29,35 **** [ NULL [ AS ] '<replaceable class="parameter">null string</replaceable>' ] [ CSV [ QUOTE [ AS ] '<replaceable class="parameter">quote</replaceable>' ] [ ESCAPE [ AS ] '<replaceable class="parameter">escape</replaceable>' ] ! [ LITERAL <replaceable class="parameter">column</replaceable> [, ...] ] COPY <replaceable class="parameter">tablename</replaceable> [ ( <replaceable class="parameter">column</replaceable> [,...] ) ] TO { '<replaceable class="parameter">filename</replaceable>' | STDOUT } --- 29,35 ---- [ NULL [ AS ] '<replaceable class="parameter">null string</replaceable>' ] [ CSV [ 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> [,...] ) ] TO { '<replaceable class="parameter">filename</replaceable>' | STDOUT } *************** *** 40,46 **** [ NULL [ AS ] '<replaceable class="parameter">null string</replaceable>' ] [ CSV [ QUOTE [ AS ] '<replaceable class="parameter">quote</replaceable>' ] [ ESCAPE [ AS ] '<replaceable class="parameter">escape</replaceable>' ] ! [ FORCE <replaceable class="parameter">column</replaceable> [, ...] ] </synopsis> </refsynopsisdiv> --- 40,46 ---- [ NULL [ AS ] '<replaceable class="parameter">null string</replaceable>' ] [ CSV [ QUOTE [ AS ] '<replaceable class="parameter">quote</replaceable>' ] [ ESCAPE [ AS ] '<replaceable class="parameter">escape</replaceable>' ] ! [ FORCE QUOTE <replaceable class="parameter">column</replaceable> [, ...] ] </synopsis> </refsynopsisdiv> *************** *** 185,194 **** <term><literal>CSV</literal></term> <listitem> <para> ! Enables Comma Separated Variable (<literal>CSV</>) mode. (Also called ! Comma Separated Value). It sets the default <literal>DELIMITER</> to ! comma, and <literal>QUOTE</> and <literal>ESCAPE</> values to ! double-quote. </para> </listitem> </varlistentry> --- 185,194 ---- <term><literal>CSV</literal></term> <listitem> <para> ! Enables Comma Separated Variable (<literal>CSV</>) mode. (Also ! called Comma Separated Value). It sets the default ! <literal>DELIMITER</> to comma, and <literal>QUOTE</> and ! <literal>ESCAPE</> values to double-quote. </para> </listitem> </varlistentry> *************** *** 207,244 **** <term><replaceable class="parameter">escape</replaceable></term> <listitem> <para> ! Specifies the character that should appear before a <literal>QUOTE</> ! data character value in <literal>CSV</> mode. The default is the ! <literal>QUOTE</> value (usually double-quote). </para> </listitem> </varlistentry> <varlistentry> ! <term><literal>FORCE</></term> <listitem> <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> <varlistentry> ! <term><literal>LITERAL</></term> <listitem> <para> ! In <literal>CSV</> <command>COPY FROM</> mode, for each column specified, ! do not do a <literal>null string</> comparison; instead load the value ! literally. <literal>QUOTE</> and <literal>ESCAPE</> processing are still ! performed. ! </para> ! <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> </listitem> </varlistentry> --- 207,239 ---- <term><replaceable class="parameter">escape</replaceable></term> <listitem> <para> ! Specifies the character that should appear before a ! <literal>QUOTE</> data character value in <literal>CSV</> mode. ! The default is the <literal>QUOTE</> value (usually double-quote). </para> </listitem> </varlistentry> <varlistentry> ! <term><literal>FORCE QUOTE</></term> <listitem> <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> <varlistentry> ! <term><literal>FORCE NOT NULL</></term> <listitem> <para> ! In <literal>CSV</> <command>COPY FROM</> mode, process each ! specified column as though it was quoted and not a ! <literal>NULL</> value. For the default <literal>null string</> in ! <literal>CSV</> mode (<literal>''</>), this causes a missing ! values to be input as a zero-length strings. </para> </listitem> </varlistentry> *************** *** 483,489 **** suffixed by the <literal>QUOTE</> character, and any occurrence within the value of a <literal>QUOTE</> character or the <literal>ESCAPE</> character is preceded by the escape character. ! You can also use <literal>FORCE</> to force quotes when outputting non-<literal>NULL</> values in specific columns. </para> --- 478,484 ---- suffixed by the <literal>QUOTE</> character, and any occurrence within the value of a <literal>QUOTE</> character or the <literal>ESCAPE</> character is preceded by the escape character. ! You can also use <literal>FORCE QUOTE</> to force quotes when outputting non-<literal>NULL</> values in specific columns. </para> *************** *** 496,502 **** is quoted. Therefore, using the default settings, a <literal>NULL</> is written as an unquoted empty string, while an empty string is written with double quotes (<literal>""</>). Reading values follows ! similar rules. You can use <literal>LITERAL</> to prevent <literal>NULL</> input comparisons for specific columns. </para> --- 491,497 ---- is quoted. Therefore, using the default settings, a <literal>NULL</> is written as an unquoted empty string, while an empty string is written with double quotes (<literal>""</>). Reading values follows ! similar rules. You can use <literal>FORCE NOT NULL</> to prevent <literal>NULL</> input comparisons for specific columns. </para> Index: doc/src/sgml/ref/psql-ref.sgml =================================================================== RCS file: /cvsroot/pgsql-server/doc/src/sgml/ref/psql-ref.sgml,v retrieving revision 1.111 diff -c -c -r1.111 psql-ref.sgml *** doc/src/sgml/ref/psql-ref.sgml 19 Apr 2004 17:22:30 -0000 1.111 --- doc/src/sgml/ref/psql-ref.sgml 21 Apr 2004 00:17:53 -0000 *************** *** 713,720 **** [ <literal>null [as] </literal> '<replaceable class="parameter">string</replaceable>' ]</literal> [ <literal>csv [ quote [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>literal</> <replaceable class="parameter">column_list</replaceable> ] ] </term> <listitem> --- 713,720 ---- [ <literal>null [as] </literal> '<replaceable class="parameter">string</replaceable>' ]</literal> [ <literal>csv [ quote [as] </literal> '<replaceable class="parameter">character</replaceable>' ] [ <literal>escape [as] </literal> '<replaceable class="parameter">character</replaceable>' ] ! [ <literal>force quote</> <replaceable class="parameter">column_list</replaceable> ] ! [ <literal>force not null</> <replaceable class="parameter">column_list</replaceable> ] ] </term> <listitem> Index: src/backend/commands/copy.c =================================================================== RCS file: /cvsroot/pgsql-server/src/backend/commands/copy.c,v retrieving revision 1.222 diff -c -c -r1.222 copy.c *** src/backend/commands/copy.c 19 Apr 2004 21:58:02 -0000 1.222 --- src/backend/commands/copy.c 21 Apr 2004 00:17:55 -0000 *************** *** 132,141 **** /* non-export function prototypes */ static void CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, char *delim, char *null_print, bool csv_mode, char *quote, char *escape, ! List *force_atts); static void CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, char *delim, char *null_print, bool csv_mode, char *quote, char *escape, ! List *literal_atts); static bool CopyReadLine(void); static char *CopyReadAttribute(const char *delim, const char *null_print, CopyReadResult *result, bool *isnull); --- 132,141 ---- /* non-export function prototypes */ static void CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, char *delim, char *null_print, bool csv_mode, char *quote, char *escape, ! List *force_quote_atts); static void CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, char *delim, char *null_print, bool csv_mode, char *quote, char *escape, ! List *force_notnull_atts); static bool CopyReadLine(void); static char *CopyReadAttribute(const char *delim, const char *null_print, CopyReadResult *result, bool *isnull); *************** *** 695,704 **** char *quote = NULL; char *escape = NULL; char *null_print = NULL; ! List *force = NIL; ! List *literal = NIL; ! List *force_atts = NIL; ! List *literal_atts = NIL; Relation rel; AclMode required_access = (is_from ? ACL_INSERT : ACL_SELECT); AclResult aclresult; --- 695,704 ---- char *quote = NULL; char *escape = NULL; char *null_print = NULL; ! List *force_quote = NIL; ! List *force_notnull = NIL; ! List *force_quote_atts = NIL; ! List *force_notnull_atts = NIL; Relation rel; AclMode required_access = (is_from ? ACL_INSERT : ACL_SELECT); AclResult aclresult; *************** *** 764,784 **** errmsg("conflicting or redundant options"))); escape = strVal(defel->arg); } ! else if (strcmp(defel->defname, "force") == 0) { ! if (force) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); ! force = (List *)defel->arg; } ! else if (strcmp(defel->defname, "literal") == 0) { ! if (literal) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); ! literal = (List *)defel->arg; } else elog(ERROR, "option \"%s\" not recognized", --- 764,784 ---- errmsg("conflicting or redundant options"))); escape = strVal(defel->arg); } ! else if (strcmp(defel->defname, "force_quote") == 0) { ! if (force_quote) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); ! force_quote = (List *)defel->arg; } ! else if (strcmp(defel->defname, "force_notnull") == 0) { ! if (force_notnull) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); ! force_notnull = (List *)defel->arg; } else elog(ERROR, "option \"%s\" not recognized", *************** *** 850,877 **** errmsg("COPY escape must be a single character"))); /* ! * Check force */ ! if (!csv_mode && force != NIL) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ! errmsg("COPY force available only in CSV mode"))); ! if (force != NIL && is_from) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ! errmsg("COPY force only available using COPY TO"))); /* ! * Check literal */ ! if (!csv_mode && literal != NIL) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ! errmsg("COPY literal available only in CSV mode"))); ! if (literal != NIL && !is_from) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ! errmsg("COPY literal only available using COPY FROM"))); /* * Don't allow the delimiter to appear in the null string. --- 850,877 ---- errmsg("COPY escape must be a single character"))); /* ! * Check force_quote */ ! if (!csv_mode && force_quote != NIL) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ! errmsg("COPY force quote available only in CSV mode"))); ! if (force_quote != NIL && is_from) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ! errmsg("COPY force quote only available using COPY TO"))); /* ! * Check force_notnull */ ! if (!csv_mode && force_notnull != NIL) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ! errmsg("COPY force not null available only in CSV mode"))); ! if (force_notnull != NIL && !is_from) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ! errmsg("COPY force not null only available using COPY FROM"))); /* * Don't allow the delimiter to appear in the null string. *************** *** 928,974 **** attnumlist = CopyGetAttnums(rel, attnamelist); /* ! * Check that FORCE references valid COPY columns */ ! if (force) { TupleDesc tupDesc = RelationGetDescr(rel); Form_pg_attribute *attr = tupDesc->attrs; List *cur; ! force_atts = CopyGetAttnums(rel, force); ! foreach(cur, force_atts) { int attnum = lfirsti(cur); if (!intMember(attnum, attnumlist)) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), ! errmsg("FORCE column \"%s\" not referenced by COPY", NameStr(attr[attnum - 1]->attname)))); } } /* ! * Check that LITERAL references valid COPY columns */ ! if (literal) { List *cur; TupleDesc tupDesc = RelationGetDescr(rel); Form_pg_attribute *attr = tupDesc->attrs; ! literal_atts = CopyGetAttnums(rel, literal); ! foreach(cur, literal_atts) { int attnum = lfirsti(cur); if (!intMember(attnum, attnumlist)) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), ! errmsg("LITERAL column \"%s\" not referenced by COPY", NameStr(attr[attnum - 1]->attname)))); } } --- 928,974 ---- attnumlist = CopyGetAttnums(rel, attnamelist); /* ! * Check that FORCE QUOTE references valid COPY columns */ ! if (force_quote) { TupleDesc tupDesc = RelationGetDescr(rel); Form_pg_attribute *attr = tupDesc->attrs; List *cur; ! force_quote_atts = CopyGetAttnums(rel, force_quote); ! foreach(cur, force_quote_atts) { int attnum = lfirsti(cur); if (!intMember(attnum, attnumlist)) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), ! errmsg("FORCE QUOTE column \"%s\" not referenced by COPY", NameStr(attr[attnum - 1]->attname)))); } } /* ! * Check that FORCE NOT NULL references valid COPY columns */ ! if (force_notnull) { List *cur; TupleDesc tupDesc = RelationGetDescr(rel); Form_pg_attribute *attr = tupDesc->attrs; ! force_notnull_atts = CopyGetAttnums(rel, force_notnull); ! foreach(cur, force_notnull_atts) { int attnum = lfirsti(cur); if (!intMember(attnum, attnumlist)) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), ! errmsg("FORCE NOT NULL column \"%s\" not referenced by COPY", NameStr(attr[attnum - 1]->attname)))); } } *************** *** 1037,1043 **** } } CopyFrom(rel, attnumlist, binary, oids, delim, null_print, csv_mode, ! quote, escape, literal_atts); } else { /* copy from database to file */ --- 1037,1043 ---- } } CopyFrom(rel, attnumlist, binary, oids, delim, null_print, csv_mode, ! quote, escape, force_notnull_atts); } else { /* copy from database to file */ *************** *** 1100,1106 **** } } CopyTo(rel, attnumlist, binary, oids, delim, null_print, csv_mode, ! quote, escape, force_atts); } if (!pipe) --- 1100,1106 ---- } } CopyTo(rel, attnumlist, binary, oids, delim, null_print, csv_mode, ! quote, escape, force_quote_atts); } if (!pipe) *************** *** 1133,1139 **** static void CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, char *delim, char *null_print, bool csv_mode, char *quote, ! char *escape, List *force_atts) { HeapTuple tuple; TupleDesc tupDesc; --- 1133,1139 ---- static void CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, char *delim, char *null_print, bool csv_mode, char *quote, ! char *escape, List *force_quote_atts) { HeapTuple tuple; TupleDesc tupDesc; *************** *** 1180,1186 **** &isvarlena[attnum - 1]); fmgr_info(out_func_oid, &out_functions[attnum - 1]); ! if (intMember(attnum, force_atts)) force_quote[attnum - 1] = true; else force_quote[attnum - 1] = false; --- 1180,1186 ---- &isvarlena[attnum - 1]); fmgr_info(out_func_oid, &out_functions[attnum - 1]); ! if (intMember(attnum, force_quote_atts)) force_quote[attnum - 1] = true; else force_quote[attnum - 1] = false; *************** *** 1434,1440 **** static void CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, char *delim, char *null_print, bool csv_mode, char *quote, ! char *escape, List *literal_atts) { HeapTuple tuple; TupleDesc tupDesc; --- 1434,1440 ---- static void CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, char *delim, char *null_print, bool csv_mode, char *quote, ! char *escape, List *force_notnull_atts) { HeapTuple tuple; TupleDesc tupDesc; *************** *** 1447,1453 **** Oid *elements; Oid oid_in_element; ExprState **constraintexprs; ! bool *literal_nullstr; bool hasConstraints = false; int attnum; int i; --- 1447,1453 ---- Oid *elements; Oid oid_in_element; ExprState **constraintexprs; ! bool *force_notnull; bool hasConstraints = false; int attnum; int i; *************** *** 1509,1515 **** defmap = (int *) palloc((num_phys_attrs + 1) * sizeof(int)); defexprs = (ExprState **) palloc((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)); for (attnum = 1; attnum <= num_phys_attrs; attnum++) { --- 1509,1515 ---- defmap = (int *) palloc((num_phys_attrs + 1) * sizeof(int)); defexprs = (ExprState **) palloc((num_phys_attrs + 1) * sizeof(ExprState *)); constraintexprs = (ExprState **) palloc0((num_phys_attrs + 1) * sizeof(ExprState *)); ! force_notnull = (bool *) palloc((num_phys_attrs + 1) * sizeof(bool)); for (attnum = 1; attnum <= num_phys_attrs; attnum++) { *************** *** 1526,1535 **** &in_func_oid, &elements[attnum - 1]); fmgr_info(in_func_oid, &in_functions[attnum - 1]); ! if (intMember(attnum, literal_atts)) ! literal_nullstr[attnum - 1] = true; else ! literal_nullstr[attnum - 1] = false; /* Get default info if needed */ if (!intMember(attnum, attnumlist)) --- 1526,1535 ---- &in_func_oid, &elements[attnum - 1]); fmgr_info(in_func_oid, &in_functions[attnum - 1]); ! if (intMember(attnum, force_notnull_atts)) ! force_notnull[attnum - 1] = true; else ! force_notnull[attnum - 1] = false; /* Get default info if needed */ if (!intMember(attnum, attnumlist)) *************** *** 1748,1754 **** string = CopyReadAttribute(delim, null_print, &result, &isnull); ! if (csv_mode && isnull && literal_nullstr[m]) { string = null_print; /* set to NULL string */ isnull = false; --- 1748,1754 ---- string = CopyReadAttribute(delim, null_print, &result, &isnull); ! if (csv_mode && isnull && force_notnull[m]) { string = null_print; /* set to NULL string */ isnull = false; *************** *** 1947,1953 **** pfree(defmap); pfree(defexprs); pfree(constraintexprs); ! pfree(literal_nullstr); ExecDropTupleTable(tupleTable, true); --- 1947,1953 ---- pfree(defmap); pfree(defexprs); pfree(constraintexprs); ! pfree(force_notnull); ExecDropTupleTable(tupleTable, true); *************** *** 2558,2571 **** */ static void CopyAttributeOutCSV(char *server_string, char *delim, char *quote, ! char *escape, bool force_quote) { char *string; char c; char delimc = delim[0]; char quotec = quote[0]; char escapec = escape[0]; - bool need_quote = force_quote; char *test_string; bool same_encoding; int mblen; --- 2558,2570 ---- */ static void CopyAttributeOutCSV(char *server_string, char *delim, char *quote, ! char *escape, bool use_quote) { char *string; char c; char delimc = delim[0]; char quotec = quote[0]; char escapec = escape[0]; char *test_string; bool same_encoding; int mblen; *************** *** 2583,2605 **** */ for(test_string = string; ! !need_quote && (c = *test_string) != '\0'; test_string += mblen) { if (c == delimc || c == quotec || c == '\n' || c == '\r') ! need_quote = true; if (!same_encoding) mblen = pg_encoding_mblen(client_encoding, test_string); else mblen = 1; } ! if (need_quote) CopySendChar(quotec); for (; (c = *string) != '\0'; string += mblen) { ! if (need_quote && (c == quotec || c == escapec)) CopySendChar(escapec); CopySendChar(c); --- 2582,2604 ---- */ for(test_string = string; ! !use_quote && (c = *test_string) != '\0'; test_string += mblen) { if (c == delimc || c == quotec || c == '\n' || c == '\r') ! use_quote = true; if (!same_encoding) mblen = pg_encoding_mblen(client_encoding, test_string); else mblen = 1; } ! if (use_quote) CopySendChar(quotec); for (; (c = *string) != '\0'; string += mblen) { ! if (use_quote && (c == quotec || c == escapec)) CopySendChar(escapec); CopySendChar(c); *************** *** 2615,2621 **** mblen = 1; } ! if (need_quote) CopySendChar(quotec); } --- 2614,2620 ---- mblen = 1; } ! if (use_quote) CopySendChar(quotec); } Index: src/backend/parser/gram.y =================================================================== RCS file: /cvsroot/pgsql-server/src/backend/parser/gram.y,v retrieving revision 2.451 diff -c -c -r2.451 gram.y *** src/backend/parser/gram.y 19 Apr 2004 17:22:30 -0000 2.451 --- src/backend/parser/gram.y 21 Apr 2004 00:18:00 -0000 *************** *** 370,376 **** KEY LANCOMPILER LANGUAGE LARGE_P LAST_P LEADING LEFT LEVEL LIKE LIMIT ! LISTEN LITERAL LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION LOCK_P MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE --- 370,376 ---- KEY LANCOMPILER LANGUAGE LARGE_P LAST_P LEADING LEFT LEVEL LIKE LIMIT ! LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION LOCK_P MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE *************** *** 1374,1386 **** { $$ = makeDefElem("escape", (Node *)makeString($3)); } ! | FORCE columnList { ! $$ = makeDefElem("force", (Node *)$2); } ! | LITERAL columnList { ! $$ = makeDefElem("literal", (Node *)$2); } ; --- 1374,1386 ---- { $$ = makeDefElem("escape", (Node *)makeString($3)); } ! | FORCE QUOTE columnList { ! $$ = makeDefElem("force_quote", (Node *)$3); } ! | FORCE NOT NULL_P columnList { ! $$ = makeDefElem("force_notnull", (Node *)$4); } ; *************** *** 7496,7502 **** | LAST_P | LEVEL | LISTEN - | LITERAL | LOAD | LOCAL | LOCATION --- 7496,7501 ---- Index: src/backend/parser/keywords.c =================================================================== RCS file: /cvsroot/pgsql-server/src/backend/parser/keywords.c,v retrieving revision 1.148 diff -c -c -r1.148 keywords.c *** src/backend/parser/keywords.c 19 Apr 2004 17:22:31 -0000 1.148 --- src/backend/parser/keywords.c 21 Apr 2004 00:18:01 -0000 *************** *** 187,193 **** {"like", LIKE}, {"limit", LIMIT}, {"listen", LISTEN}, - {"literal", LITERAL}, {"load", LOAD}, {"local", LOCAL}, {"localtime", LOCALTIME}, --- 187,192 ---- Index: src/bin/psql/copy.c =================================================================== RCS file: /cvsroot/pgsql-server/src/bin/psql/copy.c,v retrieving revision 1.45 diff -c -c -r1.45 copy.c *** src/bin/psql/copy.c 19 Apr 2004 17:42:58 -0000 1.45 --- src/bin/psql/copy.c 21 Apr 2004 00:18:03 -0000 *************** *** 71,78 **** char *null; char *quote; char *escape; ! char *force_list; ! char *literal_list; }; --- 71,78 ---- char *null; char *quote; char *escape; ! char *force_quote_list; ! char *force_notnull_list; }; *************** *** 88,95 **** free(ptr->null); free(ptr->quote); free(ptr->escape); ! free(ptr->force_list); ! free(ptr->literal_list); free(ptr); } --- 88,95 ---- free(ptr->null); free(ptr->quote); free(ptr->escape); ! free(ptr->force_quote_list); ! free(ptr->force_notnull_list); free(ptr); } *************** *** 344,388 **** } else if (strcasecmp(token, "force") == 0) { ! /* handle column list */ ! fetch_next = false; ! for (;;) { ! token = strtokx(NULL, whitespace, ",", "\"", ! 0, false, pset.encoding); ! if (!token || strchr(",", token[0])) ! goto error; ! if (!result->force_list) ! result->force_list = pg_strdup(token); ! else ! xstrcat(&result->force_list, token); ! token = strtokx(NULL, whitespace, ",", "\"", ! 0, false, pset.encoding); ! if (!token || token[0] != ',') ! break; ! xstrcat(&result->force_list, token); } ! } ! else if (strcasecmp(token, "literal") == 0) ! { ! /* handle column list */ ! fetch_next = false; ! for (;;) { token = strtokx(NULL, whitespace, ",", "\"", 0, false, pset.encoding); ! if (!token || strchr(",", token[0])) goto error; ! if (!result->literal_list) ! result->literal_list = pg_strdup(token); ! else ! xstrcat(&result->literal_list, token); ! token = strtokx(NULL, whitespace, ",", "\"", ! 0, false, pset.encoding); ! if (!token || token[0] != ',') ! break; ! xstrcat(&result->literal_list, token); } } else goto error; --- 344,399 ---- } else if (strcasecmp(token, "force") == 0) { ! token = strtokx(NULL, whitespace, ",", "\"", ! 0, false, pset.encoding); ! if (strcasecmp(token, "quote") == 0) { ! /* handle column list */ ! fetch_next = false; ! for (;;) ! { ! token = strtokx(NULL, whitespace, ",", "\"", ! 0, false, pset.encoding); ! if (!token || strchr(",", token[0])) ! goto error; ! if (!result->force_quote_list) ! result->force_quote_list = pg_strdup(token); ! else ! xstrcat(&result->force_quote_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) { token = strtokx(NULL, whitespace, ",", "\"", 0, false, pset.encoding); ! if (strcasecmp(token, "null") != 0) goto error; ! /* handle column list */ ! fetch_next = false; ! for (;;) ! { ! token = strtokx(NULL, whitespace, ",", "\"", ! 0, false, pset.encoding); ! if (!token || strchr(",", token[0])) ! goto error; ! 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 goto error; *************** *** 493,506 **** appendPQExpBuffer(&query, " ESCAPE AS '%s'", options->escape); } ! if (options->force_list) { ! appendPQExpBuffer(&query, " FORCE %s", options->force_list); } ! if (options->literal_list) { ! appendPQExpBuffer(&query, " LITERAL %s", options->literal_list); } if (options->from) --- 504,517 ---- appendPQExpBuffer(&query, " ESCAPE AS '%s'", options->escape); } ! if (options->force_quote_list) { ! appendPQExpBuffer(&query, " FORCE QUOTE %s", options->force_quote_list); } ! if (options->force_notnull_list) { ! appendPQExpBuffer(&query, " FORCE NOT NULL %s", options->force_notnull_list); } if (options->from)
pgsql-patches by date: