LCOV - code coverage report
Current view: top level - src/backend/nodes - readfuncs.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 88.7 % 265 235
Test Date: 2026-03-20 03:16:04 Functions: 86.7 % 15 13
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     12922302 : nullable_string(const char *token, int length)
     187              : {
     188              :     /* outToken emits <> for NULL, and pg_strtok makes that an empty string */
     189     12922302 :     if (length == 0)
     190      6686680 :         return NULL;
     191              :     /* outToken emits "" for empty string */
     192      6235622 :     if (length == 2 && token[0] == '"' && token[1] == '"')
     193          122 :         return pstrdup("");
     194              :     /* otherwise, we must remove protective backslashes added by outToken */
     195      6235500 :     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     13904783 : _readBitmapset(void)
     208              : {
     209     13904783 :     Bitmapset  *result = NULL;
     210              : 
     211              :     READ_TEMP_LOCALS();
     212              : 
     213     13904783 :     token = pg_strtok(&length);
     214     13904783 :     if (token == NULL)
     215            0 :         elog(ERROR, "incomplete Bitmapset structure");
     216     13904783 :     if (length != 1 || token[0] != '(')
     217            0 :         elog(ERROR, "unrecognized token: \"%.*s\"", length, token);
     218              : 
     219     13904783 :     token = pg_strtok(&length);
     220     13904783 :     if (token == NULL)
     221            0 :         elog(ERROR, "incomplete Bitmapset structure");
     222     13904783 :     if (length != 1 || token[0] != 'b')
     223            0 :         elog(ERROR, "unrecognized token: \"%.*s\"", length, token);
     224              : 
     225              :     for (;;)
     226      3983362 :     {
     227              :         int         val;
     228              :         char       *endptr;
     229              : 
     230     17888145 :         token = pg_strtok(&length);
     231     17888145 :         if (token == NULL)
     232            0 :             elog(ERROR, "unterminated Bitmapset structure");
     233     17888145 :         if (length == 1 && token[0] == ')')
     234     13904783 :             break;
     235      3983362 :         val = (int) strtol(token, &endptr, 10);
     236      3983362 :         if (endptr != token + length)
     237            0 :             elog(ERROR, "unrecognized integer: \"%.*s\"", length, token);
     238      3983362 :         result = bms_add_member(result, val);
     239              :     }
     240              : 
     241     13904783 :     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      2025271 : _readConst(void)
     264              : {
     265      2025271 :     READ_LOCALS(Const);
     266              : 
     267      2025271 :     READ_OID_FIELD(consttype);
     268      2025271 :     READ_INT_FIELD(consttypmod);
     269      2025271 :     READ_OID_FIELD(constcollid);
     270      2025271 :     READ_INT_FIELD(constlen);
     271      2025271 :     READ_BOOL_FIELD(constbyval);
     272      2025271 :     READ_BOOL_FIELD(constisnull);
     273      2025271 :     READ_LOCATION_FIELD(location);
     274              : 
     275      2025271 :     token = pg_strtok(&length); /* skip :constvalue */
     276      2025271 :     if (local_node->constisnull)
     277       190915 :         token = pg_strtok(&length); /* skip "<>" */
     278              :     else
     279      1834356 :         local_node->constvalue = readDatum(local_node->constbyval);
     280              : 
     281      2025271 :     READ_DONE();
     282              : }
     283              : 
     284              : static BoolExpr *
     285       293783 : _readBoolExpr(void)
     286              : {
     287       293783 :     READ_LOCALS(BoolExpr);
     288              : 
     289              :     /* do-it-yourself enum representation */
     290       293783 :     token = pg_strtok(&length); /* skip :boolop */
     291       293783 :     token = pg_strtok(&length); /* get field value */
     292       293783 :     if (length == 3 && strncmp(token, "and", 3) == 0)
     293       208734 :         local_node->boolop = AND_EXPR;
     294        85049 :     else if (length == 2 && strncmp(token, "or", 2) == 0)
     295        39421 :         local_node->boolop = OR_EXPR;
     296        45628 :     else if (length == 3 && strncmp(token, "not", 3) == 0)
     297        45628 :         local_node->boolop = NOT_EXPR;
     298              :     else
     299            0 :         elog(ERROR, "unrecognized boolop \"%.*s\"", length, token);
     300              : 
     301       293783 :     READ_NODE_FIELD(args);
     302       293783 :     READ_LOCATION_FIELD(location);
     303              : 
     304       293783 :     READ_DONE();
     305              : }
     306              : 
     307              : static A_Const *
     308       919877 : _readA_Const(void)
     309              : {
     310       919877 :     READ_LOCALS(A_Const);
     311              : 
     312              :     /* We expect either NULL or :val here */
     313       919877 :     token = pg_strtok(&length);
     314       919877 :     if (length == 4 && strncmp(token, "NULL", 4) == 0)
     315        51555 :         local_node->isnull = true;
     316              :     else
     317              :     {
     318       868322 :         union ValUnion *tmp = nodeRead(NULL, 0);
     319              : 
     320              :         /* To forestall valgrind complaints, copy only the valid data */
     321       868322 :         switch (nodeTag(tmp))
     322              :         {
     323       286988 :             case T_Integer:
     324       286988 :                 memcpy(&local_node->val, tmp, sizeof(Integer));
     325       286988 :                 break;
     326         7605 :             case T_Float:
     327         7605 :                 memcpy(&local_node->val, tmp, sizeof(Float));
     328         7605 :                 break;
     329        39844 :             case T_Boolean:
     330        39844 :                 memcpy(&local_node->val, tmp, sizeof(Boolean));
     331        39844 :                 break;
     332       531158 :             case T_String:
     333       531158 :                 memcpy(&local_node->val, tmp, sizeof(String));
     334       531158 :                 break;
     335         2727 :             case T_BitString:
     336         2727 :                 memcpy(&local_node->val, tmp, sizeof(BitString));
     337         2727 :                 break;
     338            0 :             default:
     339            0 :                 elog(ERROR, "unrecognized node type: %d",
     340              :                      (int) nodeTag(tmp));
     341              :                 break;
     342              :         }
     343              :     }
     344              : 
     345       919877 :     READ_LOCATION_FIELD(location);
     346              : 
     347       919877 :     READ_DONE();
     348              : }
     349              : 
     350              : static RangeTblEntry *
     351      1221606 : _readRangeTblEntry(void)
     352              : {
     353      1221606 :     READ_LOCALS(RangeTblEntry);
     354              : 
     355      1221606 :     READ_NODE_FIELD(alias);
     356      1221606 :     READ_NODE_FIELD(eref);
     357      1221606 :     READ_ENUM_FIELD(rtekind, RTEKind);
     358              : 
     359      1221606 :     switch (local_node->rtekind)
     360              :     {
     361       730247 :         case RTE_RELATION:
     362       730247 :             READ_OID_FIELD(relid);
     363       730247 :             READ_BOOL_FIELD(inh);
     364       730247 :             READ_CHAR_FIELD(relkind);
     365       730247 :             READ_INT_FIELD(rellockmode);
     366       730247 :             READ_UINT_FIELD(perminfoindex);
     367       730247 :             READ_NODE_FIELD(tablesample);
     368       730247 :             break;
     369       117074 :         case RTE_SUBQUERY:
     370       117074 :             READ_NODE_FIELD(subquery);
     371       117074 :             READ_BOOL_FIELD(security_barrier);
     372              :             /* we re-use these RELATION fields, too: */
     373       117074 :             READ_OID_FIELD(relid);
     374       117074 :             READ_BOOL_FIELD(inh);
     375       117074 :             READ_CHAR_FIELD(relkind);
     376       117074 :             READ_INT_FIELD(rellockmode);
     377       117074 :             READ_UINT_FIELD(perminfoindex);
     378       117074 :             break;
     379       149234 :         case RTE_JOIN:
     380       149234 :             READ_ENUM_FIELD(jointype, JoinType);
     381       149234 :             READ_INT_FIELD(joinmergedcols);
     382       149234 :             READ_NODE_FIELD(joinaliasvars);
     383       149234 :             READ_NODE_FIELD(joinleftcols);
     384       149234 :             READ_NODE_FIELD(joinrightcols);
     385       149234 :             READ_NODE_FIELD(join_using_alias);
     386       149234 :             break;
     387        69253 :         case RTE_FUNCTION:
     388        69253 :             READ_NODE_FIELD(functions);
     389        69253 :             READ_BOOL_FIELD(funcordinality);
     390        69253 :             break;
     391          982 :         case RTE_TABLEFUNC:
     392          982 :             READ_NODE_FIELD(tablefunc);
     393              :             /* The RTE must have a copy of the column type info, if any */
     394          982 :             if (local_node->tablefunc)
     395              :             {
     396          566 :                 TableFunc  *tf = local_node->tablefunc;
     397              : 
     398          566 :                 local_node->coltypes = tf->coltypes;
     399          566 :                 local_node->coltypmods = tf->coltypmods;
     400          566 :                 local_node->colcollations = tf->colcollations;
     401              :             }
     402          982 :             break;
     403        15030 :         case RTE_VALUES:
     404        15030 :             READ_NODE_FIELD(values_lists);
     405        15030 :             READ_NODE_FIELD(coltypes);
     406        15030 :             READ_NODE_FIELD(coltypmods);
     407        15030 :             READ_NODE_FIELD(colcollations);
     408        15030 :             break;
     409         7992 :         case RTE_CTE:
     410         7992 :             READ_STRING_FIELD(ctename);
     411         7992 :             READ_UINT_FIELD(ctelevelsup);
     412         7992 :             READ_BOOL_FIELD(self_reference);
     413         7992 :             READ_NODE_FIELD(coltypes);
     414         7992 :             READ_NODE_FIELD(coltypmods);
     415         7992 :             READ_NODE_FIELD(colcollations);
     416         7992 :             break;
     417          628 :         case RTE_NAMEDTUPLESTORE:
     418          628 :             READ_STRING_FIELD(enrname);
     419          628 :             READ_FLOAT_FIELD(enrtuples);
     420          628 :             READ_NODE_FIELD(coltypes);
     421          628 :             READ_NODE_FIELD(coltypmods);
     422          628 :             READ_NODE_FIELD(colcollations);
     423              :             /* we re-use these RELATION fields, too: */
     424          628 :             READ_OID_FIELD(relid);
     425          628 :             break;
     426           85 :         case RTE_GRAPH_TABLE:
     427           85 :             READ_NODE_FIELD(graph_pattern);
     428           85 :             READ_NODE_FIELD(graph_table_columns);
     429              :             /* we re-use these RELATION fields, too: */
     430           85 :             READ_OID_FIELD(relid);
     431           85 :             READ_CHAR_FIELD(relkind);
     432           85 :             READ_INT_FIELD(rellockmode);
     433           85 :             READ_UINT_FIELD(perminfoindex);
     434           85 :             break;
     435       123374 :         case RTE_RESULT:
     436              :             /* no extra fields */
     437       123374 :             break;
     438         7707 :         case RTE_GROUP:
     439         7707 :             READ_NODE_FIELD(groupexprs);
     440         7707 :             break;
     441            0 :         default:
     442            0 :             elog(ERROR, "unrecognized RTE kind: %d",
     443              :                  (int) local_node->rtekind);
     444              :             break;
     445              :     }
     446              : 
     447      1221606 :     READ_BOOL_FIELD(lateral);
     448      1221606 :     READ_BOOL_FIELD(inFromCl);
     449      1221606 :     READ_NODE_FIELD(securityQuals);
     450              : 
     451      1221606 :     READ_DONE();
     452              : }
     453              : 
     454              : static A_Expr *
     455       422892 : _readA_Expr(void)
     456              : {
     457       422892 :     READ_LOCALS(A_Expr);
     458              : 
     459       422892 :     token = pg_strtok(&length);
     460              : 
     461       422892 :     if (length == 3 && strncmp(token, "ANY", 3) == 0)
     462              :     {
     463        10904 :         local_node->kind = AEXPR_OP_ANY;
     464        10904 :         READ_NODE_FIELD(name);
     465              :     }
     466       411988 :     else if (length == 3 && strncmp(token, "ALL", 3) == 0)
     467              :     {
     468           96 :         local_node->kind = AEXPR_OP_ALL;
     469           96 :         READ_NODE_FIELD(name);
     470              :     }
     471       411892 :     else if (length == 8 && strncmp(token, "DISTINCT", 8) == 0)
     472              :     {
     473          778 :         local_node->kind = AEXPR_DISTINCT;
     474          778 :         READ_NODE_FIELD(name);
     475              :     }
     476       411114 :     else if (length == 12 && strncmp(token, "NOT_DISTINCT", 12) == 0)
     477              :     {
     478           88 :         local_node->kind = AEXPR_NOT_DISTINCT;
     479           88 :         READ_NODE_FIELD(name);
     480              :     }
     481       411026 :     else if (length == 6 && strncmp(token, "NULLIF", 6) == 0)
     482              :     {
     483          443 :         local_node->kind = AEXPR_NULLIF;
     484          443 :         READ_NODE_FIELD(name);
     485              :     }
     486       410583 :     else if (length == 2 && strncmp(token, "IN", 2) == 0)
     487              :     {
     488        16182 :         local_node->kind = AEXPR_IN;
     489        16182 :         READ_NODE_FIELD(name);
     490              :     }
     491       394401 :     else if (length == 4 && strncmp(token, "LIKE", 4) == 0)
     492              :     {
     493         1508 :         local_node->kind = AEXPR_LIKE;
     494         1508 :         READ_NODE_FIELD(name);
     495              :     }
     496       392893 :     else if (length == 5 && strncmp(token, "ILIKE", 5) == 0)
     497              :     {
     498          132 :         local_node->kind = AEXPR_ILIKE;
     499          132 :         READ_NODE_FIELD(name);
     500              :     }
     501       392761 :     else if (length == 7 && strncmp(token, "SIMILAR", 7) == 0)
     502              :     {
     503           82 :         local_node->kind = AEXPR_SIMILAR;
     504           82 :         READ_NODE_FIELD(name);
     505              :     }
     506       392679 :     else if (length == 7 && strncmp(token, "BETWEEN", 7) == 0)
     507              :     {
     508          368 :         local_node->kind = AEXPR_BETWEEN;
     509          368 :         READ_NODE_FIELD(name);
     510              :     }
     511       392311 :     else if (length == 11 && strncmp(token, "NOT_BETWEEN", 11) == 0)
     512              :     {
     513            8 :         local_node->kind = AEXPR_NOT_BETWEEN;
     514            8 :         READ_NODE_FIELD(name);
     515              :     }
     516       392303 :     else if (length == 11 && strncmp(token, "BETWEEN_SYM", 11) == 0)
     517              :     {
     518            8 :         local_node->kind = AEXPR_BETWEEN_SYM;
     519            8 :         READ_NODE_FIELD(name);
     520              :     }
     521       392295 :     else if (length == 15 && strncmp(token, "NOT_BETWEEN_SYM", 15) == 0)
     522              :     {
     523            8 :         local_node->kind = AEXPR_NOT_BETWEEN_SYM;
     524            8 :         READ_NODE_FIELD(name);
     525              :     }
     526       392287 :     else if (length == 5 && strncmp(token, ":name", 5) == 0)
     527              :     {
     528       392287 :         local_node->kind = AEXPR_OP;
     529       392287 :         local_node->name = nodeRead(NULL, 0);
     530              :     }
     531              :     else
     532            0 :         elog(ERROR, "unrecognized A_Expr kind: \"%.*s\"", length, token);
     533              : 
     534       422892 :     READ_NODE_FIELD(lexpr);
     535       422892 :     READ_NODE_FIELD(rexpr);
     536       422892 :     READ_LOCATION_FIELD(rexpr_list_start);
     537       422892 :     READ_LOCATION_FIELD(rexpr_list_end);
     538       422892 :     READ_LOCATION_FIELD(location);
     539              : 
     540       422892 :     READ_DONE();
     541              : }
     542              : 
     543              : static ExtensibleNode *
     544            0 : _readExtensibleNode(void)
     545              : {
     546              :     const ExtensibleNodeMethods *methods;
     547              :     ExtensibleNode *local_node;
     548              :     const char *extnodename;
     549              : 
     550              :     READ_TEMP_LOCALS();
     551              : 
     552            0 :     token = pg_strtok(&length); /* skip :extnodename */
     553            0 :     token = pg_strtok(&length); /* get extnodename */
     554              : 
     555            0 :     extnodename = nullable_string(token, length);
     556            0 :     if (!extnodename)
     557            0 :         elog(ERROR, "extnodename has to be supplied");
     558            0 :     methods = GetExtensibleNodeMethods(extnodename, false);
     559              : 
     560            0 :     local_node = (ExtensibleNode *) newNode(methods->node_size,
     561              :                                             T_ExtensibleNode);
     562            0 :     local_node->extnodename = extnodename;
     563              : 
     564              :     /* deserialize the private fields */
     565            0 :     methods->nodeRead(local_node);
     566              : 
     567            0 :     READ_DONE();
     568              : }
     569              : 
     570              : 
     571              : /*
     572              :  * parseNodeString
     573              :  *
     574              :  * Given a character string representing a node tree, parseNodeString creates
     575              :  * the internal node structure.
     576              :  *
     577              :  * The string to be read must already have been loaded into pg_strtok().
     578              :  */
     579              : Node *
     580     34157042 : parseNodeString(void)
     581              : {
     582              :     READ_TEMP_LOCALS();
     583              : 
     584              :     /* Guard against stack overflow due to overly complex expressions */
     585     34157042 :     check_stack_depth();
     586              : 
     587     34157042 :     token = pg_strtok(&length);
     588              : 
     589              : #define MATCH(tokname, namelen) \
     590              :     (length == namelen && memcmp(token, tokname, namelen) == 0)
     591              : 
     592              : #include "readfuncs.switch.c"
     593              : 
     594            0 :     elog(ERROR, "badly formatted node string \"%.32s\"...", token);
     595              :     return NULL;                /* keep compiler quiet */
     596              : }
     597              : 
     598              : 
     599              : /*
     600              :  * readDatum
     601              :  *
     602              :  * Given a string representation of a constant, recreate the appropriate
     603              :  * Datum.  The string representation embeds length info, but not byValue,
     604              :  * so we must be told that.
     605              :  */
     606              : Datum
     607      1834356 : readDatum(bool typbyval)
     608              : {
     609              :     Size        length;
     610              :     int         tokenLength;
     611              :     const char *token;
     612              :     Datum       res;
     613              :     char       *s;
     614              : 
     615              :     /*
     616              :      * read the actual length of the value
     617              :      */
     618      1834356 :     token = pg_strtok(&tokenLength);
     619      1834356 :     length = atoui(token);
     620              : 
     621      1834356 :     token = pg_strtok(&tokenLength);    /* read the '[' */
     622      1834356 :     if (token == NULL || token[0] != '[')
     623            0 :         elog(ERROR, "expected \"[\" to start datum, but got \"%s\"; length = %zu",
     624              :              token ? token : "[NULL]", length);
     625              : 
     626      1834356 :     if (typbyval)
     627              :     {
     628      1215069 :         if (length > (Size) sizeof(Datum))
     629            0 :             elog(ERROR, "byval datum but length = %zu", length);
     630      1215069 :         res = (Datum) 0;
     631      1215069 :         s = (char *) (&res);
     632     10935621 :         for (Size i = 0; i < (Size) sizeof(Datum); i++)
     633              :         {
     634      9720552 :             token = pg_strtok(&tokenLength);
     635      9720552 :             s[i] = (char) atoi(token);
     636              :         }
     637              :     }
     638       619287 :     else if (length <= 0)
     639            0 :         res = (Datum) 0;
     640              :     else
     641              :     {
     642       619287 :         s = (char *) palloc(length);
     643     78165473 :         for (Size i = 0; i < length; i++)
     644              :         {
     645     77546186 :             token = pg_strtok(&tokenLength);
     646     77546186 :             s[i] = (char) atoi(token);
     647              :         }
     648       619287 :         res = PointerGetDatum(s);
     649              :     }
     650              : 
     651      1834356 :     token = pg_strtok(&tokenLength);    /* read the ']' */
     652      1834356 :     if (token == NULL || token[0] != ']')
     653            0 :         elog(ERROR, "expected \"]\" to end datum, but got \"%s\"; length = %zu",
     654              :              token ? token : "[NULL]", length);
     655              : 
     656      1834356 :     return res;
     657              : }
     658              : 
     659              : /*
     660              :  * common implementation for scalar-array-reading functions
     661              :  *
     662              :  * The data format is either "<>" for a NULL pointer (in which case numCols
     663              :  * is ignored) or "(item item item)" where the number of items must equal
     664              :  * numCols.  The convfunc must be okay with stopping at whitespace or a
     665              :  * right parenthesis, since pg_strtok won't null-terminate the token.
     666              :  */
     667              : #define READ_SCALAR_ARRAY(fnname, datatype, convfunc) \
     668              : datatype * \
     669              : fnname(int numCols) \
     670              : { \
     671              :     datatype   *vals; \
     672              :     READ_TEMP_LOCALS(); \
     673              :     token = pg_strtok(&length); \
     674              :     if (token == NULL) \
     675              :         elog(ERROR, "incomplete scalar array"); \
     676              :     if (length == 0) \
     677              :         return NULL;            /* it was "<>", so return NULL pointer */ \
     678              :     if (length != 1 || token[0] != '(') \
     679              :         elog(ERROR, "unrecognized token: \"%.*s\"", length, token); \
     680              :     vals = (datatype *) palloc(numCols * sizeof(datatype)); \
     681              :     for (int i = 0; i < numCols; i++) \
     682              :     { \
     683              :         token = pg_strtok(&length); \
     684              :         if (token == NULL || token[0] == ')') \
     685              :             elog(ERROR, "incomplete scalar array"); \
     686              :         vals[i] = convfunc(token); \
     687              :     } \
     688              :     token = pg_strtok(&length); \
     689              :     if (token == NULL || length != 1 || token[0] != ')') \
     690              :         elog(ERROR, "incomplete scalar array"); \
     691              :     return vals; \
     692              : }
     693              : 
     694              : /*
     695              :  * Note: these functions are exported in nodes.h for possible use by
     696              :  * extensions, so don't mess too much with their names or API.
     697              :  */
     698       366434 : READ_SCALAR_ARRAY(readAttrNumberCols, int16, atoi)
     699       446771 : READ_SCALAR_ARRAY(readOidCols, Oid, atooid)
     700              : /* outfuncs.c has writeIndexCols, but we don't yet need that here */
     701              : /* READ_SCALAR_ARRAY(readIndexCols, Index, atoui) */
     702        10935 : READ_SCALAR_ARRAY(readIntCols, int, atoi)
     703       164701 : READ_SCALAR_ARRAY(readBoolCols, bool, strtobool)
        

Generated by: LCOV version 2.0-1