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 49241246 : outToken(StringInfo str, const char *s)
150 : {
151 49241246 : if (s == NULL)
152 : {
153 10041406 : appendStringInfoString(str, "<>");
154 10041406 : return;
155 : }
156 39199840 : 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 39199684 : if (*s == '<' ||
169 39131520 : *s == '"' ||
170 39125440 : isdigit((unsigned char) *s) ||
171 38916920 : ((*s == '+' || *s == '-') &&
172 32846 : (isdigit((unsigned char) s[1]) || s[1] == '.')))
173 289886 : appendStringInfoChar(str, '\\');
174 354134810 : while (*s)
175 : {
176 : /* These chars must be backslashed anywhere in the string */
177 314935126 : if (*s == ' ' || *s == '\n' || *s == '\t' ||
178 313573262 : *s == '(' || *s == ')' || *s == '{' || *s == '}' ||
179 313336428 : *s == '\\')
180 1609404 : appendStringInfoChar(str, '\\');
181 314935126 : 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 3010438 : outChar(StringInfo str, char c)
191 : {
192 : char in[2];
193 :
194 : /* Traditionally, we've represented \0 as <>, so keep doing that */
195 3010438 : if (c == '\0')
196 : {
197 909128 : appendStringInfoString(str, "<>");
198 909128 : return;
199 : }
200 :
201 2101310 : in[0] = c;
202 2101310 : in[1] = '\0';
203 :
204 2101310 : outToken(str, in);
205 : }
206 :
207 : /*
208 : * Convert a double value, attempting to ensure the value is preserved exactly.
209 : */
210 : static void
211 3612934 : outDouble(StringInfo str, double d)
212 : {
213 : char buf[DOUBLE_SHORTEST_DECIMAL_LEN];
214 :
215 3612934 : double_to_shortest_decimal_buf(d, buf);
216 3612934 : appendStringInfoString(str, buf);
217 3612934 : }
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 476432 : WRITE_SCALAR_ARRAY(writeAttrNumberCols, AttrNumber, " %d",)
243 644882 : WRITE_SCALAR_ARRAY(writeOidCols, Oid, " %u",)
244 0 : WRITE_SCALAR_ARRAY(writeIndexCols, Index, " %u",)
245 14526 : WRITE_SCALAR_ARRAY(writeIntCols, int, " %d",)
246 245512 : 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 18545024 : _outList(StringInfo str, const List *node)
276 : {
277 : const ListCell *lc;
278 :
279 18545024 : appendStringInfoChar(str, '(');
280 :
281 18545024 : if (IsA(node, IntList))
282 594618 : appendStringInfoChar(str, 'i');
283 17950406 : else if (IsA(node, OidList))
284 713678 : appendStringInfoChar(str, 'o');
285 17236728 : else if (IsA(node, XidList))
286 0 : appendStringInfoChar(str, 'x');
287 :
288 78666060 : 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 60121036 : if (IsA(node, List))
296 : {
297 54274802 : outNode(str, lfirst(lc));
298 54274802 : if (lnext(node, lc))
299 37038074 : appendStringInfoChar(str, ' ');
300 : }
301 5846234 : else if (IsA(node, IntList))
302 4441044 : appendStringInfo(str, " %d", lfirst_int(lc));
303 1405190 : else if (IsA(node, OidList))
304 1405190 : 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 18545024 : appendStringInfoChar(str, ')');
313 18545024 : }
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 19019870 : outBitmapset(StringInfo str, const Bitmapset *bms)
326 : {
327 : int x;
328 :
329 19019870 : appendStringInfoChar(str, '(');
330 19019870 : appendStringInfoChar(str, 'b');
331 19019870 : x = -1;
332 24421102 : while ((x = bms_next_member(bms, x)) >= 0)
333 5401232 : appendStringInfo(str, " %d", x);
334 19019870 : appendStringInfoChar(str, ')');
335 19019870 : }
336 :
337 : /*
338 : * Print the value of a Datum given its type.
339 : */
340 : void
341 2592102 : outDatum(StringInfo str, Datum value, int typlen, bool typbyval)
342 : {
343 : Size length,
344 : i;
345 : char *s;
346 :
347 2592102 : length = datumGetSize(value, typbyval, typlen);
348 :
349 2592102 : if (typbyval)
350 : {
351 1650942 : s = (char *) (&value);
352 1650942 : appendStringInfo(str, "%u [ ", (unsigned int) length);
353 14858478 : for (i = 0; i < (Size) sizeof(Datum); i++)
354 13207536 : appendStringInfo(str, "%d ", (int) (s[i]));
355 1650942 : appendStringInfoChar(str, ']');
356 : }
357 : else
358 : {
359 941160 : s = (char *) DatumGetPointer(value);
360 941160 : if (!PointerIsValid(s))
361 0 : appendStringInfoString(str, "0 [ ]");
362 : else
363 : {
364 941160 : appendStringInfo(str, "%u [ ", (unsigned int) length);
365 121486528 : for (i = 0; i < length; i++)
366 120545368 : appendStringInfo(str, "%d ", (int) (s[i]));
367 941160 : appendStringInfoChar(str, ']');
368 : }
369 : }
370 2592102 : }
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 2802742 : _outConst(StringInfo str, const Const *node)
383 : {
384 2802742 : WRITE_NODE_TYPE("CONST");
385 :
386 2802742 : WRITE_OID_FIELD(consttype);
387 2802742 : WRITE_INT_FIELD(consttypmod);
388 2802742 : WRITE_OID_FIELD(constcollid);
389 2802742 : WRITE_INT_FIELD(constlen);
390 2802742 : WRITE_BOOL_FIELD(constbyval);
391 2802742 : WRITE_BOOL_FIELD(constisnull);
392 2802742 : WRITE_LOCATION_FIELD(location);
393 :
394 2802742 : appendStringInfoString(str, " :constvalue ");
395 2802742 : if (node->constisnull)
396 210640 : appendStringInfoString(str, "<>");
397 : else
398 2592102 : outDatum(str, node->constvalue, node->constlen, node->constbyval);
399 2802742 : }
400 :
401 : static void
402 380648 : _outBoolExpr(StringInfo str, const BoolExpr *node)
403 : {
404 380648 : char *opstr = NULL;
405 :
406 380648 : WRITE_NODE_TYPE("BOOLEXPR");
407 :
408 : /* do-it-yourself enum representation */
409 380648 : switch (node->boolop)
410 : {
411 286850 : case AND_EXPR:
412 286850 : opstr = "and";
413 286850 : break;
414 44112 : case OR_EXPR:
415 44112 : opstr = "or";
416 44112 : break;
417 49686 : case NOT_EXPR:
418 49686 : opstr = "not";
419 49686 : break;
420 : }
421 380648 : appendStringInfoString(str, " :boolop ");
422 380648 : outToken(str, opstr);
423 :
424 380648 : WRITE_NODE_FIELD(args);
425 380648 : WRITE_LOCATION_FIELD(location);
426 380648 : }
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_INT_FIELD(ec_childmembers_size);
469 0 : WRITE_NODE_FIELD(ec_members);
470 0 : WRITE_NODE_ARRAY(ec_childmembers, node->ec_childmembers_size);
471 0 : WRITE_NODE_FIELD(ec_sources);
472 : /* Only ec_derives_list is written; hash is not serialized. */
473 0 : WRITE_NODE_FIELD(ec_derives_list);
474 0 : WRITE_BITMAPSET_FIELD(ec_relids);
475 0 : WRITE_BOOL_FIELD(ec_has_const);
476 0 : WRITE_BOOL_FIELD(ec_has_volatile);
477 0 : WRITE_BOOL_FIELD(ec_broken);
478 0 : WRITE_UINT_FIELD(ec_sortref);
479 0 : WRITE_UINT_FIELD(ec_min_security);
480 0 : WRITE_UINT_FIELD(ec_max_security);
481 0 : }
482 :
483 : static void
484 0 : _outExtensibleNode(StringInfo str, const ExtensibleNode *node)
485 : {
486 : const ExtensibleNodeMethods *methods;
487 :
488 0 : methods = GetExtensibleNodeMethods(node->extnodename, false);
489 :
490 0 : WRITE_NODE_TYPE("EXTENSIBLENODE");
491 :
492 0 : WRITE_STRING_FIELD(extnodename);
493 :
494 : /* serialize the private fields */
495 0 : methods->nodeOut(str, node);
496 0 : }
497 :
498 : static void
499 1716468 : _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
500 : {
501 1716468 : WRITE_NODE_TYPE("RANGETBLENTRY");
502 :
503 1716468 : WRITE_NODE_FIELD(alias);
504 1716468 : WRITE_NODE_FIELD(eref);
505 1716468 : WRITE_ENUM_FIELD(rtekind, RTEKind);
506 :
507 1716468 : switch (node->rtekind)
508 : {
509 1027468 : case RTE_RELATION:
510 1027468 : WRITE_OID_FIELD(relid);
511 1027468 : WRITE_BOOL_FIELD(inh);
512 1027468 : WRITE_CHAR_FIELD(relkind);
513 1027468 : WRITE_INT_FIELD(rellockmode);
514 1027468 : WRITE_UINT_FIELD(perminfoindex);
515 1027468 : WRITE_NODE_FIELD(tablesample);
516 1027468 : break;
517 138902 : case RTE_SUBQUERY:
518 138902 : WRITE_NODE_FIELD(subquery);
519 138902 : WRITE_BOOL_FIELD(security_barrier);
520 : /* we re-use these RELATION fields, too: */
521 138902 : WRITE_OID_FIELD(relid);
522 138902 : WRITE_BOOL_FIELD(inh);
523 138902 : WRITE_CHAR_FIELD(relkind);
524 138902 : WRITE_INT_FIELD(rellockmode);
525 138902 : WRITE_UINT_FIELD(perminfoindex);
526 138902 : break;
527 189804 : case RTE_JOIN:
528 189804 : WRITE_ENUM_FIELD(jointype, JoinType);
529 189804 : WRITE_INT_FIELD(joinmergedcols);
530 189804 : WRITE_NODE_FIELD(joinaliasvars);
531 189804 : WRITE_NODE_FIELD(joinleftcols);
532 189804 : WRITE_NODE_FIELD(joinrightcols);
533 189804 : WRITE_NODE_FIELD(join_using_alias);
534 189804 : break;
535 113732 : case RTE_FUNCTION:
536 113732 : WRITE_NODE_FIELD(functions);
537 113732 : WRITE_BOOL_FIELD(funcordinality);
538 113732 : break;
539 1296 : case RTE_TABLEFUNC:
540 1296 : WRITE_NODE_FIELD(tablefunc);
541 1296 : break;
542 21340 : case RTE_VALUES:
543 21340 : WRITE_NODE_FIELD(values_lists);
544 21340 : WRITE_NODE_FIELD(coltypes);
545 21340 : WRITE_NODE_FIELD(coltypmods);
546 21340 : WRITE_NODE_FIELD(colcollations);
547 21340 : break;
548 11918 : case RTE_CTE:
549 11918 : WRITE_STRING_FIELD(ctename);
550 11918 : WRITE_UINT_FIELD(ctelevelsup);
551 11918 : WRITE_BOOL_FIELD(self_reference);
552 11918 : WRITE_NODE_FIELD(coltypes);
553 11918 : WRITE_NODE_FIELD(coltypmods);
554 11918 : WRITE_NODE_FIELD(colcollations);
555 11918 : break;
556 942 : case RTE_NAMEDTUPLESTORE:
557 942 : WRITE_STRING_FIELD(enrname);
558 942 : WRITE_FLOAT_FIELD(enrtuples);
559 942 : WRITE_NODE_FIELD(coltypes);
560 942 : WRITE_NODE_FIELD(coltypmods);
561 942 : WRITE_NODE_FIELD(colcollations);
562 : /* we re-use these RELATION fields, too: */
563 942 : WRITE_OID_FIELD(relid);
564 942 : break;
565 201690 : case RTE_RESULT:
566 : /* no extra fields */
567 201690 : break;
568 9376 : case RTE_GROUP:
569 9376 : WRITE_NODE_FIELD(groupexprs);
570 9376 : break;
571 0 : default:
572 0 : elog(ERROR, "unrecognized RTE kind: %d", (int) node->rtekind);
573 : break;
574 : }
575 :
576 1716468 : WRITE_BOOL_FIELD(lateral);
577 1716468 : WRITE_BOOL_FIELD(inFromCl);
578 1716468 : WRITE_NODE_FIELD(securityQuals);
579 1716468 : }
580 :
581 : static void
582 662670 : _outA_Expr(StringInfo str, const A_Expr *node)
583 : {
584 662670 : WRITE_NODE_TYPE("A_EXPR");
585 :
586 662670 : switch (node->kind)
587 : {
588 612118 : case AEXPR_OP:
589 612118 : WRITE_NODE_FIELD(name);
590 612118 : break;
591 17192 : case AEXPR_OP_ANY:
592 17192 : appendStringInfoString(str, " ANY");
593 17192 : WRITE_NODE_FIELD(name);
594 17192 : break;
595 144 : case AEXPR_OP_ALL:
596 144 : appendStringInfoString(str, " ALL");
597 144 : WRITE_NODE_FIELD(name);
598 144 : break;
599 1256 : case AEXPR_DISTINCT:
600 1256 : appendStringInfoString(str, " DISTINCT");
601 1256 : WRITE_NODE_FIELD(name);
602 1256 : break;
603 74 : case AEXPR_NOT_DISTINCT:
604 74 : appendStringInfoString(str, " NOT_DISTINCT");
605 74 : WRITE_NODE_FIELD(name);
606 74 : break;
607 688 : case AEXPR_NULLIF:
608 688 : appendStringInfoString(str, " NULLIF");
609 688 : WRITE_NODE_FIELD(name);
610 688 : break;
611 27992 : case AEXPR_IN:
612 27992 : appendStringInfoString(str, " IN");
613 27992 : WRITE_NODE_FIELD(name);
614 27992 : break;
615 2338 : case AEXPR_LIKE:
616 2338 : appendStringInfoString(str, " LIKE");
617 2338 : WRITE_NODE_FIELD(name);
618 2338 : break;
619 204 : case AEXPR_ILIKE:
620 204 : appendStringInfoString(str, " ILIKE");
621 204 : WRITE_NODE_FIELD(name);
622 204 : break;
623 70 : case AEXPR_SIMILAR:
624 70 : appendStringInfoString(str, " SIMILAR");
625 70 : WRITE_NODE_FIELD(name);
626 70 : break;
627 558 : case AEXPR_BETWEEN:
628 558 : appendStringInfoString(str, " BETWEEN");
629 558 : WRITE_NODE_FIELD(name);
630 558 : break;
631 12 : case AEXPR_NOT_BETWEEN:
632 12 : appendStringInfoString(str, " NOT_BETWEEN");
633 12 : WRITE_NODE_FIELD(name);
634 12 : break;
635 12 : case AEXPR_BETWEEN_SYM:
636 12 : appendStringInfoString(str, " BETWEEN_SYM");
637 12 : WRITE_NODE_FIELD(name);
638 12 : break;
639 12 : case AEXPR_NOT_BETWEEN_SYM:
640 12 : appendStringInfoString(str, " NOT_BETWEEN_SYM");
641 12 : WRITE_NODE_FIELD(name);
642 12 : break;
643 0 : default:
644 0 : elog(ERROR, "unrecognized A_Expr_Kind: %d", (int) node->kind);
645 : break;
646 : }
647 :
648 662670 : WRITE_NODE_FIELD(lexpr);
649 662670 : WRITE_NODE_FIELD(rexpr);
650 662670 : WRITE_LOCATION_FIELD(location);
651 662670 : }
652 :
653 : static void
654 478208 : _outInteger(StringInfo str, const Integer *node)
655 : {
656 478208 : appendStringInfo(str, "%d", node->ival);
657 478208 : }
658 :
659 : static void
660 11984 : _outFloat(StringInfo str, const Float *node)
661 : {
662 : /*
663 : * We assume the value is a valid numeric literal and so does not need
664 : * quoting.
665 : */
666 11984 : appendStringInfoString(str, node->fval);
667 11984 : }
668 :
669 : static void
670 104404 : _outBoolean(StringInfo str, const Boolean *node)
671 : {
672 104404 : appendStringInfoString(str, node->boolval ? "true" : "false");
673 104404 : }
674 :
675 : static void
676 27808578 : _outString(StringInfo str, const String *node)
677 : {
678 : /*
679 : * We use outToken to provide escaping of the string's content, but we
680 : * don't want it to convert an empty string to '""', because we're putting
681 : * double quotes around the string already.
682 : */
683 27808578 : appendStringInfoChar(str, '"');
684 27808578 : if (node->sval[0] != '\0')
685 27776760 : outToken(str, node->sval);
686 27808578 : appendStringInfoChar(str, '"');
687 27808578 : }
688 :
689 : static void
690 4068 : _outBitString(StringInfo str, const BitString *node)
691 : {
692 : /*
693 : * The lexer will always produce a string starting with 'b' or 'x'. There
694 : * might be characters following that that need escaping, but outToken
695 : * won't escape the 'b' or 'x'. This is relied on by nodeTokenType.
696 : */
697 : Assert(node->bsval[0] == 'b' || node->bsval[0] == 'x');
698 4068 : outToken(str, node->bsval);
699 4068 : }
700 :
701 : static void
702 1509924 : _outA_Const(StringInfo str, const A_Const *node)
703 : {
704 1509924 : WRITE_NODE_TYPE("A_CONST");
705 :
706 1509924 : if (node->isnull)
707 84594 : appendStringInfoString(str, " NULL");
708 : else
709 : {
710 1425330 : appendStringInfoString(str, " :val ");
711 1425330 : outNode(str, &node->val);
712 : }
713 1509924 : WRITE_LOCATION_FIELD(location);
714 1509924 : }
715 :
716 :
717 : /*
718 : * outNode -
719 : * converts a Node into ascii string and append it to 'str'
720 : */
721 : void
722 149810778 : outNode(StringInfo str, const void *obj)
723 : {
724 : /* Guard against stack overflow due to overly complex expressions */
725 149810778 : check_stack_depth();
726 :
727 149810778 : if (obj == NULL)
728 53927272 : appendStringInfoString(str, "<>");
729 95883506 : else if (IsA(obj, List) || IsA(obj, IntList) || IsA(obj, OidList) ||
730 77338482 : IsA(obj, XidList))
731 18545024 : _outList(str, obj);
732 : /* nodeRead does not want to see { } around these! */
733 77338482 : else if (IsA(obj, Integer))
734 478208 : _outInteger(str, (Integer *) obj);
735 76860274 : else if (IsA(obj, Float))
736 11984 : _outFloat(str, (Float *) obj);
737 76848290 : else if (IsA(obj, Boolean))
738 104404 : _outBoolean(str, (Boolean *) obj);
739 76743886 : else if (IsA(obj, String))
740 27808578 : _outString(str, (String *) obj);
741 48935308 : else if (IsA(obj, BitString))
742 4068 : _outBitString(str, (BitString *) obj);
743 48931240 : else if (IsA(obj, Bitmapset))
744 0 : outBitmapset(str, (Bitmapset *) obj);
745 : else
746 : {
747 48931240 : appendStringInfoChar(str, '{');
748 48931240 : switch (nodeTag(obj))
749 : {
750 : #include "outfuncs.switch.c"
751 :
752 0 : default:
753 :
754 : /*
755 : * This should be an ERROR, but it's too useful to be able to
756 : * dump structures that outNode only understands part of.
757 : */
758 0 : elog(WARNING, "could not dump unrecognized node type: %d",
759 : (int) nodeTag(obj));
760 0 : break;
761 : }
762 48931240 : appendStringInfoChar(str, '}');
763 : }
764 149810778 : }
765 :
766 : /*
767 : * nodeToString -
768 : * returns the ascii representation of the Node as a palloc'd string
769 : *
770 : * write_loc_fields determines whether location fields are output with their
771 : * actual value rather than -1. The actual value can be useful for debugging,
772 : * but for most uses, the actual value is not useful, since the original query
773 : * string is no longer available.
774 : */
775 : static char *
776 2042896 : nodeToStringInternal(const void *obj, bool write_loc_fields)
777 : {
778 : StringInfoData str;
779 : bool save_write_location_fields;
780 :
781 2042896 : save_write_location_fields = write_location_fields;
782 2042896 : write_location_fields = write_loc_fields;
783 :
784 : /* see stringinfo.h for an explanation of this maneuver */
785 2042896 : initStringInfo(&str);
786 2042896 : outNode(&str, obj);
787 :
788 2042896 : write_location_fields = save_write_location_fields;
789 :
790 2042896 : return str.data;
791 : }
792 :
793 : /*
794 : * Externally visible entry points
795 : */
796 : char *
797 68358 : nodeToString(const void *obj)
798 : {
799 68358 : return nodeToStringInternal(obj, false);
800 : }
801 :
802 : char *
803 1974538 : nodeToStringWithLocations(const void *obj)
804 : {
805 1974538 : return nodeToStringInternal(obj, true);
806 : }
807 :
808 :
809 : /*
810 : * bmsToString -
811 : * returns the ascii representation of the Bitmapset as a palloc'd string
812 : */
813 : char *
814 0 : bmsToString(const Bitmapset *bms)
815 : {
816 : StringInfoData str;
817 :
818 : /* see stringinfo.h for an explanation of this maneuver */
819 0 : initStringInfo(&str);
820 0 : outBitmapset(&str, bms);
821 0 : return str.data;
822 : }
|