1 /*-------------------------------------------------------------------------
4 * various print routines (used mostly for debugging)
6 * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/nodes/print.c,v 1.86 2007/11/15 21:14:35 momjian Exp $
14 * AUTHOR DATE MAJOR EVENT
15 * Andrew Yu Oct 26, 1994 file creation
17 *-------------------------------------------------------------------------
22 #include "access/printtup.h"
23 #include "nodes/print.h"
24 #include "optimizer/clauses.h"
25 #include "parser/parsetree.h"
26 #include "utils/lsyscache.h"
31 * print contents of Node to stdout
39 s = nodeToString(obj);
40 f = format_node_dump(s);
49 * pretty-print contents of Node to stdout
57 s = nodeToString(obj);
58 f = pretty_format_node_dump(s);
67 * send pretty-printed contents of Node to postmaster log
70 elog_node_display(int lev, const char *title, void *obj, bool pretty)
75 s = nodeToString(obj);
77 f = pretty_format_node_dump(s);
79 f = format_node_dump(s);
82 (errmsg_internal("%s:", title),
88 * Format a nodeToString output for display on a terminal.
90 * The result is a palloc'd string.
92 * This version just tries to break at whitespace.
95 format_node_dump(const char *dump)
98 char line[LINELEN + 1];
104 initStringInfo(&str);
108 for (j = 0; j < LINELEN && dump[i] != '\0'; i++, j++)
114 /* ok to break at adjacent space */
119 for (k = j - 1; k > 0; k--)
124 /* back up; will reprint all after space */
130 appendStringInfo(&str, "%s\n", line);
135 appendStringInfo(&str, "%s\n", line);
142 * Format a nodeToString output for display on a terminal.
144 * The result is a palloc'd string.
146 * This version tries to indent intelligently.
149 pretty_format_node_dump(const char *dump)
154 char line[LINELEN + 1];
161 initStringInfo(&str);
162 indentLev = 0; /* logical indent level */
163 indentDist = 0; /* physical indent distance */
167 for (j = 0; j < indentDist; j++)
169 for (; j < LINELEN && dump[i] != '\0'; i++, j++)
177 /* print data before the } */
179 appendStringInfo(&str, "%s\n", line);
181 /* print the } at indentDist */
182 line[indentDist] = '}';
183 line[indentDist + 1] = '\0';
184 appendStringInfo(&str, "%s\n", line);
189 indentDist = Min(indentLev * INDENTSTOP, MAXINDENT);
192 /* j will equal indentDist on next loop iteration */
193 /* suppress whitespace just after } */
194 while (dump[i + 1] == ' ')
198 /* force line break after ), unless another ) follows */
199 if (dump[i + 1] != ')')
202 appendStringInfo(&str, "%s\n", line);
204 while (dump[i + 1] == ' ')
209 /* force line break before { */
213 appendStringInfo(&str, "%s\n", line);
217 indentDist = Min(indentLev * INDENTSTOP, MAXINDENT);
218 for (j = 0; j < indentDist; j++)
223 /* force line break before : */
227 appendStringInfo(&str, "%s\n", line);
237 appendStringInfo(&str, "%s\n", line);
240 appendStringInfo(&str, "%s\n", line);
249 * print contents of range table
252 print_rt(List *rtable)
257 printf("resno\trefname \trelid\tinFromCl\n");
258 printf("-----\t---------\t-----\t--------\n");
261 RangeTblEntry *rte = lfirst(l);
263 switch (rte->rtekind)
267 i, rte->eref->aliasname, rte->relid);
270 printf("%d\t%s\t[subquery]",
271 i, rte->eref->aliasname);
274 printf("%d\t%s\t[rangefunction]",
275 i, rte->eref->aliasname);
278 printf("%d\t%s\t[values list]",
279 i, rte->eref->aliasname);
282 printf("%d\t%s\t[join]",
283 i, rte->eref->aliasname);
286 printf("%d\t%s\t[special]",
287 i, rte->eref->aliasname);
290 printf("%d\t%s\t[unknown rtekind]",
291 i, rte->eref->aliasname);
295 (rte->inh ? "inh" : ""),
296 (rte->inFromCl ? "inFromCl" : ""));
304 * print an expression
307 print_expr(Node *expr, List *rtable)
317 Var *var = (Var *) expr;
335 Assert(var->varno > 0 &&
336 (int) var->varno <= list_length(rtable));
337 rte = rt_fetch(var->varno, rtable);
338 relname = rte->eref->aliasname;
339 attname = get_rte_attribute_name(rte, var->varattno);
343 printf("%s.%s", relname, attname);
345 else if (IsA(expr, Const))
347 Const *c = (Const *) expr;
358 getTypeOutputInfo(c->consttype,
359 &typoutput, &typIsVarlena);
361 outputstr = OidOutputFunctionCall(typoutput, c->constvalue);
362 printf("%s", outputstr);
365 else if (IsA(expr, OpExpr))
367 OpExpr *e = (OpExpr *) expr;
370 opname = get_opname(e->opno);
371 if (list_length(e->args) > 1)
373 print_expr(get_leftop((Expr *) e), rtable);
374 printf(" %s ", ((opname != NULL) ? opname : "(invalid operator)"));
375 print_expr(get_rightop((Expr *) e), rtable);
379 /* we print prefix and postfix ops the same... */
380 printf("%s ", ((opname != NULL) ? opname : "(invalid operator)"));
381 print_expr(get_leftop((Expr *) e), rtable);
384 else if (IsA(expr, FuncExpr))
386 FuncExpr *e = (FuncExpr *) expr;
390 funcname = get_func_name(e->funcid);
391 printf("%s(", ((funcname != NULL) ? funcname : "(invalid function)"));
394 print_expr(lfirst(l), rtable);
401 printf("unknown expr");
406 * pathkeys list of PathKeys
409 print_pathkeys(List *pathkeys, List *rtable)
416 PathKey *pathkey = (PathKey *) lfirst(i);
417 EquivalenceClass *eclass;
421 eclass = pathkey->pk_eclass;
422 /* chase up, in case pathkey is non-canonical */
423 while (eclass->ec_merged)
424 eclass = eclass->ec_merged;
427 foreach(k, eclass->ec_members)
429 EquivalenceMember *mem = (EquivalenceMember *) lfirst(k);
435 print_expr((Node *) mem->em_expr, rtable);
446 * print targetlist in a more legible way.
449 print_tl(List *tlist, List *rtable)
456 TargetEntry *tle = (TargetEntry *) lfirst(tl);
458 printf("\t%d %s\t", tle->resno,
459 tle->resname ? tle->resname : "<null>");
460 if (tle->ressortgroupref != 0)
461 printf("(%u):\t", tle->ressortgroupref);
464 print_expr((Node *) tle->expr, rtable);
472 * print out the tuple with the given TupleTableSlot
475 print_slot(TupleTableSlot *slot)
479 printf("tuple is null.\n");
482 if (!slot->tts_tupleDescriptor)
484 printf("no tuple descriptor.\n");
488 debugtup(slot, NULL);