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

Commit819d552

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 parenta6b5ddf commit819d552

File tree

10 files changed

+385
-341
lines changed

10 files changed

+385
-341
lines changed

‎contrib/adminpack/adminpack.c

Lines changed: 38 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,6 @@ static int64 pg_file_write_internal(text *file, text *data, bool replace);
5454
staticboolpg_file_rename_internal(text*file1,text*file2,text*file3);
5555
staticDatumpg_logdir_ls_internal(FunctionCallInfofcinfo);
5656

57-
typedefstruct
58-
{
59-
char*location;
60-
DIR*dirdesc;
61-
}directory_fctx;
6257

6358
/*-----------------------
6459
* some helper functions
@@ -483,50 +478,51 @@ pg_logdir_ls_v1_1(PG_FUNCTION_ARGS)
483478
staticDatum
484479
pg_logdir_ls_internal(FunctionCallInfofcinfo)
485480
{
486-
FuncCallContext*funcctx;
481+
ReturnSetInfo*rsinfo= (ReturnSetInfo*)fcinfo->resultinfo;
482+
boolrandomAccess;
483+
TupleDesctupdesc;
484+
Tuplestorestate*tupstore;
485+
AttInMetadata*attinmeta;
486+
DIR*dirdesc;
487487
structdirent*de;
488-
directory_fctx*fctx;
488+
MemoryContextoldcontext;
489489

490490
if (strcmp(Log_filename,"postgresql-%Y-%m-%d_%H%M%S.log")!=0)
491491
ereport(ERROR,
492492
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
493-
(errmsg("the log_filename parameter must equal 'postgresql-%%Y-%%m-%%d_%%H%%M%%S.log'"))));
494-
495-
if (SRF_IS_FIRSTCALL())
496-
{
497-
MemoryContextoldcontext;
498-
TupleDesctupdesc;
499-
500-
funcctx=SRF_FIRSTCALL_INIT();
501-
oldcontext=MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
493+
errmsg("the log_filename parameter must equal 'postgresql-%%Y-%%m-%%d_%%H%%M%%S.log'")));
502494

503-
fctx=palloc(sizeof(directory_fctx));
504-
505-
tupdesc=CreateTemplateTupleDesc(2, false);
506-
TupleDescInitEntry(tupdesc, (AttrNumber)1,"starttime",
507-
TIMESTAMPOID,-1,0);
508-
TupleDescInitEntry(tupdesc, (AttrNumber)2,"filename",
509-
TEXTOID,-1,0);
495+
/* check to see if caller supports us returning a tuplestore */
496+
if (rsinfo==NULL|| !IsA(rsinfo,ReturnSetInfo))
497+
ereport(ERROR,
498+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
499+
errmsg("set-valued function called in context that cannot accept a set")));
500+
if (!(rsinfo->allowedModes&SFRM_Materialize))
501+
ereport(ERROR,
502+
(errcode(ERRCODE_SYNTAX_ERROR),
503+
errmsg("materialize mode required, but it is not allowed in this context")));
510504

511-
funcctx->attinmeta=TupleDescGetAttInMetadata(tupdesc);
505+
/* The tupdesc and tuplestore must be created in ecxt_per_query_memory */
506+
oldcontext=MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
512507

513-
fctx->location=pstrdup(Log_directory);
514-
fctx->dirdesc=AllocateDir(fctx->location);
508+
tupdesc=CreateTemplateTupleDesc(2, false);
509+
TupleDescInitEntry(tupdesc, (AttrNumber)1,"starttime",
510+
TIMESTAMPOID,-1,0);
511+
TupleDescInitEntry(tupdesc, (AttrNumber)2,"filename",
512+
TEXTOID,-1,0);
515513

516-
if (!fctx->dirdesc)
517-
ereport(ERROR,
518-
(errcode_for_file_access(),
519-
errmsg("could not open directory \"%s\": %m",
520-
fctx->location)));
514+
randomAccess= (rsinfo->allowedModes&SFRM_Materialize_Random)!=0;
515+
tupstore=tuplestore_begin_heap(randomAccess, false,work_mem);
516+
rsinfo->returnMode=SFRM_Materialize;
517+
rsinfo->setResult=tupstore;
518+
rsinfo->setDesc=tupdesc;
521519

522-
funcctx->user_fctx=fctx;
523-
MemoryContextSwitchTo(oldcontext);
524-
}
520+
MemoryContextSwitchTo(oldcontext);
525521

526-
funcctx=SRF_PERCALL_SETUP();
527-
fctx= (directory_fctx*)funcctx->user_fctx;
522+
attinmeta=TupleDescGetAttInMetadata(tupdesc);
528523

529-
while ((de=ReadDir(fctx->dirdesc,fctx->location))!=NULL)
524+
dirdesc=AllocateDir(Log_directory);
525+
while ((de=ReadDir(dirdesc,Log_directory))!=NULL)
530526
{
531527
char*values[2];
532528
HeapTupletuple;
@@ -563,13 +559,13 @@ pg_logdir_ls_internal(FunctionCallInfo fcinfo)
563559
/* Seems the timestamp is OK; prepare and return tuple */
564560

565561
values[0]=timestampbuf;
566-
values[1]=psprintf("%s/%s",fctx->location,de->d_name);
562+
values[1]=psprintf("%s/%s",Log_directory,de->d_name);
567563

568-
tuple=BuildTupleFromCStrings(funcctx->attinmeta,values);
564+
tuple=BuildTupleFromCStrings(attinmeta,values);
569565

570-
SRF_RETURN_NEXT(funcctx,HeapTupleGetDatum(tuple));
566+
tuplestore_puttuple(tupstore,tuple);
571567
}
572568

573-
FreeDir(fctx->dirdesc);
574-
SRF_RETURN_DONE(funcctx);
569+
FreeDir(dirdesc);
570+
return (Datum)0;
575571
}

‎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,get_relkind_objtype(rel->rd_rel->relkind),
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,get_relkind_objtype(rel->rd_rel->relkind),
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