Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Functions

misc.c File Reference

#include "postgres.h"
#include <sys/file.h>
#include <signal.h>
#include <dirent.h>
#include <math.h>
#include <unistd.h>
#include "catalog/catalog.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_type.h"
#include "commands/dbcommands.h"
#include "common/relpath.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "parser/keywords.h"
#include "postmaster/syslogger.h"
#include "rewrite/rewriteHandler.h"
#include "storage/fd.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/lsyscache.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/timestamp.h"
Include dependency graph for misc.c:

Go to the source code of this file.

Data Structures

struct  ts_db_fctx

Defines

#define atooid(x)   ((Oid) strtoul((x), NULL, 10))
#define SIGNAL_BACKEND_SUCCESS   0
#define SIGNAL_BACKEND_ERROR   1
#define SIGNAL_BACKEND_NOPERMISSION   2
#define GetNowFloat()   GetCurrentTimestamp()

Functions

Datum current_database (PG_FUNCTION_ARGS)
Datum current_query (PG_FUNCTION_ARGS)
static int pg_signal_backend (int pid, int sig)
Datum pg_cancel_backend (PG_FUNCTION_ARGS)
Datum pg_terminate_backend (PG_FUNCTION_ARGS)
Datum pg_reload_conf (PG_FUNCTION_ARGS)
Datum pg_rotate_logfile (PG_FUNCTION_ARGS)
Datum pg_tablespace_databases (PG_FUNCTION_ARGS)
Datum pg_tablespace_location (PG_FUNCTION_ARGS)
Datum pg_sleep (PG_FUNCTION_ARGS)
Datum pg_get_keywords (PG_FUNCTION_ARGS)
Datum pg_typeof (PG_FUNCTION_ARGS)
Datum pg_collation_for (PG_FUNCTION_ARGS)
Datum pg_view_is_insertable (PG_FUNCTION_ARGS)
Datum pg_view_is_updatable (PG_FUNCTION_ARGS)

Define Documentation

#define atooid (   x  )     ((Oid) strtoul((x), NULL, 10))

Definition at line 42 of file misc.c.

Referenced by pg_tablespace_databases().

#define GetNowFloat (  )     GetCurrentTimestamp()

Referenced by pg_sleep().

#define SIGNAL_BACKEND_ERROR   1

Definition at line 89 of file misc.c.

#define SIGNAL_BACKEND_NOPERMISSION   2

Definition at line 90 of file misc.c.

Referenced by pg_cancel_backend(), and pg_terminate_backend().

#define SIGNAL_BACKEND_SUCCESS   0

Definition at line 88 of file misc.c.

Referenced by pg_cancel_backend(), and pg_terminate_backend().


Function Documentation

Datum current_database ( PG_FUNCTION_ARGS   ) 
Datum current_query ( PG_FUNCTION_ARGS   ) 

Definition at line 67 of file misc.c.

References cstring_to_text(), debug_query_string, PG_RETURN_NULL, and PG_RETURN_TEXT_P.

Referenced by dblink_current_query().

{
    /* there is no easy way to access the more concise 'query_string' */
    if (debug_query_string)
        PG_RETURN_TEXT_P(cstring_to_text(debug_query_string));
    else
        PG_RETURN_NULL();
}

Datum pg_cancel_backend ( PG_FUNCTION_ARGS   ) 

Definition at line 147 of file misc.c.

References ereport, errcode(), errmsg(), ERROR, PG_GETARG_INT32, PG_RETURN_BOOL, pg_signal_backend(), SIGNAL_BACKEND_NOPERMISSION, and SIGNAL_BACKEND_SUCCESS.

{
    int         r = pg_signal_backend(PG_GETARG_INT32(0), SIGINT);

    if (r == SIGNAL_BACKEND_NOPERMISSION)
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 (errmsg("must be superuser or have the same role to cancel queries running in other server processes"))));

    PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);
}

Datum pg_collation_for ( PG_FUNCTION_ARGS   ) 

Definition at line 509 of file misc.c.

References cstring_to_text(), ereport, errcode(), errmsg(), ERROR, format_type_be(), generate_collation_name(), get_fn_expr_argtype(), PG_GET_COLLATION, PG_RETURN_NULL, PG_RETURN_TEXT_P, type_is_collatable(), and UNKNOWNOID.

{
    Oid         typeid;
    Oid         collid;

    typeid = get_fn_expr_argtype(fcinfo->flinfo, 0);
    if (!typeid)
        PG_RETURN_NULL();
    if (!type_is_collatable(typeid) && typeid != UNKNOWNOID)
        ereport(ERROR,
                (errcode(ERRCODE_DATATYPE_MISMATCH),
                 errmsg("collations are not supported by type %s",
                        format_type_be(typeid))));

    collid = PG_GET_COLLATION();
    if (!collid)
        PG_RETURN_NULL();
    PG_RETURN_TEXT_P(cstring_to_text(generate_collation_name(collid)));
}

Datum pg_get_keywords ( PG_FUNCTION_ARGS   ) 

Definition at line 426 of file misc.c.

References _, FuncCallContext::attinmeta, BuildTupleFromCStrings(), FuncCallContext::call_cntr, ScanKeyword::category, CHAROID, COL_NAME_KEYWORD, CreateTemplateTupleDesc(), HeapTupleGetDatum, MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, ScanKeyword::name, NumScanKeywords, RESERVED_KEYWORD, ScanKeywords, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, TEXTOID, TupleDescGetAttInMetadata(), TupleDescInitEntry(), TYPE_FUNC_NAME_KEYWORD, UNRESERVED_KEYWORD, and values.

{
    FuncCallContext *funcctx;

    if (SRF_IS_FIRSTCALL())
    {
        MemoryContext oldcontext;
        TupleDesc   tupdesc;

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

        tupdesc = CreateTemplateTupleDesc(3, false);
        TupleDescInitEntry(tupdesc, (AttrNumber) 1, "word",
                           TEXTOID, -1, 0);
        TupleDescInitEntry(tupdesc, (AttrNumber) 2, "catcode",
                           CHAROID, -1, 0);
        TupleDescInitEntry(tupdesc, (AttrNumber) 3, "catdesc",
                           TEXTOID, -1, 0);

        funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);

        MemoryContextSwitchTo(oldcontext);
    }

    funcctx = SRF_PERCALL_SETUP();

    if (funcctx->call_cntr < NumScanKeywords)
    {
        char       *values[3];
        HeapTuple   tuple;

        /* cast-away-const is ugly but alternatives aren't much better */
        values[0] = (char *) ScanKeywords[funcctx->call_cntr].name;

        switch (ScanKeywords[funcctx->call_cntr].category)
        {
            case UNRESERVED_KEYWORD:
                values[1] = "U";
                values[2] = _("unreserved");
                break;
            case COL_NAME_KEYWORD:
                values[1] = "C";
                values[2] = _("unreserved (cannot be function or type name)");
                break;
            case TYPE_FUNC_NAME_KEYWORD:
                values[1] = "T";
                values[2] = _("reserved (can be function or type name)");
                break;
            case RESERVED_KEYWORD:
                values[1] = "R";
                values[2] = _("reserved");
                break;
            default:            /* shouldn't be possible */
                values[1] = NULL;
                values[2] = NULL;
                break;
        }

        tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);

        SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
    }

    SRF_RETURN_DONE(funcctx);
}

Datum pg_reload_conf ( PG_FUNCTION_ARGS   ) 

Definition at line 180 of file misc.c.

References ereport, errcode(), errmsg(), ERROR, PG_RETURN_BOOL, PostmasterPid, SIGHUP, superuser(), and WARNING.

{
    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_BOOL(false);
    }

    PG_RETURN_BOOL(true);
}

Datum pg_rotate_logfile ( PG_FUNCTION_ARGS   ) 

Definition at line 202 of file misc.c.

References ereport, errcode(), errmsg(), ERROR, Logging_collector, PG_RETURN_BOOL, PMSIGNAL_ROTATE_LOGFILE, SendPostmasterSignal(), superuser(), and WARNING.

{
    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 (errmsg("must be superuser to rotate log files"))));

    if (!Logging_collector)
    {
        ereport(WARNING,
        (errmsg("rotation not possible because log collection not active")));
        PG_RETURN_BOOL(false);
    }

    SendPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE);
    PG_RETURN_BOOL(true);
}

static int pg_signal_backend ( int  pid,
int  sig 
) [static]

Definition at line 92 of file misc.c.

References BackendPidGetProc(), ereport, errmsg(), GetUserId(), NULL, PGPROC::roleId, superuser(), and WARNING.

Referenced by pg_cancel_backend(), and pg_terminate_backend().

{
    PGPROC     *proc = BackendPidGetProc(pid);

    /*
     * BackendPidGetProc returns NULL if the pid isn't valid; but by the time
     * we reach kill(), a process for which we get a valid proc here might have
     * terminated on its own.  There's no way to acquire a lock on an arbitrary
     * process to prevent that. But since so far all the callers of this
     * mechanism involve some request for ending the process anyway, that it
     * might end on its own first is not a problem.
     */
    if (proc == NULL)
    {
        /*
         * This is just a warning so a loop-through-resultset will not abort
         * if one backend terminated on its own during the run.
         */
        ereport(WARNING,
                (errmsg("PID %d is not a PostgreSQL server process", pid)));
        return SIGNAL_BACKEND_ERROR;
    }

    if (!(superuser() || proc->roleId == GetUserId()))
        return SIGNAL_BACKEND_NOPERMISSION;

    /*
     * Can the process we just validated above end, followed by the pid being
     * recycled for a new process, before reaching here?  Then we'd be trying
     * to kill the wrong thing.  Seems near impossible when sequential pid
     * assignment and wraparound is used.  Perhaps it could happen on a system
     * where pid re-use is randomized.  That race condition possibility seems
     * too unlikely to worry about.
     */

    /* If we have setsid(), signal the backend's whole process group */
#ifdef HAVE_SETSID
    if (kill(-pid, sig))
#else
    if (kill(pid, sig))
#endif
    {
        /* Again, just a warning to allow loops */
        ereport(WARNING,
                (errmsg("could not send signal to process %d: %m", pid)));
        return SIGNAL_BACKEND_ERROR;
    }
    return SIGNAL_BACKEND_SUCCESS;
}

Datum pg_sleep ( PG_FUNCTION_ARGS   ) 

Definition at line 381 of file misc.c.

References CHECK_FOR_INTERRUPTS, GetNowFloat, PG_GETARG_FLOAT8, PG_RETURN_VOID, and pg_usleep().

{
    float8      secs = PG_GETARG_FLOAT8(0);
    float8      endtime;

    /*
     * We break the requested sleep into segments of no more than 1 second, to
     * put an upper bound on how long it will take us to respond to a cancel
     * or die interrupt.  (Note that pg_usleep is interruptible by signals on
     * some platforms but not others.)  Also, this method avoids exposing
     * pg_usleep's upper bound on allowed delays.
     *
     * By computing the intended stop time initially, we avoid accumulation of
     * extra delay across multiple sleeps.  This also ensures we won't delay
     * less than the specified time if pg_usleep is interrupted by other
     * signals such as SIGHUP.
     */

#ifdef HAVE_INT64_TIMESTAMP
#define GetNowFloat()   ((float8) GetCurrentTimestamp() / 1000000.0)
#else
#define GetNowFloat()   GetCurrentTimestamp()
#endif

    endtime = GetNowFloat() + secs;

    for (;;)
    {
        float8      delay;

        CHECK_FOR_INTERRUPTS();
        delay = endtime - GetNowFloat();
        if (delay >= 1.0)
            pg_usleep(1000000L);
        else if (delay > 0.0)
            pg_usleep((long) ceil(delay * 1000000.0));
        else
            break;
    }

    PG_RETURN_VOID();
}

Datum pg_tablespace_databases ( PG_FUNCTION_ARGS   ) 

Definition at line 229 of file misc.c.

References AllocateDir(), atooid, dirent::d_name, DEFAULTTABLESPACE_OID, ts_db_fctx::dirdesc, ereport, errcode_for_file_access(), errmsg(), ERROR, FreeDir(), GLOBALTABLESPACE_OID, ts_db_fctx::location, MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, NULL, ObjectIdGetDatum, OIDCHARS, palloc(), pfree(), PG_GETARG_OID, ReadDir(), SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, TABLESPACE_VERSION_DIRECTORY, FuncCallContext::user_fctx, and WARNING.

{
    FuncCallContext *funcctx;
    struct dirent *de;
    ts_db_fctx *fctx;

    if (SRF_IS_FIRSTCALL())
    {
        MemoryContext oldcontext;
        Oid         tablespaceOid = PG_GETARG_OID(0);

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

        fctx = palloc(sizeof(ts_db_fctx));

        /*
         * size = tablespace dirname length + dir sep char + oid + terminator
         */
        fctx->location = (char *) palloc(9 + 1 + OIDCHARS + 1 +
                                   strlen(TABLESPACE_VERSION_DIRECTORY) + 1);
        if (tablespaceOid == GLOBALTABLESPACE_OID)
        {
            fctx->dirdesc = NULL;
            ereport(WARNING,
                    (errmsg("global tablespace never has databases")));
        }
        else
        {
            if (tablespaceOid == DEFAULTTABLESPACE_OID)
                sprintf(fctx->location, "base");
            else
                sprintf(fctx->location, "pg_tblspc/%u/%s", tablespaceOid,
                        TABLESPACE_VERSION_DIRECTORY);

            fctx->dirdesc = AllocateDir(fctx->location);

            if (!fctx->dirdesc)
            {
                /* the only expected error is ENOENT */
                if (errno != ENOENT)
                    ereport(ERROR,
                            (errcode_for_file_access(),
                             errmsg("could not open directory \"%s\": %m",
                                    fctx->location)));
                ereport(WARNING,
                      (errmsg("%u is not a tablespace OID", tablespaceOid)));
            }
        }
        funcctx->user_fctx = fctx;
        MemoryContextSwitchTo(oldcontext);
    }

    funcctx = SRF_PERCALL_SETUP();
    fctx = (ts_db_fctx *) funcctx->user_fctx;

    if (!fctx->dirdesc)         /* not a tablespace */
        SRF_RETURN_DONE(funcctx);

    while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL)
    {
        char       *subdir;
        DIR        *dirdesc;
        Oid         datOid = atooid(de->d_name);

        /* this test skips . and .., but is awfully weak */
        if (!datOid)
            continue;

        /* if database subdir is empty, don't report tablespace as used */

        /* size = path length + dir sep char + file name + terminator */
        subdir = palloc(strlen(fctx->location) + 1 + strlen(de->d_name) + 1);
        sprintf(subdir, "%s/%s", fctx->location, de->d_name);
        dirdesc = AllocateDir(subdir);
        while ((de = ReadDir(dirdesc, subdir)) != NULL)
        {
            if (strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0)
                break;
        }
        FreeDir(dirdesc);
        pfree(subdir);

        if (!de)
            continue;           /* indeed, nothing in it */

        SRF_RETURN_NEXT(funcctx, ObjectIdGetDatum(datOid));
    }

    FreeDir(fctx->dirdesc);
    SRF_RETURN_DONE(funcctx);
}

Datum pg_tablespace_location ( PG_FUNCTION_ARGS   ) 

Definition at line 327 of file misc.c.

References cstring_to_text(), DEFAULTTABLESPACE_OID, ereport, errcode(), errmsg(), ERROR, GLOBALTABLESPACE_OID, InvalidOid, MyDatabaseTableSpace, PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, and snprintf().

{
    Oid         tablespaceOid = PG_GETARG_OID(0);
    char        sourcepath[MAXPGPATH];
    char        targetpath[MAXPGPATH];
    int         rllen;

    /*
     * It's useful to apply this function to pg_class.reltablespace, wherein
     * zero means "the database's default tablespace".  So, rather than
     * throwing an error for zero, we choose to assume that's what is meant.
     */
    if (tablespaceOid == InvalidOid)
        tablespaceOid = MyDatabaseTableSpace;

    /*
     * Return empty string for the cluster's default tablespaces
     */
    if (tablespaceOid == DEFAULTTABLESPACE_OID ||
        tablespaceOid == GLOBALTABLESPACE_OID)
        PG_RETURN_TEXT_P(cstring_to_text(""));

#if defined(HAVE_READLINK) || defined(WIN32)

    /*
     * Find the location of the tablespace by reading the symbolic link that
     * is in pg_tblspc/<oid>.
     */
    snprintf(sourcepath, sizeof(sourcepath), "pg_tblspc/%u", tablespaceOid);

    rllen = readlink(sourcepath, targetpath, sizeof(targetpath));
    if (rllen < 0)
        ereport(ERROR,
                (errmsg("could not read symbolic link \"%s\": %m",
                        sourcepath)));
    else if (rllen >= sizeof(targetpath))
        ereport(ERROR,
                (errmsg("symbolic link \"%s\" target is too long",
                        sourcepath)));
    targetpath[rllen] = '\0';

    PG_RETURN_TEXT_P(cstring_to_text(targetpath));
#else
    ereport(ERROR,
            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
             errmsg("tablespaces are not supported on this platform")));
    PG_RETURN_NULL();
#endif
}

Datum pg_terminate_backend ( PG_FUNCTION_ARGS   ) 

Definition at line 164 of file misc.c.

References ereport, errcode(), errmsg(), ERROR, PG_GETARG_INT32, PG_RETURN_BOOL, pg_signal_backend(), SIGNAL_BACKEND_NOPERMISSION, and SIGNAL_BACKEND_SUCCESS.

{
    int         r = pg_signal_backend(PG_GETARG_INT32(0), SIGTERM);

    if (r == SIGNAL_BACKEND_NOPERMISSION)
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 (errmsg("must be superuser or have the same role to terminate other server processes"))));

    PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);
}

Datum pg_typeof ( PG_FUNCTION_ARGS   ) 

Definition at line 498 of file misc.c.

References get_fn_expr_argtype(), and PG_RETURN_OID.

{
    PG_RETURN_OID(get_fn_expr_argtype(fcinfo->flinfo, 0));
}

Datum pg_view_is_insertable ( PG_FUNCTION_ARGS   ) 

Definition at line 542 of file misc.c.

References PG_GETARG_OID, PG_RETURN_BOOL, and relation_is_updatable().

{
    Oid         viewoid = PG_GETARG_OID(0);
    int         req_events = (1 << CMD_INSERT);

    PG_RETURN_BOOL(relation_is_updatable(viewoid, req_events));
}

Datum pg_view_is_updatable ( PG_FUNCTION_ARGS   ) 

Definition at line 551 of file misc.c.

References CMD_DELETE, PG_GETARG_OID, PG_RETURN_BOOL, and relation_is_updatable().

{
    Oid         viewoid = PG_GETARG_OID(0);
    int         req_events = (1 << CMD_UPDATE) | (1 << CMD_DELETE);

    PG_RETURN_BOOL(relation_is_updatable(viewoid, req_events));
}