Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * misc.c
4 : *
5 : *
6 : * Portions Copyright (c) 1996-2023, 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 <sys/stat.h>
19 : #include <dirent.h>
20 : #include <fcntl.h>
21 : #include <math.h>
22 : #include <unistd.h>
23 :
24 : #include "access/sysattr.h"
25 : #include "access/table.h"
26 : #include "catalog/catalog.h"
27 : #include "catalog/pg_tablespace.h"
28 : #include "catalog/pg_type.h"
29 : #include "catalog/system_fk_info.h"
30 : #include "commands/dbcommands.h"
31 : #include "commands/tablespace.h"
32 : #include "common/keywords.h"
33 : #include "funcapi.h"
34 : #include "miscadmin.h"
35 : #include "nodes/miscnodes.h"
36 : #include "parser/parse_type.h"
37 : #include "parser/scansup.h"
38 : #include "pgstat.h"
39 : #include "postmaster/syslogger.h"
40 : #include "rewrite/rewriteHandler.h"
41 : #include "storage/fd.h"
42 : #include "storage/latch.h"
43 : #include "tcop/tcopprot.h"
44 : #include "utils/builtins.h"
45 : #include "utils/fmgroids.h"
46 : #include "utils/lsyscache.h"
47 : #include "utils/ruleutils.h"
48 : #include "utils/timestamp.h"
49 :
50 :
51 : /*
52 : * structure to cache metadata needed in pg_input_is_valid_common
53 : */
54 : typedef struct ValidIOData
55 : {
56 : Oid typoid;
57 : int32 typmod;
58 : bool typname_constant;
59 : Oid typiofunc;
60 : Oid typioparam;
61 : FmgrInfo inputproc;
62 : } ValidIOData;
63 :
64 : static bool pg_input_is_valid_common(FunctionCallInfo fcinfo,
65 : text *txt, text *typname,
66 : ErrorSaveContext *escontext);
67 :
68 :
69 : /*
70 : * Common subroutine for num_nulls() and num_nonnulls().
71 : * Returns true if successful, false if function should return NULL.
72 : * If successful, total argument count and number of nulls are
73 : * returned into *nargs and *nulls.
74 : */
75 : static bool
2621 tgl 76 GIC 60 : count_nulls(FunctionCallInfo fcinfo,
77 : int32 *nargs, int32 *nulls)
78 : {
79 60 : int32 count = 0;
80 : int i;
81 :
82 : /* Did we get a VARIADIC array argument, or separate arguments? */
83 60 : if (get_fn_expr_variadic(fcinfo->flinfo))
84 : {
85 : ArrayType *arr;
86 : int ndims,
87 : nitems,
88 : *dims;
89 : bits8 *bitmap;
90 :
91 30 : Assert(PG_NARGS() == 1);
92 :
93 : /*
94 : * If we get a null as VARIADIC array argument, we can't say anything
95 : * useful about the number of elements, so return NULL. This behavior
96 : * is consistent with other variadic functions - see concat_internal.
2621 tgl 97 ECB : */
2621 tgl 98 GIC 30 : if (PG_ARGISNULL(0))
99 6 : return false;
2621 tgl 100 ECB :
101 : /*
102 : * Non-null argument had better be an array. We assume that any call
103 : * context that could let get_fn_expr_variadic return true will have
104 : * checked that a VARIADIC-labeled parameter actually is an array. So
105 : * it should be okay to just Assert that it's an array rather than
106 : * doing a full-fledged error check.
107 : */
2621 tgl 108 GIC 24 : Assert(OidIsValid(get_base_element_type(get_fn_expr_argtype(fcinfo->flinfo, 0))));
109 :
110 : /* OK, safe to fetch the array value */
111 24 : arr = PG_GETARG_ARRAYTYPE_P(0);
2621 tgl 112 ECB :
113 : /* Count the array elements */
2621 tgl 114 GIC 24 : ndims = ARR_NDIM(arr);
115 24 : dims = ARR_DIMS(arr);
116 24 : nitems = ArrayGetNItems(ndims, dims);
117 :
118 : /* Count those that are NULL */
2621 tgl 119 CBC 24 : bitmap = ARR_NULLBITMAP(arr);
120 24 : if (bitmap)
121 : {
2621 tgl 122 GIC 12 : int bitmask = 1;
123 :
124 636 : for (i = 0; i < nitems; i++)
125 : {
126 624 : if ((*bitmap & bitmask) == 0)
127 12 : count++;
128 :
2621 tgl 129 CBC 624 : bitmask <<= 1;
2621 tgl 130 GIC 624 : if (bitmask == 0x100)
131 : {
2621 tgl 132 CBC 72 : bitmap++;
2621 tgl 133 GIC 72 : bitmask = 1;
134 : }
2621 tgl 135 ECB : }
136 : }
137 :
2621 tgl 138 GIC 24 : *nargs = nitems;
139 24 : *nulls = count;
2621 tgl 140 ECB : }
141 : else
142 : {
143 : /* Separate arguments, so just count 'em */
2621 tgl 144 GIC 102 : for (i = 0; i < PG_NARGS(); i++)
2621 tgl 145 ECB : {
2621 tgl 146 GIC 72 : if (PG_ARGISNULL(i))
2621 tgl 147 CBC 42 : count++;
2621 tgl 148 ECB : }
149 :
2621 tgl 150 CBC 30 : *nargs = PG_NARGS();
151 30 : *nulls = count;
152 : }
2621 tgl 153 ECB :
2621 tgl 154 CBC 54 : return true;
155 : }
156 :
157 : /*
158 : * num_nulls()
2621 tgl 159 ECB : * Count the number of NULL arguments
160 : */
161 : Datum
2621 tgl 162 GIC 30 : pg_num_nulls(PG_FUNCTION_ARGS)
163 : {
164 : int32 nargs,
2621 tgl 165 ECB : nulls;
166 :
2621 tgl 167 CBC 30 : if (!count_nulls(fcinfo, &nargs, &nulls))
168 3 : PG_RETURN_NULL();
169 :
2621 tgl 170 GIC 27 : PG_RETURN_INT32(nulls);
2621 tgl 171 ECB : }
172 :
173 : /*
174 : * num_nonnulls()
175 : * Count the number of non-NULL arguments
176 : */
177 : Datum
2621 tgl 178 GIC 30 : pg_num_nonnulls(PG_FUNCTION_ARGS)
179 : {
180 : int32 nargs,
181 : nulls;
182 :
2621 tgl 183 CBC 30 : if (!count_nulls(fcinfo, &nargs, &nulls))
2621 tgl 184 GIC 3 : PG_RETURN_NULL();
185 :
186 27 : PG_RETURN_INT32(nargs - nulls);
187 : }
2621 tgl 188 ECB :
189 :
190 : /*
7537 bruce 191 : * current_database()
192 : * Expose the current database to the user
193 : */
194 : Datum
7537 bruce 195 GIC 2371 : current_database(PG_FUNCTION_ARGS)
196 : {
197 : Name db;
198 :
7537 bruce 199 CBC 2371 : db = (Name) palloc(NAMEDATALEN);
200 :
7226 peter_e 201 GIC 2371 : namestrcpy(db, get_database_name(MyDatabaseId));
7537 bruce 202 2371 : PG_RETURN_NAME(db);
203 : }
6885 bruce 204 ECB :
205 :
206 : /*
5483 207 : * current_query()
208 : * Expose the current query to the user (useful in stored procedures)
209 : * We might want to use ActivePortal->sourceText someday.
210 : */
211 : Datum
5483 bruce 212 UIC 0 : current_query(PG_FUNCTION_ARGS)
213 : {
214 : /* there is no easy way to access the more concise 'query_string' */
5204 215 0 : if (debug_query_string)
5204 bruce 216 LBC 0 : PG_RETURN_TEXT_P(cstring_to_text(debug_query_string));
217 : else
5204 bruce 218 UIC 0 : PG_RETURN_NULL();
219 : }
5483 bruce 220 ECB :
221 : /* Function to find out which databases make use of a tablespace */
6855 mail 222 :
6797 bruce 223 : Datum
6797 bruce 224 GIC 3 : pg_tablespace_databases(PG_FUNCTION_ARGS)
225 : {
1119 tgl 226 3 : Oid tablespaceOid = PG_GETARG_OID(0);
227 3 : ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
228 : char *location;
229 : DIR *dirdesc;
230 : struct dirent *de;
231 :
173 michael 232 3 : InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC);
1119 tgl 233 EUB :
1119 tgl 234 GIC 3 : if (tablespaceOid == GLOBALTABLESPACE_OID)
235 : {
1119 tgl 236 UBC 0 : ereport(WARNING,
1119 tgl 237 EUB : (errmsg("global tablespace never has databases")));
238 : /* return empty tuplestore */
1119 tgl 239 UBC 0 : return (Datum) 0;
240 : }
241 :
1119 tgl 242 GIC 3 : if (tablespaceOid == DEFAULTTABLESPACE_OID)
215 drowley 243 GNC 3 : location = "base";
244 : else
1119 tgl 245 LBC 0 : location = psprintf("pg_tblspc/%u/%s", tablespaceOid,
246 : TABLESPACE_VERSION_DIRECTORY);
6855 mail 247 ECB :
1119 tgl 248 CBC 3 : dirdesc = AllocateDir(location);
249 :
1119 tgl 250 GIC 3 : if (!dirdesc)
251 : {
252 : /* the only expected error is ENOENT */
1119 tgl 253 LBC 0 : if (errno != ENOENT)
1119 tgl 254 UIC 0 : ereport(ERROR,
1119 tgl 255 ECB : (errcode_for_file_access(),
256 : errmsg("could not open directory \"%s\": %m",
1119 tgl 257 EUB : location)));
1119 tgl 258 UIC 0 : ereport(WARNING,
259 : (errmsg("%u is not a tablespace OID", tablespaceOid)));
1119 tgl 260 EUB : /* return empty tuplestore */
1119 tgl 261 UIC 0 : return (Datum) 0;
262 : }
1119 tgl 263 ECB :
1119 tgl 264 CBC 27 : while ((de = ReadDir(dirdesc, location)) != NULL)
265 : {
6797 bruce 266 GBC 24 : Oid datOid = atooid(de->d_name);
267 : char *subdir;
268 : bool isempty;
1119 tgl 269 ECB : Datum values[1];
270 : bool nulls[1];
6855 mail 271 :
272 : /* this test skips . and .., but is awfully weak */
6855 mail 273 GIC 24 : if (!datOid)
6855 mail 274 GBC 9 : continue;
6855 mail 275 EUB :
276 : /* if database subdir is empty, don't report tablespace as used */
277 :
1119 tgl 278 GIC 15 : subdir = psprintf("%s/%s", location, de->d_name);
1952 tgl 279 GBC 15 : isempty = directory_is_empty(subdir);
6503 tgl 280 GIC 15 : pfree(subdir);
281 :
1952 tgl 282 GBC 15 : if (isempty)
6823 tgl 283 UIC 0 : continue; /* indeed, nothing in it */
284 :
1119 tgl 285 CBC 15 : values[0] = ObjectIdGetDatum(datOid);
1119 tgl 286 GIC 15 : nulls[0] = false;
1119 tgl 287 ECB :
398 michael 288 GIC 15 : tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
289 : values, nulls);
290 : }
291 :
1119 tgl 292 3 : FreeDir(dirdesc);
293 3 : return (Datum) 0;
6855 mail 294 ECB : }
6297 tgl 295 :
296 :
297 : /*
298 : * pg_tablespace_location - get location for a tablespace
4141 magnus 299 : */
300 : Datum
4141 magnus 301 CBC 25 : pg_tablespace_location(PG_FUNCTION_ARGS)
302 : {
3955 bruce 303 25 : Oid tablespaceOid = PG_GETARG_OID(0);
3955 bruce 304 EUB : char sourcepath[MAXPGPATH];
305 : char targetpath[MAXPGPATH];
3955 bruce 306 ECB : int rllen;
307 : struct stat st;
308 :
309 : /*
310 : * It's useful to apply this function to pg_class.reltablespace, wherein
3260 311 : * zero means "the database's default tablespace". So, rather than
4016 tgl 312 : * throwing an error for zero, we choose to assume that's what is meant.
313 : */
4016 tgl 314 GIC 25 : if (tablespaceOid == InvalidOid)
4016 tgl 315 UIC 0 : tablespaceOid = MyDatabaseTableSpace;
316 :
317 : /*
318 : * Return empty string for the cluster's default tablespaces
319 : */
4141 magnus 320 CBC 25 : if (tablespaceOid == DEFAULTTABLESPACE_OID ||
321 : tablespaceOid == GLOBALTABLESPACE_OID)
322 22 : PG_RETURN_TEXT_P(cstring_to_text(""));
323 :
324 : /*
325 : * Find the location of the tablespace by reading the symbolic link that
326 : * is in pg_tblspc/<oid>.
327 : */
4141 magnus 328 GIC 3 : snprintf(sourcepath, sizeof(sourcepath), "pg_tblspc/%u", tablespaceOid);
329 :
330 : /*
388 michael 331 ECB : * Before reading the link, check if the source path is a link or a
388 michael 332 EUB : * junction point. Note that a directory is possible for a tablespace
333 : * created with allow_in_place_tablespaces enabled. If a directory is
334 : * found, a relative path to the data directory is returned.
335 : */
388 michael 336 GIC 3 : if (lstat(sourcepath, &st) < 0)
337 : {
388 michael 338 UIC 0 : ereport(ERROR,
339 : (errcode_for_file_access(),
340 : errmsg("could not stat file \"%s\": %m",
388 michael 341 ECB : sourcepath)));
342 : }
343 :
388 michael 344 GIC 3 : if (!S_ISLNK(st.st_mode))
345 3 : PG_RETURN_TEXT_P(cstring_to_text(sourcepath));
346 :
347 : /*
388 michael 348 ECB : * In presence of a link or a junction point, return the path pointing to.
349 : */
4141 tgl 350 UBC 0 : rllen = readlink(sourcepath, targetpath, sizeof(targetpath));
4141 magnus 351 UIC 0 : if (rllen < 0)
352 0 : ereport(ERROR,
353 : (errcode_for_file_access(),
354 : errmsg("could not read symbolic link \"%s\": %m",
355 : sourcepath)));
2873 tgl 356 LBC 0 : if (rllen >= sizeof(targetpath))
4141 magnus 357 0 : ereport(ERROR,
358 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
359 : errmsg("symbolic link \"%s\" target is too long",
360 : sourcepath)));
4141 magnus 361 UIC 0 : targetpath[rllen] = '\0';
4141 magnus 362 EUB :
4141 magnus 363 UBC 0 : PG_RETURN_TEXT_P(cstring_to_text(targetpath));
364 : }
365 :
366 : /*
6297 tgl 367 EUB : * pg_sleep - delay for N seconds
368 : */
369 : Datum
6297 tgl 370 GIC 36 : pg_sleep(PG_FUNCTION_ARGS)
371 : {
372 36 : float8 secs = PG_GETARG_FLOAT8(0);
373 : float8 endtime;
374 :
375 : /*
3585 tgl 376 ECB : * We sleep using WaitLatch, to ensure that we'll wake up promptly if an
377 : * important signal (such as SIGALRM or SIGINT) arrives. Because
378 : * WaitLatch's upper limit of delay is INT_MAX milliseconds, and the user
379 : * might ask for more than that, we sleep for at most 10 minutes and then
380 : * loop.
381 : *
382 : * By computing the intended stop time initially, we avoid accumulation of
383 : * extra delay across multiple sleeps. This also ensures we won't delay
384 : * less than the specified time when WaitLatch is terminated early by a
385 : * non-query-canceling signal such as SIGHUP.
386 : */
387 : #define GetNowFloat() ((float8) GetCurrentTimestamp() / 1000000.0)
388 :
6297 tgl 389 GIC 36 : endtime = GetNowFloat() + secs;
390 :
391 : for (;;)
392 47 : {
393 : float8 delay;
394 : long delay_ms;
6297 tgl 395 ECB :
6297 tgl 396 GIC 83 : CHECK_FOR_INTERRUPTS();
397 :
6297 tgl 398 CBC 82 : delay = endtime - GetNowFloat();
3585 tgl 399 GIC 82 : if (delay >= 600.0)
3585 tgl 400 UIC 0 : delay_ms = 600000;
6297 tgl 401 GIC 82 : else if (delay > 0.0)
3585 tgl 402 CBC 47 : delay_ms = (long) ceil(delay * 1000.0);
403 : else
6297 404 35 : break;
3585 tgl 405 ECB :
3007 andres 406 GBC 47 : (void) WaitLatch(MyLatch,
1598 tmunro 407 ECB : WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
2378 rhaas 408 : delay_ms,
409 : WAIT_EVENT_PG_SLEEP);
3007 andres 410 CBC 47 : ResetLatch(MyLatch);
411 : }
6297 tgl 412 ECB :
6297 tgl 413 GIC 35 : PG_RETURN_VOID();
414 : }
415 :
5393 tgl 416 ECB : /* Function to return the list of grammar keywords */
417 : Datum
5393 tgl 418 UIC 0 : pg_get_keywords(PG_FUNCTION_ARGS)
5393 tgl 419 ECB : {
420 : FuncCallContext *funcctx;
421 :
5393 tgl 422 UIC 0 : if (SRF_IS_FIRSTCALL())
423 : {
5393 tgl 424 EUB : MemoryContext oldcontext;
425 : TupleDesc tupdesc;
426 :
5393 tgl 427 UIC 0 : funcctx = SRF_FIRSTCALL_INIT();
5393 tgl 428 UBC 0 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
429 :
109 michael 430 UNC 0 : if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
431 0 : elog(ERROR, "return type must be a row type");
432 0 : funcctx->tuple_desc = tupdesc;
5393 tgl 433 UIC 0 : funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
434 :
5393 tgl 435 UBC 0 : MemoryContextSwitchTo(oldcontext);
436 : }
5393 tgl 437 EUB :
5393 tgl 438 UIC 0 : funcctx = SRF_PERCALL_SETUP();
439 :
1554 440 0 : if (funcctx->call_cntr < ScanKeywords.num_keywords)
441 : {
442 : char *values[5];
5393 tgl 443 EUB : HeapTuple tuple;
444 :
445 : /* cast-away-const is ugly but alternatives aren't much better */
1554 tgl 446 UIC 0 : values[0] = unconstify(char *,
1554 tgl 447 EUB : GetScanKeyword(funcctx->call_cntr,
448 : &ScanKeywords));
5393 449 :
1554 tgl 450 UBC 0 : switch (ScanKeywordCategories[funcctx->call_cntr])
5393 tgl 451 EUB : {
5393 tgl 452 UBC 0 : case UNRESERVED_KEYWORD:
453 0 : values[1] = "U";
933 454 0 : values[3] = _("unreserved");
5393 455 0 : break;
456 0 : case COL_NAME_KEYWORD:
457 0 : values[1] = "C";
933 458 0 : values[3] = _("unreserved (cannot be function or type name)");
5393 459 0 : break;
460 0 : case TYPE_FUNC_NAME_KEYWORD:
461 0 : values[1] = "T";
933 462 0 : values[3] = _("reserved (can be function or type name)");
5393 463 0 : break;
464 0 : case RESERVED_KEYWORD:
465 0 : values[1] = "R";
933 466 0 : values[3] = _("reserved");
5393 467 0 : break;
468 0 : default: /* shouldn't be possible */
5393 tgl 469 UIC 0 : values[1] = NULL;
933 470 0 : values[3] = NULL;
5393 tgl 471 UBC 0 : break;
472 : }
5393 tgl 473 EUB :
933 tgl 474 UBC 0 : if (ScanKeywordBareLabel[funcctx->call_cntr])
475 : {
933 tgl 476 UIC 0 : values[2] = "true";
477 0 : values[4] = _("can be bare label");
933 tgl 478 EUB : }
479 : else
480 : {
933 tgl 481 UIC 0 : values[2] = "false";
933 tgl 482 UBC 0 : values[4] = _("requires AS");
483 : }
933 tgl 484 EUB :
5393 tgl 485 UIC 0 : tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
486 :
5393 tgl 487 UBC 0 : SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
488 : }
489 :
5393 tgl 490 UIC 0 : SRF_RETURN_DONE(funcctx);
491 : }
492 :
5270 tgl 493 ECB :
494 : /* Function to return the list of catalog foreign key relationships */
495 : Datum
796 tgl 496 GIC 660 : pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
497 : {
796 tgl 498 ECB : FuncCallContext *funcctx;
499 : FmgrInfo *arrayinp;
500 :
796 tgl 501 GIC 660 : if (SRF_IS_FIRSTCALL())
502 : {
796 tgl 503 ECB : MemoryContext oldcontext;
504 : TupleDesc tupdesc;
505 :
796 tgl 506 CBC 3 : funcctx = SRF_FIRSTCALL_INIT();
796 tgl 507 GBC 3 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
796 tgl 508 ECB :
109 michael 509 GNC 3 : if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
109 michael 510 UNC 0 : elog(ERROR, "return type must be a row type");
796 tgl 511 CBC 3 : funcctx->tuple_desc = BlessTupleDesc(tupdesc);
796 tgl 512 ECB :
513 : /*
514 : * We use array_in to convert the C strings in sys_fk_relationships[]
515 : * to text arrays. But we cannot use DirectFunctionCallN to call
516 : * array_in, and it wouldn't be very efficient if we could. Fill an
517 : * FmgrInfo to use for the call.
518 : */
796 tgl 519 GIC 3 : arrayinp = (FmgrInfo *) palloc(sizeof(FmgrInfo));
520 3 : fmgr_info(F_ARRAY_IN, arrayinp);
796 tgl 521 CBC 3 : funcctx->user_fctx = arrayinp;
522 :
523 3 : MemoryContextSwitchTo(oldcontext);
796 tgl 524 ECB : }
525 :
796 tgl 526 GIC 660 : funcctx = SRF_PERCALL_SETUP();
527 660 : arrayinp = (FmgrInfo *) funcctx->user_fctx;
796 tgl 528 ECB :
796 tgl 529 CBC 660 : if (funcctx->call_cntr < lengthof(sys_fk_relationships))
530 : {
796 tgl 531 GIC 657 : const SysFKRelationship *fkrel = &sys_fk_relationships[funcctx->call_cntr];
532 : Datum values[6];
796 tgl 533 ECB : bool nulls[6];
534 : HeapTuple tuple;
535 :
796 tgl 536 CBC 657 : memset(nulls, false, sizeof(nulls));
537 :
538 657 : values[0] = ObjectIdGetDatum(fkrel->fk_table);
796 tgl 539 GIC 657 : values[1] = FunctionCall3(arrayinp,
540 : CStringGetDatum(fkrel->fk_columns),
796 tgl 541 ECB : ObjectIdGetDatum(TEXTOID),
542 : Int32GetDatum(-1));
796 tgl 543 GIC 657 : values[2] = ObjectIdGetDatum(fkrel->pk_table);
544 657 : values[3] = FunctionCall3(arrayinp,
545 : CStringGetDatum(fkrel->pk_columns),
546 : ObjectIdGetDatum(TEXTOID),
547 : Int32GetDatum(-1));
548 657 : values[4] = BoolGetDatum(fkrel->is_array);
796 tgl 549 CBC 657 : values[5] = BoolGetDatum(fkrel->is_opt);
550 :
551 657 : tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
552 :
796 tgl 553 GIC 657 : SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
554 : }
555 :
556 3 : SRF_RETURN_DONE(funcctx);
557 : }
558 :
559 :
5270 tgl 560 ECB : /*
561 : * Return the type of the argument.
562 : */
563 : Datum
5270 tgl 564 GIC 758 : pg_typeof(PG_FUNCTION_ARGS)
5270 tgl 565 ECB : {
5270 tgl 566 CBC 758 : PG_RETURN_OID(get_fn_expr_argtype(fcinfo->flinfo, 0));
5270 tgl 567 EUB : }
4055 peter_e 568 ECB :
569 :
570 : /*
571 : * Implementation of the COLLATE FOR expression; returns the collation
572 : * of the argument.
573 : */
574 : Datum
4055 peter_e 575 CBC 15 : pg_collation_for(PG_FUNCTION_ARGS)
4055 peter_e 576 ECB : {
3955 bruce 577 : Oid typeid;
578 : Oid collid;
579 :
4055 peter_e 580 GIC 15 : typeid = get_fn_expr_argtype(fcinfo->flinfo, 0);
581 15 : if (!typeid)
4055 peter_e 582 UIC 0 : PG_RETURN_NULL();
4055 peter_e 583 GIC 15 : if (!type_is_collatable(typeid) && typeid != UNKNOWNOID)
584 3 : ereport(ERROR,
585 : (errcode(ERRCODE_DATATYPE_MISMATCH),
586 : errmsg("collations are not supported by type %s",
587 : format_type_be(typeid))));
588 :
4055 peter_e 589 CBC 12 : collid = PG_GET_COLLATION();
4055 peter_e 590 GIC 12 : if (!collid)
4055 peter_e 591 CBC 3 : PG_RETURN_NULL();
592 9 : PG_RETURN_TEXT_P(cstring_to_text(generate_collation_name(collid)));
593 : }
3774 tgl 594 ECB :
595 :
596 : /*
597 : * pg_relation_is_updatable - determine which update events the specified
598 : * relation supports.
599 : *
600 : * This relies on relation_is_updatable() in rewriteHandler.c, which see
601 : * for additional information.
602 : */
603 : Datum
3588 tgl 604 GIC 447 : pg_relation_is_updatable(PG_FUNCTION_ARGS)
605 : {
3588 tgl 606 CBC 447 : Oid reloid = PG_GETARG_OID(0);
3588 tgl 607 GIC 447 : bool include_triggers = PG_GETARG_BOOL(1);
3774 tgl 608 ECB :
1235 tgl 609 CBC 447 : PG_RETURN_INT32(relation_is_updatable(reloid, NIL, include_triggers, NULL));
3774 tgl 610 ECB : }
611 :
612 : /*
613 : * pg_column_is_updatable - determine whether a column is updatable
614 : *
3460 rhaas 615 : * This function encapsulates the decision about just what
3260 bruce 616 EUB : * information_schema.columns.is_updatable actually means. It's not clear
617 : * whether deletability of the column's relation should be required, so
3588 tgl 618 ECB : * we want that decision in C code where we could change it without initdb.
619 : */
620 : Datum
3588 tgl 621 GIC 285 : pg_column_is_updatable(PG_FUNCTION_ARGS)
622 : {
623 285 : Oid reloid = PG_GETARG_OID(0);
3588 tgl 624 CBC 285 : AttrNumber attnum = PG_GETARG_INT16(1);
3460 rhaas 625 GIC 285 : AttrNumber col = attnum - FirstLowInvalidHeapAttributeNumber;
3588 tgl 626 285 : bool include_triggers = PG_GETARG_BOOL(2);
627 : int events;
628 :
629 : /* System columns are never updatable */
630 285 : if (attnum <= 0)
3588 tgl 631 UIC 0 : PG_RETURN_BOOL(false);
632 :
1235 tgl 633 GIC 285 : events = relation_is_updatable(reloid, NIL, include_triggers,
634 : bms_make_singleton(col));
635 :
636 : /* We require both updatability and deletability of the relation */
3588 tgl 637 ECB : #define REQ_EVENTS ((1 << CMD_UPDATE) | (1 << CMD_DELETE))
638 :
3588 tgl 639 CBC 285 : PG_RETURN_BOOL((events & REQ_EVENTS) == REQ_EVENTS);
3774 tgl 640 ECB : }
2578 teodor 641 :
642 :
643 : /*
644 : * pg_input_is_valid - test whether string is valid input for datatype.
645 : *
646 : * Returns true if OK, false if not.
647 : *
648 : * This will only work usefully if the datatype's input function has been
649 : * updated to return "soft" errors via errsave/ereturn.
650 : */
651 : Datum
121 tgl 652 GNC 442 : pg_input_is_valid(PG_FUNCTION_ARGS)
653 : {
654 442 : text *txt = PG_GETARG_TEXT_PP(0);
655 442 : text *typname = PG_GETARG_TEXT_PP(1);
656 442 : ErrorSaveContext escontext = {T_ErrorSaveContext};
657 :
658 442 : PG_RETURN_BOOL(pg_input_is_valid_common(fcinfo, txt, typname,
659 : &escontext));
660 : }
661 :
662 : /*
663 : * pg_input_error_info - test whether string is valid input for datatype.
664 : *
665 : * Returns NULL if OK, else the primary message, detail message, hint message
666 : * and sql error code from the error.
667 : *
668 : * This will only work usefully if the datatype's input function has been
669 : * updated to return "soft" errors via errsave/ereturn.
670 : */
671 : Datum
40 michael 672 383 : pg_input_error_info(PG_FUNCTION_ARGS)
673 : {
121 tgl 674 383 : text *txt = PG_GETARG_TEXT_PP(0);
675 383 : text *typname = PG_GETARG_TEXT_PP(1);
676 383 : ErrorSaveContext escontext = {T_ErrorSaveContext};
677 : TupleDesc tupdesc;
678 : Datum values[4];
679 : bool isnull[4];
680 :
40 michael 681 383 : if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
40 michael 682 UNC 0 : elog(ERROR, "return type must be a row type");
683 :
684 : /* Enable details_wanted */
121 tgl 685 GNC 383 : escontext.details_wanted = true;
686 :
687 383 : if (pg_input_is_valid_common(fcinfo, txt, typname,
688 : &escontext))
40 michael 689 13 : memset(isnull, true, sizeof(isnull));
690 : else
691 : {
692 : char *sqlstate;
693 :
694 355 : Assert(escontext.error_occurred);
695 355 : Assert(escontext.error_data != NULL);
696 355 : Assert(escontext.error_data->message != NULL);
697 :
698 355 : memset(isnull, false, sizeof(isnull));
699 :
700 355 : values[0] = CStringGetTextDatum(escontext.error_data->message);
701 :
702 355 : if (escontext.error_data->detail != NULL)
703 31 : values[1] = CStringGetTextDatum(escontext.error_data->detail);
704 : else
705 324 : isnull[1] = true;
706 :
707 355 : if (escontext.error_data->hint != NULL)
40 michael 708 UNC 0 : values[2] = CStringGetTextDatum(escontext.error_data->hint);
709 : else
40 michael 710 GNC 355 : isnull[2] = true;
711 :
712 355 : sqlstate = unpack_sql_state(escontext.error_data->sqlerrcode);
713 355 : values[3] = CStringGetTextDatum(sqlstate);
714 : }
715 :
716 368 : return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
717 : }
718 :
719 : /* Common subroutine for the above */
720 : static bool
121 tgl 721 825 : pg_input_is_valid_common(FunctionCallInfo fcinfo,
722 : text *txt, text *typname,
723 : ErrorSaveContext *escontext)
724 : {
725 825 : char *str = text_to_cstring(txt);
726 : ValidIOData *my_extra;
727 : Datum converted;
728 :
729 : /*
730 : * We arrange to look up the needed I/O info just once per series of
731 : * calls, assuming the data type doesn't change underneath us.
732 : */
733 825 : my_extra = (ValidIOData *) fcinfo->flinfo->fn_extra;
734 825 : if (my_extra == NULL)
735 : {
736 1538 : fcinfo->flinfo->fn_extra =
737 769 : MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
738 : sizeof(ValidIOData));
739 769 : my_extra = (ValidIOData *) fcinfo->flinfo->fn_extra;
740 769 : my_extra->typoid = InvalidOid;
741 : /* Detect whether typname argument is constant. */
742 769 : my_extra->typname_constant = get_fn_expr_arg_stable(fcinfo->flinfo, 1);
743 : }
744 :
745 : /*
746 : * If the typname argument is constant, we only need to parse it the first
747 : * time through.
748 : */
749 825 : if (my_extra->typoid == InvalidOid || !my_extra->typname_constant)
750 : {
751 787 : char *typnamestr = text_to_cstring(typname);
752 : Oid typoid;
753 :
754 : /* Parse type-name argument to obtain type OID and encoded typmod. */
103 755 787 : (void) parseTypeString(typnamestr, &typoid, &my_extra->typmod, NULL);
756 :
757 : /* Update type-specific info if typoid changed. */
121 758 787 : if (my_extra->typoid != typoid)
759 : {
760 777 : getTypeInputInfo(typoid,
761 : &my_extra->typiofunc,
762 : &my_extra->typioparam);
763 777 : fmgr_info_cxt(my_extra->typiofunc, &my_extra->inputproc,
764 777 : fcinfo->flinfo->fn_mcxt);
765 777 : my_extra->typoid = typoid;
766 : }
767 : }
768 :
769 : /* Now we can try to perform the conversion. */
770 825 : return InputFunctionCallSafe(&my_extra->inputproc,
771 : str,
772 : my_extra->typioparam,
773 : my_extra->typmod,
774 : (Node *) escontext,
775 : &converted);
776 : }
777 :
778 :
2578 teodor 779 ECB : /*
780 : * Is character a valid identifier start?
781 : * Must match scan.l's {ident_start} character class.
782 : */
783 : static bool
2578 teodor 784 GIC 1101 : is_ident_start(unsigned char c)
785 : {
786 : /* Underscores and ASCII letters are OK */
787 1101 : if (c == '_')
2578 teodor 788 UIC 0 : return true;
2578 teodor 789 GIC 1101 : if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
790 1026 : return true;
791 : /* Any high-bit-set character is OK (might be part of a multibyte char) */
2568 tgl 792 75 : if (IS_HIGHBIT_SET(c))
2578 teodor 793 LBC 0 : return true;
2578 teodor 794 GIC 75 : return false;
2578 teodor 795 ECB : }
796 :
2568 tgl 797 : /*
798 : * Is character a valid identifier continuation?
799 : * Must match scan.l's {ident_cont} character class.
800 : */
801 : static bool
2578 teodor 802 CBC 1026 : is_ident_cont(unsigned char c)
2578 teodor 803 EUB : {
804 : /* Can be digit or dollar sign ... */
2568 tgl 805 GIC 1026 : if ((c >= '0' && c <= '9') || c == '$')
2578 teodor 806 LBC 0 : return true;
807 : /* ... or an identifier start character */
2578 teodor 808 CBC 1026 : return is_ident_start(c);
809 : }
2578 teodor 810 ECB :
811 : /*
812 : * parse_ident - parse a SQL qualified identifier into separate identifiers.
813 : * When strict mode is active (second parameter), then any chars after
814 : * the last identifier are disallowed.
815 : */
816 : Datum
2578 teodor 817 CBC 57 : parse_ident(PG_FUNCTION_ARGS)
818 : {
2568 tgl 819 57 : text *qualname = PG_GETARG_TEXT_PP(0);
2568 tgl 820 GIC 57 : bool strict = PG_GETARG_BOOL(1);
2568 tgl 821 CBC 57 : char *qualname_str = text_to_cstring(qualname);
2568 tgl 822 GIC 57 : ArrayBuildState *astate = NULL;
2578 teodor 823 ECB : char *nextp;
2578 teodor 824 CBC 57 : bool after_dot = false;
825 :
2568 tgl 826 ECB : /*
827 : * The code below scribbles on qualname_str in some cases, so we should
828 : * reconvert qualname if we need to show the original string in error
2568 tgl 829 EUB : * messages.
830 : */
2578 teodor 831 CBC 57 : nextp = qualname_str;
832 :
2578 teodor 833 ECB : /* skip leading whitespace */
2146 tgl 834 CBC 72 : while (scanner_isspace(*nextp))
2578 teodor 835 GIC 15 : nextp++;
836 :
2578 teodor 837 ECB : for (;;)
2578 teodor 838 GIC 48 : {
839 : char *curname;
2568 tgl 840 105 : bool missing_ident = true;
841 :
2568 tgl 842 CBC 105 : if (*nextp == '"')
843 : {
844 : char *endp;
845 :
2578 teodor 846 30 : curname = nextp + 1;
847 : for (;;)
848 : {
2568 tgl 849 GIC 30 : endp = strchr(nextp + 1, '"');
2578 teodor 850 30 : if (endp == NULL)
2578 teodor 851 UIC 0 : ereport(ERROR,
852 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
853 : errmsg("string is not a valid identifier: \"%s\"",
2118 tgl 854 ECB : text_to_cstring(qualname)),
855 : errdetail("String has unclosed double quotes.")));
2568 tgl 856 GIC 30 : if (endp[1] != '"')
2578 teodor 857 CBC 30 : break;
2578 teodor 858 LBC 0 : memmove(endp, endp + 1, strlen(endp));
2578 teodor 859 UIC 0 : nextp = endp;
2578 teodor 860 ECB : }
2578 teodor 861 CBC 30 : nextp = endp + 1;
2578 teodor 862 GIC 30 : *endp = '\0';
2578 teodor 863 ECB :
2578 teodor 864 GIC 30 : if (endp - curname == 0)
2578 teodor 865 UIC 0 : ereport(ERROR,
866 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
867 : errmsg("string is not a valid identifier: \"%s\"",
868 : text_to_cstring(qualname)),
869 : errdetail("Quoted identifier must not be empty.")));
2578 teodor 870 ECB :
2578 teodor 871 GIC 30 : astate = accumArrayResult(astate, CStringGetTextDatum(curname),
2578 teodor 872 ECB : false, TEXTOID, CurrentMemoryContext);
2578 teodor 873 GIC 30 : missing_ident = false;
874 : }
2568 tgl 875 75 : else if (is_ident_start((unsigned char) *nextp))
2578 teodor 876 ECB : {
877 : char *downname;
878 : int len;
2568 tgl 879 : text *part;
880 :
2568 tgl 881 CBC 51 : curname = nextp++;
2568 tgl 882 GIC 1026 : while (is_ident_cont((unsigned char) *nextp))
883 975 : nextp++;
2568 tgl 884 ECB :
2568 tgl 885 CBC 51 : len = nextp - curname;
2568 tgl 886 ECB :
887 : /*
888 : * We don't implicitly truncate identifiers. This is useful for
889 : * allowing the user to check for specific parts of the identifier
890 : * being too long. It's easy enough for the user to get the
891 : * truncated names by casting our output to name[].
892 : */
2568 tgl 893 GIC 51 : downname = downcase_identifier(curname, len, false, false);
894 51 : part = cstring_to_text_with_len(downname, len);
895 51 : astate = accumArrayResult(astate, PointerGetDatum(part), false,
896 : TEXTOID, CurrentMemoryContext);
897 51 : missing_ident = false;
898 : }
899 :
2578 teodor 900 105 : if (missing_ident)
901 : {
902 : /* Different error messages based on where we failed. */
903 24 : if (*nextp == '.')
904 9 : ereport(ERROR,
2568 tgl 905 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
906 : errmsg("string is not a valid identifier: \"%s\"",
907 : text_to_cstring(qualname)),
2495 rhaas 908 : errdetail("No valid identifier before \".\".")));
2578 teodor 909 GBC 15 : else if (after_dot)
2578 teodor 910 CBC 6 : ereport(ERROR,
2568 tgl 911 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
912 : errmsg("string is not a valid identifier: \"%s\"",
913 : text_to_cstring(qualname)),
2495 rhaas 914 EUB : errdetail("No valid identifier after \".\".")));
2578 teodor 915 ECB : else
2578 teodor 916 GIC 9 : ereport(ERROR,
917 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
918 : errmsg("string is not a valid identifier: \"%s\"",
919 : text_to_cstring(qualname))));
920 : }
921 :
2146 tgl 922 102 : while (scanner_isspace(*nextp))
2578 teodor 923 CBC 21 : nextp++;
924 :
2578 teodor 925 GIC 81 : if (*nextp == '.')
2578 teodor 926 ECB : {
2578 teodor 927 GBC 48 : after_dot = true;
2578 teodor 928 GIC 48 : nextp++;
2146 tgl 929 CBC 63 : while (scanner_isspace(*nextp))
2578 teodor 930 GIC 15 : nextp++;
931 : }
932 33 : else if (*nextp == '\0')
933 : {
934 18 : break;
935 : }
936 : else
937 : {
2578 teodor 938 CBC 15 : if (strict)
2578 teodor 939 GIC 12 : ereport(ERROR,
2568 tgl 940 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
941 : errmsg("string is not a valid identifier: \"%s\"",
942 : text_to_cstring(qualname))));
2578 teodor 943 CBC 3 : break;
944 : }
2578 teodor 945 ECB : }
946 :
2578 teodor 947 GIC 21 : PG_RETURN_DATUM(makeArrayResult(astate, CurrentMemoryContext));
948 : }
949 :
950 : /*
951 : * pg_current_logfile
2228 rhaas 952 ECB : *
953 : * Report current log file used by log collector by scanning current_logfiles.
954 : */
955 : Datum
2228 rhaas 956 CBC 6 : pg_current_logfile(PG_FUNCTION_ARGS)
957 : {
958 : FILE *fd;
2228 rhaas 959 ECB : char lbuffer[MAXPGPATH];
960 : char *logfmt;
961 :
962 : /* The log format parameter is optional */
2228 rhaas 963 CBC 6 : if (PG_NARGS() == 0 || PG_ARGISNULL(0))
2228 rhaas 964 UIC 0 : logfmt = NULL;
965 : else
966 : {
2228 rhaas 967 CBC 6 : logfmt = text_to_cstring(PG_GETARG_TEXT_PP(0));
968 :
447 michael 969 GIC 6 : if (strcmp(logfmt, "stderr") != 0 &&
447 michael 970 CBC 4 : strcmp(logfmt, "csvlog") != 0 &&
971 2 : strcmp(logfmt, "jsonlog") != 0)
2228 rhaas 972 UBC 0 : ereport(ERROR,
973 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
974 : errmsg("log format \"%s\" is not supported", logfmt),
975 : errhint("The supported log formats are \"stderr\", \"csvlog\", and \"jsonlog\".")));
976 : }
2228 rhaas 977 ECB :
2228 rhaas 978 CBC 6 : fd = AllocateFile(LOG_METAINFO_DATAFILE, "r");
2228 rhaas 979 GBC 6 : if (fd == NULL)
2228 rhaas 980 EUB : {
2228 rhaas 981 UIC 0 : if (errno != ENOENT)
2228 rhaas 982 LBC 0 : ereport(ERROR,
2228 rhaas 983 ECB : (errcode_for_file_access(),
984 : errmsg("could not read file \"%s\": %m",
985 : LOG_METAINFO_DATAFILE)));
2228 rhaas 986 UBC 0 : PG_RETURN_NULL();
987 : }
988 :
989 : #ifdef WIN32
990 : /* syslogger.c writes CRLF line endings on Windows */
991 : _setmode(_fileno(fd), _O_TEXT);
1004 tgl 992 ECB : #endif
993 :
2228 rhaas 994 : /*
995 : * Read the file to gather current log filename(s) registered by the
996 : * syslogger.
997 : */
2228 rhaas 998 GIC 12 : while (fgets(lbuffer, sizeof(lbuffer), fd) != NULL)
999 : {
1000 : char *log_format;
1001 : char *log_filepath;
1004 tgl 1002 ECB : char *nlpos;
1003 :
1004 : /* Extract log format and log file path from the line. */
1004 tgl 1005 GIC 12 : log_format = lbuffer;
2228 rhaas 1006 CBC 12 : log_filepath = strchr(lbuffer, ' ');
2228 rhaas 1007 GIC 12 : if (log_filepath == NULL)
1008 : {
1009 : /* Uh oh. No space found, so file content is corrupted. */
2228 rhaas 1010 UIC 0 : elog(ERROR,
1011 : "missing space character in \"%s\"", LOG_METAINFO_DATAFILE);
1012 : break;
1013 : }
2228 rhaas 1014 ECB :
2228 rhaas 1015 CBC 12 : *log_filepath = '\0';
1016 12 : log_filepath++;
2228 rhaas 1017 GIC 12 : nlpos = strchr(log_filepath, '\n');
2228 rhaas 1018 CBC 12 : if (nlpos == NULL)
1019 : {
1020 : /* Uh oh. No newline found, so file content is corrupted. */
2228 rhaas 1021 LBC 0 : elog(ERROR,
1022 : "missing newline character in \"%s\"", LOG_METAINFO_DATAFILE);
1023 : break;
2228 rhaas 1024 ECB : }
2228 rhaas 1025 CBC 12 : *nlpos = '\0';
1026 :
2228 rhaas 1027 GIC 12 : if (logfmt == NULL || strcmp(logfmt, log_format) == 0)
1028 : {
1029 6 : FreeFile(fd);
2228 rhaas 1030 CBC 6 : PG_RETURN_TEXT_P(cstring_to_text(log_filepath));
2228 rhaas 1031 ECB : }
1032 : }
1033 :
1034 : /* Close the current log filename file. */
2228 rhaas 1035 UIC 0 : FreeFile(fd);
1036 :
2228 rhaas 1037 LBC 0 : PG_RETURN_NULL();
1038 : }
1039 :
1040 : /*
1041 : * Report current log file used by log collector (1 argument version)
1042 : *
2228 rhaas 1043 ECB : * note: this wrapper is necessary to pass the sanity check in opr_sanity,
1044 : * which checks that all built-in functions that share the implementing C
1045 : * function take the same number of arguments
1046 : */
1047 : Datum
2228 rhaas 1048 CBC 6 : pg_current_logfile_1arg(PG_FUNCTION_ARGS)
2228 rhaas 1049 ECB : {
2228 rhaas 1050 CBC 6 : return pg_current_logfile(fcinfo);
2228 rhaas 1051 ECB : }
1052 :
2208 peter_e 1053 : /*
1054 : * SQL wrapper around RelationGetReplicaIndex().
1055 : */
1056 : Datum
2208 peter_e 1057 GIC 310 : pg_get_replica_identity_index(PG_FUNCTION_ARGS)
1058 : {
2208 peter_e 1059 CBC 310 : Oid reloid = PG_GETARG_OID(0);
2208 peter_e 1060 ECB : Oid idxoid;
1061 : Relation rel;
1062 :
1539 andres 1063 GIC 310 : rel = table_open(reloid, AccessShareLock);
2208 peter_e 1064 CBC 310 : idxoid = RelationGetReplicaIndex(rel);
1539 andres 1065 GIC 310 : table_close(rel, AccessShareLock);
1066 :
2208 peter_e 1067 310 : if (OidIsValid(idxoid))
2208 peter_e 1068 CBC 184 : PG_RETURN_OID(idxoid);
1069 : else
2208 peter_e 1070 GIC 126 : PG_RETURN_NULL();
1071 : }
1072 :
1073 : /*
1074 : * Transition function for the ANY_VALUE aggregate
1075 : */
1076 : Datum
46 peter 1077 GNC 9 : any_value_transfn(PG_FUNCTION_ARGS)
1078 : {
1079 9 : PG_RETURN_DATUM(PG_GETARG_DATUM(0));
1080 : }
|