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 ] 'null string' ]
[ CSV [ QUOTE [ AS ] 'quote' ]
[ ESCAPE [ AS ] 'escape' ]
! [ LITERAL column [, ...] ]
COPY tablename [ ( column [, ...] ) ]
TO { 'filename' | STDOUT }
--- 29,35 ----
[ NULL [ AS ] 'null string' ]
[ CSV [ QUOTE [ AS ] 'quote' ]
[ ESCAPE [ AS ] 'escape' ]
! [ FORCE NOT NULL column [, ...] ]
COPY tablename [ ( column [, ...] ) ]
TO { 'filename' | STDOUT }
***************
*** 40,46 ****
[ NULL [ AS ] 'null string' ]
[ CSV [ QUOTE [ AS ] 'quote' ]
[ ESCAPE [ AS ] 'escape' ]
! [ FORCE column [, ...] ]
--- 40,46 ----
[ NULL [ AS ] 'null string' ]
[ CSV [ QUOTE [ AS ] 'quote' ]
[ ESCAPE [ AS ] 'escape' ]
! [ FORCE QUOTE column [, ...] ]
***************
*** 185,194 ****
CSV
! Enables Comma Separated Variable (CSV>) mode. (Also called
! Comma Separated Value). It sets the default DELIMITER> to
! comma, and QUOTE> and ESCAPE> values to
! double-quote.
--- 185,194 ----
CSV
! Enables Comma Separated Variable (CSV>) mode. (Also
! called Comma Separated Value). It sets the default
! DELIMITER> to comma, and QUOTE> and
! ESCAPE> values to double-quote.
***************
*** 207,244 ****
escape
! Specifies the character that should appear before a QUOTE>
! data character value in CSV> mode. The default is the
! QUOTE> value (usually double-quote).
! FORCE>
! In CSV> COPY TO> mode, forces quoting
! to be used for all non-NULL> values in each specified
! column. NULL> output is never quoted.
! LITERAL>
! In CSV> COPY FROM> mode, for each column specified,
! do not do a null string> comparison; instead load the value
! literally. QUOTE> and ESCAPE> processing are still
! performed.
!
!
! If the null string> is ''> (the default
! in CSV> mode), a missing input value (delimiter,
! delimiter>), will load as a zero-length string. Delimiter, quote,
! quote, delimiter> is always treated as a zero-length string on input.
--- 207,239 ----
escape
! Specifies the character that should appear before a
! QUOTE> data character value in CSV> mode.
! The default is the QUOTE> value (usually double-quote).
! FORCE QUOTE>
! In CSV> COPY TO> mode, forces quoting to be
! used for all non-NULL> values in each specified column.
! NULL> output is never quoted.
! FORCE NOT NULL>
! In CSV> COPY FROM> mode, process each
! specified column as though it was quoted and not a
! NULL> value. For the default null string> in
! CSV> mode (''>), this causes a missing
! values to be input as a zero-length strings.
***************
*** 483,489 ****
suffixed by the QUOTE> character, and any occurrence
within the value of a QUOTE> character or the
ESCAPE> character is preceded by the escape character.
! You can also use FORCE> to force quotes when outputting
non-NULL> values in specific columns.
--- 478,484 ----
suffixed by the QUOTE> character, and any occurrence
within the value of a QUOTE> character or the
ESCAPE> character is preceded by the escape character.
! You can also use FORCE QUOTE> to force quotes when outputting
non-NULL> values in specific columns.
***************
*** 496,502 ****
is quoted. Therefore, using the default settings, a NULL> is
written as an unquoted empty string, while an empty string is
written with double quotes ("">). Reading values follows
! similar rules. You can use LITERAL> to prevent NULL>
input comparisons for specific columns.
--- 491,497 ----
is quoted. Therefore, using the default settings, a NULL> is
written as an unquoted empty string, while an empty string is
written with double quotes ("">). Reading values follows
! similar rules. You can use FORCE NOT NULL> to prevent NULL>
input comparisons for specific columns.
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 ****
[ null [as] 'string' ]
[ csv [ quote [as] 'character' ]
[ escape [as] 'character' ]
! [ force> column_list ]
! [ literal> column_list ] ]
--- 713,720 ----
[ null [as] 'string' ]
[ csv [ quote [as] 'character' ]
[ escape [as] 'character' ]
! [ force quote> column_list ]
! [ force not null> column_list ] ]
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)