LCOV - code coverage report
Current view: top level - src/backend/nodes - outfuncs.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 81.5 % 378 308
Test Date: 2026-07-08 05:15:38 Functions: 80.0 % 30 24
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 81.0 % 606 491

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * outfuncs.c
       4                 :             :  *    Output 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/outfuncs.c
      12                 :             :  *
      13                 :             :  *-------------------------------------------------------------------------
      14                 :             :  */
      15                 :             : #include "postgres.h"
      16                 :             : 
      17                 :             : #include <ctype.h>
      18                 :             : 
      19                 :             : #include "access/attnum.h"
      20                 :             : #include "common/shortest_dec.h"
      21                 :             : #include "lib/stringinfo.h"
      22                 :             : #include "miscadmin.h"
      23                 :             : #include "nodes/bitmapset.h"
      24                 :             : #include "nodes/nodes.h"
      25                 :             : #include "nodes/pg_list.h"
      26                 :             : #include "utils/datum.h"
      27                 :             : 
      28                 :             : /* State flag that determines how nodeToStringInternal() should treat location fields */
      29                 :             : static bool write_location_fields = false;
      30                 :             : 
      31                 :             : static void outChar(StringInfo str, char c);
      32                 :             : static void outDouble(StringInfo str, double d);
      33                 :             : 
      34                 :             : 
      35                 :             : /*
      36                 :             :  * Macros to simplify output of different kinds of fields.  Use these
      37                 :             :  * wherever possible to reduce the chance for silly typos.  Note that these
      38                 :             :  * hard-wire conventions about the names of the local variables in an Out
      39                 :             :  * routine.
      40                 :             :  */
      41                 :             : 
      42                 :             : /* Write the label for the node type */
      43                 :             : #define WRITE_NODE_TYPE(nodelabel) \
      44                 :             :     appendStringInfoString(str, nodelabel)
      45                 :             : 
      46                 :             : /* Write an integer field (anything written as ":fldname %d") */
      47                 :             : #define WRITE_INT_FIELD(fldname) \
      48                 :             :     appendStringInfo(str, " :" CppAsString(fldname) " %d", node->fldname)
      49                 :             : 
      50                 :             : /* Write an unsigned integer field (anything written as ":fldname %u") */
      51                 :             : #define WRITE_UINT_FIELD(fldname) \
      52                 :             :     appendStringInfo(str, " :" CppAsString(fldname) " %u", node->fldname)
      53                 :             : 
      54                 :             : /* Write a signed integer field (anything written with INT64_FORMAT) */
      55                 :             : #define WRITE_INT64_FIELD(fldname) \
      56                 :             :     appendStringInfo(str, \
      57                 :             :                      " :" CppAsString(fldname) " " INT64_FORMAT, \
      58                 :             :                      node->fldname)
      59                 :             : 
      60                 :             : /* Write an unsigned integer field (anything written with UINT64_FORMAT) */
      61                 :             : #define WRITE_UINT64_FIELD(fldname) \
      62                 :             :     appendStringInfo(str, " :" CppAsString(fldname) " " UINT64_FORMAT, \
      63                 :             :                      node->fldname)
      64                 :             : 
      65                 :             : /* Write an OID field (don't hard-wire assumption that OID is same as uint) */
      66                 :             : #define WRITE_OID_FIELD(fldname) \
      67                 :             :     appendStringInfo(str, " :" CppAsString(fldname) " %u", node->fldname)
      68                 :             : 
      69                 :             : /* Write a long-integer field */
      70                 :             : #define WRITE_LONG_FIELD(fldname) \
      71                 :             :     appendStringInfo(str, " :" CppAsString(fldname) " %ld", node->fldname)
      72                 :             : 
      73                 :             : /* Write a char field (ie, one ascii character) */
      74                 :             : #define WRITE_CHAR_FIELD(fldname) \
      75                 :             :     (appendStringInfo(str, " :" CppAsString(fldname) " "), \
      76                 :             :      outChar(str, node->fldname))
      77                 :             : 
      78                 :             : /* Write an enumerated-type field as an integer code */
      79                 :             : #define WRITE_ENUM_FIELD(fldname, enumtype) \
      80                 :             :     appendStringInfo(str, " :" CppAsString(fldname) " %d", \
      81                 :             :                      (int) node->fldname)
      82                 :             : 
      83                 :             : /* Write a float field (actually, they're double) */
      84                 :             : #define WRITE_FLOAT_FIELD(fldname) \
      85                 :             :     (appendStringInfo(str, " :" CppAsString(fldname) " "), \
      86                 :             :      outDouble(str, node->fldname))
      87                 :             : 
      88                 :             : /* Write a boolean field */
      89                 :             : #define WRITE_BOOL_FIELD(fldname) \
      90                 :             :     appendStringInfo(str, " :" CppAsString(fldname) " %s", \
      91                 :             :                      booltostr(node->fldname))
      92                 :             : 
      93                 :             : /* Write a character-string (possibly NULL) field */
      94                 :             : #define WRITE_STRING_FIELD(fldname) \
      95                 :             :     (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
      96                 :             :      outToken(str, node->fldname))
      97                 :             : 
      98                 :             : /* Write a parse location field (actually same as INT case) */
      99                 :             : #define WRITE_LOCATION_FIELD(fldname) \
     100                 :             :     appendStringInfo(str, " :" CppAsString(fldname) " %d", write_location_fields ? node->fldname : -1)
     101                 :             : 
     102                 :             : /* Write a Node field */
     103                 :             : #define WRITE_NODE_FIELD(fldname) \
     104                 :             :     (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
     105                 :             :      outNode(str, node->fldname))
     106                 :             : 
     107                 :             : /* Write a bitmapset field */
     108                 :             : #define WRITE_BITMAPSET_FIELD(fldname) \
     109                 :             :     (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
     110                 :             :      outBitmapset(str, node->fldname))
     111                 :             : 
     112                 :             : /* Write a variable-length array (not a List) of Node pointers */
     113                 :             : #define WRITE_NODE_ARRAY(fldname, len) \
     114                 :             :     (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
     115                 :             :      writeNodeArray(str, (const Node * const *) node->fldname, len))
     116                 :             : 
     117                 :             : /* Write a variable-length array of AttrNumber */
     118                 :             : #define WRITE_ATTRNUMBER_ARRAY(fldname, len) \
     119                 :             :     (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
     120                 :             :      writeAttrNumberCols(str, node->fldname, len))
     121                 :             : 
     122                 :             : /* Write a variable-length array of Oid */
     123                 :             : #define WRITE_OID_ARRAY(fldname, len) \
     124                 :             :     (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
     125                 :             :      writeOidCols(str, node->fldname, len))
     126                 :             : 
     127                 :             : /* Write a variable-length array of Index */
     128                 :             : #define WRITE_INDEX_ARRAY(fldname, len) \
     129                 :             :     (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
     130                 :             :      writeIndexCols(str, node->fldname, len))
     131                 :             : 
     132                 :             : /* Write a variable-length array of int */
     133                 :             : #define WRITE_INT_ARRAY(fldname, len) \
     134                 :             :     (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
     135                 :             :      writeIntCols(str, node->fldname, len))
     136                 :             : 
     137                 :             : /* Write a variable-length array of bool */
     138                 :             : #define WRITE_BOOL_ARRAY(fldname, len) \
     139                 :             :     (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
     140                 :             :      writeBoolCols(str, node->fldname, len))
     141                 :             : 
     142                 :             : #define booltostr(x)  ((x) ? "true" : "false")
     143                 :             : 
     144                 :             : 
     145                 :             : /*
     146                 :             :  * outToken
     147                 :             :  *    Convert an ordinary string (eg, an identifier) into a form that
     148                 :             :  *    will be decoded back to a plain token by read.c's functions.
     149                 :             :  *
     150                 :             :  *    If a null string pointer is given, it is encoded as '<>'.
     151                 :             :  *    An empty string is encoded as '""'.  To avoid ambiguity, input
     152                 :             :  *    strings beginning with '<' or '"' receive a leading backslash.
     153                 :             :  */
     154                 :             : void
     155                 :    32298319 : outToken(StringInfo str, const char *s)
     156                 :             : {
     157         [ +  + ]:    32298319 :     if (s == NULL)
     158                 :             :     {
     159                 :     6630891 :         appendStringInfoString(str, "<>");
     160                 :     6630891 :         return;
     161                 :             :     }
     162         [ +  + ]:    25667428 :     if (*s == '\0')
     163                 :             :     {
     164                 :         124 :         appendStringInfoString(str, "\"\"");
     165                 :         124 :         return;
     166                 :             :     }
     167                 :             : 
     168                 :             :     /*
     169                 :             :      * Look for characters or patterns that are treated specially by read.c
     170                 :             :      * (either in pg_strtok() or in nodeRead()), and therefore need a
     171                 :             :      * protective backslash.
     172                 :             :      */
     173                 :             :     /* These characters only need to be quoted at the start of the string */
     174         [ +  + ]:    25667304 :     if (*s == '<' ||
     175         [ +  + ]:    25625541 :         *s == '"' ||
     176         [ +  + ]:    25621594 :         isdigit((unsigned char) *s) ||
     177   [ +  +  +  + ]:    25497058 :         ((*s == '+' || *s == '-') &&
     178   [ +  +  +  + ]:       20576 :          (isdigit((unsigned char) s[1]) || s[1] == '.')))
     179                 :      173642 :         appendStringInfoChar(str, '\\');
     180         [ +  + ]:   233103629 :     while (*s)
     181                 :             :     {
     182                 :             :         /* These chars must be backslashed anywhere in the string */
     183   [ +  +  +  +  :   207436325 :         if (*s == ' ' || *s == '\n' || *s == '\t' ||
                   +  + ]
     184   [ +  +  +  +  :   206674215 :             *s == '(' || *s == ')' || *s == '{' || *s == '}' ||
             +  +  +  + ]
     185         [ +  + ]:   206231922 :             *s == '\\')
     186                 :     1212048 :             appendStringInfoChar(str, '\\');
     187                 :   207436325 :         appendStringInfoChar(str, *s++);
     188                 :             :     }
     189                 :             : }
     190                 :             : 
     191                 :             : /*
     192                 :             :  * Convert one char.  Goes through outToken() so that special characters are
     193                 :             :  * escaped.
     194                 :             :  */
     195                 :             : static void
     196                 :     1988871 : outChar(StringInfo str, char c)
     197                 :             : {
     198                 :             :     char        in[2];
     199                 :             : 
     200                 :             :     /* Traditionally, we've represented \0 as <>, so keep doing that */
     201         [ +  + ]:     1988871 :     if (c == '\0')
     202                 :             :     {
     203                 :      601034 :         appendStringInfoString(str, "<>");
     204                 :      601034 :         return;
     205                 :             :     }
     206                 :             : 
     207                 :     1387837 :     in[0] = c;
     208                 :     1387837 :     in[1] = '\0';
     209                 :             : 
     210                 :     1387837 :     outToken(str, in);
     211                 :             : }
     212                 :             : 
     213                 :             : /*
     214                 :             :  * Convert a double value, attempting to ensure the value is preserved exactly.
     215                 :             :  */
     216                 :             : static void
     217                 :     2491411 : outDouble(StringInfo str, double d)
     218                 :             : {
     219                 :             :     char        buf[DOUBLE_SHORTEST_DECIMAL_LEN];
     220                 :             : 
     221                 :     2491411 :     double_to_shortest_decimal_buf(d, buf);
     222                 :     2491411 :     appendStringInfoString(str, buf);
     223                 :     2491411 : }
     224                 :             : 
     225                 :             : /*
     226                 :             :  * common implementation for scalar-array-writing functions
     227                 :             :  *
     228                 :             :  * The data format is either "<>" for a NULL pointer or "(item item item)".
     229                 :             :  * fmtstr must include a leading space, and the rest of it must produce
     230                 :             :  * something that will be seen as a single simple token by pg_strtok().
     231                 :             :  * convfunc can be empty, or the name of a conversion macro or function.
     232                 :             :  */
     233                 :             : #define WRITE_SCALAR_ARRAY(fnname, datatype, fmtstr, convfunc) \
     234                 :             : static void \
     235                 :             : fnname(StringInfo str, const datatype *arr, int len) \
     236                 :             : { \
     237                 :             :     if (arr != NULL) \
     238                 :             :     { \
     239                 :             :         appendStringInfoChar(str, '('); \
     240                 :             :         for (int i = 0; i < len; i++) \
     241                 :             :             appendStringInfo(str, fmtstr, convfunc(arr[i])); \
     242                 :             :         appendStringInfoChar(str, ')'); \
     243                 :             :     } \
     244                 :             :     else \
     245                 :             :         appendStringInfoString(str, "<>"); \
     246                 :             : }
     247                 :             : 
     248   [ +  +  +  + ]:      358997 : WRITE_SCALAR_ARRAY(writeAttrNumberCols, AttrNumber, " %d",)
     249   [ +  +  +  + ]:      441069 : WRITE_SCALAR_ARRAY(writeOidCols, Oid, " %u",)
     250   [ #  #  #  # ]:           0 : WRITE_SCALAR_ARRAY(writeIndexCols, Index, " %u",)
     251   [ +  -  +  + ]:        9741 : WRITE_SCALAR_ARRAY(writeIntCols, int, " %d",)
     252   [ +  +  +  +  :      161461 : WRITE_SCALAR_ARRAY(writeBoolCols, bool, " %s", booltostr)
                   +  + ]
     253                 :             : 
     254                 :             : /*
     255                 :             :  * Print an array (not a List) of Node pointers.
     256                 :             :  *
     257                 :             :  * The decoration is identical to that of scalar arrays, but we can't
     258                 :             :  * quite use appendStringInfo() in the loop.
     259                 :             :  */
     260                 :             : static void
     261                 :           0 : writeNodeArray(StringInfo str, const Node *const *arr, int len)
     262                 :             : {
     263         [ #  # ]:           0 :     if (arr != NULL)
     264                 :             :     {
     265                 :           0 :         appendStringInfoChar(str, '(');
     266         [ #  # ]:           0 :         for (int i = 0; i < len; i++)
     267                 :             :         {
     268                 :           0 :             appendStringInfoChar(str, ' ');
     269                 :           0 :             outNode(str, arr[i]);
     270                 :             :         }
     271                 :           0 :         appendStringInfoChar(str, ')');
     272                 :             :     }
     273                 :             :     else
     274                 :           0 :         appendStringInfoString(str, "<>");
     275                 :           0 : }
     276                 :             : 
     277                 :             : /*
     278                 :             :  * Print a List.
     279                 :             :  */
     280                 :             : static void
     281                 :    12129784 : _outList(StringInfo str, const List *node)
     282                 :             : {
     283                 :             :     const ListCell *lc;
     284                 :             : 
     285                 :    12129784 :     appendStringInfoChar(str, '(');
     286                 :             : 
     287         [ +  + ]:    12129784 :     if (IsA(node, IntList))
     288                 :      274024 :         appendStringInfoChar(str, 'i');
     289         [ +  + ]:    11855760 :     else if (IsA(node, OidList))
     290                 :      478527 :         appendStringInfoChar(str, 'o');
     291         [ -  + ]:    11377233 :     else if (IsA(node, XidList))
     292                 :           0 :         appendStringInfoChar(str, 'x');
     293                 :             : 
     294   [ +  -  +  +  :    51650128 :     foreach(lc, node)
                   +  + ]
     295                 :             :     {
     296                 :             :         /*
     297                 :             :          * For the sake of backward compatibility, we emit a slightly
     298                 :             :          * different whitespace format for lists of nodes vs. other types of
     299                 :             :          * lists. XXX: is this necessary?
     300                 :             :          */
     301         [ +  + ]:    39520344 :         if (IsA(node, List))
     302                 :             :         {
     303                 :    35665671 :             outNode(str, lfirst(lc));
     304         [ +  + ]:    35665671 :             if (lnext(node, lc))
     305                 :    24288438 :                 appendStringInfoChar(str, ' ');
     306                 :             :         }
     307         [ +  + ]:     3854673 :         else if (IsA(node, IntList))
     308                 :     2872513 :             appendStringInfo(str, " %d", lfirst_int(lc));
     309         [ +  - ]:      982160 :         else if (IsA(node, OidList))
     310                 :      982160 :             appendStringInfo(str, " %u", lfirst_oid(lc));
     311         [ #  # ]:           0 :         else if (IsA(node, XidList))
     312                 :           0 :             appendStringInfo(str, " %u", lfirst_xid(lc));
     313                 :             :         else
     314         [ #  # ]:           0 :             elog(ERROR, "unrecognized list node type: %d",
     315                 :             :                  (int) node->type);
     316                 :             :     }
     317                 :             : 
     318                 :    12129784 :     appendStringInfoChar(str, ')');
     319                 :    12129784 : }
     320                 :             : 
     321                 :             : /*
     322                 :             :  * outBitmapset -
     323                 :             :  *     converts a bitmap set of integers
     324                 :             :  *
     325                 :             :  * Note: the output format is "(b int int ...)", similar to an integer List.
     326                 :             :  *
     327                 :             :  * We export this function for use by extensions that define extensible nodes.
     328                 :             :  * That's somewhat historical, though, because calling outNode() will work.
     329                 :             :  */
     330                 :             : void
     331                 :    13383348 : outBitmapset(StringInfo str, const Bitmapset *bms)
     332                 :             : {
     333                 :             :     int         x;
     334                 :             : 
     335                 :    13383348 :     appendStringInfoChar(str, '(');
     336                 :    13383348 :     appendStringInfoChar(str, 'b');
     337                 :    13383348 :     x = -1;
     338         [ +  + ]:    17165009 :     while ((x = bms_next_member(bms, x)) >= 0)
     339                 :     3781661 :         appendStringInfo(str, " %d", x);
     340                 :    13383348 :     appendStringInfoChar(str, ')');
     341                 :    13383348 : }
     342                 :             : 
     343                 :             : /*
     344                 :             :  * Print the value of a Datum given its type.
     345                 :             :  */
     346                 :             : void
     347                 :     1665912 : outDatum(StringInfo str, Datum value, int typlen, bool typbyval)
     348                 :             : {
     349                 :             :     Size        length;
     350                 :             :     char       *s;
     351                 :             : 
     352                 :     1665912 :     length = datumGetSize(value, typbyval, typlen);
     353                 :             : 
     354         [ +  + ]:     1665912 :     if (typbyval)
     355                 :             :     {
     356                 :     1070348 :         s = (char *) (&value);
     357                 :     1070348 :         appendStringInfo(str, "%zu [ ", length);
     358         [ +  + ]:     9633132 :         for (Size i = 0; i < (Size) sizeof(Datum); i++)
     359                 :     8562784 :             appendStringInfo(str, "%d ", (int) (s[i]));
     360                 :     1070348 :         appendStringInfoChar(str, ']');
     361                 :             :     }
     362                 :             :     else
     363                 :             :     {
     364                 :      595564 :         s = (char *) DatumGetPointer(value);
     365         [ -  + ]:      595564 :         if (!s)
     366                 :           0 :             appendStringInfoString(str, "0 [ ]");
     367                 :             :         else
     368                 :             :         {
     369                 :      595564 :             appendStringInfo(str, "%zu [ ", length);
     370         [ +  + ]:    78394936 :             for (Size i = 0; i < length; i++)
     371                 :    77799372 :                 appendStringInfo(str, "%d ", (int) (s[i]));
     372                 :      595564 :             appendStringInfoChar(str, ']');
     373                 :             :         }
     374                 :             :     }
     375                 :     1665912 : }
     376                 :             : 
     377                 :             : 
     378                 :             : #include "outfuncs.funcs.c"
     379                 :             : 
     380                 :             : 
     381                 :             : /*
     382                 :             :  * Support functions for nodes with custom_read_write attribute or
     383                 :             :  * special_read_write attribute
     384                 :             :  */
     385                 :             : 
     386                 :             : static void
     387                 :     1830817 : _outConst(StringInfo str, const Const *node)
     388                 :             : {
     389                 :     1830817 :     WRITE_NODE_TYPE("CONST");
     390                 :             : 
     391                 :     1830817 :     WRITE_OID_FIELD(consttype);
     392                 :     1830817 :     WRITE_INT_FIELD(consttypmod);
     393                 :     1830817 :     WRITE_OID_FIELD(constcollid);
     394                 :     1830817 :     WRITE_INT_FIELD(constlen);
     395         [ +  + ]:     1830817 :     WRITE_BOOL_FIELD(constbyval);
     396         [ +  + ]:     1830817 :     WRITE_BOOL_FIELD(constisnull);
     397         [ +  + ]:     1830817 :     WRITE_LOCATION_FIELD(location);
     398                 :             : 
     399                 :     1830817 :     appendStringInfoString(str, " :constvalue ");
     400         [ +  + ]:     1830817 :     if (node->constisnull)
     401                 :      164899 :         appendStringInfoString(str, "<>");
     402                 :             :     else
     403                 :     1665918 :         outDatum(str, node->constvalue, node->constlen, node->constbyval);
     404                 :     1830817 : }
     405                 :             : 
     406                 :             : static void
     407                 :      273875 : _outBoolExpr(StringInfo str, const BoolExpr *node)
     408                 :             : {
     409                 :      273875 :     char       *opstr = NULL;
     410                 :             : 
     411                 :      273875 :     WRITE_NODE_TYPE("BOOLEXPR");
     412                 :             : 
     413                 :             :     /* do-it-yourself enum representation */
     414   [ +  +  +  - ]:      273875 :     switch (node->boolop)
     415                 :             :     {
     416                 :      192108 :         case AND_EXPR:
     417                 :      192108 :             opstr = "and";
     418                 :      192108 :             break;
     419                 :       37323 :         case OR_EXPR:
     420                 :       37323 :             opstr = "or";
     421                 :       37323 :             break;
     422                 :       44444 :         case NOT_EXPR:
     423                 :       44444 :             opstr = "not";
     424                 :       44444 :             break;
     425                 :             :     }
     426                 :      273875 :     appendStringInfoString(str, " :boolop ");
     427                 :      273875 :     outToken(str, opstr);
     428                 :             : 
     429                 :      273875 :     WRITE_NODE_FIELD(args);
     430         [ +  + ]:      273875 :     WRITE_LOCATION_FIELD(location);
     431                 :      273875 : }
     432                 :             : 
     433                 :             : static void
     434                 :           0 : _outForeignKeyOptInfo(StringInfo str, const ForeignKeyOptInfo *node)
     435                 :             : {
     436                 :           0 :     WRITE_NODE_TYPE("FOREIGNKEYOPTINFO");
     437                 :             : 
     438                 :           0 :     WRITE_UINT_FIELD(con_relid);
     439                 :           0 :     WRITE_UINT_FIELD(ref_relid);
     440                 :           0 :     WRITE_INT_FIELD(nkeys);
     441                 :           0 :     WRITE_ATTRNUMBER_ARRAY(conkey, node->nkeys);
     442                 :           0 :     WRITE_ATTRNUMBER_ARRAY(confkey, node->nkeys);
     443                 :           0 :     WRITE_OID_ARRAY(conpfeqop, node->nkeys);
     444                 :           0 :     WRITE_INT_FIELD(nmatched_ec);
     445                 :           0 :     WRITE_INT_FIELD(nconst_ec);
     446                 :           0 :     WRITE_INT_FIELD(nmatched_rcols);
     447                 :           0 :     WRITE_INT_FIELD(nmatched_ri);
     448                 :             :     /* for compactness, just print the number of matches per column: */
     449                 :           0 :     appendStringInfoString(str, " :eclass");
     450         [ #  # ]:           0 :     for (int i = 0; i < node->nkeys; i++)
     451                 :           0 :         appendStringInfo(str, " %d", (node->eclass[i] != NULL));
     452                 :           0 :     appendStringInfoString(str, " :rinfos");
     453         [ #  # ]:           0 :     for (int i = 0; i < node->nkeys; i++)
     454                 :           0 :         appendStringInfo(str, " %d", list_length(node->rinfos[i]));
     455                 :           0 : }
     456                 :             : 
     457                 :             : static void
     458                 :           0 : _outEquivalenceClass(StringInfo str, const EquivalenceClass *node)
     459                 :             : {
     460                 :             :     /*
     461                 :             :      * To simplify reading, we just chase up to the topmost merged EC and
     462                 :             :      * print that, without bothering to show the merge-ees separately.
     463                 :             :      */
     464         [ #  # ]:           0 :     while (node->ec_merged)
     465                 :           0 :         node = node->ec_merged;
     466                 :             : 
     467                 :           0 :     WRITE_NODE_TYPE("EQUIVALENCECLASS");
     468                 :             : 
     469                 :           0 :     WRITE_NODE_FIELD(ec_opfamilies);
     470                 :           0 :     WRITE_OID_FIELD(ec_collation);
     471                 :           0 :     WRITE_INT_FIELD(ec_childmembers_size);
     472                 :           0 :     WRITE_NODE_FIELD(ec_members);
     473                 :           0 :     WRITE_NODE_ARRAY(ec_childmembers, node->ec_childmembers_size);
     474                 :           0 :     WRITE_NODE_FIELD(ec_sources);
     475                 :             :     /* Only ec_derives_list is written; hash is not serialized. */
     476                 :           0 :     WRITE_NODE_FIELD(ec_derives_list);
     477                 :           0 :     WRITE_BITMAPSET_FIELD(ec_relids);
     478         [ #  # ]:           0 :     WRITE_BOOL_FIELD(ec_has_const);
     479         [ #  # ]:           0 :     WRITE_BOOL_FIELD(ec_has_volatile);
     480         [ #  # ]:           0 :     WRITE_BOOL_FIELD(ec_broken);
     481                 :           0 :     WRITE_UINT_FIELD(ec_sortref);
     482                 :           0 :     WRITE_UINT_FIELD(ec_min_security);
     483                 :           0 :     WRITE_UINT_FIELD(ec_max_security);
     484                 :           0 : }
     485                 :             : 
     486                 :             : static void
     487                 :           0 : _outExtensibleNode(StringInfo str, const ExtensibleNode *node)
     488                 :             : {
     489                 :             :     const ExtensibleNodeMethods *methods;
     490                 :             : 
     491                 :           0 :     methods = GetExtensibleNodeMethods(node->extnodename, false);
     492                 :             : 
     493                 :           0 :     WRITE_NODE_TYPE("EXTENSIBLENODE");
     494                 :             : 
     495                 :           0 :     WRITE_STRING_FIELD(extnodename);
     496                 :             : 
     497                 :             :     /* serialize the private fields */
     498                 :           0 :     methods->nodeOut(str, node);
     499                 :           0 : }
     500                 :             : 
     501                 :             : static void
     502                 :     1146205 : _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
     503                 :             : {
     504                 :     1146205 :     WRITE_NODE_TYPE("RANGETBLENTRY");
     505                 :             : 
     506                 :     1146205 :     WRITE_NODE_FIELD(alias);
     507                 :     1146205 :     WRITE_NODE_FIELD(eref);
     508                 :     1146205 :     WRITE_ENUM_FIELD(rtekind, RTEKind);
     509                 :             : 
     510   [ +  +  +  +  :     1146205 :     switch (node->rtekind)
          +  +  +  +  +  
                +  +  - ]
     511                 :             :     {
     512                 :      683912 :         case RTE_RELATION:
     513                 :      683912 :             WRITE_OID_FIELD(relid);
     514         [ +  + ]:      683912 :             WRITE_BOOL_FIELD(inh);
     515                 :      683912 :             WRITE_CHAR_FIELD(relkind);
     516                 :      683912 :             WRITE_INT_FIELD(rellockmode);
     517                 :      683912 :             WRITE_UINT_FIELD(perminfoindex);
     518                 :      683912 :             WRITE_NODE_FIELD(tablesample);
     519                 :      683912 :             break;
     520                 :      108693 :         case RTE_SUBQUERY:
     521                 :      108693 :             WRITE_NODE_FIELD(subquery);
     522         [ +  + ]:      108693 :             WRITE_BOOL_FIELD(security_barrier);
     523                 :             :             /* we re-use these RELATION fields, too: */
     524                 :      108693 :             WRITE_OID_FIELD(relid);
     525         [ +  + ]:      108693 :             WRITE_BOOL_FIELD(inh);
     526                 :      108693 :             WRITE_CHAR_FIELD(relkind);
     527                 :      108693 :             WRITE_INT_FIELD(rellockmode);
     528                 :      108693 :             WRITE_UINT_FIELD(perminfoindex);
     529                 :      108693 :             break;
     530                 :      130671 :         case RTE_JOIN:
     531                 :      130671 :             WRITE_ENUM_FIELD(jointype, JoinType);
     532                 :      130671 :             WRITE_INT_FIELD(joinmergedcols);
     533                 :      130671 :             WRITE_NODE_FIELD(joinaliasvars);
     534                 :      130671 :             WRITE_NODE_FIELD(joinleftcols);
     535                 :      130671 :             WRITE_NODE_FIELD(joinrightcols);
     536                 :      130671 :             WRITE_NODE_FIELD(join_using_alias);
     537                 :      130671 :             break;
     538                 :       64731 :         case RTE_FUNCTION:
     539                 :       64731 :             WRITE_NODE_FIELD(functions);
     540         [ +  + ]:       64731 :             WRITE_BOOL_FIELD(funcordinality);
     541                 :       64731 :             break;
     542                 :         874 :         case RTE_TABLEFUNC:
     543                 :         874 :             WRITE_NODE_FIELD(tablefunc);
     544                 :         874 :             break;
     545                 :       14954 :         case RTE_VALUES:
     546                 :       14954 :             WRITE_NODE_FIELD(values_lists);
     547                 :       14954 :             WRITE_NODE_FIELD(coltypes);
     548                 :       14954 :             WRITE_NODE_FIELD(coltypmods);
     549                 :       14954 :             WRITE_NODE_FIELD(colcollations);
     550                 :       14954 :             break;
     551                 :        7565 :         case RTE_CTE:
     552                 :        7565 :             WRITE_STRING_FIELD(ctename);
     553                 :        7565 :             WRITE_UINT_FIELD(ctelevelsup);
     554         [ +  + ]:        7565 :             WRITE_BOOL_FIELD(self_reference);
     555                 :        7565 :             WRITE_NODE_FIELD(coltypes);
     556                 :        7565 :             WRITE_NODE_FIELD(coltypmods);
     557                 :        7565 :             WRITE_NODE_FIELD(colcollations);
     558                 :        7565 :             break;
     559                 :         696 :         case RTE_NAMEDTUPLESTORE:
     560                 :         696 :             WRITE_STRING_FIELD(enrname);
     561                 :         696 :             WRITE_FLOAT_FIELD(enrtuples);
     562                 :         696 :             WRITE_NODE_FIELD(coltypes);
     563                 :         696 :             WRITE_NODE_FIELD(coltypmods);
     564                 :         696 :             WRITE_NODE_FIELD(colcollations);
     565                 :             :             /* we re-use these RELATION fields, too: */
     566                 :         696 :             WRITE_OID_FIELD(relid);
     567                 :         696 :             break;
     568                 :          29 :         case RTE_GRAPH_TABLE:
     569                 :          29 :             WRITE_NODE_FIELD(graph_pattern);
     570                 :          29 :             WRITE_NODE_FIELD(graph_table_columns);
     571                 :             :             /* we re-use these RELATION fields, too: */
     572                 :          29 :             WRITE_OID_FIELD(relid);
     573                 :          29 :             WRITE_CHAR_FIELD(relkind);
     574                 :          29 :             WRITE_INT_FIELD(rellockmode);
     575                 :          29 :             WRITE_UINT_FIELD(perminfoindex);
     576                 :          29 :             break;
     577                 :      126606 :         case RTE_RESULT:
     578                 :             :             /* no extra fields */
     579                 :      126606 :             break;
     580                 :        7474 :         case RTE_GROUP:
     581                 :        7474 :             WRITE_NODE_FIELD(groupexprs);
     582                 :        7474 :             break;
     583                 :           0 :         default:
     584         [ #  # ]:           0 :             elog(ERROR, "unrecognized RTE kind: %d", (int) node->rtekind);
     585                 :             :             break;
     586                 :             :     }
     587                 :             : 
     588         [ +  + ]:     1146205 :     WRITE_BOOL_FIELD(lateral);
     589         [ +  + ]:     1146205 :     WRITE_BOOL_FIELD(inFromCl);
     590                 :     1146205 :     WRITE_NODE_FIELD(securityQuals);
     591                 :     1146205 : }
     592                 :             : 
     593                 :             : static void
     594                 :      427694 : _outA_Expr(StringInfo str, const A_Expr *node)
     595                 :             : {
     596                 :      427694 :     WRITE_NODE_TYPE("A_EXPR");
     597                 :             : 
     598   [ +  +  +  +  :      427694 :     switch (node->kind)
          +  +  +  +  +  
          +  +  +  +  +  
                      - ]
     599                 :             :     {
     600                 :      397043 :         case AEXPR_OP:
     601                 :      397043 :             WRITE_NODE_FIELD(name);
     602                 :      397043 :             break;
     603                 :       10800 :         case AEXPR_OP_ANY:
     604                 :       10800 :             appendStringInfoString(str, " ANY");
     605                 :       10800 :             WRITE_NODE_FIELD(name);
     606                 :       10800 :             break;
     607                 :          96 :         case AEXPR_OP_ALL:
     608                 :          96 :             appendStringInfoString(str, " ALL");
     609                 :          96 :             WRITE_NODE_FIELD(name);
     610                 :          96 :             break;
     611                 :         646 :         case AEXPR_DISTINCT:
     612                 :         646 :             appendStringInfoString(str, " DISTINCT");
     613                 :         646 :             WRITE_NODE_FIELD(name);
     614                 :         646 :             break;
     615                 :          88 :         case AEXPR_NOT_DISTINCT:
     616                 :          88 :             appendStringInfoString(str, " NOT_DISTINCT");
     617                 :          88 :             WRITE_NODE_FIELD(name);
     618                 :          88 :             break;
     619                 :         589 :         case AEXPR_NULLIF:
     620                 :         589 :             appendStringInfoString(str, " NULLIF");
     621                 :         589 :             WRITE_NODE_FIELD(name);
     622                 :         589 :             break;
     623                 :       16229 :         case AEXPR_IN:
     624                 :       16229 :             appendStringInfoString(str, " IN");
     625                 :       16229 :             WRITE_NODE_FIELD(name);
     626                 :       16229 :             break;
     627                 :        1593 :         case AEXPR_LIKE:
     628                 :        1593 :             appendStringInfoString(str, " LIKE");
     629                 :        1593 :             WRITE_NODE_FIELD(name);
     630                 :        1593 :             break;
     631                 :         136 :         case AEXPR_ILIKE:
     632                 :         136 :             appendStringInfoString(str, " ILIKE");
     633                 :         136 :             WRITE_NODE_FIELD(name);
     634                 :         136 :             break;
     635                 :          82 :         case AEXPR_SIMILAR:
     636                 :          82 :             appendStringInfoString(str, " SIMILAR");
     637                 :          82 :             WRITE_NODE_FIELD(name);
     638                 :          82 :             break;
     639                 :         368 :         case AEXPR_BETWEEN:
     640                 :         368 :             appendStringInfoString(str, " BETWEEN");
     641                 :         368 :             WRITE_NODE_FIELD(name);
     642                 :         368 :             break;
     643                 :           8 :         case AEXPR_NOT_BETWEEN:
     644                 :           8 :             appendStringInfoString(str, " NOT_BETWEEN");
     645                 :           8 :             WRITE_NODE_FIELD(name);
     646                 :           8 :             break;
     647                 :           8 :         case AEXPR_BETWEEN_SYM:
     648                 :           8 :             appendStringInfoString(str, " BETWEEN_SYM");
     649                 :           8 :             WRITE_NODE_FIELD(name);
     650                 :           8 :             break;
     651                 :           8 :         case AEXPR_NOT_BETWEEN_SYM:
     652                 :           8 :             appendStringInfoString(str, " NOT_BETWEEN_SYM");
     653                 :           8 :             WRITE_NODE_FIELD(name);
     654                 :           8 :             break;
     655                 :           0 :         default:
     656         [ #  # ]:           0 :             elog(ERROR, "unrecognized A_Expr_Kind: %d", (int) node->kind);
     657                 :             :             break;
     658                 :             :     }
     659                 :             : 
     660                 :      427694 :     WRITE_NODE_FIELD(lexpr);
     661                 :      427694 :     WRITE_NODE_FIELD(rexpr);
     662         [ +  - ]:      427694 :     WRITE_LOCATION_FIELD(rexpr_list_start);
     663         [ +  - ]:      427694 :     WRITE_LOCATION_FIELD(rexpr_list_end);
     664         [ +  - ]:      427694 :     WRITE_LOCATION_FIELD(location);
     665                 :      427694 : }
     666                 :             : 
     667                 :             : static void
     668                 :      463046 : _outInteger(StringInfo str, const Integer *node)
     669                 :             : {
     670                 :      463046 :     appendStringInfo(str, "%d", node->ival);
     671                 :      463046 : }
     672                 :             : 
     673                 :             : static void
     674                 :        8362 : _outFloat(StringInfo str, const Float *node)
     675                 :             : {
     676                 :             :     /*
     677                 :             :      * We assume the value is a valid numeric literal and so does not need
     678                 :             :      * quoting.
     679                 :             :      */
     680                 :        8362 :     appendStringInfoString(str, node->fval);
     681                 :        8362 : }
     682                 :             : 
     683                 :             : static void
     684                 :       57226 : _outBoolean(StringInfo str, const Boolean *node)
     685                 :             : {
     686         [ +  + ]:       57226 :     appendStringInfoString(str, node->boolval ? "true" : "false");
     687                 :       57226 : }
     688                 :             : 
     689                 :             : static void
     690                 :    18042102 : _outString(StringInfo str, const String *node)
     691                 :             : {
     692                 :             :     /*
     693                 :             :      * We use outToken to provide escaping of the string's content, but we
     694                 :             :      * don't want it to convert an empty string to '""', because we're putting
     695                 :             :      * double quotes around the string already.
     696                 :             :      */
     697                 :    18042102 :     appendStringInfoChar(str, '"');
     698         [ +  + ]:    18042102 :     if (node->sval[0] != '\0')
     699                 :    18021689 :         outToken(str, node->sval);
     700                 :    18042102 :     appendStringInfoChar(str, '"');
     701                 :    18042102 : }
     702                 :             : 
     703                 :             : static void
     704                 :        2735 : _outBitString(StringInfo str, const BitString *node)
     705                 :             : {
     706                 :             :     /*
     707                 :             :      * The lexer will always produce a string starting with 'b' or 'x'.  There
     708                 :             :      * might be characters following that that need escaping, but outToken
     709                 :             :      * won't escape the 'b' or 'x'.  This is relied on by nodeTokenType.
     710                 :             :      */
     711                 :             :     Assert(node->bsval[0] == 'b' || node->bsval[0] == 'x');
     712                 :        2735 :     outToken(str, node->bsval);
     713                 :        2735 : }
     714                 :             : 
     715                 :             : static void
     716                 :      948753 : _outA_Const(StringInfo str, const A_Const *node)
     717                 :             : {
     718                 :      948753 :     WRITE_NODE_TYPE("A_CONST");
     719                 :             : 
     720         [ +  + ]:      948753 :     if (node->isnull)
     721                 :       55192 :         appendStringInfoString(str, " NULL");
     722                 :             :     else
     723                 :             :     {
     724                 :      893561 :         appendStringInfoString(str, " :val ");
     725                 :      893561 :         outNode(str, &node->val);
     726                 :             :     }
     727         [ +  - ]:      948753 :     WRITE_LOCATION_FIELD(location);
     728                 :      948753 : }
     729                 :             : 
     730                 :             : 
     731                 :             : /*
     732                 :             :  * outNode -
     733                 :             :  *    converts a Node into ascii string and append it to 'str'
     734                 :             :  */
     735                 :             : void
     736                 :    98516477 : outNode(StringInfo str, const void *obj)
     737                 :             : {
     738                 :             :     /* Guard against stack overflow due to overly complex expressions */
     739                 :    98516477 :     check_stack_depth();
     740                 :             : 
     741         [ +  + ]:    98516477 :     if (obj == NULL)
     742                 :    35718414 :         appendStringInfoString(str, "<>");
     743   [ +  +  +  +  :    62798063 :     else if (IsA(obj, List) || IsA(obj, IntList) || IsA(obj, OidList) ||
                   +  + ]
     744         [ -  + ]:    50668268 :              IsA(obj, XidList))
     745                 :    12129795 :         _outList(str, obj);
     746                 :             :     /* nodeRead does not want to see { } around these! */
     747         [ +  + ]:    50668268 :     else if (IsA(obj, Integer))
     748                 :      463046 :         _outInteger(str, (const Integer *) obj);
     749         [ +  + ]:    50205222 :     else if (IsA(obj, Float))
     750                 :        8362 :         _outFloat(str, (const Float *) obj);
     751         [ +  + ]:    50196860 :     else if (IsA(obj, Boolean))
     752                 :       57226 :         _outBoolean(str, (const Boolean *) obj);
     753         [ +  + ]:    50139634 :     else if (IsA(obj, String))
     754                 :    18042102 :         _outString(str, (const String *) obj);
     755         [ +  + ]:    32097532 :     else if (IsA(obj, BitString))
     756                 :        2735 :         _outBitString(str, (const BitString *) obj);
     757         [ +  + ]:    32094797 :     else if (IsA(obj, Bitmapset))
     758                 :        1845 :         outBitmapset(str, (const Bitmapset *) obj);
     759                 :             :     else
     760                 :             :     {
     761                 :    32092952 :         appendStringInfoChar(str, '{');
     762   [ +  +  +  +  :    32092952 :         switch (nodeTag(obj))
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  -  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  -  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  -  +  +  
          +  +  +  +  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          +  -  -  -  -  
          -  -  -  -  -  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          -  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  -  -  
                      - ]
     763                 :             :         {
     764                 :             : #include "outfuncs.switch.c"
     765                 :             : 
     766                 :           0 :             default:
     767                 :             : 
     768                 :             :                 /*
     769                 :             :                  * This should be an ERROR, but it's too useful to be able to
     770                 :             :                  * dump structures that outNode only understands part of.
     771                 :             :                  */
     772         [ #  # ]:           0 :                 elog(WARNING, "could not dump unrecognized node type: %d",
     773                 :             :                      (int) nodeTag(obj));
     774                 :           0 :                 break;
     775                 :             :         }
     776                 :    32092952 :         appendStringInfoChar(str, '}');
     777                 :             :     }
     778                 :    98516477 : }
     779                 :             : 
     780                 :             : /*
     781                 :             :  * nodeToString -
     782                 :             :  *     returns the ascii representation of the Node as a palloc'd string
     783                 :             :  *
     784                 :             :  * write_loc_fields determines whether location fields are output with their
     785                 :             :  * actual value rather than -1.  The actual value can be useful for debugging,
     786                 :             :  * but for most uses, the actual value is not useful, since the original query
     787                 :             :  * string is no longer available.
     788                 :             :  */
     789                 :             : static char *
     790                 :     1287982 : nodeToStringInternal(const void *obj, bool write_loc_fields)
     791                 :             : {
     792                 :             :     StringInfoData str;
     793                 :             :     bool        save_write_location_fields;
     794                 :             : 
     795                 :     1287982 :     save_write_location_fields = write_location_fields;
     796                 :     1287982 :     write_location_fields = write_loc_fields;
     797                 :             : 
     798                 :             :     /* see stringinfo.h for an explanation of this maneuver */
     799                 :     1287982 :     initStringInfo(&str);
     800                 :     1287982 :     outNode(&str, obj);
     801                 :             : 
     802                 :     1287982 :     write_location_fields = save_write_location_fields;
     803                 :             : 
     804                 :     1287982 :     return str.data;
     805                 :             : }
     806                 :             : 
     807                 :             : /*
     808                 :             :  * Externally visible entry points
     809                 :             :  */
     810                 :             : char *
     811                 :       48965 : nodeToString(const void *obj)
     812                 :             : {
     813                 :       48965 :     return nodeToStringInternal(obj, false);
     814                 :             : }
     815                 :             : 
     816                 :             : char *
     817                 :     1239017 : nodeToStringWithLocations(const void *obj)
     818                 :             : {
     819                 :     1239017 :     return nodeToStringInternal(obj, true);
     820                 :             : }
     821                 :             : 
     822                 :             : 
     823                 :             : /*
     824                 :             :  * bmsToString -
     825                 :             :  *     returns the ascii representation of the Bitmapset as a palloc'd string
     826                 :             :  */
     827                 :             : char *
     828                 :           0 : bmsToString(const Bitmapset *bms)
     829                 :             : {
     830                 :             :     StringInfoData str;
     831                 :             : 
     832                 :             :     /* see stringinfo.h for an explanation of this maneuver */
     833                 :           0 :     initStringInfo(&str);
     834                 :           0 :     outBitmapset(&str, bms);
     835                 :           0 :     return str.data;
     836                 :             : }
        

Generated by: LCOV version 2.0-1