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))
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 */