LCOV - code coverage report
Current view: top level - src/common - percentrepl.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 20 30 66.7 %
Date: 2024-04-26 04:11:37 Functions: 1 1 100.0 %
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-2024, 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         388 : replace_percent_placeholders(const char *instr, const char *param_name, const char *letters,...)
      60             : {
      61             :     StringInfoData result;
      62             : 
      63         388 :     initStringInfo(&result);
      64             : 
      65       42278 :     for (const char *sp = instr; *sp; sp++)
      66             :     {
      67       41890 :         if (*sp == '%')
      68             :         {
      69         748 :             if (sp[1] == '%')
      70             :             {
      71             :                 /* Convert %% to a single % */
      72           0 :                 sp++;
      73           0 :                 appendStringInfoChar(&result, *sp);
      74             :             }
      75         748 :             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         748 :                 bool        found = false;
      93             :                 va_list     ap;
      94             : 
      95         748 :                 sp++;
      96             : 
      97         748 :                 va_start(ap, letters);
      98        1436 :                 for (const char *lp = letters; *lp; lp++)
      99             :                 {
     100        1436 :                     char       *val = va_arg(ap, char *);
     101             : 
     102        1436 :                     if (*sp == *lp)
     103             :                     {
     104         748 :                         if (val)
     105             :                         {
     106         748 :                             appendStringInfoString(&result, val);
     107         748 :                             found = true;
     108             :                         }
     109             :                         /* If val is NULL, we will report an error. */
     110         748 :                         break;
     111             :                     }
     112             :                 }
     113         748 :                 va_end(ap);
     114         748 :                 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       41142 :             appendStringInfoChar(&result, *sp);
     133             :         }
     134             :     }
     135             : 
     136         388 :     return result.data;
     137             : }

Generated by: LCOV version 1.14