diff options
author | Tom Lane | 2004-01-20 23:48:56 +0000 |
---|---|---|
committer | Tom Lane | 2004-01-20 23:48:56 +0000 |
commit | 0561b8346e725d8b9e8803150b2b7e81b26ae3de (patch) | |
tree | 86c96d3dd62ee9ff89b5f1c5287cd6c0d95273c4 | |
parent | 4cd932740c0ca7aabc9ee625c6eeadfdb270d421 (diff) |
Implement '\copy from -' to support reading copy data from the same
source the \copy came from. Also, fix prompting logic so that initial
and per-line prompts appear for all cases of reading from an interactive
terminal. Patch by Mark Feit, with some kibitzing by Tom Lane.
-rw-r--r-- | doc/src/sgml/ref/psql-ref.sgml | 38 | ||||
-rw-r--r-- | src/bin/psql/common.c | 7 | ||||
-rw-r--r-- | src/bin/psql/copy.c | 45 | ||||
-rw-r--r-- | src/bin/psql/copy.h | 2 |
4 files changed, 64 insertions, 28 deletions
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index c7cfeda1fd..7c247b88b8 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -705,7 +705,7 @@ testdb=> <term><literal>\copy <replaceable class="parameter">table</replaceable> [ ( <replaceable class="parameter">column_list</replaceable> ) ] { <literal>from</literal> | <literal>to</literal> } - <replaceable class="parameter">filename</replaceable> | stdin | stdout + { <replaceable class="parameter">filename</replaceable> | stdin | stdout | - } [ <literal>with</literal> ] [ <literal>oids</literal> ] [ <literal>delimiter [as] </literal> '<replaceable class="parameter">character</replaceable>' ] @@ -720,26 +720,41 @@ testdb=> reading or writing the specified file, <application>psql</application> reads or writes the file and routes the data between the server and the local file system. - This means that file accessibility and privileges are those - of the local user, not the server, and no SQL superuser - privileges are required. + This means that file accessibility and privileges are those of + the local user, not the server, and no SQL superuser + privileges are required. </para> <para> The syntax of the command is similar to that of the - <acronym>SQL</acronym> <command>COPY</command> command. (See its - description for the details.) Note that, because of this, + <acronym>SQL</acronym> <xref linkend="sql-copy" + endterm="sql-copy-title"> command. Note that, because of this, special parsing rules apply to the <command>\copy</command> command. In particular, the variable substitution rules and backslash escapes do not apply. </para> + <para> + For <literal>\copy <replaceable + class="parameter">table</replaceable> from <replaceable + class="parameter">filename</replaceable></literal> operations, + <application>psql</application> adds the option of using a + hyphen instead of <replaceable + class="parameter">filename</replaceable>. This causes + <literal>\copy</literal> to read rows from the same source that + issued the command, continuing until <literal>\.</literal> is + read or the stream reaches <acronym>EOF</>. This option is + useful for populating tables in-line within a SQL script file. + In contrast, <literal>\copy from stdin</> always reads from + <application>psql</application>'s standard input. + </para> + <tip> <para> This operation is not as efficient as the <acronym>SQL</acronym> <command>COPY</command> command because all data must pass through the client/server connection. For large - amounts of data the other technique may be preferable. + amounts of data the <acronym>SQL</acronym> command may be preferable. </para> </tip> @@ -747,11 +762,12 @@ testdb=> <para> Note the difference in interpretation of <literal>stdin</literal> and <literal>stdout</literal> between - client and server copies: in a client copy these always + <literal>\copy</literal> and <command>COPY</command>. + In <literal>\copy</literal> these always refer to <application>psql</application>'s input and output - stream. On a server copy <literal>stdin</literal> comes from - wherever the <command>COPY</command> itself came from (for - example, a script run with the <option>-f</option> option), and + streams. In <command>COPY</command>, <literal>stdin</literal> comes + from wherever the <command>COPY</command> itself came from (for + example, a script run with the <option>-f</option> option), while <literal>stdout</literal> refers to the query output stream (see <command>\o</command> meta-command below). </para> diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c index 9f5bf4bc8d..88f6173997 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -513,12 +513,7 @@ ProcessCopyResult(PGresult *results) break; case PGRES_COPY_IN: - if (pset.cur_cmd_interactive && !QUIET()) - puts(gettext("Enter data to be copied followed by a newline.\n" - "End with a backslash and a period on a line by itself.")); - - success = handleCopyIn(pset.db, pset.cur_cmd_source, - pset.cur_cmd_interactive ? get_prompt(PROMPT_COPY) : NULL); + success = handleCopyIn(pset.db, pset.cur_cmd_source); break; default: diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c index 1279053de9..ad3485c69d 100644 --- a/src/bin/psql/copy.c +++ b/src/bin/psql/copy.c @@ -23,6 +23,7 @@ #include "settings.h" #include "common.h" +#include "prompt.h" #include "stringutils.h" #ifdef WIN32 @@ -53,6 +54,7 @@ struct copy_options char *table; char *column_list; char *file; /* NULL = stdin/stdout */ + bool in_dash; /* true = use src stream not true stdin */ bool from; bool binary; bool oids; @@ -218,10 +220,25 @@ parse_slash_copy(const char *args) if (strcasecmp(token, "stdin") == 0 || strcasecmp(token, "stdout") == 0) + { + result->in_dash = false; + result->file = NULL; + } + else if (strcmp(token, "-") == 0) + { + /* Can't do this on output */ + if (!result->from) + goto error; + + result->in_dash = true; result->file = NULL; + } else + { + result->in_dash = false; result->file = xstrdup(token); - expand_tilde(&result->file); + expand_tilde(&result->file); + } token = strtokx(NULL, whitespace, NULL, NULL, 0, false, pset.encoding); @@ -362,8 +379,10 @@ do_copy(const char *args) { if (options->file) copystream = fopen(options->file, "r"); + else if (options->in_dash) + copystream = pset.cur_cmd_source; else - copystream = stdin; + copystream = stdin; } else { @@ -401,7 +420,7 @@ do_copy(const char *args) success = handleCopyOut(pset.db, copystream); break; case PGRES_COPY_IN: - success = handleCopyIn(pset.db, copystream, NULL); + success = handleCopyIn(pset.db, copystream); break; case PGRES_NONFATAL_ERROR: case PGRES_FATAL_ERROR: @@ -416,7 +435,7 @@ do_copy(const char *args) PQclear(result); - if (copystream != stdout && copystream != stdin) + if (options->file != NULL) fclose(copystream); free_copy_options(options); return success; @@ -486,13 +505,12 @@ handleCopyOut(PGconn *conn, FILE *copystream) * conn should be a database connection that you just called COPY FROM on * (and which gave you PGRES_COPY_IN back); * copystream is the file stream you want the input to come from - * prompt is something to display to request user input (only makes sense - * if stdin is an interactive tty) */ bool -handleCopyIn(PGconn *conn, FILE *copystream, const char *prompt) +handleCopyIn(PGconn *conn, FILE *copystream) { + const char *prompt; bool copydone = false; bool firstload; bool linedone; @@ -503,10 +521,17 @@ handleCopyIn(PGconn *conn, FILE *copystream, const char *prompt) int ret; unsigned int linecount = 0; - if (prompt) /* disable prompt if not interactive */ + /* Prompt if interactive input */ + if (isatty(fileno(copystream))) + { + if (!QUIET()) + puts(gettext("Enter data to be copied followed by a newline.\n" + "End with a backslash and a period on a line by itself.")); + prompt = get_prompt(PROMPT_COPY); + } + else { - if (!isatty(fileno(copystream))) - prompt = NULL; + prompt = NULL; } while (!copydone) diff --git a/src/bin/psql/copy.h b/src/bin/psql/copy.h index 525760293c..db757a9c05 100644 --- a/src/bin/psql/copy.h +++ b/src/bin/psql/copy.h @@ -17,6 +17,6 @@ bool do_copy(const char *args); /* lower level processors for copy in/out streams */ bool handleCopyOut(PGconn *conn, FILE *copystream); -bool handleCopyIn(PGconn *conn, FILE *copystream, const char *prompt); +bool handleCopyIn(PGconn *conn, FILE *copystream); #endif |