1 /*-------------------------------------------------------------------------
4 * Generator for recovery configuration
6 * Portions Copyright (c) 2011-2021, 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
23 GenerateRecoveryConfig(PGconn
*pgconn
, char *replication_slot
)
25 PQconninfoOption
*connOptions
;
26 PQExpBufferData conninfo_buf
;
30 Assert(pgconn
!= NULL
);
32 contents
= createPQExpBuffer();
35 pg_log_error("out of memory");
40 * In PostgreSQL 12 and newer versions, standby_mode is gone, replaced by
41 * standby.signal to trigger a standby state at recovery.
43 if (PQserverVersion(pgconn
) < MINIMUM_VERSION_FOR_RECOVERY_GUC
)
44 appendPQExpBufferStr(contents
, "standby_mode = 'on'\n");
46 connOptions
= PQconninfo(pgconn
);
47 if (connOptions
== NULL
)
49 pg_log_error("out of memory");
53 initPQExpBuffer(&conninfo_buf
);
54 for (PQconninfoOption
*opt
= connOptions
; opt
&& opt
->keyword
; opt
++)
56 /* Omit empty settings and those libpqwalreceiver overrides. */
57 if (strcmp(opt
->keyword
, "replication") == 0 ||
58 strcmp(opt
->keyword
, "dbname") == 0 ||
59 strcmp(opt
->keyword
, "fallback_application_name") == 0 ||
61 (opt
->val
!= NULL
&& opt
->val
[0] == '\0'))
64 /* Separate key-value pairs with spaces */
65 if (conninfo_buf
.len
!= 0)
66 appendPQExpBufferChar(&conninfo_buf
, ' ');
69 * Write "keyword=value" pieces, the value string is escaped and/or
70 * quoted if necessary.
72 appendPQExpBuffer(&conninfo_buf
, "%s=", opt
->keyword
);
73 appendConnStrVal(&conninfo_buf
, opt
->val
);
75 if (PQExpBufferDataBroken(conninfo_buf
))
77 pg_log_error("out of memory");
82 * Escape the connection string, so that it can be put in the config file.
83 * Note that this is different from the escaping of individual connection
86 escaped
= escape_quotes(conninfo_buf
.data
);
87 termPQExpBuffer(&conninfo_buf
);
88 appendPQExpBuffer(contents
, "primary_conninfo = '%s'\n", escaped
);
93 /* unescaped: ReplicationSlotValidateName allows [a-z0-9_] only */
94 appendPQExpBuffer(contents
, "primary_slot_name = '%s'\n",
98 if (PQExpBufferBroken(contents
))
100 pg_log_error("out of memory");
104 PQconninfoFree(connOptions
);
110 * Write the configuration file in the directory specified in target_dir,
111 * with the contents already collected in memory appended. Then write
112 * the signal file into the target_dir. If the server does not support
113 * recovery parameters as GUCs, the signal file is not necessary, and
114 * configuration is written to recovery.conf.
117 WriteRecoveryConfig(PGconn
*pgconn
, char *target_dir
, PQExpBuffer contents
)
119 char filename
[MAXPGPATH
];
121 bool use_recovery_conf
;
123 Assert(pgconn
!= NULL
);
126 PQserverVersion(pgconn
) < MINIMUM_VERSION_FOR_RECOVERY_GUC
;
128 snprintf(filename
, MAXPGPATH
, "%s/%s", target_dir
,
129 use_recovery_conf
? "recovery.conf" : "postgresql.auto.conf");
131 cf
= fopen(filename
, use_recovery_conf
? "w" : "a");
134 pg_log_error("could not open file \"%s\": %m", filename
);
138 if (fwrite(contents
->data
, contents
->len
, 1, cf
) != 1)
140 pg_log_error("could not write to file \"%s\": %m", filename
);
146 if (!use_recovery_conf
)
148 snprintf(filename
, MAXPGPATH
, "%s/%s", target_dir
, "standby.signal");
149 cf
= fopen(filename
, "w");
152 pg_log_error("could not create file \"%s\": %m", filename
);
161 * Escape a string so that it can be used as a value in a key-value pair
162 * a configuration file.
165 escape_quotes(const char *src
)
167 char *result
= escape_single_quotes_ascii(src
);
171 pg_log_error("out of memory");