LCOV - code coverage report
Current view: top level - src/backend/nodes - readfuncs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18beta1 Lines: 227 257 88.3 %
Date: 2025-06-28 05:17:58 Functions: 13 15 86.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * readfuncs.c
       4             :  *    Reader functions for Postgres tree nodes.
       5             :  *
       6             :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/nodes/readfuncs.c
      12             :  *
      13             :  * NOTES
      14             :  *    Parse location fields are written out by outfuncs.c, but only for
      15             :  *    debugging use.  When reading a location field, we normally discard
      16             :  *    the stored value and set the location field to -1 (ie, "unknown").
      17             :  *    This is because nodes coming from a stored rule should not be thought
      18             :  *    to have a known location in the current query's text.
      19             :  *
      20             :  *    However, if restore_location_fields is true, we do restore location
      21             :  *    fields from the string.  This is currently intended only for use by the
      22             :  *    debug_write_read_parse_plan_trees test code, which doesn't want to cause
      23             :  *    any change in the node contents.
      24             :  *
      25             :  *-------------------------------------------------------------------------
      26             :  */
      27             : #include "postgres.h"
      28             : 
      29             : #include <math.h>
      30             : 
      31             : #include "miscadmin.h"
      32             : #include "nodes/bitmapset.h"
      33             : #include "nodes/readfuncs.h"
      34             : 
      35             : 
      36             : /*
      37             :  * Macros to simplify reading of different kinds of fields.  Use these
      38             :  * wherever possible to reduce the chance for silly typos.  Note that these
      39             :  * hard-wire conventions about the names of the local variables in a Read
      40             :  * routine.
      41             :  */
      42             : 
      43             : /* Macros for declaring appropriate local variables */
      44             : 
      45             : /* A few guys need only local_node */
      46             : #define READ_LOCALS_NO_FIELDS(nodeTypeName) \
      47             :     nodeTypeName *local_node = makeNode(nodeTypeName)
      48             : 
      49             : /* And a few guys need only the pg_strtok support fields */
      50             : #define READ_TEMP_LOCALS()  \
      51             :     const char *token;      \
      52             :     int         length
      53             : 
      54             : /* ... but most need both */
      55             : #define READ_LOCALS(nodeTypeName)           \
      56             :     READ_LOCALS_NO_FIELDS(nodeTypeName);    \
      57             :     READ_TEMP_LOCALS()
      58             : 
      59             : /* Read an integer field (anything written as ":fldname %d") */
      60             : #define READ_INT_FIELD(fldname) \
      61             :     token = pg_strtok(&length);     /* skip :fldname */ \
      62             :     token = pg_strtok(&length);     /* get field value */ \
      63             :     local_node->fldname = atoi(token)
      64             : 
      65             : /* Read an unsigned integer field (anything written as ":fldname %u") */
      66             : #define READ_UINT_FIELD(fldname) \
      67             :     token = pg_strtok(&length);     /* skip :fldname */ \
      68             :     token = pg_strtok(&length);     /* get field value */ \
      69             :     local_node->fldname = atoui(token)
      70             : 
      71             : /* Read a signed integer field (anything written using INT64_FORMAT) */
      72             : #define READ_INT64_FIELD(fldname) \
      73             :     token = pg_strtok(&length); /* skip :fldname */ \
      74             :     token = pg_strtok(&length); /* get field value */ \
      75             :     local_node->fldname = strtoi64(token, NULL, 10)
      76             : 
      77             : /* Read an unsigned integer field (anything written using UINT64_FORMAT) */
      78             : #define READ_UINT64_FIELD(fldname) \
      79             :     token = pg_strtok(&length);     /* skip :fldname */ \
      80             :     token = pg_strtok(&length);     /* get field value */ \
      81             :     local_node->fldname = strtou64(token, NULL, 10)
      82             : 
      83             : /* Read a long integer field (anything written as ":fldname %ld") */
      84             : #define READ_LONG_FIELD(fldname) \
      85             :     token = pg_strtok(&length);     /* skip :fldname */ \
      86             :     token = pg_strtok(&length);     /* get field value */ \
      87             :     local_node->fldname = atol(token)
      88             : 
      89             : /* Read an OID field (don't hard-wire assumption that OID is same as uint) */
      90             : #define READ_OID_FIELD(fldname) \
      91             :     token = pg_strtok(&length);     /* skip :fldname */ \
      92             :     token = pg_strtok(&length);     /* get field value */ \
      93             :     local_node->fldname = atooid(token)
      94             : 
      95             : /* Read a char field (ie, one ascii character) */
      96             : #define READ_CHAR_FIELD(fldname) \
      97             :     token = pg_strtok(&length);     /* skip :fldname */ \
      98             :     token = pg_strtok(&length);     /* get field value */ \
      99             :     /* avoid overhead of calling debackslash() for one char */ \
     100             :     local_node->fldname = (length == 0) ? '\0' : (token[0] == '\\' ? token[1] : token[0])
     101             : 
     102             : /* Read an enumerated-type field that was written as an integer code */
     103             : #define READ_ENUM_FIELD(fldname, enumtype) \
     104             :     token = pg_strtok(&length);     /* skip :fldname */ \
     105             :     token = pg_strtok(&length);     /* get field value */ \
     106             :     local_node->fldname = (enumtype) atoi(token)
     107             : 
     108             : /* Read a float field */
     109             : #define READ_FLOAT_FIELD(fldname) \
     110             :     token = pg_strtok(&length);     /* skip :fldname */ \
     111             :     token = pg_strtok(&length);     /* get field value */ \
     112             :     local_node->fldname = atof(token)
     113             : 
     114             : /* Read a boolean field */
     115             : #define READ_BOOL_FIELD(fldname) \
     116             :     token = pg_strtok(&length);     /* skip :fldname */ \
     117             :     token = pg_strtok(&length);     /* get field value */ \
     118             :     local_node->fldname = strtobool(token)
     119             : 
     120             : /* Read a character-string field */
     121             : #define READ_STRING_FIELD(fldname) \
     122             :     token = pg_strtok(&length);     /* skip :fldname */ \
     123             :     token = pg_strtok(&length);     /* get field value */ \
     124             :     local_node->fldname = nullable_string(token, length)
     125             : 
     126             : /* Read a parse location field (and possibly throw away the value) */
     127             : #ifdef DEBUG_NODE_TESTS_ENABLED
     128             : #define READ_LOCATION_FIELD(fldname) \
     129             :     token = pg_strtok(&length);     /* skip :fldname */ \
     130             :     token = pg_strtok(&length);     /* get field value */ \
     131             :     local_node->fldname = restore_location_fields ? atoi(token) : -1
     132             : #else
     133             : #define READ_LOCATION_FIELD(fldname) \
     134             :     token = pg_strtok(&length);     /* skip :fldname */ \
     135             :     token = pg_strtok(&length);     /* get field value */ \
     136             :     (void) token;               /* in case not used elsewhere */ \
     137             :     local_node->fldname = -1 /* set field to "unknown" */
     138             : #endif
     139             : 
     140             : /* Read a Node field */
     141             : #define READ_NODE_FIELD(fldname) \
     142             :     token = pg_strtok(&length);     /* skip :fldname */ \
     143             :     (void) token;               /* in case not used elsewhere */ \
     144             :     local_node->fldname = nodeRead(NULL, 0)
     145             : 
     146             : /* Read a bitmapset field */
     147             : #define READ_BITMAPSET_FIELD(fldname) \
     148             :     token = pg_strtok(&length);     /* skip :fldname */ \
     149             :     (void) token;               /* in case not used elsewhere */ \
     150             :     local_node->fldname = _readBitmapset()
     151             : 
     152             : /* Read an attribute number array */
     153             : #define READ_ATTRNUMBER_ARRAY(fldname, len) \
     154             :     token = pg_strtok(&length);     /* skip :fldname */ \
     155             :     local_node->fldname = readAttrNumberCols(len)
     156             : 
     157             : /* Read an oid array */
     158             : #define READ_OID_ARRAY(fldname, len) \
     159             :     token = pg_strtok(&length);     /* skip :fldname */ \
     160             :     local_node->fldname = readOidCols(len)
     161             : 
     162             : /* Read an int array */
     163             : #define READ_INT_ARRAY(fldname, len) \
     164             :     token = pg_strtok(&length);     /* skip :fldname */ \
     165             :     local_node->fldname = readIntCols(len)
     166             : 
     167             : /* Read a bool array */
     168             : #define READ_BOOL_ARRAY(fldname, len) \
     169             :     token = pg_strtok(&length);     /* skip :fldname */ \
     170             :     local_node->fldname = readBoolCols(len)
     171             : 
     172             : /* Routine exit */
     173             : #define READ_DONE() \
     174             :     return local_node
     175             : 
     176             : 
     177             : /*
     178             :  * NOTE: use atoi() to read values written with %d, or atoui() to read
     179             :  * values written with %u in outfuncs.c.  An exception is OID values,
     180             :  * for which use atooid().  (As of 7.1, outfuncs.c writes OIDs as %u,
     181             :  * but this will probably change in the future.)
     182             :  */
     183             : #define atoui(x)  ((unsigned int) strtoul((x), NULL, 10))
     184             : 
     185             : #define strtobool(x)  ((*(x) == 't') ? true : false)
     186             : 
     187             : static char *
     188    19378886 : nullable_string(const char *token, int length)
     189             : {
     190             :     /* outToken emits <> for NULL, and pg_strtok makes that an empty string */
     191    19378886 :     if (length == 0)
     192    10110620 :         return NULL;
     193             :     /* outToken emits "" for empty string */
     194     9268266 :     if (length == 2 && token[0] == '"' && token[1] == '"')
     195         156 :         return pstrdup("");
     196             :     /* otherwise, we must remove protective backslashes added by outToken */
     197     9268110 :     return debackslash(token, length);
     198             : }
     199             : 
     200             : 
     201             : /*
     202             :  * _readBitmapset
     203             :  *
     204             :  * Note: this code is used in contexts where we know that a Bitmapset
     205             :  * is expected.  There is equivalent code in nodeRead() that can read a
     206             :  * Bitmapset when we come across one in other contexts.
     207             :  */
     208             : static Bitmapset *
     209    20105414 : _readBitmapset(void)
     210             : {
     211    20105414 :     Bitmapset  *result = NULL;
     212             : 
     213             :     READ_TEMP_LOCALS();
     214             : 
     215    20105414 :     token = pg_strtok(&length);
     216    20105414 :     if (token == NULL)
     217           0 :         elog(ERROR, "incomplete Bitmapset structure");
     218    20105414 :     if (length != 1 || token[0] != '(')
     219           0 :         elog(ERROR, "unrecognized token: \"%.*s\"", length, token);
     220             : 
     221    20105414 :     token = pg_strtok(&length);
     222    20105414 :     if (token == NULL)
     223           0 :         elog(ERROR, "incomplete Bitmapset structure");
     224    20105414 :     if (length != 1 || token[0] != 'b')
     225           0 :         elog(ERROR, "unrecognized token: \"%.*s\"", length, token);
     226             : 
     227             :     for (;;)
     228     5725150 :     {
     229             :         int         val;
     230             :         char       *endptr;
     231             : 
     232    25830564 :         token = pg_strtok(&length);
     233    25830564 :         if (token == NULL)
     234           0 :             elog(ERROR, "unterminated Bitmapset structure");
     235    25830564 :         if (length == 1 && token[0] == ')')
     236    20105414 :             break;
     237     5725150 :         val = (int) strtol(token, &endptr, 10);
     238     5725150 :         if (endptr != token + length)
     239           0 :             elog(ERROR, "unrecognized integer: \"%.*s\"", length, token);
     240     5725150 :         result = bms_add_member(result, val);
     241             :     }
     242             : 
     243    20105414 :     return result;
     244             : }
     245             : 
     246             : /*
     247             :  * We export this function for use by extensions that define extensible nodes.
     248             :  * That's somewhat historical, though, because calling nodeRead() will work.
     249             :  */
     250             : Bitmapset *
     251           0 : readBitmapset(void)
     252             : {
     253           0 :     return _readBitmapset();
     254             : }
     255             : 
     256             : #include "readfuncs.funcs.c"
     257             : 
     258             : 
     259             : /*
     260             :  * Support functions for nodes with custom_read_write attribute or
     261             :  * special_read_write attribute
     262             :  */
     263             : 
     264             : static Const *
     265     3023420 : _readConst(void)
     266             : {
     267     3023420 :     READ_LOCALS(Const);
     268             : 
     269     3023420 :     READ_OID_FIELD(consttype);
     270     3023420 :     READ_INT_FIELD(consttypmod);
     271     3023420 :     READ_OID_FIELD(constcollid);
     272     3023420 :     READ_INT_FIELD(constlen);
     273     3023420 :     READ_BOOL_FIELD(constbyval);
     274     3023420 :     READ_BOOL_FIELD(constisnull);
     275     3023420 :     READ_LOCATION_FIELD(location);
     276             : 
     277     3023420 :     token = pg_strtok(&length); /* skip :constvalue */
     278     3023420 :     if (local_node->constisnull)
     279      254500 :         token = pg_strtok(&length); /* skip "<>" */
     280             :     else
     281     2768920 :         local_node->constvalue = readDatum(local_node->constbyval);
     282             : 
     283     3023420 :     READ_DONE();
     284             : }
     285             : 
     286             : static BoolExpr *
     287      398222 : _readBoolExpr(void)
     288             : {
     289      398222 :     READ_LOCALS(BoolExpr);
     290             : 
     291             :     /* do-it-yourself enum representation */
     292      398222 :     token = pg_strtok(&length); /* skip :boolop */
     293      398222 :     token = pg_strtok(&length); /* get field value */
     294      398222 :     if (length == 3 && strncmp(token, "and", 3) == 0)
     295      300054 :         local_node->boolop = AND_EXPR;
     296       98168 :     else if (length == 2 && strncmp(token, "or", 2) == 0)
     297       48176 :         local_node->boolop = OR_EXPR;
     298       49992 :     else if (length == 3 && strncmp(token, "not", 3) == 0)
     299       49992 :         local_node->boolop = NOT_EXPR;
     300             :     else
     301           0 :         elog(ERROR, "unrecognized boolop \"%.*s\"", length, token);
     302             : 
     303      398222 :     READ_NODE_FIELD(args);
     304      398222 :     READ_LOCATION_FIELD(location);
     305             : 
     306      398222 :     READ_DONE();
     307             : }
     308             : 
     309             : static A_Const *
     310     1458906 : _readA_Const(void)
     311             : {
     312     1458906 :     READ_LOCALS(A_Const);
     313             : 
     314             :     /* We expect either NULL or :val here */
     315     1458906 :     token = pg_strtok(&length);
     316     1458906 :     if (length == 4 && strncmp(token, "NULL", 4) == 0)
     317       86244 :         local_node->isnull = true;
     318             :     else
     319             :     {
     320     1372662 :         union ValUnion *tmp = nodeRead(NULL, 0);
     321             : 
     322             :         /* To forestall valgrind complaints, copy only the valid data */
     323     1372662 :         switch (nodeTag(tmp))
     324             :         {
     325      434034 :             case T_Integer:
     326      434034 :                 memcpy(&local_node->val, tmp, sizeof(Integer));
     327      434034 :                 break;
     328       11740 :             case T_Float:
     329       11740 :                 memcpy(&local_node->val, tmp, sizeof(Float));
     330       11740 :                 break;
     331       71486 :             case T_Boolean:
     332       71486 :                 memcpy(&local_node->val, tmp, sizeof(Boolean));
     333       71486 :                 break;
     334      851334 :             case T_String:
     335      851334 :                 memcpy(&local_node->val, tmp, sizeof(String));
     336      851334 :                 break;
     337        4068 :             case T_BitString:
     338        4068 :                 memcpy(&local_node->val, tmp, sizeof(BitString));
     339        4068 :                 break;
     340           0 :             default:
     341           0 :                 elog(ERROR, "unrecognized node type: %d",
     342             :                      (int) nodeTag(tmp));
     343             :                 break;
     344             :         }
     345             :     }
     346             : 
     347     1458906 :     READ_LOCATION_FIELD(location);
     348             : 
     349     1458906 :     READ_DONE();
     350             : }
     351             : 
     352             : static RangeTblEntry *
     353     1787364 : _readRangeTblEntry(void)
     354             : {
     355     1787364 :     READ_LOCALS(RangeTblEntry);
     356             : 
     357     1787364 :     READ_NODE_FIELD(alias);
     358     1787364 :     READ_NODE_FIELD(eref);
     359     1787364 :     READ_ENUM_FIELD(rtekind, RTEKind);
     360             : 
     361     1787364 :     switch (local_node->rtekind)
     362             :     {
     363     1075142 :         case RTE_RELATION:
     364     1075142 :             READ_OID_FIELD(relid);
     365     1075142 :             READ_BOOL_FIELD(inh);
     366     1075142 :             READ_CHAR_FIELD(relkind);
     367     1075142 :             READ_INT_FIELD(rellockmode);
     368     1075142 :             READ_UINT_FIELD(perminfoindex);
     369     1075142 :             READ_NODE_FIELD(tablesample);
     370     1075142 :             break;
     371      147164 :         case RTE_SUBQUERY:
     372      147164 :             READ_NODE_FIELD(subquery);
     373      147164 :             READ_BOOL_FIELD(security_barrier);
     374             :             /* we re-use these RELATION fields, too: */
     375      147164 :             READ_OID_FIELD(relid);
     376      147164 :             READ_BOOL_FIELD(inh);
     377      147164 :             READ_CHAR_FIELD(relkind);
     378      147164 :             READ_INT_FIELD(rellockmode);
     379      147164 :             READ_UINT_FIELD(perminfoindex);
     380      147164 :             break;
     381      204804 :         case RTE_JOIN:
     382      204804 :             READ_ENUM_FIELD(jointype, JoinType);
     383      204804 :             READ_INT_FIELD(joinmergedcols);
     384      204804 :             READ_NODE_FIELD(joinaliasvars);
     385      204804 :             READ_NODE_FIELD(joinleftcols);
     386      204804 :             READ_NODE_FIELD(joinrightcols);
     387      204804 :             READ_NODE_FIELD(join_using_alias);
     388      204804 :             break;
     389      114744 :         case RTE_FUNCTION:
     390      114744 :             READ_NODE_FIELD(functions);
     391      114744 :             READ_BOOL_FIELD(funcordinality);
     392      114744 :             break;
     393        1520 :         case RTE_TABLEFUNC:
     394        1520 :             READ_NODE_FIELD(tablefunc);
     395             :             /* The RTE must have a copy of the column type info, if any */
     396        1520 :             if (local_node->tablefunc)
     397             :             {
     398         894 :                 TableFunc  *tf = local_node->tablefunc;
     399             : 
     400         894 :                 local_node->coltypes = tf->coltypes;
     401         894 :                 local_node->coltypmods = tf->coltypmods;
     402         894 :                 local_node->colcollations = tf->colcollations;
     403             :             }
     404        1520 :             break;
     405       22458 :         case RTE_VALUES:
     406       22458 :             READ_NODE_FIELD(values_lists);
     407       22458 :             READ_NODE_FIELD(coltypes);
     408       22458 :             READ_NODE_FIELD(coltypmods);
     409       22458 :             READ_NODE_FIELD(colcollations);
     410       22458 :             break;
     411       12354 :         case RTE_CTE:
     412       12354 :             READ_STRING_FIELD(ctename);
     413       12354 :             READ_UINT_FIELD(ctelevelsup);
     414       12354 :             READ_BOOL_FIELD(self_reference);
     415       12354 :             READ_NODE_FIELD(coltypes);
     416       12354 :             READ_NODE_FIELD(coltypmods);
     417       12354 :             READ_NODE_FIELD(colcollations);
     418       12354 :             break;
     419         936 :         case RTE_NAMEDTUPLESTORE:
     420         936 :             READ_STRING_FIELD(enrname);
     421         936 :             READ_FLOAT_FIELD(enrtuples);
     422         936 :             READ_NODE_FIELD(coltypes);
     423         936 :             READ_NODE_FIELD(coltypmods);
     424         936 :             READ_NODE_FIELD(colcollations);
     425             :             /* we re-use these RELATION fields, too: */
     426         936 :             READ_OID_FIELD(relid);
     427         936 :             break;
     428      197384 :         case RTE_RESULT:
     429             :             /* no extra fields */
     430      197384 :             break;
     431       10858 :         case RTE_GROUP:
     432       10858 :             READ_NODE_FIELD(groupexprs);
     433       10858 :             break;
     434           0 :         default:
     435           0 :             elog(ERROR, "unrecognized RTE kind: %d",
     436             :                  (int) local_node->rtekind);
     437             :             break;
     438             :     }
     439             : 
     440     1787364 :     READ_BOOL_FIELD(lateral);
     441     1787364 :     READ_BOOL_FIELD(inFromCl);
     442     1787364 :     READ_NODE_FIELD(securityQuals);
     443             : 
     444     1787364 :     READ_DONE();
     445             : }
     446             : 
     447             : static A_Expr *
     448      666016 : _readA_Expr(void)
     449             : {
     450      666016 :     READ_LOCALS(A_Expr);
     451             : 
     452      666016 :     token = pg_strtok(&length);
     453             : 
     454      666016 :     if (length == 3 && strncmp(token, "ANY", 3) == 0)
     455             :     {
     456       16912 :         local_node->kind = AEXPR_OP_ANY;
     457       16912 :         READ_NODE_FIELD(name);
     458             :     }
     459      649104 :     else if (length == 3 && strncmp(token, "ALL", 3) == 0)
     460             :     {
     461         144 :         local_node->kind = AEXPR_OP_ALL;
     462         144 :         READ_NODE_FIELD(name);
     463             :     }
     464      648960 :     else if (length == 8 && strncmp(token, "DISTINCT", 8) == 0)
     465             :     {
     466        1254 :         local_node->kind = AEXPR_DISTINCT;
     467        1254 :         READ_NODE_FIELD(name);
     468             :     }
     469      647706 :     else if (length == 12 && strncmp(token, "NOT_DISTINCT", 12) == 0)
     470             :     {
     471          74 :         local_node->kind = AEXPR_NOT_DISTINCT;
     472          74 :         READ_NODE_FIELD(name);
     473             :     }
     474      647632 :     else if (length == 6 && strncmp(token, "NULLIF", 6) == 0)
     475             :     {
     476         692 :         local_node->kind = AEXPR_NULLIF;
     477         692 :         READ_NODE_FIELD(name);
     478             :     }
     479      646940 :     else if (length == 2 && strncmp(token, "IN", 2) == 0)
     480             :     {
     481       28166 :         local_node->kind = AEXPR_IN;
     482       28166 :         READ_NODE_FIELD(name);
     483             :     }
     484      618774 :     else if (length == 4 && strncmp(token, "LIKE", 4) == 0)
     485             :     {
     486        2338 :         local_node->kind = AEXPR_LIKE;
     487        2338 :         READ_NODE_FIELD(name);
     488             :     }
     489      616436 :     else if (length == 5 && strncmp(token, "ILIKE", 5) == 0)
     490             :     {
     491         202 :         local_node->kind = AEXPR_ILIKE;
     492         202 :         READ_NODE_FIELD(name);
     493             :     }
     494      616234 :     else if (length == 7 && strncmp(token, "SIMILAR", 7) == 0)
     495             :     {
     496         118 :         local_node->kind = AEXPR_SIMILAR;
     497         118 :         READ_NODE_FIELD(name);
     498             :     }
     499      616116 :     else if (length == 7 && strncmp(token, "BETWEEN", 7) == 0)
     500             :     {
     501         558 :         local_node->kind = AEXPR_BETWEEN;
     502         558 :         READ_NODE_FIELD(name);
     503             :     }
     504      615558 :     else if (length == 11 && strncmp(token, "NOT_BETWEEN", 11) == 0)
     505             :     {
     506          12 :         local_node->kind = AEXPR_NOT_BETWEEN;
     507          12 :         READ_NODE_FIELD(name);
     508             :     }
     509      615546 :     else if (length == 11 && strncmp(token, "BETWEEN_SYM", 11) == 0)
     510             :     {
     511          12 :         local_node->kind = AEXPR_BETWEEN_SYM;
     512          12 :         READ_NODE_FIELD(name);
     513             :     }
     514      615534 :     else if (length == 15 && strncmp(token, "NOT_BETWEEN_SYM", 15) == 0)
     515             :     {
     516          12 :         local_node->kind = AEXPR_NOT_BETWEEN_SYM;
     517          12 :         READ_NODE_FIELD(name);
     518             :     }
     519      615522 :     else if (length == 5 && strncmp(token, ":name", 5) == 0)
     520             :     {
     521      615522 :         local_node->kind = AEXPR_OP;
     522      615522 :         local_node->name = nodeRead(NULL, 0);
     523             :     }
     524             :     else
     525           0 :         elog(ERROR, "unrecognized A_Expr kind: \"%.*s\"", length, token);
     526             : 
     527      666016 :     READ_NODE_FIELD(lexpr);
     528      666016 :     READ_NODE_FIELD(rexpr);
     529      666016 :     READ_LOCATION_FIELD(rexpr_list_start);
     530      666016 :     READ_LOCATION_FIELD(rexpr_list_end);
     531      666016 :     READ_LOCATION_FIELD(location);
     532             : 
     533      666016 :     READ_DONE();
     534             : }
     535             : 
     536             : static ExtensibleNode *
     537           0 : _readExtensibleNode(void)
     538             : {
     539             :     const ExtensibleNodeMethods *methods;
     540             :     ExtensibleNode *local_node;
     541             :     const char *extnodename;
     542             : 
     543             :     READ_TEMP_LOCALS();
     544             : 
     545           0 :     token = pg_strtok(&length); /* skip :extnodename */
     546           0 :     token = pg_strtok(&length); /* get extnodename */
     547             : 
     548           0 :     extnodename = nullable_string(token, length);
     549           0 :     if (!extnodename)
     550           0 :         elog(ERROR, "extnodename has to be supplied");
     551           0 :     methods = GetExtensibleNodeMethods(extnodename, false);
     552             : 
     553           0 :     local_node = (ExtensibleNode *) newNode(methods->node_size,
     554             :                                             T_ExtensibleNode);
     555           0 :     local_node->extnodename = extnodename;
     556             : 
     557             :     /* deserialize the private fields */
     558           0 :     methods->nodeRead(local_node);
     559             : 
     560           0 :     READ_DONE();
     561             : }
     562             : 
     563             : 
     564             : /*
     565             :  * parseNodeString
     566             :  *
     567             :  * Given a character string representing a node tree, parseNodeString creates
     568             :  * the internal node structure.
     569             :  *
     570             :  * The string to be read must already have been loaded into pg_strtok().
     571             :  */
     572             : Node *
     573    51085742 : parseNodeString(void)
     574             : {
     575             :     READ_TEMP_LOCALS();
     576             : 
     577             :     /* Guard against stack overflow due to overly complex expressions */
     578    51085742 :     check_stack_depth();
     579             : 
     580    51085742 :     token = pg_strtok(&length);
     581             : 
     582             : #define MATCH(tokname, namelen) \
     583             :     (length == namelen && memcmp(token, tokname, namelen) == 0)
     584             : 
     585             : #include "readfuncs.switch.c"
     586             : 
     587           0 :     elog(ERROR, "badly formatted node string \"%.32s\"...", token);
     588             :     return NULL;                /* keep compiler quiet */
     589             : }
     590             : 
     591             : 
     592             : /*
     593             :  * readDatum
     594             :  *
     595             :  * Given a string representation of a constant, recreate the appropriate
     596             :  * Datum.  The string representation embeds length info, but not byValue,
     597             :  * so we must be told that.
     598             :  */
     599             : Datum
     600     2768920 : readDatum(bool typbyval)
     601             : {
     602             :     Size        length,
     603             :                 i;
     604             :     int         tokenLength;
     605             :     const char *token;
     606             :     Datum       res;
     607             :     char       *s;
     608             : 
     609             :     /*
     610             :      * read the actual length of the value
     611             :      */
     612     2768920 :     token = pg_strtok(&tokenLength);
     613     2768920 :     length = atoui(token);
     614             : 
     615     2768920 :     token = pg_strtok(&tokenLength);    /* read the '[' */
     616     2768920 :     if (token == NULL || token[0] != '[')
     617           0 :         elog(ERROR, "expected \"[\" to start datum, but got \"%s\"; length = %zu",
     618             :              token ? token : "[NULL]", length);
     619             : 
     620     2768920 :     if (typbyval)
     621             :     {
     622     1827608 :         if (length > (Size) sizeof(Datum))
     623           0 :             elog(ERROR, "byval datum but length = %zu", length);
     624     1827608 :         res = (Datum) 0;
     625     1827608 :         s = (char *) (&res);
     626    16448472 :         for (i = 0; i < (Size) sizeof(Datum); i++)
     627             :         {
     628    14620864 :             token = pg_strtok(&tokenLength);
     629    14620864 :             s[i] = (char) atoi(token);
     630             :         }
     631             :     }
     632      941312 :     else if (length <= 0)
     633           0 :         res = (Datum) NULL;
     634             :     else
     635             :     {
     636      941312 :         s = (char *) palloc(length);
     637   119800480 :         for (i = 0; i < length; i++)
     638             :         {
     639   118859168 :             token = pg_strtok(&tokenLength);
     640   118859168 :             s[i] = (char) atoi(token);
     641             :         }
     642      941312 :         res = PointerGetDatum(s);
     643             :     }
     644             : 
     645     2768920 :     token = pg_strtok(&tokenLength);    /* read the ']' */
     646     2768920 :     if (token == NULL || token[0] != ']')
     647           0 :         elog(ERROR, "expected \"]\" to end datum, but got \"%s\"; length = %zu",
     648             :              token ? token : "[NULL]", length);
     649             : 
     650     2768920 :     return res;
     651             : }
     652             : 
     653             : /*
     654             :  * common implementation for scalar-array-reading functions
     655             :  *
     656             :  * The data format is either "<>" for a NULL pointer (in which case numCols
     657             :  * is ignored) or "(item item item)" where the number of items must equal
     658             :  * numCols.  The convfunc must be okay with stopping at whitespace or a
     659             :  * right parenthesis, since pg_strtok won't null-terminate the token.
     660             :  */
     661             : #define READ_SCALAR_ARRAY(fnname, datatype, convfunc) \
     662             : datatype * \
     663             : fnname(int numCols) \
     664             : { \
     665             :     datatype   *vals; \
     666             :     READ_TEMP_LOCALS(); \
     667             :     token = pg_strtok(&length); \
     668             :     if (token == NULL) \
     669             :         elog(ERROR, "incomplete scalar array"); \
     670             :     if (length == 0) \
     671             :         return NULL;            /* it was "<>", so return NULL pointer */ \
     672             :     if (length != 1 || token[0] != '(') \
     673             :         elog(ERROR, "unrecognized token: \"%.*s\"", length, token); \
     674             :     vals = (datatype *) palloc(numCols * sizeof(datatype)); \
     675             :     for (int i = 0; i < numCols; i++) \
     676             :     { \
     677             :         token = pg_strtok(&length); \
     678             :         if (token == NULL || token[0] == ')') \
     679             :             elog(ERROR, "incomplete scalar array"); \
     680             :         vals[i] = convfunc(token); \
     681             :     } \
     682             :     token = pg_strtok(&length); \
     683             :     if (token == NULL || length != 1 || token[0] != ')') \
     684             :         elog(ERROR, "incomplete scalar array"); \
     685             :     return vals; \
     686             : }
     687             : 
     688             : /*
     689             :  * Note: these functions are exported in nodes.h for possible use by
     690             :  * extensions, so don't mess too much with their names or API.
     691             :  */
     692      479078 : READ_SCALAR_ARRAY(readAttrNumberCols, int16, atoi)
     693      647796 : READ_SCALAR_ARRAY(readOidCols, Oid, atooid)
     694             : /* outfuncs.c has writeIndexCols, but we don't yet need that here */
     695             : /* READ_SCALAR_ARRAY(readIndexCols, Index, atoui) */
     696       16128 : READ_SCALAR_ARRAY(readIntCols, int, atoi)
     697      245416 : READ_SCALAR_ARRAY(readBoolCols, bool, strtobool)

Generated by: LCOV version 1.16