Coverage Report

Created: 2025-07-03 06:49

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