sepgsql: update TAP test to use fat comma style
[pgsql.git] / src / backend / utils / adt / misc.c
blob6fcfd031428ed46ae563e88cb2c9bb390c0d4b8e
1 /*-------------------------------------------------------------------------
3 * misc.c
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * IDENTIFICATION
11 * src/backend/utils/adt/misc.c
13 *-------------------------------------------------------------------------
15 #include "postgres.h"
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>
24 #include "access/sysattr.h"
25 #include "access/table.h"
26 #include "catalog/pg_tablespace.h"
27 #include "catalog/pg_type.h"
28 #include "catalog/system_fk_info.h"
29 #include "commands/dbcommands.h"
30 #include "commands/tablespace.h"
31 #include "common/keywords.h"
32 #include "funcapi.h"
33 #include "miscadmin.h"
34 #include "nodes/miscnodes.h"
35 #include "parser/parse_type.h"
36 #include "parser/scansup.h"
37 #include "pgstat.h"
38 #include "postmaster/syslogger.h"
39 #include "rewrite/rewriteHandler.h"
40 #include "storage/fd.h"
41 #include "storage/latch.h"
42 #include "tcop/tcopprot.h"
43 #include "utils/builtins.h"
44 #include "utils/fmgroids.h"
45 #include "utils/lsyscache.h"
46 #include "utils/ruleutils.h"
47 #include "utils/syscache.h"
48 #include "utils/timestamp.h"
52 * structure to cache metadata needed in pg_input_is_valid_common
54 typedef struct ValidIOData
56 Oid typoid;
57 int32 typmod;
58 bool typname_constant;
59 Oid typiofunc;
60 Oid typioparam;
61 FmgrInfo inputproc;
62 } ValidIOData;
64 static bool pg_input_is_valid_common(FunctionCallInfo fcinfo,
65 text *txt, text *typname,
66 ErrorSaveContext *escontext);
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.
75 static bool
76 count_nulls(FunctionCallInfo fcinfo,
77 int32 *nargs, int32 *nulls)
79 int32 count = 0;
80 int i;
82 /* Did we get a VARIADIC array argument, or separate arguments? */
83 if (get_fn_expr_variadic(fcinfo->flinfo))
85 ArrayType *arr;
86 int ndims,
87 nitems,
88 *dims;
89 bits8 *bitmap;
91 Assert(PG_NARGS() == 1);
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.
98 if (PG_ARGISNULL(0))
99 return false;
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.
108 Assert(OidIsValid(get_base_element_type(get_fn_expr_argtype(fcinfo->flinfo, 0))));
110 /* OK, safe to fetch the array value */
111 arr = PG_GETARG_ARRAYTYPE_P(0);
113 /* Count the array elements */
114 ndims = ARR_NDIM(arr);
115 dims = ARR_DIMS(arr);
116 nitems = ArrayGetNItems(ndims, dims);
118 /* Count those that are NULL */
119 bitmap = ARR_NULLBITMAP(arr);
120 if (bitmap)
122 int bitmask = 1;
124 for (i = 0; i < nitems; i++)
126 if ((*bitmap & bitmask) == 0)
127 count++;
129 bitmask <<= 1;
130 if (bitmask == 0x100)
132 bitmap++;
133 bitmask = 1;
138 *nargs = nitems;
139 *nulls = count;
141 else
143 /* Separate arguments, so just count 'em */
144 for (i = 0; i < PG_NARGS(); i++)
146 if (PG_ARGISNULL(i))
147 count++;
150 *nargs = PG_NARGS();
151 *nulls = count;
154 return true;
158 * num_nulls()
159 * Count the number of NULL arguments
161 Datum
162 pg_num_nulls(PG_FUNCTION_ARGS)
164 int32 nargs,
165 nulls;
167 if (!count_nulls(fcinfo, &nargs, &nulls))
168 PG_RETURN_NULL();
170 PG_RETURN_INT32(nulls);
174 * num_nonnulls()
175 * Count the number of non-NULL arguments
177 Datum
178 pg_num_nonnulls(PG_FUNCTION_ARGS)
180 int32 nargs,
181 nulls;
183 if (!count_nulls(fcinfo, &nargs, &nulls))
184 PG_RETURN_NULL();
186 PG_RETURN_INT32(nargs - nulls);
191 * current_database()
192 * Expose the current database to the user
194 Datum
195 current_database(PG_FUNCTION_ARGS)
197 Name db;
199 db = (Name) palloc(NAMEDATALEN);
201 namestrcpy(db, get_database_name(MyDatabaseId));
202 PG_RETURN_NAME(db);
207 * current_query()
208 * Expose the current query to the user (useful in stored procedures)
209 * We might want to use ActivePortal->sourceText someday.
211 Datum
212 current_query(PG_FUNCTION_ARGS)
214 /* there is no easy way to access the more concise 'query_string' */
215 if (debug_query_string)
216 PG_RETURN_TEXT_P(cstring_to_text(debug_query_string));
217 else
218 PG_RETURN_NULL();
221 /* Function to find out which databases make use of a tablespace */
223 Datum
224 pg_tablespace_databases(PG_FUNCTION_ARGS)
226 Oid tablespaceOid = PG_GETARG_OID(0);
227 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
228 char *location;
229 DIR *dirdesc;
230 struct dirent *de;
232 InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC);
234 if (tablespaceOid == GLOBALTABLESPACE_OID)
236 ereport(WARNING,
237 (errmsg("global tablespace never has databases")));
238 /* return empty tuplestore */
239 return (Datum) 0;
242 if (tablespaceOid == DEFAULTTABLESPACE_OID)
243 location = "base";
244 else
245 location = psprintf("%s/%u/%s", PG_TBLSPC_DIR, tablespaceOid,
246 TABLESPACE_VERSION_DIRECTORY);
248 dirdesc = AllocateDir(location);
250 if (!dirdesc)
252 /* the only expected error is ENOENT */
253 if (errno != ENOENT)
254 ereport(ERROR,
255 (errcode_for_file_access(),
256 errmsg("could not open directory \"%s\": %m",
257 location)));
258 ereport(WARNING,
259 (errmsg("%u is not a tablespace OID", tablespaceOid)));
260 /* return empty tuplestore */
261 return (Datum) 0;
264 while ((de = ReadDir(dirdesc, location)) != NULL)
266 Oid datOid = atooid(de->d_name);
267 char *subdir;
268 bool isempty;
269 Datum values[1];
270 bool nulls[1];
272 /* this test skips . and .., but is awfully weak */
273 if (!datOid)
274 continue;
276 /* if database subdir is empty, don't report tablespace as used */
278 subdir = psprintf("%s/%s", location, de->d_name);
279 isempty = directory_is_empty(subdir);
280 pfree(subdir);
282 if (isempty)
283 continue; /* indeed, nothing in it */
285 values[0] = ObjectIdGetDatum(datOid);
286 nulls[0] = false;
288 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
289 values, nulls);
292 FreeDir(dirdesc);
293 return (Datum) 0;
298 * pg_tablespace_location - get location for a tablespace
300 Datum
301 pg_tablespace_location(PG_FUNCTION_ARGS)
303 Oid tablespaceOid = PG_GETARG_OID(0);
304 char sourcepath[MAXPGPATH];
305 char targetpath[MAXPGPATH];
306 int rllen;
307 struct stat st;
310 * It's useful to apply this function to pg_class.reltablespace, wherein
311 * zero means "the database's default tablespace". So, rather than
312 * throwing an error for zero, we choose to assume that's what is meant.
314 if (tablespaceOid == InvalidOid)
315 tablespaceOid = MyDatabaseTableSpace;
318 * Return empty string for the cluster's default tablespaces
320 if (tablespaceOid == DEFAULTTABLESPACE_OID ||
321 tablespaceOid == GLOBALTABLESPACE_OID)
322 PG_RETURN_TEXT_P(cstring_to_text(""));
325 * Find the location of the tablespace by reading the symbolic link that
326 * is in pg_tblspc/<oid>.
328 snprintf(sourcepath, sizeof(sourcepath), "%s/%u", PG_TBLSPC_DIR, tablespaceOid);
331 * Before reading the link, check if the source path is a link or a
332 * 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.
336 if (lstat(sourcepath, &st) < 0)
338 ereport(ERROR,
339 (errcode_for_file_access(),
340 errmsg("could not stat file \"%s\": %m",
341 sourcepath)));
344 if (!S_ISLNK(st.st_mode))
345 PG_RETURN_TEXT_P(cstring_to_text(sourcepath));
348 * In presence of a link or a junction point, return the path pointing to.
350 rllen = readlink(sourcepath, targetpath, sizeof(targetpath));
351 if (rllen < 0)
352 ereport(ERROR,
353 (errcode_for_file_access(),
354 errmsg("could not read symbolic link \"%s\": %m",
355 sourcepath)));
356 if (rllen >= sizeof(targetpath))
357 ereport(ERROR,
358 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
359 errmsg("symbolic link \"%s\" target is too long",
360 sourcepath)));
361 targetpath[rllen] = '\0';
363 PG_RETURN_TEXT_P(cstring_to_text(targetpath));
367 * pg_sleep - delay for N seconds
369 Datum
370 pg_sleep(PG_FUNCTION_ARGS)
372 float8 secs = PG_GETARG_FLOAT8(0);
373 float8 endtime;
376 * 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.
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.
387 #define GetNowFloat() ((float8) GetCurrentTimestamp() / 1000000.0)
389 endtime = GetNowFloat() + secs;
391 for (;;)
393 float8 delay;
394 long delay_ms;
396 CHECK_FOR_INTERRUPTS();
398 delay = endtime - GetNowFloat();
399 if (delay >= 600.0)
400 delay_ms = 600000;
401 else if (delay > 0.0)
402 delay_ms = (long) ceil(delay * 1000.0);
403 else
404 break;
406 (void) WaitLatch(MyLatch,
407 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
408 delay_ms,
409 WAIT_EVENT_PG_SLEEP);
410 ResetLatch(MyLatch);
413 PG_RETURN_VOID();
416 /* Function to return the list of grammar keywords */
417 Datum
418 pg_get_keywords(PG_FUNCTION_ARGS)
420 FuncCallContext *funcctx;
422 if (SRF_IS_FIRSTCALL())
424 MemoryContext oldcontext;
425 TupleDesc tupdesc;
427 funcctx = SRF_FIRSTCALL_INIT();
428 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
430 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
431 elog(ERROR, "return type must be a row type");
432 funcctx->tuple_desc = tupdesc;
433 funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
435 MemoryContextSwitchTo(oldcontext);
438 funcctx = SRF_PERCALL_SETUP();
440 if (funcctx->call_cntr < ScanKeywords.num_keywords)
442 char *values[5];
443 HeapTuple tuple;
445 /* cast-away-const is ugly but alternatives aren't much better */
446 values[0] = unconstify(char *,
447 GetScanKeyword(funcctx->call_cntr,
448 &ScanKeywords));
450 switch (ScanKeywordCategories[funcctx->call_cntr])
452 case UNRESERVED_KEYWORD:
453 values[1] = "U";
454 values[3] = _("unreserved");
455 break;
456 case COL_NAME_KEYWORD:
457 values[1] = "C";
458 values[3] = _("unreserved (cannot be function or type name)");
459 break;
460 case TYPE_FUNC_NAME_KEYWORD:
461 values[1] = "T";
462 values[3] = _("reserved (can be function or type name)");
463 break;
464 case RESERVED_KEYWORD:
465 values[1] = "R";
466 values[3] = _("reserved");
467 break;
468 default: /* shouldn't be possible */
469 values[1] = NULL;
470 values[3] = NULL;
471 break;
474 if (ScanKeywordBareLabel[funcctx->call_cntr])
476 values[2] = "true";
477 values[4] = _("can be bare label");
479 else
481 values[2] = "false";
482 values[4] = _("requires AS");
485 tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
487 SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
490 SRF_RETURN_DONE(funcctx);
494 /* Function to return the list of catalog foreign key relationships */
495 Datum
496 pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
498 FuncCallContext *funcctx;
499 FmgrInfo *arrayinp;
501 if (SRF_IS_FIRSTCALL())
503 MemoryContext oldcontext;
504 TupleDesc tupdesc;
506 funcctx = SRF_FIRSTCALL_INIT();
507 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
509 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
510 elog(ERROR, "return type must be a row type");
511 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
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.
519 arrayinp = (FmgrInfo *) palloc(sizeof(FmgrInfo));
520 fmgr_info(F_ARRAY_IN, arrayinp);
521 funcctx->user_fctx = arrayinp;
523 MemoryContextSwitchTo(oldcontext);
526 funcctx = SRF_PERCALL_SETUP();
527 arrayinp = (FmgrInfo *) funcctx->user_fctx;
529 if (funcctx->call_cntr < lengthof(sys_fk_relationships))
531 const SysFKRelationship *fkrel = &sys_fk_relationships[funcctx->call_cntr];
532 Datum values[6];
533 bool nulls[6];
534 HeapTuple tuple;
536 memset(nulls, false, sizeof(nulls));
538 values[0] = ObjectIdGetDatum(fkrel->fk_table);
539 values[1] = FunctionCall3(arrayinp,
540 CStringGetDatum(fkrel->fk_columns),
541 ObjectIdGetDatum(TEXTOID),
542 Int32GetDatum(-1));
543 values[2] = ObjectIdGetDatum(fkrel->pk_table);
544 values[3] = FunctionCall3(arrayinp,
545 CStringGetDatum(fkrel->pk_columns),
546 ObjectIdGetDatum(TEXTOID),
547 Int32GetDatum(-1));
548 values[4] = BoolGetDatum(fkrel->is_array);
549 values[5] = BoolGetDatum(fkrel->is_opt);
551 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
553 SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
556 SRF_RETURN_DONE(funcctx);
561 * Return the type of the argument.
563 Datum
564 pg_typeof(PG_FUNCTION_ARGS)
566 PG_RETURN_OID(get_fn_expr_argtype(fcinfo->flinfo, 0));
571 * Return the base type of the argument.
572 * If the given type is a domain, return its base type;
573 * otherwise return the type's own OID.
574 * Return NULL if the type OID doesn't exist or points to a
575 * non-existent base type.
577 * This is a SQL-callable version of getBaseType(). Unlike that function,
578 * we don't want to fail for a bogus type OID; this is helpful to keep race
579 * conditions from turning into query failures when scanning the catalogs.
580 * Hence we need our own implementation.
582 Datum
583 pg_basetype(PG_FUNCTION_ARGS)
585 Oid typid = PG_GETARG_OID(0);
588 * We loop to find the bottom base type in a stack of domains.
590 for (;;)
592 HeapTuple tup;
593 Form_pg_type typTup;
595 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
596 if (!HeapTupleIsValid(tup))
597 PG_RETURN_NULL(); /* return NULL for bogus OID */
598 typTup = (Form_pg_type) GETSTRUCT(tup);
599 if (typTup->typtype != TYPTYPE_DOMAIN)
601 /* Not a domain, so done */
602 ReleaseSysCache(tup);
603 break;
606 typid = typTup->typbasetype;
607 ReleaseSysCache(tup);
610 PG_RETURN_OID(typid);
615 * Implementation of the COLLATE FOR expression; returns the collation
616 * of the argument.
618 Datum
619 pg_collation_for(PG_FUNCTION_ARGS)
621 Oid typeid;
622 Oid collid;
624 typeid = get_fn_expr_argtype(fcinfo->flinfo, 0);
625 if (!typeid)
626 PG_RETURN_NULL();
627 if (!type_is_collatable(typeid) && typeid != UNKNOWNOID)
628 ereport(ERROR,
629 (errcode(ERRCODE_DATATYPE_MISMATCH),
630 errmsg("collations are not supported by type %s",
631 format_type_be(typeid))));
633 collid = PG_GET_COLLATION();
634 if (!collid)
635 PG_RETURN_NULL();
636 PG_RETURN_TEXT_P(cstring_to_text(generate_collation_name(collid)));
641 * pg_relation_is_updatable - determine which update events the specified
642 * relation supports.
644 * This relies on relation_is_updatable() in rewriteHandler.c, which see
645 * for additional information.
647 Datum
648 pg_relation_is_updatable(PG_FUNCTION_ARGS)
650 Oid reloid = PG_GETARG_OID(0);
651 bool include_triggers = PG_GETARG_BOOL(1);
653 PG_RETURN_INT32(relation_is_updatable(reloid, NIL, include_triggers, NULL));
657 * pg_column_is_updatable - determine whether a column is updatable
659 * This function encapsulates the decision about just what
660 * information_schema.columns.is_updatable actually means. It's not clear
661 * whether deletability of the column's relation should be required, so
662 * we want that decision in C code where we could change it without initdb.
664 Datum
665 pg_column_is_updatable(PG_FUNCTION_ARGS)
667 Oid reloid = PG_GETARG_OID(0);
668 AttrNumber attnum = PG_GETARG_INT16(1);
669 AttrNumber col = attnum - FirstLowInvalidHeapAttributeNumber;
670 bool include_triggers = PG_GETARG_BOOL(2);
671 int events;
673 /* System columns are never updatable */
674 if (attnum <= 0)
675 PG_RETURN_BOOL(false);
677 events = relation_is_updatable(reloid, NIL, include_triggers,
678 bms_make_singleton(col));
680 /* We require both updatability and deletability of the relation */
681 #define REQ_EVENTS ((1 << CMD_UPDATE) | (1 << CMD_DELETE))
683 PG_RETURN_BOOL((events & REQ_EVENTS) == REQ_EVENTS);
688 * pg_input_is_valid - test whether string is valid input for datatype.
690 * Returns true if OK, false if not.
692 * This will only work usefully if the datatype's input function has been
693 * updated to return "soft" errors via errsave/ereturn.
695 Datum
696 pg_input_is_valid(PG_FUNCTION_ARGS)
698 text *txt = PG_GETARG_TEXT_PP(0);
699 text *typname = PG_GETARG_TEXT_PP(1);
700 ErrorSaveContext escontext = {T_ErrorSaveContext};
702 PG_RETURN_BOOL(pg_input_is_valid_common(fcinfo, txt, typname,
703 &escontext));
707 * pg_input_error_info - test whether string is valid input for datatype.
709 * Returns NULL if OK, else the primary message, detail message, hint message
710 * and sql error code from the error.
712 * This will only work usefully if the datatype's input function has been
713 * updated to return "soft" errors via errsave/ereturn.
715 Datum
716 pg_input_error_info(PG_FUNCTION_ARGS)
718 text *txt = PG_GETARG_TEXT_PP(0);
719 text *typname = PG_GETARG_TEXT_PP(1);
720 ErrorSaveContext escontext = {T_ErrorSaveContext};
721 TupleDesc tupdesc;
722 Datum values[4];
723 bool isnull[4];
725 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
726 elog(ERROR, "return type must be a row type");
728 /* Enable details_wanted */
729 escontext.details_wanted = true;
731 if (pg_input_is_valid_common(fcinfo, txt, typname,
732 &escontext))
733 memset(isnull, true, sizeof(isnull));
734 else
736 char *sqlstate;
738 Assert(escontext.error_occurred);
739 Assert(escontext.error_data != NULL);
740 Assert(escontext.error_data->message != NULL);
742 memset(isnull, false, sizeof(isnull));
744 values[0] = CStringGetTextDatum(escontext.error_data->message);
746 if (escontext.error_data->detail != NULL)
747 values[1] = CStringGetTextDatum(escontext.error_data->detail);
748 else
749 isnull[1] = true;
751 if (escontext.error_data->hint != NULL)
752 values[2] = CStringGetTextDatum(escontext.error_data->hint);
753 else
754 isnull[2] = true;
756 sqlstate = unpack_sql_state(escontext.error_data->sqlerrcode);
757 values[3] = CStringGetTextDatum(sqlstate);
760 return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
763 /* Common subroutine for the above */
764 static bool
765 pg_input_is_valid_common(FunctionCallInfo fcinfo,
766 text *txt, text *typname,
767 ErrorSaveContext *escontext)
769 char *str = text_to_cstring(txt);
770 ValidIOData *my_extra;
771 Datum converted;
774 * We arrange to look up the needed I/O info just once per series of
775 * calls, assuming the data type doesn't change underneath us.
777 my_extra = (ValidIOData *) fcinfo->flinfo->fn_extra;
778 if (my_extra == NULL)
780 fcinfo->flinfo->fn_extra =
781 MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
782 sizeof(ValidIOData));
783 my_extra = (ValidIOData *) fcinfo->flinfo->fn_extra;
784 my_extra->typoid = InvalidOid;
785 /* Detect whether typname argument is constant. */
786 my_extra->typname_constant = get_fn_expr_arg_stable(fcinfo->flinfo, 1);
790 * If the typname argument is constant, we only need to parse it the first
791 * time through.
793 if (my_extra->typoid == InvalidOid || !my_extra->typname_constant)
795 char *typnamestr = text_to_cstring(typname);
796 Oid typoid;
798 /* Parse type-name argument to obtain type OID and encoded typmod. */
799 (void) parseTypeString(typnamestr, &typoid, &my_extra->typmod, NULL);
801 /* Update type-specific info if typoid changed. */
802 if (my_extra->typoid != typoid)
804 getTypeInputInfo(typoid,
805 &my_extra->typiofunc,
806 &my_extra->typioparam);
807 fmgr_info_cxt(my_extra->typiofunc, &my_extra->inputproc,
808 fcinfo->flinfo->fn_mcxt);
809 my_extra->typoid = typoid;
813 /* Now we can try to perform the conversion. */
814 return InputFunctionCallSafe(&my_extra->inputproc,
815 str,
816 my_extra->typioparam,
817 my_extra->typmod,
818 (Node *) escontext,
819 &converted);
824 * Is character a valid identifier start?
825 * Must match scan.l's {ident_start} character class.
827 static bool
828 is_ident_start(unsigned char c)
830 /* Underscores and ASCII letters are OK */
831 if (c == '_')
832 return true;
833 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
834 return true;
835 /* Any high-bit-set character is OK (might be part of a multibyte char) */
836 if (IS_HIGHBIT_SET(c))
837 return true;
838 return false;
842 * Is character a valid identifier continuation?
843 * Must match scan.l's {ident_cont} character class.
845 static bool
846 is_ident_cont(unsigned char c)
848 /* Can be digit or dollar sign ... */
849 if ((c >= '0' && c <= '9') || c == '$')
850 return true;
851 /* ... or an identifier start character */
852 return is_ident_start(c);
856 * parse_ident - parse a SQL qualified identifier into separate identifiers.
857 * When strict mode is active (second parameter), then any chars after
858 * the last identifier are disallowed.
860 Datum
861 parse_ident(PG_FUNCTION_ARGS)
863 text *qualname = PG_GETARG_TEXT_PP(0);
864 bool strict = PG_GETARG_BOOL(1);
865 char *qualname_str = text_to_cstring(qualname);
866 ArrayBuildState *astate = NULL;
867 char *nextp;
868 bool after_dot = false;
871 * The code below scribbles on qualname_str in some cases, so we should
872 * reconvert qualname if we need to show the original string in error
873 * messages.
875 nextp = qualname_str;
877 /* skip leading whitespace */
878 while (scanner_isspace(*nextp))
879 nextp++;
881 for (;;)
883 char *curname;
884 bool missing_ident = true;
886 if (*nextp == '"')
888 char *endp;
890 curname = nextp + 1;
891 for (;;)
893 endp = strchr(nextp + 1, '"');
894 if (endp == NULL)
895 ereport(ERROR,
896 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
897 errmsg("string is not a valid identifier: \"%s\"",
898 text_to_cstring(qualname)),
899 errdetail("String has unclosed double quotes.")));
900 if (endp[1] != '"')
901 break;
902 memmove(endp, endp + 1, strlen(endp));
903 nextp = endp;
905 nextp = endp + 1;
906 *endp = '\0';
908 if (endp - curname == 0)
909 ereport(ERROR,
910 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
911 errmsg("string is not a valid identifier: \"%s\"",
912 text_to_cstring(qualname)),
913 errdetail("Quoted identifier must not be empty.")));
915 astate = accumArrayResult(astate, CStringGetTextDatum(curname),
916 false, TEXTOID, CurrentMemoryContext);
917 missing_ident = false;
919 else if (is_ident_start((unsigned char) *nextp))
921 char *downname;
922 int len;
923 text *part;
925 curname = nextp++;
926 while (is_ident_cont((unsigned char) *nextp))
927 nextp++;
929 len = nextp - curname;
932 * We don't implicitly truncate identifiers. This is useful for
933 * allowing the user to check for specific parts of the identifier
934 * being too long. It's easy enough for the user to get the
935 * truncated names by casting our output to name[].
937 downname = downcase_identifier(curname, len, false, false);
938 part = cstring_to_text_with_len(downname, len);
939 astate = accumArrayResult(astate, PointerGetDatum(part), false,
940 TEXTOID, CurrentMemoryContext);
941 missing_ident = false;
944 if (missing_ident)
946 /* Different error messages based on where we failed. */
947 if (*nextp == '.')
948 ereport(ERROR,
949 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
950 errmsg("string is not a valid identifier: \"%s\"",
951 text_to_cstring(qualname)),
952 errdetail("No valid identifier before \".\".")));
953 else if (after_dot)
954 ereport(ERROR,
955 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
956 errmsg("string is not a valid identifier: \"%s\"",
957 text_to_cstring(qualname)),
958 errdetail("No valid identifier after \".\".")));
959 else
960 ereport(ERROR,
961 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
962 errmsg("string is not a valid identifier: \"%s\"",
963 text_to_cstring(qualname))));
966 while (scanner_isspace(*nextp))
967 nextp++;
969 if (*nextp == '.')
971 after_dot = true;
972 nextp++;
973 while (scanner_isspace(*nextp))
974 nextp++;
976 else if (*nextp == '\0')
978 break;
980 else
982 if (strict)
983 ereport(ERROR,
984 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
985 errmsg("string is not a valid identifier: \"%s\"",
986 text_to_cstring(qualname))));
987 break;
991 PG_RETURN_DATUM(makeArrayResult(astate, CurrentMemoryContext));
995 * pg_current_logfile
997 * Report current log file used by log collector by scanning current_logfiles.
999 Datum
1000 pg_current_logfile(PG_FUNCTION_ARGS)
1002 FILE *fd;
1003 char lbuffer[MAXPGPATH];
1004 char *logfmt;
1006 /* The log format parameter is optional */
1007 if (PG_NARGS() == 0 || PG_ARGISNULL(0))
1008 logfmt = NULL;
1009 else
1011 logfmt = text_to_cstring(PG_GETARG_TEXT_PP(0));
1013 if (strcmp(logfmt, "stderr") != 0 &&
1014 strcmp(logfmt, "csvlog") != 0 &&
1015 strcmp(logfmt, "jsonlog") != 0)
1016 ereport(ERROR,
1017 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1018 errmsg("log format \"%s\" is not supported", logfmt),
1019 errhint("The supported log formats are \"stderr\", \"csvlog\", and \"jsonlog\".")));
1022 fd = AllocateFile(LOG_METAINFO_DATAFILE, "r");
1023 if (fd == NULL)
1025 if (errno != ENOENT)
1026 ereport(ERROR,
1027 (errcode_for_file_access(),
1028 errmsg("could not read file \"%s\": %m",
1029 LOG_METAINFO_DATAFILE)));
1030 PG_RETURN_NULL();
1033 #ifdef WIN32
1034 /* syslogger.c writes CRLF line endings on Windows */
1035 _setmode(_fileno(fd), _O_TEXT);
1036 #endif
1039 * Read the file to gather current log filename(s) registered by the
1040 * syslogger.
1042 while (fgets(lbuffer, sizeof(lbuffer), fd) != NULL)
1044 char *log_format;
1045 char *log_filepath;
1046 char *nlpos;
1048 /* Extract log format and log file path from the line. */
1049 log_format = lbuffer;
1050 log_filepath = strchr(lbuffer, ' ');
1051 if (log_filepath == NULL)
1053 /* Uh oh. No space found, so file content is corrupted. */
1054 elog(ERROR,
1055 "missing space character in \"%s\"", LOG_METAINFO_DATAFILE);
1056 break;
1059 *log_filepath = '\0';
1060 log_filepath++;
1061 nlpos = strchr(log_filepath, '\n');
1062 if (nlpos == NULL)
1064 /* Uh oh. No newline found, so file content is corrupted. */
1065 elog(ERROR,
1066 "missing newline character in \"%s\"", LOG_METAINFO_DATAFILE);
1067 break;
1069 *nlpos = '\0';
1071 if (logfmt == NULL || strcmp(logfmt, log_format) == 0)
1073 FreeFile(fd);
1074 PG_RETURN_TEXT_P(cstring_to_text(log_filepath));
1078 /* Close the current log filename file. */
1079 FreeFile(fd);
1081 PG_RETURN_NULL();
1085 * Report current log file used by log collector (1 argument version)
1087 * note: this wrapper is necessary to pass the sanity check in opr_sanity,
1088 * which checks that all built-in functions that share the implementing C
1089 * function take the same number of arguments
1091 Datum
1092 pg_current_logfile_1arg(PG_FUNCTION_ARGS)
1094 return pg_current_logfile(fcinfo);
1098 * SQL wrapper around RelationGetReplicaIndex().
1100 Datum
1101 pg_get_replica_identity_index(PG_FUNCTION_ARGS)
1103 Oid reloid = PG_GETARG_OID(0);
1104 Oid idxoid;
1105 Relation rel;
1107 rel = table_open(reloid, AccessShareLock);
1108 idxoid = RelationGetReplicaIndex(rel);
1109 table_close(rel, AccessShareLock);
1111 if (OidIsValid(idxoid))
1112 PG_RETURN_OID(idxoid);
1113 else
1114 PG_RETURN_NULL();
1118 * Transition function for the ANY_VALUE aggregate
1120 Datum
1121 any_value_transfn(PG_FUNCTION_ARGS)
1123 PG_RETURN_DATUM(PG_GETARG_DATUM(0));