Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * misc.c
4 : *
5 : *
6 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/utils/adt/misc.c
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 : #include <unistd.h>
22 :
23 : #include "access/sysattr.h"
24 : #include "catalog/pg_authid.h"
25 : #include "catalog/catalog.h"
26 : #include "catalog/pg_tablespace.h"
27 : #include "catalog/pg_type.h"
28 : #include "commands/dbcommands.h"
29 : #include "common/keywords.h"
30 : #include "funcapi.h"
31 : #include "miscadmin.h"
32 : #include "pgstat.h"
33 : #include "parser/scansup.h"
34 : #include "postmaster/syslogger.h"
35 : #include "rewrite/rewriteHandler.h"
36 : #include "storage/fd.h"
37 : #include "storage/pmsignal.h"
38 : #include "storage/proc.h"
39 : #include "storage/procarray.h"
40 : #include "utils/lsyscache.h"
41 : #include "utils/ruleutils.h"
42 : #include "tcop/tcopprot.h"
43 : #include "utils/acl.h"
44 : #include "utils/builtins.h"
45 : #include "utils/timestamp.h"
46 :
47 :
48 : /*
49 : * Common subroutine for num_nulls() and num_nonnulls().
50 : * Returns TRUE if successful, FALSE if function should return NULL.
51 : * If successful, total argument count and number of nulls are
52 : * returned into *nargs and *nulls.
53 : */
54 : static bool
55 20 : count_nulls(FunctionCallInfo fcinfo,
56 : int32 *nargs, int32 *nulls)
57 : {
58 20 : int32 count = 0;
59 : int i;
60 :
61 : /* Did we get a VARIADIC array argument, or separate arguments? */
62 20 : if (get_fn_expr_variadic(fcinfo->flinfo))
63 : {
64 : ArrayType *arr;
65 : int ndims,
66 : nitems,
67 : *dims;
68 : bits8 *bitmap;
69 :
70 10 : Assert(PG_NARGS() == 1);
71 :
72 : /*
73 : * If we get a null as VARIADIC array argument, we can't say anything
74 : * useful about the number of elements, so return NULL. This behavior
75 : * is consistent with other variadic functions - see concat_internal.
76 : */
77 10 : if (PG_ARGISNULL(0))
78 2 : return false;
79 :
80 : /*
81 : * Non-null argument had better be an array. We assume that any call
82 : * context that could let get_fn_expr_variadic return true will have
83 : * checked that a VARIADIC-labeled parameter actually is an array. So
84 : * it should be okay to just Assert that it's an array rather than
85 : * doing a full-fledged error check.
86 : */
87 8 : Assert(OidIsValid(get_base_element_type(get_fn_expr_argtype(fcinfo->flinfo, 0))));
88 :
89 : /* OK, safe to fetch the array value */
90 8 : arr = PG_GETARG_ARRAYTYPE_P(0);
91 :
92 : /* Count the array elements */
93 8 : ndims = ARR_NDIM(arr);
94 8 : dims = ARR_DIMS(arr);
95 8 : nitems = ArrayGetNItems(ndims, dims);
96 :
97 : /* Count those that are NULL */
98 8 : bitmap = ARR_NULLBITMAP(arr);
99 8 : if (bitmap)
100 : {
101 4 : int bitmask = 1;
102 :
103 212 : for (i = 0; i < nitems; i++)
104 : {
105 208 : if ((*bitmap & bitmask) == 0)
106 4 : count++;
107 :
108 208 : bitmask <<= 1;
109 208 : if (bitmask == 0x100)
110 : {
111 24 : bitmap++;
112 24 : bitmask = 1;
113 : }
114 : }
115 : }
116 :
117 8 : *nargs = nitems;
118 8 : *nulls = count;
119 : }
120 : else
121 : {
122 : /* Separate arguments, so just count 'em */
123 34 : for (i = 0; i < PG_NARGS(); i++)
124 : {
125 24 : if (PG_ARGISNULL(i))
126 14 : count++;
127 : }
128 :
129 10 : *nargs = PG_NARGS();
130 10 : *nulls = count;
131 : }
132 :
133 18 : return true;
134 : }
135 :
136 : /*
137 : * num_nulls()
138 : * Count the number of NULL arguments
139 : */
140 : Datum
141 10 : pg_num_nulls(PG_FUNCTION_ARGS)
142 : {
143 : int32 nargs,
144 : nulls;
145 :
146 10 : if (!count_nulls(fcinfo, &nargs, &nulls))
147 1 : PG_RETURN_NULL();
148 :
149 9 : PG_RETURN_INT32(nulls);
150 : }
151 :
152 : /*
153 : * num_nonnulls()
154 : * Count the number of non-NULL arguments
155 : */
156 : Datum
157 10 : pg_num_nonnulls(PG_FUNCTION_ARGS)
158 : {
159 : int32 nargs,
160 : nulls;
161 :
162 10 : if (!count_nulls(fcinfo, &nargs, &nulls))
163 1 : PG_RETURN_NULL();
164 :
165 9 : PG_RETURN_INT32(nargs - nulls);
166 : }
167 :
168 :
169 : /*
170 : * current_database()
171 : * Expose the current database to the user
172 : */
173 : Datum
174 124 : current_database(PG_FUNCTION_ARGS)
175 : {
176 : Name db;
177 :
178 124 : db = (Name) palloc(NAMEDATALEN);
179 :
180 124 : namestrcpy(db, get_database_name(MyDatabaseId));
181 124 : PG_RETURN_NAME(db);
182 : }
183 :
184 :
185 : /*
186 : * current_query()
187 : * Expose the current query to the user (useful in stored procedures)
188 : * We might want to use ActivePortal->sourceText someday.
189 : */
190 : Datum
191 0 : current_query(PG_FUNCTION_ARGS)
192 : {
193 : /* there is no easy way to access the more concise 'query_string' */
194 0 : if (debug_query_string)
195 0 : PG_RETURN_TEXT_P(cstring_to_text(debug_query_string));
196 : else
197 0 : PG_RETURN_NULL();
198 : }
199 :
200 : /*
201 : * Send a signal to another backend.
202 : *
203 : * The signal is delivered if the user is either a superuser or the same
204 : * role as the backend being signaled. For "dangerous" signals, an explicit
205 : * check for superuser needs to be done prior to calling this function.
206 : *
207 : * Returns 0 on success, 1 on general failure, 2 on normal permission error
208 : * and 3 if the caller needs to be a superuser.
209 : *
210 : * In the event of a general failure (return code 1), a warning message will
211 : * be emitted. For permission errors, doing that is the responsibility of
212 : * the caller.
213 : */
214 : #define SIGNAL_BACKEND_SUCCESS 0
215 : #define SIGNAL_BACKEND_ERROR 1
216 : #define SIGNAL_BACKEND_NOPERMISSION 2
217 : #define SIGNAL_BACKEND_NOSUPERUSER 3
218 : static int
219 0 : pg_signal_backend(int pid, int sig)
220 : {
221 0 : PGPROC *proc = BackendPidGetProc(pid);
222 :
223 : /*
224 : * BackendPidGetProc returns NULL if the pid isn't valid; but by the time
225 : * we reach kill(), a process for which we get a valid proc here might
226 : * have terminated on its own. There's no way to acquire a lock on an
227 : * arbitrary process to prevent that. But since so far all the callers of
228 : * this mechanism involve some request for ending the process anyway, that
229 : * it might end on its own first is not a problem.
230 : */
231 0 : if (proc == NULL)
232 : {
233 : /*
234 : * This is just a warning so a loop-through-resultset will not abort
235 : * if one backend terminated on its own during the run.
236 : */
237 0 : ereport(WARNING,
238 : (errmsg("PID %d is not a PostgreSQL server process", pid)));
239 0 : return SIGNAL_BACKEND_ERROR;
240 : }
241 :
242 : /* Only allow superusers to signal superuser-owned backends. */
243 0 : if (superuser_arg(proc->roleId) && !superuser())
244 0 : return SIGNAL_BACKEND_NOSUPERUSER;
245 :
246 : /* Users can signal backends they have role membership in. */
247 0 : if (!has_privs_of_role(GetUserId(), proc->roleId) &&
248 0 : !has_privs_of_role(GetUserId(), DEFAULT_ROLE_SIGNAL_BACKENDID))
249 0 : return SIGNAL_BACKEND_NOPERMISSION;
250 :
251 : /*
252 : * Can the process we just validated above end, followed by the pid being
253 : * recycled for a new process, before reaching here? Then we'd be trying
254 : * to kill the wrong thing. Seems near impossible when sequential pid
255 : * assignment and wraparound is used. Perhaps it could happen on a system
256 : * where pid re-use is randomized. That race condition possibility seems
257 : * too unlikely to worry about.
258 : */
259 :
260 : /* If we have setsid(), signal the backend's whole process group */
261 : #ifdef HAVE_SETSID
262 0 : if (kill(-pid, sig))
263 : #else
264 : if (kill(pid, sig))
265 : #endif
266 : {
267 : /* Again, just a warning to allow loops */
268 0 : ereport(WARNING,
269 : (errmsg("could not send signal to process %d: %m", pid)));
270 0 : return SIGNAL_BACKEND_ERROR;
271 : }
272 0 : return SIGNAL_BACKEND_SUCCESS;
273 : }
274 :
275 : /*
276 : * Signal to cancel a backend process. This is allowed if you are a member of
277 : * the role whose process is being canceled.
278 : *
279 : * Note that only superusers can signal superuser-owned processes.
280 : */
281 : Datum
282 0 : pg_cancel_backend(PG_FUNCTION_ARGS)
283 : {
284 0 : int r = pg_signal_backend(PG_GETARG_INT32(0), SIGINT);
285 :
286 0 : if (r == SIGNAL_BACKEND_NOSUPERUSER)
287 0 : ereport(ERROR,
288 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
289 : (errmsg("must be a superuser to cancel superuser query"))));
290 :
291 0 : if (r == SIGNAL_BACKEND_NOPERMISSION)
292 0 : ereport(ERROR,
293 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
294 : (errmsg("must be a member of the role whose query is being canceled or member of pg_signal_backend"))));
295 :
296 0 : PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);
297 : }
298 :
299 : /*
300 : * Signal to terminate a backend process. This is allowed if you are a member
301 : * of the role whose process is being terminated.
302 : *
303 : * Note that only superusers can signal superuser-owned processes.
304 : */
305 : Datum
306 0 : pg_terminate_backend(PG_FUNCTION_ARGS)
307 : {
308 0 : int r = pg_signal_backend(PG_GETARG_INT32(0), SIGTERM);
309 :
310 0 : if (r == SIGNAL_BACKEND_NOSUPERUSER)
311 0 : ereport(ERROR,
312 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
313 : (errmsg("must be a superuser to terminate superuser process"))));
314 :
315 0 : if (r == SIGNAL_BACKEND_NOPERMISSION)
316 0 : ereport(ERROR,
317 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
318 : (errmsg("must be a member of the role whose process is being terminated or member of pg_signal_backend"))));
319 :
320 0 : PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);
321 : }
322 :
323 : /*
324 : * Signal to reload the database configuration
325 : *
326 : * Permission checking for this function is managed through the normal
327 : * GRANT system.
328 : */
329 : Datum
330 0 : pg_reload_conf(PG_FUNCTION_ARGS)
331 : {
332 0 : if (kill(PostmasterPid, SIGHUP))
333 : {
334 0 : ereport(WARNING,
335 : (errmsg("failed to send signal to postmaster: %m")));
336 0 : PG_RETURN_BOOL(false);
337 : }
338 :
339 0 : PG_RETURN_BOOL(true);
340 : }
341 :
342 :
343 : /*
344 : * Rotate log file
345 : *
346 : * Permission checking for this function is managed through the normal
347 : * GRANT system.
348 : */
349 : Datum
350 0 : pg_rotate_logfile(PG_FUNCTION_ARGS)
351 : {
352 0 : if (!Logging_collector)
353 : {
354 0 : ereport(WARNING,
355 : (errmsg("rotation not possible because log collection not active")));
356 0 : PG_RETURN_BOOL(false);
357 : }
358 :
359 0 : SendPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE);
360 0 : PG_RETURN_BOOL(true);
361 : }
362 :
363 : /* Function to find out which databases make use of a tablespace */
364 :
365 : typedef struct
366 : {
367 : char *location;
368 : DIR *dirdesc;
369 : } ts_db_fctx;
370 :
371 : Datum
372 0 : pg_tablespace_databases(PG_FUNCTION_ARGS)
373 : {
374 : FuncCallContext *funcctx;
375 : struct dirent *de;
376 : ts_db_fctx *fctx;
377 :
378 0 : if (SRF_IS_FIRSTCALL())
379 : {
380 : MemoryContext oldcontext;
381 0 : Oid tablespaceOid = PG_GETARG_OID(0);
382 :
383 0 : funcctx = SRF_FIRSTCALL_INIT();
384 0 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
385 :
386 0 : fctx = palloc(sizeof(ts_db_fctx));
387 :
388 0 : if (tablespaceOid == GLOBALTABLESPACE_OID)
389 : {
390 0 : fctx->dirdesc = NULL;
391 0 : ereport(WARNING,
392 : (errmsg("global tablespace never has databases")));
393 : }
394 : else
395 : {
396 0 : if (tablespaceOid == DEFAULTTABLESPACE_OID)
397 0 : fctx->location = psprintf("base");
398 : else
399 0 : fctx->location = psprintf("pg_tblspc/%u/%s", tablespaceOid,
400 : TABLESPACE_VERSION_DIRECTORY);
401 :
402 0 : fctx->dirdesc = AllocateDir(fctx->location);
403 :
404 0 : if (!fctx->dirdesc)
405 : {
406 : /* the only expected error is ENOENT */
407 0 : if (errno != ENOENT)
408 0 : ereport(ERROR,
409 : (errcode_for_file_access(),
410 : errmsg("could not open directory \"%s\": %m",
411 : fctx->location)));
412 0 : ereport(WARNING,
413 : (errmsg("%u is not a tablespace OID", tablespaceOid)));
414 : }
415 : }
416 0 : funcctx->user_fctx = fctx;
417 0 : MemoryContextSwitchTo(oldcontext);
418 : }
419 :
420 0 : funcctx = SRF_PERCALL_SETUP();
421 0 : fctx = (ts_db_fctx *) funcctx->user_fctx;
422 :
423 0 : if (!fctx->dirdesc) /* not a tablespace */
424 0 : SRF_RETURN_DONE(funcctx);
425 :
426 0 : while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL)
427 : {
428 : char *subdir;
429 : DIR *dirdesc;
430 0 : Oid datOid = atooid(de->d_name);
431 :
432 : /* this test skips . and .., but is awfully weak */
433 0 : if (!datOid)
434 0 : continue;
435 :
436 : /* if database subdir is empty, don't report tablespace as used */
437 :
438 0 : subdir = psprintf("%s/%s", fctx->location, de->d_name);
439 0 : dirdesc = AllocateDir(subdir);
440 0 : while ((de = ReadDir(dirdesc, subdir)) != NULL)
441 : {
442 0 : if (strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0)
443 0 : break;
444 : }
445 0 : FreeDir(dirdesc);
446 0 : pfree(subdir);
447 :
448 0 : if (!de)
449 0 : continue; /* indeed, nothing in it */
450 :
451 0 : SRF_RETURN_NEXT(funcctx, ObjectIdGetDatum(datOid));
452 : }
453 :
454 0 : FreeDir(fctx->dirdesc);
455 0 : SRF_RETURN_DONE(funcctx);
456 : }
457 :
458 :
459 : /*
460 : * pg_tablespace_location - get location for a tablespace
461 : */
462 : Datum
463 0 : pg_tablespace_location(PG_FUNCTION_ARGS)
464 : {
465 0 : Oid tablespaceOid = PG_GETARG_OID(0);
466 : char sourcepath[MAXPGPATH];
467 : char targetpath[MAXPGPATH];
468 : int rllen;
469 :
470 : /*
471 : * It's useful to apply this function to pg_class.reltablespace, wherein
472 : * zero means "the database's default tablespace". So, rather than
473 : * throwing an error for zero, we choose to assume that's what is meant.
474 : */
475 0 : if (tablespaceOid == InvalidOid)
476 0 : tablespaceOid = MyDatabaseTableSpace;
477 :
478 : /*
479 : * Return empty string for the cluster's default tablespaces
480 : */
481 0 : if (tablespaceOid == DEFAULTTABLESPACE_OID ||
482 : tablespaceOid == GLOBALTABLESPACE_OID)
483 0 : PG_RETURN_TEXT_P(cstring_to_text(""));
484 :
485 : #if defined(HAVE_READLINK) || defined(WIN32)
486 :
487 : /*
488 : * Find the location of the tablespace by reading the symbolic link that
489 : * is in pg_tblspc/<oid>.
490 : */
491 0 : snprintf(sourcepath, sizeof(sourcepath), "pg_tblspc/%u", tablespaceOid);
492 :
493 0 : rllen = readlink(sourcepath, targetpath, sizeof(targetpath));
494 0 : if (rllen < 0)
495 0 : ereport(ERROR,
496 : (errcode_for_file_access(),
497 : errmsg("could not read symbolic link \"%s\": %m",
498 : sourcepath)));
499 0 : if (rllen >= sizeof(targetpath))
500 0 : ereport(ERROR,
501 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
502 : errmsg("symbolic link \"%s\" target is too long",
503 : sourcepath)));
504 0 : targetpath[rllen] = '\0';
505 :
506 0 : PG_RETURN_TEXT_P(cstring_to_text(targetpath));
507 : #else
508 : ereport(ERROR,
509 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
510 : errmsg("tablespaces are not supported on this platform")));
511 : PG_RETURN_NULL();
512 : #endif
513 : }
514 :
515 : /*
516 : * pg_sleep - delay for N seconds
517 : */
518 : Datum
519 10 : pg_sleep(PG_FUNCTION_ARGS)
520 : {
521 10 : float8 secs = PG_GETARG_FLOAT8(0);
522 : float8 endtime;
523 :
524 : /*
525 : * We sleep using WaitLatch, to ensure that we'll wake up promptly if an
526 : * important signal (such as SIGALRM or SIGINT) arrives. Because
527 : * WaitLatch's upper limit of delay is INT_MAX milliseconds, and the user
528 : * might ask for more than that, we sleep for at most 10 minutes and then
529 : * loop.
530 : *
531 : * By computing the intended stop time initially, we avoid accumulation of
532 : * extra delay across multiple sleeps. This also ensures we won't delay
533 : * less than the specified time when WaitLatch is terminated early by a
534 : * non-query-canceling signal such as SIGHUP.
535 : */
536 : #define GetNowFloat() ((float8) GetCurrentTimestamp() / 1000000.0)
537 :
538 10 : endtime = GetNowFloat() + secs;
539 :
540 : for (;;)
541 : {
542 : float8 delay;
543 : long delay_ms;
544 :
545 21 : CHECK_FOR_INTERRUPTS();
546 :
547 21 : delay = endtime - GetNowFloat();
548 21 : if (delay >= 600.0)
549 0 : delay_ms = 600000;
550 21 : else if (delay > 0.0)
551 11 : delay_ms = (long) ceil(delay * 1000.0);
552 : else
553 10 : break;
554 :
555 11 : (void) WaitLatch(MyLatch,
556 : WL_LATCH_SET | WL_TIMEOUT,
557 : delay_ms,
558 : WAIT_EVENT_PG_SLEEP);
559 11 : ResetLatch(MyLatch);
560 11 : }
561 :
562 10 : PG_RETURN_VOID();
563 : }
564 :
565 : /* Function to return the list of grammar keywords */
566 : Datum
567 0 : pg_get_keywords(PG_FUNCTION_ARGS)
568 : {
569 : FuncCallContext *funcctx;
570 :
571 0 : if (SRF_IS_FIRSTCALL())
572 : {
573 : MemoryContext oldcontext;
574 : TupleDesc tupdesc;
575 :
576 0 : funcctx = SRF_FIRSTCALL_INIT();
577 0 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
578 :
579 0 : tupdesc = CreateTemplateTupleDesc(3, false);
580 0 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "word",
581 : TEXTOID, -1, 0);
582 0 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "catcode",
583 : CHAROID, -1, 0);
584 0 : TupleDescInitEntry(tupdesc, (AttrNumber) 3, "catdesc",
585 : TEXTOID, -1, 0);
586 :
587 0 : funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
588 :
589 0 : MemoryContextSwitchTo(oldcontext);
590 : }
591 :
592 0 : funcctx = SRF_PERCALL_SETUP();
593 :
594 0 : if (funcctx->call_cntr < NumScanKeywords)
595 : {
596 : char *values[3];
597 : HeapTuple tuple;
598 :
599 : /* cast-away-const is ugly but alternatives aren't much better */
600 0 : values[0] = (char *) ScanKeywords[funcctx->call_cntr].name;
601 :
602 0 : switch (ScanKeywords[funcctx->call_cntr].category)
603 : {
604 : case UNRESERVED_KEYWORD:
605 0 : values[1] = "U";
606 0 : values[2] = _("unreserved");
607 0 : break;
608 : case COL_NAME_KEYWORD:
609 0 : values[1] = "C";
610 0 : values[2] = _("unreserved (cannot be function or type name)");
611 0 : break;
612 : case TYPE_FUNC_NAME_KEYWORD:
613 0 : values[1] = "T";
614 0 : values[2] = _("reserved (can be function or type name)");
615 0 : break;
616 : case RESERVED_KEYWORD:
617 0 : values[1] = "R";
618 0 : values[2] = _("reserved");
619 0 : break;
620 : default: /* shouldn't be possible */
621 0 : values[1] = NULL;
622 0 : values[2] = NULL;
623 0 : break;
624 : }
625 :
626 0 : tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
627 :
628 0 : SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
629 : }
630 :
631 0 : SRF_RETURN_DONE(funcctx);
632 : }
633 :
634 :
635 : /*
636 : * Return the type of the argument.
637 : */
638 : Datum
639 15 : pg_typeof(PG_FUNCTION_ARGS)
640 : {
641 15 : PG_RETURN_OID(get_fn_expr_argtype(fcinfo->flinfo, 0));
642 : }
643 :
644 :
645 : /*
646 : * Implementation of the COLLATE FOR expression; returns the collation
647 : * of the argument.
648 : */
649 : Datum
650 5 : pg_collation_for(PG_FUNCTION_ARGS)
651 : {
652 : Oid typeid;
653 : Oid collid;
654 :
655 5 : typeid = get_fn_expr_argtype(fcinfo->flinfo, 0);
656 5 : if (!typeid)
657 0 : PG_RETURN_NULL();
658 5 : if (!type_is_collatable(typeid) && typeid != UNKNOWNOID)
659 1 : ereport(ERROR,
660 : (errcode(ERRCODE_DATATYPE_MISMATCH),
661 : errmsg("collations are not supported by type %s",
662 : format_type_be(typeid))));
663 :
664 4 : collid = PG_GET_COLLATION();
665 4 : if (!collid)
666 1 : PG_RETURN_NULL();
667 3 : PG_RETURN_TEXT_P(cstring_to_text(generate_collation_name(collid)));
668 : }
669 :
670 :
671 : /*
672 : * pg_relation_is_updatable - determine which update events the specified
673 : * relation supports.
674 : *
675 : * This relies on relation_is_updatable() in rewriteHandler.c, which see
676 : * for additional information.
677 : */
678 : Datum
679 147 : pg_relation_is_updatable(PG_FUNCTION_ARGS)
680 : {
681 147 : Oid reloid = PG_GETARG_OID(0);
682 147 : bool include_triggers = PG_GETARG_BOOL(1);
683 :
684 147 : PG_RETURN_INT32(relation_is_updatable(reloid, include_triggers, NULL));
685 : }
686 :
687 : /*
688 : * pg_column_is_updatable - determine whether a column is updatable
689 : *
690 : * This function encapsulates the decision about just what
691 : * information_schema.columns.is_updatable actually means. It's not clear
692 : * whether deletability of the column's relation should be required, so
693 : * we want that decision in C code where we could change it without initdb.
694 : */
695 : Datum
696 95 : pg_column_is_updatable(PG_FUNCTION_ARGS)
697 : {
698 95 : Oid reloid = PG_GETARG_OID(0);
699 95 : AttrNumber attnum = PG_GETARG_INT16(1);
700 95 : AttrNumber col = attnum - FirstLowInvalidHeapAttributeNumber;
701 95 : bool include_triggers = PG_GETARG_BOOL(2);
702 : int events;
703 :
704 : /* System columns are never updatable */
705 95 : if (attnum <= 0)
706 0 : PG_RETURN_BOOL(false);
707 :
708 95 : events = relation_is_updatable(reloid, include_triggers,
709 : bms_make_singleton(col));
710 :
711 : /* We require both updatability and deletability of the relation */
712 : #define REQ_EVENTS ((1 << CMD_UPDATE) | (1 << CMD_DELETE))
713 :
714 95 : PG_RETURN_BOOL((events & REQ_EVENTS) == REQ_EVENTS);
715 : }
716 :
717 :
718 : /*
719 : * Is character a valid identifier start?
720 : * Must match scan.l's {ident_start} character class.
721 : */
722 : static bool
723 367 : is_ident_start(unsigned char c)
724 : {
725 : /* Underscores and ASCII letters are OK */
726 367 : if (c == '_')
727 0 : return true;
728 367 : if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
729 342 : return true;
730 : /* Any high-bit-set character is OK (might be part of a multibyte char) */
731 25 : if (IS_HIGHBIT_SET(c))
732 0 : return true;
733 25 : return false;
734 : }
735 :
736 : /*
737 : * Is character a valid identifier continuation?
738 : * Must match scan.l's {ident_cont} character class.
739 : */
740 : static bool
741 342 : is_ident_cont(unsigned char c)
742 : {
743 : /* Can be digit or dollar sign ... */
744 342 : if ((c >= '0' && c <= '9') || c == '$')
745 0 : return true;
746 : /* ... or an identifier start character */
747 342 : return is_ident_start(c);
748 : }
749 :
750 : /*
751 : * parse_ident - parse a SQL qualified identifier into separate identifiers.
752 : * When strict mode is active (second parameter), then any chars after
753 : * the last identifier are disallowed.
754 : */
755 : Datum
756 19 : parse_ident(PG_FUNCTION_ARGS)
757 : {
758 19 : text *qualname = PG_GETARG_TEXT_PP(0);
759 19 : bool strict = PG_GETARG_BOOL(1);
760 19 : char *qualname_str = text_to_cstring(qualname);
761 19 : ArrayBuildState *astate = NULL;
762 : char *nextp;
763 19 : bool after_dot = false;
764 :
765 : /*
766 : * The code below scribbles on qualname_str in some cases, so we should
767 : * reconvert qualname if we need to show the original string in error
768 : * messages.
769 : */
770 19 : nextp = qualname_str;
771 :
772 : /* skip leading whitespace */
773 43 : while (scanner_isspace(*nextp))
774 5 : nextp++;
775 :
776 : for (;;)
777 : {
778 : char *curname;
779 35 : bool missing_ident = true;
780 :
781 35 : if (*nextp == '"')
782 : {
783 : char *endp;
784 :
785 10 : curname = nextp + 1;
786 : for (;;)
787 : {
788 10 : endp = strchr(nextp + 1, '"');
789 10 : if (endp == NULL)
790 0 : ereport(ERROR,
791 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
792 : errmsg("string is not a valid identifier: \"%s\"",
793 : text_to_cstring(qualname)),
794 : errdetail("String has unclosed double quotes.")));
795 10 : if (endp[1] != '"')
796 10 : break;
797 0 : memmove(endp, endp + 1, strlen(endp));
798 0 : nextp = endp;
799 0 : }
800 10 : nextp = endp + 1;
801 10 : *endp = '\0';
802 :
803 10 : if (endp - curname == 0)
804 0 : ereport(ERROR,
805 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
806 : errmsg("string is not a valid identifier: \"%s\"",
807 : text_to_cstring(qualname)),
808 : errdetail("Quoted identifier must not be empty.")));
809 :
810 10 : astate = accumArrayResult(astate, CStringGetTextDatum(curname),
811 : false, TEXTOID, CurrentMemoryContext);
812 10 : missing_ident = false;
813 : }
814 25 : else if (is_ident_start((unsigned char) *nextp))
815 : {
816 : char *downname;
817 : int len;
818 : text *part;
819 :
820 17 : curname = nextp++;
821 359 : while (is_ident_cont((unsigned char) *nextp))
822 325 : nextp++;
823 :
824 17 : len = nextp - curname;
825 :
826 : /*
827 : * We don't implicitly truncate identifiers. This is useful for
828 : * allowing the user to check for specific parts of the identifier
829 : * being too long. It's easy enough for the user to get the
830 : * truncated names by casting our output to name[].
831 : */
832 17 : downname = downcase_identifier(curname, len, false, false);
833 17 : part = cstring_to_text_with_len(downname, len);
834 17 : astate = accumArrayResult(astate, PointerGetDatum(part), false,
835 : TEXTOID, CurrentMemoryContext);
836 17 : missing_ident = false;
837 : }
838 :
839 35 : if (missing_ident)
840 : {
841 : /* Different error messages based on where we failed. */
842 8 : if (*nextp == '.')
843 3 : ereport(ERROR,
844 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
845 : errmsg("string is not a valid identifier: \"%s\"",
846 : text_to_cstring(qualname)),
847 : errdetail("No valid identifier before \".\".")));
848 5 : else if (after_dot)
849 2 : ereport(ERROR,
850 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
851 : errmsg("string is not a valid identifier: \"%s\"",
852 : text_to_cstring(qualname)),
853 : errdetail("No valid identifier after \".\".")));
854 : else
855 3 : ereport(ERROR,
856 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
857 : errmsg("string is not a valid identifier: \"%s\"",
858 : text_to_cstring(qualname))));
859 : }
860 :
861 61 : while (scanner_isspace(*nextp))
862 7 : nextp++;
863 :
864 27 : if (*nextp == '.')
865 : {
866 16 : after_dot = true;
867 16 : nextp++;
868 37 : while (scanner_isspace(*nextp))
869 5 : nextp++;
870 : }
871 11 : else if (*nextp == '\0')
872 : {
873 6 : break;
874 : }
875 : else
876 : {
877 5 : if (strict)
878 4 : ereport(ERROR,
879 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
880 : errmsg("string is not a valid identifier: \"%s\"",
881 : text_to_cstring(qualname))));
882 1 : break;
883 : }
884 16 : }
885 :
886 7 : PG_RETURN_DATUM(makeArrayResult(astate, CurrentMemoryContext));
887 : }
888 :
889 : /*
890 : * pg_current_logfile
891 : *
892 : * Report current log file used by log collector by scanning current_logfiles.
893 : */
894 : Datum
895 0 : pg_current_logfile(PG_FUNCTION_ARGS)
896 : {
897 : FILE *fd;
898 : char lbuffer[MAXPGPATH];
899 : char *logfmt;
900 : char *log_filepath;
901 0 : char *log_format = lbuffer;
902 : char *nlpos;
903 :
904 : /* The log format parameter is optional */
905 0 : if (PG_NARGS() == 0 || PG_ARGISNULL(0))
906 0 : logfmt = NULL;
907 : else
908 : {
909 0 : logfmt = text_to_cstring(PG_GETARG_TEXT_PP(0));
910 :
911 0 : if (strcmp(logfmt, "stderr") != 0 && strcmp(logfmt, "csvlog") != 0)
912 0 : ereport(ERROR,
913 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
914 : errmsg("log format \"%s\" is not supported", logfmt),
915 : errhint("The supported log formats are \"stderr\" and \"csvlog\".")));
916 : }
917 :
918 0 : fd = AllocateFile(LOG_METAINFO_DATAFILE, "r");
919 0 : if (fd == NULL)
920 : {
921 0 : if (errno != ENOENT)
922 0 : ereport(ERROR,
923 : (errcode_for_file_access(),
924 : errmsg("could not read file \"%s\": %m",
925 : LOG_METAINFO_DATAFILE)));
926 0 : PG_RETURN_NULL();
927 : }
928 :
929 : /*
930 : * Read the file to gather current log filename(s) registered by the
931 : * syslogger.
932 : */
933 0 : while (fgets(lbuffer, sizeof(lbuffer), fd) != NULL)
934 : {
935 : /*
936 : * Extract log format and log file path from the line; lbuffer ==
937 : * log_format, they share storage.
938 : */
939 0 : log_filepath = strchr(lbuffer, ' ');
940 0 : if (log_filepath == NULL)
941 : {
942 : /* Uh oh. No space found, so file content is corrupted. */
943 0 : elog(ERROR,
944 : "missing space character in \"%s\"", LOG_METAINFO_DATAFILE);
945 : break;
946 : }
947 :
948 0 : *log_filepath = '\0';
949 0 : log_filepath++;
950 0 : nlpos = strchr(log_filepath, '\n');
951 0 : if (nlpos == NULL)
952 : {
953 : /* Uh oh. No newline found, so file content is corrupted. */
954 0 : elog(ERROR,
955 : "missing newline character in \"%s\"", LOG_METAINFO_DATAFILE);
956 : break;
957 : }
958 0 : *nlpos = '\0';
959 :
960 0 : if (logfmt == NULL || strcmp(logfmt, log_format) == 0)
961 : {
962 0 : FreeFile(fd);
963 0 : PG_RETURN_TEXT_P(cstring_to_text(log_filepath));
964 : }
965 : }
966 :
967 : /* Close the current log filename file. */
968 0 : FreeFile(fd);
969 :
970 0 : PG_RETURN_NULL();
971 : }
972 :
973 : /*
974 : * Report current log file used by log collector (1 argument version)
975 : *
976 : * note: this wrapper is necessary to pass the sanity check in opr_sanity,
977 : * which checks that all built-in functions that share the implementing C
978 : * function take the same number of arguments
979 : */
980 : Datum
981 0 : pg_current_logfile_1arg(PG_FUNCTION_ARGS)
982 : {
983 0 : return pg_current_logfile(fcinfo);
984 : }
985 :
986 : /*
987 : * SQL wrapper around RelationGetReplicaIndex().
988 : */
989 : Datum
990 0 : pg_get_replica_identity_index(PG_FUNCTION_ARGS)
991 : {
992 0 : Oid reloid = PG_GETARG_OID(0);
993 : Oid idxoid;
994 : Relation rel;
995 :
996 0 : rel = heap_open(reloid, AccessShareLock);
997 0 : idxoid = RelationGetReplicaIndex(rel);
998 0 : heap_close(rel, AccessShareLock);
999 :
1000 0 : if (OidIsValid(idxoid))
1001 0 : PG_RETURN_OID(idxoid);
1002 : else
1003 0 : PG_RETURN_NULL();
1004 : }
|