On Thu, Mar 27, 2025 at 06:31:14PM +0900, Michael Paquier wrote: > I am not sure that I'll have the time to look at 0002 for this release > cycle, could it be possible to get a rebase for it?
Here is a simple rebase that I have been able to assemble this morning. I won't have the space to review it for this release cycle unfortunately, but at least it works in the CI. I am moving this patch entry to the next CF for v19, as a result of that. -- Michael
From 83818caa5f5d5847ca99210446cc37fa8f8a1caf Mon Sep 17 00:00:00 2001 From: Michael Paquier <mich...@paquier.xyz> Date: Fri, 28 Mar 2025 08:26:01 +0900 Subject: [PATCH v4] add servicefile connection option feature --- src/interfaces/libpq/fe-connect.c | 27 +++++++++++-- src/interfaces/libpq/t/006_service.pl | 58 +++++++++++++++++++++++++++ doc/src/sgml/libpq.sgml | 16 +++++++- 3 files changed, 97 insertions(+), 4 deletions(-) diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index d5051f5e820f..f16468be7d14 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -195,6 +195,9 @@ static const internalPQconninfoOption PQconninfoOptions[] = { "Database-Service", "", 20, offsetof(struct pg_conn, pgservice)}, + {"servicefile", "PGSERVICEFILE", NULL, NULL, + "Database-Service-File", "", 64, -1}, + {"user", "PGUSER", NULL, NULL, "Database-User", "", 20, offsetof(struct pg_conn, pguser)}, @@ -5838,6 +5841,7 @@ static int parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage) { const char *service = conninfo_getval(options, "service"); + const char *service_fname = conninfo_getval(options, "servicefile"); char serviceFile[MAXPGPATH]; char *env; bool group_found = false; @@ -5857,11 +5861,18 @@ parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage) return 0; /* - * Try PGSERVICEFILE if specified, else try ~/.pg_service.conf (if that - * exists). + * First, check servicefile option on connection string. Second, check + * PGSERVICEFILE environment variable. Finally, check ~/.pg_service.conf + * (if that exists). */ - if ((env = getenv("PGSERVICEFILE")) != NULL) + if (service_fname != NULL) + { + strlcpy(serviceFile, service_fname, sizeof(serviceFile)); + } + else if ((env = getenv("PGSERVICEFILE")) != NULL) + { strlcpy(serviceFile, env, sizeof(serviceFile)); + } else { char homedir[MAXPGPATH]; @@ -6023,6 +6034,16 @@ parseServiceFile(const char *serviceFile, goto exit; } + if (strcmp(key, "servicefile") == 0) + { + libpq_append_error(errorMessage, + "nested servicefile specifications not supported in service file \"%s\", line %d", + serviceFile, + linenr); + result = 3; + goto exit; + } + /* * Set the parameter --- but don't override any previous * explicit setting. diff --git a/src/interfaces/libpq/t/006_service.pl b/src/interfaces/libpq/t/006_service.pl index d3ecfa6b6fc8..752973d96534 100644 --- a/src/interfaces/libpq/t/006_service.pl +++ b/src/interfaces/libpq/t/006_service.pl @@ -136,6 +136,64 @@ local $ENV{PGSERVICEFILE} = "$srvfile_empty"; unlink($srvfile_default); } +# Backslashes escaped path string for getting collect result at concatenation +# for Windows environment +my $srvfile_win_cared = $srvfile_valid; +$srvfile_win_cared =~ s/\\/\\\\/g; + +# Check that servicefile option works as expected +{ + $node->connect_ok( + q{service=my_srv servicefile='} . $srvfile_win_cared . q{'}, + 'service=my_srv servicefile=...', + sql => "SELECT 'connect4'", + expected_stdout => qr/connect4/); + + # Encode slashes and backslash + my $encoded_srvfile = $srvfile_valid =~ s{([\\/])}{ + $1 eq '/' ? '%2F' : '%5C' + }ger; + + # Additionaly encode a colon in servicefile path of Windows + $encoded_srvfile =~ s/:/%3A/g; + + $node->connect_ok( + 'postgresql:///?service=my_srv&servicefile=' . $encoded_srvfile, + 'postgresql:///?service=my_srv&servicefile=...', + sql => "SELECT 'connect5'", + expected_stdout => qr/connect5/); + + local $ENV{PGSERVICE} = 'my_srv'; + $node->connect_ok( + q{servicefile='} . $srvfile_win_cared . q{'}, + 'envvar: PGSERVICE=my_srv + servicefile=...', + sql => "SELECT 'connect6'", + expected_stdout => qr/connect6/); + + $node->connect_ok( + 'postgresql://?servicefile=' . $encoded_srvfile, + 'envvar: PGSERVICE=my_srv + postgresql://?servicefile=...', + sql => "SELECT 'connect7'", + expected_stdout => qr/connect7/); +} + +# Check that servicefile option takes precedence over PGSERVICEFILE environment variable +{ + local $ENV{PGSERVICEFILE} = 'non-existent-file.conf'; + + $node->connect_fails( + 'service=my_srv', + 'service=... fails with wrong PGSERVICEFILE', + expected_stderr => + qr/service file "non-existent-file\.conf" not found/); + + $node->connect_ok( + q{service=my_srv servicefile='} . $srvfile_win_cared . q{'}, + 'servicefile= takes precedence over PGSERVICEFILE', + sql => "SELECT 'connect8'", + expected_stdout => qr/connect8/); +} + $node->teardown_node; done_testing(); diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index b359fbff295b..f387f8910319 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -2248,6 +2248,19 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname </listitem> </varlistentry> + <varlistentry id="libpq-connect-servicefile" xreflabel="servicefile"> + <term><literal>servicefile</literal></term> + <listitem> + <para> + This option specifies the name of the per-user connection service file + (see <xref linkend="libpq-pgservice"/>). + Defaults to <filename>~/.pg_service.conf</filename>, or + <filename>%APPDATA%\postgresql\.pg_service.conf</filename> on + Microsoft Windows. + </para> + </listitem> + </varlistentry> + <varlistentry id="libpq-connect-target-session-attrs" xreflabel="target_session_attrs"> <term><literal>target_session_attrs</literal></term> <listitem> @@ -9504,7 +9517,8 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough) On Microsoft Windows, it is named <filename>%APPDATA%\postgresql\.pg_service.conf</filename> (where <filename>%APPDATA%</filename> refers to the Application Data subdirectory - in the user's profile). A different file name can be specified by + in the user's profile). A different file name can be specified using the + <literal>servicefile</literal> key word in a libpq connection string or by setting the environment variable <envar>PGSERVICEFILE</envar>. The system-wide file is named <filename>pg_service.conf</filename>. By default it is sought in the <filename>etc</filename> directory -- 2.49.0
signature.asc
Description: PGP signature