]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/misc.c
pgindent run for 8.2.
[postgresql] / src / backend / utils / adt / misc.c
1 /*-------------------------------------------------------------------------
2  *
3  * misc.c
4  *
5  *
6  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/utils/adt/misc.c,v 1.54 2006/10/04 00:29:59 momjian Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include <sys/file.h>
18 #include <signal.h>
19 #include <dirent.h>
20 #include <math.h>
21
22 #include "access/xact.h"
23 #include "catalog/pg_tablespace.h"
24 #include "commands/dbcommands.h"
25 #include "funcapi.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"
32
33 #define atooid(x)  ((Oid) strtoul((x), NULL, 10))
34
35
36 /*
37  * Check if data is Null
38  */
39 Datum
40 nullvalue(PG_FUNCTION_ARGS)
41 {
42         if (PG_ARGISNULL(0))
43                 PG_RETURN_BOOL(true);
44         PG_RETURN_BOOL(false);
45 }
46
47 /*
48  * Check if data is not Null
49  */
50 Datum
51 nonnullvalue(PG_FUNCTION_ARGS)
52 {
53         if (PG_ARGISNULL(0))
54                 PG_RETURN_BOOL(false);
55         PG_RETURN_BOOL(true);
56 }
57
58 /*
59  * current_database()
60  *      Expose the current database to the user
61  */
62 Datum
63 current_database(PG_FUNCTION_ARGS)
64 {
65         Name            db;
66
67         db = (Name) palloc(NAMEDATALEN);
68
69         namestrcpy(db, get_database_name(MyDatabaseId));
70         PG_RETURN_NAME(db);
71 }
72
73
74 /*
75  * Functions to send signals to other backends.
76  */
77 static bool
78 pg_signal_backend(int pid, int sig)
79 {
80         if (!superuser())
81                 ereport(ERROR,
82                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
83                         (errmsg("must be superuser to signal other server processes"))));
84
85         if (!IsBackendPid(pid))
86         {
87                 /*
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
90                  */
91                 ereport(WARNING,
92                                 (errmsg("PID %d is not a PostgreSQL server process", pid)));
93                 return false;
94         }
95
96         if (kill(pid, sig))
97         {
98                 /* Again, just a warning to allow loops */
99                 ereport(WARNING,
100                                 (errmsg("could not send signal to process %d: %m", pid)));
101                 return false;
102         }
103         return true;
104 }
105
106 Datum
107 pg_cancel_backend(PG_FUNCTION_ARGS)
108 {
109         PG_RETURN_BOOL(pg_signal_backend(PG_GETARG_INT32(0), SIGINT));
110 }
111
112 Datum
113 pg_reload_conf(PG_FUNCTION_ARGS)
114 {
115         if (!superuser())
116                 ereport(ERROR,
117                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
118                                  (errmsg("must be superuser to signal the postmaster"))));
119
120         if (kill(PostmasterPid, SIGHUP))
121         {
122                 ereport(WARNING,
123                                 (errmsg("failed to send signal to postmaster: %m")));
124                 PG_RETURN_BOOL(false);
125         }
126
127         PG_RETURN_BOOL(true);
128 }
129
130
131 /*
132  * Rotate log file
133  */
134 Datum
135 pg_rotate_logfile(PG_FUNCTION_ARGS)
136 {
137         if (!superuser())
138                 ereport(ERROR,
139                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
140                                  (errmsg("must be superuser to rotate log files"))));
141
142         if (!Redirect_stderr)
143         {
144                 ereport(WARNING,
145                 (errmsg("rotation not possible because log redirection not active")));
146                 PG_RETURN_BOOL(false);
147         }
148
149         SendPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE);
150         PG_RETURN_BOOL(true);
151 }
152
153 #ifdef NOT_USED
154
155 /* Disabled in 8.0 due to reliability concerns; FIXME someday */
156 Datum
157 pg_terminate_backend(PG_FUNCTION_ARGS)
158 {
159         PG_RETURN_INT32(pg_signal_backend(PG_GETARG_INT32(0), SIGTERM));
160 }
161 #endif
162
163
164 /* Function to find out which databases make use of a tablespace */
165
166 typedef struct
167 {
168         char       *location;
169         DIR                *dirdesc;
170 } ts_db_fctx;
171
172 Datum
173 pg_tablespace_databases(PG_FUNCTION_ARGS)
174 {
175         FuncCallContext *funcctx;
176         struct dirent *de;
177         ts_db_fctx *fctx;
178
179         if (SRF_IS_FIRSTCALL())
180         {
181                 MemoryContext oldcontext;
182                 Oid                     tablespaceOid = PG_GETARG_OID(0);
183
184                 funcctx = SRF_FIRSTCALL_INIT();
185                 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
186
187                 fctx = palloc(sizeof(ts_db_fctx));
188
189                 /*
190                  * size = tablespace dirname length + dir sep char + oid + terminator
191                  */
192                 fctx->location = (char *) palloc(10 + 10 + 1);
193                 if (tablespaceOid == GLOBALTABLESPACE_OID)
194                 {
195                         fctx->dirdesc = NULL;
196                         ereport(WARNING,
197                                         (errmsg("global tablespace never has databases")));
198                 }
199                 else
200                 {
201                         if (tablespaceOid == DEFAULTTABLESPACE_OID)
202                                 sprintf(fctx->location, "base");
203                         else
204                                 sprintf(fctx->location, "pg_tblspc/%u", tablespaceOid);
205
206                         fctx->dirdesc = AllocateDir(fctx->location);
207
208                         if (!fctx->dirdesc)
209                         {
210                                 /* the only expected error is ENOENT */
211                                 if (errno != ENOENT)
212                                         ereport(ERROR,
213                                                         (errcode_for_file_access(),
214                                                          errmsg("could not open directory \"%s\": %m",
215                                                                         fctx->location)));
216                                 ereport(WARNING,
217                                           (errmsg("%u is not a tablespace OID", tablespaceOid)));
218                         }
219                 }
220                 funcctx->user_fctx = fctx;
221                 MemoryContextSwitchTo(oldcontext);
222         }
223
224         funcctx = SRF_PERCALL_SETUP();
225         fctx = (ts_db_fctx *) funcctx->user_fctx;
226
227         if (!fctx->dirdesc)                     /* not a tablespace */
228                 SRF_RETURN_DONE(funcctx);
229
230         while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL)
231         {
232                 char       *subdir;
233                 DIR                *dirdesc;
234                 Oid                     datOid = atooid(de->d_name);
235
236                 /* this test skips . and .., but is awfully weak */
237                 if (!datOid)
238                         continue;
239
240                 /* if database subdir is empty, don't report tablespace as used */
241
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)
247                 {
248                         if (strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0)
249                                 break;
250                 }
251                 FreeDir(dirdesc);
252                 pfree(subdir);
253
254                 if (!de)
255                         continue;                       /* indeed, nothing in it */
256
257                 SRF_RETURN_NEXT(funcctx, ObjectIdGetDatum(datOid));
258         }
259
260         FreeDir(fctx->dirdesc);
261         SRF_RETURN_DONE(funcctx);
262 }
263
264
265 /*
266  * pg_sleep - delay for N seconds
267  */
268 Datum
269 pg_sleep(PG_FUNCTION_ARGS)
270 {
271         float8          secs = PG_GETARG_FLOAT8(0);
272         float8          endtime;
273
274         /*
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.
280          *
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.
285          */
286
287 #ifdef HAVE_INT64_TIMESTAMP
288 #define GetNowFloat()   ((float8) GetCurrentTimestamp() / 1000000.0)
289 #else
290 #define GetNowFloat()   GetCurrentTimestamp()
291 #endif
292
293         endtime = GetNowFloat() + secs;
294
295         for (;;)
296         {
297                 float8          delay;
298
299                 CHECK_FOR_INTERRUPTS();
300                 delay = endtime - GetNowFloat();
301                 if (delay >= 1.0)
302                         pg_usleep(1000000L);
303                 else if (delay > 0.0)
304                         pg_usleep((long) ceil(delay * 1000000.0));
305                 else
306                         break;
307         }
308
309         PG_RETURN_VOID();
310 }