1 /*-------------------------------------------------------------------------
4 * various print routines (used mostly for debugging)
6 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/nodes/print.c
14 * AUTHOR DATE MAJOR EVENT
15 * Andrew Yu Oct 26, 1994 file creation
17 *-------------------------------------------------------------------------
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"
33 * print contents of Node to stdout
36 print(const void *obj
)
41 s
= nodeToString(obj
);
42 f
= format_node_dump(s
);
51 * pretty-print contents of Node to stdout
54 pprint(const void *obj
)
59 s
= nodeToString(obj
);
60 f
= pretty_format_node_dump(s
);
69 * send pretty-printed contents of Node to postmaster log
72 elog_node_display(int lev
, const char *title
, const void *obj
, bool pretty
)
77 s
= nodeToString(obj
);
79 f
= pretty_format_node_dump(s
);
81 f
= format_node_dump(s
);
84 (errmsg_internal("%s:", title
),
85 errdetail_internal("%s", f
)));
90 * Format a nodeToString output for display on a terminal.
92 * The result is a palloc'd string.
94 * This version just tries to break at whitespace.
97 format_node_dump(const char *dump
)
100 char line
[LINELEN
+ 1];
106 initStringInfo(&str
);
110 for (j
= 0; j
< LINELEN
&& dump
[i
] != '\0'; i
++, j
++)
116 /* ok to break at adjacent space */
121 for (k
= j
- 1; k
> 0; k
--)
126 /* back up; will reprint all after space */
132 appendStringInfo(&str
, "%s\n", line
);
137 appendStringInfo(&str
, "%s\n", line
);
144 * Format a nodeToString output for display on a terminal.
146 * The result is a palloc'd string.
148 * This version tries to indent intelligently.
151 pretty_format_node_dump(const char *dump
)
156 char line
[LINELEN
+ 1];
163 initStringInfo(&str
);
164 indentLev
= 0; /* logical indent level */
165 indentDist
= 0; /* physical indent distance */
169 for (j
= 0; j
< indentDist
; j
++)
171 for (; j
< LINELEN
&& dump
[i
] != '\0'; i
++, j
++)
179 /* print data before the } */
181 appendStringInfo(&str
, "%s\n", line
);
183 /* print the } at indentDist */
184 line
[indentDist
] = '}';
185 line
[indentDist
+ 1] = '\0';
186 appendStringInfo(&str
, "%s\n", line
);
191 indentDist
= Min(indentLev
* INDENTSTOP
, MAXINDENT
);
194 /* j will equal indentDist on next loop iteration */
195 /* suppress whitespace just after } */
196 while (dump
[i
+ 1] == ' ')
200 /* force line break after ), unless another ) follows */
201 if (dump
[i
+ 1] != ')')
204 appendStringInfo(&str
, "%s\n", line
);
206 while (dump
[i
+ 1] == ' ')
211 /* force line break before { */
215 appendStringInfo(&str
, "%s\n", line
);
219 indentDist
= Min(indentLev
* INDENTSTOP
, MAXINDENT
);
220 for (j
= 0; j
< indentDist
; j
++)
225 /* force line break before : */
229 appendStringInfo(&str
, "%s\n", line
);
239 appendStringInfo(&str
, "%s\n", line
);
242 appendStringInfo(&str
, "%s\n", line
);
251 * print contents of range table
254 print_rt(const List
*rtable
)
259 printf("resno\trefname \trelid\tinFromCl\n");
260 printf("-----\t---------\t-----\t--------\n");
263 RangeTblEntry
*rte
= lfirst(l
);
265 switch (rte
->rtekind
)
268 printf("%d\t%s\t%u\t%c",
269 i
, rte
->eref
->aliasname
, rte
->relid
, rte
->relkind
);
272 printf("%d\t%s\t[subquery]",
273 i
, rte
->eref
->aliasname
);
276 printf("%d\t%s\t[join]",
277 i
, rte
->eref
->aliasname
);
280 printf("%d\t%s\t[rangefunction]",
281 i
, rte
->eref
->aliasname
);
284 printf("%d\t%s\t[table function]",
285 i
, rte
->eref
->aliasname
);
288 printf("%d\t%s\t[values list]",
289 i
, rte
->eref
->aliasname
);
292 printf("%d\t%s\t[cte]",
293 i
, rte
->eref
->aliasname
);
295 case RTE_NAMEDTUPLESTORE
:
296 printf("%d\t%s\t[tuplestore]",
297 i
, rte
->eref
->aliasname
);
300 printf("%d\t%s\t[result]",
301 i
, rte
->eref
->aliasname
);
304 printf("%d\t%s\t[unknown rtekind]",
305 i
, rte
->eref
->aliasname
);
309 (rte
->inh
? "inh" : ""),
310 (rte
->inFromCl
? "inFromCl" : ""));
318 * print an expression
321 print_expr(const Node
*expr
, const List
*rtable
)
331 const Var
*var
= (const Var
*) expr
;
353 Assert(var
->varno
> 0 &&
354 (int) var
->varno
<= list_length(rtable
));
355 rte
= rt_fetch(var
->varno
, rtable
);
356 relname
= rte
->eref
->aliasname
;
357 attname
= get_rte_attribute_name(rte
, var
->varattno
);
361 printf("%s.%s", relname
, attname
);
363 else if (IsA(expr
, Const
))
365 const Const
*c
= (const Const
*) expr
;
376 getTypeOutputInfo(c
->consttype
,
377 &typoutput
, &typIsVarlena
);
379 outputstr
= OidOutputFunctionCall(typoutput
, c
->constvalue
);
380 printf("%s", outputstr
);
383 else if (IsA(expr
, OpExpr
))
385 const OpExpr
*e
= (const OpExpr
*) expr
;
388 opname
= get_opname(e
->opno
);
389 if (list_length(e
->args
) > 1)
391 print_expr(get_leftop((const Expr
*) e
), rtable
);
392 printf(" %s ", ((opname
!= NULL
) ? opname
: "(invalid operator)"));
393 print_expr(get_rightop((const Expr
*) e
), rtable
);
397 printf("%s ", ((opname
!= NULL
) ? opname
: "(invalid operator)"));
398 print_expr(get_leftop((const Expr
*) e
), rtable
);
401 else if (IsA(expr
, FuncExpr
))
403 const FuncExpr
*e
= (const FuncExpr
*) expr
;
407 funcname
= get_func_name(e
->funcid
);
408 printf("%s(", ((funcname
!= NULL
) ? funcname
: "(invalid function)"));
411 print_expr(lfirst(l
), rtable
);
412 if (lnext(e
->args
, l
))
418 printf("unknown expr");
423 * pathkeys list of PathKeys
426 print_pathkeys(const List
*pathkeys
, const List
*rtable
)
433 PathKey
*pathkey
= (PathKey
*) lfirst(i
);
434 EquivalenceClass
*eclass
;
438 eclass
= pathkey
->pk_eclass
;
439 /* chase up, in case pathkey is non-canonical */
440 while (eclass
->ec_merged
)
441 eclass
= eclass
->ec_merged
;
444 foreach(k
, eclass
->ec_members
)
446 EquivalenceMember
*mem
= (EquivalenceMember
*) lfirst(k
);
452 print_expr((Node
*) mem
->em_expr
, rtable
);
455 if (lnext(pathkeys
, i
))
463 * print targetlist in a more legible way.
466 print_tl(const List
*tlist
, const List
*rtable
)
473 TargetEntry
*tle
= (TargetEntry
*) lfirst(tl
);
475 printf("\t%d %s\t", tle
->resno
,
476 tle
->resname
? tle
->resname
: "<null>");
477 if (tle
->ressortgroupref
!= 0)
478 printf("(%u):\t", tle
->ressortgroupref
);
481 print_expr((Node
*) tle
->expr
, rtable
);
489 * print out the tuple with the given TupleTableSlot
492 print_slot(TupleTableSlot
*slot
)
496 printf("tuple is null.\n");
499 if (!slot
->tts_tupleDescriptor
)
501 printf("no tuple descriptor.\n");
505 debugtup(slot
, NULL
);