Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * outfuncs.c
4 : * Output functions for Postgres tree nodes.
5 : *
6 : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/nodes/outfuncs.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : #include "postgres.h"
16 :
17 : #include <ctype.h>
18 :
19 : #include "access/attnum.h"
20 : #include "common/shortest_dec.h"
21 : #include "lib/stringinfo.h"
22 : #include "miscadmin.h"
23 : #include "nodes/bitmapset.h"
24 : #include "nodes/nodes.h"
25 : #include "nodes/pg_list.h"
26 : #include "utils/datum.h"
27 :
28 : /* State flag that determines how nodeToStringInternal() should treat location fields */
29 : static bool write_location_fields = false;
30 :
31 : static void outChar(StringInfo str, char c);
32 : static void outDouble(StringInfo str, double d);
33 :
34 :
35 : /*
36 : * Macros to simplify output of different kinds of fields. Use these
37 : * wherever possible to reduce the chance for silly typos. Note that these
38 : * hard-wire conventions about the names of the local variables in an Out
39 : * routine.
40 : */
41 :
42 : /* Write the label for the node type */
43 : #define WRITE_NODE_TYPE(nodelabel) \
44 : appendStringInfoString(str, nodelabel)
45 :
46 : /* Write an integer field (anything written as ":fldname %d") */
47 : #define WRITE_INT_FIELD(fldname) \
48 : appendStringInfo(str, " :" CppAsString(fldname) " %d", node->fldname)
49 :
50 : /* Write an unsigned integer field (anything written as ":fldname %u") */
51 : #define WRITE_UINT_FIELD(fldname) \
52 : appendStringInfo(str, " :" CppAsString(fldname) " %u", node->fldname)
53 :
54 : /* Write a signed integer field (anything written with INT64_FORMAT) */
55 : #define WRITE_INT64_FIELD(fldname) \
56 : appendStringInfo(str, \
57 : " :" CppAsString(fldname) " " INT64_FORMAT, \
58 : node->fldname)
59 :
60 : /* Write an unsigned integer field (anything written with UINT64_FORMAT) */
61 : #define WRITE_UINT64_FIELD(fldname) \
62 : appendStringInfo(str, " :" CppAsString(fldname) " " UINT64_FORMAT, \
63 : node->fldname)
64 :
65 : /* Write an OID field (don't hard-wire assumption that OID is same as uint) */
66 : #define WRITE_OID_FIELD(fldname) \
67 : appendStringInfo(str, " :" CppAsString(fldname) " %u", node->fldname)
68 :
69 : /* Write a long-integer field */
70 : #define WRITE_LONG_FIELD(fldname) \
71 : appendStringInfo(str, " :" CppAsString(fldname) " %ld", node->fldname)
72 :
73 : /* Write a char field (ie, one ascii character) */
74 : #define WRITE_CHAR_FIELD(fldname) \
75 : (appendStringInfo(str, " :" CppAsString(fldname) " "), \
76 : outChar(str, node->fldname))
77 :
78 : /* Write an enumerated-type field as an integer code */
79 : #define WRITE_ENUM_FIELD(fldname, enumtype) \
80 : appendStringInfo(str, " :" CppAsString(fldname) " %d", \
81 : (int) node->fldname)
82 :
83 : /* Write a float field (actually, they're double) */
84 : #define WRITE_FLOAT_FIELD(fldname) \
85 : (appendStringInfo(str, " :" CppAsString(fldname) " "), \
86 : outDouble(str, node->fldname))
87 :
88 : /* Write a boolean field */
89 : #define WRITE_BOOL_FIELD(fldname) \
90 : appendStringInfo(str, " :" CppAsString(fldname) " %s", \
91 : booltostr(node->fldname))
92 :
93 : /* Write a character-string (possibly NULL) field */
94 : #define WRITE_STRING_FIELD(fldname) \
95 : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
96 : outToken(str, node->fldname))
97 :
98 : /* Write a parse location field (actually same as INT case) */
99 : #define WRITE_LOCATION_FIELD(fldname) \
100 : appendStringInfo(str, " :" CppAsString(fldname) " %d", write_location_fields ? node->fldname : -1)
101 :
102 : /* Write a Node field */
103 : #define WRITE_NODE_FIELD(fldname) \
104 : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
105 : outNode(str, node->fldname))
106 :
107 : /* Write a bitmapset field */
108 : #define WRITE_BITMAPSET_FIELD(fldname) \
109 : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
110 : outBitmapset(str, node->fldname))
111 :
112 : /* Write a variable-length array (not a List) of Node pointers */
113 : #define WRITE_NODE_ARRAY(fldname, len) \
114 : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
115 : writeNodeArray(str, (const Node * const *) node->fldname, len))
116 :
117 : /* Write a variable-length array of AttrNumber */
118 : #define WRITE_ATTRNUMBER_ARRAY(fldname, len) \
119 : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
120 : writeAttrNumberCols(str, node->fldname, len))
121 :
122 : /* Write a variable-length array of Oid */
123 : #define WRITE_OID_ARRAY(fldname, len) \
124 : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
125 : writeOidCols(str, node->fldname, len))
126 :
127 : /* Write a variable-length array of Index */
128 : #define WRITE_INDEX_ARRAY(fldname, len) \
129 : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
130 : writeIndexCols(str, node->fldname, len))
131 :
132 : /* Write a variable-length array of int */
133 : #define WRITE_INT_ARRAY(fldname, len) \
134 : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
135 : writeIntCols(str, node->fldname, len))
136 :
137 : /* Write a variable-length array of bool */
138 : #define WRITE_BOOL_ARRAY(fldname, len) \
139 : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
140 : writeBoolCols(str, node->fldname, len))
141 :
142 : #define booltostr(x) ((x) ? "true" : "false")
143 :
144 :
145 : /*
146 : * outToken
147 : * Convert an ordinary string (eg, an identifier) into a form that
148 : * will be decoded back to a plain token by read.c's functions.
149 : *
150 : * If a null string pointer is given, it is encoded as '<>'.
151 : * An empty string is encoded as '""'. To avoid ambiguity, input
152 : * strings beginning with '<' or '"' receive a leading backslash.
153 : */
154 : void
155 48773272 : outToken(StringInfo str, const char *s)
156 : {
157 48773272 : if (s == NULL)
158 : {
159 9951192 : appendStringInfoString(str, "<>");
160 9951192 : return;
161 : }
162 38822080 : if (*s == '\0')
163 : {
164 156 : appendStringInfoString(str, "\"\"");
165 156 : return;
166 : }
167 :
168 : /*
169 : * Look for characters or patterns that are treated specially by read.c
170 : * (either in pg_strtok() or in nodeRead()), and therefore need a
171 : * protective backslash.
172 : */
173 : /* These characters only need to be quoted at the start of the string */
174 38821924 : if (*s == '<' ||
175 38753880 : *s == '"' ||
176 38747784 : isdigit((unsigned char) *s) ||
177 38556816 : ((*s == '+' || *s == '-') &&
178 31326 : (isdigit((unsigned char) s[1]) || s[1] == '.')))
179 270694 : appendStringInfoChar(str, '\\');
180 349843740 : while (*s)
181 : {
182 : /* These chars must be backslashed anywhere in the string */
183 311021816 : if (*s == ' ' || *s == '\n' || *s == '\t' ||
184 309649204 : *s == '(' || *s == ')' || *s == '{' || *s == '}' ||
185 309419414 : *s == '\\')
186 1613772 : appendStringInfoChar(str, '\\');
187 311021816 : 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 2995148 : outChar(StringInfo str, char c)
197 : {
198 : char in[2];
199 :
200 : /* Traditionally, we've represented \0 as <>, so keep doing that */
201 2995148 : if (c == '\0')
202 : {
203 910076 : appendStringInfoString(str, "<>");
204 910076 : return;
205 : }
206 :
207 2085072 : in[0] = c;
208 2085072 : in[1] = '\0';
209 :
210 2085072 : outToken(str, in);
211 : }
212 :
213 : /*
214 : * Convert a double value, attempting to ensure the value is preserved exactly.
215 : */
216 : static void
217 3559932 : outDouble(StringInfo str, double d)
218 : {
219 : char buf[DOUBLE_SHORTEST_DECIMAL_LEN];
220 :
221 3559932 : double_to_shortest_decimal_buf(d, buf);
222 3559932 : appendStringInfoString(str, buf);
223 3559932 : }
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 475340 : WRITE_SCALAR_ARRAY(writeAttrNumberCols, AttrNumber, " %d",)
249 639402 : WRITE_SCALAR_ARRAY(writeOidCols, Oid, " %u",)
250 0 : WRITE_SCALAR_ARRAY(writeIndexCols, Index, " %u",)
251 14526 : WRITE_SCALAR_ARRAY(writeIntCols, int, " %d",)
252 242870 : 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 18231430 : _outList(StringInfo str, const List *node)
282 : {
283 : const ListCell *lc;
284 :
285 18231430 : appendStringInfoChar(str, '(');
286 :
287 18231430 : if (IsA(node, IntList))
288 489790 : appendStringInfoChar(str, 'i');
289 17741640 : else if (IsA(node, OidList))
290 704604 : appendStringInfoChar(str, 'o');
291 17037036 : else if (IsA(node, XidList))
292 0 : appendStringInfoChar(str, 'x');
293 :
294 77504458 : 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 59273028 : if (IsA(node, List))
302 : {
303 53582754 : outNode(str, lfirst(lc));
304 53582754 : if (lnext(node, lc))
305 36545718 : appendStringInfoChar(str, ' ');
306 : }
307 5690274 : else if (IsA(node, IntList))
308 4292276 : appendStringInfo(str, " %d", lfirst_int(lc));
309 1397998 : else if (IsA(node, OidList))
310 1397998 : 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 18231430 : appendStringInfoChar(str, ')');
319 18231430 : }
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 18766898 : outBitmapset(StringInfo str, const Bitmapset *bms)
332 : {
333 : int x;
334 :
335 18766898 : appendStringInfoChar(str, '(');
336 18766898 : appendStringInfoChar(str, 'b');
337 18766898 : x = -1;
338 24123270 : while ((x = bms_next_member(bms, x)) >= 0)
339 5356372 : appendStringInfo(str, " %d", x);
340 18766898 : appendStringInfoChar(str, ')');
341 18766898 : }
342 :
343 : /*
344 : * Print the value of a Datum given its type.
345 : */
346 : void
347 2445346 : outDatum(StringInfo str, Datum value, int typlen, bool typbyval)
348 : {
349 : Size length,
350 : i;
351 : char *s;
352 :
353 2445346 : length = datumGetSize(value, typbyval, typlen);
354 :
355 2445346 : if (typbyval)
356 : {
357 1574718 : s = (char *) (&value);
358 1574718 : appendStringInfo(str, "%u [ ", (unsigned int) length);
359 14172462 : for (i = 0; i < (Size) sizeof(Datum); i++)
360 12597744 : appendStringInfo(str, "%d ", (int) (s[i]));
361 1574718 : appendStringInfoChar(str, ']');
362 : }
363 : else
364 : {
365 870628 : s = (char *) DatumGetPointer(value);
366 870628 : if (!PointerIsValid(s))
367 0 : appendStringInfoString(str, "0 [ ]");
368 : else
369 : {
370 870628 : appendStringInfo(str, "%u [ ", (unsigned int) length);
371 117577838 : for (i = 0; i < length; i++)
372 116707210 : appendStringInfo(str, "%d ", (int) (s[i]));
373 870628 : appendStringInfoChar(str, ']');
374 : }
375 : }
376 2445346 : }
377 :
378 :
379 : #include "outfuncs.funcs.c"
380 :
381 :
382 : /*
383 : * Support functions for nodes with custom_read_write attribute or
384 : * special_read_write attribute
385 : */
386 :
387 : static void
388 2652418 : _outConst(StringInfo str, const Const *node)
389 : {
390 2652418 : WRITE_NODE_TYPE("CONST");
391 :
392 2652418 : WRITE_OID_FIELD(consttype);
393 2652418 : WRITE_INT_FIELD(consttypmod);
394 2652418 : WRITE_OID_FIELD(constcollid);
395 2652418 : WRITE_INT_FIELD(constlen);
396 2652418 : WRITE_BOOL_FIELD(constbyval);
397 2652418 : WRITE_BOOL_FIELD(constisnull);
398 2652418 : WRITE_LOCATION_FIELD(location);
399 :
400 2652418 : appendStringInfoString(str, " :constvalue ");
401 2652418 : if (node->constisnull)
402 207064 : appendStringInfoString(str, "<>");
403 : else
404 2445354 : outDatum(str, node->constvalue, node->constlen, node->constbyval);
405 2652418 : }
406 :
407 : static void
408 378112 : _outBoolExpr(StringInfo str, const BoolExpr *node)
409 : {
410 378112 : char *opstr = NULL;
411 :
412 378112 : WRITE_NODE_TYPE("BOOLEXPR");
413 :
414 : /* do-it-yourself enum representation */
415 378112 : switch (node->boolop)
416 : {
417 285792 : case AND_EXPR:
418 285792 : opstr = "and";
419 285792 : break;
420 43762 : case OR_EXPR:
421 43762 : opstr = "or";
422 43762 : break;
423 48558 : case NOT_EXPR:
424 48558 : opstr = "not";
425 48558 : break;
426 : }
427 378112 : appendStringInfoString(str, " :boolop ");
428 378112 : outToken(str, opstr);
429 :
430 378112 : WRITE_NODE_FIELD(args);
431 378112 : WRITE_LOCATION_FIELD(location);
432 378112 : }
433 :
434 : static void
435 0 : _outForeignKeyOptInfo(StringInfo str, const ForeignKeyOptInfo *node)
436 : {
437 : int i;
438 :
439 0 : WRITE_NODE_TYPE("FOREIGNKEYOPTINFO");
440 :
441 0 : WRITE_UINT_FIELD(con_relid);
442 0 : WRITE_UINT_FIELD(ref_relid);
443 0 : WRITE_INT_FIELD(nkeys);
444 0 : WRITE_ATTRNUMBER_ARRAY(conkey, node->nkeys);
445 0 : WRITE_ATTRNUMBER_ARRAY(confkey, node->nkeys);
446 0 : WRITE_OID_ARRAY(conpfeqop, node->nkeys);
447 0 : WRITE_INT_FIELD(nmatched_ec);
448 0 : WRITE_INT_FIELD(nconst_ec);
449 0 : WRITE_INT_FIELD(nmatched_rcols);
450 0 : WRITE_INT_FIELD(nmatched_ri);
451 : /* for compactness, just print the number of matches per column: */
452 0 : appendStringInfoString(str, " :eclass");
453 0 : for (i = 0; i < node->nkeys; i++)
454 0 : appendStringInfo(str, " %d", (node->eclass[i] != NULL));
455 0 : appendStringInfoString(str, " :rinfos");
456 0 : for (i = 0; i < node->nkeys; i++)
457 0 : appendStringInfo(str, " %d", list_length(node->rinfos[i]));
458 0 : }
459 :
460 : static void
461 0 : _outEquivalenceClass(StringInfo str, const EquivalenceClass *node)
462 : {
463 : /*
464 : * To simplify reading, we just chase up to the topmost merged EC and
465 : * print that, without bothering to show the merge-ees separately.
466 : */
467 0 : while (node->ec_merged)
468 0 : node = node->ec_merged;
469 :
470 0 : WRITE_NODE_TYPE("EQUIVALENCECLASS");
471 :
472 0 : WRITE_NODE_FIELD(ec_opfamilies);
473 0 : WRITE_OID_FIELD(ec_collation);
474 0 : WRITE_INT_FIELD(ec_childmembers_size);
475 0 : WRITE_NODE_FIELD(ec_members);
476 0 : WRITE_NODE_ARRAY(ec_childmembers, node->ec_childmembers_size);
477 0 : WRITE_NODE_FIELD(ec_sources);
478 : /* Only ec_derives_list is written; hash is not serialized. */
479 0 : WRITE_NODE_FIELD(ec_derives_list);
480 0 : WRITE_BITMAPSET_FIELD(ec_relids);
481 0 : WRITE_BOOL_FIELD(ec_has_const);
482 0 : WRITE_BOOL_FIELD(ec_has_volatile);
483 0 : WRITE_BOOL_FIELD(ec_broken);
484 0 : WRITE_UINT_FIELD(ec_sortref);
485 0 : WRITE_UINT_FIELD(ec_min_security);
486 0 : WRITE_UINT_FIELD(ec_max_security);
487 0 : }
488 :
489 : static void
490 0 : _outExtensibleNode(StringInfo str, const ExtensibleNode *node)
491 : {
492 : const ExtensibleNodeMethods *methods;
493 :
494 0 : methods = GetExtensibleNodeMethods(node->extnodename, false);
495 :
496 0 : WRITE_NODE_TYPE("EXTENSIBLENODE");
497 :
498 0 : WRITE_STRING_FIELD(extnodename);
499 :
500 : /* serialize the private fields */
501 0 : methods->nodeOut(str, node);
502 0 : }
503 :
504 : static void
505 1689978 : _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
506 : {
507 1689978 : WRITE_NODE_TYPE("RANGETBLENTRY");
508 :
509 1689978 : WRITE_NODE_FIELD(alias);
510 1689978 : WRITE_NODE_FIELD(eref);
511 1689978 : WRITE_ENUM_FIELD(rtekind, RTEKind);
512 :
513 1689978 : switch (node->rtekind)
514 : {
515 1015412 : case RTE_RELATION:
516 1015412 : WRITE_OID_FIELD(relid);
517 1015412 : WRITE_BOOL_FIELD(inh);
518 1015412 : WRITE_CHAR_FIELD(relkind);
519 1015412 : WRITE_INT_FIELD(rellockmode);
520 1015412 : WRITE_UINT_FIELD(perminfoindex);
521 1015412 : WRITE_NODE_FIELD(tablesample);
522 1015412 : break;
523 138738 : case RTE_SUBQUERY:
524 138738 : WRITE_NODE_FIELD(subquery);
525 138738 : WRITE_BOOL_FIELD(security_barrier);
526 : /* we re-use these RELATION fields, too: */
527 138738 : WRITE_OID_FIELD(relid);
528 138738 : WRITE_BOOL_FIELD(inh);
529 138738 : WRITE_CHAR_FIELD(relkind);
530 138738 : WRITE_INT_FIELD(rellockmode);
531 138738 : WRITE_UINT_FIELD(perminfoindex);
532 138738 : break;
533 188658 : case RTE_JOIN:
534 188658 : WRITE_ENUM_FIELD(jointype, JoinType);
535 188658 : WRITE_INT_FIELD(joinmergedcols);
536 188658 : WRITE_NODE_FIELD(joinaliasvars);
537 188658 : WRITE_NODE_FIELD(joinleftcols);
538 188658 : WRITE_NODE_FIELD(joinrightcols);
539 188658 : WRITE_NODE_FIELD(join_using_alias);
540 188658 : break;
541 107416 : case RTE_FUNCTION:
542 107416 : WRITE_NODE_FIELD(functions);
543 107416 : WRITE_BOOL_FIELD(funcordinality);
544 107416 : break;
545 1296 : case RTE_TABLEFUNC:
546 1296 : WRITE_NODE_FIELD(tablefunc);
547 1296 : break;
548 21422 : case RTE_VALUES:
549 21422 : WRITE_NODE_FIELD(values_lists);
550 21422 : WRITE_NODE_FIELD(coltypes);
551 21422 : WRITE_NODE_FIELD(coltypmods);
552 21422 : WRITE_NODE_FIELD(colcollations);
553 21422 : break;
554 11918 : case RTE_CTE:
555 11918 : WRITE_STRING_FIELD(ctename);
556 11918 : WRITE_UINT_FIELD(ctelevelsup);
557 11918 : WRITE_BOOL_FIELD(self_reference);
558 11918 : WRITE_NODE_FIELD(coltypes);
559 11918 : WRITE_NODE_FIELD(coltypmods);
560 11918 : WRITE_NODE_FIELD(colcollations);
561 11918 : break;
562 950 : case RTE_NAMEDTUPLESTORE:
563 950 : WRITE_STRING_FIELD(enrname);
564 950 : WRITE_FLOAT_FIELD(enrtuples);
565 950 : WRITE_NODE_FIELD(coltypes);
566 950 : WRITE_NODE_FIELD(coltypmods);
567 950 : WRITE_NODE_FIELD(colcollations);
568 : /* we re-use these RELATION fields, too: */
569 950 : WRITE_OID_FIELD(relid);
570 950 : break;
571 194788 : case RTE_RESULT:
572 : /* no extra fields */
573 194788 : break;
574 9380 : case RTE_GROUP:
575 9380 : WRITE_NODE_FIELD(groupexprs);
576 9380 : break;
577 0 : default:
578 0 : elog(ERROR, "unrecognized RTE kind: %d", (int) node->rtekind);
579 : break;
580 : }
581 :
582 1689978 : WRITE_BOOL_FIELD(lateral);
583 1689978 : WRITE_BOOL_FIELD(inFromCl);
584 1689978 : WRITE_NODE_FIELD(securityQuals);
585 1689978 : }
586 :
587 : static void
588 661924 : _outA_Expr(StringInfo str, const A_Expr *node)
589 : {
590 661924 : WRITE_NODE_TYPE("A_EXPR");
591 :
592 661924 : switch (node->kind)
593 : {
594 611630 : case AEXPR_OP:
595 611630 : WRITE_NODE_FIELD(name);
596 611630 : break;
597 16826 : case AEXPR_OP_ANY:
598 16826 : appendStringInfoString(str, " ANY");
599 16826 : WRITE_NODE_FIELD(name);
600 16826 : break;
601 144 : case AEXPR_OP_ALL:
602 144 : appendStringInfoString(str, " ALL");
603 144 : WRITE_NODE_FIELD(name);
604 144 : break;
605 1256 : case AEXPR_DISTINCT:
606 1256 : appendStringInfoString(str, " DISTINCT");
607 1256 : WRITE_NODE_FIELD(name);
608 1256 : break;
609 74 : case AEXPR_NOT_DISTINCT:
610 74 : appendStringInfoString(str, " NOT_DISTINCT");
611 74 : WRITE_NODE_FIELD(name);
612 74 : break;
613 688 : case AEXPR_NULLIF:
614 688 : appendStringInfoString(str, " NULLIF");
615 688 : WRITE_NODE_FIELD(name);
616 688 : break;
617 28054 : case AEXPR_IN:
618 28054 : appendStringInfoString(str, " IN");
619 28054 : WRITE_NODE_FIELD(name);
620 28054 : break;
621 2338 : case AEXPR_LIKE:
622 2338 : appendStringInfoString(str, " LIKE");
623 2338 : WRITE_NODE_FIELD(name);
624 2338 : break;
625 202 : case AEXPR_ILIKE:
626 202 : appendStringInfoString(str, " ILIKE");
627 202 : WRITE_NODE_FIELD(name);
628 202 : break;
629 118 : case AEXPR_SIMILAR:
630 118 : appendStringInfoString(str, " SIMILAR");
631 118 : WRITE_NODE_FIELD(name);
632 118 : break;
633 558 : case AEXPR_BETWEEN:
634 558 : appendStringInfoString(str, " BETWEEN");
635 558 : WRITE_NODE_FIELD(name);
636 558 : break;
637 12 : case AEXPR_NOT_BETWEEN:
638 12 : appendStringInfoString(str, " NOT_BETWEEN");
639 12 : WRITE_NODE_FIELD(name);
640 12 : break;
641 12 : case AEXPR_BETWEEN_SYM:
642 12 : appendStringInfoString(str, " BETWEEN_SYM");
643 12 : WRITE_NODE_FIELD(name);
644 12 : break;
645 12 : case AEXPR_NOT_BETWEEN_SYM:
646 12 : appendStringInfoString(str, " NOT_BETWEEN_SYM");
647 12 : WRITE_NODE_FIELD(name);
648 12 : break;
649 0 : default:
650 0 : elog(ERROR, "unrecognized A_Expr_Kind: %d", (int) node->kind);
651 : break;
652 : }
653 :
654 661924 : WRITE_NODE_FIELD(lexpr);
655 661924 : WRITE_NODE_FIELD(rexpr);
656 661924 : WRITE_LOCATION_FIELD(location);
657 661924 : }
658 :
659 : static void
660 468168 : _outInteger(StringInfo str, const Integer *node)
661 : {
662 468168 : appendStringInfo(str, "%d", node->ival);
663 468168 : }
664 :
665 : static void
666 11984 : _outFloat(StringInfo str, const Float *node)
667 : {
668 : /*
669 : * We assume the value is a valid numeric literal and so does not need
670 : * quoting.
671 : */
672 11984 : appendStringInfoString(str, node->fval);
673 11984 : }
674 :
675 : static void
676 104010 : _outBoolean(StringInfo str, const Boolean *node)
677 : {
678 104010 : appendStringInfoString(str, node->boolval ? "true" : "false");
679 104010 : }
680 :
681 : static void
682 27531182 : _outString(StringInfo str, const String *node)
683 : {
684 : /*
685 : * We use outToken to provide escaping of the string's content, but we
686 : * don't want it to convert an empty string to '""', because we're putting
687 : * double quotes around the string already.
688 : */
689 27531182 : appendStringInfoChar(str, '"');
690 27531182 : if (node->sval[0] != '\0')
691 27499322 : outToken(str, node->sval);
692 27531182 : appendStringInfoChar(str, '"');
693 27531182 : }
694 :
695 : static void
696 4068 : _outBitString(StringInfo str, const BitString *node)
697 : {
698 : /*
699 : * The lexer will always produce a string starting with 'b' or 'x'. There
700 : * might be characters following that that need escaping, but outToken
701 : * won't escape the 'b' or 'x'. This is relied on by nodeTokenType.
702 : */
703 : Assert(node->bsval[0] == 'b' || node->bsval[0] == 'x');
704 4068 : outToken(str, node->bsval);
705 4068 : }
706 :
707 : static void
708 1447492 : _outA_Const(StringInfo str, const A_Const *node)
709 : {
710 1447492 : WRITE_NODE_TYPE("A_CONST");
711 :
712 1447492 : if (node->isnull)
713 84866 : appendStringInfoString(str, " NULL");
714 : else
715 : {
716 1362626 : appendStringInfoString(str, " :val ");
717 1362626 : outNode(str, &node->val);
718 : }
719 1447492 : WRITE_LOCATION_FIELD(location);
720 1447492 : }
721 :
722 :
723 : /*
724 : * outNode -
725 : * converts a Node into ascii string and append it to 'str'
726 : */
727 : void
728 147343808 : outNode(StringInfo str, const void *obj)
729 : {
730 : /* Guard against stack overflow due to overly complex expressions */
731 147343808 : check_stack_depth();
732 :
733 147343808 : if (obj == NULL)
734 52799688 : appendStringInfoString(str, "<>");
735 94544120 : else if (IsA(obj, List) || IsA(obj, IntList) || IsA(obj, OidList) ||
736 76312652 : IsA(obj, XidList))
737 18231468 : _outList(str, obj);
738 : /* nodeRead does not want to see { } around these! */
739 76312652 : else if (IsA(obj, Integer))
740 468168 : _outInteger(str, (Integer *) obj);
741 75844484 : else if (IsA(obj, Float))
742 11984 : _outFloat(str, (Float *) obj);
743 75832500 : else if (IsA(obj, Boolean))
744 104010 : _outBoolean(str, (Boolean *) obj);
745 75728490 : else if (IsA(obj, String))
746 27531182 : _outString(str, (String *) obj);
747 48197308 : else if (IsA(obj, BitString))
748 4068 : _outBitString(str, (BitString *) obj);
749 48193240 : else if (IsA(obj, Bitmapset))
750 0 : outBitmapset(str, (Bitmapset *) obj);
751 : else
752 : {
753 48193240 : appendStringInfoChar(str, '{');
754 48193240 : switch (nodeTag(obj))
755 : {
756 : #include "outfuncs.switch.c"
757 :
758 0 : default:
759 :
760 : /*
761 : * This should be an ERROR, but it's too useful to be able to
762 : * dump structures that outNode only understands part of.
763 : */
764 0 : elog(WARNING, "could not dump unrecognized node type: %d",
765 : (int) nodeTag(obj));
766 0 : break;
767 : }
768 48193240 : appendStringInfoChar(str, '}');
769 : }
770 147343808 : }
771 :
772 : /*
773 : * nodeToString -
774 : * returns the ascii representation of the Node as a palloc'd string
775 : *
776 : * write_loc_fields determines whether location fields are output with their
777 : * actual value rather than -1. The actual value can be useful for debugging,
778 : * but for most uses, the actual value is not useful, since the original query
779 : * string is no longer available.
780 : */
781 : static char *
782 2015530 : nodeToStringInternal(const void *obj, bool write_loc_fields)
783 : {
784 : StringInfoData str;
785 : bool save_write_location_fields;
786 :
787 2015530 : save_write_location_fields = write_location_fields;
788 2015530 : write_location_fields = write_loc_fields;
789 :
790 : /* see stringinfo.h for an explanation of this maneuver */
791 2015530 : initStringInfo(&str);
792 2015530 : outNode(&str, obj);
793 :
794 2015530 : write_location_fields = save_write_location_fields;
795 :
796 2015530 : return str.data;
797 : }
798 :
799 : /*
800 : * Externally visible entry points
801 : */
802 : char *
803 68534 : nodeToString(const void *obj)
804 : {
805 68534 : return nodeToStringInternal(obj, false);
806 : }
807 :
808 : char *
809 1946996 : nodeToStringWithLocations(const void *obj)
810 : {
811 1946996 : return nodeToStringInternal(obj, true);
812 : }
813 :
814 :
815 : /*
816 : * bmsToString -
817 : * returns the ascii representation of the Bitmapset as a palloc'd string
818 : */
819 : char *
820 0 : bmsToString(const Bitmapset *bms)
821 : {
822 : StringInfoData str;
823 :
824 : /* see stringinfo.h for an explanation of this maneuver */
825 0 : initStringInfo(&str);
826 0 : outBitmapset(&str, bms);
827 0 : return str.data;
828 : }
|