Age Owner TLA 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 */
1569 peter_e 129 ECB : #define WRITE_BOOL_ARRAY(fldname, len) \
130 : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
131 : writeBoolCols(str, node->fldname, len))
7440 tgl 132 EUB :
8126 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.
8486 tgl 144 ECB : */
2396 145 : void
2396 tgl 146 CBC 5872388 : outToken(StringInfo str, const char *s)
8486 tgl 147 ECB : {
195 peter 148 GNC 5872388 : if (s == NULL)
8486 tgl 149 ECB : {
3447 rhaas 150 CBC 27325 : appendStringInfoString(str, "<>");
8486 tgl 151 GIC 27325 : return;
152 : }
195 peter 153 GNC 5845063 : if (*s == '\0')
154 : {
195 peter 155 UNC 0 : appendStringInfoString(str, "\"\"");
156 0 : return;
157 : }
8397 bruce 158 ECB :
8486 tgl 159 : /*
6385 bruce 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 */
8486 tgl 165 GIC 5845063 : if (*s == '<' ||
2665 peter_e 166 5845057 : *s == '"' ||
8162 tgl 167 5845057 : isdigit((unsigned char) *s) ||
8126 168 5845057 : ((*s == '+' || *s == '-') &&
8126 tgl 169 UIC 0 : (isdigit((unsigned char) s[1]) || s[1] == '.')))
8486 tgl 170 GIC 6 : appendStringInfoChar(str, '\\');
8486 tgl 171 CBC 59393099 : while (*s)
172 : {
173 : /* These chars must be backslashed anywhere in the string */
8486 tgl 174 GIC 53548036 : if (*s == ' ' || *s == '\n' || *s == '\t' ||
175 53513191 : *s == '(' || *s == ')' || *s == '{' || *s == '}' ||
8486 tgl 176 CBC 53513191 : *s == '\\')
8486 tgl 177 GIC 34845 : appendStringInfoChar(str, '\\');
8486 tgl 178 GBC 53548036 : appendStringInfoChar(str, *s++);
8486 tgl 179 EUB : }
180 : }
181 :
2118 peter_e 182 ECB : /*
183 : * Convert one char. Goes through outToken() so that special characters are
184 : * escaped.
185 : */
186 : static void
2118 peter_e 187 GIC 152249 : outChar(StringInfo str, char c)
188 : {
189 : char in[2];
190 :
191 : /* Traditionally, we've represented \0 as <>, so keep doing that */
195 peter 192 GNC 152249 : if (c == '\0')
193 : {
195 peter 194 UNC 0 : appendStringInfoString(str, "<>");
195 0 : return;
196 : }
197 :
2118 peter_e 198 GIC 152249 : in[0] = c;
2118 peter_e 199 CBC 152249 : in[1] = '\0';
200 :
2118 peter_e 201 GIC 152249 : outToken(str, in);
202 : }
2118 peter_e 203 ECB :
204 : /*
205 : * Convert a double value, attempting to ensure the value is preserved exactly.
206 : */
207 : static void
195 peter 208 GNC 4566 : outDouble(StringInfo str, double d)
209 : {
210 : char buf[DOUBLE_SHORTEST_DECIMAL_LEN];
211 :
212 4566 : double_to_shortest_decimal_buf(d, buf);
213 4566 : appendStringInfoString(str, buf);
214 4566 : }
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 :
263 tgl 239 584 : WRITE_SCALAR_ARRAY(writeAttrNumberCols, AttrNumber, " %d",)
240 1717 : WRITE_SCALAR_ARRAY(writeOidCols, Oid, " %u",)
263 tgl 241 UNC 0 : WRITE_SCALAR_ARRAY(writeIndexCols, Index, " %u",)
263 tgl 242 GNC 1056 : WRITE_SCALAR_ARRAY(writeIntCols, int, " %d",)
243 161 : 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
263 tgl 252 UNC 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 : */
9646 bruce 271 ECB : static void
4141 peter_e 272 CBC 1460578 : _outList(StringInfo str, const List *node)
273 : {
274 : const ListCell *lc;
275 :
8486 tgl 276 GIC 1460578 : appendStringInfoChar(str, '(');
277 :
6892 neilc 278 1460578 : if (IsA(node, IntList))
279 100385 : appendStringInfoChar(str, 'i');
280 1360193 : else if (IsA(node, OidList))
281 29841 : appendStringInfoChar(str, 'o');
279 alvherre 282 GNC 1330352 : else if (IsA(node, XidList))
279 alvherre 283 UNC 0 : appendStringInfoChar(str, 'x');
284 :
6797 bruce 285 GIC 13223340 : 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 : */
6892 neilc 292 11762762 : if (IsA(node, List))
293 : {
2557 andres 294 9348408 : outNode(str, lfirst(lc));
1364 tgl 295 9348408 : if (lnext(node, lc))
6892 neilc 296 8018056 : appendStringInfoChar(str, ' ');
297 : }
298 2414354 : else if (IsA(node, IntList))
6892 neilc 299 CBC 2272495 : appendStringInfo(str, " %d", lfirst_int(lc));
300 141859 : else if (IsA(node, OidList))
6892 neilc 301 GBC 141859 : appendStringInfo(str, " %u", lfirst_oid(lc));
279 alvherre 302 UNC 0 : else if (IsA(node, XidList))
303 0 : appendStringInfo(str, " %u", lfirst_xid(lc));
6892 neilc 304 ECB : else
6797 bruce 305 LBC 0 : elog(ERROR, "unrecognized list node type: %d",
306 : (int) node->type);
307 : }
308 :
8126 tgl 309 GIC 1460578 : appendStringInfoChar(str, ')');
310 1460578 : }
311 :
312 : /*
313 : * outBitmapset -
7365 tgl 314 EUB : * converts a bitmap set of integers
315 : *
6910 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 : */
2396 321 : void
2396 tgl 322 GBC 3573485 : outBitmapset(StringInfo str, const Bitmapset *bms)
323 : {
7365 tgl 324 EUB : int x;
325 :
7365 tgl 326 GIC 3573485 : appendStringInfoChar(str, '(');
6910 tgl 327 GBC 3573485 : appendStringInfoChar(str, 'b');
3054 tgl 328 GIC 3573485 : x = -1;
329 4489977 : while ((x = bms_next_member(bms, x)) >= 0)
7365 tgl 330 GBC 916492 : appendStringInfo(str, " %d", x);
331 3573485 : appendStringInfoChar(str, ')');
7365 tgl 332 GIC 3573485 : }
333 :
334 : /*
335 : * Print the value of a Datum given its type.
336 : */
2557 andres 337 ECB : void
2557 andres 338 GIC 390985 : outDatum(StringInfo str, Datum value, int typlen, bool typbyval)
339 : {
340 : Size length,
7423 tgl 341 ECB : i;
342 : char *s;
7440 343 :
7423 tgl 344 CBC 390985 : length = datumGetSize(value, typbyval, typlen);
8844 vadim4o 345 ECB :
7423 tgl 346 CBC 390985 : if (typbyval)
9257 lockhart 347 ECB : {
7423 tgl 348 GBC 235742 : s = (char *) (&value);
7423 tgl 349 GIC 235742 : appendStringInfo(str, "%u [ ", (unsigned int) length);
7423 tgl 350 CBC 2121678 : for (i = 0; i < (Size) sizeof(Datum); i++)
7423 tgl 351 GIC 1885936 : appendStringInfo(str, "%d ", (int) (s[i]));
3447 rhaas 352 235742 : appendStringInfoChar(str, ']');
353 : }
354 : else
355 : {
7423 tgl 356 155243 : s = (char *) DatumGetPointer(value);
7423 tgl 357 CBC 155243 : if (!PointerIsValid(s))
3447 rhaas 358 UIC 0 : appendStringInfoString(str, "0 [ ]");
7423 tgl 359 ECB : else
9257 lockhart 360 : {
7423 tgl 361 CBC 155243 : appendStringInfo(str, "%u [ ", (unsigned int) length);
7423 tgl 362 GIC 3218451 : for (i = 0; i < length; i++)
7423 tgl 363 CBC 3063208 : appendStringInfo(str, "%d ", (int) (s[i]));
3447 rhaas 364 155243 : appendStringInfoChar(str, ']');
9257 lockhart 365 ECB : }
366 : }
9770 scrappy 367 GBC 390985 : }
9770 scrappy 368 EUB :
369 :
370 : #include "outfuncs.funcs.c"
371 :
372 :
7440 tgl 373 ECB : /*
374 : * Support functions for nodes with custom_read_write attribute or
375 : * special_read_write attribute
376 : */
377 :
378 : static void
274 peter 379 GIC 467276 : _outConst(StringInfo str, const Const *node)
380 : {
381 467276 : WRITE_NODE_TYPE("CONST");
382 :
383 467276 : WRITE_OID_FIELD(consttype);
384 467276 : WRITE_INT_FIELD(consttypmod);
385 467276 : WRITE_OID_FIELD(constcollid);
386 467276 : WRITE_INT_FIELD(constlen);
387 467276 : WRITE_BOOL_FIELD(constbyval);
388 467276 : WRITE_BOOL_FIELD(constisnull);
389 467276 : WRITE_LOCATION_FIELD(location);
390 :
391 467276 : appendStringInfoString(str, " :constvalue ");
392 467276 : if (node->constisnull)
393 76291 : appendStringInfoString(str, "<>");
394 : else
395 390985 : outDatum(str, node->constvalue, node->constlen, node->constbyval);
7440 tgl 396 467276 : }
397 :
398 : static void
274 peter 399 70533 : _outBoolExpr(StringInfo str, const BoolExpr *node)
400 : {
401 70533 : char *opstr = NULL;
402 :
403 70533 : WRITE_NODE_TYPE("BOOLEXPR");
404 :
405 : /* do-it-yourself enum representation */
406 70533 : switch (node->boolop)
407 : {
408 41660 : case AND_EXPR:
409 41660 : opstr = "and";
410 41660 : break;
411 19135 : case OR_EXPR:
412 19135 : opstr = "or";
413 19135 : break;
414 9738 : case NOT_EXPR:
415 9738 : opstr = "not";
416 9738 : break;
417 : }
418 70533 : appendStringInfoString(str, " :boolop ");
419 70533 : outToken(str, opstr);
420 :
421 70533 : WRITE_NODE_FIELD(args);
422 70533 : WRITE_LOCATION_FIELD(location);
7440 tgl 423 70533 : }
424 :
425 : static void
274 peter 426 UIC 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]));
2272 andres 449 0 : }
450 :
451 : static void
274 peter 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);
4929 tgl 475 0 : }
476 :
477 : static void
274 peter 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);
4560 tgl 490 0 : }
491 :
492 : static void
274 peter 493 GIC 229315 : _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
494 : {
495 229315 : WRITE_NODE_TYPE("RANGETBLENTRY");
496 :
497 : /* put alias + eref first to make dump more legible */
498 229315 : WRITE_NODE_FIELD(alias);
499 229315 : WRITE_NODE_FIELD(eref);
500 229315 : WRITE_ENUM_FIELD(rtekind, RTEKind);
501 :
502 229315 : switch (node->rtekind)
503 : {
504 142736 : case RTE_RELATION:
505 142736 : WRITE_OID_FIELD(relid);
506 142736 : WRITE_CHAR_FIELD(relkind);
507 142736 : WRITE_INT_FIELD(rellockmode);
508 142736 : WRITE_NODE_FIELD(tablesample);
124 alvherre 509 GNC 142736 : WRITE_UINT_FIELD(perminfoindex);
274 peter 510 GIC 142736 : break;
511 27954 : case RTE_SUBQUERY:
512 27954 : WRITE_NODE_FIELD(subquery);
513 27954 : WRITE_BOOL_FIELD(security_barrier);
514 : /* we re-use these RELATION fields, too: */
81 tgl 515 GNC 27954 : WRITE_OID_FIELD(relid);
516 27954 : WRITE_INT_FIELD(rellockmode);
517 27954 : WRITE_UINT_FIELD(perminfoindex);
274 peter 518 GIC 27954 : break;
519 44248 : case RTE_JOIN:
520 44248 : WRITE_ENUM_FIELD(jointype, JoinType);
521 44248 : WRITE_INT_FIELD(joinmergedcols);
522 44248 : WRITE_NODE_FIELD(joinaliasvars);
523 44248 : WRITE_NODE_FIELD(joinleftcols);
524 44248 : WRITE_NODE_FIELD(joinrightcols);
525 44248 : WRITE_NODE_FIELD(join_using_alias);
526 44248 : break;
527 13850 : case RTE_FUNCTION:
528 13850 : WRITE_NODE_FIELD(functions);
529 13850 : WRITE_BOOL_FIELD(funcordinality);
530 13850 : break;
531 8 : case RTE_TABLEFUNC:
532 8 : WRITE_NODE_FIELD(tablefunc);
533 8 : break;
534 426 : case RTE_VALUES:
535 426 : WRITE_NODE_FIELD(values_lists);
536 426 : WRITE_NODE_FIELD(coltypes);
537 426 : WRITE_NODE_FIELD(coltypmods);
538 426 : WRITE_NODE_FIELD(colcollations);
539 426 : break;
540 69 : case RTE_CTE:
541 69 : WRITE_STRING_FIELD(ctename);
542 69 : WRITE_UINT_FIELD(ctelevelsup);
543 69 : WRITE_BOOL_FIELD(self_reference);
544 69 : WRITE_NODE_FIELD(coltypes);
545 69 : WRITE_NODE_FIELD(coltypmods);
546 69 : WRITE_NODE_FIELD(colcollations);
547 69 : break;
274 peter 548 UIC 0 : case RTE_NAMEDTUPLESTORE:
549 0 : WRITE_STRING_FIELD(enrname);
195 peter 550 UNC 0 : WRITE_FLOAT_FIELD(enrtuples);
274 peter 551 UIC 0 : WRITE_NODE_FIELD(coltypes);
552 0 : WRITE_NODE_FIELD(coltypmods);
553 0 : WRITE_NODE_FIELD(colcollations);
554 : /* we re-use these RELATION fields, too: */
81 tgl 555 UNC 0 : WRITE_OID_FIELD(relid);
274 peter 556 UIC 0 : break;
274 peter 557 GIC 24 : case RTE_RESULT:
558 : /* no extra fields */
559 24 : break;
274 peter 560 UIC 0 : default:
561 0 : elog(ERROR, "unrecognized RTE kind: %d", (int) node->rtekind);
562 : break;
563 : }
564 :
274 peter 565 GIC 229315 : WRITE_BOOL_FIELD(lateral);
566 229315 : WRITE_BOOL_FIELD(inh);
567 229315 : WRITE_BOOL_FIELD(inFromCl);
568 229315 : WRITE_NODE_FIELD(securityQuals);
6564 tgl 569 229315 : }
570 :
571 : static void
274 peter 572 UIC 0 : _outA_Expr(StringInfo str, const A_Expr *node)
573 : {
274 peter 574 UNC 0 : WRITE_NODE_TYPE("A_EXPR");
575 :
274 peter 576 UIC 0 : switch (node->kind)
577 : {
578 0 : case AEXPR_OP:
579 0 : WRITE_NODE_FIELD(name);
580 0 : break;
581 0 : case AEXPR_OP_ANY:
237 peter 582 UNC 0 : appendStringInfoString(str, " ANY");
197 peter 583 UIC 0 : WRITE_NODE_FIELD(name);
274 584 0 : break;
585 0 : case AEXPR_OP_ALL:
237 peter 586 UNC 0 : appendStringInfoString(str, " ALL");
197 peter 587 UIC 0 : WRITE_NODE_FIELD(name);
274 588 0 : break;
589 0 : case AEXPR_DISTINCT:
237 peter 590 UNC 0 : appendStringInfoString(str, " DISTINCT");
274 peter 591 UIC 0 : WRITE_NODE_FIELD(name);
592 0 : break;
593 0 : case AEXPR_NOT_DISTINCT:
237 peter 594 UNC 0 : appendStringInfoString(str, " NOT_DISTINCT");
274 peter 595 UIC 0 : WRITE_NODE_FIELD(name);
596 0 : break;
597 0 : case AEXPR_NULLIF:
237 peter 598 UNC 0 : appendStringInfoString(str, " NULLIF");
274 peter 599 UIC 0 : WRITE_NODE_FIELD(name);
600 0 : break;
601 0 : case AEXPR_IN:
237 peter 602 UNC 0 : appendStringInfoString(str, " IN");
274 peter 603 UIC 0 : WRITE_NODE_FIELD(name);
604 0 : break;
605 0 : case AEXPR_LIKE:
237 peter 606 UNC 0 : appendStringInfoString(str, " LIKE");
274 peter 607 UIC 0 : WRITE_NODE_FIELD(name);
608 0 : break;
609 0 : case AEXPR_ILIKE:
237 peter 610 UNC 0 : appendStringInfoString(str, " ILIKE");
274 peter 611 UIC 0 : WRITE_NODE_FIELD(name);
612 0 : break;
613 0 : case AEXPR_SIMILAR:
237 peter 614 UNC 0 : appendStringInfoString(str, " SIMILAR");
274 peter 615 UIC 0 : WRITE_NODE_FIELD(name);
616 0 : break;
617 0 : case AEXPR_BETWEEN:
237 peter 618 UNC 0 : appendStringInfoString(str, " BETWEEN");
274 peter 619 UIC 0 : WRITE_NODE_FIELD(name);
620 0 : break;
621 0 : case AEXPR_NOT_BETWEEN:
237 peter 622 UNC 0 : appendStringInfoString(str, " NOT_BETWEEN");
274 peter 623 UIC 0 : WRITE_NODE_FIELD(name);
624 0 : break;
625 0 : case AEXPR_BETWEEN_SYM:
237 peter 626 UNC 0 : appendStringInfoString(str, " BETWEEN_SYM");
274 peter 627 UIC 0 : WRITE_NODE_FIELD(name);
628 0 : break;
629 0 : case AEXPR_NOT_BETWEEN_SYM:
237 peter 630 UNC 0 : appendStringInfoString(str, " NOT_BETWEEN_SYM");
274 peter 631 UIC 0 : WRITE_NODE_FIELD(name);
632 0 : break;
633 0 : default:
197 peter 634 UNC 0 : elog(ERROR, "unrecognized A_Expr_Kind: %d", (int) node->kind);
635 : break;
636 : }
637 :
274 peter 638 UIC 0 : WRITE_NODE_FIELD(lexpr);
639 0 : WRITE_NODE_FIELD(rexpr);
640 0 : WRITE_LOCATION_FIELD(location);
9770 scrappy 641 0 : }
642 :
643 : static void
274 peter 644 0 : _outInteger(StringInfo str, const Integer *node)
645 : {
646 0 : appendStringInfo(str, "%d", node->ival);
9770 scrappy 647 0 : }
648 :
649 : static void
274 peter 650 0 : _outFloat(StringInfo str, const Float *node)
651 : {
652 : /*
653 : * We assume the value is a valid numeric literal and so does not need
654 : * quoting.
655 : */
656 0 : appendStringInfoString(str, node->fval);
2815 tgl 657 0 : }
658 :
659 : static void
274 peter 660 0 : _outBoolean(StringInfo str, const Boolean *node)
661 : {
662 0 : appendStringInfoString(str, node->boolval ? "true" : "false");
4198 tgl 663 0 : }
664 :
665 : static void
274 peter 666 GIC 4641538 : _outString(StringInfo str, const String *node)
667 : {
668 : /*
669 : * We use outToken to provide escaping of the string's content, but we
670 : * don't want it to convert an empty string to '""', because we're putting
671 : * double quotes around the string already.
672 : */
673 4641538 : appendStringInfoChar(str, '"');
674 4641538 : if (node->sval[0] != '\0')
675 4641484 : outToken(str, node->sval);
676 4641538 : appendStringInfoChar(str, '"');
9770 scrappy 677 4641538 : }
678 :
679 : static void
274 peter 680 UIC 0 : _outBitString(StringInfo str, const BitString *node)
681 : {
682 : /* internal representation already has leading 'b' */
683 0 : appendStringInfoString(str, node->bsval);
6564 tgl 684 0 : }
685 :
686 : static void
274 peter 687 0 : _outA_Const(StringInfo str, const A_Const *node)
688 : {
689 0 : WRITE_NODE_TYPE("A_CONST");
690 :
691 0 : if (node->isnull)
241 692 0 : appendStringInfoString(str, " NULL");
693 : else
694 : {
274 695 0 : appendStringInfoString(str, " :val ");
696 0 : outNode(str, &node->val);
697 : }
698 0 : WRITE_LOCATION_FIELD(location);
6564 tgl 699 0 : }
700 :
701 : static void
274 peter 702 0 : _outConstraint(StringInfo str, const Constraint *node)
703 : {
704 0 : WRITE_NODE_TYPE("CONSTRAINT");
705 :
706 0 : WRITE_STRING_FIELD(conname);
707 0 : WRITE_BOOL_FIELD(deferrable);
708 0 : WRITE_BOOL_FIELD(initdeferred);
709 0 : WRITE_LOCATION_FIELD(location);
710 :
711 0 : appendStringInfoString(str, " :contype ");
712 0 : switch (node->contype)
713 : {
714 0 : case CONSTR_NULL:
715 0 : appendStringInfoString(str, "NULL");
716 0 : break;
717 :
718 0 : case CONSTR_NOTNULL:
719 0 : appendStringInfoString(str, "NOT_NULL");
2 alvherre 720 UNC 0 : WRITE_BOOL_FIELD(is_no_inherit);
721 0 : WRITE_STRING_FIELD(colname);
722 0 : WRITE_BOOL_FIELD(skip_validation);
723 0 : WRITE_BOOL_FIELD(initially_valid);
274 peter 724 UIC 0 : break;
725 :
726 0 : case CONSTR_DEFAULT:
727 0 : appendStringInfoString(str, "DEFAULT");
728 0 : WRITE_NODE_FIELD(raw_expr);
729 0 : WRITE_STRING_FIELD(cooked_expr);
730 0 : break;
731 :
732 0 : case CONSTR_IDENTITY:
733 0 : appendStringInfoString(str, "IDENTITY");
240 734 0 : WRITE_NODE_FIELD(options);
274 735 0 : WRITE_CHAR_FIELD(generated_when);
736 0 : break;
737 :
738 0 : case CONSTR_GENERATED:
739 0 : appendStringInfoString(str, "GENERATED");
740 0 : WRITE_NODE_FIELD(raw_expr);
741 0 : WRITE_STRING_FIELD(cooked_expr);
742 0 : WRITE_CHAR_FIELD(generated_when);
743 0 : break;
744 :
745 0 : case CONSTR_CHECK:
746 0 : appendStringInfoString(str, "CHECK");
747 0 : WRITE_BOOL_FIELD(is_no_inherit);
748 0 : WRITE_NODE_FIELD(raw_expr);
749 0 : WRITE_STRING_FIELD(cooked_expr);
239 750 0 : WRITE_BOOL_FIELD(skip_validation);
751 0 : WRITE_BOOL_FIELD(initially_valid);
274 752 0 : break;
753 :
754 0 : case CONSTR_PRIMARY:
755 0 : appendStringInfoString(str, "PRIMARY_KEY");
756 0 : WRITE_NODE_FIELD(keys);
757 0 : WRITE_NODE_FIELD(including);
758 0 : WRITE_NODE_FIELD(options);
759 0 : WRITE_STRING_FIELD(indexname);
760 0 : WRITE_STRING_FIELD(indexspace);
761 0 : WRITE_BOOL_FIELD(reset_default_tblspc);
762 : /* access_method and where_clause not currently used */
763 0 : break;
764 :
765 0 : case CONSTR_UNIQUE:
766 0 : appendStringInfoString(str, "UNIQUE");
767 0 : WRITE_BOOL_FIELD(nulls_not_distinct);
768 0 : WRITE_NODE_FIELD(keys);
769 0 : WRITE_NODE_FIELD(including);
770 0 : WRITE_NODE_FIELD(options);
771 0 : WRITE_STRING_FIELD(indexname);
772 0 : WRITE_STRING_FIELD(indexspace);
773 0 : WRITE_BOOL_FIELD(reset_default_tblspc);
774 : /* access_method and where_clause not currently used */
775 0 : break;
776 :
777 0 : case CONSTR_EXCLUSION:
778 0 : appendStringInfoString(str, "EXCLUSION");
779 0 : WRITE_NODE_FIELD(exclusions);
780 0 : WRITE_NODE_FIELD(including);
781 0 : WRITE_NODE_FIELD(options);
782 0 : WRITE_STRING_FIELD(indexname);
783 0 : WRITE_STRING_FIELD(indexspace);
784 0 : WRITE_BOOL_FIELD(reset_default_tblspc);
785 0 : WRITE_STRING_FIELD(access_method);
786 0 : WRITE_NODE_FIELD(where_clause);
787 0 : break;
788 :
789 0 : case CONSTR_FOREIGN:
790 0 : appendStringInfoString(str, "FOREIGN_KEY");
791 0 : WRITE_NODE_FIELD(pktable);
792 0 : WRITE_NODE_FIELD(fk_attrs);
793 0 : WRITE_NODE_FIELD(pk_attrs);
794 0 : WRITE_CHAR_FIELD(fk_matchtype);
795 0 : WRITE_CHAR_FIELD(fk_upd_action);
796 0 : WRITE_CHAR_FIELD(fk_del_action);
797 0 : WRITE_NODE_FIELD(fk_del_set_cols);
798 0 : WRITE_NODE_FIELD(old_conpfeqop);
799 0 : WRITE_OID_FIELD(old_pktable_oid);
800 0 : WRITE_BOOL_FIELD(skip_validation);
801 0 : WRITE_BOOL_FIELD(initially_valid);
802 0 : break;
803 :
804 0 : case CONSTR_ATTR_DEFERRABLE:
805 0 : appendStringInfoString(str, "ATTR_DEFERRABLE");
806 0 : break;
807 :
808 0 : case CONSTR_ATTR_NOT_DEFERRABLE:
809 0 : appendStringInfoString(str, "ATTR_NOT_DEFERRABLE");
810 0 : break;
811 :
812 0 : case CONSTR_ATTR_DEFERRED:
813 0 : appendStringInfoString(str, "ATTR_DEFERRED");
814 0 : break;
815 :
816 0 : case CONSTR_ATTR_IMMEDIATE:
817 0 : appendStringInfoString(str, "ATTR_IMMEDIATE");
818 0 : break;
819 :
820 0 : default:
197 peter 821 UNC 0 : elog(ERROR, "unrecognized ConstrType: %d", (int) node->contype);
822 : break;
823 : }
6094 mail 824 UIC 0 : }
825 :
826 :
827 : /*
828 : * outNode -
829 : * converts a Node into ascii string and append it to 'str'
830 : */
831 : void
274 peter 832 GIC 15586109 : outNode(StringInfo str, const void *obj)
833 : {
834 : /* Guard against stack overflow due to overly complex expressions */
835 15586109 : check_stack_depth();
836 :
9345 bruce 837 15586109 : if (obj == NULL)
3447 rhaas 838 2860774 : appendStringInfoString(str, "<>");
270 alvherre 839 GNC 12725335 : else if (IsA(obj, List) || IsA(obj, IntList) || IsA(obj, OidList) ||
840 11264757 : IsA(obj, XidList))
6892 neilc 841 GIC 1460578 : _outList(str, obj);
842 : /* nodeRead does not want to see { } around these! */
577 peter 843 11264757 : else if (IsA(obj, Integer))
577 peter 844 UIC 0 : _outInteger(str, (Integer *) obj);
577 peter 845 GIC 11264757 : else if (IsA(obj, Float))
577 peter 846 UIC 0 : _outFloat(str, (Float *) obj);
450 peter 847 GIC 11264757 : else if (IsA(obj, Boolean))
450 peter 848 UIC 0 : _outBoolean(str, (Boolean *) obj);
577 peter 849 GIC 11264757 : else if (IsA(obj, String))
850 4641538 : _outString(str, (String *) obj);
851 6623219 : else if (IsA(obj, BitString))
577 peter 852 UIC 0 : _outBitString(str, (BitString *) obj);
147 tgl 853 GNC 6623219 : else if (IsA(obj, Bitmapset))
147 tgl 854 UNC 0 : outBitmapset(str, (Bitmapset *) obj);
855 : else
856 : {
8486 tgl 857 GIC 6623219 : appendStringInfoChar(str, '{');
9345 bruce 858 6623219 : switch (nodeTag(obj))
859 : {
860 : #include "outfuncs.switch.c"
861 :
9344 bruce 862 UIC 0 : default:
863 :
864 : /*
865 : * This should be an ERROR, but it's too useful to be able to
866 : * dump structures that outNode only understands part of.
867 : */
7201 tgl 868 0 : elog(WARNING, "could not dump unrecognized node type: %d",
869 : (int) nodeTag(obj));
9344 bruce 870 0 : break;
871 : }
8486 tgl 872 GIC 6623219 : appendStringInfoChar(str, '}');
873 : }
9770 scrappy 874 15586109 : }
875 :
876 : /*
877 : * nodeToString -
878 : * returns the ascii representation of the Node as a palloc'd string
879 : */
880 : char *
4141 peter_e 881 127923 : nodeToString(const void *obj)
882 : {
883 : StringInfoData str;
884 :
885 : /* see stringinfo.h for an explanation of this maneuver */
8750 tgl 886 127923 : initStringInfo(&str);
2557 andres 887 127923 : outNode(&str, obj);
8750 tgl 888 127923 : return str.data;
889 : }
890 :
891 : /*
892 : * bmsToString -
893 : * returns the ascii representation of the Bitmapset as a palloc'd string
894 : */
895 : char *
2396 tgl 896 UIC 0 : bmsToString(const Bitmapset *bms)
897 : {
898 : StringInfoData str;
899 :
900 : /* see stringinfo.h for an explanation of this maneuver */
901 0 : initStringInfo(&str);
902 0 : outBitmapset(&str, bms);
903 0 : return str.data;
904 : }
|