aboutsummaryrefslogtreecommitdiff
path: root/src/bin/psql/copy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/psql/copy.c')
-rw-r--r--src/bin/psql/copy.c75
1 files changed, 51 insertions, 24 deletions
diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c
index 1d2a24c39f7..800a8f41eda 100644
--- a/src/bin/psql/copy.c
+++ b/src/bin/psql/copy.c
@@ -27,7 +27,7 @@
* parse_slash_copy
* -- parses \copy command line
*
- * Accepted syntax: \copy [binary] table|"table" [with oids] from|to filename|'filename' using delimiters ['<char>']
+ * Accepted syntax: \copy [binary] table|"table" [with oids] from|to filename|'filename' using delimiters ['<char>'] [ with null as 'string' ]
* (binary is not here yet)
*
* returns a malloc'ed structure with the options, or NULL on parsing error
@@ -41,6 +41,7 @@ struct copy_options
bool binary;
bool oids;
char *delim;
+ char *null;
};
@@ -52,12 +53,13 @@ free_copy_options(struct copy_options * ptr)
free(ptr->table);
free(ptr->file);
free(ptr->delim);
+ free(ptr->null);
free(ptr);
}
static struct copy_options *
-parse_slash_copy(const char *args)
+parse_slash_copy(const char *args, PsqlSettings *pset)
{
struct copy_options *result;
char *line;
@@ -78,7 +80,9 @@ parse_slash_copy(const char *args)
error = true;
else
{
- if (!quote && strcasecmp(token, "binary") == 0)
+#ifdef NOT_USED
+ /* this is not implemented yet */
+ if (!quote && strcasecmp(token, "binary") == 0)
{
result->binary = true;
token = strtokx(NULL, " \t", "\"", '\\', &quote, NULL);
@@ -86,6 +90,7 @@ parse_slash_copy(const char *args)
error = true;
}
if (token)
+#endif
result->table = xstrdup(token);
}
@@ -143,9 +148,7 @@ parse_slash_copy(const char *args)
token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL);
if (token)
{
- if (strcasecmp(token, "using") != 0)
- error = true;
- else
+ if (strcasecmp(token, "using") == 0)
{
token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL);
if (!token || strcasecmp(token, "delimiters") != 0)
@@ -154,11 +157,36 @@ parse_slash_copy(const char *args)
{
token = strtokx(NULL, " \t", "'", '\\', NULL, NULL);
if (token)
+ {
result->delim = xstrdup(token);
+ token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL);
+ }
else
error = true;
}
}
+
+ if (!error && token)
+ {
+ if (strcasecmp(token, "with") == 0)
+ {
+ token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL);
+ if (!token || strcasecmp(token, "null") != 0)
+ error = true;
+ else
+ {
+ token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL);
+ if (!token || strcasecmp(token, "as") != 0)
+ error = true;
+ else
+ {
+ token = strtokx(NULL, " \t", "'", '\\', NULL, NULL);
+ if (token)
+ result->null = xstrdup(token);
+ }
+ }
+ }
+ }
}
}
@@ -166,11 +194,13 @@ parse_slash_copy(const char *args)
if (error)
{
- fputs("Parse error at ", stderr);
+ if (!pset->cur_cmd_interactive)
+ fprintf(stderr, "%s: ", pset->progname);
+ fputs("\\copy: parse error at ", stderr);
if (!token)
- fputs("end of line.", stderr);
+ fputs("end of line", stderr);
else
- fprintf(stderr, "'%s'.", token);
+ fprintf(stderr, "'%s'", token);
fputs("\n", stderr);
free(result);
return NULL;
@@ -196,15 +226,14 @@ do_copy(const char *args, PsqlSettings *pset)
bool success;
/* parse options */
- options = parse_slash_copy(args);
+ options = parse_slash_copy(args, pset);
if (!options)
return false;
strcpy(query, "COPY ");
if (options->binary)
- fputs("Warning: \\copy binary is not implemented. Resorting to text output.\n", stderr);
-/* strcat(query, "BINARY "); */
+ strcat(query, "BINARY ");
strcat(query, "\"");
strncat(query, options->table, NAMEDATALEN);
@@ -220,13 +249,7 @@ do_copy(const char *args, PsqlSettings *pset)
if (options->delim)
{
-
- /*
- * backend copy only uses the first character here, but that might
- * be the escape backslash (makes me wonder though why it's called
- * delimiterS)
- */
- strncat(query, " USING DELIMITERS '", 2);
+ strcat(query, " USING DELIMITERS '");
strcat(query, options->delim);
strcat(query, "'");
}
@@ -247,9 +270,11 @@ do_copy(const char *args, PsqlSettings *pset)
if (!copystream)
{
+ if (!pset->cur_cmd_interactive)
+ fprintf(stderr, "%s: ", pset->progname);
fprintf(stderr,
- "Unable to open file %s which to copy: %s\n",
- options->from ? "from" : "to", strerror(errno));
+ "unable to open file %s: %s\n",
+ options->file, strerror(errno));
free_copy_options(options);
return false;
}
@@ -272,7 +297,9 @@ do_copy(const char *args, PsqlSettings *pset)
break;
default:
success = false;
- fprintf(stderr, "Unexpected response (%d)\n", PQresultStatus(result));
+ if (!pset->cur_cmd_interactive)
+ fprintf(stderr, "%s: ", pset->progname);
+ fprintf(stderr, "\\copy: unexpected response (%d)\n", PQresultStatus(result));
}
PQclear(result);
@@ -280,9 +307,9 @@ do_copy(const char *args, PsqlSettings *pset)
if (!GetVariable(pset->vars, "quiet"))
{
if (success)
- puts("Successfully copied.");
+ puts("Successfully copied");
else
- puts("Copy failed.");
+ puts("Copy failed");
}
fclose(copystream);