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

Commit5e4a0b7

Browse files
committed
Avoid holding a directory FD open across assorted SRF calls.
This extends the fixes made in commit085b6b6 to other SRFs with thesame bug, namely pg_logdir_ls(), pgrowlocks(), pg_timezone_names(),pg_ls_dir(), and pg_tablespace_databases().Also adjust various comments and documentation to warn againstexpecting to clean up resources during a ValuePerCall SRF's finalcall.Back-patch to all supported branches, since these functions wereall born broken.Justin Pryzby, with cosmetic tweaks by meDiscussion:https://postgr.es/m/20200308173103.GC1357@telsasoft.com
1 parentc6b75b3 commit5e4a0b7

File tree

10 files changed

+391
-347
lines changed

10 files changed

+391
-347
lines changed

‎contrib/adminpack/adminpack.c

Lines changed: 38 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,6 @@ PG_FUNCTION_INFO_V1(pg_file_rename);
4545
PG_FUNCTION_INFO_V1(pg_file_unlink);
4646
PG_FUNCTION_INFO_V1(pg_logdir_ls);
4747

48-
typedefstruct
49-
{
50-
char*location;
51-
DIR*dirdesc;
52-
}directory_fctx;
5348

5449
/*-----------------------
5550
* some helper functions
@@ -281,9 +276,14 @@ pg_file_unlink(PG_FUNCTION_ARGS)
281276
Datum
282277
pg_logdir_ls(PG_FUNCTION_ARGS)
283278
{
284-
FuncCallContext*funcctx;
279+
ReturnSetInfo*rsinfo= (ReturnSetInfo*)fcinfo->resultinfo;
280+
boolrandomAccess;
281+
TupleDesctupdesc;
282+
Tuplestorestate*tupstore;
283+
AttInMetadata*attinmeta;
284+
DIR*dirdesc;
285285
structdirent*de;
286-
directory_fctx*fctx;
286+
MemoryContextoldcontext;
287287

288288
if (!superuser())
289289
ereport(ERROR,
@@ -293,43 +293,39 @@ pg_logdir_ls(PG_FUNCTION_ARGS)
293293
if (strcmp(Log_filename,"postgresql-%Y-%m-%d_%H%M%S.log")!=0)
294294
ereport(ERROR,
295295
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
296-
(errmsg("the log_filename parameter must equal 'postgresql-%%Y-%%m-%%d_%%H%%M%%S.log'"))));
297-
298-
if (SRF_IS_FIRSTCALL())
299-
{
300-
MemoryContextoldcontext;
301-
TupleDesctupdesc;
302-
303-
funcctx=SRF_FIRSTCALL_INIT();
304-
oldcontext=MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
296+
errmsg("the log_filename parameter must equal 'postgresql-%%Y-%%m-%%d_%%H%%M%%S.log'")));
305297

306-
fctx=palloc(sizeof(directory_fctx));
307-
308-
tupdesc=CreateTemplateTupleDesc(2, false);
309-
TupleDescInitEntry(tupdesc, (AttrNumber)1,"starttime",
310-
TIMESTAMPOID,-1,0);
311-
TupleDescInitEntry(tupdesc, (AttrNumber)2,"filename",
312-
TEXTOID,-1,0);
298+
/* check to see if caller supports us returning a tuplestore */
299+
if (rsinfo==NULL|| !IsA(rsinfo,ReturnSetInfo))
300+
ereport(ERROR,
301+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
302+
errmsg("set-valued function called in context that cannot accept a set")));
303+
if (!(rsinfo->allowedModes&SFRM_Materialize))
304+
ereport(ERROR,
305+
(errcode(ERRCODE_SYNTAX_ERROR),
306+
errmsg("materialize mode required, but it is not allowed in this context")));
313307

314-
funcctx->attinmeta=TupleDescGetAttInMetadata(tupdesc);
308+
/* The tupdesc and tuplestore must be created in ecxt_per_query_memory */
309+
oldcontext=MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
315310

316-
fctx->location=pstrdup(Log_directory);
317-
fctx->dirdesc=AllocateDir(fctx->location);
311+
tupdesc=CreateTemplateTupleDesc(2, false);
312+
TupleDescInitEntry(tupdesc, (AttrNumber)1,"starttime",
313+
TIMESTAMPOID,-1,0);
314+
TupleDescInitEntry(tupdesc, (AttrNumber)2,"filename",
315+
TEXTOID,-1,0);
318316

319-
if (!fctx->dirdesc)
320-
ereport(ERROR,
321-
(errcode_for_file_access(),
322-
errmsg("could not read directory \"%s\": %m",
323-
fctx->location)));
317+
randomAccess= (rsinfo->allowedModes&SFRM_Materialize_Random)!=0;
318+
tupstore=tuplestore_begin_heap(randomAccess, false,work_mem);
319+
rsinfo->returnMode=SFRM_Materialize;
320+
rsinfo->setResult=tupstore;
321+
rsinfo->setDesc=tupdesc;
324322

325-
funcctx->user_fctx=fctx;
326-
MemoryContextSwitchTo(oldcontext);
327-
}
323+
MemoryContextSwitchTo(oldcontext);
328324

329-
funcctx=SRF_PERCALL_SETUP();
330-
fctx= (directory_fctx*)funcctx->user_fctx;
325+
attinmeta=TupleDescGetAttInMetadata(tupdesc);
331326

332-
while ((de=ReadDir(fctx->dirdesc,fctx->location))!=NULL)
327+
dirdesc=AllocateDir(Log_directory);
328+
while ((de=ReadDir(dirdesc,Log_directory))!=NULL)
333329
{
334330
char*values[2];
335331
HeapTupletuple;
@@ -366,13 +362,13 @@ pg_logdir_ls(PG_FUNCTION_ARGS)
366362
/* Seems the timestamp is OK; prepare and return tuple */
367363

368364
values[0]=timestampbuf;
369-
values[1]=psprintf("%s/%s",fctx->location,de->d_name);
365+
values[1]=psprintf("%s/%s",Log_directory,de->d_name);
370366

371-
tuple=BuildTupleFromCStrings(funcctx->attinmeta,values);
367+
tuple=BuildTupleFromCStrings(attinmeta,values);
372368

373-
SRF_RETURN_NEXT(funcctx,HeapTupleGetDatum(tuple));
369+
tuplestore_puttuple(tupstore,tuple);
374370
}
375371

376-
FreeDir(fctx->dirdesc);
377-
SRF_RETURN_DONE(funcctx);
372+
FreeDir(dirdesc);
373+
return (Datum)0;
378374
}

‎contrib/pgrowlocks/pgrowlocks.c

Lines changed: 73 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,6 @@ PG_FUNCTION_INFO_V1(pgrowlocks);
5252

5353
#defineNCHARS 32
5454

55-
typedefstruct
56-
{
57-
Relationrel;
58-
HeapScanDescscan;
59-
intncolumns;
60-
}MyData;
61-
6255
#defineAtnum_tid0
6356
#defineAtnum_xmax1
6457
#defineAtnum_ismulti2
@@ -69,77 +62,80 @@ typedef struct
6962
Datum
7063
pgrowlocks(PG_FUNCTION_ARGS)
7164
{
72-
FuncCallContext*funcctx;
73-
HeapScanDescscan;
74-
HeapTupletuple;
65+
text*relname=PG_GETARG_TEXT_PP(0);
66+
ReturnSetInfo*rsinfo= (ReturnSetInfo*)fcinfo->resultinfo;
67+
boolrandomAccess;
7568
TupleDesctupdesc;
69+
Tuplestorestate*tupstore;
7670
AttInMetadata*attinmeta;
77-
Datumresult;
78-
MyData*mydata;
7971
Relationrel;
72+
RangeVar*relrv;
73+
HeapScanDescscan;
74+
HeapTupletuple;
75+
MemoryContextoldcontext;
76+
AclResultaclresult;
77+
char**values;
78+
79+
/* check to see if caller supports us returning a tuplestore */
80+
if (rsinfo==NULL|| !IsA(rsinfo,ReturnSetInfo))
81+
ereport(ERROR,
82+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
83+
errmsg("set-valued function called in context that cannot accept a set")));
84+
if (!(rsinfo->allowedModes&SFRM_Materialize))
85+
ereport(ERROR,
86+
(errcode(ERRCODE_SYNTAX_ERROR),
87+
errmsg("materialize mode required, but it is not allowed in this context")));
88+
89+
/* The tupdesc and tuplestore must be created in ecxt_per_query_memory */
90+
oldcontext=MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
91+
92+
if (get_call_result_type(fcinfo,NULL,&tupdesc)!=TYPEFUNC_COMPOSITE)
93+
elog(ERROR,"return type must be a row type");
94+
95+
randomAccess= (rsinfo->allowedModes&SFRM_Materialize_Random)!=0;
96+
tupstore=tuplestore_begin_heap(randomAccess, false,work_mem);
97+
rsinfo->returnMode=SFRM_Materialize;
98+
rsinfo->setResult=tupstore;
99+
rsinfo->setDesc=tupdesc;
100+
101+
MemoryContextSwitchTo(oldcontext);
102+
103+
/* Access the table */
104+
relrv=makeRangeVarFromNameList(textToQualifiedNameList(relname));
105+
rel=relation_openrv(relrv,AccessShareLock);
106+
107+
if (rel->rd_rel->relkind==RELKIND_PARTITIONED_TABLE)
108+
ereport(ERROR,
109+
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
110+
errmsg("\"%s\" is a partitioned table",
111+
RelationGetRelationName(rel)),
112+
errdetail("Partitioned tables do not contain rows.")));
113+
elseif (rel->rd_rel->relkind!=RELKIND_RELATION)
114+
ereport(ERROR,
115+
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
116+
errmsg("\"%s\" is not a table",
117+
RelationGetRelationName(rel))));
118+
119+
/*
120+
* check permissions: must have SELECT on table or be in
121+
* pg_stat_scan_tables
122+
*/
123+
aclresult=pg_class_aclcheck(RelationGetRelid(rel),GetUserId(),
124+
ACL_SELECT);
125+
if (aclresult!=ACLCHECK_OK)
126+
aclresult=is_member_of_role(GetUserId(),DEFAULT_ROLE_STAT_SCAN_TABLES) ?ACLCHECK_OK :ACLCHECK_NO_PRIV;
127+
128+
if (aclresult!=ACLCHECK_OK)
129+
aclcheck_error(aclresult,ACL_KIND_CLASS,
130+
RelationGetRelationName(rel));
131+
132+
/* Scan the relation */
133+
scan=heap_beginscan(rel,GetActiveSnapshot(),0,NULL);
134+
135+
attinmeta=TupleDescGetAttInMetadata(tupdesc);
136+
137+
values= (char**)palloc(tupdesc->natts*sizeof(char*));
80138

81-
if (SRF_IS_FIRSTCALL())
82-
{
83-
text*relname;
84-
RangeVar*relrv;
85-
MemoryContextoldcontext;
86-
AclResultaclresult;
87-
88-
funcctx=SRF_FIRSTCALL_INIT();
89-
oldcontext=MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
90-
91-
/* Build a tuple descriptor for our result type */
92-
if (get_call_result_type(fcinfo,NULL,&tupdesc)!=TYPEFUNC_COMPOSITE)
93-
elog(ERROR,"return type must be a row type");
94-
95-
attinmeta=TupleDescGetAttInMetadata(tupdesc);
96-
funcctx->attinmeta=attinmeta;
97-
98-
relname=PG_GETARG_TEXT_PP(0);
99-
relrv=makeRangeVarFromNameList(textToQualifiedNameList(relname));
100-
rel=relation_openrv(relrv,AccessShareLock);
101-
102-
if (rel->rd_rel->relkind==RELKIND_PARTITIONED_TABLE)
103-
ereport(ERROR,
104-
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
105-
errmsg("\"%s\" is a partitioned table",
106-
RelationGetRelationName(rel)),
107-
errdetail("Partitioned tables do not contain rows.")));
108-
elseif (rel->rd_rel->relkind!=RELKIND_RELATION)
109-
ereport(ERROR,
110-
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
111-
errmsg("\"%s\" is not a table",
112-
RelationGetRelationName(rel))));
113-
114-
/*
115-
* check permissions: must have SELECT on table or be in
116-
* pg_stat_scan_tables
117-
*/
118-
aclresult=pg_class_aclcheck(RelationGetRelid(rel),GetUserId(),
119-
ACL_SELECT);
120-
if (aclresult!=ACLCHECK_OK)
121-
aclresult=is_member_of_role(GetUserId(),DEFAULT_ROLE_STAT_SCAN_TABLES) ?ACLCHECK_OK :ACLCHECK_NO_PRIV;
122-
123-
if (aclresult!=ACLCHECK_OK)
124-
aclcheck_error(aclresult,ACL_KIND_CLASS,
125-
RelationGetRelationName(rel));
126-
127-
scan=heap_beginscan(rel,GetActiveSnapshot(),0,NULL);
128-
mydata=palloc(sizeof(*mydata));
129-
mydata->rel=rel;
130-
mydata->scan=scan;
131-
mydata->ncolumns=tupdesc->natts;
132-
funcctx->user_fctx=mydata;
133-
134-
MemoryContextSwitchTo(oldcontext);
135-
}
136-
137-
funcctx=SRF_PERCALL_SETUP();
138-
attinmeta=funcctx->attinmeta;
139-
mydata= (MyData*)funcctx->user_fctx;
140-
scan=mydata->scan;
141-
142-
/* scan the relation */
143139
while ((tuple=heap_getnext(scan,ForwardScanDirection))!=NULL)
144140
{
145141
HTSU_Resulthtsu;
@@ -160,10 +156,6 @@ pgrowlocks(PG_FUNCTION_ARGS)
160156
*/
161157
if (htsu==HeapTupleBeingUpdated)
162158
{
163-
char**values;
164-
165-
values= (char**)palloc(mydata->ncolumns*sizeof(char*));
166-
167159
values[Atnum_tid]= (char*)DirectFunctionCall1(tidout,
168160
PointerGetDatum(&tuple->t_self));
169161

@@ -288,16 +280,7 @@ pgrowlocks(PG_FUNCTION_ARGS)
288280

289281
/* build a tuple */
290282
tuple=BuildTupleFromCStrings(attinmeta,values);
291-
292-
/* make the tuple into a datum */
293-
result=HeapTupleGetDatum(tuple);
294-
295-
/*
296-
* no need to pfree what we allocated; it's on a short-lived
297-
* memory context anyway
298-
*/
299-
300-
SRF_RETURN_NEXT(funcctx,result);
283+
tuplestore_puttuple(tupstore,tuple);
301284
}
302285
else
303286
{
@@ -306,7 +289,6 @@ pgrowlocks(PG_FUNCTION_ARGS)
306289
}
307290

308291
heap_endscan(scan);
309-
heap_close(mydata->rel,AccessShareLock);
310-
311-
SRF_RETURN_DONE(funcctx);
292+
heap_close(rel,AccessShareLock);
293+
return (Datum)0;
312294
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp