Skip to content

Commit 27a8dbd

Browse files
ryogridCommitfest Bot
authored and
Commitfest Bot
committed
add servicefile connection option feature
1 parent 0ff95e0 commit 27a8dbd

File tree

3 files changed

+103
-5
lines changed

3 files changed

+103
-5
lines changed

doc/src/sgml/libpq.sgml

+15-1
Original file line numberDiff line numberDiff line change
@@ -2320,6 +2320,19 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
23202320
</listitem>
23212321
</varlistentry>
23222322

2323+
<varlistentry id="libpq-connect-servicefile" xreflabel="servicefile">
2324+
<term><literal>servicefile</literal></term>
2325+
<listitem>
2326+
<para>
2327+
This option specifies the name of the per-user connection service file
2328+
(see <xref linkend="libpq-pgservice"/>).
2329+
Defaults to <filename>~/.pg_service.conf</filename>, or
2330+
<filename>%APPDATA%\postgresql\.pg_service.conf</filename> on
2331+
Microsoft Windows.
2332+
</para>
2333+
</listitem>
2334+
</varlistentry>
2335+
23232336
<varlistentry id="libpq-connect-target-session-attrs" xreflabel="target_session_attrs">
23242337
<term><literal>target_session_attrs</literal></term>
23252338
<listitem>
@@ -9596,7 +9609,8 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
95969609
On Microsoft Windows, it is named
95979610
<filename>%APPDATA%\postgresql\.pg_service.conf</filename> (where
95989611
<filename>%APPDATA%</filename> refers to the Application Data subdirectory
9599-
in the user's profile). A different file name can be specified by
9612+
in the user's profile). A different file name can be specified using the
9613+
<literal>servicefile</literal> key word in a libpq connection string or by
96009614
setting the environment variable <envar>PGSERVICEFILE</envar>.
96019615
The system-wide file is named <filename>pg_service.conf</filename>.
96029616
By default it is sought in the <filename>etc</filename> directory

src/interfaces/libpq/fe-connect.c

+24-3
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,9 @@ static const internalPQconninfoOption PQconninfoOptions[] = {
195195
"Database-Service", "", 20,
196196
offsetof(struct pg_conn, pgservice)},
197197

198+
{"servicefile", "PGSERVICEFILE", NULL, NULL,
199+
"Database-Service-File", "", 64, -1},
200+
198201
{"user", "PGUSER", NULL, NULL,
199202
"Database-User", "", 20,
200203
offsetof(struct pg_conn, pguser)},
@@ -5904,6 +5907,7 @@ static int
59045907
parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage)
59055908
{
59065909
const char *service = conninfo_getval(options, "service");
5910+
const char *service_fname = conninfo_getval(options, "servicefile");
59075911
char serviceFile[MAXPGPATH];
59085912
char *env;
59095913
bool group_found = false;
@@ -5923,11 +5927,18 @@ parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage)
59235927
return 0;
59245928

59255929
/*
5926-
* Try PGSERVICEFILE if specified, else try ~/.pg_service.conf (if that
5927-
* exists).
5930+
* First, check servicefile option on connection string. Second, check
5931+
* PGSERVICEFILE environment variable. Finally, check ~/.pg_service.conf
5932+
* (if that exists).
59285933
*/
5929-
if ((env = getenv("PGSERVICEFILE")) != NULL)
5934+
if (service_fname != NULL)
5935+
{
5936+
strlcpy(serviceFile, service_fname, sizeof(serviceFile));
5937+
}
5938+
else if ((env = getenv("PGSERVICEFILE")) != NULL)
5939+
{
59305940
strlcpy(serviceFile, env, sizeof(serviceFile));
5941+
}
59315942
else
59325943
{
59335944
char homedir[MAXPGPATH];
@@ -6089,6 +6100,16 @@ parseServiceFile(const char *serviceFile,
60896100
goto exit;
60906101
}
60916102

6103+
if (strcmp(key, "servicefile") == 0)
6104+
{
6105+
libpq_append_error(errorMessage,
6106+
"nested servicefile specifications not supported in service file \"%s\", line %d",
6107+
serviceFile,
6108+
linenr);
6109+
result = 3;
6110+
goto exit;
6111+
}
6112+
60926113
/*
60936114
* Set the parameter --- but don't override any previous
60946115
* explicit setting.

src/interfaces/libpq/t/006_service.pl

+64-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use Test::More;
88

99
# This tests scenarios related to the service name and the service file,
10-
# for the connection options and their environment variables.
10+
# for the connection options, servicefile options and their environment variables.
1111

1212
my $node = PostgreSQL::Test::Cluster->new('node');
1313
$node->init;
@@ -146,6 +146,69 @@
146146
unlink($srvfile_default);
147147
}
148148

149+
# Backslashes escaped path string for getting collect result at concatenation
150+
# for Windows environment
151+
my $srvfile_win_cared = $srvfile_valid;
152+
$srvfile_win_cared =~ s/\\/\\\\/g;
153+
154+
# Check that servicefile option works as expected
155+
{
156+
$dummy_node->connect_ok(
157+
q{service=my_srv servicefile='} . $srvfile_win_cared . q{'},
158+
'service=my_srv servicefile=...',
159+
sql => "SELECT 'connect3'",
160+
expected_stdout => qr/connect3/
161+
);
162+
163+
# Encode slashes and backslash
164+
my $encoded_srvfile = $srvfile_valid =~ s{([\\/])}{
165+
$1 eq '/' ? '%2F' : '%5C'
166+
}ger;
167+
168+
# Additionaly encode a colon in servicefile path of Windows
169+
$encoded_srvfile =~ s/:/%3A/g;
170+
171+
$dummy_node->connect_ok(
172+
'postgresql:///?service=my_srv&servicefile=' . $encoded_srvfile,
173+
'postgresql:///?service=my_srv&servicefile=...',
174+
sql => "SELECT 'connect4'",
175+
expected_stdout => qr/connect4/
176+
);
177+
178+
local $ENV{PGSERVICE} = 'my_srv';
179+
$dummy_node->connect_ok(
180+
q{servicefile='} . $srvfile_win_cared . q{'},
181+
'envvar: PGSERVICE=my_srv + servicefile=...',
182+
sql => "SELECT 'connect5'",
183+
expected_stdout => qr/connect5/
184+
);
185+
186+
$dummy_node->connect_ok(
187+
'postgresql://?servicefile=' . $encoded_srvfile,
188+
'envvar: PGSERVICE=my_srv + postgresql://?servicefile=...',
189+
sql => "SELECT 'connect6'",
190+
expected_stdout => qr/connect6/
191+
);
192+
}
193+
194+
# Check that servicefile option takes precedence over PGSERVICEFILE environment variable
195+
{
196+
local $ENV{PGSERVICEFILE} = 'non-existent-file.conf';
197+
198+
$dummy_node->connect_fails(
199+
'service=my_srv',
200+
'service=... fails with wrong PGSERVICEFILE',
201+
expected_stderr => qr/service file "non-existent-file\.conf" not found/
202+
);
203+
204+
$dummy_node->connect_ok(
205+
q{service=my_srv servicefile='} . $srvfile_win_cared . q{'},
206+
'servicefile= takes precedence over PGSERVICEFILE',
207+
sql => "SELECT 'connect7'",
208+
expected_stdout => qr/connect7/
209+
);
210+
}
211+
149212
$node->teardown_node;
150213

151214
done_testing();

0 commit comments

Comments
 (0)