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

Generated by: LCOV version 1.14