Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * outfuncs.c
4 : * Output functions for Postgres tree nodes.
5 : *
6 : * Portions Copyright (c) 1996-2023, 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 : static void outChar(StringInfo str, char c);
29 : static void outDouble(StringInfo str, double d);
30 :
31 :
32 : /*
33 : * Macros to simplify output of different kinds of fields. Use these
34 : * wherever possible to reduce the chance for silly typos. Note that these
35 : * hard-wire conventions about the names of the local variables in an Out
36 : * routine.
37 : */
38 :
39 : /* Write the label for the node type */
40 : #define WRITE_NODE_TYPE(nodelabel) \
41 : appendStringInfoString(str, nodelabel)
42 :
43 : /* Write an integer field (anything written as ":fldname %d") */
44 : #define WRITE_INT_FIELD(fldname) \
45 : appendStringInfo(str, " :" CppAsString(fldname) " %d", node->fldname)
46 :
47 : /* Write an unsigned integer field (anything written as ":fldname %u") */
48 : #define WRITE_UINT_FIELD(fldname) \
49 : appendStringInfo(str, " :" CppAsString(fldname) " %u", node->fldname)
50 :
51 : /* Write an unsigned integer field (anything written with UINT64_FORMAT) */
52 : #define WRITE_UINT64_FIELD(fldname) \
53 : appendStringInfo(str, " :" CppAsString(fldname) " " UINT64_FORMAT, \
54 : node->fldname)
55 :
56 : /* Write an OID field (don't hard-wire assumption that OID is same as uint) */
57 : #define WRITE_OID_FIELD(fldname) \
58 : appendStringInfo(str, " :" CppAsString(fldname) " %u", node->fldname)
59 :
60 : /* Write a long-integer field */
61 : #define WRITE_LONG_FIELD(fldname) \
62 : appendStringInfo(str, " :" CppAsString(fldname) " %ld", node->fldname)
63 :
64 : /* Write a char field (ie, one ascii character) */
65 : #define WRITE_CHAR_FIELD(fldname) \
66 : (appendStringInfo(str, " :" CppAsString(fldname) " "), \
67 : outChar(str, node->fldname))
68 :
69 : /* Write an enumerated-type field as an integer code */
70 : #define WRITE_ENUM_FIELD(fldname, enumtype) \
71 : appendStringInfo(str, " :" CppAsString(fldname) " %d", \
72 : (int) node->fldname)
73 :
74 : /* Write a float field (actually, they're double) */
75 : #define WRITE_FLOAT_FIELD(fldname) \
76 : (appendStringInfo(str, " :" CppAsString(fldname) " "), \
77 : outDouble(str, node->fldname))
78 :
79 : /* Write a boolean field */
80 : #define WRITE_BOOL_FIELD(fldname) \
81 : appendStringInfo(str, " :" CppAsString(fldname) " %s", \
82 : booltostr(node->fldname))
83 :
84 : /* Write a character-string (possibly NULL) field */
85 : #define WRITE_STRING_FIELD(fldname) \
86 : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
87 : outToken(str, node->fldname))
88 :
89 : /* Write a parse location field (actually same as INT case) */
90 : #define WRITE_LOCATION_FIELD(fldname) \
91 : appendStringInfo(str, " :" CppAsString(fldname) " %d", node->fldname)
92 :
93 : /* Write a Node field */
94 : #define WRITE_NODE_FIELD(fldname) \
95 : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
96 : outNode(str, node->fldname))
97 :
98 : /* Write a bitmapset field */
99 : #define WRITE_BITMAPSET_FIELD(fldname) \
100 : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
101 : outBitmapset(str, node->fldname))
102 :
103 : /* Write a variable-length array (not a List) of Node pointers */
104 : #define WRITE_NODE_ARRAY(fldname, len) \
105 : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
106 : writeNodeArray(str, (const Node * const *) node->fldname, len))
107 :
108 : /* Write a variable-length array of AttrNumber */
109 : #define WRITE_ATTRNUMBER_ARRAY(fldname, len) \
110 : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
111 : writeAttrNumberCols(str, node->fldname, len))
112 :
113 : /* Write a variable-length array of Oid */
114 : #define WRITE_OID_ARRAY(fldname, len) \
115 : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
116 : writeOidCols(str, node->fldname, len))
117 :
118 : /* Write a variable-length array of Index */
119 : #define WRITE_INDEX_ARRAY(fldname, len) \
120 : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
121 : writeIndexCols(str, node->fldname, len))
122 :
123 : /* Write a variable-length array of int */
124 : #define WRITE_INT_ARRAY(fldname, len) \
125 : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
126 : writeIntCols(str, node->fldname, len))
127 :
128 : /* Write a variable-length array of bool */
129 : #define WRITE_BOOL_ARRAY(fldname, len) \
130 : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
131 : writeBoolCols(str, node->fldname, len))
132 :
133 : #define booltostr(x) ((x) ? "true" : "false")
134 :
135 :
136 : /*
137 : * outToken
138 : * Convert an ordinary string (eg, an identifier) into a form that
139 : * will be decoded back to a plain token by read.c's functions.
140 : *
141 : * If a null string pointer is given, it is encoded as '<>'.
142 : * An empty string is encoded as '""'. To avoid ambiguity, input
143 : * strings beginning with '<' or '"' receive a leading backslash.
144 : */
145 : void
146 36573844 : outToken(StringInfo str, const char *s)
147 : {
148 36573844 : if (s == NULL)
149 : {
150 6064680 : appendStringInfoString(str, "<>");
151 6064680 : return;
152 : }
153 30509164 : if (*s == '\0')
154 : {
155 156 : appendStringInfoString(str, "\"\"");
156 156 : return;
157 : }
158 :
159 : /*
160 : * Look for characters or patterns that are treated specially by read.c
161 : * (either in pg_strtok() or in nodeRead()), and therefore need a
162 : * protective backslash.
163 : */
164 : /* These characters only need to be quoted at the start of the string */
165 30509008 : if (*s == '<' ||
166 30438548 : *s == '"' ||
167 30434018 : isdigit((unsigned char) *s) ||
168 30303944 : ((*s == '+' || *s == '-') &&
169 25350 : (isdigit((unsigned char) s[1]) || s[1] == '.')))
170 208522 : appendStringInfoChar(str, '\\');
171 273550552 : while (*s)
172 : {
173 : /* These chars must be backslashed anywhere in the string */
174 243041544 : if (*s == ' ' || *s == '\n' || *s == '\t' ||
175 241926766 : *s == '(' || *s == ')' || *s == '{' || *s == '}' ||
176 241729368 : *s == '\\')
177 1321788 : appendStringInfoChar(str, '\\');
178 243041544 : appendStringInfoChar(str, *s++);
179 : }
180 : }
181 :
182 : /*
183 : * Convert one char. Goes through outToken() so that special characters are
184 : * escaped.
185 : */
186 : static void
187 2086790 : outChar(StringInfo str, char c)
188 : {
189 : char in[2];
190 :
191 : /* Traditionally, we've represented \0 as <>, so keep doing that */
192 2086790 : if (c == '\0')
193 : {
194 450838 : appendStringInfoString(str, "<>");
195 450838 : return;
196 : }
197 :
198 1635952 : in[0] = c;
199 1635952 : in[1] = '\0';
200 :
201 1635952 : outToken(str, in);
202 : }
203 :
204 : /*
205 : * Convert a double value, attempting to ensure the value is preserved exactly.
206 : */
207 : static void
208 2907912 : outDouble(StringInfo str, double d)
209 : {
210 : char buf[DOUBLE_SHORTEST_DECIMAL_LEN];
211 :
212 2907912 : double_to_shortest_decimal_buf(d, buf);
213 2907912 : appendStringInfoString(str, buf);
214 2907912 : }
215 :
216 : /*
217 : * common implementation for scalar-array-writing functions
218 : *
219 : * The data format is either "<>" for a NULL pointer or "(item item item)".
220 : * fmtstr must include a leading space, and the rest of it must produce
221 : * something that will be seen as a single simple token by pg_strtok().
222 : * convfunc can be empty, or the name of a conversion macro or function.
223 : */
224 : #define WRITE_SCALAR_ARRAY(fnname, datatype, fmtstr, convfunc) \
225 : static void \
226 : fnname(StringInfo str, const datatype *arr, int len) \
227 : { \
228 : if (arr != NULL) \
229 : { \
230 : appendStringInfoChar(str, '('); \
231 : for (int i = 0; i < len; i++) \
232 : appendStringInfo(str, fmtstr, convfunc(arr[i])); \
233 : appendStringInfoChar(str, ')'); \
234 : } \
235 : else \
236 : appendStringInfoString(str, "<>"); \
237 : }
238 :
239 363254 : WRITE_SCALAR_ARRAY(writeAttrNumberCols, AttrNumber, " %d",)
240 456806 : WRITE_SCALAR_ARRAY(writeOidCols, Oid, " %u",)
241 0 : WRITE_SCALAR_ARRAY(writeIndexCols, Index, " %u",)
242 20360 : WRITE_SCALAR_ARRAY(writeIntCols, int, " %d",)
243 148000 : WRITE_SCALAR_ARRAY(writeBoolCols, bool, " %s", booltostr)
244 :
245 : /*
246 : * Print an array (not a List) of Node pointers.
247 : *
248 : * The decoration is identical to that of scalar arrays, but we can't
249 : * quite use appendStringInfo() in the loop.
250 : */
251 : static void
252 0 : writeNodeArray(StringInfo str, const Node *const *arr, int len)
253 : {
254 0 : if (arr != NULL)
255 : {
256 0 : appendStringInfoChar(str, '(');
257 0 : for (int i = 0; i < len; i++)
258 : {
259 0 : appendStringInfoChar(str, ' ');
260 0 : outNode(str, arr[i]);
261 : }
262 0 : appendStringInfoChar(str, ')');
263 : }
264 : else
265 0 : appendStringInfoString(str, "<>");
266 0 : }
267 :
268 : /*
269 : * Print a List.
270 : */
271 : static void
272 14476562 : _outList(StringInfo str, const List *node)
273 : {
274 : const ListCell *lc;
275 :
276 14476562 : appendStringInfoChar(str, '(');
277 :
278 14476562 : if (IsA(node, IntList))
279 386826 : appendStringInfoChar(str, 'i');
280 14089736 : else if (IsA(node, OidList))
281 564932 : appendStringInfoChar(str, 'o');
282 13524804 : else if (IsA(node, XidList))
283 0 : appendStringInfoChar(str, 'x');
284 :
285 61757226 : foreach(lc, node)
286 : {
287 : /*
288 : * For the sake of backward compatibility, we emit a slightly
289 : * different whitespace format for lists of nodes vs. other types of
290 : * lists. XXX: is this necessary?
291 : */
292 47280664 : if (IsA(node, List))
293 : {
294 42668272 : outNode(str, lfirst(lc));
295 42668272 : if (lnext(node, lc))
296 29143468 : appendStringInfoChar(str, ' ');
297 : }
298 4612392 : else if (IsA(node, IntList))
299 3518642 : appendStringInfo(str, " %d", lfirst_int(lc));
300 1093750 : else if (IsA(node, OidList))
301 1093750 : appendStringInfo(str, " %u", lfirst_oid(lc));
302 0 : else if (IsA(node, XidList))
303 0 : appendStringInfo(str, " %u", lfirst_xid(lc));
304 : else
305 0 : elog(ERROR, "unrecognized list node type: %d",
306 : (int) node->type);
307 : }
308 :
309 14476562 : appendStringInfoChar(str, ')');
310 14476562 : }
311 :
312 : /*
313 : * outBitmapset -
314 : * converts a bitmap set of integers
315 : *
316 : * Note: the output format is "(b int int ...)", similar to an integer List.
317 : *
318 : * We export this function for use by extensions that define extensible nodes.
319 : * That's somewhat historical, though, because calling outNode() will work.
320 : */
321 : void
322 14559044 : outBitmapset(StringInfo str, const Bitmapset *bms)
323 : {
324 : int x;
325 :
326 14559044 : appendStringInfoChar(str, '(');
327 14559044 : appendStringInfoChar(str, 'b');
328 14559044 : x = -1;
329 18514752 : while ((x = bms_next_member(bms, x)) >= 0)
330 3955708 : appendStringInfo(str, " %d", x);
331 14559044 : appendStringInfoChar(str, ')');
332 14559044 : }
333 :
334 : /*
335 : * Print the value of a Datum given its type.
336 : */
337 : void
338 1953160 : outDatum(StringInfo str, Datum value, int typlen, bool typbyval)
339 : {
340 : Size length,
341 : i;
342 : char *s;
343 :
344 1953160 : length = datumGetSize(value, typbyval, typlen);
345 :
346 1953160 : if (typbyval)
347 : {
348 1320578 : s = (char *) (&value);
349 1320578 : appendStringInfo(str, "%u [ ", (unsigned int) length);
350 11885202 : for (i = 0; i < (Size) sizeof(Datum); i++)
351 10564624 : appendStringInfo(str, "%d ", (int) (s[i]));
352 1320578 : appendStringInfoChar(str, ']');
353 : }
354 : else
355 : {
356 632582 : s = (char *) DatumGetPointer(value);
357 632582 : if (!PointerIsValid(s))
358 0 : appendStringInfoString(str, "0 [ ]");
359 : else
360 : {
361 632582 : appendStringInfo(str, "%u [ ", (unsigned int) length);
362 53540550 : for (i = 0; i < length; i++)
363 52907968 : appendStringInfo(str, "%d ", (int) (s[i]));
364 632582 : appendStringInfoChar(str, ']');
365 : }
366 : }
367 1953160 : }
368 :
369 :
370 : #include "outfuncs.funcs.c"
371 :
372 :
373 : /*
374 : * Support functions for nodes with custom_read_write attribute or
375 : * special_read_write attribute
376 : */
377 :
378 : static void
379 2107494 : _outConst(StringInfo str, const Const *node)
380 : {
381 2107494 : WRITE_NODE_TYPE("CONST");
382 :
383 2107494 : WRITE_OID_FIELD(consttype);
384 2107494 : WRITE_INT_FIELD(consttypmod);
385 2107494 : WRITE_OID_FIELD(constcollid);
386 2107494 : WRITE_INT_FIELD(constlen);
387 2107494 : WRITE_BOOL_FIELD(constbyval);
388 2107494 : WRITE_BOOL_FIELD(constisnull);
389 2107494 : WRITE_LOCATION_FIELD(location);
390 :
391 2107494 : appendStringInfoString(str, " :constvalue ");
392 2107494 : if (node->constisnull)
393 154334 : appendStringInfoString(str, "<>");
394 : else
395 1953160 : outDatum(str, node->constvalue, node->constlen, node->constbyval);
396 2107494 : }
397 :
398 : static void
399 292344 : _outBoolExpr(StringInfo str, const BoolExpr *node)
400 : {
401 292344 : char *opstr = NULL;
402 :
403 292344 : WRITE_NODE_TYPE("BOOLEXPR");
404 :
405 : /* do-it-yourself enum representation */
406 292344 : switch (node->boolop)
407 : {
408 223578 : case AND_EXPR:
409 223578 : opstr = "and";
410 223578 : break;
411 34114 : case OR_EXPR:
412 34114 : opstr = "or";
413 34114 : break;
414 34652 : case NOT_EXPR:
415 34652 : opstr = "not";
416 34652 : break;
417 : }
418 292344 : appendStringInfoString(str, " :boolop ");
419 292344 : outToken(str, opstr);
420 :
421 292344 : WRITE_NODE_FIELD(args);
422 292344 : WRITE_LOCATION_FIELD(location);
423 292344 : }
424 :
425 : static void
426 0 : _outForeignKeyOptInfo(StringInfo str, const ForeignKeyOptInfo *node)
427 : {
428 : int i;
429 :
430 0 : WRITE_NODE_TYPE("FOREIGNKEYOPTINFO");
431 :
432 0 : WRITE_UINT_FIELD(con_relid);
433 0 : WRITE_UINT_FIELD(ref_relid);
434 0 : WRITE_INT_FIELD(nkeys);
435 0 : WRITE_ATTRNUMBER_ARRAY(conkey, node->nkeys);
436 0 : WRITE_ATTRNUMBER_ARRAY(confkey, node->nkeys);
437 0 : WRITE_OID_ARRAY(conpfeqop, node->nkeys);
438 0 : WRITE_INT_FIELD(nmatched_ec);
439 0 : WRITE_INT_FIELD(nconst_ec);
440 0 : WRITE_INT_FIELD(nmatched_rcols);
441 0 : WRITE_INT_FIELD(nmatched_ri);
442 : /* for compactness, just print the number of matches per column: */
443 0 : appendStringInfoString(str, " :eclass");
444 0 : for (i = 0; i < node->nkeys; i++)
445 0 : appendStringInfo(str, " %d", (node->eclass[i] != NULL));
446 0 : appendStringInfoString(str, " :rinfos");
447 0 : for (i = 0; i < node->nkeys; i++)
448 0 : appendStringInfo(str, " %d", list_length(node->rinfos[i]));
449 0 : }
450 :
451 : static void
452 0 : _outEquivalenceClass(StringInfo str, const EquivalenceClass *node)
453 : {
454 : /*
455 : * To simplify reading, we just chase up to the topmost merged EC and
456 : * print that, without bothering to show the merge-ees separately.
457 : */
458 0 : while (node->ec_merged)
459 0 : node = node->ec_merged;
460 :
461 0 : WRITE_NODE_TYPE("EQUIVALENCECLASS");
462 :
463 0 : WRITE_NODE_FIELD(ec_opfamilies);
464 0 : WRITE_OID_FIELD(ec_collation);
465 0 : WRITE_NODE_FIELD(ec_members);
466 0 : WRITE_NODE_FIELD(ec_sources);
467 0 : WRITE_NODE_FIELD(ec_derives);
468 0 : WRITE_BITMAPSET_FIELD(ec_relids);
469 0 : WRITE_BOOL_FIELD(ec_has_const);
470 0 : WRITE_BOOL_FIELD(ec_has_volatile);
471 0 : WRITE_BOOL_FIELD(ec_broken);
472 0 : WRITE_UINT_FIELD(ec_sortref);
473 0 : WRITE_UINT_FIELD(ec_min_security);
474 0 : WRITE_UINT_FIELD(ec_max_security);
475 0 : }
476 :
477 : static void
478 0 : _outExtensibleNode(StringInfo str, const ExtensibleNode *node)
479 : {
480 : const ExtensibleNodeMethods *methods;
481 :
482 0 : methods = GetExtensibleNodeMethods(node->extnodename, false);
483 :
484 0 : WRITE_NODE_TYPE("EXTENSIBLENODE");
485 :
486 0 : WRITE_STRING_FIELD(extnodename);
487 :
488 : /* serialize the private fields */
489 0 : methods->nodeOut(str, node);
490 0 : }
491 :
492 : static void
493 1353236 : _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
494 : {
495 1353236 : WRITE_NODE_TYPE("RANGETBLENTRY");
496 :
497 : /* put alias + eref first to make dump more legible */
498 1353236 : WRITE_NODE_FIELD(alias);
499 1353236 : WRITE_NODE_FIELD(eref);
500 1353236 : WRITE_ENUM_FIELD(rtekind, RTEKind);
501 :
502 1353236 : switch (node->rtekind)
503 : {
504 820542 : case RTE_RELATION:
505 820542 : WRITE_OID_FIELD(relid);
506 820542 : WRITE_CHAR_FIELD(relkind);
507 820542 : WRITE_INT_FIELD(rellockmode);
508 820542 : WRITE_NODE_FIELD(tablesample);
509 820542 : WRITE_UINT_FIELD(perminfoindex);
510 820542 : break;
511 96496 : case RTE_SUBQUERY:
512 96496 : WRITE_NODE_FIELD(subquery);
513 96496 : WRITE_BOOL_FIELD(security_barrier);
514 : /* we re-use these RELATION fields, too: */
515 96496 : WRITE_OID_FIELD(relid);
516 96496 : WRITE_CHAR_FIELD(relkind);
517 96496 : WRITE_INT_FIELD(rellockmode);
518 96496 : WRITE_UINT_FIELD(perminfoindex);
519 96496 : break;
520 143862 : case RTE_JOIN:
521 143862 : WRITE_ENUM_FIELD(jointype, JoinType);
522 143862 : WRITE_INT_FIELD(joinmergedcols);
523 143862 : WRITE_NODE_FIELD(joinaliasvars);
524 143862 : WRITE_NODE_FIELD(joinleftcols);
525 143862 : WRITE_NODE_FIELD(joinrightcols);
526 143862 : WRITE_NODE_FIELD(join_using_alias);
527 143862 : break;
528 79432 : case RTE_FUNCTION:
529 79432 : WRITE_NODE_FIELD(functions);
530 79432 : WRITE_BOOL_FIELD(funcordinality);
531 79432 : break;
532 436 : case RTE_TABLEFUNC:
533 436 : WRITE_NODE_FIELD(tablefunc);
534 436 : break;
535 16128 : case RTE_VALUES:
536 16128 : WRITE_NODE_FIELD(values_lists);
537 16128 : WRITE_NODE_FIELD(coltypes);
538 16128 : WRITE_NODE_FIELD(coltypmods);
539 16128 : WRITE_NODE_FIELD(colcollations);
540 16128 : break;
541 8786 : case RTE_CTE:
542 8786 : WRITE_STRING_FIELD(ctename);
543 8786 : WRITE_UINT_FIELD(ctelevelsup);
544 8786 : WRITE_BOOL_FIELD(self_reference);
545 8786 : WRITE_NODE_FIELD(coltypes);
546 8786 : WRITE_NODE_FIELD(coltypmods);
547 8786 : WRITE_NODE_FIELD(colcollations);
548 8786 : break;
549 884 : case RTE_NAMEDTUPLESTORE:
550 884 : WRITE_STRING_FIELD(enrname);
551 884 : WRITE_FLOAT_FIELD(enrtuples);
552 884 : WRITE_NODE_FIELD(coltypes);
553 884 : WRITE_NODE_FIELD(coltypmods);
554 884 : WRITE_NODE_FIELD(colcollations);
555 : /* we re-use these RELATION fields, too: */
556 884 : WRITE_OID_FIELD(relid);
557 884 : break;
558 186670 : case RTE_RESULT:
559 : /* no extra fields */
560 186670 : break;
561 0 : default:
562 0 : elog(ERROR, "unrecognized RTE kind: %d", (int) node->rtekind);
563 : break;
564 : }
565 :
566 1353236 : WRITE_BOOL_FIELD(lateral);
567 1353236 : WRITE_BOOL_FIELD(inh);
568 1353236 : WRITE_BOOL_FIELD(inFromCl);
569 1353236 : WRITE_NODE_FIELD(securityQuals);
570 1353236 : }
571 :
572 : static void
573 537510 : _outA_Expr(StringInfo str, const A_Expr *node)
574 : {
575 537510 : WRITE_NODE_TYPE("A_EXPR");
576 :
577 537510 : switch (node->kind)
578 : {
579 502816 : case AEXPR_OP:
580 502816 : WRITE_NODE_FIELD(name);
581 502816 : break;
582 12418 : case AEXPR_OP_ANY:
583 12418 : appendStringInfoString(str, " ANY");
584 12418 : WRITE_NODE_FIELD(name);
585 12418 : break;
586 144 : case AEXPR_OP_ALL:
587 144 : appendStringInfoString(str, " ALL");
588 144 : WRITE_NODE_FIELD(name);
589 144 : break;
590 744 : case AEXPR_DISTINCT:
591 744 : appendStringInfoString(str, " DISTINCT");
592 744 : WRITE_NODE_FIELD(name);
593 744 : break;
594 68 : case AEXPR_NOT_DISTINCT:
595 68 : appendStringInfoString(str, " NOT_DISTINCT");
596 68 : WRITE_NODE_FIELD(name);
597 68 : break;
598 294 : case AEXPR_NULLIF:
599 294 : appendStringInfoString(str, " NULLIF");
600 294 : WRITE_NODE_FIELD(name);
601 294 : break;
602 18198 : case AEXPR_IN:
603 18198 : appendStringInfoString(str, " IN");
604 18198 : WRITE_NODE_FIELD(name);
605 18198 : break;
606 2050 : case AEXPR_LIKE:
607 2050 : appendStringInfoString(str, " LIKE");
608 2050 : WRITE_NODE_FIELD(name);
609 2050 : break;
610 144 : case AEXPR_ILIKE:
611 144 : appendStringInfoString(str, " ILIKE");
612 144 : WRITE_NODE_FIELD(name);
613 144 : break;
614 58 : case AEXPR_SIMILAR:
615 58 : appendStringInfoString(str, " SIMILAR");
616 58 : WRITE_NODE_FIELD(name);
617 58 : break;
618 540 : case AEXPR_BETWEEN:
619 540 : appendStringInfoString(str, " BETWEEN");
620 540 : WRITE_NODE_FIELD(name);
621 540 : break;
622 12 : case AEXPR_NOT_BETWEEN:
623 12 : appendStringInfoString(str, " NOT_BETWEEN");
624 12 : WRITE_NODE_FIELD(name);
625 12 : break;
626 12 : case AEXPR_BETWEEN_SYM:
627 12 : appendStringInfoString(str, " BETWEEN_SYM");
628 12 : WRITE_NODE_FIELD(name);
629 12 : break;
630 12 : case AEXPR_NOT_BETWEEN_SYM:
631 12 : appendStringInfoString(str, " NOT_BETWEEN_SYM");
632 12 : WRITE_NODE_FIELD(name);
633 12 : break;
634 0 : default:
635 0 : elog(ERROR, "unrecognized A_Expr_Kind: %d", (int) node->kind);
636 : break;
637 : }
638 :
639 537510 : WRITE_NODE_FIELD(lexpr);
640 537510 : WRITE_NODE_FIELD(rexpr);
641 537510 : WRITE_LOCATION_FIELD(location);
642 537510 : }
643 :
644 : static void
645 450530 : _outInteger(StringInfo str, const Integer *node)
646 : {
647 450530 : appendStringInfo(str, "%d", node->ival);
648 450530 : }
649 :
650 : static void
651 10956 : _outFloat(StringInfo str, const Float *node)
652 : {
653 : /*
654 : * We assume the value is a valid numeric literal and so does not need
655 : * quoting.
656 : */
657 10956 : appendStringInfoString(str, node->fval);
658 10956 : }
659 :
660 : static void
661 77708 : _outBoolean(StringInfo str, const Boolean *node)
662 : {
663 77708 : appendStringInfoString(str, node->boolval ? "true" : "false");
664 77708 : }
665 :
666 : static void
667 21871234 : _outString(StringInfo str, const String *node)
668 : {
669 : /*
670 : * We use outToken to provide escaping of the string's content, but we
671 : * don't want it to convert an empty string to '""', because we're putting
672 : * double quotes around the string already.
673 : */
674 21871234 : appendStringInfoChar(str, '"');
675 21871234 : if (node->sval[0] != '\0')
676 21845502 : outToken(str, node->sval);
677 21871234 : appendStringInfoChar(str, '"');
678 21871234 : }
679 :
680 : static void
681 4044 : _outBitString(StringInfo str, const BitString *node)
682 : {
683 : /* internal representation already has leading 'b' */
684 4044 : appendStringInfoString(str, node->bsval);
685 4044 : }
686 :
687 : static void
688 1134858 : _outA_Const(StringInfo str, const A_Const *node)
689 : {
690 1134858 : WRITE_NODE_TYPE("A_CONST");
691 :
692 1134858 : if (node->isnull)
693 60194 : appendStringInfoString(str, " NULL");
694 : else
695 : {
696 1074664 : appendStringInfoString(str, " :val ");
697 1074664 : outNode(str, &node->val);
698 : }
699 1134858 : WRITE_LOCATION_FIELD(location);
700 1134858 : }
701 :
702 : static void
703 53794 : _outConstraint(StringInfo str, const Constraint *node)
704 : {
705 53794 : WRITE_NODE_TYPE("CONSTRAINT");
706 :
707 53794 : WRITE_STRING_FIELD(conname);
708 53794 : WRITE_BOOL_FIELD(deferrable);
709 53794 : WRITE_BOOL_FIELD(initdeferred);
710 53794 : WRITE_LOCATION_FIELD(location);
711 :
712 53794 : appendStringInfoString(str, " :contype ");
713 53794 : switch (node->contype)
714 : {
715 48 : case CONSTR_NULL:
716 48 : appendStringInfoString(str, "NULL");
717 48 : break;
718 :
719 11604 : case CONSTR_NOTNULL:
720 11604 : appendStringInfoString(str, "NOT_NULL");
721 11604 : WRITE_NODE_FIELD(keys);
722 11604 : WRITE_INT_FIELD(inhcount);
723 11604 : WRITE_BOOL_FIELD(is_no_inherit);
724 11604 : WRITE_BOOL_FIELD(skip_validation);
725 11604 : WRITE_BOOL_FIELD(initially_valid);
726 11604 : break;
727 :
728 3152 : case CONSTR_DEFAULT:
729 3152 : appendStringInfoString(str, "DEFAULT");
730 3152 : WRITE_NODE_FIELD(raw_expr);
731 3152 : WRITE_STRING_FIELD(cooked_expr);
732 3152 : break;
733 :
734 664 : case CONSTR_IDENTITY:
735 664 : appendStringInfoString(str, "IDENTITY");
736 664 : WRITE_NODE_FIELD(options);
737 664 : WRITE_CHAR_FIELD(generated_when);
738 664 : break;
739 :
740 1690 : case CONSTR_GENERATED:
741 1690 : appendStringInfoString(str, "GENERATED");
742 1690 : WRITE_NODE_FIELD(raw_expr);
743 1690 : WRITE_STRING_FIELD(cooked_expr);
744 1690 : WRITE_CHAR_FIELD(generated_when);
745 1690 : break;
746 :
747 3688 : case CONSTR_CHECK:
748 3688 : appendStringInfoString(str, "CHECK");
749 3688 : WRITE_BOOL_FIELD(is_no_inherit);
750 3688 : WRITE_NODE_FIELD(raw_expr);
751 3688 : WRITE_STRING_FIELD(cooked_expr);
752 3688 : WRITE_BOOL_FIELD(skip_validation);
753 3688 : WRITE_BOOL_FIELD(initially_valid);
754 3688 : break;
755 :
756 20790 : case CONSTR_PRIMARY:
757 20790 : appendStringInfoString(str, "PRIMARY_KEY");
758 20790 : WRITE_NODE_FIELD(keys);
759 20790 : WRITE_NODE_FIELD(including);
760 20790 : WRITE_NODE_FIELD(options);
761 20790 : WRITE_STRING_FIELD(indexname);
762 20790 : WRITE_STRING_FIELD(indexspace);
763 20790 : WRITE_BOOL_FIELD(reset_default_tblspc);
764 : /* access_method and where_clause not currently used */
765 20790 : break;
766 :
767 7218 : case CONSTR_UNIQUE:
768 7218 : appendStringInfoString(str, "UNIQUE");
769 7218 : WRITE_BOOL_FIELD(nulls_not_distinct);
770 7218 : WRITE_NODE_FIELD(keys);
771 7218 : WRITE_NODE_FIELD(including);
772 7218 : WRITE_NODE_FIELD(options);
773 7218 : WRITE_STRING_FIELD(indexname);
774 7218 : WRITE_STRING_FIELD(indexspace);
775 7218 : WRITE_BOOL_FIELD(reset_default_tblspc);
776 : /* access_method and where_clause not currently used */
777 7218 : break;
778 :
779 420 : case CONSTR_EXCLUSION:
780 420 : appendStringInfoString(str, "EXCLUSION");
781 420 : WRITE_NODE_FIELD(exclusions);
782 420 : WRITE_NODE_FIELD(including);
783 420 : WRITE_NODE_FIELD(options);
784 420 : WRITE_STRING_FIELD(indexname);
785 420 : WRITE_STRING_FIELD(indexspace);
786 420 : WRITE_BOOL_FIELD(reset_default_tblspc);
787 420 : WRITE_STRING_FIELD(access_method);
788 420 : WRITE_NODE_FIELD(where_clause);
789 420 : break;
790 :
791 4220 : case CONSTR_FOREIGN:
792 4220 : appendStringInfoString(str, "FOREIGN_KEY");
793 4220 : WRITE_NODE_FIELD(pktable);
794 4220 : WRITE_NODE_FIELD(fk_attrs);
795 4220 : WRITE_NODE_FIELD(pk_attrs);
796 4220 : WRITE_CHAR_FIELD(fk_matchtype);
797 4220 : WRITE_CHAR_FIELD(fk_upd_action);
798 4220 : WRITE_CHAR_FIELD(fk_del_action);
799 4220 : WRITE_NODE_FIELD(fk_del_set_cols);
800 4220 : WRITE_NODE_FIELD(old_conpfeqop);
801 4220 : WRITE_OID_FIELD(old_pktable_oid);
802 4220 : WRITE_BOOL_FIELD(skip_validation);
803 4220 : WRITE_BOOL_FIELD(initially_valid);
804 4220 : break;
805 :
806 162 : case CONSTR_ATTR_DEFERRABLE:
807 162 : appendStringInfoString(str, "ATTR_DEFERRABLE");
808 162 : break;
809 :
810 0 : case CONSTR_ATTR_NOT_DEFERRABLE:
811 0 : appendStringInfoString(str, "ATTR_NOT_DEFERRABLE");
812 0 : break;
813 :
814 126 : case CONSTR_ATTR_DEFERRED:
815 126 : appendStringInfoString(str, "ATTR_DEFERRED");
816 126 : break;
817 :
818 12 : case CONSTR_ATTR_IMMEDIATE:
819 12 : appendStringInfoString(str, "ATTR_IMMEDIATE");
820 12 : break;
821 :
822 0 : default:
823 0 : elog(ERROR, "unrecognized ConstrType: %d", (int) node->contype);
824 : break;
825 : }
826 53794 : }
827 :
828 :
829 : /*
830 : * outNode -
831 : * converts a Node into ascii string and append it to 'str'
832 : */
833 : void
834 116636414 : outNode(StringInfo str, const void *obj)
835 : {
836 : /* Guard against stack overflow due to overly complex expressions */
837 116636414 : check_stack_depth();
838 :
839 116636414 : if (obj == NULL)
840 41554532 : appendStringInfoString(str, "<>");
841 75081882 : else if (IsA(obj, List) || IsA(obj, IntList) || IsA(obj, OidList) ||
842 60605320 : IsA(obj, XidList))
843 14476562 : _outList(str, obj);
844 : /* nodeRead does not want to see { } around these! */
845 60605320 : else if (IsA(obj, Integer))
846 450530 : _outInteger(str, (Integer *) obj);
847 60154790 : else if (IsA(obj, Float))
848 10956 : _outFloat(str, (Float *) obj);
849 60143834 : else if (IsA(obj, Boolean))
850 77708 : _outBoolean(str, (Boolean *) obj);
851 60066126 : else if (IsA(obj, String))
852 21871234 : _outString(str, (String *) obj);
853 38194892 : else if (IsA(obj, BitString))
854 4044 : _outBitString(str, (BitString *) obj);
855 38190848 : else if (IsA(obj, Bitmapset))
856 0 : outBitmapset(str, (Bitmapset *) obj);
857 : else
858 : {
859 38190848 : appendStringInfoChar(str, '{');
860 38190848 : switch (nodeTag(obj))
861 : {
862 : #include "outfuncs.switch.c"
863 :
864 0 : default:
865 :
866 : /*
867 : * This should be an ERROR, but it's too useful to be able to
868 : * dump structures that outNode only understands part of.
869 : */
870 0 : elog(WARNING, "could not dump unrecognized node type: %d",
871 : (int) nodeTag(obj));
872 0 : break;
873 : }
874 38190848 : appendStringInfoChar(str, '}');
875 : }
876 116636414 : }
877 :
878 : /*
879 : * nodeToString -
880 : * returns the ascii representation of the Node as a palloc'd string
881 : */
882 : char *
883 1703212 : nodeToString(const void *obj)
884 : {
885 : StringInfoData str;
886 :
887 : /* see stringinfo.h for an explanation of this maneuver */
888 1703212 : initStringInfo(&str);
889 1703212 : outNode(&str, obj);
890 1703212 : return str.data;
891 : }
892 :
893 : /*
894 : * bmsToString -
895 : * returns the ascii representation of the Bitmapset as a palloc'd string
896 : */
897 : char *
898 0 : bmsToString(const Bitmapset *bms)
899 : {
900 : StringInfoData str;
901 :
902 : /* see stringinfo.h for an explanation of this maneuver */
903 0 : initStringInfo(&str);
904 0 : outBitmapset(&str, bms);
905 0 : return str.data;
906 : }
|