@@ -81,6 +81,9 @@ static void makePackHTAB(Package *package, bool is_trans);
81
81
static inline ChangedObject * makeChangedObject (TransObject * object ,
82
82
MemoryContext ctx );
83
83
84
+ /* Hook functions */
85
+ static void variable_ExecutorEnd (QueryDesc * queryDesc );
86
+
84
87
#define CHECK_ARGS_FOR_NULL () \
85
88
do { \
86
89
if (fcinfo->argnull[0]) \
@@ -103,6 +106,16 @@ static Variable *LastVariable = NULL;
103
106
/* Recent row type id */
104
107
static Oid LastTypeId = InvalidOid ;
105
108
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 ;
106
119
107
120
/* This stack contains lists of changed variables and packages per each subxact level */
108
121
static dlist_head * changesStack = NULL ;
@@ -596,6 +609,8 @@ variable_select(PG_FUNCTION_ARGS)
596
609
MemoryContextSwitchTo (oldcontext );
597
610
PG_FREE_IF_COPY (package_name , 0 );
598
611
PG_FREE_IF_COPY (var_name , 1 );
612
+
613
+ LastHSeqStatus = rstat ;
599
614
}
600
615
601
616
funcctx = SRF_PERCALL_SETUP ();
@@ -613,6 +628,7 @@ variable_select(PG_FUNCTION_ARGS)
613
628
}
614
629
else
615
630
{
631
+ LastHSeqStatus = NULL ;
616
632
pfree (rstat );
617
633
SRF_RETURN_DONE (funcctx );
618
634
}
@@ -1187,6 +1203,8 @@ get_packages_stats(PG_FUNCTION_ARGS)
1187
1203
hash_seq_init (pstat , packagesHash );
1188
1204
1189
1205
funcctx -> user_fctx = pstat ;
1206
+
1207
+ LastHSeqStatus = pstat ;
1190
1208
}
1191
1209
else
1192
1210
funcctx -> user_fctx = NULL ;
@@ -1232,6 +1250,7 @@ get_packages_stats(PG_FUNCTION_ARGS)
1232
1250
}
1233
1251
else
1234
1252
{
1253
+ LastHSeqStatus = NULL ;
1235
1254
pfree (pstat );
1236
1255
SRF_RETURN_DONE (funcctx );
1237
1256
}
@@ -2093,6 +2112,23 @@ pgvTransCallback(XactEvent event, void *arg)
2093
2112
}
2094
2113
}
2095
2114
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
+
2096
2132
/*
2097
2133
* Register callback function when module starts
2098
2134
*/
@@ -2101,6 +2137,10 @@ _PG_init(void)
2101
2137
{
2102
2138
RegisterXactCallback (pgvTransCallback , NULL );
2103
2139
RegisterSubXactCallback (pgvSubTransCallback , NULL );
2140
+
2141
+ /* Install hooks. */
2142
+ prev_ExecutorEnd = ExecutorEnd_hook ;
2143
+ ExecutorEnd_hook = variable_ExecutorEnd ;
2104
2144
}
2105
2145
2106
2146
/*
@@ -2111,4 +2151,5 @@ _PG_fini(void)
2111
2151
{
2112
2152
UnregisterXactCallback (pgvTransCallback , NULL );
2113
2153
UnregisterSubXactCallback (pgvSubTransCallback , NULL );
2154
+ ExecutorEnd_hook = prev_ExecutorEnd ;
2114
2155
}
0 commit comments