Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * print.c
4 : : * various print routines (used mostly for debugging)
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/print.c
12 : : *
13 : : * HISTORY
14 : : * AUTHOR DATE MAJOR EVENT
15 : : * Andrew Yu Oct 26, 1994 file creation
16 : : *
17 : : *-------------------------------------------------------------------------
18 : : */
19 : :
20 : : #include "postgres.h"
21 : :
22 : : #include "access/printtup.h"
23 : : #include "lib/stringinfo.h"
24 : : #include "nodes/nodeFuncs.h"
25 : : #include "nodes/pathnodes.h"
26 : : #include "nodes/print.h"
27 : : #include "parser/parsetree.h"
28 : : #include "utils/lsyscache.h"
29 : :
30 : :
31 : : /*
32 : : * print
33 : : * print contents of Node to stdout
34 : : */
35 : : void
5263 peter_e@gmx.net 36 :UBC 0 : print(const void *obj)
37 : : {
38 : : char *s;
39 : : char *f;
40 : :
774 peter@eisentraut.org 41 : 0 : s = nodeToStringWithLocations(obj);
8808 tgl@sss.pgh.pa.us 42 : 0 : f = format_node_dump(s);
8903 43 : 0 : pfree(s);
8808 44 : 0 : printf("%s\n", f);
45 : 0 : fflush(stdout);
46 : 0 : pfree(f);
10892 scrappy@hub.org 47 : 0 : }
48 : :
49 : : /*
50 : : * pprint
51 : : * pretty-print contents of Node to stdout
52 : : */
53 : : void
5263 peter_e@gmx.net 54 : 0 : pprint(const void *obj)
55 : : {
56 : : char *s;
57 : : char *f;
58 : :
774 peter@eisentraut.org 59 : 0 : s = nodeToStringWithLocations(obj);
8808 tgl@sss.pgh.pa.us 60 : 0 : f = pretty_format_node_dump(s);
61 : 0 : pfree(s);
62 : 0 : printf("%s\n", f);
63 : 0 : fflush(stdout);
64 : 0 : pfree(f);
65 : 0 : }
66 : :
67 : : /*
68 : : * elog_node_display
69 : : * send pretty-printed contents of Node to postmaster log
70 : : */
71 : : void
5263 peter_e@gmx.net 72 : 0 : elog_node_display(int lev, const char *title, const void *obj, bool pretty)
73 : : {
74 : : char *s;
75 : : char *f;
76 : :
774 peter@eisentraut.org 77 : 0 : s = nodeToStringWithLocations(obj);
8808 tgl@sss.pgh.pa.us 78 [ # # ]: 0 : if (pretty)
79 : 0 : f = pretty_format_node_dump(s);
80 : : else
81 : 0 : f = format_node_dump(s);
82 : 0 : pfree(s);
8323 83 [ # # ]: 0 : ereport(lev,
84 : : (errmsg_internal("%s:", title),
85 : : errdetail_internal("%s", f)));
8808 86 : 0 : pfree(f);
87 : 0 : }
88 : :
89 : : /*
90 : : * Format a nodeToString output for display on a terminal.
91 : : *
92 : : * The result is a palloc'd string.
93 : : *
94 : : * This version just tries to break at whitespace.
95 : : */
96 : : char *
97 : 0 : format_node_dump(const char *dump)
98 : : {
99 : : #define LINELEN 78
100 : : char line[LINELEN + 1];
101 : : StringInfoData str;
102 : : int i;
103 : : int j;
104 : : int k;
105 : :
106 : 0 : initStringInfo(&str);
107 : 0 : i = 0;
108 : : for (;;)
109 : : {
110 [ # # # # ]: 0 : for (j = 0; j < LINELEN && dump[i] != '\0'; i++, j++)
111 : 0 : line[j] = dump[i];
112 [ # # ]: 0 : if (dump[i] == '\0')
113 : 0 : break;
114 [ # # ]: 0 : if (dump[i] == ' ')
115 : : {
116 : : /* ok to break at adjacent space */
117 : 0 : i++;
118 : : }
119 : : else
120 : : {
8644 bruce@momjian.us 121 [ # # ]: 0 : for (k = j - 1; k > 0; k--)
8808 tgl@sss.pgh.pa.us 122 [ # # ]: 0 : if (line[k] == ' ')
123 : 0 : break;
124 [ # # ]: 0 : if (k > 0)
125 : : {
126 : : /* back up; will reprint all after space */
8644 bruce@momjian.us 127 : 0 : i -= (j - k - 1);
8808 tgl@sss.pgh.pa.us 128 : 0 : j = k;
129 : : }
130 : : }
131 : 0 : line[j] = '\0';
132 : 0 : appendStringInfo(&str, "%s\n", line);
133 : : }
134 [ # # ]: 0 : if (j > 0)
135 : : {
136 : 0 : line[j] = '\0';
137 : 0 : appendStringInfo(&str, "%s\n", line);
138 : : }
139 : 0 : return str.data;
140 : : #undef LINELEN
141 : : }
142 : :
143 : : /*
144 : : * Format a nodeToString output for display on a terminal.
145 : : *
146 : : * The result is a palloc'd string.
147 : : *
148 : : * This version tries to indent intelligently.
149 : : */
150 : : char *
151 : 0 : pretty_format_node_dump(const char *dump)
152 : : {
153 : : #define INDENTSTOP 3
154 : : #define MAXINDENT 60
155 : : #define LINELEN 78
156 : : char line[LINELEN + 1];
157 : : StringInfoData str;
158 : : int indentLev;
159 : : int indentDist;
160 : : int i;
161 : : int j;
162 : :
163 : 0 : initStringInfo(&str);
8903 164 : 0 : indentLev = 0; /* logical indent level */
165 : 0 : indentDist = 0; /* physical indent distance */
10467 bruce@momjian.us 166 : 0 : i = 0;
167 : : for (;;)
168 : : {
8903 tgl@sss.pgh.pa.us 169 [ # # ]: 0 : for (j = 0; j < indentDist; j++)
10892 scrappy@hub.org 170 : 0 : line[j] = ' ';
8808 tgl@sss.pgh.pa.us 171 [ # # # # ]: 0 : for (; j < LINELEN && dump[i] != '\0'; i++, j++)
172 : : {
173 : 0 : line[j] = dump[i];
10467 bruce@momjian.us 174 [ # # # # : 0 : switch (line[j])
# ]
175 : : {
10466 176 : 0 : case '}':
8903 tgl@sss.pgh.pa.us 177 [ # # ]: 0 : if (j != indentDist)
178 : : {
179 : : /* print data before the } */
10466 bruce@momjian.us 180 : 0 : line[j] = '\0';
8808 tgl@sss.pgh.pa.us 181 : 0 : appendStringInfo(&str, "%s\n", line);
182 : : }
183 : : /* print the } at indentDist */
184 : 0 : line[indentDist] = '}';
8644 bruce@momjian.us 185 : 0 : line[indentDist + 1] = '\0';
8808 tgl@sss.pgh.pa.us 186 : 0 : appendStringInfo(&str, "%s\n", line);
187 : : /* outdent */
8903 188 [ # # ]: 0 : if (indentLev > 0)
189 : : {
190 : 0 : indentLev--;
8902 bruce@momjian.us 191 : 0 : indentDist = Min(indentLev * INDENTSTOP, MAXINDENT);
192 : : }
8903 tgl@sss.pgh.pa.us 193 : 0 : j = indentDist - 1;
194 : : /* j will equal indentDist on next loop iteration */
195 : : /* suppress whitespace just after } */
7919 bruce@momjian.us 196 [ # # ]: 0 : while (dump[i + 1] == ' ')
8032 tgl@sss.pgh.pa.us 197 : 0 : i++;
10466 bruce@momjian.us 198 : 0 : break;
199 : 0 : case ')':
200 : : /* force line break after ), unless another ) follows */
7919 201 [ # # ]: 0 : if (dump[i + 1] != ')')
202 : : {
8032 tgl@sss.pgh.pa.us 203 : 0 : line[j + 1] = '\0';
204 : 0 : appendStringInfo(&str, "%s\n", line);
205 : 0 : j = indentDist - 1;
7919 bruce@momjian.us 206 [ # # ]: 0 : while (dump[i + 1] == ' ')
8032 tgl@sss.pgh.pa.us 207 : 0 : i++;
208 : : }
10466 bruce@momjian.us 209 : 0 : break;
210 : 0 : case '{':
211 : : /* force line break before { */
8903 tgl@sss.pgh.pa.us 212 [ # # ]: 0 : if (j != indentDist)
213 : : {
214 : 0 : line[j] = '\0';
8808 215 : 0 : appendStringInfo(&str, "%s\n", line);
216 : : }
217 : : /* indent */
10466 bruce@momjian.us 218 : 0 : indentLev++;
8902 219 : 0 : indentDist = Min(indentLev * INDENTSTOP, MAXINDENT);
8903 tgl@sss.pgh.pa.us 220 [ # # ]: 0 : for (j = 0; j < indentDist; j++)
221 : 0 : line[j] = ' ';
8808 222 : 0 : line[j] = dump[i];
8903 223 : 0 : break;
10466 bruce@momjian.us 224 : 0 : case ':':
225 : : /* force line break before : */
8903 tgl@sss.pgh.pa.us 226 [ # # ]: 0 : if (j != indentDist)
227 : : {
10466 bruce@momjian.us 228 : 0 : line[j] = '\0';
8808 tgl@sss.pgh.pa.us 229 : 0 : appendStringInfo(&str, "%s\n", line);
230 : : }
8903 231 : 0 : j = indentDist;
8808 232 : 0 : line[j] = dump[i];
10466 bruce@momjian.us 233 : 0 : break;
234 : : }
235 : : }
10467 236 : 0 : line[j] = '\0';
8808 tgl@sss.pgh.pa.us 237 [ # # ]: 0 : if (dump[i] == '\0')
10467 bruce@momjian.us 238 : 0 : break;
8808 tgl@sss.pgh.pa.us 239 : 0 : appendStringInfo(&str, "%s\n", line);
240 : : }
241 [ # # ]: 0 : if (j > 0)
242 : 0 : appendStringInfo(&str, "%s\n", line);
243 : 0 : return str.data;
244 : : #undef INDENTSTOP
245 : : #undef MAXINDENT
246 : : #undef LINELEN
247 : : }
248 : :
249 : : /*
250 : : * print_rt
251 : : * print contents of range table
252 : : */
253 : : void
5263 peter_e@gmx.net 254 : 0 : print_rt(const List *rtable)
255 : : {
256 : : const ListCell *l;
10466 bruce@momjian.us 257 : 0 : int i = 1;
258 : :
8810 tgl@sss.pgh.pa.us 259 : 0 : printf("resno\trefname \trelid\tinFromCl\n");
260 : 0 : printf("-----\t---------\t-----\t--------\n");
10467 bruce@momjian.us 261 [ # # # # : 0 : foreach(l, rtable)
# # ]
262 : : {
10466 263 : 0 : RangeTblEntry *rte = lfirst(l);
264 : :
8759 tgl@sss.pgh.pa.us 265 [ # # # # : 0 : switch (rte->rtekind)
# # # # #
# # # ]
266 : : {
267 : 0 : case RTE_RELATION:
5551 268 : 0 : printf("%d\t%s\t%u\t%c",
269 : : i, rte->eref->aliasname, rte->relid, rte->relkind);
8759 270 : 0 : break;
271 : 0 : case RTE_SUBQUERY:
272 : 0 : printf("%d\t%s\t[subquery]",
273 : : i, rte->eref->aliasname);
274 : 0 : break;
6422 275 : 0 : case RTE_JOIN:
276 : 0 : printf("%d\t%s\t[join]",
277 : : i, rte->eref->aliasname);
278 : 0 : break;
8759 279 : 0 : case RTE_FUNCTION:
280 : 0 : printf("%d\t%s\t[rangefunction]",
281 : : i, rte->eref->aliasname);
3345 alvherre@alvh.no-ip. 282 : 0 : break;
283 : 0 : case RTE_TABLEFUNC:
284 : 0 : printf("%d\t%s\t[table function]",
285 : : i, rte->eref->aliasname);
8759 tgl@sss.pgh.pa.us 286 : 0 : break;
7216 mail@joeconway.com 287 : 0 : case RTE_VALUES:
288 : 0 : printf("%d\t%s\t[values list]",
289 : : i, rte->eref->aliasname);
290 : 0 : break;
6422 tgl@sss.pgh.pa.us 291 : 0 : case RTE_CTE:
292 : 0 : printf("%d\t%s\t[cte]",
293 : : i, rte->eref->aliasname);
8759 294 : 0 : break;
3322 kgrittn@postgresql.o 295 : 0 : case RTE_NAMEDTUPLESTORE:
296 : 0 : printf("%d\t%s\t[tuplestore]",
297 : : i, rte->eref->aliasname);
298 : 0 : break;
2654 tgl@sss.pgh.pa.us 299 : 0 : case RTE_RESULT:
300 : 0 : printf("%d\t%s\t[result]",
301 : : i, rte->eref->aliasname);
302 : 0 : break;
602 rguo@postgresql.org 303 : 0 : case RTE_GROUP:
304 : 0 : printf("%d\t%s\t[group]",
305 : : i, rte->eref->aliasname);
306 : 0 : break;
50 peter@eisentraut.org 307 :UNC 0 : case RTE_GRAPH_TABLE:
308 : 0 : printf("%d\t%s\t[graph table]",
309 : : i, rte->eref->aliasname);
310 : 0 : break;
8759 tgl@sss.pgh.pa.us 311 :UBC 0 : default:
312 : 0 : printf("%d\t%s\t[unknown rtekind]",
313 : : i, rte->eref->aliasname);
314 : : }
315 : :
9349 316 [ # # # # ]: 0 : printf("\t%s\t%s\n",
317 : : (rte->inh ? "inh" : ""),
318 : : (rte->inFromCl ? "inFromCl" : ""));
10467 bruce@momjian.us 319 : 0 : i++;
320 : : }
10892 scrappy@hub.org 321 : 0 : }
322 : :
323 : :
324 : : /*
325 : : * print_expr
326 : : * print an expression
327 : : */
328 : : void
5263 peter_e@gmx.net 329 : 0 : print_expr(const Node *expr, const List *rtable)
330 : : {
10467 bruce@momjian.us 331 [ # # ]: 0 : if (expr == NULL)
332 : : {
10345 333 : 0 : printf("<>");
10467 334 : 0 : return;
335 : : }
336 : :
337 [ # # ]: 0 : if (IsA(expr, Var))
338 : : {
5077 339 : 0 : const Var *var = (const Var *) expr;
340 : : char *relname,
341 : : *attname;
342 : :
10467 343 [ # # # # ]: 0 : switch (var->varno)
344 : : {
5320 tgl@sss.pgh.pa.us 345 : 0 : case INNER_VAR:
10466 bruce@momjian.us 346 : 0 : relname = "INNER";
347 : 0 : attname = "?";
348 : 0 : break;
5320 tgl@sss.pgh.pa.us 349 : 0 : case OUTER_VAR:
10466 bruce@momjian.us 350 : 0 : relname = "OUTER";
351 : 0 : attname = "?";
352 : 0 : break;
5320 tgl@sss.pgh.pa.us 353 : 0 : case INDEX_VAR:
354 : 0 : relname = "INDEX";
355 : 0 : attname = "?";
356 : 0 : break;
10466 bruce@momjian.us 357 : 0 : default:
358 : : {
359 : : RangeTblEntry *rte;
360 : :
9353 tgl@sss.pgh.pa.us 361 [ # # # # ]: 0 : Assert(var->varno > 0 &&
362 : : (int) var->varno <= list_length(rtable));
363 : 0 : rte = rt_fetch(var->varno, rtable);
8811 364 : 0 : relname = rte->eref->aliasname;
9353 365 : 0 : attname = get_rte_attribute_name(rte, var->varattno);
366 : : }
10466 bruce@momjian.us 367 : 0 : break;
368 : : }
10467 369 : 0 : printf("%s.%s", relname, attname);
370 : : }
8965 tgl@sss.pgh.pa.us 371 [ # # ]: 0 : else if (IsA(expr, Const))
372 : : {
5077 bruce@momjian.us 373 : 0 : const Const *c = (const Const *) expr;
374 : : Oid typoutput;
375 : : bool typIsVarlena;
376 : : char *outputstr;
377 : :
8965 tgl@sss.pgh.pa.us 378 [ # # ]: 0 : if (c->constisnull)
379 : : {
380 : 0 : printf("NULL");
381 : 0 : return;
382 : : }
383 : :
8003 384 : 0 : getTypeOutputInfo(c->consttype,
385 : : &typoutput, &typIsVarlena);
386 : :
7336 387 : 0 : outputstr = OidOutputFunctionCall(typoutput, c->constvalue);
8965 388 : 0 : printf("%s", outputstr);
389 : 0 : pfree(outputstr);
390 : : }
8504 391 [ # # ]: 0 : else if (IsA(expr, OpExpr))
392 : : {
5077 bruce@momjian.us 393 : 0 : const OpExpr *e = (const OpExpr *) expr;
394 : : char *opname;
395 : :
8504 tgl@sss.pgh.pa.us 396 : 0 : opname = get_opname(e->opno);
8010 neilc@samurai.com 397 [ # # ]: 0 : if (list_length(e->args) > 1)
398 : : {
5263 peter_e@gmx.net 399 : 0 : print_expr(get_leftop((const Expr *) e), rtable);
10108 bruce@momjian.us 400 [ # # ]: 0 : printf(" %s ", ((opname != NULL) ? opname : "(invalid operator)"));
5263 peter_e@gmx.net 401 : 0 : print_expr(get_rightop((const Expr *) e), rtable);
402 : : }
403 : : else
404 : : {
8504 tgl@sss.pgh.pa.us 405 [ # # ]: 0 : printf("%s ", ((opname != NULL) ? opname : "(invalid operator)"));
5263 peter_e@gmx.net 406 : 0 : print_expr(get_leftop((const Expr *) e), rtable);
407 : : }
408 : : }
8504 tgl@sss.pgh.pa.us 409 [ # # ]: 0 : else if (IsA(expr, FuncExpr))
410 : : {
5077 bruce@momjian.us 411 : 0 : const FuncExpr *e = (const FuncExpr *) expr;
412 : : char *funcname;
413 : : ListCell *l;
414 : :
8504 tgl@sss.pgh.pa.us 415 : 0 : funcname = get_func_name(e->funcid);
416 [ # # ]: 0 : printf("%s(", ((funcname != NULL) ? funcname : "(invalid function)"));
417 [ # # # # : 0 : foreach(l, e->args)
# # ]
418 : : {
419 : 0 : print_expr(lfirst(l), rtable);
2486 420 [ # # ]: 0 : if (lnext(e->args, l))
8504 421 : 0 : printf(",");
422 : : }
423 : 0 : printf(")");
424 : : }
425 : : else
426 : 0 : printf("unknown expr");
427 : : }
428 : :
429 : : /*
430 : : * print_pathkeys -
431 : : * pathkeys list of PathKeys
432 : : */
433 : : void
5263 peter_e@gmx.net 434 : 0 : print_pathkeys(const List *pathkeys, const List *rtable)
435 : : {
436 : : const ListCell *i;
437 : :
10467 bruce@momjian.us 438 : 0 : printf("(");
9936 439 [ # # # # : 0 : foreach(i, pathkeys)
# # ]
440 : : {
6746 441 : 0 : PathKey *pathkey = (PathKey *) lfirst(i);
442 : : EquivalenceClass *eclass;
443 : : ListCell *k;
7045 tgl@sss.pgh.pa.us 444 : 0 : bool first = true;
445 : :
446 : 0 : eclass = pathkey->pk_eclass;
447 : : /* chase up, in case pathkey is non-canonical */
448 [ # # ]: 0 : while (eclass->ec_merged)
449 : 0 : eclass = eclass->ec_merged;
450 : :
9936 bruce@momjian.us 451 : 0 : printf("(");
7045 tgl@sss.pgh.pa.us 452 [ # # # # : 0 : foreach(k, eclass->ec_members)
# # ]
453 : : {
454 : 0 : EquivalenceMember *mem = (EquivalenceMember *) lfirst(k);
455 : :
456 [ # # ]: 0 : if (first)
457 : 0 : first = false;
458 : : else
9936 bruce@momjian.us 459 : 0 : printf(", ");
7045 tgl@sss.pgh.pa.us 460 : 0 : print_expr((Node *) mem->em_expr, rtable);
461 : : }
8965 462 : 0 : printf(")");
2486 463 [ # # ]: 0 : if (lnext(pathkeys, i))
10467 bruce@momjian.us 464 : 0 : printf(", ");
465 : : }
466 : 0 : printf(")\n");
10892 scrappy@hub.org 467 : 0 : }
468 : :
469 : : /*
470 : : * print_tl
471 : : * print targetlist in a more legible way.
472 : : */
473 : : void
5263 peter_e@gmx.net 474 : 0 : print_tl(const List *tlist, const List *rtable)
475 : : {
476 : : const ListCell *tl;
477 : :
10467 bruce@momjian.us 478 : 0 : printf("(\n");
479 [ # # # # : 0 : foreach(tl, tlist)
# # ]
480 : : {
8014 neilc@samurai.com 481 : 0 : TargetEntry *tle = (TargetEntry *) lfirst(tl);
482 : :
7699 tgl@sss.pgh.pa.us 483 [ # # ]: 0 : printf("\t%d %s\t", tle->resno,
484 : : tle->resname ? tle->resname : "<null>");
485 [ # # ]: 0 : if (tle->ressortgroupref != 0)
486 : 0 : printf("(%u):\t", tle->ressortgroupref);
487 : : else
10467 bruce@momjian.us 488 : 0 : printf(" :\t");
8545 tgl@sss.pgh.pa.us 489 : 0 : print_expr((Node *) tle->expr, rtable);
10467 bruce@momjian.us 490 : 0 : printf("\n");
491 : : }
492 : 0 : printf(")\n");
10892 scrappy@hub.org 493 : 0 : }
494 : :
495 : : /*
496 : : * print_slot
497 : : * print out the tuple with the given TupleTableSlot
498 : : */
499 : : void
10466 bruce@momjian.us 500 : 0 : print_slot(TupleTableSlot *slot)
501 : : {
7720 tgl@sss.pgh.pa.us 502 [ # # # # ]: 0 : if (TupIsNull(slot))
503 : : {
10467 bruce@momjian.us 504 : 0 : printf("tuple is null.\n");
505 : 0 : return;
506 : : }
7720 tgl@sss.pgh.pa.us 507 [ # # ]: 0 : if (!slot->tts_tupleDescriptor)
508 : : {
10467 bruce@momjian.us 509 : 0 : printf("no tuple descriptor.\n");
510 : 0 : return;
511 : : }
512 : :
7720 tgl@sss.pgh.pa.us 513 : 0 : debugtup(slot, NULL);
514 : : }
|