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