Skip to content

Commit

Permalink
postgres_fdw: Allow application_name of remote connection to be set v…
Browse files Browse the repository at this point in the history
…ia GUC.

This commit adds postgres_fdw.application_name GUC which specifies
a value for application_name configuration parameter used
when postgres_fdw establishes a connection to a foreign server.
This GUC setting always overrides application_name option of
the foreign server object. This GUC is useful when we want to
specify our own application_name per remote connection.

Previously application_name of a remote connection could be set
basically only via options of a server object. But which meant that
every session connecting to the same foreign server basically
should use the same application_name. Also if we want to change
the setting, we had to execute "ALTER SERVER ... OPTIONS ..." command.
It was inconvenient.

Author: Hayato Kuroda
Reviewed-by: Masahiro Ikeda, Fujii Masao
Discussion: https://postgr.es/m/TYCPR01MB5870D1E8B949DAF6D3B84E02F5F29@TYCPR01MB5870.jpnprd01.prod.outlook.com
  • Loading branch information
MasaoFujii committed Sep 7, 2021
1 parent 4c34788 commit 449ab63
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 5 deletions.
25 changes: 21 additions & 4 deletions contrib/postgres_fdw/connection.c
Expand Up @@ -353,10 +353,11 @@ connect_pg_server(ForeignServer *server, UserMapping *user)
/*
* Construct connection params from generic options of ForeignServer
* and UserMapping. (Some of them might not be libpq options, in
* which case we'll just waste a few array slots.) Add 3 extra slots
* for fallback_application_name, client_encoding, end marker.
* which case we'll just waste a few array slots.) Add 4 extra slots
* for application_name, fallback_application_name, client_encoding,
* end marker.
*/
n = list_length(server->options) + list_length(user->options) + 3;
n = list_length(server->options) + list_length(user->options) + 4;
keywords = (const char **) palloc(n * sizeof(char *));
values = (const char **) palloc(n * sizeof(char *));

Expand All @@ -366,7 +367,23 @@ connect_pg_server(ForeignServer *server, UserMapping *user)
n += ExtractConnectionOptions(user->options,
keywords + n, values + n);

/* Use "postgres_fdw" as fallback_application_name. */
/*
* Use pgfdw_application_name as application_name if set.
*
* PQconnectdbParams() processes the parameter arrays from start to
* end. If any key word is repeated, the last value is used. Therefore
* note that pgfdw_application_name must be added to the arrays after
* options of ForeignServer are, so that it can override
* application_name set in ForeignServer.
*/
if (pgfdw_application_name && *pgfdw_application_name != '\0')
{
keywords[n] = "application_name";
values[n] = pgfdw_application_name;
n++;
}

/* Use "postgres_fdw" as fallback_application_name */
keywords[n] = "fallback_application_name";
values[n] = "postgres_fdw";
n++;
Expand Down
79 changes: 79 additions & 0 deletions contrib/postgres_fdw/expected/postgres_fdw.out
Expand Up @@ -10761,3 +10761,82 @@ ERROR: invalid value for integer option "fetch_size": 100$%$#$#
CREATE FOREIGN TABLE inv_bsz (c1 int )
SERVER loopback OPTIONS (batch_size '100$%$#$#');
ERROR: invalid value for integer option "batch_size": 100$%$#$#
-- ===================================================================
-- test postgres_fdw.application_name GUC
-- ===================================================================
-- Turn debug_discard_caches off for this test to make that
-- the remote connection is alive when checking its application_name.
-- For each test, close all the existing cached connections manually and
-- establish connection with new setting of application_name.
SET debug_discard_caches = 0;
-- If appname is set as GUC but not as options of server object,
-- the GUC setting is used as application_name of remote connection.
SET postgres_fdw.application_name TO 'fdw_guc_appname';
SELECT 1 FROM postgres_fdw_disconnect_all();
?column?
----------
1
(1 row)

SELECT 1 FROM ft6 LIMIT 1;
?column?
----------
1
(1 row)

SELECT application_name FROM pg_stat_activity
WHERE application_name IN ('loopback2', 'fdw_guc_appname');
application_name
------------------
fdw_guc_appname
(1 row)

-- If appname is set as options of server object but not as GUC,
-- appname of server object is used.
RESET postgres_fdw.application_name;
ALTER SERVER loopback2 OPTIONS (ADD application_name 'loopback2');
SELECT 1 FROM postgres_fdw_disconnect_all();
?column?
----------
1
(1 row)

SELECT 1 FROM ft6 LIMIT 1;
?column?
----------
1
(1 row)

SELECT application_name FROM pg_stat_activity
WHERE application_name IN ('loopback2', 'fdw_guc_appname');
application_name
------------------
loopback2
(1 row)

-- If appname is set both as GUC and as options of server object,
-- the GUC setting overrides appname of server object and is used.
SET postgres_fdw.application_name TO 'fdw_guc_appname';
SELECT 1 FROM postgres_fdw_disconnect_all();
?column?
----------
1
(1 row)

SELECT 1 FROM ft6 LIMIT 1;
?column?
----------
1
(1 row)

SELECT application_name FROM pg_stat_activity
WHERE application_name IN ('loopback2', 'fdw_guc_appname');
application_name
------------------
fdw_guc_appname
(1 row)

--Clean up
ALTER SERVER loopback2 OPTIONS (DROP application_name);
RESET postgres_fdw.application_name;
RESET debug_discard_caches;
35 changes: 34 additions & 1 deletion contrib/postgres_fdw/option.c
@@ -1,7 +1,7 @@
/*-------------------------------------------------------------------------
*
* option.c
* FDW option handling for postgres_fdw
* FDW and GUC option handling for postgres_fdw
*
* Portions Copyright (c) 2012-2021, PostgreSQL Global Development Group
*
Expand Down Expand Up @@ -45,6 +45,13 @@ static PgFdwOption *postgres_fdw_options;
*/
static PQconninfoOption *libpq_options;

/*
* GUC parameters
*/
char *pgfdw_application_name = NULL;

void _PG_init(void);

/*
* Helper functions
*/
Expand Down Expand Up @@ -435,3 +442,29 @@ ExtractExtensionList(const char *extensionsString, bool warnOnMissing)
list_free(extlist);
return extensionOids;
}

/*
* Module load callback
*/
void
_PG_init(void)
{
/*
* Unlike application_name GUC, don't set GUC_IS_NAME flag nor check_hook
* to allow postgres_fdw.application_name to be any string more than
* NAMEDATALEN characters and to include non-ASCII characters. Instead,
* remote server truncates application_name of remote connection to less
* than NAMEDATALEN and replaces any non-ASCII characters in it with a '?'
* character.
*/
DefineCustomStringVariable("postgres_fdw.application_name",
"Sets the application name to be used on the remote server.",
NULL,
&pgfdw_application_name,
NULL,
PGC_USERSET,
0,
NULL,
NULL,
NULL);
}
1 change: 1 addition & 0 deletions contrib/postgres_fdw/postgres_fdw.h
Expand Up @@ -158,6 +158,7 @@ extern int ExtractConnectionOptions(List *defelems,
const char **values);
extern List *ExtractExtensionList(const char *extensionsString,
bool warnOnMissing);
extern char *pgfdw_application_name;

/* in deparse.c */
extern void classifyConditions(PlannerInfo *root,
Expand Down
39 changes: 39 additions & 0 deletions contrib/postgres_fdw/sql/postgres_fdw.sql
Expand Up @@ -3422,3 +3422,42 @@ CREATE FOREIGN TABLE inv_fsz (c1 int )
-- Invalid batch_size option
CREATE FOREIGN TABLE inv_bsz (c1 int )
SERVER loopback OPTIONS (batch_size '100$%$#$#');

-- ===================================================================
-- test postgres_fdw.application_name GUC
-- ===================================================================
-- Turn debug_discard_caches off for this test to make that
-- the remote connection is alive when checking its application_name.
-- For each test, close all the existing cached connections manually and
-- establish connection with new setting of application_name.
SET debug_discard_caches = 0;

-- If appname is set as GUC but not as options of server object,
-- the GUC setting is used as application_name of remote connection.
SET postgres_fdw.application_name TO 'fdw_guc_appname';
SELECT 1 FROM postgres_fdw_disconnect_all();
SELECT 1 FROM ft6 LIMIT 1;
SELECT application_name FROM pg_stat_activity
WHERE application_name IN ('loopback2', 'fdw_guc_appname');

-- If appname is set as options of server object but not as GUC,
-- appname of server object is used.
RESET postgres_fdw.application_name;
ALTER SERVER loopback2 OPTIONS (ADD application_name 'loopback2');
SELECT 1 FROM postgres_fdw_disconnect_all();
SELECT 1 FROM ft6 LIMIT 1;
SELECT application_name FROM pg_stat_activity
WHERE application_name IN ('loopback2', 'fdw_guc_appname');

-- If appname is set both as GUC and as options of server object,
-- the GUC setting overrides appname of server object and is used.
SET postgres_fdw.application_name TO 'fdw_guc_appname';
SELECT 1 FROM postgres_fdw_disconnect_all();
SELECT 1 FROM ft6 LIMIT 1;
SELECT application_name FROM pg_stat_activity
WHERE application_name IN ('loopback2', 'fdw_guc_appname');

--Clean up
ALTER SERVER loopback2 OPTIONS (DROP application_name);
RESET postgres_fdw.application_name;
RESET debug_discard_caches;
25 changes: 25 additions & 0 deletions doc/src/sgml/postgres-fdw.sgml
Expand Up @@ -905,6 +905,31 @@ postgres=# SELECT postgres_fdw_disconnect_all();
</para>
</sect2>

<sect2>
<title>Configuration Parameters</title>

<variablelist>
<varlistentry>
<term>
<varname>postgres_fdw.application_name</varname> (<type>string</type>)
<indexterm>
<primary><varname>postgres_fdw.application_name</varname> configuration parameter</primary>
</indexterm>
</term>
<listitem>
<para>
Specifies a value for <xref linkend="guc-application-name"/>
configuration parameter used when <filename>postgres_fdw</filename>
establishes a connection to a foreign server. This overrides
<varname>application_name</varname> option of the server object.
Note that change of this parameter doesn't affect any existing
connections until they are re-established.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>

<sect2>
<title>Examples</title>

Expand Down

0 comments on commit 449ab63

Please sign in to comment.