1 /*-------------------------------------------------------------------------
6 * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/utils/adt/misc.c,v 1.54 2006/10/04 00:29:59 momjian Exp $
13 *-------------------------------------------------------------------------
22 #include "access/xact.h"
23 #include "catalog/pg_tablespace.h"
24 #include "commands/dbcommands.h"
26 #include "miscadmin.h"
27 #include "postmaster/syslogger.h"
28 #include "storage/fd.h"
29 #include "storage/pmsignal.h"
30 #include "storage/procarray.h"
31 #include "utils/builtins.h"
33 #define atooid(x) ((Oid) strtoul((x), NULL, 10))
37 * Check if data is Null
40 nullvalue(PG_FUNCTION_ARGS)
44 PG_RETURN_BOOL(false);
48 * Check if data is not Null
51 nonnullvalue(PG_FUNCTION_ARGS)
54 PG_RETURN_BOOL(false);
60 * Expose the current database to the user
63 current_database(PG_FUNCTION_ARGS)
67 db = (Name) palloc(NAMEDATALEN);
69 namestrcpy(db, get_database_name(MyDatabaseId));
75 * Functions to send signals to other backends.
78 pg_signal_backend(int pid, int sig)
82 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
83 (errmsg("must be superuser to signal other server processes"))));
85 if (!IsBackendPid(pid))
88 * This is just a warning so a loop-through-resultset will not abort
89 * if one backend terminated on it's own during the run
92 (errmsg("PID %d is not a PostgreSQL server process", pid)));
98 /* Again, just a warning to allow loops */
100 (errmsg("could not send signal to process %d: %m", pid)));
107 pg_cancel_backend(PG_FUNCTION_ARGS)
109 PG_RETURN_BOOL(pg_signal_backend(PG_GETARG_INT32(0), SIGINT));
113 pg_reload_conf(PG_FUNCTION_ARGS)
117 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
118 (errmsg("must be superuser to signal the postmaster"))));
120 if (kill(PostmasterPid, SIGHUP))
123 (errmsg("failed to send signal to postmaster: %m")));
124 PG_RETURN_BOOL(false);
127 PG_RETURN_BOOL(true);
135 pg_rotate_logfile(PG_FUNCTION_ARGS)
139 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
140 (errmsg("must be superuser to rotate log files"))));
142 if (!Redirect_stderr)
145 (errmsg("rotation not possible because log redirection not active")));
146 PG_RETURN_BOOL(false);
149 SendPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE);
150 PG_RETURN_BOOL(true);
155 /* Disabled in 8.0 due to reliability concerns; FIXME someday */
157 pg_terminate_backend(PG_FUNCTION_ARGS)
159 PG_RETURN_INT32(pg_signal_backend(PG_GETARG_INT32(0), SIGTERM));
164 /* Function to find out which databases make use of a tablespace */
173 pg_tablespace_databases(PG_FUNCTION_ARGS)
175 FuncCallContext *funcctx;
179 if (SRF_IS_FIRSTCALL())
181 MemoryContext oldcontext;
182 Oid tablespaceOid = PG_GETARG_OID(0);
184 funcctx = SRF_FIRSTCALL_INIT();
185 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
187 fctx = palloc(sizeof(ts_db_fctx));
190 * size = tablespace dirname length + dir sep char + oid + terminator
192 fctx->location = (char *) palloc(10 + 10 + 1);
193 if (tablespaceOid == GLOBALTABLESPACE_OID)
195 fctx->dirdesc = NULL;
197 (errmsg("global tablespace never has databases")));
201 if (tablespaceOid == DEFAULTTABLESPACE_OID)
202 sprintf(fctx->location, "base");
204 sprintf(fctx->location, "pg_tblspc/%u", tablespaceOid);
206 fctx->dirdesc = AllocateDir(fctx->location);
210 /* the only expected error is ENOENT */
213 (errcode_for_file_access(),
214 errmsg("could not open directory \"%s\": %m",
217 (errmsg("%u is not a tablespace OID", tablespaceOid)));
220 funcctx->user_fctx = fctx;
221 MemoryContextSwitchTo(oldcontext);
224 funcctx = SRF_PERCALL_SETUP();
225 fctx = (ts_db_fctx *) funcctx->user_fctx;
227 if (!fctx->dirdesc) /* not a tablespace */
228 SRF_RETURN_DONE(funcctx);
230 while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL)
234 Oid datOid = atooid(de->d_name);
236 /* this test skips . and .., but is awfully weak */
240 /* if database subdir is empty, don't report tablespace as used */
242 /* size = path length + dir sep char + file name + terminator */
243 subdir = palloc(strlen(fctx->location) + 1 + strlen(de->d_name) + 1);
244 sprintf(subdir, "%s/%s", fctx->location, de->d_name);
245 dirdesc = AllocateDir(subdir);
246 while ((de = ReadDir(dirdesc, subdir)) != NULL)
248 if (strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0)
255 continue; /* indeed, nothing in it */
257 SRF_RETURN_NEXT(funcctx, ObjectIdGetDatum(datOid));
260 FreeDir(fctx->dirdesc);
261 SRF_RETURN_DONE(funcctx);
266 * pg_sleep - delay for N seconds
269 pg_sleep(PG_FUNCTION_ARGS)
271 float8 secs = PG_GETARG_FLOAT8(0);
275 * We break the requested sleep into segments of no more than 1 second, to
276 * put an upper bound on how long it will take us to respond to a cancel
277 * or die interrupt. (Note that pg_usleep is interruptible by signals on
278 * some platforms but not others.) Also, this method avoids exposing
279 * pg_usleep's upper bound on allowed delays.
281 * By computing the intended stop time initially, we avoid accumulation of
282 * extra delay across multiple sleeps. This also ensures we won't delay
283 * less than the specified time if pg_usleep is interrupted by other
284 * signals such as SIGHUP.
287 #ifdef HAVE_INT64_TIMESTAMP
288 #define GetNowFloat() ((float8) GetCurrentTimestamp() / 1000000.0)
290 #define GetNowFloat() GetCurrentTimestamp()
293 endtime = GetNowFloat() + secs;
299 CHECK_FOR_INTERRUPTS();
300 delay = endtime - GetNowFloat();
303 else if (delay > 0.0)
304 pg_usleep((long) ceil(delay * 1000000.0));