LCOV - code coverage report
Current view: top level - src/common - percentrepl.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 66.7 % 30 20
Test Date: 2026-03-04 11:16:30 Functions: 100.0 % 1 1
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * percentrepl.c
       4              :  *    Common routines to replace percent placeholders in strings
       5              :  *
       6              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7              :  * Portions Copyright (c) 1994, Regents of the University of California
       8              :  *
       9              :  *
      10              :  * IDENTIFICATION
      11              :  *    src/common/percentrepl.c
      12              :  *
      13              :  *-------------------------------------------------------------------------
      14              :  */
      15              : 
      16              : #ifndef FRONTEND
      17              : #include "postgres.h"
      18              : #else
      19              : #include "postgres_fe.h"
      20              : #include "common/logging.h"
      21              : #endif
      22              : 
      23              : #include "common/percentrepl.h"
      24              : #include "lib/stringinfo.h"
      25              : 
      26              : /*
      27              :  * replace_percent_placeholders
      28              :  *
      29              :  * Replace percent-letter placeholders in input string with the supplied
      30              :  * values.  For example, to replace %f with foo and %b with bar, call
      31              :  *
      32              :  * replace_percent_placeholders(instr, "param_name", "bf", bar, foo);
      33              :  *
      34              :  * The return value is palloc'd.
      35              :  *
      36              :  * "%%" is replaced by a single "%".
      37              :  *
      38              :  * This throws an error for an unsupported placeholder or a "%" at the end of
      39              :  * the input string.
      40              :  *
      41              :  * A value may be NULL.  If the corresponding placeholder is found in the
      42              :  * input string, it will be treated as if an unsupported placeholder was used.
      43              :  * This allows callers to share a "letters" specification but vary the
      44              :  * actually supported placeholders at run time.
      45              :  *
      46              :  * This functions is meant for cases where all the values are readily
      47              :  * available or cheap to compute and most invocations will use most values
      48              :  * (for example for archive_command).  Also, it requires that all values are
      49              :  * strings.  It won't be a good match for things like log prefixes or prompts
      50              :  * that use a mix of data types and any invocation will only use a few of the
      51              :  * possible values.
      52              :  *
      53              :  * param_name is the name of the underlying GUC parameter, for error
      54              :  * reporting.  At the moment, this function is only used for GUC parameters.
      55              :  * If other kinds of uses were added, the error reporting would need to be
      56              :  * revised.
      57              :  */
      58              : char *
      59          904 : replace_percent_placeholders(const char *instr, const char *param_name, const char *letters,...)
      60              : {
      61              :     StringInfoData result;
      62              : 
      63          904 :     initStringInfo(&result);
      64              : 
      65       101787 :     for (const char *sp = instr; *sp; sp++)
      66              :     {
      67       100883 :         if (*sp == '%')
      68              :         {
      69         1774 :             if (sp[1] == '%')
      70              :             {
      71              :                 /* Convert %% to a single % */
      72            0 :                 sp++;
      73            0 :                 appendStringInfoChar(&result, *sp);
      74              :             }
      75         1774 :             else if (sp[1] == '\0')
      76              :             {
      77              :                 /* Incomplete escape sequence, expected a character afterward */
      78              : #ifdef FRONTEND
      79            0 :                 pg_log_error("invalid value for parameter \"%s\": \"%s\"", param_name, instr);
      80            0 :                 pg_log_error_detail("String ends unexpectedly after escape character \"%%\".");
      81            0 :                 exit(1);
      82              : #else
      83            0 :                 ereport(ERROR,
      84              :                         errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      85              :                         errmsg("invalid value for parameter \"%s\": \"%s\"", param_name, instr),
      86              :                         errdetail("String ends unexpectedly after escape character \"%%\"."));
      87              : #endif
      88              :             }
      89              :             else
      90              :             {
      91              :                 /* Look up placeholder character */
      92         1774 :                 bool        found = false;
      93              :                 va_list     ap;
      94              : 
      95         1774 :                 sp++;
      96              : 
      97         1774 :                 va_start(ap, letters);
      98         3181 :                 for (const char *lp = letters; *lp; lp++)
      99              :                 {
     100         3181 :                     char       *val = va_arg(ap, char *);
     101              : 
     102         3181 :                     if (*sp == *lp)
     103              :                     {
     104         1774 :                         if (val)
     105              :                         {
     106         1774 :                             appendStringInfoString(&result, val);
     107         1774 :                             found = true;
     108              :                         }
     109              :                         /* If val is NULL, we will report an error. */
     110         1774 :                         break;
     111              :                     }
     112              :                 }
     113         1774 :                 va_end(ap);
     114         1774 :                 if (!found)
     115              :                 {
     116              :                     /* Unknown placeholder */
     117              : #ifdef FRONTEND
     118            0 :                     pg_log_error("invalid value for parameter \"%s\": \"%s\"", param_name, instr);
     119            0 :                     pg_log_error_detail("String contains unexpected placeholder \"%%%c\".", *sp);
     120            0 :                     exit(1);
     121              : #else
     122            0 :                     ereport(ERROR,
     123              :                             errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     124              :                             errmsg("invalid value for parameter \"%s\": \"%s\"", param_name, instr),
     125              :                             errdetail("String contains unexpected placeholder \"%%%c\".", *sp));
     126              : #endif
     127              :                 }
     128              :             }
     129              :         }
     130              :         else
     131              :         {
     132        99109 :             appendStringInfoChar(&result, *sp);
     133              :         }
     134              :     }
     135              : 
     136          904 :     return result.data;
     137              : }
        

Generated by: LCOV version 2.0-1