LCOV - code coverage report
Current view: top level - src/backend/nodes - outfuncs.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 81.5 % 378 308
Test Date: 2026-04-07 14:16:30 Functions: 80.0 % 30 24
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-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     33086453 : outToken(StringInfo str, const char *s)
     156              : {
     157     33086453 :     if (s == NULL)
     158              :     {
     159      6756371 :         appendStringInfoString(str, "<>");
     160      6756371 :         return;
     161              :     }
     162     26330082 :     if (*s == '\0')
     163              :     {
     164          154 :         appendStringInfoString(str, "\"\"");
     165          154 :         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     26329928 :     if (*s == '<' ||
     175     26287205 :         *s == '"' ||
     176     26283274 :         isdigit((unsigned char) *s) ||
     177     26160074 :         ((*s == '+' || *s == '-') &&
     178        20417 :          (isdigit((unsigned char) s[1]) || s[1] == '.')))
     179       173250 :         appendStringInfoChar(str, '\\');
     180    239491371 :     while (*s)
     181              :     {
     182              :         /* These chars must be backslashed anywhere in the string */
     183    213161443 :         if (*s == ' ' || *s == '\n' || *s == '\t' ||
     184    212403096 :             *s == '(' || *s == ')' || *s == '{' || *s == '}' ||
     185    211963383 :             *s == '\\')
     186      1206345 :             appendStringInfoChar(str, '\\');
     187    213161443 :         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      1993122 : outChar(StringInfo str, char c)
     197              : {
     198              :     char        in[2];
     199              : 
     200              :     /* Traditionally, we've represented \0 as <>, so keep doing that */
     201      1993122 :     if (c == '\0')
     202              :     {
     203       595552 :         appendStringInfoString(str, "<>");
     204       595552 :         return;
     205              :     }
     206              : 
     207      1397570 :     in[0] = c;
     208      1397570 :     in[1] = '\0';
     209              : 
     210      1397570 :     outToken(str, in);
     211              : }
     212              : 
     213              : /*
     214              :  * Convert a double value, attempting to ensure the value is preserved exactly.
     215              :  */
     216              : static void
     217      2511556 : outDouble(StringInfo str, double d)
     218              : {
     219              :     char        buf[DOUBLE_SHORTEST_DECIMAL_LEN];
     220              : 
     221      2511556 :     double_to_shortest_decimal_buf(d, buf);
     222      2511556 :     appendStringInfoString(str, buf);
     223      2511556 : }
     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       368593 : WRITE_SCALAR_ARRAY(writeAttrNumberCols, AttrNumber, " %d",)
     249       446730 : WRITE_SCALAR_ARRAY(writeOidCols, Oid, " %u",)
     250            0 : WRITE_SCALAR_ARRAY(writeIndexCols, Index, " %u",)
     251         9744 : WRITE_SCALAR_ARRAY(writeIntCols, int, " %d",)
     252       165685 : 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     12273206 : _outList(StringInfo str, const List *node)
     282              : {
     283              :     const ListCell *lc;
     284              : 
     285     12273206 :     appendStringInfoChar(str, '(');
     286              : 
     287     12273206 :     if (IsA(node, IntList))
     288       279811 :         appendStringInfoChar(str, 'i');
     289     11993395 :     else if (IsA(node, OidList))
     290       475639 :         appendStringInfoChar(str, 'o');
     291     11517756 :     else if (IsA(node, XidList))
     292            0 :         appendStringInfoChar(str, 'x');
     293              : 
     294     52935724 :     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     40662518 :         if (IsA(node, List))
     302              :         {
     303     36655254 :             outNode(str, lfirst(lc));
     304     36655254 :             if (lnext(node, lc))
     305     25137498 :                 appendStringInfoChar(str, ' ');
     306              :         }
     307      4007264 :         else if (IsA(node, IntList))
     308      3002687 :             appendStringInfo(str, " %d", lfirst_int(lc));
     309      1004577 :         else if (IsA(node, OidList))
     310      1004577 :             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     12273206 :     appendStringInfoChar(str, ')');
     319     12273206 : }
     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     13676199 : outBitmapset(StringInfo str, const Bitmapset *bms)
     332              : {
     333              :     int         x;
     334              : 
     335     13676199 :     appendStringInfoChar(str, '(');
     336     13676199 :     appendStringInfoChar(str, 'b');
     337     13676199 :     x = -1;
     338     17552134 :     while ((x = bms_next_member(bms, x)) >= 0)
     339      3875935 :         appendStringInfo(str, " %d", x);
     340     13676199 :     appendStringInfoChar(str, ')');
     341     13676199 : }
     342              : 
     343              : /*
     344              :  * Print the value of a Datum given its type.
     345              :  */
     346              : void
     347      1661655 : outDatum(StringInfo str, Datum value, int typlen, bool typbyval)
     348              : {
     349              :     Size        length;
     350              :     char       *s;
     351              : 
     352      1661655 :     length = datumGetSize(value, typbyval, typlen);
     353              : 
     354      1661655 :     if (typbyval)
     355              :     {
     356      1070508 :         s = (char *) (&value);
     357      1070508 :         appendStringInfo(str, "%zu [ ", length);
     358      9634572 :         for (Size i = 0; i < (Size) sizeof(Datum); i++)
     359      8564064 :             appendStringInfo(str, "%d ", (int) (s[i]));
     360      1070508 :         appendStringInfoChar(str, ']');
     361              :     }
     362              :     else
     363              :     {
     364       591147 :         s = (char *) DatumGetPointer(value);
     365       591147 :         if (!s)
     366            0 :             appendStringInfoString(str, "0 [ ]");
     367              :         else
     368              :         {
     369       591147 :             appendStringInfo(str, "%zu [ ", length);
     370     77603803 :             for (Size i = 0; i < length; i++)
     371     77012656 :                 appendStringInfo(str, "%d ", (int) (s[i]));
     372       591147 :             appendStringInfoChar(str, ']');
     373              :         }
     374              :     }
     375      1661655 : }
     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      1830091 : _outConst(StringInfo str, const Const *node)
     388              : {
     389      1830091 :     WRITE_NODE_TYPE("CONST");
     390              : 
     391      1830091 :     WRITE_OID_FIELD(consttype);
     392      1830091 :     WRITE_INT_FIELD(consttypmod);
     393      1830091 :     WRITE_OID_FIELD(constcollid);
     394      1830091 :     WRITE_INT_FIELD(constlen);
     395      1830091 :     WRITE_BOOL_FIELD(constbyval);
     396      1830091 :     WRITE_BOOL_FIELD(constisnull);
     397      1830091 :     WRITE_LOCATION_FIELD(location);
     398              : 
     399      1830091 :     appendStringInfoString(str, " :constvalue ");
     400      1830091 :     if (node->constisnull)
     401       168436 :         appendStringInfoString(str, "<>");
     402              :     else
     403      1661655 :         outDatum(str, node->constvalue, node->constlen, node->constbyval);
     404      1830091 : }
     405              : 
     406              : static void
     407       284066 : _outBoolExpr(StringInfo str, const BoolExpr *node)
     408              : {
     409       284066 :     char       *opstr = NULL;
     410              : 
     411       284066 :     WRITE_NODE_TYPE("BOOLEXPR");
     412              : 
     413              :     /* do-it-yourself enum representation */
     414       284066 :     switch (node->boolop)
     415              :     {
     416       199561 :         case AND_EXPR:
     417       199561 :             opstr = "and";
     418       199561 :             break;
     419        38606 :         case OR_EXPR:
     420        38606 :             opstr = "or";
     421        38606 :             break;
     422        45899 :         case NOT_EXPR:
     423        45899 :             opstr = "not";
     424        45899 :             break;
     425              :     }
     426       284066 :     appendStringInfoString(str, " :boolop ");
     427       284066 :     outToken(str, opstr);
     428              : 
     429       284066 :     WRITE_NODE_FIELD(args);
     430       284066 :     WRITE_LOCATION_FIELD(location);
     431       284066 : }
     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      1162790 : _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
     503              : {
     504      1162790 :     WRITE_NODE_TYPE("RANGETBLENTRY");
     505              : 
     506      1162790 :     WRITE_NODE_FIELD(alias);
     507      1162790 :     WRITE_NODE_FIELD(eref);
     508      1162790 :     WRITE_ENUM_FIELD(rtekind, RTEKind);
     509              : 
     510      1162790 :     switch (node->rtekind)
     511              :     {
     512       694861 :         case RTE_RELATION:
     513       694861 :             WRITE_OID_FIELD(relid);
     514       694861 :             WRITE_BOOL_FIELD(inh);
     515       694861 :             WRITE_CHAR_FIELD(relkind);
     516       694861 :             WRITE_INT_FIELD(rellockmode);
     517       694861 :             WRITE_UINT_FIELD(perminfoindex);
     518       694861 :             WRITE_NODE_FIELD(tablesample);
     519       694861 :             break;
     520       110132 :         case RTE_SUBQUERY:
     521       110132 :             WRITE_NODE_FIELD(subquery);
     522       110132 :             WRITE_BOOL_FIELD(security_barrier);
     523              :             /* we re-use these RELATION fields, too: */
     524       110132 :             WRITE_OID_FIELD(relid);
     525       110132 :             WRITE_BOOL_FIELD(inh);
     526       110132 :             WRITE_CHAR_FIELD(relkind);
     527       110132 :             WRITE_INT_FIELD(rellockmode);
     528       110132 :             WRITE_UINT_FIELD(perminfoindex);
     529       110132 :             break;
     530       136843 :         case RTE_JOIN:
     531       136843 :             WRITE_ENUM_FIELD(jointype, JoinType);
     532       136843 :             WRITE_INT_FIELD(joinmergedcols);
     533       136843 :             WRITE_NODE_FIELD(joinaliasvars);
     534       136843 :             WRITE_NODE_FIELD(joinleftcols);
     535       136843 :             WRITE_NODE_FIELD(joinrightcols);
     536       136843 :             WRITE_NODE_FIELD(join_using_alias);
     537       136843 :             break;
     538        66286 :         case RTE_FUNCTION:
     539        66286 :             WRITE_NODE_FIELD(functions);
     540        66286 :             WRITE_BOOL_FIELD(funcordinality);
     541        66286 :             break;
     542          858 :         case RTE_TABLEFUNC:
     543          858 :             WRITE_NODE_FIELD(tablefunc);
     544          858 :             break;
     545        14583 :         case RTE_VALUES:
     546        14583 :             WRITE_NODE_FIELD(values_lists);
     547        14583 :             WRITE_NODE_FIELD(coltypes);
     548        14583 :             WRITE_NODE_FIELD(coltypmods);
     549        14583 :             WRITE_NODE_FIELD(colcollations);
     550        14583 :             break;
     551         7741 :         case RTE_CTE:
     552         7741 :             WRITE_STRING_FIELD(ctename);
     553         7741 :             WRITE_UINT_FIELD(ctelevelsup);
     554         7741 :             WRITE_BOOL_FIELD(self_reference);
     555         7741 :             WRITE_NODE_FIELD(coltypes);
     556         7741 :             WRITE_NODE_FIELD(coltypmods);
     557         7741 :             WRITE_NODE_FIELD(colcollations);
     558         7741 :             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       123794 :         case RTE_RESULT:
     578              :             /* no extra fields */
     579       123794 :             break;
     580         6967 :         case RTE_GROUP:
     581         6967 :             WRITE_NODE_FIELD(groupexprs);
     582         6967 :             break;
     583            0 :         default:
     584            0 :             elog(ERROR, "unrecognized RTE kind: %d", (int) node->rtekind);
     585              :             break;
     586              :     }
     587              : 
     588      1162790 :     WRITE_BOOL_FIELD(lateral);
     589      1162790 :     WRITE_BOOL_FIELD(inFromCl);
     590      1162790 :     WRITE_NODE_FIELD(securityQuals);
     591      1162790 : }
     592              : 
     593              : static void
     594       436726 : _outA_Expr(StringInfo str, const A_Expr *node)
     595              : {
     596       436726 :     WRITE_NODE_TYPE("A_EXPR");
     597              : 
     598       436726 :     switch (node->kind)
     599              :     {
     600       405406 :         case AEXPR_OP:
     601       405406 :             WRITE_NODE_FIELD(name);
     602       405406 :             break;
     603        11028 :         case AEXPR_OP_ANY:
     604        11028 :             appendStringInfoString(str, " ANY");
     605        11028 :             WRITE_NODE_FIELD(name);
     606        11028 :             break;
     607           96 :         case AEXPR_OP_ALL:
     608           96 :             appendStringInfoString(str, " ALL");
     609           96 :             WRITE_NODE_FIELD(name);
     610           96 :             break;
     611          779 :         case AEXPR_DISTINCT:
     612          779 :             appendStringInfoString(str, " DISTINCT");
     613          779 :             WRITE_NODE_FIELD(name);
     614          779 :             break;
     615           88 :         case AEXPR_NOT_DISTINCT:
     616           88 :             appendStringInfoString(str, " NOT_DISTINCT");
     617           88 :             WRITE_NODE_FIELD(name);
     618           88 :             break;
     619          583 :         case AEXPR_NULLIF:
     620          583 :             appendStringInfoString(str, " NULLIF");
     621          583 :             WRITE_NODE_FIELD(name);
     622          583 :             break;
     623        16624 :         case AEXPR_IN:
     624        16624 :             appendStringInfoString(str, " IN");
     625        16624 :             WRITE_NODE_FIELD(name);
     626        16624 :             break;
     627         1516 :         case AEXPR_LIKE:
     628         1516 :             appendStringInfoString(str, " LIKE");
     629         1516 :             WRITE_NODE_FIELD(name);
     630         1516 :             break;
     631          132 :         case AEXPR_ILIKE:
     632          132 :             appendStringInfoString(str, " ILIKE");
     633          132 :             WRITE_NODE_FIELD(name);
     634          132 :             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       436726 :     WRITE_NODE_FIELD(lexpr);
     661       436726 :     WRITE_NODE_FIELD(rexpr);
     662       436726 :     WRITE_LOCATION_FIELD(rexpr_list_start);
     663       436726 :     WRITE_LOCATION_FIELD(rexpr_list_end);
     664       436726 :     WRITE_LOCATION_FIELD(location);
     665       436726 : }
     666              : 
     667              : static void
     668       458873 : _outInteger(StringInfo str, const Integer *node)
     669              : {
     670       458873 :     appendStringInfo(str, "%d", node->ival);
     671       458873 : }
     672              : 
     673              : static void
     674         8059 : _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         8059 :     appendStringInfoString(str, node->fval);
     681         8059 : }
     682              : 
     683              : static void
     684        57354 : _outBoolean(StringInfo str, const Boolean *node)
     685              : {
     686        57354 :     appendStringInfoString(str, node->boolval ? "true" : "false");
     687        57354 : }
     688              : 
     689              : static void
     690     18584128 : _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     18584128 :     appendStringInfoChar(str, '"');
     698     18584128 :     if (node->sval[0] != '\0')
     699     18563604 :         outToken(str, node->sval);
     700     18584128 :     appendStringInfoChar(str, '"');
     701     18584128 : }
     702              : 
     703              : static void
     704         2727 : _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         2727 :     outToken(str, node->bsval);
     713         2727 : }
     714              : 
     715              : static void
     716       951698 : _outA_Const(StringInfo str, const A_Const *node)
     717              : {
     718       951698 :     WRITE_NODE_TYPE("A_CONST");
     719              : 
     720       951698 :     if (node->isnull)
     721        55541 :         appendStringInfoString(str, " NULL");
     722              :     else
     723              :     {
     724       896157 :         appendStringInfoString(str, " :val ");
     725       896157 :         outNode(str, &node->val);
     726              :     }
     727       951698 :     WRITE_LOCATION_FIELD(location);
     728       951698 : }
     729              : 
     730              : 
     731              : /*
     732              :  * outNode -
     733              :  *    converts a Node into ascii string and append it to 'str'
     734              :  */
     735              : void
     736     99998156 : outNode(StringInfo str, const void *obj)
     737              : {
     738              :     /* Guard against stack overflow due to overly complex expressions */
     739     99998156 :     check_stack_depth();
     740              : 
     741     99998156 :     if (obj == NULL)
     742     35770920 :         appendStringInfoString(str, "<>");
     743     64227236 :     else if (IsA(obj, List) || IsA(obj, IntList) || IsA(obj, OidList) ||
     744     51954030 :              IsA(obj, XidList))
     745     12273206 :         _outList(str, obj);
     746              :     /* nodeRead does not want to see { } around these! */
     747     51954030 :     else if (IsA(obj, Integer))
     748       458873 :         _outInteger(str, (const Integer *) obj);
     749     51495157 :     else if (IsA(obj, Float))
     750         8059 :         _outFloat(str, (const Float *) obj);
     751     51487098 :     else if (IsA(obj, Boolean))
     752        57354 :         _outBoolean(str, (const Boolean *) obj);
     753     51429744 :     else if (IsA(obj, String))
     754     18584128 :         _outString(str, (const String *) obj);
     755     32845616 :     else if (IsA(obj, BitString))
     756         2727 :         _outBitString(str, (const BitString *) obj);
     757     32842889 :     else if (IsA(obj, Bitmapset))
     758         1847 :         outBitmapset(str, (const Bitmapset *) obj);
     759              :     else
     760              :     {
     761     32841042 :         appendStringInfoChar(str, '{');
     762     32841042 :         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     32841042 :         appendStringInfoChar(str, '}');
     777              :     }
     778     99998156 : }
     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      1283625 : nodeToStringInternal(const void *obj, bool write_loc_fields)
     791              : {
     792              :     StringInfoData str;
     793              :     bool        save_write_location_fields;
     794              : 
     795      1283625 :     save_write_location_fields = write_location_fields;
     796      1283625 :     write_location_fields = write_loc_fields;
     797              : 
     798              :     /* see stringinfo.h for an explanation of this maneuver */
     799      1283625 :     initStringInfo(&str);
     800      1283625 :     outNode(&str, obj);
     801              : 
     802      1283625 :     write_location_fields = save_write_location_fields;
     803              : 
     804      1283625 :     return str.data;
     805              : }
     806              : 
     807              : /*
     808              :  * Externally visible entry points
     809              :  */
     810              : char *
     811        48256 : nodeToString(const void *obj)
     812              : {
     813        48256 :     return nodeToStringInternal(obj, false);
     814              : }
     815              : 
     816              : char *
     817      1235369 : nodeToStringWithLocations(const void *obj)
     818              : {
     819      1235369 :     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