00001_free_function_memory.patch
application/octet-stream
Filename: 00001_free_function_memory.patch
Type: application/octet-stream
Part: 0
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index f63b5ef420b..7604f1a0064 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -1301,6 +1301,7 @@ RemoveFunctionById(Oid funcOid)
Relation relation;
HeapTuple tup;
char prokind;
+ remove_function_plancache RemoveFunctionPlanCacheById;
/*
* Delete the pg_proc tuple.
@@ -1311,6 +1312,11 @@ RemoveFunctionById(Oid funcOid)
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for function %u", funcOid);
+ /* Try to release plancache */
+ RemoveFunctionPlanCacheById = (remove_function_plancache) *find_rendezvous_variable("RemoveFunctionPlanCacheById");
+ if (RemoveFunctionPlanCacheById != NULL)
+ RemoveFunctionPlanCacheById(funcOid);
+
prokind = ((Form_pg_proc) GETSTRUCT(tup))->prokind;
CatalogTupleDelete(relation, &tup->t_self);
diff --git a/src/include/utils/plancache.h b/src/include/utils/plancache.h
index a443181d416..a8e6388a330 100644
--- a/src/include/utils/plancache.h
+++ b/src/include/utils/plancache.h
@@ -233,4 +233,5 @@ extern bool CachedPlanIsSimplyValid(CachedPlanSource *plansource,
extern CachedExpression *GetCachedExpression(Node *expr);
extern void FreeCachedExpression(CachedExpression *cexpr);
+typedef void (*remove_function_plancache) (Oid funcoid);
#endif /* PLANCACHE_H */
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index a341cde2c14..12adcc37ef9 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -67,6 +67,23 @@ typedef struct plpgsql_hashent
PLpgSQL_function *function;
} plpgsql_HashEnt;
+/* ----------
+ * Hash table for recording funcOid and functions
+ * ----------
+ */
+static HTAB *plpgsql_funcOid_HashTable = NULL;
+
+typedef struct PLpgSQL_funcOid_hashkey
+{
+ Oid funcOid;
+} PLpgSQL_funcOid_hashkey;
+
+typedef struct plpgsql_function_hashent
+{
+ PLpgSQL_funcOid_hashkey key;
+ PLpgSQL_function *function;
+} plpgsql_function_hashent;
+
#define FUNCS_PER_USER 128 /* initial table size */
/* ----------
@@ -121,6 +138,9 @@ static void plpgsql_HashTableInsert(PLpgSQL_function *function,
PLpgSQL_func_hashkey *func_key);
static void plpgsql_HashTableDelete(PLpgSQL_function *function);
static void delete_function(PLpgSQL_function *func);
+static PLpgSQL_function *plpgsql_funcOid_HashTableLookup(PLpgSQL_funcOid_hashkey *func_key);
+static void plpgsql_funcOid_HashTableInsert(PLpgSQL_function *function);
+static void plpgsql_funcOid_HashTableDelete(PLpgSQL_funcOid_hashkey *func_key);
/* ----------
* plpgsql_compile Make an execution tree for a PL/pgSQL function.
@@ -223,6 +243,9 @@ recheck:
*/
function = do_compile(fcinfo, procTup, function,
&hashkey, forValidator);
+
+ /* Record the relationship between funcOid and function */
+ plpgsql_funcOid_HashTableInsert(function);
}
ReleaseSysCache(procTup);
@@ -2670,3 +2693,87 @@ plpgsql_HashTableDelete(PLpgSQL_function *function)
/* remove back link, which no longer points to allocated storage */
function->fn_hashkey = NULL;
}
+
+/* Try to delete and release the plan cache from the hash table */
+void
+RemoveFunctionPlanCacheById(Oid funcoid)
+{
+ PLpgSQL_funcOid_hashkey func_key;
+ PLpgSQL_function *function = NULL;
+
+ func_key.funcOid = funcoid;
+ function = plpgsql_funcOid_HashTableLookup(&func_key);
+ if (function)
+ {
+ plpgsql_funcOid_HashTableDelete(&func_key);
+ delete_function(function);
+ }
+}
+
+void
+plpgsql_funcOid_HashTableInit(void)
+{
+ HASHCTL ctl;
+
+ /* don't allow double-initialization */
+ Assert(plpgsql_funcOid_HashTable == NULL);
+
+ ctl.keysize = sizeof(PLpgSQL_funcOid_hashkey);
+ ctl.entrysize = sizeof(plpgsql_function_hashent);
+ plpgsql_funcOid_HashTable = hash_create("PLpgSQL function Oid hash",
+ FUNCS_PER_USER,
+ &ctl,
+ HASH_ELEM | HASH_BLOBS);
+}
+
+static PLpgSQL_function *
+plpgsql_funcOid_HashTableLookup(PLpgSQL_funcOid_hashkey *func_key)
+{
+ plpgsql_function_hashent *hentry;
+
+ hentry = (plpgsql_function_hashent *) hash_search(plpgsql_funcOid_HashTable,
+ func_key,
+ HASH_FIND,
+ NULL);
+ if (hentry)
+ return hentry->function;
+ else
+ return NULL;
+}
+
+static void
+plpgsql_funcOid_HashTableInsert(PLpgSQL_function *function)
+{
+ bool found;
+ plpgsql_function_hashent *hentry;
+ PLpgSQL_funcOid_hashkey func_key;
+ func_key.funcOid = function->fn_oid;
+
+ if (plpgsql_funcOid_HashTableLookup(&func_key))
+ return;
+
+ hentry = (plpgsql_function_hashent *) hash_search(plpgsql_funcOid_HashTable,
+ &func_key,
+ HASH_ENTER,
+ &found);
+
+ hentry->function = function;
+ hentry->key.funcOid = func_key.funcOid;
+}
+
+static void
+plpgsql_funcOid_HashTableDelete(PLpgSQL_funcOid_hashkey *func_key)
+{
+ plpgsql_function_hashent *hentry;
+
+ hentry = (plpgsql_function_hashent *) hash_search(plpgsql_funcOid_HashTable,
+ func_key,
+ HASH_REMOVE,
+ NULL);
+ if (hentry == NULL)
+ elog(WARNING, "trying to delete function that does not exist");
+
+ /* remove back link, which no longer points to allocated storage */
+ hentry->function = NULL;
+ hentry->key.funcOid = InvalidOid;
+}
\ No newline at end of file
diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c
index d8994538b76..7edbf974979 100644
--- a/src/pl/plpgsql/src/pl_handler.c
+++ b/src/pl/plpgsql/src/pl_handler.c
@@ -146,6 +146,7 @@ _PG_init(void)
{
/* Be sure we do initialization only once (should be redundant now) */
static bool inited = false;
+ remove_function_plancache *remove_function_plancache_ptr;
if (inited)
return;
@@ -203,6 +204,10 @@ _PG_init(void)
RegisterXactCallback(plpgsql_xact_cb, NULL);
RegisterSubXactCallback(plpgsql_subxact_cb, NULL);
+ plpgsql_funcOid_HashTableInit();
+ remove_function_plancache_ptr = (remove_function_plancache *) find_rendezvous_variable("RemoveFunctionPlanCacheById");
+ *remove_function_plancache_ptr = &RemoveFunctionPlanCacheById;
+
/* Set up a rendezvous point with optional instrumentation plugin */
plpgsql_plugin_ptr = (PLpgSQL_plugin **) find_rendezvous_variable("PLpgSQL_plugin");
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index cead9eb7263..3ce25635009 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -1263,6 +1263,8 @@ extern PLpgSQL_condition *plpgsql_parse_err_condition(char *condname);
extern void plpgsql_adddatum(PLpgSQL_datum *newdatum);
extern int plpgsql_add_initdatums(int **varnos);
extern void plpgsql_HashTableInit(void);
+extern void plpgsql_funcOid_HashTableInit(void);
+extern void RemoveFunctionPlanCacheById(Oid funcoid);
/*
* Functions in pl_exec.c