LCOV - code coverage report
Current view: top level - src/backend/commands - copy.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 321 347 92.5 %
Date: 2024-04-13 09:11:47 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14