1 /*-------------------------------------------------------------------------
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
13 *-------------------------------------------------------------------------
22 #include "access/xact.h"
23 #include "catalog/pg_type.h"
24 #include "catalog/pg_tablespace.h"
25 #include "commands/dbcommands.h"
27 #include "miscadmin.h"
28 #include "parser/keywords.h"
29 #include "postmaster/syslogger.h"
30 #include "storage/fd.h"
31 #include "storage/pmsignal.h"
32 #include "storage/procarray.h"
33 #include "utils/builtins.h"
34 #include "tcop/tcopprot.h"
36 #define atooid(x) ((Oid) strtoul((x), NULL, 10))
41 * Expose the current database to the user
44 current_database(PG_FUNCTION_ARGS
)
48 db
= (Name
) palloc(NAMEDATALEN
);
50 namestrcpy(db
, get_database_name(MyDatabaseId
));
57 * Expose the current query to the user (useful in stored procedures)
60 current_query(PG_FUNCTION_ARGS
)
62 if (debug_query_string
)
63 PG_RETURN_TEXT_P(cstring_to_text(debug_query_string
));
69 * Functions to send signals to other backends.
72 pg_signal_backend(int pid
, int sig
)
76 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
77 (errmsg("must be superuser to signal other server processes"))));
79 if (!IsBackendPid(pid
))
82 * This is just a warning so a loop-through-resultset will not abort
83 * if one backend terminated on it's own during the run
86 (errmsg("PID %d is not a PostgreSQL server process", pid
)));
90 /* If we have setsid(), signal the backend's whole process group */
97 /* Again, just a warning to allow loops */
99 (errmsg("could not send signal to process %d: %m", pid
)));
106 pg_cancel_backend(PG_FUNCTION_ARGS
)
108 PG_RETURN_BOOL(pg_signal_backend(PG_GETARG_INT32(0), SIGINT
));
112 pg_terminate_backend(PG_FUNCTION_ARGS
)
114 PG_RETURN_BOOL(pg_signal_backend(PG_GETARG_INT32(0), SIGTERM
));
118 pg_reload_conf(PG_FUNCTION_ARGS
)
122 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
123 (errmsg("must be superuser to signal the postmaster"))));
125 if (kill(PostmasterPid
, SIGHUP
))
128 (errmsg("failed to send signal to postmaster: %m")));
129 PG_RETURN_BOOL(false);
132 PG_RETURN_BOOL(true);
140 pg_rotate_logfile(PG_FUNCTION_ARGS
)
144 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
145 (errmsg("must be superuser to rotate log files"))));
147 if (!Logging_collector
)
150 (errmsg("rotation not possible because log collection not active")));
151 PG_RETURN_BOOL(false);
154 SendPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE
);
155 PG_RETURN_BOOL(true);
158 /* Function to find out which databases make use of a tablespace */
167 pg_tablespace_databases(PG_FUNCTION_ARGS
)
169 FuncCallContext
*funcctx
;
173 if (SRF_IS_FIRSTCALL())
175 MemoryContext oldcontext
;
176 Oid tablespaceOid
= PG_GETARG_OID(0);
178 funcctx
= SRF_FIRSTCALL_INIT();
179 oldcontext
= MemoryContextSwitchTo(funcctx
->multi_call_memory_ctx
);
181 fctx
= palloc(sizeof(ts_db_fctx
));
184 * size = tablespace dirname length + dir sep char + oid + terminator
186 fctx
->location
= (char *) palloc(10 + 10 + 1);
187 if (tablespaceOid
== GLOBALTABLESPACE_OID
)
189 fctx
->dirdesc
= NULL
;
191 (errmsg("global tablespace never has databases")));
195 if (tablespaceOid
== DEFAULTTABLESPACE_OID
)
196 sprintf(fctx
->location
, "base");
198 sprintf(fctx
->location
, "pg_tblspc/%u", tablespaceOid
);
200 fctx
->dirdesc
= AllocateDir(fctx
->location
);
204 /* the only expected error is ENOENT */
207 (errcode_for_file_access(),
208 errmsg("could not open directory \"%s\": %m",
211 (errmsg("%u is not a tablespace OID", tablespaceOid
)));
214 funcctx
->user_fctx
= fctx
;
215 MemoryContextSwitchTo(oldcontext
);
218 funcctx
= SRF_PERCALL_SETUP();
219 fctx
= (ts_db_fctx
*) funcctx
->user_fctx
;
221 if (!fctx
->dirdesc
) /* not a tablespace */
222 SRF_RETURN_DONE(funcctx
);
224 while ((de
= ReadDir(fctx
->dirdesc
, fctx
->location
)) != NULL
)
228 Oid datOid
= atooid(de
->d_name
);
230 /* this test skips . and .., but is awfully weak */
234 /* if database subdir is empty, don't report tablespace as used */
236 /* size = path length + dir sep char + file name + terminator */
237 subdir
= palloc(strlen(fctx
->location
) + 1 + strlen(de
->d_name
) + 1);
238 sprintf(subdir
, "%s/%s", fctx
->location
, de
->d_name
);
239 dirdesc
= AllocateDir(subdir
);
240 while ((de
= ReadDir(dirdesc
, subdir
)) != NULL
)
242 if (strcmp(de
->d_name
, ".") != 0 && strcmp(de
->d_name
, "..") != 0)
249 continue; /* indeed, nothing in it */
251 SRF_RETURN_NEXT(funcctx
, ObjectIdGetDatum(datOid
));
254 FreeDir(fctx
->dirdesc
);
255 SRF_RETURN_DONE(funcctx
);
260 * pg_sleep - delay for N seconds
263 pg_sleep(PG_FUNCTION_ARGS
)
265 float8 secs
= PG_GETARG_FLOAT8(0);
269 * We break the requested sleep into segments of no more than 1 second, to
270 * put an upper bound on how long it will take us to respond to a cancel
271 * or die interrupt. (Note that pg_usleep is interruptible by signals on
272 * some platforms but not others.) Also, this method avoids exposing
273 * pg_usleep's upper bound on allowed delays.
275 * By computing the intended stop time initially, we avoid accumulation of
276 * extra delay across multiple sleeps. This also ensures we won't delay
277 * less than the specified time if pg_usleep is interrupted by other
278 * signals such as SIGHUP.
281 #ifdef HAVE_INT64_TIMESTAMP
282 #define GetNowFloat() ((float8) GetCurrentTimestamp() / 1000000.0)
284 #define GetNowFloat() GetCurrentTimestamp()
287 endtime
= GetNowFloat() + secs
;
293 CHECK_FOR_INTERRUPTS();
294 delay
= endtime
- GetNowFloat();
297 else if (delay
> 0.0)
298 pg_usleep((long) ceil(delay
* 1000000.0));
306 /* Function to return the list of grammar keywords */
308 pg_get_keywords(PG_FUNCTION_ARGS
)
310 FuncCallContext
*funcctx
;
312 if (SRF_IS_FIRSTCALL())
314 MemoryContext oldcontext
;
317 funcctx
= SRF_FIRSTCALL_INIT();
318 oldcontext
= MemoryContextSwitchTo(funcctx
->multi_call_memory_ctx
);
320 tupdesc
= CreateTemplateTupleDesc(3, false);
321 TupleDescInitEntry(tupdesc
, (AttrNumber
) 1, "word",
323 TupleDescInitEntry(tupdesc
, (AttrNumber
) 2, "catcode",
325 TupleDescInitEntry(tupdesc
, (AttrNumber
) 3, "catdesc",
328 funcctx
->attinmeta
= TupleDescGetAttInMetadata(tupdesc
);
330 MemoryContextSwitchTo(oldcontext
);
333 funcctx
= SRF_PERCALL_SETUP();
335 if (&ScanKeywords
[funcctx
->call_cntr
] < LastScanKeyword
)
340 /* cast-away-const is ugly but alternatives aren't much better */
341 values
[0] = (char *) ScanKeywords
[funcctx
->call_cntr
].name
;
343 switch (ScanKeywords
[funcctx
->call_cntr
].category
)
345 case UNRESERVED_KEYWORD
:
347 values
[2] = _("Unreserved");
349 case COL_NAME_KEYWORD
:
351 values
[2] = _("Column name");
353 case TYPE_FUNC_NAME_KEYWORD
:
355 values
[2] = _("Type or function name");
357 case RESERVED_KEYWORD
:
359 values
[2] = _("Reserved");
361 default: /* shouldn't be possible */
367 tuple
= BuildTupleFromCStrings(funcctx
->attinmeta
, values
);
369 SRF_RETURN_NEXT(funcctx
, HeapTupleGetDatum(tuple
));
372 SRF_RETURN_DONE(funcctx
);
377 * Return the type of the argument.
380 pg_typeof(PG_FUNCTION_ARGS
)
382 PG_RETURN_OID(get_fn_expr_argtype(fcinfo
->flinfo
, 0));