Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * copy.c
4 : * Implements the COPY utility command
5 : *
6 : * Portions Copyright (c) 1996-2024, 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 9466 : DoCopy(ParseState *pstate, const CopyStmt *stmt,
63 : int stmt_location, int stmt_len,
64 : uint64 *processed)
65 : {
66 9466 : bool is_from = stmt->is_from;
67 9466 : bool pipe = (stmt->filename == NULL);
68 : Relation rel;
69 : Oid relid;
70 9466 : RawStmt *query = NULL;
71 9466 : Node *whereClause = NULL;
72 :
73 : /*
74 : * Disallow COPY to/from file or program except to users with the
75 : * appropriate role.
76 : */
77 9466 : if (!pipe)
78 : {
79 372 : 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 372 : 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 372 : 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 9466 : if (stmt->relation)
113 : {
114 9072 : 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 9072 : rel = table_openrv(stmt->relation, lockmode);
125 :
126 9070 : relid = RelationGetRelid(rel);
127 :
128 9070 : nsitem = addRangeTableEntryForRelation(pstate, rel, lockmode,
129 : NULL, false, false);
130 :
131 9070 : perminfo = nsitem->p_perminfo;
132 9070 : perminfo->requiredPerms = (is_from ? ACL_INSERT : ACL_SELECT);
133 :
134 9070 : 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 9040 : tupDesc = RelationGetDescr(rel);
155 9040 : attnums = CopyGetAttnums(tupDesc, rel, stmt->attlist);
156 40520 : foreach(cur, attnums)
157 : {
158 : int attno;
159 : Bitmapset **bms;
160 :
161 31540 : attno = lfirst_int(cur) - FirstLowInvalidHeapAttributeNumber;
162 31540 : bms = is_from ? &perminfo->insertedCols : &perminfo->selectedCols;
163 :
164 31540 : *bms = bms_add_member(*bms, attno);
165 : }
166 8980 : 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 8896 : if (check_enable_rls(relid, InvalidOid, false) == RLS_ENABLED)
183 : {
184 : SelectStmt *select;
185 : ColumnRef *cr;
186 : ResTarget *target;
187 : RangeVar *from;
188 60 : List *targetList = NIL;
189 :
190 60 : 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 54 : if (!stmt->attlist)
209 : {
210 18 : cr = makeNode(ColumnRef);
211 18 : cr->fields = list_make1(makeNode(A_Star));
212 18 : cr->location = -1;
213 :
214 18 : target = makeNode(ResTarget);
215 18 : target->name = NULL;
216 18 : target->indirection = NIL;
217 18 : target->val = (Node *) cr;
218 18 : target->location = -1;
219 :
220 18 : 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 54 : from = makeRangeVar(get_namespace_name(RelationGetNamespace(rel)),
256 54 : pstrdup(RelationGetRelationName(rel)),
257 : -1);
258 54 : from->inh = false; /* apply ONLY */
259 :
260 : /* Build query */
261 54 : select = makeNode(SelectStmt);
262 54 : select->targetList = targetList;
263 54 : select->fromClause = list_make1(from);
264 :
265 54 : query = makeNode(RawStmt);
266 54 : query->stmt = (Node *) select;
267 54 : query->stmt_location = stmt_location;
268 54 : query->stmt_len = stmt_len;
269 :
270 : /*
271 : * Close the relation for now, but keep the lock on it to prevent
272 : * changes between now and when we start the query-based COPY.
273 : *
274 : * We'll reopen it later as part of the query-based COPY.
275 : */
276 54 : table_close(rel, NoLock);
277 54 : rel = NULL;
278 : }
279 : }
280 : else
281 : {
282 : Assert(stmt->query);
283 :
284 394 : query = makeNode(RawStmt);
285 394 : query->stmt = stmt->query;
286 394 : query->stmt_location = stmt_location;
287 394 : query->stmt_len = stmt_len;
288 :
289 394 : relid = InvalidOid;
290 394 : rel = NULL;
291 : }
292 :
293 9266 : if (is_from)
294 : {
295 : CopyFromState cstate;
296 :
297 : Assert(rel);
298 :
299 : /* check read-only transaction and parallel mode */
300 1398 : if (XactReadOnly && !rel->rd_islocaltemp)
301 0 : PreventCommandIfReadOnly("COPY FROM");
302 :
303 1398 : cstate = BeginCopyFrom(pstate, rel, whereClause,
304 1398 : stmt->filename, stmt->is_program,
305 : NULL, stmt->attlist, stmt->options);
306 1218 : *processed = CopyFrom(cstate); /* copy from file to database */
307 1024 : EndCopyFrom(cstate);
308 : }
309 : else
310 : {
311 : CopyToState cstate;
312 :
313 7868 : cstate = BeginCopyTo(pstate, rel, query, relid,
314 7868 : stmt->filename, stmt->is_program,
315 : NULL, stmt->attlist, stmt->options);
316 7662 : *processed = DoCopyTo(cstate); /* copy from database to file */
317 7660 : EndCopyTo(cstate);
318 : }
319 :
320 8684 : if (rel != NULL)
321 8370 : table_close(rel, NoLock);
322 8684 : }
323 :
324 : /*
325 : * Extract a CopyHeaderChoice value from a DefElem. This is like
326 : * defGetBoolean() but also accepts the special value "match".
327 : */
328 : static CopyHeaderChoice
329 156 : defGetCopyHeaderChoice(DefElem *def, bool is_from)
330 : {
331 : /*
332 : * If no parameter value given, assume "true" is meant.
333 : */
334 156 : if (def->arg == NULL)
335 12 : return COPY_HEADER_TRUE;
336 :
337 : /*
338 : * Allow 0, 1, "true", "false", "on", "off", or "match".
339 : */
340 144 : switch (nodeTag(def->arg))
341 : {
342 0 : case T_Integer:
343 0 : switch (intVal(def->arg))
344 : {
345 0 : case 0:
346 0 : return COPY_HEADER_FALSE;
347 0 : case 1:
348 0 : return COPY_HEADER_TRUE;
349 0 : default:
350 : /* otherwise, error out below */
351 0 : break;
352 : }
353 0 : break;
354 144 : default:
355 : {
356 144 : char *sval = defGetString(def);
357 :
358 : /*
359 : * The set of strings accepted here should match up with the
360 : * grammar's opt_boolean_or_string production.
361 : */
362 144 : if (pg_strcasecmp(sval, "true") == 0)
363 46 : return COPY_HEADER_TRUE;
364 98 : if (pg_strcasecmp(sval, "false") == 0)
365 0 : return COPY_HEADER_FALSE;
366 98 : if (pg_strcasecmp(sval, "on") == 0)
367 0 : return COPY_HEADER_TRUE;
368 98 : if (pg_strcasecmp(sval, "off") == 0)
369 6 : return COPY_HEADER_FALSE;
370 92 : if (pg_strcasecmp(sval, "match") == 0)
371 : {
372 86 : if (!is_from)
373 6 : ereport(ERROR,
374 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
375 : errmsg("cannot use \"%s\" with HEADER in COPY TO",
376 : sval)));
377 80 : return COPY_HEADER_MATCH;
378 : }
379 : }
380 6 : break;
381 : }
382 6 : ereport(ERROR,
383 : (errcode(ERRCODE_SYNTAX_ERROR),
384 : errmsg("%s requires a Boolean value or \"match\"",
385 : def->defname)));
386 : return COPY_HEADER_FALSE; /* keep compiler quiet */
387 : }
388 :
389 : /*
390 : * Extract a CopyOnErrorChoice value from a DefElem.
391 : */
392 : static CopyOnErrorChoice
393 60 : defGetCopyOnErrorChoice(DefElem *def, ParseState *pstate, bool is_from)
394 : {
395 60 : char *sval = defGetString(def);
396 :
397 60 : if (!is_from)
398 6 : ereport(ERROR,
399 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
400 : errmsg("COPY ON_ERROR cannot be used with COPY TO"),
401 : parser_errposition(pstate, def->location)));
402 :
403 : /*
404 : * Allow "stop", or "ignore" values.
405 : */
406 54 : if (pg_strcasecmp(sval, "stop") == 0)
407 6 : return COPY_ON_ERROR_STOP;
408 48 : if (pg_strcasecmp(sval, "ignore") == 0)
409 42 : return COPY_ON_ERROR_IGNORE;
410 :
411 6 : ereport(ERROR,
412 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
413 : errmsg("COPY ON_ERROR \"%s\" not recognized", sval),
414 : parser_errposition(pstate, def->location)));
415 : return COPY_ON_ERROR_STOP; /* keep compiler quiet */
416 : }
417 :
418 : /*
419 : * Extract a CopyLogVerbosityChoice value from a DefElem.
420 : */
421 : static CopyLogVerbosityChoice
422 24 : defGetCopyLogVerbosityChoice(DefElem *def, ParseState *pstate)
423 : {
424 : char *sval;
425 :
426 : /*
427 : * Allow "default", or "verbose" values.
428 : */
429 24 : sval = defGetString(def);
430 24 : if (pg_strcasecmp(sval, "default") == 0)
431 6 : return COPY_LOG_VERBOSITY_DEFAULT;
432 18 : if (pg_strcasecmp(sval, "verbose") == 0)
433 12 : return COPY_LOG_VERBOSITY_VERBOSE;
434 :
435 6 : ereport(ERROR,
436 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
437 : errmsg("COPY LOG_VERBOSITY \"%s\" not recognized", sval),
438 : parser_errposition(pstate, def->location)));
439 : return COPY_LOG_VERBOSITY_DEFAULT; /* keep compiler quiet */
440 : }
441 :
442 : /*
443 : * Process the statement option list for COPY.
444 : *
445 : * Scan the options list (a list of DefElem) and transpose the information
446 : * into *opts_out, applying appropriate error checking.
447 : *
448 : * If 'opts_out' is not NULL, it is assumed to be filled with zeroes initially.
449 : *
450 : * This is exported so that external users of the COPY API can sanity-check
451 : * a list of options. In that usage, 'opts_out' can be passed as NULL and
452 : * the collected data is just leaked until CurrentMemoryContext is reset.
453 : *
454 : * Note that additional checking, such as whether column names listed in FORCE
455 : * QUOTE actually exist, has to be applied later. This just checks for
456 : * self-consistency of the options list.
457 : */
458 : void
459 9742 : ProcessCopyOptions(ParseState *pstate,
460 : CopyFormatOptions *opts_out,
461 : bool is_from,
462 : List *options)
463 : {
464 9742 : bool format_specified = false;
465 9742 : bool freeze_specified = false;
466 9742 : bool header_specified = false;
467 9742 : bool on_error_specified = false;
468 9742 : bool log_verbosity_specified = false;
469 : ListCell *option;
470 :
471 : /* Support external use for option sanity checking */
472 9742 : if (opts_out == NULL)
473 86 : opts_out = (CopyFormatOptions *) palloc0(sizeof(CopyFormatOptions));
474 :
475 9742 : opts_out->file_encoding = -1;
476 :
477 : /* Extract options from the statement node tree */
478 11378 : foreach(option, options)
479 : {
480 1764 : DefElem *defel = lfirst_node(DefElem, option);
481 :
482 1764 : if (strcmp(defel->defname, "format") == 0)
483 : {
484 528 : char *fmt = defGetString(defel);
485 :
486 528 : if (format_specified)
487 6 : errorConflictingDefElem(defel, pstate);
488 522 : format_specified = true;
489 522 : if (strcmp(fmt, "text") == 0)
490 : /* default format */ ;
491 464 : else if (strcmp(fmt, "csv") == 0)
492 394 : opts_out->csv_mode = true;
493 70 : else if (strcmp(fmt, "binary") == 0)
494 68 : opts_out->binary = true;
495 : else
496 2 : ereport(ERROR,
497 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
498 : errmsg("COPY format \"%s\" not recognized", fmt),
499 : parser_errposition(pstate, defel->location)));
500 : }
501 1236 : else if (strcmp(defel->defname, "freeze") == 0)
502 : {
503 78 : if (freeze_specified)
504 6 : errorConflictingDefElem(defel, pstate);
505 72 : freeze_specified = true;
506 72 : opts_out->freeze = defGetBoolean(defel);
507 : }
508 1158 : else if (strcmp(defel->defname, "delimiter") == 0)
509 : {
510 266 : if (opts_out->delim)
511 6 : errorConflictingDefElem(defel, pstate);
512 260 : opts_out->delim = defGetString(defel);
513 : }
514 892 : else if (strcmp(defel->defname, "null") == 0)
515 : {
516 126 : if (opts_out->null_print)
517 6 : errorConflictingDefElem(defel, pstate);
518 120 : opts_out->null_print = defGetString(defel);
519 : }
520 766 : else if (strcmp(defel->defname, "default") == 0)
521 : {
522 90 : if (opts_out->default_print)
523 0 : errorConflictingDefElem(defel, pstate);
524 90 : opts_out->default_print = defGetString(defel);
525 : }
526 676 : else if (strcmp(defel->defname, "header") == 0)
527 : {
528 162 : if (header_specified)
529 6 : errorConflictingDefElem(defel, pstate);
530 156 : header_specified = true;
531 156 : opts_out->header_line = defGetCopyHeaderChoice(defel, is_from);
532 : }
533 514 : else if (strcmp(defel->defname, "quote") == 0)
534 : {
535 84 : if (opts_out->quote)
536 6 : errorConflictingDefElem(defel, pstate);
537 78 : opts_out->quote = defGetString(defel);
538 : }
539 430 : else if (strcmp(defel->defname, "escape") == 0)
540 : {
541 76 : if (opts_out->escape)
542 6 : errorConflictingDefElem(defel, pstate);
543 70 : opts_out->escape = defGetString(defel);
544 : }
545 354 : else if (strcmp(defel->defname, "force_quote") == 0)
546 : {
547 66 : if (opts_out->force_quote || opts_out->force_quote_all)
548 6 : errorConflictingDefElem(defel, pstate);
549 60 : if (defel->arg && IsA(defel->arg, A_Star))
550 18 : opts_out->force_quote_all = true;
551 42 : else if (defel->arg && IsA(defel->arg, List))
552 42 : opts_out->force_quote = castNode(List, defel->arg);
553 : else
554 0 : ereport(ERROR,
555 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
556 : errmsg("argument to option \"%s\" must be a list of column names",
557 : defel->defname),
558 : parser_errposition(pstate, defel->location)));
559 : }
560 288 : else if (strcmp(defel->defname, "force_not_null") == 0)
561 : {
562 76 : if (opts_out->force_notnull || opts_out->force_notnull_all)
563 12 : errorConflictingDefElem(defel, pstate);
564 64 : if (defel->arg && IsA(defel->arg, A_Star))
565 18 : opts_out->force_notnull_all = true;
566 46 : else if (defel->arg && IsA(defel->arg, List))
567 46 : opts_out->force_notnull = castNode(List, defel->arg);
568 : else
569 0 : ereport(ERROR,
570 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
571 : errmsg("argument to option \"%s\" must be a list of column names",
572 : defel->defname),
573 : parser_errposition(pstate, defel->location)));
574 : }
575 212 : else if (strcmp(defel->defname, "force_null") == 0)
576 : {
577 76 : if (opts_out->force_null || opts_out->force_null_all)
578 12 : errorConflictingDefElem(defel, pstate);
579 64 : if (defel->arg && IsA(defel->arg, A_Star))
580 18 : opts_out->force_null_all = true;
581 46 : else if (defel->arg && IsA(defel->arg, List))
582 46 : opts_out->force_null = castNode(List, defel->arg);
583 : else
584 0 : ereport(ERROR,
585 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
586 : errmsg("argument to option \"%s\" must be a list of column names",
587 : defel->defname),
588 : parser_errposition(pstate, defel->location)));
589 : }
590 136 : else if (strcmp(defel->defname, "convert_selectively") == 0)
591 : {
592 : /*
593 : * Undocumented, not-accessible-from-SQL option: convert only the
594 : * named columns to binary form, storing the rest as NULLs. It's
595 : * allowed for the column list to be NIL.
596 : */
597 16 : if (opts_out->convert_selectively)
598 6 : errorConflictingDefElem(defel, pstate);
599 10 : opts_out->convert_selectively = true;
600 10 : if (defel->arg == NULL || IsA(defel->arg, List))
601 10 : opts_out->convert_select = castNode(List, defel->arg);
602 : else
603 0 : ereport(ERROR,
604 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
605 : errmsg("argument to option \"%s\" must be a list of column names",
606 : defel->defname),
607 : parser_errposition(pstate, defel->location)));
608 : }
609 120 : else if (strcmp(defel->defname, "encoding") == 0)
610 : {
611 24 : if (opts_out->file_encoding >= 0)
612 6 : errorConflictingDefElem(defel, pstate);
613 18 : opts_out->file_encoding = pg_char_to_encoding(defGetString(defel));
614 18 : if (opts_out->file_encoding < 0)
615 0 : ereport(ERROR,
616 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
617 : errmsg("argument to option \"%s\" must be a valid encoding name",
618 : defel->defname),
619 : parser_errposition(pstate, defel->location)));
620 : }
621 96 : else if (strcmp(defel->defname, "on_error") == 0)
622 : {
623 66 : if (on_error_specified)
624 6 : errorConflictingDefElem(defel, pstate);
625 60 : on_error_specified = true;
626 60 : opts_out->on_error = defGetCopyOnErrorChoice(defel, pstate, is_from);
627 : }
628 30 : else if (strcmp(defel->defname, "log_verbosity") == 0)
629 : {
630 30 : if (log_verbosity_specified)
631 6 : errorConflictingDefElem(defel, pstate);
632 24 : log_verbosity_specified = true;
633 24 : opts_out->log_verbosity = defGetCopyLogVerbosityChoice(defel, pstate);
634 : }
635 : else
636 0 : ereport(ERROR,
637 : (errcode(ERRCODE_SYNTAX_ERROR),
638 : errmsg("option \"%s\" not recognized",
639 : defel->defname),
640 : parser_errposition(pstate, defel->location)));
641 : }
642 :
643 : /*
644 : * Check for incompatible options (must do these two before inserting
645 : * defaults)
646 : */
647 9614 : if (opts_out->binary && opts_out->delim)
648 6 : ereport(ERROR,
649 : (errcode(ERRCODE_SYNTAX_ERROR),
650 : errmsg("cannot specify DELIMITER in BINARY mode")));
651 :
652 9608 : if (opts_out->binary && opts_out->null_print)
653 6 : ereport(ERROR,
654 : (errcode(ERRCODE_SYNTAX_ERROR),
655 : errmsg("cannot specify NULL in BINARY mode")));
656 :
657 9602 : if (opts_out->binary && opts_out->default_print)
658 6 : ereport(ERROR,
659 : (errcode(ERRCODE_SYNTAX_ERROR),
660 : errmsg("cannot specify DEFAULT in BINARY mode")));
661 :
662 9596 : if (opts_out->binary && opts_out->on_error != COPY_ON_ERROR_STOP)
663 6 : ereport(ERROR,
664 : (errcode(ERRCODE_SYNTAX_ERROR),
665 : errmsg("only ON_ERROR STOP is allowed in BINARY mode")));
666 :
667 : /* Set defaults for omitted options */
668 9590 : if (!opts_out->delim)
669 9342 : opts_out->delim = opts_out->csv_mode ? "," : "\t";
670 :
671 9590 : if (!opts_out->null_print)
672 9482 : opts_out->null_print = opts_out->csv_mode ? "" : "\\N";
673 9590 : opts_out->null_print_len = strlen(opts_out->null_print);
674 :
675 9590 : if (opts_out->csv_mode)
676 : {
677 376 : if (!opts_out->quote)
678 308 : opts_out->quote = "\"";
679 376 : if (!opts_out->escape)
680 318 : opts_out->escape = opts_out->quote;
681 : }
682 :
683 : /* Only single-byte delimiter strings are supported. */
684 9590 : if (strlen(opts_out->delim) != 1)
685 2 : ereport(ERROR,
686 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
687 : errmsg("COPY delimiter must be a single one-byte character")));
688 :
689 : /* Disallow end-of-line characters */
690 9588 : if (strchr(opts_out->delim, '\r') != NULL ||
691 9588 : strchr(opts_out->delim, '\n') != NULL)
692 2 : ereport(ERROR,
693 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
694 : errmsg("COPY delimiter cannot be newline or carriage return")));
695 :
696 9586 : if (strchr(opts_out->null_print, '\r') != NULL ||
697 9586 : strchr(opts_out->null_print, '\n') != NULL)
698 2 : ereport(ERROR,
699 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
700 : errmsg("COPY null representation cannot use newline or carriage return")));
701 :
702 9584 : if (opts_out->default_print)
703 : {
704 84 : opts_out->default_print_len = strlen(opts_out->default_print);
705 :
706 84 : if (strchr(opts_out->default_print, '\r') != NULL ||
707 78 : strchr(opts_out->default_print, '\n') != NULL)
708 12 : ereport(ERROR,
709 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
710 : errmsg("COPY default representation cannot use newline or carriage return")));
711 : }
712 :
713 : /*
714 : * Disallow unsafe delimiter characters in non-CSV mode. We can't allow
715 : * backslash because it would be ambiguous. We can't allow the other
716 : * cases because data characters matching the delimiter must be
717 : * backslashed, and certain backslash combinations are interpreted
718 : * non-literally by COPY IN. Disallowing all lower case ASCII letters is
719 : * more than strictly necessary, but seems best for consistency and
720 : * future-proofing. Likewise we disallow all digits though only octal
721 : * digits are actually dangerous.
722 : */
723 9572 : if (!opts_out->csv_mode &&
724 9202 : strchr("\\.abcdefghijklmnopqrstuvwxyz0123456789",
725 9202 : opts_out->delim[0]) != NULL)
726 10 : ereport(ERROR,
727 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
728 : errmsg("COPY delimiter cannot be \"%s\"", opts_out->delim)));
729 :
730 : /* Check header */
731 9562 : if (opts_out->binary && opts_out->header_line)
732 2 : ereport(ERROR,
733 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
734 : errmsg("cannot specify HEADER in BINARY mode")));
735 :
736 : /* Check quote */
737 9560 : if (!opts_out->csv_mode && opts_out->quote != NULL)
738 4 : ereport(ERROR,
739 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
740 : errmsg("COPY QUOTE requires CSV mode")));
741 :
742 9556 : if (opts_out->csv_mode && strlen(opts_out->quote) != 1)
743 2 : ereport(ERROR,
744 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
745 : errmsg("COPY quote must be a single one-byte character")));
746 :
747 9554 : if (opts_out->csv_mode && opts_out->delim[0] == opts_out->quote[0])
748 2 : ereport(ERROR,
749 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
750 : errmsg("COPY delimiter and quote must be different")));
751 :
752 : /* Check escape */
753 9552 : if (!opts_out->csv_mode && opts_out->escape != NULL)
754 6 : ereport(ERROR,
755 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
756 : errmsg("COPY ESCAPE requires CSV mode")));
757 :
758 9546 : if (opts_out->csv_mode && strlen(opts_out->escape) != 1)
759 2 : ereport(ERROR,
760 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
761 : errmsg("COPY escape must be a single one-byte character")));
762 :
763 : /* Check force_quote */
764 9544 : if (!opts_out->csv_mode && (opts_out->force_quote || opts_out->force_quote_all))
765 6 : ereport(ERROR,
766 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
767 : errmsg("COPY FORCE_QUOTE requires CSV mode")));
768 9538 : if ((opts_out->force_quote || opts_out->force_quote_all) && is_from)
769 6 : ereport(ERROR,
770 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
771 : errmsg("COPY FORCE_QUOTE cannot be used with COPY FROM")));
772 :
773 : /* Check force_notnull */
774 9532 : if (!opts_out->csv_mode && opts_out->force_notnull != NIL)
775 8 : ereport(ERROR,
776 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
777 : errmsg("COPY FORCE_NOT_NULL requires CSV mode")));
778 9524 : if (opts_out->force_notnull != NIL && !is_from)
779 6 : ereport(ERROR,
780 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
781 : errmsg("COPY FORCE_NOT_NULL cannot be used with COPY TO")));
782 :
783 : /* Check force_null */
784 9518 : if (!opts_out->csv_mode && opts_out->force_null != NIL)
785 6 : ereport(ERROR,
786 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
787 : errmsg("COPY FORCE_NULL requires CSV mode")));
788 :
789 9512 : if (opts_out->force_null != NIL && !is_from)
790 6 : ereport(ERROR,
791 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
792 : errmsg("COPY FORCE_NULL cannot be used with COPY TO")));
793 :
794 : /* Don't allow the delimiter to appear in the null string. */
795 9506 : if (strchr(opts_out->null_print, opts_out->delim[0]) != NULL)
796 2 : ereport(ERROR,
797 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
798 : errmsg("COPY delimiter character must not appear in the NULL specification")));
799 :
800 : /* Don't allow the CSV quote char to appear in the null string. */
801 9504 : if (opts_out->csv_mode &&
802 344 : strchr(opts_out->null_print, opts_out->quote[0]) != NULL)
803 2 : ereport(ERROR,
804 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
805 : errmsg("CSV quote character must not appear in the NULL specification")));
806 :
807 : /* Check freeze */
808 9502 : if (opts_out->freeze && !is_from)
809 0 : ereport(ERROR,
810 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
811 : errmsg("COPY FREEZE cannot be used with COPY TO")));
812 :
813 9502 : if (opts_out->default_print)
814 : {
815 72 : if (!is_from)
816 6 : ereport(ERROR,
817 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
818 : errmsg("COPY DEFAULT only available using COPY FROM")));
819 :
820 : /* Don't allow the delimiter to appear in the default string. */
821 66 : if (strchr(opts_out->default_print, opts_out->delim[0]) != NULL)
822 6 : ereport(ERROR,
823 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
824 : errmsg("COPY delimiter must not appear in the DEFAULT specification")));
825 :
826 : /* Don't allow the CSV quote char to appear in the default string. */
827 60 : if (opts_out->csv_mode &&
828 30 : strchr(opts_out->default_print, opts_out->quote[0]) != NULL)
829 6 : ereport(ERROR,
830 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
831 : errmsg("CSV quote character must not appear in the DEFAULT specification")));
832 :
833 : /* Don't allow the NULL and DEFAULT string to be the same */
834 54 : if (opts_out->null_print_len == opts_out->default_print_len &&
835 24 : strncmp(opts_out->null_print, opts_out->default_print,
836 24 : opts_out->null_print_len) == 0)
837 6 : ereport(ERROR,
838 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
839 : errmsg("NULL specification and DEFAULT specification cannot be the same")));
840 : }
841 9478 : }
842 :
843 : /*
844 : * CopyGetAttnums - build an integer list of attnums to be copied
845 : *
846 : * The input attnamelist is either the user-specified column list,
847 : * or NIL if there was none (in which case we want all the non-dropped
848 : * columns).
849 : *
850 : * We don't include generated columns in the generated full list and we don't
851 : * allow them to be specified explicitly. They don't make sense for COPY
852 : * FROM, but we could possibly allow them for COPY TO. But this way it's at
853 : * least ensured that whatever we copy out can be copied back in.
854 : *
855 : * rel can be NULL ... it's only used for error reports.
856 : */
857 : List *
858 18424 : CopyGetAttnums(TupleDesc tupDesc, Relation rel, List *attnamelist)
859 : {
860 18424 : List *attnums = NIL;
861 :
862 18424 : if (attnamelist == NIL)
863 : {
864 : /* Generate default column list */
865 3300 : int attr_count = tupDesc->natts;
866 : int i;
867 :
868 11318 : for (i = 0; i < attr_count; i++)
869 : {
870 8018 : if (TupleDescAttr(tupDesc, i)->attisdropped)
871 196 : continue;
872 7822 : if (TupleDescAttr(tupDesc, i)->attgenerated)
873 54 : continue;
874 7768 : attnums = lappend_int(attnums, i + 1);
875 : }
876 : }
877 : else
878 : {
879 : /* Validate the user-supplied list and extract attnums */
880 : ListCell *l;
881 :
882 70444 : foreach(l, attnamelist)
883 : {
884 55380 : char *name = strVal(lfirst(l));
885 : int attnum;
886 : int i;
887 :
888 : /* Lookup column name */
889 55380 : attnum = InvalidAttrNumber;
890 9874338 : for (i = 0; i < tupDesc->natts; i++)
891 : {
892 9874308 : Form_pg_attribute att = TupleDescAttr(tupDesc, i);
893 :
894 9874308 : if (att->attisdropped)
895 792 : continue;
896 9873516 : if (namestrcmp(&(att->attname), name) == 0)
897 : {
898 55350 : if (att->attgenerated)
899 24 : ereport(ERROR,
900 : (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
901 : errmsg("column \"%s\" is a generated column",
902 : name),
903 : errdetail("Generated columns cannot be used in COPY.")));
904 55326 : attnum = att->attnum;
905 55326 : break;
906 : }
907 : }
908 55356 : if (attnum == InvalidAttrNumber)
909 : {
910 30 : if (rel != NULL)
911 30 : ereport(ERROR,
912 : (errcode(ERRCODE_UNDEFINED_COLUMN),
913 : errmsg("column \"%s\" of relation \"%s\" does not exist",
914 : name, RelationGetRelationName(rel))));
915 : else
916 0 : ereport(ERROR,
917 : (errcode(ERRCODE_UNDEFINED_COLUMN),
918 : errmsg("column \"%s\" does not exist",
919 : name)));
920 : }
921 : /* Check for duplicates */
922 55326 : if (list_member_int(attnums, attnum))
923 6 : ereport(ERROR,
924 : (errcode(ERRCODE_DUPLICATE_COLUMN),
925 : errmsg("column \"%s\" specified more than once",
926 : name)));
927 55320 : attnums = lappend_int(attnums, attnum);
928 : }
929 : }
930 :
931 18364 : return attnums;
932 : }
|