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