LCOV - code coverage report
Current view: top level - src/common - percentrepl.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 66.7 % 30 20
Test Date: 2026-07-21 09:15:43 Functions: 100.0 % 1 1
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 55.0 % 20 11

             Branch data     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                 :         952 : replace_percent_placeholders(const char *instr, const char *param_name, const char *letters, ...)
      60                 :             : {
      61                 :             :     StringInfoData result;
      62                 :             : 
      63                 :         952 :     initStringInfo(&result);
      64                 :             : 
      65         [ +  + ]:      106346 :     for (const char *sp = instr; *sp; sp++)
      66                 :             :     {
      67         [ +  + ]:      105394 :         if (*sp == '%')
      68                 :             :         {
      69         [ -  + ]:        1852 :             if (sp[1] == '%')
      70                 :             :             {
      71                 :             :                 /* Convert %% to a single % */
      72                 :           0 :                 sp++;
      73                 :           0 :                 appendStringInfoChar(&result, *sp);
      74                 :             :             }
      75         [ -  + ]:        1852 :             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                 :        1852 :                 bool        found = false;
      93                 :             :                 va_list     ap;
      94                 :             : 
      95                 :        1852 :                 sp++;
      96                 :             : 
      97                 :        1852 :                 va_start(ap, letters);
      98         [ +  - ]:        3331 :                 for (const char *lp = letters; *lp; lp++)
      99                 :             :                 {
     100                 :        3331 :                     char       *val = va_arg(ap, char *);
     101                 :             : 
     102         [ +  + ]:        3331 :                     if (*sp == *lp)
     103                 :             :                     {
     104         [ +  - ]:        1852 :                         if (val)
     105                 :             :                         {
     106                 :        1852 :                             appendStringInfoString(&result, val);
     107                 :        1852 :                             found = true;
     108                 :             :                         }
     109                 :             :                         /* If val is NULL, we will report an error. */
     110                 :        1852 :                         break;
     111                 :             :                     }
     112                 :             :                 }
     113                 :        1852 :                 va_end(ap);
     114         [ -  + ]:        1852 :                 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                 :      103542 :             appendStringInfoChar(&result, *sp);
     133                 :             :         }
     134                 :             :     }
     135                 :             : 
     136                 :         952 :     return result.data;
     137                 :             : }
        

Generated by: LCOV version 2.0-1