Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * outfuncs.c
4 : : * Output functions for Postgres tree nodes.
5 : : *
6 : : * Portions Copyright (c) 1996-2024, 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
2767 tgl@sss.pgh.pa.us 149 :CBC 780252 : outToken(StringInfo str, const char *s)
150 : : {
566 peter@eisentraut.org 151 [ + + ]: 780252 : if (s == NULL)
152 : : {
3818 rhaas@postgresql.org 153 : 6588 : appendStringInfoString(str, "<>");
8857 tgl@sss.pgh.pa.us 154 : 6588 : return;
155 : : }
566 peter@eisentraut.org 156 [ - + ]: 773664 : if (*s == '\0')
157 : : {
566 peter@eisentraut.org 158 :UBC 0 : appendStringInfoString(str, "\"\"");
159 : 0 : 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 */
8857 tgl@sss.pgh.pa.us 168 [ + + ]:CBC 773664 : if (*s == '<' ||
3036 peter_e@gmx.net 169 [ + - ]: 773658 : *s == '"' ||
8533 tgl@sss.pgh.pa.us 170 [ + - ]: 773658 : isdigit((unsigned char) *s) ||
8497 171 [ + - - + ]: 773658 : ((*s == '+' || *s == '-') &&
8497 tgl@sss.pgh.pa.us 172 [ # # # # ]:UBC 0 : (isdigit((unsigned char) s[1]) || s[1] == '.')))
8857 tgl@sss.pgh.pa.us 173 :CBC 6 : appendStringInfoChar(str, '\\');
174 [ + + ]: 7644770 : while (*s)
175 : : {
176 : : /* These chars must be backslashed anywhere in the string */
177 [ + + + - : 6871106 : if (*s == ' ' || *s == '\n' || *s == '\t' ||
+ - ]
178 [ + + + + : 6866563 : *s == '(' || *s == ')' || *s == '{' || *s == '}' ||
+ - + - ]
179 [ - + ]: 6866545 : *s == '\\')
180 : 4561 : appendStringInfoChar(str, '\\');
181 : 6871106 : 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
2489 peter_e@gmx.net 190 : 31136 : outChar(StringInfo str, char c)
191 : : {
192 : : char in[2];
193 : :
194 : : /* Traditionally, we've represented \0 as <>, so keep doing that */
566 peter@eisentraut.org 195 [ + + ]: 31136 : if (c == '\0')
196 : : {
197 : 3702 : appendStringInfoString(str, "<>");
198 : 3702 : return;
199 : : }
200 : :
2489 peter_e@gmx.net 201 : 27434 : in[0] = c;
202 : 27434 : in[1] = '\0';
203 : :
204 : 27434 : outToken(str, in);
205 : : }
206 : :
207 : : /*
208 : : * Convert a double value, attempting to ensure the value is preserved exactly.
209 : : */
210 : : static void
566 peter@eisentraut.org 211 : 4779 : outDouble(StringInfo str, double d)
212 : : {
213 : : char buf[DOUBLE_SHORTEST_DECIMAL_LEN];
214 : :
215 : 4779 : double_to_shortest_decimal_buf(d, buf);
216 : 4779 : appendStringInfoString(str, buf);
217 : 4779 : }
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 : :
634 tgl@sss.pgh.pa.us 242 [ + + + + ]: 602 : WRITE_SCALAR_ARRAY(writeAttrNumberCols, AttrNumber, " %d",)
243 [ + + + + ]: 1735 : WRITE_SCALAR_ARRAY(writeOidCols, Oid, " %u",)
634 tgl@sss.pgh.pa.us 244 [ # # # # ]:UBC 0 : WRITE_SCALAR_ARRAY(writeIndexCols, Index, " %u",)
634 tgl@sss.pgh.pa.us 245 [ + - + + ]:CBC 1020 : WRITE_SCALAR_ARRAY(writeIntCols, int, " %d",)
246 [ + - - + : 173 : 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
634 tgl@sss.pgh.pa.us 255 :UBC 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
4512 peter_e@gmx.net 275 :CBC 217310 : _outList(StringInfo str, const List *node)
276 : : {
277 : : const ListCell *lc;
278 : :
8857 tgl@sss.pgh.pa.us 279 : 217310 : appendStringInfoChar(str, '(');
280 : :
7263 neilc@samurai.com 281 [ + + ]: 217310 : if (IsA(node, IntList))
282 : 13230 : appendStringInfoChar(str, 'i');
283 [ + + ]: 204080 : else if (IsA(node, OidList))
284 : 5195 : appendStringInfoChar(str, 'o');
650 alvherre@alvh.no-ip. 285 [ - + ]: 198885 : else if (IsA(node, XidList))
650 alvherre@alvh.no-ip. 286 :UBC 0 : appendStringInfoChar(str, 'x');
287 : :
7168 bruce@momjian.us 288 [ + - + + :CBC 1771919 : 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 : : */
7263 neilc@samurai.com 295 [ + + ]: 1554609 : if (IsA(node, List))
296 : : {
2928 andres@anarazel.de 297 : 1242898 : outNode(str, lfirst(lc));
1735 tgl@sss.pgh.pa.us 298 [ + + ]: 1242898 : if (lnext(node, lc))
7263 neilc@samurai.com 299 : 1044013 : appendStringInfoChar(str, ' ');
300 : : }
301 [ + + ]: 311711 : else if (IsA(node, IntList))
302 : 292050 : appendStringInfo(str, " %d", lfirst_int(lc));
303 [ + - ]: 19661 : else if (IsA(node, OidList))
304 : 19661 : appendStringInfo(str, " %u", lfirst_oid(lc));
650 alvherre@alvh.no-ip. 305 [ # # ]:UBC 0 : else if (IsA(node, XidList))
306 : 0 : appendStringInfo(str, " %u", lfirst_xid(lc));
307 : : else
7168 bruce@momjian.us 308 [ # # ]: 0 : elog(ERROR, "unrecognized list node type: %d",
309 : : (int) node->type);
310 : : }
311 : :
8497 tgl@sss.pgh.pa.us 312 :CBC 217310 : appendStringInfoChar(str, ')');
313 : 217310 : }
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
2767 325 : 479475 : outBitmapset(StringInfo str, const Bitmapset *bms)
326 : : {
327 : : int x;
328 : :
7736 329 : 479475 : appendStringInfoChar(str, '(');
7281 330 : 479475 : appendStringInfoChar(str, 'b');
3425 331 : 479475 : x = -1;
332 [ + + ]: 608866 : while ((x = bms_next_member(bms, x)) >= 0)
7736 333 : 129391 : appendStringInfo(str, " %d", x);
334 : 479475 : appendStringInfoChar(str, ')');
335 : 479475 : }
336 : :
337 : : /*
338 : : * Print the value of a Datum given its type.
339 : : */
340 : : void
2928 andres@anarazel.de 341 : 63709 : outDatum(StringInfo str, Datum value, int typlen, bool typbyval)
342 : : {
343 : : Size length,
344 : : i;
345 : : char *s;
346 : :
7794 tgl@sss.pgh.pa.us 347 : 63709 : length = datumGetSize(value, typbyval, typlen);
348 : :
349 [ + + ]: 63709 : if (typbyval)
350 : : {
351 : 41793 : s = (char *) (&value);
352 : 41793 : appendStringInfo(str, "%u [ ", (unsigned int) length);
353 [ + + ]: 376137 : for (i = 0; i < (Size) sizeof(Datum); i++)
354 : 334344 : appendStringInfo(str, "%d ", (int) (s[i]));
3818 rhaas@postgresql.org 355 : 41793 : appendStringInfoChar(str, ']');
356 : : }
357 : : else
358 : : {
7794 tgl@sss.pgh.pa.us 359 : 21916 : s = (char *) DatumGetPointer(value);
360 [ - + ]: 21916 : if (!PointerIsValid(s))
3818 rhaas@postgresql.org 361 :UBC 0 : appendStringInfoString(str, "0 [ ]");
362 : : else
363 : : {
7794 tgl@sss.pgh.pa.us 364 :CBC 21916 : appendStringInfo(str, "%u [ ", (unsigned int) length);
365 [ + + ]: 493105 : for (i = 0; i < length; i++)
366 : 471189 : appendStringInfo(str, "%d ", (int) (s[i]));
3818 rhaas@postgresql.org 367 : 21916 : appendStringInfoChar(str, ']');
368 : : }
369 : : }
10141 scrappy@hub.org 370 : 63709 : }
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
645 peter@eisentraut.org 382 : 73389 : _outConst(StringInfo str, const Const *node)
383 : : {
384 : 73389 : WRITE_NODE_TYPE("CONST");
385 : :
386 : 73389 : WRITE_OID_FIELD(consttype);
387 : 73389 : WRITE_INT_FIELD(consttypmod);
388 : 73389 : WRITE_OID_FIELD(constcollid);
389 : 73389 : WRITE_INT_FIELD(constlen);
390 [ + + ]: 73389 : WRITE_BOOL_FIELD(constbyval);
391 [ + + ]: 73389 : WRITE_BOOL_FIELD(constisnull);
392 [ - + ]: 73389 : WRITE_LOCATION_FIELD(location);
393 : :
394 : 73389 : appendStringInfoString(str, " :constvalue ");
395 [ + + ]: 73389 : if (node->constisnull)
396 : 9680 : appendStringInfoString(str, "<>");
397 : : else
398 : 63709 : outDatum(str, node->constvalue, node->constlen, node->constbyval);
7811 tgl@sss.pgh.pa.us 399 : 73389 : }
400 : :
401 : : static void
645 peter@eisentraut.org 402 : 9022 : _outBoolExpr(StringInfo str, const BoolExpr *node)
403 : : {
404 : 9022 : char *opstr = NULL;
405 : :
406 : 9022 : WRITE_NODE_TYPE("BOOLEXPR");
407 : :
408 : : /* do-it-yourself enum representation */
409 [ + + + - ]: 9022 : switch (node->boolop)
410 : : {
411 : 5527 : case AND_EXPR:
412 : 5527 : opstr = "and";
413 : 5527 : break;
414 : 2340 : case OR_EXPR:
415 : 2340 : opstr = "or";
416 : 2340 : break;
417 : 1155 : case NOT_EXPR:
418 : 1155 : opstr = "not";
419 : 1155 : break;
420 : : }
421 : 9022 : appendStringInfoString(str, " :boolop ");
422 : 9022 : outToken(str, opstr);
423 : :
424 : 9022 : WRITE_NODE_FIELD(args);
425 [ - + ]: 9022 : WRITE_LOCATION_FIELD(location);
7811 tgl@sss.pgh.pa.us 426 : 9022 : }
427 : :
428 : : static void
645 peter@eisentraut.org 429 :UBC 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]));
2643 andres@anarazel.de 452 : 0 : }
453 : :
454 : : static void
645 peter@eisentraut.org 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_NODE_FIELD(ec_members);
469 : 0 : WRITE_NODE_FIELD(ec_sources);
470 : 0 : WRITE_NODE_FIELD(ec_derives);
471 : 0 : WRITE_BITMAPSET_FIELD(ec_relids);
472 [ # # ]: 0 : WRITE_BOOL_FIELD(ec_has_const);
473 [ # # ]: 0 : WRITE_BOOL_FIELD(ec_has_volatile);
474 [ # # ]: 0 : WRITE_BOOL_FIELD(ec_broken);
475 : 0 : WRITE_UINT_FIELD(ec_sortref);
476 : 0 : WRITE_UINT_FIELD(ec_min_security);
477 : 0 : WRITE_UINT_FIELD(ec_max_security);
5300 tgl@sss.pgh.pa.us 478 : 0 : }
479 : :
480 : : static void
645 peter@eisentraut.org 481 : 0 : _outExtensibleNode(StringInfo str, const ExtensibleNode *node)
482 : : {
483 : : const ExtensibleNodeMethods *methods;
484 : :
485 : 0 : methods = GetExtensibleNodeMethods(node->extnodename, false);
486 : :
487 : 0 : WRITE_NODE_TYPE("EXTENSIBLENODE");
488 : :
489 : 0 : WRITE_STRING_FIELD(extnodename);
490 : :
491 : : /* serialize the private fields */
492 : 0 : methods->nodeOut(str, node);
4931 tgl@sss.pgh.pa.us 493 : 0 : }
494 : :
495 : : static void
645 peter@eisentraut.org 496 :CBC 32900 : _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
497 : : {
498 : 32900 : WRITE_NODE_TYPE("RANGETBLENTRY");
499 : :
500 : 32900 : WRITE_NODE_FIELD(alias);
501 : 32900 : WRITE_NODE_FIELD(eref);
502 : 32900 : WRITE_ENUM_FIELD(rtekind, RTEKind);
503 : :
504 [ + + + + : 32900 : switch (node->rtekind)
+ + + - +
- ]
505 : : {
506 : 21121 : case RTE_RELATION:
507 : 21121 : WRITE_OID_FIELD(relid);
38 peter@eisentraut.org 508 [ + + ]:GNC 21121 : WRITE_BOOL_FIELD(inh);
645 peter@eisentraut.org 509 :CBC 21121 : WRITE_CHAR_FIELD(relkind);
510 : 21121 : WRITE_INT_FIELD(rellockmode);
495 alvherre@alvh.no-ip. 511 : 21121 : WRITE_UINT_FIELD(perminfoindex);
40 peter@eisentraut.org 512 :GNC 21121 : WRITE_NODE_FIELD(tablesample);
645 peter@eisentraut.org 513 :CBC 21121 : break;
514 : 3714 : case RTE_SUBQUERY:
515 : 3714 : WRITE_NODE_FIELD(subquery);
516 [ - + ]: 3714 : WRITE_BOOL_FIELD(security_barrier);
517 : : /* we re-use these RELATION fields, too: */
452 tgl@sss.pgh.pa.us 518 : 3714 : WRITE_OID_FIELD(relid);
38 peter@eisentraut.org 519 [ + + ]:GNC 3714 : WRITE_BOOL_FIELD(inh);
306 amitlan@postgresql.o 520 :CBC 3714 : WRITE_CHAR_FIELD(relkind);
452 tgl@sss.pgh.pa.us 521 : 3714 : WRITE_INT_FIELD(rellockmode);
522 : 3714 : WRITE_UINT_FIELD(perminfoindex);
645 peter@eisentraut.org 523 : 3714 : break;
524 : 5841 : case RTE_JOIN:
525 : 5841 : WRITE_ENUM_FIELD(jointype, JoinType);
526 : 5841 : WRITE_INT_FIELD(joinmergedcols);
527 : 5841 : WRITE_NODE_FIELD(joinaliasvars);
528 : 5841 : WRITE_NODE_FIELD(joinleftcols);
529 : 5841 : WRITE_NODE_FIELD(joinrightcols);
530 : 5841 : WRITE_NODE_FIELD(join_using_alias);
531 : 5841 : break;
532 : 1933 : case RTE_FUNCTION:
533 : 1933 : WRITE_NODE_FIELD(functions);
534 [ + + ]: 1933 : WRITE_BOOL_FIELD(funcordinality);
535 : 1933 : break;
536 : 29 : case RTE_TABLEFUNC:
537 : 29 : WRITE_NODE_FIELD(tablefunc);
538 : 29 : break;
539 : 166 : case RTE_VALUES:
540 : 166 : WRITE_NODE_FIELD(values_lists);
541 : 166 : WRITE_NODE_FIELD(coltypes);
542 : 166 : WRITE_NODE_FIELD(coltypmods);
543 : 166 : WRITE_NODE_FIELD(colcollations);
544 : 166 : break;
545 : 75 : case RTE_CTE:
546 : 75 : WRITE_STRING_FIELD(ctename);
547 : 75 : WRITE_UINT_FIELD(ctelevelsup);
548 [ + + ]: 75 : WRITE_BOOL_FIELD(self_reference);
549 : 75 : WRITE_NODE_FIELD(coltypes);
550 : 75 : WRITE_NODE_FIELD(coltypmods);
551 : 75 : WRITE_NODE_FIELD(colcollations);
552 : 75 : break;
645 peter@eisentraut.org 553 :UBC 0 : case RTE_NAMEDTUPLESTORE:
554 : 0 : WRITE_STRING_FIELD(enrname);
566 555 : 0 : WRITE_FLOAT_FIELD(enrtuples);
645 556 : 0 : WRITE_NODE_FIELD(coltypes);
557 : 0 : WRITE_NODE_FIELD(coltypmods);
558 : 0 : WRITE_NODE_FIELD(colcollations);
559 : : /* we re-use these RELATION fields, too: */
452 tgl@sss.pgh.pa.us 560 : 0 : WRITE_OID_FIELD(relid);
645 peter@eisentraut.org 561 : 0 : break;
645 peter@eisentraut.org 562 :CBC 21 : case RTE_RESULT:
563 : : /* no extra fields */
564 : 21 : break;
645 peter@eisentraut.org 565 :UBC 0 : default:
566 [ # # ]: 0 : elog(ERROR, "unrecognized RTE kind: %d", (int) node->rtekind);
567 : : break;
568 : : }
569 : :
645 peter@eisentraut.org 570 [ + + ]:CBC 32900 : WRITE_BOOL_FIELD(lateral);
571 [ + + ]: 32900 : WRITE_BOOL_FIELD(inFromCl);
572 : 32900 : WRITE_NODE_FIELD(securityQuals);
6935 tgl@sss.pgh.pa.us 573 : 32900 : }
574 : :
575 : : static void
645 peter@eisentraut.org 576 :UBC 0 : _outA_Expr(StringInfo str, const A_Expr *node)
577 : : {
578 : 0 : WRITE_NODE_TYPE("A_EXPR");
579 : :
580 [ # # # # : 0 : switch (node->kind)
# # # # #
# # # # #
# ]
581 : : {
582 : 0 : case AEXPR_OP:
583 : 0 : WRITE_NODE_FIELD(name);
584 : 0 : break;
585 : 0 : case AEXPR_OP_ANY:
608 586 : 0 : appendStringInfoString(str, " ANY");
568 587 : 0 : WRITE_NODE_FIELD(name);
645 588 : 0 : break;
589 : 0 : case AEXPR_OP_ALL:
608 590 : 0 : appendStringInfoString(str, " ALL");
568 591 : 0 : WRITE_NODE_FIELD(name);
645 592 : 0 : break;
593 : 0 : case AEXPR_DISTINCT:
608 594 : 0 : appendStringInfoString(str, " DISTINCT");
645 595 : 0 : WRITE_NODE_FIELD(name);
596 : 0 : break;
597 : 0 : case AEXPR_NOT_DISTINCT:
608 598 : 0 : appendStringInfoString(str, " NOT_DISTINCT");
645 599 : 0 : WRITE_NODE_FIELD(name);
600 : 0 : break;
601 : 0 : case AEXPR_NULLIF:
608 602 : 0 : appendStringInfoString(str, " NULLIF");
645 603 : 0 : WRITE_NODE_FIELD(name);
604 : 0 : break;
605 : 0 : case AEXPR_IN:
608 606 : 0 : appendStringInfoString(str, " IN");
645 607 : 0 : WRITE_NODE_FIELD(name);
608 : 0 : break;
609 : 0 : case AEXPR_LIKE:
608 610 : 0 : appendStringInfoString(str, " LIKE");
645 611 : 0 : WRITE_NODE_FIELD(name);
612 : 0 : break;
613 : 0 : case AEXPR_ILIKE:
608 614 : 0 : appendStringInfoString(str, " ILIKE");
645 615 : 0 : WRITE_NODE_FIELD(name);
616 : 0 : break;
617 : 0 : case AEXPR_SIMILAR:
608 618 : 0 : appendStringInfoString(str, " SIMILAR");
645 619 : 0 : WRITE_NODE_FIELD(name);
620 : 0 : break;
621 : 0 : case AEXPR_BETWEEN:
608 622 : 0 : appendStringInfoString(str, " BETWEEN");
645 623 : 0 : WRITE_NODE_FIELD(name);
624 : 0 : break;
625 : 0 : case AEXPR_NOT_BETWEEN:
608 626 : 0 : appendStringInfoString(str, " NOT_BETWEEN");
645 627 : 0 : WRITE_NODE_FIELD(name);
628 : 0 : break;
629 : 0 : case AEXPR_BETWEEN_SYM:
608 630 : 0 : appendStringInfoString(str, " BETWEEN_SYM");
645 631 : 0 : WRITE_NODE_FIELD(name);
632 : 0 : break;
633 : 0 : case AEXPR_NOT_BETWEEN_SYM:
608 634 : 0 : appendStringInfoString(str, " NOT_BETWEEN_SYM");
645 635 : 0 : WRITE_NODE_FIELD(name);
636 : 0 : break;
637 : 0 : default:
568 638 [ # # ]: 0 : elog(ERROR, "unrecognized A_Expr_Kind: %d", (int) node->kind);
639 : : break;
640 : : }
641 : :
645 642 : 0 : WRITE_NODE_FIELD(lexpr);
643 : 0 : WRITE_NODE_FIELD(rexpr);
644 [ # # ]: 0 : WRITE_LOCATION_FIELD(location);
10141 scrappy@hub.org 645 : 0 : }
646 : :
647 : : static void
645 peter@eisentraut.org 648 : 0 : _outInteger(StringInfo str, const Integer *node)
649 : : {
650 : 0 : appendStringInfo(str, "%d", node->ival);
10141 scrappy@hub.org 651 : 0 : }
652 : :
653 : : static void
645 peter@eisentraut.org 654 : 0 : _outFloat(StringInfo str, const Float *node)
655 : : {
656 : : /*
657 : : * We assume the value is a valid numeric literal and so does not need
658 : : * quoting.
659 : : */
660 : 0 : appendStringInfoString(str, node->fval);
3186 tgl@sss.pgh.pa.us 661 : 0 : }
662 : :
663 : : static void
645 peter@eisentraut.org 664 : 0 : _outBoolean(StringInfo str, const Boolean *node)
665 : : {
666 [ # # ]: 0 : appendStringInfoString(str, node->boolval ? "true" : "false");
4569 tgl@sss.pgh.pa.us 667 : 0 : }
668 : :
669 : : static void
645 peter@eisentraut.org 670 :CBC 603614 : _outString(StringInfo str, const String *node)
671 : : {
672 : : /*
673 : : * We use outToken to provide escaping of the string's content, but we
674 : : * don't want it to convert an empty string to '""', because we're putting
675 : : * double quotes around the string already.
676 : : */
677 : 603614 : appendStringInfoChar(str, '"');
678 [ + + ]: 603614 : if (node->sval[0] != '\0')
679 : 603560 : outToken(str, node->sval);
680 : 603614 : appendStringInfoChar(str, '"');
10141 scrappy@hub.org 681 : 603614 : }
682 : :
683 : : static void
645 peter@eisentraut.org 684 :UBC 0 : _outBitString(StringInfo str, const BitString *node)
685 : : {
686 : : /*
687 : : * The lexer will always produce a string starting with 'b' or 'x'. There
688 : : * might be characters following that that need escaping, but outToken
689 : : * won't escape the 'b' or 'x'. This is relied on by nodeTokenType.
690 : : */
61 tgl@sss.pgh.pa.us 691 [ # # # # ]: 0 : Assert(node->bsval[0] == 'b' || node->bsval[0] == 'x');
692 : 0 : outToken(str, node->bsval);
6935 693 : 0 : }
694 : :
695 : : static void
645 peter@eisentraut.org 696 : 0 : _outA_Const(StringInfo str, const A_Const *node)
697 : : {
698 : 0 : WRITE_NODE_TYPE("A_CONST");
699 : :
700 [ # # ]: 0 : if (node->isnull)
612 701 : 0 : appendStringInfoString(str, " NULL");
702 : : else
703 : : {
645 704 : 0 : appendStringInfoString(str, " :val ");
705 : 0 : outNode(str, &node->val);
706 : : }
707 [ # # ]: 0 : WRITE_LOCATION_FIELD(location);
6935 tgl@sss.pgh.pa.us 708 : 0 : }
709 : :
710 : :
711 : : /*
712 : : * outNode -
713 : : * converts a Node into ascii string and append it to 'str'
714 : : */
715 : : void
645 peter@eisentraut.org 716 :CBC 2180764 : outNode(StringInfo str, const void *obj)
717 : : {
718 : : /* Guard against stack overflow due to overly complex expressions */
719 : 2180764 : check_stack_depth();
720 : :
9716 bruce@momjian.us 721 [ + + ]: 2180764 : if (obj == NULL)
3818 rhaas@postgresql.org 722 : 446374 : appendStringInfoString(str, "<>");
641 alvherre@alvh.no-ip. 723 [ + + + + : 1734390 : else if (IsA(obj, List) || IsA(obj, IntList) || IsA(obj, OidList) ||
+ + ]
724 [ - + ]: 1517080 : IsA(obj, XidList))
7263 neilc@samurai.com 725 : 217310 : _outList(str, obj);
726 : : /* nodeRead does not want to see { } around these! */
948 peter@eisentraut.org 727 [ - + ]: 1517080 : else if (IsA(obj, Integer))
948 peter@eisentraut.org 728 :UBC 0 : _outInteger(str, (Integer *) obj);
948 peter@eisentraut.org 729 [ - + ]:CBC 1517080 : else if (IsA(obj, Float))
948 peter@eisentraut.org 730 :UBC 0 : _outFloat(str, (Float *) obj);
821 peter@eisentraut.org 731 [ - + ]:CBC 1517080 : else if (IsA(obj, Boolean))
821 peter@eisentraut.org 732 :UBC 0 : _outBoolean(str, (Boolean *) obj);
948 peter@eisentraut.org 733 [ + + ]:CBC 1517080 : else if (IsA(obj, String))
734 : 603614 : _outString(str, (String *) obj);
735 [ - + ]: 913466 : else if (IsA(obj, BitString))
948 peter@eisentraut.org 736 :UBC 0 : _outBitString(str, (BitString *) obj);
518 tgl@sss.pgh.pa.us 737 [ - + ]:CBC 913466 : else if (IsA(obj, Bitmapset))
518 tgl@sss.pgh.pa.us 738 :UBC 0 : outBitmapset(str, (Bitmapset *) obj);
739 : : else
740 : : {
8857 tgl@sss.pgh.pa.us 741 :CBC 913466 : appendStringInfoChar(str, '{');
9716 bruce@momjian.us 742 [ + - + - : 913466 : switch (nodeTag(obj))
+ + + + +
+ + + + +
+ + + + +
+ + - + +
+ + + - +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ - - + +
+ + + + +
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
+ + - - +
+ + + - +
+ + + - -
- + + + -
- - - - -
- - - - -
- - - - -
- - - - -
- - - + -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
+ - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - + +
+ - + - -
- - + - +
+ + + - -
- + - - -
- - - - +
+ + + - +
+ - - + -
- - - + -
- + - + +
+ + - - -
- ]
743 : : {
744 : : #include "outfuncs.switch.c"
745 : :
9715 bruce@momjian.us 746 :UBC 0 : default:
747 : :
748 : : /*
749 : : * This should be an ERROR, but it's too useful to be able to
750 : : * dump structures that outNode only understands part of.
751 : : */
7572 tgl@sss.pgh.pa.us 752 [ # # ]: 0 : elog(WARNING, "could not dump unrecognized node type: %d",
753 : : (int) nodeTag(obj));
9715 bruce@momjian.us 754 : 0 : break;
755 : : }
8857 tgl@sss.pgh.pa.us 756 :CBC 913466 : appendStringInfoChar(str, '}');
757 : : }
10141 scrappy@hub.org 758 : 2180764 : }
759 : :
760 : : /*
761 : : * nodeToString -
762 : : * returns the ascii representation of the Node as a palloc'd string
763 : : *
764 : : * write_loc_fields determines whether location fields are output with their
765 : : * actual value rather than -1. The actual value can be useful for debugging,
766 : : * but for most uses, the actual value is not useful, since the original query
767 : : * string is no longer available.
768 : : */
769 : : static char *
23 peter@eisentraut.org 770 :GNC 28651 : nodeToStringInternal(const void *obj, bool write_loc_fields)
771 : : {
772 : : StringInfoData str;
773 : : bool save_write_location_fields;
774 : :
775 : 28651 : save_write_location_fields = write_location_fields;
776 : 28651 : write_location_fields = write_loc_fields;
777 : :
778 : : /* see stringinfo.h for an explanation of this maneuver */
9121 tgl@sss.pgh.pa.us 779 :CBC 28651 : initStringInfo(&str);
2928 andres@anarazel.de 780 : 28651 : outNode(&str, obj);
781 : :
23 peter@eisentraut.org 782 :GNC 28651 : write_location_fields = save_write_location_fields;
783 : :
9121 tgl@sss.pgh.pa.us 784 :CBC 28651 : return str.data;
785 : : }
786 : :
787 : : /*
788 : : * Externally visible entry points
789 : : */
790 : : char *
23 peter@eisentraut.org 791 :GNC 28651 : nodeToString(const void *obj)
792 : : {
793 : 28651 : return nodeToStringInternal(obj, false);
794 : : }
795 : :
796 : : char *
23 peter@eisentraut.org 797 :UNC 0 : nodeToStringWithLocations(const void *obj)
798 : : {
799 : 0 : return nodeToStringInternal(obj, true);
800 : : }
801 : :
802 : :
803 : : /*
804 : : * bmsToString -
805 : : * returns the ascii representation of the Bitmapset as a palloc'd string
806 : : */
807 : : char *
2767 tgl@sss.pgh.pa.us 808 :UBC 0 : bmsToString(const Bitmapset *bms)
809 : : {
810 : : StringInfoData str;
811 : :
812 : : /* see stringinfo.h for an explanation of this maneuver */
813 : 0 : initStringInfo(&str);
814 : 0 : outBitmapset(&str, bms);
815 : 0 : return str.data;
816 : : }
|