LCOV - code coverage report
Current view: top level - src/backend/nodes - read.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 84.5 % 174 147
Test Date: 2026-09-05 22:15:48 Functions: 100.0 % 7 7
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 66.1 % 186 123

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * read.c
       4                 :             :  *    routines to convert a string (legal ascii representation of node) back
       5                 :             :  *    to nodes
       6                 :             :  *
       7                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       8                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       9                 :             :  *
      10                 :             :  *
      11                 :             :  * IDENTIFICATION
      12                 :             :  *    src/backend/nodes/read.c
      13                 :             :  *
      14                 :             :  * HISTORY
      15                 :             :  *    AUTHOR            DATE            MAJOR EVENT
      16                 :             :  *    Andrew Yu         Nov 2, 1994     file creation
      17                 :             :  *
      18                 :             :  *-------------------------------------------------------------------------
      19                 :             :  */
      20                 :             : #include "postgres.h"
      21                 :             : 
      22                 :             : #include <ctype.h>
      23                 :             : 
      24                 :             : #include "common/string.h"
      25                 :             : #include "nodes/bitmapset.h"
      26                 :             : #include "nodes/pg_list.h"
      27                 :             : #include "nodes/readfuncs.h"
      28                 :             : #include "nodes/value.h"
      29                 :             : 
      30                 :             : 
      31                 :             : /*
      32                 :             :  * stringToNode -
      33                 :             :  *    builds a Node tree from its string representation (assumed valid)
      34                 :             :  *
      35                 :             :  * restore_loc_fields instructs readfuncs.c whether to restore location
      36                 :             :  * fields rather than set them to -1.  This is currently only supported
      37                 :             :  * in builds with DEBUG_NODE_TESTS_ENABLED defined.
      38                 :             :  */
      39                 :             : static void *
      40                 :     1496069 : stringToNodeInternal(const char *str, bool restore_loc_fields)
      41                 :             : {
      42                 :             :     ReadNodeContext ctx;
      43                 :             : 
      44                 :             :     /* initialize the context  */
      45                 :     1496069 :     ctx.str = str;
      46                 :             : #ifdef DEBUG_NODE_TESTS_ENABLED
      47                 :     1496069 :     ctx.restore_location_fields = restore_loc_fields;
      48                 :             : #endif
      49                 :             : 
      50                 :             :     /* do the reading, and return */
      51                 :     1496069 :     return nodeRead(&ctx, NULL, 0);
      52                 :             : }
      53                 :             : 
      54                 :             : /*
      55                 :             :  * Externally visible entry points
      56                 :             :  */
      57                 :             : void *
      58                 :      254786 : stringToNode(const char *str)
      59                 :             : {
      60                 :      254786 :     return stringToNodeInternal(str, false);
      61                 :             : }
      62                 :             : 
      63                 :             : #ifdef DEBUG_NODE_TESTS_ENABLED
      64                 :             : 
      65                 :             : void *
      66                 :     1241283 : stringToNodeWithLocations(const char *str)
      67                 :             : {
      68                 :     1241283 :     return stringToNodeInternal(str, true);
      69                 :             : }
      70                 :             : 
      71                 :             : #endif
      72                 :             : 
      73                 :             : 
      74                 :             : /*****************************************************************************
      75                 :             :  *
      76                 :             :  * the lisp token parser
      77                 :             :  *
      78                 :             :  *****************************************************************************/
      79                 :             : 
      80                 :             : /*
      81                 :             :  * pg_strtok --- retrieve next "token" from a string.
      82                 :             :  *
      83                 :             :  * Works kinda like strtok, except it never modifies the source string.
      84                 :             :  * (Instead of storing nulls into the string, the length of the token
      85                 :             :  * is returned to the caller.)
      86                 :             :  * Also, the rules about what is a token are hard-wired rather than being
      87                 :             :  * configured by passing a set of terminating characters.
      88                 :             :  *
      89                 :             :  * The rules for tokens are:
      90                 :             :  *  * Whitespace (space, tab, newline) always separates tokens.
      91                 :             :  *  * The characters '(', ')', '{', '}' form individual tokens even
      92                 :             :  *    without any whitespace around them.
      93                 :             :  *  * Otherwise, a token is all the characters up to the next whitespace
      94                 :             :  *    or occurrence of one of the four special characters.
      95                 :             :  *  * A backslash '\' can be used to quote whitespace or one of the four
      96                 :             :  *    special characters, so that it is treated as a plain token character.
      97                 :             :  *    Backslashes themselves must also be backslashed for consistency.
      98                 :             :  *    Any other character can be, but need not be, backslashed as well.
      99                 :             :  *  * If the resulting token is '<>' (with no backslash), it is returned
     100                 :             :  *    as a non-NULL pointer to the token but with length == 0.  Note that
     101                 :             :  *    there is no other way to get a zero-length token.
     102                 :             :  *
     103                 :             :  * Returns a pointer to the start of the next token, and the length of the
     104                 :             :  * token (including any embedded backslashes!) in *length.  If there are
     105                 :             :  * no more tokens, NULL and 0 are returned.
     106                 :             :  *
     107                 :             :  * NOTE: this routine doesn't remove backslashes; the caller must do so
     108                 :             :  * if necessary (see "debackslash").
     109                 :             :  *
     110                 :             :  * NOTE: prior to release 7.0, this routine also had a special case to treat
     111                 :             :  * a token starting with '"' as extending to the next '"'.  This code was
     112                 :             :  * broken, however, since it would fail to cope with a string containing an
     113                 :             :  * embedded '"'.  I have therefore removed this special case, and instead
     114                 :             :  * introduced rules for using backslashes to quote characters.  Higher-level
     115                 :             :  * code should add backslashes to a string constant to ensure it is treated
     116                 :             :  * as a single token.
     117                 :             :  */
     118                 :             : const char *
     119                 :   862158031 : pg_strtok(ReadNodeContext *ctx, int *length)
     120                 :             : {
     121                 :             :     const char *local_str;      /* working pointer to string */
     122                 :             :     const char *ret_str;        /* start of token to return */
     123                 :             : 
     124                 :   862158031 :     local_str = ctx->str;
     125                 :             : 
     126   [ +  +  -  +  :  1599071047 :     while (*local_str == ' ' || *local_str == '\n' || *local_str == '\t')
                   -  + ]
     127                 :   736913016 :         local_str++;
     128                 :             : 
     129         [ +  + ]:   862158031 :     if (*local_str == '\0')
     130                 :             :     {
     131                 :           1 :         *length = 0;
     132                 :           1 :         ctx->str = local_str;
     133                 :           1 :         return NULL;            /* no more tokens */
     134                 :             :     }
     135                 :             : 
     136                 :             :     /*
     137                 :             :      * Now pointing at start of next token.
     138                 :             :      */
     139                 :   862158030 :     ret_str = local_str;
     140                 :             : 
     141   [ +  +  +  + ]:   862158030 :     if (*local_str == '(' || *local_str == ')' ||
     142   [ +  +  +  + ]:   807006980 :         *local_str == '{' || *local_str == '}')
     143                 :             :     {
     144                 :             :         /* special 1-character token */
     145                 :   124080848 :         local_str++;
     146                 :             :     }
     147                 :             :     else
     148                 :             :     {
     149                 :             :         /* Normal token, possibly containing backslashes */
     150                 :   738077182 :         while (*local_str != '\0' &&
     151   [ +  +  +  - ]:  5251359610 :                *local_str != ' ' && *local_str != '\n' &&
     152         [ +  - ]:  4564690585 :                *local_str != '\t' &&
     153   [ +  -  +  + ]:  4564690585 :                *local_str != '(' && *local_str != ')' &&
     154   [ +  +  +  -  :  9796508599 :                *local_str != '{' && *local_str != '}')
                   +  + ]
     155                 :             :         {
     156   [ +  +  +  - ]:  4513307319 :             if (*local_str == '\\' && local_str[1] != '\0')
     157                 :     1411092 :                 local_str += 2;
     158                 :             :             else
     159                 :  4511896227 :                 local_str++;
     160                 :             :         }
     161                 :             :     }
     162                 :             : 
     163                 :   862158030 :     *length = local_str - ret_str;
     164                 :             : 
     165                 :             :     /* Recognize special case for "empty" token */
     166   [ +  +  +  +  :   862158030 :     if (*length == 2 && ret_str[0] == '<' && ret_str[1] == '>')
                   +  - ]
     167                 :    44606389 :         *length = 0;
     168                 :             : 
     169                 :   862158030 :     ctx->str = local_str;
     170                 :             : 
     171                 :   862158030 :     return ret_str;
     172                 :             : }
     173                 :             : 
     174                 :             : /*
     175                 :             :  * debackslash -
     176                 :             :  *    create a palloc'd string holding the given token.
     177                 :             :  *    any protective backslashes in the token are removed.
     178                 :             :  */
     179                 :             : char *
     180                 :    25420700 : debackslash(const char *token, int length)
     181                 :             : {
     182                 :    25420700 :     char       *result = palloc(length + 1);
     183                 :    25420700 :     char       *ptr = result;
     184                 :             : 
     185         [ +  + ]:   243130303 :     while (length > 0)
     186                 :             :     {
     187   [ +  +  +  - ]:   217709603 :         if (*token == '\\' && length > 1)
     188                 :     1411092 :             token++, length--;
     189                 :   217709603 :         *ptr++ = *token++;
     190                 :   217709603 :         length--;
     191                 :             :     }
     192                 :    25420700 :     *ptr = '\0';
     193                 :    25420700 :     return result;
     194                 :             : }
     195                 :             : 
     196                 :             : #define RIGHT_PAREN (1000000 + 1)
     197                 :             : #define LEFT_PAREN  (1000000 + 2)
     198                 :             : #define LEFT_BRACE  (1000000 + 3)
     199                 :             : #define OTHER_TOKEN (1000000 + 4)
     200                 :             : 
     201                 :             : /*
     202                 :             :  * nodeTokenType -
     203                 :             :  *    returns the type of the node token contained in token.
     204                 :             :  *    It returns one of the following valid NodeTags:
     205                 :             :  *      T_Integer, T_Float, T_Boolean, T_String, T_BitString
     206                 :             :  *    and some of its own:
     207                 :             :  *      RIGHT_PAREN, LEFT_PAREN, LEFT_BRACE, OTHER_TOKEN
     208                 :             :  *
     209                 :             :  *    Assumption: the ascii representation is legal
     210                 :             :  */
     211                 :             : static NodeTag
     212                 :   103846860 : nodeTokenType(const char *token, int length)
     213                 :             : {
     214                 :             :     NodeTag     retval;
     215                 :             :     const char *numptr;
     216                 :             :     int         numlen;
     217                 :             : 
     218                 :             :     /*
     219                 :             :      * Check if the token is a number
     220                 :             :      */
     221                 :   103846860 :     numptr = token;
     222                 :   103846860 :     numlen = length;
     223   [ +  -  +  + ]:   103846860 :     if (*numptr == '+' || *numptr == '-')
     224                 :       18969 :         numptr++, numlen--;
     225   [ +  +  +  +  :   103846860 :     if ((numlen > 0 && isdigit((unsigned char) *numptr)) ||
                   +  + ]
     226   [ +  +  +  - ]:    19211768 :         (numlen > 1 && *numptr == '.' && isdigit((unsigned char) numptr[1])))
     227                 :             :     {
     228                 :             :         /*
     229                 :             :          * Yes.  Figure out whether it is integral or float; this requires
     230                 :             :          * both a syntax check and a range check. strtoint() can do both for
     231                 :             :          * us. We know the token will end at a character that strtoint will
     232                 :             :          * stop at, so we do not need to modify the string.
     233                 :             :          */
     234                 :             :         char       *endptr;
     235                 :             : 
     236                 :      472766 :         errno = 0;
     237                 :      472766 :         (void) strtoint(numptr, &endptr, 10);
     238   [ +  +  +  + ]:      472766 :         if (endptr != token + length || errno == ERANGE)
     239                 :        8374 :             return T_Float;
     240                 :      464392 :         return T_Integer;
     241                 :             :     }
     242                 :             : 
     243                 :             :     /*
     244                 :             :      * these three cases do not need length checks, since pg_strtok() will
     245                 :             :      * always treat them as single-byte tokens
     246                 :             :      */
     247         [ +  + ]:   103374094 :     else if (*token == '(')
     248                 :    12778951 :         retval = LEFT_PAREN;
     249         [ -  + ]:    90595143 :     else if (*token == ')')
     250                 :           0 :         retval = RIGHT_PAREN;
     251         [ +  + ]:    90595143 :     else if (*token == '{')
     252                 :    34464899 :         retval = LEFT_BRACE;
     253   [ +  +  +  +  :    56130244 :     else if ((length == 4 && strncmp(token, "true", 4) == 0) ||
                   +  + ]
     254         [ +  + ]:     1214549 :              (length == 5 && strncmp(token, "false", 5) == 0))
     255                 :       57822 :         retval = T_Boolean;
     256   [ +  +  +  -  :    56072422 :     else if (*token == '"' && length > 1 && token[length - 1] == '"')
                   +  - ]
     257                 :    19151199 :         retval = T_String;
     258   [ +  +  +  + ]:    36921223 :     else if (*token == 'b' || *token == 'x')
     259                 :        2735 :         retval = T_BitString;
     260                 :             :     else
     261                 :    36918488 :         retval = OTHER_TOKEN;
     262                 :   103374094 :     return retval;
     263                 :             : }
     264                 :             : 
     265                 :             : /*
     266                 :             :  * nodeRead -
     267                 :             :  *    Slightly higher-level reader.
     268                 :             :  *
     269                 :             :  * This routine applies some semantic knowledge on top of the purely
     270                 :             :  * lexical tokenizer pg_strtok().   It can read
     271                 :             :  *  * Value token nodes (integers, floats, booleans, or strings);
     272                 :             :  *  * General nodes (via parseNodeString() from readfuncs.c);
     273                 :             :  *  * Lists of the above;
     274                 :             :  *  * Lists of integers, OIDs, or TransactionIds.
     275                 :             :  * The return value is declared void *, not Node *, to avoid having to
     276                 :             :  * cast it explicitly in callers that assign to fields of different types.
     277                 :             :  *
     278                 :             :  * External callers should always pass NULL/0 for the arguments.  Internally
     279                 :             :  * a non-NULL token may be passed when the upper recursion level has already
     280                 :             :  * scanned the first token of a node's representation.
     281                 :             :  *
     282                 :             :  * We assume pg_strtok is already initialized with a string to read (hence
     283                 :             :  * this should only be invoked from within a stringToNode operation).
     284                 :             :  */
     285                 :             : void *
     286                 :   103846860 : nodeRead(ReadNodeContext *ctx, const char *token, int tok_len)
     287                 :             : {
     288                 :             :     Node       *result;
     289                 :             :     NodeTag     type;
     290                 :             : 
     291         [ +  + ]:   103846860 :     if (token == NULL)          /* need to read a token? */
     292                 :             :     {
     293                 :    65557816 :         token = pg_strtok(ctx, &tok_len);
     294                 :             : 
     295         [ -  + ]:    65557816 :         if (token == NULL)      /* end of input */
     296                 :           0 :             return NULL;
     297                 :             :     }
     298                 :             : 
     299                 :   103846860 :     type = nodeTokenType(token, tok_len);
     300                 :             : 
     301   [ +  +  -  +  :   103846860 :     switch ((int) type)
          +  +  +  +  +  
                      - ]
     302                 :             :     {
     303                 :    34464899 :         case LEFT_BRACE:
     304                 :    34464899 :             result = parseNodeString(ctx);
     305                 :    34464898 :             token = pg_strtok(ctx, &tok_len);
     306   [ +  -  -  + ]:    34464898 :             if (token == NULL || token[0] != '}')
     307         [ #  # ]:           0 :                 elog(ERROR, "did not find '}' at end of input node");
     308                 :    34464898 :             break;
     309                 :    12778951 :         case LEFT_PAREN:
     310                 :             :             {
     311                 :    12778951 :                 List       *l = NIL;
     312                 :             : 
     313                 :             :                 /*----------
     314                 :             :                  * Could be an integer list:    (i int int ...)
     315                 :             :                  * or an OID list:              (o int int ...)
     316                 :             :                  * or an XID list:              (x int int ...)
     317                 :             :                  * or a bitmapset:              (b int int ...)
     318                 :             :                  * or a list of nodes/values:   (node node ...)
     319                 :             :                  *----------
     320                 :             :                  */
     321                 :    12778951 :                 token = pg_strtok(ctx, &tok_len);
     322         [ -  + ]:    12778951 :                 if (token == NULL)
     323         [ #  # ]:           0 :                     elog(ERROR, "unterminated List structure");
     324   [ +  +  +  + ]:    12778951 :                 if (tok_len == 1 && token[0] == 'i')
     325                 :             :                 {
     326                 :             :                     /* List of integers */
     327                 :             :                     for (;;)
     328                 :     3421133 :                     {
     329                 :             :                         int         val;
     330                 :             :                         char       *endptr;
     331                 :             : 
     332                 :     3725991 :                         token = pg_strtok(ctx, &tok_len);
     333         [ -  + ]:     3725991 :                         if (token == NULL)
     334         [ #  # ]:           0 :                             elog(ERROR, "unterminated List structure");
     335         [ +  + ]:     3725991 :                         if (token[0] == ')')
     336                 :      304858 :                             break;
     337                 :     3421133 :                         val = (int) strtol(token, &endptr, 10);
     338         [ -  + ]:     3421133 :                         if (endptr != token + tok_len)
     339         [ #  # ]:           0 :                             elog(ERROR, "unrecognized integer: \"%.*s\"",
     340                 :             :                                  tok_len, token);
     341                 :     3421133 :                         l = lappend_int(l, val);
     342                 :             :                     }
     343                 :      304858 :                     result = (Node *) l;
     344                 :             :                 }
     345   [ +  +  +  + ]:    12474093 :                 else if (tok_len == 1 && token[0] == 'o')
     346                 :             :                 {
     347                 :             :                     /* List of OIDs */
     348                 :             :                     for (;;)
     349                 :     1051924 :                     {
     350                 :             :                         Oid         val;
     351                 :             :                         char       *endptr;
     352                 :             : 
     353                 :     1547217 :                         token = pg_strtok(ctx, &tok_len);
     354         [ -  + ]:     1547217 :                         if (token == NULL)
     355         [ #  # ]:           0 :                             elog(ERROR, "unterminated List structure");
     356         [ +  + ]:     1547217 :                         if (token[0] == ')')
     357                 :      495293 :                             break;
     358                 :     1051924 :                         val = (Oid) strtoul(token, &endptr, 10);
     359         [ -  + ]:     1051924 :                         if (endptr != token + tok_len)
     360         [ #  # ]:           0 :                             elog(ERROR, "unrecognized OID: \"%.*s\"",
     361                 :             :                                  tok_len, token);
     362                 :     1051924 :                         l = lappend_oid(l, val);
     363                 :             :                     }
     364                 :      495293 :                     result = (Node *) l;
     365                 :             :                 }
     366   [ +  +  -  + ]:    11978800 :                 else if (tok_len == 1 && token[0] == 'x')
     367                 :             :                 {
     368                 :             :                     /* List of TransactionIds */
     369                 :             :                     for (;;)
     370                 :           0 :                     {
     371                 :             :                         TransactionId val;
     372                 :             :                         char       *endptr;
     373                 :             : 
     374                 :           0 :                         token = pg_strtok(ctx, &tok_len);
     375         [ #  # ]:           0 :                         if (token == NULL)
     376         [ #  # ]:           0 :                             elog(ERROR, "unterminated List structure");
     377         [ #  # ]:           0 :                         if (token[0] == ')')
     378                 :           0 :                             break;
     379                 :           0 :                         val = (TransactionId) strtoul(token, &endptr, 10);
     380         [ #  # ]:           0 :                         if (endptr != token + tok_len)
     381         [ #  # ]:           0 :                             elog(ERROR, "unrecognized Xid: \"%.*s\"",
     382                 :             :                                  tok_len, token);
     383                 :           0 :                         l = lappend_xid(l, val);
     384                 :             :                     }
     385                 :           0 :                     result = (Node *) l;
     386                 :             :                 }
     387   [ +  +  +  + ]:    11978800 :                 else if (tok_len == 1 && token[0] == 'b')
     388                 :        2173 :                 {
     389                 :             :                     /* Bitmapset -- see also _readBitmapset() */
     390                 :        2173 :                     Bitmapset  *bms = NULL;
     391                 :             : 
     392                 :             :                     for (;;)
     393                 :        3193 :                     {
     394                 :             :                         int         val;
     395                 :             :                         char       *endptr;
     396                 :             : 
     397                 :        5366 :                         token = pg_strtok(ctx, &tok_len);
     398         [ -  + ]:        5366 :                         if (token == NULL)
     399         [ #  # ]:           0 :                             elog(ERROR, "unterminated Bitmapset structure");
     400   [ +  +  +  + ]:        5366 :                         if (tok_len == 1 && token[0] == ')')
     401                 :        2173 :                             break;
     402                 :        3193 :                         val = (int) strtol(token, &endptr, 10);
     403         [ -  + ]:        3193 :                         if (endptr != token + tok_len)
     404         [ #  # ]:           0 :                             elog(ERROR, "unrecognized integer: \"%.*s\"",
     405                 :             :                                  tok_len, token);
     406                 :        3193 :                         bms = bms_add_member(bms, val);
     407                 :             :                     }
     408                 :        2173 :                     result = (Node *) bms;
     409                 :             :                 }
     410                 :             :                 else
     411                 :             :                 {
     412                 :             :                     /* List of other node types */
     413                 :             :                     for (;;)
     414                 :             :                     {
     415                 :             :                         /* We have already scanned next token... */
     416         [ +  + ]:    50265671 :                         if (token[0] == ')')
     417                 :    11976627 :                             break;
     418                 :    38289044 :                         l = lappend(l, nodeRead(ctx, token, tok_len));
     419                 :    38289044 :                         token = pg_strtok(ctx, &tok_len);
     420         [ -  + ]:    38289044 :                         if (token == NULL)
     421         [ #  # ]:           0 :                             elog(ERROR, "unterminated List structure");
     422                 :             :                     }
     423                 :    11976627 :                     result = (Node *) l;
     424                 :             :                 }
     425                 :    12778951 :                 break;
     426                 :             :             }
     427                 :           0 :         case RIGHT_PAREN:
     428         [ #  # ]:           0 :             elog(ERROR, "unexpected right parenthesis");
     429                 :             :             result = NULL;      /* keep compiler happy */
     430                 :             :             break;
     431                 :    36918488 :         case OTHER_TOKEN:
     432         [ +  - ]:    36918488 :             if (tok_len == 0)
     433                 :             :             {
     434                 :             :                 /* must be "<>" --- represents a null pointer */
     435                 :    36918488 :                 result = NULL;
     436                 :             :             }
     437                 :             :             else
     438                 :             :             {
     439         [ #  # ]:           0 :                 elog(ERROR, "unrecognized token: \"%.*s\"", tok_len, token);
     440                 :             :                 result = NULL;  /* keep compiler happy */
     441                 :             :             }
     442                 :    36918488 :             break;
     443                 :      464392 :         case T_Integer:
     444                 :             : 
     445                 :             :             /*
     446                 :             :              * we know that the token terminates on a char atoi will stop at
     447                 :             :              */
     448                 :      464392 :             result = (Node *) makeInteger(atoi(token));
     449                 :      464392 :             break;
     450                 :        8374 :         case T_Float:
     451                 :             :             {
     452                 :        8374 :                 char       *fval = (char *) palloc(tok_len + 1);
     453                 :             : 
     454                 :        8374 :                 memcpy(fval, token, tok_len);
     455                 :        8374 :                 fval[tok_len] = '\0';
     456                 :        8374 :                 result = (Node *) makeFloat(fval);
     457                 :             :             }
     458                 :        8374 :             break;
     459                 :       57822 :         case T_Boolean:
     460                 :       57822 :             result = (Node *) makeBoolean(token[0] == 't');
     461                 :       57822 :             break;
     462                 :    19151199 :         case T_String:
     463                 :             :             /* need to remove leading and trailing quotes, and backslashes */
     464                 :    19151199 :             result = (Node *) makeString(debackslash(token + 1, tok_len - 2));
     465                 :    19151199 :             break;
     466                 :        2735 :         case T_BitString:
     467                 :             :             /* need to remove backslashes, but there are no quotes */
     468                 :        2735 :             result = (Node *) makeBitString(debackslash(token, tok_len));
     469                 :        2735 :             break;
     470                 :           0 :         default:
     471         [ #  # ]:           0 :             elog(ERROR, "unrecognized node type: %d", (int) type);
     472                 :             :             result = NULL;      /* keep compiler happy */
     473                 :             :             break;
     474                 :             :     }
     475                 :             : 
     476                 :   103846859 :     return result;
     477                 :             : }
        

Generated by: LCOV version 2.0-1