Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * copy.c
4 : * Implements the COPY utility command
5 : *
6 : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/commands/copy.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : #include "postgres.h"
16 :
17 : #include <ctype.h>
18 : #include <unistd.h>
19 : #include <sys/stat.h>
20 :
21 : #include "access/sysattr.h"
22 : #include "access/table.h"
23 : #include "access/xact.h"
24 : #include "catalog/pg_authid.h"
25 : #include "commands/copy.h"
26 : #include "commands/defrem.h"
27 : #include "executor/executor.h"
28 : #include "mb/pg_wchar.h"
29 : #include "miscadmin.h"
30 : #include "nodes/makefuncs.h"
31 : #include "optimizer/optimizer.h"
32 : #include "parser/parse_coerce.h"
33 : #include "parser/parse_collate.h"
34 : #include "parser/parse_expr.h"
35 : #include "parser/parse_relation.h"
36 : #include "utils/acl.h"
37 : #include "utils/builtins.h"
38 : #include "utils/lsyscache.h"
39 : #include "utils/rel.h"
40 : #include "utils/rls.h"
41 :
42 : /*
43 : * DoCopy executes the SQL COPY statement
44 : *
45 : * Either unload or reload contents of table <relation>, depending on <from>.
46 : * (<from> = true means we are inserting into the table.) In the "TO" case
47 : * we also support copying the output of an arbitrary SELECT, INSERT, UPDATE
48 : * or DELETE query.
49 : *
50 : * If <pipe> is false, transfer is between the table and the file named
51 : * <filename>. Otherwise, transfer is between the table and our regular
52 : * input/output stream. The latter could be either stdin/stdout or a
53 : * socket, depending on whether we're running under Postmaster control.
54 : *
55 : * Do not allow a Postgres user without the 'pg_read_server_files' or
56 : * 'pg_write_server_files' role to read from or write to a file.
57 : *
58 : * Do not allow the copy if user doesn't have proper permission to access
59 : * the table or the specifically requested columns.
60 : */
61 : void
62 11292 : DoCopy(ParseState *pstate, const CopyStmt *stmt,
63 : int stmt_location, int stmt_len,
64 : uint64 *processed)
65 : {
66 11292 : bool is_from = stmt->is_from;
67 11292 : bool pipe = (stmt->filename == NULL);
68 : Relation rel;
69 : Oid relid;
70 11292 : RawStmt *query = NULL;
71 11292 : Node *whereClause = NULL;
72 :
73 : /*
74 : * Disallow COPY to/from file or program except to users with the
75 : * appropriate role.
76 : */
77 11292 : if (!pipe)
78 : {
79 446 : if (stmt->is_program)
80 : {
81 0 : if (!has_privs_of_role(GetUserId(), ROLE_PG_EXECUTE_SERVER_PROGRAM))
82 0 : ereport(ERROR,
83 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
84 : errmsg("permission denied to COPY to or from an external program"),
85 : errdetail("Only roles with privileges of the \"%s\" role may COPY to or from an external program.",
86 : "pg_execute_server_program"),
87 : errhint("Anyone can COPY to stdout or from stdin. "
88 : "psql's \\copy command also works for anyone.")));
89 : }
90 : else
91 : {
92 446 : if (is_from && !has_privs_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES))
93 0 : ereport(ERROR,
94 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
95 : errmsg("permission denied to COPY from a file"),
96 : errdetail("Only roles with privileges of the \"%s\" role may COPY from a file.",
97 : "pg_read_server_files"),
98 : errhint("Anyone can COPY to stdout or from stdin. "
99 : "psql's \\copy command also works for anyone.")));
100 :
101 446 : if (!is_from && !has_privs_of_role(GetUserId(), ROLE_PG_WRITE_SERVER_FILES))
102 0 : ereport(ERROR,
103 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
104 : errmsg("permission denied to COPY to a file"),
105 : errdetail("Only roles with privileges of the \"%s\" role may COPY to a file.",
106 : "pg_write_server_files"),
107 : errhint("Anyone can COPY to stdout or from stdin. "
108 : "psql's \\copy command also works for anyone.")));
109 : }
110 : }
111 :
112 11292 : if (stmt->relation)
113 : {
114 10690 : LOCKMODE lockmode = is_from ? RowExclusiveLock : AccessShareLock;
115 : ParseNamespaceItem *nsitem;
116 : RTEPermissionInfo *perminfo;
117 : TupleDesc tupDesc;
118 : List *attnums;
119 : ListCell *cur;
120 :
121 : Assert(!stmt->query);
122 :
123 : /* Open and lock the relation, using the appropriate lock type. */
124 10690 : rel = table_openrv(stmt->relation, lockmode);
125 :
126 10688 : relid = RelationGetRelid(rel);
127 :
128 10688 : nsitem = addRangeTableEntryForRelation(pstate, rel, lockmode,
129 : NULL, false, false);
130 :
131 10688 : perminfo = nsitem->p_perminfo;
132 10688 : perminfo->requiredPerms = (is_from ? ACL_INSERT : ACL_SELECT);
133 :
134 10688 : if (stmt->whereClause)
135 : {
136 : /* add nsitem to query namespace */
137 48 : addNSItemToQuery(pstate, nsitem, false, true, true);
138 :
139 : /* Transform the raw expression tree */
140 48 : whereClause = transformExpr(pstate, stmt->whereClause, EXPR_KIND_COPY_WHERE);
141 :
142 : /* Make sure it yields a boolean result. */
143 18 : whereClause = coerce_to_boolean(pstate, whereClause, "WHERE");
144 :
145 : /* we have to fix its collations too */
146 18 : assign_expr_collations(pstate, whereClause);
147 :
148 18 : whereClause = eval_const_expressions(NULL, whereClause);
149 :
150 18 : whereClause = (Node *) canonicalize_qual((Expr *) whereClause, false);
151 18 : whereClause = (Node *) make_ands_implicit((Expr *) whereClause);
152 : }
153 :
154 10658 : tupDesc = RelationGetDescr(rel);
155 10658 : attnums = CopyGetAttnums(tupDesc, rel, stmt->attlist);
156 47174 : foreach(cur, attnums)
157 : {
158 : int attno;
159 : Bitmapset **bms;
160 :
161 36600 : attno = lfirst_int(cur) - FirstLowInvalidHeapAttributeNumber;
162 36600 : bms = is_from ? &perminfo->insertedCols : &perminfo->selectedCols;
163 :
164 36600 : *bms = bms_add_member(*bms, attno);
165 : }
166 10574 : ExecCheckPermissions(pstate->p_rtable, list_make1(perminfo), true);
167 :
168 : /*
169 : * Permission check for row security policies.
170 : *
171 : * check_enable_rls will ereport(ERROR) if the user has requested
172 : * something invalid and will otherwise indicate if we should enable
173 : * RLS (returns RLS_ENABLED) or not for this COPY statement.
174 : *
175 : * If the relation has a row security policy and we are to apply it
176 : * then perform a "query" copy and allow the normal query processing
177 : * to handle the policies.
178 : *
179 : * If RLS is not enabled for this, then just fall through to the
180 : * normal non-filtering relation handling.
181 : */
182 10490 : if (check_enable_rls(relid, InvalidOid, false) == RLS_ENABLED)
183 : {
184 : SelectStmt *select;
185 : ColumnRef *cr;
186 : ResTarget *target;
187 : RangeVar *from;
188 84 : List *targetList = NIL;
189 :
190 84 : if (is_from)
191 6 : ereport(ERROR,
192 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
193 : errmsg("COPY FROM not supported with row-level security"),
194 : errhint("Use INSERT statements instead.")));
195 :
196 : /*
197 : * Build target list
198 : *
199 : * If no columns are specified in the attribute list of the COPY
200 : * command, then the target list is 'all' columns. Therefore, '*'
201 : * should be used as the target list for the resulting SELECT
202 : * statement.
203 : *
204 : * In the case that columns are specified in the attribute list,
205 : * create a ColumnRef and ResTarget for each column and add them
206 : * to the target list for the resulting SELECT statement.
207 : */
208 78 : if (!stmt->attlist)
209 : {
210 42 : cr = makeNode(ColumnRef);
211 42 : cr->fields = list_make1(makeNode(A_Star));
212 42 : cr->location = -1;
213 :
214 42 : target = makeNode(ResTarget);
215 42 : target->name = NULL;
216 42 : target->indirection = NIL;
217 42 : target->val = (Node *) cr;
218 42 : target->location = -1;
219 :
220 42 : targetList = list_make1(target);
221 : }
222 : else
223 : {
224 : ListCell *lc;
225 :
226 102 : foreach(lc, stmt->attlist)
227 : {
228 : /*
229 : * Build the ColumnRef for each column. The ColumnRef
230 : * 'fields' property is a String node that corresponds to
231 : * the column name respectively.
232 : */
233 66 : cr = makeNode(ColumnRef);
234 66 : cr->fields = list_make1(lfirst(lc));
235 66 : cr->location = -1;
236 :
237 : /* Build the ResTarget and add the ColumnRef to it. */
238 66 : target = makeNode(ResTarget);
239 66 : target->name = NULL;
240 66 : target->indirection = NIL;
241 66 : target->val = (Node *) cr;
242 66 : target->location = -1;
243 :
244 : /* Add each column to the SELECT statement's target list */
245 66 : targetList = lappend(targetList, target);
246 : }
247 : }
248 :
249 : /*
250 : * Build RangeVar for from clause, fully qualified based on the
251 : * relation which we have opened and locked. Use "ONLY" so that
252 : * COPY retrieves rows from only the target table not any
253 : * inheritance children, the same as when RLS doesn't apply.
254 : *
255 : * However, when copying data from a partitioned table, we don't
256 : * use "ONLY", since we need to retrieve rows from its descendant
257 : * tables too.
258 : */
259 78 : from = makeRangeVar(get_namespace_name(RelationGetNamespace(rel)),
260 78 : pstrdup(RelationGetRelationName(rel)),
261 : -1);
262 78 : from->inh = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
263 :
264 : /* Build query */
265 78 : select = makeNode(SelectStmt);
266 78 : select->targetList = targetList;
267 78 : select->fromClause = list_make1(from);
268 :
269 78 : query = makeNode(RawStmt);
270 78 : query->stmt = (Node *) select;
271 78 : query->stmt_location = stmt_location;
272 78 : query->stmt_len = stmt_len;
273 :
274 : /*
275 : * Close the relation for now, but keep the lock on it to prevent
276 : * changes between now and when we start the query-based COPY.
277 : *
278 : * We'll reopen it later as part of the query-based COPY.
279 : */
280 78 : table_close(rel, NoLock);
281 78 : rel = NULL;
282 : }
283 : }
284 : else
285 : {
286 : Assert(stmt->query);
287 :
288 602 : query = makeNode(RawStmt);
289 602 : query->stmt = stmt->query;
290 602 : query->stmt_location = stmt_location;
291 602 : query->stmt_len = stmt_len;
292 :
293 602 : relid = InvalidOid;
294 602 : rel = NULL;
295 : }
296 :
297 11068 : if (is_from)
298 : {
299 : CopyFromState cstate;
300 :
301 : Assert(rel);
302 :
303 : /* check read-only transaction and parallel mode */
304 1726 : if (XactReadOnly && !rel->rd_islocaltemp)
305 0 : PreventCommandIfReadOnly("COPY FROM");
306 :
307 1726 : cstate = BeginCopyFrom(pstate, rel, whereClause,
308 1726 : stmt->filename, stmt->is_program,
309 1726 : NULL, stmt->attlist, stmt->options);
310 1462 : *processed = CopyFrom(cstate); /* copy from file to database */
311 1224 : EndCopyFrom(cstate);
312 : }
313 : else
314 : {
315 : CopyToState cstate;
316 :
317 9342 : cstate = BeginCopyTo(pstate, rel, query, relid,
318 9342 : stmt->filename, stmt->is_program,
319 9342 : NULL, stmt->attlist, stmt->options);
320 9140 : *processed = DoCopyTo(cstate); /* copy from database to file */
321 9138 : EndCopyTo(cstate);
322 : }
323 :
324 10362 : if (rel != NULL)
325 9822 : table_close(rel, NoLock);
326 10362 : }
327 :
328 : /*
329 : * Extract the CopyFormatOptions.header_line value from a DefElem.
330 : *
331 : * Parses the HEADER option for COPY, which can be a boolean, a non-negative
332 : * integer (number of lines to skip), or the special value "match".
333 : */
334 : static int
335 228 : defGetCopyHeaderOption(DefElem *def, bool is_from)
336 : {
337 : /*
338 : * If no parameter value given, assume "true" is meant.
339 : */
340 228 : if (def->arg == NULL)
341 30 : return COPY_HEADER_TRUE;
342 :
343 : /*
344 : * Allow 0, 1, "true", "false", "on", "off", a non-negative integer, or
345 : * "match".
346 : */
347 198 : switch (nodeTag(def->arg))
348 : {
349 30 : case T_Integer:
350 : {
351 30 : int ival = intVal(def->arg);
352 :
353 30 : if (ival < 0)
354 6 : ereport(ERROR,
355 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
356 : errmsg("a negative integer value cannot be "
357 : "specified for %s", def->defname)));
358 :
359 24 : if (!is_from && ival > 1)
360 6 : ereport(ERROR,
361 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
362 : errmsg("cannot use multi-line header in COPY TO")));
363 :
364 18 : return ival;
365 : }
366 : break;
367 168 : default:
368 : {
369 168 : char *sval = defGetString(def);
370 :
371 : /*
372 : * The set of strings accepted here should match up with the
373 : * grammar's opt_boolean_or_string production.
374 : */
375 168 : if (pg_strcasecmp(sval, "true") == 0)
376 64 : return COPY_HEADER_TRUE;
377 104 : if (pg_strcasecmp(sval, "false") == 0)
378 0 : return COPY_HEADER_FALSE;
379 104 : if (pg_strcasecmp(sval, "on") == 0)
380 0 : return COPY_HEADER_TRUE;
381 104 : if (pg_strcasecmp(sval, "off") == 0)
382 6 : return COPY_HEADER_FALSE;
383 98 : if (pg_strcasecmp(sval, "match") == 0)
384 : {
385 86 : if (!is_from)
386 6 : ereport(ERROR,
387 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
388 : errmsg("cannot use \"%s\" with HEADER in COPY TO",
389 : sval)));
390 80 : return COPY_HEADER_MATCH;
391 : }
392 : }
393 12 : break;
394 : }
395 12 : ereport(ERROR,
396 : (errcode(ERRCODE_SYNTAX_ERROR),
397 : errmsg("%s requires a Boolean value, a non-negative integer, "
398 : "or the string \"match\"",
399 : def->defname)));
400 : return COPY_HEADER_FALSE; /* keep compiler quiet */
401 : }
402 :
403 : /*
404 : * Extract a CopyOnErrorChoice value from a DefElem.
405 : */
406 : static CopyOnErrorChoice
407 114 : defGetCopyOnErrorChoice(DefElem *def, ParseState *pstate, bool is_from)
408 : {
409 114 : char *sval = defGetString(def);
410 :
411 114 : if (!is_from)
412 6 : ereport(ERROR,
413 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
414 : /*- translator: first %s is the name of a COPY option, e.g. ON_ERROR,
415 : second %s is a COPY with direction, e.g. COPY TO */
416 : errmsg("COPY %s cannot be used with %s", "ON_ERROR", "COPY TO"),
417 : parser_errposition(pstate, def->location)));
418 :
419 : /*
420 : * Allow "stop", or "ignore" values.
421 : */
422 108 : if (pg_strcasecmp(sval, "stop") == 0)
423 6 : return COPY_ON_ERROR_STOP;
424 102 : if (pg_strcasecmp(sval, "ignore") == 0)
425 94 : return COPY_ON_ERROR_IGNORE;
426 :
427 8 : ereport(ERROR,
428 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
429 : /*- translator: first %s is the name of a COPY option, e.g. ON_ERROR */
430 : errmsg("COPY %s \"%s\" not recognized", "ON_ERROR", sval),
431 : parser_errposition(pstate, def->location)));
432 : return COPY_ON_ERROR_STOP; /* keep compiler quiet */
433 : }
434 :
435 : /*
436 : * Extract REJECT_LIMIT value from a DefElem.
437 : *
438 : * REJECT_LIMIT can be specified in two ways: as an int64 for the COPY command
439 : * option or as a single-quoted string for the foreign table option using
440 : * file_fdw. Therefore this function needs to handle both formats.
441 : */
442 : static int64
443 38 : defGetCopyRejectLimitOption(DefElem *def)
444 : {
445 : int64 reject_limit;
446 :
447 38 : if (def->arg == NULL)
448 0 : ereport(ERROR,
449 : (errcode(ERRCODE_SYNTAX_ERROR),
450 : errmsg("%s requires a numeric value",
451 : def->defname)));
452 38 : else if (nodeTag(def->arg) == T_String)
453 14 : reject_limit = pg_strtoint64(strVal(def->arg));
454 : else
455 24 : reject_limit = defGetInt64(def);
456 :
457 38 : if (reject_limit <= 0)
458 8 : ereport(ERROR,
459 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
460 : errmsg("REJECT_LIMIT (%" PRId64 ") must be greater than zero",
461 : reject_limit)));
462 :
463 30 : return reject_limit;
464 : }
465 :
466 : /*
467 : * Extract a CopyLogVerbosityChoice value from a DefElem.
468 : */
469 : static CopyLogVerbosityChoice
470 46 : defGetCopyLogVerbosityChoice(DefElem *def, ParseState *pstate)
471 : {
472 : char *sval;
473 :
474 : /*
475 : * Allow "silent", "default", or "verbose" values.
476 : */
477 46 : sval = defGetString(def);
478 46 : if (pg_strcasecmp(sval, "silent") == 0)
479 20 : return COPY_LOG_VERBOSITY_SILENT;
480 26 : if (pg_strcasecmp(sval, "default") == 0)
481 6 : return COPY_LOG_VERBOSITY_DEFAULT;
482 20 : if (pg_strcasecmp(sval, "verbose") == 0)
483 12 : return COPY_LOG_VERBOSITY_VERBOSE;
484 :
485 8 : ereport(ERROR,
486 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
487 : /*- translator: first %s is the name of a COPY option, e.g. ON_ERROR */
488 : errmsg("COPY %s \"%s\" not recognized", "LOG_VERBOSITY", sval),
489 : parser_errposition(pstate, def->location)));
490 : return COPY_LOG_VERBOSITY_DEFAULT; /* keep compiler quiet */
491 : }
492 :
493 : /*
494 : * Process the statement option list for COPY.
495 : *
496 : * Scan the options list (a list of DefElem) and transpose the information
497 : * into *opts_out, applying appropriate error checking.
498 : *
499 : * If 'opts_out' is not NULL, it is assumed to be filled with zeroes initially.
500 : *
501 : * This is exported so that external users of the COPY API can sanity-check
502 : * a list of options. In that usage, 'opts_out' can be passed as NULL and
503 : * the collected data is just leaked until CurrentMemoryContext is reset.
504 : *
505 : * Note that additional checking, such as whether column names listed in FORCE
506 : * QUOTE actually exist, has to be applied later. This just checks for
507 : * self-consistency of the options list.
508 : */
509 : void
510 11612 : ProcessCopyOptions(ParseState *pstate,
511 : CopyFormatOptions *opts_out,
512 : bool is_from,
513 : List *options)
514 : {
515 11612 : bool format_specified = false;
516 11612 : bool freeze_specified = false;
517 11612 : bool header_specified = false;
518 11612 : bool on_error_specified = false;
519 11612 : bool log_verbosity_specified = false;
520 11612 : bool reject_limit_specified = false;
521 : ListCell *option;
522 :
523 : /* Support external use for option sanity checking */
524 11612 : if (opts_out == NULL)
525 104 : opts_out = (CopyFormatOptions *) palloc0(sizeof(CopyFormatOptions));
526 :
527 11612 : opts_out->file_encoding = -1;
528 :
529 : /* Extract options from the statement node tree */
530 13688 : foreach(option, options)
531 : {
532 2234 : DefElem *defel = lfirst_node(DefElem, option);
533 :
534 2234 : if (strcmp(defel->defname, "format") == 0)
535 : {
536 656 : char *fmt = defGetString(defel);
537 :
538 656 : if (format_specified)
539 6 : errorConflictingDefElem(defel, pstate);
540 650 : format_specified = true;
541 650 : if (strcmp(fmt, "text") == 0)
542 : /* default format */ ;
543 574 : else if (strcmp(fmt, "csv") == 0)
544 502 : opts_out->csv_mode = true;
545 72 : else if (strcmp(fmt, "binary") == 0)
546 70 : opts_out->binary = true;
547 : else
548 2 : ereport(ERROR,
549 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
550 : errmsg("COPY format \"%s\" not recognized", fmt),
551 : parser_errposition(pstate, defel->location)));
552 : }
553 1578 : else if (strcmp(defel->defname, "freeze") == 0)
554 : {
555 84 : if (freeze_specified)
556 6 : errorConflictingDefElem(defel, pstate);
557 78 : freeze_specified = true;
558 78 : opts_out->freeze = defGetBoolean(defel);
559 : }
560 1494 : else if (strcmp(defel->defname, "delimiter") == 0)
561 : {
562 302 : if (opts_out->delim)
563 6 : errorConflictingDefElem(defel, pstate);
564 296 : opts_out->delim = defGetString(defel);
565 : }
566 1192 : else if (strcmp(defel->defname, "null") == 0)
567 : {
568 144 : if (opts_out->null_print)
569 6 : errorConflictingDefElem(defel, pstate);
570 138 : opts_out->null_print = defGetString(defel);
571 : }
572 1048 : else if (strcmp(defel->defname, "default") == 0)
573 : {
574 90 : if (opts_out->default_print)
575 0 : errorConflictingDefElem(defel, pstate);
576 90 : opts_out->default_print = defGetString(defel);
577 : }
578 958 : else if (strcmp(defel->defname, "header") == 0)
579 : {
580 234 : if (header_specified)
581 6 : errorConflictingDefElem(defel, pstate);
582 228 : header_specified = true;
583 228 : opts_out->header_line = defGetCopyHeaderOption(defel, is_from);
584 : }
585 724 : else if (strcmp(defel->defname, "quote") == 0)
586 : {
587 102 : if (opts_out->quote)
588 6 : errorConflictingDefElem(defel, pstate);
589 96 : opts_out->quote = defGetString(defel);
590 : }
591 622 : else if (strcmp(defel->defname, "escape") == 0)
592 : {
593 94 : if (opts_out->escape)
594 6 : errorConflictingDefElem(defel, pstate);
595 88 : opts_out->escape = defGetString(defel);
596 : }
597 528 : else if (strcmp(defel->defname, "force_quote") == 0)
598 : {
599 78 : if (opts_out->force_quote || opts_out->force_quote_all)
600 6 : errorConflictingDefElem(defel, pstate);
601 72 : if (defel->arg && IsA(defel->arg, A_Star))
602 30 : opts_out->force_quote_all = true;
603 42 : else if (defel->arg && IsA(defel->arg, List))
604 42 : opts_out->force_quote = castNode(List, defel->arg);
605 : else
606 0 : ereport(ERROR,
607 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
608 : errmsg("argument to option \"%s\" must be a list of column names",
609 : defel->defname),
610 : parser_errposition(pstate, defel->location)));
611 : }
612 450 : else if (strcmp(defel->defname, "force_not_null") == 0)
613 : {
614 88 : if (opts_out->force_notnull || opts_out->force_notnull_all)
615 12 : errorConflictingDefElem(defel, pstate);
616 76 : if (defel->arg && IsA(defel->arg, A_Star))
617 30 : opts_out->force_notnull_all = true;
618 46 : else if (defel->arg && IsA(defel->arg, List))
619 46 : opts_out->force_notnull = castNode(List, defel->arg);
620 : else
621 0 : ereport(ERROR,
622 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
623 : errmsg("argument to option \"%s\" must be a list of column names",
624 : defel->defname),
625 : parser_errposition(pstate, defel->location)));
626 : }
627 362 : else if (strcmp(defel->defname, "force_null") == 0)
628 : {
629 88 : if (opts_out->force_null || opts_out->force_null_all)
630 12 : errorConflictingDefElem(defel, pstate);
631 76 : if (defel->arg && IsA(defel->arg, A_Star))
632 30 : opts_out->force_null_all = true;
633 46 : else if (defel->arg && IsA(defel->arg, List))
634 46 : opts_out->force_null = castNode(List, defel->arg);
635 : else
636 0 : ereport(ERROR,
637 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
638 : errmsg("argument to option \"%s\" must be a list of column names",
639 : defel->defname),
640 : parser_errposition(pstate, defel->location)));
641 : }
642 274 : else if (strcmp(defel->defname, "convert_selectively") == 0)
643 : {
644 : /*
645 : * Undocumented, not-accessible-from-SQL option: convert only the
646 : * named columns to binary form, storing the rest as NULLs. It's
647 : * allowed for the column list to be NIL.
648 : */
649 16 : if (opts_out->convert_selectively)
650 6 : errorConflictingDefElem(defel, pstate);
651 10 : opts_out->convert_selectively = true;
652 10 : if (defel->arg == NULL || IsA(defel->arg, List))
653 10 : opts_out->convert_select = castNode(List, defel->arg);
654 : else
655 0 : ereport(ERROR,
656 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
657 : errmsg("argument to option \"%s\" must be a list of column names",
658 : defel->defname),
659 : parser_errposition(pstate, defel->location)));
660 : }
661 258 : else if (strcmp(defel->defname, "encoding") == 0)
662 : {
663 48 : if (opts_out->file_encoding >= 0)
664 6 : errorConflictingDefElem(defel, pstate);
665 42 : opts_out->file_encoding = pg_char_to_encoding(defGetString(defel));
666 42 : if (opts_out->file_encoding < 0)
667 0 : ereport(ERROR,
668 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
669 : errmsg("argument to option \"%s\" must be a valid encoding name",
670 : defel->defname),
671 : parser_errposition(pstate, defel->location)));
672 : }
673 210 : else if (strcmp(defel->defname, "on_error") == 0)
674 : {
675 120 : if (on_error_specified)
676 6 : errorConflictingDefElem(defel, pstate);
677 114 : on_error_specified = true;
678 114 : opts_out->on_error = defGetCopyOnErrorChoice(defel, pstate, is_from);
679 : }
680 90 : else if (strcmp(defel->defname, "log_verbosity") == 0)
681 : {
682 52 : if (log_verbosity_specified)
683 6 : errorConflictingDefElem(defel, pstate);
684 46 : log_verbosity_specified = true;
685 46 : opts_out->log_verbosity = defGetCopyLogVerbosityChoice(defel, pstate);
686 : }
687 38 : else if (strcmp(defel->defname, "reject_limit") == 0)
688 : {
689 38 : if (reject_limit_specified)
690 0 : errorConflictingDefElem(defel, pstate);
691 38 : reject_limit_specified = true;
692 38 : opts_out->reject_limit = defGetCopyRejectLimitOption(defel);
693 : }
694 : else
695 0 : ereport(ERROR,
696 : (errcode(ERRCODE_SYNTAX_ERROR),
697 : errmsg("option \"%s\" not recognized",
698 : defel->defname),
699 : parser_errposition(pstate, defel->location)));
700 : }
701 :
702 : /*
703 : * Check for incompatible options (must do these three before inserting
704 : * defaults)
705 : */
706 11454 : if (opts_out->binary && opts_out->delim)
707 6 : ereport(ERROR,
708 : (errcode(ERRCODE_SYNTAX_ERROR),
709 : /*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
710 : errmsg("cannot specify %s in BINARY mode", "DELIMITER")));
711 :
712 11448 : if (opts_out->binary && opts_out->null_print)
713 6 : ereport(ERROR,
714 : (errcode(ERRCODE_SYNTAX_ERROR),
715 : errmsg("cannot specify %s in BINARY mode", "NULL")));
716 :
717 11442 : if (opts_out->binary && opts_out->default_print)
718 6 : ereport(ERROR,
719 : (errcode(ERRCODE_SYNTAX_ERROR),
720 : errmsg("cannot specify %s in BINARY mode", "DEFAULT")));
721 :
722 : /* Set defaults for omitted options */
723 11436 : if (!opts_out->delim)
724 11152 : opts_out->delim = opts_out->csv_mode ? "," : "\t";
725 :
726 11436 : if (!opts_out->null_print)
727 11310 : opts_out->null_print = opts_out->csv_mode ? "" : "\\N";
728 11436 : opts_out->null_print_len = strlen(opts_out->null_print);
729 :
730 11436 : if (opts_out->csv_mode)
731 : {
732 484 : if (!opts_out->quote)
733 398 : opts_out->quote = "\"";
734 484 : if (!opts_out->escape)
735 408 : opts_out->escape = opts_out->quote;
736 : }
737 :
738 : /* Only single-byte delimiter strings are supported. */
739 11436 : if (strlen(opts_out->delim) != 1)
740 2 : ereport(ERROR,
741 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
742 : errmsg("COPY delimiter must be a single one-byte character")));
743 :
744 : /* Disallow end-of-line characters */
745 11434 : if (strchr(opts_out->delim, '\r') != NULL ||
746 11434 : strchr(opts_out->delim, '\n') != NULL)
747 2 : ereport(ERROR,
748 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
749 : errmsg("COPY delimiter cannot be newline or carriage return")));
750 :
751 11432 : if (strchr(opts_out->null_print, '\r') != NULL ||
752 11432 : strchr(opts_out->null_print, '\n') != NULL)
753 2 : ereport(ERROR,
754 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
755 : errmsg("COPY null representation cannot use newline or carriage return")));
756 :
757 11430 : if (opts_out->default_print)
758 : {
759 84 : opts_out->default_print_len = strlen(opts_out->default_print);
760 :
761 84 : if (strchr(opts_out->default_print, '\r') != NULL ||
762 78 : strchr(opts_out->default_print, '\n') != NULL)
763 12 : ereport(ERROR,
764 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
765 : errmsg("COPY default representation cannot use newline or carriage return")));
766 : }
767 :
768 : /*
769 : * Disallow unsafe delimiter characters in non-CSV mode. We can't allow
770 : * backslash because it would be ambiguous. We can't allow the other
771 : * cases because data characters matching the delimiter must be
772 : * backslashed, and certain backslash combinations are interpreted
773 : * non-literally by COPY IN. Disallowing all lower case ASCII letters is
774 : * more than strictly necessary, but seems best for consistency and
775 : * future-proofing. Likewise we disallow all digits though only octal
776 : * digits are actually dangerous.
777 : */
778 11418 : if (!opts_out->csv_mode &&
779 10940 : strchr("\\.abcdefghijklmnopqrstuvwxyz0123456789",
780 10940 : opts_out->delim[0]) != NULL)
781 10 : ereport(ERROR,
782 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
783 : errmsg("COPY delimiter cannot be \"%s\"", opts_out->delim)));
784 :
785 : /* Check header */
786 11408 : if (opts_out->binary && opts_out->header_line != COPY_HEADER_FALSE)
787 2 : ereport(ERROR,
788 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
789 : /*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
790 : errmsg("cannot specify %s in BINARY mode", "HEADER")));
791 :
792 : /* Check quote */
793 11406 : if (!opts_out->csv_mode && opts_out->quote != NULL)
794 4 : ereport(ERROR,
795 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
796 : /*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
797 : errmsg("COPY %s requires CSV mode", "QUOTE")));
798 :
799 11402 : if (opts_out->csv_mode && strlen(opts_out->quote) != 1)
800 2 : ereport(ERROR,
801 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
802 : errmsg("COPY quote must be a single one-byte character")));
803 :
804 11400 : if (opts_out->csv_mode && opts_out->delim[0] == opts_out->quote[0])
805 2 : ereport(ERROR,
806 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
807 : errmsg("COPY delimiter and quote must be different")));
808 :
809 : /* Check escape */
810 11398 : if (!opts_out->csv_mode && opts_out->escape != NULL)
811 6 : ereport(ERROR,
812 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
813 : /*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
814 : errmsg("COPY %s requires CSV mode", "ESCAPE")));
815 :
816 11392 : if (opts_out->csv_mode && strlen(opts_out->escape) != 1)
817 2 : ereport(ERROR,
818 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
819 : errmsg("COPY escape must be a single one-byte character")));
820 :
821 : /* Check force_quote */
822 11390 : if (!opts_out->csv_mode && (opts_out->force_quote || opts_out->force_quote_all))
823 12 : ereport(ERROR,
824 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
825 : /*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
826 : errmsg("COPY %s requires CSV mode", "FORCE_QUOTE")));
827 11378 : if ((opts_out->force_quote || opts_out->force_quote_all) && is_from)
828 12 : ereport(ERROR,
829 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
830 : /*- translator: first %s is the name of a COPY option, e.g. ON_ERROR,
831 : second %s is a COPY with direction, e.g. COPY TO */
832 : errmsg("COPY %s cannot be used with %s", "FORCE_QUOTE",
833 : "COPY FROM")));
834 :
835 : /* Check force_notnull */
836 11366 : if (!opts_out->csv_mode && (opts_out->force_notnull != NIL ||
837 10898 : opts_out->force_notnull_all))
838 14 : ereport(ERROR,
839 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
840 : /*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
841 : errmsg("COPY %s requires CSV mode", "FORCE_NOT_NULL")));
842 11352 : if ((opts_out->force_notnull != NIL || opts_out->force_notnull_all) &&
843 50 : !is_from)
844 12 : ereport(ERROR,
845 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
846 : /*- translator: first %s is the name of a COPY option, e.g. ON_ERROR,
847 : second %s is a COPY with direction, e.g. COPY TO */
848 : errmsg("COPY %s cannot be used with %s", "FORCE_NOT_NULL",
849 : "COPY TO")));
850 :
851 : /* Check force_null */
852 11340 : if (!opts_out->csv_mode && (opts_out->force_null != NIL ||
853 10886 : opts_out->force_null_all))
854 12 : ereport(ERROR,
855 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
856 : /*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
857 : errmsg("COPY %s requires CSV mode", "FORCE_NULL")));
858 :
859 11328 : if ((opts_out->force_null != NIL || opts_out->force_null_all) &&
860 50 : !is_from)
861 12 : ereport(ERROR,
862 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
863 : /*- translator: first %s is the name of a COPY option, e.g. ON_ERROR,
864 : second %s is a COPY with direction, e.g. COPY TO */
865 : errmsg("COPY %s cannot be used with %s", "FORCE_NULL",
866 : "COPY TO")));
867 :
868 : /* Don't allow the delimiter to appear in the null string. */
869 11316 : if (strchr(opts_out->null_print, opts_out->delim[0]) != NULL)
870 2 : ereport(ERROR,
871 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
872 : /*- translator: %s is the name of a COPY option, e.g. NULL */
873 : errmsg("COPY delimiter character must not appear in the %s specification",
874 : "NULL")));
875 :
876 : /* Don't allow the CSV quote char to appear in the null string. */
877 11314 : if (opts_out->csv_mode &&
878 434 : strchr(opts_out->null_print, opts_out->quote[0]) != NULL)
879 2 : ereport(ERROR,
880 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
881 : /*- translator: %s is the name of a COPY option, e.g. NULL */
882 : errmsg("CSV quote character must not appear in the %s specification",
883 : "NULL")));
884 :
885 : /* Check freeze */
886 11312 : if (opts_out->freeze && !is_from)
887 0 : ereport(ERROR,
888 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
889 : /*- translator: first %s is the name of a COPY option, e.g. ON_ERROR,
890 : second %s is a COPY with direction, e.g. COPY TO */
891 : errmsg("COPY %s cannot be used with %s", "FREEZE",
892 : "COPY TO")));
893 :
894 11312 : if (opts_out->default_print)
895 : {
896 72 : if (!is_from)
897 6 : ereport(ERROR,
898 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
899 : /*- translator: first %s is the name of a COPY option, e.g. ON_ERROR,
900 : second %s is a COPY with direction, e.g. COPY TO */
901 : errmsg("COPY %s cannot be used with %s", "DEFAULT",
902 : "COPY TO")));
903 :
904 : /* Don't allow the delimiter to appear in the default string. */
905 66 : if (strchr(opts_out->default_print, opts_out->delim[0]) != NULL)
906 6 : ereport(ERROR,
907 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
908 : /*- translator: %s is the name of a COPY option, e.g. NULL */
909 : errmsg("COPY delimiter character must not appear in the %s specification",
910 : "DEFAULT")));
911 :
912 : /* Don't allow the CSV quote char to appear in the default string. */
913 60 : if (opts_out->csv_mode &&
914 30 : strchr(opts_out->default_print, opts_out->quote[0]) != NULL)
915 6 : ereport(ERROR,
916 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
917 : /*- translator: %s is the name of a COPY option, e.g. NULL */
918 : errmsg("CSV quote character must not appear in the %s specification",
919 : "DEFAULT")));
920 :
921 : /* Don't allow the NULL and DEFAULT string to be the same */
922 54 : if (opts_out->null_print_len == opts_out->default_print_len &&
923 24 : strncmp(opts_out->null_print, opts_out->default_print,
924 24 : opts_out->null_print_len) == 0)
925 6 : ereport(ERROR,
926 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
927 : errmsg("NULL specification and DEFAULT specification cannot be the same")));
928 : }
929 : /* Check on_error */
930 11288 : if (opts_out->binary && opts_out->on_error != COPY_ON_ERROR_STOP)
931 8 : ereport(ERROR,
932 : (errcode(ERRCODE_SYNTAX_ERROR),
933 : errmsg("only ON_ERROR STOP is allowed in BINARY mode")));
934 :
935 11280 : if (opts_out->reject_limit && !opts_out->on_error)
936 8 : ereport(ERROR,
937 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
938 : /*- translator: first and second %s are the names of COPY option, e.g.
939 : * ON_ERROR, third is the value of the COPY option, e.g. IGNORE */
940 : errmsg("COPY %s requires %s to be set to %s",
941 : "REJECT_LIMIT", "ON_ERROR", "IGNORE")));
942 11272 : }
943 :
944 : /*
945 : * CopyGetAttnums - build an integer list of attnums to be copied
946 : *
947 : * The input attnamelist is either the user-specified column list,
948 : * or NIL if there was none (in which case we want all the non-dropped
949 : * columns).
950 : *
951 : * We don't include generated columns in the generated full list and we don't
952 : * allow them to be specified explicitly. They don't make sense for COPY
953 : * FROM, but we could possibly allow them for COPY TO. But this way it's at
954 : * least ensured that whatever we copy out can be copied back in.
955 : *
956 : * rel can be NULL ... it's only used for error reports.
957 : */
958 : List *
959 21822 : CopyGetAttnums(TupleDesc tupDesc, Relation rel, List *attnamelist)
960 : {
961 21822 : List *attnums = NIL;
962 :
963 21822 : if (attnamelist == NIL)
964 : {
965 : /* Generate default column list */
966 3876 : int attr_count = tupDesc->natts;
967 : int i;
968 :
969 13676 : for (i = 0; i < attr_count; i++)
970 : {
971 9800 : CompactAttribute *attr = TupleDescCompactAttr(tupDesc, i);
972 :
973 9800 : if (attr->attisdropped || attr->attgenerated)
974 302 : continue;
975 9498 : attnums = lappend_int(attnums, i + 1);
976 : }
977 : }
978 : else
979 : {
980 : /* Validate the user-supplied list and extract attnums */
981 : ListCell *l;
982 :
983 82262 : foreach(l, attnamelist)
984 : {
985 64400 : char *name = strVal(lfirst(l));
986 : int attnum;
987 : int i;
988 :
989 : /* Lookup column name */
990 64400 : attnum = InvalidAttrNumber;
991 9926840 : for (i = 0; i < tupDesc->natts; i++)
992 : {
993 9926810 : Form_pg_attribute att = TupleDescAttr(tupDesc, i);
994 :
995 9926810 : if (att->attisdropped)
996 792 : continue;
997 9926018 : if (namestrcmp(&(att->attname), name) == 0)
998 : {
999 64370 : if (att->attgenerated)
1000 48 : ereport(ERROR,
1001 : (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
1002 : errmsg("column \"%s\" is a generated column",
1003 : name),
1004 : errdetail("Generated columns cannot be used in COPY.")));
1005 64322 : attnum = att->attnum;
1006 64322 : break;
1007 : }
1008 : }
1009 64352 : if (attnum == InvalidAttrNumber)
1010 : {
1011 30 : if (rel != NULL)
1012 30 : ereport(ERROR,
1013 : (errcode(ERRCODE_UNDEFINED_COLUMN),
1014 : errmsg("column \"%s\" of relation \"%s\" does not exist",
1015 : name, RelationGetRelationName(rel))));
1016 : else
1017 0 : ereport(ERROR,
1018 : (errcode(ERRCODE_UNDEFINED_COLUMN),
1019 : errmsg("column \"%s\" does not exist",
1020 : name)));
1021 : }
1022 : /* Check for duplicates */
1023 64322 : if (list_member_int(attnums, attnum))
1024 6 : ereport(ERROR,
1025 : (errcode(ERRCODE_DUPLICATE_COLUMN),
1026 : errmsg("column \"%s\" specified more than once",
1027 : name)));
1028 64316 : attnums = lappend_int(attnums, attnum);
1029 : }
1030 : }
1031 :
1032 21738 : return attnums;
1033 : }
|