mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Add support for using SQL/MED compliant FOREIGN DATA WRAPPER, SERVER,
and USER MAPPING as method to supply dblink connect parameters. Per mailing list and PGCon discussions.
This commit is contained in:
@ -8,7 +8,7 @@
|
||||
* Darko Prenosil <Darko.Prenosil@finteh.hr>
|
||||
* Shridhar Daithankar <shridhar_daithankar@persistent.co.in>
|
||||
*
|
||||
* $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.78 2009/06/02 03:21:56 joe Exp $
|
||||
* $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.79 2009/06/06 21:27:56 joe Exp $
|
||||
* Copyright (c) 2001-2009, PostgreSQL Global Development Group
|
||||
* ALL RIGHTS RESERVED;
|
||||
*
|
||||
@ -46,6 +46,7 @@
|
||||
#include "catalog/pg_type.h"
|
||||
#include "executor/executor.h"
|
||||
#include "executor/spi.h"
|
||||
#include "foreign/foreign.h"
|
||||
#include "lib/stringinfo.h"
|
||||
#include "miscadmin.h"
|
||||
#include "nodes/execnodes.h"
|
||||
@ -96,6 +97,8 @@ static char *generate_relation_name(Oid relid);
|
||||
static void dblink_connstr_check(const char *connstr);
|
||||
static void dblink_security_check(PGconn *conn, remoteConn *rconn);
|
||||
static void dblink_res_error(const char *conname, PGresult *res, const char *dblink_context_msg, bool fail);
|
||||
static char *get_connect_string(const char *servername);
|
||||
static char *escape_param_str(const char *from);
|
||||
|
||||
/* Global */
|
||||
static remoteConn *pconn = NULL;
|
||||
@ -165,7 +168,11 @@ typedef struct remoteConnHashEnt
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
connstr = conname_or_str; \
|
||||
connstr = get_connect_string(conname_or_str); \
|
||||
if (connstr == NULL) \
|
||||
{ \
|
||||
connstr = conname_or_str; \
|
||||
} \
|
||||
dblink_connstr_check(connstr); \
|
||||
conn = PQconnectdb(connstr); \
|
||||
if (PQstatus(conn) == CONNECTION_BAD) \
|
||||
@ -210,6 +217,7 @@ PG_FUNCTION_INFO_V1(dblink_connect);
|
||||
Datum
|
||||
dblink_connect(PG_FUNCTION_ARGS)
|
||||
{
|
||||
char *conname_or_str = NULL;
|
||||
char *connstr = NULL;
|
||||
char *connname = NULL;
|
||||
char *msg;
|
||||
@ -220,16 +228,21 @@ dblink_connect(PG_FUNCTION_ARGS)
|
||||
|
||||
if (PG_NARGS() == 2)
|
||||
{
|
||||
connstr = text_to_cstring(PG_GETARG_TEXT_PP(1));
|
||||
conname_or_str = text_to_cstring(PG_GETARG_TEXT_PP(1));
|
||||
connname = text_to_cstring(PG_GETARG_TEXT_PP(0));
|
||||
}
|
||||
else if (PG_NARGS() == 1)
|
||||
connstr = text_to_cstring(PG_GETARG_TEXT_PP(0));
|
||||
conname_or_str = text_to_cstring(PG_GETARG_TEXT_PP(0));
|
||||
|
||||
if (connname)
|
||||
rconn = (remoteConn *) MemoryContextAlloc(TopMemoryContext,
|
||||
sizeof(remoteConn));
|
||||
|
||||
/* first check for valid foreign data server */
|
||||
connstr = get_connect_string(conname_or_str);
|
||||
if (connstr == NULL)
|
||||
connstr = conname_or_str;
|
||||
|
||||
/* check password in connection string if not superuser */
|
||||
dblink_connstr_check(connstr);
|
||||
conn = PQconnectdb(connstr);
|
||||
@ -2353,3 +2366,86 @@ dblink_res_error(const char *conname, PGresult *res, const char *dblink_context_
|
||||
errcontext("Error occurred on dblink connection named \"%s\": %s.",
|
||||
dblink_context_conname, dblink_context_msg)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Obtain connection string for a foreign server
|
||||
*/
|
||||
static char *
|
||||
get_connect_string(const char *servername)
|
||||
{
|
||||
ForeignServer *foreign_server = NULL;
|
||||
UserMapping *user_mapping;
|
||||
ListCell *cell;
|
||||
StringInfo buf = makeStringInfo();
|
||||
ForeignDataWrapper *fdw;
|
||||
AclResult aclresult;
|
||||
|
||||
/* first gather the server connstr options */
|
||||
if (strlen(servername) < NAMEDATALEN)
|
||||
foreign_server = GetForeignServerByName(servername, 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 = pg_foreign_server_aclcheck(serverid, userid, ACL_USAGE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_FOREIGN_SERVER, foreign_server->servername);
|
||||
|
||||
foreach (cell, fdw->options)
|
||||
{
|
||||
DefElem *def = lfirst(cell);
|
||||
|
||||
appendStringInfo(buf, "%s='%s' ", def->defname,
|
||||
escape_param_str(strVal(def->arg)));
|
||||
}
|
||||
|
||||
foreach (cell, foreign_server->options)
|
||||
{
|
||||
DefElem *def = lfirst(cell);
|
||||
|
||||
appendStringInfo(buf, "%s='%s' ", def->defname,
|
||||
escape_param_str(strVal(def->arg)));
|
||||
}
|
||||
|
||||
foreach (cell, user_mapping->options)
|
||||
{
|
||||
|
||||
DefElem *def = lfirst(cell);
|
||||
|
||||
appendStringInfo(buf, "%s='%s' ", def->defname,
|
||||
escape_param_str(strVal(def->arg)));
|
||||
}
|
||||
|
||||
return buf->data;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Escaping libpq connect parameter strings.
|
||||
*
|
||||
* Replaces "'" with "\'" and "\" with "\\".
|
||||
*/
|
||||
static char *
|
||||
escape_param_str(const char *str)
|
||||
{
|
||||
const char *cp;
|
||||
StringInfo buf = makeStringInfo();
|
||||
|
||||
for (cp = str; *cp; cp++)
|
||||
{
|
||||
if (*cp == '\\' || *cp == '\'')
|
||||
appendStringInfoChar(buf, '\\');
|
||||
appendStringInfoChar(buf, *cp);
|
||||
}
|
||||
|
||||
return buf->data;
|
||||
}
|
||||
|
Reference in New Issue
Block a user