]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/dumputils.c
acce7f82fa448a52987e2ea31598a0c3a91fb83e
[postgresql] / src / bin / pg_dump / dumputils.c
1 /*-------------------------------------------------------------------------
2  *
3  * Utility routines for SQL dumping
4  *      Basically this is stuff that is useful in both pg_dump and pg_dumpall.
5  *      Lately it's also being used by psql and bin/scripts/ ...
6  *
7  *
8  * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
9  * Portions Copyright (c) 1994, Regents of the University of California
10  *
11  * src/bin/pg_dump/dumputils.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres_fe.h"
16
17 #include <ctype.h>
18
19 #include "dumputils.h"
20
21 #include "parser/keywords.h"
22
23
24 int                     quote_all_identifiers = 0;
25
26
27 #define supports_grant_options(version) ((version) >= 70400)
28
29 static bool parseAclItem(const char *item, const char *type,
30                          const char *name, const char *subname, int remoteVersion,
31                          PQExpBuffer grantee, PQExpBuffer grantor,
32                          PQExpBuffer privs, PQExpBuffer privswgo);
33 static char *copyAclUserName(PQExpBuffer output, char *input);
34 static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
35            const char *subname);
36
37 #ifdef WIN32
38 static bool parallel_init_done = false;
39 static DWORD tls_index;
40 #endif
41
42 void
43 init_parallel_dump_utils(void)
44 {
45 #ifdef WIN32
46         if (!parallel_init_done)
47         {
48                 tls_index = TlsAlloc();
49                 parallel_init_done = true;
50         }
51 #endif
52 }
53
54 /*
55  *      Quotes input string if it's not a legitimate SQL identifier as-is.
56  *
57  *      Note that the returned string must be used before calling fmtId again,
58  *      since we re-use the same return buffer each time.  Non-reentrant but
59  *      reduces memory leakage. (On Windows the memory leakage will be one buffer
60  *      per thread, which is at least better than one per call).
61  */
62 const char *
63 fmtId(const char *rawid)
64 {
65         /*
66          * The Tls code goes awry if we use a static var, so we provide for both
67          * static and auto, and omit any use of the static var when using Tls.
68          */
69         static PQExpBuffer s_id_return = NULL;
70         PQExpBuffer id_return;
71
72         const char *cp;
73         bool            need_quotes = false;
74
75 #ifdef WIN32
76         if (parallel_init_done)
77                 id_return = (PQExpBuffer) TlsGetValue(tls_index);               /* 0 when not set */
78         else
79                 id_return = s_id_return;
80 #else
81         id_return = s_id_return;
82 #endif
83
84         if (id_return)                          /* first time through? */
85         {
86                 /* same buffer, just wipe contents */
87                 resetPQExpBuffer(id_return);
88         }
89         else
90         {
91                 /* new buffer */
92                 id_return = createPQExpBuffer();
93 #ifdef WIN32
94                 if (parallel_init_done)
95                         TlsSetValue(tls_index, id_return);
96                 else
97                         s_id_return = id_return;
98 #else
99                 s_id_return = id_return;
100 #endif
101
102         }
103
104         /*
105          * These checks need to match the identifier production in scan.l. Don't
106          * use islower() etc.
107          */
108         if (quote_all_identifiers)
109                 need_quotes = true;
110         /* slightly different rules for first character */
111         else if (!((rawid[0] >= 'a' && rawid[0] <= 'z') || rawid[0] == '_'))
112                 need_quotes = true;
113         else
114         {
115                 /* otherwise check the entire string */
116                 for (cp = rawid; *cp; cp++)
117                 {
118                         if (!((*cp >= 'a' && *cp <= 'z')
119                                   || (*cp >= '0' && *cp <= '9')
120                                   || (*cp == '_')))
121                         {
122                                 need_quotes = true;
123                                 break;
124                         }
125                 }
126         }
127
128         if (!need_quotes)
129         {
130                 /*
131                  * Check for keyword.  We quote keywords except for unreserved ones.
132                  * (In some cases we could avoid quoting a col_name or type_func_name
133                  * keyword, but it seems much harder than it's worth to tell that.)
134                  *
135                  * Note: ScanKeywordLookup() does case-insensitive comparison, but
136                  * that's fine, since we already know we have all-lower-case.
137                  */
138                 const ScanKeyword *keyword = ScanKeywordLookup(rawid,
139                                                                                                            ScanKeywords,
140                                                                                                            NumScanKeywords);
141
142                 if (keyword != NULL && keyword->category != UNRESERVED_KEYWORD)
143                         need_quotes = true;
144         }
145
146         if (!need_quotes)
147         {
148                 /* no quoting needed */
149                 appendPQExpBufferStr(id_return, rawid);
150         }
151         else
152         {
153                 appendPQExpBufferChar(id_return, '\"');
154                 for (cp = rawid; *cp; cp++)
155                 {
156                         /*
157                          * Did we find a double-quote in the string? Then make this a
158                          * double double-quote per SQL99. Before, we put in a
159                          * backslash/double-quote pair. - thomas 2000-08-05
160                          */
161                         if (*cp == '\"')
162                                 appendPQExpBufferChar(id_return, '\"');
163                         appendPQExpBufferChar(id_return, *cp);
164                 }
165                 appendPQExpBufferChar(id_return, '\"');
166         }
167
168         return id_return->data;
169 }
170
171
172 /*
173  * Convert a string value to an SQL string literal and append it to
174  * the given buffer.  We assume the specified client_encoding and
175  * standard_conforming_strings settings.
176  *
177  * This is essentially equivalent to libpq's PQescapeStringInternal,
178  * except for the output buffer structure.      We need it in situations
179  * where we do not have a PGconn available.  Where we do,
180  * appendStringLiteralConn is a better choice.
181  */
182 void
183 appendStringLiteral(PQExpBuffer buf, const char *str,
184                                         int encoding, bool std_strings)
185 {
186         size_t          length = strlen(str);
187         const char *source = str;
188         char       *target;
189
190         if (!enlargePQExpBuffer(buf, 2 * length + 2))
191                 return;
192
193         target = buf->data + buf->len;
194         *target++ = '\'';
195
196         while (*source != '\0')
197         {
198                 char            c = *source;
199                 int                     len;
200                 int                     i;
201
202                 /* Fast path for plain ASCII */
203                 if (!IS_HIGHBIT_SET(c))
204                 {
205                         /* Apply quoting if needed */
206                         if (SQL_STR_DOUBLE(c, !std_strings))
207                                 *target++ = c;
208                         /* Copy the character */
209                         *target++ = c;
210                         source++;
211                         continue;
212                 }
213
214                 /* Slow path for possible multibyte characters */
215                 len = PQmblen(source, encoding);
216
217                 /* Copy the character */
218                 for (i = 0; i < len; i++)
219                 {
220                         if (*source == '\0')
221                                 break;
222                         *target++ = *source++;
223                 }
224
225                 /*
226                  * If we hit premature end of string (ie, incomplete multibyte
227                  * character), try to pad out to the correct length with spaces. We
228                  * may not be able to pad completely, but we will always be able to
229                  * insert at least one pad space (since we'd not have quoted a
230                  * multibyte character).  This should be enough to make a string that
231                  * the server will error out on.
232                  */
233                 if (i < len)
234                 {
235                         char       *stop = buf->data + buf->maxlen - 2;
236
237                         for (; i < len; i++)
238                         {
239                                 if (target >= stop)
240                                         break;
241                                 *target++ = ' ';
242                         }
243                         break;
244                 }
245         }
246
247         /* Write the terminating quote and NUL character. */
248         *target++ = '\'';
249         *target = '\0';
250
251         buf->len = target - buf->data;
252 }
253
254
255 /*
256  * Convert a string value to an SQL string literal and append it to
257  * the given buffer.  Encoding and string syntax rules are as indicated
258  * by current settings of the PGconn.
259  */
260 void
261 appendStringLiteralConn(PQExpBuffer buf, const char *str, PGconn *conn)
262 {
263         size_t          length = strlen(str);
264
265         /*
266          * XXX This is a kluge to silence escape_string_warning in our utility
267          * programs.  It should go away someday.
268          */
269         if (strchr(str, '\\') != NULL && PQserverVersion(conn) >= 80100)
270         {
271                 /* ensure we are not adjacent to an identifier */
272                 if (buf->len > 0 && buf->data[buf->len - 1] != ' ')
273                         appendPQExpBufferChar(buf, ' ');
274                 appendPQExpBufferChar(buf, ESCAPE_STRING_SYNTAX);
275                 appendStringLiteral(buf, str, PQclientEncoding(conn), false);
276                 return;
277         }
278         /* XXX end kluge */
279
280         if (!enlargePQExpBuffer(buf, 2 * length + 2))
281                 return;
282         appendPQExpBufferChar(buf, '\'');
283         buf->len += PQescapeStringConn(conn, buf->data + buf->len,
284                                                                    str, length, NULL);
285         appendPQExpBufferChar(buf, '\'');
286 }
287
288
289 /*
290  * Convert a string value to a dollar quoted literal and append it to
291  * the given buffer. If the dqprefix parameter is not NULL then the
292  * dollar quote delimiter will begin with that (after the opening $).
293  *
294  * No escaping is done at all on str, in compliance with the rules
295  * for parsing dollar quoted strings.  Also, we need not worry about
296  * encoding issues.
297  */
298 void
299 appendStringLiteralDQ(PQExpBuffer buf, const char *str, const char *dqprefix)
300 {
301         static const char suffixes[] = "_XXXXXXX";
302         int                     nextchar = 0;
303         PQExpBuffer delimBuf = createPQExpBuffer();
304
305         /* start with $ + dqprefix if not NULL */
306         appendPQExpBufferChar(delimBuf, '$');
307         if (dqprefix)
308                 appendPQExpBufferStr(delimBuf, dqprefix);
309
310         /*
311          * Make sure we choose a delimiter which (without the trailing $) is not
312          * present in the string being quoted. We don't check with the trailing $
313          * because a string ending in $foo must not be quoted with $foo$.
314          */
315         while (strstr(str, delimBuf->data) != NULL)
316         {
317                 appendPQExpBufferChar(delimBuf, suffixes[nextchar++]);
318                 nextchar %= sizeof(suffixes) - 1;
319         }
320
321         /* add trailing $ */
322         appendPQExpBufferChar(delimBuf, '$');
323
324         /* quote it and we are all done */
325         appendPQExpBufferStr(buf, delimBuf->data);
326         appendPQExpBufferStr(buf, str);
327         appendPQExpBufferStr(buf, delimBuf->data);
328
329         destroyPQExpBuffer(delimBuf);
330 }
331
332
333 /*
334  * Convert a bytea value (presented as raw bytes) to an SQL string literal
335  * and append it to the given buffer.  We assume the specified
336  * standard_conforming_strings setting.
337  *
338  * This is needed in situations where we do not have a PGconn available.
339  * Where we do, PQescapeByteaConn is a better choice.
340  */
341 void
342 appendByteaLiteral(PQExpBuffer buf, const unsigned char *str, size_t length,
343                                    bool std_strings)
344 {
345         const unsigned char *source = str;
346         char       *target;
347
348         static const char hextbl[] = "0123456789abcdef";
349
350         /*
351          * This implementation is hard-wired to produce hex-format output. We do
352          * not know the server version the output will be loaded into, so making
353          * an intelligent format choice is impossible.  It might be better to
354          * always use the old escaped format.
355          */
356         if (!enlargePQExpBuffer(buf, 2 * length + 5))
357                 return;
358
359         target = buf->data + buf->len;
360         *target++ = '\'';
361         if (!std_strings)
362                 *target++ = '\\';
363         *target++ = '\\';
364         *target++ = 'x';
365
366         while (length-- > 0)
367         {
368                 unsigned char c = *source++;
369
370                 *target++ = hextbl[(c >> 4) & 0xF];
371                 *target++ = hextbl[c & 0xF];
372         }
373
374         /* Write the terminating quote and NUL character. */
375         *target++ = '\'';
376         *target = '\0';
377
378         buf->len = target - buf->data;
379 }
380
381
382 /*
383  * Convert backend's version string into a number.
384  */
385 int
386 parse_version(const char *versionString)
387 {
388         int                     cnt;
389         int                     vmaj,
390                                 vmin,
391                                 vrev;
392
393         cnt = sscanf(versionString, "%d.%d.%d", &vmaj, &vmin, &vrev);
394
395         if (cnt < 2)
396                 return -1;
397
398         if (cnt == 2)
399                 vrev = 0;
400
401         return (100 * vmaj + vmin) * 100 + vrev;
402 }
403
404
405 /*
406  * Deconstruct the text representation of a 1-dimensional Postgres array
407  * into individual items.
408  *
409  * On success, returns true and sets *itemarray and *nitems to describe
410  * an array of individual strings.      On parse failure, returns false;
411  * *itemarray may exist or be NULL.
412  *
413  * NOTE: free'ing itemarray is sufficient to deallocate the working storage.
414  */
415 bool
416 parsePGArray(const char *atext, char ***itemarray, int *nitems)
417 {
418         int                     inputlen;
419         char      **items;
420         char       *strings;
421         int                     curitem;
422
423         /*
424          * We expect input in the form of "{item,item,item}" where any item is
425          * either raw data, or surrounded by double quotes (in which case embedded
426          * characters including backslashes and quotes are backslashed).
427          *
428          * We build the result as an array of pointers followed by the actual
429          * string data, all in one malloc block for convenience of deallocation.
430          * The worst-case storage need is not more than one pointer and one
431          * character for each input character (consider "{,,,,,,,,,,}").
432          */
433         *itemarray = NULL;
434         *nitems = 0;
435         inputlen = strlen(atext);
436         if (inputlen < 2 || atext[0] != '{' || atext[inputlen - 1] != '}')
437                 return false;                   /* bad input */
438         items = (char **) malloc(inputlen * (sizeof(char *) + sizeof(char)));
439         if (items == NULL)
440                 return false;                   /* out of memory */
441         *itemarray = items;
442         strings = (char *) (items + inputlen);
443
444         atext++;                                        /* advance over initial '{' */
445         curitem = 0;
446         while (*atext != '}')
447         {
448                 if (*atext == '\0')
449                         return false;           /* premature end of string */
450                 items[curitem] = strings;
451                 while (*atext != '}' && *atext != ',')
452                 {
453                         if (*atext == '\0')
454                                 return false;   /* premature end of string */
455                         if (*atext != '"')
456                                 *strings++ = *atext++;  /* copy unquoted data */
457                         else
458                         {
459                                 /* process quoted substring */
460                                 atext++;
461                                 while (*atext != '"')
462                                 {
463                                         if (*atext == '\0')
464                                                 return false;   /* premature end of string */
465                                         if (*atext == '\\')
466                                         {
467                                                 atext++;
468                                                 if (*atext == '\0')
469                                                         return false;           /* premature end of string */
470                                         }
471                                         *strings++ = *atext++;          /* copy quoted data */
472                                 }
473                                 atext++;
474                         }
475                 }
476                 *strings++ = '\0';
477                 if (*atext == ',')
478                         atext++;
479                 curitem++;
480         }
481         if (atext[1] != '\0')
482                 return false;                   /* bogus syntax (embedded '}') */
483         *nitems = curitem;
484         return true;
485 }
486
487
488 /*
489  * Build GRANT/REVOKE command(s) for an object.
490  *
491  *      name: the object name, in the form to use in the commands (already quoted)
492  *      subname: the sub-object name, if any (already quoted); NULL if none
493  *      type: the object type (as seen in GRANT command: must be one of
494  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
495  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT)
496  *      acls: the ACL string fetched from the database
497  *      owner: username of object owner (will be passed through fmtId); can be
498  *              NULL or empty string to indicate "no owner known"
499  *      prefix: string to prefix to each generated command; typically empty
500  *      remoteVersion: version of database
501  *
502  * Returns TRUE if okay, FALSE if could not parse the acl string.
503  * The resulting commands (if any) are appended to the contents of 'sql'.
504  *
505  * Note: when processing a default ACL, prefix is "ALTER DEFAULT PRIVILEGES "
506  * or something similar, and name is an empty string.
507  *
508  * Note: beware of passing a fmtId() result directly as 'name' or 'subname',
509  * since this routine uses fmtId() internally.
510  */
511 bool
512 buildACLCommands(const char *name, const char *subname,
513                                  const char *type, const char *acls, const char *owner,
514                                  const char *prefix, int remoteVersion,
515                                  PQExpBuffer sql)
516 {
517         char      **aclitems;
518         int                     naclitems;
519         int                     i;
520         PQExpBuffer grantee,
521                                 grantor,
522                                 privs,
523                                 privswgo;
524         PQExpBuffer firstsql,
525                                 secondsql;
526         bool            found_owner_privs = false;
527
528         if (strlen(acls) == 0)
529                 return true;                    /* object has default permissions */
530
531         /* treat empty-string owner same as NULL */
532         if (owner && *owner == '\0')
533                 owner = NULL;
534
535         if (!parsePGArray(acls, &aclitems, &naclitems))
536         {
537                 if (aclitems)
538                         free(aclitems);
539                 return false;
540         }
541
542         grantee = createPQExpBuffer();
543         grantor = createPQExpBuffer();
544         privs = createPQExpBuffer();
545         privswgo = createPQExpBuffer();
546
547         /*
548          * At the end, these two will be pasted together to form the result. But
549          * the owner privileges need to go before the other ones to keep the
550          * dependencies valid.  In recent versions this is normally the case, but
551          * in old versions they come after the PUBLIC privileges and that results
552          * in problems if we need to run REVOKE on the owner privileges.
553          */
554         firstsql = createPQExpBuffer();
555         secondsql = createPQExpBuffer();
556
557         /*
558          * Always start with REVOKE ALL FROM PUBLIC, so that we don't have to
559          * wire-in knowledge about the default public privileges for different
560          * kinds of objects.
561          */
562         appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
563         if (subname)
564                 appendPQExpBuffer(firstsql, "(%s)", subname);
565         appendPQExpBuffer(firstsql, " ON %s %s FROM PUBLIC;\n", type, name);
566
567         /*
568          * We still need some hacking though to cover the case where new default
569          * public privileges are added in new versions: the REVOKE ALL will revoke
570          * them, leading to behavior different from what the old version had,
571          * which is generally not what's wanted.  So add back default privs if the
572          * source database is too old to have had that particular priv.
573          */
574         if (remoteVersion < 80200 && strcmp(type, "DATABASE") == 0)
575         {
576                 /* database CONNECT priv didn't exist before 8.2 */
577                 appendPQExpBuffer(firstsql, "%sGRANT CONNECT ON %s %s TO PUBLIC;\n",
578                                                   prefix, type, name);
579         }
580
581         /* Scan individual ACL items */
582         for (i = 0; i < naclitems; i++)
583         {
584                 if (!parseAclItem(aclitems[i], type, name, subname, remoteVersion,
585                                                   grantee, grantor, privs, privswgo))
586                         return false;
587
588                 if (grantor->len == 0 && owner)
589                         printfPQExpBuffer(grantor, "%s", owner);
590
591                 if (privs->len > 0 || privswgo->len > 0)
592                 {
593                         if (owner
594                                 && strcmp(grantee->data, owner) == 0
595                                 && strcmp(grantor->data, owner) == 0)
596                         {
597                                 found_owner_privs = true;
598
599                                 /*
600                                  * For the owner, the default privilege level is ALL WITH
601                                  * GRANT OPTION (only ALL prior to 7.4).
602                                  */
603                                 if (supports_grant_options(remoteVersion)
604                                         ? strcmp(privswgo->data, "ALL") != 0
605                                         : strcmp(privs->data, "ALL") != 0)
606                                 {
607                                         appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
608                                         if (subname)
609                                                 appendPQExpBuffer(firstsql, "(%s)", subname);
610                                         appendPQExpBuffer(firstsql, " ON %s %s FROM %s;\n",
611                                                                           type, name, fmtId(grantee->data));
612                                         if (privs->len > 0)
613                                                 appendPQExpBuffer(firstsql,
614                                                                                   "%sGRANT %s ON %s %s TO %s;\n",
615                                                                                   prefix, privs->data, type, name,
616                                                                                   fmtId(grantee->data));
617                                         if (privswgo->len > 0)
618                                                 appendPQExpBuffer(firstsql,
619                                                         "%sGRANT %s ON %s %s TO %s WITH GRANT OPTION;\n",
620                                                                                   prefix, privswgo->data, type, name,
621                                                                                   fmtId(grantee->data));
622                                 }
623                         }
624                         else
625                         {
626                                 /*
627                                  * Otherwise can assume we are starting from no privs.
628                                  */
629                                 if (grantor->len > 0
630                                         && (!owner || strcmp(owner, grantor->data) != 0))
631                                         appendPQExpBuffer(secondsql, "SET SESSION AUTHORIZATION %s;\n",
632                                                                           fmtId(grantor->data));
633
634                                 if (privs->len > 0)
635                                 {
636                                         appendPQExpBuffer(secondsql, "%sGRANT %s ON %s %s TO ",
637                                                                           prefix, privs->data, type, name);
638                                         if (grantee->len == 0)
639                                                 appendPQExpBuffer(secondsql, "PUBLIC;\n");
640                                         else if (strncmp(grantee->data, "group ",
641                                                                          strlen("group ")) == 0)
642                                                 appendPQExpBuffer(secondsql, "GROUP %s;\n",
643                                                                         fmtId(grantee->data + strlen("group ")));
644                                         else
645                                                 appendPQExpBuffer(secondsql, "%s;\n", fmtId(grantee->data));
646                                 }
647                                 if (privswgo->len > 0)
648                                 {
649                                         appendPQExpBuffer(secondsql, "%sGRANT %s ON %s %s TO ",
650                                                                           prefix, privswgo->data, type, name);
651                                         if (grantee->len == 0)
652                                                 appendPQExpBuffer(secondsql, "PUBLIC");
653                                         else if (strncmp(grantee->data, "group ",
654                                                                          strlen("group ")) == 0)
655                                                 appendPQExpBuffer(secondsql, "GROUP %s",
656                                                                         fmtId(grantee->data + strlen("group ")));
657                                         else
658                                                 appendPQExpBuffer(secondsql, "%s", fmtId(grantee->data));
659                                         appendPQExpBuffer(secondsql, " WITH GRANT OPTION;\n");
660                                 }
661
662                                 if (grantor->len > 0
663                                         && (!owner || strcmp(owner, grantor->data) != 0))
664                                         appendPQExpBuffer(secondsql, "RESET SESSION AUTHORIZATION;\n");
665                         }
666                 }
667         }
668
669         /*
670          * If we didn't find any owner privs, the owner must have revoked 'em all
671          */
672         if (!found_owner_privs && owner)
673         {
674                 appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
675                 if (subname)
676                         appendPQExpBuffer(firstsql, "(%s)", subname);
677                 appendPQExpBuffer(firstsql, " ON %s %s FROM %s;\n",
678                                                   type, name, fmtId(owner));
679         }
680
681         destroyPQExpBuffer(grantee);
682         destroyPQExpBuffer(grantor);
683         destroyPQExpBuffer(privs);
684         destroyPQExpBuffer(privswgo);
685
686         appendPQExpBuffer(sql, "%s%s", firstsql->data, secondsql->data);
687         destroyPQExpBuffer(firstsql);
688         destroyPQExpBuffer(secondsql);
689
690         free(aclitems);
691
692         return true;
693 }
694
695 /*
696  * Build ALTER DEFAULT PRIVILEGES command(s) for single pg_default_acl entry.
697  *
698  *      type: the object type (TABLES, FUNCTIONS, etc)
699  *      nspname: schema name, or NULL for global default privileges
700  *      acls: the ACL string fetched from the database
701  *      owner: username of privileges owner (will be passed through fmtId)
702  *      remoteVersion: version of database
703  *
704  * Returns TRUE if okay, FALSE if could not parse the acl string.
705  * The resulting commands (if any) are appended to the contents of 'sql'.
706  */
707 bool
708 buildDefaultACLCommands(const char *type, const char *nspname,
709                                                 const char *acls, const char *owner,
710                                                 int remoteVersion,
711                                                 PQExpBuffer sql)
712 {
713         bool            result;
714         PQExpBuffer prefix;
715
716         prefix = createPQExpBuffer();
717
718         /*
719          * We incorporate the target role directly into the command, rather than
720          * playing around with SET ROLE or anything like that.  This is so that a
721          * permissions error leads to nothing happening, rather than changing
722          * default privileges for the wrong user.
723          */
724         appendPQExpBuffer(prefix, "ALTER DEFAULT PRIVILEGES FOR ROLE %s ",
725                                           fmtId(owner));
726         if (nspname)
727                 appendPQExpBuffer(prefix, "IN SCHEMA %s ", fmtId(nspname));
728
729         result = buildACLCommands("", NULL,
730                                                           type, acls, owner,
731                                                           prefix->data, remoteVersion,
732                                                           sql);
733
734         destroyPQExpBuffer(prefix);
735
736         return result;
737 }
738
739 /*
740  * This will parse an aclitem string, having the general form
741  *              username=privilegecodes/grantor
742  * or
743  *              group groupname=privilegecodes/grantor
744  * (the /grantor part will not be present if pre-7.4 database).
745  *
746  * The returned grantee string will be the dequoted username or groupname
747  * (preceded with "group " in the latter case).  The returned grantor is
748  * the dequoted grantor name or empty.  Privilege characters are decoded
749  * and split between privileges with grant option (privswgo) and without
750  * (privs).
751  *
752  * Note: for cross-version compatibility, it's important to use ALL when
753  * appropriate.
754  */
755 static bool
756 parseAclItem(const char *item, const char *type,
757                          const char *name, const char *subname, int remoteVersion,
758                          PQExpBuffer grantee, PQExpBuffer grantor,
759                          PQExpBuffer privs, PQExpBuffer privswgo)
760 {
761         char       *buf;
762         bool            all_with_go = true;
763         bool            all_without_go = true;
764         char       *eqpos;
765         char       *slpos;
766         char       *pos;
767
768         buf = strdup(item);
769         if (!buf)
770                 return false;
771
772         /* user or group name is string up to = */
773         eqpos = copyAclUserName(grantee, buf);
774         if (*eqpos != '=')
775                 return false;
776
777         /* grantor may be listed after / */
778         slpos = strchr(eqpos + 1, '/');
779         if (slpos)
780         {
781                 *slpos++ = '\0';
782                 slpos = copyAclUserName(grantor, slpos);
783                 if (*slpos != '\0')
784                         return false;
785         }
786         else
787                 resetPQExpBuffer(grantor);
788
789         /* privilege codes */
790 #define CONVERT_PRIV(code, keywd) \
791 do { \
792         if ((pos = strchr(eqpos + 1, code))) \
793         { \
794                 if (*(pos + 1) == '*') \
795                 { \
796                         AddAcl(privswgo, keywd, subname); \
797                         all_without_go = false; \
798                 } \
799                 else \
800                 { \
801                         AddAcl(privs, keywd, subname); \
802                         all_with_go = false; \
803                 } \
804         } \
805         else \
806                 all_with_go = all_without_go = false; \
807 } while (0)
808
809         resetPQExpBuffer(privs);
810         resetPQExpBuffer(privswgo);
811
812         if (strcmp(type, "TABLE") == 0 || strcmp(type, "SEQUENCE") == 0 ||
813                 strcmp(type, "TABLES") == 0 || strcmp(type, "SEQUENCES") == 0)
814         {
815                 CONVERT_PRIV('r', "SELECT");
816
817                 if (strcmp(type, "SEQUENCE") == 0 ||
818                         strcmp(type, "SEQUENCES") == 0)
819                         /* sequence only */
820                         CONVERT_PRIV('U', "USAGE");
821                 else
822                 {
823                         /* table only */
824                         CONVERT_PRIV('a', "INSERT");
825                         if (remoteVersion >= 70200)
826                                 CONVERT_PRIV('x', "REFERENCES");
827                         /* rest are not applicable to columns */
828                         if (subname == NULL)
829                         {
830                                 if (remoteVersion >= 70200)
831                                 {
832                                         CONVERT_PRIV('d', "DELETE");
833                                         CONVERT_PRIV('t', "TRIGGER");
834                                 }
835                                 if (remoteVersion >= 80400)
836                                         CONVERT_PRIV('D', "TRUNCATE");
837                         }
838                 }
839
840                 /* UPDATE */
841                 if (remoteVersion >= 70200 ||
842                         strcmp(type, "SEQUENCE") == 0 ||
843                         strcmp(type, "SEQUENCES") == 0)
844                         CONVERT_PRIV('w', "UPDATE");
845                 else
846                         /* 7.0 and 7.1 have a simpler worldview */
847                         CONVERT_PRIV('w', "UPDATE,DELETE");
848         }
849         else if (strcmp(type, "FUNCTION") == 0 ||
850                          strcmp(type, "FUNCTIONS") == 0)
851                 CONVERT_PRIV('X', "EXECUTE");
852         else if (strcmp(type, "LANGUAGE") == 0)
853                 CONVERT_PRIV('U', "USAGE");
854         else if (strcmp(type, "SCHEMA") == 0)
855         {
856                 CONVERT_PRIV('C', "CREATE");
857                 CONVERT_PRIV('U', "USAGE");
858         }
859         else if (strcmp(type, "DATABASE") == 0)
860         {
861                 CONVERT_PRIV('C', "CREATE");
862                 CONVERT_PRIV('c', "CONNECT");
863                 CONVERT_PRIV('T', "TEMPORARY");
864         }
865         else if (strcmp(type, "TABLESPACE") == 0)
866                 CONVERT_PRIV('C', "CREATE");
867         else if (strcmp(type, "FOREIGN DATA WRAPPER") == 0)
868                 CONVERT_PRIV('U', "USAGE");
869         else if (strcmp(type, "FOREIGN SERVER") == 0)
870                 CONVERT_PRIV('U', "USAGE");
871         else if (strcmp(type, "FOREIGN TABLE") == 0)
872                 CONVERT_PRIV('r', "SELECT");
873         else if (strcmp(type, "LARGE OBJECT") == 0)
874         {
875                 CONVERT_PRIV('r', "SELECT");
876                 CONVERT_PRIV('w', "UPDATE");
877         }
878         else
879                 abort();
880
881 #undef CONVERT_PRIV
882
883         if (all_with_go)
884         {
885                 resetPQExpBuffer(privs);
886                 printfPQExpBuffer(privswgo, "ALL");
887                 if (subname)
888                         appendPQExpBuffer(privswgo, "(%s)", subname);
889         }
890         else if (all_without_go)
891         {
892                 resetPQExpBuffer(privswgo);
893                 printfPQExpBuffer(privs, "ALL");
894                 if (subname)
895                         appendPQExpBuffer(privs, "(%s)", subname);
896         }
897
898         free(buf);
899
900         return true;
901 }
902
903 /*
904  * Transfer a user or group name starting at *input into the output buffer,
905  * dequoting if needed.  Returns a pointer to just past the input name.
906  * The name is taken to end at an unquoted '=' or end of string.
907  */
908 static char *
909 copyAclUserName(PQExpBuffer output, char *input)
910 {
911         resetPQExpBuffer(output);
912
913         while (*input && *input != '=')
914         {
915                 /*
916                  * If user name isn't quoted, then just add it to the output buffer
917                  */
918                 if (*input != '"')
919                         appendPQExpBufferChar(output, *input++);
920                 else
921                 {
922                         /* Otherwise, it's a quoted username */
923                         input++;
924                         /* Loop until we come across an unescaped quote */
925                         while (!(*input == '"' && *(input + 1) != '"'))
926                         {
927                                 if (*input == '\0')
928                                         return input;           /* really a syntax error... */
929
930                                 /*
931                                  * Quoting convention is to escape " as "".  Keep this code in
932                                  * sync with putid() in backend's acl.c.
933                                  */
934                                 if (*input == '"' && *(input + 1) == '"')
935                                         input++;
936                                 appendPQExpBufferChar(output, *input++);
937                         }
938                         input++;
939                 }
940         }
941         return input;
942 }
943
944 /*
945  * Append a privilege keyword to a keyword list, inserting comma if needed.
946  */
947 static void
948 AddAcl(PQExpBuffer aclbuf, const char *keyword, const char *subname)
949 {
950         if (aclbuf->len > 0)
951                 appendPQExpBufferChar(aclbuf, ',');
952         appendPQExpBuffer(aclbuf, "%s", keyword);
953         if (subname)
954                 appendPQExpBuffer(aclbuf, "(%s)", subname);
955 }
956
957
958 /*
959  * processSQLNamePattern
960  *
961  * Scan a wildcard-pattern string and generate appropriate WHERE clauses
962  * to limit the set of objects returned.  The WHERE clauses are appended
963  * to the already-partially-constructed query in buf.  Returns whether
964  * any clause was added.
965  *
966  * conn: connection query will be sent to (consulted for escaping rules).
967  * buf: output parameter.
968  * pattern: user-specified pattern option, or NULL if none ("*" is implied).
969  * have_where: true if caller already emitted "WHERE" (clauses will be ANDed
970  * onto the existing WHERE clause).
971  * force_escape: always quote regexp special characters, even outside
972  * double quotes (else they are quoted only between double quotes).
973  * schemavar: name of query variable to match against a schema-name pattern.
974  * Can be NULL if no schema.
975  * namevar: name of query variable to match against an object-name pattern.
976  * altnamevar: NULL, or name of an alternative variable to match against name.
977  * visibilityrule: clause to use if we want to restrict to visible objects
978  * (for example, "pg_catalog.pg_table_is_visible(p.oid)").      Can be NULL.
979  *
980  * Formatting note: the text already present in buf should end with a newline.
981  * The appended text, if any, will end with one too.
982  */
983 bool
984 processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern,
985                                           bool have_where, bool force_escape,
986                                           const char *schemavar, const char *namevar,
987                                           const char *altnamevar, const char *visibilityrule)
988 {
989         PQExpBufferData schemabuf;
990         PQExpBufferData namebuf;
991         int                     encoding = PQclientEncoding(conn);
992         bool            inquotes;
993         const char *cp;
994         int                     i;
995         bool            added_clause = false;
996
997 #define WHEREAND() \
998         (appendPQExpBufferStr(buf, have_where ? "  AND " : "WHERE "), \
999          have_where = true, added_clause = true)
1000
1001         if (pattern == NULL)
1002         {
1003                 /* Default: select all visible objects */
1004                 if (visibilityrule)
1005                 {
1006                         WHEREAND();
1007                         appendPQExpBuffer(buf, "%s\n", visibilityrule);
1008                 }
1009                 return added_clause;
1010         }
1011
1012         initPQExpBuffer(&schemabuf);
1013         initPQExpBuffer(&namebuf);
1014
1015         /*
1016          * Parse the pattern, converting quotes and lower-casing unquoted letters.
1017          * Also, adjust shell-style wildcard characters into regexp notation.
1018          *
1019          * We surround the pattern with "^(...)$" to force it to match the whole
1020          * string, as per SQL practice.  We have to have parens in case the string
1021          * contains "|", else the "^" and "$" will be bound into the first and
1022          * last alternatives which is not what we want.
1023          *
1024          * Note: the result of this pass is the actual regexp pattern(s) we want
1025          * to execute.  Quoting/escaping into SQL literal format will be done
1026          * below using appendStringLiteralConn().
1027          */
1028         appendPQExpBufferStr(&namebuf, "^(");
1029
1030         inquotes = false;
1031         cp = pattern;
1032
1033         while (*cp)
1034         {
1035                 char            ch = *cp;
1036
1037                 if (ch == '"')
1038                 {
1039                         if (inquotes && cp[1] == '"')
1040                         {
1041                                 /* emit one quote, stay in inquotes mode */
1042                                 appendPQExpBufferChar(&namebuf, '"');
1043                                 cp++;
1044                         }
1045                         else
1046                                 inquotes = !inquotes;
1047                         cp++;
1048                 }
1049                 else if (!inquotes && isupper((unsigned char) ch))
1050                 {
1051                         appendPQExpBufferChar(&namebuf,
1052                                                                   pg_tolower((unsigned char) ch));
1053                         cp++;
1054                 }
1055                 else if (!inquotes && ch == '*')
1056                 {
1057                         appendPQExpBufferStr(&namebuf, ".*");
1058                         cp++;
1059                 }
1060                 else if (!inquotes && ch == '?')
1061                 {
1062                         appendPQExpBufferChar(&namebuf, '.');
1063                         cp++;
1064                 }
1065                 else if (!inquotes && ch == '.')
1066                 {
1067                         /* Found schema/name separator, move current pattern to schema */
1068                         resetPQExpBuffer(&schemabuf);
1069                         appendPQExpBufferStr(&schemabuf, namebuf.data);
1070                         resetPQExpBuffer(&namebuf);
1071                         appendPQExpBufferStr(&namebuf, "^(");
1072                         cp++;
1073                 }
1074                 else if (ch == '$')
1075                 {
1076                         /*
1077                          * Dollar is always quoted, whether inside quotes or not. The
1078                          * reason is that it's allowed in SQL identifiers, so there's a
1079                          * significant use-case for treating it literally, while because
1080                          * we anchor the pattern automatically there is no use-case for
1081                          * having it possess its regexp meaning.
1082                          */
1083                         appendPQExpBufferStr(&namebuf, "\\$");
1084                         cp++;
1085                 }
1086                 else
1087                 {
1088                         /*
1089                          * Ordinary data character, transfer to pattern
1090                          *
1091                          * Inside double quotes, or at all times if force_escape is true,
1092                          * quote regexp special characters with a backslash to avoid
1093                          * regexp errors.  Outside quotes, however, let them pass through
1094                          * as-is; this lets knowledgeable users build regexp expressions
1095                          * that are more powerful than shell-style patterns.
1096                          */
1097                         if ((inquotes || force_escape) &&
1098                                 strchr("|*+?()[]{}.^$\\", ch))
1099                                 appendPQExpBufferChar(&namebuf, '\\');
1100                         i = PQmblen(cp, encoding);
1101                         while (i-- && *cp)
1102                         {
1103                                 appendPQExpBufferChar(&namebuf, *cp);
1104                                 cp++;
1105                         }
1106                 }
1107         }
1108
1109         /*
1110          * Now decide what we need to emit.  Note there will be a leading "^(" in
1111          * the patterns in any case.
1112          */
1113         if (namebuf.len > 2)
1114         {
1115                 /* We have a name pattern, so constrain the namevar(s) */
1116
1117                 appendPQExpBufferStr(&namebuf, ")$");
1118                 /* Optimize away a "*" pattern */
1119                 if (strcmp(namebuf.data, "^(.*)$") != 0)
1120                 {
1121                         WHEREAND();
1122                         if (altnamevar)
1123                         {
1124                                 appendPQExpBuffer(buf, "(%s ~ ", namevar);
1125                                 appendStringLiteralConn(buf, namebuf.data, conn);
1126                                 appendPQExpBuffer(buf, "\n        OR %s ~ ", altnamevar);
1127                                 appendStringLiteralConn(buf, namebuf.data, conn);
1128                                 appendPQExpBufferStr(buf, ")\n");
1129                         }
1130                         else
1131                         {
1132                                 appendPQExpBuffer(buf, "%s ~ ", namevar);
1133                                 appendStringLiteralConn(buf, namebuf.data, conn);
1134                                 appendPQExpBufferChar(buf, '\n');
1135                         }
1136                 }
1137         }
1138
1139         if (schemabuf.len > 2)
1140         {
1141                 /* We have a schema pattern, so constrain the schemavar */
1142
1143                 appendPQExpBufferStr(&schemabuf, ")$");
1144                 /* Optimize away a "*" pattern */
1145                 if (strcmp(schemabuf.data, "^(.*)$") != 0 && schemavar)
1146                 {
1147                         WHEREAND();
1148                         appendPQExpBuffer(buf, "%s ~ ", schemavar);
1149                         appendStringLiteralConn(buf, schemabuf.data, conn);
1150                         appendPQExpBufferChar(buf, '\n');
1151                 }
1152         }
1153         else
1154         {
1155                 /* No schema pattern given, so select only visible objects */
1156                 if (visibilityrule)
1157                 {
1158                         WHEREAND();
1159                         appendPQExpBuffer(buf, "%s\n", visibilityrule);
1160                 }
1161         }
1162
1163         termPQExpBuffer(&schemabuf);
1164         termPQExpBuffer(&namebuf);
1165
1166         return added_clause;
1167 #undef WHEREAND
1168 }
1169
1170 /*
1171  * buildShSecLabelQuery
1172  *
1173  * Build a query to retrieve security labels for a shared object.
1174  */
1175 void
1176 buildShSecLabelQuery(PGconn *conn, const char *catalog_name, uint32 objectId,
1177                                          PQExpBuffer sql)
1178 {
1179         appendPQExpBuffer(sql,
1180                                           "SELECT provider, label FROM pg_catalog.pg_shseclabel "
1181                                           "WHERE classoid = '%s'::pg_catalog.regclass AND "
1182                                           "objoid = %u", catalog_name, objectId);
1183 }
1184
1185 /*
1186  * emitShSecLabels
1187  *
1188  * Format security label data retrieved by the query generated in
1189  * buildShSecLabelQuery.
1190  */
1191 void
1192 emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer,
1193                                 const char *target, const char *objname)
1194 {
1195         int                     i;
1196
1197         for (i = 0; i < PQntuples(res); i++)
1198     {
1199                 char   *provider = PQgetvalue(res, i, 0);
1200                 char   *label = PQgetvalue(res, i, 1);
1201
1202                 /* must use fmtId result before calling it again */
1203                 appendPQExpBuffer(buffer,
1204                                                   "SECURITY LABEL FOR %s ON %s",
1205                                                   fmtId(provider), target);
1206                 appendPQExpBuffer(buffer,
1207                                                   " %s IS ",
1208                                                   fmtId(objname));
1209                 appendStringLiteralConn(buffer, label, conn);
1210         appendPQExpBuffer(buffer, ";\n");
1211         }
1212 }