Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit04eb75e

Browse files
committed
pageinspect: Fix relcache leak in gist_page_items().
The gist_page_items() function opened the index relation on first call andclosed it on the last call. But there's no guarantee that the function isrun to completion, leading to a relcache leak and warning at the end ofthe transaction. To fix, refactor the function to return all the rows inone call, as a tuplestore.Reported-by: Tom LaneDiscussion:https://www.postgresql.org/message-id/234863.1610916631%40sss.pgh.pa.us
1 parent7db0cd2 commit04eb75e

File tree

1 file changed

+74
-96
lines changed

1 file changed

+74
-96
lines changed

‎contrib/pageinspect/gistfuncs.c

Lines changed: 74 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -92,65 +92,56 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
9292
returnHeapTupleGetDatum(resultTuple);
9393
}
9494

95-
typedefstructgist_page_items_state
96-
{
97-
Pagepage;
98-
TupleDesctupd;
99-
OffsetNumberoffset;
100-
Relationrel;
101-
}gist_page_items_state;
102-
10395
Datum
10496
gist_page_items_bytea(PG_FUNCTION_ARGS)
10597
{
10698
bytea*raw_page=PG_GETARG_BYTEA_P(0);
107-
FuncCallContext*fctx;
108-
gist_page_items_state*inter_call_data;
99+
ReturnSetInfo*rsinfo= (ReturnSetInfo*)fcinfo->resultinfo;
100+
boolrandomAccess;
101+
TupleDesctupdesc;
102+
Tuplestorestate*tupstore;
103+
MemoryContextoldcontext;
104+
Pagepage;
105+
OffsetNumberoffset;
109106

110107
if (!superuser())
111108
ereport(ERROR,
112109
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
113110
errmsg("must be superuser to use raw page functions")));
114111

115-
if (SRF_IS_FIRSTCALL())
116-
{
117-
TupleDesctupdesc;
118-
MemoryContextmctx;
119-
Pagepage;
120-
121-
fctx=SRF_FIRSTCALL_INIT();
122-
mctx=MemoryContextSwitchTo(fctx->multi_call_memory_ctx);
123-
124-
page=get_page_from_raw(raw_page);
125-
126-
inter_call_data=palloc(sizeof(gist_page_items_state));
112+
/* check to see if caller supports us returning a tuplestore */
113+
if (rsinfo==NULL|| !IsA(rsinfo,ReturnSetInfo))
114+
ereport(ERROR,
115+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
116+
errmsg("set-valued function called in context that cannot accept a set")));
117+
if (!(rsinfo->allowedModes&SFRM_Materialize))
118+
ereport(ERROR,
119+
(errcode(ERRCODE_SYNTAX_ERROR),
120+
errmsg("materialize mode required, but it is not allowed in this context")));
127121

128-
/* Build a tuple descriptor for our result type */
129-
if (get_call_result_type(fcinfo,NULL,&tupdesc)!=TYPEFUNC_COMPOSITE)
130-
elog(ERROR,"return type must be a row type");
122+
/* The tupdesc and tuplestore must be created in ecxt_per_query_memory */
123+
oldcontext=MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
131124

132-
if (GistPageIsDeleted(page))
133-
elog(NOTICE,"page is deleted");
125+
if (get_call_result_type(fcinfo,NULL,&tupdesc)!=TYPEFUNC_COMPOSITE)
126+
elog(ERROR,"return type must be a row type");
134127

135-
inter_call_data->page=page;
136-
inter_call_data->tupd=tupdesc;
137-
inter_call_data->offset=FirstOffsetNumber;
128+
randomAccess= (rsinfo->allowedModes&SFRM_Materialize_Random)!=0;
129+
tupstore=tuplestore_begin_heap(randomAccess, false,work_mem);
130+
rsinfo->returnMode=SFRM_Materialize;
131+
rsinfo->setResult=tupstore;
132+
rsinfo->setDesc=tupdesc;
138133

139-
fctx->max_calls=PageGetMaxOffsetNumber(page);
140-
fctx->user_fctx=inter_call_data;
134+
MemoryContextSwitchTo(oldcontext);
141135

142-
MemoryContextSwitchTo(mctx);
143-
}
136+
page=get_page_from_raw(raw_page);
144137

145-
fctx=SRF_PERCALL_SETUP();
146-
inter_call_data=fctx->user_fctx;
138+
if (GistPageIsDeleted(page))
139+
elog(NOTICE,"page is deleted");
147140

148-
if (fctx->call_cntr<fctx->max_calls)
141+
for (offset=FirstOffsetNumber;
142+
offset <=PageGetMaxOffsetNumber(page);
143+
offset++)
149144
{
150-
Pagepage=inter_call_data->page;
151-
OffsetNumberoffset=inter_call_data->offset;
152-
HeapTupleresultTuple;
153-
Datumresult;
154145
Datumvalues[4];
155146
boolnulls[4];
156147
ItemIdid;
@@ -177,74 +168,67 @@ gist_page_items_bytea(PG_FUNCTION_ARGS)
177168
memcpy(VARDATA(tuple_bytea),itup,tuple_len);
178169
values[3]=PointerGetDatum(tuple_bytea);
179170

180-
/* Build and return the result tuple. */
181-
resultTuple=heap_form_tuple(inter_call_data->tupd,values,nulls);
182-
result=HeapTupleGetDatum(resultTuple);
183-
184-
inter_call_data->offset++;
185-
SRF_RETURN_NEXT(fctx,result);
171+
tuplestore_putvalues(tupstore,tupdesc,values,nulls);
186172
}
187173

188-
SRF_RETURN_DONE(fctx);
174+
return (Datum)0;
189175
}
190176

191177
Datum
192178
gist_page_items(PG_FUNCTION_ARGS)
193179
{
194180
bytea*raw_page=PG_GETARG_BYTEA_P(0);
195181
OidindexRelid=PG_GETARG_OID(1);
196-
FuncCallContext*fctx;
197-
gist_page_items_state*inter_call_data;
182+
ReturnSetInfo*rsinfo= (ReturnSetInfo*)fcinfo->resultinfo;
183+
boolrandomAccess;
184+
RelationindexRel;
185+
TupleDesctupdesc;
186+
Tuplestorestate*tupstore;
187+
MemoryContextoldcontext;
188+
Pagepage;
189+
OffsetNumberoffset;
198190

199191
if (!superuser())
200192
ereport(ERROR,
201193
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
202194
errmsg("must be superuser to use raw page functions")));
203195

204-
if (SRF_IS_FIRSTCALL())
205-
{
206-
RelationindexRel;
207-
TupleDesctupdesc;
208-
MemoryContextmctx;
209-
Pagepage;
210-
211-
fctx=SRF_FIRSTCALL_INIT();
212-
mctx=MemoryContextSwitchTo(fctx->multi_call_memory_ctx);
213-
214-
page=get_page_from_raw(raw_page);
215-
216-
inter_call_data=palloc(sizeof(gist_page_items_state));
196+
/* check to see if caller supports us returning a tuplestore */
197+
if (rsinfo==NULL|| !IsA(rsinfo,ReturnSetInfo))
198+
ereport(ERROR,
199+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
200+
errmsg("set-valued function called in context that cannot accept a set")));
201+
if (!(rsinfo->allowedModes&SFRM_Materialize))
202+
ereport(ERROR,
203+
(errcode(ERRCODE_SYNTAX_ERROR),
204+
errmsg("materialize mode required, but it is not allowed in this context")));
217205

218-
/*Open the relation */
219-
indexRel=index_open(indexRelid,AccessShareLock);
206+
/*The tupdesc and tuplestore must be created in ecxt_per_query_memory */
207+
oldcontext=MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
220208

221-
/* Build a tuple descriptor for our result type */
222-
if (get_call_result_type(fcinfo,NULL,&tupdesc)!=TYPEFUNC_COMPOSITE)
223-
elog(ERROR,"return type must be a row type");
209+
if (get_call_result_type(fcinfo,NULL,&tupdesc)!=TYPEFUNC_COMPOSITE)
210+
elog(ERROR,"return type must be a row type");
224211

225-
if (GistPageIsDeleted(page))
226-
elog(NOTICE,"page is deleted");
212+
randomAccess= (rsinfo->allowedModes&SFRM_Materialize_Random)!=0;
213+
tupstore=tuplestore_begin_heap(randomAccess, false,work_mem);
214+
rsinfo->returnMode=SFRM_Materialize;
215+
rsinfo->setResult=tupstore;
216+
rsinfo->setDesc=tupdesc;
227217

228-
inter_call_data->page=page;
229-
inter_call_data->tupd=tupdesc;
230-
inter_call_data->offset=FirstOffsetNumber;
231-
inter_call_data->rel=indexRel;
218+
MemoryContextSwitchTo(oldcontext);
232219

233-
fctx->max_calls=PageGetMaxOffsetNumber(page);
234-
fctx->user_fctx=inter_call_data;
220+
/* Open the relation */
221+
indexRel=index_open(indexRelid,AccessShareLock);
235222

236-
MemoryContextSwitchTo(mctx);
237-
}
223+
page=get_page_from_raw(raw_page);
238224

239-
fctx=SRF_PERCALL_SETUP();
240-
inter_call_data=fctx->user_fctx;
225+
if (GistPageIsDeleted(page))
226+
elog(NOTICE,"page is deleted");
241227

242-
if (fctx->call_cntr<fctx->max_calls)
228+
for (offset=FirstOffsetNumber;
229+
offset <=PageGetMaxOffsetNumber(page);
230+
offset++)
243231
{
244-
Pagepage=inter_call_data->page;
245-
OffsetNumberoffset=inter_call_data->offset;
246-
HeapTupleresultTuple;
247-
Datumresult;
248232
Datumvalues[4];
249233
boolnulls[4];
250234
ItemIdid;
@@ -260,11 +244,10 @@ gist_page_items(PG_FUNCTION_ARGS)
260244

261245
itup= (IndexTuple)PageGetItem(page,id);
262246

263-
index_deform_tuple(itup,RelationGetDescr(inter_call_data->rel),
247+
index_deform_tuple(itup,RelationGetDescr(indexRel),
264248
itup_values,itup_isnull);
265249

266-
key_desc=BuildIndexValueDescription(inter_call_data->rel,itup_values,
267-
itup_isnull);
250+
key_desc=BuildIndexValueDescription(indexRel,itup_values,itup_isnull);
268251

269252
memset(nulls,0,sizeof(nulls));
270253

@@ -273,15 +256,10 @@ gist_page_items(PG_FUNCTION_ARGS)
273256
values[2]=Int32GetDatum((int)IndexTupleSize(itup));
274257
values[3]=CStringGetTextDatum(key_desc);
275258

276-
/* Build and return the result tuple. */
277-
resultTuple=heap_form_tuple(inter_call_data->tupd,values,nulls);
278-
result=HeapTupleGetDatum(resultTuple);
279-
280-
inter_call_data->offset++;
281-
SRF_RETURN_NEXT(fctx,result);
259+
tuplestore_putvalues(tupstore,tupdesc,values,nulls);
282260
}
283261

284-
relation_close(inter_call_data->rel,AccessShareLock);
262+
relation_close(indexRel,AccessShareLock);
285263

286-
SRF_RETURN_DONE(fctx);
264+
return (Datum)0;
287265
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp