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