LCOV - code coverage report
Current view: top level - src/backend/utils/adt - misc.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 73.7 % 471 347
Test Date: 2026-01-26 10:56:24 Functions: 80.8 % 26 21
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 48.6 % 288 140

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

Generated by: LCOV version 2.3.2-1