Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * copy.c
4 : * Implements the COPY utility command
5 : *
6 : * Portions Copyright (c) 1996-2023, 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 "rewrite/rewriteHandler.h"
37 : #include "utils/acl.h"
38 : #include "utils/builtins.h"
39 : #include "utils/lsyscache.h"
40 : #include "utils/memutils.h"
41 : #include "utils/rel.h"
42 : #include "utils/rls.h"
43 :
44 : /*
45 : * DoCopy executes the SQL COPY statement
46 : *
47 : * Either unload or reload contents of table <relation>, depending on <from>.
48 : * (<from> = true means we are inserting into the table.) In the "TO" case
49 : * we also support copying the output of an arbitrary SELECT, INSERT, UPDATE
50 : * or DELETE query.
51 : *
52 : * If <pipe> is false, transfer is between the table and the file named
53 : * <filename>. Otherwise, transfer is between the table and our regular
54 : * input/output stream. The latter could be either stdin/stdout or a
55 : * socket, depending on whether we're running under Postmaster control.
56 : *
57 : * Do not allow a Postgres user without the 'pg_read_server_files' or
58 : * 'pg_write_server_files' role to read from or write to a file.
59 : *
60 : * Do not allow the copy if user doesn't have proper permission to access
61 : * the table or the specifically requested columns.
62 : */
63 : void
64 8890 : DoCopy(ParseState *pstate, const CopyStmt *stmt,
65 : int stmt_location, int stmt_len,
66 : uint64 *processed)
67 : {
68 8890 : bool is_from = stmt->is_from;
69 8890 : bool pipe = (stmt->filename == NULL);
70 : Relation rel;
71 : Oid relid;
72 8890 : RawStmt *query = NULL;
73 8890 : Node *whereClause = NULL;
74 :
75 : /*
76 : * Disallow COPY to/from file or program except to users with the
77 : * appropriate role.
78 : */
79 8890 : if (!pipe)
80 : {
81 892 : if (stmt->is_program)
82 : {
83 0 : if (!has_privs_of_role(GetUserId(), ROLE_PG_EXECUTE_SERVER_PROGRAM))
84 0 : ereport(ERROR,
85 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
86 : errmsg("permission denied to COPY to or from an external program"),
87 : errdetail("Only roles with privileges of the \"%s\" role may COPY to or from an external program.",
88 : "pg_execute_server_program"),
89 : errhint("Anyone can COPY to stdout or from stdin. "
90 : "psql's \\copy command also works for anyone.")));
91 : }
92 : else
93 : {
94 892 : if (is_from && !has_privs_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES))
95 0 : ereport(ERROR,
96 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
97 : errmsg("permission denied to COPY from a file"),
98 : errdetail("Only roles with privileges of the \"%s\" role may COPY from a file.",
99 : "pg_read_server_files"),
100 : errhint("Anyone can COPY to stdout or from stdin. "
101 : "psql's \\copy command also works for anyone.")));
102 :
103 892 : if (!is_from && !has_privs_of_role(GetUserId(), ROLE_PG_WRITE_SERVER_FILES))
104 0 : ereport(ERROR,
105 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
106 : errmsg("permission denied to COPY to a file"),
107 : errdetail("Only roles with privileges of the \"%s\" role may COPY to a file.",
108 : "pg_write_server_files"),
109 : errhint("Anyone can COPY to stdout or from stdin. "
110 : "psql's \\copy command also works for anyone.")));
111 : }
112 : }
113 :
114 8890 : if (stmt->relation)
115 : {
116 8504 : LOCKMODE lockmode = is_from ? RowExclusiveLock : AccessShareLock;
117 : ParseNamespaceItem *nsitem;
118 : RTEPermissionInfo *perminfo;
119 : TupleDesc tupDesc;
120 : List *attnums;
121 : ListCell *cur;
122 :
123 : Assert(!stmt->query);
124 :
125 : /* Open and lock the relation, using the appropriate lock type. */
126 8504 : rel = table_openrv(stmt->relation, lockmode);
127 :
128 8502 : relid = RelationGetRelid(rel);
129 :
130 8502 : nsitem = addRangeTableEntryForRelation(pstate, rel, lockmode,
131 : NULL, false, false);
132 :
133 8502 : perminfo = nsitem->p_perminfo;
134 8502 : perminfo->requiredPerms = (is_from ? ACL_INSERT : ACL_SELECT);
135 :
136 8502 : if (stmt->whereClause)
137 : {
138 : /* add nsitem to query namespace */
139 48 : addNSItemToQuery(pstate, nsitem, false, true, true);
140 :
141 : /* Transform the raw expression tree */
142 48 : whereClause = transformExpr(pstate, stmt->whereClause, EXPR_KIND_COPY_WHERE);
143 :
144 : /* Make sure it yields a boolean result. */
145 18 : whereClause = coerce_to_boolean(pstate, whereClause, "WHERE");
146 :
147 : /* we have to fix its collations too */
148 18 : assign_expr_collations(pstate, whereClause);
149 :
150 18 : whereClause = eval_const_expressions(NULL, whereClause);
151 :
152 18 : whereClause = (Node *) canonicalize_qual((Expr *) whereClause, false);
153 18 : whereClause = (Node *) make_ands_implicit((Expr *) whereClause);
154 : }
155 :
156 8472 : tupDesc = RelationGetDescr(rel);
157 8472 : attnums = CopyGetAttnums(tupDesc, rel, stmt->attlist);
158 39994 : foreach(cur, attnums)
159 : {
160 : int attno;
161 : Bitmapset **bms;
162 :
163 31582 : attno = lfirst_int(cur) - FirstLowInvalidHeapAttributeNumber;
164 31582 : bms = is_from ? &perminfo->insertedCols : &perminfo->selectedCols;
165 :
166 31582 : *bms = bms_add_member(*bms, attno);
167 : }
168 8412 : ExecCheckPermissions(pstate->p_rtable, list_make1(perminfo), true);
169 :
170 : /*
171 : * Permission check for row security policies.
172 : *
173 : * check_enable_rls will ereport(ERROR) if the user has requested
174 : * something invalid and will otherwise indicate if we should enable
175 : * RLS (returns RLS_ENABLED) or not for this COPY statement.
176 : *
177 : * If the relation has a row security policy and we are to apply it
178 : * then perform a "query" copy and allow the normal query processing
179 : * to handle the policies.
180 : *
181 : * If RLS is not enabled for this, then just fall through to the
182 : * normal non-filtering relation handling.
183 : */
184 8328 : if (check_enable_rls(relid, InvalidOid, false) == RLS_ENABLED)
185 : {
186 : SelectStmt *select;
187 : ColumnRef *cr;
188 : ResTarget *target;
189 : RangeVar *from;
190 60 : List *targetList = NIL;
191 :
192 60 : if (is_from)
193 6 : ereport(ERROR,
194 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
195 : errmsg("COPY FROM not supported with row-level security"),
196 : errhint("Use INSERT statements instead.")));
197 :
198 : /*
199 : * Build target list
200 : *
201 : * If no columns are specified in the attribute list of the COPY
202 : * command, then the target list is 'all' columns. Therefore, '*'
203 : * should be used as the target list for the resulting SELECT
204 : * statement.
205 : *
206 : * In the case that columns are specified in the attribute list,
207 : * create a ColumnRef and ResTarget for each column and add them
208 : * to the target list for the resulting SELECT statement.
209 : */
210 54 : if (!stmt->attlist)
211 : {
212 18 : cr = makeNode(ColumnRef);
213 18 : cr->fields = list_make1(makeNode(A_Star));
214 18 : cr->location = -1;
215 :
216 18 : target = makeNode(ResTarget);
217 18 : target->name = NULL;
218 18 : target->indirection = NIL;
219 18 : target->val = (Node *) cr;
220 18 : target->location = -1;
221 :
222 18 : targetList = list_make1(target);
223 : }
224 : else
225 : {
226 : ListCell *lc;
227 :
228 102 : foreach(lc, stmt->attlist)
229 : {
230 : /*
231 : * Build the ColumnRef for each column. The ColumnRef
232 : * 'fields' property is a String node that corresponds to
233 : * the column name respectively.
234 : */
235 66 : cr = makeNode(ColumnRef);
236 66 : cr->fields = list_make1(lfirst(lc));
237 66 : cr->location = -1;
238 :
239 : /* Build the ResTarget and add the ColumnRef to it. */
240 66 : target = makeNode(ResTarget);
241 66 : target->name = NULL;
242 66 : target->indirection = NIL;
243 66 : target->val = (Node *) cr;
244 66 : target->location = -1;
245 :
246 : /* Add each column to the SELECT statement's target list */
247 66 : targetList = lappend(targetList, target);
248 : }
249 : }
250 :
251 : /*
252 : * Build RangeVar for from clause, fully qualified based on the
253 : * relation which we have opened and locked. Use "ONLY" so that
254 : * COPY retrieves rows from only the target table not any
255 : * inheritance children, the same as when RLS doesn't apply.
256 : */
257 54 : from = makeRangeVar(get_namespace_name(RelationGetNamespace(rel)),
258 54 : pstrdup(RelationGetRelationName(rel)),
259 : -1);
260 54 : from->inh = false; /* apply ONLY */
261 :
262 : /* Build query */
263 54 : select = makeNode(SelectStmt);
264 54 : select->targetList = targetList;
265 54 : select->fromClause = list_make1(from);
266 :
267 54 : query = makeNode(RawStmt);
268 54 : query->stmt = (Node *) select;
269 54 : query->stmt_location = stmt_location;
270 54 : query->stmt_len = stmt_len;
271 :
272 : /*
273 : * Close the relation for now, but keep the lock on it to prevent
274 : * changes between now and when we start the query-based COPY.
275 : *
276 : * We'll reopen it later as part of the query-based COPY.
277 : */
278 54 : table_close(rel, NoLock);
279 54 : rel = NULL;
280 : }
281 : }
282 : else
283 : {
284 : Assert(stmt->query);
285 :
286 : /* MERGE is allowed by parser, but unimplemented. Reject for now */
287 386 : if (IsA(stmt->query, MergeStmt))
288 6 : ereport(ERROR,
289 : errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
290 : errmsg("MERGE not supported in COPY"));
291 :
292 380 : query = makeNode(RawStmt);
293 380 : query->stmt = stmt->query;
294 380 : query->stmt_location = stmt_location;
295 380 : query->stmt_len = stmt_len;
296 :
297 380 : relid = InvalidOid;
298 380 : rel = NULL;
299 : }
300 :
301 8684 : if (is_from)
302 : {
303 : CopyFromState cstate;
304 :
305 : Assert(rel);
306 :
307 : /* check read-only transaction and parallel mode */
308 1800 : if (XactReadOnly && !rel->rd_islocaltemp)
309 0 : PreventCommandIfReadOnly("COPY FROM");
310 :
311 1800 : cstate = BeginCopyFrom(pstate, rel, whereClause,
312 1800 : stmt->filename, stmt->is_program,
313 : NULL, stmt->attlist, stmt->options);
314 1668 : *processed = CopyFrom(cstate); /* copy from file to database */
315 1498 : EndCopyFrom(cstate);
316 : }
317 : else
318 : {
319 : CopyToState cstate;
320 :
321 6884 : cstate = BeginCopyTo(pstate, rel, query, relid,
322 6884 : stmt->filename, stmt->is_program,
323 : NULL, stmt->attlist, stmt->options);
324 6696 : *processed = DoCopyTo(cstate); /* copy from database to file */
325 6694 : EndCopyTo(cstate);
326 : }
327 :
328 8192 : if (rel != NULL)
329 7886 : table_close(rel, NoLock);
330 8192 : }
331 :
332 : /*
333 : * Extract a CopyHeaderChoice value from a DefElem. This is like
334 : * defGetBoolean() but also accepts the special value "match".
335 : */
336 : static CopyHeaderChoice
337 156 : defGetCopyHeaderChoice(DefElem *def, bool is_from)
338 : {
339 : /*
340 : * If no parameter value given, assume "true" is meant.
341 : */
342 156 : if (def->arg == NULL)
343 12 : return COPY_HEADER_TRUE;
344 :
345 : /*
346 : * Allow 0, 1, "true", "false", "on", "off", or "match".
347 : */
348 144 : switch (nodeTag(def->arg))
349 : {
350 0 : case T_Integer:
351 0 : switch (intVal(def->arg))
352 : {
353 0 : case 0:
354 0 : return COPY_HEADER_FALSE;
355 0 : case 1:
356 0 : return COPY_HEADER_TRUE;
357 0 : default:
358 : /* otherwise, error out below */
359 0 : break;
360 : }
361 0 : break;
362 144 : default:
363 : {
364 144 : char *sval = defGetString(def);
365 :
366 : /*
367 : * The set of strings accepted here should match up with the
368 : * grammar's opt_boolean_or_string production.
369 : */
370 144 : if (pg_strcasecmp(sval, "true") == 0)
371 46 : return COPY_HEADER_TRUE;
372 98 : if (pg_strcasecmp(sval, "false") == 0)
373 0 : return COPY_HEADER_FALSE;
374 98 : if (pg_strcasecmp(sval, "on") == 0)
375 0 : return COPY_HEADER_TRUE;
376 98 : if (pg_strcasecmp(sval, "off") == 0)
377 6 : return COPY_HEADER_FALSE;
378 92 : if (pg_strcasecmp(sval, "match") == 0)
379 : {
380 86 : if (!is_from)
381 6 : ereport(ERROR,
382 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
383 : errmsg("cannot use \"%s\" with HEADER in COPY TO",
384 : sval)));
385 80 : return COPY_HEADER_MATCH;
386 : }
387 : }
388 6 : break;
389 : }
390 6 : ereport(ERROR,
391 : (errcode(ERRCODE_SYNTAX_ERROR),
392 : errmsg("%s requires a Boolean value or \"match\"",
393 : def->defname)));
394 : return COPY_HEADER_FALSE; /* keep compiler quiet */
395 : }
396 :
397 : /*
398 : * Process the statement option list for COPY.
399 : *
400 : * Scan the options list (a list of DefElem) and transpose the information
401 : * into *opts_out, applying appropriate error checking.
402 : *
403 : * If 'opts_out' is not NULL, it is assumed to be filled with zeroes initially.
404 : *
405 : * This is exported so that external users of the COPY API can sanity-check
406 : * a list of options. In that usage, 'opts_out' can be passed as NULL and
407 : * the collected data is just leaked until CurrentMemoryContext is reset.
408 : *
409 : * Note that additional checking, such as whether column names listed in FORCE
410 : * QUOTE actually exist, has to be applied later. This just checks for
411 : * self-consistency of the options list.
412 : */
413 : void
414 9134 : ProcessCopyOptions(ParseState *pstate,
415 : CopyFormatOptions *opts_out,
416 : bool is_from,
417 : List *options)
418 : {
419 9134 : bool format_specified = false;
420 9134 : bool freeze_specified = false;
421 9134 : bool header_specified = false;
422 : ListCell *option;
423 :
424 : /* Support external use for option sanity checking */
425 9134 : if (opts_out == NULL)
426 86 : opts_out = (CopyFormatOptions *) palloc0(sizeof(CopyFormatOptions));
427 :
428 9134 : opts_out->file_encoding = -1;
429 :
430 : /* Extract options from the statement node tree */
431 10612 : foreach(option, options)
432 : {
433 1564 : DefElem *defel = lfirst_node(DefElem, option);
434 :
435 1564 : if (strcmp(defel->defname, "format") == 0)
436 : {
437 486 : char *fmt = defGetString(defel);
438 :
439 486 : if (format_specified)
440 6 : errorConflictingDefElem(defel, pstate);
441 480 : format_specified = true;
442 480 : if (strcmp(fmt, "text") == 0)
443 : /* default format */ ;
444 422 : else if (strcmp(fmt, "csv") == 0)
445 364 : opts_out->csv_mode = true;
446 58 : else if (strcmp(fmt, "binary") == 0)
447 56 : opts_out->binary = true;
448 : else
449 2 : ereport(ERROR,
450 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
451 : errmsg("COPY format \"%s\" not recognized", fmt),
452 : parser_errposition(pstate, defel->location)));
453 : }
454 1078 : else if (strcmp(defel->defname, "freeze") == 0)
455 : {
456 70 : if (freeze_specified)
457 6 : errorConflictingDefElem(defel, pstate);
458 64 : freeze_specified = true;
459 64 : opts_out->freeze = defGetBoolean(defel);
460 : }
461 1008 : else if (strcmp(defel->defname, "delimiter") == 0)
462 : {
463 266 : if (opts_out->delim)
464 6 : errorConflictingDefElem(defel, pstate);
465 260 : opts_out->delim = defGetString(defel);
466 : }
467 742 : else if (strcmp(defel->defname, "null") == 0)
468 : {
469 126 : if (opts_out->null_print)
470 6 : errorConflictingDefElem(defel, pstate);
471 120 : opts_out->null_print = defGetString(defel);
472 : }
473 616 : else if (strcmp(defel->defname, "default") == 0)
474 : {
475 84 : if (opts_out->default_print)
476 0 : errorConflictingDefElem(defel, pstate);
477 84 : opts_out->default_print = defGetString(defel);
478 : }
479 532 : else if (strcmp(defel->defname, "header") == 0)
480 : {
481 162 : if (header_specified)
482 6 : errorConflictingDefElem(defel, pstate);
483 156 : header_specified = true;
484 156 : opts_out->header_line = defGetCopyHeaderChoice(defel, is_from);
485 : }
486 370 : else if (strcmp(defel->defname, "quote") == 0)
487 : {
488 84 : if (opts_out->quote)
489 6 : errorConflictingDefElem(defel, pstate);
490 78 : opts_out->quote = defGetString(defel);
491 : }
492 286 : else if (strcmp(defel->defname, "escape") == 0)
493 : {
494 76 : if (opts_out->escape)
495 6 : errorConflictingDefElem(defel, pstate);
496 70 : opts_out->escape = defGetString(defel);
497 : }
498 210 : else if (strcmp(defel->defname, "force_quote") == 0)
499 : {
500 66 : if (opts_out->force_quote || opts_out->force_quote_all)
501 6 : errorConflictingDefElem(defel, pstate);
502 60 : if (defel->arg && IsA(defel->arg, A_Star))
503 18 : opts_out->force_quote_all = true;
504 42 : else if (defel->arg && IsA(defel->arg, List))
505 42 : opts_out->force_quote = castNode(List, defel->arg);
506 : else
507 0 : ereport(ERROR,
508 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
509 : errmsg("argument to option \"%s\" must be a list of column names",
510 : defel->defname),
511 : parser_errposition(pstate, defel->location)));
512 : }
513 144 : else if (strcmp(defel->defname, "force_not_null") == 0)
514 : {
515 52 : if (opts_out->force_notnull)
516 6 : errorConflictingDefElem(defel, pstate);
517 46 : if (defel->arg && IsA(defel->arg, List))
518 46 : opts_out->force_notnull = castNode(List, defel->arg);
519 : else
520 0 : ereport(ERROR,
521 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
522 : errmsg("argument to option \"%s\" must be a list of column names",
523 : defel->defname),
524 : parser_errposition(pstate, defel->location)));
525 : }
526 92 : else if (strcmp(defel->defname, "force_null") == 0)
527 : {
528 52 : if (opts_out->force_null)
529 6 : errorConflictingDefElem(defel, pstate);
530 46 : if (defel->arg && IsA(defel->arg, List))
531 46 : opts_out->force_null = castNode(List, defel->arg);
532 : else
533 0 : ereport(ERROR,
534 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
535 : errmsg("argument to option \"%s\" must be a list of column names",
536 : defel->defname),
537 : parser_errposition(pstate, defel->location)));
538 : }
539 40 : else if (strcmp(defel->defname, "convert_selectively") == 0)
540 : {
541 : /*
542 : * Undocumented, not-accessible-from-SQL option: convert only the
543 : * named columns to binary form, storing the rest as NULLs. It's
544 : * allowed for the column list to be NIL.
545 : */
546 16 : if (opts_out->convert_selectively)
547 6 : errorConflictingDefElem(defel, pstate);
548 10 : opts_out->convert_selectively = true;
549 10 : if (defel->arg == NULL || IsA(defel->arg, List))
550 10 : opts_out->convert_select = castNode(List, defel->arg);
551 : else
552 0 : ereport(ERROR,
553 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
554 : errmsg("argument to option \"%s\" must be a list of column names",
555 : defel->defname),
556 : parser_errposition(pstate, defel->location)));
557 : }
558 24 : else if (strcmp(defel->defname, "encoding") == 0)
559 : {
560 24 : if (opts_out->file_encoding >= 0)
561 6 : errorConflictingDefElem(defel, pstate);
562 18 : opts_out->file_encoding = pg_char_to_encoding(defGetString(defel));
563 18 : if (opts_out->file_encoding < 0)
564 0 : ereport(ERROR,
565 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
566 : errmsg("argument to option \"%s\" must be a valid encoding name",
567 : defel->defname),
568 : parser_errposition(pstate, defel->location)));
569 : }
570 : else
571 0 : ereport(ERROR,
572 : (errcode(ERRCODE_SYNTAX_ERROR),
573 : errmsg("option \"%s\" not recognized",
574 : defel->defname),
575 : parser_errposition(pstate, defel->location)));
576 : }
577 :
578 : /*
579 : * Check for incompatible options (must do these two before inserting
580 : * defaults)
581 : */
582 9048 : if (opts_out->binary && opts_out->delim)
583 6 : ereport(ERROR,
584 : (errcode(ERRCODE_SYNTAX_ERROR),
585 : errmsg("cannot specify DELIMITER in BINARY mode")));
586 :
587 9042 : if (opts_out->binary && opts_out->null_print)
588 6 : ereport(ERROR,
589 : (errcode(ERRCODE_SYNTAX_ERROR),
590 : errmsg("cannot specify NULL in BINARY mode")));
591 :
592 9036 : if (opts_out->binary && opts_out->default_print)
593 6 : ereport(ERROR,
594 : (errcode(ERRCODE_SYNTAX_ERROR),
595 : errmsg("cannot specify DEFAULT in BINARY mode")));
596 :
597 : /* Set defaults for omitted options */
598 9030 : if (!opts_out->delim)
599 8782 : opts_out->delim = opts_out->csv_mode ? "," : "\t";
600 :
601 9030 : if (!opts_out->null_print)
602 8922 : opts_out->null_print = opts_out->csv_mode ? "" : "\\N";
603 9030 : opts_out->null_print_len = strlen(opts_out->null_print);
604 :
605 9030 : if (opts_out->csv_mode)
606 : {
607 358 : if (!opts_out->quote)
608 290 : opts_out->quote = "\"";
609 358 : if (!opts_out->escape)
610 300 : opts_out->escape = opts_out->quote;
611 : }
612 :
613 : /* Only single-byte delimiter strings are supported. */
614 9030 : if (strlen(opts_out->delim) != 1)
615 2 : ereport(ERROR,
616 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
617 : errmsg("COPY delimiter must be a single one-byte character")));
618 :
619 : /* Disallow end-of-line characters */
620 9028 : if (strchr(opts_out->delim, '\r') != NULL ||
621 9028 : strchr(opts_out->delim, '\n') != NULL)
622 2 : ereport(ERROR,
623 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
624 : errmsg("COPY delimiter cannot be newline or carriage return")));
625 :
626 9026 : if (strchr(opts_out->null_print, '\r') != NULL ||
627 9026 : strchr(opts_out->null_print, '\n') != NULL)
628 2 : ereport(ERROR,
629 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
630 : errmsg("COPY null representation cannot use newline or carriage return")));
631 :
632 9024 : if (opts_out->default_print)
633 : {
634 78 : opts_out->default_print_len = strlen(opts_out->default_print);
635 :
636 78 : if (strchr(opts_out->default_print, '\r') != NULL ||
637 72 : strchr(opts_out->default_print, '\n') != NULL)
638 12 : ereport(ERROR,
639 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
640 : errmsg("COPY default representation cannot use newline or carriage return")));
641 : }
642 :
643 : /*
644 : * Disallow unsafe delimiter characters in non-CSV mode. We can't allow
645 : * backslash because it would be ambiguous. We can't allow the other
646 : * cases because data characters matching the delimiter must be
647 : * backslashed, and certain backslash combinations are interpreted
648 : * non-literally by COPY IN. Disallowing all lower case ASCII letters is
649 : * more than strictly necessary, but seems best for consistency and
650 : * future-proofing. Likewise we disallow all digits though only octal
651 : * digits are actually dangerous.
652 : */
653 9012 : if (!opts_out->csv_mode &&
654 8660 : strchr("\\.abcdefghijklmnopqrstuvwxyz0123456789",
655 8660 : opts_out->delim[0]) != NULL)
656 10 : ereport(ERROR,
657 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
658 : errmsg("COPY delimiter cannot be \"%s\"", opts_out->delim)));
659 :
660 : /* Check header */
661 9002 : if (opts_out->binary && opts_out->header_line)
662 2 : ereport(ERROR,
663 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
664 : errmsg("cannot specify HEADER in BINARY mode")));
665 :
666 : /* Check quote */
667 9000 : if (!opts_out->csv_mode && opts_out->quote != NULL)
668 4 : ereport(ERROR,
669 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
670 : errmsg("COPY quote available only in CSV mode")));
671 :
672 8996 : if (opts_out->csv_mode && strlen(opts_out->quote) != 1)
673 2 : ereport(ERROR,
674 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
675 : errmsg("COPY quote must be a single one-byte character")));
676 :
677 8994 : if (opts_out->csv_mode && opts_out->delim[0] == opts_out->quote[0])
678 2 : ereport(ERROR,
679 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
680 : errmsg("COPY delimiter and quote must be different")));
681 :
682 : /* Check escape */
683 8992 : if (!opts_out->csv_mode && opts_out->escape != NULL)
684 6 : ereport(ERROR,
685 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
686 : errmsg("COPY escape available only in CSV mode")));
687 :
688 8986 : if (opts_out->csv_mode && strlen(opts_out->escape) != 1)
689 2 : ereport(ERROR,
690 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
691 : errmsg("COPY escape must be a single one-byte character")));
692 :
693 : /* Check force_quote */
694 8984 : if (!opts_out->csv_mode && (opts_out->force_quote || opts_out->force_quote_all))
695 6 : ereport(ERROR,
696 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
697 : errmsg("COPY force quote available only in CSV mode")));
698 8978 : if ((opts_out->force_quote || opts_out->force_quote_all) && is_from)
699 6 : ereport(ERROR,
700 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
701 : errmsg("COPY force quote only available using COPY TO")));
702 :
703 : /* Check force_notnull */
704 8972 : if (!opts_out->csv_mode && opts_out->force_notnull != NIL)
705 8 : ereport(ERROR,
706 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
707 : errmsg("COPY force not null available only in CSV mode")));
708 8964 : if (opts_out->force_notnull != NIL && !is_from)
709 6 : ereport(ERROR,
710 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
711 : errmsg("COPY force not null only available using COPY FROM")));
712 :
713 : /* Check force_null */
714 8958 : if (!opts_out->csv_mode && opts_out->force_null != NIL)
715 6 : ereport(ERROR,
716 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
717 : errmsg("COPY force null available only in CSV mode")));
718 :
719 8952 : if (opts_out->force_null != NIL && !is_from)
720 6 : ereport(ERROR,
721 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
722 : errmsg("COPY force null only available using COPY FROM")));
723 :
724 : /* Don't allow the delimiter to appear in the null string. */
725 8946 : if (strchr(opts_out->null_print, opts_out->delim[0]) != NULL)
726 2 : ereport(ERROR,
727 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
728 : errmsg("COPY delimiter must not appear in the NULL specification")));
729 :
730 : /* Don't allow the CSV quote char to appear in the null string. */
731 8944 : if (opts_out->csv_mode &&
732 326 : strchr(opts_out->null_print, opts_out->quote[0]) != NULL)
733 2 : ereport(ERROR,
734 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
735 : errmsg("CSV quote character must not appear in the NULL specification")));
736 :
737 8942 : if (opts_out->default_print)
738 : {
739 66 : if (!is_from)
740 6 : ereport(ERROR,
741 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
742 : errmsg("COPY DEFAULT only available using COPY FROM")));
743 :
744 : /* Don't allow the delimiter to appear in the default string. */
745 60 : if (strchr(opts_out->default_print, opts_out->delim[0]) != NULL)
746 6 : ereport(ERROR,
747 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
748 : errmsg("COPY delimiter must not appear in the DEFAULT specification")));
749 :
750 : /* Don't allow the CSV quote char to appear in the default string. */
751 54 : if (opts_out->csv_mode &&
752 30 : strchr(opts_out->default_print, opts_out->quote[0]) != NULL)
753 6 : ereport(ERROR,
754 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
755 : errmsg("CSV quote character must not appear in the DEFAULT specification")));
756 :
757 : /* Don't allow the NULL and DEFAULT string to be the same */
758 48 : if (opts_out->null_print_len == opts_out->default_print_len &&
759 24 : strncmp(opts_out->null_print, opts_out->default_print,
760 24 : opts_out->null_print_len) == 0)
761 6 : ereport(ERROR,
762 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
763 : errmsg("NULL specification and DEFAULT specification cannot be the same")));
764 : }
765 8918 : }
766 :
767 : /*
768 : * CopyGetAttnums - build an integer list of attnums to be copied
769 : *
770 : * The input attnamelist is either the user-specified column list,
771 : * or NIL if there was none (in which case we want all the non-dropped
772 : * columns).
773 : *
774 : * We don't include generated columns in the generated full list and we don't
775 : * allow them to be specified explicitly. They don't make sense for COPY
776 : * FROM, but we could possibly allow them for COPY TO. But this way it's at
777 : * least ensured that whatever we copy out can be copied back in.
778 : *
779 : * rel can be NULL ... it's only used for error reports.
780 : */
781 : List *
782 17302 : CopyGetAttnums(TupleDesc tupDesc, Relation rel, List *attnamelist)
783 : {
784 17302 : List *attnums = NIL;
785 :
786 17302 : if (attnamelist == NIL)
787 : {
788 : /* Generate default column list */
789 3134 : int attr_count = tupDesc->natts;
790 : int i;
791 :
792 10640 : for (i = 0; i < attr_count; i++)
793 : {
794 7506 : if (TupleDescAttr(tupDesc, i)->attisdropped)
795 196 : continue;
796 7310 : if (TupleDescAttr(tupDesc, i)->attgenerated)
797 54 : continue;
798 7256 : attnums = lappend_int(attnums, i + 1);
799 : }
800 : }
801 : else
802 : {
803 : /* Validate the user-supplied list and extract attnums */
804 : ListCell *l;
805 :
806 70252 : foreach(l, attnamelist)
807 : {
808 56144 : char *name = strVal(lfirst(l));
809 : int attnum;
810 : int i;
811 :
812 : /* Lookup column name */
813 56144 : attnum = InvalidAttrNumber;
814 9871966 : for (i = 0; i < tupDesc->natts; i++)
815 : {
816 9871936 : Form_pg_attribute att = TupleDescAttr(tupDesc, i);
817 :
818 9871936 : if (att->attisdropped)
819 760 : continue;
820 9871176 : if (namestrcmp(&(att->attname), name) == 0)
821 : {
822 56114 : if (att->attgenerated)
823 24 : ereport(ERROR,
824 : (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
825 : errmsg("column \"%s\" is a generated column",
826 : name),
827 : errdetail("Generated columns cannot be used in COPY.")));
828 56090 : attnum = att->attnum;
829 56090 : break;
830 : }
831 : }
832 56120 : if (attnum == InvalidAttrNumber)
833 : {
834 30 : if (rel != NULL)
835 30 : ereport(ERROR,
836 : (errcode(ERRCODE_UNDEFINED_COLUMN),
837 : errmsg("column \"%s\" of relation \"%s\" does not exist",
838 : name, RelationGetRelationName(rel))));
839 : else
840 0 : ereport(ERROR,
841 : (errcode(ERRCODE_UNDEFINED_COLUMN),
842 : errmsg("column \"%s\" does not exist",
843 : name)));
844 : }
845 : /* Check for duplicates */
846 56090 : if (list_member_int(attnums, attnum))
847 6 : ereport(ERROR,
848 : (errcode(ERRCODE_DUPLICATE_COLUMN),
849 : errmsg("column \"%s\" specified more than once",
850 : name)));
851 56084 : attnums = lappend_int(attnums, attnum);
852 : }
853 : }
854 :
855 17242 : return attnums;
856 : }
|