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

Generated by: LCOV version 1.16