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(stdout);
292  fflush(stderr);
293  errno = 0;
294  copystream = popen(options->file, PG_BINARY_R);
295  }
296  else
297  copystream = fopen(options->file, PG_BINARY_R);
298  }
299  else if (!options->psql_inout)
300  copystream = pset.cur_cmd_source;
301  else
302  copystream = stdin;
303  }
304  else
305  {
306  if (options->file)
307  {
308  if (options->program)
309  {
310  fflush(stdout);
311  fflush(stderr);
312  errno = 0;
314  copystream = popen(options->file, PG_BINARY_W);
315  }
316  else
317  copystream = fopen(options->file, PG_BINARY_W);
318  }
319  else if (!options->psql_inout)
320  copystream = pset.queryFout;
321  else
322  copystream = stdout;
323  }
324 
325  if (!copystream)
326  {
327  if (options->program)
328  pg_log_error("could not execute command \"%s\": %m",
329  options->file);
330  else
331  pg_log_error("%s: %m",
332  options->file);
334  return false;
335  }
336 
337  if (!options->program)
338  {
339  struct stat st;
340  int result;
341 
342  /* make sure the specified file is not a directory */
343  if ((result = fstat(fileno(copystream), &st)) < 0)
344  pg_log_error("could not stat file \"%s\": %m",
345  options->file);
346 
347  if (result == 0 && S_ISDIR(st.st_mode))
348  pg_log_error("%s: cannot copy from/to a directory",
349  options->file);
350 
351  if (result < 0 || S_ISDIR(st.st_mode))
352  {
353  fclose(copystream);
355  return false;
356  }
357  }
358 
359  /* build the command we will send to the backend */
360  initPQExpBuffer(&query);
361  printfPQExpBuffer(&query, "COPY ");
362  appendPQExpBufferStr(&query, options->before_tofrom);
363  if (options->from)
364  appendPQExpBufferStr(&query, " FROM STDIN ");
365  else
366  appendPQExpBufferStr(&query, " TO STDOUT ");
367  if (options->after_tofrom)
368  appendPQExpBufferStr(&query, options->after_tofrom);
369 
370  /* run it like a user command, but with copystream as data source/sink */
371  pset.copyStream = copystream;
372  success = SendQuery(query.data);
373  pset.copyStream = NULL;
374  termPQExpBuffer(&query);
375 
376  if (options->file != NULL)
377  {
378  if (options->program)
379  {
380  int pclose_rc = pclose(copystream);
381 
382  if (pclose_rc != 0)
383  {
384  if (pclose_rc < 0)
385  pg_log_error("could not close pipe to external command: %m");
386  else
387  {
388  char *reason = wait_result_to_str(pclose_rc);
389 
390  pg_log_error("%s: %s", options->file,
391  reason ? reason : "");
392  free(reason);
393  }
394  success = false;
395  }
397  }
398  else
399  {
400  if (fclose(copystream) != 0)
401  {
402  pg_log_error("%s: %m", options->file);
403  success = false;
404  }
405  }
406  }
408  return success;
409 }
bool SendQuery(const char *query)
Definition: common.c:1076
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:1266
#define PG_BINARY_W
Definition: c.h:1267
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:170
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:237
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
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:105
char * wait_result_to_str(int exitstatus)
Definition: wait_error.c:32
#define S_ISDIR(m)
Definition: win32_port.h:318
#define fstat
Definition: win32_port.h:276

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 512 of file copy.c.

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

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 435 of file copy.c.

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

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

Referenced by HandleCopyResult().