LCOV - code coverage report
Current view: top level - src/backend/utils/adt - misc.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 78.5 % 354 278
Test Date: 2026-03-12 06:14:44 Functions: 92.3 % 26 24
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.0-1