Fix obsolete comment regarding FSM truncation.
[PostgreSQL.git] / src / bin / psql / copy.c
blob2ddc9d7cb383e677d278cd2bfd1dfd8720dc54ca
1 /*
2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2008, PostgreSQL Global Development Group
6 * $PostgreSQL$
7 */
8 #include "postgres_fe.h"
9 #include "copy.h"
11 #include <signal.h>
12 #include <sys/stat.h>
13 #ifndef WIN32
14 #include <unistd.h> /* for isatty */
15 #else
16 #include <io.h> /* I think */
17 #endif
19 #include "libpq-fe.h"
20 #include "pqexpbuffer.h"
21 #include "pqsignal.h"
22 #include "dumputils.h"
24 #include "settings.h"
25 #include "common.h"
26 #include "prompt.h"
27 #include "stringutils.h"
29 #if defined(WIN32) && !defined(S_ISDIR)
30 #define __S_ISTYPE(mode, mask) (((mode) & S_IFMT) == (mask))
31 #define S_ISDIR(mode) __S_ISTYPE((mode), S_IFDIR)
32 #endif
35 * parse_slash_copy
36 * -- parses \copy command line
38 * The documented syntax is:
39 * \copy tablename [(columnlist)] from|to filename
40 * [ with ] [ binary ] [ oids ] [ delimiter [as] char ] [ null [as] string ]
41 * [ csv [ header ] [ quote [ AS ] string ] escape [as] string
42 * [ force not null column [, ...] | force quote column [, ...] ] ]
44 * \copy ( select stmt ) to filename
45 * [ with ] [ binary ] [ delimiter [as] char ] [ null [as] string ]
46 * [ csv [ header ] [ quote [ AS ] string ] escape [as] string
47 * [ force quote column [, ...] ] ]
49 * Force quote only applies for copy to; force not null only applies for
50 * copy from.
52 * table name can be double-quoted and can have a schema part.
53 * column names can be double-quoted.
54 * filename, char, and string can be single-quoted like SQL literals.
56 * returns a malloc'ed structure with the options, or NULL on parsing error
59 struct copy_options
61 char *table;
62 char *column_list;
63 char *file; /* NULL = stdin/stdout */
64 bool psql_inout; /* true = use psql stdin/stdout */
65 bool from;
66 bool binary;
67 bool oids;
68 bool csv_mode;
69 bool header;
70 char *delim;
71 char *null;
72 char *quote;
73 char *escape;
74 char *force_quote_list;
75 char *force_notnull_list;
79 static void
80 free_copy_options(struct copy_options * ptr)
82 if (!ptr)
83 return;
84 free(ptr->table);
85 free(ptr->column_list);
86 free(ptr->file);
87 free(ptr->delim);
88 free(ptr->null);
89 free(ptr->quote);
90 free(ptr->escape);
91 free(ptr->force_quote_list);
92 free(ptr->force_notnull_list);
93 free(ptr);
97 /* concatenate "more" onto "var", freeing the original value of *var */
98 static void
99 xstrcat(char **var, const char *more)
101 char *newvar;
103 newvar = pg_malloc(strlen(*var) + strlen(more) + 1);
104 strcpy(newvar, *var);
105 strcat(newvar, more);
106 free(*var);
107 *var = newvar;
111 static struct copy_options *
112 parse_slash_copy(const char *args)
114 struct copy_options *result;
115 char *line;
116 char *token;
117 const char *whitespace = " \t\n\r";
118 char nonstd_backslash = standard_strings() ? 0 : '\\';
120 if (args)
121 line = pg_strdup(args);
122 else
124 psql_error("\\copy: arguments required\n");
125 return NULL;
128 result = pg_calloc(1, sizeof(struct copy_options));
130 token = strtokx(line, whitespace, ".,()", "\"",
131 0, false, false, pset.encoding);
132 if (!token)
133 goto error;
135 if (pg_strcasecmp(token, "binary") == 0)
137 result->binary = true;
138 token = strtokx(NULL, whitespace, ".,()", "\"",
139 0, false, false, pset.encoding);
140 if (!token)
141 goto error;
144 result->table = pg_strdup(token);
146 /* Handle COPY (SELECT) case */
147 if (token[0] == '(')
149 int parens = 1;
151 while (parens > 0)
153 token = strtokx(NULL, whitespace, ".,()", "\"'",
154 nonstd_backslash, true, false, pset.encoding);
155 if (!token)
156 goto error;
157 if (token[0] == '(')
158 parens++;
159 else if (token[0] == ')')
160 parens--;
161 xstrcat(&result->table, " ");
162 xstrcat(&result->table, token);
166 token = strtokx(NULL, whitespace, ".,()", "\"",
167 0, false, false, pset.encoding);
168 if (!token)
169 goto error;
172 * strtokx() will not have returned a multi-character token starting with
173 * '.', so we don't need strcmp() here. Likewise for '(', etc, below.
175 if (token[0] == '.')
177 /* handle schema . table */
178 xstrcat(&result->table, token);
179 token = strtokx(NULL, whitespace, ".,()", "\"",
180 0, false, false, pset.encoding);
181 if (!token)
182 goto error;
183 xstrcat(&result->table, token);
184 token = strtokx(NULL, whitespace, ".,()", "\"",
185 0, false, false, pset.encoding);
186 if (!token)
187 goto error;
190 if (token[0] == '(')
192 /* handle parenthesized column list */
193 result->column_list = pg_strdup(token);
194 for (;;)
196 token = strtokx(NULL, whitespace, ".,()", "\"",
197 0, false, false, pset.encoding);
198 if (!token || strchr(".,()", token[0]))
199 goto error;
200 xstrcat(&result->column_list, token);
201 token = strtokx(NULL, whitespace, ".,()", "\"",
202 0, false, false, pset.encoding);
203 if (!token)
204 goto error;
205 xstrcat(&result->column_list, token);
206 if (token[0] == ')')
207 break;
208 if (token[0] != ',')
209 goto error;
211 token = strtokx(NULL, whitespace, ".,()", "\"",
212 0, false, false, pset.encoding);
213 if (!token)
214 goto error;
217 if (pg_strcasecmp(token, "from") == 0)
218 result->from = true;
219 else if (pg_strcasecmp(token, "to") == 0)
220 result->from = false;
221 else
222 goto error;
224 token = strtokx(NULL, whitespace, NULL, "'",
225 0, false, true, pset.encoding);
226 if (!token)
227 goto error;
229 if (pg_strcasecmp(token, "stdin") == 0 ||
230 pg_strcasecmp(token, "stdout") == 0)
232 result->psql_inout = false;
233 result->file = NULL;
235 else if (pg_strcasecmp(token, "pstdin") == 0 ||
236 pg_strcasecmp(token, "pstdout") == 0)
238 result->psql_inout = true;
239 result->file = NULL;
241 else
243 result->psql_inout = false;
244 result->file = pg_strdup(token);
245 expand_tilde(&result->file);
248 token = strtokx(NULL, whitespace, NULL, NULL,
249 0, false, false, pset.encoding);
251 if (token)
254 * WITH is optional. Also, the backend will allow WITH followed by
255 * nothing, so we do too.
257 if (pg_strcasecmp(token, "with") == 0)
258 token = strtokx(NULL, whitespace, NULL, NULL,
259 0, false, false, pset.encoding);
261 while (token)
263 bool fetch_next;
265 fetch_next = true;
267 if (pg_strcasecmp(token, "oids") == 0)
268 result->oids = true;
269 else if (pg_strcasecmp(token, "binary") == 0)
270 result->binary = true;
271 else if (pg_strcasecmp(token, "csv") == 0)
272 result->csv_mode = true;
273 else if (pg_strcasecmp(token, "header") == 0)
274 result->header = true;
275 else if (pg_strcasecmp(token, "delimiter") == 0)
277 if (result->delim)
278 goto error;
279 token = strtokx(NULL, whitespace, NULL, "'",
280 nonstd_backslash, true, false, pset.encoding);
281 if (token && pg_strcasecmp(token, "as") == 0)
282 token = strtokx(NULL, whitespace, NULL, "'",
283 nonstd_backslash, true, false, pset.encoding);
284 if (token)
285 result->delim = pg_strdup(token);
286 else
287 goto error;
289 else if (pg_strcasecmp(token, "null") == 0)
291 if (result->null)
292 goto error;
293 token = strtokx(NULL, whitespace, NULL, "'",
294 nonstd_backslash, true, false, pset.encoding);
295 if (token && pg_strcasecmp(token, "as") == 0)
296 token = strtokx(NULL, whitespace, NULL, "'",
297 nonstd_backslash, true, false, pset.encoding);
298 if (token)
299 result->null = pg_strdup(token);
300 else
301 goto error;
303 else if (pg_strcasecmp(token, "quote") == 0)
305 if (result->quote)
306 goto error;
307 token = strtokx(NULL, whitespace, NULL, "'",
308 nonstd_backslash, true, false, pset.encoding);
309 if (token && pg_strcasecmp(token, "as") == 0)
310 token = strtokx(NULL, whitespace, NULL, "'",
311 nonstd_backslash, true, false, pset.encoding);
312 if (token)
313 result->quote = pg_strdup(token);
314 else
315 goto error;
317 else if (pg_strcasecmp(token, "escape") == 0)
319 if (result->escape)
320 goto error;
321 token = strtokx(NULL, whitespace, NULL, "'",
322 nonstd_backslash, true, false, pset.encoding);
323 if (token && pg_strcasecmp(token, "as") == 0)
324 token = strtokx(NULL, whitespace, NULL, "'",
325 nonstd_backslash, true, false, pset.encoding);
326 if (token)
327 result->escape = pg_strdup(token);
328 else
329 goto error;
331 else if (pg_strcasecmp(token, "force") == 0)
333 token = strtokx(NULL, whitespace, ",", "\"",
334 0, false, false, pset.encoding);
335 if (pg_strcasecmp(token, "quote") == 0)
337 if (result->force_quote_list)
338 goto error;
339 /* handle column list */
340 fetch_next = false;
341 for (;;)
343 token = strtokx(NULL, whitespace, ",", "\"",
344 0, false, false, pset.encoding);
345 if (!token || strchr(",", token[0]))
346 goto error;
347 if (!result->force_quote_list)
348 result->force_quote_list = pg_strdup(token);
349 else
350 xstrcat(&result->force_quote_list, token);
351 token = strtokx(NULL, whitespace, ",", "\"",
352 0, false, false, pset.encoding);
353 if (!token || token[0] != ',')
354 break;
355 xstrcat(&result->force_quote_list, token);
358 else if (pg_strcasecmp(token, "not") == 0)
360 if (result->force_notnull_list)
361 goto error;
362 token = strtokx(NULL, whitespace, ",", "\"",
363 0, false, false, pset.encoding);
364 if (pg_strcasecmp(token, "null") != 0)
365 goto error;
366 /* handle column list */
367 fetch_next = false;
368 for (;;)
370 token = strtokx(NULL, whitespace, ",", "\"",
371 0, false, false, pset.encoding);
372 if (!token || strchr(",", token[0]))
373 goto error;
374 if (!result->force_notnull_list)
375 result->force_notnull_list = pg_strdup(token);
376 else
377 xstrcat(&result->force_notnull_list, token);
378 token = strtokx(NULL, whitespace, ",", "\"",
379 0, false, false, pset.encoding);
380 if (!token || token[0] != ',')
381 break;
382 xstrcat(&result->force_notnull_list, token);
385 else
386 goto error;
388 else
389 goto error;
391 if (fetch_next)
392 token = strtokx(NULL, whitespace, NULL, NULL,
393 0, false, false, pset.encoding);
397 free(line);
399 return result;
401 error:
402 if (token)
403 psql_error("\\copy: parse error at \"%s\"\n", token);
404 else
405 psql_error("\\copy: parse error at end of line\n");
406 free_copy_options(result);
407 free(line);
409 return NULL;
414 * Handle one of the "string" options of COPY. If the user gave a quoted
415 * string, pass it to the backend as-is; if it wasn't quoted then quote
416 * and escape it.
418 static void
419 emit_copy_option(PQExpBuffer query, const char *keyword, const char *option)
421 appendPQExpBufferStr(query, keyword);
422 if (option[0] == '\'' ||
423 ((option[0] == 'E' || option[0] == 'e') && option[1] == '\''))
424 appendPQExpBufferStr(query, option);
425 else
426 appendStringLiteralConn(query, option, pset.db);
431 * Execute a \copy command (frontend copy). We have to open a file, then
432 * submit a COPY query to the backend and either feed it data from the
433 * file or route its response into the file.
435 bool
436 do_copy(const char *args)
438 PQExpBufferData query;
439 FILE *copystream;
440 struct copy_options *options;
441 PGresult *result;
442 bool success;
443 struct stat st;
445 /* parse options */
446 options = parse_slash_copy(args);
448 if (!options)
449 return false;
451 initPQExpBuffer(&query);
453 printfPQExpBuffer(&query, "COPY ");
455 appendPQExpBuffer(&query, "%s ", options->table);
457 if (options->column_list)
458 appendPQExpBuffer(&query, "%s ", options->column_list);
460 if (options->from)
461 appendPQExpBuffer(&query, "FROM STDIN");
462 else
463 appendPQExpBuffer(&query, "TO STDOUT");
466 if (options->binary)
467 appendPQExpBuffer(&query, " BINARY ");
469 if (options->oids)
470 appendPQExpBuffer(&query, " OIDS ");
472 if (options->delim)
473 emit_copy_option(&query, " DELIMITER ", options->delim);
475 if (options->null)
476 emit_copy_option(&query, " NULL AS ", options->null);
478 if (options->csv_mode)
479 appendPQExpBuffer(&query, " CSV");
481 if (options->header)
482 appendPQExpBuffer(&query, " HEADER");
484 if (options->quote)
485 emit_copy_option(&query, " QUOTE AS ", options->quote);
487 if (options->escape)
488 emit_copy_option(&query, " ESCAPE AS ", options->escape);
490 if (options->force_quote_list)
491 appendPQExpBuffer(&query, " FORCE QUOTE %s", options->force_quote_list);
493 if (options->force_notnull_list)
494 appendPQExpBuffer(&query, " FORCE NOT NULL %s", options->force_notnull_list);
496 if (options->file)
497 canonicalize_path(options->file);
499 if (options->from)
501 if (options->file)
502 copystream = fopen(options->file, PG_BINARY_R);
503 else if (!options->psql_inout)
504 copystream = pset.cur_cmd_source;
505 else
506 copystream = stdin;
508 else
510 if (options->file)
511 copystream = fopen(options->file,
512 options->binary ? PG_BINARY_W : "w");
513 else if (!options->psql_inout)
514 copystream = pset.queryFout;
515 else
516 copystream = stdout;
519 if (!copystream)
521 psql_error("%s: %s\n",
522 options->file, strerror(errno));
523 free_copy_options(options);
524 return false;
527 /* make sure the specified file is not a directory */
528 fstat(fileno(copystream), &st);
529 if (S_ISDIR(st.st_mode))
531 fclose(copystream);
532 psql_error("%s: cannot copy from/to a directory\n",
533 options->file);
534 free_copy_options(options);
535 return false;
538 result = PSQLexec(query.data, true);
539 termPQExpBuffer(&query);
541 switch (PQresultStatus(result))
543 case PGRES_COPY_OUT:
544 SetCancelConn();
545 success = handleCopyOut(pset.db, copystream);
546 ResetCancelConn();
547 break;
548 case PGRES_COPY_IN:
549 SetCancelConn();
550 success = handleCopyIn(pset.db, copystream,
551 PQbinaryTuples(result));
552 ResetCancelConn();
553 break;
554 case PGRES_NONFATAL_ERROR:
555 case PGRES_FATAL_ERROR:
556 case PGRES_BAD_RESPONSE:
557 success = false;
558 psql_error("\\copy: %s", PQerrorMessage(pset.db));
559 break;
560 default:
561 success = false;
562 psql_error("\\copy: unexpected response (%d)\n",
563 PQresultStatus(result));
564 break;
567 PQclear(result);
570 * Make sure we have pumped libpq dry of results; else it may still be in
571 * ASYNC_BUSY state, leading to false readings in, eg, get_prompt().
573 while ((result = PQgetResult(pset.db)) != NULL)
575 success = false;
576 psql_error("\\copy: unexpected response (%d)\n",
577 PQresultStatus(result));
578 PQclear(result);
581 if (options->file != NULL)
583 if (fclose(copystream) != 0)
585 psql_error("%s: %s\n", options->file, strerror(errno));
586 success = false;
589 free_copy_options(options);
590 return success;
595 * Functions for handling COPY IN/OUT data transfer.
597 * If you want to use COPY TO STDOUT/FROM STDIN in your application,
598 * this is the code to steal ;)
602 * handleCopyOut
603 * receives data as a result of a COPY ... TO STDOUT command
605 * conn should be a database connection that you just issued COPY TO on
606 * and got back a PGRES_COPY_OUT result.
607 * copystream is the file stream for the data to go to.
609 * result is true if successful, false if not.
611 bool
612 handleCopyOut(PGconn *conn, FILE *copystream)
614 bool OK = true;
615 char *buf;
616 int ret;
617 PGresult *res;
619 for (;;)
621 ret = PQgetCopyData(conn, &buf, 0);
623 if (ret < 0)
624 break; /* done or error */
626 if (buf)
628 if (fwrite(buf, 1, ret, copystream) != ret)
630 if (OK) /* complain only once, keep reading data */
631 psql_error("could not write COPY data: %s\n",
632 strerror(errno));
633 OK = false;
635 PQfreemem(buf);
639 if (OK && fflush(copystream))
641 psql_error("could not write COPY data: %s\n",
642 strerror(errno));
643 OK = false;
646 if (ret == -2)
648 psql_error("COPY data transfer failed: %s", PQerrorMessage(conn));
649 OK = false;
652 /* Check command status and return to normal libpq state */
653 res = PQgetResult(conn);
654 if (PQresultStatus(res) != PGRES_COMMAND_OK)
656 psql_error("%s", PQerrorMessage(conn));
657 OK = false;
659 PQclear(res);
661 return OK;
665 * handleCopyIn
666 * sends data to complete a COPY ... FROM STDIN command
668 * conn should be a database connection that you just issued COPY FROM on
669 * and got back a PGRES_COPY_IN result.
670 * copystream is the file stream to read the data from.
671 * isbinary can be set from PQbinaryTuples().
673 * result is true if successful, false if not.
676 /* read chunk size for COPY IN - size is not critical */
677 #define COPYBUFSIZ 8192
679 bool
680 handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary)
682 bool OK;
683 const char *prompt;
684 char buf[COPYBUFSIZ];
685 PGresult *res;
688 * Establish longjmp destination for exiting from wait-for-input. (This is
689 * only effective while sigint_interrupt_enabled is TRUE.)
691 if (sigsetjmp(sigint_interrupt_jmp, 1) != 0)
693 /* got here with longjmp */
695 /* Terminate data transfer */
696 PQputCopyEnd(conn, _("canceled by user"));
698 /* Check command status and return to normal libpq state */
699 res = PQgetResult(conn);
700 if (PQresultStatus(res) != PGRES_COMMAND_OK)
701 psql_error("%s", PQerrorMessage(conn));
702 PQclear(res);
704 return false;
707 /* Prompt if interactive input */
708 if (isatty(fileno(copystream)))
710 if (!pset.quiet)
711 puts(_("Enter data to be copied followed by a newline.\n"
712 "End with a backslash and a period on a line by itself."));
713 prompt = get_prompt(PROMPT_COPY);
715 else
716 prompt = NULL;
718 OK = true;
720 if (isbinary)
722 /* interactive input probably silly, but give one prompt anyway */
723 if (prompt)
725 fputs(prompt, stdout);
726 fflush(stdout);
729 for (;;)
731 int buflen;
733 /* enable longjmp while waiting for input */
734 sigint_interrupt_enabled = true;
736 buflen = fread(buf, 1, COPYBUFSIZ, copystream);
738 sigint_interrupt_enabled = false;
740 if (buflen <= 0)
741 break;
743 if (PQputCopyData(conn, buf, buflen) <= 0)
745 OK = false;
746 break;
750 else
752 bool copydone = false;
754 while (!copydone)
755 { /* for each input line ... */
756 bool firstload;
757 bool linedone;
759 if (prompt)
761 fputs(prompt, stdout);
762 fflush(stdout);
765 firstload = true;
766 linedone = false;
768 while (!linedone)
769 { /* for each bufferload in line ... */
770 int linelen;
771 char *fgresult;
773 /* enable longjmp while waiting for input */
774 sigint_interrupt_enabled = true;
776 fgresult = fgets(buf, sizeof(buf), copystream);
778 sigint_interrupt_enabled = false;
780 if (!fgresult)
782 copydone = true;
783 break;
786 linelen = strlen(buf);
788 /* current line is done? */
789 if (linelen > 0 && buf[linelen - 1] == '\n')
790 linedone = true;
792 /* check for EOF marker, but not on a partial line */
793 if (firstload)
795 if (strcmp(buf, "\\.\n") == 0 ||
796 strcmp(buf, "\\.\r\n") == 0)
798 copydone = true;
799 break;
802 firstload = false;
805 if (PQputCopyData(conn, buf, linelen) <= 0)
807 OK = false;
808 copydone = true;
809 break;
813 pset.lineno++;
817 /* Check for read error */
818 if (ferror(copystream))
819 OK = false;
821 /* Terminate data transfer */
822 if (PQputCopyEnd(conn,
823 OK ? NULL : _("aborted because of read failure")) <= 0)
824 OK = false;
826 /* Check command status and return to normal libpq state */
827 res = PQgetResult(conn);
828 if (PQresultStatus(res) != PGRES_COMMAND_OK)
830 psql_error("%s", PQerrorMessage(conn));
831 OK = false;
833 PQclear(res);
835 return OK;