00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "postgres.h"
00016
00017 #include <sys/file.h>
00018 #include <signal.h>
00019 #include <dirent.h>
00020 #include <math.h>
00021 #include <unistd.h>
00022
00023 #include "catalog/catalog.h"
00024 #include "catalog/pg_tablespace.h"
00025 #include "catalog/pg_type.h"
00026 #include "commands/dbcommands.h"
00027 #include "common/relpath.h"
00028 #include "funcapi.h"
00029 #include "miscadmin.h"
00030 #include "parser/keywords.h"
00031 #include "postmaster/syslogger.h"
00032 #include "rewrite/rewriteHandler.h"
00033 #include "storage/fd.h"
00034 #include "storage/pmsignal.h"
00035 #include "storage/proc.h"
00036 #include "storage/procarray.h"
00037 #include "utils/lsyscache.h"
00038 #include "tcop/tcopprot.h"
00039 #include "utils/builtins.h"
00040 #include "utils/timestamp.h"
00041
00042 #define atooid(x) ((Oid) strtoul((x), NULL, 10))
00043
00044
00045
00046
00047
00048
00049 Datum
00050 current_database(PG_FUNCTION_ARGS)
00051 {
00052 Name db;
00053
00054 db = (Name) palloc(NAMEDATALEN);
00055
00056 namestrcpy(db, get_database_name(MyDatabaseId));
00057 PG_RETURN_NAME(db);
00058 }
00059
00060
00061
00062
00063
00064
00065
00066 Datum
00067 current_query(PG_FUNCTION_ARGS)
00068 {
00069
00070 if (debug_query_string)
00071 PG_RETURN_TEXT_P(cstring_to_text(debug_query_string));
00072 else
00073 PG_RETURN_NULL();
00074 }
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088 #define SIGNAL_BACKEND_SUCCESS 0
00089 #define SIGNAL_BACKEND_ERROR 1
00090 #define SIGNAL_BACKEND_NOPERMISSION 2
00091 static int
00092 pg_signal_backend(int pid, int sig)
00093 {
00094 PGPROC *proc = BackendPidGetProc(pid);
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 if (proc == NULL)
00105 {
00106
00107
00108
00109
00110 ereport(WARNING,
00111 (errmsg("PID %d is not a PostgreSQL server process", pid)));
00112 return SIGNAL_BACKEND_ERROR;
00113 }
00114
00115 if (!(superuser() || proc->roleId == GetUserId()))
00116 return SIGNAL_BACKEND_NOPERMISSION;
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128 #ifdef HAVE_SETSID
00129 if (kill(-pid, sig))
00130 #else
00131 if (kill(pid, sig))
00132 #endif
00133 {
00134
00135 ereport(WARNING,
00136 (errmsg("could not send signal to process %d: %m", pid)));
00137 return SIGNAL_BACKEND_ERROR;
00138 }
00139 return SIGNAL_BACKEND_SUCCESS;
00140 }
00141
00142
00143
00144
00145
00146 Datum
00147 pg_cancel_backend(PG_FUNCTION_ARGS)
00148 {
00149 int r = pg_signal_backend(PG_GETARG_INT32(0), SIGINT);
00150
00151 if (r == SIGNAL_BACKEND_NOPERMISSION)
00152 ereport(ERROR,
00153 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00154 (errmsg("must be superuser or have the same role to cancel queries running in other server processes"))));
00155
00156 PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);
00157 }
00158
00159
00160
00161
00162
00163 Datum
00164 pg_terminate_backend(PG_FUNCTION_ARGS)
00165 {
00166 int r = pg_signal_backend(PG_GETARG_INT32(0), SIGTERM);
00167
00168 if (r == SIGNAL_BACKEND_NOPERMISSION)
00169 ereport(ERROR,
00170 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00171 (errmsg("must be superuser or have the same role to terminate other server processes"))));
00172
00173 PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);
00174 }
00175
00176
00177
00178
00179 Datum
00180 pg_reload_conf(PG_FUNCTION_ARGS)
00181 {
00182 if (!superuser())
00183 ereport(ERROR,
00184 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00185 (errmsg("must be superuser to signal the postmaster"))));
00186
00187 if (kill(PostmasterPid, SIGHUP))
00188 {
00189 ereport(WARNING,
00190 (errmsg("failed to send signal to postmaster: %m")));
00191 PG_RETURN_BOOL(false);
00192 }
00193
00194 PG_RETURN_BOOL(true);
00195 }
00196
00197
00198
00199
00200
00201 Datum
00202 pg_rotate_logfile(PG_FUNCTION_ARGS)
00203 {
00204 if (!superuser())
00205 ereport(ERROR,
00206 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00207 (errmsg("must be superuser to rotate log files"))));
00208
00209 if (!Logging_collector)
00210 {
00211 ereport(WARNING,
00212 (errmsg("rotation not possible because log collection not active")));
00213 PG_RETURN_BOOL(false);
00214 }
00215
00216 SendPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE);
00217 PG_RETURN_BOOL(true);
00218 }
00219
00220
00221
00222 typedef struct
00223 {
00224 char *location;
00225 DIR *dirdesc;
00226 } ts_db_fctx;
00227
00228 Datum
00229 pg_tablespace_databases(PG_FUNCTION_ARGS)
00230 {
00231 FuncCallContext *funcctx;
00232 struct dirent *de;
00233 ts_db_fctx *fctx;
00234
00235 if (SRF_IS_FIRSTCALL())
00236 {
00237 MemoryContext oldcontext;
00238 Oid tablespaceOid = PG_GETARG_OID(0);
00239
00240 funcctx = SRF_FIRSTCALL_INIT();
00241 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
00242
00243 fctx = palloc(sizeof(ts_db_fctx));
00244
00245
00246
00247
00248 fctx->location = (char *) palloc(9 + 1 + OIDCHARS + 1 +
00249 strlen(TABLESPACE_VERSION_DIRECTORY) + 1);
00250 if (tablespaceOid == GLOBALTABLESPACE_OID)
00251 {
00252 fctx->dirdesc = NULL;
00253 ereport(WARNING,
00254 (errmsg("global tablespace never has databases")));
00255 }
00256 else
00257 {
00258 if (tablespaceOid == DEFAULTTABLESPACE_OID)
00259 sprintf(fctx->location, "base");
00260 else
00261 sprintf(fctx->location, "pg_tblspc/%u/%s", tablespaceOid,
00262 TABLESPACE_VERSION_DIRECTORY);
00263
00264 fctx->dirdesc = AllocateDir(fctx->location);
00265
00266 if (!fctx->dirdesc)
00267 {
00268
00269 if (errno != ENOENT)
00270 ereport(ERROR,
00271 (errcode_for_file_access(),
00272 errmsg("could not open directory \"%s\": %m",
00273 fctx->location)));
00274 ereport(WARNING,
00275 (errmsg("%u is not a tablespace OID", tablespaceOid)));
00276 }
00277 }
00278 funcctx->user_fctx = fctx;
00279 MemoryContextSwitchTo(oldcontext);
00280 }
00281
00282 funcctx = SRF_PERCALL_SETUP();
00283 fctx = (ts_db_fctx *) funcctx->user_fctx;
00284
00285 if (!fctx->dirdesc)
00286 SRF_RETURN_DONE(funcctx);
00287
00288 while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL)
00289 {
00290 char *subdir;
00291 DIR *dirdesc;
00292 Oid datOid = atooid(de->d_name);
00293
00294
00295 if (!datOid)
00296 continue;
00297
00298
00299
00300
00301 subdir = palloc(strlen(fctx->location) + 1 + strlen(de->d_name) + 1);
00302 sprintf(subdir, "%s/%s", fctx->location, de->d_name);
00303 dirdesc = AllocateDir(subdir);
00304 while ((de = ReadDir(dirdesc, subdir)) != NULL)
00305 {
00306 if (strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0)
00307 break;
00308 }
00309 FreeDir(dirdesc);
00310 pfree(subdir);
00311
00312 if (!de)
00313 continue;
00314
00315 SRF_RETURN_NEXT(funcctx, ObjectIdGetDatum(datOid));
00316 }
00317
00318 FreeDir(fctx->dirdesc);
00319 SRF_RETURN_DONE(funcctx);
00320 }
00321
00322
00323
00324
00325
00326 Datum
00327 pg_tablespace_location(PG_FUNCTION_ARGS)
00328 {
00329 Oid tablespaceOid = PG_GETARG_OID(0);
00330 char sourcepath[MAXPGPATH];
00331 char targetpath[MAXPGPATH];
00332 int rllen;
00333
00334
00335
00336
00337
00338
00339 if (tablespaceOid == InvalidOid)
00340 tablespaceOid = MyDatabaseTableSpace;
00341
00342
00343
00344
00345 if (tablespaceOid == DEFAULTTABLESPACE_OID ||
00346 tablespaceOid == GLOBALTABLESPACE_OID)
00347 PG_RETURN_TEXT_P(cstring_to_text(""));
00348
00349 #if defined(HAVE_READLINK) || defined(WIN32)
00350
00351
00352
00353
00354
00355 snprintf(sourcepath, sizeof(sourcepath), "pg_tblspc/%u", tablespaceOid);
00356
00357 rllen = readlink(sourcepath, targetpath, sizeof(targetpath));
00358 if (rllen < 0)
00359 ereport(ERROR,
00360 (errmsg("could not read symbolic link \"%s\": %m",
00361 sourcepath)));
00362 else if (rllen >= sizeof(targetpath))
00363 ereport(ERROR,
00364 (errmsg("symbolic link \"%s\" target is too long",
00365 sourcepath)));
00366 targetpath[rllen] = '\0';
00367
00368 PG_RETURN_TEXT_P(cstring_to_text(targetpath));
00369 #else
00370 ereport(ERROR,
00371 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00372 errmsg("tablespaces are not supported on this platform")));
00373 PG_RETURN_NULL();
00374 #endif
00375 }
00376
00377
00378
00379
00380 Datum
00381 pg_sleep(PG_FUNCTION_ARGS)
00382 {
00383 float8 secs = PG_GETARG_FLOAT8(0);
00384 float8 endtime;
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399 #ifdef HAVE_INT64_TIMESTAMP
00400 #define GetNowFloat() ((float8) GetCurrentTimestamp() / 1000000.0)
00401 #else
00402 #define GetNowFloat() GetCurrentTimestamp()
00403 #endif
00404
00405 endtime = GetNowFloat() + secs;
00406
00407 for (;;)
00408 {
00409 float8 delay;
00410
00411 CHECK_FOR_INTERRUPTS();
00412 delay = endtime - GetNowFloat();
00413 if (delay >= 1.0)
00414 pg_usleep(1000000L);
00415 else if (delay > 0.0)
00416 pg_usleep((long) ceil(delay * 1000000.0));
00417 else
00418 break;
00419 }
00420
00421 PG_RETURN_VOID();
00422 }
00423
00424
00425 Datum
00426 pg_get_keywords(PG_FUNCTION_ARGS)
00427 {
00428 FuncCallContext *funcctx;
00429
00430 if (SRF_IS_FIRSTCALL())
00431 {
00432 MemoryContext oldcontext;
00433 TupleDesc tupdesc;
00434
00435 funcctx = SRF_FIRSTCALL_INIT();
00436 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
00437
00438 tupdesc = CreateTemplateTupleDesc(3, false);
00439 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "word",
00440 TEXTOID, -1, 0);
00441 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "catcode",
00442 CHAROID, -1, 0);
00443 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "catdesc",
00444 TEXTOID, -1, 0);
00445
00446 funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
00447
00448 MemoryContextSwitchTo(oldcontext);
00449 }
00450
00451 funcctx = SRF_PERCALL_SETUP();
00452
00453 if (funcctx->call_cntr < NumScanKeywords)
00454 {
00455 char *values[3];
00456 HeapTuple tuple;
00457
00458
00459 values[0] = (char *) ScanKeywords[funcctx->call_cntr].name;
00460
00461 switch (ScanKeywords[funcctx->call_cntr].category)
00462 {
00463 case UNRESERVED_KEYWORD:
00464 values[1] = "U";
00465 values[2] = _("unreserved");
00466 break;
00467 case COL_NAME_KEYWORD:
00468 values[1] = "C";
00469 values[2] = _("unreserved (cannot be function or type name)");
00470 break;
00471 case TYPE_FUNC_NAME_KEYWORD:
00472 values[1] = "T";
00473 values[2] = _("reserved (can be function or type name)");
00474 break;
00475 case RESERVED_KEYWORD:
00476 values[1] = "R";
00477 values[2] = _("reserved");
00478 break;
00479 default:
00480 values[1] = NULL;
00481 values[2] = NULL;
00482 break;
00483 }
00484
00485 tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
00486
00487 SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
00488 }
00489
00490 SRF_RETURN_DONE(funcctx);
00491 }
00492
00493
00494
00495
00496
00497 Datum
00498 pg_typeof(PG_FUNCTION_ARGS)
00499 {
00500 PG_RETURN_OID(get_fn_expr_argtype(fcinfo->flinfo, 0));
00501 }
00502
00503
00504
00505
00506
00507
00508 Datum
00509 pg_collation_for(PG_FUNCTION_ARGS)
00510 {
00511 Oid typeid;
00512 Oid collid;
00513
00514 typeid = get_fn_expr_argtype(fcinfo->flinfo, 0);
00515 if (!typeid)
00516 PG_RETURN_NULL();
00517 if (!type_is_collatable(typeid) && typeid != UNKNOWNOID)
00518 ereport(ERROR,
00519 (errcode(ERRCODE_DATATYPE_MISMATCH),
00520 errmsg("collations are not supported by type %s",
00521 format_type_be(typeid))));
00522
00523 collid = PG_GET_COLLATION();
00524 if (!collid)
00525 PG_RETURN_NULL();
00526 PG_RETURN_TEXT_P(cstring_to_text(generate_collation_name(collid)));
00527 }
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541 Datum
00542 pg_view_is_insertable(PG_FUNCTION_ARGS)
00543 {
00544 Oid viewoid = PG_GETARG_OID(0);
00545 int req_events = (1 << CMD_INSERT);
00546
00547 PG_RETURN_BOOL(relation_is_updatable(viewoid, req_events));
00548 }
00549
00550 Datum
00551 pg_view_is_updatable(PG_FUNCTION_ARGS)
00552 {
00553 Oid viewoid = PG_GETARG_OID(0);
00554 int req_events = (1 << CMD_UPDATE) | (1 << CMD_DELETE);
00555
00556 PG_RETURN_BOOL(relation_is_updatable(viewoid, req_events));
00557 }