diff options
author | Tom Lane | 2020-03-17 01:05:28 +0000 |
---|---|---|
committer | Tom Lane | 2020-03-17 01:05:52 +0000 |
commit | b4570d33aa045df330bb325ba8a2cbf02266a555 (patch) | |
tree | 4e7ebfee102862d095bfa9eb0dede58a4cca471f /contrib/adminpack/adminpack.c | |
parent | 113758155c11cf993ca0ecee8856e300a2525a30 (diff) |
Avoid holding a directory FD open across assorted SRF calls.
This extends the fixes made in commit 085b6b667 to other SRFs with the
same bug, namely pg_logdir_ls(), pgrowlocks(), pg_timezone_names(),
pg_ls_dir(), and pg_tablespace_databases().
Also adjust various comments and documentation to warn against
expecting to clean up resources during a ValuePerCall SRF's final
call.
Back-patch to all supported branches, since these functions were
all born broken.
Justin Pryzby, with cosmetic tweaks by me
Discussion: https://postgr.es/m/20200308173103.GC1357@telsasoft.com
Diffstat (limited to 'contrib/adminpack/adminpack.c')
-rw-r--r-- | contrib/adminpack/adminpack.c | 78 |
1 files changed, 37 insertions, 41 deletions
diff --git a/contrib/adminpack/adminpack.c b/contrib/adminpack/adminpack.c index bc45e798951..7d0a19b2949 100644 --- a/contrib/adminpack/adminpack.c +++ b/contrib/adminpack/adminpack.c @@ -56,11 +56,6 @@ static int64 pg_file_write_internal(text *file, text *data, bool replace); static bool pg_file_rename_internal(text *file1, text *file2, text *file3); static Datum pg_logdir_ls_internal(FunctionCallInfo fcinfo); -typedef struct -{ - char *location; - DIR *dirdesc; -} directory_fctx; /*----------------------- * some helper functions @@ -504,50 +499,51 @@ pg_logdir_ls_v1_1(PG_FUNCTION_ARGS) static Datum pg_logdir_ls_internal(FunctionCallInfo fcinfo) { - FuncCallContext *funcctx; + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + bool randomAccess; + TupleDesc tupdesc; + Tuplestorestate *tupstore; + AttInMetadata *attinmeta; + DIR *dirdesc; struct dirent *de; - directory_fctx *fctx; + MemoryContext oldcontext; if (strcmp(Log_filename, "postgresql-%Y-%m-%d_%H%M%S.log") != 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("the log_filename parameter must equal 'postgresql-%%Y-%%m-%%d_%%H%%M%%S.log'"))); - if (SRF_IS_FIRSTCALL()) - { - MemoryContext oldcontext; - TupleDesc tupdesc; - - funcctx = SRF_FIRSTCALL_INIT(); - oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - - fctx = palloc(sizeof(directory_fctx)); - - tupdesc = CreateTemplateTupleDesc(2); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "starttime", - TIMESTAMPOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "filename", - TEXTOID, -1, 0); + /* check to see if caller supports us returning a tuplestore */ + if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("set-valued function called in context that cannot accept a set"))); + if (!(rsinfo->allowedModes & SFRM_Materialize)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("materialize mode required, but it is not allowed in this context"))); - funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc); + /* The tupdesc and tuplestore must be created in ecxt_per_query_memory */ + oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory); - fctx->location = pstrdup(Log_directory); - fctx->dirdesc = AllocateDir(fctx->location); + tupdesc = CreateTemplateTupleDesc(2); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "starttime", + TIMESTAMPOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "filename", + TEXTOID, -1, 0); - if (!fctx->dirdesc) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not open directory \"%s\": %m", - fctx->location))); + randomAccess = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0; + tupstore = tuplestore_begin_heap(randomAccess, false, work_mem); + rsinfo->returnMode = SFRM_Materialize; + rsinfo->setResult = tupstore; + rsinfo->setDesc = tupdesc; - funcctx->user_fctx = fctx; - MemoryContextSwitchTo(oldcontext); - } + MemoryContextSwitchTo(oldcontext); - funcctx = SRF_PERCALL_SETUP(); - fctx = (directory_fctx *) funcctx->user_fctx; + attinmeta = TupleDescGetAttInMetadata(tupdesc); - while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL) + dirdesc = AllocateDir(Log_directory); + while ((de = ReadDir(dirdesc, Log_directory)) != NULL) { char *values[2]; HeapTuple tuple; @@ -584,13 +580,13 @@ pg_logdir_ls_internal(FunctionCallInfo fcinfo) /* Seems the timestamp is OK; prepare and return tuple */ values[0] = timestampbuf; - values[1] = psprintf("%s/%s", fctx->location, de->d_name); + values[1] = psprintf("%s/%s", Log_directory, de->d_name); - tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); + tuple = BuildTupleFromCStrings(attinmeta, values); - SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + tuplestore_puttuple(tupstore, tuple); } - FreeDir(fctx->dirdesc); - SRF_RETURN_DONE(funcctx); + FreeDir(dirdesc); + return (Datum) 0; } |