LCOV - differential code coverage report
Current view: top level - contrib/postgres_fdw - option.c (source / functions) Coverage Total Hit LBC UIC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 94.6 % 168 159 3 6 3 96 14 46 6 106 4
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 9 9 9 9
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * option.c
       4                 :  *        FDW and GUC option handling for postgres_fdw
       5                 :  *
       6                 :  * Portions Copyright (c) 2012-2023, PostgreSQL Global Development Group
       7                 :  *
       8                 :  * IDENTIFICATION
       9                 :  *        contrib/postgres_fdw/option.c
      10                 :  *
      11                 :  *-------------------------------------------------------------------------
      12                 :  */
      13                 : #include "postgres.h"
      14                 : 
      15                 : #include "access/reloptions.h"
      16                 : #include "catalog/pg_foreign_server.h"
      17                 : #include "catalog/pg_foreign_table.h"
      18                 : #include "catalog/pg_user_mapping.h"
      19                 : #include "commands/defrem.h"
      20                 : #include "commands/extension.h"
      21                 : #include "libpq/libpq-be.h"
      22                 : #include "postgres_fdw.h"
      23                 : #include "utils/builtins.h"
      24                 : #include "utils/guc.h"
      25                 : #include "utils/varlena.h"
      26                 : 
      27                 : /*
      28                 :  * Describes the valid options for objects that this wrapper uses.
      29                 :  */
      30                 : typedef struct PgFdwOption
      31                 : {
      32                 :     const char *keyword;
      33                 :     Oid         optcontext;     /* OID of catalog in which option may appear */
      34                 :     bool        is_libpq_opt;   /* true if it's used in libpq */
      35                 : } PgFdwOption;
      36                 : 
      37                 : /*
      38                 :  * Valid options for postgres_fdw.
      39                 :  * Allocated and filled in InitPgFdwOptions.
      40                 :  */
      41                 : static PgFdwOption *postgres_fdw_options;
      42                 : 
      43                 : /*
      44                 :  * Valid options for libpq.
      45                 :  * Allocated and filled in InitPgFdwOptions.
      46                 :  */
      47                 : static PQconninfoOption *libpq_options;
      48                 : 
      49                 : /*
      50                 :  * GUC parameters
      51                 :  */
      52                 : char       *pgfdw_application_name = NULL;
      53                 : 
      54                 : /*
      55                 :  * Helper functions
      56                 :  */
      57                 : static void InitPgFdwOptions(void);
      58                 : static bool is_valid_option(const char *keyword, Oid context);
      59                 : static bool is_libpq_option(const char *keyword);
      60                 : 
      61                 : #include "miscadmin.h"
      62                 : 
      63                 : /*
      64                 :  * Validate the generic options given to a FOREIGN DATA WRAPPER, SERVER,
      65                 :  * USER MAPPING or FOREIGN TABLE that uses postgres_fdw.
      66                 :  *
      67 ECB             :  * Raise an ERROR if the option or its value is considered invalid.
      68                 :  */
      69 GIC           3 : PG_FUNCTION_INFO_V1(postgres_fdw_validator);
      70 ECB             : 
      71                 : Datum
      72 CBC         263 : postgres_fdw_validator(PG_FUNCTION_ARGS)
      73 ECB             : {
      74 GIC         263 :     List       *options_list = untransformRelOptions(PG_GETARG_DATUM(0));
      75             263 :     Oid         catalog = PG_GETARG_OID(1);
      76                 :     ListCell   *cell;
      77 ECB             : 
      78                 :     /* Build our options lists if we didn't yet. */
      79 GIC         263 :     InitPgFdwOptions();
      80                 : 
      81                 :     /*
      82                 :      * Check that only options supported by postgres_fdw, and allowed for the
      83 ECB             :      * current object type, are given.
      84                 :      */
      85 CBC         841 :     foreach(cell, options_list)
      86                 :     {
      87             590 :         DefElem    *def = (DefElem *) lfirst(cell);
      88                 : 
      89 GIC         590 :         if (!is_valid_option(def->defname, catalog))
      90                 :         {
      91                 :             /*
      92                 :              * Unknown option specified, complain about it. Provide a hint
      93                 :              * with a valid option that looks similar, if there is one.
      94                 :              */
      95                 :             PgFdwOption *opt;
      96                 :             const char *closest_match;
      97                 :             ClosestMatchState match_state;
      98 GNC           3 :             bool        has_valid_options = false;
      99                 : 
     100               3 :             initClosestMatch(&match_state, def->defname, 4);
     101 CBC         189 :             for (opt = postgres_fdw_options; opt->keyword; opt++)
     102                 :             {
     103             186 :                 if (catalog == opt->optcontext)
     104                 :                 {
     105 GNC          52 :                     has_valid_options = true;
     106              52 :                     updateClosestMatch(&match_state, opt->keyword);
     107                 :                 }
     108 ECB             :             }
     109                 : 
     110 GNC           3 :             closest_match = getClosestMatch(&match_state);
     111 GIC           3 :             ereport(ERROR,
     112                 :                     (errcode(ERRCODE_FDW_INVALID_OPTION_NAME),
     113 ECB             :                      errmsg("invalid option \"%s\"", def->defname),
     114                 :                      has_valid_options ? closest_match ?
     115                 :                      errhint("Perhaps you meant the option \"%s\".",
     116                 :                              closest_match) : 0 :
     117                 :                      errhint("There are no valid options in this context.")));
     118                 :         }
     119                 : 
     120                 :         /*
     121                 :          * Validate option value, when we can do so without any context.
     122                 :          */
     123 GIC         587 :         if (strcmp(def->defname, "use_remote_estimate") == 0 ||
     124             557 :             strcmp(def->defname, "updatable") == 0 ||
     125             553 :             strcmp(def->defname, "truncatable") == 0 ||
     126 CBC         548 :             strcmp(def->defname, "async_capable") == 0 ||
     127             546 :             strcmp(def->defname, "parallel_commit") == 0 ||
     128 GNC         542 :             strcmp(def->defname, "parallel_abort") == 0 ||
     129 CBC         538 :             strcmp(def->defname, "keep_connections") == 0)
     130 ECB             :         {
     131                 :             /* these accept only boolean values */
     132 CBC          66 :             (void) defGetBoolean(def);
     133 ECB             :         }
     134 GIC         521 :         else if (strcmp(def->defname, "fdw_startup_cost") == 0 ||
     135             515 :                  strcmp(def->defname, "fdw_tuple_cost") == 0)
     136 CBC          10 :         {
     137                 :             /*
     138 ECB             :              * These must have a floating point value greater than or equal to
     139                 :              * zero.
     140                 :              */
     141                 :             char       *value;
     142                 :             double      real_val;
     143                 :             bool        is_parsed;
     144                 : 
     145 GIC          12 :             value = defGetString(def);
     146              12 :             is_parsed = parse_real(value, &real_val, 0, NULL);
     147                 : 
     148              12 :             if (!is_parsed)
     149 CBC           2 :                 ereport(ERROR,
     150 ECB             :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     151                 :                          errmsg("invalid value for floating point option \"%s\": %s",
     152                 :                                 def->defname, value)));
     153                 : 
     154 GIC          10 :             if (real_val < 0)
     155 UIC           0 :                 ereport(ERROR,
     156                 :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     157                 :                          errmsg("\"%s\" must be a floating point value greater than or equal to zero",
     158 ECB             :                                 def->defname)));
     159 EUB             :         }
     160 GIC         509 :         else if (strcmp(def->defname, "extensions") == 0)
     161                 :         {
     162                 :             /* check list syntax, warn about uninstalled extensions */
     163              31 :             (void) ExtractExtensionList(defGetString(def), true);
     164 ECB             :         }
     165 GIC         478 :         else if (strcmp(def->defname, "fetch_size") == 0 ||
     166             473 :                  strcmp(def->defname, "batch_size") == 0)
     167 CBC          24 :         {
     168                 :             char       *value;
     169 ECB             :             int         int_val;
     170                 :             bool        is_parsed;
     171                 : 
     172 GIC          26 :             value = defGetString(def);
     173              26 :             is_parsed = parse_int(value, &int_val, 0, NULL);
     174                 : 
     175              26 :             if (!is_parsed)
     176 CBC           2 :                 ereport(ERROR,
     177 ECB             :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     178                 :                          errmsg("invalid value for integer option \"%s\": %s",
     179                 :                                 def->defname, value)));
     180                 : 
     181 GIC          24 :             if (int_val <= 0)
     182 UIC           0 :                 ereport(ERROR,
     183                 :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     184                 :                          errmsg("\"%s\" must be an integer value greater than zero",
     185 ECB             :                                 def->defname)));
     186 EUB             :         }
     187 GIC         452 :         else if (strcmp(def->defname, "password_required") == 0)
     188                 :         {
     189               5 :             bool        pw_required = defGetBoolean(def);
     190                 : 
     191 ECB             :             /*
     192                 :              * Only the superuser may set this option on a user mapping, or
     193                 :              * alter a user mapping on which this option is set. We allow a
     194                 :              * user to clear this option if it's set - in fact, we don't have
     195                 :              * a choice since we can't see the old mapping when validating an
     196                 :              * alter.
     197                 :              */
     198 GIC           5 :             if (!superuser() && !pw_required)
     199               1 :                 ereport(ERROR,
     200                 :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     201                 :                          errmsg("password_required=false is superuser-only"),
     202 ECB             :                          errhint("User mappings with the password_required option set to false may only be created or modified by the superuser.")));
     203                 :         }
     204 GIC         447 :         else if (strcmp(def->defname, "sslcert") == 0 ||
     205             441 :                  strcmp(def->defname, "sslkey") == 0)
     206                 :         {
     207                 :             /* similarly for sslcert / sslkey on user mapping */
     208 CBC          12 :             if (catalog == UserMappingRelationId && !superuser())
     209               2 :                 ereport(ERROR,
     210                 :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     211                 :                          errmsg("sslcert and sslkey are superuser-only"),
     212 ECB             :                          errhint("User mappings with the sslcert or sslkey options set may only be created or modified by the superuser.")));
     213                 :         }
     214 GNC         435 :         else if (strcmp(def->defname, "analyze_sampling") == 0)
     215                 :         {
     216                 :             char       *value;
     217                 : 
     218               6 :             value = defGetString(def);
     219                 : 
     220                 :             /* we recognize off/auto/random/system/bernoulli */
     221               6 :             if (strcmp(value, "off") != 0 &&
     222               5 :                 strcmp(value, "auto") != 0 &&
     223               4 :                 strcmp(value, "random") != 0 &&
     224               3 :                 strcmp(value, "system") != 0 &&
     225               2 :                 strcmp(value, "bernoulli") != 0)
     226               1 :                 ereport(ERROR,
     227                 :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     228                 :                          errmsg("invalid value for string option \"%s\": %s",
     229                 :                                 def->defname, value)));
     230                 :         }
     231                 :     }
     232                 : 
     233 GIC         251 :     PG_RETURN_VOID();
     234                 : }
     235 ECB             : 
     236                 : /*
     237                 :  * Initialize option lists.
     238                 :  */
     239                 : static void
     240 GIC         387 : InitPgFdwOptions(void)
     241                 : {
     242 ECB             :     int         num_libpq_opts;
     243                 :     PQconninfoOption *lopt;
     244                 :     PgFdwOption *popt;
     245                 : 
     246                 :     /* non-libpq FDW-specific FDW options */
     247                 :     static const PgFdwOption non_libpq_options[] = {
     248                 :         {"schema_name", ForeignTableRelationId, false},
     249                 :         {"table_name", ForeignTableRelationId, false},
     250                 :         {"column_name", AttributeRelationId, false},
     251                 :         /* use_remote_estimate is available on both server and table */
     252                 :         {"use_remote_estimate", ForeignServerRelationId, false},
     253                 :         {"use_remote_estimate", ForeignTableRelationId, false},
     254                 :         /* cost factors */
     255                 :         {"fdw_startup_cost", ForeignServerRelationId, false},
     256                 :         {"fdw_tuple_cost", ForeignServerRelationId, false},
     257                 :         /* shippable extensions */
     258                 :         {"extensions", ForeignServerRelationId, false},
     259                 :         /* updatable is available on both server and table */
     260                 :         {"updatable", ForeignServerRelationId, false},
     261                 :         {"updatable", ForeignTableRelationId, false},
     262                 :         /* truncatable is available on both server and table */
     263                 :         {"truncatable", ForeignServerRelationId, false},
     264                 :         {"truncatable", ForeignTableRelationId, false},
     265                 :         /* fetch_size is available on both server and table */
     266                 :         {"fetch_size", ForeignServerRelationId, false},
     267                 :         {"fetch_size", ForeignTableRelationId, false},
     268                 :         /* batch_size is available on both server and table */
     269                 :         {"batch_size", ForeignServerRelationId, false},
     270                 :         {"batch_size", ForeignTableRelationId, false},
     271                 :         /* async_capable is available on both server and table */
     272                 :         {"async_capable", ForeignServerRelationId, false},
     273                 :         {"async_capable", ForeignTableRelationId, false},
     274                 :         {"parallel_commit", ForeignServerRelationId, false},
     275                 :         {"parallel_abort", ForeignServerRelationId, false},
     276                 :         {"keep_connections", ForeignServerRelationId, false},
     277                 :         {"password_required", UserMappingRelationId, false},
     278                 : 
     279                 :         /* sampling is available on both server and table */
     280                 :         {"analyze_sampling", ForeignServerRelationId, false},
     281                 :         {"analyze_sampling", ForeignTableRelationId, false},
     282                 : 
     283                 :         /*
     284                 :          * sslcert and sslkey are in fact libpq options, but we repeat them
     285                 :          * here to allow them to appear in both foreign server context (when
     286                 :          * we generate libpq options) and user mapping context (from here).
     287                 :          */
     288                 :         {"sslcert", UserMappingRelationId, true},
     289                 :         {"sslkey", UserMappingRelationId, true},
     290                 : 
     291                 :         {NULL, InvalidOid, false}
     292                 :     };
     293                 : 
     294                 :     /* Prevent redundant initialization. */
     295 GIC         387 :     if (postgres_fdw_options)
     296             383 :         return;
     297                 : 
     298                 :     /*
     299                 :      * Get list of valid libpq options.
     300                 :      *
     301                 :      * To avoid unnecessary work, we get the list once and use it throughout
     302                 :      * the lifetime of this backend process.  We don't need to care about
     303                 :      * memory context issues, because PQconndefaults allocates with malloc.
     304                 :      */
     305               4 :     libpq_options = PQconndefaults();
     306               4 :     if (!libpq_options)         /* assume reason for failure is OOM */
     307 UIC           0 :         ereport(ERROR,
     308                 :                 (errcode(ERRCODE_FDW_OUT_OF_MEMORY),
     309                 :                  errmsg("out of memory"),
     310                 :                  errdetail("Could not get libpq's default connection options.")));
     311                 : 
     312                 :     /* Count how many libpq options are available. */
     313 GIC           4 :     num_libpq_opts = 0;
     314             160 :     for (lopt = libpq_options; lopt->keyword; lopt++)
     315             156 :         num_libpq_opts++;
     316                 : 
     317                 :     /*
     318                 :      * Construct an array which consists of all valid options for
     319                 :      * postgres_fdw, by appending FDW-specific options to libpq options.
     320                 :      *
     321 ECB             :      * We use plain malloc here to allocate postgres_fdw_options because it
     322                 :      * lives as long as the backend process does.  Besides, keeping
     323                 :      * libpq_options in memory allows us to avoid copying every keyword
     324                 :      * string.
     325                 :      */
     326 GIC           4 :     postgres_fdw_options = (PgFdwOption *)
     327               4 :         malloc(sizeof(PgFdwOption) * num_libpq_opts +
     328                 :                sizeof(non_libpq_options));
     329               4 :     if (postgres_fdw_options == NULL)
     330 UIC           0 :         ereport(ERROR,
     331 ECB             :                 (errcode(ERRCODE_FDW_OUT_OF_MEMORY),
     332                 :                  errmsg("out of memory")));
     333 EUB             : 
     334 GIC           4 :     popt = postgres_fdw_options;
     335             160 :     for (lopt = libpq_options; lopt->keyword; lopt++)
     336                 :     {
     337                 :         /* Hide debug options, as well as settings we override internally. */
     338             156 :         if (strchr(lopt->dispchar, 'D') ||
     339 CBC         152 :             strcmp(lopt->keyword, "fallback_application_name") == 0 ||
     340             148 :             strcmp(lopt->keyword, "client_encoding") == 0)
     341              12 :             continue;
     342                 : 
     343                 :         /* We don't have to copy keyword string, as described above. */
     344 GIC         144 :         popt->keyword = lopt->keyword;
     345                 : 
     346                 :         /*
     347                 :          * "user" and any secret options are allowed only on user mappings.
     348                 :          * Everything else is a server option.
     349                 :          */
     350             144 :         if (strcmp(lopt->keyword, "user") == 0 || strchr(lopt->dispchar, '*'))
     351              12 :             popt->optcontext = UserMappingRelationId;
     352 ECB             :         else
     353 CBC         132 :             popt->optcontext = ForeignServerRelationId;
     354 GIC         144 :         popt->is_libpq_opt = true;
     355 ECB             : 
     356 GBC         144 :         popt++;
     357                 :     }
     358                 : 
     359                 :     /* Append FDW-specific options and dummy terminator. */
     360 CBC           4 :     memcpy(popt, non_libpq_options, sizeof(non_libpq_options));
     361 ECB             : }
     362                 : 
     363                 : /*
     364                 :  * Check whether the given option is one of the valid postgres_fdw options.
     365                 :  * context is the Oid of the catalog holding the object the option is for.
     366                 :  */
     367                 : static bool
     368 GIC         590 : is_valid_option(const char *keyword, Oid context)
     369                 : {
     370 ECB             :     PgFdwOption *opt;
     371                 : 
     372 GIC         590 :     Assert(postgres_fdw_options);   /* must be initialized already */
     373                 : 
     374           17587 :     for (opt = postgres_fdw_options; opt->keyword; opt++)
     375                 :     {
     376 CBC       17584 :         if (context == opt->optcontext && strcmp(opt->keyword, keyword) == 0)
     377             587 :             return true;
     378                 :     }
     379 ECB             : 
     380 CBC           3 :     return false;
     381                 : }
     382 ECB             : 
     383                 : /*
     384                 :  * Check whether the given option is one of the valid libpq options.
     385                 :  */
     386                 : static bool
     387 GIC         211 : is_libpq_option(const char *keyword)
     388                 : {
     389                 :     PgFdwOption *opt;
     390                 : 
     391             211 :     Assert(postgres_fdw_options);   /* must be initialized already */
     392                 : 
     393            5478 :     for (opt = postgres_fdw_options; opt->keyword; opt++)
     394 ECB             :     {
     395 GIC        5411 :         if (opt->is_libpq_opt && strcmp(opt->keyword, keyword) == 0)
     396             144 :             return true;
     397                 :     }
     398 ECB             : 
     399 GIC          67 :     return false;
     400 ECB             : }
     401                 : 
     402                 : /*
     403                 :  * Generate key-value arrays which include only libpq options from the
     404                 :  * given list (which can contain any kind of options).  Caller must have
     405                 :  * allocated large-enough arrays.  Returns number of options found.
     406                 :  */
     407                 : int
     408 GIC         124 : ExtractConnectionOptions(List *defelems, const char **keywords,
     409                 :                          const char **values)
     410                 : {
     411                 :     ListCell   *lc;
     412                 :     int         i;
     413 ECB             : 
     414                 :     /* Build our options lists if we didn't yet. */
     415 GIC         124 :     InitPgFdwOptions();
     416                 : 
     417 CBC         124 :     i = 0;
     418 GIC         335 :     foreach(lc, defelems)
     419 ECB             :     {
     420 GIC         211 :         DefElem    *d = (DefElem *) lfirst(lc);
     421 ECB             : 
     422 CBC         211 :         if (is_libpq_option(d->defname))
     423                 :         {
     424 GIC         144 :             keywords[i] = d->defname;
     425 CBC         144 :             values[i] = defGetString(d);
     426 GIC         144 :             i++;
     427                 :         }
     428                 :     }
     429             124 :     return i;
     430                 : }
     431                 : 
     432                 : /*
     433                 :  * Parse a comma-separated string and return a List of the OIDs of the
     434 ECB             :  * extensions named in the string.  If any names in the list cannot be
     435                 :  * found, report a warning if warnOnMissing is true, else just silently
     436                 :  * ignore them.
     437                 :  */
     438                 : List *
     439 GIC         855 : ExtractExtensionList(const char *extensionsString, bool warnOnMissing)
     440                 : {
     441 CBC         855 :     List       *extensionOids = NIL;
     442                 :     List       *extlist;
     443 ECB             :     ListCell   *lc;
     444                 : 
     445                 :     /* SplitIdentifierString scribbles on its input, so pstrdup first */
     446 CBC         855 :     if (!SplitIdentifierString(pstrdup(extensionsString), ',', &extlist))
     447                 :     {
     448 ECB             :         /* syntax error in name list */
     449 GIC           1 :         ereport(ERROR,
     450 ECB             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     451                 :                  errmsg("parameter \"%s\" must be a list of extension names",
     452                 :                         "extensions")));
     453                 :     }
     454                 : 
     455 CBC        1709 :     foreach(lc, extlist)
     456                 :     {
     457 GIC         855 :         const char *extension_name = (const char *) lfirst(lc);
     458             855 :         Oid         extension_oid = get_extension_oid(extension_name, true);
     459                 : 
     460             855 :         if (OidIsValid(extension_oid))
     461                 :         {
     462             853 :             extensionOids = lappend_oid(extensionOids, extension_oid);
     463                 :         }
     464               2 :         else if (warnOnMissing)
     465 ECB             :         {
     466 GIC           2 :             ereport(WARNING,
     467 ECB             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
     468                 :                      errmsg("extension \"%s\" is not installed",
     469                 :                             extension_name)));
     470                 :         }
     471                 :     }
     472                 : 
     473 GIC         854 :     list_free(extlist);
     474             854 :     return extensionOids;
     475 ECB             : }
     476                 : 
     477                 : /*
     478                 :  * Replace escape sequences beginning with % character in the given
     479                 :  * application_name with status information, and return it.
     480                 :  *
     481                 :  * This function always returns a palloc'd string, so the caller is
     482                 :  * responsible for pfreeing it.
     483                 :  */
     484                 : char *
     485 GIC          16 : process_pgfdw_appname(const char *appname)
     486 ECB             : {
     487                 :     const char *p;
     488                 :     StringInfoData buf;
     489                 : 
     490 CBC          16 :     initStringInfo(&buf);
     491                 : 
     492             221 :     for (p = appname; *p != '\0'; p++)
     493                 :     {
     494 GIC         205 :         if (*p != '%')
     495                 :         {
     496                 :             /* literal char, just copy */
     497             196 :             appendStringInfoChar(&buf, *p);
     498             196 :             continue;
     499 ECB             :         }
     500                 : 
     501                 :         /* must be a '%', so skip to the next char */
     502 GIC           9 :         p++;
     503               9 :         if (*p == '\0')
     504 UIC           0 :             break;              /* format error - ignore it */
     505 GIC           9 :         else if (*p == '%')
     506                 :         {
     507                 :             /* string contains %% */
     508               1 :             appendStringInfoChar(&buf, '%');
     509               1 :             continue;
     510                 :         }
     511 ECB             : 
     512                 :         /* process the option */
     513 GIC           8 :         switch (*p)
     514                 :         {
     515               1 :             case 'a':
     516 CBC           1 :                 appendStringInfoString(&buf, application_name);
     517 GIC           1 :                 break;
     518 CBC           2 :             case 'c':
     519 GIC           2 :                 appendStringInfo(&buf, "%lx.%x", (long) (MyStartTime), MyProcPid);
     520 CBC           2 :                 break;
     521 GIC           2 :             case 'C':
     522               2 :                 appendStringInfoString(&buf, cluster_name);
     523 CBC           2 :                 break;
     524               1 :             case 'd':
     525 GIC           1 :                 if (MyProcPort)
     526                 :                 {
     527               1 :                     const char *dbname = MyProcPort->database_name;
     528 ECB             : 
     529 CBC           1 :                     if (dbname)
     530 GBC           1 :                         appendStringInfoString(&buf, dbname);
     531 ECB             :                     else
     532 UIC           0 :                         appendStringInfoString(&buf, "[unknown]");
     533                 :                 }
     534 CBC           1 :                 break;
     535               1 :             case 'p':
     536 GIC           1 :                 appendStringInfo(&buf, "%d", MyProcPid);
     537               1 :                 break;
     538               1 :             case 'u':
     539 CBC           1 :                 if (MyProcPort)
     540                 :                 {
     541               1 :                     const char *username = MyProcPort->user_name;
     542 ECB             : 
     543 CBC           1 :                     if (username)
     544               1 :                         appendStringInfoString(&buf, username);
     545 ECB             :                     else
     546 LBC           0 :                         appendStringInfoString(&buf, "[unknown]");
     547 ECB             :                 }
     548 CBC           1 :                 break;
     549 LBC           0 :             default:
     550 ECB             :                 /* format error - ignore it */
     551 LBC           0 :                 break;
     552                 :         }
     553 ECB             :     }
     554                 : 
     555 CBC          16 :     return buf.data;
     556 ECB             : }
     557                 : 
     558 EUB             : /*
     559                 :  * Module load callback
     560 ECB             :  */
     561                 : void
     562 CBC           4 : _PG_init(void)
     563 ECB             : {
     564                 :     /*
     565                 :      * Unlike application_name GUC, don't set GUC_IS_NAME flag nor check_hook
     566                 :      * to allow postgres_fdw.application_name to be any string more than
     567                 :      * NAMEDATALEN characters and to include non-ASCII characters. Instead,
     568                 :      * remote server truncates application_name of remote connection to less
     569                 :      * than NAMEDATALEN and replaces any non-ASCII characters in it with a '?'
     570                 :      * character.
     571                 :      */
     572 GBC           4 :     DefineCustomStringVariable("postgres_fdw.application_name",
     573                 :                                "Sets the application name to be used on the remote server.",
     574 ECB             :                                NULL,
     575 EUB             :                                &pgfdw_application_name,
     576                 :                                NULL,
     577                 :                                PGC_USERSET,
     578                 :                                0,
     579                 :                                NULL,
     580                 :                                NULL,
     581 ECB             :                                NULL);
     582                 : 
     583 GIC           4 :     MarkGUCPrefixReserved("postgres_fdw");
     584               4 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a