mirror of
https://github.com/postgres/postgres.git
synced 2025-06-13 07:41:39 +03:00
Add support for piping COPY to/from an external program.
This includes backend "COPY TO/FROM PROGRAM '...'" syntax, and corresponding psql \copy syntax. Like with reading/writing files, the backend version is superuser-only, and in the psql version, the program is run in the client. In the passing, the psql \copy STDIN/STDOUT syntax is subtly changed: if you the stdin/stdout is quoted, it's now interpreted as a filename. For example, "\copy foo from 'stdin'" now reads from a file called 'stdin', not from standard input. Before this, there was no way to specify a filename called stdin, stdout, pstdin or pstdout. This creates a new function in pgport, wait_result_to_str(), which can be used to convert the exit status of a process, as returned by wait(3), to a human-readable string. Etsuro Fujita, reviewed by Amit Kapila.
This commit is contained in:
@ -381,7 +381,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
|
||||
%type <boolean> opt_freeze opt_default opt_recheck
|
||||
%type <defelt> opt_binary opt_oids copy_delimiter
|
||||
|
||||
%type <boolean> copy_from
|
||||
%type <boolean> copy_from opt_program
|
||||
|
||||
%type <ival> opt_column event cursor_options opt_hold opt_set_data
|
||||
%type <objtype> reindex_type drop_type comment_type security_label_type
|
||||
@ -568,7 +568,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
|
||||
|
||||
PARSER PARTIAL PARTITION PASSING PASSWORD PLACING PLANS POSITION
|
||||
PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY
|
||||
PRIOR PRIVILEGES PROCEDURAL PROCEDURE
|
||||
PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROGRAM
|
||||
|
||||
QUOTE
|
||||
|
||||
@ -2309,7 +2309,10 @@ ClosePortalStmt:
|
||||
*
|
||||
* QUERY :
|
||||
* COPY relname [(columnList)] FROM/TO file [WITH] [(options)]
|
||||
* COPY ( SELECT ... ) TO file [WITH] [(options)]
|
||||
* COPY ( SELECT ... ) TO file [WITH] [(options)]
|
||||
*
|
||||
* where 'file' can be one of:
|
||||
* { PROGRAM 'command' | STDIN | STDOUT | 'filename' }
|
||||
*
|
||||
* In the preferred syntax the options are comma-separated
|
||||
* and use generic identifiers instead of keywords. The pre-9.0
|
||||
@ -2324,14 +2327,21 @@ ClosePortalStmt:
|
||||
*****************************************************************************/
|
||||
|
||||
CopyStmt: COPY opt_binary qualified_name opt_column_list opt_oids
|
||||
copy_from copy_file_name copy_delimiter opt_with copy_options
|
||||
copy_from opt_program copy_file_name copy_delimiter opt_with copy_options
|
||||
{
|
||||
CopyStmt *n = makeNode(CopyStmt);
|
||||
n->relation = $3;
|
||||
n->query = NULL;
|
||||
n->attlist = $4;
|
||||
n->is_from = $6;
|
||||
n->filename = $7;
|
||||
n->is_program = $7;
|
||||
n->filename = $8;
|
||||
|
||||
if (n->is_program && n->filename == NULL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("STDIN/STDOUT not allowed with PROGRAM"),
|
||||
parser_errposition(@8)));
|
||||
|
||||
n->options = NIL;
|
||||
/* Concatenate user-supplied flags */
|
||||
@ -2339,21 +2349,29 @@ CopyStmt: COPY opt_binary qualified_name opt_column_list opt_oids
|
||||
n->options = lappend(n->options, $2);
|
||||
if ($5)
|
||||
n->options = lappend(n->options, $5);
|
||||
if ($8)
|
||||
n->options = lappend(n->options, $8);
|
||||
if ($10)
|
||||
n->options = list_concat(n->options, $10);
|
||||
if ($9)
|
||||
n->options = lappend(n->options, $9);
|
||||
if ($11)
|
||||
n->options = list_concat(n->options, $11);
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| COPY select_with_parens TO copy_file_name opt_with copy_options
|
||||
| COPY select_with_parens TO opt_program copy_file_name opt_with copy_options
|
||||
{
|
||||
CopyStmt *n = makeNode(CopyStmt);
|
||||
n->relation = NULL;
|
||||
n->query = $2;
|
||||
n->attlist = NIL;
|
||||
n->is_from = false;
|
||||
n->filename = $4;
|
||||
n->options = $6;
|
||||
n->is_program = $4;
|
||||
n->filename = $5;
|
||||
n->options = $7;
|
||||
|
||||
if (n->is_program && n->filename == NULL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("STDIN/STDOUT not allowed with PROGRAM"),
|
||||
parser_errposition(@5)));
|
||||
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
;
|
||||
@ -2363,6 +2381,11 @@ copy_from:
|
||||
| TO { $$ = FALSE; }
|
||||
;
|
||||
|
||||
opt_program:
|
||||
PROGRAM { $$ = TRUE; }
|
||||
| /* EMPTY */ { $$ = FALSE; }
|
||||
;
|
||||
|
||||
/*
|
||||
* copy_file_name NULL indicates stdio is used. Whether stdin or stdout is
|
||||
* used depends on the direction. (It really doesn't make sense to copy from
|
||||
@ -12666,6 +12689,7 @@ unreserved_keyword:
|
||||
| PRIVILEGES
|
||||
| PROCEDURAL
|
||||
| PROCEDURE
|
||||
| PROGRAM
|
||||
| QUOTE
|
||||
| RANGE
|
||||
| READ
|
||||
|
Reference in New Issue
Block a user