LCOV - differential code coverage report
Current view: top level - src/bin/pg_dump - dumputils.c (source / functions) Coverage Total Hit UNC UBC GNC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 84.1 % 321 270 51 1 269
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 11 11 1 10
Baseline: 16@8cea358b128 Branches: 62.7 % 408 256 3 149 3 253
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 % 1 1 1
(240..) days: 84.1 % 320 269 51 269
Function coverage date bins:
(240..) days: 100.0 % 11 11 1 10
Branch coverage date bins:
[..60] days: 50.0 % 6 3 3 3
(240..) days: 62.9 % 402 253 149 253

 Age         Owner                    Branch data    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-2024, 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
 2239 tgl@sss.pgh.pa.us          64                 :CBC       23063 : 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                 :                : {
 3350                            69                 :          23063 :     bool        ok = true;
 2930 sfrost@snowman.net         70                 :          23063 :     char      **aclitems = NULL;
  860 tgl@sss.pgh.pa.us          71                 :          23063 :     char      **baseitems = NULL;
                                 72                 :          23063 :     char      **grantitems = NULL;
                                 73                 :          23063 :     char      **revokeitems = NULL;
 2930 sfrost@snowman.net         74                 :          23063 :     int         naclitems = 0;
  860 tgl@sss.pgh.pa.us          75                 :          23063 :     int         nbaseitems = 0;
                                 76                 :          23063 :     int         ngrantitems = 0;
                                 77                 :          23063 :     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   [ +  -  +  + ]:          23063 :     if (acls == NULL || *acls == '\0')
 7625                            92                 :             92 :         return true;            /* object has default permissions */
                                 93                 :                : 
                                 94                 :                :     /* treat empty-string owner same as NULL */
 6707                            95   [ +  -  -  + ]:          22971 :     if (owner && *owner == '\0')
 6707 tgl@sss.pgh.pa.us          96                 :UBC           0 :         owner = NULL;
                                 97                 :                : 
                                 98                 :                :     /* Parse the acls array */
  860 tgl@sss.pgh.pa.us          99         [ -  + ]:CBC       22971 :     if (!parsePGArray(acls, &aclitems, &naclitems))
                                100                 :                :     {
  668 peter@eisentraut.org      101                 :UBC           0 :         free(aclitems);
  860 tgl@sss.pgh.pa.us         102                 :              0 :         return false;
                                103                 :                :     }
                                104                 :                : 
                                105                 :                :     /* Parse the baseacls too */
  850 tgl@sss.pgh.pa.us         106         [ -  + ]:CBC       22971 :     if (!parsePGArray(baseacls, &baseitems, &nbaseitems))
                                107                 :                :     {
  668 peter@eisentraut.org      108                 :UBC           0 :         free(aclitems);
                                109                 :              0 :         free(baseitems);
  850 tgl@sss.pgh.pa.us         110                 :              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.
                                120                 :                :      * Besides, a false mismatch will just cause the output to be a little
                                121                 :                :      * more verbose than it really needed to be.
                                122                 :                :      */
  860 tgl@sss.pgh.pa.us         123                 :CBC       22971 :     grantitems = (char **) pg_malloc(naclitems * sizeof(char *));
                                124         [ +  + ]:          47289 :     for (i = 0; i < naclitems; i++)
                                125                 :                :     {
                                126                 :          24318 :         bool        found = false;
                                127                 :                : 
                                128         [ +  + ]:          26347 :         for (int j = 0; j < nbaseitems; j++)
                                129                 :                :         {
                                130         [ +  + ]:          24459 :             if (strcmp(aclitems[i], baseitems[j]) == 0)
                                131                 :                :             {
                                132                 :          22430 :                 found = true;
                                133                 :          22430 :                 break;
                                134                 :                :             }
                                135                 :                :         }
                                136         [ +  + ]:          24318 :         if (!found)
                                137                 :           1888 :             grantitems[ngrantitems++] = aclitems[i];
                                138                 :                :     }
                                139                 :          22971 :     revokeitems = (char **) pg_malloc(nbaseitems * sizeof(char *));
                                140         [ +  + ]:          45767 :     for (i = 0; i < nbaseitems; i++)
                                141                 :                :     {
                                142                 :          22796 :         bool        found = false;
                                143                 :                : 
                                144         [ +  + ]:          24100 :         for (int j = 0; j < naclitems; j++)
                                145                 :                :         {
                                146         [ +  + ]:          23734 :             if (strcmp(baseitems[i], aclitems[j]) == 0)
                                147                 :                :             {
                                148                 :          22430 :                 found = true;
                                149                 :          22430 :                 break;
                                150                 :                :             }
                                151                 :                :         }
                                152         [ +  + ]:          22796 :         if (!found)
                                153                 :            366 :             revokeitems[nrevokeitems++] = baseitems[i];
                                154                 :                :     }
                                155                 :                : 
                                156                 :                :     /* Prepare working buffers */
 7625                           157                 :          22971 :     grantee = createPQExpBuffer();
                                158                 :          22971 :     grantor = createPQExpBuffer();
                                159                 :          22971 :     privs = createPQExpBuffer();
                                160                 :          22971 :     privswgo = createPQExpBuffer();
                                161                 :                : 
                                162                 :                :     /*
                                163                 :                :      * At the end, these two will be pasted together to form the result.
                                164                 :                :      */
 7570 peter_e@gmx.net           165                 :          22971 :     firstsql = createPQExpBuffer();
                                166                 :          22971 :     secondsql = createPQExpBuffer();
                                167                 :                : 
                                168                 :                :     /*
                                169                 :                :      * Build REVOKE statements for ACLs listed in revokeitems[].
                                170                 :                :      */
  847 tgl@sss.pgh.pa.us         171         [ +  + ]:          23337 :     for (i = 0; i < nrevokeitems; i++)
                                172                 :                :     {
                                173         [ -  + ]:            366 :         if (!parseAclItem(revokeitems[i],
                                174                 :                :                           type, name, subname, remoteVersion,
                                175                 :                :                           grantee, grantor, privs, NULL))
                                176                 :                :         {
  847 tgl@sss.pgh.pa.us         177                 :UBC           0 :             ok = false;
                                178                 :              0 :             break;
                                179                 :                :         }
                                180                 :                : 
  847 tgl@sss.pgh.pa.us         181         [ +  - ]:CBC         366 :         if (privs->len > 0)
                                182                 :                :         {
                                183                 :            366 :             appendPQExpBuffer(firstsql, "%sREVOKE %s ON %s ",
                                184                 :                :                               prefix, privs->data, type);
                                185   [ +  +  +  - ]:            366 :             if (nspname && *nspname)
                                186                 :            212 :                 appendPQExpBuffer(firstsql, "%s.", fmtId(nspname));
  489 jdavis@postgresql.or      187   [ +  -  +  + ]:            366 :             if (name && *name)
                                188                 :            298 :                 appendPQExpBuffer(firstsql, "%s ", name);
                                189                 :            366 :             appendPQExpBufferStr(firstsql, "FROM ");
  847 tgl@sss.pgh.pa.us         190         [ +  + ]:            366 :             if (grantee->len == 0)
                                191                 :            190 :                 appendPQExpBufferStr(firstsql, "PUBLIC;\n");
                                192                 :                :             else
                                193                 :            176 :                 appendPQExpBuffer(firstsql, "%s;\n",
                                194                 :            176 :                                   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.
                                220                 :                :      */
  860                           221         [ +  + ]:          24859 :     for (i = 0; i < ngrantitems; i++)
                                222                 :                :     {
                                223         [ +  - ]:           1888 :         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.
                                230                 :                :              */
                                231   [ +  +  +  - ]:           1888 :             if (privs->len > 0 || privswgo->len > 0)
                                232                 :                :             {
                                233                 :                :                 PQExpBuffer thissql;
                                234                 :                : 
                                235                 :                :                 /* Set owner as grantor if that's not explicit in the ACL */
                                236   [ -  +  -  - ]:           1888 :                 if (grantor->len == 0 && owner)
  860 tgl@sss.pgh.pa.us         237                 :UBC           0 :                     printfPQExpBuffer(grantor, "%s", owner);
                                238                 :                : 
                                239                 :                :                 /* Make sure owner's own grants are output before others */
  860 tgl@sss.pgh.pa.us         240         [ +  - ]:CBC        1888 :                 if (owner &&
                                241         [ +  + ]:           1888 :                     strcmp(grantee->data, owner) == 0 &&
                                242         [ +  - ]:            129 :                     strcmp(grantor->data, owner) == 0)
                                243                 :            129 :                     thissql = firstsql;
                                244                 :                :                 else
                                245                 :           1759 :                     thissql = secondsql;
                                246                 :                : 
 7570 peter_e@gmx.net           247         [ +  - ]:           1888 :                 if (grantor->len > 0
                                248   [ +  -  -  + ]:           1888 :                     && (!owner || strcmp(owner, grantor->data) != 0))
  860 tgl@sss.pgh.pa.us         249                 :UBC           0 :                     appendPQExpBuffer(thissql, "SET SESSION AUTHORIZATION %s;\n",
 7570 peter_e@gmx.net           250                 :              0 :                                       fmtId(grantor->data));
                                251                 :                : 
 7625 tgl@sss.pgh.pa.us         252         [ +  + ]:CBC        1888 :                 if (privs->len > 0)
                                253                 :                :                 {
  860                           254                 :           1886 :                     appendPQExpBuffer(thissql, "%sGRANT %s ON %s ",
                                255                 :                :                                       prefix, privs->data, type);
 2239                           256   [ +  +  +  - ]:           1886 :                     if (nspname && *nspname)
  860                           257                 :           1627 :                         appendPQExpBuffer(thissql, "%s.", fmtId(nspname));
  489 jdavis@postgresql.or      258   [ +  -  +  + ]:           1886 :                     if (name && *name)
                                259                 :           1782 :                         appendPQExpBuffer(thissql, "%s ", name);
                                260                 :           1886 :                     appendPQExpBufferStr(thissql, "TO ");
 7625 tgl@sss.pgh.pa.us         261         [ +  + ]:           1886 :                     if (grantee->len == 0)
  860                           262                 :           1094 :                         appendPQExpBufferStr(thissql, "PUBLIC;\n");
                                263                 :                :                     else
                                264                 :            792 :                         appendPQExpBuffer(thissql, "%s;\n", fmtId(grantee->data));
                                265                 :                :                 }
 7625                           266         [ +  + ]:           1888 :                 if (privswgo->len > 0)
                                267                 :                :                 {
  860                           268                 :             20 :                     appendPQExpBuffer(thissql, "%sGRANT %s ON %s ",
                                269                 :                :                                       prefix, privswgo->data, type);
 2239                           270   [ +  +  +  - ]:             20 :                     if (nspname && *nspname)
  860                           271                 :             19 :                         appendPQExpBuffer(thissql, "%s.", fmtId(nspname));
  489 jdavis@postgresql.or      272   [ +  -  +  - ]:             20 :                     if (name && *name)
                                273                 :             20 :                         appendPQExpBuffer(thissql, "%s ", name);
                                274                 :             20 :                     appendPQExpBufferStr(thissql, "TO ");
 7625 tgl@sss.pgh.pa.us         275         [ -  + ]:             20 :                     if (grantee->len == 0)
  860 tgl@sss.pgh.pa.us         276                 :UBC           0 :                         appendPQExpBufferStr(thissql, "PUBLIC");
                                277                 :                :                     else
  860 tgl@sss.pgh.pa.us         278                 :CBC          20 :                         appendPQExpBufferStr(thissql, fmtId(grantee->data));
                                279                 :             20 :                     appendPQExpBufferStr(thissql, " WITH GRANT OPTION;\n");
                                280                 :                :                 }
                                281                 :                : 
 7570 peter_e@gmx.net           282         [ +  - ]:           1888 :                 if (grantor->len > 0
                                283   [ +  -  -  + ]:           1888 :                     && (!owner || strcmp(owner, grantor->data) != 0))
  860 tgl@sss.pgh.pa.us         284                 :UBC           0 :                     appendPQExpBufferStr(thissql, "RESET SESSION AUTHORIZATION;\n");
                                285                 :                :             }
                                286                 :                :         }
                                287                 :                :         else
                                288                 :                :         {
                                289                 :                :             /* parseAclItem failed, give up */
                                290                 :              0 :             ok = false;
                                291                 :              0 :             break;
                                292                 :                :         }
                                293                 :                :     }
                                294                 :                : 
 7625 tgl@sss.pgh.pa.us         295                 :CBC       22971 :     destroyPQExpBuffer(grantee);
                                296                 :          22971 :     destroyPQExpBuffer(grantor);
                                297                 :          22971 :     destroyPQExpBuffer(privs);
                                298                 :          22971 :     destroyPQExpBuffer(privswgo);
                                299                 :                : 
 7570 peter_e@gmx.net           300                 :          22971 :     appendPQExpBuffer(sql, "%s%s", firstsql->data, secondsql->data);
                                301                 :          22971 :     destroyPQExpBuffer(firstsql);
                                302                 :          22971 :     destroyPQExpBuffer(secondsql);
                                303                 :                : 
  668 peter@eisentraut.org      304                 :          22971 :     free(aclitems);
                                305                 :          22971 :     free(baseitems);
                                306                 :          22971 :     free(grantitems);
                                307                 :          22971 :     free(revokeitems);
                                308                 :                : 
 3350 tgl@sss.pgh.pa.us         309                 :          22971 :     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                 :                :  */
                                325                 :                : bool
 5305                           326                 :            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;
                                333                 :                : 
                                334                 :            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.
                                341                 :                :      */
                                342                 :            138 :     appendPQExpBuffer(prefix, "ALTER DEFAULT PRIVILEGES FOR ROLE %s ",
                                343                 :                :                       fmtId(owner));
                                344         [ +  + ]:            138 :     if (nspname)
                                345                 :             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.
                                350                 :                :      */
 2239                           351         [ -  + ]:            138 :     if (!buildACLCommands("", NULL, NULL, type,
                                352                 :                :                           acls, acldefault, owner,
 2630 sfrost@snowman.net        353                 :            138 :                           prefix->data, remoteVersion, sql))
                                354                 :                :     {
 2535 sfrost@snowman.net        355                 :UBC           0 :         destroyPQExpBuffer(prefix);
 2630                           356                 :              0 :         return false;
                                357                 :                :     }
                                358                 :                : 
 5305 tgl@sss.pgh.pa.us         359                 :CBC         138 :     destroyPQExpBuffer(prefix);
                                360                 :                : 
 2630 sfrost@snowman.net        361                 :            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                 :                :  */
                                382                 :                : static bool
 5561 tgl@sss.pgh.pa.us         383                 :           2254 : 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                 :                : {
                                388                 :                :     char       *buf;
 7625                           389                 :           2254 :     bool        all_with_go = true;
                                390                 :           2254 :     bool        all_without_go = true;
                                391                 :                :     char       *eqpos;
                                392                 :                :     char       *slpos;
                                393                 :                :     char       *pos;
                                394                 :                : 
 1807 michael@paquier.xyz       395                 :           2254 :     buf = pg_strdup(item);
                                396                 :                : 
                                397                 :                :     /* user or group name is string up to = */
  860 tgl@sss.pgh.pa.us         398                 :           2254 :     eqpos = dequoteAclUserName(grantee, buf);
 7563                           399         [ -  + ]:           2254 :     if (*eqpos != '=')
                                400                 :                :     {
 1807 michael@paquier.xyz       401                 :UBC           0 :         pg_free(buf);
 7625 tgl@sss.pgh.pa.us         402                 :              0 :         return false;
                                403                 :                :     }
                                404                 :                : 
                                405                 :                :     /* grantor should appear after / */
 7625 tgl@sss.pgh.pa.us         406                 :CBC        2254 :     slpos = strchr(eqpos + 1, '/');
                                407         [ +  - ]:           2254 :     if (slpos)
                                408                 :                :     {
 7563                           409                 :           2254 :         *slpos++ = '\0';
  860                           410                 :           2254 :         slpos = dequoteAclUserName(grantor, slpos);
 7563                           411         [ -  + ]:           2254 :         if (*slpos != '\0')
                                412                 :                :         {
 1807 michael@paquier.xyz       413                 :UBC           0 :             pg_free(buf);
 7563 tgl@sss.pgh.pa.us         414                 :              0 :             return false;
                                415                 :                :         }
                                416                 :                :     }
                                417                 :                :     else
                                418                 :                :     {
 1807 michael@paquier.xyz       419                 :              0 :         pg_free(buf);
 2741 tgl@sss.pgh.pa.us         420                 :              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)
                                442                 :                : 
 7625 tgl@sss.pgh.pa.us         443                 :CBC        2254 :     resetPQExpBuffer(privs);
                                444                 :           2254 :     resetPQExpBuffer(privswgo);
                                445                 :                : 
 5298                           446   [ +  +  +  + ]:           2254 :     if (strcmp(type, "TABLE") == 0 || strcmp(type, "SEQUENCE") == 0 ||
                                447   [ +  +  -  + ]:            714 :         strcmp(type, "TABLES") == 0 || strcmp(type, "SEQUENCES") == 0)
                                448                 :                :     {
 7625                           449   [ +  +  -  +  :           1643 :         CONVERT_PRIV('r', "SELECT");
                                              -  - ]
                                450                 :                : 
 5298                           451         [ +  + ]:           1643 :         if (strcmp(type, "SEQUENCE") == 0 ||
                                452         [ -  + ]:           1588 :             strcmp(type, "SEQUENCES") == 0)
                                453                 :                :             /* sequence only */
 6658 bruce@momjian.us          454   [ +  +  +  +  :            109 :             CONVERT_PRIV('U', "USAGE");
                                              +  + ]
                                455                 :                :         else
                                456                 :                :         {
                                457                 :                :             /* table only */
                                458   [ +  +  -  +  :           1588 :             CONVERT_PRIV('a', "INSERT");
                                              -  - ]
 2741 tgl@sss.pgh.pa.us         459   [ +  +  -  +  :           1588 :             CONVERT_PRIV('x', "REFERENCES");
                                              -  - ]
                                460                 :                :             /* rest are not applicable to columns */
 5561                           461         [ +  + ]:           1588 :             if (subname == NULL)
                                462                 :                :             {
 2741                           463   [ +  +  -  +  :            418 :                 CONVERT_PRIV('d', "DELETE");
                                              -  - ]
                                464   [ +  +  -  +  :            418 :                 CONVERT_PRIV('t', "TRIGGER");
                                              -  - ]
  852                           465   [ +  +  -  +  :            418 :                 CONVERT_PRIV('D', "TRUNCATE");
                                              -  - ]
   32 nathan@postgresql.or      466   [ +  +  -  +  :GNC         418 :                 CONVERT_PRIV('m', "MAINTAIN");
                                              -  - ]
                                467                 :                :             }
                                468                 :                :         }
                                469                 :                : 
                                470                 :                :         /* UPDATE */
 2741 tgl@sss.pgh.pa.us         471   [ +  +  +  +  :CBC        1756 :         CONVERT_PRIV('w', "UPDATE");
                                              +  + ]
                                472                 :                :     }
 5298                           473         [ +  + ]:            611 :     else if (strcmp(type, "FUNCTION") == 0 ||
                                474         [ +  + ]:            452 :              strcmp(type, "FUNCTIONS") == 0)
 7625                           475   [ +  -  +  +  :            456 :         CONVERT_PRIV('X', "EXECUTE");
                                              +  + ]
 2327 peter_e@gmx.net           476         [ +  - ]:            383 :     else if (strcmp(type, "PROCEDURE") == 0 ||
                                477         [ -  + ]:            383 :              strcmp(type, "PROCEDURES") == 0)
 2327 peter_e@gmx.net           478   [ #  #  #  #  :UBC           0 :         CONVERT_PRIV('X', "EXECUTE");
                                              #  # ]
 7625 tgl@sss.pgh.pa.us         479         [ +  + ]:CBC         383 :     else if (strcmp(type, "LANGUAGE") == 0)
                                480   [ +  -  -  +  :             41 :         CONVERT_PRIV('U', "USAGE");
                                              -  - ]
 2574 teodor@sigaev.ru          481         [ +  + ]:            342 :     else if (strcmp(type, "SCHEMA") == 0 ||
 2525 tgl@sss.pgh.pa.us         482         [ -  + ]:            262 :              strcmp(type, "SCHEMAS") == 0)
                                483                 :                :     {
 7625                           484   [ +  +  -  +  :             80 :         CONVERT_PRIV('C', "CREATE");
                                              -  - ]
                                485   [ +  -  -  +  :            160 :         CONVERT_PRIV('U', "USAGE");
                                              -  - ]
                                486                 :                :     }
                                487         [ +  + ]:            262 :     else if (strcmp(type, "DATABASE") == 0)
                                488                 :                :     {
                                489   [ +  +  -  +  :             14 :         CONVERT_PRIV('C', "CREATE");
                                              -  - ]
 6559                           490   [ +  +  -  +  :             14 :         CONVERT_PRIV('c', "CONNECT");
                                              -  - ]
 7625                           491   [ +  +  -  +  :             14 :         CONVERT_PRIV('T', "TEMPORARY");
                                              -  - ]
                                492                 :                :     }
 7240                           493         [ -  + ]:            248 :     else if (strcmp(type, "TABLESPACE") == 0)
 7240 tgl@sss.pgh.pa.us         494   [ #  #  #  #  :UBC           0 :         CONVERT_PRIV('C', "CREATE");
                                              #  # ]
 4144 tgl@sss.pgh.pa.us         495         [ +  + ]:CBC         248 :     else if (strcmp(type, "TYPE") == 0 ||
                                496         [ -  + ]:            107 :              strcmp(type, "TYPES") == 0)
                                497   [ +  -  -  +  :            282 :         CONVERT_PRIV('U', "USAGE");
                                              -  - ]
 5595 peter_e@gmx.net           498         [ +  + ]:            107 :     else if (strcmp(type, "FOREIGN DATA WRAPPER") == 0)
                                499   [ +  -  -  +  :             34 :         CONVERT_PRIV('U', "USAGE");
                                              -  - ]
 5156 heikki.linnakangas@i      500         [ +  + ]:             73 :     else if (strcmp(type, "FOREIGN SERVER") == 0)
 5595 peter_e@gmx.net           501   [ +  -  -  +  :             34 :         CONVERT_PRIV('U', "USAGE");
                                              -  - ]
 4852 rhaas@postgresql.org      502         [ -  + ]:             39 :     else if (strcmp(type, "FOREIGN TABLE") == 0)
 4852 rhaas@postgresql.org      503   [ #  #  #  #  :UBC           0 :         CONVERT_PRIV('r', "SELECT");
                                              #  # ]
  739 tgl@sss.pgh.pa.us         504         [ +  + ]:CBC          39 :     else if (strcmp(type, "PARAMETER") == 0)
                                505                 :                :     {
                                506   [ +  +  +  +  :              3 :         CONVERT_PRIV('s', "SET");
                                              +  - ]
                                507   [ +  -  +  +  :              3 :         CONVERT_PRIV('A', "ALTER SYSTEM");
                                              +  - ]
                                508                 :                :     }
 5238 itagaki.takahiro@gma      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
 7625 tgl@sss.pgh.pa.us         515                 :UBC           0 :         abort();
                                516                 :                : 
                                517                 :                : #undef CONVERT_PRIV
                                518                 :                : 
 7625 tgl@sss.pgh.pa.us         519         [ +  + ]:CBC        2254 :     if (all_with_go)
                                520                 :                :     {
                                521                 :              2 :         resetPQExpBuffer(privs);
                                522                 :              2 :         printfPQExpBuffer(privswgo, "ALL");
 5561                           523         [ -  + ]:              2 :         if (subname)
 5561 tgl@sss.pgh.pa.us         524                 :UBC           0 :             appendPQExpBuffer(privswgo, "(%s)", subname);
                                525                 :                :     }
 7625 tgl@sss.pgh.pa.us         526         [ +  + ]:CBC        2252 :     else if (all_without_go)
                                527                 :                :     {
                                528                 :            609 :         resetPQExpBuffer(privswgo);
                                529                 :            609 :         printfPQExpBuffer(privs, "ALL");
 5561                           530         [ -  + ]:            609 :         if (subname)
 5561 tgl@sss.pgh.pa.us         531                 :UBC           0 :             appendPQExpBuffer(privs, "(%s)", subname);
                                532                 :                :     }
                                533                 :                : 
 1807 michael@paquier.xyz       534                 :CBC        2254 :     pg_free(buf);
                                535                 :                : 
 7625 tgl@sss.pgh.pa.us         536                 :           2254 :     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
  860                           544                 :            456 : quoteAclUserName(PQExpBuffer output, const char *input)
                                545                 :                : {
                                546                 :                :     const char *src;
                                547                 :            456 :     bool        safe = true;
                                548                 :                : 
                                549         [ +  + ]:           7749 :     for (src = input; *src; src++)
                                550                 :                :     {
                                551                 :                :         /* This test had better match what putid() does */
                                552   [ +  +  +  + ]:           7446 :         if (!isalnum((unsigned char) *src) && *src != '_')
                                553                 :                :         {
                                554                 :            153 :             safe = false;
                                555                 :            153 :             break;
                                556                 :                :         }
                                557                 :                :     }
                                558         [ +  + ]:            456 :     if (!safe)
                                559                 :            153 :         appendPQExpBufferChar(output, '"');
                                560         [ +  + ]:           9126 :     for (src = input; *src; src++)
                                561                 :                :     {
                                562                 :                :         /* A double quote character in a username is encoded as "" */
                                563         [ +  + ]:           8670 :         if (*src == '"')
                                564                 :            153 :             appendPQExpBufferChar(output, '"');
                                565                 :           8670 :         appendPQExpBufferChar(output, *src);
                                566                 :                :     }
                                567         [ +  + ]:            456 :     if (!safe)
                                568                 :            153 :         appendPQExpBufferChar(output, '"');
                                569                 :            456 : }
                                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                 :           4508 : dequoteAclUserName(PQExpBuffer output, char *input)
                                579                 :                : {
 7563                           580                 :           4508 :     resetPQExpBuffer(output);
                                581                 :                : 
                                582   [ +  +  +  + ]:          39258 :     while (*input && *input != '=')
                                583                 :                :     {
                                584                 :                :         /*
                                585                 :                :          * If user name isn't quoted, then just add it to the output buffer
                                586                 :                :          */
                                587         [ +  + ]:          34750 :         if (*input != '"')
                                588                 :          34647 :             appendPQExpBufferChar(output, *input++);
                                589                 :                :         else
                                590                 :                :         {
                                591                 :                :             /* Otherwise, it's a quoted username */
                                592                 :            103 :             input++;
                                593                 :                :             /* Loop until we come across an unescaped quote */
 7549                           594   [ +  +  +  + ]:           2472 :             while (!(*input == '"' && *(input + 1) != '"'))
                                595                 :                :             {
 7563                           596         [ -  + ]:           2369 :                 if (*input == '\0')
 2489 tgl@sss.pgh.pa.us         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                 :                :                  */
 7549 tgl@sss.pgh.pa.us         603   [ +  +  +  - ]:CBC        2369 :                 if (*input == '"' && *(input + 1) == '"')
                                604                 :            103 :                     input++;
 7563                           605                 :           2369 :                 appendPQExpBufferChar(output, *input++);
                                606                 :                :             }
                                607                 :            103 :             input++;
                                608                 :                :         }
                                609                 :                :     }
                                610                 :           4508 :     return input;
                                611                 :                : }
                                612                 :                : 
                                613                 :                : /*
                                614                 :                :  * Append a privilege keyword to a keyword list, inserting comma if needed.
                                615                 :                :  */
                                616                 :                : static void
 5561                           617                 :           2914 : AddAcl(PQExpBuffer aclbuf, const char *keyword, const char *subname)
                                618                 :                : {
 7625                           619         [ +  + ]:           2914 :     if (aclbuf->len > 0)
                                620                 :            642 :         appendPQExpBufferChar(aclbuf, ',');
 3800 heikki.linnakangas@i      621                 :           2914 :     appendPQExpBufferStr(aclbuf, keyword);
 5561 tgl@sss.pgh.pa.us         622         [ +  + ]:           2914 :     if (subname)
                                623                 :           1170 :         appendPQExpBuffer(aclbuf, "(%s)", subname);
 7625                           624                 :           2914 : }
                                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
 1328 peter@eisentraut.org      637                 :            131 : buildShSecLabelQuery(const char *catalog_name, Oid objectId,
                                638                 :                :                      PQExpBuffer sql)
                                639                 :                : {
 4652 rhaas@postgresql.org      640                 :            131 :     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                 :            131 : }
                                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                 :            131 : emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer,
                                656                 :                :                 const char *objtype, const char *objname)
                                657                 :                : {
                                658                 :                :     int         i;
                                659                 :                : 
                                660         [ -  + ]:            131 :     for (i = 0; i < PQntuples(res); i++)
                                661                 :                :     {
 4326 bruce@momjian.us          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 */
 4652 rhaas@postgresql.org      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);
 3800 heikki.linnakangas@i      673                 :              0 :         appendPQExpBufferStr(buffer, ";\n");
                                674                 :                :     }
 4652 rhaas@postgresql.org      675                 :CBC         131 : }
                                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
 2216 tgl@sss.pgh.pa.us         689                 :             65 : variable_is_guc_list_quote(const char *name)
                                690                 :                : {
 1254 michael@paquier.xyz       691   [ +  +  +  + ]:            125 :     if (pg_strcasecmp(name, "local_preload_libraries") == 0 ||
                                692         [ +  - ]:            115 :         pg_strcasecmp(name, "search_path") == 0 ||
 2216 tgl@sss.pgh.pa.us         693         [ +  - ]:            110 :         pg_strcasecmp(name, "session_preload_libraries") == 0 ||
                                694         [ +  - ]:            110 :         pg_strcasecmp(name, "shared_preload_libraries") == 0 ||
 1254 michael@paquier.xyz       695         [ -  + ]:            110 :         pg_strcasecmp(name, "temp_tablespaces") == 0 ||
                                696                 :             55 :         pg_strcasecmp(name, "unix_socket_directories") == 0)
 2216 tgl@sss.pgh.pa.us         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
 2084                           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))
 2084 tgl@sss.pgh.pa.us         740                 :UBC           0 :         nextp++;                /* skip leading whitespace */
                                741                 :                : 
 2084 tgl@sss.pgh.pa.us         742         [ -  + ]:CBC          10 :     if (*nextp == '\0')
 2084 tgl@sss.pgh.pa.us         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                 :                : 
 2084 tgl@sss.pgh.pa.us         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)
 2084 tgl@sss.pgh.pa.us         759                 :UBC           0 :                     return false;   /* mismatched quotes */
 2084 tgl@sss.pgh.pa.us         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)
 2084 tgl@sss.pgh.pa.us         778                 :UBC           0 :                 return false;   /* empty unquoted name not allowed */
                                779                 :                :         }
                                780                 :                : 
 2084 tgl@sss.pgh.pa.us         781         [ -  + ]:CBC          25 :         while (isspace((unsigned char) *nextp))
 2084 tgl@sss.pgh.pa.us         782                 :UBC           0 :             nextp++;            /* skip trailing whitespace */
                                783                 :                : 
 2084 tgl@sss.pgh.pa.us         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
 2084 tgl@sss.pgh.pa.us         794                 :UBC           0 :             return false;       /* invalid syntax */
                                795                 :                : 
                                796                 :                :         /* Now safe to overwrite separator with a null */
 2084 tgl@sss.pgh.pa.us         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
 2274                           823                 :             30 : makeAlterConfigCommand(PGconn *conn, const char *configitem,
                                824                 :                :                        const char *type, const char *name,
                                825                 :                :                        const char *type2, const char *name2,
                                826                 :                :                        PQExpBuffer buf)
                                827                 :                : {
                                828                 :                :     char       *mine;
                                829                 :                :     char       *pos;
                                830                 :                : 
                                831                 :                :     /* Parse the configitem.  If we can't find an "=", silently do nothing. */
                                832                 :             30 :     mine = pg_strdup(configitem);
                                833                 :             30 :     pos = strchr(mine, '=');
                                834         [ -  + ]:             30 :     if (pos == NULL)
                                835                 :                :     {
 2274 tgl@sss.pgh.pa.us         836                 :UBC           0 :         pg_free(mine);
                                837                 :              0 :         return;
                                838                 :                :     }
 2274 tgl@sss.pgh.pa.us         839                 :CBC          30 :     *pos++ = '\0';
                                840                 :                : 
                                841                 :                :     /* Build the command, with suitable quoting for everything. */
                                842                 :             30 :     appendPQExpBuffer(buf, "ALTER %s %s ", type, fmtId(name));
                                843   [ -  +  -  - ]:             30 :     if (type2 != NULL && name2 != NULL)
 2274 tgl@sss.pgh.pa.us         844                 :UBC           0 :         appendPQExpBuffer(buf, "IN %s %s ", type2, fmtId(name2));
 2274 tgl@sss.pgh.pa.us         845                 :CBC          30 :     appendPQExpBuffer(buf, "SET %s TO ", fmtId(mine));
                                846                 :                : 
                                847                 :                :     /*
                                848                 :                :      * Variables that are marked GUC_LIST_QUOTE were already fully quoted by
                                849                 :                :      * flatten_set_variable_args() before they were put into the setconfig
                                850                 :                :      * array.  However, because the quoting rules used there aren't exactly
                                851                 :                :      * like SQL's, we have to break the list value apart and then quote the
                                852                 :                :      * elements as string literals.  (The elements may be double-quoted as-is,
                                853                 :                :      * but we can't just feed them to the SQL parser; it would do the wrong
                                854                 :                :      * thing with elements that are zero-length or longer than NAMEDATALEN.)
                                855                 :                :      *
                                856                 :                :      * Variables that are not so marked should just be emitted as simple
                                857                 :                :      * string literals.  If the variable is not known to
                                858                 :                :      * variable_is_guc_list_quote(), we'll do that; this makes it unsafe to
                                859                 :                :      * use GUC_LIST_QUOTE for extension variables.
                                860                 :                :      */
 2216                           861         [ -  + ]:             30 :     if (variable_is_guc_list_quote(mine))
                                862                 :                :     {
                                863                 :                :         char      **namelist;
                                864                 :                :         char      **nameptr;
                                865                 :                : 
                                866                 :                :         /* Parse string into list of identifiers */
                                867                 :                :         /* this shouldn't fail really */
 2084 tgl@sss.pgh.pa.us         868         [ #  # ]:UBC           0 :         if (SplitGUCList(pos, ',', &namelist))
                                869                 :                :         {
                                870         [ #  # ]:              0 :             for (nameptr = namelist; *nameptr; nameptr++)
                                871                 :                :             {
                                872         [ #  # ]:              0 :                 if (nameptr != namelist)
                                873                 :              0 :                     appendPQExpBufferStr(buf, ", ");
                                874                 :              0 :                 appendStringLiteralConn(buf, *nameptr, conn);
                                875                 :                :             }
                                876                 :                :         }
                                877                 :              0 :         pg_free(namelist);
                                878                 :                :     }
                                879                 :                :     else
 2274 tgl@sss.pgh.pa.us         880                 :CBC          30 :         appendStringLiteralConn(buf, pos, conn);
                                881                 :                : 
                                882                 :             30 :     appendPQExpBufferStr(buf, ";\n");
                                883                 :                : 
                                884                 :             30 :     pg_free(mine);
                                885                 :                : }
        

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