diff options
Diffstat (limited to 'src/bin/psql/copy.c')
| -rw-r--r-- | src/bin/psql/copy.c | 526 |
1 files changed, 273 insertions, 253 deletions
diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c index d8d11e3267..1d2a24c39f 100644 --- a/src/bin/psql/copy.c +++ b/src/bin/psql/copy.c @@ -8,9 +8,9 @@ #include <errno.h> #include <assert.h> #ifndef WIN32 -#include <unistd.h> /* for isatty */ +#include <unistd.h> /* for isatty */ #else -#include <io.h> /* I think */ +#include <io.h> /* I think */ #endif #include <libpq-fe.h> @@ -33,137 +33,151 @@ * returns a malloc'ed structure with the options, or NULL on parsing error */ -struct copy_options { - char * table; - char * file; - bool from; - bool binary; - bool oids; - char * delim; +struct copy_options +{ + char *table; + char *file; + bool from; + bool binary; + bool oids; + char *delim; }; static void free_copy_options(struct copy_options * ptr) { - if (!ptr) - return; - free(ptr->table); - free(ptr->file); - free(ptr->delim); - free(ptr); + if (!ptr) + return; + free(ptr->table); + free(ptr->file); + free(ptr->delim); + free(ptr); } static struct copy_options * parse_slash_copy(const char *args) { - struct copy_options * result; - char * line; - char * token; - bool error = false; - char quote; - - line = xstrdup(args); - - if (!(result = calloc(1, sizeof (struct copy_options)))) { - perror("calloc"); - exit(EXIT_FAILURE); - } - - token = strtokx(line, " \t", "\"", '\\', "e, NULL); - if (!token) - error = true; - else { - if (!quote && strcasecmp(token, "binary")==0) { - result->binary = true; - token = strtokx(NULL, " \t", "\"", '\\', "e, NULL); - if (!token) + struct copy_options *result; + char *line; + char *token; + bool error = false; + char quote; + + line = xstrdup(args); + + if (!(result = calloc(1, sizeof(struct copy_options)))) + { + perror("calloc"); + exit(EXIT_FAILURE); + } + + token = strtokx(line, " \t", "\"", '\\', "e, NULL); + if (!token) error = true; + else + { + if (!quote && strcasecmp(token, "binary") == 0) + { + result->binary = true; + token = strtokx(NULL, " \t", "\"", '\\', "e, NULL); + if (!token) + error = true; + } + if (token) + result->table = xstrdup(token); } - if (token) - result->table = xstrdup(token); - } #ifdef USE_ASSERT_CHECKING - assert(error || result->table); + assert(error || result->table); #endif - if (!error) { - token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); - if (!token) - error = true; - else { - if (strcasecmp(token, "with")==0) { + if (!error) + { token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); - if (!token || strcasecmp(token, "oids")!=0) - error = true; - else - result->oids = true; - - if (!error) { - token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); - if (!token) + if (!token) error = true; + else + { + if (strcasecmp(token, "with") == 0) + { + token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); + if (!token || strcasecmp(token, "oids") != 0) + error = true; + else + result->oids = true; + + if (!error) + { + token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); + if (!token) + error = true; + } + } + + if (!error && strcasecmp(token, "from") == 0) + result->from = true; + else if (!error && strcasecmp(token, "to") == 0) + result->from = false; + else + error = true; } - } - - if (!error && strcasecmp(token, "from")==0) - result->from = true; - else if (!error && strcasecmp(token, "to")==0) - result->from = false; - else - error = true; } - } - if (!error) { - token = strtokx(NULL, " \t", "'", '\\', NULL, NULL); - if (!token) - error = true; - else - result->file=xstrdup(token); - } + if (!error) + { + token = strtokx(NULL, " \t", "'", '\\', NULL, NULL); + if (!token) + error = true; + else + result->file = xstrdup(token); + } #ifdef USE_ASSERT_CHECKING - assert(error || result->file); + assert(error || result->file); #endif - if (!error) { - token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); - if (token) { - if (strcasecmp(token, "using")!=0) - error = true; - else { + if (!error) + { token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); - if (!token || strcasecmp(token, "delimiters")!=0) - error = true; - else { - token = strtokx(NULL, " \t", "'", '\\', NULL, NULL); - if (token) - result->delim = xstrdup(token); - else - error = true; + if (token) + { + if (strcasecmp(token, "using") != 0) + error = true; + else + { + token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); + if (!token || strcasecmp(token, "delimiters") != 0) + error = true; + else + { + token = strtokx(NULL, " \t", "'", '\\', NULL, NULL); + if (token) + result->delim = xstrdup(token); + else + error = true; + } + } } - } } - } - free(line); + free(line); - if (error) { - fputs("Parse error at ", stderr); - if (!token) - fputs("end of line.", stderr); + if (error) + { + fputs("Parse error at ", stderr); + if (!token) + fputs("end of line.", stderr); + else + fprintf(stderr, "'%s'.", token); + fputs("\n", stderr); + free(result); + return NULL; + } else - fprintf(stderr, "'%s'.", token); - fputs("\n", stderr); - free(result); - return NULL; - } - else - return result; -} + return result; +} @@ -171,103 +185,109 @@ parse_slash_copy(const char *args) * Execute a \copy command (frontend copy). We have to open a file, then * submit a COPY query to the backend and either feed it data from the * file or route its response into the file. - */ + */ bool -do_copy(const char * args, PsqlSettings *pset) +do_copy(const char *args, PsqlSettings *pset) { - char query[128 + NAMEDATALEN]; - FILE *copystream; - struct copy_options *options; - PGresult *result; - bool success; + char query[128 + NAMEDATALEN]; + FILE *copystream; + struct copy_options *options; + PGresult *result; + bool success; - /* parse options */ - options = parse_slash_copy(args); + /* parse options */ + options = parse_slash_copy(args); - if (!options) - return false; + if (!options) + return false; - strcpy(query, "COPY "); - if (options->binary) - fputs("Warning: \\copy binary is not implemented. Resorting to text output.\n", stderr); + strcpy(query, "COPY "); + if (options->binary) + fputs("Warning: \\copy binary is not implemented. Resorting to text output.\n", stderr); /* strcat(query, "BINARY "); */ - strcat(query, "\""); - strncat(query, options->table, NAMEDATALEN); - strcat(query, "\" "); - if (options->oids) - strcat(query, "WITH OIDS "); + strcat(query, "\""); + strncat(query, options->table, NAMEDATALEN); + strcat(query, "\" "); + if (options->oids) + strcat(query, "WITH OIDS "); - if (options->from) - strcat(query, "FROM stdin"); - else - strcat(query, "TO stdout"); + if (options->from) + strcat(query, "FROM stdin"); + else + strcat(query, "TO stdout"); - 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, options->delim); - strcat(query, "'"); - } + 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, options->delim); + strcat(query, "'"); + } - if (options->from) + if (options->from) #ifndef __CYGWIN32__ - copystream = fopen(options->file, "r"); + copystream = fopen(options->file, "r"); #else - copystream = fopen(options->file, "rb"); + copystream = fopen(options->file, "rb"); #endif - else + else #ifndef __CYGWIN32__ - copystream = fopen(options->file, "w"); + copystream = fopen(options->file, "w"); #else - copystream = fopen(options->file, "wb"); + copystream = fopen(options->file, "wb"); #endif - if (!copystream) { - fprintf(stderr, - "Unable to open file %s which to copy: %s\n", - options->from ? "from" : "to", strerror(errno)); - free_copy_options(options); - return false; - } - - result = PSQLexec(pset, query); - - switch (PQresultStatus(result)) - { - case PGRES_COPY_OUT: - success = handleCopyOut(pset->db, copystream); - break; - case PGRES_COPY_IN: - success = handleCopyIn(pset->db, copystream, NULL); - break; - case PGRES_NONFATAL_ERROR: - case PGRES_FATAL_ERROR: - case PGRES_BAD_RESPONSE: - success = false; - fputs(PQerrorMessage(pset->db), stderr); - break; - default: - success = false; - fprintf(stderr, "Unexpected response (%d)\n", PQresultStatus(result)); - } - - PQclear(result); - - if (!GetVariable(pset->vars, "quiet")) { - if (success) - puts("Successfully copied."); - else - puts("Copy failed."); - } + if (!copystream) + { + fprintf(stderr, + "Unable to open file %s which to copy: %s\n", + options->from ? "from" : "to", strerror(errno)); + free_copy_options(options); + return false; + } + + result = PSQLexec(pset, query); + + switch (PQresultStatus(result)) + { + case PGRES_COPY_OUT: + success = handleCopyOut(pset->db, copystream); + break; + case PGRES_COPY_IN: + success = handleCopyIn(pset->db, copystream, NULL); + break; + case PGRES_NONFATAL_ERROR: + case PGRES_FATAL_ERROR: + case PGRES_BAD_RESPONSE: + success = false; + fputs(PQerrorMessage(pset->db), stderr); + break; + default: + success = false; + fprintf(stderr, "Unexpected response (%d)\n", PQresultStatus(result)); + } + + PQclear(result); - fclose(copystream); - free_copy_options(options); - return success; + if (!GetVariable(pset->vars, "quiet")) + { + if (success) + puts("Successfully copied."); + else + puts("Copy failed."); + } + + fclose(copystream); + free_copy_options(options); + return success; } @@ -287,38 +307,38 @@ do_copy(const char * args, PsqlSettings *pset) bool handleCopyOut(PGconn *conn, FILE *copystream) { - bool copydone = false; /* haven't started yet */ - char copybuf[COPYBUFSIZ]; - int ret; - - while (!copydone) - { - ret = PQgetline(conn, copybuf, COPYBUFSIZ); + bool copydone = false; /* haven't started yet */ + char copybuf[COPYBUFSIZ]; + int ret; - if (copybuf[0] == '\\' && - copybuf[1] == '.' && - copybuf[2] == '\0') + while (!copydone) { - copydone = true; /* we're at the end */ - } - else - { - fputs(copybuf, copystream); - switch (ret) - { - case EOF: - copydone = true; - /* FALLTHROUGH */ - case 0: - fputc('\n', copystream); - break; - case 1: - break; - } + ret = PQgetline(conn, copybuf, COPYBUFSIZ); + + if (copybuf[0] == '\\' && + copybuf[1] == '.' && + copybuf[2] == '\0') + { + copydone = true; /* we're at the end */ + } + else + { + fputs(copybuf, copystream); + switch (ret) + { + case EOF: + copydone = true; + /* FALLTHROUGH */ + case 0: + fputc('\n', copystream); + break; + case 1: + break; + } + } } - } - fflush(copystream); - return !PQendcopy(conn); + fflush(copystream); + return !PQendcopy(conn); } @@ -333,58 +353,58 @@ handleCopyOut(PGconn *conn, FILE *copystream) * (and which gave you PGRES_COPY_IN back); * copystream is the file stream you want the input to come from * prompt is something to display to request user input (only makes sense - * if stdin is an interactive tty) + * if stdin is an interactive tty) */ bool -handleCopyIn(PGconn *conn, FILE *copystream, const char * prompt) +handleCopyIn(PGconn *conn, FILE *copystream, const char *prompt) { - bool copydone = false; - bool firstload; - bool linedone; - char copybuf[COPYBUFSIZ]; - char *s; - int buflen; - int c = 0; - - while (!copydone) - { /* for each input line ... */ - if (prompt && isatty(fileno(stdin))) - { - fputs(prompt, stdout); - fflush(stdout); - } - firstload = true; - linedone = false; - while (!linedone) - { /* for each buffer ... */ - s = copybuf; - for (buflen = COPYBUFSIZ; buflen > 1; buflen--) - { - c = getc(copystream); - if (c == '\n' || c == EOF) + bool copydone = false; + bool firstload; + bool linedone; + char copybuf[COPYBUFSIZ]; + char *s; + int buflen; + int c = 0; + + while (!copydone) + { /* for each input line ... */ + if (prompt && isatty(fileno(stdin))) { - linedone = true; - break; + fputs(prompt, stdout); + fflush(stdout); + } + firstload = true; + linedone = false; + while (!linedone) + { /* for each buffer ... */ + s = copybuf; + for (buflen = COPYBUFSIZ; buflen > 1; buflen--) + { + c = getc(copystream); + if (c == '\n' || c == EOF) + { + linedone = true; + break; + } + *s++ = c; + } + *s = '\0'; + if (c == EOF) + { + PQputline(conn, "\\."); + copydone = true; + break; + } + PQputline(conn, copybuf); + if (firstload) + { + if (!strcmp(copybuf, "\\.")) + copydone = true; + firstload = false; + } } - *s++ = c; - } - *s = '\0'; - if (c == EOF) - { - PQputline(conn, "\\."); - copydone = true; - break; - } - PQputline(conn, copybuf); - if (firstload) - { - if (!strcmp(copybuf, "\\.")) - copydone = true; - firstload = false; - } + PQputline(conn, "\n"); } - PQputline(conn, "\n"); - } - return !PQendcopy(conn); + return !PQendcopy(conn); } |
