PostgreSQL Source Code  git master
recovery_gen.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * recovery_gen.c
4  * Generator for recovery configuration
5  *
6  * Portions Copyright (c) 2011-2024, PostgreSQL Global Development Group
7  *
8  *-------------------------------------------------------------------------
9  */
10 #include "postgres_fe.h"
11 
12 #include "common/logging.h"
13 #include "fe_utils/recovery_gen.h"
14 #include "fe_utils/string_utils.h"
15 
16 static char *escape_quotes(const char *src);
17 
18 /*
19  * Write recovery configuration contents into a fresh PQExpBuffer, and
20  * return it.
21  *
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.
25  */
28  char *dbname)
29 {
30  PQconninfoOption *connOptions;
31  PQExpBufferData conninfo_buf;
32  char *escaped;
33  PQExpBuffer contents;
34 
35  Assert(pgconn != NULL);
36 
37  contents = createPQExpBuffer();
38  if (!contents)
39  pg_fatal("out of memory");
40 
41  /*
42  * In PostgreSQL 12 and newer versions, standby_mode is gone, replaced by
43  * standby.signal to trigger a standby state at recovery.
44  */
46  appendPQExpBufferStr(contents, "standby_mode = 'on'\n");
47 
48  connOptions = PQconninfo(pgconn);
49  if (connOptions == NULL)
50  pg_fatal("out of memory");
51 
52  initPQExpBuffer(&conninfo_buf);
53  for (PQconninfoOption *opt = connOptions; opt && opt->keyword; opt++)
54  {
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;
62 
63  /* Separate key-value pairs with spaces */
64  if (conninfo_buf.len != 0)
65  appendPQExpBufferChar(&conninfo_buf, ' ');
66 
67  /*
68  * Write "keyword=value" pieces, the value string is escaped and/or
69  * quoted if necessary.
70  */
71  appendPQExpBuffer(&conninfo_buf, "%s=", opt->keyword);
72  appendConnStrVal(&conninfo_buf, opt->val);
73  }
74 
75  if (dbname)
76  {
77  /*
78  * If dbname is specified in the connection, append the dbname. This
79  * will be used later for logical replication slot synchronization.
80  */
81  if (conninfo_buf.len != 0)
82  appendPQExpBufferChar(&conninfo_buf, ' ');
83 
84  appendPQExpBuffer(&conninfo_buf, "%s=", "dbname");
85  appendConnStrVal(&conninfo_buf, dbname);
86  }
87 
88  if (PQExpBufferDataBroken(conninfo_buf))
89  pg_fatal("out of memory");
90 
91  /*
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!
95  */
96  escaped = escape_quotes(conninfo_buf.data);
97  termPQExpBuffer(&conninfo_buf);
98  appendPQExpBuffer(contents, "primary_conninfo = '%s'\n", escaped);
99  free(escaped);
100 
101  if (replication_slot)
102  {
103  /* unescaped: ReplicationSlotValidateName allows [a-z0-9_] only */
104  appendPQExpBuffer(contents, "primary_slot_name = '%s'\n",
106  }
107 
108  if (PQExpBufferBroken(contents))
109  pg_fatal("out of memory");
110 
111  PQconninfoFree(connOptions);
112 
113  return contents;
114 }
115 
116 /*
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.
122  */
123 void
124 WriteRecoveryConfig(PGconn *pgconn, const char *target_dir, PQExpBuffer contents)
125 {
126  char filename[MAXPGPATH];
127  FILE *cf;
128  bool use_recovery_conf;
129 
130  Assert(pgconn != NULL);
131 
132  use_recovery_conf =
134 
135  snprintf(filename, MAXPGPATH, "%s/%s", target_dir,
136  use_recovery_conf ? "recovery.conf" : "postgresql.auto.conf");
137 
138  cf = fopen(filename, use_recovery_conf ? "w" : "a");
139  if (cf == NULL)
140  pg_fatal("could not open file \"%s\": %m", filename);
141 
142  if (fwrite(contents->data, contents->len, 1, cf) != 1)
143  pg_fatal("could not write to file \"%s\": %m", filename);
144 
145  fclose(cf);
146 
147  if (!use_recovery_conf)
148  {
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);
153 
154  fclose(cf);
155  }
156 }
157 
158 /*
159  * Escape a string so that it can be used as a value in a key-value pair
160  * a configuration file.
161  */
162 static char *
163 escape_quotes(const char *src)
164 {
165  char *result = escape_single_quotes_ascii(src);
166 
167  if (!result)
168  pg_fatal("out of memory");
169  return result;
170 }
#define Assert(condition)
Definition: c.h:858
int PQserverVersion(const PGconn *conn)
Definition: fe-connect.c:7157
void PQconninfoFree(PQconninfoOption *connOptions)
Definition: fe-connect.c:7000
PQconninfoOption * PQconninfo(PGconn *conn)
Definition: fe-connect.c:6956
#define free(a)
Definition: header.h:65
#define pg_fatal(...)
static char * replication_slot
#define MAXPGPATH
static char * filename
Definition: pg_dumpall.c:119
#define snprintf
Definition: port.h:238
char * escape_single_quotes_ascii(const char *src)
Definition: quotes.c:33
PQExpBuffer createPQExpBuffer(void)
Definition: pqexpbuffer.c:72
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:90
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:265
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:378
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:367
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:129
#define PQExpBufferBroken(str)
Definition: pqexpbuffer.h:59
#define PQExpBufferDataBroken(buf)
Definition: pqexpbuffer.h:67
void WriteRecoveryConfig(PGconn *pgconn, const char *target_dir, PQExpBuffer contents)
Definition: recovery_gen.c:124
PQExpBuffer GenerateRecoveryConfig(PGconn *pgconn, const char *replication_slot, char *dbname)
Definition: recovery_gen.c:27
static char * escape_quotes(const char *src)
Definition: recovery_gen.c:163
#define MINIMUM_VERSION_FOR_RECOVERY_GUC
Definition: recovery_gen.h:21
char * dbname
Definition: streamutil.c:52
void appendConnStrVal(PQExpBuffer buf, const char *str)
Definition: string_utils.c:545