fdw_disconn_on_alter_objs.patch
text/x-patch
Filename: fdw_disconn_on_alter_objs.patch
Type: text/x-patch
Part: 0
Patch
Format: unified
| File | + | − |
|---|---|---|
| contrib/postgres_fdw/connection.c | 30 | 0 |
| contrib/postgres_fdw/postgres_fdw.c | 67 | 0 |
| contrib/postgres_fdw/postgres_fdw.h | 1 | 0 |
| src/backend/commands/foreigncmds.c | 3 | 0 |
diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c
index 189f290..3d1b4fa 100644
--- a/contrib/postgres_fdw/connection.c
+++ b/contrib/postgres_fdw/connection.c
@@ -47,6 +47,7 @@ typedef struct ConnCacheEntry
* one level of subxact open, etc */
bool have_prep_stmt; /* have we prepared any stmts in this xact? */
bool have_error; /* have any subxacts aborted in this xact? */
+ bool to_be_disconnected;
} ConnCacheEntry;
/*
@@ -137,6 +138,7 @@ GetConnection(UserMapping *user, bool will_prep_stmt)
entry->xact_depth = 0;
entry->have_prep_stmt = false;
entry->have_error = false;
+ entry->to_be_disconnected = false;
}
/*
@@ -145,6 +147,14 @@ GetConnection(UserMapping *user, bool will_prep_stmt)
* connection is actually used.
*/
+ if (entry->conn != NULL &&
+ entry->to_be_disconnected && entry->xact_depth == 0)
+ {
+ elog(LOG, "disconnected");
+ PQfinish(entry->conn);
+ entry->conn = NULL;
+ entry->to_be_disconnected = false;
+ }
/*
* If cache entry doesn't have a connection, we have to establish a new
* connection. (If connect_pg_server throws an error, the cache entry
@@ -270,6 +280,26 @@ connect_pg_server(ForeignServer *server, UserMapping *user)
return conn;
}
+void
+reserve_pg_disconnect(Oid umid)
+{
+ bool found;
+ ConnCacheEntry *entry;
+ ConnCacheKey key;
+
+ if (ConnectionHash == NULL)
+ return;
+
+ /* Find existing connectionentry */
+ key = umid;
+ entry = hash_search(ConnectionHash, &key, HASH_ENTER, &found);
+
+ if (!found || entry->conn == NULL)
+ return;
+
+ entry->to_be_disconnected = true;
+}
+
/*
* For non-superusers, insist that the connstr specify a password. This
* prevents a password from being picked up from .pgpass, a service file,
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 4fbbde1..7777875 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -16,6 +16,9 @@
#include "access/htup_details.h"
#include "access/sysattr.h"
+#include "catalog/pg_foreign_server.h"
+#include "catalog/pg_user_mapping.h"
+#include "catalog/objectaccess.h"
#include "commands/defrem.h"
#include "commands/explain.h"
#include "commands/vacuum.h"
@@ -33,7 +36,9 @@
#include "optimizer/tlist.h"
#include "parser/parsetree.h"
#include "utils/builtins.h"
+#include "utils/fmgroids.h"
#include "utils/guc.h"
+#include "utils/syscache.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
@@ -407,7 +412,16 @@ static List *get_useful_pathkeys_for_relation(PlannerInfo *root,
static List *get_useful_ecs_for_relation(PlannerInfo *root, RelOptInfo *rel);
static void add_paths_with_pathkeys_for_rel(PlannerInfo *root, RelOptInfo *rel,
Path *epq_path);
+static void postgresObjectAccessHook(ObjectAccessType access,
+ Oid classId,
+ Oid objectId,
+ int subId,
+ void *arg);
+
+static object_access_hook_type previous_object_access_hook;
+void _PG_init(void);
+void _PG_fini(void);
/*
* Foreign-data wrapper handler function: return a struct with pointers
@@ -460,6 +474,19 @@ postgres_fdw_handler(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(routine);
}
+void
+_PG_init(void)
+{
+ previous_object_access_hook = object_access_hook;
+ object_access_hook = postgresObjectAccessHook;
+}
+
+void
+_PG_fini(void)
+{
+ object_access_hook = previous_object_access_hook;
+}
+
/*
* postgresGetForeignRelSize
* Estimate # of rows and width of the result of the scan
@@ -4492,3 +4519,43 @@ find_em_expr_for_rel(EquivalenceClass *ec, RelOptInfo *rel)
/* We didn't find any suitable equivalence class expression */
return NULL;
}
+
+static void
+postgresObjectAccessHook(ObjectAccessType access,
+ Oid classId,
+ Oid objectId,
+ int subId,
+ void *arg)
+{
+ if (access == OAT_POST_ALTER)
+ {
+ if (classId == ForeignServerRelationId)
+ {
+ Relation umrel;
+ ScanKeyData skey;
+ SysScanDesc scan;
+ HeapTuple umtup;
+
+ umrel = heap_open(UserMappingRelationId, AccessShareLock);
+ ScanKeyInit(&skey,
+ Anum_pg_user_mapping_umserver,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(objectId));
+ scan = systable_beginscan(umrel, InvalidOid, false,
+ NULL, 1, &skey);
+ while(HeapTupleIsValid(umtup = systable_getnext(scan)))
+ reserve_pg_disconnect(HeapTupleGetOid(umtup));
+
+ systable_endscan(scan);
+ heap_close(umrel, AccessShareLock);
+ }
+ if (classId == UserMappingRelationId)
+ {
+ reserve_pg_disconnect(objectId);
+ }
+ }
+
+
+ if (previous_object_access_hook)
+ previous_object_access_hook(access, classId, objectId, subId, arg);
+}
diff --git a/contrib/postgres_fdw/postgres_fdw.h b/contrib/postgres_fdw/postgres_fdw.h
index 3a11d99..7e8ea31 100644
--- a/contrib/postgres_fdw/postgres_fdw.h
+++ b/contrib/postgres_fdw/postgres_fdw.h
@@ -100,6 +100,7 @@ extern void reset_transmission_modes(int nestlevel);
/* in connection.c */
extern PGconn *GetConnection(UserMapping *user, bool will_prep_stmt);
+extern void reserve_pg_disconnect(Oid umid);
extern void ReleaseConnection(PGconn *conn);
extern unsigned int GetCursorNumber(PGconn *conn);
extern unsigned int GetPrepStmtNumber(PGconn *conn);
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index 804bab2..ebae253 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -1312,6 +1312,9 @@ AlterUserMapping(AlterUserMappingStmt *stmt)
ObjectAddressSet(address, UserMappingRelationId, umId);
+ /* Post alter hook for new user mapping */
+ InvokeObjectPostAlterHook(UserMappingRelationId, umId, 0);
+
heap_freetuple(tp);
heap_close(rel, RowExclusiveLock);