diff options
Diffstat (limited to 'src/bin/psql/copy.c')
-rw-r--r-- | src/bin/psql/copy.c | 490 |
1 files changed, 0 insertions, 490 deletions
diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c deleted file mode 100644 index 32f875db84d..00000000000 --- a/src/bin/psql/copy.c +++ /dev/null @@ -1,490 +0,0 @@ -/* - * psql - the PostgreSQL interactive terminal - * - * Copyright 2000 by PostgreSQL Global Development Group - * - * $Header: /cvsroot/pgsql/src/bin/psql/copy.c,v 1.23 2002/06/20 16:00:44 momjian Exp $ - */ -#include "postgres_fe.h" -#include "copy.h" - -#include <errno.h> -#include <assert.h> -#include <signal.h> -#include <sys/stat.h> -#ifndef WIN32 -#include <unistd.h> /* for isatty */ -#else -#include <io.h> /* I think */ -#endif - -#include "libpq-fe.h" -#include "pqexpbuffer.h" -#include "pqsignal.h" - -#include "settings.h" -#include "common.h" -#include "stringutils.h" - -#ifdef WIN32 -#define strcasecmp(x,y) stricmp(x,y) -#endif - -bool copy_in_state; - -/* - * parse_slash_copy - * -- parses \copy command line - * - * Accepted syntax: \copy table|"table" [with oids] from|to filename|'filename' [with ] [ oids ] [ delimiter '<char>'] [ null as 'string' ] - * (binary is not here yet) - * - * Old syntax for backward compatibility: (2002-06-19): - * \copy table|"table" [with oids] from|to filename|'filename' [ using delimiters '<char>'] [ with null as 'string' ] - * - * returns a malloc'ed structure with the options, or NULL on parsing error - */ - -struct copy_options -{ - char *table; - char *file; /* NULL = stdin/stdout */ - bool from; - bool binary; - bool oids; - char *delim; - char *null; -}; - - -static void -free_copy_options(struct copy_options * ptr) -{ - if (!ptr) - return; - free(ptr->table); - free(ptr->file); - free(ptr->delim); - free(ptr->null); - 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; - - if (args) - line = xstrdup(args); - else - { - psql_error("\\copy: arguments required\n"); - return NULL; - } - - if (!(result = calloc(1, sizeof(struct copy_options)))) - { - psql_error("out of memory\n"); - exit(EXIT_FAILURE); - } - - token = strtokx(line, " \t\n\r", "\"", '\\', "e, NULL, pset.encoding); - if (!token) - error = true; - else - { -#ifdef NOT_USED - /* this is not implemented yet */ - if (!quote && strcasecmp(token, "binary") == 0) - { - result->binary = true; - token = strtokx(NULL, " \t\n\r", "\"", '\\', "e, NULL, pset.encoding); - if (!token) - error = true; - } - if (token) -#endif - result->table = xstrdup(token); - } - -#ifdef USE_ASSERT_CHECKING - assert(error || result->table); -#endif - - if (!error) - { - token = strtokx(NULL, " \t\n\r", NULL, '\\', NULL, NULL, pset.encoding); - if (!token) - error = true; - else - { - /* Allows old COPY syntax for backward compatibility 2002-06-19 */ - if (strcasecmp(token, "with") == 0) - { - token = strtokx(NULL, " \t\n\r", NULL, '\\', NULL, NULL, pset.encoding); - if (!token || strcasecmp(token, "oids") != 0) - error = true; - else - result->oids = true; - - if (!error) - { - token = strtokx(NULL, " \t\n\r", NULL, '\\', NULL, NULL, pset.encoding); - 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) - { - token = strtokx(NULL, " \t\n\r", "'", '\\', "e, NULL, pset.encoding); - if (!token) - error = true; - else if (!quote && (strcasecmp(token, "stdin") == 0 || strcasecmp(token, "stdout") == 0)) - result->file = NULL; - else - result->file = xstrdup(token); - } - - if (!error) - { - token = strtokx(NULL, " \t\n\r", NULL, '\\', NULL, NULL, pset.encoding); - if (token) - { - /* Allows old COPY syntax for backward compatibility 2002-06-19 */ - if (strcasecmp(token, "using") == 0) - { - token = strtokx(NULL, " \t\n\r", NULL, '\\', NULL, NULL, pset.encoding); - if (token && strcasecmp(token, "delimiters") == 0) - { - token = strtokx(NULL, " \t\n\r", "'", '\\', NULL, NULL, pset.encoding); - if (token) - { - result->delim = xstrdup(token); - token = strtokx(NULL, " \t\n\r", NULL, '\\', NULL, NULL, pset.encoding); - } - else - error = true; - } - else - error = true; - } - } - } - - if (!error && token) - { - if (strcasecmp(token, "with") == 0) - { - while (!error && (token = strtokx(NULL, " \t\n\r", NULL, '\\', NULL, NULL, pset.encoding))) - { - if (strcasecmp(token, "delimiter") == 0) - { - token = strtokx(NULL, " \t\n\r", "'", '\\', NULL, NULL, pset.encoding); - if (token && strcasecmp(token, "as") == 0) - token = strtokx(NULL, " \t\n\r", "'", '\\', NULL, NULL, pset.encoding); - if (token) - result->delim = xstrdup(token); - else - error = true; - } - else if (strcasecmp(token, "null") == 0) - { - token = strtokx(NULL, " \t\n\r", "'", '\\', NULL, NULL, pset.encoding); - if (token && strcasecmp(token, "as") == 0) - token = strtokx(NULL, " \t\n\r", "'", '\\', NULL, NULL, pset.encoding); - if (token) - result->null = xstrdup(token); - else - error = true; - } - else error = true; - } - } - else error = true; - } - - free(line); - - if (error) - { - if (token) - psql_error("\\copy: parse error at '%s'\n", token); - else - psql_error("\\copy: parse error at end of line\n"); - free_copy_options(result); - return NULL; - } - else - return result; -} - - - -/* - * 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) -{ - PQExpBufferData query; - FILE *copystream; - struct copy_options *options; - PGresult *result; - bool success; - struct stat st; - - /* parse options */ - options = parse_slash_copy(args); - - if (!options) - return false; - - initPQExpBuffer(&query); - - printfPQExpBuffer(&query, "COPY "); - if (options->binary) - appendPQExpBuffer(&query, "BINARY "); - - appendPQExpBuffer(&query, "\"%s\" ", options->table); - /* Uses old COPY syntax for backward compatibility 2002-06-19 */ - if (options->oids) - appendPQExpBuffer(&query, "WITH OIDS "); - - if (options->from) - appendPQExpBuffer(&query, "FROM STDIN"); - else - appendPQExpBuffer(&query, "TO STDOUT"); - - - /* Uses old COPY syntax for backward compatibility 2002-06-19 */ - if (options->delim) - appendPQExpBuffer(&query, " USING DELIMITERS '%s'", options->delim); - - if (options->null) - appendPQExpBuffer(&query, " WITH NULL AS '%s'", options->null); - - if (options->from) - { - if (options->file) - copystream = fopen(options->file, "r"); - else - copystream = stdin; - } - else - { - if (options->file) - copystream = fopen(options->file, "w"); - else - copystream = stdout; - } - - if (!copystream) - { - psql_error("%s: %s\n", - options->file, strerror(errno)); - free_copy_options(options); - return false; - } - - /* make sure the specified file is not a directory */ - fstat(fileno(copystream), &st); - if( S_ISDIR(st.st_mode) ) - { - fclose(copystream); - psql_error("%s: cannot COPY TO/FROM a directory\n", - options->file); - free_copy_options(options); - return false; - } - - result = PSQLexec(query.data); - termPQExpBuffer(&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; - psql_error("\\copy: %s", PQerrorMessage(pset.db)); - break; - default: - success = false; - psql_error("\\copy: unexpected response (%d)\n", PQresultStatus(result)); - } - - PQclear(result); - - if (copystream != stdout && copystream != stdin) - fclose(copystream); - free_copy_options(options); - return success; -} - - -#define COPYBUFSIZ 8192 /* size doesn't matter */ - - -/* - * handleCopyOut - * receives data as a result of a COPY ... TO stdout command - * - * If you want to use COPY TO in your application, this is the code to steal :) - * - * conn should be a database connection that you just called COPY TO on - * (and which gave you PGRES_COPY_OUT back); - * copystream is the file stream you want the output to go to - */ -bool -handleCopyOut(PGconn *conn, FILE *copystream) -{ - bool copydone = false; /* haven't started yet */ - char copybuf[COPYBUFSIZ]; - int ret; - - assert(cancelConn); - - while (!copydone) - { - 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); - ret = !PQendcopy(conn); - cancelConn = NULL; - return ret; -} - - - -/* - * handleCopyIn - * receives data as a result of a COPY ... FROM stdin command - * - * Again, if you want to use COPY FROM in your application, copy this. - * - * conn should be a database connection that you just called COPY FROM on - * (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) - */ - -bool -handleCopyIn(PGconn *conn, FILE *copystream, const char *prompt) -{ - bool copydone = false; - bool firstload; - bool linedone; - char copybuf[COPYBUFSIZ]; - char *s; - int bufleft; - int c = 0; - int ret; - unsigned int linecount = 0; - -#ifdef USE_ASSERT_CHECKING - assert(copy_in_state); -#endif - - if (prompt) /* disable prompt if not interactive */ - { - if (!isatty(fileno(copystream))) - prompt = NULL; - } - - while (!copydone) - { /* for each input line ... */ - if (prompt) - { - fputs(prompt, stdout); - fflush(stdout); - } - firstload = true; - linedone = false; - - while (!linedone) - { /* for each bufferload in line ... */ - s = copybuf; - for (bufleft = COPYBUFSIZ - 1; bufleft > 0; bufleft--) - { - c = getc(copystream); - if (c == '\n' || c == EOF) - { - linedone = true; - break; - } - *s++ = c; - } - *s = '\0'; - if (c == EOF && s == copybuf && firstload) - { - PQputline(conn, "\\."); - copydone = true; - if (pset.cur_cmd_interactive) - puts("\\."); - break; - } - PQputline(conn, copybuf); - if (firstload) - { - if (!strcmp(copybuf, "\\.")) - { - copydone = true; - break; - } - firstload = false; - } - } - PQputline(conn, "\n"); - linecount++; - } - ret = !PQendcopy(conn); - copy_in_state = false; - pset.lineno += linecount; - return ret; -} |