PostgreSQL Source Code  git master
copy.h File Reference
#include "libpq-fe.h"
Include dependency graph for copy.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

bool do_copy (const char *args)
 
bool handleCopyOut (PGconn *conn, FILE *copystream, PGresult **res)
 
bool handleCopyIn (PGconn *conn, FILE *copystream, bool isbinary, PGresult **res)
 

Function Documentation

◆ do_copy()

bool do_copy ( const char *  args)

Definition at line 268 of file copy.c.

269 {
270  PQExpBufferData query;
271  FILE *copystream;
272  struct copy_options *options;
273  bool success;
274 
275  /* parse options */
277 
278  if (!options)
279  return false;
280 
281  /* prepare to read or write the target file */
282  if (options->file && !options->program)
283  canonicalize_path(options->file);
284 
285  if (options->from)
286  {
287  if (options->file)
288  {
289  if (options->program)
290  {
291  fflush(NULL);
292  errno = 0;
293  copystream = popen(options->file, PG_BINARY_R);
294  }
295  else
296  copystream = fopen(options->file, PG_BINARY_R);
297  }
298  else if (!options->psql_inout)
299  copystream = pset.cur_cmd_source;
300  else
301  copystream = stdin;
302  }
303  else
304  {
305  if (options->file)
306  {
307  if (options->program)
308  {
309  fflush(NULL);
311  errno = 0;
312  copystream = popen(options->file, PG_BINARY_W);
313  }
314  else
315  copystream = fopen(options->file, PG_BINARY_W);
316  }
317  else if (!options->psql_inout)
318  copystream = pset.queryFout;
319  else
320  copystream = stdout;
321  }
322 
323  if (!copystream)
324  {
325  if (options->program)
326  pg_log_error("could not execute command \"%s\": %m",
327  options->file);
328  else
329  pg_log_error("%s: %m",
330  options->file);
332  return false;
333  }
334 
335  if (!options->program)
336  {
337  struct stat st;
338  int result;
339 
340  /* make sure the specified file is not a directory */
341  if ((result = fstat(fileno(copystream), &st)) < 0)
342  pg_log_error("could not stat file \"%s\": %m",
343  options->file);
344 
345  if (result == 0 && S_ISDIR(st.st_mode))
346  pg_log_error("%s: cannot copy from/to a directory",
347  options->file);
348 
349  if (result < 0 || S_ISDIR(st.st_mode))
350  {
351  fclose(copystream);
353  return false;
354  }
355  }
356 
357  /* build the command we will send to the backend */
358  initPQExpBuffer(&query);
359  printfPQExpBuffer(&query, "COPY ");
360  appendPQExpBufferStr(&query, options->before_tofrom);
361  if (options->from)
362  appendPQExpBufferStr(&query, " FROM STDIN ");
363  else
364  appendPQExpBufferStr(&query, " TO STDOUT ");
365  if (options->after_tofrom)
366  appendPQExpBufferStr(&query, options->after_tofrom);
367 
368  /* run it like a user command, but with copystream as data source/sink */
369  pset.copyStream = copystream;
370  success = SendQuery(query.data);
371  pset.copyStream = NULL;
372  termPQExpBuffer(&query);
373 
374  if (options->file != NULL)
375  {
376  if (options->program)
377  {
378  int pclose_rc = pclose(copystream);
379 
380  if (pclose_rc != 0)
381  {
382  if (pclose_rc < 0)
383  pg_log_error("could not close pipe to external command: %m");
384  else
385  {
386  char *reason = wait_result_to_str(pclose_rc);
387 
388  pg_log_error("%s: %s", options->file,
389  reason ? reason : "");
390  free(reason);
391  }
392  success = false;
393  }
395  }
396  else
397  {
398  if (fclose(copystream) != 0)
399  {
400  pg_log_error("%s: %m", options->file);
401  success = false;
402  }
403  }
404  }
406  return success;
407 }
bool SendQuery(const char *query)
Definition: common.c:1022
static struct copy_options * parse_slash_copy(const char *args)
Definition: copy.c:89
static void free_copy_options(struct copy_options *ptr)
Definition: copy.c:65
#define PG_BINARY_R
Definition: c.h:1262
#define PG_BINARY_W
Definition: c.h:1263
void restore_sigpipe_trap(void)
Definition: print.c:3061
void disable_sigpipe_trap(void)
Definition: print.c:3038
#define free(a)
Definition: header.h:65
static bool success
Definition: initdb.c:187
static void const char fflush(stdout)
#define pg_log_error(...)
Definition: logging.h:106
static char ** options
void canonicalize_path(char *path)
Definition: path.c:264
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:235
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:90
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:367
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:129
PsqlSettings pset
Definition: startup.c:32
FILE * copyStream
Definition: settings.h:87
FILE * queryFout
Definition: settings.h:84
FILE * cur_cmd_source
Definition: settings.h:108
char * wait_result_to_str(int exitstatus)
Definition: wait_error.c:33
#define S_ISDIR(m)
Definition: win32_port.h:327
#define fstat
Definition: win32_port.h:285

References appendPQExpBufferStr(), generate_unaccent_rules::args, canonicalize_path(), _psqlSettings::copyStream, _psqlSettings::cur_cmd_source, PQExpBufferData::data, disable_sigpipe_trap(), fflush(), free, free_copy_options(), fstat, initPQExpBuffer(), options, parse_slash_copy(), PG_BINARY_R, PG_BINARY_W, pg_log_error, printfPQExpBuffer(), pset, _psqlSettings::queryFout, restore_sigpipe_trap(), S_ISDIR, SendQuery(), stat::st_mode, generate_unaccent_rules::stdout, success, termPQExpBuffer(), and wait_result_to_str().

Referenced by exec_command_copy().

◆ handleCopyIn()

bool handleCopyIn ( PGconn conn,
FILE *  copystream,
bool  isbinary,
PGresult **  res 
)

Definition at line 510 of file copy.c.

511 {
512  bool OK;
513  char buf[COPYBUFSIZ];
514  bool showprompt;
515 
516  /*
517  * Establish longjmp destination for exiting from wait-for-input. (This is
518  * only effective while sigint_interrupt_enabled is TRUE.)
519  */
520  if (sigsetjmp(sigint_interrupt_jmp, 1) != 0)
521  {
522  /* got here with longjmp */
523 
524  /* Terminate data transfer */
526  (PQprotocolVersion(conn) < 3) ? NULL :
527  _("canceled by user"));
528 
529  OK = false;
530  goto copyin_cleanup;
531  }
532 
533  /* Prompt if interactive input */
534  if (isatty(fileno(copystream)))
535  {
536  showprompt = true;
537  if (!pset.quiet)
538  puts(_("Enter data to be copied followed by a newline.\n"
539  "End with a backslash and a period on a line by itself, or an EOF signal."));
540  }
541  else
542  showprompt = false;
543 
544  OK = true;
545 
546  if (isbinary)
547  {
548  /* interactive input probably silly, but give one prompt anyway */
549  if (showprompt)
550  {
551  const char *prompt = get_prompt(PROMPT_COPY, NULL);
552 
553  fputs(prompt, stdout);
554  fflush(stdout);
555  }
556 
557  for (;;)
558  {
559  int buflen;
560 
561  /* enable longjmp while waiting for input */
563 
564  buflen = fread(buf, 1, COPYBUFSIZ, copystream);
565 
566  sigint_interrupt_enabled = false;
567 
568  if (buflen <= 0)
569  break;
570 
571  if (PQputCopyData(conn, buf, buflen) <= 0)
572  {
573  OK = false;
574  break;
575  }
576  }
577  }
578  else
579  {
580  bool copydone = false;
581  int buflen;
582  bool at_line_begin = true;
583 
584  /*
585  * In text mode, we have to read the input one line at a time, so that
586  * we can stop reading at the EOF marker (\.). We mustn't read beyond
587  * the EOF marker, because if the data was inlined in a SQL script, we
588  * would eat up the commands after the EOF marker.
589  */
590  buflen = 0;
591  while (!copydone)
592  {
593  char *fgresult;
594 
595  if (at_line_begin && showprompt)
596  {
597  const char *prompt = get_prompt(PROMPT_COPY, NULL);
598 
599  fputs(prompt, stdout);
600  fflush(stdout);
601  }
602 
603  /* enable longjmp while waiting for input */
605 
606  fgresult = fgets(&buf[buflen], COPYBUFSIZ - buflen, copystream);
607 
608  sigint_interrupt_enabled = false;
609 
610  if (!fgresult)
611  copydone = true;
612  else
613  {
614  int linelen;
615 
616  linelen = strlen(fgresult);
617  buflen += linelen;
618 
619  /* current line is done? */
620  if (buf[buflen - 1] == '\n')
621  {
622  /* check for EOF marker, but not on a partial line */
623  if (at_line_begin)
624  {
625  /*
626  * This code erroneously assumes '\.' on a line alone
627  * inside a quoted CSV string terminates the \copy.
628  * https://www.postgresql.org/message-id/E1TdNVQ-0001ju-GO@wrigleys.postgresql.org
629  */
630  if ((linelen == 3 && memcmp(fgresult, "\\.\n", 3) == 0) ||
631  (linelen == 4 && memcmp(fgresult, "\\.\r\n", 4) == 0))
632  {
633  copydone = true;
634  }
635  }
636 
637  if (copystream == pset.cur_cmd_source)
638  {
639  pset.lineno++;
640  pset.stmt_lineno++;
641  }
642  at_line_begin = true;
643  }
644  else
645  at_line_begin = false;
646  }
647 
648  /*
649  * If the buffer is full, or we've reached the EOF, flush it.
650  *
651  * Make sure there's always space for four more bytes in the
652  * buffer, plus a NUL terminator. That way, an EOF marker is
653  * never split across two fgets() calls, which simplifies the
654  * logic.
655  */
656  if (buflen >= COPYBUFSIZ - 5 || (copydone && buflen > 0))
657  {
658  if (PQputCopyData(conn, buf, buflen) <= 0)
659  {
660  OK = false;
661  break;
662  }
663 
664  buflen = 0;
665  }
666  }
667  }
668 
669  /* Check for read error */
670  if (ferror(copystream))
671  OK = false;
672 
673  /*
674  * Terminate data transfer. We can't send an error message if we're using
675  * protocol version 2. (libpq no longer supports protocol version 2, but
676  * keep the version checks just in case you're using a pre-v14 libpq.so at
677  * runtime)
678  */
679  if (PQputCopyEnd(conn,
680  (OK || PQprotocolVersion(conn) < 3) ? NULL :
681  _("aborted because of read failure")) <= 0)
682  OK = false;
683 
684 copyin_cleanup:
685 
686  /*
687  * Clear the EOF flag on the stream, in case copying ended due to an EOF
688  * signal. This allows an interactive TTY session to perform another COPY
689  * FROM STDIN later. (In non-STDIN cases, we're about to close the file
690  * anyway, so it doesn't matter.) Although we don't ever test the flag
691  * with feof(), some fread() implementations won't read more data if it's
692  * set. This also clears the error flag, but we already checked that.
693  */
694  clearerr(copystream);
695 
696  /*
697  * Check command status and return to normal libpq state.
698  *
699  * We do not want to return with the status still PGRES_COPY_IN: our
700  * caller would be unable to distinguish that situation from reaching the
701  * next COPY in a command string that happened to contain two consecutive
702  * COPY FROM STDIN commands. We keep trying PQputCopyEnd() in the hope
703  * it'll work eventually. (What's actually likely to happen is that in
704  * attempting to flush the data, libpq will eventually realize that the
705  * connection is lost. But that's fine; it will get us out of COPY_IN
706  * state, which is what we need.)
707  */
709  {
710  OK = false;
711  PQclear(*res);
712  /* We can't send an error message if we're using protocol version 2 */
714  (PQprotocolVersion(conn) < 3) ? NULL :
715  _("trying to exit copy mode"));
716  }
718  {
720  OK = false;
721  }
722 
723  return OK;
724 }
volatile sig_atomic_t sigint_interrupt_enabled
Definition: common.c:253
sigjmp_buf sigint_interrupt_jmp
Definition: common.c:255
#define COPYBUFSIZ
Definition: copy.c:507
#define _(x)
Definition: elog.c:91
int PQprotocolVersion(const PGconn *conn)
Definition: fe-connect.c:6998
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:7018
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:3240
int PQputCopyEnd(PGconn *conn, const char *errormsg)
Definition: fe-exec.c:2631
int PQputCopyData(PGconn *conn, const char *buffer, int nbytes)
Definition: fe-exec.c:2576
PGresult * PQgetResult(PGconn *conn)
Definition: fe-exec.c:2031
@ PGRES_COPY_IN
Definition: libpq-fe.h:104
@ PGRES_COMMAND_OK
Definition: libpq-fe.h:97
#define pg_log_info(...)
Definition: logging.h:124
static char * buf
Definition: pg_test_fsync.c:67
char * get_prompt(promptStatus_t status, ConditionalStack cstack)
Definition: prompt.c:66
@ PROMPT_COPY
Definition: psqlscan.h:48
PGconn * conn
Definition: streamutil.c:54
uint64 lineno
Definition: settings.h:114
uint64 stmt_lineno
Definition: settings.h:115

References _, buf, conn, COPYBUFSIZ, _psqlSettings::cur_cmd_source, fflush(), get_prompt(), _psqlSettings::lineno, pg_log_info, PGRES_COMMAND_OK, PGRES_COPY_IN, PQclear(), PQerrorMessage(), PQgetResult(), PQprotocolVersion(), PQputCopyData(), PQputCopyEnd(), PQresultStatus(), PROMPT_COPY, pset, _psqlSettings::quiet, res, sigint_interrupt_enabled, sigint_interrupt_jmp, generate_unaccent_rules::stdout, and _psqlSettings::stmt_lineno.

Referenced by HandleCopyResult().

◆ handleCopyOut()

bool handleCopyOut ( PGconn conn,
FILE *  copystream,
PGresult **  res 
)

Definition at line 433 of file copy.c.

434 {
435  bool OK = true;
436  char *buf;
437  int ret;
438 
439  for (;;)
440  {
441  ret = PQgetCopyData(conn, &buf, 0);
442 
443  if (ret < 0)
444  break; /* done or server/connection error */
445 
446  if (buf)
447  {
448  if (OK && copystream && fwrite(buf, 1, ret, copystream) != ret)
449  {
450  pg_log_error("could not write COPY data: %m");
451  /* complain only once, keep reading data from server */
452  OK = false;
453  }
454  PQfreemem(buf);
455  }
456  }
457 
458  if (OK && copystream && fflush(copystream))
459  {
460  pg_log_error("could not write COPY data: %m");
461  OK = false;
462  }
463 
464  if (ret == -2)
465  {
466  pg_log_error("COPY data transfer failed: %s", PQerrorMessage(conn));
467  OK = false;
468  }
469 
470  /*
471  * Check command status and return to normal libpq state.
472  *
473  * If for some reason libpq is still reporting PGRES_COPY_OUT state, we
474  * would like to forcibly exit that state, since our caller would be
475  * unable to distinguish that situation from reaching the next COPY in a
476  * command string that happened to contain two consecutive COPY TO STDOUT
477  * commands. However, libpq provides no API for doing that, and in
478  * principle it's a libpq bug anyway if PQgetCopyData() returns -1 or -2
479  * but hasn't exited COPY_OUT state internally. So we ignore the
480  * possibility here.
481  */
482  *res = PQgetResult(conn);
484  {
486  OK = false;
487  }
488 
489  return OK;
490 }
void PQfreemem(void *ptr)
Definition: fe-exec.c:3865
int PQgetCopyData(PGconn *conn, char **buffer, int async)
Definition: fe-exec.c:2698

References buf, conn, fflush(), pg_log_error, pg_log_info, PGRES_COMMAND_OK, PQerrorMessage(), PQfreemem(), PQgetCopyData(), PQgetResult(), PQresultStatus(), and res.

Referenced by HandleCopyResult().