v17-0002-dblink-support-foreign-data-wrapper-CONNECTION-c.patch
text/x-patch
Filename: v17-0002-dblink-support-foreign-data-wrapper-CONNECTION-c.patch
Type: text/x-patch
Part: 1
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 v17-0002
Subject: dblink: support foreign data wrapper CONNECTION clause.
| File | + | − |
|---|---|---|
| contrib/dblink/dblink--1.2--1.3.sql | 12 | 0 |
| contrib/dblink/dblink--1.3.sql | 9 | 2 |
| contrib/dblink/dblink.c | 84 | 79 |
| contrib/dblink/dblink.control | 1 | 1 |
| contrib/dblink/Makefile | 1 | 1 |
| contrib/dblink/meson.build | 2 | 1 |
From a778d1fd8a6dca1737770043321f7ebc17cec811 Mon Sep 17 00:00:00 2001
From: Jeff Davis <jeff@j-davis.com>
Date: Thu, 26 Feb 2026 10:42:08 -0800
Subject: [PATCH v17 2/2] dblink: support foreign data wrapper CONNECTION
clause.
---
contrib/dblink/Makefile | 2 +-
contrib/dblink/dblink--1.2--1.3.sql | 12 ++
.../{dblink--1.2.sql => dblink--1.3.sql} | 11 +-
contrib/dblink/dblink.c | 163 +++++++++---------
contrib/dblink/dblink.control | 2 +-
contrib/dblink/meson.build | 3 +-
6 files changed, 109 insertions(+), 84 deletions(-)
create mode 100644 contrib/dblink/dblink--1.2--1.3.sql
rename contrib/dblink/{dblink--1.2.sql => dblink--1.3.sql} (96%)
diff --git a/contrib/dblink/Makefile b/contrib/dblink/Makefile
index fde0b49ddbb..caa76c9cb27 100644
--- a/contrib/dblink/Makefile
+++ b/contrib/dblink/Makefile
@@ -8,7 +8,7 @@ PG_CPPFLAGS = -I$(libpq_srcdir)
SHLIB_LINK_INTERNAL = $(libpq)
EXTENSION = dblink
-DATA = dblink--1.2.sql dblink--1.1--1.2.sql dblink--1.0--1.1.sql
+DATA = dblink--1.3.sql dblink--1.2--1.3.sql dblink--1.1--1.2.sql dblink--1.0--1.1.sql
PGFILEDESC = "dblink - connect to other PostgreSQL databases"
REGRESS = dblink
diff --git a/contrib/dblink/dblink--1.2--1.3.sql b/contrib/dblink/dblink--1.2--1.3.sql
new file mode 100644
index 00000000000..77928a9e656
--- /dev/null
+++ b/contrib/dblink/dblink--1.2--1.3.sql
@@ -0,0 +1,12 @@
+/* contrib/dblink/dblink--1.2--1.3.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION dblink UPDATE TO '1.3'" to load this file. \quit
+
+-- takes internal parameter to prevent calling from SQL
+CREATE FUNCTION dblink_fdw_connection(oid, oid, internal)
+RETURNS text
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+ALTER FOREIGN DATA WRAPPER dblink_fdw CONNECTION dblink_fdw_connection;
diff --git a/contrib/dblink/dblink--1.2.sql b/contrib/dblink/dblink--1.3.sql
similarity index 96%
rename from contrib/dblink/dblink--1.2.sql
rename to contrib/dblink/dblink--1.3.sql
index 405eccb0ff9..22e4ea2061e 100644
--- a/contrib/dblink/dblink--1.2.sql
+++ b/contrib/dblink/dblink--1.3.sql
@@ -1,4 +1,4 @@
-/* contrib/dblink/dblink--1.2.sql */
+/* contrib/dblink/dblink--1.3.sql */
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION dblink" to load this file. \quit
@@ -232,4 +232,11 @@ RETURNS void
AS 'MODULE_PATHNAME', 'dblink_fdw_validator'
LANGUAGE C STRICT PARALLEL SAFE;
-CREATE FOREIGN DATA WRAPPER dblink_fdw VALIDATOR dblink_fdw_validator;
+-- takes internal parameter to prevent calling from SQL
+CREATE FUNCTION dblink_fdw_connection(oid, oid, internal)
+RETURNS text
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FOREIGN DATA WRAPPER dblink_fdw VALIDATOR dblink_fdw_validator
+ CONNECTION dblink_fdw_connection;
diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 2498d80c8e7..3a4b307ff64 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1993,6 +1993,87 @@ dblink_fdw_validator(PG_FUNCTION_ARGS)
PG_RETURN_VOID();
}
+/*
+ * Implement FDW CONNECTION clause.
+ */
+PG_FUNCTION_INFO_V1(dblink_fdw_connection);
+Datum
+dblink_fdw_connection(PG_FUNCTION_ARGS)
+{
+ Oid userid = PG_GETARG_OID(0);
+ Oid serverid = PG_GETARG_OID(1);
+ ForeignServer *foreign_server = GetForeignServer(serverid);
+ UserMapping *user_mapping = GetUserMapping(userid, serverid);
+ ForeignDataWrapper *fdw = GetForeignDataWrapper(foreign_server->fdwid);
+ AclResult aclresult;
+ ListCell *cell;
+ StringInfoData buf;
+
+ static const PQconninfoOption *options = NULL;
+
+ initStringInfo(&buf);
+
+ /*
+ * Get list of valid libpq options.
+ *
+ * To avoid unnecessary work, we get the list once and use it throughout
+ * the lifetime of this backend process. We don't need to care about
+ * memory context issues, because PQconndefaults allocates with malloc.
+ */
+ if (!options)
+ {
+ options = PQconndefaults();
+ if (!options) /* assume reason for failure is OOM */
+ ereport(ERROR,
+ (errcode(ERRCODE_FDW_OUT_OF_MEMORY),
+ errmsg("out of memory"),
+ errdetail("Could not get libpq's default connection options.")));
+ }
+
+ /* Check permissions, user must have usage on the server. */
+ aclresult = object_aclcheck(ForeignServerRelationId, serverid, userid, ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, OBJECT_FOREIGN_SERVER, foreign_server->servername);
+
+ /*
+ * First append hardcoded options needed for SCRAM pass-through, so if the
+ * user overwrites these options we can ereport on dblink_connstr_check
+ * and dblink_security_check.
+ */
+ if (MyProcPort != NULL && MyProcPort->has_scram_keys && UseScramPassthrough(foreign_server, user_mapping))
+ appendSCRAMKeysInfo(&buf);
+
+ foreach(cell, fdw->options)
+ {
+ DefElem *def = lfirst(cell);
+
+ if (is_valid_dblink_option(options, def->defname, ForeignDataWrapperRelationId))
+ appendStringInfo(&buf, "%s='%s' ", def->defname,
+ escape_param_str(strVal(def->arg)));
+ }
+
+ foreach(cell, foreign_server->options)
+ {
+ DefElem *def = lfirst(cell);
+
+ if (is_valid_dblink_option(options, def->defname, ForeignServerRelationId))
+ appendStringInfo(&buf, "%s='%s' ", def->defname,
+ escape_param_str(strVal(def->arg)));
+ }
+
+ foreach(cell, user_mapping->options)
+ {
+
+ DefElem *def = lfirst(cell);
+
+ if (is_valid_dblink_option(options, def->defname, UserMappingRelationId))
+ appendStringInfo(&buf, "%s='%s' ", def->defname,
+ escape_param_str(strVal(def->arg)));
+ }
+
+ PG_RETURN_TEXT_P(cstring_to_text(buf.data));
+}
+
/*************************************************************
* internal functions
@@ -2855,93 +2936,17 @@ static char *
get_connect_string(const char *servername)
{
ForeignServer *foreign_server = NULL;
- UserMapping *user_mapping;
- ListCell *cell;
- StringInfoData buf;
- ForeignDataWrapper *fdw;
- AclResult aclresult;
char *srvname;
- static const PQconninfoOption *options = NULL;
-
- initStringInfo(&buf);
-
- /*
- * Get list of valid libpq options.
- *
- * To avoid unnecessary work, we get the list once and use it throughout
- * the lifetime of this backend process. We don't need to care about
- * memory context issues, because PQconndefaults allocates with malloc.
- */
- if (!options)
- {
- options = PQconndefaults();
- if (!options) /* assume reason for failure is OOM */
- ereport(ERROR,
- (errcode(ERRCODE_FDW_OUT_OF_MEMORY),
- errmsg("out of memory"),
- errdetail("Could not get libpq's default connection options.")));
- }
-
/* first gather the server connstr options */
srvname = pstrdup(servername);
truncate_identifier(srvname, strlen(srvname), false);
foreign_server = GetForeignServerByName(srvname, true);
- if (foreign_server)
- {
- Oid serverid = foreign_server->serverid;
- Oid fdwid = foreign_server->fdwid;
- Oid userid = GetUserId();
-
- user_mapping = GetUserMapping(userid, serverid);
- fdw = GetForeignDataWrapper(fdwid);
-
- /* Check permissions, user must have usage on the server. */
- aclresult = object_aclcheck(ForeignServerRelationId, serverid, userid, ACL_USAGE);
- if (aclresult != ACLCHECK_OK)
- aclcheck_error(aclresult, OBJECT_FOREIGN_SERVER, foreign_server->servername);
-
- /*
- * First append hardcoded options needed for SCRAM pass-through, so if
- * the user overwrites these options we can ereport on
- * dblink_connstr_check and dblink_security_check.
- */
- if (MyProcPort != NULL && MyProcPort->has_scram_keys && UseScramPassthrough(foreign_server, user_mapping))
- appendSCRAMKeysInfo(&buf);
-
- foreach(cell, fdw->options)
- {
- DefElem *def = lfirst(cell);
-
- if (is_valid_dblink_option(options, def->defname, ForeignDataWrapperRelationId))
- appendStringInfo(&buf, "%s='%s' ", def->defname,
- escape_param_str(strVal(def->arg)));
- }
-
- foreach(cell, foreign_server->options)
- {
- DefElem *def = lfirst(cell);
-
- if (is_valid_dblink_option(options, def->defname, ForeignServerRelationId))
- appendStringInfo(&buf, "%s='%s' ", def->defname,
- escape_param_str(strVal(def->arg)));
- }
-
- foreach(cell, user_mapping->options)
- {
-
- DefElem *def = lfirst(cell);
-
- if (is_valid_dblink_option(options, def->defname, UserMappingRelationId))
- appendStringInfo(&buf, "%s='%s' ", def->defname,
- escape_param_str(strVal(def->arg)));
- }
-
- return buf.data;
- }
- else
+ if (!foreign_server)
return NULL;
+
+ return ForeignServerConnectionString(GetUserId(), foreign_server->serverid);
}
/*
diff --git a/contrib/dblink/dblink.control b/contrib/dblink/dblink.control
index bdd17d28a4b..816d19f4483 100644
--- a/contrib/dblink/dblink.control
+++ b/contrib/dblink/dblink.control
@@ -1,5 +1,5 @@
# dblink extension
comment = 'connect to other PostgreSQL databases from within a database'
-default_version = '1.2'
+default_version = '1.3'
module_pathname = '$libdir/dblink'
relocatable = true
diff --git a/contrib/dblink/meson.build b/contrib/dblink/meson.build
index e2489f41229..fc91b4a918d 100644
--- a/contrib/dblink/meson.build
+++ b/contrib/dblink/meson.build
@@ -22,7 +22,8 @@ install_data(
'dblink.control',
'dblink--1.0--1.1.sql',
'dblink--1.1--1.2.sql',
- 'dblink--1.2.sql',
+ 'dblink--1.2--1.3.sql',
+ 'dblink--1.3.sql',
kwargs: contrib_data_args,
)
--
2.43.0