Here is an updated patch I have just applied (catalog version updated).
I have added these functions:
pg_stat_file()
pg_read_file()
pg_ls_dir()
pg_reload_conf()
pg_rotate_logfile()
I did not include pg_logdir_ls because that was basically pg_ls_dir with
logic to decode the log file name and convert it to a timestamp. That
seemed best done in the client.
I also renamed a number of the functions to be use verb-noun, rather
than noun-verb.
--
Bruce Momjian | http://candle.pha.pa.us
[email protected] | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Index: doc/src/sgml/func.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/func.sgml,v
retrieving revision 1.276
diff -c -c -r1.276 func.sgml
*** doc/src/sgml/func.sgml 2 Aug 2005 16:11:56 -0000 1.276
--- doc/src/sgml/func.sgml 12 Aug 2005 03:18:29 -0000
***************
*** 9061,9066 ****
--- 9061,9069 ----
<indexterm zone="functions-admin">
<primary>pg_cancel_backend</primary>
</indexterm>
+ <indexterm zone="functions-admin">
+ <primary>pg_reload_conf</primary>
+ </indexterm>
<indexterm zone="functions-admin">
<primary>signal</primary>
***************
*** 9068,9074 ****
</indexterm>
<para>
! The function shown in <xref
linkend="functions-admin-signal-table"> sends control signals to
other server processes. Use of this function is restricted
to superusers.
--- 9071,9077 ----
</indexterm>
<para>
! The functions shown in <xref
linkend="functions-admin-signal-table"> sends control signals to
other server processes. Use of this function is restricted
to superusers.
***************
*** 9090,9115 ****
<entry><type>int</type></entry>
<entry>Cancel a backend's current query</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
! This function returns 1 if successful, 0 if not successful.
The process ID (<literal>pid</literal>) of an active backend can be found
from the <structfield>procpid</structfield> column in the
<structname>pg_stat_activity</structname> view, or by listing the
<command>postgres</command>
processes on the server with <application>ps</>.
</para>
<indexterm zone="functions-admin">
<primary>pg_start_backup</primary>
</indexterm>
-
<indexterm zone="functions-admin">
<primary>pg_stop_backup</primary>
</indexterm>
-
<indexterm zone="functions-admin">
<primary>backup</primary>
</indexterm>
--- 9093,9128 ----
<entry><type>int</type></entry>
<entry>Cancel a backend's current query</entry>
</row>
+ <row>
+ <entry>
+ <literal><function>pg_reload_conf</function>()</literal>
+ </entry>
+ <entry><type>int</type></entry>
+ <entry>Causes server processes to reload their configuration
files</entry>
+ </row>
</tbody>
</tgroup>
</table>
<para>
! These functions return 1 if successful, 0 if not successful.
The process ID (<literal>pid</literal>) of an active backend can be found
from the <structfield>procpid</structfield> column in the
<structname>pg_stat_activity</structname> view, or by listing the
<command>postgres</command>
processes on the server with <application>ps</>.
</para>
+ <para>
+ <function>pg_reload_conf</> sends a SIGHUP signal to the
+ postmaster, causing the reload of the configuration files
+ in all backend processes.
+ </para>
<indexterm zone="functions-admin">
<primary>pg_start_backup</primary>
</indexterm>
<indexterm zone="functions-admin">
<primary>pg_stop_backup</primary>
</indexterm>
<indexterm zone="functions-admin">
<primary>backup</primary>
</indexterm>
***************
*** 9309,9314 ****
--- 9322,9434 ----
appropriate.
</para>
+ <para>
+ The functions shown in <xref
+ linkend="functions-admin-genfile"> provide native file access to
+ files on the machine hosting the server. Only files relative to
+ the cluster directory are allowed, and the logfile directory,
+ because the logfile directory might be stored outside the
+ cluster directory. Use of these functions is restricted to
+ superusers.
+ </para>
+
+ <table id="functions-admin-genfile">
+ <title>Generic File Access Functions</title>
+ <tgroup cols="3">
+ <thead>
+ <row><entry>Name</entry> <entry>Return Type</entry>
<entry>Description</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry>
+
<literal><function>pg_file_length</function>(<parameter>filename_text</parameter>)</literal>
+ <indexterm zone="functions-admin">
+ <primary>pg_file_length</primary>
+ </indexterm>
+ </entry>
+ <entry><type>int8</type></entry>
+ <entry>Returns the file length</entry>
+ </row>
+ <row>
+ <entry>
+
<literal><function>pg_ls_dir</function>(<parameter>dirname_text</parameter>,<parameter>fullpath_bool</parameter>)</literal>
+ <indexterm zone="functions-admin">
+ <primary>pg_ls_dir</primary>
+ </indexterm>
+ </entry>
+ <entry><type>setof text</type></entry>
+ <entry>List the contents of a directory</entry>
+ </row>
+ <row>
+ <entry>
+
<literal><function>pg_read_file</function>(<parameter>filename_text</parameter>,
+
<parameter>offset_int8</parameter>,<parameter>length_int8</parameter>)</literal>
+ </entry>
+ <entry><type>text</type></entry>
+ <entry>Returns the contents of a text file</entry>
+ </row>
+ <row>
+ <entry>
+
<literal><function>pg_stat_file</function>(<parameter>filename_text</parameter>)</literal>
+ </entry>
+ <entry><type>record</type></entry>
+ <entry>Returns information about the file</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <indexterm zone="functions-admin">
+ <primary>pg_read_file</primary>
+ </indexterm>
+ <para>
+ <function>pg_read_file()</> returns part of a textfile, starting
+ at the given offset, returning length bytes. If offset is negative,
+ it is treated relative to the end of the file.
+ </para>
+
+ <indexterm zone="functions-admin">
+ <primary>pg_stat_file</primary>
+ </indexterm>
+ <para>
+ <function>pg_stat_file()</> returns a record containing the
+ length, last accessed timestamp, last modified timestamp,
+ creation timestamp, and a flag indicating if it is a directory.
+ </para>
+
+ <para>
+ The function shown in <xref
+ linkend="functions-admin-logfile"> forces the server
+ logfile to be rotated if <varname>redirect_stderr</>
+ is used for logging. Use of this functions is restricted
+ to superusers.
+ </para>
+
+ <table id="functions-admin-logfile">
+ <title>Backend Logfile Functions</title>
+ <tgroup cols="3">
+ <thead>
+ <row><entry>Name</entry> <entry>Return Type</entry>
<entry>Description</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry>
+ <literal><function>pg_rotate_logfile</function>()</literal>
+ <indexterm zone="functions-admin">
+ <primary>pg_rotate_logfile</primary>
+ </indexterm>
+ </entry>
+ <entry><type>int</type></entry>
+ <entry>Rotate logfile</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
</sect1>
</chapter>
Index: src/backend/postmaster/postmaster.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v
retrieving revision 1.462
diff -c -c -r1.462 postmaster.c
*** src/backend/postmaster/postmaster.c 11 Aug 2005 21:11:44 -0000 1.462
--- src/backend/postmaster/postmaster.c 12 Aug 2005 03:18:32 -0000
***************
*** 3394,3399 ****
--- 3394,3402 ----
}
}
+ if (CheckPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE) && SysLoggerPID != 0)
+ kill(SysLoggerPID, SIGUSR1);
+
PG_SETMASK(&UnBlockSig);
errno = save_errno;
Index: src/backend/postmaster/syslogger.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/postmaster/syslogger.c,v
retrieving revision 1.18
diff -c -c -r1.18 syslogger.c
*** src/backend/postmaster/syslogger.c 21 Jul 2005 18:06:12 -0000 1.18
--- src/backend/postmaster/syslogger.c 12 Aug 2005 03:18:33 -0000
***************
*** 101,106 ****
--- 101,107 ----
* Flags set by interrupt handlers for later service in the main loop.
*/
static volatile sig_atomic_t got_SIGHUP = false;
+ static volatile sig_atomic_t rotation_requested = false;
/* Local subroutines */
***************
*** 117,122 ****
--- 118,124 ----
static char *logfile_getname(pg_time_t timestamp);
static void set_next_rotation_time(void);
static void sigHupHandler(SIGNAL_ARGS);
+ static void sigUsr1Handler(SIGNAL_ARGS);
/*
***************
*** 200,206 ****
pqsignal(SIGQUIT, SIG_IGN);
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
! pqsignal(SIGUSR1, SIG_IGN);
pqsignal(SIGUSR2, SIG_IGN);
/*
--- 202,208 ----
pqsignal(SIGQUIT, SIG_IGN);
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
! pqsignal(SIGUSR1, sigUsr1Handler); /* request log rotation */
pqsignal(SIGUSR2, SIG_IGN);
/*
***************
*** 235,241 ****
/* main worker loop */
for (;;)
{
- bool rotation_requested = false;
bool time_based_rotation = false;
#ifndef WIN32
--- 237,242 ----
***************
*** 726,731 ****
--- 727,734 ----
char *filename;
FILE *fh;
+ rotation_requested = false;
+
/*
* When doing a time-based rotation, invent the new logfile name based
* on the planned rotation time, not current time, to avoid "slippage"
***************
*** 876,878 ****
--- 879,888 ----
{
got_SIGHUP = true;
}
+
+ /* SIGUSR1: set flag to rotate logfile */
+ static void
+ sigUsr1Handler(SIGNAL_ARGS)
+ {
+ rotation_requested = true;
+ }
Index: src/backend/utils/adt/Makefile
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/adt/Makefile,v
retrieving revision 1.58
diff -c -c -r1.58 Makefile
*** src/backend/utils/adt/Makefile 29 Jul 2005 14:46:57 -0000 1.58
--- src/backend/utils/adt/Makefile 12 Aug 2005 03:18:33 -0000
***************
*** 24,30 ****
tid.o timestamp.o varbit.o varchar.o varlena.o version.o xid.o \
network.o mac.o inet_net_ntop.o inet_net_pton.o \
ri_triggers.o pg_lzcompress.o pg_locale.o formatting.o \
! ascii.o quote.o pgstatfuncs.o encode.o dbsize.o
like.o: like.c like_match.c
--- 24,30 ----
tid.o timestamp.o varbit.o varchar.o varlena.o version.o xid.o \
network.o mac.o inet_net_ntop.o inet_net_pton.o \
ri_triggers.o pg_lzcompress.o pg_locale.o formatting.o \
! ascii.o quote.o pgstatfuncs.o encode.o dbsize.o genfile.o
like.o: like.c like_match.c
Index: src/backend/utils/adt/misc.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/adt/misc.c,v
retrieving revision 1.45
diff -c -c -r1.45 misc.c
*** src/backend/utils/adt/misc.c 4 Jul 2005 04:51:50 -0000 1.45
--- src/backend/utils/adt/misc.c 12 Aug 2005 03:18:33 -0000
***************
*** 21,34 ****
--- 21,43 ----
#include "commands/dbcommands.h"
#include "miscadmin.h"
#include "storage/procarray.h"
+ #include "storage/pmsignal.h"
#include "storage/fd.h"
#include "utils/builtins.h"
+ #include "utils/elog.h"
#include "funcapi.h"
#include "catalog/pg_type.h"
#include "catalog/pg_tablespace.h"
+ #include "postmaster/syslogger.h"
#define atooid(x) ((Oid) strtoul((x), NULL, 10))
+ typedef struct
+ {
+ char *location;
+ DIR *dirdesc;
+ } directory_fctx;
+
/*
* Check if data is Null
***************
*** 107,112 ****
--- 116,166 ----
PG_RETURN_INT32(pg_signal_backend(PG_GETARG_INT32(0), SIGINT));
}
+
+ Datum
+ pg_reload_conf(PG_FUNCTION_ARGS)
+ {
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ (errmsg("must be superuser to signal the
postmaster"))));
+
+ if (kill(PostmasterPid, SIGHUP))
+ {
+ ereport(WARNING,
+ (errmsg("failed to send signal to postmaster:
%m")));
+
+ PG_RETURN_INT32(0);
+ }
+
+ PG_RETURN_INT32(1);
+ }
+
+
+ /*
+ * Rotate log file
+ */
+ Datum
+ pg_rotate_logfile(PG_FUNCTION_ARGS)
+ {
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ (errmsg("must be superuser to rotate log
files"))));
+
+ if (!Redirect_stderr)
+ {
+ ereport(NOTICE,
+ (errcode(ERRCODE_WARNING),
+ errmsg("no logfile configured; rotation not
supported")));
+ PG_RETURN_INT32(0);
+ }
+
+ SendPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE);
+
+ PG_RETURN_INT32(0);
+ }
+
#ifdef NOT_USED
/* Disabled in 8.0 due to reliability concerns; FIXME someday */
Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/catalog/pg_proc.h,v
retrieving revision 1.380
diff -c -c -r1.380 pg_proc.h
*** src/include/catalog/pg_proc.h 2 Aug 2005 16:11:57 -0000 1.380
--- src/include/catalog/pg_proc.h 12 Aug 2005 03:18:41 -0000
***************
*** 3049,3054 ****
--- 3049,3071 ----
DATA(insert OID = 2173 ( pg_stop_backup PGNSP PGUID 12
f f t f v 0 25 "" _null_ _null_ _null_ pg_stop_backup - _null_ ));
DESCR("Finish taking an online backup");
+ DATA(insert OID = 2621 ( pg_reload_conf PGNSP PGUID 12 f f t f v 0 23
"" _null_ _null_ _null_ pg_reload_conf - _null_ ));
+ DESCR("Reload configuration files");
+
+ DATA(insert OID = 2622 ( pg_rotate_logfile PGNSP PGUID 12 f f t f
v 0 23 "" _null_ _null_ _null_ pg_rotate_logfile - _null_ ));
+ DESCR("Rotate log file");
+
+
+ DATA(insert OID = 2623 ( pg_stat_file PGNSP PGUID 12 f f t f v 1 2249
"25" _null_ _null_ _null_ pg_stat_file - _null_ ));
+ DESCR("Return file information");
+ DATA(insert OID = 2624 ( pg_file_length PGNSP PGUID 14 f f t f v 1
20 "25" _null_ _null_ _null_ "SELECT len FROM pg_stat_file($1) AS s(len int8, c
timestamp, a timestamp, m timestamp, i bool)" - _null_ ));
+ DESCR("Return file length");
+ DATA(insert OID = 2625 ( pg_read_file PGNSP PGUID 12 f f t f v 3 25 "25
20 20" _null_ _null_ _null_ pg_read_file - _null_ ));
+ DESCR("Read text from a file");
+ DATA(insert OID = 2626 ( pg_ls_dir PGNSP PGUID 12 f f t t v 1
25 "25" _null_ _null_ _null_ pg_ls_dir - _null_ ));
+ DESCR("List all file in a directory");
+
+
/* Aggregates (moved here from pg_aggregate for 7.3) */
DATA(insert OID = 2100 ( avg PGNSP PGUID 12 t f f f
i 1 1700 "20" _null_ _null_ _null_ aggregate_dummy - _null_ ));
Index: src/include/storage/pmsignal.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/storage/pmsignal.h,v
retrieving revision 1.12
diff -c -c -r1.12 pmsignal.h
*** src/include/storage/pmsignal.h 28 Jun 2005 19:51:25 -0000 1.12
--- src/include/storage/pmsignal.h 12 Aug 2005 03:18:42 -0000
***************
*** 25,30 ****
--- 25,31 ----
PMSIGNAL_PASSWORD_CHANGE, /* pg_auth file has changed */
PMSIGNAL_WAKEN_CHILDREN, /* send a SIGUSR1 signal to all
backends */
PMSIGNAL_WAKEN_ARCHIVER, /* send a NOTIFY signal to xlog
archiver */
+ PMSIGNAL_ROTATE_LOGFILE, /* send SIGUSR1 to syslogger to rotate
logfile */
NUM_PMSIGNALS /* Must be last value of enum!
*/
} PMSignalReason;
Index: src/include/utils/builtins.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/utils/builtins.h,v
retrieving revision 1.262
diff -c -c -r1.262 builtins.h
*** src/include/utils/builtins.h 29 Jul 2005 14:47:04 -0000 1.262
--- src/include/utils/builtins.h 12 Aug 2005 03:18:42 -0000
***************
*** 374,385 ****
--- 374,392 ----
extern Datum pg_complete_relation_size_name(PG_FUNCTION_ARGS);
extern Datum pg_size_pretty(PG_FUNCTION_ARGS);
+ /* genfile.c */
+ extern Datum pg_stat_file(PG_FUNCTION_ARGS);
+ extern Datum pg_read_file(PG_FUNCTION_ARGS);
+ extern Datum pg_ls_dir(PG_FUNCTION_ARGS);
+
/* misc.c */
extern Datum nullvalue(PG_FUNCTION_ARGS);
extern Datum nonnullvalue(PG_FUNCTION_ARGS);
extern Datum current_database(PG_FUNCTION_ARGS);
extern Datum pg_cancel_backend(PG_FUNCTION_ARGS);
+ extern Datum pg_reload_conf(PG_FUNCTION_ARGS);
extern Datum pg_tablespace_databases(PG_FUNCTION_ARGS);
+ extern Datum pg_rotate_logfile(PG_FUNCTION_ARGS);
/* not_in.c */
extern Datum int4notin(PG_FUNCTION_ARGS);
/*-------------------------------------------------------------------------
*
* genfile.c
*
*
* Copyright (c) 2004, PostgreSQL Global Development Group
*
* Author: Andreas Pflug <[EMAIL PROTECTED]>
*
* IDENTIFICATION
* $PostgreSQL: $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <sys/file.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include "utils/builtins.h"
#include "miscadmin.h"
#include "storage/fd.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
extern char *Log_directory;
typedef struct
{
char *location;
DIR *dirdesc;
} directory_fctx;
/*
* Return an absolute path. Argument may be absolute or
* relative to the DataDir.
*/
static char *check_and_make_absolute(text *arg)
{
char *filename;
int filename_len = VARSIZE(arg) - VARHDRSZ;
int datadir_len = strlen(DataDir);
filename = palloc(filename_len + 1);
memcpy(filename, VARDATA(arg), filename_len);
filename[filename_len] = '\0';
canonicalize_path(filename);
filename_len = strlen(filename); /* recompute */
/*
* Prevent reference to the parent directory.
* "..a.." is a valid file name though.
*/
if (strcmp(filename, "..") == 0 ||
/* beginning */
strncmp(filename, "../", 3) == 0 ||
/* beginning */
strcmp(filename, "/..") == 0 ||
/* beginning */
strncmp(filename, "../", 3) == 0 ||
/* beginning */
strstr(filename, "/../") != NULL ||
/* middle */
strncmp(filename + filename_len - 3, "/..", 3) == 0) /* end
*/
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("Reference to a parent directory
(\"..\") not allowed"))));
if (is_absolute_path(filename))
{
/* The log directory might be outside our datadir, but allow it
*/
if ((strncmp(filename, Log_directory, strlen(Log_directory)) == 0 &&
(filename[strlen(Log_directory)] == '/' ||
filename[strlen(Log_directory)] == '\0')) ||
(strncmp(filename, DataDir, datadir_len) == 0 &&
(filename[datadir_len] == '/' ||
filename[datadir_len] == '\0')))
return filename;
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("Absolute path not allowed"))));
return NULL;
}
else
{
char *absname = palloc(datadir_len + filename_len + 2);
sprintf(absname, "%s/%s", DataDir, filename);
pfree(filename);
return absname;
}
}
Datum pg_file_read(PG_FUNCTION_ARGS)
{
size_t bytes_to_read = PG_GETARG_INT64(2);
int64 seek_offset = PG_GETARG_INT64(1);
char *buf = 0;
size_t nbytes;
FILE *file;
char *filename;
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("only superuser may access generic
file functions"))));
filename = check_and_make_absolute(PG_GETARG_TEXT_P(0));
if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
{
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open file %s for reading:
%m", filename)));
PG_RETURN_NULL();
}
if (fseeko(file, (off_t)seek_offset,
(seek_offset >= 0) ? SEEK_SET : SEEK_END) != 0)
{
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not seek in file %s: %m",
filename)));
PG_RETURN_NULL();
}
buf = palloc(bytes_to_read + VARHDRSZ);
nbytes = fread(VARDATA(buf), bytes_to_read, 1, file);
FreeFile(file);
if (nbytes < 0)
{
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not read file %s: %m",
filename)));
PG_RETURN_NULL();
}
VARATT_SIZEP(buf) = nbytes + VARHDRSZ;
pfree(filename);
PG_RETURN_TEXT_P(buf);
}
Datum pg_file_stat(PG_FUNCTION_ARGS)
{
AttInMetadata *attinmeta;
char *filename =
check_and_make_absolute(PG_GETARG_TEXT_P(0));
struct stat fst;
char lenbuf[30], cbuf[30], abuf[30], mbuf[30], dirbuf[2];
char *values[5] = {lenbuf, cbuf, abuf, mbuf, dirbuf};
pg_time_t timestamp;
HeapTuple tuple;
TupleDesc tupdesc = CreateTemplateTupleDesc(5, false);
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("only superuser may access generic
file functions"))));
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "length", INT8OID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "ctime", TIMESTAMPOID, -1,
0);
TupleDescInitEntry(tupdesc, (AttrNumber) 3, "atime", TIMESTAMPOID, -1,
0);
TupleDescInitEntry(tupdesc, (AttrNumber) 4, "mtime", TIMESTAMPOID, -1,
0);
TupleDescInitEntry(tupdesc, (AttrNumber) 5, "isdir", BOOLOID, -1, 0);
attinmeta = TupleDescGetAttInMetadata(tupdesc);
if (stat(filename, &fst) < 0)
{
ereport(WARNING,
(errcode_for_file_access(),
errmsg("could not stat file %s: %m",
filename)));
MemSet(values, 0, sizeof(char *) * 5);
tuple = BuildTupleFromCStrings(attinmeta, values);
}
else
{
snprintf(lenbuf, 30, INT64_FORMAT, (int64)fst.st_size);
timestamp = fst.st_ctime;
pg_strftime(cbuf, 30, "%F %T", pg_localtime(×tamp,
global_timezone));
timestamp = fst.st_atime;
pg_strftime(abuf, 30, "%F %T", pg_localtime(×tamp,
global_timezone));
timestamp = fst.st_mtime;
pg_strftime(mbuf, 30, "%F %T", pg_localtime(×tamp,
global_timezone));
if (fst.st_mode & S_IFDIR)
strcpy(dirbuf, "t");
else
strcpy(dirbuf, "f");
tuple = BuildTupleFromCStrings(attinmeta, values);
}
pfree(filename);
PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
}
Datum pg_dir_ls(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx;
struct dirent *de;
directory_fctx *fctx;
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("only superuser may access generic
file functions"))));
if (SRF_IS_FIRSTCALL())
{
MemoryContext oldcontext;
funcctx = SRF_FIRSTCALL_INIT();
oldcontext =
MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
fctx = palloc(sizeof(directory_fctx));
fctx->location = check_and_make_absolute(PG_GETARG_TEXT_P(0));
fctx->dirdesc = AllocateDir(fctx->location);
if (!fctx->dirdesc)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("%s is not browsable: %m",
fctx->location)));
if (PG_ARGISNULL(1) || !PG_GETARG_BOOL(1))
{
pfree(fctx->location);
fctx->location = NULL;
}
funcctx->user_fctx = fctx;
MemoryContextSwitchTo(oldcontext);
}
funcctx = SRF_PERCALL_SETUP();
fctx = (directory_fctx*) funcctx->user_fctx;
if (!fctx->dirdesc) /* not a readable directory */
SRF_RETURN_DONE(funcctx);
while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL)
{
char *name;
text *result;
int len;
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
continue;
if (fctx->location)
{
char *path = palloc(strlen(fctx->location) +
strlen(de->d_name) + 2);
sprintf(path, "%s/%s", fctx->location, de->d_name);
name = path;
}
else
name = de->d_name;
len = strlen(name);
result = palloc(len + VARHDRSZ);
VARATT_SIZEP(result) = len + VARHDRSZ;
memcpy(VARDATA(result), name, len);
SRF_RETURN_NEXT(funcctx, PointerGetDatum(result));
}
FreeDir(fctx->dirdesc);
SRF_RETURN_DONE(funcctx);
}
---------------------------(end of broadcast)---------------------------
TIP 6: explain analyze is your friend