LCOV - differential code coverage report
Current view: top level - src/bin/pg_dump - dumputils.c (source / functions) Coverage Total Hit UBC CBC
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 82.7 % 358 296 62 296
Current Date: 2025-09-06 07:49:51 +0900 Functions: 100.0 % 15 15 15
Baseline: lcov-20250906-005545-baseline Branches: 62.8 % 438 275 163 275
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 95.2 % 21 20 1 20
(30,360] days: 41.2 % 17 7 10 7
(360..) days: 84.1 % 320 269 51 269
Function coverage date bins:
(7,30] days: 100.0 % 3 3 3
(30,360] days: 100.0 % 1 1 1
(360..) days: 100.0 % 11 11 11
Branch coverage date bins:
(7,30] days: 80.0 % 20 16 4 16
(30,360] days: 25.0 % 12 3 9 3
(360..) days: 63.1 % 406 256 150 256

 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-2025, 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 "common/file_perm.h"
                                 20                 :                : #include "common/logging.h"
                                 21                 :                : #include "dumputils.h"
                                 22                 :                : #include "fe_utils/string_utils.h"
                                 23                 :                : 
                                 24                 :                : static const char restrict_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
                                 25                 :                : 
                                 26                 :                : static bool parseAclItem(const char *item, const char *type,
                                 27                 :                :                          const char *name, const char *subname, int remoteVersion,
                                 28                 :                :                          PQExpBuffer grantee, PQExpBuffer grantor,
                                 29                 :                :                          PQExpBuffer privs, PQExpBuffer privswgo);
                                 30                 :                : static char *dequoteAclUserName(PQExpBuffer output, char *input);
                                 31                 :                : static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
                                 32                 :                :                    const char *subname);
                                 33                 :                : 
                                 34                 :                : 
                                 35                 :                : /*
                                 36                 :                :  * Sanitize a string to be included in an SQL comment or TOC listing, by
                                 37                 :                :  * replacing any newlines with spaces.  This ensures each logical output line
                                 38                 :                :  * is in fact one physical output line, to prevent corruption of the dump
                                 39                 :                :  * (which could, in the worst case, present an SQL injection vulnerability
                                 40                 :                :  * if someone were to incautiously load a dump containing objects with
                                 41                 :                :  * maliciously crafted names).
                                 42                 :                :  *
                                 43                 :                :  * The result is a freshly malloc'd string.  If the input string is NULL,
                                 44                 :                :  * return a malloc'ed empty string, unless want_hyphen, in which case return a
                                 45                 :                :  * malloc'ed hyphen.
                                 46                 :                :  *
                                 47                 :                :  * Note that we currently don't bother to quote names, meaning that the name
                                 48                 :                :  * fields aren't automatically parseable.  "pg_restore -L" doesn't care because
                                 49                 :                :  * it only examines the dumpId field, but someday we might want to try harder.
                                 50                 :                :  */
                                 51                 :                : char *
   26 noah@leadboat.com          52                 :CBC      129389 : sanitize_line(const char *str, bool want_hyphen)
                                 53                 :                : {
                                 54                 :                :     char       *result;
                                 55                 :                :     char       *s;
                                 56                 :                : 
                                 57         [ +  + ]:         129389 :     if (!str)
                                 58         [ +  + ]:           5405 :         return pg_strdup(want_hyphen ? "-" : "");
                                 59                 :                : 
                                 60                 :         123984 :     result = pg_strdup(str);
                                 61                 :                : 
                                 62         [ +  + ]:        1515520 :     for (s = result; *s != '\0'; s++)
                                 63                 :                :     {
                                 64   [ +  +  +  + ]:        1391536 :         if (*s == '\n' || *s == '\r')
                                 65                 :            228 :             *s = ' ';
                                 66                 :                :     }
                                 67                 :                : 
                                 68                 :         123984 :     return result;
                                 69                 :                : }
                                 70                 :                : 
                                 71                 :                : 
                                 72                 :                : /*
                                 73                 :                :  * Build GRANT/REVOKE command(s) for an object.
                                 74                 :                :  *
                                 75                 :                :  *  name: the object name, in the form to use in the commands (already quoted)
                                 76                 :                :  *  subname: the sub-object name, if any (already quoted); NULL if none
                                 77                 :                :  *  nspname: the namespace the object is in (NULL if none); not pre-quoted
                                 78                 :                :  *  type: the object type (as seen in GRANT command: must be one of
                                 79                 :                :  *      TABLE, SEQUENCE, FUNCTION, PROCEDURE, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
                                 80                 :                :  *      FOREIGN DATA WRAPPER, SERVER, PARAMETER or LARGE OBJECT)
                                 81                 :                :  *  acls: the ACL string fetched from the database
                                 82                 :                :  *  baseacls: the initial ACL string for this object
                                 83                 :                :  *  owner: username of object owner (will be passed through fmtId); can be
                                 84                 :                :  *      NULL or empty string to indicate "no owner known"
                                 85                 :                :  *  prefix: string to prefix to each generated command; typically empty
                                 86                 :                :  *  remoteVersion: version of database
                                 87                 :                :  *
                                 88                 :                :  * Returns true if okay, false if could not parse the acl string.
                                 89                 :                :  * The resulting commands (if any) are appended to the contents of 'sql'.
                                 90                 :                :  *
                                 91                 :                :  * baseacls is typically the result of acldefault() for the object's type
                                 92                 :                :  * and owner.  However, if there is a pg_init_privs entry for the object,
                                 93                 :                :  * it should instead be the initprivs ACLs.  When acls is itself a
                                 94                 :                :  * pg_init_privs entry, baseacls is what to dump that relative to; then
                                 95                 :                :  * it can be either an acldefault() value or an empty ACL "{}".
                                 96                 :                :  *
                                 97                 :                :  * Note: when processing a default ACL, prefix is "ALTER DEFAULT PRIVILEGES "
                                 98                 :                :  * or something similar, and name is an empty string.
                                 99                 :                :  *
                                100                 :                :  * Note: beware of passing a fmtId() result directly as 'name' or 'subname',
                                101                 :                :  * since this routine uses fmtId() internally.
                                102                 :                :  */
                                103                 :                : bool
 2749 tgl@sss.pgh.pa.us         104                 :          28507 : buildACLCommands(const char *name, const char *subname, const char *nspname,
                                105                 :                :                  const char *type, const char *acls, const char *baseacls,
                                106                 :                :                  const char *owner, const char *prefix, int remoteVersion,
                                107                 :                :                  PQExpBuffer sql)
                                108                 :                : {
 3860                           109                 :          28507 :     bool        ok = true;
 3440 sfrost@snowman.net        110                 :          28507 :     char      **aclitems = NULL;
 1370 tgl@sss.pgh.pa.us         111                 :          28507 :     char      **baseitems = NULL;
                                112                 :          28507 :     char      **grantitems = NULL;
                                113                 :          28507 :     char      **revokeitems = NULL;
 3440 sfrost@snowman.net        114                 :          28507 :     int         naclitems = 0;
 1370 tgl@sss.pgh.pa.us         115                 :          28507 :     int         nbaseitems = 0;
                                116                 :          28507 :     int         ngrantitems = 0;
                                117                 :          28507 :     int         nrevokeitems = 0;
                                118                 :                :     int         i;
                                119                 :                :     PQExpBuffer grantee,
                                120                 :                :                 grantor,
                                121                 :                :                 privs,
                                122                 :                :                 privswgo;
                                123                 :                :     PQExpBuffer firstsql,
                                124                 :                :                 secondsql;
                                125                 :                : 
                                126                 :                :     /*
                                127                 :                :      * If the acl was NULL (initial default state), we need do nothing.  Note
                                128                 :                :      * that this is distinguishable from all-privileges-revoked, which will
                                129                 :                :      * look like an empty array ("{}").
                                130                 :                :      */
                                131   [ +  -  +  + ]:          28507 :     if (acls == NULL || *acls == '\0')
 8135                           132                 :            117 :         return true;            /* object has default permissions */
                                133                 :                : 
                                134                 :                :     /* treat empty-string owner same as NULL */
 7217                           135   [ +  -  -  + ]:          28390 :     if (owner && *owner == '\0')
 7217 tgl@sss.pgh.pa.us         136                 :UBC           0 :         owner = NULL;
                                137                 :                : 
                                138                 :                :     /* Parse the acls array */
 1370 tgl@sss.pgh.pa.us         139         [ -  + ]:CBC       28390 :     if (!parsePGArray(acls, &aclitems, &naclitems))
                                140                 :                :     {
 1178 peter@eisentraut.org      141                 :UBC           0 :         free(aclitems);
 1370 tgl@sss.pgh.pa.us         142                 :              0 :         return false;
                                143                 :                :     }
                                144                 :                : 
                                145                 :                :     /* Parse the baseacls too */
 1360 tgl@sss.pgh.pa.us         146         [ -  + ]:CBC       28390 :     if (!parsePGArray(baseacls, &baseitems, &nbaseitems))
                                147                 :                :     {
 1178 peter@eisentraut.org      148                 :UBC           0 :         free(aclitems);
                                149                 :              0 :         free(baseitems);
 1360 tgl@sss.pgh.pa.us         150                 :              0 :         return false;
                                151                 :                :     }
                                152                 :                : 
                                153                 :                :     /*
                                154                 :                :      * Compare the actual ACL with the base ACL, extracting the privileges
                                155                 :                :      * that need to be granted (i.e., are in the actual ACL but not the base
                                156                 :                :      * ACL) and the ones that need to be revoked (the reverse).  We use plain
                                157                 :                :      * string comparisons to check for matches.  In principle that could be
                                158                 :                :      * fooled by extraneous issues such as whitespace, but since all these
                                159                 :                :      * strings are the work of aclitemout(), it should be OK in practice.
                                160                 :                :      * Besides, a false mismatch will just cause the output to be a little
                                161                 :                :      * more verbose than it really needed to be.
                                162                 :                :      */
 1370 tgl@sss.pgh.pa.us         163                 :CBC       28390 :     grantitems = (char **) pg_malloc(naclitems * sizeof(char *));
                                164         [ +  + ]:          78712 :     for (i = 0; i < naclitems; i++)
                                165                 :                :     {
                                166                 :          50322 :         bool        found = false;
                                167                 :                : 
                                168         [ +  + ]:          72806 :         for (int j = 0; j < nbaseitems; j++)
                                169                 :                :         {
                                170         [ +  + ]:          70801 :             if (strcmp(aclitems[i], baseitems[j]) == 0)
                                171                 :                :             {
                                172                 :          48317 :                 found = true;
                                173                 :          48317 :                 break;
                                174                 :                :             }
                                175                 :                :         }
                                176         [ +  + ]:          50322 :         if (!found)
                                177                 :           2005 :             grantitems[ngrantitems++] = aclitems[i];
                                178                 :                :     }
                                179                 :          28390 :     revokeitems = (char **) pg_malloc(nbaseitems * sizeof(char *));
                                180         [ +  + ]:          77103 :     for (i = 0; i < nbaseitems; i++)
                                181                 :                :     {
                                182                 :          48713 :         bool        found = false;
                                183                 :                : 
                                184         [ +  + ]:          70476 :         for (int j = 0; j < naclitems; j++)
                                185                 :                :         {
                                186         [ +  + ]:          70080 :             if (strcmp(baseitems[i], aclitems[j]) == 0)
                                187                 :                :             {
                                188                 :          48317 :                 found = true;
                                189                 :          48317 :                 break;
                                190                 :                :             }
                                191                 :                :         }
                                192         [ +  + ]:          48713 :         if (!found)
                                193                 :            396 :             revokeitems[nrevokeitems++] = baseitems[i];
                                194                 :                :     }
                                195                 :                : 
                                196                 :                :     /* Prepare working buffers */
 8135                           197                 :          28390 :     grantee = createPQExpBuffer();
                                198                 :          28390 :     grantor = createPQExpBuffer();
                                199                 :          28390 :     privs = createPQExpBuffer();
                                200                 :          28390 :     privswgo = createPQExpBuffer();
                                201                 :                : 
                                202                 :                :     /*
                                203                 :                :      * At the end, these two will be pasted together to form the result.
                                204                 :                :      */
 8080 peter_e@gmx.net           205                 :          28390 :     firstsql = createPQExpBuffer();
                                206                 :          28390 :     secondsql = createPQExpBuffer();
                                207                 :                : 
                                208                 :                :     /*
                                209                 :                :      * Build REVOKE statements for ACLs listed in revokeitems[].
                                210                 :                :      */
 1357 tgl@sss.pgh.pa.us         211         [ +  + ]:          28786 :     for (i = 0; i < nrevokeitems; i++)
                                212                 :                :     {
                                213         [ -  + ]:            396 :         if (!parseAclItem(revokeitems[i],
                                214                 :                :                           type, name, subname, remoteVersion,
                                215                 :                :                           grantee, grantor, privs, NULL))
                                216                 :                :         {
 1357 tgl@sss.pgh.pa.us         217                 :UBC           0 :             ok = false;
                                218                 :              0 :             break;
                                219                 :                :         }
                                220                 :                : 
 1357 tgl@sss.pgh.pa.us         221         [ +  - ]:CBC         396 :         if (privs->len > 0)
                                222                 :                :         {
                                223                 :            396 :             appendPQExpBuffer(firstsql, "%sREVOKE %s ON %s ",
                                224                 :                :                               prefix, privs->data, type);
                                225   [ +  +  +  - ]:            396 :             if (nspname && *nspname)
                                226                 :            218 :                 appendPQExpBuffer(firstsql, "%s.", fmtId(nspname));
  999 jdavis@postgresql.or      227   [ +  -  +  + ]:            396 :             if (name && *name)
                                228                 :            314 :                 appendPQExpBuffer(firstsql, "%s ", name);
                                229                 :            396 :             appendPQExpBufferStr(firstsql, "FROM ");
 1357 tgl@sss.pgh.pa.us         230         [ +  + ]:            396 :             if (grantee->len == 0)
                                231                 :            204 :                 appendPQExpBufferStr(firstsql, "PUBLIC;\n");
                                232                 :                :             else
                                233                 :            192 :                 appendPQExpBuffer(firstsql, "%s;\n",
                                234                 :            192 :                                   fmtId(grantee->data));
                                235                 :                :         }
                                236                 :                :     }
                                237                 :                : 
                                238                 :                :     /*
                                239                 :                :      * At this point we have issued REVOKE statements for all initial and
                                240                 :                :      * default privileges that are no longer present on the object, so we are
                                241                 :                :      * almost ready to GRANT the privileges listed in grantitems[].
                                242                 :                :      *
                                243                 :                :      * We still need some hacking though to cover the case where new default
                                244                 :                :      * public privileges are added in new versions: the REVOKE ALL will revoke
                                245                 :                :      * them, leading to behavior different from what the old version had,
                                246                 :                :      * which is generally not what's wanted.  So add back default privs if the
                                247                 :                :      * source database is too old to have had that particular priv.  (As of
                                248                 :                :      * right now, no such cases exist in supported versions.)
                                249                 :                :      */
                                250                 :                : 
                                251                 :                :     /*
                                252                 :                :      * Scan individual ACL items to be granted.
                                253                 :                :      *
                                254                 :                :      * The order in which privileges appear in the ACL string (the order they
                                255                 :                :      * have been GRANT'd in, which the backend maintains) must be preserved to
                                256                 :                :      * ensure that GRANTs WITH GRANT OPTION and subsequent GRANTs based on
                                257                 :                :      * those are dumped in the correct order.  However, some old server
                                258                 :                :      * versions will show grants to PUBLIC before the owner's own grants; for
                                259                 :                :      * consistency's sake, force the owner's grants to be output first.
                                260                 :                :      */
 1370                           261         [ +  + ]:          30395 :     for (i = 0; i < ngrantitems; i++)
                                262                 :                :     {
                                263         [ +  - ]:           2005 :         if (parseAclItem(grantitems[i], type, name, subname, remoteVersion,
                                264                 :                :                          grantee, grantor, privs, privswgo))
                                265                 :                :         {
                                266                 :                :             /*
                                267                 :                :              * If the grantor isn't the owner, we'll need to use SET SESSION
                                268                 :                :              * AUTHORIZATION to become the grantor.  Issue the SET/RESET only
                                269                 :                :              * if there's something useful to do.
                                270                 :                :              */
                                271   [ +  +  +  - ]:           2005 :             if (privs->len > 0 || privswgo->len > 0)
                                272                 :                :             {
                                273                 :                :                 PQExpBuffer thissql;
                                274                 :                : 
                                275                 :                :                 /* Set owner as grantor if that's not explicit in the ACL */
                                276   [ -  +  -  - ]:           2005 :                 if (grantor->len == 0 && owner)
 1370 tgl@sss.pgh.pa.us         277                 :UBC           0 :                     printfPQExpBuffer(grantor, "%s", owner);
                                278                 :                : 
                                279                 :                :                 /* Make sure owner's own grants are output before others */
 1370 tgl@sss.pgh.pa.us         280         [ +  - ]:CBC        2005 :                 if (owner &&
                                281         [ +  + ]:           2005 :                     strcmp(grantee->data, owner) == 0 &&
                                282         [ +  - ]:            136 :                     strcmp(grantor->data, owner) == 0)
                                283                 :            136 :                     thissql = firstsql;
                                284                 :                :                 else
                                285                 :           1869 :                     thissql = secondsql;
                                286                 :                : 
 8080 peter_e@gmx.net           287         [ +  - ]:           2005 :                 if (grantor->len > 0
                                288   [ +  -  -  + ]:           2005 :                     && (!owner || strcmp(owner, grantor->data) != 0))
 1370 tgl@sss.pgh.pa.us         289                 :UBC           0 :                     appendPQExpBuffer(thissql, "SET SESSION AUTHORIZATION %s;\n",
 8080 peter_e@gmx.net           290                 :              0 :                                       fmtId(grantor->data));
                                291                 :                : 
 8135 tgl@sss.pgh.pa.us         292         [ +  + ]:CBC        2005 :                 if (privs->len > 0)
                                293                 :                :                 {
 1370                           294                 :           2003 :                     appendPQExpBuffer(thissql, "%sGRANT %s ON %s ",
                                295                 :                :                                       prefix, privs->data, type);
 2749                           296   [ +  +  +  - ]:           2003 :                     if (nspname && *nspname)
 1370                           297                 :           1714 :                         appendPQExpBuffer(thissql, "%s.", fmtId(nspname));
  999 jdavis@postgresql.or      298   [ +  -  +  + ]:           2003 :                     if (name && *name)
                                299                 :           1893 :                         appendPQExpBuffer(thissql, "%s ", name);
                                300                 :           2003 :                     appendPQExpBufferStr(thissql, "TO ");
 8135 tgl@sss.pgh.pa.us         301         [ +  + ]:           2003 :                     if (grantee->len == 0)
 1370                           302                 :           1170 :                         appendPQExpBufferStr(thissql, "PUBLIC;\n");
                                303                 :                :                     else
                                304                 :            833 :                         appendPQExpBuffer(thissql, "%s;\n", fmtId(grantee->data));
                                305                 :                :                 }
 8135                           306         [ +  + ]:           2005 :                 if (privswgo->len > 0)
                                307                 :                :                 {
 1370                           308                 :             20 :                     appendPQExpBuffer(thissql, "%sGRANT %s ON %s ",
                                309                 :                :                                       prefix, privswgo->data, type);
 2749                           310   [ +  +  +  - ]:             20 :                     if (nspname && *nspname)
 1370                           311                 :             19 :                         appendPQExpBuffer(thissql, "%s.", fmtId(nspname));
  999 jdavis@postgresql.or      312   [ +  -  +  - ]:             20 :                     if (name && *name)
                                313                 :             20 :                         appendPQExpBuffer(thissql, "%s ", name);
                                314                 :             20 :                     appendPQExpBufferStr(thissql, "TO ");
 8135 tgl@sss.pgh.pa.us         315         [ -  + ]:             20 :                     if (grantee->len == 0)
 1370 tgl@sss.pgh.pa.us         316                 :UBC           0 :                         appendPQExpBufferStr(thissql, "PUBLIC");
                                317                 :                :                     else
 1370 tgl@sss.pgh.pa.us         318                 :CBC          20 :                         appendPQExpBufferStr(thissql, fmtId(grantee->data));
                                319                 :             20 :                     appendPQExpBufferStr(thissql, " WITH GRANT OPTION;\n");
                                320                 :                :                 }
                                321                 :                : 
 8080 peter_e@gmx.net           322         [ +  - ]:           2005 :                 if (grantor->len > 0
                                323   [ +  -  -  + ]:           2005 :                     && (!owner || strcmp(owner, grantor->data) != 0))
 1370 tgl@sss.pgh.pa.us         324                 :UBC           0 :                     appendPQExpBufferStr(thissql, "RESET SESSION AUTHORIZATION;\n");
                                325                 :                :             }
                                326                 :                :         }
                                327                 :                :         else
                                328                 :                :         {
                                329                 :                :             /* parseAclItem failed, give up */
                                330                 :              0 :             ok = false;
                                331                 :              0 :             break;
                                332                 :                :         }
                                333                 :                :     }
                                334                 :                : 
 8135 tgl@sss.pgh.pa.us         335                 :CBC       28390 :     destroyPQExpBuffer(grantee);
                                336                 :          28390 :     destroyPQExpBuffer(grantor);
                                337                 :          28390 :     destroyPQExpBuffer(privs);
                                338                 :          28390 :     destroyPQExpBuffer(privswgo);
                                339                 :                : 
 8080 peter_e@gmx.net           340                 :          28390 :     appendPQExpBuffer(sql, "%s%s", firstsql->data, secondsql->data);
                                341                 :          28390 :     destroyPQExpBuffer(firstsql);
                                342                 :          28390 :     destroyPQExpBuffer(secondsql);
                                343                 :                : 
 1178 peter@eisentraut.org      344                 :          28390 :     free(aclitems);
                                345                 :          28390 :     free(baseitems);
                                346                 :          28390 :     free(grantitems);
                                347                 :          28390 :     free(revokeitems);
                                348                 :                : 
 3860 tgl@sss.pgh.pa.us         349                 :          28390 :     return ok;
                                350                 :                : }
                                351                 :                : 
                                352                 :                : /*
                                353                 :                :  * Build ALTER DEFAULT PRIVILEGES command(s) for a single pg_default_acl entry.
                                354                 :                :  *
                                355                 :                :  *  type: the object type (TABLES, FUNCTIONS, etc)
                                356                 :                :  *  nspname: schema name, or NULL for global default privileges
                                357                 :                :  *  acls: the ACL string fetched from the database
                                358                 :                :  *  acldefault: the appropriate default ACL for the object type and owner
                                359                 :                :  *  owner: username of privileges owner (will be passed through fmtId)
                                360                 :                :  *  remoteVersion: version of database
                                361                 :                :  *
                                362                 :                :  * Returns true if okay, false if could not parse the acl string.
                                363                 :                :  * The resulting commands (if any) are appended to the contents of 'sql'.
                                364                 :                :  */
                                365                 :                : bool
 5815                           366                 :            156 : buildDefaultACLCommands(const char *type, const char *nspname,
                                367                 :                :                         const char *acls, const char *acldefault,
                                368                 :                :                         const char *owner,
                                369                 :                :                         int remoteVersion,
                                370                 :                :                         PQExpBuffer sql)
                                371                 :                : {
                                372                 :                :     PQExpBuffer prefix;
                                373                 :                : 
                                374                 :            156 :     prefix = createPQExpBuffer();
                                375                 :                : 
                                376                 :                :     /*
                                377                 :                :      * We incorporate the target role directly into the command, rather than
                                378                 :                :      * playing around with SET ROLE or anything like that.  This is so that a
                                379                 :                :      * permissions error leads to nothing happening, rather than changing
                                380                 :                :      * default privileges for the wrong user.
                                381                 :                :      */
                                382                 :            156 :     appendPQExpBuffer(prefix, "ALTER DEFAULT PRIVILEGES FOR ROLE %s ",
                                383                 :                :                       fmtId(owner));
                                384         [ +  + ]:            156 :     if (nspname)
                                385                 :             74 :         appendPQExpBuffer(prefix, "IN SCHEMA %s ", fmtId(nspname));
                                386                 :                : 
                                387                 :                :     /*
                                388                 :                :      * There's no such thing as initprivs for a default ACL, so the base ACL
                                389                 :                :      * is always just the object-type-specific default.
                                390                 :                :      */
 2749                           391         [ -  + ]:            156 :     if (!buildACLCommands("", NULL, NULL, type,
                                392                 :                :                           acls, acldefault, owner,
 3140 sfrost@snowman.net        393                 :            156 :                           prefix->data, remoteVersion, sql))
                                394                 :                :     {
 3045 sfrost@snowman.net        395                 :UBC           0 :         destroyPQExpBuffer(prefix);
 3140                           396                 :              0 :         return false;
                                397                 :                :     }
                                398                 :                : 
 5815 tgl@sss.pgh.pa.us         399                 :CBC         156 :     destroyPQExpBuffer(prefix);
                                400                 :                : 
 3140 sfrost@snowman.net        401                 :            156 :     return true;
                                402                 :                : }
                                403                 :                : 
                                404                 :                : /*
                                405                 :                :  * This will parse an aclitem string, having the general form
                                406                 :                :  *      username=privilegecodes/grantor
                                407                 :                :  *
                                408                 :                :  * Returns true on success, false on parse error.  On success, the components
                                409                 :                :  * of the string are returned in the PQExpBuffer parameters.
                                410                 :                :  *
                                411                 :                :  * The returned grantee string will be the dequoted username, or an empty
                                412                 :                :  * string in the case of a grant to PUBLIC.  The returned grantor is the
                                413                 :                :  * dequoted grantor name.  Privilege characters are translated to GRANT/REVOKE
                                414                 :                :  * comma-separated privileges lists.  If "privswgo" is non-NULL, the result is
                                415                 :                :  * separate lists for privileges with grant option ("privswgo") and without
                                416                 :                :  * ("privs").  Otherwise, "privs" bears every relevant privilege, ignoring the
                                417                 :                :  * grant option distinction.
                                418                 :                :  *
                                419                 :                :  * Note: for cross-version compatibility, it's important to use ALL to
                                420                 :                :  * represent the privilege sets whenever appropriate.
                                421                 :                :  */
                                422                 :                : static bool
 6071 tgl@sss.pgh.pa.us         423                 :           2401 : parseAclItem(const char *item, const char *type,
                                424                 :                :              const char *name, const char *subname, int remoteVersion,
                                425                 :                :              PQExpBuffer grantee, PQExpBuffer grantor,
                                426                 :                :              PQExpBuffer privs, PQExpBuffer privswgo)
                                427                 :                : {
                                428                 :                :     char       *buf;
 8135                           429                 :           2401 :     bool        all_with_go = true;
                                430                 :           2401 :     bool        all_without_go = true;
                                431                 :                :     char       *eqpos;
                                432                 :                :     char       *slpos;
                                433                 :                :     char       *pos;
                                434                 :                : 
 2317 michael@paquier.xyz       435                 :           2401 :     buf = pg_strdup(item);
                                436                 :                : 
                                437                 :                :     /* user or group name is string up to = */
 1370 tgl@sss.pgh.pa.us         438                 :           2401 :     eqpos = dequoteAclUserName(grantee, buf);
 8073                           439         [ -  + ]:           2401 :     if (*eqpos != '=')
                                440                 :                :     {
 2317 michael@paquier.xyz       441                 :UBC           0 :         pg_free(buf);
 8135 tgl@sss.pgh.pa.us         442                 :              0 :         return false;
                                443                 :                :     }
                                444                 :                : 
                                445                 :                :     /* grantor should appear after / */
 8135 tgl@sss.pgh.pa.us         446                 :CBC        2401 :     slpos = strchr(eqpos + 1, '/');
                                447         [ +  - ]:           2401 :     if (slpos)
                                448                 :                :     {
 8073                           449                 :           2401 :         *slpos++ = '\0';
 1370                           450                 :           2401 :         slpos = dequoteAclUserName(grantor, slpos);
 8073                           451         [ -  + ]:           2401 :         if (*slpos != '\0')
                                452                 :                :         {
 2317 michael@paquier.xyz       453                 :UBC           0 :             pg_free(buf);
 8073 tgl@sss.pgh.pa.us         454                 :              0 :             return false;
                                455                 :                :         }
                                456                 :                :     }
                                457                 :                :     else
                                458                 :                :     {
 2317 michael@paquier.xyz       459                 :              0 :         pg_free(buf);
 3251 tgl@sss.pgh.pa.us         460                 :              0 :         return false;
                                461                 :                :     }
                                462                 :                : 
                                463                 :                :     /* privilege codes */
                                464                 :                : #define CONVERT_PRIV(code, keywd) \
                                465                 :                : do { \
                                466                 :                :     if ((pos = strchr(eqpos + 1, code))) \
                                467                 :                :     { \
                                468                 :                :         if (*(pos + 1) == '*' && privswgo != NULL) \
                                469                 :                :         { \
                                470                 :                :             AddAcl(privswgo, keywd, subname); \
                                471                 :                :             all_without_go = false; \
                                472                 :                :         } \
                                473                 :                :         else \
                                474                 :                :         { \
                                475                 :                :             AddAcl(privs, keywd, subname); \
                                476                 :                :             all_with_go = false; \
                                477                 :                :         } \
                                478                 :                :     } \
                                479                 :                :     else \
                                480                 :                :         all_with_go = all_without_go = false; \
                                481                 :                : } while (0)
                                482                 :                : 
 8135 tgl@sss.pgh.pa.us         483                 :CBC        2401 :     resetPQExpBuffer(privs);
                                484                 :           2401 :     resetPQExpBuffer(privswgo);
                                485                 :                : 
 5808                           486   [ +  +  +  + ]:           2401 :     if (strcmp(type, "TABLE") == 0 || strcmp(type, "SEQUENCE") == 0 ||
                                487   [ +  +  -  + ]:            782 :         strcmp(type, "TABLES") == 0 || strcmp(type, "SEQUENCES") == 0)
                                488                 :                :     {
 8135                           489   [ +  +  -  +  :           1728 :         CONVERT_PRIV('r', "SELECT");
                                              -  - ]
                                490                 :                : 
 5808                           491         [ +  + ]:           1728 :         if (strcmp(type, "SEQUENCE") == 0 ||
                                492         [ -  + ]:           1673 :             strcmp(type, "SEQUENCES") == 0)
                                493                 :                :             /* sequence only */
 7168 bruce@momjian.us          494   [ +  +  +  +  :            109 :             CONVERT_PRIV('U', "USAGE");
                                              +  + ]
                                495                 :                :         else
                                496                 :                :         {
                                497                 :                :             /* table only */
                                498   [ +  +  -  +  :           1673 :             CONVERT_PRIV('a', "INSERT");
                                              -  - ]
 3251 tgl@sss.pgh.pa.us         499   [ +  +  -  +  :           1673 :             CONVERT_PRIV('x', "REFERENCES");
                                              -  - ]
                                500                 :                :             /* rest are not applicable to columns */
 6071                           501         [ +  + ]:           1673 :             if (subname == NULL)
                                502                 :                :             {
 3251                           503   [ +  +  -  +  :            433 :                 CONVERT_PRIV('d', "DELETE");
                                              -  - ]
                                504   [ +  +  -  +  :            433 :                 CONVERT_PRIV('t', "TRIGGER");
                                              -  - ]
 1362                           505   [ +  +  -  +  :            433 :                 CONVERT_PRIV('D', "TRUNCATE");
                                              -  - ]
  542 nathan@postgresql.or      506   [ +  +  -  +  :            433 :                 CONVERT_PRIV('m', "MAINTAIN");
                                              -  - ]
                                507                 :                :             }
                                508                 :                :         }
                                509                 :                : 
                                510                 :                :         /* UPDATE */
 3251 tgl@sss.pgh.pa.us         511   [ +  +  +  +  :           1845 :         CONVERT_PRIV('w', "UPDATE");
                                              +  + ]
                                512                 :                :     }
 5808                           513         [ +  + ]:            673 :     else if (strcmp(type, "FUNCTION") == 0 ||
                                514         [ +  + ]:            508 :              strcmp(type, "FUNCTIONS") == 0)
 8135                           515   [ +  -  +  +  :            476 :         CONVERT_PRIV('X', "EXECUTE");
                                              +  + ]
 2837 peter_e@gmx.net           516         [ +  - ]:            435 :     else if (strcmp(type, "PROCEDURE") == 0 ||
                                517         [ -  + ]:            435 :              strcmp(type, "PROCEDURES") == 0)
 2837 peter_e@gmx.net           518   [ #  #  #  #  :UBC           0 :         CONVERT_PRIV('X', "EXECUTE");
                                              #  # ]
 8135 tgl@sss.pgh.pa.us         519         [ +  + ]:CBC         435 :     else if (strcmp(type, "LANGUAGE") == 0)
                                520   [ +  -  -  +  :             43 :         CONVERT_PRIV('U', "USAGE");
                                              -  - ]
 3084 teodor@sigaev.ru          521         [ +  + ]:            392 :     else if (strcmp(type, "SCHEMA") == 0 ||
 3035 tgl@sss.pgh.pa.us         522         [ -  + ]:            298 :              strcmp(type, "SCHEMAS") == 0)
                                523                 :                :     {
 8135                           524   [ +  +  -  +  :             94 :         CONVERT_PRIV('C', "CREATE");
                                              -  - ]
                                525   [ +  -  -  +  :            188 :         CONVERT_PRIV('U', "USAGE");
                                              -  - ]
                                526                 :                :     }
                                527         [ +  + ]:            298 :     else if (strcmp(type, "DATABASE") == 0)
                                528                 :                :     {
                                529   [ +  +  -  +  :             26 :         CONVERT_PRIV('C', "CREATE");
                                              -  - ]
 7069                           530   [ +  +  -  +  :             26 :         CONVERT_PRIV('c', "CONNECT");
                                              -  - ]
 8135                           531   [ +  +  -  +  :             26 :         CONVERT_PRIV('T', "TEMPORARY");
                                              -  - ]
                                532                 :                :     }
 7750                           533         [ -  + ]:            272 :     else if (strcmp(type, "TABLESPACE") == 0)
 7750 tgl@sss.pgh.pa.us         534   [ #  #  #  #  :UBC           0 :         CONVERT_PRIV('C', "CREATE");
                                              #  # ]
 4654 tgl@sss.pgh.pa.us         535         [ +  + ]:CBC         272 :     else if (strcmp(type, "TYPE") == 0 ||
                                536         [ +  + ]:            123 :              strcmp(type, "TYPES") == 0)
                                537   [ +  -  -  +  :            318 :         CONVERT_PRIV('U', "USAGE");
                                              -  - ]
 6105 peter_e@gmx.net           538         [ +  + ]:            113 :     else if (strcmp(type, "FOREIGN DATA WRAPPER") == 0)
                                539   [ +  -  -  +  :             36 :         CONVERT_PRIV('U', "USAGE");
                                              -  - ]
 5666 heikki.linnakangas@i      540         [ +  + ]:             77 :     else if (strcmp(type, "FOREIGN SERVER") == 0)
 6105 peter_e@gmx.net           541   [ +  -  -  +  :             36 :         CONVERT_PRIV('U', "USAGE");
                                              -  - ]
 5362 rhaas@postgresql.org      542         [ -  + ]:             41 :     else if (strcmp(type, "FOREIGN TABLE") == 0)
 5362 rhaas@postgresql.org      543   [ #  #  #  #  :UBC           0 :         CONVERT_PRIV('r', "SELECT");
                                              #  # ]
 1249 tgl@sss.pgh.pa.us         544         [ +  + ]:CBC          41 :     else if (strcmp(type, "PARAMETER") == 0)
                                545                 :                :     {
                                546   [ +  +  +  +  :              3 :         CONVERT_PRIV('s', "SET");
                                              +  - ]
                                547   [ +  -  +  +  :              3 :         CONVERT_PRIV('A', "ALTER SYSTEM");
                                              +  - ]
                                548                 :                :     }
  155 fujii@postgresql.org      549         [ -  + ]:             38 :     else if (strcmp(type, "LARGE OBJECT") == 0 ||
  155 fujii@postgresql.org      550         [ #  # ]:UBC           0 :              strcmp(type, "LARGE OBJECTS") == 0)
                                551                 :                :     {
 5748 itagaki.takahiro@gma      552   [ +  -  -  +  :CBC          38 :         CONVERT_PRIV('r', "SELECT");
                                              -  - ]
                                553   [ +  -  -  +  :             76 :         CONVERT_PRIV('w', "UPDATE");
                                              -  - ]
                                554                 :                :     }
                                555                 :                :     else
 8135 tgl@sss.pgh.pa.us         556                 :UBC           0 :         abort();
                                557                 :                : 
                                558                 :                : #undef CONVERT_PRIV
                                559                 :                : 
 8135 tgl@sss.pgh.pa.us         560         [ +  + ]:CBC        2401 :     if (all_with_go)
                                561                 :                :     {
                                562                 :              2 :         resetPQExpBuffer(privs);
                                563                 :              2 :         printfPQExpBuffer(privswgo, "ALL");
 6071                           564         [ -  + ]:              2 :         if (subname)
 6071 tgl@sss.pgh.pa.us         565                 :UBC           0 :             appendPQExpBuffer(privswgo, "(%s)", subname);
                                566                 :                :     }
 8135 tgl@sss.pgh.pa.us         567         [ +  + ]:CBC        2399 :     else if (all_without_go)
                                568                 :                :     {
                                569                 :            649 :         resetPQExpBuffer(privswgo);
                                570                 :            649 :         printfPQExpBuffer(privs, "ALL");
 6071                           571         [ -  + ]:            649 :         if (subname)
 6071 tgl@sss.pgh.pa.us         572                 :UBC           0 :             appendPQExpBuffer(privs, "(%s)", subname);
                                573                 :                :     }
                                574                 :                : 
 2317 michael@paquier.xyz       575                 :CBC        2401 :     pg_free(buf);
                                576                 :                : 
 8135 tgl@sss.pgh.pa.us         577                 :           2401 :     return true;
                                578                 :                : }
                                579                 :                : 
                                580                 :                : /*
                                581                 :                :  * Transfer the role name at *input into the output buffer, adding
                                582                 :                :  * quoting according to the same rules as putid() in backend's acl.c.
                                583                 :                :  */
                                584                 :                : void
 1370                           585                 :            546 : quoteAclUserName(PQExpBuffer output, const char *input)
                                586                 :                : {
                                587                 :                :     const char *src;
                                588                 :            546 :     bool        safe = true;
                                589                 :                : 
                                590         [ +  + ]:           9324 :     for (src = input; *src; src++)
                                591                 :                :     {
                                592                 :                :         /* This test had better match what putid() does */
                                593   [ +  +  +  + ]:           8946 :         if (!isalnum((unsigned char) *src) && *src != '_')
                                594                 :                :         {
                                595                 :            168 :             safe = false;
                                596                 :            168 :             break;
                                597                 :                :         }
                                598                 :                :     }
                                599         [ +  + ]:            546 :     if (!safe)
                                600                 :            168 :         appendPQExpBufferChar(output, '"');
                                601         [ +  + ]:          10836 :     for (src = input; *src; src++)
                                602                 :                :     {
                                603                 :                :         /* A double quote character in a username is encoded as "" */
                                604         [ +  + ]:          10290 :         if (*src == '"')
                                605                 :            168 :             appendPQExpBufferChar(output, '"');
                                606                 :          10290 :         appendPQExpBufferChar(output, *src);
                                607                 :                :     }
                                608         [ +  + ]:            546 :     if (!safe)
                                609                 :            168 :         appendPQExpBufferChar(output, '"');
                                610                 :            546 : }
                                611                 :                : 
                                612                 :                : /*
                                613                 :                :  * Transfer a user or group name starting at *input into the output buffer,
                                614                 :                :  * dequoting if needed.  Returns a pointer to just past the input name.
                                615                 :                :  * The name is taken to end at an unquoted '=' or end of string.
                                616                 :                :  * Note: unlike quoteAclUserName(), this first clears the output buffer.
                                617                 :                :  */
                                618                 :                : static char *
                                619                 :           4802 : dequoteAclUserName(PQExpBuffer output, char *input)
                                620                 :                : {
 8073                           621                 :           4802 :     resetPQExpBuffer(output);
                                622                 :                : 
                                623   [ +  +  +  + ]:          41796 :     while (*input && *input != '=')
                                624                 :                :     {
                                625                 :                :         /*
                                626                 :                :          * If user name isn't quoted, then just add it to the output buffer
                                627                 :                :          */
                                628         [ +  + ]:          36994 :         if (*input != '"')
                                629                 :          36885 :             appendPQExpBufferChar(output, *input++);
                                630                 :                :         else
                                631                 :                :         {
                                632                 :                :             /* Otherwise, it's a quoted username */
                                633                 :            109 :             input++;
                                634                 :                :             /* Loop until we come across an unescaped quote */
 8059                           635   [ +  +  +  + ]:           2616 :             while (!(*input == '"' && *(input + 1) != '"'))
                                636                 :                :             {
 8073                           637         [ -  + ]:           2507 :                 if (*input == '\0')
 2999 tgl@sss.pgh.pa.us         638                 :UBC           0 :                     return input;   /* really a syntax error... */
                                639                 :                : 
                                640                 :                :                 /*
                                641                 :                :                  * Quoting convention is to escape " as "".  Keep this code in
                                642                 :                :                  * sync with putid() in backend's acl.c.
                                643                 :                :                  */
 8059 tgl@sss.pgh.pa.us         644   [ +  +  +  - ]:CBC        2507 :                 if (*input == '"' && *(input + 1) == '"')
                                645                 :            109 :                     input++;
 8073                           646                 :           2507 :                 appendPQExpBufferChar(output, *input++);
                                647                 :                :             }
                                648                 :            109 :             input++;
                                649                 :                :         }
                                650                 :                :     }
                                651                 :           4802 :     return input;
                                652                 :                : }
                                653                 :                : 
                                654                 :                : /*
                                655                 :                :  * Append a privilege keyword to a keyword list, inserting comma if needed.
                                656                 :                :  */
                                657                 :                : static void
 6071                           658                 :           3097 : AddAcl(PQExpBuffer aclbuf, const char *keyword, const char *subname)
                                659                 :                : {
 8135                           660         [ +  + ]:           3097 :     if (aclbuf->len > 0)
                                661                 :            678 :         appendPQExpBufferChar(aclbuf, ',');
 4310 heikki.linnakangas@i      662                 :           3097 :     appendPQExpBufferStr(aclbuf, keyword);
 6071 tgl@sss.pgh.pa.us         663         [ +  + ]:           3097 :     if (subname)
                                664                 :           1240 :         appendPQExpBuffer(aclbuf, "(%s)", subname);
 8135                           665                 :           3097 : }
                                666                 :                : 
                                667                 :                : 
                                668                 :                : /*
                                669                 :                :  * buildShSecLabelQuery
                                670                 :                :  *
                                671                 :                :  * Build a query to retrieve security labels for a shared object.
                                672                 :                :  * The object is identified by its OID plus the name of the catalog
                                673                 :                :  * it can be found in (e.g., "pg_database" for database names).
                                674                 :                :  * The query is appended to "sql".  (We don't execute it here so as to
                                675                 :                :  * keep this file free of assumptions about how to deal with SQL errors.)
                                676                 :                :  */
                                677                 :                : void
 1838 peter@eisentraut.org      678                 :            172 : buildShSecLabelQuery(const char *catalog_name, Oid objectId,
                                679                 :                :                      PQExpBuffer sql)
                                680                 :                : {
 5162 rhaas@postgresql.org      681                 :            172 :     appendPQExpBuffer(sql,
                                682                 :                :                       "SELECT provider, label FROM pg_catalog.pg_shseclabel "
                                683                 :                :                       "WHERE classoid = 'pg_catalog.%s'::pg_catalog.regclass "
                                684                 :                :                       "AND objoid = '%u'", catalog_name, objectId);
                                685                 :            172 : }
                                686                 :                : 
                                687                 :                : /*
                                688                 :                :  * emitShSecLabels
                                689                 :                :  *
                                690                 :                :  * Construct SECURITY LABEL commands using the data retrieved by the query
                                691                 :                :  * generated by buildShSecLabelQuery, and append them to "buffer".
                                692                 :                :  * Here, the target object is identified by its type name (e.g. "DATABASE")
                                693                 :                :  * and its name (not pre-quoted).
                                694                 :                :  */
                                695                 :                : void
                                696                 :            172 : emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer,
                                697                 :                :                 const char *objtype, const char *objname)
                                698                 :                : {
                                699                 :                :     int         i;
                                700                 :                : 
                                701         [ -  + ]:            172 :     for (i = 0; i < PQntuples(res); i++)
                                702                 :                :     {
 4836 bruce@momjian.us          703                 :UBC           0 :         char       *provider = PQgetvalue(res, i, 0);
                                704                 :              0 :         char       *label = PQgetvalue(res, i, 1);
                                705                 :                : 
                                706                 :                :         /* must use fmtId result before calling it again */
 5162 rhaas@postgresql.org      707                 :              0 :         appendPQExpBuffer(buffer,
                                708                 :                :                           "SECURITY LABEL FOR %s ON %s",
                                709                 :                :                           fmtId(provider), objtype);
                                710                 :              0 :         appendPQExpBuffer(buffer,
                                711                 :                :                           " %s IS ",
                                712                 :                :                           fmtId(objname));
                                713                 :              0 :         appendStringLiteralConn(buffer, label, conn);
 4310 heikki.linnakangas@i      714                 :              0 :         appendPQExpBufferStr(buffer, ";\n");
                                715                 :                :     }
 5162 rhaas@postgresql.org      716                 :CBC         172 : }
                                717                 :                : 
                                718                 :                : 
                                719                 :                : /*
                                720                 :                :  * Detect whether the given GUC variable is of GUC_LIST_QUOTE type.
                                721                 :                :  *
                                722                 :                :  * It'd be better if we could inquire this directly from the backend; but even
                                723                 :                :  * if there were a function for that, it could only tell us about variables
                                724                 :                :  * currently known to guc.c, so that it'd be unsafe for extensions to declare
                                725                 :                :  * GUC_LIST_QUOTE variables anyway.  Lacking a solution for that, it doesn't
                                726                 :                :  * seem worth the work to do more than have this list, which must be kept in
                                727                 :                :  * sync with the variables actually marked GUC_LIST_QUOTE in guc_parameters.dat.
                                728                 :                :  */
                                729                 :                : bool
 2726 tgl@sss.pgh.pa.us         730                 :             70 : variable_is_guc_list_quote(const char *name)
                                731                 :                : {
 1764 michael@paquier.xyz       732   [ +  +  +  + ]:            135 :     if (pg_strcasecmp(name, "local_preload_libraries") == 0 ||
                                733         [ +  - ]:            125 :         pg_strcasecmp(name, "search_path") == 0 ||
 2726 tgl@sss.pgh.pa.us         734         [ +  - ]:            120 :         pg_strcasecmp(name, "session_preload_libraries") == 0 ||
                                735         [ +  - ]:            120 :         pg_strcasecmp(name, "shared_preload_libraries") == 0 ||
 1764 michael@paquier.xyz       736         [ -  + ]:            120 :         pg_strcasecmp(name, "temp_tablespaces") == 0 ||
                                737                 :             60 :         pg_strcasecmp(name, "unix_socket_directories") == 0)
 2726 tgl@sss.pgh.pa.us         738                 :             10 :         return true;
                                739                 :                :     else
                                740                 :             60 :         return false;
                                741                 :                : }
                                742                 :                : 
                                743                 :                : /*
                                744                 :                :  * SplitGUCList --- parse a string containing identifiers or file names
                                745                 :                :  *
                                746                 :                :  * This is used to split the value of a GUC_LIST_QUOTE GUC variable, without
                                747                 :                :  * presuming whether the elements will be taken as identifiers or file names.
                                748                 :                :  * See comparable code in src/backend/utils/adt/varlena.c.
                                749                 :                :  *
                                750                 :                :  * Inputs:
                                751                 :                :  *  rawstring: the input string; must be overwritable!  On return, it's
                                752                 :                :  *             been modified to contain the separated identifiers.
                                753                 :                :  *  separator: the separator punctuation expected between identifiers
                                754                 :                :  *             (typically '.' or ',').  Whitespace may also appear around
                                755                 :                :  *             identifiers.
                                756                 :                :  * Outputs:
                                757                 :                :  *  namelist: receives a malloc'd, null-terminated array of pointers to
                                758                 :                :  *            identifiers within rawstring.  Caller should free this
                                759                 :                :  *            even on error return.
                                760                 :                :  *
                                761                 :                :  * Returns true if okay, false if there is a syntax error in the string.
                                762                 :                :  */
                                763                 :                : bool
 2594                           764                 :             10 : SplitGUCList(char *rawstring, char separator,
                                765                 :                :              char ***namelist)
                                766                 :                : {
                                767                 :             10 :     char       *nextp = rawstring;
                                768                 :             10 :     bool        done = false;
                                769                 :                :     char      **nextptr;
                                770                 :                : 
                                771                 :                :     /*
                                772                 :                :      * Since we disallow empty identifiers, this is a conservative
                                773                 :                :      * overestimate of the number of pointers we could need.  Allow one for
                                774                 :                :      * list terminator.
                                775                 :                :      */
                                776                 :             10 :     *namelist = nextptr = (char **)
                                777                 :             10 :         pg_malloc((strlen(rawstring) / 2 + 2) * sizeof(char *));
                                778                 :             10 :     *nextptr = NULL;
                                779                 :                : 
                                780         [ -  + ]:             10 :     while (isspace((unsigned char) *nextp))
 2594 tgl@sss.pgh.pa.us         781                 :UBC           0 :         nextp++;                /* skip leading whitespace */
                                782                 :                : 
 2594 tgl@sss.pgh.pa.us         783         [ -  + ]:CBC          10 :     if (*nextp == '\0')
 2594 tgl@sss.pgh.pa.us         784                 :UBC           0 :         return true;            /* allow empty string */
                                785                 :                : 
                                786                 :                :     /* At the top of the loop, we are at start of a new identifier. */
                                787                 :                :     do
                                788                 :                :     {
                                789                 :                :         char       *curname;
                                790                 :                :         char       *endp;
                                791                 :                : 
 2594 tgl@sss.pgh.pa.us         792         [ +  + ]:CBC          25 :         if (*nextp == '"')
                                793                 :                :         {
                                794                 :                :             /* Quoted name --- collapse quote-quote pairs */
                                795                 :             20 :             curname = nextp + 1;
                                796                 :                :             for (;;)
                                797                 :                :             {
                                798                 :             30 :                 endp = strchr(nextp + 1, '"');
                                799         [ -  + ]:             25 :                 if (endp == NULL)
 2594 tgl@sss.pgh.pa.us         800                 :UBC           0 :                     return false;   /* mismatched quotes */
 2594 tgl@sss.pgh.pa.us         801         [ +  + ]:CBC          25 :                 if (endp[1] != '"')
                                802                 :             20 :                     break;      /* found end of quoted name */
                                803                 :                :                 /* Collapse adjacent quotes into one quote, and look again */
                                804                 :              5 :                 memmove(endp, endp + 1, strlen(endp));
                                805                 :              5 :                 nextp = endp;
                                806                 :                :             }
                                807                 :                :             /* endp now points at the terminating quote */
                                808                 :             20 :             nextp = endp + 1;
                                809                 :                :         }
                                810                 :                :         else
                                811                 :                :         {
                                812                 :                :             /* Unquoted name --- extends to separator or whitespace */
                                813                 :              5 :             curname = nextp;
                                814   [ +  +  +  - ]:             55 :             while (*nextp && *nextp != separator &&
                                815         [ +  - ]:             50 :                    !isspace((unsigned char) *nextp))
                                816                 :             50 :                 nextp++;
                                817                 :              5 :             endp = nextp;
                                818         [ -  + ]:              5 :             if (curname == nextp)
 2594 tgl@sss.pgh.pa.us         819                 :UBC           0 :                 return false;   /* empty unquoted name not allowed */
                                820                 :                :         }
                                821                 :                : 
 2594 tgl@sss.pgh.pa.us         822         [ -  + ]:CBC          25 :         while (isspace((unsigned char) *nextp))
 2594 tgl@sss.pgh.pa.us         823                 :UBC           0 :             nextp++;            /* skip trailing whitespace */
                                824                 :                : 
 2594 tgl@sss.pgh.pa.us         825         [ +  + ]:CBC          25 :         if (*nextp == separator)
                                826                 :                :         {
                                827                 :             15 :             nextp++;
                                828         [ +  + ]:             30 :             while (isspace((unsigned char) *nextp))
                                829                 :             15 :                 nextp++;        /* skip leading whitespace for next */
                                830                 :                :             /* we expect another name, so done remains false */
                                831                 :                :         }
                                832         [ +  - ]:             10 :         else if (*nextp == '\0')
                                833                 :             10 :             done = true;
                                834                 :                :         else
 2594 tgl@sss.pgh.pa.us         835                 :UBC           0 :             return false;       /* invalid syntax */
                                836                 :                : 
                                837                 :                :         /* Now safe to overwrite separator with a null */
 2594 tgl@sss.pgh.pa.us         838                 :CBC          25 :         *endp = '\0';
                                839                 :                : 
                                840                 :                :         /*
                                841                 :                :          * Finished isolating current name --- add it to output array
                                842                 :                :          */
                                843                 :             25 :         *nextptr++ = curname;
                                844                 :                : 
                                845                 :                :         /* Loop back if we didn't reach end of string */
                                846         [ +  + ]:             25 :     } while (!done);
                                847                 :                : 
                                848                 :             10 :     *nextptr = NULL;
                                849                 :             10 :     return true;
                                850                 :                : }
                                851                 :                : 
                                852                 :                : /*
                                853                 :                :  * Helper function for dumping "ALTER DATABASE/ROLE SET ..." commands.
                                854                 :                :  *
                                855                 :                :  * Parse the contents of configitem (a "name=value" string), wrap it in
                                856                 :                :  * a complete ALTER command, and append it to buf.
                                857                 :                :  *
                                858                 :                :  * type is DATABASE or ROLE, and name is the name of the database or role.
                                859                 :                :  * If we need an "IN" clause, type2 and name2 similarly define what to put
                                860                 :                :  * there; otherwise they should be NULL.
                                861                 :                :  * conn is used only to determine string-literal quoting conventions.
                                862                 :                :  */
                                863                 :                : void
 2784                           864                 :             35 : makeAlterConfigCommand(PGconn *conn, const char *configitem,
                                865                 :                :                        const char *type, const char *name,
                                866                 :                :                        const char *type2, const char *name2,
                                867                 :                :                        PQExpBuffer buf)
                                868                 :                : {
                                869                 :                :     char       *mine;
                                870                 :                :     char       *pos;
                                871                 :                : 
                                872                 :                :     /* Parse the configitem.  If we can't find an "=", silently do nothing. */
                                873                 :             35 :     mine = pg_strdup(configitem);
                                874                 :             35 :     pos = strchr(mine, '=');
                                875         [ -  + ]:             35 :     if (pos == NULL)
                                876                 :                :     {
 2784 tgl@sss.pgh.pa.us         877                 :UBC           0 :         pg_free(mine);
                                878                 :              0 :         return;
                                879                 :                :     }
 2784 tgl@sss.pgh.pa.us         880                 :CBC          35 :     *pos++ = '\0';
                                881                 :                : 
                                882                 :                :     /* Build the command, with suitable quoting for everything. */
                                883                 :             35 :     appendPQExpBuffer(buf, "ALTER %s %s ", type, fmtId(name));
                                884   [ -  +  -  - ]:             35 :     if (type2 != NULL && name2 != NULL)
 2784 tgl@sss.pgh.pa.us         885                 :UBC           0 :         appendPQExpBuffer(buf, "IN %s %s ", type2, fmtId(name2));
 2784 tgl@sss.pgh.pa.us         886                 :CBC          35 :     appendPQExpBuffer(buf, "SET %s TO ", fmtId(mine));
                                887                 :                : 
                                888                 :                :     /*
                                889                 :                :      * Variables that are marked GUC_LIST_QUOTE were already fully quoted by
                                890                 :                :      * flatten_set_variable_args() before they were put into the setconfig
                                891                 :                :      * array.  However, because the quoting rules used there aren't exactly
                                892                 :                :      * like SQL's, we have to break the list value apart and then quote the
                                893                 :                :      * elements as string literals.  (The elements may be double-quoted as-is,
                                894                 :                :      * but we can't just feed them to the SQL parser; it would do the wrong
                                895                 :                :      * thing with elements that are zero-length or longer than NAMEDATALEN.)
                                896                 :                :      *
                                897                 :                :      * Variables that are not so marked should just be emitted as simple
                                898                 :                :      * string literals.  If the variable is not known to
                                899                 :                :      * variable_is_guc_list_quote(), we'll do that; this makes it unsafe to
                                900                 :                :      * use GUC_LIST_QUOTE for extension variables.
                                901                 :                :      */
 2726                           902         [ -  + ]:             35 :     if (variable_is_guc_list_quote(mine))
                                903                 :                :     {
                                904                 :                :         char      **namelist;
                                905                 :                :         char      **nameptr;
                                906                 :                : 
                                907                 :                :         /* Parse string into list of identifiers */
                                908                 :                :         /* this shouldn't fail really */
 2594 tgl@sss.pgh.pa.us         909         [ #  # ]:UBC           0 :         if (SplitGUCList(pos, ',', &namelist))
                                910                 :                :         {
                                911         [ #  # ]:              0 :             for (nameptr = namelist; *nameptr; nameptr++)
                                912                 :                :             {
                                913         [ #  # ]:              0 :                 if (nameptr != namelist)
                                914                 :              0 :                     appendPQExpBufferStr(buf, ", ");
                                915                 :              0 :                 appendStringLiteralConn(buf, *nameptr, conn);
                                916                 :                :             }
                                917                 :                :         }
                                918                 :              0 :         pg_free(namelist);
                                919                 :                :     }
                                920                 :                :     else
 2784 tgl@sss.pgh.pa.us         921                 :CBC          35 :         appendStringLiteralConn(buf, pos, conn);
                                922                 :                : 
                                923                 :             35 :     appendPQExpBufferStr(buf, ";\n");
                                924                 :                : 
                                925                 :             35 :     pg_free(mine);
                                926                 :                : }
                                927                 :                : 
                                928                 :                : /*
                                929                 :                :  * create_or_open_dir
                                930                 :                :  *
                                931                 :                :  * This will create a new directory with the given dirname. If there is
                                932                 :                :  * already an empty directory with that name, then use it.
                                933                 :                :  */
                                934                 :                : void
  149 andrew@dunslane.net       935                 :             11 : create_or_open_dir(const char *dirname)
                                936                 :                : {
                                937                 :                :     int         ret;
                                938                 :                : 
                                939   [ -  +  -  - ]:             11 :     switch ((ret = pg_check_dir(dirname)))
                                940                 :                :     {
  149 andrew@dunslane.net       941                 :UBC           0 :         case -1:
                                942                 :                :             /* opendir failed but not with ENOENT */
                                943                 :              0 :             pg_fatal("could not open directory \"%s\": %m", dirname);
                                944                 :                :             break;
  149 andrew@dunslane.net       945                 :CBC          11 :         case 0:
                                946                 :                :             /* directory does not exist */
                                947         [ -  + ]:             11 :             if (mkdir(dirname, pg_dir_create_mode) < 0)
  149 andrew@dunslane.net       948                 :UBC           0 :                 pg_fatal("could not create directory \"%s\": %m", dirname);
  149 andrew@dunslane.net       949                 :CBC          11 :             break;
  149 andrew@dunslane.net       950                 :UBC           0 :         case 1:
                                951                 :                :             /* exists and is empty, fix perms */
                                952         [ #  # ]:              0 :             if (chmod(dirname, pg_dir_create_mode) != 0)
                                953                 :              0 :                 pg_fatal("could not change permissions of directory \"%s\": %m",
                                954                 :                :                          dirname);
                                955                 :              0 :             break;
                                956                 :              0 :         default:
                                957                 :                :             /* exists and is not empty */
                                958                 :              0 :             pg_fatal("directory \"%s\" is not empty", dirname);
                                959                 :                :     }
  149 andrew@dunslane.net       960                 :CBC          11 : }
                                961                 :                : 
                                962                 :                : /*
                                963                 :                :  * Generates a valid restrict key (i.e., an alphanumeric string) for use with
                                964                 :                :  * psql's \restrict and \unrestrict meta-commands.  For safety, the value is
                                965                 :                :  * chosen at random.
                                966                 :                :  */
                                967                 :                : char *
   26 nathan@postgresql.or      968                 :            188 : generate_restrict_key(void)
                                969                 :                : {
                                970                 :                :     uint8       buf[64];
                                971                 :            188 :     char       *ret = palloc(sizeof(buf));
                                972                 :                : 
                                973         [ -  + ]:            188 :     if (!pg_strong_random(buf, sizeof(buf)))
   26 nathan@postgresql.or      974                 :UBC           0 :         return NULL;
                                975                 :                : 
   26 nathan@postgresql.or      976         [ +  + ]:CBC       12032 :     for (int i = 0; i < sizeof(buf) - 1; i++)
                                977                 :                :     {
                                978                 :          11844 :         uint8       idx = buf[i] % strlen(restrict_chars);
                                979                 :                : 
                                980                 :          11844 :         ret[i] = restrict_chars[idx];
                                981                 :                :     }
                                982                 :            188 :     ret[sizeof(buf) - 1] = '\0';
                                983                 :                : 
                                984                 :            188 :     return ret;
                                985                 :                : }
                                986                 :                : 
                                987                 :                : /*
                                988                 :                :  * Checks that a given restrict key (intended for use with psql's \restrict and
                                989                 :                :  * \unrestrict meta-commands) contains only alphanumeric characters.
                                990                 :                :  */
                                991                 :                : bool
                                992                 :            220 : valid_restrict_key(const char *restrict_key)
                                993                 :                : {
                                994                 :            220 :     return restrict_key != NULL &&
                                995   [ +  -  +  - ]:            440 :         restrict_key[0] != '\0' &&
                                996         [ +  - ]:            220 :         strspn(restrict_key, restrict_chars) == strlen(restrict_key);
                                997                 :                : }
        

Generated by: LCOV version 2.4-beta