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

Commitb4570d3

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 parent1137581 commitb4570d3

File tree

10 files changed

+388
-348
lines changed

10 files changed

+388
-348
lines changed

‎contrib/adminpack/adminpack.c

Lines changed: 37 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,6 @@ static int64 pg_file_write_internal(text *file, text *data, bool replace);
5656
staticboolpg_file_rename_internal(text*file1,text*file2,text*file3);
5757
staticDatumpg_logdir_ls_internal(FunctionCallInfofcinfo);
5858

59-
typedefstruct
60-
{
61-
char*location;
62-
DIR*dirdesc;
63-
}directory_fctx;
6459

6560
/*-----------------------
6661
* some helper functions
@@ -504,50 +499,51 @@ pg_logdir_ls_v1_1(PG_FUNCTION_ARGS)
504499
staticDatum
505500
pg_logdir_ls_internal(FunctionCallInfofcinfo)
506501
{
507-
FuncCallContext*funcctx;
502+
ReturnSetInfo*rsinfo= (ReturnSetInfo*)fcinfo->resultinfo;
503+
boolrandomAccess;
504+
TupleDesctupdesc;
505+
Tuplestorestate*tupstore;
506+
AttInMetadata*attinmeta;
507+
DIR*dirdesc;
508508
structdirent*de;
509-
directory_fctx*fctx;
509+
MemoryContextoldcontext;
510510

511511
if (strcmp(Log_filename,"postgresql-%Y-%m-%d_%H%M%S.log")!=0)
512512
ereport(ERROR,
513513
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
514514
errmsg("the log_filename parameter must equal 'postgresql-%%Y-%%m-%%d_%%H%%M%%S.log'")));
515515

516-
if (SRF_IS_FIRSTCALL())
517-
{
518-
MemoryContextoldcontext;
519-
TupleDesctupdesc;
520-
521-
funcctx=SRF_FIRSTCALL_INIT();
522-
oldcontext=MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
523-
524-
fctx=palloc(sizeof(directory_fctx));
525-
526-
tupdesc=CreateTemplateTupleDesc(2);
527-
TupleDescInitEntry(tupdesc, (AttrNumber)1,"starttime",
528-
TIMESTAMPOID,-1,0);
529-
TupleDescInitEntry(tupdesc, (AttrNumber)2,"filename",
530-
TEXTOID,-1,0);
516+
/* check to see if caller supports us returning a tuplestore */
517+
if (rsinfo==NULL|| !IsA(rsinfo,ReturnSetInfo))
518+
ereport(ERROR,
519+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
520+
errmsg("set-valued function called in context that cannot accept a set")));
521+
if (!(rsinfo->allowedModes&SFRM_Materialize))
522+
ereport(ERROR,
523+
(errcode(ERRCODE_SYNTAX_ERROR),
524+
errmsg("materialize mode required, but it is not allowed in this context")));
531525

532-
funcctx->attinmeta=TupleDescGetAttInMetadata(tupdesc);
526+
/* The tupdesc and tuplestore must be created in ecxt_per_query_memory */
527+
oldcontext=MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
533528

534-
fctx->location=pstrdup(Log_directory);
535-
fctx->dirdesc=AllocateDir(fctx->location);
529+
tupdesc=CreateTemplateTupleDesc(2);
530+
TupleDescInitEntry(tupdesc, (AttrNumber)1,"starttime",
531+
TIMESTAMPOID,-1,0);
532+
TupleDescInitEntry(tupdesc, (AttrNumber)2,"filename",
533+
TEXTOID,-1,0);
536534

537-
if (!fctx->dirdesc)
538-
ereport(ERROR,
539-
(errcode_for_file_access(),
540-
errmsg("could not open directory \"%s\": %m",
541-
fctx->location)));
535+
randomAccess= (rsinfo->allowedModes&SFRM_Materialize_Random)!=0;
536+
tupstore=tuplestore_begin_heap(randomAccess, false,work_mem);
537+
rsinfo->returnMode=SFRM_Materialize;
538+
rsinfo->setResult=tupstore;
539+
rsinfo->setDesc=tupdesc;
542540

543-
funcctx->user_fctx=fctx;
544-
MemoryContextSwitchTo(oldcontext);
545-
}
541+
MemoryContextSwitchTo(oldcontext);
546542

547-
funcctx=SRF_PERCALL_SETUP();
548-
fctx= (directory_fctx*)funcctx->user_fctx;
543+
attinmeta=TupleDescGetAttInMetadata(tupdesc);
549544

550-
while ((de=ReadDir(fctx->dirdesc,fctx->location))!=NULL)
545+
dirdesc=AllocateDir(Log_directory);
546+
while ((de=ReadDir(dirdesc,Log_directory))!=NULL)
551547
{
552548
char*values[2];
553549
HeapTupletuple;
@@ -584,13 +580,13 @@ pg_logdir_ls_internal(FunctionCallInfo fcinfo)
584580
/* Seems the timestamp is OK; prepare and return tuple */
585581

586582
values[0]=timestampbuf;
587-
values[1]=psprintf("%s/%s",fctx->location,de->d_name);
583+
values[1]=psprintf("%s/%s",Log_directory,de->d_name);
588584

589-
tuple=BuildTupleFromCStrings(funcctx->attinmeta,values);
585+
tuple=BuildTupleFromCStrings(attinmeta,values);
590586

591-
SRF_RETURN_NEXT(funcctx,HeapTupleGetDatum(tuple));
587+
tuplestore_puttuple(tupstore,tuple);
592588
}
593589

594-
FreeDir(fctx->dirdesc);
595-
SRF_RETURN_DONE(funcctx);
590+
FreeDir(dirdesc);
591+
return (Datum)0;
596592
}

‎contrib/pgrowlocks/pgrowlocks.c

Lines changed: 77 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,6 @@ PG_FUNCTION_INFO_V1(pgrowlocks);
5454

5555
#defineNCHARS 32
5656

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

84-
if (SRF_IS_FIRSTCALL())
85-
{
86-
text*relname;
87-
RangeVar*relrv;
88-
MemoryContextoldcontext;
89-
AclResultaclresult;
90-
91-
funcctx=SRF_FIRSTCALL_INIT();
92-
oldcontext=MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
93-
94-
/* Build a tuple descriptor for our result type */
95-
if (get_call_result_type(fcinfo,NULL,&tupdesc)!=TYPEFUNC_COMPOSITE)
96-
elog(ERROR,"return type must be a row type");
97-
98-
attinmeta=TupleDescGetAttInMetadata(tupdesc);
99-
funcctx->attinmeta=attinmeta;
100-
101-
relname=PG_GETARG_TEXT_PP(0);
102-
relrv=makeRangeVarFromNameList(textToQualifiedNameList(relname));
103-
rel=relation_openrv(relrv,AccessShareLock);
104-
105-
if (rel->rd_rel->relam!=HEAP_TABLE_AM_OID)
106-
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
107-
errmsg("only heap AM is supported")));
108-
109-
if (rel->rd_rel->relkind==RELKIND_PARTITIONED_TABLE)
110-
ereport(ERROR,
111-
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
112-
errmsg("\"%s\" is a partitioned table",
113-
RelationGetRelationName(rel)),
114-
errdetail("Partitioned tables do not contain rows.")));
115-
elseif (rel->rd_rel->relkind!=RELKIND_RELATION)
116-
ereport(ERROR,
117-
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
118-
errmsg("\"%s\" is not a table",
119-
RelationGetRelationName(rel))));
120-
121-
/*
122-
* check permissions: must have SELECT on table or be in
123-
* pg_stat_scan_tables
124-
*/
125-
aclresult=pg_class_aclcheck(RelationGetRelid(rel),GetUserId(),
126-
ACL_SELECT);
127-
if (aclresult!=ACLCHECK_OK)
128-
aclresult=is_member_of_role(GetUserId(),DEFAULT_ROLE_STAT_SCAN_TABLES) ?ACLCHECK_OK :ACLCHECK_NO_PRIV;
129-
130-
if (aclresult!=ACLCHECK_OK)
131-
aclcheck_error(aclresult,get_relkind_objtype(rel->rd_rel->relkind),
132-
RelationGetRelationName(rel));
133-
134-
scan=table_beginscan(rel,GetActiveSnapshot(),0,NULL);
135-
hscan= (HeapScanDesc)scan;
136-
mydata=palloc(sizeof(*mydata));
137-
mydata->rel=rel;
138-
mydata->scan=scan;
139-
mydata->ncolumns=tupdesc->natts;
140-
funcctx->user_fctx=mydata;
141-
142-
MemoryContextSwitchTo(oldcontext);
143-
}
143+
attinmeta=TupleDescGetAttInMetadata(tupdesc);
144144

145-
funcctx=SRF_PERCALL_SETUP();
146-
attinmeta=funcctx->attinmeta;
147-
mydata= (MyData*)funcctx->user_fctx;
148-
scan=mydata->scan;
149-
hscan= (HeapScanDesc)scan;
145+
values= (char**)palloc(tupdesc->natts*sizeof(char*));
150146

151-
/* scan the relation */
152147
while ((tuple=heap_getnext(scan,ForwardScanDirection))!=NULL)
153148
{
154149
TM_Resulthtsu;
@@ -169,10 +164,6 @@ pgrowlocks(PG_FUNCTION_ARGS)
169164
*/
170165
if (htsu==TM_BeingModified)
171166
{
172-
char**values;
173-
174-
values= (char**)palloc(mydata->ncolumns*sizeof(char*));
175-
176167
values[Atnum_tid]= (char*)DirectFunctionCall1(tidout,
177168
PointerGetDatum(&tuple->t_self));
178169

@@ -297,16 +288,7 @@ pgrowlocks(PG_FUNCTION_ARGS)
297288

298289
/* build a tuple */
299290
tuple=BuildTupleFromCStrings(attinmeta,values);
300-
301-
/* make the tuple into a datum */
302-
result=HeapTupleGetDatum(tuple);
303-
304-
/*
305-
* no need to pfree what we allocated; it's on a short-lived
306-
* memory context anyway
307-
*/
308-
309-
SRF_RETURN_NEXT(funcctx,result);
291+
tuplestore_puttuple(tupstore,tuple);
310292
}
311293
else
312294
{
@@ -315,7 +297,6 @@ pgrowlocks(PG_FUNCTION_ARGS)
315297
}
316298

317299
table_endscan(scan);
318-
table_close(mydata->rel,AccessShareLock);
319-
320-
SRF_RETURN_DONE(funcctx);
300+
table_close(rel,AccessShareLock);
301+
return (Datum)0;
321302
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp