LCOV - differential code coverage report
Current view: top level - src/bin/psql - copy.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB
Current: Differential Code Coverage HEAD vs 15 Lines: 55.7 % 271 151 5 4 39 72 12 47 92 30 55 6
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 6 6 2 1 3 2
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 [..60] days: 0.0 % 1 0 1
Legend: Lines: hit not hit (180,240] days: 0.0 % 3 0 3
(240..) days: 56.6 % 267 151 1 4 39 72 12 47 92 30 55
Function coverage date bins:
(240..) days: 75.0 % 8 6 2 1 3 2

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

Generated by: LCOV version v1.16-55-g56c0a2a