Server instrumentation - Mailing list pgsql-patches

From Andreas Pflug
Subject Server instrumentation
Date
Msg-id 42A95E2D.5010304@pse-consulting.de
Whole thread Raw
Responses Re: Server instrumentation  (Tom Lane <tgl@sss.pgh.pa.us>)
Re: Server instrumentation  (Andreas Pflug <pgadmin@pse-consulting.de>)
List pgsql-patches
This post includes "dbsize backend integration" and "Server
instrumentation: pg_terminate_backend, pg_reload_conf"

Server instrumentation functions included:

pg_tablespace_size()
pg_database_size()
pg_relation_size()
pg_size_pretty()
     well-known from contrib/dbsize, waiting in unapplied patches
http://candle.pha.pa.us/mhonarc/patches/msg00002.html


The rest is superuser only:

pg_terminate_backend()
     exposing kill -SIGTERM <backendpid> to the client
pg_reload_conf()
     SIGHUP to reload configuration files


pg_logfile_rotate()
     Logfile rotation
pg_logdir_ls() and view pg_logdir_ls
     lists all available log files in the log directory.

As posted in the initial version of the logger subprocess from July 2004.


pg_file_stat()
pg_file_length()
pg_file_read()
pg_file_write()
pg_file_unlink()
pg_file_rename()
pg_dir_ls()
     generic file functions to access files in logdir and cluster dir.
These functions where implemented as initiated by Bruce, and discussed
intensively in
http://archives.postgresql.org/pgsql-patches/2004-07/msg00287.php


All functions are fully documented.
Additionally, documentation for pg_postmaster_start_time is included,
the code itself ist posted by Matthias Schmidt
http://candle.pha.pa.us/mhonarc/patches/msg00008.html

Regards,
Andreas

/*
 * dbsize.c
 * object size functions
 *
 * Copyright (c) 2002-2005, PostgreSQL Global Development Group
 *
 * IDENTIFICATION
 *      $PostgreSQL: pgsql/contrib/dbsize/dbsize.c,v 1.17 2005/05/27 00:57:48 neilc Exp $
 *
 */

#include "postgres.h"

#include <sys/types.h>
#include <sys/stat.h>

#include "access/heapam.h"
#include "catalog/namespace.h"
#include "catalog/pg_tablespace.h"
#include "commands/dbcommands.h"
#include "miscadmin.h"
#include "storage/fd.h"
#include "utils/builtins.h"
#include "utils/syscache.h"


/* Return physical size of directory contents, or 0 if dir doesn't exist */
static int64
db_dir_size(const char *path)
{
    int64        dirsize = 0;
    struct dirent *direntry;
    DIR         *dirdesc;
    char filename[MAXPGPATH];

    dirdesc = AllocateDir(path);

    if (!dirdesc)
        return 0;

    while ((direntry = readdir(dirdesc)) != NULL)
    {
        struct stat fst;

        if (strcmp(direntry->d_name, ".") == 0 ||
            strcmp(direntry->d_name, "..") == 0)
            continue;

        snprintf(filename, MAXPGPATH, "%s/%s", path, direntry->d_name);

        if (stat(filename, &fst) < 0)
            ereport(ERROR,
                    (errcode_for_file_access(),
                     errmsg("could not stat \"%s\": %m", filename)));
        dirsize += fst.st_size;
    }

    FreeDir(dirdesc);
    return dirsize;
}


static int64
calculate_database_size(Oid dbOid)
{
    int64        totalsize = 0;
    DIR         *dirdesc;
    struct dirent *direntry;
    char pathname[MAXPGPATH];

    /* Shared storage in pg_global is not counted */

    /* Include pg_default storage */
    snprintf(pathname, MAXPGPATH, "%s/base/%u", DataDir, dbOid);
    totalsize += db_dir_size(pathname);

    /* Scan the non-default tablespaces */
    snprintf(pathname, MAXPGPATH, "%s/pg_tblspc", DataDir);
    dirdesc = AllocateDir(pathname);
    if (!dirdesc)
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not open tablespace directory \"%s\": %m",
                        pathname)));

    while ((direntry = readdir(dirdesc)) != NULL)
    {
        if (strcmp(direntry->d_name, ".") == 0 ||
            strcmp(direntry->d_name, "..") == 0)
            continue;

        snprintf(pathname, MAXPGPATH, "%s/pg_tblspc/%s/%u",
                 DataDir, direntry->d_name, dbOid);
        totalsize += db_dir_size(pathname);
    }

    FreeDir(dirdesc);

    /* Complain if we found no trace of the DB at all */
    if (!totalsize)
        ereport(ERROR,
                (ERRCODE_UNDEFINED_DATABASE,
                 errmsg("database with OID %u does not exist", dbOid)));

    return totalsize;
}

/*
 * calculate total size of tablespace
 */
Datum
pg_tablespace_size(PG_FUNCTION_ARGS)
{
    Oid tblspcOid = PG_GETARG_OID(0);
    char tblspcPath[MAXPGPATH];
    char pathname[MAXPGPATH];
    int64        totalsize=0;
    DIR         *dirdesc;
    struct dirent *direntry;

    if (tblspcOid == DEFAULTTABLESPACE_OID)
        snprintf(tblspcPath, MAXPGPATH, "%s/base", DataDir);
    else if (tblspcOid == GLOBALTABLESPACE_OID)
        snprintf(tblspcPath, MAXPGPATH, "%s/global", DataDir);
    else
        snprintf(tblspcPath, MAXPGPATH, "%s/pg_tblspc/%u", DataDir, tblspcOid);

    dirdesc = AllocateDir(tblspcPath);

    if (!dirdesc)
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not open tablespace directory \"%s\": %m",
                        tblspcPath)));

    while ((direntry = readdir(dirdesc)) != NULL)
    {
        struct stat fst;

        if (strcmp(direntry->d_name, ".") == 0 ||
            strcmp(direntry->d_name, "..") == 0)
            continue;

        snprintf(pathname, MAXPGPATH, "%s/%s", tblspcPath, direntry->d_name);

        if (stat(pathname, &fst) < 0)
            ereport(ERROR,
                    (errcode_for_file_access(),
                     errmsg("could not stat \"%s\": %m", pathname)));
        totalsize += fst.st_size;

        if (fst.st_mode & S_IFDIR)
            totalsize += db_dir_size(pathname);
    }

    FreeDir(dirdesc);

    PG_RETURN_INT64(totalsize);
}


/*
 * calculate size of database in all tablespaces
 */
Datum
pg_database_size(PG_FUNCTION_ARGS)
{
    Oid dbOid = PG_GETARG_OID(0);

    PG_RETURN_INT64(calculate_database_size(dbOid));
}


/* Calculate relation size given tablespace and relation OIDs */
static int64
calculate_relation_size(Oid tblspcOid, Oid relnodeOid)
{
    int64        totalsize=0;
    unsigned int segcount=0;
    char dirpath[MAXPGPATH];
    char pathname[MAXPGPATH];

    if (!tblspcOid)
        tblspcOid = MyDatabaseTableSpace;

    if (tblspcOid == DEFAULTTABLESPACE_OID)
        snprintf(dirpath, MAXPGPATH, "%s/base/%u", DataDir, MyDatabaseId);
    else if (tblspcOid == GLOBALTABLESPACE_OID)
        snprintf(dirpath, MAXPGPATH, "%s/global", DataDir);
    else
        snprintf(dirpath, MAXPGPATH, "%s/pg_tblspc/%u/%u",
                 DataDir, tblspcOid, MyDatabaseId);

    for (segcount = 0 ;; segcount++)
    {
        struct stat fst;

        if (segcount == 0)
            snprintf(pathname, MAXPGPATH, "%s/%u",
                     dirpath, relnodeOid);
        else
            snprintf(pathname, MAXPGPATH, "%s/%u.%u",
                     dirpath, relnodeOid, segcount);

        if (stat(pathname, &fst) < 0)
        {
            if (errno == ENOENT)
                break;
            else
                ereport(ERROR,
                        (errcode_for_file_access(),
                         errmsg("could not stat \"%s\": %m", pathname)));
        }
        totalsize += fst.st_size;
    }

    return totalsize;
}

/*
 * calculate size of relation
 */
Datum
pg_relation_size(PG_FUNCTION_ARGS)
{
    Oid         relOid=PG_GETARG_OID(0);
    HeapTuple   tuple;
    Form_pg_class pg_class;
    Oid            relnodeOid;
    Oid         tblspcOid;

    tuple = SearchSysCache(RELOID,
                           ObjectIdGetDatum(relOid),
                           0, 0, 0);
    if (!HeapTupleIsValid(tuple))
        ereport(ERROR,
                (ERRCODE_UNDEFINED_TABLE,
                 errmsg("relation with OID %u does not exist", relOid)));

    pg_class = (Form_pg_class) GETSTRUCT(tuple);
    relnodeOid = pg_class->relfilenode;
    tblspcOid = pg_class->reltablespace;

    ReleaseSysCache(tuple);

    PG_RETURN_INT64(calculate_relation_size(tblspcOid, relnodeOid));
}


/*
 * formatting with size units
 */
Datum
pg_size_pretty(PG_FUNCTION_ARGS)
{
    int64 size=PG_GETARG_INT64(0);
    char *result=palloc(50+VARHDRSZ);
    int64 limit = 10*1024;
    int64 mult=1;

    if (size < limit*mult)
        snprintf(VARDATA(result), 50, INT64_FORMAT" bytes",
                 size);
    else
    {
        mult *= 1024;
        if (size < limit*mult)
             snprintf(VARDATA(result), 50, INT64_FORMAT " kB",
                      (size+mult/2) / mult);
        else
        {
            mult *= 1024;
            if (size < limit*mult)
                snprintf(VARDATA(result), 50, INT64_FORMAT " MB",
                         (size+mult/2) / mult);
            else
            {
                mult *= 1024;
                if (size < limit*mult)
                    snprintf(VARDATA(result), 50, INT64_FORMAT " GB",
                             (size+mult/2) / mult);
                else
                {
                    mult *= 1024;
                    snprintf(VARDATA(result), 50, INT64_FORMAT " TB",
                             (size+mult/2) / mult);
                }
            }
        }
    }

    VARATT_SIZEP(result) = strlen(VARDATA(result)) + VARHDRSZ;

    PG_RETURN_TEXT_P(result);
}

/*-------------------------------------------------------------------------
 *
 * genfile.c
 *
 *
 * Copyright (c) 2004, PostgreSQL Global Development Group
 *
 * Author: Andreas Pflug <pgadmin@pse-consulting.de>
 *
 * 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"

#ifdef WIN32

/* we don't want *nix emulating retry stuff here, but the native behaviour */

#ifdef rename
#undef rename
#endif

#ifdef unlink
#undef unlink
#endif

#endif

extern  char *Log_directory;


typedef struct
{
    char *location;
    DIR *dirdesc;
} directory_fctx;

/*-----------------------
 * some helper functions
 */

/*
 * Return an absolute path. Argument may be absolute or
 * relative to the DataDir.
 */
static char *absClusterPath(text *arg, bool logAllowed)
{
    char *filename;
    int len=VARSIZE(arg) - VARHDRSZ;
    int dlen = strlen(DataDir);

    filename = palloc(len+1);
    memcpy(filename, VARDATA(arg), len);
    filename[len] = 0;

    if (strstr(filename, "..") != NULL)
      ereport(ERROR,
              (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
               (errmsg("No .. allowed in filenames"))));

    if (is_absolute_path(filename))
    {
        if (logAllowed && !strncmp(filename, Log_directory, strlen(Log_directory)))
            return filename;
        if (strncmp(filename, DataDir, dlen))
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                     (errmsg("Absolute path not allowed"))));

        return filename;
    }
    else
    {
        char *absname = palloc(dlen+len+2);
        sprintf(absname, "%s/%s", DataDir, filename);
        pfree(filename);
        return absname;
    }
}


/*
 * check for superuser, bark if not.
 */
static void
requireSuperuser(void)
{
    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 (errmsg("only superuser may access generic file functions"))));
}



/* ------------------------------------
 * generic file handling functions
 */


Datum pg_file_stat(PG_FUNCTION_ARGS)
{
    AttInMetadata *attinmeta = NULL;
    char *    filename = absClusterPath(PG_GETARG_TEXT_P(0), true);
    struct stat fst;
    int64 length;
    char lenbuf[30];
    char cbuf[30], abuf[30], mbuf[30], dbuf[]="f";
    char *values[5] =
       { lenbuf, cbuf, abuf, mbuf, dbuf };

    pg_time_t timestamp;
    HeapTuple tuple;

    if (attinmeta == NULL)
    {
        TupleDesc tupdesc = CreateTemplateTupleDesc(5, false);

        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)));

        strcpy(lenbuf, "-1");
        strcpy(cbuf, "NULL");
        strcpy(abuf, "NULL");
        strcpy(mbuf, "NULL");
    }
    else
    {
        length = fst.st_size;
        snprintf(lenbuf, 30, INT64_FORMAT, length);

        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)
          dbuf[0] = 't';
    }
    tuple = BuildTupleFromCStrings(attinmeta, values);

    PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
}


Datum pg_file_read(PG_FUNCTION_ARGS)
{
    size_t size;
    char *buf=0;
    size_t nbytes;
    int64 pos;
    FILE *f;
    char *filename;

    requireSuperuser();

    filename = absClusterPath(PG_GETARG_TEXT_P(0), true);
    pos = PG_GETARG_INT64(1);
    size = PG_GETARG_INT64(2);

    f = fopen(filename, "rb");
    if (!f)
    {
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not open file %s for reading: %m", filename)));
        PG_RETURN_NULL();
    }

    if (pos >= 0)
        fseek(f, pos, SEEK_SET);
    else
        fseek(f, pos, SEEK_END);


    buf = palloc(size + VARHDRSZ);

    nbytes = fread(VARDATA(buf), 1, size, f);
    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;
    fclose(f);

    PG_RETURN_TEXT_P(buf);
}


Datum pg_file_write(PG_FUNCTION_ARGS)
{
    FILE *f;
    char *filename;
    text *data;
    int64 count = 0;

    requireSuperuser();

    filename = absClusterPath(PG_GETARG_TEXT_P(0), false);
    data = PG_GETARG_TEXT_P(1);

    if (PG_ARGISNULL(2) || !PG_GETARG_BOOL(2))
    {
        struct stat fst;
        if (stat(filename, &fst) >= 0)
            ereport(ERROR,
                    (ERRCODE_DUPLICATE_FILE,
                     errmsg("file %s exists", filename)));

        f = fopen(filename, "wb");
    }
    else
        f = fopen(filename, "ab");

    if (!f)
    {
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could open file %s for writing: %m", filename)));
    }

    if (VARSIZE(data) != 0)
    {
        count = fwrite(VARDATA(data), 1, VARSIZE(data) - VARHDRSZ, f);

        if (count != VARSIZE(data) - VARHDRSZ)
            ereport(ERROR,
                    (errcode_for_file_access(),
                     errmsg("error writing file %s: %m", filename)));
    }
    fclose(f);

    PG_RETURN_INT64(count);
}


Datum pg_file_rename(PG_FUNCTION_ARGS)
{
    char *fn1, *fn2, *fn3;
    int rc;

    requireSuperuser();

    if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
        PG_RETURN_NULL();

    fn1=absClusterPath(PG_GETARG_TEXT_P(0), false);
    fn2=absClusterPath(PG_GETARG_TEXT_P(1), false);
    if (PG_ARGISNULL(2))
        fn3=0;
    else
        fn3=absClusterPath(PG_GETARG_TEXT_P(2), false);

    if (access(fn1, W_OK) < 0)
    {
        ereport(WARNING,
                (errcode_for_file_access(),
                 errmsg("file %s not accessible: %m", fn1)));

        PG_RETURN_BOOL(false);
    }

    if (fn3 && access(fn2, W_OK) < 0)
    {
        ereport(WARNING,
                (errcode_for_file_access(),
                 errmsg("file %s not accessible: %m", fn2)));

        PG_RETURN_BOOL(false);
    }


    rc = access(fn3 ? fn3 : fn2, 2);
    if (rc >= 0 || errno != ENOENT)
    {
        ereport(ERROR,
                (ERRCODE_DUPLICATE_FILE,
                 errmsg("cannot rename to target file %s", fn3 ? fn3 : fn2)));
    }

    if (fn3)
    {
        if (rename(fn2, fn3) != 0)
        {
            ereport(ERROR,
                    (errcode_for_file_access(),
                     errmsg("could not rename %s to %s: %m", fn2, fn3)));
        }
        if (rename(fn1, fn2) != 0)
        {
            ereport(WARNING,
                    (errcode_for_file_access(),
                     errmsg("could not rename %s to %s: %m", fn1, fn2)));

            if (rename(fn3, fn2) != 0)
            {
                ereport(ERROR,
                        (errcode_for_file_access(),
                         errmsg("could not rename %s back to %s: %m", fn3, fn2)));
            }
            else
            {
                ereport(ERROR,
                        (ERRCODE_UNDEFINED_FILE,
                         errmsg("renaming %s to %s was reverted", fn2, fn3)));

            }
        }
    }
    else if (rename(fn1, fn2) != 0)
    {
            ereport(WARNING,
                    (errcode_for_file_access(),
                     errmsg("renaming %s to %s %m", fn1, fn2)));
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not rename %s to %s: %m", fn1, fn2)));
    }

    PG_RETURN_BOOL(true);
}


Datum pg_file_unlink(PG_FUNCTION_ARGS)
{
    char *filename;

    requireSuperuser();

    filename = absClusterPath(PG_GETARG_TEXT_P(0), false);

    if (access(filename, W_OK) < 0)
    {
        if (errno == ENOENT)
            PG_RETURN_BOOL(false);
        else
            ereport(ERROR,
                    (errcode_for_file_access(),
                     errmsg("file %s not accessible: %m", filename)));

    }

    if (unlink(filename) < 0)
    {
        ereport(WARNING,
                (errcode_for_file_access(),
                 errmsg("could not unlink file %s: %m", filename)));

        PG_RETURN_BOOL(false);
    }
    PG_RETURN_BOOL(true);
}


Datum pg_dir_ls(PG_FUNCTION_ARGS)
{
    FuncCallContext *funcctx;
    struct dirent *de;
    directory_fctx *fctx;

    requireSuperuser();

    if (SRF_IS_FIRSTCALL())
    {
        MemoryContext oldcontext;

        funcctx=SRF_FIRSTCALL_INIT();
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

        fctx = palloc(sizeof(directory_fctx));
        fctx->location = absClusterPath(PG_GETARG_TEXT_P(0), false);

        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 = 0;
        }
        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)) != 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);
}



Index: doc/src/sgml/func.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/func.sgml,v
retrieving revision 1.253
diff -u -r1.253 func.sgml
--- doc/src/sgml/func.sgml    9 Jun 2005 16:35:08 -0000    1.253
+++ doc/src/sgml/func.sgml    10 Jun 2005 09:27:22 -0000
@@ -8130,6 +8130,11 @@
        <entry><type>text</type></entry>
        <entry>PostgreSQL version information</entry>
       </row>
+      <row>
+       <entry><function>pg_postmaster_start_time()</function></entry>
+       <entry><type>timestamp</type></entry>
+       <entry>PostgreSQL postmaster process start time</entry>
+      </row>
      </tbody>
     </tgroup>
    </table>
@@ -8225,6 +8230,15 @@
     <productname>PostgreSQL</productname> server's version.
    </para>

+   <indexterm zone="functions-info">
+    <primary>pg_postmaster_start_time</primary>
+   </indexterm>
+
+   <para>
+    <function>pg_postmaster_start_time()</function> returns a timestamp
+    giving the time when the postmaster process was started.
+   </para>
+
   <indexterm>
    <primary>privilege</primary>
    <secondary>querying</secondary>
@@ -8898,6 +8912,12 @@
    <indexterm zone="functions-admin">
     <primary>pg_cancel_backend</primary>
    </indexterm>
+   <indexterm zone="functions-admin">
+    <primary>pg_terminate_backend</primary>
+   </indexterm>
+   <indexterm zone="functions-admin">
+    <primary>pg_reload_conf</primary>
+   </indexterm>

    <indexterm zone="functions-admin">
     <primary>signal</primary>
@@ -8905,7 +8925,7 @@
    </indexterm>

    <para>
-    The function shown in <xref
+    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.
@@ -8927,21 +8947,46 @@
        <entry><type>int</type></entry>
        <entry>Cancel a backend's current query</entry>
       </row>
+      <row>
+       <entry>
+        <literal><function>pg_terminate_backend</function>(<parameter>pid</parameter>)</literal>
+        </entry>
+       <entry><type>int</type></entry>
+       <entry>Terminate a backend process</entry>
+      </row>
+      <row>
+       <entry>
+        <literal><function>pg_reload_conf</function>()</literal>
+        </entry>
+       <entry><type>int</type></entry>
+       <entry>Triggers the server processes to reload configuration files</entry>
+      </row>
      </tbody>
     </tgroup>
    </table>

    <para>
-    This function returns 1 if successful, 0 if not successful.
+    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>
-
-   <indexterm zone="functions-admin">
-    <primary>pg_start_backup</primary>
-   </indexterm>
+   <para>
+    Terminating a backend with <function>pg_terminate_backend</>
+    should be used only as a last resort, i.e. if the backend process
+    doesn't react to <function>pg_cancel_backend</> any more and can't
+    be controlled otherwise. Since the exact state of the
+    backend at the moment of termination isn't precisely known, some
+    locked resources might remain in the server's shared memory
+    structure, effectively blocking other backends. In this case,
+    you'd have to stop and restart the postmaster.
+   </para>
+   <para>
+    <function>pg_reload_conf</> sends a SIGHUP event to the
+    postmaster, and thus triggers a reload of the configuration files
+    in all backend processes.
+   </para>

    <indexterm zone="functions-admin">
     <primary>pg_stop_backup</primary>
@@ -9008,6 +9053,272 @@
     For details about proper usage of these functions, see
     <xref linkend="backup-online">.
    </para>
+
+   <para>
+    The functions shown in <xref
+    linkend="functions-admin-dbsize"> calculate the actual disk space
+    usage of database objects.
+   </para>
+
+   <table id="functions-admin-dbsize">
+    <title>Database Object Size 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_tablespace_size</function>(<parameter>tablespace_oid</parameter>)</literal>
+        </entry>
+       <entry><type>int8</type></entry>
+       <entry>Calculates total disk space of a tablespace</entry>
+      </row>
+      <row>
+       <entry>
+        <literal><function>pg_database_size</function>(<parameter>database_oid</parameter>)</literal>
+        </entry>
+       <entry><type>int8</type></entry>
+       <entry>Calculates total disk space of a database</entry>
+      </row>
+      <row>
+       <entry>
+        <literal><function>pg_relation_size</function>(<parameter>relation_oid</parameter>)</literal>
+        </entry>
+       <entry><type>int8</type></entry>
+       <entry>Calculates total disk space of a relation</entry>
+      </row>
+      <row>
+       <entry>
+        <literal><function>pg_size_pretty</function>(<parameter>size_int8</parameter>)</literal>
+        </entry>
+       <entry><type>text</type></entry>
+       <entry>Formats the size in a human readable format with size units </entry>
+      </row>
+     </tbody>
+    </tgroup>
+   </table>
+
+   <para>
+    <function>pg_tablespace_size</>, <function>pg_database_size</>
+    and <function>pg_relation_size</> accept an oid, and calculate
+    the disk space usage of the object.
+   </para>
+
+   <indexterm zone="functions-admin">
+    <primary>pg_relation_size</primary>
+   </indexterm>
+   <para>
+    <function>pg_relation_size</> accepts oids of standard tables, indexes and
+    toast tables. To calculate the disk space usage of a table
+    including all its indexes and toast tables, these components need
+    to be summed up.
+   </para>
+   <para>
+    <function>pg_size_pretty</> can be used to format the size of the
+    database objects in a human readable way, using kB, MB, GB or TB as appropriate.
+   </para>
+
+   <para>
+    The functions shown in <xref
+    linkend="functions-admin-genfile"> provide native file access to
+    files on the machine hosting the server. They are restricted to
+    the cluster directory or the logfile 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_stat</function>(<parameter>filename_text</parameter>)</literal>
+        </entry>
+       <entry><type>record</type></entry>
+       <entry>Retrieves file stats</entry>
+      </row>
+      <row>
+       <entry>
+        <literal><function>pg_file_length</function>(<parameter>filename_text</parameter>)</literal>
+        </entry>
+       <entry><type>int8</type></entry>
+       <entry>Returns the file length</entry>
+      </row>
+      <row>
+       <entry>
+        <literal><function>pg_file_read</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_file_write</function>(<parameter>filename_text</parameter>,<parameter>offset_int8></parameter>,<parameter>append_bool</parameter>)</literal>
+        </entry>
+       <entry><type>int8</type></entry>
+       <entry>Writes text to a file</entry>
+      </row>
+      <row>
+       <entry>
+
<literal><function>pg_file_rename</function>(<parameter>oldname_text</parameter>,<parameter>newname_text</parameter>)</literal>
+        </entry>
+       <entry><type>bool</type></entry>
+       <entry>Renames a file</entry>
+      </row>
+      <row>
+       <entry>
+
<literal><function>pg_file_rename</function>(<parameter>oldname_text</parameter>,<parameter>newname_text</parameter>,<parameter>archivname_text</parameter>)</literal>
+        </entry>
+       <entry><type>bool</type></entry>
+       <entry>Renames a file and its archive file</entry>
+      </row>
+      <row>
+       <entry>
+        <literal><function>pg_file_unlink</function>(<parameter>filename_text</parameter>)</literal>
+        </entry>
+       <entry><type>bool</type></entry>
+       <entry>Returns the file length</entry>
+      </row>
+      <row>
+       <entry>
+
<literal><function>pg_dir_ls</function>(<parameter>dirname_text</parameter>,<parameter>fullpath_bool</parameter>)</literal>
+        </entry>
+       <entry><type>setof text</type></entry>
+       <entry>Returns the file length</entry>
+      </row>
+     </tbody>
+    </tgroup>
+   </table>
+
+   <indexterm zone="functions-admin">
+    <primary>pg_file_stat</primary>
+   </indexterm>
+
+   <para>
+    <function>pg_file_stat()</> returns a record that contains the
+    length, creation timestamp, last accessed timestamp, last modified
+    timestamp and and a flag indicating a directory.
+   </para>
+
+   <indexterm zone="functions-admin">
+    <primary>pg_file_length</primary>
+   </indexterm>
+   <para>
+    <function>pg_file_length()</> returns the length of the given file.
+   </para>
+
+   <indexterm zone="functions-admin">
+    <primary>pg_file_read</primary>
+   </indexterm>
+   <para>
+    <function>pg_file_read()</> returns a part of a textfile, starting
+    at the offset giving length bytes.
+
+   <indexterm zone="functions-admin">
+    <primary>pg_file_write</primary>
+   </indexterm>
+   <para>
+    <function>pg_file_write()</> writes text to a file at the given
+    offset. If the append flag is false, the file may not exist. If
+    the append file is set, the file must exist and be accessible.
+   </para>
+
+   <indexterm zone="functions-admin">
+    <primary>pg_file_rename</primary>
+   </indexterm>
+   <para>
+    <function>pg_file_rename(oldname_text,newname_text)</> is used to
+    rename a file to a new name.
+   </para>
+   <para>
+    <function>pg_file_rename(oldname_text,newname_text,archivname_text)</> is used to
+    rename a file and its backup file to new names. The
+    oldname and newname files must exist, while the archivname file
+    may not exist when this command is issued.This can be used
+    to replace important files in a relatively safe way, because the
+    function will try to do the whole renaming or nothing at all.
+   Example:
+   <programlisting>
+   select pg_file_rename('postgresql.conf.tmp', 'postgresql.conf', 'postgresql.conf.bak');
+   </programlisting>
+    will replace postgresql.conf with a new version which was
+    previously written to the temporary file postgresql.conf.tmp,
+    saving the former version as postgresql.conf.bak.
+   </para>
+
+   <indexterm zone="functions-admin">
+    <primary>pg_file_unlink</primary>
+   </indexterm>
+   <para>
+    <function>pg_file_unlink()</> unlinks the file.
+   </para>
+   <para>
+    <function>pg_dir_ls</> lists all filenames in the named directory.
+   </para>
+
+   <para>
+    The functions shown in <xref
+    linkend="functions-admin-logfile"> allow access to the server
+    logfile, if the stderr log output is redirected.
+    Use of these 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_logfile_rotate</function>()</literal>
+        </entry>
+       <entry><type>int</type></entry>
+       <entry>Trigger logfile rotation</entry>
+      </row>
+      <row>
+       <entry>
+        <literal><function>pg_logdir_ls</function>()</literal>
+        </entry>
+       <entry><type>setof record</type></entry>
+       <entry>lists all logfiles in the pg_log subdirectory</entry>
+      </row>
+     </tbody>
+    </tgroup>
+   </table>
+
+   <indexterm zone="functions-admin">
+    <primary>pg_logfile_rotate</primary>
+   </indexterm>
+   <para>
+    <function>pg_logfile_rotate</> issues a logfile rotation trigger,
+    which forces the server to close the current logfile and open a
+    fresh one.
+   </para>
+
+   <indexterm zone="functions-admin">
+    <primary>pg_logdir_ls</primary>
+   </indexterm>
+   <para>
+    <function>pg_logdir_ls</> lists all files in the pg_log
+    subdirectory. For each log file, a record consisting of a
+    timestamp of its creation time and a complete path to the file is
+    returned. For convenience, the view pg_logdir_ls wraps the
+    function.
+   </para>
+
   </sect1>
 </chapter>

Index: src/backend/catalog/system_views.sql
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/catalog/system_views.sql,v
retrieving revision 1.13
diff -u -r1.13 system_views.sql
--- src/backend/catalog/system_views.sql    17 May 2005 21:46:09 -0000    1.13
+++ src/backend/catalog/system_views.sql    10 Jun 2005 09:27:24 -0000
@@ -282,3 +282,8 @@
     DO INSTEAD NOTHING;

 GRANT SELECT, UPDATE ON pg_settings TO PUBLIC;
+
+CREATE VIEW pg_logdir_ls AS
+    SELECT *
+    FROM pg_logdir_ls() AS A
+    (filetime timestamp, filename text);
Index: src/backend/postmaster/postmaster.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/postmaster/postmaster.c,v
retrieving revision 1.452
diff -u -r1.452 postmaster.c
--- src/backend/postmaster/postmaster.c    9 Jun 2005 22:01:12 -0000    1.452
+++ src/backend/postmaster/postmaster.c    10 Jun 2005 09:27:31 -0000
@@ -3306,6 +3306,11 @@
         }
     }

+    if (CheckPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE) && SysLoggerPID != 0)
+    {
+        kill(SysLoggerPID, SIGUSR1);
+    }
+
     PG_SETMASK(&UnBlockSig);

     errno = save_errno;
Index: src/backend/postmaster/syslogger.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/postmaster/syslogger.c,v
retrieving revision 1.15
diff -u -r1.15 syslogger.c
--- src/backend/postmaster/syslogger.c    19 Apr 2005 03:13:59 -0000    1.15
+++ src/backend/postmaster/syslogger.c    10 Jun 2005 09:27:32 -0000
@@ -101,6 +101,7 @@
  * 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,6 +118,7 @@
 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,7 +202,7 @@
     pqsignal(SIGQUIT, SIG_IGN);
     pqsignal(SIGALRM, SIG_IGN);
     pqsignal(SIGPIPE, SIG_IGN);
-    pqsignal(SIGUSR1, SIG_IGN);
+    pqsignal(SIGUSR1, sigUsr1Handler);  /* request log rotation */
     pqsignal(SIGUSR2, SIG_IGN);

     /*
@@ -235,7 +237,6 @@
     /* main worker loop */
     for (;;)
     {
-        bool        rotation_requested = false;
         bool        time_based_rotation = false;

 #ifndef WIN32
@@ -734,6 +735,8 @@
     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"
@@ -887,3 +890,10 @@
 {
     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: /projects/cvsroot/pgsql/src/backend/utils/adt/Makefile,v
retrieving revision 1.57
diff -u -r1.57 Makefile
--- src/backend/utils/adt/Makefile    1 Apr 2004 21:28:45 -0000    1.57
+++ src/backend/utils/adt/Makefile    10 Jun 2005 09:27:33 -0000
@@ -24,7 +24,7 @@
     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
+    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: /projects/cvsroot/pgsql/src/backend/utils/adt/misc.c,v
retrieving revision 1.43
diff -u -r1.43 misc.c
--- src/backend/utils/adt/misc.c    19 May 2005 21:35:47 -0000    1.43
+++ src/backend/utils/adt/misc.c    10 Jun 2005 09:27:33 -0000
@@ -17,15 +17,20 @@
 #include <sys/file.h>
 #include <signal.h>
 #include <dirent.h>
+#include <time.h>
+#include <sys/time.h>

 #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))

@@ -101,22 +106,177 @@
     return 1;
 }

+
 Datum
 pg_cancel_backend(PG_FUNCTION_ARGS)
 {
     PG_RETURN_INT32(pg_signal_backend(PG_GETARG_INT32(0), SIGINT));
 }

-#ifdef NOT_USED
-
-/* Disabled in 8.0 due to reliability concerns; FIXME someday */

 Datum
 pg_terminate_backend(PG_FUNCTION_ARGS)
 {
     PG_RETURN_INT32(pg_signal_backend(PG_GETARG_INT32(0), SIGTERM));
 }
-#endif
+
+
+Datum
+pg_reload_conf(PG_FUNCTION_ARGS)
+{
+    if (!superuser())
+        ereport(ERROR,
+                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                 (errmsg("only superuser can 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_logfile_rotate(PG_FUNCTION_ARGS)
+{
+    if (!superuser())
+        ereport(ERROR,
+                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                 (errmsg("only superuser can 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);
+}
+
+typedef struct
+{
+    char *location;
+    DIR *dirdesc;
+} directory_fctx;
+
+/*
+ * scan log directory for log files
+ */
+Datum pg_logdir_ls(PG_FUNCTION_ARGS)
+{
+    FuncCallContext *funcctx;
+    struct dirent *de;
+    directory_fctx *fctx;
+
+    if (!superuser())
+        ereport(ERROR,
+                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                 (errmsg("only superuser can list the log directory"))));
+
+    if (memcmp(Log_filename, "postgresql-%Y-%m-%d_%H%M%S.log", 30) != 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));
+        if (is_absolute_path(Log_directory))
+            fctx->location = Log_directory;
+        else
+        {
+            fctx->location = palloc(strlen(DataDir) + strlen(Log_directory) +2);
+            sprintf(fctx->location, "%s/%s", DataDir, Log_directory);
+        }
+        tupdesc = CreateTemplateTupleDesc(2, false);
+        TupleDescInitEntry(tupdesc, (AttrNumber) 1, "starttime",
+                           TIMESTAMPOID, -1, 0);
+        TupleDescInitEntry(tupdesc, (AttrNumber) 2, "filename",
+                           TEXTOID, -1, 0);
+
+        funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
+
+        fctx->dirdesc = AllocateDir(fctx->location);
+
+        if (!fctx->dirdesc)
+            ereport(ERROR,
+                    (errcode_for_file_access(),
+                     errmsg("%s is not browsable: %m", fctx->location)));
+
+        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)) != NULL)
+    {
+        char *values[2];
+        HeapTuple tuple;
+
+        char     *field[MAXDATEFIELDS];
+        char    lowstr[MAXDATELEN + 1];
+        int        dtype;
+        int        nf, ftype[MAXDATEFIELDS];
+        fsec_t    fsec;
+        int        tz = 0;
+        struct    pg_tm date;
+
+        /*
+         * Default format:
+         *        postgresql-YYYY-MM-DD_HHMMSS.log
+         */
+        if (strlen(de->d_name) != 32
+            || memcmp(de->d_name, "postgresql-", 11)
+            || de->d_name[21] != '_'
+            || strcmp(de->d_name + 28, ".log"))
+              continue;
+
+        values[1] = palloc(strlen(fctx->location) + strlen(de->d_name) + 2);
+        sprintf(values[1], "%s/%s", fctx->location, de->d_name);
+
+        values[0] = de->d_name + 11;       /* timestamp */
+        values[0][17] = 0;
+
+                    /* parse and decode expected timestamp */
+        if (ParseDateTime(values[0], lowstr, sizeof(lowstr), field, ftype, MAXDATEFIELDS, &nf))
+            continue;
+
+        if (DecodeDateTime(field, ftype, nf, &dtype, &date, &fsec, &tz))
+            continue;
+
+        /* Seems the format fits the expected format; feed it into the tuple */
+
+        tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
+
+        SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+    }
+
+    FreeDir(fctx->dirdesc);
+    SRF_RETURN_DONE(funcctx);
+}


 /* Function to find out which databases make use of a tablespace */
Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_proc.h,v
retrieving revision 1.365
diff -u -r1.365 pg_proc.h
--- src/include/catalog/pg_proc.h    9 Jun 2005 16:35:09 -0000    1.365
+++ src/include/catalog/pg_proc.h    10 Jun 2005 09:27:52 -0000
@@ -3018,12 +3018,50 @@
 DESCR("is conversion visible in search path?");


+DATA(insert OID = 2168 ( pg_terminate_backend    PGNSP PGUID 12 f f t f v 1 23 "23" _null_ _null_ _null_
pg_terminate_backend- _null_ )); 
+DESCR("Terminate a server process");
 DATA(insert OID = 2171 ( pg_cancel_backend        PGNSP PGUID 12 f f t f v 1 23 "23" _null_ _null_ _null_
pg_cancel_backend- _null_ )); 
 DESCR("Cancel a server process' current query");
 DATA(insert OID = 2172 ( pg_start_backup        PGNSP PGUID 12 f f t f v 1 25 "25" _null_ _null_ _null_
pg_start_backup- _null_ )); 
 DESCR("Prepare for taking an online backup");
 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 = 2284 ( pg_reload_conf         PGNSP PGUID 12 f f t f v 0 23 "" _null_ _null_ _null_ pg_reload_conf -
_null_)); 
+DESCR("Reloads configuration files");
+
+DATA(insert OID = 2285 ( pg_tablespace_size        PGNSP PGUID 12 f f t f v 1 20 "26" _null_ _null_ _null_
pg_tablespace_size- _null_ )); 
+DESCR("Calculate total disk space usage for tablespace");
+DATA(insert OID = 2286 ( pg_database_size        PGNSP PGUID 12 f f t f v 1 20 "26" _null_ _null_ _null_
pg_database_size- _null_ )); 
+DESCR("Calculate total disk space usage for database");
+DATA(insert OID = 2287 ( pg_relation_size        PGNSP PGUID 12 f f t f v 1 20 "26" _null_ _null_ _null_
pg_relation_size- _null_ )); 
+DESCR("Calculate total disk space usage for relation");
+DATA(insert OID = 2288 ( pg_size_pretty          PGNSP PGUID 12 f f t f v 1 25 "20" _null_ _null_ _null_
pg_size_pretty- _null_ )); 
+DESCR("Convert a long int to a human readable text using size units");
+
+DATA(insert OID = 1232 ( pg_logfile_rotate        PGNSP PGUID 12 f f t f v 0 23 "" _null_ _null_ _null_
pg_logfile_rotate- _null_ )); 
+DESCR("rotate log file");
+DATA(insert OID = 1233 ( pg_logdir_ls            PGNSP PGUID 12 f f t t v 0 2249 "" _null_ _null_ _null_ pg_logdir_ls
-_null_ )); 
+DESCR("list all available log files");
+
+
+DATA(insert OID = 2560 ( pg_file_stat        PGNSP PGUID 12 f f t f v 1 2249 "25" _null_ _null_ _null_ pg_file_stat -
_null_)); 
+DESCR("retrieve file stats");
+DATA(insert OID = 2561 ( pg_file_length        PGNSP PGUID 14 f f t f v 1 20 "25" _null_ _null_ _null_ "SELECT len
FROMpg_file_stat($1) AS s(len int8, c timestamp, a timestamp, m timestamp, i bool)" - _null_ )); 
+DESCR("returns length of a file");
+DATA(insert OID = 2562 ( pg_file_read        PGNSP PGUID 12 f f t f v 3 25 "25 20 20" _null_ _null_ _null_
pg_file_read- _null_ )); 
+DESCR("reads text from a file");
+DATA(insert OID = 2563 ( pg_file_write      PGNSP PGUID 12 f f t f v 3 20 "25 25 16" _null_ _null_ _null_
pg_file_write- _null_ )); 
+DESCR("writes text to a file");
+DATA(insert OID = 2564 ( pg_file_rename        PGNSP PGUID 12 f f f f v 3 16 "25 25 25" _null_ _null_ _null_
pg_file_rename- _null_ )); 
+DESCR("renames a file and its backup file");
+DATA(insert OID = 2565 ( pg_file_rename        PGNSP PGUID 12 f f f t v 2 16 "25 25" _null_ _null_ _null_
pg_file_rename- _null_ )); 
+DESCR("renames a file");
+DATA(insert OID = 2566 ( pg_file_unlink        PGNSP PGUID 12 f f t f v 1 16 "25" _null_ _null_ _null_ pg_file_unlink
-_null_ )); 
+DESCR("unlinks a file");
+DATA(insert OID = 2567 ( pg_dir_ls            PGNSP PGUID 12 f f t t v 2 25 "25 16" _null_ _null_ _null_ pg_dir_ls -
_null_)); 
+DESCR("lists all filenames from a directory");
+
+


 /* Aggregates (moved here from pg_aggregate for 7.3) */
Index: src/include/storage/pmsignal.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/storage/pmsignal.h,v
retrieving revision 1.11
diff -u -r1.11 pmsignal.h
--- src/include/storage/pmsignal.h    31 Dec 2004 22:03:42 -0000    1.11
+++ src/include/storage/pmsignal.h    10 Jun 2005 09:27:53 -0000
@@ -25,7 +25,7 @@
     PMSIGNAL_PASSWORD_CHANGE,    /* pg_pwd 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: /projects/cvsroot/pgsql/src/include/utils/builtins.h,v
retrieving revision 1.257
diff -u -r1.257 builtins.h
--- src/include/utils/builtins.h    27 May 2005 00:57:49 -0000    1.257
+++ src/include/utils/builtins.h    10 Jun 2005 09:27:55 -0000
@@ -362,7 +362,26 @@
 extern Datum nonnullvalue(PG_FUNCTION_ARGS);
 extern Datum current_database(PG_FUNCTION_ARGS);
 extern Datum pg_cancel_backend(PG_FUNCTION_ARGS);
+extern Datum pg_terminate_backend(PG_FUNCTION_ARGS);
+extern Datum pg_reload_conf(PG_FUNCTION_ARGS);
 extern Datum pg_tablespace_databases(PG_FUNCTION_ARGS);
+extern Datum pg_logfile_rotate(PG_FUNCTION_ARGS);
+extern Datum pg_logdir_ls(PG_FUNCTION_ARGS);
+
+/* dbsize.c */
+extern Datum pg_tablespace_size(PG_FUNCTION_ARGS);
+extern Datum pg_database_size(PG_FUNCTION_ARGS);
+extern Datum pg_relation_size(PG_FUNCTION_ARGS);
+extern Datum pg_size_pretty(PG_FUNCTION_ARGS);
+
+
+/* genfile.c */
+extern Datum pg_file_stat(PG_FUNCTION_ARGS);
+extern Datum pg_file_read(PG_FUNCTION_ARGS);
+extern Datum pg_file_write(PG_FUNCTION_ARGS);
+extern Datum pg_file_rename(PG_FUNCTION_ARGS);
+extern Datum pg_file_unlink(PG_FUNCTION_ARGS);
+extern Datum pg_dir_ls(PG_FUNCTION_ARGS);

 /* not_in.c */
 extern Datum int4notin(PG_FUNCTION_ARGS);

pgsql-patches by date:

Previous
From: Volkan YAZICI
Date:
Subject: PQmakeEmptyPGresult() will return NULL if allocation fails
Next
From: Atsushi Ogawa
Date:
Subject: bugfix: character-code conversion of MIC -> EUC_JP.