LCOV - code coverage report
Current view: top level - src/fe_utils - recovery_gen.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 46 55 83.6 %
Date: 2024-02-28 05:11:08 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : PQExpBuffer
      23          14 : GenerateRecoveryConfig(PGconn *pgconn, char *replication_slot)
      24             : {
      25             :     PQconninfoOption *connOptions;
      26             :     PQExpBufferData conninfo_buf;
      27             :     char       *escaped;
      28             :     PQExpBuffer contents;
      29             : 
      30             :     Assert(pgconn != NULL);
      31             : 
      32          14 :     contents = createPQExpBuffer();
      33          14 :     if (!contents)
      34           0 :         pg_fatal("out of memory");
      35             : 
      36             :     /*
      37             :      * In PostgreSQL 12 and newer versions, standby_mode is gone, replaced by
      38             :      * standby.signal to trigger a standby state at recovery.
      39             :      */
      40          14 :     if (PQserverVersion(pgconn) < MINIMUM_VERSION_FOR_RECOVERY_GUC)
      41           0 :         appendPQExpBufferStr(contents, "standby_mode = 'on'\n");
      42             : 
      43          14 :     connOptions = PQconninfo(pgconn);
      44          14 :     if (connOptions == NULL)
      45           0 :         pg_fatal("out of memory");
      46             : 
      47          14 :     initPQExpBuffer(&conninfo_buf);
      48         574 :     for (PQconninfoOption *opt = connOptions; opt && opt->keyword; opt++)
      49             :     {
      50             :         /* Omit empty settings and those libpqwalreceiver overrides. */
      51         560 :         if (strcmp(opt->keyword, "replication") == 0 ||
      52         546 :             strcmp(opt->keyword, "dbname") == 0 ||
      53         532 :             strcmp(opt->keyword, "fallback_application_name") == 0 ||
      54         518 :             (opt->val == NULL) ||
      55         236 :             (opt->val != NULL && opt->val[0] == '\0'))
      56         338 :             continue;
      57             : 
      58             :         /* Separate key-value pairs with spaces */
      59         222 :         if (conninfo_buf.len != 0)
      60         208 :             appendPQExpBufferChar(&conninfo_buf, ' ');
      61             : 
      62             :         /*
      63             :          * Write "keyword=value" pieces, the value string is escaped and/or
      64             :          * quoted if necessary.
      65             :          */
      66         222 :         appendPQExpBuffer(&conninfo_buf, "%s=", opt->keyword);
      67         222 :         appendConnStrVal(&conninfo_buf, opt->val);
      68             :     }
      69          14 :     if (PQExpBufferDataBroken(conninfo_buf))
      70           0 :         pg_fatal("out of memory");
      71             : 
      72             :     /*
      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
      75             :      * options above!
      76             :      */
      77          14 :     escaped = escape_quotes(conninfo_buf.data);
      78          14 :     termPQExpBuffer(&conninfo_buf);
      79          14 :     appendPQExpBuffer(contents, "primary_conninfo = '%s'\n", escaped);
      80          14 :     free(escaped);
      81             : 
      82          14 :     if (replication_slot)
      83             :     {
      84             :         /* unescaped: ReplicationSlotValidateName allows [a-z0-9_] only */
      85           2 :         appendPQExpBuffer(contents, "primary_slot_name = '%s'\n",
      86             :                           replication_slot);
      87             :     }
      88             : 
      89          14 :     if (PQExpBufferBroken(contents))
      90           0 :         pg_fatal("out of memory");
      91             : 
      92          14 :     PQconninfoFree(connOptions);
      93             : 
      94          14 :     return contents;
      95             : }
      96             : 
      97             : /*
      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.
     103             :  */
     104             : void
     105          10 : WriteRecoveryConfig(PGconn *pgconn, char *target_dir, PQExpBuffer contents)
     106             : {
     107             :     char        filename[MAXPGPATH];
     108             :     FILE       *cf;
     109             :     bool        use_recovery_conf;
     110             : 
     111             :     Assert(pgconn != NULL);
     112             : 
     113          10 :     use_recovery_conf =
     114          10 :         PQserverVersion(pgconn) < MINIMUM_VERSION_FOR_RECOVERY_GUC;
     115             : 
     116          10 :     snprintf(filename, MAXPGPATH, "%s/%s", target_dir,
     117             :              use_recovery_conf ? "recovery.conf" : "postgresql.auto.conf");
     118             : 
     119          10 :     cf = fopen(filename, use_recovery_conf ? "w" : "a");
     120          10 :     if (cf == NULL)
     121           0 :         pg_fatal("could not open file \"%s\": %m", filename);
     122             : 
     123          10 :     if (fwrite(contents->data, contents->len, 1, cf) != 1)
     124           0 :         pg_fatal("could not write to file \"%s\": %m", filename);
     125             : 
     126          10 :     fclose(cf);
     127             : 
     128          10 :     if (!use_recovery_conf)
     129             :     {
     130          10 :         snprintf(filename, MAXPGPATH, "%s/%s", target_dir, "standby.signal");
     131          10 :         cf = fopen(filename, "w");
     132          10 :         if (cf == NULL)
     133           0 :             pg_fatal("could not create file \"%s\": %m", filename);
     134             : 
     135          10 :         fclose(cf);
     136             :     }
     137          10 : }
     138             : 
     139             : /*
     140             :  * Escape a string so that it can be used as a value in a key-value pair
     141             :  * a configuration file.
     142             :  */
     143             : static char *
     144          14 : escape_quotes(const char *src)
     145             : {
     146          14 :     char       *result = escape_single_quotes_ascii(src);
     147             : 
     148          14 :     if (!result)
     149           0 :         pg_fatal("out of memory");
     150          14 :     return result;
     151             : }

Generated by: LCOV version 1.14