Skip to content

Commit a0d2553

Browse files
committed
fix: clear DBMS_OUTPUT buffer on DISCARD ALL/PACKAGES
Use ProcessUtility_hook to intercept DISCARD ALL/PACKAGES commands and reset DBMS_OUTPUT buffer state. This prevents session state leakage in connection pooling environments like PgBouncer. All changes confined to contrib/ivorysql_ora - no backend modifications.
1 parent 406fd47 commit a0d2553

File tree

2 files changed

+78
-0
lines changed

2 files changed

+78
-0
lines changed

contrib/ivorysql_ora/src/builtin_packages/dbms_output/dbms_output.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,3 +625,17 @@ ora_dbms_output_get_lines(PG_FUNCTION_ARGS)
625625
tuple = heap_form_tuple(tupdesc, values, nulls);
626626
PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
627627
}
628+
629+
/*
630+
* ora_dbms_output_reset
631+
*
632+
* Reset DBMS_OUTPUT buffer state. Called by DISCARD ALL/PACKAGES
633+
* to ensure session state is properly cleared, which is important
634+
* for connection pooling environments (e.g., PgBouncer).
635+
*/
636+
void
637+
ora_dbms_output_reset(void)
638+
{
639+
if (output_buffer != NULL)
640+
cleanup_output_buffer();
641+
}

contrib/ivorysql_ora/src/ivorysql_ora.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@
3131
#include "access/heapam.h"
3232
#include "fmgr.h"
3333
#include "miscadmin.h"
34+
#include "nodes/parsenodes.h"
3435
#include "parser/parse_oper.h"
3536
#include "parser/parse_merge.h"
37+
#include "tcop/utility.h"
3638

3739
/* Begin - ReqID:SRS-SQL-XML */
3840
#include "executor/execExpr.h"
@@ -41,6 +43,9 @@
4143
#include "include/guc.h"
4244
#include "include/ivorysql_ora.h"
4345

46+
/* DBMS_OUTPUT reset function from builtin_packages/dbms_output/dbms_output.c */
47+
extern void ora_dbms_output_reset(void);
48+
4449

4550
/* Only include it once in any C file */
4651
PG_MODULE_MAGIC_EXT(
@@ -60,6 +65,19 @@ static transform_merge_stmt_hook_type pre_transform_merge_stmt_hook = NULL;
6065
static ora_updatexml_hook_type pre_ora_updatexml_hook = NULL;
6166
/* End - ReqID:SRS-SQL-XML */
6267

68+
/* ProcessUtility hook for DISCARD ALL/PACKAGES handling */
69+
static ProcessUtility_hook_type prev_ProcessUtility_hook = NULL;
70+
71+
/* Forward declaration */
72+
static void ivorysql_ora_ProcessUtility(PlannedStmt *pstmt,
73+
const char *queryString,
74+
bool readOnlyTree,
75+
ProcessUtilityContext context,
76+
ParamListInfo params,
77+
QueryEnvironment *queryEnv,
78+
DestReceiver *dest,
79+
QueryCompletion *qc);
80+
6381
void _PG_init(void);
6482
void _PG_fini(void);
6583

@@ -95,6 +113,10 @@ _PG_init(void)
95113
pre_ora_updatexml_hook = ora_updatexml_hook;
96114
ora_updatexml_hook = updatexml;
97115
/* End - ReqID:SRS-SQL-XML */
116+
117+
/* ProcessUtility hook for DISCARD ALL/PACKAGES */
118+
prev_ProcessUtility_hook = ProcessUtility_hook;
119+
ProcessUtility_hook = ivorysql_ora_ProcessUtility;
98120
}
99121

100122
/*
@@ -116,4 +138,46 @@ _PG_fini(void)
116138
/* Begin - ReqID:SRS-SQL-XML */
117139
ora_updatexml_hook = pre_ora_updatexml_hook;
118140
/* End - ReqID:SRS-SQL-XML */
141+
142+
/* ProcessUtility hook */
143+
ProcessUtility_hook = prev_ProcessUtility_hook;
144+
}
145+
146+
/*
147+
* ProcessUtility hook to intercept DISCARD ALL/PACKAGES commands.
148+
* Resets DBMS_OUTPUT buffer state after these commands execute.
149+
*/
150+
static void
151+
ivorysql_ora_ProcessUtility(PlannedStmt *pstmt,
152+
const char *queryString,
153+
bool readOnlyTree,
154+
ProcessUtilityContext context,
155+
ParamListInfo params,
156+
QueryEnvironment *queryEnv,
157+
DestReceiver *dest,
158+
QueryCompletion *qc)
159+
{
160+
Node *parsetree = pstmt->utilityStmt;
161+
bool is_discard_reset = false;
162+
163+
/* Check if this is DISCARD ALL or DISCARD PACKAGES */
164+
if (nodeTag(parsetree) == T_DiscardStmt)
165+
{
166+
DiscardStmt *stmt = (DiscardStmt *) parsetree;
167+
168+
if (stmt->target == DISCARD_ALL || stmt->target == DISCARD_PACKAGES)
169+
is_discard_reset = true;
170+
}
171+
172+
/* Call the previous hook or standard function */
173+
if (prev_ProcessUtility_hook)
174+
(*prev_ProcessUtility_hook)(pstmt, queryString, readOnlyTree,
175+
context, params, queryEnv, dest, qc);
176+
else
177+
standard_ProcessUtility(pstmt, queryString, readOnlyTree,
178+
context, params, queryEnv, dest, qc);
179+
180+
/* Reset DBMS_OUTPUT buffer after DISCARD ALL/PACKAGES */
181+
if (is_discard_reset)
182+
ora_dbms_output_reset();
119183
}

0 commit comments

Comments
 (0)