diff options
Diffstat (limited to 'src/backend/utils/adt/genfile.c')
-rw-r--r-- | src/backend/utils/adt/genfile.c | 83 |
1 files changed, 42 insertions, 41 deletions
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c index a97cbea2483..a5822d6201c 100644 --- a/src/backend/utils/adt/genfile.c +++ b/src/backend/utils/adt/genfile.c @@ -518,67 +518,68 @@ pg_ls_dir_1arg(PG_FUNCTION_ARGS) return pg_ls_dir(fcinfo); } -/* Generic function to return a directory listing of files */ +/* + * Generic function to return a directory listing of files. + */ static Datum pg_ls_dir_files(FunctionCallInfo fcinfo, const char *dir) { - FuncCallContext *funcctx; + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + bool randomAccess; + TupleDesc tupdesc; + Tuplestorestate *tupstore; + DIR *dirdesc; struct dirent *de; - directory_fctx *fctx; - - if (SRF_IS_FIRSTCALL()) - { - MemoryContext oldcontext; - TupleDesc tupdesc; - - funcctx = SRF_FIRSTCALL_INIT(); - oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - - fctx = palloc(sizeof(directory_fctx)); + MemoryContext oldcontext; - tupdesc = CreateTemplateTupleDesc(3, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", - TEXTOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "size", - INT8OID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 3, "modification", - TIMESTAMPTZOID, -1, 0); - funcctx->tuple_desc = BlessTupleDesc(tupdesc); + /* 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"))); - fctx->location = pstrdup(dir); - fctx->dirdesc = AllocateDir(fctx->location); + /* The tupdesc and tuplestore must be created in ecxt_per_query_memory */ + oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory); - if (!fctx->dirdesc) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not open directory \"%s\": %m", - fctx->location))); + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + elog(ERROR, "return type must be a row type"); - funcctx->user_fctx = fctx; - MemoryContextSwitchTo(oldcontext); - } + 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 = SRF_PERCALL_SETUP(); - fctx = (directory_fctx *) funcctx->user_fctx; + MemoryContextSwitchTo(oldcontext); - while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL) + /* + * Now walk the directory. Note that we must do this within a single SRF + * call, not leave the directory open across multiple calls, since we + * can't count on the SRF being run to completion. + */ + dirdesc = AllocateDir(dir); + while ((de = ReadDir(dirdesc, dir)) != NULL) { Datum values[3]; bool nulls[3]; char path[MAXPGPATH * 2]; struct stat attrib; - HeapTuple tuple; /* Skip hidden files */ if (de->d_name[0] == '.') continue; /* Get the file info */ - snprintf(path, sizeof(path), "%s/%s", fctx->location, de->d_name); + snprintf(path, sizeof(path), "%s/%s", dir, de->d_name); if (stat(path, &attrib) < 0) ereport(ERROR, (errcode_for_file_access(), - errmsg("could not stat directory \"%s\": %m", dir))); + errmsg("could not stat file \"%s\": %m", path))); /* Ignore anything but regular files */ if (!S_ISREG(attrib.st_mode)) @@ -589,12 +590,12 @@ pg_ls_dir_files(FunctionCallInfo fcinfo, const char *dir) values[2] = TimestampTzGetDatum(time_t_to_timestamptz(attrib.st_mtime)); memset(nulls, 0, sizeof(nulls)); - tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); - SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + tuplestore_putvalues(tupstore, tupdesc, values, nulls); } - FreeDir(fctx->dirdesc); - SRF_RETURN_DONE(funcctx); + FreeDir(dirdesc); + tuplestore_donestoring(tupstore); + return (Datum) 0; } /* Function to return the list of files in the log directory */ |