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