LCOV - differential code coverage report
Current view: top level - src/bin/pg_dump - dumputils.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 83.9 % 323 271 4 3 17 28 4 65 15 187 16 72 4 9
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 11 11 2 2 7 2
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (60,120] days: 100.0 % 10 10 10
Legend: Lines: hit not hit (120,180] days: 50.0 % 2 1 1 1
(240..) days: 83.6 % 311 260 3 3 17 28 4 65 4 187 16 70
Function coverage date bins:
(240..) days: 84.6 % 13 11 2 2 7 2

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * Utility routines for SQL dumping
                                  4                 :  *
                                  5                 :  * Basically this is stuff that is useful in both pg_dump and pg_dumpall.
                                  6                 :  *
                                  7                 :  *
                                  8                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
                                  9                 :  * Portions Copyright (c) 1994, Regents of the University of California
                                 10                 :  *
                                 11                 :  * src/bin/pg_dump/dumputils.c
                                 12                 :  *
                                 13                 :  *-------------------------------------------------------------------------
                                 14                 :  */
                                 15                 : #include "postgres_fe.h"
                                 16                 : 
                                 17                 : #include <ctype.h>
                                 18                 : 
                                 19                 : #include "dumputils.h"
                                 20                 : #include "fe_utils/string_utils.h"
                                 21                 : 
                                 22                 : 
                                 23                 : static bool parseAclItem(const char *item, const char *type,
                                 24                 :                          const char *name, const char *subname, int remoteVersion,
                                 25                 :                          PQExpBuffer grantee, PQExpBuffer grantor,
                                 26                 :                          PQExpBuffer privs, PQExpBuffer privswgo);
                                 27                 : static char *dequoteAclUserName(PQExpBuffer output, char *input);
                                 28                 : static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
                                 29                 :                    const char *subname);
                                 30                 : 
                                 31                 : 
                                 32                 : /*
                                 33                 :  * Build GRANT/REVOKE command(s) for an object.
                                 34                 :  *
                                 35                 :  *  name: the object name, in the form to use in the commands (already quoted)
                                 36                 :  *  subname: the sub-object name, if any (already quoted); NULL if none
                                 37                 :  *  nspname: the namespace the object is in (NULL if none); not pre-quoted
                                 38                 :  *  type: the object type (as seen in GRANT command: must be one of
                                 39                 :  *      TABLE, SEQUENCE, FUNCTION, PROCEDURE, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
                                 40                 :  *      FOREIGN DATA WRAPPER, SERVER, PARAMETER or LARGE OBJECT)
                                 41                 :  *  acls: the ACL string fetched from the database
                                 42                 :  *  baseacls: the initial ACL string for this object
                                 43                 :  *  owner: username of object owner (will be passed through fmtId); can be
                                 44                 :  *      NULL or empty string to indicate "no owner known"
                                 45                 :  *  prefix: string to prefix to each generated command; typically empty
                                 46                 :  *  remoteVersion: version of database
                                 47                 :  *
                                 48                 :  * Returns true if okay, false if could not parse the acl string.
                                 49                 :  * The resulting commands (if any) are appended to the contents of 'sql'.
                                 50                 :  *
                                 51                 :  * baseacls is typically the result of acldefault() for the object's type
                                 52                 :  * and owner.  However, if there is a pg_init_privs entry for the object,
                                 53                 :  * it should instead be the initprivs ACLs.  When acls is itself a
                                 54                 :  * pg_init_privs entry, baseacls is what to dump that relative to; then
                                 55                 :  * it can be either an acldefault() value or an empty ACL "{}".
                                 56                 :  *
                                 57                 :  * Note: when processing a default ACL, prefix is "ALTER DEFAULT PRIVILEGES "
                                 58                 :  * or something similar, and name is an empty string.
                                 59                 :  *
                                 60                 :  * Note: beware of passing a fmtId() result directly as 'name' or 'subname',
                                 61                 :  * since this routine uses fmtId() internally.
                                 62                 :  */
                                 63                 : bool
 1868 tgl                        64 CBC       18120 : buildACLCommands(const char *name, const char *subname, const char *nspname,
                                 65                 :                  const char *type, const char *acls, const char *baseacls,
                                 66                 :                  const char *owner, const char *prefix, int remoteVersion,
                                 67                 :                  PQExpBuffer sql)
                                 68                 : {
 2979                            69           18120 :     bool        ok = true;
 2559 sfrost                     70           18120 :     char      **aclitems = NULL;
  489 tgl                        71           18120 :     char      **baseitems = NULL;
                                 72           18120 :     char      **grantitems = NULL;
                                 73           18120 :     char      **revokeitems = NULL;
 2559 sfrost                     74           18120 :     int         naclitems = 0;
  489 tgl                        75           18120 :     int         nbaseitems = 0;
                                 76           18120 :     int         ngrantitems = 0;
                                 77           18120 :     int         nrevokeitems = 0;
                                 78                 :     int         i;
                                 79                 :     PQExpBuffer grantee,
                                 80                 :                 grantor,
                                 81                 :                 privs,
                                 82                 :                 privswgo;
                                 83                 :     PQExpBuffer firstsql,
                                 84                 :                 secondsql;
                                 85                 : 
                                 86                 :     /*
                                 87                 :      * If the acl was NULL (initial default state), we need do nothing.  Note
                                 88                 :      * that this is distinguishable from all-privileges-revoked, which will
                                 89                 :      * look like an empty array ("{}").
                                 90                 :      */
                                 91           18120 :     if (acls == NULL || *acls == '\0')
 7254                            92              78 :         return true;            /* object has default permissions */
                                 93                 : 
                                 94                 :     /* treat empty-string owner same as NULL */
 6336                            95           18042 :     if (owner && *owner == '\0')
 6336 tgl                        96 UBC           0 :         owner = NULL;
                                 97                 : 
                                 98                 :     /* Parse the acls array */
  489 tgl                        99 CBC       18042 :     if (!parsePGArray(acls, &aclitems, &naclitems))
                                100                 :     {
  297 peter                     101 UNC           0 :         free(aclitems);
  489 tgl                       102 UIC           0 :         return false;
                                103                 :     }
                                104                 : 
  479 tgl                       105 ECB             :     /* Parse the baseacls too */
  479 tgl                       106 GIC       18042 :     if (!parsePGArray(baseacls, &baseitems, &nbaseitems))
 7192 tgl                       107 EUB             :     {
  297 peter                     108 UNC           0 :         free(aclitems);
                                109               0 :         free(baseitems);
  479 tgl                       110 UIC           0 :         return false;
                                111                 :     }
                                112                 : 
                                113                 :     /*
                                114                 :      * Compare the actual ACL with the base ACL, extracting the privileges
                                115                 :      * that need to be granted (i.e., are in the actual ACL but not the base
                                116                 :      * ACL) and the ones that need to be revoked (the reverse).  We use plain
                                117                 :      * string comparisons to check for matches.  In principle that could be
                                118                 :      * fooled by extraneous issues such as whitespace, but since all these
                                119                 :      * strings are the work of aclitemout(), it should be OK in practice.
  489 tgl                       120 ECB             :      * Besides, a false mismatch will just cause the output to be a little
                                121                 :      * more verbose than it really needed to be.
                                122                 :      */
  489 tgl                       123 CBC       18042 :     grantitems = (char **) pg_malloc(naclitems * sizeof(char *));
  489 tgl                       124 GIC       49994 :     for (i = 0; i < naclitems; i++)
 2559 sfrost                    125 ECB             :     {
  489 tgl                       126 GIC       31952 :         bool        found = false;
  489 tgl                       127 ECB             : 
  489 tgl                       128 GIC       46364 :         for (int j = 0; j < nbaseitems; j++)
 2559 sfrost                    129 ECB             :         {
  489 tgl                       130 CBC       44555 :             if (strcmp(aclitems[i], baseitems[j]) == 0)
                                131                 :             {
  489 tgl                       132 GIC       30143 :                 found = true;
  489 tgl                       133 CBC       30143 :                 break;
  489 tgl                       134 ECB             :             }
                                135                 :         }
  489 tgl                       136 CBC       31952 :         if (!found)
                                137            1809 :             grantitems[ngrantitems++] = aclitems[i];
                                138                 :     }
                                139           18042 :     revokeitems = (char **) pg_malloc(nbaseitems * sizeof(char *));
  489 tgl                       140 GIC       48538 :     for (i = 0; i < nbaseitems; i++)
  489 tgl                       141 ECB             :     {
  489 tgl                       142 GIC       30496 :         bool        found = false;
 7192 tgl                       143 ECB             : 
  489 tgl                       144 GIC       44225 :         for (int j = 0; j < naclitems; j++)
  489 tgl                       145 ECB             :         {
  489 tgl                       146 CBC       43872 :             if (strcmp(baseitems[i], aclitems[j]) == 0)
                                147                 :             {
  489 tgl                       148 GIC       30143 :                 found = true;
  489 tgl                       149 CBC       30143 :                 break;
  489 tgl                       150 ECB             :             }
                                151                 :         }
  489 tgl                       152 GIC       30496 :         if (!found)
                                153             353 :             revokeitems[nrevokeitems++] = baseitems[i];
  489 tgl                       154 ECB             :     }
                                155                 : 
                                156                 :     /* Prepare working buffers */
 7254 tgl                       157 CBC       18042 :     grantee = createPQExpBuffer();
 7254 tgl                       158 GIC       18042 :     grantor = createPQExpBuffer();
                                159           18042 :     privs = createPQExpBuffer();
                                160           18042 :     privswgo = createPQExpBuffer();
                                161                 : 
 7199 peter_e                   162 ECB             :     /*
 2559 sfrost                    163                 :      * At the end, these two will be pasted together to form the result.
                                164                 :      */
 7199 peter_e                   165 GIC       18042 :     firstsql = createPQExpBuffer();
                                166           18042 :     secondsql = createPQExpBuffer();
                                167                 : 
 7254 tgl                       168 ECB             :     /*
                                169                 :      * Build REVOKE statements for ACLs listed in revokeitems[].
                                170                 :      */
  476 tgl                       171 GIC       18395 :     for (i = 0; i < nrevokeitems; i++)
                                172                 :     {
                                173             353 :         if (!parseAclItem(revokeitems[i],
  476 tgl                       174 EUB             :                           type, name, subname, remoteVersion,
                                175                 :                           grantee, grantor, privs, NULL))
                                176                 :         {
  476 tgl                       177 UIC           0 :             ok = false;
  476 tgl                       178 LBC           0 :             break;
                                179                 :         }
 2559 sfrost                    180 ECB             : 
  476 tgl                       181 GIC         353 :         if (privs->len > 0)
  476 tgl                       182 ECB             :         {
  476 tgl                       183 CBC         353 :             appendPQExpBuffer(firstsql, "%sREVOKE %s ON %s ",
  476 tgl                       184 ECB             :                               prefix, privs->data, type);
  476 tgl                       185 CBC         353 :             if (nspname && *nspname)
                                186             203 :                 appendPQExpBuffer(firstsql, "%s.", fmtId(nspname));
  118 jdavis                    187 GNC         353 :             if (name && *name)
                                188             285 :                 appendPQExpBuffer(firstsql, "%s ", name);
                                189             353 :             appendPQExpBufferStr(firstsql, "FROM ");
  476 tgl                       190 CBC         353 :             if (grantee->len == 0)
  476 tgl                       191 GIC         182 :                 appendPQExpBufferStr(firstsql, "PUBLIC;\n");
  476 tgl                       192 ECB             :             else
  476 tgl                       193 CBC         171 :                 appendPQExpBuffer(firstsql, "%s;\n",
  476 tgl                       194 GIC         171 :                                   fmtId(grantee->data));
                                195                 :         }
                                196                 :     }
                                197                 : 
                                198                 :     /*
                                199                 :      * At this point we have issued REVOKE statements for all initial and
                                200                 :      * default privileges that are no longer present on the object, so we are
                                201                 :      * almost ready to GRANT the privileges listed in grantitems[].
                                202                 :      *
                                203                 :      * We still need some hacking though to cover the case where new default
                                204                 :      * public privileges are added in new versions: the REVOKE ALL will revoke
                                205                 :      * them, leading to behavior different from what the old version had,
                                206                 :      * which is generally not what's wanted.  So add back default privs if the
                                207                 :      * source database is too old to have had that particular priv.  (As of
                                208                 :      * right now, no such cases exist in supported versions.)
                                209                 :      */
                                210                 : 
                                211                 :     /*
                                212                 :      * Scan individual ACL items to be granted.
                                213                 :      *
                                214                 :      * The order in which privileges appear in the ACL string (the order they
                                215                 :      * have been GRANT'd in, which the backend maintains) must be preserved to
                                216                 :      * ensure that GRANTs WITH GRANT OPTION and subsequent GRANTs based on
                                217                 :      * those are dumped in the correct order.  However, some old server
                                218                 :      * versions will show grants to PUBLIC before the owner's own grants; for
                                219                 :      * consistency's sake, force the owner's grants to be output first.
  489 tgl                       220 ECB             :      */
  489 tgl                       221 GIC       19851 :     for (i = 0; i < ngrantitems; i++)
 7254 tgl                       222 ECB             :     {
  489 tgl                       223 GIC        1809 :         if (parseAclItem(grantitems[i], type, name, subname, remoteVersion,
                                224                 :                          grantee, grantor, privs, privswgo))
                                225                 :         {
                                226                 :             /*
                                227                 :              * If the grantor isn't the owner, we'll need to use SET SESSION
                                228                 :              * AUTHORIZATION to become the grantor.  Issue the SET/RESET only
                                229                 :              * if there's something useful to do.
 2559 sfrost                    230 ECB             :              */
  489 tgl                       231 GIC        1809 :             if (privs->len > 0 || privswgo->len > 0)
                                232                 :             {
                                233                 :                 PQExpBuffer thissql;
                                234                 : 
  489 tgl                       235 ECB             :                 /* Set owner as grantor if that's not explicit in the ACL */
  489 tgl                       236 GBC        1809 :                 if (grantor->len == 0 && owner)
  489 tgl                       237 UIC           0 :                     printfPQExpBuffer(grantor, "%s", owner);
                                238                 : 
  489 tgl                       239 ECB             :                 /* Make sure owner's own grants are output before others */
  489 tgl                       240 CBC        1809 :                 if (owner &&
                                241            1809 :                     strcmp(grantee->data, owner) == 0 &&
                                242             124 :                     strcmp(grantor->data, owner) == 0)
  489 tgl                       243 GIC         124 :                     thissql = firstsql;
  489 tgl                       244 ECB             :                 else
  489 tgl                       245 GIC        1685 :                     thissql = secondsql;
 7188 bruce                     246 ECB             : 
 7199 peter_e                   247 CBC        1809 :                 if (grantor->len > 0
 7199 peter_e                   248 GBC        1809 :                     && (!owner || strcmp(owner, grantor->data) != 0))
  489 tgl                       249 UBC           0 :                     appendPQExpBuffer(thissql, "SET SESSION AUTHORIZATION %s;\n",
 7199 peter_e                   250 UIC           0 :                                       fmtId(grantor->data));
 7199 peter_e                   251 ECB             : 
 7254 tgl                       252 GIC        1809 :                 if (privs->len > 0)
 7254 tgl                       253 ECB             :                 {
  489 tgl                       254 GIC        1807 :                     appendPQExpBuffer(thissql, "%sGRANT %s ON %s ",
 1868 tgl                       255 ECB             :                                       prefix, privs->data, type);
 1868 tgl                       256 CBC        1807 :                     if (nspname && *nspname)
  489                           257            1551 :                         appendPQExpBuffer(thissql, "%s.", fmtId(nspname));
  118 jdavis                    258 GNC        1807 :                     if (name && *name)
                                259            1703 :                         appendPQExpBuffer(thissql, "%s ", name);
                                260            1807 :                     appendPQExpBufferStr(thissql, "TO ");
 7254 tgl                       261 CBC        1807 :                     if (grantee->len == 0)
  489                           262            1059 :                         appendPQExpBufferStr(thissql, "PUBLIC;\n");
 7254 tgl                       263 ECB             :                     else
  489 tgl                       264 GIC         748 :                         appendPQExpBuffer(thissql, "%s;\n", fmtId(grantee->data));
 7254 tgl                       265 ECB             :                 }
 7254 tgl                       266 GIC        1809 :                 if (privswgo->len > 0)
 7254 tgl                       267 ECB             :                 {
  489 tgl                       268 GIC          19 :                     appendPQExpBuffer(thissql, "%sGRANT %s ON %s ",
 1868 tgl                       269 ECB             :                                       prefix, privswgo->data, type);
 1868 tgl                       270 GIC          19 :                     if (nspname && *nspname)
  489 tgl                       271 CBC          18 :                         appendPQExpBuffer(thissql, "%s.", fmtId(nspname));
  118 jdavis                    272 GNC          19 :                     if (name && *name)
                                273              19 :                         appendPQExpBuffer(thissql, "%s ", name);
                                274              19 :                     appendPQExpBufferStr(thissql, "TO ");
 7254 tgl                       275 CBC          19 :                     if (grantee->len == 0)
  489 tgl                       276 LBC           0 :                         appendPQExpBufferStr(thissql, "PUBLIC");
 7254 tgl                       277 ECB             :                     else
  489 tgl                       278 CBC          19 :                         appendPQExpBufferStr(thissql, fmtId(grantee->data));
  489 tgl                       279 GBC          19 :                     appendPQExpBufferStr(thissql, " WITH GRANT OPTION;\n");
                                280                 :                 }
 7199 peter_e                   281 ECB             : 
 7199 peter_e                   282 CBC        1809 :                 if (grantor->len > 0
 7199 peter_e                   283 GIC        1809 :                     && (!owner || strcmp(owner, grantor->data) != 0))
  489 tgl                       284 UIC           0 :                     appendPQExpBufferStr(thissql, "RESET SESSION AUTHORIZATION;\n");
 7254 tgl                       285 ECB             :             }
                                286                 :         }
  489 tgl                       287 EUB             :         else
                                288                 :         {
                                289                 :             /* parseAclItem failed, give up */
  489 tgl                       290 UIC           0 :             ok = false;
                                291               0 :             break;
                                292                 :         }
 5190 tgl                       293 EUB             :     }
 7254                           294                 : 
 7254 tgl                       295 GIC       18042 :     destroyPQExpBuffer(grantee);
                                296           18042 :     destroyPQExpBuffer(grantor);
                                297           18042 :     destroyPQExpBuffer(privs);
 7254 tgl                       298 CBC       18042 :     destroyPQExpBuffer(privswgo);
 7254 tgl                       299 ECB             : 
 7199 peter_e                   300 CBC       18042 :     appendPQExpBuffer(sql, "%s%s", firstsql->data, secondsql->data);
                                301           18042 :     destroyPQExpBuffer(firstsql);
 7199 peter_e                   302 GIC       18042 :     destroyPQExpBuffer(secondsql);
 7199 peter_e                   303 ECB             : 
  297 peter                     304 GNC       18042 :     free(aclitems);
                                305           18042 :     free(baseitems);
                                306           18042 :     free(grantitems);
                                307           18042 :     free(revokeitems);
 7192 tgl                       308 ECB             : 
 2979 tgl                       309 GIC       18042 :     return ok;
                                310                 : }
                                311                 : 
                                312                 : /*
                                313                 :  * Build ALTER DEFAULT PRIVILEGES command(s) for a single pg_default_acl entry.
                                314                 :  *
                                315                 :  *  type: the object type (TABLES, FUNCTIONS, etc)
                                316                 :  *  nspname: schema name, or NULL for global default privileges
                                317                 :  *  acls: the ACL string fetched from the database
                                318                 :  *  acldefault: the appropriate default ACL for the object type and owner
                                319                 :  *  owner: username of privileges owner (will be passed through fmtId)
                                320                 :  *  remoteVersion: version of database
                                321                 :  *
                                322                 :  * Returns true if okay, false if could not parse the acl string.
                                323                 :  * The resulting commands (if any) are appended to the contents of 'sql'.
                                324                 :  */
 4934 tgl                       325 ECB             : bool
 4934 tgl                       326 GIC         138 : buildDefaultACLCommands(const char *type, const char *nspname,
                                327                 :                         const char *acls, const char *acldefault,
                                328                 :                         const char *owner,
                                329                 :                         int remoteVersion,
                                330                 :                         PQExpBuffer sql)
                                331                 : {
                                332                 :     PQExpBuffer prefix;
 4934 tgl                       333 ECB             : 
 4934 tgl                       334 GIC         138 :     prefix = createPQExpBuffer();
                                335                 : 
                                336                 :     /*
                                337                 :      * We incorporate the target role directly into the command, rather than
                                338                 :      * playing around with SET ROLE or anything like that.  This is so that a
                                339                 :      * permissions error leads to nothing happening, rather than changing
                                340                 :      * default privileges for the wrong user.
 4934 tgl                       341 ECB             :      */
 4934 tgl                       342 GIC         138 :     appendPQExpBuffer(prefix, "ALTER DEFAULT PRIVILEGES FOR ROLE %s ",
 4934 tgl                       343 ECB             :                       fmtId(owner));
 4934 tgl                       344 CBC         138 :     if (nspname)
 4934 tgl                       345 GIC          70 :         appendPQExpBuffer(prefix, "IN SCHEMA %s ", fmtId(nspname));
                                346                 : 
                                347                 :     /*
                                348                 :      * There's no such thing as initprivs for a default ACL, so the base ACL
                                349                 :      * is always just the object-type-specific default.
  489 tgl                       350 ECB             :      */
 1868 tgl                       351 GIC         138 :     if (!buildACLCommands("", NULL, NULL, type,
  489 tgl                       352 ECB             :                           acls, acldefault, owner,
 2259 sfrost                    353 GIC         138 :                           prefix->data, remoteVersion, sql))
 2164 sfrost                    354 EUB             :     {
 2164 sfrost                    355 UBC           0 :         destroyPQExpBuffer(prefix);
 2259 sfrost                    356 UIC           0 :         return false;
                                357                 :     }
 4934 tgl                       358 ECB             : 
 4934 tgl                       359 GIC         138 :     destroyPQExpBuffer(prefix);
 4934 tgl                       360 ECB             : 
 2259 sfrost                    361 GIC         138 :     return true;
                                362                 : }
                                363                 : 
                                364                 : /*
                                365                 :  * This will parse an aclitem string, having the general form
                                366                 :  *      username=privilegecodes/grantor
                                367                 :  *
                                368                 :  * Returns true on success, false on parse error.  On success, the components
                                369                 :  * of the string are returned in the PQExpBuffer parameters.
                                370                 :  *
                                371                 :  * The returned grantee string will be the dequoted username, or an empty
                                372                 :  * string in the case of a grant to PUBLIC.  The returned grantor is the
                                373                 :  * dequoted grantor name.  Privilege characters are translated to GRANT/REVOKE
                                374                 :  * comma-separated privileges lists.  If "privswgo" is non-NULL, the result is
                                375                 :  * separate lists for privileges with grant option ("privswgo") and without
                                376                 :  * ("privs").  Otherwise, "privs" bears every relevant privilege, ignoring the
                                377                 :  * grant option distinction.
                                378                 :  *
                                379                 :  * Note: for cross-version compatibility, it's important to use ALL to
                                380                 :  * represent the privilege sets whenever appropriate.
                                381                 :  */
 7254 tgl                       382 ECB             : static bool
 5190 tgl                       383 GIC        2162 : parseAclItem(const char *item, const char *type,
                                384                 :              const char *name, const char *subname, int remoteVersion,
                                385                 :              PQExpBuffer grantee, PQExpBuffer grantor,
                                386                 :              PQExpBuffer privs, PQExpBuffer privswgo)
                                387                 : {
 7254 tgl                       388 ECB             :     char       *buf;
 7254 tgl                       389 CBC        2162 :     bool        all_with_go = true;
 7254 tgl                       390 GIC        2162 :     bool        all_without_go = true;
                                391                 :     char       *eqpos;
                                392                 :     char       *slpos;
                                393                 :     char       *pos;
 7254 tgl                       394 ECB             : 
 1436 michael                   395 GIC        2162 :     buf = pg_strdup(item);
                                396                 : 
 7192 tgl                       397 ECB             :     /* user or group name is string up to = */
  489 tgl                       398 CBC        2162 :     eqpos = dequoteAclUserName(grantee, buf);
 7192 tgl                       399 GIC        2162 :     if (*eqpos != '=')
 3962 tgl                       400 EUB             :     {
 1436 michael                   401 UBC           0 :         pg_free(buf);
 7254 tgl                       402 UIC           0 :         return false;
                                403                 :     }
                                404                 : 
 2370 tgl                       405 ECB             :     /* grantor should appear after / */
 7254 tgl                       406 CBC        2162 :     slpos = strchr(eqpos + 1, '/');
 7254 tgl                       407 GIC        2162 :     if (slpos)
 7254 tgl                       408 ECB             :     {
 7192 tgl                       409 CBC        2162 :         *slpos++ = '\0';
  489                           410            2162 :         slpos = dequoteAclUserName(grantor, slpos);
 7192 tgl                       411 GIC        2162 :         if (*slpos != '\0')
 3962 tgl                       412 EUB             :         {
 1436 michael                   413 UBC           0 :             pg_free(buf);
 7192 tgl                       414 UIC           0 :             return false;
                                415                 :         }
                                416                 :     }
                                417                 :     else
 2370 tgl                       418 EUB             :     {
 1436 michael                   419 UBC           0 :         pg_free(buf);
 2370 tgl                       420 UIC           0 :         return false;
                                421                 :     }
                                422                 : 
                                423                 :     /* privilege codes */
                                424                 : #define CONVERT_PRIV(code, keywd) \
                                425                 : do { \
                                426                 :     if ((pos = strchr(eqpos + 1, code))) \
                                427                 :     { \
                                428                 :         if (*(pos + 1) == '*' && privswgo != NULL) \
                                429                 :         { \
                                430                 :             AddAcl(privswgo, keywd, subname); \
                                431                 :             all_without_go = false; \
                                432                 :         } \
                                433                 :         else \
                                434                 :         { \
                                435                 :             AddAcl(privs, keywd, subname); \
                                436                 :             all_with_go = false; \
                                437                 :         } \
                                438                 :     } \
                                439                 :     else \
                                440                 :         all_with_go = all_without_go = false; \
                                441                 : } while (0)
 7254 tgl                       442 ECB             : 
 7254 tgl                       443 CBC        2162 :     resetPQExpBuffer(privs);
 7254 tgl                       444 GIC        2162 :     resetPQExpBuffer(privswgo);
 7254 tgl                       445 ECB             : 
 4927 tgl                       446 CBC        2162 :     if (strcmp(type, "TABLE") == 0 || strcmp(type, "SEQUENCE") == 0 ||
 4927 tgl                       447 GIC         701 :         strcmp(type, "TABLES") == 0 || strcmp(type, "SEQUENCES") == 0)
 7254 tgl                       448 ECB             :     {
 7254 tgl                       449 GIC        1564 :         CONVERT_PRIV('r', "SELECT");
 6031 bruce                     450 ECB             : 
 4927 tgl                       451 CBC        1564 :         if (strcmp(type, "SEQUENCE") == 0 ||
 4927 tgl                       452 GIC        1513 :             strcmp(type, "SEQUENCES") == 0)
 6287 bruce                     453 ECB             :             /* sequence only */
 6287 bruce                     454 GIC          51 :             CONVERT_PRIV('U', "USAGE");
                                455                 :         else
                                456                 :         {
 6287 bruce                     457 ECB             :             /* table only */
 6287 bruce                     458 CBC        1513 :             CONVERT_PRIV('a', "INSERT");
 2370 tgl                       459 GIC        1513 :             CONVERT_PRIV('x', "REFERENCES");
 5190 tgl                       460 ECB             :             /* rest are not applicable to columns */
 5190 tgl                       461 GIC        1513 :             if (subname == NULL)
 5190 tgl                       462 ECB             :             {
 2370 tgl                       463 CBC         410 :                 CONVERT_PRIV('d', "DELETE");
                                464             410 :                 CONVERT_PRIV('t', "TRIGGER");
  481                           465             410 :                 CONVERT_PRIV('D', "TRUNCATE");
  117 jdavis                    466 GNC         410 :                 CONVERT_PRIV('m', "MAINTAIN");
                                467                 :             }
                                468                 :         }
                                469                 : 
                                470                 :         /* UPDATE */
 2370 tgl                       471 CBC        1564 :         CONVERT_PRIV('w', "UPDATE");
                                472                 :     }
 4927                           473             598 :     else if (strcmp(type, "FUNCTION") == 0 ||
                                474             445 :              strcmp(type, "FUNCTIONS") == 0)
 7254                           475             222 :         CONVERT_PRIV('X', "EXECUTE");
 1956 peter_e                   476             376 :     else if (strcmp(type, "PROCEDURE") == 0 ||
                                477             376 :              strcmp(type, "PROCEDURES") == 0)
 1956 peter_e                   478 UBC           0 :         CONVERT_PRIV('X', "EXECUTE");
 7254 tgl                       479 CBC         376 :     else if (strcmp(type, "LANGUAGE") == 0)
                                480              40 :         CONVERT_PRIV('U', "USAGE");
 2203 teodor                    481             336 :     else if (strcmp(type, "SCHEMA") == 0 ||
 2154 tgl                       482             256 :              strcmp(type, "SCHEMAS") == 0)
                                483                 :     {
 7254                           484              80 :         CONVERT_PRIV('C', "CREATE");
                                485              80 :         CONVERT_PRIV('U', "USAGE");
                                486                 :     }
                                487             256 :     else if (strcmp(type, "DATABASE") == 0)
                                488                 :     {
                                489               8 :         CONVERT_PRIV('C', "CREATE");
 6188                           490               8 :         CONVERT_PRIV('c', "CONNECT");
 7254                           491               8 :         CONVERT_PRIV('T', "TEMPORARY");
                                492                 :     }
 6869                           493             248 :     else if (strcmp(type, "TABLESPACE") == 0)
 6869 tgl                       494 UBC           0 :         CONVERT_PRIV('C', "CREATE");
 3773 tgl                       495 CBC         248 :     else if (strcmp(type, "TYPE") == 0 ||
                                496             107 :              strcmp(type, "TYPES") == 0)
                                497             141 :         CONVERT_PRIV('U', "USAGE");
 5224 peter_e                   498             107 :     else if (strcmp(type, "FOREIGN DATA WRAPPER") == 0)
                                499              34 :         CONVERT_PRIV('U', "USAGE");
 4785 heikki.linnakangas        500              73 :     else if (strcmp(type, "FOREIGN SERVER") == 0)
 5224 peter_e                   501              34 :         CONVERT_PRIV('U', "USAGE");
 4481 rhaas                     502              39 :     else if (strcmp(type, "FOREIGN TABLE") == 0)
 4481 rhaas                     503 UBC           0 :         CONVERT_PRIV('r', "SELECT");
  368 tgl                       504 CBC          39 :     else if (strcmp(type, "PARAMETER") == 0)
                                505                 :     {
                                506               3 :         CONVERT_PRIV('s', "SET");
                                507               3 :         CONVERT_PRIV('A', "ALTER SYSTEM");
                                508                 :     }
 4867 itagaki.takahiro          509              36 :     else if (strcmp(type, "LARGE OBJECT") == 0)
                                510                 :     {
                                511              36 :         CONVERT_PRIV('r', "SELECT");
                                512              36 :         CONVERT_PRIV('w', "UPDATE");
                                513                 :     }
                                514                 :     else
 7254 tgl                       515 UBC           0 :         abort();
                                516                 : 
                                517                 : #undef CONVERT_PRIV
                                518                 : 
 7254 tgl                       519 CBC        2162 :     if (all_with_go)
                                520                 :     {
                                521               2 :         resetPQExpBuffer(privs);
                                522               2 :         printfPQExpBuffer(privswgo, "ALL");
 5190                           523               2 :         if (subname)
 5190 tgl                       524 UBC           0 :             appendPQExpBuffer(privswgo, "(%s)", subname);
                                525                 :     }
 7254 tgl                       526 CBC        2160 :     else if (all_without_go)
                                527                 :     {
                                528             601 :         resetPQExpBuffer(privswgo);
                                529             601 :         printfPQExpBuffer(privs, "ALL");
 5190                           530             601 :         if (subname)
 5190 tgl                       531 UBC           0 :             appendPQExpBuffer(privs, "(%s)", subname);
                                532                 :     }
                                533                 : 
 1436 michael                   534 CBC        2162 :     pg_free(buf);
                                535                 : 
 7254 tgl                       536            2162 :     return true;
                                537                 : }
                                538                 : 
                                539                 : /*
                                540                 :  * Transfer the role name at *input into the output buffer, adding
                                541                 :  * quoting according to the same rules as putid() in backend's acl.c.
                                542                 :  */
                                543                 : void
  489                           544             345 : quoteAclUserName(PQExpBuffer output, const char *input)
                                545                 : {
                                546                 :     const char *src;
                                547             345 :     bool        safe = true;
                                548                 : 
                                549            5760 :     for (src = input; *src; src++)
                                550                 :     {
                                551                 :         /* This test had better match what putid() does */
                                552            5565 :         if (!isalnum((unsigned char) *src) && *src != '_')
                                553                 :         {
                                554             150 :             safe = false;
                                555             150 :             break;
                                556                 :         }
                                557                 :     }
                                558             345 :     if (!safe)
                                559             150 :         appendPQExpBufferChar(output, '"');
                                560            7110 :     for (src = input; *src; src++)
                                561                 :     {
                                562                 :         /* A double quote character in a username is encoded as "" */
                                563            6765 :         if (*src == '"')
                                564             150 :             appendPQExpBufferChar(output, '"');
                                565            6765 :         appendPQExpBufferChar(output, *src);
                                566                 :     }
                                567             345 :     if (!safe)
                                568             150 :         appendPQExpBufferChar(output, '"');
                                569             345 : }
                                570                 : 
                                571                 : /*
                                572                 :  * Transfer a user or group name starting at *input into the output buffer,
                                573                 :  * dequoting if needed.  Returns a pointer to just past the input name.
                                574                 :  * The name is taken to end at an unquoted '=' or end of string.
                                575                 :  * Note: unlike quoteAclUserName(), this first clears the output buffer.
                                576                 :  */
                                577                 : static char *
                                578            4324 : dequoteAclUserName(PQExpBuffer output, char *input)
                                579                 : {
 7192                           580            4324 :     resetPQExpBuffer(output);
                                581                 : 
                                582           38306 :     while (*input && *input != '=')
                                583                 :     {
                                584                 :         /*
                                585                 :          * If user name isn't quoted, then just add it to the output buffer
                                586                 :          */
                                587           33982 :         if (*input != '"')
                                588           33914 :             appendPQExpBufferChar(output, *input++);
                                589                 :         else
                                590                 :         {
                                591                 :             /* Otherwise, it's a quoted username */
                                592              68 :             input++;
                                593                 :             /* Loop until we come across an unescaped quote */
 7178                           594            1632 :             while (!(*input == '"' && *(input + 1) != '"'))
                                595                 :             {
 7192                           596            1564 :                 if (*input == '\0')
 2118 tgl                       597 UBC           0 :                     return input;   /* really a syntax error... */
                                598                 : 
                                599                 :                 /*
                                600                 :                  * Quoting convention is to escape " as "".  Keep this code in
                                601                 :                  * sync with putid() in backend's acl.c.
                                602                 :                  */
 7178 tgl                       603 CBC        1564 :                 if (*input == '"' && *(input + 1) == '"')
                                604              68 :                     input++;
 7192                           605            1564 :                 appendPQExpBufferChar(output, *input++);
                                606                 :             }
                                607              68 :             input++;
                                608                 :         }
                                609                 :     }
                                610            4324 :     return input;
                                611                 : }
                                612                 : 
                                613                 : /*
                                614                 :  * Append a privilege keyword to a keyword list, inserting comma if needed.
                                615                 :  */
                                616                 : static void
 5190                           617            2815 : AddAcl(PQExpBuffer aclbuf, const char *keyword, const char *subname)
                                618                 : {
 7254                           619            2815 :     if (aclbuf->len > 0)
                                620             636 :         appendPQExpBufferChar(aclbuf, ',');
 3429 heikki.linnakangas        621            2815 :     appendPQExpBufferStr(aclbuf, keyword);
 5190 tgl                       622            2815 :     if (subname)
                                623            1103 :         appendPQExpBuffer(aclbuf, "(%s)", subname);
 7254                           624            2815 : }
                                625                 : 
                                626                 : 
                                627                 : /*
                                628                 :  * buildShSecLabelQuery
                                629                 :  *
                                630                 :  * Build a query to retrieve security labels for a shared object.
                                631                 :  * The object is identified by its OID plus the name of the catalog
                                632                 :  * it can be found in (e.g., "pg_database" for database names).
                                633                 :  * The query is appended to "sql".  (We don't execute it here so as to
                                634                 :  * keep this file free of assumptions about how to deal with SQL errors.)
                                635                 :  */
                                636                 : void
  957 peter                     637             107 : buildShSecLabelQuery(const char *catalog_name, Oid objectId,
                                638                 :                      PQExpBuffer sql)
                                639                 : {
 4281 rhaas                     640             107 :     appendPQExpBuffer(sql,
                                641                 :                       "SELECT provider, label FROM pg_catalog.pg_shseclabel "
                                642                 :                       "WHERE classoid = 'pg_catalog.%s'::pg_catalog.regclass "
                                643                 :                       "AND objoid = '%u'", catalog_name, objectId);
                                644             107 : }
                                645                 : 
                                646                 : /*
                                647                 :  * emitShSecLabels
                                648                 :  *
                                649                 :  * Construct SECURITY LABEL commands using the data retrieved by the query
                                650                 :  * generated by buildShSecLabelQuery, and append them to "buffer".
                                651                 :  * Here, the target object is identified by its type name (e.g. "DATABASE")
                                652                 :  * and its name (not pre-quoted).
                                653                 :  */
                                654                 : void
                                655             107 : emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer,
                                656                 :                 const char *objtype, const char *objname)
                                657                 : {
                                658                 :     int         i;
                                659                 : 
                                660             107 :     for (i = 0; i < PQntuples(res); i++)
                                661                 :     {
 3955 bruce                     662 UBC           0 :         char       *provider = PQgetvalue(res, i, 0);
                                663               0 :         char       *label = PQgetvalue(res, i, 1);
                                664                 : 
                                665                 :         /* must use fmtId result before calling it again */
 4281 rhaas                     666               0 :         appendPQExpBuffer(buffer,
                                667                 :                           "SECURITY LABEL FOR %s ON %s",
                                668                 :                           fmtId(provider), objtype);
                                669               0 :         appendPQExpBuffer(buffer,
                                670                 :                           " %s IS ",
                                671                 :                           fmtId(objname));
                                672               0 :         appendStringLiteralConn(buffer, label, conn);
 3429 heikki.linnakangas        673               0 :         appendPQExpBufferStr(buffer, ";\n");
                                674                 :     }
 4281 rhaas                     675 CBC         107 : }
                                676                 : 
                                677                 : 
                                678                 : /*
                                679                 :  * Detect whether the given GUC variable is of GUC_LIST_QUOTE type.
                                680                 :  *
                                681                 :  * It'd be better if we could inquire this directly from the backend; but even
                                682                 :  * if there were a function for that, it could only tell us about variables
                                683                 :  * currently known to guc.c, so that it'd be unsafe for extensions to declare
                                684                 :  * GUC_LIST_QUOTE variables anyway.  Lacking a solution for that, it doesn't
                                685                 :  * seem worth the work to do more than have this list, which must be kept in
                                686                 :  * sync with the variables actually marked GUC_LIST_QUOTE in guc_tables.c.
                                687                 :  */
                                688                 : bool
 1845 tgl                       689              65 : variable_is_guc_list_quote(const char *name)
                                690                 : {
  883 michael                   691             125 :     if (pg_strcasecmp(name, "local_preload_libraries") == 0 ||
                                692             115 :         pg_strcasecmp(name, "search_path") == 0 ||
 1845 tgl                       693             110 :         pg_strcasecmp(name, "session_preload_libraries") == 0 ||
                                694             110 :         pg_strcasecmp(name, "shared_preload_libraries") == 0 ||
  883 michael                   695             110 :         pg_strcasecmp(name, "temp_tablespaces") == 0 ||
                                696              55 :         pg_strcasecmp(name, "unix_socket_directories") == 0)
 1845 tgl                       697              10 :         return true;
                                698                 :     else
                                699              55 :         return false;
                                700                 : }
                                701                 : 
                                702                 : /*
                                703                 :  * SplitGUCList --- parse a string containing identifiers or file names
                                704                 :  *
                                705                 :  * This is used to split the value of a GUC_LIST_QUOTE GUC variable, without
                                706                 :  * presuming whether the elements will be taken as identifiers or file names.
                                707                 :  * See comparable code in src/backend/utils/adt/varlena.c.
                                708                 :  *
                                709                 :  * Inputs:
                                710                 :  *  rawstring: the input string; must be overwritable!  On return, it's
                                711                 :  *             been modified to contain the separated identifiers.
                                712                 :  *  separator: the separator punctuation expected between identifiers
                                713                 :  *             (typically '.' or ',').  Whitespace may also appear around
                                714                 :  *             identifiers.
                                715                 :  * Outputs:
                                716                 :  *  namelist: receives a malloc'd, null-terminated array of pointers to
                                717                 :  *            identifiers within rawstring.  Caller should free this
                                718                 :  *            even on error return.
                                719                 :  *
                                720                 :  * Returns true if okay, false if there is a syntax error in the string.
                                721                 :  */
                                722                 : bool
 1713                           723              10 : SplitGUCList(char *rawstring, char separator,
                                724                 :              char ***namelist)
                                725                 : {
                                726              10 :     char       *nextp = rawstring;
                                727              10 :     bool        done = false;
                                728                 :     char      **nextptr;
                                729                 : 
                                730                 :     /*
                                731                 :      * Since we disallow empty identifiers, this is a conservative
                                732                 :      * overestimate of the number of pointers we could need.  Allow one for
                                733                 :      * list terminator.
                                734                 :      */
                                735              10 :     *namelist = nextptr = (char **)
                                736              10 :         pg_malloc((strlen(rawstring) / 2 + 2) * sizeof(char *));
                                737              10 :     *nextptr = NULL;
                                738                 : 
                                739              10 :     while (isspace((unsigned char) *nextp))
 1713 tgl                       740 UBC           0 :         nextp++;                /* skip leading whitespace */
                                741                 : 
 1713 tgl                       742 CBC          10 :     if (*nextp == '\0')
 1713 tgl                       743 UBC           0 :         return true;            /* allow empty string */
                                744                 : 
                                745                 :     /* At the top of the loop, we are at start of a new identifier. */
                                746                 :     do
                                747                 :     {
                                748                 :         char       *curname;
                                749                 :         char       *endp;
                                750                 : 
 1713 tgl                       751 CBC          25 :         if (*nextp == '"')
                                752                 :         {
                                753                 :             /* Quoted name --- collapse quote-quote pairs */
                                754              20 :             curname = nextp + 1;
                                755                 :             for (;;)
                                756                 :             {
                                757              30 :                 endp = strchr(nextp + 1, '"');
                                758              25 :                 if (endp == NULL)
 1713 tgl                       759 UBC           0 :                     return false;   /* mismatched quotes */
 1713 tgl                       760 CBC          25 :                 if (endp[1] != '"')
                                761              20 :                     break;      /* found end of quoted name */
                                762                 :                 /* Collapse adjacent quotes into one quote, and look again */
                                763               5 :                 memmove(endp, endp + 1, strlen(endp));
                                764               5 :                 nextp = endp;
                                765                 :             }
                                766                 :             /* endp now points at the terminating quote */
                                767              20 :             nextp = endp + 1;
                                768                 :         }
                                769                 :         else
                                770                 :         {
                                771                 :             /* Unquoted name --- extends to separator or whitespace */
                                772               5 :             curname = nextp;
                                773              55 :             while (*nextp && *nextp != separator &&
                                774              50 :                    !isspace((unsigned char) *nextp))
                                775              50 :                 nextp++;
                                776               5 :             endp = nextp;
                                777               5 :             if (curname == nextp)
 1713 tgl                       778 UBC           0 :                 return false;   /* empty unquoted name not allowed */
                                779                 :         }
                                780                 : 
 1713 tgl                       781 CBC          25 :         while (isspace((unsigned char) *nextp))
 1713 tgl                       782 UBC           0 :             nextp++;            /* skip trailing whitespace */
                                783                 : 
 1713 tgl                       784 CBC          25 :         if (*nextp == separator)
                                785                 :         {
                                786              15 :             nextp++;
                                787              30 :             while (isspace((unsigned char) *nextp))
                                788              15 :                 nextp++;        /* skip leading whitespace for next */
                                789                 :             /* we expect another name, so done remains false */
                                790                 :         }
                                791              10 :         else if (*nextp == '\0')
                                792              10 :             done = true;
                                793                 :         else
 1713 tgl                       794 UBC           0 :             return false;       /* invalid syntax */
                                795                 : 
                                796                 :         /* Now safe to overwrite separator with a null */
 1713 tgl                       797 CBC          25 :         *endp = '\0';
                                798                 : 
                                799                 :         /*
                                800                 :          * Finished isolating current name --- add it to output array
                                801                 :          */
                                802              25 :         *nextptr++ = curname;
                                803                 : 
                                804                 :         /* Loop back if we didn't reach end of string */
                                805              25 :     } while (!done);
                                806                 : 
                                807              10 :     *nextptr = NULL;
                                808              10 :     return true;
                                809                 : }
                                810                 : 
                                811                 : /*
                                812                 :  * Helper function for dumping "ALTER DATABASE/ROLE SET ..." commands.
                                813                 :  *
                                814                 :  * Parse the contents of configitem (a "name=value" string), wrap it in
                                815                 :  * a complete ALTER command, and append it to buf.
                                816                 :  *
                                817                 :  * type is DATABASE or ROLE, and name is the name of the database or role.
                                818                 :  * If we need an "IN" clause, type2 and name2 similarly define what to put
                                819                 :  * there; otherwise they should be NULL.
                                820                 :  * conn is used only to determine string-literal quoting conventions.
                                821                 :  */
                                822                 : void
 1903                           823              30 : makeAlterConfigCommand(PGconn *conn, const char *configitem,
                                824                 :                        const char *userset,
                                825                 :                        const char *type, const char *name,
                                826                 :                        const char *type2, const char *name2,
                                827                 :                        PQExpBuffer buf)
                                828                 : {
                                829                 :     char       *mine;
                                830                 :     char       *pos;
                                831                 : 
                                832                 :     /* Parse the configitem.  If we can't find an "=", silently do nothing. */
 1903 tgl                       833 GIC          30 :     mine = pg_strdup(configitem);
 1903 tgl                       834 CBC          30 :     pos = strchr(mine, '=');
                                835              30 :     if (pos == NULL)
 1903 tgl                       836 ECB             :     {
 1903 tgl                       837 UIC           0 :         pg_free(mine);
 1903 tgl                       838 UBC           0 :         return;
 1903 tgl                       839 EUB             :     }
 1903 tgl                       840 GIC          30 :     *pos++ = '\0';
 1903 tgl                       841 ECB             : 
                                842                 :     /* Build the command, with suitable quoting for everything. */
 1903 tgl                       843 GIC          30 :     appendPQExpBuffer(buf, "ALTER %s %s ", type, fmtId(name));
 1903 tgl                       844 CBC          30 :     if (type2 != NULL && name2 != NULL)
 1903 tgl                       845 LBC           0 :         appendPQExpBuffer(buf, "IN %s %s ", type2, fmtId(name2));
 1903 tgl                       846 GBC          30 :     appendPQExpBuffer(buf, "SET %s TO ", fmtId(mine));
 1903 tgl                       847 ECB             : 
                                848                 :     /*
                                849                 :      * Variables that are marked GUC_LIST_QUOTE were already fully quoted by
                                850                 :      * flatten_set_variable_args() before they were put into the setconfig
                                851                 :      * array.  However, because the quoting rules used there aren't exactly
                                852                 :      * like SQL's, we have to break the list value apart and then quote the
                                853                 :      * elements as string literals.  (The elements may be double-quoted as-is,
                                854                 :      * but we can't just feed them to the SQL parser; it would do the wrong
                                855                 :      * thing with elements that are zero-length or longer than NAMEDATALEN.)
                                856                 :      *
                                857                 :      * Variables that are not so marked should just be emitted as simple
                                858                 :      * string literals.  If the variable is not known to
                                859                 :      * variable_is_guc_list_quote(), we'll do that; this makes it unsafe to
                                860                 :      * use GUC_LIST_QUOTE for extension variables.
                                861                 :      */
 1845 tgl                       862 GIC          30 :     if (variable_is_guc_list_quote(mine))
 1713 tgl                       863 ECB             :     {
                                864                 :         char      **namelist;
                                865                 :         char      **nameptr;
                                866                 : 
                                867                 :         /* Parse string into list of identifiers */
                                868                 :         /* this shouldn't fail really */
 1713 tgl                       869 UIC           0 :         if (SplitGUCList(pos, ',', &namelist))
 1713 tgl                       870 EUB             :         {
 1713 tgl                       871 UIC           0 :             for (nameptr = namelist; *nameptr; nameptr++)
 1713 tgl                       872 EUB             :             {
 1713 tgl                       873 UIC           0 :                 if (nameptr != namelist)
 1713 tgl                       874 UBC           0 :                     appendPQExpBufferStr(buf, ", ");
                                875               0 :                 appendStringLiteralConn(buf, *nameptr, conn);
 1713 tgl                       876 EUB             :             }
                                877                 :         }
 1713 tgl                       878 UIC           0 :         pg_free(namelist);
 1713 tgl                       879 EUB             :     }
                                880                 :     else
 1903 tgl                       881 GIC          30 :         appendStringLiteralConn(buf, pos, conn);
 1903 tgl                       882 ECB             : 
                                883                 :     /* Add USER SET flag if specified in the string */
  121 akorotkov                 884 GNC          30 :     if (userset && !strcmp(userset, "t"))
  121 akorotkov                 885 UNC           0 :         appendPQExpBufferStr(buf, " USER SET");
                                886                 : 
 1903 tgl                       887 GIC          30 :     appendPQExpBufferStr(buf, ";\n");
                                888                 : 
 1903 tgl                       889 CBC          30 :     pg_free(mine);
 1903 tgl                       890 EUB             : }
        

Generated by: LCOV version v1.16-55-g56c0a2a