LCOV - code coverage report
Current view: top level - src/bin/psql - copy.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 134 276 48.6 %
Date: 2017-09-29 13:40:31 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * psql - the PostgreSQL interactive terminal
       3             :  *
       4             :  * Copyright (c) 2000-2017, PostgreSQL Global Development Group
       5             :  *
       6             :  * src/bin/psql/copy.c
       7             :  */
       8             : #include "postgres_fe.h"
       9             : #include "copy.h"
      10             : 
      11             : #include <signal.h>
      12             : #include <sys/stat.h>
      13             : #ifndef WIN32
      14             : #include <unistd.h>               /* for isatty */
      15             : #else
      16             : #include <io.h>                   /* I think */
      17             : #endif
      18             : 
      19             : #include "libpq-fe.h"
      20             : #include "pqexpbuffer.h"
      21             : 
      22             : #include "settings.h"
      23             : #include "common.h"
      24             : #include "prompt.h"
      25             : #include "stringutils.h"
      26             : 
      27             : 
      28             : /*
      29             :  * parse_slash_copy
      30             :  * -- parses \copy command line
      31             :  *
      32             :  * The documented syntax is:
      33             :  *  \copy tablename [(columnlist)] from|to filename [options]
      34             :  *  \copy ( query stmt ) to filename [options]
      35             :  *
      36             :  * where 'filename' can be one of the following:
      37             :  *  '<file path>' | PROGRAM '<command>' | stdin | stdout | pstdout | pstdout
      38             :  * and 'query' can be one of the following:
      39             :  *  SELECT | UPDATE | INSERT | DELETE
      40             :  *
      41             :  * An undocumented fact is that you can still write BINARY before the
      42             :  * tablename; this is a hangover from the pre-7.3 syntax.  The options
      43             :  * syntax varies across backend versions, but we avoid all that mess
      44             :  * by just transmitting the stuff after the filename literally.
      45             :  *
      46             :  * table name can be double-quoted and can have a schema part.
      47             :  * column names can be double-quoted.
      48             :  * filename can be single-quoted like SQL literals.
      49             :  * command must be single-quoted like SQL literals.
      50             :  *
      51             :  * returns a malloc'ed structure with the options, or NULL on parsing error
      52             :  */
      53             : 
      54             : struct copy_options
      55             : {
      56             :     char       *before_tofrom;  /* COPY string before TO/FROM */
      57             :     char       *after_tofrom;   /* COPY string after TO/FROM filename */
      58             :     char       *file;           /* NULL = stdin/stdout */
      59             :     bool        program;        /* is 'file' a program to popen? */
      60             :     bool        psql_inout;     /* true = use psql stdin/stdout */
      61             :     bool        from;           /* true = FROM, false = TO */
      62             : };
      63             : 
      64             : 
      65             : static void
      66          11 : free_copy_options(struct copy_options *ptr)
      67             : {
      68          11 :     if (!ptr)
      69          11 :         return;
      70          11 :     free(ptr->before_tofrom);
      71          11 :     free(ptr->after_tofrom);
      72          11 :     free(ptr->file);
      73          11 :     free(ptr);
      74             : }
      75             : 
      76             : 
      77             : /* concatenate "more" onto "var", freeing the original value of *var */
      78             : static void
      79         136 : xstrcat(char **var, const char *more)
      80             : {
      81             :     char       *newvar;
      82             : 
      83         136 :     newvar = psprintf("%s%s", *var, more);
      84         136 :     free(*var);
      85         136 :     *var = newvar;
      86         136 : }
      87             : 
      88             : 
      89             : static struct copy_options *
      90          11 : parse_slash_copy(const char *args)
      91             : {
      92             :     struct copy_options *result;
      93             :     char       *token;
      94          11 :     const char *whitespace = " \t\n\r";
      95          11 :     char        nonstd_backslash = standard_strings() ? 0 : '\\';
      96             : 
      97          11 :     if (!args)
      98             :     {
      99           0 :         psql_error("\\copy: arguments required\n");
     100           0 :         return NULL;
     101             :     }
     102             : 
     103          11 :     result = pg_malloc0(sizeof(struct copy_options));
     104             : 
     105          11 :     result->before_tofrom = pg_strdup(""); /* initialize for appending */
     106             : 
     107          11 :     token = strtokx(args, whitespace, ".,()", "\"",
     108             :                     0, false, false, pset.encoding);
     109          11 :     if (!token)
     110           0 :         goto error;
     111             : 
     112             :     /* The following can be removed when we drop 7.3 syntax support */
     113          11 :     if (pg_strcasecmp(token, "binary") == 0)
     114             :     {
     115           0 :         xstrcat(&result->before_tofrom, token);
     116           0 :         token = strtokx(NULL, whitespace, ".,()", "\"",
     117             :                         0, false, false, pset.encoding);
     118           0 :         if (!token)
     119           0 :             goto error;
     120             :     }
     121             : 
     122             :     /* Handle COPY (query) case */
     123          11 :     if (token[0] == '(')
     124             :     {
     125           4 :         int         parens = 1;
     126             : 
     127          65 :         while (parens > 0)
     128             :         {
     129          57 :             xstrcat(&result->before_tofrom, " ");
     130          57 :             xstrcat(&result->before_tofrom, token);
     131          57 :             token = strtokx(NULL, whitespace, "()", "\"'",
     132             :                             nonstd_backslash, true, false, pset.encoding);
     133          57 :             if (!token)
     134           0 :                 goto error;
     135          57 :             if (token[0] == '(')
     136           3 :                 parens++;
     137          54 :             else if (token[0] == ')')
     138           7 :                 parens--;
     139             :         }
     140             :     }
     141             : 
     142          11 :     xstrcat(&result->before_tofrom, " ");
     143          11 :     xstrcat(&result->before_tofrom, token);
     144          11 :     token = strtokx(NULL, whitespace, ".,()", "\"",
     145             :                     0, false, false, pset.encoding);
     146          11 :     if (!token)
     147           0 :         goto error;
     148             : 
     149             :     /*
     150             :      * strtokx() will not have returned a multi-character token starting with
     151             :      * '.', so we don't need strcmp() here.  Likewise for '(', etc, below.
     152             :      */
     153          11 :     if (token[0] == '.')
     154             :     {
     155             :         /* handle schema . table */
     156           0 :         xstrcat(&result->before_tofrom, token);
     157           0 :         token = strtokx(NULL, whitespace, ".,()", "\"",
     158             :                         0, false, false, pset.encoding);
     159           0 :         if (!token)
     160           0 :             goto error;
     161           0 :         xstrcat(&result->before_tofrom, token);
     162           0 :         token = strtokx(NULL, whitespace, ".,()", "\"",
     163             :                         0, false, false, pset.encoding);
     164           0 :         if (!token)
     165           0 :             goto error;
     166             :     }
     167             : 
     168          11 :     if (token[0] == '(')
     169             :     {
     170             :         /* handle parenthesized column list */
     171             :         for (;;)
     172             :         {
     173           0 :             xstrcat(&result->before_tofrom, " ");
     174           0 :             xstrcat(&result->before_tofrom, token);
     175           0 :             token = strtokx(NULL, whitespace, "()", "\"",
     176             :                             0, false, false, pset.encoding);
     177           0 :             if (!token)
     178           0 :                 goto error;
     179           0 :             if (token[0] == ')')
     180           0 :                 break;
     181           0 :         }
     182           0 :         xstrcat(&result->before_tofrom, " ");
     183           0 :         xstrcat(&result->before_tofrom, token);
     184           0 :         token = strtokx(NULL, whitespace, ".,()", "\"",
     185             :                         0, false, false, pset.encoding);
     186           0 :         if (!token)
     187           0 :             goto error;
     188             :     }
     189             : 
     190          11 :     if (pg_strcasecmp(token, "from") == 0)
     191           1 :         result->from = true;
     192          10 :     else if (pg_strcasecmp(token, "to") == 0)
     193          10 :         result->from = false;
     194             :     else
     195           0 :         goto error;
     196             : 
     197             :     /* { 'filename' | PROGRAM 'command' | STDIN | STDOUT | PSTDIN | PSTDOUT } */
     198          11 :     token = strtokx(NULL, whitespace, ";", "'",
     199             :                     0, false, false, pset.encoding);
     200          11 :     if (!token)
     201           0 :         goto error;
     202             : 
     203          11 :     if (pg_strcasecmp(token, "program") == 0)
     204             :     {
     205             :         int         toklen;
     206             : 
     207           0 :         token = strtokx(NULL, whitespace, ";", "'",
     208             :                         0, false, false, pset.encoding);
     209           0 :         if (!token)
     210           0 :             goto error;
     211             : 
     212             :         /*
     213             :          * The shell command must be quoted. This isn't fool-proof, but
     214             :          * catches most quoting errors.
     215             :          */
     216           0 :         toklen = strlen(token);
     217           0 :         if (token[0] != '\'' || toklen < 2 || token[toklen - 1] != '\'')
     218             :             goto error;
     219             : 
     220           0 :         strip_quotes(token, '\'', 0, pset.encoding);
     221             : 
     222           0 :         result->program = true;
     223           0 :         result->file = pg_strdup(token);
     224             :     }
     225          21 :     else if (pg_strcasecmp(token, "stdin") == 0 ||
     226          10 :              pg_strcasecmp(token, "stdout") == 0)
     227             :     {
     228          11 :         result->file = NULL;
     229             :     }
     230           0 :     else if (pg_strcasecmp(token, "pstdin") == 0 ||
     231           0 :              pg_strcasecmp(token, "pstdout") == 0)
     232             :     {
     233           0 :         result->psql_inout = true;
     234           0 :         result->file = NULL;
     235             :     }
     236             :     else
     237             :     {
     238             :         /* filename can be optionally quoted */
     239           0 :         strip_quotes(token, '\'', 0, pset.encoding);
     240           0 :         result->file = pg_strdup(token);
     241           0 :         expand_tilde(&result->file);
     242             :     }
     243             : 
     244             :     /* Collect the rest of the line (COPY options) */
     245          11 :     token = strtokx(NULL, "", NULL, NULL,
     246             :                     0, false, false, pset.encoding);
     247          11 :     if (token)
     248           7 :         result->after_tofrom = pg_strdup(token);
     249             : 
     250          11 :     return result;
     251             : 
     252             : error:
     253           0 :     if (token)
     254           0 :         psql_error("\\copy: parse error at \"%s\"\n", token);
     255             :     else
     256           0 :         psql_error("\\copy: parse error at end of line\n");
     257           0 :     free_copy_options(result);
     258             : 
     259           0 :     return NULL;
     260             : }
     261             : 
     262             : 
     263             : /*
     264             :  * Execute a \copy command (frontend copy). We have to open a file (or execute
     265             :  * a command), then submit a COPY query to the backend and either feed it data
     266             :  * from the file or route its response into the file.
     267             :  */
     268             : bool
     269          11 : do_copy(const char *args)
     270             : {
     271             :     PQExpBufferData query;
     272             :     FILE       *copystream;
     273             :     struct copy_options *options;
     274             :     bool        success;
     275             : 
     276             :     /* parse options */
     277          11 :     options = parse_slash_copy(args);
     278             : 
     279          11 :     if (!options)
     280           0 :         return false;
     281             : 
     282             :     /* prepare to read or write the target file */
     283          11 :     if (options->file && !options->program)
     284           0 :         canonicalize_path(options->file);
     285             : 
     286          11 :     if (options->from)
     287             :     {
     288           1 :         if (options->file)
     289             :         {
     290           0 :             if (options->program)
     291             :             {
     292           0 :                 fflush(stdout);
     293           0 :                 fflush(stderr);
     294           0 :                 errno = 0;
     295           0 :                 copystream = popen(options->file, PG_BINARY_R);
     296             :             }
     297             :             else
     298           0 :                 copystream = fopen(options->file, PG_BINARY_R);
     299             :         }
     300           1 :         else if (!options->psql_inout)
     301           1 :             copystream = pset.cur_cmd_source;
     302             :         else
     303           0 :             copystream = stdin;
     304             :     }
     305             :     else
     306             :     {
     307          10 :         if (options->file)
     308             :         {
     309           0 :             if (options->program)
     310             :             {
     311           0 :                 fflush(stdout);
     312           0 :                 fflush(stderr);
     313           0 :                 errno = 0;
     314           0 :                 disable_sigpipe_trap();
     315           0 :                 copystream = popen(options->file, PG_BINARY_W);
     316             :             }
     317             :             else
     318           0 :                 copystream = fopen(options->file, PG_BINARY_W);
     319             :         }
     320          10 :         else if (!options->psql_inout)
     321          10 :             copystream = pset.queryFout;
     322             :         else
     323           0 :             copystream = stdout;
     324             :     }
     325             : 
     326          11 :     if (!copystream)
     327             :     {
     328           0 :         if (options->program)
     329           0 :             psql_error("could not execute command \"%s\": %s\n",
     330           0 :                        options->file, strerror(errno));
     331             :         else
     332           0 :             psql_error("%s: %s\n",
     333           0 :                        options->file, strerror(errno));
     334           0 :         free_copy_options(options);
     335           0 :         return false;
     336             :     }
     337             : 
     338          11 :     if (!options->program)
     339             :     {
     340             :         struct stat st;
     341             :         int         result;
     342             : 
     343             :         /* make sure the specified file is not a directory */
     344          11 :         if ((result = fstat(fileno(copystream), &st)) < 0)
     345           0 :             psql_error("could not stat file \"%s\": %s\n",
     346           0 :                        options->file, strerror(errno));
     347             : 
     348          11 :         if (result == 0 && S_ISDIR(st.st_mode))
     349           0 :             psql_error("%s: cannot copy from/to a directory\n",
     350             :                        options->file);
     351             : 
     352          11 :         if (result < 0 || S_ISDIR(st.st_mode))
     353             :         {
     354           0 :             fclose(copystream);
     355           0 :             free_copy_options(options);
     356           0 :             return false;
     357             :         }
     358             :     }
     359             : 
     360             :     /* build the command we will send to the backend */
     361          11 :     initPQExpBuffer(&query);
     362          11 :     printfPQExpBuffer(&query, "COPY ");
     363          11 :     appendPQExpBufferStr(&query, options->before_tofrom);
     364          11 :     if (options->from)
     365           1 :         appendPQExpBufferStr(&query, " FROM STDIN ");
     366             :     else
     367          10 :         appendPQExpBufferStr(&query, " TO STDOUT ");
     368          11 :     if (options->after_tofrom)
     369           7 :         appendPQExpBufferStr(&query, options->after_tofrom);
     370             : 
     371             :     /* run it like a user command, but with copystream as data source/sink */
     372          11 :     pset.copyStream = copystream;
     373          11 :     success = SendQuery(query.data);
     374          11 :     pset.copyStream = NULL;
     375          11 :     termPQExpBuffer(&query);
     376             : 
     377          11 :     if (options->file != NULL)
     378             :     {
     379           0 :         if (options->program)
     380             :         {
     381           0 :             int         pclose_rc = pclose(copystream);
     382             : 
     383           0 :             if (pclose_rc != 0)
     384             :             {
     385           0 :                 if (pclose_rc < 0)
     386           0 :                     psql_error("could not close pipe to external command: %s\n",
     387           0 :                                strerror(errno));
     388             :                 else
     389             :                 {
     390           0 :                     char       *reason = wait_result_to_str(pclose_rc);
     391             : 
     392           0 :                     psql_error("%s: %s\n", options->file,
     393             :                                reason ? reason : "");
     394           0 :                     if (reason)
     395           0 :                         free(reason);
     396             :                 }
     397           0 :                 success = false;
     398             :             }
     399           0 :             restore_sigpipe_trap();
     400             :         }
     401             :         else
     402             :         {
     403           0 :             if (fclose(copystream) != 0)
     404             :             {
     405           0 :                 psql_error("%s: %s\n", options->file, strerror(errno));
     406           0 :                 success = false;
     407             :             }
     408             :         }
     409             :     }
     410          11 :     free_copy_options(options);
     411          11 :     return success;
     412             : }
     413             : 
     414             : 
     415             : /*
     416             :  * Functions for handling COPY IN/OUT data transfer.
     417             :  *
     418             :  * If you want to use COPY TO STDOUT/FROM STDIN in your application,
     419             :  * this is the code to steal ;)
     420             :  */
     421             : 
     422             : /*
     423             :  * handleCopyOut
     424             :  * receives data as a result of a COPY ... TO STDOUT command
     425             :  *
     426             :  * conn should be a database connection that you just issued COPY TO on
     427             :  * and got back a PGRES_COPY_OUT result.
     428             :  * copystream is the file stream for the data to go to.
     429             :  * The final status for the COPY is returned into *res (but note
     430             :  * we already reported the error, if it's not a success result).
     431             :  *
     432             :  * result is true if successful, false if not.
     433             :  */
     434             : bool
     435          64 : handleCopyOut(PGconn *conn, FILE *copystream, PGresult **res)
     436             : {
     437          64 :     bool        OK = true;
     438             :     char       *buf;
     439             :     int         ret;
     440             : 
     441             :     for (;;)
     442             :     {
     443         318 :         ret = PQgetCopyData(conn, &buf, 0);
     444             : 
     445         318 :         if (ret < 0)
     446          64 :             break;              /* done or server/connection error */
     447             : 
     448         254 :         if (buf)
     449             :         {
     450         254 :             if (OK && fwrite(buf, 1, ret, copystream) != ret)
     451             :             {
     452           0 :                 psql_error("could not write COPY data: %s\n",
     453           0 :                            strerror(errno));
     454             :                 /* complain only once, keep reading data from server */
     455           0 :                 OK = false;
     456             :             }
     457         254 :             PQfreemem(buf);
     458             :         }
     459         254 :     }
     460             : 
     461          64 :     if (OK && fflush(copystream))
     462             :     {
     463           0 :         psql_error("could not write COPY data: %s\n",
     464           0 :                    strerror(errno));
     465           0 :         OK = false;
     466             :     }
     467             : 
     468          64 :     if (ret == -2)
     469             :     {
     470           0 :         psql_error("COPY data transfer failed: %s", PQerrorMessage(conn));
     471           0 :         OK = false;
     472             :     }
     473             : 
     474             :     /*
     475             :      * Check command status and return to normal libpq state.
     476             :      *
     477             :      * If for some reason libpq is still reporting PGRES_COPY_OUT state, we
     478             :      * would like to forcibly exit that state, since our caller would be
     479             :      * unable to distinguish that situation from reaching the next COPY in a
     480             :      * command string that happened to contain two consecutive COPY TO STDOUT
     481             :      * commands.  However, libpq provides no API for doing that, and in
     482             :      * principle it's a libpq bug anyway if PQgetCopyData() returns -1 or -2
     483             :      * but hasn't exited COPY_OUT state internally.  So we ignore the
     484             :      * possibility here.
     485             :      */
     486          64 :     *res = PQgetResult(conn);
     487          64 :     if (PQresultStatus(*res) != PGRES_COMMAND_OK)
     488             :     {
     489           0 :         psql_error("%s", PQerrorMessage(conn));
     490           0 :         OK = false;
     491             :     }
     492             : 
     493          64 :     return OK;
     494             : }
     495             : 
     496             : /*
     497             :  * handleCopyIn
     498             :  * sends data to complete a COPY ... FROM STDIN command
     499             :  *
     500             :  * conn should be a database connection that you just issued COPY FROM on
     501             :  * and got back a PGRES_COPY_IN result.
     502             :  * copystream is the file stream to read the data from.
     503             :  * isbinary can be set from PQbinaryTuples().
     504             :  * The final status for the COPY is returned into *res (but note
     505             :  * we already reported the error, if it's not a success result).
     506             :  *
     507             :  * result is true if successful, false if not.
     508             :  */
     509             : 
     510             : /* read chunk size for COPY IN - size is not critical */
     511             : #define COPYBUFSIZ 8192
     512             : 
     513             : bool
     514          77 : handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res)
     515             : {
     516             :     bool        OK;
     517             :     char        buf[COPYBUFSIZ];
     518             :     bool        showprompt;
     519             : 
     520             :     /*
     521             :      * Establish longjmp destination for exiting from wait-for-input. (This is
     522             :      * only effective while sigint_interrupt_enabled is TRUE.)
     523             :      */
     524          77 :     if (sigsetjmp(sigint_interrupt_jmp, 1) != 0)
     525             :     {
     526             :         /* got here with longjmp */
     527             : 
     528             :         /* Terminate data transfer */
     529           0 :         PQputCopyEnd(conn,
     530           0 :                      (PQprotocolVersion(conn) < 3) ? NULL :
     531             :                      _("canceled by user"));
     532             : 
     533           0 :         OK = false;
     534           0 :         goto copyin_cleanup;
     535             :     }
     536             : 
     537             :     /* Prompt if interactive input */
     538          77 :     if (isatty(fileno(copystream)))
     539             :     {
     540           0 :         showprompt = true;
     541           0 :         if (!pset.quiet)
     542           0 :             puts(_("Enter data to be copied followed by a newline.\n"
     543             :                    "End with a backslash and a period on a line by itself, or an EOF signal."));
     544             :     }
     545             :     else
     546          77 :         showprompt = false;
     547             : 
     548          77 :     OK = true;
     549             : 
     550          77 :     if (isbinary)
     551             :     {
     552             :         /* interactive input probably silly, but give one prompt anyway */
     553           0 :         if (showprompt)
     554             :         {
     555           0 :             const char *prompt = get_prompt(PROMPT_COPY, NULL);
     556             : 
     557           0 :             fputs(prompt, stdout);
     558           0 :             fflush(stdout);
     559             :         }
     560             : 
     561             :         for (;;)
     562             :         {
     563             :             int         buflen;
     564             : 
     565             :             /* enable longjmp while waiting for input */
     566           0 :             sigint_interrupt_enabled = true;
     567             : 
     568           0 :             buflen = fread(buf, 1, COPYBUFSIZ, copystream);
     569             : 
     570           0 :             sigint_interrupt_enabled = false;
     571             : 
     572           0 :             if (buflen <= 0)
     573           0 :                 break;
     574             : 
     575           0 :             if (PQputCopyData(conn, buf, buflen) <= 0)
     576             :             {
     577           0 :                 OK = false;
     578           0 :                 break;
     579             :             }
     580           0 :         }
     581             :     }
     582             :     else
     583             :     {
     584          77 :         bool        copydone = false;
     585             : 
     586         451 :         while (!copydone)
     587             :         {                       /* for each input line ... */
     588             :             bool        firstload;
     589             :             bool        linedone;
     590             : 
     591         297 :             if (showprompt)
     592             :             {
     593           0 :                 const char *prompt = get_prompt(PROMPT_COPY, NULL);
     594             : 
     595           0 :                 fputs(prompt, stdout);
     596           0 :                 fflush(stdout);
     597             :             }
     598             : 
     599         297 :             firstload = true;
     600         297 :             linedone = false;
     601             : 
     602         814 :             while (!linedone)
     603             :             {                   /* for each bufferload in line ... */
     604             :                 int         linelen;
     605             :                 char       *fgresult;
     606             : 
     607             :                 /* enable longjmp while waiting for input */
     608         297 :                 sigint_interrupt_enabled = true;
     609             : 
     610         297 :                 fgresult = fgets(buf, sizeof(buf), copystream);
     611             : 
     612         297 :                 sigint_interrupt_enabled = false;
     613             : 
     614         297 :                 if (!fgresult)
     615             :                 {
     616           0 :                     copydone = true;
     617           0 :                     break;
     618             :                 }
     619             : 
     620         297 :                 linelen = strlen(buf);
     621             : 
     622             :                 /* current line is done? */
     623         297 :                 if (linelen > 0 && buf[linelen - 1] == '\n')
     624         297 :                     linedone = true;
     625             : 
     626             :                 /* check for EOF marker, but not on a partial line */
     627         297 :                 if (firstload)
     628             :                 {
     629             :                     /*
     630             :                      * This code erroneously assumes '\.' on a line alone
     631             :                      * inside a quoted CSV string terminates the \copy.
     632             :                      * http://www.postgresql.org/message-id/E1TdNVQ-0001ju-GO@wrigleys.postgresql.org
     633             :                      */
     634         517 :                     if (strcmp(buf, "\\.\n") == 0 ||
     635         220 :                         strcmp(buf, "\\.\r\n") == 0)
     636             :                     {
     637          77 :                         copydone = true;
     638          77 :                         break;
     639             :                     }
     640             : 
     641         220 :                     firstload = false;
     642             :                 }
     643             : 
     644         220 :                 if (PQputCopyData(conn, buf, linelen) <= 0)
     645             :                 {
     646           0 :                     OK = false;
     647           0 :                     copydone = true;
     648           0 :                     break;
     649             :                 }
     650             :             }
     651             : 
     652         297 :             if (copystream == pset.cur_cmd_source)
     653             :             {
     654         297 :                 pset.lineno++;
     655         297 :                 pset.stmt_lineno++;
     656             :             }
     657             :         }
     658             :     }
     659             : 
     660             :     /* Check for read error */
     661          77 :     if (ferror(copystream))
     662           0 :         OK = false;
     663             : 
     664             :     /*
     665             :      * Terminate data transfer.  We can't send an error message if we're using
     666             :      * protocol version 2.
     667             :      */
     668          77 :     if (PQputCopyEnd(conn,
     669           0 :                      (OK || PQprotocolVersion(conn) < 3) ? NULL :
     670             :                      _("aborted because of read failure")) <= 0)
     671           0 :         OK = false;
     672             : 
     673             : copyin_cleanup:
     674             : 
     675             :     /*
     676             :      * Clear the EOF flag on the stream, in case copying ended due to an EOF
     677             :      * signal.  This allows an interactive TTY session to perform another COPY
     678             :      * FROM STDIN later.  (In non-STDIN cases, we're about to close the file
     679             :      * anyway, so it doesn't matter.)  Although we don't ever test the flag
     680             :      * with feof(), some fread() implementations won't read more data if it's
     681             :      * set.  This also clears the error flag, but we already checked that.
     682             :      */
     683          77 :     clearerr(copystream);
     684             : 
     685             :     /*
     686             :      * Check command status and return to normal libpq state.
     687             :      *
     688             :      * We do not want to return with the status still PGRES_COPY_IN: our
     689             :      * caller would be unable to distinguish that situation from reaching the
     690             :      * next COPY in a command string that happened to contain two consecutive
     691             :      * COPY FROM STDIN commands.  We keep trying PQputCopyEnd() in the hope
     692             :      * it'll work eventually.  (What's actually likely to happen is that in
     693             :      * attempting to flush the data, libpq will eventually realize that the
     694             :      * connection is lost.  But that's fine; it will get us out of COPY_IN
     695             :      * state, which is what we need.)
     696             :      */
     697         154 :     while (*res = PQgetResult(conn), PQresultStatus(*res) == PGRES_COPY_IN)
     698             :     {
     699           0 :         OK = false;
     700           0 :         PQclear(*res);
     701             :         /* We can't send an error message if we're using protocol version 2 */
     702           0 :         PQputCopyEnd(conn,
     703           0 :                      (PQprotocolVersion(conn) < 3) ? NULL :
     704             :                      _("trying to exit copy mode"));
     705             :     }
     706          77 :     if (PQresultStatus(*res) != PGRES_COMMAND_OK)
     707             :     {
     708          16 :         psql_error("%s", PQerrorMessage(conn));
     709          16 :         OK = false;
     710             :     }
     711             : 
     712          77 :     return OK;
     713             : }

Generated by: LCOV version 1.11