Header And Logo

PostgreSQL
| The world's most advanced open source database.

copy.c

Go to the documentation of this file.
00001 /*
00002  * psql - the PostgreSQL interactive terminal
00003  *
00004  * Copyright (c) 2000-2013, PostgreSQL Global Development Group
00005  *
00006  * src/bin/psql/copy.c
00007  */
00008 #include "postgres_fe.h"
00009 #include "copy.h"
00010 
00011 #include <signal.h>
00012 #include <sys/stat.h>
00013 #ifndef WIN32
00014 #include <unistd.h>             /* for isatty */
00015 #else
00016 #include <io.h>                 /* I think */
00017 #endif
00018 
00019 #include "libpq-fe.h"
00020 #include "pqexpbuffer.h"
00021 #include "dumputils.h"
00022 
00023 #include "settings.h"
00024 #include "common.h"
00025 #include "prompt.h"
00026 #include "stringutils.h"
00027 
00028 
00029 /*
00030  * parse_slash_copy
00031  * -- parses \copy command line
00032  *
00033  * The documented syntax is:
00034  *  \copy tablename [(columnlist)] from|to filename [options]
00035  *  \copy ( select stmt ) to filename [options]
00036  *
00037  * where 'filename' can be one of the following:
00038  *  '<file path>' | PROGRAM '<command>' | stdin | stdout | pstdout | pstdout
00039  *
00040  * An undocumented fact is that you can still write BINARY before the
00041  * tablename; this is a hangover from the pre-7.3 syntax.  The options
00042  * syntax varies across backend versions, but we avoid all that mess
00043  * by just transmitting the stuff after the filename literally.
00044  *
00045  * table name can be double-quoted and can have a schema part.
00046  * column names can be double-quoted.
00047  * filename can be single-quoted like SQL literals.
00048  * command must be single-quoted like SQL literals.
00049  *
00050  * returns a malloc'ed structure with the options, or NULL on parsing error
00051  */
00052 
00053 struct copy_options
00054 {
00055     char       *before_tofrom;  /* COPY string before TO/FROM */
00056     char       *after_tofrom;   /* COPY string after TO/FROM filename */
00057     char       *file;           /* NULL = stdin/stdout */
00058     bool        program;        /* is 'file' a program to popen? */
00059     bool        psql_inout;     /* true = use psql stdin/stdout */
00060     bool        from;           /* true = FROM, false = TO */
00061 };
00062 
00063 
00064 static void
00065 free_copy_options(struct copy_options * ptr)
00066 {
00067     if (!ptr)
00068         return;
00069     free(ptr->before_tofrom);
00070     free(ptr->after_tofrom);
00071     free(ptr->file);
00072     free(ptr);
00073 }
00074 
00075 
00076 /* concatenate "more" onto "var", freeing the original value of *var */
00077 static void
00078 xstrcat(char **var, const char *more)
00079 {
00080     char       *newvar;
00081 
00082     newvar = pg_malloc(strlen(*var) + strlen(more) + 1);
00083     strcpy(newvar, *var);
00084     strcat(newvar, more);
00085     free(*var);
00086     *var = newvar;
00087 }
00088 
00089 
00090 static struct copy_options *
00091 parse_slash_copy(const char *args)
00092 {
00093     struct copy_options *result;
00094     char       *token;
00095     const char *whitespace = " \t\n\r";
00096     char        nonstd_backslash = standard_strings() ? 0 : '\\';
00097 
00098     if (!args)
00099     {
00100         psql_error("\\copy: arguments required\n");
00101         return NULL;
00102     }
00103 
00104     result = pg_malloc0(sizeof(struct copy_options));
00105 
00106     result->before_tofrom = pg_strdup("");      /* initialize for appending */
00107 
00108     token = strtokx(args, whitespace, ".,()", "\"",
00109                     0, false, false, pset.encoding);
00110     if (!token)
00111         goto error;
00112 
00113     /* The following can be removed when we drop 7.3 syntax support */
00114     if (pg_strcasecmp(token, "binary") == 0)
00115     {
00116         xstrcat(&result->before_tofrom, token);
00117         token = strtokx(NULL, whitespace, ".,()", "\"",
00118                         0, false, false, pset.encoding);
00119         if (!token)
00120             goto error;
00121     }
00122 
00123     /* Handle COPY (SELECT) case */
00124     if (token[0] == '(')
00125     {
00126         int         parens = 1;
00127 
00128         while (parens > 0)
00129         {
00130             xstrcat(&result->before_tofrom, " ");
00131             xstrcat(&result->before_tofrom, token);
00132             token = strtokx(NULL, whitespace, "()", "\"'",
00133                             nonstd_backslash, true, false, pset.encoding);
00134             if (!token)
00135                 goto error;
00136             if (token[0] == '(')
00137                 parens++;
00138             else if (token[0] == ')')
00139                 parens--;
00140         }
00141     }
00142 
00143     xstrcat(&result->before_tofrom, " ");
00144     xstrcat(&result->before_tofrom, token);
00145     token = strtokx(NULL, whitespace, ".,()", "\"",
00146                     0, false, false, pset.encoding);
00147     if (!token)
00148         goto error;
00149 
00150     /*
00151      * strtokx() will not have returned a multi-character token starting with
00152      * '.', so we don't need strcmp() here.  Likewise for '(', etc, below.
00153      */
00154     if (token[0] == '.')
00155     {
00156         /* handle schema . table */
00157         xstrcat(&result->before_tofrom, token);
00158         token = strtokx(NULL, whitespace, ".,()", "\"",
00159                         0, false, false, pset.encoding);
00160         if (!token)
00161             goto error;
00162         xstrcat(&result->before_tofrom, token);
00163         token = strtokx(NULL, whitespace, ".,()", "\"",
00164                         0, false, false, pset.encoding);
00165         if (!token)
00166             goto error;
00167     }
00168 
00169     if (token[0] == '(')
00170     {
00171         /* handle parenthesized column list */
00172         for (;;)
00173         {
00174             xstrcat(&result->before_tofrom, " ");
00175             xstrcat(&result->before_tofrom, token);
00176             token = strtokx(NULL, whitespace, "()", "\"",
00177                             0, false, false, pset.encoding);
00178             if (!token)
00179                 goto error;
00180             if (token[0] == ')')
00181                 break;
00182         }
00183         xstrcat(&result->before_tofrom, " ");
00184         xstrcat(&result->before_tofrom, token);
00185         token = strtokx(NULL, whitespace, ".,()", "\"",
00186                         0, false, false, pset.encoding);
00187         if (!token)
00188             goto error;
00189     }
00190 
00191     if (pg_strcasecmp(token, "from") == 0)
00192         result->from = true;
00193     else if (pg_strcasecmp(token, "to") == 0)
00194         result->from = false;
00195     else
00196         goto error;
00197 
00198     /* { 'filename' | PROGRAM 'command' | STDIN | STDOUT | PSTDIN | PSTDOUT } */
00199     token = strtokx(NULL, whitespace, NULL, "'",
00200                     0, false, false, pset.encoding);
00201     if (!token)
00202         goto error;
00203 
00204     if (pg_strcasecmp(token, "program") == 0)
00205     {
00206         int toklen;
00207 
00208         token = strtokx(NULL, whitespace, NULL, "'",
00209                         0, false, false, pset.encoding);
00210         if (!token)
00211             goto error;
00212 
00213         /*
00214          * The shell command must be quoted. This isn't fool-proof, but catches
00215          * most quoting errors.
00216          */
00217         toklen = strlen(token);
00218         if (token[0] != '\'' || toklen < 2 || token[toklen - 1] != '\'')
00219             goto error;
00220 
00221         strip_quotes(token, '\'', 0, pset.encoding);
00222 
00223         result->program = true;
00224         result->file = pg_strdup(token);
00225     }
00226     else if (pg_strcasecmp(token, "stdin") == 0 ||
00227              pg_strcasecmp(token, "stdout") == 0)
00228     {
00229         result->file = NULL;
00230     }
00231     else if (pg_strcasecmp(token, "pstdin") == 0 ||
00232              pg_strcasecmp(token, "pstdout") == 0)
00233     {
00234         result->psql_inout = true;
00235         result->file = NULL;
00236     }
00237     else
00238     {
00239         /* filename can be optionally quoted */
00240         strip_quotes(token, '\'', 0, pset.encoding);
00241         result->file = pg_strdup(token);
00242         expand_tilde(&result->file);
00243     }
00244 
00245     /* Collect the rest of the line (COPY options) */
00246     token = strtokx(NULL, "", NULL, NULL,
00247                     0, false, false, pset.encoding);
00248     if (token)
00249         result->after_tofrom = pg_strdup(token);
00250 
00251     return result;
00252 
00253 error:
00254     if (token)
00255         psql_error("\\copy: parse error at \"%s\"\n", token);
00256     else
00257         psql_error("\\copy: parse error at end of line\n");
00258     free_copy_options(result);
00259 
00260     return NULL;
00261 }
00262 
00263 
00264 /*
00265  * Execute a \copy command (frontend copy). We have to open a file (or execute
00266  * a command), then submit a COPY query to the backend and either feed it data
00267  * from the file or route its response into the file.
00268  */
00269 bool
00270 do_copy(const char *args)
00271 {
00272     PQExpBufferData query;
00273     FILE       *copystream;
00274     FILE       *save_file;
00275     FILE      **override_file;
00276     struct copy_options *options;
00277     bool        success;
00278     struct stat st;
00279 
00280     /* parse options */
00281     options = parse_slash_copy(args);
00282 
00283     if (!options)
00284         return false;
00285 
00286     /* prepare to read or write the target file */
00287     if (options->file && !options->program)
00288         canonicalize_path(options->file);
00289 
00290     if (options->from)
00291     {
00292         override_file = &pset.cur_cmd_source;
00293 
00294         if (options->file)
00295         {
00296             if (options->program)
00297             {
00298                 fflush(stdout);
00299                 fflush(stderr);
00300                 errno = 0;
00301                 copystream = popen(options->file, PG_BINARY_R);
00302             }
00303             else
00304                 copystream = fopen(options->file, PG_BINARY_R);
00305         }
00306         else if (!options->psql_inout)
00307             copystream = pset.cur_cmd_source;
00308         else
00309             copystream = stdin;
00310     }
00311     else
00312     {
00313         override_file = &pset.queryFout;
00314 
00315         if (options->file)
00316         {
00317             if (options->program)
00318             {
00319                 fflush(stdout);
00320                 fflush(stderr);
00321                 errno = 0;
00322 #ifndef WIN32
00323                 pqsignal(SIGPIPE, SIG_IGN);
00324 #endif
00325                 copystream = popen(options->file, PG_BINARY_W);
00326             }
00327             else
00328                 copystream = fopen(options->file, PG_BINARY_W);
00329         }
00330         else if (!options->psql_inout)
00331             copystream = pset.queryFout;
00332         else
00333             copystream = stdout;
00334     }
00335 
00336     if (!copystream)
00337     {
00338         if (options->program)
00339             psql_error("could not execute command \"%s\": %s\n",
00340                        options->file, strerror(errno));
00341         else
00342             psql_error("%s: %s\n",
00343                        options->file, strerror(errno));
00344         free_copy_options(options);
00345         return false;
00346     }
00347 
00348     if (!options->program)
00349     {
00350         /* make sure the specified file is not a directory */
00351         fstat(fileno(copystream), &st);
00352         if (S_ISDIR(st.st_mode))
00353         {
00354             fclose(copystream);
00355             psql_error("%s: cannot copy from/to a directory\n",
00356                        options->file);
00357             free_copy_options(options);
00358             return false;
00359         }
00360     }
00361 
00362     /* build the command we will send to the backend */
00363     initPQExpBuffer(&query);
00364     printfPQExpBuffer(&query, "COPY ");
00365     appendPQExpBufferStr(&query, options->before_tofrom);
00366     if (options->from)
00367         appendPQExpBuffer(&query, " FROM STDIN ");
00368     else
00369         appendPQExpBuffer(&query, " TO STDOUT ");
00370     if (options->after_tofrom)
00371         appendPQExpBufferStr(&query, options->after_tofrom);
00372 
00373     /* Run it like a user command, interposing the data source or sink. */
00374     save_file = *override_file;
00375     *override_file = copystream;
00376     success = SendQuery(query.data);
00377     *override_file = save_file;
00378     termPQExpBuffer(&query);
00379 
00380     if (options->file != NULL)
00381     {
00382         if (options->program)
00383         {
00384             int pclose_rc = pclose(copystream);
00385             if (pclose_rc != 0)
00386             {
00387                 if (pclose_rc < 0)
00388                     psql_error("could not close pipe to external command: %s\n",
00389                                strerror(errno));
00390                 else
00391                 {
00392                     char *reason = wait_result_to_str(pclose_rc);
00393                     psql_error("%s: %s\n", options->file,
00394                                reason ? reason : "");
00395                     if (reason)
00396                         free(reason);
00397                 }
00398                 success = false;
00399             }
00400 #ifndef WIN32
00401             pqsignal(SIGPIPE, SIG_DFL);
00402 #endif
00403         }
00404         else
00405         {
00406             if (fclose(copystream) != 0)
00407             {
00408                 psql_error("%s: %s\n", options->file, strerror(errno));
00409                 success = false;
00410             }
00411         }
00412     }
00413     free_copy_options(options);
00414     return success;
00415 }
00416 
00417 
00418 /*
00419  * Functions for handling COPY IN/OUT data transfer.
00420  *
00421  * If you want to use COPY TO STDOUT/FROM STDIN in your application,
00422  * this is the code to steal ;)
00423  */
00424 
00425 /*
00426  * handleCopyOut
00427  * receives data as a result of a COPY ... TO STDOUT command
00428  *
00429  * conn should be a database connection that you just issued COPY TO on
00430  * and got back a PGRES_COPY_OUT result.
00431  * copystream is the file stream for the data to go to.
00432  *
00433  * result is true if successful, false if not.
00434  */
00435 bool
00436 handleCopyOut(PGconn *conn, FILE *copystream)
00437 {
00438     bool        OK = true;
00439     char       *buf;
00440     int         ret;
00441     PGresult   *res;
00442 
00443     for (;;)
00444     {
00445         ret = PQgetCopyData(conn, &buf, 0);
00446 
00447         if (ret < 0)
00448             break;              /* done or error */
00449 
00450         if (buf)
00451         {
00452             if (fwrite(buf, 1, ret, copystream) != ret)
00453             {
00454                 if (OK)         /* complain only once, keep reading data */
00455                     psql_error("could not write COPY data: %s\n",
00456                                strerror(errno));
00457                 OK = false;
00458             }
00459             PQfreemem(buf);
00460         }
00461     }
00462 
00463     if (OK && fflush(copystream))
00464     {
00465         psql_error("could not write COPY data: %s\n",
00466                    strerror(errno));
00467         OK = false;
00468     }
00469 
00470     if (ret == -2)
00471     {
00472         psql_error("COPY data transfer failed: %s", PQerrorMessage(conn));
00473         OK = false;
00474     }
00475 
00476     /*
00477      * Check command status and return to normal libpq state.  After a
00478      * client-side error, the server will remain ready to deliver data.  The
00479      * cleanest thing is to fully drain and discard that data.  If the
00480      * client-side error happened early in a large file, this takes a long
00481      * time.  Instead, take advantage of the fact that PQexec() will silently
00482      * end any ongoing PGRES_COPY_OUT state.  This does cause us to lose the
00483      * results of any commands following the COPY in a single command string.
00484      * It also only works for protocol version 3.  XXX should we clean up
00485      * using the slow way when the connection is using protocol version 2?
00486      *
00487      * We must not ever return with the status still PGRES_COPY_OUT.  Our
00488      * caller is unable to distinguish that situation from reaching the next
00489      * COPY in a command string that happened to contain two consecutive COPY
00490      * TO STDOUT commands.  We trust that no condition can make PQexec() fail
00491      * indefinitely while retaining status PGRES_COPY_OUT.
00492      */
00493     while (res = PQgetResult(conn), PQresultStatus(res) == PGRES_COPY_OUT)
00494     {
00495         OK = false;
00496         PQclear(res);
00497 
00498         PQexec(conn, "-- clear PGRES_COPY_OUT state");
00499     }
00500     if (PQresultStatus(res) != PGRES_COMMAND_OK)
00501     {
00502         psql_error("%s", PQerrorMessage(conn));
00503         OK = false;
00504     }
00505     PQclear(res);
00506 
00507     return OK;
00508 }
00509 
00510 /*
00511  * handleCopyIn
00512  * sends data to complete a COPY ... FROM STDIN command
00513  *
00514  * conn should be a database connection that you just issued COPY FROM on
00515  * and got back a PGRES_COPY_IN result.
00516  * copystream is the file stream to read the data from.
00517  * isbinary can be set from PQbinaryTuples().
00518  *
00519  * result is true if successful, false if not.
00520  */
00521 
00522 /* read chunk size for COPY IN - size is not critical */
00523 #define COPYBUFSIZ 8192
00524 
00525 bool
00526 handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary)
00527 {
00528     bool        OK;
00529     const char *prompt;
00530     char        buf[COPYBUFSIZ];
00531     PGresult   *res;
00532 
00533     /*
00534      * Establish longjmp destination for exiting from wait-for-input. (This is
00535      * only effective while sigint_interrupt_enabled is TRUE.)
00536      */
00537     if (sigsetjmp(sigint_interrupt_jmp, 1) != 0)
00538     {
00539         /* got here with longjmp */
00540 
00541         /* Terminate data transfer */
00542         PQputCopyEnd(conn, _("canceled by user"));
00543 
00544         OK = false;
00545         goto copyin_cleanup;
00546     }
00547 
00548     /* Prompt if interactive input */
00549     if (isatty(fileno(copystream)))
00550     {
00551         if (!pset.quiet)
00552             puts(_("Enter data to be copied followed by a newline.\n"
00553                    "End with a backslash and a period on a line by itself."));
00554         prompt = get_prompt(PROMPT_COPY);
00555     }
00556     else
00557         prompt = NULL;
00558 
00559     OK = true;
00560 
00561     if (isbinary)
00562     {
00563         /* interactive input probably silly, but give one prompt anyway */
00564         if (prompt)
00565         {
00566             fputs(prompt, stdout);
00567             fflush(stdout);
00568         }
00569 
00570         for (;;)
00571         {
00572             int         buflen;
00573 
00574             /* enable longjmp while waiting for input */
00575             sigint_interrupt_enabled = true;
00576 
00577             buflen = fread(buf, 1, COPYBUFSIZ, copystream);
00578 
00579             sigint_interrupt_enabled = false;
00580 
00581             if (buflen <= 0)
00582                 break;
00583 
00584             if (PQputCopyData(conn, buf, buflen) <= 0)
00585             {
00586                 OK = false;
00587                 break;
00588             }
00589         }
00590     }
00591     else
00592     {
00593         bool        copydone = false;
00594 
00595         while (!copydone)
00596         {                       /* for each input line ... */
00597             bool        firstload;
00598             bool        linedone;
00599 
00600             if (prompt)
00601             {
00602                 fputs(prompt, stdout);
00603                 fflush(stdout);
00604             }
00605 
00606             firstload = true;
00607             linedone = false;
00608 
00609             while (!linedone)
00610             {                   /* for each bufferload in line ... */
00611                 int         linelen;
00612                 char       *fgresult;
00613 
00614                 /* enable longjmp while waiting for input */
00615                 sigint_interrupt_enabled = true;
00616 
00617                 fgresult = fgets(buf, sizeof(buf), copystream);
00618 
00619                 sigint_interrupt_enabled = false;
00620 
00621                 if (!fgresult)
00622                 {
00623                     copydone = true;
00624                     break;
00625                 }
00626 
00627                 linelen = strlen(buf);
00628 
00629                 /* current line is done? */
00630                 if (linelen > 0 && buf[linelen - 1] == '\n')
00631                     linedone = true;
00632 
00633                 /* check for EOF marker, but not on a partial line */
00634                 if (firstload)
00635                 {
00636                     if (strcmp(buf, "\\.\n") == 0 ||
00637                         strcmp(buf, "\\.\r\n") == 0)
00638                     {
00639                         copydone = true;
00640                         break;
00641                     }
00642 
00643                     firstload = false;
00644                 }
00645 
00646                 if (PQputCopyData(conn, buf, linelen) <= 0)
00647                 {
00648                     OK = false;
00649                     copydone = true;
00650                     break;
00651                 }
00652             }
00653 
00654             if (copystream == pset.cur_cmd_source)
00655                 pset.lineno++;
00656         }
00657     }
00658 
00659     /* Check for read error */
00660     if (ferror(copystream))
00661         OK = false;
00662 
00663     /* Terminate data transfer */
00664     if (PQputCopyEnd(conn,
00665                      OK ? NULL : _("aborted because of read failure")) <= 0)
00666         OK = false;
00667 
00668 copyin_cleanup:
00669 
00670     /*
00671      * Check command status and return to normal libpq state
00672      *
00673      * We must not ever return with the status still PGRES_COPY_IN.  Our
00674      * caller is unable to distinguish that situation from reaching the next
00675      * COPY in a command string that happened to contain two consecutive COPY
00676      * FROM STDIN commands.  XXX if something makes PQputCopyEnd() fail
00677      * indefinitely while retaining status PGRES_COPY_IN, we get an infinite
00678      * loop.  This is more realistic than handleCopyOut()'s counterpart risk.
00679      */
00680     while (res = PQgetResult(conn), PQresultStatus(res) == PGRES_COPY_IN)
00681     {
00682         OK = false;
00683         PQclear(res);
00684 
00685         PQputCopyEnd(pset.db, _("trying to exit copy mode"));
00686     }
00687     if (PQresultStatus(res) != PGRES_COMMAND_OK)
00688     {
00689         psql_error("%s", PQerrorMessage(conn));
00690         OK = false;
00691     }
00692     PQclear(res);
00693 
00694     return OK;
00695 }