mirror of
https://github.com/postgres/postgres.git
synced 2025-11-12 05:01:15 +03:00
Improve COPY syntax to use WITH clause, keep backward compatibility.
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.156 2002/05/21 22:59:00 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.157 2002/06/20 16:00:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -261,18 +261,79 @@ CopyDonePeek(FILE *fp, int c, bool pickup)
|
||||
* the table.
|
||||
*/
|
||||
void
|
||||
DoCopy(const RangeVar *relation, bool binary, bool oids, bool from, bool pipe,
|
||||
char *filename, char *delim, char *null_print)
|
||||
DoCopy(const CopyStmt *stmt)
|
||||
{
|
||||
RangeVar *relation = stmt->relation;
|
||||
char *filename = stmt->filename;
|
||||
bool is_from = stmt->is_from;
|
||||
bool pipe = (stmt->filename == NULL);
|
||||
List *option;
|
||||
DefElem *dbinary = NULL;
|
||||
DefElem *doids = NULL;
|
||||
DefElem *ddelim = NULL;
|
||||
DefElem *dnull = NULL;
|
||||
bool binary = false;
|
||||
bool oids = false;
|
||||
char *delim = "\t";
|
||||
char *null_print = "\\N";
|
||||
FILE *fp;
|
||||
Relation rel;
|
||||
AclMode required_access = (from ? ACL_INSERT : ACL_SELECT);
|
||||
AclMode required_access = (is_from ? ACL_INSERT : ACL_SELECT);
|
||||
AclResult aclresult;
|
||||
|
||||
/* Extract options from the statement node tree */
|
||||
foreach(option, stmt->options)
|
||||
{
|
||||
DefElem *defel = (DefElem *) lfirst(option);
|
||||
|
||||
if (strcmp(defel->defname, "binary") == 0)
|
||||
{
|
||||
if (dbinary)
|
||||
elog(ERROR, "COPY: conflicting options");
|
||||
dbinary = defel;
|
||||
}
|
||||
else if (strcmp(defel->defname, "oids") == 0)
|
||||
{
|
||||
if (doids)
|
||||
elog(ERROR, "COPY: conflicting options");
|
||||
doids = defel;
|
||||
}
|
||||
else if (strcmp(defel->defname, "delimiter") == 0)
|
||||
{
|
||||
if (ddelim)
|
||||
elog(ERROR, "COPY: conflicting options");
|
||||
ddelim = defel;
|
||||
}
|
||||
else if (strcmp(defel->defname, "null") == 0)
|
||||
{
|
||||
if (dnull)
|
||||
elog(ERROR, "COPY: conflicting options");
|
||||
dnull = defel;
|
||||
}
|
||||
else
|
||||
elog(ERROR, "COPY: option \"%s\" not recognized",
|
||||
defel->defname);
|
||||
}
|
||||
|
||||
if (dbinary)
|
||||
binary = intVal(dbinary->arg);
|
||||
if (doids)
|
||||
oids = intVal(doids->arg);
|
||||
if (ddelim)
|
||||
delim = strVal(ddelim->arg);
|
||||
if (dnull)
|
||||
null_print = strVal(dnull->arg);
|
||||
|
||||
if (binary && ddelim)
|
||||
elog(ERROR, "You can not specify the DELIMITER in BINARY mode.");
|
||||
|
||||
if (binary && dnull)
|
||||
elog(ERROR, "You can not specify NULL in BINARY mode.");
|
||||
|
||||
/*
|
||||
* Open and lock the relation, using the appropriate lock type.
|
||||
*/
|
||||
rel = heap_openrv(relation, (from ? RowExclusiveLock : AccessShareLock));
|
||||
rel = heap_openrv(relation, (is_from ? RowExclusiveLock : AccessShareLock));
|
||||
|
||||
/* Check permissions. */
|
||||
aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
|
||||
@@ -306,7 +367,7 @@ DoCopy(const RangeVar *relation, bool binary, bool oids, bool from, bool pipe,
|
||||
server_encoding = GetDatabaseEncoding();
|
||||
#endif
|
||||
|
||||
if (from)
|
||||
if (is_from)
|
||||
{ /* copy from file to database */
|
||||
if (rel->rd_rel->relkind != RELKIND_RELATION)
|
||||
{
|
||||
@@ -410,7 +471,7 @@ DoCopy(const RangeVar *relation, bool binary, bool oids, bool from, bool pipe,
|
||||
|
||||
if (!pipe)
|
||||
FreeFile(fp);
|
||||
else if (!from)
|
||||
else if (!is_from)
|
||||
{
|
||||
if (!binary)
|
||||
CopySendData("\\.\n", 3, fp);
|
||||
@@ -425,7 +486,7 @@ DoCopy(const RangeVar *relation, bool binary, bool oids, bool from, bool pipe,
|
||||
* transaction to ensure that updates will be committed before lock is
|
||||
* released.
|
||||
*/
|
||||
heap_close(rel, (from ? NoLock : AccessShareLock));
|
||||
heap_close(rel, (is_from ? NoLock : AccessShareLock));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.93 2002/06/18 17:27:57 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.94 2002/06/20 16:00:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -58,7 +58,7 @@ static bool remove_dbdirs(const char *real_loc, const char *altloc);
|
||||
*/
|
||||
|
||||
void
|
||||
createdb(CreatedbStmt *stmt)
|
||||
createdb(const CreatedbStmt *stmt)
|
||||
{
|
||||
char *nominal_loc;
|
||||
char *alt_loc;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.189 2002/06/18 17:27:57 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.190 2002/06/20 16:00:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1992,16 +1992,11 @@ _copyCopyStmt(CopyStmt *from)
|
||||
{
|
||||
CopyStmt *newnode = makeNode(CopyStmt);
|
||||
|
||||
newnode->binary = from->binary;
|
||||
Node_Copy(from, newnode, relation);
|
||||
newnode->oids = from->oids;
|
||||
newnode->direction = from->direction;
|
||||
newnode->is_from = from->is_from;
|
||||
if (from->filename)
|
||||
newnode->filename = pstrdup(from->filename);
|
||||
if (from->delimiter)
|
||||
newnode->delimiter = pstrdup(from->delimiter);
|
||||
if (from->null_print)
|
||||
newnode->null_print = pstrdup(from->null_print);
|
||||
Node_Copy(from, newnode, options);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.136 2002/06/18 17:27:57 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.137 2002/06/20 16:00:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -799,19 +799,13 @@ _equalClusterStmt(ClusterStmt *a, ClusterStmt *b)
|
||||
static bool
|
||||
_equalCopyStmt(CopyStmt *a, CopyStmt *b)
|
||||
{
|
||||
if (a->binary != b->binary)
|
||||
return false;
|
||||
if (!equal(a->relation, b->relation))
|
||||
return false;
|
||||
if (a->oids != b->oids)
|
||||
return false;
|
||||
if (a->direction != b->direction)
|
||||
if (a->is_from != b->is_from)
|
||||
return false;
|
||||
if (!equalstr(a->filename, b->filename))
|
||||
return false;
|
||||
if (!equalstr(a->delimiter, b->delimiter))
|
||||
return false;
|
||||
if (!equalstr(a->null_print, b->null_print))
|
||||
if (!equal(a->options, b->options))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.331 2002/06/19 15:40:58 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.332 2002/06/20 16:00:43 momjian Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@@ -159,8 +159,8 @@ static void doNegateFloat(Value *v);
|
||||
%type <node> alter_column_default
|
||||
%type <ival> add_drop, drop_behavior, opt_drop_behavior
|
||||
|
||||
%type <list> createdb_opt_list
|
||||
%type <defelt> createdb_opt_item
|
||||
%type <list> createdb_opt_list, copy_opt_list
|
||||
%type <defelt> createdb_opt_item, copy_opt_item
|
||||
|
||||
%type <ival> opt_lock, lock_type
|
||||
%type <boolean> opt_force, opt_or_replace
|
||||
@@ -182,7 +182,7 @@ static void doNegateFloat(Value *v);
|
||||
%type <str> TriggerEvents
|
||||
%type <value> TriggerFuncArg
|
||||
|
||||
%type <str> relation_name, copy_file_name, copy_delimiter, copy_null,
|
||||
%type <str> relation_name, copy_file_name,
|
||||
database_name, access_method_clause, access_method, attr_name,
|
||||
index_name, name, function_name, file_name
|
||||
|
||||
@@ -236,11 +236,14 @@ static void doNegateFloat(Value *v);
|
||||
%type <ival> opt_interval
|
||||
%type <node> overlay_placing, substr_from, substr_for
|
||||
|
||||
%type <boolean> opt_binary, opt_instead, opt_cursor
|
||||
%type <boolean> opt_with_copy, index_opt_unique, opt_verbose, opt_full
|
||||
%type <boolean> opt_instead, opt_cursor
|
||||
%type <boolean> index_opt_unique, opt_verbose, opt_full
|
||||
%type <boolean> opt_freeze
|
||||
%type <defelt> opt_binary, opt_oids, copy_delimiter
|
||||
|
||||
%type <ival> copy_dirn, direction, reindex_type, drop_type,
|
||||
%type <boolean> copy_from
|
||||
|
||||
%type <ival> direction, reindex_type, drop_type,
|
||||
opt_column, event, comment_type
|
||||
|
||||
%type <ival> fetch_how_many
|
||||
@@ -330,8 +333,8 @@ static void doNegateFloat(Value *v);
|
||||
CURRENT_TIMESTAMP, CURRENT_USER, CURSOR, CYCLE,
|
||||
|
||||
DATABASE, DAY_P, DEC, DECIMAL, DECLARE, DEFAULT,
|
||||
DEFERRABLE, DEFERRED, DEFINER, DELETE_P, DELIMITERS, DESC,
|
||||
DISTINCT, DO, DOMAIN_P, DOUBLE, DROP,
|
||||
DEFERRABLE, DEFERRED, DEFINER, DELETE_P, DELIMITER, DELIMITERS,
|
||||
DESC, DISTINCT, DO, DOMAIN_P, DOUBLE, DROP,
|
||||
|
||||
EACH, ELSE, ENCODING, ENCRYPTED, END_TRANS, ESCAPE, EXCEPT,
|
||||
EXCLUSIVE, EXECUTE, EXISTS, EXPLAIN, EXTERNAL, EXTRACT,
|
||||
@@ -1293,27 +1296,38 @@ opt_id: ColId { $$ = $1; }
|
||||
/*****************************************************************************
|
||||
*
|
||||
* QUERY :
|
||||
* COPY [BINARY] <relname> FROM/TO
|
||||
* [USING DELIMITERS <delimiter>]
|
||||
* COPY <relname> FROM/TO [WITH options]
|
||||
*
|
||||
* BINARY, OIDS, and DELIMITERS kept in old locations
|
||||
* for backward compatibility. 2002-06-18
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
CopyStmt: COPY opt_binary qualified_name opt_with_copy copy_dirn copy_file_name copy_delimiter copy_null
|
||||
CopyStmt: COPY opt_binary qualified_name opt_oids copy_from
|
||||
copy_file_name copy_delimiter opt_with copy_opt_list
|
||||
{
|
||||
CopyStmt *n = makeNode(CopyStmt);
|
||||
n->binary = $2;
|
||||
n->relation = $3;
|
||||
n->oids = $4;
|
||||
n->direction = $5;
|
||||
n->is_from = $5;
|
||||
n->filename = $6;
|
||||
n->delimiter = $7;
|
||||
n->null_print = $8;
|
||||
|
||||
n->options = NIL;
|
||||
/* Concatenate user-supplied flags */
|
||||
if ($2)
|
||||
n->options = lappend(n->options, $2);
|
||||
if ($4)
|
||||
n->options = lappend(n->options, $4);
|
||||
if ($7)
|
||||
n->options = lappend(n->options, $7);
|
||||
if ($9)
|
||||
n->options = nconc(n->options, $9);
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
;
|
||||
|
||||
copy_dirn: TO { $$ = TO; }
|
||||
| FROM { $$ = FROM; }
|
||||
copy_from:
|
||||
FROM { $$ = TRUE; }
|
||||
| TO { $$ = FALSE; }
|
||||
;
|
||||
|
||||
/*
|
||||
@@ -1327,30 +1341,79 @@ copy_file_name:
|
||||
| STDOUT { $$ = NULL; }
|
||||
;
|
||||
|
||||
opt_binary: BINARY { $$ = TRUE; }
|
||||
| /*EMPTY*/ { $$ = FALSE; }
|
||||
|
||||
|
||||
copy_opt_list:
|
||||
copy_opt_list copy_opt_item { $$ = lappend($1, $2); }
|
||||
| /* EMPTY */ { $$ = NIL; }
|
||||
;
|
||||
|
||||
opt_with_copy:
|
||||
WITH OIDS { $$ = TRUE; }
|
||||
| /*EMPTY*/ { $$ = FALSE; }
|
||||
|
||||
copy_opt_item:
|
||||
BINARY
|
||||
{
|
||||
$$ = makeNode(DefElem);
|
||||
$$->defname = "binary";
|
||||
$$->arg = (Node *)makeInteger(TRUE);
|
||||
}
|
||||
| OIDS
|
||||
{
|
||||
$$ = makeNode(DefElem);
|
||||
$$->defname = "oids";
|
||||
$$->arg = (Node *)makeInteger(TRUE);
|
||||
}
|
||||
| DELIMITER opt_as Sconst
|
||||
{
|
||||
$$ = makeNode(DefElem);
|
||||
$$->defname = "delimiter";
|
||||
$$->arg = (Node *)makeString($3);
|
||||
}
|
||||
| NULL_P opt_as Sconst
|
||||
{
|
||||
$$ = makeNode(DefElem);
|
||||
$$->defname = "null";
|
||||
$$->arg = (Node *)makeString($3);
|
||||
}
|
||||
;
|
||||
|
||||
/* The following exist for backward compatibility */
|
||||
|
||||
opt_binary:
|
||||
BINARY
|
||||
{
|
||||
$$ = makeNode(DefElem);
|
||||
$$->defname = "binary";
|
||||
$$->arg = (Node *)makeInteger(TRUE);
|
||||
}
|
||||
| /*EMPTY*/ { $$ = NULL; }
|
||||
;
|
||||
|
||||
opt_oids:
|
||||
WITH OIDS
|
||||
{
|
||||
$$ = makeNode(DefElem);
|
||||
$$->defname = "oids";
|
||||
$$->arg = (Node *)makeInteger(TRUE);
|
||||
}
|
||||
| /*EMPTY*/ { $$ = NULL; }
|
||||
;
|
||||
|
||||
/*
|
||||
* the default copy delimiter is tab but the user can configure it
|
||||
*/
|
||||
copy_delimiter:
|
||||
opt_using DELIMITERS Sconst { $$ = $3; }
|
||||
| /*EMPTY*/ { $$ = "\t"; }
|
||||
/* USING DELIMITERS kept for backward compatibility. 2002-06-15 */
|
||||
opt_using DELIMITERS Sconst
|
||||
{
|
||||
$$ = makeNode(DefElem);
|
||||
$$->defname = "delimiter";
|
||||
$$->arg = (Node *)makeString($3);
|
||||
}
|
||||
| /*EMPTY*/ { $$ = NULL; }
|
||||
;
|
||||
|
||||
opt_using: USING {}
|
||||
opt_using:
|
||||
USING {}
|
||||
| /*EMPTY*/ {}
|
||||
;
|
||||
|
||||
copy_null: WITH NULL_P AS Sconst { $$ = $4; }
|
||||
| /*EMPTY*/ { $$ = "\\N"; }
|
||||
;
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
@@ -3422,10 +3485,6 @@ createdb_opt_list:
|
||||
| /* EMPTY */ { $$ = NIL; }
|
||||
;
|
||||
|
||||
/*
|
||||
* createdb_opt_item returns 2-element lists, with the first element
|
||||
* being an integer code to indicate which item was specified.
|
||||
*/
|
||||
createdb_opt_item:
|
||||
LOCATION opt_equal Sconst
|
||||
{
|
||||
@@ -6529,6 +6588,7 @@ unreserved_keyword:
|
||||
| DEFERRED
|
||||
| DEFINER
|
||||
| DELETE_P
|
||||
| DELIMITER
|
||||
| DELIMITERS
|
||||
| DOMAIN_P
|
||||
| DOUBLE
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.114 2002/06/15 03:00:03 thomas Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.115 2002/06/20 16:00:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -98,6 +98,7 @@ static const ScanKeyword ScanKeywords[] = {
|
||||
{"deferred", DEFERRED},
|
||||
{"definer", DEFINER},
|
||||
{"delete", DELETE_P},
|
||||
{"delimiter", DELIMITER},
|
||||
{"delimiters", DELIMITERS},
|
||||
{"desc", DESC},
|
||||
{"distinct", DISTINCT},
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.157 2002/06/18 17:27:58 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.158 2002/06/20 16:00:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -347,22 +347,10 @@ ProcessUtility(Node *parsetree,
|
||||
{
|
||||
CopyStmt *stmt = (CopyStmt *) parsetree;
|
||||
|
||||
if (stmt->direction != FROM)
|
||||
if (!stmt->is_from)
|
||||
SetQuerySnapshot();
|
||||
|
||||
DoCopy(stmt->relation,
|
||||
stmt->binary,
|
||||
stmt->oids,
|
||||
(bool) (stmt->direction == FROM),
|
||||
(bool) (stmt->filename == NULL),
|
||||
|
||||
/*
|
||||
* null filename means copy to/from stdout/stdin, rather
|
||||
* than to/from a file.
|
||||
*/
|
||||
stmt->filename,
|
||||
stmt->delimiter,
|
||||
stmt->null_print);
|
||||
DoCopy(stmt);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user