LCOV - differential code coverage report
Current view: top level - src/bin/psql - copy.c (source / functions) Coverage Total Hit UIC GIC
Current: ba12a202ce1b5581dc0ed149cf3f637d7897ad5d vs 2866d8c7dbfc9d882a7d80fef93fbbe763709932 Lines: 56.7 % 277 157 120 157
Current Date: 2026-08-27 14:31:44 +0300 Functions: 100.0 % 6 6 6
Baseline: lcov-20260827-baseline Branches: 54.2 % 214 116 98 116
Baseline Date: 2026-08-27 14:31:58 +0300 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 56.2 % 16 9 7 9
(30,360] days: 100.0 % 1 1 1
(360..) days: 56.5 % 260 147 113 147
Function coverage date bins:
(360..) days: 100.0 % 6 6 6
Branch coverage date bins:
(7,30] days: 39.3 % 28 11 17 11
(360..) days: 56.5 % 186 105 81 105

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*
                                  2                 :                :  * psql - the PostgreSQL interactive terminal
                                  3                 :                :  *
                                  4                 :                :  * Copyright (c) 2000-2026, 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 | pstdin | 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
 3354 tgl@sss.pgh.pa.us          65                 :GIC          99 : free_copy_options(struct copy_options *ptr)
                                 66                 :                : {
 9793 bruce@momjian.us           67         [ -  + ]:             99 :     if (!ptr)
 9793 bruce@momjian.us           68                 :UIC           0 :         return;
 6186 tgl@sss.pgh.pa.us          69                 :GIC          99 :     free(ptr->before_tofrom);
                                 70                 :             99 :     free(ptr->after_tofrom);
 9793 bruce@momjian.us           71                 :             99 :     free(ptr->file);
                                 72                 :             99 :     free(ptr);
                                 73                 :                : }
                                 74                 :                : 
                                 75                 :                : 
                                 76                 :                : /* concatenate "more" onto "var", freeing the original value of *var */
                                 77                 :                : static void
 8713 tgl@sss.pgh.pa.us          78                 :            654 : xstrcat(char **var, const char *more)
                                 79                 :                : {
                                 80                 :                :     char       *newvar;
                                 81                 :                : 
 4692                            82                 :            654 :     newvar = psprintf("%s%s", *var, more);
 8713                            83                 :            654 :     free(*var);
                                 84                 :            654 :     *var = newvar;
                                 85                 :            654 : }
                                 86                 :                : 
                                 87                 :                : 
                                 88                 :                : static struct copy_options *
 9718 peter_e@gmx.net            89                 :             99 : parse_slash_copy(const char *args)
                                 90                 :                : {
                                 91                 :                :     struct copy_options *result;
                                 92                 :                :     char       *token;
 8713 tgl@sss.pgh.pa.us          93                 :             99 :     const char *whitespace = " \t\n\r";
 7392                            94         [ +  - ]:             99 :     char        nonstd_backslash = standard_strings() ? 0 : '\\';
                                 95                 :                : 
 6186                            96         [ -  + ]:             99 :     if (!args)
                                 97                 :                :     {
 2705 peter@eisentraut.org       98                 :UIC           0 :         pg_log_error("\\copy: arguments required");
 9629 peter_e@gmx.net            99                 :              0 :         return NULL;
                                100                 :                :     }
                                101                 :                : 
  181 michael@paquier.xyz       102                 :GIC          99 :     result = pg_malloc0_object(struct copy_options);
                                103                 :                : 
 3354 tgl@sss.pgh.pa.us         104                 :             99 :     result->before_tofrom = pg_strdup(""); /* initialize for appending */
                                105                 :                : 
 6186                           106                 :             99 :     token = strtokx(args, whitespace, ".,()", "\"",
                                107                 :                :                     0, false, false, pset.encoding);
 9793 bruce@momjian.us          108         [ -  + ]:             99 :     if (!token)
 8713 tgl@sss.pgh.pa.us         109                 :UIC           0 :         goto error;
                                110                 :                : 
                                111                 :                :     /* The following can be removed when we drop 7.3 syntax support */
 8147 tgl@sss.pgh.pa.us         112         [ -  + ]:GIC          99 :     if (pg_strcasecmp(token, "binary") == 0)
                                113                 :                :     {
 6186 tgl@sss.pgh.pa.us         114                 :UIC           0 :         xstrcat(&result->before_tofrom, token);
 8713                           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 */
 7302 tgl@sss.pgh.pa.us         122         [ +  + ]:GIC          99 :     if (token[0] == '(')
                                123                 :                :     {
 7267 bruce@momjian.us          124                 :             16 :         int         parens = 1;
                                125                 :                : 
 7302 tgl@sss.pgh.pa.us         126         [ +  + ]:            244 :         while (parens > 0)
                                127                 :                :         {
 6186                           128                 :            228 :             xstrcat(&result->before_tofrom, " ");
                                129                 :            228 :             xstrcat(&result->before_tofrom, token);
                                130                 :            228 :             token = strtokx(NULL, whitespace, "()", "\"'",
                                131                 :                :                             nonstd_backslash, true, false, pset.encoding);
 7302                           132         [ -  + ]:            228 :             if (!token)
 7302 tgl@sss.pgh.pa.us         133                 :UIC           0 :                 goto error;
 7302 tgl@sss.pgh.pa.us         134         [ +  + ]:GIC         228 :             if (token[0] == '(')
                                135                 :             12 :                 parens++;
                                136         [ +  + ]:            216 :             else if (token[0] == ')')
                                137                 :             28 :                 parens--;
                                138                 :                :         }
                                139                 :                :     }
                                140                 :                : 
 6186                           141                 :             99 :     xstrcat(&result->before_tofrom, " ");
                                142                 :             99 :     xstrcat(&result->before_tofrom, token);
 8713                           143                 :             99 :     token = strtokx(NULL, whitespace, ".,()", "\"",
                                144                 :                :                     0, false, false, pset.encoding);
                                145         [ -  + ]:             99 :     if (!token)
 8713 tgl@sss.pgh.pa.us         146                 :UIC           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                 :                :      */
 8713 tgl@sss.pgh.pa.us         152         [ -  + ]:GIC          99 :     if (token[0] == '.')
                                153                 :                :     {
                                154                 :                :         /* handle schema . table */
 6186 tgl@sss.pgh.pa.us         155                 :UIC           0 :         xstrcat(&result->before_tofrom, token);
 8713                           156                 :              0 :         token = strtokx(NULL, whitespace, ".,()", "\"",
                                157                 :                :                         0, false, false, pset.encoding);
 9793 bruce@momjian.us          158         [ #  # ]:              0 :         if (!token)
 8713 tgl@sss.pgh.pa.us         159                 :              0 :             goto error;
 6186                           160                 :              0 :         xstrcat(&result->before_tofrom, token);
 8713                           161                 :              0 :         token = strtokx(NULL, whitespace, ".,()", "\"",
                                162                 :                :                         0, false, false, pset.encoding);
                                163         [ #  # ]:              0 :         if (!token)
                                164                 :              0 :             goto error;
                                165                 :                :     }
                                166                 :                : 
 8713 tgl@sss.pgh.pa.us         167         [ -  + ]:GIC          99 :     if (token[0] == '(')
                                168                 :                :     {
                                169                 :                :         /* handle parenthesized column list */
                                170                 :                :         for (;;)
                                171                 :                :         {
 6186 tgl@sss.pgh.pa.us         172                 :UIC           0 :             xstrcat(&result->before_tofrom, " ");
                                173                 :              0 :             xstrcat(&result->before_tofrom, token);
                                174                 :              0 :             token = strtokx(NULL, whitespace, "()", "\"",
                                175                 :                :                             0, false, false, pset.encoding);
 8713                           176         [ #  # ]:              0 :             if (!token)
                                177                 :              0 :                 goto error;
                                178         [ #  # ]:              0 :             if (token[0] == ')')
                                179                 :              0 :                 break;
                                180                 :                :         }
 6186                           181                 :              0 :         xstrcat(&result->before_tofrom, " ");
                                182                 :              0 :         xstrcat(&result->before_tofrom, token);
 8713                           183                 :              0 :         token = strtokx(NULL, whitespace, ".,()", "\"",
                                184                 :                :                         0, false, false, pset.encoding);
                                185         [ #  # ]:              0 :         if (!token)
                                186                 :              0 :             goto error;
                                187                 :                :     }
                                188                 :                : 
 8147 tgl@sss.pgh.pa.us         189         [ +  + ]:GIC          99 :     if (pg_strcasecmp(token, "from") == 0)
 8713                           190                 :             58 :         result->from = true;
 8147                           191         [ +  - ]:             41 :     else if (pg_strcasecmp(token, "to") == 0)
 8713                           192                 :             41 :         result->from = false;
                                193                 :                :     else
 8713 tgl@sss.pgh.pa.us         194                 :UIC           0 :         goto error;
                                195                 :                : 
                                196                 :                :     /* { 'filename' | PROGRAM 'command' | STDIN | STDOUT | PSTDIN | PSTDOUT } */
 4734 bruce@momjian.us          197                 :GIC          99 :     token = strtokx(NULL, whitespace, ";", "'",
                                198                 :                :                     0, false, false, pset.encoding);
 8713 tgl@sss.pgh.pa.us         199         [ -  + ]:             99 :     if (!token)
 8713 tgl@sss.pgh.pa.us         200                 :UIC           0 :         goto error;
                                201                 :                : 
 4929 heikki.linnakangas@i      202         [ -  + ]:GIC          99 :     if (pg_strcasecmp(token, "program") == 0)
                                203                 :                :     {
                                204                 :                :         int         toklen;
                                205                 :                : 
 4734 bruce@momjian.us          206                 :UIC           0 :         token = strtokx(NULL, whitespace, ";", "'",
                                207                 :                :                         0, false, false, pset.encoding);
 4929 heikki.linnakangas@i      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                 :                :     }
 4929 heikki.linnakangas@i      224   [ +  +  +  + ]:GIC         187 :     else if (pg_strcasecmp(token, "stdin") == 0 ||
                                225                 :             88 :              pg_strcasecmp(token, "stdout") == 0)
                                226                 :                :     {
 8255 tgl@sss.pgh.pa.us         227                 :             52 :         result->file = NULL;
                                228                 :                :     }
 8147                           229   [ +  -  -  + ]:             94 :     else if (pg_strcasecmp(token, "pstdin") == 0 ||
 8033 bruce@momjian.us          230                 :             47 :              pg_strcasecmp(token, "pstdout") == 0)
                                231                 :                :     {
 8172 bruce@momjian.us          232                 :UIC           0 :         result->psql_inout = true;
 8713 tgl@sss.pgh.pa.us         233                 :              0 :         result->file = NULL;
                                234                 :                :     }
                                235                 :                :     else
                                236                 :                :     {
                                237                 :                :         /* filename can be optionally quoted */
 4929 heikki.linnakangas@i      238                 :GIC          47 :         strip_quotes(token, '\'', 0, pset.encoding);
 8250 neilc@samurai.com         239                 :             47 :         result->file = pg_strdup(token);
 8255 tgl@sss.pgh.pa.us         240                 :             47 :         expand_tilde(&result->file);
                                241                 :                :     }
                                242                 :                : 
                                243                 :                :     /* Collect the rest of the line (COPY options) */
 6186                           244                 :             99 :     token = strtokx(NULL, "", NULL, NULL,
                                245                 :                :                     0, false, false, pset.encoding);
 8713                           246         [ +  + ]:             99 :     if (token)
 6186                           247                 :             34 :         result->after_tofrom = pg_strdup(token);
                                248                 :                : 
 8713                           249                 :             99 :     return result;
                                250                 :                : 
 8713 tgl@sss.pgh.pa.us         251                 :UIC           0 : error:
                                252         [ #  # ]:              0 :     if (token)
 2705 peter@eisentraut.org      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");
 8713 tgl@sss.pgh.pa.us         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
 9718 peter_e@gmx.net           268                 :GIC          99 : 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                 :             99 :     options = parse_slash_copy(args);
                                277                 :                : 
 9793 bruce@momjian.us          278         [ -  + ]:             99 :     if (!options)
 9793 bruce@momjian.us          279                 :UIC           0 :         return false;
                                280                 :                : 
                                281                 :                :     /* prepare to read or write the target file */
 4929 heikki.linnakangas@i      282   [ +  +  +  - ]:GIC          99 :     if (options->file && !options->program)
  575 tgl@sss.pgh.pa.us         283                 :             47 :         canonicalize_path_enc(options->file, pset.encoding);
                                284                 :                : 
 9793 bruce@momjian.us          285         [ +  + ]:             99 :     if (options->from)
                                286                 :                :     {
 9633                           287         [ +  + ]:             58 :         if (options->file)
                                288                 :                :         {
 4929 heikki.linnakangas@i      289         [ -  + ]:             47 :             if (options->program)
                                290                 :                :             {
 1459 tgl@sss.pgh.pa.us         291                 :UIC           0 :                 fflush(NULL);
 4929 heikki.linnakangas@i      292                 :              0 :                 errno = 0;
                                293                 :              0 :                 copystream = popen(options->file, PG_BINARY_R);
                                294                 :                :             }
                                295                 :                :             else
 4929 heikki.linnakangas@i      296                 :GIC          47 :                 copystream = fopen(options->file, PG_BINARY_R);
                                297                 :                :         }
 8172 bruce@momjian.us          298         [ +  - ]:             11 :         else if (!options->psql_inout)
 8033                           299                 :             11 :             copystream = pset.cur_cmd_source;
                                300                 :                :         else
 8033 bruce@momjian.us          301                 :UIC           0 :             copystream = stdin;
                                302                 :                :     }
                                303                 :                :     else
                                304                 :                :     {
 9633 bruce@momjian.us          305         [ -  + ]:GIC          41 :         if (options->file)
                                306                 :                :         {
 4929 heikki.linnakangas@i      307         [ #  # ]:UIC           0 :             if (options->program)
                                308                 :                :             {
 1459 tgl@sss.pgh.pa.us         309                 :              0 :                 fflush(NULL);
 3920                           310                 :              0 :                 disable_sigpipe_trap();
 1459                           311                 :              0 :                 errno = 0;
 4929 heikki.linnakangas@i      312                 :              0 :                 copystream = popen(options->file, PG_BINARY_W);
                                313                 :                :             }
                                314                 :                :             else
                                315                 :              0 :                 copystream = fopen(options->file, PG_BINARY_W);
                                316                 :                :         }
 8172 bruce@momjian.us          317         [ +  - ]:GIC          41 :         else if (!options->psql_inout)
 8033                           318                 :             41 :             copystream = pset.queryFout;
                                319                 :                :         else
 9633 bruce@momjian.us          320                 :UIC           0 :             copystream = stdout;
                                321                 :                :     }
                                322                 :                : 
 9793 bruce@momjian.us          323         [ +  + ]:GIC          99 :     if (!copystream)
                                324                 :                :     {
 4929 heikki.linnakangas@i      325         [ -  + ]:              5 :         if (options->program)
 2705 peter@eisentraut.org      326                 :UIC           0 :             pg_log_error("could not execute command \"%s\": %m",
                                327                 :                :                          options->file);
                                328                 :                :         else
 2705 peter@eisentraut.org      329                 :GIC           5 :             pg_log_error("%s: %m",
                                330                 :                :                          options->file);
 9793 bruce@momjian.us          331                 :              5 :         free_copy_options(options);
                                332                 :              5 :         return false;
                                333                 :                :     }
                                334                 :                : 
 4929 heikki.linnakangas@i      335         [ +  - ]:             94 :     if (!options->program)
                                336                 :                :     {
                                337                 :                :         struct stat st;
                                338                 :                :         int         result;
                                339                 :                : 
                                340                 :                :         /* make sure the specified file is not a directory */
 4562 sfrost@snowman.net        341         [ -  + ]:             94 :         if ((result = fstat(fileno(copystream), &st)) < 0)
 2705 peter@eisentraut.org      342                 :UIC           0 :             pg_log_error("could not stat file \"%s\": %m",
                                343                 :                :                          options->file);
                                344                 :                : 
 4562 sfrost@snowman.net        345   [ +  -  -  + ]:GIC          94 :         if (result == 0 && S_ISDIR(st.st_mode))
 2705 peter@eisentraut.org      346                 :UIC           0 :             pg_log_error("%s: cannot copy from/to a directory",
                                347                 :                :                          options->file);
                                348                 :                : 
 4562 sfrost@snowman.net        349   [ +  -  -  + ]:GIC          94 :         if (result < 0 || S_ISDIR(st.st_mode))
                                350                 :                :         {
 4562 sfrost@snowman.net        351                 :UIC           0 :             fclose(copystream);
 4929 heikki.linnakangas@i      352                 :              0 :             free_copy_options(options);
                                353                 :              0 :             return false;
                                354                 :                :         }
                                355                 :                :     }
                                356                 :                : 
                                357                 :                :     /* build the command we will send to the backend */
 6186 tgl@sss.pgh.pa.us         358                 :GIC          94 :     initPQExpBuffer(&query);
                                359                 :             94 :     printfPQExpBuffer(&query, "COPY ");
                                360                 :             94 :     appendPQExpBufferStr(&query, options->before_tofrom);
                                361         [ +  + ]:             94 :     if (options->from)
 4665 heikki.linnakangas@i      362                 :             53 :         appendPQExpBufferStr(&query, " FROM STDIN ");
                                363                 :                :     else
                                364                 :             41 :         appendPQExpBufferStr(&query, " TO STDOUT ");
 6186 tgl@sss.pgh.pa.us         365         [ +  + ]:             94 :     if (options->after_tofrom)
                                366                 :             31 :         appendPQExpBufferStr(&query, options->after_tofrom);
                                367                 :                : 
                                368                 :                :     /* run it like a user command, but with copystream as data source/sink */
 4553                           369                 :             94 :     pset.copyStream = copystream;
   17                           370                 :             94 :     success = SendQuery(query.data, options->from ? 1 : 0);
 4553                           371                 :             94 :     pset.copyStream = NULL;
 8891 peter_e@gmx.net           372                 :             94 :     termPQExpBuffer(&query);
                                373                 :                : 
 8033 bruce@momjian.us          374         [ +  + ]:             94 :     if (options->file != NULL)
                                375                 :                :     {
 4929 heikki.linnakangas@i      376         [ -  + ]:             42 :         if (options->program)
                                377                 :                :         {
 4838 bruce@momjian.us          378                 :UIC           0 :             int         pclose_rc = pclose(copystream);
                                379                 :                : 
 4929 heikki.linnakangas@i      380         [ #  # ]:              0 :             if (pclose_rc != 0)
                                381                 :                :             {
                                382         [ #  # ]:              0 :                 if (pclose_rc < 0)
 2705 peter@eisentraut.org      383                 :              0 :                     pg_log_error("could not close pipe to external command: %m");
                                384                 :                :                 else
                                385                 :                :                 {
 4838 bruce@momjian.us          386                 :              0 :                     char       *reason = wait_result_to_str(pclose_rc);
                                387                 :                : 
 2705 peter@eisentraut.org      388         [ #  # ]:              0 :                     pg_log_error("%s: %s", options->file,
                                389                 :                :                                  reason ? reason : "");
 1533                           390                 :              0 :                     free(reason);
                                391                 :                :                 }
 4929 heikki.linnakangas@i      392                 :              0 :                 success = false;
                                393                 :                :             }
 1239 tgl@sss.pgh.pa.us         394                 :              0 :             SetShellResultVariables(pclose_rc);
 3920                           395                 :              0 :             restore_sigpipe_trap();
                                396                 :                :         }
                                397                 :                :         else
                                398                 :                :         {
 4929 heikki.linnakangas@i      399         [ -  + ]:GIC          42 :             if (fclose(copystream) != 0)
                                400                 :                :             {
 2705 peter@eisentraut.org      401                 :UIC           0 :                 pg_log_error("%s: %m", options->file);
 4929 heikki.linnakangas@i      402                 :              0 :                 success = false;
                                403                 :                :             }
                                404                 :                :         }
                                405                 :                :     }
 9793 bruce@momjian.us          406                 :GIC          94 :     free_copy_options(options);
                                407                 :             94 :     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.
                                432                 :                :  */
                                433                 :                : bool
 4550 tgl@sss.pgh.pa.us         434                 :            486 : handleCopyOut(PGconn *conn, FILE *copystream, PGresult **res)
                                435                 :                : {
 7267 bruce@momjian.us          436                 :            486 :     bool        OK = true;
                                437                 :                :     char       *buf;
                                438                 :                :     int         ret;
                                439                 :                : 
                                440                 :                :     for (;;)
                                441                 :                :     {
 7482 tgl@sss.pgh.pa.us         442                 :           2193 :         ret = PQgetCopyData(conn, &buf, 0);
                                443                 :                : 
                                444         [ +  + ]:           2193 :         if (ret < 0)
 4578                           445                 :            486 :             break;              /* done or server/connection error */
                                446                 :                : 
 7482                           447         [ +  - ]:           1707 :         if (buf)
                                448                 :                :         {
 2770                           449   [ +  -  +  -  :           1707 :             if (OK && copystream && fwrite(buf, 1, ret, copystream) != ret)
                                              -  + ]
                                450                 :                :             {
 2705 peter@eisentraut.org      451                 :UIC           0 :                 pg_log_error("could not write COPY data: %m");
                                452                 :                :                 /* complain only once, keep reading data from server */
 7398 tgl@sss.pgh.pa.us         453                 :              0 :                 OK = false;
                                454                 :                :             }
 7482 tgl@sss.pgh.pa.us         455                 :GIC        1707 :             PQfreemem(buf);
                                456                 :                :         }
                                457                 :                :     }
                                458                 :                : 
 2770                           459   [ +  -  +  -  :            486 :     if (OK && copystream && fflush(copystream))
                                              -  + ]
                                460                 :                :     {
 2705 peter@eisentraut.org      461                 :UIC           0 :         pg_log_error("could not write COPY data: %m");
 7398 tgl@sss.pgh.pa.us         462                 :              0 :         OK = false;
                                463                 :                :     }
                                464                 :                : 
 7482 tgl@sss.pgh.pa.us         465         [ -  + ]:GIC         486 :     if (ret == -2)
                                466                 :                :     {
 2705 peter@eisentraut.org      467                 :UIC           0 :         pg_log_error("COPY data transfer failed: %s", PQerrorMessage(conn));
 7482 tgl@sss.pgh.pa.us         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
                                481                 :                :      * possibility here.
                                482                 :                :      */
 4550 tgl@sss.pgh.pa.us         483                 :GIC         486 :     *res = PQgetResult(conn);
                                484         [ +  + ]:            486 :     if (PQresultStatus(*res) != PGRES_COMMAND_OK)
                                485                 :                :     {
 2705 peter@eisentraut.org      486                 :              2 :         pg_log_info("%s", PQerrorMessage(conn));
 7482 tgl@sss.pgh.pa.us         487                 :              2 :         OK = false;
                                488                 :                :     }
                                489                 :                : 
                                490                 :            486 :     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.  Alternatively, if conn is NULL,
                                499                 :                :  * we read and discard the appropriate amount of data from copystream.
                                500                 :                :  * copystream is the file stream to read the data from.
                                501                 :                :  * isbinary can be set from PQbinaryTuples().
                                502                 :                :  * The final status for the COPY is returned into *res; but note
                                503                 :                :  * we already reported the error, if it's not a success result.
                                504                 :                :  * Also, if conn is NULL then *res is not touched.
                                505                 :                :  *
                                506                 :                :  * result is true if successful, false if not.
                                507                 :                :  */
                                508                 :                : 
                                509                 :                : /* read chunk size for COPY IN - size is not critical */
                                510                 :                : #define COPYBUFSIZ 8192
                                511                 :                : 
                                512                 :                : bool
 4550                           513                 :            945 : handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res)
                                514                 :                : {
                                515                 :                :     bool        OK;
                                516                 :                :     char        buf[COPYBUFSIZ];
                                517                 :                :     bool        showprompt;
                                518                 :                : 
                                519                 :                :     /* We want to prompt if interactive input ... */
   17                           520                 :            945 :     showprompt = isatty(fileno(copystream));
                                521                 :                :     /* ... but if we're just discarding data, don't bother the user at all */
                                522   [ -  +  -  - ]:            945 :     if (showprompt && !conn)
   17 tgl@sss.pgh.pa.us         523                 :UIC           0 :         return true;
                                524                 :                : 
                                525                 :                :     /*
                                526                 :                :      * Establish longjmp destination for exiting from wait-for-input. (This is
                                527                 :                :      * only effective while sigint_interrupt_enabled is TRUE.)
                                528                 :                :      */
 7379 tgl@sss.pgh.pa.us         529         [ -  + ]:GIC         945 :     if (sigsetjmp(sigint_interrupt_jmp, 1) != 0)
                                530                 :                :     {
                                531                 :                :         /* got here with longjmp */
                                532                 :                : 
                                533                 :                :         /* Terminate data transfer */
   17 tgl@sss.pgh.pa.us         534         [ #  # ]:UIC           0 :         if (conn)
                                535                 :              0 :             PQputCopyEnd(conn,
                                536         [ #  # ]:              0 :                          (PQprotocolVersion(conn) < 3) ? NULL :
                                537                 :              0 :                          _("canceled by user"));
                                538                 :                : 
 5328 alvherre@alvh.no-ip.      539                 :              0 :         OK = false;
                                540                 :              0 :         goto copyin_cleanup;
                                541                 :                :     }
                                542                 :                : 
                                543                 :                :     /* Issue initial prompt if interactive input */
   17 tgl@sss.pgh.pa.us         544   [ -  +  -  - ]:GIC         945 :     if (showprompt && !pset.quiet)
   17 tgl@sss.pgh.pa.us         545                 :UIC           0 :         puts(_("Enter data to be copied followed by a newline.\n"
                                546                 :                :                "End with a backslash and a period on a line by itself, or an EOF signal."));
                                547                 :                : 
 7379 tgl@sss.pgh.pa.us         548                 :GIC         945 :     OK = true;
                                549                 :                : 
 7398                           550         [ -  + ]:            945 :     if (isbinary)
                                551                 :                :     {
                                552                 :                :         /* interactive input probably silly, but give one prompt anyway */
 4377 andres@anarazel.de        553         [ #  # ]:UIC           0 :         if (showprompt)
                                554                 :                :         {
 3437 tgl@sss.pgh.pa.us         555                 :              0 :             const char *prompt = get_prompt(PROMPT_COPY, NULL);
                                556                 :                : 
 9793 bruce@momjian.us          557                 :              0 :             fputs(prompt, stdout);
                                558                 :              0 :             fflush(stdout);
                                559                 :                :         }
                                560                 :                : 
                                561                 :                :         for (;;)
 7398 tgl@sss.pgh.pa.us         562                 :              0 :         {
                                563                 :                :             int         buflen;
                                564                 :                : 
                                565                 :                :             /* enable longjmp while waiting for input */
 7379                           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                 :                : 
   17                           575   [ #  #  #  # ]:              0 :             if (conn && PQputCopyData(conn, buf, buflen) <= 0)
                                576                 :                :             {
 7398                           577                 :              0 :                 OK = false;
 9793 bruce@momjian.us          578                 :              0 :                 break;
                                579                 :                :             }
                                580                 :                :         }
                                581                 :                :     }
                                582                 :                :     else
                                583                 :                :     {
 7398 tgl@sss.pgh.pa.us         584                 :GIC         945 :         bool        copydone = false;
                                585                 :                :         int         buflen;
 1870 heikki.linnakangas@i      586                 :            945 :         bool        at_line_begin = true;
                                587                 :                : 
                                588                 :                :         /*
                                589                 :                :          * In text mode, we have to read the input one line at a time, so that
                                590                 :                :          * we can stop reading at the EOF marker (\.).  We mustn't read beyond
                                591                 :                :          * the EOF marker, because if the data was inlined in a SQL script, we
                                592                 :                :          * would eat up the commands after the EOF marker.
                                593                 :                :          */
                                594                 :            945 :         buflen = 0;
 7398 tgl@sss.pgh.pa.us         595         [ +  + ]:          38204 :         while (!copydone)
                                596                 :                :         {
                                597                 :                :             char       *fgresult;
                                598                 :                : 
 1870 heikki.linnakangas@i      599   [ +  +  -  + ]:          37259 :             if (at_line_begin && showprompt)
                                600                 :                :             {
 3437 tgl@sss.pgh.pa.us         601                 :UIC           0 :                 const char *prompt = get_prompt(PROMPT_COPY, NULL);
                                602                 :                : 
 7398                           603                 :              0 :                 fputs(prompt, stdout);
                                604                 :              0 :                 fflush(stdout);
                                605                 :                :             }
                                606                 :                : 
                                607                 :                :             /* enable longjmp while waiting for input */
 1870 heikki.linnakangas@i      608                 :GIC       37259 :             sigint_interrupt_enabled = true;
                                609                 :                : 
                                610                 :          37259 :             fgresult = fgets(&buf[buflen], COPYBUFSIZ - buflen, copystream);
                                611                 :                : 
                                612                 :          37259 :             sigint_interrupt_enabled = false;
                                613                 :                : 
                                614         [ +  + ]:          37259 :             if (!fgresult)
                                615                 :             42 :                 copydone = true;
                                616                 :                :             else
                                617                 :                :             {
                                618                 :                :                 int         linelen;
                                619                 :                : 
                                620                 :          37217 :                 linelen = strlen(fgresult);
                                621                 :          37217 :                 buflen += linelen;
                                622                 :                : 
                                623                 :                :                 /* current line is done? */
                                624         [ +  + ]:          37217 :                 if (buf[buflen - 1] == '\n')
                                625                 :                :                 {
                                626                 :                :                     /*
                                627                 :                :                      * When at the beginning of the line and the data is
                                628                 :                :                      * inlined, check for EOF marker.  If the marker is found,
                                629                 :                :                      * we must stop at this point.  If not, the \. line can be
                                630                 :                :                      * sent to the server, and we let it decide whether it's
                                631                 :                :                      * an EOF or not depending on the format: in TEXT mode, \.
                                632                 :                :                      * will be interpreted as an EOF, in CSV, it will not.
                                633                 :                :                      */
  696 tgl@sss.pgh.pa.us         634   [ +  +  +  + ]:          37155 :                     if (at_line_begin && copystream == pset.cur_cmd_source)
                                635                 :                :                     {
 1870 heikki.linnakangas@i      636   [ +  +  +  +  :           2707 :                         if ((linelen == 3 && memcmp(fgresult, "\\.\n", 3) == 0) ||
                                              +  + ]
                                637         [ -  + ]:             60 :                             (linelen == 4 && memcmp(fgresult, "\\.\r\n", 4) == 0))
                                638                 :                :                         {
                                639                 :            903 :                             copydone = true;
                                640                 :                : 
                                641                 :                :                             /*
                                642                 :                :                              * Remove the EOF marker from the data sent.  In
                                643                 :                :                              * CSV mode, the EOF marker must be removed,
                                644                 :                :                              * otherwise it would be interpreted by the server
                                645                 :                :                              * as valid data.
                                646                 :                :                              */
  696 tgl@sss.pgh.pa.us         647                 :            903 :                             *fgresult = '\0';
                                648                 :            903 :                             buflen -= linelen;
                                649                 :                :                         }
                                650                 :                :                     }
                                651                 :                : 
 1870 heikki.linnakangas@i      652         [ +  + ]:          37155 :                     if (copystream == pset.cur_cmd_source)
                                653                 :                :                     {
                                654                 :           2716 :                         pset.lineno++;
                                655                 :           2716 :                         pset.stmt_lineno++;
                                656                 :                :                     }
                                657                 :          37155 :                     at_line_begin = true;
                                658                 :                :                 }
                                659                 :                :                 else
                                660                 :             62 :                     at_line_begin = false;
                                661                 :                :             }
                                662                 :                : 
                                663                 :                :             /*
                                664                 :                :              * If the buffer is full, or we've reached the EOF, flush it.
                                665                 :                :              *
                                666                 :                :              * Make sure there's always space for four more bytes in the
                                667                 :                :              * buffer, plus a NUL terminator.  That way, an EOF marker is
                                668                 :                :              * never split across two fgets() calls, which simplifies the
                                669                 :                :              * logic.
                                670                 :                :              */
                                671   [ +  +  +  +  :          37259 :             if (buflen >= COPYBUFSIZ - 5 || (copydone && buflen > 0))
                                              +  + ]
                                672                 :                :             {
   17 tgl@sss.pgh.pa.us         673   [ +  +  -  + ]:            715 :                 if (conn && PQputCopyData(conn, buf, buflen) <= 0)
                                674                 :                :                 {
 7398 tgl@sss.pgh.pa.us         675                 :UIC           0 :                     OK = false;
                                676                 :              0 :                     break;
                                677                 :                :                 }
                                678                 :                : 
 1870 heikki.linnakangas@i      679                 :GIC         715 :                 buflen = 0;
                                680                 :                :             }
                                681                 :                :         }
                                682                 :                :     }
                                683                 :                : 
                                684                 :                :     /* Check for read error */
 7398 tgl@sss.pgh.pa.us         685         [ -  + ]:            945 :     if (ferror(copystream))
 7398 tgl@sss.pgh.pa.us         686                 :UIC           0 :         OK = false;
                                687                 :                : 
                                688                 :                :     /*
                                689                 :                :      * Terminate data transfer.  We can't send an error message if we're using
                                690                 :                :      * protocol version 2.  (libpq no longer supports protocol version 2, but
                                691                 :                :      * keep the version checks just in case you're using a pre-v14 libpq.so at
                                692                 :                :      * runtime)
                                693                 :                :      */
   17 tgl@sss.pgh.pa.us         694         [ +  + ]:GIC         945 :     if (conn &&
                                695   [ -  +  +  - ]:            641 :         PQputCopyEnd(conn,
 4578 tgl@sss.pgh.pa.us         696         [ #  # ]:UIC           0 :                      (OK || PQprotocolVersion(conn) < 3) ? NULL :
                                697                 :              0 :                      _("aborted because of read failure")) <= 0)
 7482                           698                 :              0 :         OK = false;
                                699                 :                : 
 5328 alvherre@alvh.no-ip.      700                 :GIC         945 : copyin_cleanup:
                                701                 :                : 
                                702                 :                :     /*
                                703                 :                :      * Clear the EOF flag on the stream, in case copying ended due to an EOF
                                704                 :                :      * signal.  This allows an interactive TTY session to perform another COPY
                                705                 :                :      * FROM STDIN later.  (In non-STDIN cases, we're about to close the file
                                706                 :                :      * anyway, so it doesn't matter.)  Although we don't ever test the flag
                                707                 :                :      * with feof(), some fread() implementations won't read more data if it's
                                708                 :                :      * set.  This also clears the error flag, but we already checked that.
                                709                 :                :      */
 3389 tgl@sss.pgh.pa.us         710                 :            945 :     clearerr(copystream);
                                711                 :                : 
                                712                 :                :     /* Done if we don't have a connection to clean up */
   17                           713         [ +  + ]:            945 :     if (!conn)
                                714                 :            304 :         return OK;
                                715                 :                : 
                                716                 :                :     /*
                                717                 :                :      * Check command status and return to normal libpq state.
                                718                 :                :      *
                                719                 :                :      * We do not want to return with the status still PGRES_COPY_IN: our
                                720                 :                :      * caller would be unable to distinguish that situation from reaching the
                                721                 :                :      * next COPY in a command string that happened to contain two consecutive
                                722                 :                :      * COPY FROM STDIN commands.  We keep trying PQputCopyEnd() in the hope
                                723                 :                :      * it'll work eventually.  (What's actually likely to happen is that in
                                724                 :                :      * attempting to flush the data, libpq will eventually realize that the
                                725                 :                :      * connection is lost.  But that's fine; it will get us out of COPY_IN
                                726                 :                :      * state, which is what we need.)
                                727                 :                :      */
 4550                           728         [ -  + ]:            641 :     while (*res = PQgetResult(conn), PQresultStatus(*res) == PGRES_COPY_IN)
                                729                 :                :     {
 5328 alvherre@alvh.no-ip.      730                 :UIC           0 :         OK = false;
 4550 tgl@sss.pgh.pa.us         731                 :              0 :         PQclear(*res);
                                732                 :                :         /* We can't send an error message if we're using protocol version 2 */
 4578                           733                 :              0 :         PQputCopyEnd(conn,
                                734         [ #  # ]:              0 :                      (PQprotocolVersion(conn) < 3) ? NULL :
                                735                 :              0 :                      _("trying to exit copy mode"));
                                736                 :                :     }
 4550 tgl@sss.pgh.pa.us         737         [ +  + ]:GIC         641 :     if (PQresultStatus(*res) != PGRES_COMMAND_OK)
                                738                 :                :     {
 2705 peter@eisentraut.org      739                 :            161 :         pg_log_info("%s", PQerrorMessage(conn));
 7482 tgl@sss.pgh.pa.us         740                 :            161 :         OK = false;
                                741                 :                :     }
                                742                 :                : 
                                743                 :            641 :     return OK;
                                744                 :                : }
        

Generated by: LCOV version 2.0-1