2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2008, PostgreSQL Global Development Group
8 #include "postgres_fe.h"
14 #include <unistd.h> /* for isatty */
16 #include <io.h> /* I think */
20 #include "pqexpbuffer.h"
22 #include "dumputils.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)
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
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
63 char *file
; /* NULL = stdin/stdout */
64 bool psql_inout
; /* true = use psql stdin/stdout */
74 char *force_quote_list
;
75 char *force_notnull_list
;
80 free_copy_options(struct copy_options
* ptr
)
85 free(ptr
->column_list
);
91 free(ptr
->force_quote_list
);
92 free(ptr
->force_notnull_list
);
97 /* concatenate "more" onto "var", freeing the original value of *var */
99 xstrcat(char **var
, const char *more
)
103 newvar
= pg_malloc(strlen(*var
) + strlen(more
) + 1);
104 strcpy(newvar
, *var
);
105 strcat(newvar
, more
);
111 static struct copy_options
*
112 parse_slash_copy(const char *args
)
114 struct copy_options
*result
;
117 const char *whitespace
= " \t\n\r";
118 char nonstd_backslash
= standard_strings() ? 0 : '\\';
121 line
= pg_strdup(args
);
124 psql_error("\\copy: arguments required\n");
128 result
= pg_calloc(1, sizeof(struct copy_options
));
130 token
= strtokx(line
, whitespace
, ".,()", "\"",
131 0, false, false, pset
.encoding
);
135 if (pg_strcasecmp(token
, "binary") == 0)
137 result
->binary
= true;
138 token
= strtokx(NULL
, whitespace
, ".,()", "\"",
139 0, false, false, pset
.encoding
);
144 result
->table
= pg_strdup(token
);
146 /* Handle COPY (SELECT) case */
153 token
= strtokx(NULL
, whitespace
, ".,()", "\"'",
154 nonstd_backslash
, true, false, pset
.encoding
);
159 else if (token
[0] == ')')
161 xstrcat(&result
->table
, " ");
162 xstrcat(&result
->table
, token
);
166 token
= strtokx(NULL
, whitespace
, ".,()", "\"",
167 0, false, false, pset
.encoding
);
172 * strtokx() will not have returned a multi-character token starting with
173 * '.', so we don't need strcmp() here. Likewise for '(', etc, below.
177 /* handle schema . table */
178 xstrcat(&result
->table
, token
);
179 token
= strtokx(NULL
, whitespace
, ".,()", "\"",
180 0, false, false, pset
.encoding
);
183 xstrcat(&result
->table
, token
);
184 token
= strtokx(NULL
, whitespace
, ".,()", "\"",
185 0, false, false, pset
.encoding
);
192 /* handle parenthesized column list */
193 result
->column_list
= pg_strdup(token
);
196 token
= strtokx(NULL
, whitespace
, ".,()", "\"",
197 0, false, false, pset
.encoding
);
198 if (!token
|| strchr(".,()", token
[0]))
200 xstrcat(&result
->column_list
, token
);
201 token
= strtokx(NULL
, whitespace
, ".,()", "\"",
202 0, false, false, pset
.encoding
);
205 xstrcat(&result
->column_list
, token
);
211 token
= strtokx(NULL
, whitespace
, ".,()", "\"",
212 0, false, false, pset
.encoding
);
217 if (pg_strcasecmp(token
, "from") == 0)
219 else if (pg_strcasecmp(token
, "to") == 0)
220 result
->from
= false;
224 token
= strtokx(NULL
, whitespace
, NULL
, "'",
225 0, false, true, pset
.encoding
);
229 if (pg_strcasecmp(token
, "stdin") == 0 ||
230 pg_strcasecmp(token
, "stdout") == 0)
232 result
->psql_inout
= false;
235 else if (pg_strcasecmp(token
, "pstdin") == 0 ||
236 pg_strcasecmp(token
, "pstdout") == 0)
238 result
->psql_inout
= true;
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
);
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
);
267 if (pg_strcasecmp(token
, "oids") == 0)
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)
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
);
285 result
->delim
= pg_strdup(token
);
289 else if (pg_strcasecmp(token
, "null") == 0)
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
);
299 result
->null
= pg_strdup(token
);
303 else if (pg_strcasecmp(token
, "quote") == 0)
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
);
313 result
->quote
= pg_strdup(token
);
317 else if (pg_strcasecmp(token
, "escape") == 0)
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
);
327 result
->escape
= pg_strdup(token
);
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
)
339 /* handle column list */
343 token
= strtokx(NULL
, whitespace
, ",", "\"",
344 0, false, false, pset
.encoding
);
345 if (!token
|| strchr(",", token
[0]))
347 if (!result
->force_quote_list
)
348 result
->force_quote_list
= pg_strdup(token
);
350 xstrcat(&result
->force_quote_list
, token
);
351 token
= strtokx(NULL
, whitespace
, ",", "\"",
352 0, false, false, pset
.encoding
);
353 if (!token
|| token
[0] != ',')
355 xstrcat(&result
->force_quote_list
, token
);
358 else if (pg_strcasecmp(token
, "not") == 0)
360 if (result
->force_notnull_list
)
362 token
= strtokx(NULL
, whitespace
, ",", "\"",
363 0, false, false, pset
.encoding
);
364 if (pg_strcasecmp(token
, "null") != 0)
366 /* handle column list */
370 token
= strtokx(NULL
, whitespace
, ",", "\"",
371 0, false, false, pset
.encoding
);
372 if (!token
|| strchr(",", token
[0]))
374 if (!result
->force_notnull_list
)
375 result
->force_notnull_list
= pg_strdup(token
);
377 xstrcat(&result
->force_notnull_list
, token
);
378 token
= strtokx(NULL
, whitespace
, ",", "\"",
379 0, false, false, pset
.encoding
);
380 if (!token
|| token
[0] != ',')
382 xstrcat(&result
->force_notnull_list
, token
);
392 token
= strtokx(NULL
, whitespace
, NULL
, NULL
,
393 0, false, false, pset
.encoding
);
403 psql_error("\\copy: parse error at \"%s\"\n", token
);
405 psql_error("\\copy: parse error at end of line\n");
406 free_copy_options(result
);
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
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
);
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.
436 do_copy(const char *args
)
438 PQExpBufferData query
;
440 struct copy_options
*options
;
446 options
= parse_slash_copy(args
);
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
);
461 appendPQExpBuffer(&query
, "FROM STDIN");
463 appendPQExpBuffer(&query
, "TO STDOUT");
467 appendPQExpBuffer(&query
, " BINARY ");
470 appendPQExpBuffer(&query
, " OIDS ");
473 emit_copy_option(&query
, " DELIMITER ", options
->delim
);
476 emit_copy_option(&query
, " NULL AS ", options
->null
);
478 if (options
->csv_mode
)
479 appendPQExpBuffer(&query
, " CSV");
482 appendPQExpBuffer(&query
, " HEADER");
485 emit_copy_option(&query
, " QUOTE AS ", options
->quote
);
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
);
497 canonicalize_path(options
->file
);
502 copystream
= fopen(options
->file
, PG_BINARY_R
);
503 else if (!options
->psql_inout
)
504 copystream
= pset
.cur_cmd_source
;
511 copystream
= fopen(options
->file
,
512 options
->binary
? PG_BINARY_W
: "w");
513 else if (!options
->psql_inout
)
514 copystream
= pset
.queryFout
;
521 psql_error("%s: %s\n",
522 options
->file
, strerror(errno
));
523 free_copy_options(options
);
527 /* make sure the specified file is not a directory */
528 fstat(fileno(copystream
), &st
);
529 if (S_ISDIR(st
.st_mode
))
532 psql_error("%s: cannot copy from/to a directory\n",
534 free_copy_options(options
);
538 result
= PSQLexec(query
.data
, true);
539 termPQExpBuffer(&query
);
541 switch (PQresultStatus(result
))
545 success
= handleCopyOut(pset
.db
, copystream
);
550 success
= handleCopyIn(pset
.db
, copystream
,
551 PQbinaryTuples(result
));
554 case PGRES_NONFATAL_ERROR
:
555 case PGRES_FATAL_ERROR
:
556 case PGRES_BAD_RESPONSE
:
558 psql_error("\\copy: %s", PQerrorMessage(pset
.db
));
562 psql_error("\\copy: unexpected response (%d)\n",
563 PQresultStatus(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
)
576 psql_error("\\copy: unexpected response (%d)\n",
577 PQresultStatus(result
));
581 if (options
->file
!= NULL
)
583 if (fclose(copystream
) != 0)
585 psql_error("%s: %s\n", options
->file
, strerror(errno
));
589 free_copy_options(options
);
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 ;)
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.
612 handleCopyOut(PGconn
*conn
, FILE *copystream
)
621 ret
= PQgetCopyData(conn
, &buf
, 0);
624 break; /* done or error */
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",
639 if (OK
&& fflush(copystream
))
641 psql_error("could not write COPY data: %s\n",
648 psql_error("COPY data transfer failed: %s", PQerrorMessage(conn
));
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
));
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
680 handleCopyIn(PGconn
*conn
, FILE *copystream
, bool isbinary
)
684 char buf
[COPYBUFSIZ
];
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
));
707 /* Prompt if interactive input */
708 if (isatty(fileno(copystream
)))
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
);
722 /* interactive input probably silly, but give one prompt anyway */
725 fputs(prompt
, stdout
);
733 /* enable longjmp while waiting for input */
734 sigint_interrupt_enabled
= true;
736 buflen
= fread(buf
, 1, COPYBUFSIZ
, copystream
);
738 sigint_interrupt_enabled
= false;
743 if (PQputCopyData(conn
, buf
, buflen
) <= 0)
752 bool copydone
= false;
755 { /* for each input line ... */
761 fputs(prompt
, stdout
);
769 { /* for each bufferload in line ... */
773 /* enable longjmp while waiting for input */
774 sigint_interrupt_enabled
= true;
776 fgresult
= fgets(buf
, sizeof(buf
), copystream
);
778 sigint_interrupt_enabled
= false;
786 linelen
= strlen(buf
);
788 /* current line is done? */
789 if (linelen
> 0 && buf
[linelen
- 1] == '\n')
792 /* check for EOF marker, but not on a partial line */
795 if (strcmp(buf
, "\\.\n") == 0 ||
796 strcmp(buf
, "\\.\r\n") == 0)
805 if (PQputCopyData(conn
, buf
, linelen
) <= 0)
817 /* Check for read error */
818 if (ferror(copystream
))
821 /* Terminate data transfer */
822 if (PQputCopyEnd(conn
,
823 OK
? NULL
: _("aborted because of read failure")) <= 0)
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
));