v5-0001-add-servicefile-connection-option-feature.patch
application/octet-stream
Filename: v5-0001-add-servicefile-connection-option-feature.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v5-0001
Subject: add servicefile connection option feature
| File | + | − |
|---|---|---|
| doc/src/sgml/libpq.sgml | 15 | 1 |
| src/interfaces/libpq/fe-connect.c | 24 | 3 |
| src/interfaces/libpq/t/006_service.pl | 96 | 0 |
From 65cdc2b918c0ca17a199c57f0d160a7b4b42d626 Mon Sep 17 00:00:00 2001
From: Ryo Kanbayashi <ryo.contact@gmail.com>
Date: Sat, 29 Mar 2025 20:53:33 +0900
Subject: [PATCH v5] add servicefile connection option feature
---
doc/src/sgml/libpq.sgml | 16 ++++-
src/interfaces/libpq/fe-connect.c | 27 +++++++-
src/interfaces/libpq/t/006_service.pl | 96 +++++++++++++++++++++++++++
3 files changed, 135 insertions(+), 4 deletions(-)
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index b359fbff29..f387f89103 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
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index d5051f5e82..f16468be7d 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 d3ecfa6b6f..3320f1b513 100644
--- a/src/interfaces/libpq/t/006_service.pl
+++ b/src/interfaces/libpq/t/006_service.pl
@@ -136,6 +136,102 @@ 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;
+
+# Checks combinations of service name and valid "servicefile" string.
+{
+ $node->connect_ok(
+ q{service=my_srv servicefile='} . $srvfile_win_cared . q{'},
+ 'connection with correct "service" string and correct "servicefile" string',
+ sql => "SELECT 'connect3_1'",
+ expected_stdout => qr/connect3_1/);
+
+ local $ENV{PGSERVICE} = 'my_srv';
+ $node->connect_ok(
+ q{servicefile='} . $srvfile_win_cared . q{'},
+ 'connection with correct PGSERVICE and collect "servicefile" string',
+ sql => "SELECT 'connect3_2'",
+ expected_stdout => qr/connect3_2/);
+
+ $node->connect_fails(
+ q{service=undefined-service servicefile='} . $srvfile_win_cared . q{'},
+ 'connection with incorrect "service" string and collect "servicefile" string',
+ expected_stderr =>
+ qr/definition of service "undefined-service" not found/);
+
+ local $ENV{PGSERVICE} = 'undefined-service';
+ $node->connect_fails(
+ q{servicefile='} . $srvfile_win_cared . q{'},
+ 'connection with incorrect PGSERVICE and collect "servicefile"',
+ expected_stderr =>
+ qr/definition of service "undefined-service" not found/);
+}
+
+# Checks combinations of service name and a valid "servicefile" string in URI format.
+{
+ # 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,
+ 'connection with correct "service" string and correct "servicefile" in URI format',
+ sql => "SELECT 'connect4_1'",
+ expected_stdout => qr/connect4_1/);
+
+ local $ENV{PGSERVICE} = 'my_srv';
+ $node->connect_ok(
+ 'postgresql://?servicefile=' . $encoded_srvfile,
+ 'connection with correct PGSERVICE and collect "servicefile" in URI format',
+ sql => "SELECT 'connect4_2'",
+ expected_stdout => qr/connect4_2/);
+
+ $node->connect_fails(
+ 'postgresql:///?service=undefined-service&servicefile=' . $encoded_srvfile,
+ 'connection with incorrect "service" string and collect "servicefile" in URI format',
+ expected_stderr =>
+ qr/definition of service "undefined-service" not found/);
+}
+
+# Checks case of incorrect "servicefile" string.
+{
+ # Backslashes escaped path string for getting collect result at concatenation
+ # for Windows environment
+ my $srvfile_missing_win_cared = $srvfile_missing;
+ $srvfile_missing_win_cared =~ s/\\/\\\\/g;
+
+ $node->connect_fails(
+ q{service=my_srv servicefile='} . $srvfile_missing_win_cared . q{'},
+ 'connection with correct "service" string and incorrect "servicefile" string',
+ sql => "SELECT 'connect5_1'",
+ expected_stderr =>
+ qr/service file ".*pg_service_missing.conf" not found/);
+}
+
+# Check that "servicefile" string takes precedence over PGSERVICEFILE environment variable
+{
+ local $ENV{PGSERVICEFILE} = $srvfile_missing;
+
+ $node->connect_fails(
+ 'service=my_srv',
+ 'connecttion with correct "service" string and incorrect PGSERVICEFILE',
+ expected_stderr =>
+ qr/service file ".*pg_service_missing.conf" not found/);
+
+ $node->connect_ok(
+ q{service=my_srv servicefile='} . $srvfile_win_cared . q{'},
+ 'connectin with correct "service" string, incorrect PGSERVICEFILE and correct "servicefile" string',
+ sql => "SELECT 'connect6_1'",
+ expected_stdout => qr/connect6_1/);
+}
+
$node->teardown_node;
done_testing();
--
2.25.1