LCOV - code coverage report
Current view: top level - src/backend/nodes - outfuncs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18beta1 Lines: 299 370 80.8 %
Date: 2025-06-28 09:17:06 Functions: 24 30 80.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * outfuncs.c
       4             :  *    Output functions for Postgres tree nodes.
       5             :  *
       6             :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/nodes/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    48937598 : outToken(StringInfo str, const char *s)
     156             : {
     157    48937598 :     if (s == NULL)
     158             :     {
     159     9980712 :         appendStringInfoString(str, "<>");
     160     9980712 :         return;
     161             :     }
     162    38956886 :     if (*s == '\0')
     163             :     {
     164         156 :         appendStringInfoString(str, "\"\"");
     165         156 :         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    38956730 :     if (*s == '<' ||
     175    38888910 :         *s == '"' ||
     176    38882770 :         isdigit((unsigned char) *s) ||
     177    38692374 :         ((*s == '+' || *s == '-') &&
     178       31348 :          (isdigit((unsigned char) s[1]) || s[1] == '.')))
     179      269782 :         appendStringInfoChar(str, '\\');
     180   350879102 :     while (*s)
     181             :     {
     182             :         /* These chars must be backslashed anywhere in the string */
     183   311922372 :         if (*s == ' ' || *s == '\n' || *s == '\t' ||
     184   310569376 :             *s == '(' || *s == ')' || *s == '{' || *s == '}' ||
     185   310340584 :             *s == '\\')
     186     1592806 :             appendStringInfoChar(str, '\\');
     187   311922372 :         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     3005404 : outChar(StringInfo str, char c)
     197             : {
     198             :     char        in[2];
     199             : 
     200             :     /* Traditionally, we've represented \0 as <>, so keep doing that */
     201     3005404 :     if (c == '\0')
     202             :     {
     203      913848 :         appendStringInfoString(str, "<>");
     204      913848 :         return;
     205             :     }
     206             : 
     207     2091556 :     in[0] = c;
     208     2091556 :     in[1] = '\0';
     209             : 
     210     2091556 :     outToken(str, in);
     211             : }
     212             : 
     213             : /*
     214             :  * Convert a double value, attempting to ensure the value is preserved exactly.
     215             :  */
     216             : static void
     217     3564442 : outDouble(StringInfo str, double d)
     218             : {
     219             :     char        buf[DOUBLE_SHORTEST_DECIMAL_LEN];
     220             : 
     221     3564442 :     double_to_shortest_decimal_buf(d, buf);
     222     3564442 :     appendStringInfoString(str, buf);
     223     3564442 : }
     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      476636 : WRITE_SCALAR_ARRAY(writeAttrNumberCols, AttrNumber, " %d",)
     249      642054 : WRITE_SCALAR_ARRAY(writeOidCols, Oid, " %u",)
     250           0 : WRITE_SCALAR_ARRAY(writeIndexCols, Index, " %u",)
     251       14526 : WRITE_SCALAR_ARRAY(writeIntCols, int, " %d",)
     252      244330 : 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    18283638 : _outList(StringInfo str, const List *node)
     282             : {
     283             :     const ListCell *lc;
     284             : 
     285    18283638 :     appendStringInfoChar(str, '(');
     286             : 
     287    18283638 :     if (IsA(node, IntList))
     288      491370 :         appendStringInfoChar(str, 'i');
     289    17792268 :     else if (IsA(node, OidList))
     290      703710 :         appendStringInfoChar(str, 'o');
     291    17088558 :     else if (IsA(node, XidList))
     292           0 :         appendStringInfoChar(str, 'x');
     293             : 
     294    77787930 :     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    59504292 :         if (IsA(node, List))
     302             :         {
     303    53770330 :             outNode(str, lfirst(lc));
     304    53770330 :             if (lnext(node, lc))
     305    36681772 :                 appendStringInfoChar(str, ' ');
     306             :         }
     307     5733962 :         else if (IsA(node, IntList))
     308     4335362 :             appendStringInfo(str, " %d", lfirst_int(lc));
     309     1398600 :         else if (IsA(node, OidList))
     310     1398600 :             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    18283638 :     appendStringInfoChar(str, ')');
     319    18283638 : }
     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    18830304 : outBitmapset(StringInfo str, const Bitmapset *bms)
     332             : {
     333             :     int         x;
     334             : 
     335    18830304 :     appendStringInfoChar(str, '(');
     336    18830304 :     appendStringInfoChar(str, 'b');
     337    18830304 :     x = -1;
     338    24233678 :     while ((x = bms_next_member(bms, x)) >= 0)
     339     5403374 :         appendStringInfo(str, " %d", x);
     340    18830304 :     appendStringInfoChar(str, ')');
     341    18830304 : }
     342             : 
     343             : /*
     344             :  * Print the value of a Datum given its type.
     345             :  */
     346             : void
     347     2441918 : outDatum(StringInfo str, Datum value, int typlen, bool typbyval)
     348             : {
     349             :     Size        length,
     350             :                 i;
     351             :     char       *s;
     352             : 
     353     2441918 :     length = datumGetSize(value, typbyval, typlen);
     354             : 
     355     2441918 :     if (typbyval)
     356             :     {
     357     1574848 :         s = (char *) (&value);
     358     1574848 :         appendStringInfo(str, "%u [ ", (unsigned int) length);
     359    14173632 :         for (i = 0; i < (Size) sizeof(Datum); i++)
     360    12598784 :             appendStringInfo(str, "%d ", (int) (s[i]));
     361     1574848 :         appendStringInfoChar(str, ']');
     362             :     }
     363             :     else
     364             :     {
     365      867070 :         s = (char *) DatumGetPointer(value);
     366      867070 :         if (!PointerIsValid(s))
     367           0 :             appendStringInfoString(str, "0 [ ]");
     368             :         else
     369             :         {
     370      867070 :             appendStringInfo(str, "%u [ ", (unsigned int) length);
     371   118346882 :             for (i = 0; i < length; i++)
     372   117479812 :                 appendStringInfo(str, "%d ", (int) (s[i]));
     373      867070 :             appendStringInfoChar(str, ']');
     374             :         }
     375             :     }
     376     2441918 : }
     377             : 
     378             : 
     379             : #include "outfuncs.funcs.c"
     380             : 
     381             : 
     382             : /*
     383             :  * Support functions for nodes with custom_read_write attribute or
     384             :  * special_read_write attribute
     385             :  */
     386             : 
     387             : static void
     388     2649812 : _outConst(StringInfo str, const Const *node)
     389             : {
     390     2649812 :     WRITE_NODE_TYPE("CONST");
     391             : 
     392     2649812 :     WRITE_OID_FIELD(consttype);
     393     2649812 :     WRITE_INT_FIELD(consttypmod);
     394     2649812 :     WRITE_OID_FIELD(constcollid);
     395     2649812 :     WRITE_INT_FIELD(constlen);
     396     2649812 :     WRITE_BOOL_FIELD(constbyval);
     397     2649812 :     WRITE_BOOL_FIELD(constisnull);
     398     2649812 :     WRITE_LOCATION_FIELD(location);
     399             : 
     400     2649812 :     appendStringInfoString(str, " :constvalue ");
     401     2649812 :     if (node->constisnull)
     402      207874 :         appendStringInfoString(str, "<>");
     403             :     else
     404     2441938 :         outDatum(str, node->constvalue, node->constlen, node->constbyval);
     405     2649812 : }
     406             : 
     407             : static void
     408      379326 : _outBoolExpr(StringInfo str, const BoolExpr *node)
     409             : {
     410      379326 :     char       *opstr = NULL;
     411             : 
     412      379326 :     WRITE_NODE_TYPE("BOOLEXPR");
     413             : 
     414             :     /* do-it-yourself enum representation */
     415      379326 :     switch (node->boolop)
     416             :     {
     417      286610 :         case AND_EXPR:
     418      286610 :             opstr = "and";
     419      286610 :             break;
     420       44018 :         case OR_EXPR:
     421       44018 :             opstr = "or";
     422       44018 :             break;
     423       48698 :         case NOT_EXPR:
     424       48698 :             opstr = "not";
     425       48698 :             break;
     426             :     }
     427      379326 :     appendStringInfoString(str, " :boolop ");
     428      379326 :     outToken(str, opstr);
     429             : 
     430      379326 :     WRITE_NODE_FIELD(args);
     431      379326 :     WRITE_LOCATION_FIELD(location);
     432      379326 : }
     433             : 
     434             : static void
     435           0 : _outForeignKeyOptInfo(StringInfo str, const ForeignKeyOptInfo *node)
     436             : {
     437             :     int         i;
     438             : 
     439           0 :     WRITE_NODE_TYPE("FOREIGNKEYOPTINFO");
     440             : 
     441           0 :     WRITE_UINT_FIELD(con_relid);
     442           0 :     WRITE_UINT_FIELD(ref_relid);
     443           0 :     WRITE_INT_FIELD(nkeys);
     444           0 :     WRITE_ATTRNUMBER_ARRAY(conkey, node->nkeys);
     445           0 :     WRITE_ATTRNUMBER_ARRAY(confkey, node->nkeys);
     446           0 :     WRITE_OID_ARRAY(conpfeqop, node->nkeys);
     447           0 :     WRITE_INT_FIELD(nmatched_ec);
     448           0 :     WRITE_INT_FIELD(nconst_ec);
     449           0 :     WRITE_INT_FIELD(nmatched_rcols);
     450           0 :     WRITE_INT_FIELD(nmatched_ri);
     451             :     /* for compactness, just print the number of matches per column: */
     452           0 :     appendStringInfoString(str, " :eclass");
     453           0 :     for (i = 0; i < node->nkeys; i++)
     454           0 :         appendStringInfo(str, " %d", (node->eclass[i] != NULL));
     455           0 :     appendStringInfoString(str, " :rinfos");
     456           0 :     for (i = 0; i < node->nkeys; i++)
     457           0 :         appendStringInfo(str, " %d", list_length(node->rinfos[i]));
     458           0 : }
     459             : 
     460             : static void
     461           0 : _outEquivalenceClass(StringInfo str, const EquivalenceClass *node)
     462             : {
     463             :     /*
     464             :      * To simplify reading, we just chase up to the topmost merged EC and
     465             :      * print that, without bothering to show the merge-ees separately.
     466             :      */
     467           0 :     while (node->ec_merged)
     468           0 :         node = node->ec_merged;
     469             : 
     470           0 :     WRITE_NODE_TYPE("EQUIVALENCECLASS");
     471             : 
     472           0 :     WRITE_NODE_FIELD(ec_opfamilies);
     473           0 :     WRITE_OID_FIELD(ec_collation);
     474           0 :     WRITE_INT_FIELD(ec_childmembers_size);
     475           0 :     WRITE_NODE_FIELD(ec_members);
     476           0 :     WRITE_NODE_ARRAY(ec_childmembers, node->ec_childmembers_size);
     477           0 :     WRITE_NODE_FIELD(ec_sources);
     478             :     /* Only ec_derives_list is written; hash is not serialized. */
     479           0 :     WRITE_NODE_FIELD(ec_derives_list);
     480           0 :     WRITE_BITMAPSET_FIELD(ec_relids);
     481           0 :     WRITE_BOOL_FIELD(ec_has_const);
     482           0 :     WRITE_BOOL_FIELD(ec_has_volatile);
     483           0 :     WRITE_BOOL_FIELD(ec_broken);
     484           0 :     WRITE_UINT_FIELD(ec_sortref);
     485           0 :     WRITE_UINT_FIELD(ec_min_security);
     486           0 :     WRITE_UINT_FIELD(ec_max_security);
     487           0 : }
     488             : 
     489             : static void
     490           0 : _outExtensibleNode(StringInfo str, const ExtensibleNode *node)
     491             : {
     492             :     const ExtensibleNodeMethods *methods;
     493             : 
     494           0 :     methods = GetExtensibleNodeMethods(node->extnodename, false);
     495             : 
     496           0 :     WRITE_NODE_TYPE("EXTENSIBLENODE");
     497             : 
     498           0 :     WRITE_STRING_FIELD(extnodename);
     499             : 
     500             :     /* serialize the private fields */
     501           0 :     methods->nodeOut(str, node);
     502           0 : }
     503             : 
     504             : static void
     505     1692284 : _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
     506             : {
     507     1692284 :     WRITE_NODE_TYPE("RANGETBLENTRY");
     508             : 
     509     1692284 :     WRITE_NODE_FIELD(alias);
     510     1692284 :     WRITE_NODE_FIELD(eref);
     511     1692284 :     WRITE_ENUM_FIELD(rtekind, RTEKind);
     512             : 
     513     1692284 :     switch (node->rtekind)
     514             :     {
     515     1017530 :         case RTE_RELATION:
     516     1017530 :             WRITE_OID_FIELD(relid);
     517     1017530 :             WRITE_BOOL_FIELD(inh);
     518     1017530 :             WRITE_CHAR_FIELD(relkind);
     519     1017530 :             WRITE_INT_FIELD(rellockmode);
     520     1017530 :             WRITE_UINT_FIELD(perminfoindex);
     521     1017530 :             WRITE_NODE_FIELD(tablesample);
     522     1017530 :             break;
     523      138820 :         case RTE_SUBQUERY:
     524      138820 :             WRITE_NODE_FIELD(subquery);
     525      138820 :             WRITE_BOOL_FIELD(security_barrier);
     526             :             /* we re-use these RELATION fields, too: */
     527      138820 :             WRITE_OID_FIELD(relid);
     528      138820 :             WRITE_BOOL_FIELD(inh);
     529      138820 :             WRITE_CHAR_FIELD(relkind);
     530      138820 :             WRITE_INT_FIELD(rellockmode);
     531      138820 :             WRITE_UINT_FIELD(perminfoindex);
     532      138820 :             break;
     533      189302 :         case RTE_JOIN:
     534      189302 :             WRITE_ENUM_FIELD(jointype, JoinType);
     535      189302 :             WRITE_INT_FIELD(joinmergedcols);
     536      189302 :             WRITE_NODE_FIELD(joinaliasvars);
     537      189302 :             WRITE_NODE_FIELD(joinleftcols);
     538      189302 :             WRITE_NODE_FIELD(joinrightcols);
     539      189302 :             WRITE_NODE_FIELD(join_using_alias);
     540      189302 :             break;
     541      106230 :         case RTE_FUNCTION:
     542      106230 :             WRITE_NODE_FIELD(functions);
     543      106230 :             WRITE_BOOL_FIELD(funcordinality);
     544      106230 :             break;
     545        1296 :         case RTE_TABLEFUNC:
     546        1296 :             WRITE_NODE_FIELD(tablefunc);
     547        1296 :             break;
     548       21378 :         case RTE_VALUES:
     549       21378 :             WRITE_NODE_FIELD(values_lists);
     550       21378 :             WRITE_NODE_FIELD(coltypes);
     551       21378 :             WRITE_NODE_FIELD(coltypmods);
     552       21378 :             WRITE_NODE_FIELD(colcollations);
     553       21378 :             break;
     554       11860 :         case RTE_CTE:
     555       11860 :             WRITE_STRING_FIELD(ctename);
     556       11860 :             WRITE_UINT_FIELD(ctelevelsup);
     557       11860 :             WRITE_BOOL_FIELD(self_reference);
     558       11860 :             WRITE_NODE_FIELD(coltypes);
     559       11860 :             WRITE_NODE_FIELD(coltypmods);
     560       11860 :             WRITE_NODE_FIELD(colcollations);
     561       11860 :             break;
     562         942 :         case RTE_NAMEDTUPLESTORE:
     563         942 :             WRITE_STRING_FIELD(enrname);
     564         942 :             WRITE_FLOAT_FIELD(enrtuples);
     565         942 :             WRITE_NODE_FIELD(coltypes);
     566         942 :             WRITE_NODE_FIELD(coltypmods);
     567         942 :             WRITE_NODE_FIELD(colcollations);
     568             :             /* we re-use these RELATION fields, too: */
     569         942 :             WRITE_OID_FIELD(relid);
     570         942 :             break;
     571      195542 :         case RTE_RESULT:
     572             :             /* no extra fields */
     573      195542 :             break;
     574        9384 :         case RTE_GROUP:
     575        9384 :             WRITE_NODE_FIELD(groupexprs);
     576        9384 :             break;
     577           0 :         default:
     578           0 :             elog(ERROR, "unrecognized RTE kind: %d", (int) node->rtekind);
     579             :             break;
     580             :     }
     581             : 
     582     1692284 :     WRITE_BOOL_FIELD(lateral);
     583     1692284 :     WRITE_BOOL_FIELD(inFromCl);
     584     1692282 :     WRITE_NODE_FIELD(securityQuals);
     585     1692282 : }
     586             : 
     587             : static void
     588      665690 : _outA_Expr(StringInfo str, const A_Expr *node)
     589             : {
     590      665690 :     WRITE_NODE_TYPE("A_EXPR");
     591             : 
     592      665690 :     switch (node->kind)
     593             :     {
     594      615146 :         case AEXPR_OP:
     595      615146 :             WRITE_NODE_FIELD(name);
     596      615146 :             break;
     597       16916 :         case AEXPR_OP_ANY:
     598       16916 :             appendStringInfoString(str, " ANY");
     599       16916 :             WRITE_NODE_FIELD(name);
     600       16916 :             break;
     601         144 :         case AEXPR_OP_ALL:
     602         144 :             appendStringInfoString(str, " ALL");
     603         144 :             WRITE_NODE_FIELD(name);
     604         144 :             break;
     605        1256 :         case AEXPR_DISTINCT:
     606        1256 :             appendStringInfoString(str, " DISTINCT");
     607        1256 :             WRITE_NODE_FIELD(name);
     608        1256 :             break;
     609          74 :         case AEXPR_NOT_DISTINCT:
     610          74 :             appendStringInfoString(str, " NOT_DISTINCT");
     611          74 :             WRITE_NODE_FIELD(name);
     612          74 :             break;
     613         692 :         case AEXPR_NULLIF:
     614         692 :             appendStringInfoString(str, " NULLIF");
     615         692 :             WRITE_NODE_FIELD(name);
     616         692 :             break;
     617       28210 :         case AEXPR_IN:
     618       28210 :             appendStringInfoString(str, " IN");
     619       28210 :             WRITE_NODE_FIELD(name);
     620       28210 :             break;
     621        2338 :         case AEXPR_LIKE:
     622        2338 :             appendStringInfoString(str, " LIKE");
     623        2338 :             WRITE_NODE_FIELD(name);
     624        2338 :             break;
     625         202 :         case AEXPR_ILIKE:
     626         202 :             appendStringInfoString(str, " ILIKE");
     627         202 :             WRITE_NODE_FIELD(name);
     628         202 :             break;
     629         118 :         case AEXPR_SIMILAR:
     630         118 :             appendStringInfoString(str, " SIMILAR");
     631         118 :             WRITE_NODE_FIELD(name);
     632         118 :             break;
     633         558 :         case AEXPR_BETWEEN:
     634         558 :             appendStringInfoString(str, " BETWEEN");
     635         558 :             WRITE_NODE_FIELD(name);
     636         558 :             break;
     637          12 :         case AEXPR_NOT_BETWEEN:
     638          12 :             appendStringInfoString(str, " NOT_BETWEEN");
     639          12 :             WRITE_NODE_FIELD(name);
     640          12 :             break;
     641          12 :         case AEXPR_BETWEEN_SYM:
     642          12 :             appendStringInfoString(str, " BETWEEN_SYM");
     643          12 :             WRITE_NODE_FIELD(name);
     644          12 :             break;
     645          12 :         case AEXPR_NOT_BETWEEN_SYM:
     646          12 :             appendStringInfoString(str, " NOT_BETWEEN_SYM");
     647          12 :             WRITE_NODE_FIELD(name);
     648          12 :             break;
     649           0 :         default:
     650           0 :             elog(ERROR, "unrecognized A_Expr_Kind: %d", (int) node->kind);
     651             :             break;
     652             :     }
     653             : 
     654      665690 :     WRITE_NODE_FIELD(lexpr);
     655      665690 :     WRITE_NODE_FIELD(rexpr);
     656      665690 :     WRITE_LOCATION_FIELD(rexpr_list_start);
     657      665690 :     WRITE_LOCATION_FIELD(rexpr_list_end);
     658      665690 :     WRITE_LOCATION_FIELD(location);
     659      665690 : }
     660             : 
     661             : static void
     662      470430 : _outInteger(StringInfo str, const Integer *node)
     663             : {
     664      470430 :     appendStringInfo(str, "%d", node->ival);
     665      470430 : }
     666             : 
     667             : static void
     668       11992 : _outFloat(StringInfo str, const Float *node)
     669             : {
     670             :     /*
     671             :      * We assume the value is a valid numeric literal and so does not need
     672             :      * quoting.
     673             :      */
     674       11992 :     appendStringInfoString(str, node->fval);
     675       11992 : }
     676             : 
     677             : static void
     678      104230 : _outBoolean(StringInfo str, const Boolean *node)
     679             : {
     680      104230 :     appendStringInfoString(str, node->boolval ? "true" : "false");
     681      104230 : }
     682             : 
     683             : static void
     684    27633008 : _outString(StringInfo str, const String *node)
     685             : {
     686             :     /*
     687             :      * We use outToken to provide escaping of the string's content, but we
     688             :      * don't want it to convert an empty string to '""', because we're putting
     689             :      * double quotes around the string already.
     690             :      */
     691    27633008 :     appendStringInfoChar(str, '"');
     692    27633008 :     if (node->sval[0] != '\0')
     693    27600960 :         outToken(str, node->sval);
     694    27633008 :     appendStringInfoChar(str, '"');
     695    27633008 : }
     696             : 
     697             : static void
     698        4068 : _outBitString(StringInfo str, const BitString *node)
     699             : {
     700             :     /*
     701             :      * The lexer will always produce a string starting with 'b' or 'x'.  There
     702             :      * might be characters following that that need escaping, but outToken
     703             :      * won't escape the 'b' or 'x'.  This is relied on by nodeTokenType.
     704             :      */
     705             :     Assert(node->bsval[0] == 'b' || node->bsval[0] == 'x');
     706        4068 :     outToken(str, node->bsval);
     707        4068 : }
     708             : 
     709             : static void
     710     1450136 : _outA_Const(StringInfo str, const A_Const *node)
     711             : {
     712     1450136 :     WRITE_NODE_TYPE("A_CONST");
     713             : 
     714     1450136 :     if (node->isnull)
     715       86234 :         appendStringInfoString(str, " NULL");
     716             :     else
     717             :     {
     718     1363902 :         appendStringInfoString(str, " :val ");
     719     1363902 :         outNode(str, &node->val);
     720             :     }
     721     1450136 :     WRITE_LOCATION_FIELD(location);
     722     1450136 : }
     723             : 
     724             : 
     725             : /*
     726             :  * outNode -
     727             :  *    converts a Node into ascii string and append it to 'str'
     728             :  */
     729             : void
     730   147814972 : outNode(StringInfo str, const void *obj)
     731             : {
     732             :     /* Guard against stack overflow due to overly complex expressions */
     733   147814972 :     check_stack_depth();
     734             : 
     735   147814972 :     if (obj == NULL)
     736    52962478 :         appendStringInfoString(str, "<>");
     737    94852494 :     else if (IsA(obj, List) || IsA(obj, IntList) || IsA(obj, OidList) ||
     738    76568634 :              IsA(obj, XidList))
     739    18283860 :         _outList(str, obj);
     740             :     /* nodeRead does not want to see { } around these! */
     741    76568634 :     else if (IsA(obj, Integer))
     742      470430 :         _outInteger(str, (Integer *) obj);
     743    76098204 :     else if (IsA(obj, Float))
     744       11992 :         _outFloat(str, (Float *) obj);
     745    76086212 :     else if (IsA(obj, Boolean))
     746      104230 :         _outBoolean(str, (Boolean *) obj);
     747    75981982 :     else if (IsA(obj, String))
     748    27633008 :         _outString(str, (String *) obj);
     749    48348974 :     else if (IsA(obj, BitString))
     750        4068 :         _outBitString(str, (BitString *) obj);
     751    48344906 :     else if (IsA(obj, Bitmapset))
     752           0 :         outBitmapset(str, (Bitmapset *) obj);
     753             :     else
     754             :     {
     755    48344906 :         appendStringInfoChar(str, '{');
     756    48344906 :         switch (nodeTag(obj))
     757             :         {
     758             : #include "outfuncs.switch.c"
     759             : 
     760           0 :             default:
     761             : 
     762             :                 /*
     763             :                  * This should be an ERROR, but it's too useful to be able to
     764             :                  * dump structures that outNode only understands part of.
     765             :                  */
     766           0 :                 elog(WARNING, "could not dump unrecognized node type: %d",
     767             :                      (int) nodeTag(obj));
     768           0 :                 break;
     769             :         }
     770    48344906 :         appendStringInfoChar(str, '}');
     771             :     }
     772   147814972 : }
     773             : 
     774             : /*
     775             :  * nodeToString -
     776             :  *     returns the ascii representation of the Node as a palloc'd string
     777             :  *
     778             :  * write_loc_fields determines whether location fields are output with their
     779             :  * actual value rather than -1.  The actual value can be useful for debugging,
     780             :  * but for most uses, the actual value is not useful, since the original query
     781             :  * string is no longer available.
     782             :  */
     783             : static char *
     784     2021696 : nodeToStringInternal(const void *obj, bool write_loc_fields)
     785             : {
     786             :     StringInfoData str;
     787             :     bool        save_write_location_fields;
     788             : 
     789     2021696 :     save_write_location_fields = write_location_fields;
     790     2021696 :     write_location_fields = write_loc_fields;
     791             : 
     792             :     /* see stringinfo.h for an explanation of this maneuver */
     793     2021696 :     initStringInfo(&str);
     794     2021696 :     outNode(&str, obj);
     795             : 
     796     2021696 :     write_location_fields = save_write_location_fields;
     797             : 
     798     2021696 :     return str.data;
     799             : }
     800             : 
     801             : /*
     802             :  * Externally visible entry points
     803             :  */
     804             : char *
     805       69310 : nodeToString(const void *obj)
     806             : {
     807       69310 :     return nodeToStringInternal(obj, false);
     808             : }
     809             : 
     810             : char *
     811     1952386 : nodeToStringWithLocations(const void *obj)
     812             : {
     813     1952386 :     return nodeToStringInternal(obj, true);
     814             : }
     815             : 
     816             : 
     817             : /*
     818             :  * bmsToString -
     819             :  *     returns the ascii representation of the Bitmapset as a palloc'd string
     820             :  */
     821             : char *
     822           0 : bmsToString(const Bitmapset *bms)
     823             : {
     824             :     StringInfoData str;
     825             : 
     826             :     /* see stringinfo.h for an explanation of this maneuver */
     827           0 :     initStringInfo(&str);
     828           0 :     outBitmapset(&str, bms);
     829           0 :     return str.data;
     830             : }

Generated by: LCOV version 1.16