summaryrefslogtreecommitdiff
path: root/src/interfaces/libpq/fe-connect.c
diff options
context:
space:
mode:
authorMichael Paquier <michael@paquier.xyz>2025-07-13 16:52:19 +0900
committerMichael Paquier <michael@paquier.xyz>2025-07-13 16:52:19 +0900
commit092f3c63efc6a6ce235cfbed45bd05b739de8540 (patch)
treece37711db0465c3d5980bcb1184200dda1a59194 /src/interfaces/libpq/fe-connect.c
parent8893c3ab3661eb397e68a0ace17c680d1e488360 (diff)
libpq: Add "servicefile" connection option
This commit adds the possibility to specify a service file in a connection string, using a new option called "servicefile". The parsing of the service file happens so as things are done in this order of priority: - The servicefile connection option. - Environment variable PGSERVICEFILE. - Default path, depending on the HOME environment. Note that in the last default case, we need to fill in "servicefile" for the connection's PQconninfoOption to let clients know which service file has been used for the connection. Some TAP tests are added, with a few tweaks required for Windows when using URIs or connection option values, for the location paths. Author: Torsten Förtsch <tfoertsch123@gmail.com> Co-authored-by: Ryo Kanbayashi <kanbayashi.dev@gmail.com> Discussion: https://postgr.es/m/CAKkG4_nCjx3a_F3gyXHSPWxD8Sd8URaM89wey7fG_9g7KBkOCQ@mail.gmail.com
Diffstat (limited to 'src/interfaces/libpq/fe-connect.c')
-rw-r--r--src/interfaces/libpq/fe-connect.c54
1 files changed, 50 insertions, 4 deletions
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 09eb79812ac..2a2b10d5a29 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -201,6 +201,10 @@ static const internalPQconninfoOption PQconninfoOptions[] = {
"Database-Service", "", 20,
offsetof(struct pg_conn, pgservice)},
+ {"servicefile", "PGSERVICEFILE", NULL, NULL,
+ "Database-Service-File", "", 64,
+ offsetof(struct pg_conn, pgservicefile)},
+
{"user", "PGUSER", NULL, NULL,
"Database-User", "", 20,
offsetof(struct pg_conn, pguser)},
@@ -5062,6 +5066,7 @@ freePGconn(PGconn *conn)
free(conn->dbName);
free(conn->replication);
free(conn->pgservice);
+ free(conn->pgservicefile);
free(conn->pguser);
if (conn->pgpass)
{
@@ -5914,6 +5919,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;
@@ -5933,10 +5939,13 @@ parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage)
return 0;
/*
- * Try PGSERVICEFILE if specified, else try ~/.pg_service.conf (if that
- * exists).
+ * First, try the "servicefile" option in connection string. Then, try
+ * the 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
{
@@ -6092,7 +6101,17 @@ parseServiceFile(const char *serviceFile,
if (strcmp(key, "service") == 0)
{
libpq_append_error(errorMessage,
- "nested service specifications not supported in service file \"%s\", line %d",
+ "nested \"service\" specifications not supported in service file \"%s\", line %d",
+ serviceFile,
+ linenr);
+ result = 3;
+ 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;
@@ -6135,6 +6154,33 @@ parseServiceFile(const char *serviceFile,
}
exit:
+
+ /*
+ * If a service has been successfully found, set the "servicefile" option
+ * if not already set. This matters when we use a default service file or
+ * PGSERVICEFILE, where we want to be able track the value.
+ */
+ if (*group_found && result == 0)
+ {
+ for (i = 0; options[i].keyword; i++)
+ {
+ if (strcmp(options[i].keyword, "servicefile") != 0)
+ continue;
+
+ /* If value is already set, nothing to do */
+ if (options[i].val != NULL)
+ break;
+
+ options[i].val = strdup(serviceFile);
+ if (options[i].val == NULL)
+ {
+ libpq_append_error(errorMessage, "out of memory");
+ result = 3;
+ }
+ break;
+ }
+ }
+
fclose(f);
return result;