1 /*-------------------------------------------------------------------------
4 * Generator for recovery configuration
6 * Portions Copyright (c) 2011-2023, 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();
34 pg_fatal("out of memory");
37 * In PostgreSQL 12 and newer versions, standby_mode is gone, replaced by
38 * standby.signal to trigger a standby state at recovery.
40 if (PQserverVersion(pgconn
) < MINIMUM_VERSION_FOR_RECOVERY_GUC
)
41 appendPQExpBufferStr(contents
, "standby_mode = 'on'\n");
43 connOptions
= PQconninfo(pgconn
);
44 if (connOptions
== NULL
)
45 pg_fatal("out of memory");
47 initPQExpBuffer(&conninfo_buf
);
48 for (PQconninfoOption
*opt
= connOptions
; opt
&& opt
->keyword
; opt
++)
50 /* Omit empty settings and those libpqwalreceiver overrides. */
51 if (strcmp(opt
->keyword
, "replication") == 0 ||
52 strcmp(opt
->keyword
, "dbname") == 0 ||
53 strcmp(opt
->keyword
, "fallback_application_name") == 0 ||
55 (opt
->val
!= NULL
&& opt
->val
[0] == '\0'))
58 /* Separate key-value pairs with spaces */
59 if (conninfo_buf
.len
!= 0)
60 appendPQExpBufferChar(&conninfo_buf
, ' ');
63 * Write "keyword=value" pieces, the value string is escaped and/or
64 * quoted if necessary.
66 appendPQExpBuffer(&conninfo_buf
, "%s=", opt
->keyword
);
67 appendConnStrVal(&conninfo_buf
, opt
->val
);
69 if (PQExpBufferDataBroken(conninfo_buf
))
70 pg_fatal("out of memory");
73 * Escape the connection string, so that it can be put in the config file.
74 * Note that this is different from the escaping of individual connection
77 escaped
= escape_quotes(conninfo_buf
.data
);
78 termPQExpBuffer(&conninfo_buf
);
79 appendPQExpBuffer(contents
, "primary_conninfo = '%s'\n", escaped
);
84 /* unescaped: ReplicationSlotValidateName allows [a-z0-9_] only */
85 appendPQExpBuffer(contents
, "primary_slot_name = '%s'\n",
89 if (PQExpBufferBroken(contents
))
90 pg_fatal("out of memory");
92 PQconninfoFree(connOptions
);
98 * Write the configuration file in the directory specified in target_dir,
99 * with the contents already collected in memory appended. Then write
100 * the signal file into the target_dir. If the server does not support
101 * recovery parameters as GUCs, the signal file is not necessary, and
102 * configuration is written to recovery.conf.
105 WriteRecoveryConfig(PGconn
*pgconn
, char *target_dir
, PQExpBuffer contents
)
107 char filename
[MAXPGPATH
];
109 bool use_recovery_conf
;
111 Assert(pgconn
!= NULL
);
114 PQserverVersion(pgconn
) < MINIMUM_VERSION_FOR_RECOVERY_GUC
;
116 snprintf(filename
, MAXPGPATH
, "%s/%s", target_dir
,
117 use_recovery_conf
? "recovery.conf" : "postgresql.auto.conf");
119 cf
= fopen(filename
, use_recovery_conf
? "w" : "a");
121 pg_fatal("could not open file \"%s\": %m", filename
);
123 if (fwrite(contents
->data
, contents
->len
, 1, cf
) != 1)
124 pg_fatal("could not write to file \"%s\": %m", filename
);
128 if (!use_recovery_conf
)
130 snprintf(filename
, MAXPGPATH
, "%s/%s", target_dir
, "standby.signal");
131 cf
= fopen(filename
, "w");
133 pg_fatal("could not create file \"%s\": %m", filename
);
140 * Escape a string so that it can be used as a value in a key-value pair
141 * a configuration file.
144 escape_quotes(const char *src
)
146 char *result
= escape_single_quotes_ascii(src
);
149 pg_fatal("out of memory");