LCOV - differential code coverage report
Current view: top level - src/backend/commands - copy.c (source / functions) Coverage Total Hit UNC UBC GBC GNC CBC DCB
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 92.6 % 352 326 2 24 40 286 6
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 6 6 4 2
Baseline: 16@8cea358b128 Branches: 77.9 % 447 348 15 84 1 47 300
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed [..60] days: 100.0 % 13 13 13
(60,120] days: 94.7 % 19 18 1 18
(120,180] days: 50.0 % 2 1 1 1
(180,240] days: 100.0 % 8 8 8
(240..) days: 92.3 % 310 286 24 286
Function coverage date bins:
[..60] days: 100.0 % 1 1 1
(60,120] days: 100.0 % 1 1 1
(240..) days: 100.0 % 4 4 2 2
Branch coverage date bins:
[..60] days: 80.0 % 10 8 2 8
(60,120] days: 81.8 % 22 18 4 18
(120,180] days: 50.0 % 6 3 3 3
(180,240] days: 75.0 % 24 18 6 18
(240..) days: 78.2 % 385 301 84 1 300

 Age         Owner                    Branch data    TLA  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
 2647 tgl@sss.pgh.pa.us          62                 :CBC        4815 : DoCopy(ParseState *pstate, const CopyStmt *stmt,
                                 63                 :                :        int stmt_location, int stmt_len,
                                 64                 :                :        uint64 *processed)
                                 65                 :                : {
 4806 itagaki.takahiro@gma       66                 :           4815 :     bool        is_from = stmt->is_from;
                                 67                 :           4815 :     bool        pipe = (stmt->filename == NULL);
                                 68                 :                :     Relation    rel;
                                 69                 :                :     Oid         relid;
 2647 tgl@sss.pgh.pa.us          70                 :           4815 :     RawStmt    *query = NULL;
 1837 andres@anarazel.de         71                 :           4815 :     Node       *whereClause = NULL;
                                 72                 :                : 
                                 73                 :                :     /*
                                 74                 :                :      * Disallow COPY to/from file or program except to users with the
                                 75                 :                :      * appropriate role.
                                 76                 :                :      */
 2200 sfrost@snowman.net         77         [ +  + ]:           4815 :     if (!pipe)
                                 78                 :                :     {
 4064 heikki.linnakangas@i       79         [ -  + ]:            185 :         if (stmt->is_program)
                                 80                 :                :         {
  748 mail@joeconway.com         81         [ #  # ]:UBC           0 :             if (!has_privs_of_role(GetUserId(), ROLE_PG_EXECUTE_SERVER_PROGRAM))
 2200 sfrost@snowman.net         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                 :                :         {
  748 mail@joeconway.com         92   [ +  +  -  + ]:CBC         185 :             if (is_from && !has_privs_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES))
 2200 sfrost@snowman.net         93         [ #  # ]:UBC           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                 :                : 
  748 mail@joeconway.com        101   [ +  +  -  + ]:CBC         185 :             if (!is_from && !has_privs_of_role(GetUserId(), ROLE_PG_WRITE_SERVER_FILES))
 2200 sfrost@snowman.net        102         [ #  # ]:UBC           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                 :                : 
 4806 itagaki.takahiro@gma      112         [ +  + ]:CBC        4815 :     if (stmt->relation)
                                113                 :                :     {
 2023 tgl@sss.pgh.pa.us         114         [ +  + ]:           4618 :         LOCKMODE    lockmode = is_from ? RowExclusiveLock : AccessShareLock;
                                115                 :                :         ParseNamespaceItem *nsitem;
                                116                 :                :         RTEPermissionInfo *perminfo;
                                117                 :                :         TupleDesc   tupDesc;
                                118                 :                :         List       *attnums;
                                119                 :                :         ListCell   *cur;
                                120                 :                : 
 4806 itagaki.takahiro@gma      121         [ -  + ]:           4618 :         Assert(!stmt->query);
                                122                 :                : 
                                123                 :                :         /* Open and lock the relation, using the appropriate lock type. */
 1910 andres@anarazel.de        124                 :           4618 :         rel = table_openrv(stmt->relation, lockmode);
                                125                 :                : 
 4124 rhaas@postgresql.org      126                 :           4617 :         relid = RelationGetRelid(rel);
                                127                 :                : 
 1564 tgl@sss.pgh.pa.us         128                 :           4617 :         nsitem = addRangeTableEntryForRelation(pstate, rel, lockmode,
                                129                 :                :                                                NULL, false, false);
                                130                 :                : 
  495 alvherre@alvh.no-ip.      131                 :           4617 :         perminfo = nsitem->p_perminfo;
                                132         [ +  + ]:           4617 :         perminfo->requiredPerms = (is_from ? ACL_INSERT : ACL_SELECT);
                                133                 :                : 
 1912 tomas.vondra@postgre      134         [ +  + ]:           4617 :         if (stmt->whereClause)
                                135                 :                :         {
                                136                 :                :             /* add nsitem to query namespace */
 1564 tgl@sss.pgh.pa.us         137                 :             24 :             addNSItemToQuery(pstate, nsitem, false, true, true);
                                138                 :                : 
                                139                 :                :             /* Transform the raw expression tree */
 1912 tomas.vondra@postgre      140                 :             24 :             whereClause = transformExpr(pstate, stmt->whereClause, EXPR_KIND_COPY_WHERE);
                                141                 :                : 
                                142                 :                :             /* Make sure it yields a boolean result. */
                                143                 :              9 :             whereClause = coerce_to_boolean(pstate, whereClause, "WHERE");
                                144                 :                : 
                                145                 :                :             /* we have to fix its collations too */
                                146                 :              9 :             assign_expr_collations(pstate, whereClause);
                                147                 :                : 
                                148                 :              9 :             whereClause = eval_const_expressions(NULL, whereClause);
                                149                 :                : 
                                150                 :              9 :             whereClause = (Node *) canonicalize_qual((Expr *) whereClause, false);
                                151                 :              9 :             whereClause = (Node *) make_ands_implicit((Expr *) whereClause);
                                152                 :                :         }
                                153                 :                : 
 4806 itagaki.takahiro@gma      154                 :           4602 :         tupDesc = RelationGetDescr(rel);
                                155                 :           4602 :         attnums = CopyGetAttnums(tupDesc, rel, stmt->attlist);
 4802 tgl@sss.pgh.pa.us         156   [ +  +  +  +  :          20501 :         foreach(cur, attnums)
                                              +  + ]
                                157                 :                :         {
                                158                 :                :             int         attno;
                                159                 :                :             Bitmapset **bms;
                                160                 :                : 
  495 alvherre@alvh.no-ip.      161                 :          15929 :             attno = lfirst_int(cur) - FirstLowInvalidHeapAttributeNumber;
                                162         [ +  + ]:          15929 :             bms = is_from ? &perminfo->insertedCols : &perminfo->selectedCols;
                                163                 :                : 
                                164                 :          15929 :             *bms = bms_add_member(*bms, attno);
                                165                 :                :         }
                                166                 :           4572 :         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         [ +  + ]:           4530 :         if (check_enable_rls(relid, InvalidOid, false) == RLS_ENABLED)
                                183                 :                :         {
                                184                 :                :             SelectStmt *select;
                                185                 :                :             ColumnRef  *cr;
                                186                 :                :             ResTarget  *target;
                                187                 :                :             RangeVar   *from;
 2750 sfrost@snowman.net        188                 :             30 :             List       *targetList = NIL;
                                189                 :                : 
 3495                           190         [ +  + ]:             30 :             if (is_from)
                                191         [ +  - ]:              3 :                 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         [ +  + ]:             27 :             if (!stmt->attlist)
                                209                 :                :             {
 2750                           210                 :              9 :                 cr = makeNode(ColumnRef);
 3495                           211                 :              9 :                 cr->fields = list_make1(makeNode(A_Star));
 2750                           212                 :              9 :                 cr->location = -1;
                                213                 :                : 
                                214                 :              9 :                 target = makeNode(ResTarget);
                                215                 :              9 :                 target->name = NULL;
                                216                 :              9 :                 target->indirection = NIL;
                                217                 :              9 :                 target->val = (Node *) cr;
                                218                 :              9 :                 target->location = -1;
                                219                 :                : 
                                220                 :              9 :                 targetList = list_make1(target);
                                221                 :                :             }
                                222                 :                :             else
                                223                 :                :             {
                                224                 :                :                 ListCell   *lc;
                                225                 :                : 
                                226   [ +  -  +  +  :             51 :                 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                 :             33 :                     cr = makeNode(ColumnRef);
                                234                 :             33 :                     cr->fields = list_make1(lfirst(lc));
                                235                 :             33 :                     cr->location = -1;
                                236                 :                : 
                                237                 :                :                     /* Build the ResTarget and add the ColumnRef to it. */
                                238                 :             33 :                     target = makeNode(ResTarget);
                                239                 :             33 :                     target->name = NULL;
                                240                 :             33 :                     target->indirection = NIL;
                                241                 :             33 :                     target->val = (Node *) cr;
                                242                 :             33 :                     target->location = -1;
                                243                 :                : 
                                244                 :                :                     /* Add each column to the SELECT statement's target list */
                                245                 :             33 :                     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                 :                :              */
 3184                           255                 :             27 :             from = makeRangeVar(get_namespace_name(RelationGetNamespace(rel)),
 2596 tgl@sss.pgh.pa.us         256                 :             27 :                                 pstrdup(RelationGetRelationName(rel)),
                                257                 :                :                                 -1);
  401                           258                 :             27 :             from->inh = false;   /* apply ONLY */
                                259                 :                : 
                                260                 :                :             /* Build query */
 3495 sfrost@snowman.net        261                 :             27 :             select = makeNode(SelectStmt);
 2750                           262                 :             27 :             select->targetList = targetList;
 3495                           263                 :             27 :             select->fromClause = list_make1(from);
                                264                 :                : 
 2647 tgl@sss.pgh.pa.us         265                 :             27 :             query = makeNode(RawStmt);
                                266                 :             27 :             query->stmt = (Node *) select;
                                267                 :             27 :             query->stmt_location = stmt_location;
                                268                 :             27 :             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                 :                :              */
 1910 andres@anarazel.de        276                 :             27 :             table_close(rel, NoLock);
 3495 sfrost@snowman.net        277                 :             27 :             rel = NULL;
                                278                 :                :         }
                                279                 :                :     }
                                280                 :                :     else
                                281                 :                :     {
 4806 itagaki.takahiro@gma      282         [ -  + ]:            197 :         Assert(stmt->query);
                                283                 :                : 
 2647 tgl@sss.pgh.pa.us         284                 :            197 :         query = makeNode(RawStmt);
                                285                 :            197 :         query->stmt = stmt->query;
                                286                 :            197 :         query->stmt_location = stmt_location;
                                287                 :            197 :         query->stmt_len = stmt_len;
                                288                 :                : 
 4122 peter_e@gmx.net           289                 :            197 :         relid = InvalidOid;
 4806 itagaki.takahiro@gma      290                 :            197 :         rel = NULL;
                                291                 :                :     }
                                292                 :                : 
                                293         [ +  + ]:           4715 :     if (is_from)
                                294                 :                :     {
                                295                 :                :         CopyFromState cstate;
                                296                 :                : 
 4414 peter_e@gmx.net           297         [ -  + ]:            699 :         Assert(rel);
                                298                 :                : 
                                299                 :                :         /* check read-only transaction and parallel mode */
 4136 tgl@sss.pgh.pa.us         300   [ -  +  -  - ]:            699 :         if (XactReadOnly && !rel->rd_islocaltemp)
 4806 itagaki.takahiro@gma      301                 :UBC           0 :             PreventCommandIfReadOnly("COPY FROM");
                                302                 :                : 
 1238 heikki.linnakangas@i      303                 :CBC         699 :         cstate = BeginCopyFrom(pstate, rel, whereClause,
                                304                 :            699 :                                stmt->filename, stmt->is_program,
 2579 peter_e@gmx.net           305                 :            699 :                                NULL, stmt->attlist, stmt->options);
 4124 rhaas@postgresql.org      306                 :            609 :         *processed = CopyFrom(cstate);  /* copy from file to database */
 4806 itagaki.takahiro@gma      307                 :            512 :         EndCopyFrom(cstate);
                                308                 :                :     }
                                309                 :                :     else
                                310                 :                :     {
                                311                 :                :         CopyToState cstate;
                                312                 :                : 
 2777 peter_e@gmx.net           313                 :           4016 :         cstate = BeginCopyTo(pstate, rel, query, relid,
 4064 heikki.linnakangas@i      314                 :           4016 :                              stmt->filename, stmt->is_program,
  551 michael@paquier.xyz       315                 :           4016 :                              NULL, stmt->attlist, stmt->options);
 4124 rhaas@postgresql.org      316                 :           3913 :         *processed = DoCopyTo(cstate);  /* copy from database to file */
 4806 itagaki.takahiro@gma      317                 :           3912 :         EndCopyTo(cstate);
                                318                 :                :     }
                                319                 :                : 
                                320         [ +  + ]:           4424 :     if (rel != NULL)
 1430 akapila@postgresql.o      321                 :           4267 :         table_close(rel, NoLock);
 4806 itagaki.takahiro@gma      322                 :           4424 : }
                                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
  661 michael@paquier.xyz       329                 :             78 : defGetCopyHeaderChoice(DefElem *def, bool is_from)
                                330                 :                : {
                                331                 :                :     /*
                                332                 :                :      * If no parameter value given, assume "true" is meant.
                                333                 :                :      */
  746 peter@eisentraut.org      334         [ +  + ]:             78 :     if (def->arg == NULL)
                                335                 :              6 :         return COPY_HEADER_TRUE;
                                336                 :                : 
                                337                 :                :     /*
                                338                 :                :      * Allow 0, 1, "true", "false", "on", "off", or "match".
                                339                 :                :      */
                                340         [ -  + ]:             72 :     switch (nodeTag(def->arg))
                                341                 :                :     {
  746 peter@eisentraut.org      342                 :UBC           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;
  746 peter@eisentraut.org      354                 :CBC          72 :         default:
                                355                 :                :             {
  703 tgl@sss.pgh.pa.us         356                 :             72 :                 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                 :                :                  */
  746 peter@eisentraut.org      362         [ +  + ]:             72 :                 if (pg_strcasecmp(sval, "true") == 0)
                                363                 :             23 :                     return COPY_HEADER_TRUE;
                                364         [ -  + ]:             49 :                 if (pg_strcasecmp(sval, "false") == 0)
  746 peter@eisentraut.org      365                 :UBC           0 :                     return COPY_HEADER_FALSE;
  746 peter@eisentraut.org      366         [ -  + ]:CBC          49 :                 if (pg_strcasecmp(sval, "on") == 0)
  746 peter@eisentraut.org      367                 :UBC           0 :                     return COPY_HEADER_TRUE;
  746 peter@eisentraut.org      368         [ +  + ]:CBC          49 :                 if (pg_strcasecmp(sval, "off") == 0)
                                369                 :              3 :                     return COPY_HEADER_FALSE;
                                370         [ +  + ]:             46 :                 if (pg_strcasecmp(sval, "match") == 0)
                                371                 :                :                 {
  661 michael@paquier.xyz       372         [ +  + ]:             43 :                     if (!is_from)
                                373         [ +  - ]:              3 :                         ereport(ERROR,
                                374                 :                :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                375                 :                :                                  errmsg("cannot use \"%s\" with HEADER in COPY TO",
                                376                 :                :                                         sval)));
  746 peter@eisentraut.org      377                 :             40 :                     return COPY_HEADER_MATCH;
                                378                 :                :                 }
                                379                 :                :             }
                                380                 :              3 :             break;
                                381                 :                :     }
                                382         [ +  - ]:              3 :     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
   86 akorotkov@postgresql      393                 :GNC          30 : defGetCopyOnErrorChoice(DefElem *def, ParseState *pstate, bool is_from)
                                394                 :                : {
                                395                 :                :     char       *sval;
                                396                 :                : 
   89                           397         [ +  + ]:             30 :     if (!is_from)
                                398         [ +  - ]:              3 :         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         [ -  + ]:             27 :     if (def->arg == NULL)
   86 akorotkov@postgresql      407                 :UNC           0 :         return COPY_ON_ERROR_STOP;
                                408                 :                : 
                                409                 :                :     /*
                                410                 :                :      * Allow "stop", or "ignore" values.
                                411                 :                :      */
   89 akorotkov@postgresql      412                 :GNC          27 :     sval = defGetString(def);
   86                           413         [ +  + ]:             27 :     if (pg_strcasecmp(sval, "stop") == 0)
                                414                 :              3 :         return COPY_ON_ERROR_STOP;
                                415         [ +  + ]:             24 :     if (pg_strcasecmp(sval, "ignore") == 0)
                                416                 :             21 :         return COPY_ON_ERROR_IGNORE;
                                417                 :                : 
   89                           418         [ +  - ]:              3 :     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
   13 msawada@postgresql.o      429                 :             12 : defGetCopyLogVerbosityChoice(DefElem *def, ParseState *pstate)
                                430                 :                : {
                                431                 :                :     char       *sval;
                                432                 :                : 
                                433                 :                :     /*
                                434                 :                :      * Allow "default", or "verbose" values.
                                435                 :                :      */
                                436                 :             12 :     sval = defGetString(def);
                                437         [ +  + ]:             12 :     if (pg_strcasecmp(sval, "default") == 0)
                                438                 :              3 :         return COPY_LOG_VERBOSITY_DEFAULT;
                                439         [ +  + ]:              9 :     if (pg_strcasecmp(sval, "verbose") == 0)
                                440                 :              6 :         return COPY_LOG_VERBOSITY_VERBOSE;
                                441                 :                : 
                                442         [ +  - ]:              3 :     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
 2777 peter_e@gmx.net           466                 :CBC        4952 : ProcessCopyOptions(ParseState *pstate,
                                467                 :                :                    CopyFormatOptions *opts_out,
                                468                 :                :                    bool is_from,
                                469                 :                :                    List *options)
                                470                 :                : {
 5319 tgl@sss.pgh.pa.us         471                 :           4952 :     bool        format_specified = false;
 1287 michael@paquier.xyz       472                 :           4952 :     bool        freeze_specified = false;
                                473                 :           4952 :     bool        header_specified = false;
   86 akorotkov@postgresql      474                 :GNC        4952 :     bool        on_error_specified = false;
   13 msawada@postgresql.o      475                 :           4952 :     bool        log_verbosity_specified = false;
                                476                 :                :     ListCell   *option;
                                477                 :                : 
                                478                 :                :     /* Support external use for option sanity checking */
 1238 heikki.linnakangas@i      479         [ +  + ]:CBC        4952 :     if (opts_out == NULL)
                                480                 :             43 :         opts_out = (CopyFormatOptions *) palloc0(sizeof(CopyFormatOptions));
                                481                 :                : 
                                482                 :           4952 :     opts_out->file_encoding = -1;
                                483                 :                : 
                                484                 :                :     /* Extract options from the statement node tree */
 4806 itagaki.takahiro@gma      485   [ +  +  +  +  :           5769 :     foreach(option, options)
                                              +  + ]
                                486                 :                :     {
 2561 tgl@sss.pgh.pa.us         487                 :            881 :         DefElem    *defel = lfirst_node(DefElem, option);
                                488                 :                : 
 5319                           489         [ +  + ]:            881 :         if (strcmp(defel->defname, "format") == 0)
                                490                 :                :         {
 5161 bruce@momjian.us          491                 :            264 :             char       *fmt = defGetString(defel);
                                492                 :                : 
 5319 tgl@sss.pgh.pa.us         493         [ +  + ]:            264 :             if (format_specified)
 1004 dean.a.rasheed@gmail      494                 :              3 :                 errorConflictingDefElem(defel, pstate);
 5319 tgl@sss.pgh.pa.us         495                 :            261 :             format_specified = true;
                                496         [ +  + ]:            261 :             if (strcmp(fmt, "text") == 0)
                                497                 :                :                  /* default format */ ;
                                498         [ +  + ]:            232 :             else if (strcmp(fmt, "csv") == 0)
 1238 heikki.linnakangas@i      499                 :            197 :                 opts_out->csv_mode = true;
 5319 tgl@sss.pgh.pa.us         500         [ +  + ]:             35 :             else if (strcmp(fmt, "binary") == 0)
 1238 heikki.linnakangas@i      501                 :             34 :                 opts_out->binary = true;
                                502                 :                :             else
 5319 tgl@sss.pgh.pa.us         503         [ +  - ]:              1 :                 ereport(ERROR,
                                504                 :                :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                505                 :                :                          errmsg("COPY format \"%s\" not recognized", fmt),
                                506                 :                :                          parser_errposition(pstate, defel->location)));
                                507                 :                :         }
 4152 simon@2ndQuadrant.co      508         [ +  + ]:            617 :         else if (strcmp(defel->defname, "freeze") == 0)
                                509                 :                :         {
 1287 michael@paquier.xyz       510         [ +  + ]:             39 :             if (freeze_specified)
 1004 dean.a.rasheed@gmail      511                 :              3 :                 errorConflictingDefElem(defel, pstate);
 1287 michael@paquier.xyz       512                 :             36 :             freeze_specified = true;
 1238 heikki.linnakangas@i      513                 :             36 :             opts_out->freeze = defGetBoolean(defel);
                                514                 :                :         }
 7969 bruce@momjian.us          515         [ +  + ]:            578 :         else if (strcmp(defel->defname, "delimiter") == 0)
                                516                 :                :         {
 1238 heikki.linnakangas@i      517         [ +  + ]:            132 :             if (opts_out->delim)
 1004 dean.a.rasheed@gmail      518                 :              3 :                 errorConflictingDefElem(defel, pstate);
 1238 heikki.linnakangas@i      519                 :            129 :             opts_out->delim = defGetString(defel);
                                520                 :                :         }
 7969 bruce@momjian.us          521         [ +  + ]:            446 :         else if (strcmp(defel->defname, "null") == 0)
                                522                 :                :         {
 1238 heikki.linnakangas@i      523         [ +  + ]:             63 :             if (opts_out->null_print)
 1004 dean.a.rasheed@gmail      524                 :              3 :                 errorConflictingDefElem(defel, pstate);
 1238 heikki.linnakangas@i      525                 :             60 :             opts_out->null_print = defGetString(defel);
                                526                 :                :         }
  398 andrew@dunslane.net       527         [ +  + ]:            383 :         else if (strcmp(defel->defname, "default") == 0)
                                528                 :                :         {
                                529         [ -  + ]:             45 :             if (opts_out->default_print)
  398 andrew@dunslane.net       530                 :UBC           0 :                 errorConflictingDefElem(defel, pstate);
  398 andrew@dunslane.net       531                 :CBC          45 :             opts_out->default_print = defGetString(defel);
                                532                 :                :         }
 6917 bruce@momjian.us          533         [ +  + ]:            338 :         else if (strcmp(defel->defname, "header") == 0)
                                534                 :                :         {
 1287 michael@paquier.xyz       535         [ +  + ]:             81 :             if (header_specified)
 1004 dean.a.rasheed@gmail      536                 :              3 :                 errorConflictingDefElem(defel, pstate);
 1287 michael@paquier.xyz       537                 :             78 :             header_specified = true;
  661                           538                 :             78 :             opts_out->header_line = defGetCopyHeaderChoice(defel, is_from);
                                539                 :                :         }
 7300 bruce@momjian.us          540         [ +  + ]:            257 :         else if (strcmp(defel->defname, "quote") == 0)
                                541                 :                :         {
 1238 heikki.linnakangas@i      542         [ +  + ]:             42 :             if (opts_out->quote)
 1004 dean.a.rasheed@gmail      543                 :              3 :                 errorConflictingDefElem(defel, pstate);
 1238 heikki.linnakangas@i      544                 :             39 :             opts_out->quote = defGetString(defel);
                                545                 :                :         }
 7300 bruce@momjian.us          546         [ +  + ]:            215 :         else if (strcmp(defel->defname, "escape") == 0)
                                547                 :                :         {
 1238 heikki.linnakangas@i      548         [ +  + ]:             38 :             if (opts_out->escape)
 1004 dean.a.rasheed@gmail      549                 :              3 :                 errorConflictingDefElem(defel, pstate);
 1238 heikki.linnakangas@i      550                 :             35 :             opts_out->escape = defGetString(defel);
                                551                 :                :         }
 7298 bruce@momjian.us          552         [ +  + ]:            177 :         else if (strcmp(defel->defname, "force_quote") == 0)
                                553                 :                :         {
 1238 heikki.linnakangas@i      554   [ +  +  -  + ]:             33 :             if (opts_out->force_quote || opts_out->force_quote_all)
 1004 dean.a.rasheed@gmail      555                 :              3 :                 errorConflictingDefElem(defel, pstate);
 5377 tgl@sss.pgh.pa.us         556   [ +  -  +  + ]:             30 :             if (defel->arg && IsA(defel->arg, A_Star))
 1238 heikki.linnakangas@i      557                 :              9 :                 opts_out->force_quote_all = true;
 5319 tgl@sss.pgh.pa.us         558   [ +  -  +  - ]:             21 :             else if (defel->arg && IsA(defel->arg, List))
 1238 heikki.linnakangas@i      559                 :             21 :                 opts_out->force_quote = castNode(List, defel->arg);
                                560                 :                :             else
 5319 tgl@sss.pgh.pa.us         561         [ #  # ]:UBC           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                 :                :         }
 5319 tgl@sss.pgh.pa.us         567         [ +  + ]:CBC         144 :         else if (strcmp(defel->defname, "force_not_null") == 0)
                                568                 :                :         {
  197 andrew@dunslane.net       569   [ +  +  +  + ]:GNC          38 :             if (opts_out->force_notnull || opts_out->force_notnull_all)
 1004 dean.a.rasheed@gmail      570                 :CBC           6 :                 errorConflictingDefElem(defel, pstate);
  197 andrew@dunslane.net       571   [ +  -  +  + ]:GNC          32 :             if (defel->arg && IsA(defel->arg, A_Star))
                                572                 :              9 :                 opts_out->force_notnull_all = true;
                                573   [ +  -  +  - ]:             23 :             else if (defel->arg && IsA(defel->arg, List))
 1238 heikki.linnakangas@i      574                 :CBC          23 :                 opts_out->force_notnull = castNode(List, defel->arg);
                                575                 :                :             else
 5319 tgl@sss.pgh.pa.us         576         [ #  # ]:UBC           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                 :                :         }
 3694 andrew@dunslane.net       582         [ +  + ]:CBC         106 :         else if (strcmp(defel->defname, "force_null") == 0)
                                583                 :                :         {
  197 andrew@dunslane.net       584   [ +  +  +  + ]:GNC          38 :             if (opts_out->force_null || opts_out->force_null_all)
 1004 dean.a.rasheed@gmail      585                 :CBC           6 :                 errorConflictingDefElem(defel, pstate);
  197 andrew@dunslane.net       586   [ +  -  +  + ]:GNC          32 :             if (defel->arg && IsA(defel->arg, A_Star))
                                587                 :              9 :                 opts_out->force_null_all = true;
                                588   [ +  -  +  - ]:             23 :             else if (defel->arg && IsA(defel->arg, List))
 1238 heikki.linnakangas@i      589                 :CBC          23 :                 opts_out->force_null = castNode(List, defel->arg);
                                590                 :                :             else
 3694 andrew@dunslane.net       591         [ #  # ]:UBC           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                 :                :         }
 4294 tgl@sss.pgh.pa.us         597         [ +  + ]:CBC          68 :         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                 :                :              */
 1238 heikki.linnakangas@i      604         [ +  + ]:              8 :             if (opts_out->convert_selectively)
 1004 dean.a.rasheed@gmail      605                 :              3 :                 errorConflictingDefElem(defel, pstate);
 1238 heikki.linnakangas@i      606                 :              5 :             opts_out->convert_selectively = true;
 4294 tgl@sss.pgh.pa.us         607   [ +  -  +  - ]:              5 :             if (defel->arg == NULL || IsA(defel->arg, List))
 1238 heikki.linnakangas@i      608                 :              5 :                 opts_out->convert_select = castNode(List, defel->arg);
                                609                 :                :             else
 4294 tgl@sss.pgh.pa.us         610         [ #  # ]:UBC           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                 :                :         }
 4801 itagaki.takahiro@gma      616         [ +  + ]:CBC          60 :         else if (strcmp(defel->defname, "encoding") == 0)
                                617                 :                :         {
 1238 heikki.linnakangas@i      618         [ +  + ]:             12 :             if (opts_out->file_encoding >= 0)
 1004 dean.a.rasheed@gmail      619                 :              3 :                 errorConflictingDefElem(defel, pstate);
 1238 heikki.linnakangas@i      620                 :              9 :             opts_out->file_encoding = pg_char_to_encoding(defGetString(defel));
                                621         [ -  + ]:              9 :             if (opts_out->file_encoding < 0)
 4801 itagaki.takahiro@gma      622         [ #  # ]:UBC           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                 :                :         }
   86 akorotkov@postgresql      628         [ +  + ]:GNC          48 :         else if (strcmp(defel->defname, "on_error") == 0)
                                629                 :                :         {
                                630         [ +  + ]:             33 :             if (on_error_specified)
   89                           631                 :              3 :                 errorConflictingDefElem(defel, pstate);
   86                           632                 :             30 :             on_error_specified = true;
                                633                 :             30 :             opts_out->on_error = defGetCopyOnErrorChoice(defel, pstate, is_from);
                                634                 :                :         }
   13 msawada@postgresql.o      635         [ +  - ]:             15 :         else if (strcmp(defel->defname, "log_verbosity") == 0)
                                636                 :                :         {
                                637         [ +  + ]:             15 :             if (log_verbosity_specified)
                                638                 :              3 :                 errorConflictingDefElem(defel, pstate);
                                639                 :             12 :             log_verbosity_specified = true;
                                640                 :             12 :             opts_out->log_verbosity = defGetCopyLogVerbosityChoice(defel, pstate);
                                641                 :                :         }
                                642                 :                :         else
 5319 tgl@sss.pgh.pa.us         643         [ #  # ]:UBC           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                 :                :      */
 1238 heikki.linnakangas@i      654   [ +  +  +  + ]:CBC        4888 :     if (opts_out->binary && opts_out->delim)
 7574 tgl@sss.pgh.pa.us         655         [ +  - ]:              3 :         ereport(ERROR,
                                656                 :                :                 (errcode(ERRCODE_SYNTAX_ERROR),
                                657                 :                :                  errmsg("cannot specify DELIMITER in BINARY mode")));
                                658                 :                : 
 1238 heikki.linnakangas@i      659   [ +  +  +  + ]:           4885 :     if (opts_out->binary && opts_out->null_print)
 7574 tgl@sss.pgh.pa.us         660         [ +  - ]:              3 :         ereport(ERROR,
                                661                 :                :                 (errcode(ERRCODE_SYNTAX_ERROR),
                                662                 :                :                  errmsg("cannot specify NULL in BINARY mode")));
                                663                 :                : 
  398 andrew@dunslane.net       664   [ +  +  +  + ]:           4882 :     if (opts_out->binary && opts_out->default_print)
                                665         [ +  - ]:              3 :         ereport(ERROR,
                                666                 :                :                 (errcode(ERRCODE_SYNTAX_ERROR),
                                667                 :                :                  errmsg("cannot specify DEFAULT in BINARY mode")));
                                668                 :                : 
   86 akorotkov@postgresql      669   [ +  +  +  + ]:GNC        4879 :     if (opts_out->binary && opts_out->on_error != COPY_ON_ERROR_STOP)
   89                           670         [ +  - ]:              3 :         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 */
 1238 heikki.linnakangas@i      675         [ +  + ]:CBC        4876 :     if (!opts_out->delim)
                                676         [ +  + ]:           4753 :         opts_out->delim = opts_out->csv_mode ? "," : "\t";
                                677                 :                : 
                                678         [ +  + ]:           4876 :     if (!opts_out->null_print)
                                679         [ +  + ]:           4822 :         opts_out->null_print = opts_out->csv_mode ? "" : "\\N";
                                680                 :           4876 :     opts_out->null_print_len = strlen(opts_out->null_print);
                                681                 :                : 
                                682         [ +  + ]:           4876 :     if (opts_out->csv_mode)
                                683                 :                :     {
                                684         [ +  + ]:            188 :         if (!opts_out->quote)
                                685                 :            154 :             opts_out->quote = "\"";
                                686         [ +  + ]:            188 :         if (!opts_out->escape)
                                687                 :            159 :             opts_out->escape = opts_out->quote;
                                688                 :                :     }
                                689                 :                : 
                                690                 :                :     /* Only single-byte delimiter strings are supported. */
                                691         [ +  + ]:           4876 :     if (strlen(opts_out->delim) != 1)
 7300 bruce@momjian.us          692         [ +  - ]:              1 :         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 */
 1238 heikki.linnakangas@i      697         [ +  - ]:           4875 :     if (strchr(opts_out->delim, '\r') != NULL ||
                                698         [ +  + ]:           4875 :         strchr(opts_out->delim, '\n') != NULL)
 6645 bruce@momjian.us          699         [ +  - ]:              1 :         ereport(ERROR,
                                700                 :                :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                701                 :                :                  errmsg("COPY delimiter cannot be newline or carriage return")));
                                702                 :                : 
 1238 heikki.linnakangas@i      703         [ +  - ]:           4874 :     if (strchr(opts_out->null_print, '\r') != NULL ||
                                704         [ +  + ]:           4874 :         strchr(opts_out->null_print, '\n') != NULL)
 6645 bruce@momjian.us          705         [ +  - ]:              1 :         ereport(ERROR,
                                706                 :                :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                707                 :                :                  errmsg("COPY null representation cannot use newline or carriage return")));
                                708                 :                : 
  398 andrew@dunslane.net       709         [ +  + ]:           4873 :     if (opts_out->default_print)
                                710                 :                :     {
                                711                 :             42 :         opts_out->default_print_len = strlen(opts_out->default_print);
                                712                 :                : 
                                713         [ +  + ]:             42 :         if (strchr(opts_out->default_print, '\r') != NULL ||
                                714         [ +  + ]:             39 :             strchr(opts_out->default_print, '\n') != NULL)
                                715         [ +  - ]:              6 :             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                 :                :      */
 1238 heikki.linnakangas@i      730         [ +  + ]:           4867 :     if (!opts_out->csv_mode &&
 5953 tgl@sss.pgh.pa.us         731                 :           4682 :         strchr("\\.abcdefghijklmnopqrstuvwxyz0123456789",
 1238 heikki.linnakangas@i      732         [ +  + ]:           4682 :                opts_out->delim[0]) != NULL)
 6645 bruce@momjian.us          733         [ +  - ]:              5 :         ereport(ERROR,
                                734                 :                :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                735                 :                :                  errmsg("COPY delimiter cannot be \"%s\"", opts_out->delim)));
                                736                 :                : 
                                737                 :                :     /* Check header */
  807 peter@eisentraut.org      738   [ +  +  +  + ]:           4862 :     if (opts_out->binary && opts_out->header_line)
 6917 bruce@momjian.us          739         [ +  - ]:              1 :         ereport(ERROR,
                                740                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                741                 :                :                  errmsg("cannot specify HEADER in BINARY mode")));
                                742                 :                : 
                                743                 :                :     /* Check quote */
 1238 heikki.linnakangas@i      744   [ +  +  +  + ]:           4861 :     if (!opts_out->csv_mode && opts_out->quote != NULL)
 7300 bruce@momjian.us          745         [ +  - ]:              2 :         ereport(ERROR,
                                746                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                747                 :                :                  errmsg("COPY QUOTE requires CSV mode")));
                                748                 :                : 
 1238 heikki.linnakangas@i      749   [ +  +  +  + ]:           4859 :     if (opts_out->csv_mode && strlen(opts_out->quote) != 1)
 7300 bruce@momjian.us          750         [ +  - ]:              1 :         ereport(ERROR,
                                751                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                752                 :                :                  errmsg("COPY quote must be a single one-byte character")));
                                753                 :                : 
 1238 heikki.linnakangas@i      754   [ +  +  +  + ]:           4858 :     if (opts_out->csv_mode && opts_out->delim[0] == opts_out->quote[0])
 5950 andrew@dunslane.net       755         [ +  - ]:              1 :         ereport(ERROR,
                                756                 :                :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                757                 :                :                  errmsg("COPY delimiter and quote must be different")));
                                758                 :                : 
                                759                 :                :     /* Check escape */
 1238 heikki.linnakangas@i      760   [ +  +  +  + ]:           4857 :     if (!opts_out->csv_mode && opts_out->escape != NULL)
 7300 bruce@momjian.us          761         [ +  - ]:              3 :         ereport(ERROR,
                                762                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                763                 :                :                  errmsg("COPY ESCAPE requires CSV mode")));
                                764                 :                : 
 1238 heikki.linnakangas@i      765   [ +  +  +  + ]:           4854 :     if (opts_out->csv_mode && strlen(opts_out->escape) != 1)
 7300 bruce@momjian.us          766         [ +  - ]:              1 :         ereport(ERROR,
                                767                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                768                 :                :                  errmsg("COPY escape must be a single one-byte character")));
                                769                 :                : 
                                770                 :                :     /* Check force_quote */
 1238 heikki.linnakangas@i      771   [ +  +  +  +  :           4853 :     if (!opts_out->csv_mode && (opts_out->force_quote || opts_out->force_quote_all))
                                              -  + ]
 7300 bruce@momjian.us          772         [ +  - ]:              3 :         ereport(ERROR,
                                773                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                774                 :                :                  errmsg("COPY FORCE_QUOTE requires CSV mode")));
 1238 heikki.linnakangas@i      775   [ +  +  +  +  :           4850 :     if ((opts_out->force_quote || opts_out->force_quote_all) && is_from)
                                              +  + ]
 7300 bruce@momjian.us          776         [ +  - ]:              3 :         ereport(ERROR,
                                777                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                778                 :                :                  errmsg("COPY FORCE_QUOTE cannot be used with COPY FROM")));
                                779                 :                : 
                                780                 :                :     /* Check force_notnull */
 1238 heikki.linnakangas@i      781   [ +  +  +  + ]:           4847 :     if (!opts_out->csv_mode && opts_out->force_notnull != NIL)
 7300 bruce@momjian.us          782         [ +  - ]:              4 :         ereport(ERROR,
                                783                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                784                 :                :                  errmsg("COPY FORCE_NOT_NULL requires CSV mode")));
 1238 heikki.linnakangas@i      785   [ +  +  +  + ]:           4843 :     if (opts_out->force_notnull != NIL && !is_from)
 7300 bruce@momjian.us          786         [ +  - ]:              3 :         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 */
 1238 heikki.linnakangas@i      791   [ +  +  +  + ]:           4840 :     if (!opts_out->csv_mode && opts_out->force_null != NIL)
 3694 andrew@dunslane.net       792         [ +  - ]:              3 :         ereport(ERROR,
                                793                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                794                 :                :                  errmsg("COPY FORCE_NULL requires CSV mode")));
                                795                 :                : 
 1238 heikki.linnakangas@i      796   [ +  +  +  + ]:           4837 :     if (opts_out->force_null != NIL && !is_from)
 3694 andrew@dunslane.net       797         [ +  - ]:              3 :         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. */
 1238 heikki.linnakangas@i      802         [ +  + ]:           4834 :     if (strchr(opts_out->null_print, opts_out->delim[0]) != NULL)
 7300 bruce@momjian.us          803         [ +  - ]:              1 :         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. */
 1238 heikki.linnakangas@i      808         [ +  + ]:           4833 :     if (opts_out->csv_mode &&
                                809         [ +  + ]:            172 :         strchr(opts_out->null_print, opts_out->quote[0]) != NULL)
 7300 bruce@momjian.us          810         [ +  - ]:              1 :         ereport(ERROR,
                                811                 :                :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                812                 :                :                  errmsg("CSV quote character must not appear in the NULL specification")));
                                813                 :                : 
                                814                 :                :     /* Check freeze */
  153 bruce@momjian.us          815   [ +  +  -  + ]:GNC        4832 :     if (opts_out->freeze && !is_from)
  153 bruce@momjian.us          816         [ #  # ]:UNC           0 :         ereport(ERROR,
                                817                 :                :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                818                 :                :                  errmsg("COPY FREEZE cannot be used with COPY TO")));
                                819                 :                : 
  398 andrew@dunslane.net       820         [ +  + ]:CBC        4832 :     if (opts_out->default_print)
                                821                 :                :     {
                                822         [ +  + ]:             36 :         if (!is_from)
                                823         [ +  - ]:              3 :             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         [ +  + ]:             33 :         if (strchr(opts_out->default_print, opts_out->delim[0]) != NULL)
                                829         [ +  - ]:              3 :             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         [ +  + ]:             30 :         if (opts_out->csv_mode &&
                                835         [ +  + ]:             15 :             strchr(opts_out->default_print, opts_out->quote[0]) != NULL)
                                836         [ +  - ]:              3 :             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         [ +  + ]:             27 :         if (opts_out->null_print_len == opts_out->default_print_len &&
                                842                 :             12 :             strncmp(opts_out->null_print, opts_out->default_print,
                                843         [ +  + ]:             12 :                     opts_out->null_print_len) == 0)
                                844         [ +  - ]:              3 :             ereport(ERROR,
                                845                 :                :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                846                 :                :                      errmsg("NULL specification and DEFAULT specification cannot be the same")));
                                847                 :                :     }
 4802 tgl@sss.pgh.pa.us         848                 :           4820 : }
                                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 *
 1238 heikki.linnakangas@i      865                 :           9375 : CopyGetAttnums(TupleDesc tupDesc, Relation rel, List *attnamelist)
                                866                 :                : {
                                867                 :           9375 :     List       *attnums = NIL;
                                868                 :                : 
                                869         [ +  + ]:           9375 :     if (attnamelist == NIL)
                                870                 :                :     {
                                871                 :                :         /* Generate default column list */
 7893 bruce@momjian.us          872                 :           1668 :         int         attr_count = tupDesc->natts;
                                873                 :                :         int         i;
                                874                 :                : 
 7929                           875         [ +  + ]:           5675 :         for (i = 0; i < attr_count; i++)
                                876                 :                :         {
 2429 andres@anarazel.de        877         [ +  + ]:           4007 :             if (TupleDescAttr(tupDesc, i)->attisdropped)
 7926 tgl@sss.pgh.pa.us         878                 :             98 :                 continue;
 1842 peter@eisentraut.org      879         [ +  + ]:           3909 :             if (TupleDescAttr(tupDesc, i)->attgenerated)
                                880                 :             27 :                 continue;
 7263 neilc@samurai.com         881                 :           3882 :             attnums = lappend_int(attnums, i + 1);
                                882                 :                :         }
                                883                 :                :     }
                                884                 :                :     else
                                885                 :                :     {
                                886                 :                :         /* Validate the user-supplied list and extract attnums */
                                887                 :                :         ListCell   *l;
                                888                 :                : 
 7926 tgl@sss.pgh.pa.us         889   [ +  -  +  +  :          35686 :         foreach(l, attnamelist)
                                              +  + ]
                                890                 :                :         {
 7909                           891                 :          28009 :             char       *name = strVal(lfirst(l));
                                892                 :                :             int         attnum;
                                893                 :                :             int         i;
                                894                 :                : 
                                895                 :                :             /* Lookup column name */
 6437                           896                 :          28009 :             attnum = InvalidAttrNumber;
                                897         [ +  + ]:        4937780 :             for (i = 0; i < tupDesc->natts; i++)
                                898                 :                :             {
 2429 andres@anarazel.de        899                 :        4937765 :                 Form_pg_attribute att = TupleDescAttr(tupDesc, i);
                                900                 :                : 
                                901         [ +  + ]:        4937765 :                 if (att->attisdropped)
 6437 tgl@sss.pgh.pa.us         902                 :            386 :                     continue;
 2429 andres@anarazel.de        903         [ +  + ]:        4937379 :                 if (namestrcmp(&(att->attname), name) == 0)
                                904                 :                :                 {
 1842 peter@eisentraut.org      905         [ +  + ]:          27994 :                     if (att->attgenerated)
                                906         [ +  - ]:             12 :                         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.")));
 2429 andres@anarazel.de        911                 :          27982 :                     attnum = att->attnum;
 6437 tgl@sss.pgh.pa.us         912                 :          27982 :                     break;
                                913                 :                :                 }
                                914                 :                :             }
 6597                           915         [ +  + ]:          27997 :             if (attnum == InvalidAttrNumber)
                                916                 :                :             {
 6437                           917         [ +  - ]:             15 :                 if (rel != NULL)
                                918         [ +  - ]:             15 :                     ereport(ERROR,
                                919                 :                :                             (errcode(ERRCODE_UNDEFINED_COLUMN),
                                920                 :                :                              errmsg("column \"%s\" of relation \"%s\" does not exist",
                                921                 :                :                                     name, RelationGetRelationName(rel))));
                                922                 :                :                 else
 6437 tgl@sss.pgh.pa.us         923         [ #  # ]:UBC           0 :                     ereport(ERROR,
                                924                 :                :                             (errcode(ERRCODE_UNDEFINED_COLUMN),
                                925                 :                :                              errmsg("column \"%s\" does not exist",
                                926                 :                :                                     name)));
                                927                 :                :             }
                                928                 :                :             /* Check for duplicates */
 7263 neilc@samurai.com         929         [ +  + ]:CBC       27982 :             if (list_member_int(attnums, attnum))
 7574 tgl@sss.pgh.pa.us         930         [ +  - ]:              3 :                 ereport(ERROR,
                                931                 :                :                         (errcode(ERRCODE_DUPLICATE_COLUMN),
                                932                 :                :                          errmsg("column \"%s\" specified more than once",
                                933                 :                :                                 name)));
 7263 neilc@samurai.com         934                 :          27979 :             attnums = lappend_int(attnums, attnum);
                                935                 :                :         }
                                936                 :                :     }
                                937                 :                : 
 7926 tgl@sss.pgh.pa.us         938                 :           9345 :     return attnums;
                                939                 :                : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622