1 /*-------------------------------------------------------------------------
4 * Generator for recovery configuration
6 * Portions Copyright (c) 2011-2024, PostgreSQL Global Development Group
8 *-------------------------------------------------------------------------
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
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.
27 GenerateRecoveryConfig(PGconn
*pgconn
, const char *replication_slot
,
30 PQconninfoOption
*connOptions
;
31 PQExpBufferData conninfo_buf
;
35 Assert(pgconn
!= NULL
);
37 contents
= createPQExpBuffer();
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 ||
60 (opt
->val
!= NULL
&& opt
->val
[0] == '\0'))
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
);
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
96 escaped
= escape_quotes(conninfo_buf
.data
);
97 termPQExpBuffer(&conninfo_buf
);
98 appendPQExpBuffer(contents
, "primary_conninfo = '%s'\n", escaped
);
101 if (replication_slot
)
103 /* unescaped: ReplicationSlotValidateName allows [a-z0-9_] only */
104 appendPQExpBuffer(contents
, "primary_slot_name = '%s'\n",
108 if (PQExpBufferBroken(contents
))
109 pg_fatal("out of memory");
111 PQconninfoFree(connOptions
);
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.
124 WriteRecoveryConfig(PGconn
*pgconn
, const char *target_dir
, PQExpBuffer contents
)
126 char filename
[MAXPGPATH
];
128 bool use_recovery_conf
;
130 Assert(pgconn
!= NULL
);
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");
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
);
147 if (!use_recovery_conf
)
149 snprintf(filename
, MAXPGPATH
, "%s/%s", target_dir
, "standby.signal");
150 cf
= fopen(filename
, "w");
152 pg_fatal("could not create file \"%s\": %m", filename
);
159 * Escape a string so that it can be used as a value in a key-value pair
160 * a configuration file.
163 escape_quotes(const char *src
)
165 char *result
= escape_single_quotes_ascii(src
);
168 pg_fatal("out of memory");