1 /*-------------------------------------------------------------------------
4 * various print routines (used mostly for debugging)
6 * Portions Copyright (c) 1996-2011, 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/print.h"
25 #include "optimizer/clauses.h"
26 #include "parser/parsetree.h"
27 #include "utils/lsyscache.h"
28 #include "utils/rel.h"
33 * print contents of Node to stdout
41 s = nodeToString(obj);
42 f = format_node_dump(s);
51 * pretty-print contents of Node to stdout
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, 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(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[values list]",
285 i, rte->eref->aliasname);
288 printf("%d\t%s\t[cte]",
289 i, rte->eref->aliasname);
292 printf("%d\t%s\t[unknown rtekind]",
293 i, rte->eref->aliasname);
297 (rte->inh ? "inh" : ""),
298 (rte->inFromCl ? "inFromCl" : ""));
306 * print an expression
309 print_expr(Node *expr, List *rtable)
319 Var *var = (Var *) expr;
337 Assert(var->varno > 0 &&
338 (int) var->varno <= list_length(rtable));
339 rte = rt_fetch(var->varno, rtable);
340 relname = rte->eref->aliasname;
341 attname = get_rte_attribute_name(rte, var->varattno);
345 printf("%s.%s", relname, attname);
347 else if (IsA(expr, Const))
349 Const *c = (Const *) expr;
360 getTypeOutputInfo(c->consttype,
361 &typoutput, &typIsVarlena);
363 outputstr = OidOutputFunctionCall(typoutput, c->constvalue);
364 printf("%s", outputstr);
367 else if (IsA(expr, OpExpr))
369 OpExpr *e = (OpExpr *) expr;
372 opname = get_opname(e->opno);
373 if (list_length(e->args) > 1)
375 print_expr(get_leftop((Expr *) e), rtable);
376 printf(" %s ", ((opname != NULL) ? opname : "(invalid operator)"));
377 print_expr(get_rightop((Expr *) e), rtable);
381 /* we print prefix and postfix ops the same... */
382 printf("%s ", ((opname != NULL) ? opname : "(invalid operator)"));
383 print_expr(get_leftop((Expr *) e), rtable);
386 else if (IsA(expr, FuncExpr))
388 FuncExpr *e = (FuncExpr *) expr;
392 funcname = get_func_name(e->funcid);
393 printf("%s(", ((funcname != NULL) ? funcname : "(invalid function)"));
396 print_expr(lfirst(l), rtable);
403 printf("unknown expr");
408 * pathkeys list of PathKeys
411 print_pathkeys(List *pathkeys, List *rtable)
418 PathKey *pathkey = (PathKey *) lfirst(i);
419 EquivalenceClass *eclass;
423 eclass = pathkey->pk_eclass;
424 /* chase up, in case pathkey is non-canonical */
425 while (eclass->ec_merged)
426 eclass = eclass->ec_merged;
429 foreach(k, eclass->ec_members)
431 EquivalenceMember *mem = (EquivalenceMember *) lfirst(k);
437 print_expr((Node *) mem->em_expr, rtable);
448 * print targetlist in a more legible way.
451 print_tl(List *tlist, List *rtable)
458 TargetEntry *tle = (TargetEntry *) lfirst(tl);
460 printf("\t%d %s\t", tle->resno,
461 tle->resname ? tle->resname : "<null>");
462 if (tle->ressortgroupref != 0)
463 printf("(%u):\t", tle->ressortgroupref);
466 print_expr((Node *) tle->expr, rtable);
474 * print out the tuple with the given TupleTableSlot
477 print_slot(TupleTableSlot *slot)
481 printf("tuple is null.\n");
484 if (!slot->tts_tupleDescriptor)
486 printf("no tuple descriptor.\n");
490 debugtup(slot, NULL);