#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"
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 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_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().
Datum current_database | ( | PG_FUNCTION_ARGS | ) |
Definition at line 50 of file misc.c.
References get_database_name(), MyDatabaseId, NAMEDATALEN, namestrcpy(), palloc(), and PG_RETURN_NAME.
{ Name db; db = (Name) palloc(NAMEDATALEN); namestrcpy(db, get_database_name(MyDatabaseId)); PG_RETURN_NAME(db); }
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)); }