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-2026, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/nodes/outfuncs.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : : #include "postgres.h"
16 : :
17 : : #include <ctype.h>
18 : :
19 : : #include "access/attnum.h"
20 : : #include "common/shortest_dec.h"
21 : : #include "lib/stringinfo.h"
22 : : #include "miscadmin.h"
23 : : #include "nodes/bitmapset.h"
24 : : #include "nodes/nodes.h"
25 : : #include "nodes/pg_list.h"
26 : : #include "utils/datum.h"
27 : :
28 : : /* State flag that determines how nodeToStringInternal() should treat location fields */
29 : : static bool write_location_fields = false;
30 : :
31 : : static void outChar(StringInfo str, char c);
32 : : static void outDouble(StringInfo str, double d);
33 : :
34 : :
35 : : /*
36 : : * Macros to simplify output of different kinds of fields. Use these
37 : : * wherever possible to reduce the chance for silly typos. Note that these
38 : : * hard-wire conventions about the names of the local variables in an Out
39 : : * routine.
40 : : */
41 : :
42 : : /* Write the label for the node type */
43 : : #define WRITE_NODE_TYPE(nodelabel) \
44 : : appendStringInfoString(str, nodelabel)
45 : :
46 : : /* Write an integer field (anything written as ":fldname %d") */
47 : : #define WRITE_INT_FIELD(fldname) \
48 : : appendStringInfo(str, " :" CppAsString(fldname) " %d", node->fldname)
49 : :
50 : : /* Write an unsigned integer field (anything written as ":fldname %u") */
51 : : #define WRITE_UINT_FIELD(fldname) \
52 : : appendStringInfo(str, " :" CppAsString(fldname) " %u", node->fldname)
53 : :
54 : : /* Write a signed integer field (anything written with INT64_FORMAT) */
55 : : #define WRITE_INT64_FIELD(fldname) \
56 : : appendStringInfo(str, \
57 : : " :" CppAsString(fldname) " " INT64_FORMAT, \
58 : : node->fldname)
59 : :
60 : : /* Write an unsigned integer field (anything written with UINT64_FORMAT) */
61 : : #define WRITE_UINT64_FIELD(fldname) \
62 : : appendStringInfo(str, " :" CppAsString(fldname) " " UINT64_FORMAT, \
63 : : node->fldname)
64 : :
65 : : /* Write an OID field (don't hard-wire assumption that OID is same as uint) */
66 : : #define WRITE_OID_FIELD(fldname) \
67 : : appendStringInfo(str, " :" CppAsString(fldname) " %u", node->fldname)
68 : :
69 : : /* Write a long-integer field */
70 : : #define WRITE_LONG_FIELD(fldname) \
71 : : appendStringInfo(str, " :" CppAsString(fldname) " %ld", node->fldname)
72 : :
73 : : /* Write a char field (ie, one ascii character) */
74 : : #define WRITE_CHAR_FIELD(fldname) \
75 : : (appendStringInfo(str, " :" CppAsString(fldname) " "), \
76 : : outChar(str, node->fldname))
77 : :
78 : : /* Write an enumerated-type field as an integer code */
79 : : #define WRITE_ENUM_FIELD(fldname, enumtype) \
80 : : appendStringInfo(str, " :" CppAsString(fldname) " %d", \
81 : : (int) node->fldname)
82 : :
83 : : /* Write a float field (actually, they're double) */
84 : : #define WRITE_FLOAT_FIELD(fldname) \
85 : : (appendStringInfo(str, " :" CppAsString(fldname) " "), \
86 : : outDouble(str, node->fldname))
87 : :
88 : : /* Write a boolean field */
89 : : #define WRITE_BOOL_FIELD(fldname) \
90 : : appendStringInfo(str, " :" CppAsString(fldname) " %s", \
91 : : booltostr(node->fldname))
92 : :
93 : : /* Write a character-string (possibly NULL) field */
94 : : #define WRITE_STRING_FIELD(fldname) \
95 : : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
96 : : outToken(str, node->fldname))
97 : :
98 : : /* Write a parse location field (actually same as INT case) */
99 : : #define WRITE_LOCATION_FIELD(fldname) \
100 : : appendStringInfo(str, " :" CppAsString(fldname) " %d", write_location_fields ? node->fldname : -1)
101 : :
102 : : /* Write a Node field */
103 : : #define WRITE_NODE_FIELD(fldname) \
104 : : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
105 : : outNode(str, node->fldname))
106 : :
107 : : /* Write a bitmapset field */
108 : : #define WRITE_BITMAPSET_FIELD(fldname) \
109 : : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
110 : : outBitmapset(str, node->fldname))
111 : :
112 : : /* Write a variable-length array (not a List) of Node pointers */
113 : : #define WRITE_NODE_ARRAY(fldname, len) \
114 : : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
115 : : writeNodeArray(str, (const Node * const *) node->fldname, len))
116 : :
117 : : /* Write a variable-length array of AttrNumber */
118 : : #define WRITE_ATTRNUMBER_ARRAY(fldname, len) \
119 : : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
120 : : writeAttrNumberCols(str, node->fldname, len))
121 : :
122 : : /* Write a variable-length array of Oid */
123 : : #define WRITE_OID_ARRAY(fldname, len) \
124 : : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
125 : : writeOidCols(str, node->fldname, len))
126 : :
127 : : /* Write a variable-length array of Index */
128 : : #define WRITE_INDEX_ARRAY(fldname, len) \
129 : : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
130 : : writeIndexCols(str, node->fldname, len))
131 : :
132 : : /* Write a variable-length array of int */
133 : : #define WRITE_INT_ARRAY(fldname, len) \
134 : : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
135 : : writeIntCols(str, node->fldname, len))
136 : :
137 : : /* Write a variable-length array of bool */
138 : : #define WRITE_BOOL_ARRAY(fldname, len) \
139 : : (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
140 : : writeBoolCols(str, node->fldname, len))
141 : :
142 : : #define booltostr(x) ((x) ? "true" : "false")
143 : :
144 : :
145 : : /*
146 : : * outToken
147 : : * Convert an ordinary string (eg, an identifier) into a form that
148 : : * will be decoded back to a plain token by read.c's functions.
149 : : *
150 : : * If a null string pointer is given, it is encoded as '<>'.
151 : : * An empty string is encoded as '""'. To avoid ambiguity, input
152 : : * strings beginning with '<' or '"' receive a leading backslash.
153 : : */
154 : : void
3518 tgl@sss.pgh.pa.us 155 :CBC 1390966 : outToken(StringInfo str, const char *s)
156 : : {
1317 peter@eisentraut.org 157 [ + + ]: 1390966 : if (s == NULL)
158 : : {
4569 rhaas@postgresql.org 159 : 59244 : appendStringInfoString(str, "<>");
9608 tgl@sss.pgh.pa.us 160 : 59244 : return;
161 : : }
1317 peter@eisentraut.org 162 [ - + ]: 1331722 : if (*s == '\0')
163 : : {
1317 peter@eisentraut.org 164 :UBC 0 : appendStringInfoString(str, "\"\"");
165 : 0 : return;
166 : : }
167 : :
168 : : /*
169 : : * Look for characters or patterns that are treated specially by read.c
170 : : * (either in pg_strtok() or in nodeRead()), and therefore need a
171 : : * protective backslash.
172 : : */
173 : : /* These characters only need to be quoted at the start of the string */
9608 tgl@sss.pgh.pa.us 174 [ + + ]:CBC 1331722 : if (*s == '<' ||
3787 peter_e@gmx.net 175 [ + - ]: 1331714 : *s == '"' ||
9284 tgl@sss.pgh.pa.us 176 [ + - ]: 1331714 : isdigit((unsigned char) *s) ||
9248 177 [ + - - + ]: 1331714 : ((*s == '+' || *s == '-') &&
9248 tgl@sss.pgh.pa.us 178 [ # # # # ]:UBC 0 : (isdigit((unsigned char) s[1]) || s[1] == '.')))
9608 tgl@sss.pgh.pa.us 179 :CBC 8 : appendStringInfoChar(str, '\\');
180 [ + + ]: 13307747 : while (*s)
181 : : {
182 : : /* These chars must be backslashed anywhere in the string */
183 [ + + + - : 11976025 : if (*s == ' ' || *s == '\n' || *s == '\t' ||
+ - ]
184 [ + + + + : 11975873 : *s == '(' || *s == ')' || *s == '{' || *s == '}' ||
+ - + - ]
185 [ - + ]: 11975841 : *s == '\\')
186 : 184 : appendStringInfoChar(str, '\\');
187 : 11976025 : appendStringInfoChar(str, *s++);
188 : : }
189 : : }
190 : :
191 : : /*
192 : : * Convert one char. Goes through outToken() so that special characters are
193 : : * escaped.
194 : : */
195 : : static void
3240 peter_e@gmx.net 196 : 51514 : outChar(StringInfo str, char c)
197 : : {
198 : : char in[2];
199 : :
200 : : /* Traditionally, we've represented \0 as <>, so keep doing that */
1317 peter@eisentraut.org 201 [ + + ]: 51514 : if (c == '\0')
202 : : {
203 : 6527 : appendStringInfoString(str, "<>");
204 : 6527 : return;
205 : : }
206 : :
3240 peter_e@gmx.net 207 : 44987 : in[0] = c;
208 : 44987 : in[1] = '\0';
209 : :
210 : 44987 : outToken(str, in);
211 : : }
212 : :
213 : : /*
214 : : * Convert a double value, attempting to ensure the value is preserved exactly.
215 : : */
216 : : static void
1317 peter@eisentraut.org 217 : 10880 : outDouble(StringInfo str, double d)
218 : : {
219 : : char buf[DOUBLE_SHORTEST_DECIMAL_LEN];
220 : :
221 : 10880 : double_to_shortest_decimal_buf(d, buf);
222 : 10880 : appendStringInfoString(str, buf);
223 : 10880 : }
224 : :
225 : : /*
226 : : * common implementation for scalar-array-writing functions
227 : : *
228 : : * The data format is either "<>" for a NULL pointer or "(item item item)".
229 : : * fmtstr must include a leading space, and the rest of it must produce
230 : : * something that will be seen as a single simple token by pg_strtok().
231 : : * convfunc can be empty, or the name of a conversion macro or function.
232 : : */
233 : : #define WRITE_SCALAR_ARRAY(fnname, datatype, fmtstr, convfunc) \
234 : : static void \
235 : : fnname(StringInfo str, const datatype *arr, int len) \
236 : : { \
237 : : if (arr != NULL) \
238 : : { \
239 : : appendStringInfoChar(str, '('); \
240 : : for (int i = 0; i < len; i++) \
241 : : appendStringInfo(str, fmtstr, convfunc(arr[i])); \
242 : : appendStringInfoChar(str, ')'); \
243 : : } \
244 : : else \
245 : : appendStringInfoString(str, "<>"); \
246 : : }
247 : :
1385 tgl@sss.pgh.pa.us 248 [ + + + + ]: 1125 : WRITE_SCALAR_ARRAY(writeAttrNumberCols, AttrNumber, " %d",)
249 [ + + + + ]: 3198 : WRITE_SCALAR_ARRAY(writeOidCols, Oid, " %u",)
1385 tgl@sss.pgh.pa.us 250 [ # # # # ]:UBC 0 : WRITE_SCALAR_ARRAY(writeIndexCols, Index, " %u",)
1385 tgl@sss.pgh.pa.us 251 [ + - + + ]:CBC 2028 : WRITE_SCALAR_ARRAY(writeIntCols, int, " %d",)
252 [ + - - + : 770 : WRITE_SCALAR_ARRAY(writeBoolCols, bool, " %s", booltostr)
+ + ]
253 : :
254 : : /*
255 : : * Print an array (not a List) of Node pointers.
256 : : *
257 : : * The decoration is identical to that of scalar arrays, but we can't
258 : : * quite use appendStringInfo() in the loop.
259 : : */
260 : : static void
1385 tgl@sss.pgh.pa.us 261 :UBC 0 : writeNodeArray(StringInfo str, const Node *const *arr, int len)
262 : : {
263 [ # # ]: 0 : if (arr != NULL)
264 : : {
265 : 0 : appendStringInfoChar(str, '(');
266 [ # # ]: 0 : for (int i = 0; i < len; i++)
267 : : {
268 : 0 : appendStringInfoChar(str, ' ');
269 : 0 : outNode(str, arr[i]);
270 : : }
271 : 0 : appendStringInfoChar(str, ')');
272 : : }
273 : : else
274 : 0 : appendStringInfoString(str, "<>");
275 : 0 : }
276 : :
277 : : /*
278 : : * Print a List.
279 : : */
280 : : static void
5263 peter_e@gmx.net 281 :CBC 362968 : _outList(StringInfo str, const List *node)
282 : : {
283 : : const ListCell *lc;
284 : :
9608 tgl@sss.pgh.pa.us 285 : 362968 : appendStringInfoChar(str, '(');
286 : :
8014 neilc@samurai.com 287 [ + + ]: 362968 : if (IsA(node, IntList))
288 : 22026 : appendStringInfoChar(str, 'i');
289 [ + + ]: 340942 : else if (IsA(node, OidList))
290 : 8370 : appendStringInfoChar(str, 'o');
1401 alvherre@alvh.no-ip. 291 [ - + ]: 332572 : else if (IsA(node, XidList))
1401 alvherre@alvh.no-ip. 292 :UBC 0 : appendStringInfoChar(str, 'x');
293 : :
7919 bruce@momjian.us 294 [ + - + + :CBC 3038210 : foreach(lc, node)
+ + ]
295 : : {
296 : : /*
297 : : * For the sake of backward compatibility, we emit a slightly
298 : : * different whitespace format for lists of nodes vs. other types of
299 : : * lists. XXX: is this necessary?
300 : : */
8014 neilc@samurai.com 301 [ + + ]: 2675242 : if (IsA(node, List))
302 : : {
3679 andres@anarazel.de 303 : 2136832 : outNode(str, lfirst(lc));
2486 tgl@sss.pgh.pa.us 304 [ + + ]: 2136832 : if (lnext(node, lc))
8014 neilc@samurai.com 305 : 1804260 : appendStringInfoChar(str, ' ');
306 : : }
307 [ + + ]: 538410 : else if (IsA(node, IntList))
308 : 504444 : appendStringInfo(str, " %d", lfirst_int(lc));
309 [ + - ]: 33966 : else if (IsA(node, OidList))
310 : 33966 : appendStringInfo(str, " %u", lfirst_oid(lc));
1401 alvherre@alvh.no-ip. 311 [ # # ]:UBC 0 : else if (IsA(node, XidList))
312 : 0 : appendStringInfo(str, " %u", lfirst_xid(lc));
313 : : else
7919 bruce@momjian.us 314 [ # # ]: 0 : elog(ERROR, "unrecognized list node type: %d",
315 : : (int) node->type);
316 : : }
317 : :
9248 tgl@sss.pgh.pa.us 318 :CBC 362968 : appendStringInfoChar(str, ')');
319 : 362968 : }
320 : :
321 : : /*
322 : : * outBitmapset -
323 : : * converts a bitmap set of integers
324 : : *
325 : : * Note: the output format is "(b int int ...)", similar to an integer List.
326 : : *
327 : : * We export this function for use by extensions that define extensible nodes.
328 : : * That's somewhat historical, though, because calling outNode() will work.
329 : : */
330 : : void
3518 331 : 836364 : outBitmapset(StringInfo str, const Bitmapset *bms)
332 : : {
333 : : int x;
334 : :
8487 335 : 836364 : appendStringInfoChar(str, '(');
8032 336 : 836364 : appendStringInfoChar(str, 'b');
4176 337 : 836364 : x = -1;
338 [ + + ]: 1061610 : while ((x = bms_next_member(bms, x)) >= 0)
8487 339 : 225246 : appendStringInfo(str, " %d", x);
340 : 836364 : appendStringInfoChar(str, ')');
341 : 836364 : }
342 : :
343 : : /*
344 : : * Print the value of a Datum given its type.
345 : : */
346 : : void
3679 andres@anarazel.de 347 : 105650 : outDatum(StringInfo str, Datum value, int typlen, bool typbyval)
348 : : {
349 : : Size length;
350 : : char *s;
351 : :
8545 tgl@sss.pgh.pa.us 352 : 105650 : length = datumGetSize(value, typbyval, typlen);
353 : :
354 [ + + ]: 105650 : if (typbyval)
355 : : {
356 : 69074 : s = (char *) (&value);
147 peter@eisentraut.org 357 :GNC 69074 : appendStringInfo(str, "%zu [ ", length);
161 358 [ + + ]: 621666 : for (Size i = 0; i < (Size) sizeof(Datum); i++)
8545 tgl@sss.pgh.pa.us 359 :CBC 552592 : appendStringInfo(str, "%d ", (int) (s[i]));
4569 rhaas@postgresql.org 360 : 69074 : appendStringInfoChar(str, ']');
361 : : }
362 : : else
363 : : {
8545 tgl@sss.pgh.pa.us 364 : 36576 : s = (char *) DatumGetPointer(value);
223 peter@eisentraut.org 365 [ - + ]:GNC 36576 : if (!s)
4569 rhaas@postgresql.org 366 :UBC 0 : appendStringInfoString(str, "0 [ ]");
367 : : else
368 : : {
147 peter@eisentraut.org 369 :GNC 36576 : appendStringInfo(str, "%zu [ ", length);
161 370 [ + + ]: 1314504 : for (Size i = 0; i < length; i++)
8545 tgl@sss.pgh.pa.us 371 :CBC 1277928 : appendStringInfo(str, "%d ", (int) (s[i]));
4569 rhaas@postgresql.org 372 : 36576 : appendStringInfoChar(str, ']');
373 : : }
374 : : }
10892 scrappy@hub.org 375 : 105650 : }
376 : :
377 : :
378 : : #include "outfuncs.funcs.c"
379 : :
380 : :
381 : : /*
382 : : * Support functions for nodes with custom_read_write attribute or
383 : : * special_read_write attribute
384 : : */
385 : :
386 : : static void
1396 peter@eisentraut.org 387 : 122380 : _outConst(StringInfo str, const Const *node)
388 : : {
389 : 122380 : WRITE_NODE_TYPE("CONST");
390 : :
391 : 122380 : WRITE_OID_FIELD(consttype);
392 : 122380 : WRITE_INT_FIELD(consttypmod);
393 : 122380 : WRITE_OID_FIELD(constcollid);
394 : 122380 : WRITE_INT_FIELD(constlen);
395 [ + + ]: 122380 : WRITE_BOOL_FIELD(constbyval);
396 [ + + ]: 122380 : WRITE_BOOL_FIELD(constisnull);
397 [ - + ]: 122380 : WRITE_LOCATION_FIELD(location);
398 : :
399 : 122380 : appendStringInfoString(str, " :constvalue ");
400 [ + + ]: 122380 : if (node->constisnull)
401 : 16729 : appendStringInfoString(str, "<>");
402 : : else
403 : 105651 : outDatum(str, node->constvalue, node->constlen, node->constbyval);
8562 tgl@sss.pgh.pa.us 404 : 122380 : }
405 : :
406 : : static void
1396 peter@eisentraut.org 407 : 15538 : _outBoolExpr(StringInfo str, const BoolExpr *node)
408 : : {
409 : 15538 : char *opstr = NULL;
410 : :
411 : 15538 : WRITE_NODE_TYPE("BOOLEXPR");
412 : :
413 : : /* do-it-yourself enum representation */
414 [ + + + - ]: 15538 : switch (node->boolop)
415 : : {
416 : 8947 : case AND_EXPR:
417 : 8947 : opstr = "and";
418 : 8947 : break;
419 : 4206 : case OR_EXPR:
420 : 4206 : opstr = "or";
421 : 4206 : break;
422 : 2385 : case NOT_EXPR:
423 : 2385 : opstr = "not";
424 : 2385 : break;
425 : : }
426 : 15538 : appendStringInfoString(str, " :boolop ");
427 : 15538 : outToken(str, opstr);
428 : :
429 : 15538 : WRITE_NODE_FIELD(args);
430 [ - + ]: 15538 : WRITE_LOCATION_FIELD(location);
8562 tgl@sss.pgh.pa.us 431 : 15538 : }
432 : :
433 : : static void
1396 peter@eisentraut.org 434 :UBC 0 : _outForeignKeyOptInfo(StringInfo str, const ForeignKeyOptInfo *node)
435 : : {
436 : 0 : WRITE_NODE_TYPE("FOREIGNKEYOPTINFO");
437 : :
438 : 0 : WRITE_UINT_FIELD(con_relid);
439 : 0 : WRITE_UINT_FIELD(ref_relid);
440 : 0 : WRITE_INT_FIELD(nkeys);
441 : 0 : WRITE_ATTRNUMBER_ARRAY(conkey, node->nkeys);
442 : 0 : WRITE_ATTRNUMBER_ARRAY(confkey, node->nkeys);
443 : 0 : WRITE_OID_ARRAY(conpfeqop, node->nkeys);
444 : 0 : WRITE_INT_FIELD(nmatched_ec);
445 : 0 : WRITE_INT_FIELD(nconst_ec);
446 : 0 : WRITE_INT_FIELD(nmatched_rcols);
447 : 0 : WRITE_INT_FIELD(nmatched_ri);
448 : : /* for compactness, just print the number of matches per column: */
449 : 0 : appendStringInfoString(str, " :eclass");
161 peter@eisentraut.org 450 [ # # ]:UNC 0 : for (int i = 0; i < node->nkeys; i++)
1396 peter@eisentraut.org 451 :UBC 0 : appendStringInfo(str, " %d", (node->eclass[i] != NULL));
452 : 0 : appendStringInfoString(str, " :rinfos");
161 peter@eisentraut.org 453 [ # # ]:UNC 0 : for (int i = 0; i < node->nkeys; i++)
1396 peter@eisentraut.org 454 :UBC 0 : appendStringInfo(str, " %d", list_length(node->rinfos[i]));
3394 andres@anarazel.de 455 : 0 : }
456 : :
457 : : static void
1396 peter@eisentraut.org 458 : 0 : _outEquivalenceClass(StringInfo str, const EquivalenceClass *node)
459 : : {
460 : : /*
461 : : * To simplify reading, we just chase up to the topmost merged EC and
462 : : * print that, without bothering to show the merge-ees separately.
463 : : */
464 [ # # ]: 0 : while (node->ec_merged)
465 : 0 : node = node->ec_merged;
466 : :
467 : 0 : WRITE_NODE_TYPE("EQUIVALENCECLASS");
468 : :
469 : 0 : WRITE_NODE_FIELD(ec_opfamilies);
470 : 0 : WRITE_OID_FIELD(ec_collation);
392 drowley@postgresql.o 471 : 0 : WRITE_INT_FIELD(ec_childmembers_size);
1396 peter@eisentraut.org 472 : 0 : WRITE_NODE_FIELD(ec_members);
392 drowley@postgresql.o 473 : 0 : WRITE_NODE_ARRAY(ec_childmembers, node->ec_childmembers_size);
1396 peter@eisentraut.org 474 : 0 : WRITE_NODE_FIELD(ec_sources);
475 : : /* Only ec_derives_list is written; hash is not serialized. */
396 amitlan@postgresql.o 476 : 0 : WRITE_NODE_FIELD(ec_derives_list);
1396 peter@eisentraut.org 477 : 0 : WRITE_BITMAPSET_FIELD(ec_relids);
478 [ # # ]: 0 : WRITE_BOOL_FIELD(ec_has_const);
479 [ # # ]: 0 : WRITE_BOOL_FIELD(ec_has_volatile);
480 [ # # ]: 0 : WRITE_BOOL_FIELD(ec_broken);
481 : 0 : WRITE_UINT_FIELD(ec_sortref);
482 : 0 : WRITE_UINT_FIELD(ec_min_security);
483 : 0 : WRITE_UINT_FIELD(ec_max_security);
6051 tgl@sss.pgh.pa.us 484 : 0 : }
485 : :
486 : : static void
1396 peter@eisentraut.org 487 : 0 : _outExtensibleNode(StringInfo str, const ExtensibleNode *node)
488 : : {
489 : : const ExtensibleNodeMethods *methods;
490 : :
491 : 0 : methods = GetExtensibleNodeMethods(node->extnodename, false);
492 : :
493 : 0 : WRITE_NODE_TYPE("EXTENSIBLENODE");
494 : :
495 : 0 : WRITE_STRING_FIELD(extnodename);
496 : :
497 : : /* serialize the private fields */
498 : 0 : methods->nodeOut(str, node);
5682 tgl@sss.pgh.pa.us 499 : 0 : }
500 : :
501 : : static void
1396 peter@eisentraut.org 502 :CBC 55666 : _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
503 : : {
504 : 55666 : WRITE_NODE_TYPE("RANGETBLENTRY");
505 : :
506 : 55666 : WRITE_NODE_FIELD(alias);
507 : 55666 : WRITE_NODE_FIELD(eref);
508 : 55666 : WRITE_ENUM_FIELD(rtekind, RTEKind);
509 : :
510 [ + + + + : 55666 : switch (node->rtekind)
+ + + - +
+ + - ]
511 : : {
512 : 35190 : case RTE_RELATION:
513 : 35190 : WRITE_OID_FIELD(relid);
789 514 [ + + ]: 35190 : WRITE_BOOL_FIELD(inh);
1396 515 : 35190 : WRITE_CHAR_FIELD(relkind);
516 : 35190 : WRITE_INT_FIELD(rellockmode);
1246 alvherre@alvh.no-ip. 517 : 35190 : WRITE_UINT_FIELD(perminfoindex);
791 peter@eisentraut.org 518 : 35190 : WRITE_NODE_FIELD(tablesample);
1396 519 : 35190 : break;
520 : 6551 : case RTE_SUBQUERY:
521 : 6551 : WRITE_NODE_FIELD(subquery);
522 [ - + ]: 6551 : WRITE_BOOL_FIELD(security_barrier);
523 : : /* we re-use these RELATION fields, too: */
1203 tgl@sss.pgh.pa.us 524 : 6551 : WRITE_OID_FIELD(relid);
789 peter@eisentraut.org 525 [ + + ]: 6551 : WRITE_BOOL_FIELD(inh);
1057 amitlan@postgresql.o 526 : 6551 : WRITE_CHAR_FIELD(relkind);
1203 tgl@sss.pgh.pa.us 527 : 6551 : WRITE_INT_FIELD(rellockmode);
528 : 6551 : WRITE_UINT_FIELD(perminfoindex);
1396 peter@eisentraut.org 529 : 6551 : break;
530 : 9688 : case RTE_JOIN:
531 : 9688 : WRITE_ENUM_FIELD(jointype, JoinType);
532 : 9688 : WRITE_INT_FIELD(joinmergedcols);
533 : 9688 : WRITE_NODE_FIELD(joinaliasvars);
534 : 9688 : WRITE_NODE_FIELD(joinleftcols);
535 : 9688 : WRITE_NODE_FIELD(joinrightcols);
536 : 9688 : WRITE_NODE_FIELD(join_using_alias);
537 : 9688 : break;
538 : 3386 : case RTE_FUNCTION:
539 : 3386 : WRITE_NODE_FIELD(functions);
540 [ + + ]: 3386 : WRITE_BOOL_FIELD(funcordinality);
541 : 3386 : break;
542 : 54 : case RTE_TABLEFUNC:
543 : 54 : WRITE_NODE_FIELD(tablefunc);
544 : 54 : break;
545 : 261 : case RTE_VALUES:
546 : 261 : WRITE_NODE_FIELD(values_lists);
547 : 261 : WRITE_NODE_FIELD(coltypes);
548 : 261 : WRITE_NODE_FIELD(coltypmods);
549 : 261 : WRITE_NODE_FIELD(colcollations);
550 : 261 : break;
551 : 149 : case RTE_CTE:
552 : 149 : WRITE_STRING_FIELD(ctename);
553 : 149 : WRITE_UINT_FIELD(ctelevelsup);
554 [ + + ]: 149 : WRITE_BOOL_FIELD(self_reference);
555 : 149 : WRITE_NODE_FIELD(coltypes);
556 : 149 : WRITE_NODE_FIELD(coltypmods);
557 : 149 : WRITE_NODE_FIELD(colcollations);
558 : 149 : break;
1396 peter@eisentraut.org 559 :LBC (3) : case RTE_NAMEDTUPLESTORE:
560 : (3) : WRITE_STRING_FIELD(enrname);
1317 561 : (3) : WRITE_FLOAT_FIELD(enrtuples);
1396 562 : (3) : WRITE_NODE_FIELD(coltypes);
563 : (3) : WRITE_NODE_FIELD(coltypmods);
564 : (3) : WRITE_NODE_FIELD(colcollations);
565 : : /* we re-use these RELATION fields, too: */
1203 tgl@sss.pgh.pa.us 566 : (3) : WRITE_OID_FIELD(relid);
1396 peter@eisentraut.org 567 : (3) : break;
50 peter@eisentraut.org 568 :GNC 26 : case RTE_GRAPH_TABLE:
569 : 26 : WRITE_NODE_FIELD(graph_pattern);
570 : 26 : WRITE_NODE_FIELD(graph_table_columns);
571 : : /* we re-use these RELATION fields, too: */
572 : 26 : WRITE_OID_FIELD(relid);
573 : 26 : WRITE_CHAR_FIELD(relkind);
574 : 26 : WRITE_INT_FIELD(rellockmode);
575 : 26 : WRITE_UINT_FIELD(perminfoindex);
576 : 26 : break;
1396 peter@eisentraut.org 577 :CBC 56 : case RTE_RESULT:
578 : : /* no extra fields */
579 : 56 : break;
602 rguo@postgresql.org 580 : 305 : case RTE_GROUP:
581 : 305 : WRITE_NODE_FIELD(groupexprs);
582 : 305 : break;
1396 peter@eisentraut.org 583 :UBC 0 : default:
584 [ # # ]: 0 : elog(ERROR, "unrecognized RTE kind: %d", (int) node->rtekind);
585 : : break;
586 : : }
587 : :
1396 peter@eisentraut.org 588 [ + + ]:CBC 55666 : WRITE_BOOL_FIELD(lateral);
589 [ + + ]: 55666 : WRITE_BOOL_FIELD(inFromCl);
590 : 55666 : WRITE_NODE_FIELD(securityQuals);
7686 tgl@sss.pgh.pa.us 591 : 55666 : }
592 : :
593 : : static void
1396 peter@eisentraut.org 594 :UBC 0 : _outA_Expr(StringInfo str, const A_Expr *node)
595 : : {
596 : 0 : WRITE_NODE_TYPE("A_EXPR");
597 : :
598 [ # # # # : 0 : switch (node->kind)
# # # # #
# # # # #
# ]
599 : : {
600 : 0 : case AEXPR_OP:
601 : 0 : WRITE_NODE_FIELD(name);
602 : 0 : break;
603 : 0 : case AEXPR_OP_ANY:
1359 604 : 0 : appendStringInfoString(str, " ANY");
1319 605 : 0 : WRITE_NODE_FIELD(name);
1396 606 : 0 : break;
607 : 0 : case AEXPR_OP_ALL:
1359 608 : 0 : appendStringInfoString(str, " ALL");
1319 609 : 0 : WRITE_NODE_FIELD(name);
1396 610 : 0 : break;
611 : 0 : case AEXPR_DISTINCT:
1359 612 : 0 : appendStringInfoString(str, " DISTINCT");
1396 613 : 0 : WRITE_NODE_FIELD(name);
614 : 0 : break;
615 : 0 : case AEXPR_NOT_DISTINCT:
1359 616 : 0 : appendStringInfoString(str, " NOT_DISTINCT");
1396 617 : 0 : WRITE_NODE_FIELD(name);
618 : 0 : break;
619 : 0 : case AEXPR_NULLIF:
1359 620 : 0 : appendStringInfoString(str, " NULLIF");
1396 621 : 0 : WRITE_NODE_FIELD(name);
622 : 0 : break;
623 : 0 : case AEXPR_IN:
1359 624 : 0 : appendStringInfoString(str, " IN");
1396 625 : 0 : WRITE_NODE_FIELD(name);
626 : 0 : break;
627 : 0 : case AEXPR_LIKE:
1359 628 : 0 : appendStringInfoString(str, " LIKE");
1396 629 : 0 : WRITE_NODE_FIELD(name);
630 : 0 : break;
631 : 0 : case AEXPR_ILIKE:
1359 632 : 0 : appendStringInfoString(str, " ILIKE");
1396 633 : 0 : WRITE_NODE_FIELD(name);
634 : 0 : break;
635 : 0 : case AEXPR_SIMILAR:
1359 636 : 0 : appendStringInfoString(str, " SIMILAR");
1396 637 : 0 : WRITE_NODE_FIELD(name);
638 : 0 : break;
639 : 0 : case AEXPR_BETWEEN:
1359 640 : 0 : appendStringInfoString(str, " BETWEEN");
1396 641 : 0 : WRITE_NODE_FIELD(name);
642 : 0 : break;
643 : 0 : case AEXPR_NOT_BETWEEN:
1359 644 : 0 : appendStringInfoString(str, " NOT_BETWEEN");
1396 645 : 0 : WRITE_NODE_FIELD(name);
646 : 0 : break;
647 : 0 : case AEXPR_BETWEEN_SYM:
1359 648 : 0 : appendStringInfoString(str, " BETWEEN_SYM");
1396 649 : 0 : WRITE_NODE_FIELD(name);
650 : 0 : break;
651 : 0 : case AEXPR_NOT_BETWEEN_SYM:
1359 652 : 0 : appendStringInfoString(str, " NOT_BETWEEN_SYM");
1396 653 : 0 : WRITE_NODE_FIELD(name);
654 : 0 : break;
655 : 0 : default:
1319 656 [ # # ]: 0 : elog(ERROR, "unrecognized A_Expr_Kind: %d", (int) node->kind);
657 : : break;
658 : : }
659 : :
1396 660 : 0 : WRITE_NODE_FIELD(lexpr);
661 : 0 : WRITE_NODE_FIELD(rexpr);
327 alvherre@kurilemu.de 662 [ # # ]: 0 : WRITE_LOCATION_FIELD(rexpr_list_start);
663 [ # # ]: 0 : WRITE_LOCATION_FIELD(rexpr_list_end);
1396 peter@eisentraut.org 664 [ # # ]: 0 : WRITE_LOCATION_FIELD(location);
10892 scrappy@hub.org 665 : 0 : }
666 : :
667 : : static void
1396 peter@eisentraut.org 668 : 0 : _outInteger(StringInfo str, const Integer *node)
669 : : {
670 : 0 : appendStringInfo(str, "%d", node->ival);
10892 scrappy@hub.org 671 : 0 : }
672 : :
673 : : static void
1396 peter@eisentraut.org 674 : 0 : _outFloat(StringInfo str, const Float *node)
675 : : {
676 : : /*
677 : : * We assume the value is a valid numeric literal and so does not need
678 : : * quoting.
679 : : */
680 : 0 : appendStringInfoString(str, node->fval);
3937 tgl@sss.pgh.pa.us 681 : 0 : }
682 : :
683 : : static void
1396 peter@eisentraut.org 684 : 0 : _outBoolean(StringInfo str, const Boolean *node)
685 : : {
686 [ # # ]: 0 : appendStringInfoString(str, node->boolval ? "true" : "false");
5320 tgl@sss.pgh.pa.us 687 : 0 : }
688 : :
689 : : static void
1396 peter@eisentraut.org 690 :CBC 1038704 : _outString(StringInfo str, const String *node)
691 : : {
692 : : /*
693 : : * We use outToken to provide escaping of the string's content, but we
694 : : * don't want it to convert an empty string to '""', because we're putting
695 : : * double quotes around the string already.
696 : : */
697 : 1038704 : appendStringInfoChar(str, '"');
698 [ + + ]: 1038704 : if (node->sval[0] != '\0')
699 : 1038601 : outToken(str, node->sval);
700 : 1038704 : appendStringInfoChar(str, '"');
10892 scrappy@hub.org 701 : 1038704 : }
702 : :
703 : : static void
1396 peter@eisentraut.org 704 :UBC 0 : _outBitString(StringInfo str, const BitString *node)
705 : : {
706 : : /*
707 : : * The lexer will always produce a string starting with 'b' or 'x'. There
708 : : * might be characters following that that need escaping, but outToken
709 : : * won't escape the 'b' or 'x'. This is relied on by nodeTokenType.
710 : : */
812 tgl@sss.pgh.pa.us 711 [ # # # # ]: 0 : Assert(node->bsval[0] == 'b' || node->bsval[0] == 'x');
712 : 0 : outToken(str, node->bsval);
7686 713 : 0 : }
714 : :
715 : : static void
1396 peter@eisentraut.org 716 : 0 : _outA_Const(StringInfo str, const A_Const *node)
717 : : {
718 : 0 : WRITE_NODE_TYPE("A_CONST");
719 : :
720 [ # # ]: 0 : if (node->isnull)
1363 721 : 0 : appendStringInfoString(str, " NULL");
722 : : else
723 : : {
1396 724 : 0 : appendStringInfoString(str, " :val ");
725 : 0 : outNode(str, &node->val);
726 : : }
727 [ # # ]: 0 : WRITE_LOCATION_FIELD(location);
7686 tgl@sss.pgh.pa.us 728 : 0 : }
729 : :
730 : :
731 : : /*
732 : : * outNode -
733 : : * converts a Node into ascii string and append it to 'str'
734 : : */
735 : : void
1396 peter@eisentraut.org 736 :CBC 3730623 : outNode(StringInfo str, const void *obj)
737 : : {
738 : : /* Guard against stack overflow due to overly complex expressions */
739 : 3730623 : check_stack_depth();
740 : :
10467 bruce@momjian.us 741 [ + + ]: 3730623 : if (obj == NULL)
4569 rhaas@postgresql.org 742 : 758867 : appendStringInfoString(str, "<>");
1392 alvherre@alvh.no-ip. 743 [ + + + + : 2971756 : else if (IsA(obj, List) || IsA(obj, IntList) || IsA(obj, OidList) ||
+ + ]
744 [ - + ]: 2608786 : IsA(obj, XidList))
8014 neilc@samurai.com 745 : 362970 : _outList(str, obj);
746 : : /* nodeRead does not want to see { } around these! */
1699 peter@eisentraut.org 747 [ - + ]: 2608786 : else if (IsA(obj, Integer))
99 peter@eisentraut.org 748 :UNC 0 : _outInteger(str, (const Integer *) obj);
1699 peter@eisentraut.org 749 [ - + ]:CBC 2608786 : else if (IsA(obj, Float))
99 peter@eisentraut.org 750 :UNC 0 : _outFloat(str, (const Float *) obj);
1572 peter@eisentraut.org 751 [ - + ]:CBC 2608786 : else if (IsA(obj, Boolean))
99 peter@eisentraut.org 752 :UNC 0 : _outBoolean(str, (const Boolean *) obj);
1699 peter@eisentraut.org 753 [ + + ]:CBC 2608786 : else if (IsA(obj, String))
99 peter@eisentraut.org 754 :GNC 1038704 : _outString(str, (const String *) obj);
1699 peter@eisentraut.org 755 [ - + ]:CBC 1570082 : else if (IsA(obj, BitString))
99 peter@eisentraut.org 756 :UNC 0 : _outBitString(str, (const BitString *) obj);
1269 tgl@sss.pgh.pa.us 757 [ + + ]:CBC 1570082 : else if (IsA(obj, Bitmapset))
99 peter@eisentraut.org 758 :GNC 213 : outBitmapset(str, (const Bitmapset *) obj);
759 : : else
760 : : {
9608 tgl@sss.pgh.pa.us 761 :CBC 1569869 : appendStringInfoChar(str, '{');
10467 bruce@momjian.us 762 [ + - + - : 1569869 : switch (nodeTag(obj))
+ + + + +
+ - + + +
+ + + + +
+ + + - +
+ + + + -
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + - - +
- + + + +
+ + + + +
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- + + - -
+ + + + +
+ - + + +
+ - - - -
+ + + - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - +
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - + - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
+ + + - +
- - - - +
- + + + +
- + - + -
- - - - -
- + + + +
+ + + - -
+ - + - -
+ - - + -
+ + + + -
- - - -
- ]
763 : : {
764 : : #include "outfuncs.switch.c"
765 : :
10466 bruce@momjian.us 766 :UBC 0 : default:
767 : :
768 : : /*
769 : : * This should be an ERROR, but it's too useful to be able to
770 : : * dump structures that outNode only understands part of.
771 : : */
8323 tgl@sss.pgh.pa.us 772 [ # # ]: 0 : elog(WARNING, "could not dump unrecognized node type: %d",
773 : : (int) nodeTag(obj));
10466 bruce@momjian.us 774 : 0 : break;
775 : : }
9608 tgl@sss.pgh.pa.us 776 :CBC 1569869 : appendStringInfoChar(str, '}');
777 : : }
10892 scrappy@hub.org 778 : 3730623 : }
779 : :
780 : : /*
781 : : * nodeToString -
782 : : * returns the ascii representation of the Node as a palloc'd string
783 : : *
784 : : * write_loc_fields determines whether location fields are output with their
785 : : * actual value rather than -1. The actual value can be useful for debugging,
786 : : * but for most uses, the actual value is not useful, since the original query
787 : : * string is no longer available.
788 : : */
789 : : static char *
774 peter@eisentraut.org 790 : 48516 : nodeToStringInternal(const void *obj, bool write_loc_fields)
791 : : {
792 : : StringInfoData str;
793 : : bool save_write_location_fields;
794 : :
795 : 48516 : save_write_location_fields = write_location_fields;
796 : 48516 : write_location_fields = write_loc_fields;
797 : :
798 : : /* see stringinfo.h for an explanation of this maneuver */
9872 tgl@sss.pgh.pa.us 799 : 48516 : initStringInfo(&str);
3679 andres@anarazel.de 800 : 48516 : outNode(&str, obj);
801 : :
774 peter@eisentraut.org 802 : 48516 : write_location_fields = save_write_location_fields;
803 : :
9872 tgl@sss.pgh.pa.us 804 : 48516 : return str.data;
805 : : }
806 : :
807 : : /*
808 : : * Externally visible entry points
809 : : */
810 : : char *
774 peter@eisentraut.org 811 : 48516 : nodeToString(const void *obj)
812 : : {
813 : 48516 : return nodeToStringInternal(obj, false);
814 : : }
815 : :
816 : : char *
774 peter@eisentraut.org 817 :UBC 0 : nodeToStringWithLocations(const void *obj)
818 : : {
819 : 0 : return nodeToStringInternal(obj, true);
820 : : }
821 : :
822 : :
823 : : /*
824 : : * bmsToString -
825 : : * returns the ascii representation of the Bitmapset as a palloc'd string
826 : : */
827 : : char *
3518 tgl@sss.pgh.pa.us 828 : 0 : bmsToString(const Bitmapset *bms)
829 : : {
830 : : StringInfoData str;
831 : :
832 : : /* see stringinfo.h for an explanation of this maneuver */
833 : 0 : initStringInfo(&str);
834 : 0 : outBitmapset(&str, bms);
835 : 0 : return str.data;
836 : : }
|