@@ -81,6 +81,9 @@ static void makePackHTAB(Package *package, bool is_trans);
8181static inline ChangedObject * makeChangedObject (TransObject * object ,
8282 MemoryContext ctx );
8383
84+ /* Hook functions */
85+ static void variable_ExecutorEnd (QueryDesc * queryDesc );
86+
8487#define CHECK_ARGS_FOR_NULL () \
8588do { \
8689 if (fcinfo->argnull[0]) \
@@ -103,6 +106,16 @@ static Variable *LastVariable = NULL;
103106/* Recent row type id */
104107static Oid LastTypeId = InvalidOid ;
105108
109+ /*
110+ * Cache sequentially search through hash table status. It is necessary for
111+ * clean up if hash_seq_term() wasn't called or if we didn't scan the whole
112+ * table. In this case we need to manually call hash_seq_term() within
113+ * variable_ExecutorEnd().
114+ */
115+ static HASH_SEQ_STATUS * LastHSeqStatus = NULL ;
116+
117+ /* Saved hook values for recall */
118+ static ExecutorEnd_hook_type prev_ExecutorEnd = NULL ;
106119
107120/* This stack contains lists of changed variables and packages per each subxact level */
108121static dlist_head * changesStack = NULL ;
@@ -596,6 +609,8 @@ variable_select(PG_FUNCTION_ARGS)
596609 MemoryContextSwitchTo (oldcontext );
597610 PG_FREE_IF_COPY (package_name , 0 );
598611 PG_FREE_IF_COPY (var_name , 1 );
612+
613+ LastHSeqStatus = rstat ;
599614 }
600615
601616 funcctx = SRF_PERCALL_SETUP ();
@@ -613,6 +628,7 @@ variable_select(PG_FUNCTION_ARGS)
613628 }
614629 else
615630 {
631+ LastHSeqStatus = NULL ;
616632 pfree (rstat );
617633 SRF_RETURN_DONE (funcctx );
618634 }
@@ -1187,6 +1203,8 @@ get_packages_stats(PG_FUNCTION_ARGS)
11871203 hash_seq_init (pstat , packagesHash );
11881204
11891205 funcctx -> user_fctx = pstat ;
1206+
1207+ LastHSeqStatus = pstat ;
11901208 }
11911209 else
11921210 funcctx -> user_fctx = NULL ;
@@ -1232,6 +1250,7 @@ get_packages_stats(PG_FUNCTION_ARGS)
12321250 }
12331251 else
12341252 {
1253+ LastHSeqStatus = NULL ;
12351254 pfree (pstat );
12361255 SRF_RETURN_DONE (funcctx );
12371256 }
@@ -2093,6 +2112,23 @@ pgvTransCallback(XactEvent event, void *arg)
20932112 }
20942113}
20952114
2115+ /*
2116+ * ExecutorEnd hook: clean up hash table sequential scan status
2117+ */
2118+ static void
2119+ variable_ExecutorEnd (QueryDesc * queryDesc )
2120+ {
2121+ if (LastHSeqStatus )
2122+ {
2123+ hash_seq_term (LastHSeqStatus );
2124+ LastHSeqStatus = NULL ;
2125+ }
2126+ if (prev_ExecutorEnd )
2127+ prev_ExecutorEnd (queryDesc );
2128+ else
2129+ standard_ExecutorEnd (queryDesc );
2130+ }
2131+
20962132/*
20972133 * Register callback function when module starts
20982134 */
@@ -2101,6 +2137,10 @@ _PG_init(void)
21012137{
21022138 RegisterXactCallback (pgvTransCallback , NULL );
21032139 RegisterSubXactCallback (pgvSubTransCallback , NULL );
2140+
2141+ /* Install hooks. */
2142+ prev_ExecutorEnd = ExecutorEnd_hook ;
2143+ ExecutorEnd_hook = variable_ExecutorEnd ;
21042144}
21052145
21062146/*
@@ -2111,4 +2151,5 @@ _PG_fini(void)
21112151{
21122152 UnregisterXactCallback (pgvTransCallback , NULL );
21132153 UnregisterSubXactCallback (pgvSubTransCallback , NULL );
2154+ ExecutorEnd_hook = prev_ExecutorEnd ;
21142155}
0 commit comments