Respond to Jeremy Drake's original gripe that \copy needs to recognize
E'...' syntax for strings in order to track the backend.
This commit is contained in:
parent
6178762fcf
commit
87e8014d31
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/psql/copy.c,v 1.63 2006/06/01 00:15:36 tgl Exp $
|
* $PostgreSQL: pgsql/src/bin/psql/copy.c,v 1.64 2006/06/01 01:28:00 tgl Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
#include "copy.h"
|
#include "copy.h"
|
||||||
@ -127,7 +127,7 @@ parse_slash_copy(const char *args)
|
|||||||
result = pg_calloc(1, sizeof(struct copy_options));
|
result = pg_calloc(1, sizeof(struct copy_options));
|
||||||
|
|
||||||
token = strtokx(line, whitespace, ".,()", "\"",
|
token = strtokx(line, whitespace, ".,()", "\"",
|
||||||
0, false, pset.encoding);
|
0, false, false, pset.encoding);
|
||||||
if (!token)
|
if (!token)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ parse_slash_copy(const char *args)
|
|||||||
{
|
{
|
||||||
result->binary = true;
|
result->binary = true;
|
||||||
token = strtokx(NULL, whitespace, ".,()", "\"",
|
token = strtokx(NULL, whitespace, ".,()", "\"",
|
||||||
0, false, pset.encoding);
|
0, false, false, pset.encoding);
|
||||||
if (!token)
|
if (!token)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -143,7 +143,7 @@ parse_slash_copy(const char *args)
|
|||||||
result->table = pg_strdup(token);
|
result->table = pg_strdup(token);
|
||||||
|
|
||||||
token = strtokx(NULL, whitespace, ".,()", "\"",
|
token = strtokx(NULL, whitespace, ".,()", "\"",
|
||||||
0, false, pset.encoding);
|
0, false, false, pset.encoding);
|
||||||
if (!token)
|
if (!token)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
@ -156,12 +156,12 @@ parse_slash_copy(const char *args)
|
|||||||
/* handle schema . table */
|
/* handle schema . table */
|
||||||
xstrcat(&result->table, token);
|
xstrcat(&result->table, token);
|
||||||
token = strtokx(NULL, whitespace, ".,()", "\"",
|
token = strtokx(NULL, whitespace, ".,()", "\"",
|
||||||
0, false, pset.encoding);
|
0, false, false, pset.encoding);
|
||||||
if (!token)
|
if (!token)
|
||||||
goto error;
|
goto error;
|
||||||
xstrcat(&result->table, token);
|
xstrcat(&result->table, token);
|
||||||
token = strtokx(NULL, whitespace, ".,()", "\"",
|
token = strtokx(NULL, whitespace, ".,()", "\"",
|
||||||
0, false, pset.encoding);
|
0, false, false, pset.encoding);
|
||||||
if (!token)
|
if (!token)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -173,12 +173,12 @@ parse_slash_copy(const char *args)
|
|||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
token = strtokx(NULL, whitespace, ".,()", "\"",
|
token = strtokx(NULL, whitespace, ".,()", "\"",
|
||||||
0, false, pset.encoding);
|
0, false, false, pset.encoding);
|
||||||
if (!token || strchr(".,()", token[0]))
|
if (!token || strchr(".,()", token[0]))
|
||||||
goto error;
|
goto error;
|
||||||
xstrcat(&result->column_list, token);
|
xstrcat(&result->column_list, token);
|
||||||
token = strtokx(NULL, whitespace, ".,()", "\"",
|
token = strtokx(NULL, whitespace, ".,()", "\"",
|
||||||
0, false, pset.encoding);
|
0, false, false, pset.encoding);
|
||||||
if (!token)
|
if (!token)
|
||||||
goto error;
|
goto error;
|
||||||
xstrcat(&result->column_list, token);
|
xstrcat(&result->column_list, token);
|
||||||
@ -188,7 +188,7 @@ parse_slash_copy(const char *args)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
token = strtokx(NULL, whitespace, ".,()", "\"",
|
token = strtokx(NULL, whitespace, ".,()", "\"",
|
||||||
0, false, pset.encoding);
|
0, false, false, pset.encoding);
|
||||||
if (!token)
|
if (!token)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -199,13 +199,13 @@ parse_slash_copy(const char *args)
|
|||||||
if (pg_strcasecmp(token, "with") == 0)
|
if (pg_strcasecmp(token, "with") == 0)
|
||||||
{
|
{
|
||||||
token = strtokx(NULL, whitespace, NULL, NULL,
|
token = strtokx(NULL, whitespace, NULL, NULL,
|
||||||
0, false, pset.encoding);
|
0, false, false, pset.encoding);
|
||||||
if (!token || pg_strcasecmp(token, "oids") != 0)
|
if (!token || pg_strcasecmp(token, "oids") != 0)
|
||||||
goto error;
|
goto error;
|
||||||
result->oids = true;
|
result->oids = true;
|
||||||
|
|
||||||
token = strtokx(NULL, whitespace, NULL, NULL,
|
token = strtokx(NULL, whitespace, NULL, NULL,
|
||||||
0, false, pset.encoding);
|
0, false, false, pset.encoding);
|
||||||
if (!token)
|
if (!token)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -218,7 +218,7 @@ parse_slash_copy(const char *args)
|
|||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
token = strtokx(NULL, whitespace, NULL, "'",
|
token = strtokx(NULL, whitespace, NULL, "'",
|
||||||
nonstd_backslash, true, pset.encoding);
|
0, false, true, pset.encoding);
|
||||||
if (!token)
|
if (!token)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
@ -242,7 +242,7 @@ parse_slash_copy(const char *args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
token = strtokx(NULL, whitespace, NULL, NULL,
|
token = strtokx(NULL, whitespace, NULL, NULL,
|
||||||
0, false, pset.encoding);
|
0, false, false, pset.encoding);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allows old COPY syntax for backward compatibility 2002-06-19
|
* Allows old COPY syntax for backward compatibility 2002-06-19
|
||||||
@ -250,19 +250,19 @@ parse_slash_copy(const char *args)
|
|||||||
if (token && pg_strcasecmp(token, "using") == 0)
|
if (token && pg_strcasecmp(token, "using") == 0)
|
||||||
{
|
{
|
||||||
token = strtokx(NULL, whitespace, NULL, NULL,
|
token = strtokx(NULL, whitespace, NULL, NULL,
|
||||||
0, false, pset.encoding);
|
0, false, false, pset.encoding);
|
||||||
if (!(token && pg_strcasecmp(token, "delimiters") == 0))
|
if (!(token && pg_strcasecmp(token, "delimiters") == 0))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (token && pg_strcasecmp(token, "delimiters") == 0)
|
if (token && pg_strcasecmp(token, "delimiters") == 0)
|
||||||
{
|
{
|
||||||
token = strtokx(NULL, whitespace, NULL, "'",
|
token = strtokx(NULL, whitespace, NULL, "'",
|
||||||
nonstd_backslash, false, pset.encoding);
|
nonstd_backslash, true, false, pset.encoding);
|
||||||
if (!token)
|
if (!token)
|
||||||
goto error;
|
goto error;
|
||||||
result->delim = pg_strdup(token);
|
result->delim = pg_strdup(token);
|
||||||
token = strtokx(NULL, whitespace, NULL, NULL,
|
token = strtokx(NULL, whitespace, NULL, NULL,
|
||||||
0, false, pset.encoding);
|
0, false, false, pset.encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token)
|
if (token)
|
||||||
@ -273,7 +273,7 @@ parse_slash_copy(const char *args)
|
|||||||
*/
|
*/
|
||||||
if (pg_strcasecmp(token, "with") == 0)
|
if (pg_strcasecmp(token, "with") == 0)
|
||||||
token = strtokx(NULL, whitespace, NULL, NULL,
|
token = strtokx(NULL, whitespace, NULL, NULL,
|
||||||
0, false, pset.encoding);
|
0, false, false, pset.encoding);
|
||||||
|
|
||||||
while (token)
|
while (token)
|
||||||
{
|
{
|
||||||
@ -292,10 +292,10 @@ parse_slash_copy(const char *args)
|
|||||||
else if (pg_strcasecmp(token, "delimiter") == 0)
|
else if (pg_strcasecmp(token, "delimiter") == 0)
|
||||||
{
|
{
|
||||||
token = strtokx(NULL, whitespace, NULL, "'",
|
token = strtokx(NULL, whitespace, NULL, "'",
|
||||||
nonstd_backslash, false, pset.encoding);
|
nonstd_backslash, true, false, pset.encoding);
|
||||||
if (token && pg_strcasecmp(token, "as") == 0)
|
if (token && pg_strcasecmp(token, "as") == 0)
|
||||||
token = strtokx(NULL, whitespace, NULL, "'",
|
token = strtokx(NULL, whitespace, NULL, "'",
|
||||||
nonstd_backslash, false, pset.encoding);
|
nonstd_backslash, true, false, pset.encoding);
|
||||||
if (token)
|
if (token)
|
||||||
result->delim = pg_strdup(token);
|
result->delim = pg_strdup(token);
|
||||||
else
|
else
|
||||||
@ -304,10 +304,10 @@ parse_slash_copy(const char *args)
|
|||||||
else if (pg_strcasecmp(token, "null") == 0)
|
else if (pg_strcasecmp(token, "null") == 0)
|
||||||
{
|
{
|
||||||
token = strtokx(NULL, whitespace, NULL, "'",
|
token = strtokx(NULL, whitespace, NULL, "'",
|
||||||
nonstd_backslash, false, pset.encoding);
|
nonstd_backslash, true, false, pset.encoding);
|
||||||
if (token && pg_strcasecmp(token, "as") == 0)
|
if (token && pg_strcasecmp(token, "as") == 0)
|
||||||
token = strtokx(NULL, whitespace, NULL, "'",
|
token = strtokx(NULL, whitespace, NULL, "'",
|
||||||
nonstd_backslash, false, pset.encoding);
|
nonstd_backslash, true, false, pset.encoding);
|
||||||
if (token)
|
if (token)
|
||||||
result->null = pg_strdup(token);
|
result->null = pg_strdup(token);
|
||||||
else
|
else
|
||||||
@ -316,10 +316,10 @@ parse_slash_copy(const char *args)
|
|||||||
else if (pg_strcasecmp(token, "quote") == 0)
|
else if (pg_strcasecmp(token, "quote") == 0)
|
||||||
{
|
{
|
||||||
token = strtokx(NULL, whitespace, NULL, "'",
|
token = strtokx(NULL, whitespace, NULL, "'",
|
||||||
nonstd_backslash, false, pset.encoding);
|
nonstd_backslash, true, false, pset.encoding);
|
||||||
if (token && pg_strcasecmp(token, "as") == 0)
|
if (token && pg_strcasecmp(token, "as") == 0)
|
||||||
token = strtokx(NULL, whitespace, NULL, "'",
|
token = strtokx(NULL, whitespace, NULL, "'",
|
||||||
nonstd_backslash, false, pset.encoding);
|
nonstd_backslash, true, false, pset.encoding);
|
||||||
if (token)
|
if (token)
|
||||||
result->quote = pg_strdup(token);
|
result->quote = pg_strdup(token);
|
||||||
else
|
else
|
||||||
@ -328,10 +328,10 @@ parse_slash_copy(const char *args)
|
|||||||
else if (pg_strcasecmp(token, "escape") == 0)
|
else if (pg_strcasecmp(token, "escape") == 0)
|
||||||
{
|
{
|
||||||
token = strtokx(NULL, whitespace, NULL, "'",
|
token = strtokx(NULL, whitespace, NULL, "'",
|
||||||
nonstd_backslash, false, pset.encoding);
|
nonstd_backslash, true, false, pset.encoding);
|
||||||
if (token && pg_strcasecmp(token, "as") == 0)
|
if (token && pg_strcasecmp(token, "as") == 0)
|
||||||
token = strtokx(NULL, whitespace, NULL, "'",
|
token = strtokx(NULL, whitespace, NULL, "'",
|
||||||
nonstd_backslash, false, pset.encoding);
|
nonstd_backslash, true, false, pset.encoding);
|
||||||
if (token)
|
if (token)
|
||||||
result->escape = pg_strdup(token);
|
result->escape = pg_strdup(token);
|
||||||
else
|
else
|
||||||
@ -340,7 +340,7 @@ parse_slash_copy(const char *args)
|
|||||||
else if (pg_strcasecmp(token, "force") == 0)
|
else if (pg_strcasecmp(token, "force") == 0)
|
||||||
{
|
{
|
||||||
token = strtokx(NULL, whitespace, ",", "\"",
|
token = strtokx(NULL, whitespace, ",", "\"",
|
||||||
0, false, pset.encoding);
|
0, false, false, pset.encoding);
|
||||||
if (pg_strcasecmp(token, "quote") == 0)
|
if (pg_strcasecmp(token, "quote") == 0)
|
||||||
{
|
{
|
||||||
/* handle column list */
|
/* handle column list */
|
||||||
@ -348,7 +348,7 @@ parse_slash_copy(const char *args)
|
|||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
token = strtokx(NULL, whitespace, ",", "\"",
|
token = strtokx(NULL, whitespace, ",", "\"",
|
||||||
0, false, pset.encoding);
|
0, false, false, pset.encoding);
|
||||||
if (!token || strchr(",", token[0]))
|
if (!token || strchr(",", token[0]))
|
||||||
goto error;
|
goto error;
|
||||||
if (!result->force_quote_list)
|
if (!result->force_quote_list)
|
||||||
@ -356,7 +356,7 @@ parse_slash_copy(const char *args)
|
|||||||
else
|
else
|
||||||
xstrcat(&result->force_quote_list, token);
|
xstrcat(&result->force_quote_list, token);
|
||||||
token = strtokx(NULL, whitespace, ",", "\"",
|
token = strtokx(NULL, whitespace, ",", "\"",
|
||||||
0, false, pset.encoding);
|
0, false, false, pset.encoding);
|
||||||
if (!token || token[0] != ',')
|
if (!token || token[0] != ',')
|
||||||
break;
|
break;
|
||||||
xstrcat(&result->force_quote_list, token);
|
xstrcat(&result->force_quote_list, token);
|
||||||
@ -365,7 +365,7 @@ parse_slash_copy(const char *args)
|
|||||||
else if (pg_strcasecmp(token, "not") == 0)
|
else if (pg_strcasecmp(token, "not") == 0)
|
||||||
{
|
{
|
||||||
token = strtokx(NULL, whitespace, ",", "\"",
|
token = strtokx(NULL, whitespace, ",", "\"",
|
||||||
0, false, pset.encoding);
|
0, false, false, pset.encoding);
|
||||||
if (pg_strcasecmp(token, "null") != 0)
|
if (pg_strcasecmp(token, "null") != 0)
|
||||||
goto error;
|
goto error;
|
||||||
/* handle column list */
|
/* handle column list */
|
||||||
@ -373,7 +373,7 @@ parse_slash_copy(const char *args)
|
|||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
token = strtokx(NULL, whitespace, ",", "\"",
|
token = strtokx(NULL, whitespace, ",", "\"",
|
||||||
0, false, pset.encoding);
|
0, false, false, pset.encoding);
|
||||||
if (!token || strchr(",", token[0]))
|
if (!token || strchr(",", token[0]))
|
||||||
goto error;
|
goto error;
|
||||||
if (!result->force_notnull_list)
|
if (!result->force_notnull_list)
|
||||||
@ -381,7 +381,7 @@ parse_slash_copy(const char *args)
|
|||||||
else
|
else
|
||||||
xstrcat(&result->force_notnull_list, token);
|
xstrcat(&result->force_notnull_list, token);
|
||||||
token = strtokx(NULL, whitespace, ",", "\"",
|
token = strtokx(NULL, whitespace, ",", "\"",
|
||||||
0, false, pset.encoding);
|
0, false, false, pset.encoding);
|
||||||
if (!token || token[0] != ',')
|
if (!token || token[0] != ',')
|
||||||
break;
|
break;
|
||||||
xstrcat(&result->force_notnull_list, token);
|
xstrcat(&result->force_notnull_list, token);
|
||||||
@ -395,7 +395,7 @@ parse_slash_copy(const char *args)
|
|||||||
|
|
||||||
if (fetch_next)
|
if (fetch_next)
|
||||||
token = strtokx(NULL, whitespace, NULL, NULL,
|
token = strtokx(NULL, whitespace, NULL, NULL,
|
||||||
0, false, pset.encoding);
|
0, false, false, pset.encoding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,6 +415,22 @@ error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle one of the "string" options of COPY. If the user gave a quoted
|
||||||
|
* string, pass it to the backend as-is; if it wasn't quoted then quote
|
||||||
|
* and escape it.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
emit_copy_option(PQExpBuffer query, const char *keyword, const char *option)
|
||||||
|
{
|
||||||
|
appendPQExpBufferStr(query, keyword);
|
||||||
|
if (option[0] == '\'' ||
|
||||||
|
((option[0] == 'E' || option[0] == 'e') && option[1] == '\''))
|
||||||
|
appendPQExpBufferStr(query, option);
|
||||||
|
else
|
||||||
|
appendStringLiteralConn(query, option, pset.db);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Execute a \copy command (frontend copy). We have to open a file, then
|
* Execute a \copy command (frontend copy). We have to open a file, then
|
||||||
@ -462,29 +478,11 @@ do_copy(const char *args)
|
|||||||
|
|
||||||
/* Uses old COPY syntax for backward compatibility 2002-06-19 */
|
/* Uses old COPY syntax for backward compatibility 2002-06-19 */
|
||||||
if (options->delim)
|
if (options->delim)
|
||||||
{
|
emit_copy_option(&query, " USING DELIMITERS ", options->delim);
|
||||||
/* if user gave a quoted string, use it as-is */
|
|
||||||
if (options->delim[0] == '\'')
|
|
||||||
appendPQExpBuffer(&query, " USING DELIMITERS %s", options->delim);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
appendPQExpBuffer(&query, " USING DELIMITERS ");
|
|
||||||
appendStringLiteralConn(&query, options->delim, pset.db);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* There is no backward-compatible CSV syntax */
|
/* There is no backward-compatible CSV syntax */
|
||||||
if (options->null)
|
if (options->null)
|
||||||
{
|
emit_copy_option(&query, " WITH NULL AS ", options->null);
|
||||||
/* if user gave a quoted string, use it as-is */
|
|
||||||
if (options->null[0] == '\'')
|
|
||||||
appendPQExpBuffer(&query, " WITH NULL AS %s", options->null);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
appendPQExpBuffer(&query, " WITH NULL AS ");
|
|
||||||
appendStringLiteralConn(&query, options->null, pset.db);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options->csv_mode)
|
if (options->csv_mode)
|
||||||
appendPQExpBuffer(&query, " CSV");
|
appendPQExpBuffer(&query, " CSV");
|
||||||
@ -493,28 +491,10 @@ do_copy(const char *args)
|
|||||||
appendPQExpBuffer(&query, " HEADER");
|
appendPQExpBuffer(&query, " HEADER");
|
||||||
|
|
||||||
if (options->quote)
|
if (options->quote)
|
||||||
{
|
emit_copy_option(&query, " QUOTE AS ", options->quote);
|
||||||
/* if user gave a quoted string, use it as-is */
|
|
||||||
if (options->quote[0] == '\'')
|
|
||||||
appendPQExpBuffer(&query, " QUOTE AS %s", options->quote);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
appendPQExpBuffer(&query, " QUOTE AS ");
|
|
||||||
appendStringLiteralConn(&query, options->quote, pset.db);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options->escape)
|
if (options->escape)
|
||||||
{
|
emit_copy_option(&query, " ESCAPE AS ", options->escape);
|
||||||
/* if user gave a quoted string, use it as-is */
|
|
||||||
if (options->escape[0] == '\'')
|
|
||||||
appendPQExpBuffer(&query, " ESCAPE AS %s", options->escape);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
appendPQExpBuffer(&query, " ESCAPE AS ");
|
|
||||||
appendStringLiteralConn(&query, options->escape, pset.db);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options->force_quote_list)
|
if (options->force_quote_list)
|
||||||
appendPQExpBuffer(&query, " FORCE QUOTE %s", options->force_quote_list);
|
appendPQExpBuffer(&query, " FORCE QUOTE %s", options->force_quote_list);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/psql/stringutils.c,v 1.42 2006/03/05 15:58:52 momjian Exp $
|
* $PostgreSQL: pgsql/src/bin/psql/stringutils.c,v 1.43 2006/06/01 01:28:00 tgl Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
|
|
||||||
@ -32,7 +32,8 @@ static void strip_quotes(char *source, char quote, char escape, int encoding);
|
|||||||
* delim - set of non-whitespace separator characters (or NULL)
|
* delim - set of non-whitespace separator characters (or NULL)
|
||||||
* quote - set of characters that can quote a token (NULL if none)
|
* quote - set of characters that can quote a token (NULL if none)
|
||||||
* escape - character that can quote quotes (0 if none)
|
* escape - character that can quote quotes (0 if none)
|
||||||
* del_quotes - if TRUE, strip quotes from the returned token, else return
|
* e_strings - if TRUE, treat E'...' syntax as a valid token
|
||||||
|
* del_quotes - if TRUE, strip quotes from the returned token, else return
|
||||||
* it exactly as found in the string
|
* it exactly as found in the string
|
||||||
* encoding - the active character-set encoding
|
* encoding - the active character-set encoding
|
||||||
*
|
*
|
||||||
@ -43,6 +44,9 @@ static void strip_quotes(char *source, char quote, char escape, int encoding);
|
|||||||
* a single quote character in the data. If escape isn't 0, then escape
|
* a single quote character in the data. If escape isn't 0, then escape
|
||||||
* followed by anything (except \0) is a data character too.
|
* followed by anything (except \0) is a data character too.
|
||||||
*
|
*
|
||||||
|
* The combination of e_strings and del_quotes both TRUE is not currently
|
||||||
|
* handled. This could be fixed but it's not needed anywhere at the moment.
|
||||||
|
*
|
||||||
* Note that the string s is _not_ overwritten in this implementation.
|
* Note that the string s is _not_ overwritten in this implementation.
|
||||||
*
|
*
|
||||||
* NB: it's okay to vary delim, quote, and escape from one call to the
|
* NB: it's okay to vary delim, quote, and escape from one call to the
|
||||||
@ -55,6 +59,7 @@ strtokx(const char *s,
|
|||||||
const char *delim,
|
const char *delim,
|
||||||
const char *quote,
|
const char *quote,
|
||||||
char escape,
|
char escape,
|
||||||
|
bool e_strings,
|
||||||
bool del_quotes,
|
bool del_quotes,
|
||||||
int encoding)
|
int encoding)
|
||||||
{
|
{
|
||||||
@ -126,13 +131,24 @@ strtokx(const char *s,
|
|||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check for E string */
|
||||||
|
p = start;
|
||||||
|
if (e_strings &&
|
||||||
|
(*p == 'E' || *p == 'e') &&
|
||||||
|
p[1] == '\'')
|
||||||
|
{
|
||||||
|
quote = "'";
|
||||||
|
escape = '\\'; /* if std strings before, not any more */
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
/* test if quoting character */
|
/* test if quoting character */
|
||||||
if (quote && strchr(quote, *start))
|
if (quote && strchr(quote, *p))
|
||||||
{
|
{
|
||||||
/* okay, we have a quoted token, now scan for the closer */
|
/* okay, we have a quoted token, now scan for the closer */
|
||||||
char thisquote = *start;
|
char thisquote = *p++;
|
||||||
|
|
||||||
for (p = start + 1; *p; p += PQmblen(p, encoding))
|
for (; *p; p += PQmblen(p, encoding))
|
||||||
{
|
{
|
||||||
if (*p == escape && p[1] != '\0')
|
if (*p == escape && p[1] != '\0')
|
||||||
p++; /* process escaped anything */
|
p++; /* process escaped anything */
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/psql/stringutils.h,v 1.23 2006/03/05 15:58:52 momjian Exp $
|
* $PostgreSQL: pgsql/src/bin/psql/stringutils.h,v 1.24 2006/06/01 01:28:00 tgl Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef STRINGUTILS_H
|
#ifndef STRINGUTILS_H
|
||||||
#define STRINGUTILS_H
|
#define STRINGUTILS_H
|
||||||
@ -15,6 +15,7 @@ extern char *strtokx(const char *s,
|
|||||||
const char *delim,
|
const char *delim,
|
||||||
const char *quote,
|
const char *quote,
|
||||||
char escape,
|
char escape,
|
||||||
|
bool e_strings,
|
||||||
bool del_quotes,
|
bool del_quotes,
|
||||||
int encoding);
|
int encoding);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user