Remove a useless cast to (void *) in hash_search() call
[pgsql.git] / src / fe_utils / recovery_gen.c
blobc4838a4bddce1420aea91343c76c8ba75e0acc94
1 /*-------------------------------------------------------------------------
3 * recovery_gen.c
4 * Generator for recovery configuration
6 * Portions Copyright (c) 2011-2024, PostgreSQL Global Development Group
8 *-------------------------------------------------------------------------
9 */
10 #include "postgres_fe.h"
12 #include "common/logging.h"
13 #include "fe_utils/recovery_gen.h"
14 #include "fe_utils/string_utils.h"
16 static char *escape_quotes(const char *src);
19 * Write recovery configuration contents into a fresh PQExpBuffer, and
20 * return it.
22 * This accepts the dbname which will be appended to the primary_conninfo.
23 * The dbname will be ignored by walreceiver process but slotsync worker uses
24 * it to connect to the primary server.
26 PQExpBuffer
27 GenerateRecoveryConfig(PGconn *pgconn, const char *replication_slot,
28 char *dbname)
30 PQconninfoOption *connOptions;
31 PQExpBufferData conninfo_buf;
32 char *escaped;
33 PQExpBuffer contents;
35 Assert(pgconn != NULL);
37 contents = createPQExpBuffer();
38 if (!contents)
39 pg_fatal("out of memory");
42 * In PostgreSQL 12 and newer versions, standby_mode is gone, replaced by
43 * standby.signal to trigger a standby state at recovery.
45 if (PQserverVersion(pgconn) < MINIMUM_VERSION_FOR_RECOVERY_GUC)
46 appendPQExpBufferStr(contents, "standby_mode = 'on'\n");
48 connOptions = PQconninfo(pgconn);
49 if (connOptions == NULL)
50 pg_fatal("out of memory");
52 initPQExpBuffer(&conninfo_buf);
53 for (PQconninfoOption *opt = connOptions; opt && opt->keyword; opt++)
55 /* Omit empty settings and those libpqwalreceiver overrides. */
56 if (strcmp(opt->keyword, "replication") == 0 ||
57 strcmp(opt->keyword, "dbname") == 0 ||
58 strcmp(opt->keyword, "fallback_application_name") == 0 ||
59 (opt->val == NULL) ||
60 (opt->val != NULL && opt->val[0] == '\0'))
61 continue;
63 /* Separate key-value pairs with spaces */
64 if (conninfo_buf.len != 0)
65 appendPQExpBufferChar(&conninfo_buf, ' ');
68 * Write "keyword=value" pieces, the value string is escaped and/or
69 * quoted if necessary.
71 appendPQExpBuffer(&conninfo_buf, "%s=", opt->keyword);
72 appendConnStrVal(&conninfo_buf, opt->val);
75 if (dbname)
78 * If dbname is specified in the connection, append the dbname. This
79 * will be used later for logical replication slot synchronization.
81 if (conninfo_buf.len != 0)
82 appendPQExpBufferChar(&conninfo_buf, ' ');
84 appendPQExpBuffer(&conninfo_buf, "%s=", "dbname");
85 appendConnStrVal(&conninfo_buf, dbname);
88 if (PQExpBufferDataBroken(conninfo_buf))
89 pg_fatal("out of memory");
92 * Escape the connection string, so that it can be put in the config file.
93 * Note that this is different from the escaping of individual connection
94 * options above!
96 escaped = escape_quotes(conninfo_buf.data);
97 termPQExpBuffer(&conninfo_buf);
98 appendPQExpBuffer(contents, "primary_conninfo = '%s'\n", escaped);
99 free(escaped);
101 if (replication_slot)
103 /* unescaped: ReplicationSlotValidateName allows [a-z0-9_] only */
104 appendPQExpBuffer(contents, "primary_slot_name = '%s'\n",
105 replication_slot);
108 if (PQExpBufferBroken(contents))
109 pg_fatal("out of memory");
111 PQconninfoFree(connOptions);
113 return contents;
117 * Write the configuration file in the directory specified in target_dir,
118 * with the contents already collected in memory appended. Then write
119 * the signal file into the target_dir. If the server does not support
120 * recovery parameters as GUCs, the signal file is not necessary, and
121 * configuration is written to recovery.conf.
123 void
124 WriteRecoveryConfig(PGconn *pgconn, const char *target_dir, PQExpBuffer contents)
126 char filename[MAXPGPATH];
127 FILE *cf;
128 bool use_recovery_conf;
130 Assert(pgconn != NULL);
132 use_recovery_conf =
133 PQserverVersion(pgconn) < MINIMUM_VERSION_FOR_RECOVERY_GUC;
135 snprintf(filename, MAXPGPATH, "%s/%s", target_dir,
136 use_recovery_conf ? "recovery.conf" : "postgresql.auto.conf");
138 cf = fopen(filename, use_recovery_conf ? "w" : "a");
139 if (cf == NULL)
140 pg_fatal("could not open file \"%s\": %m", filename);
142 if (fwrite(contents->data, contents->len, 1, cf) != 1)
143 pg_fatal("could not write to file \"%s\": %m", filename);
145 fclose(cf);
147 if (!use_recovery_conf)
149 snprintf(filename, MAXPGPATH, "%s/%s", target_dir, "standby.signal");
150 cf = fopen(filename, "w");
151 if (cf == NULL)
152 pg_fatal("could not create file \"%s\": %m", filename);
154 fclose(cf);
159 * Escape a string so that it can be used as a value in a key-value pair
160 * a configuration file.
162 static char *
163 escape_quotes(const char *src)
165 char *result = escape_single_quotes_ascii(src);
167 if (!result)
168 pg_fatal("out of memory");
169 return result;