1 /*-------------------------------------------------------------------------
4 * various print routines (used mostly for debugging)
6 * Portions Copyright (c) 1996-2006, 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.78 2006/03/05 15:58:28 momjian Exp $
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/syscache.h"
30 static char *plannode_type(Plan *p);
34 * print contents of Node to stdout
42 s = nodeToString(obj);
43 f = format_node_dump(s);
52 * pretty-print contents of Node to stdout
60 s = nodeToString(obj);
61 f = pretty_format_node_dump(s);
70 * send pretty-printed contents of Node to postmaster log
73 elog_node_display(int lev, const char *title, void *obj, bool pretty)
78 s = nodeToString(obj);
80 f = pretty_format_node_dump(s);
82 f = format_node_dump(s);
85 (errmsg_internal("%s:", title),
91 * Format a nodeToString output for display on a terminal.
93 * The result is a palloc'd string.
95 * This version just tries to break at whitespace.
98 format_node_dump(const char *dump)
101 char line[LINELEN + 1];
107 initStringInfo(&str);
111 for (j = 0; j < LINELEN && dump[i] != '\0'; i++, j++)
117 /* ok to break at adjacent space */
122 for (k = j - 1; k > 0; k--)
127 /* back up; will reprint all after space */
133 appendStringInfo(&str, "%s\n", line);
138 appendStringInfo(&str, "%s\n", line);
145 * Format a nodeToString output for display on a terminal.
147 * The result is a palloc'd string.
149 * This version tries to indent intelligently.
152 pretty_format_node_dump(const char *dump)
157 char line[LINELEN + 1];
164 initStringInfo(&str);
165 indentLev = 0; /* logical indent level */
166 indentDist = 0; /* physical indent distance */
170 for (j = 0; j < indentDist; j++)
172 for (; j < LINELEN && dump[i] != '\0'; i++, j++)
180 /* print data before the } */
182 appendStringInfo(&str, "%s\n", line);
184 /* print the } at indentDist */
185 line[indentDist] = '}';
186 line[indentDist + 1] = '\0';
187 appendStringInfo(&str, "%s\n", line);
192 indentDist = Min(indentLev * INDENTSTOP, MAXINDENT);
195 /* j will equal indentDist on next loop iteration */
196 /* suppress whitespace just after } */
197 while (dump[i + 1] == ' ')
201 /* force line break after ), unless another ) follows */
202 if (dump[i + 1] != ')')
205 appendStringInfo(&str, "%s\n", line);
207 while (dump[i + 1] == ' ')
212 /* force line break before { */
216 appendStringInfo(&str, "%s\n", line);
220 indentDist = Min(indentLev * INDENTSTOP, MAXINDENT);
221 for (j = 0; j < indentDist; j++)
226 /* force line break before : */
230 appendStringInfo(&str, "%s\n", line);
240 appendStringInfo(&str, "%s\n", line);
243 appendStringInfo(&str, "%s\n", line);
252 * print contents of range table
255 print_rt(List *rtable)
260 printf("resno\trefname \trelid\tinFromCl\n");
261 printf("-----\t---------\t-----\t--------\n");
264 RangeTblEntry *rte = lfirst(l);
266 switch (rte->rtekind)
270 i, rte->eref->aliasname, rte->relid);
273 printf("%d\t%s\t[subquery]",
274 i, rte->eref->aliasname);
277 printf("%d\t%s\t[rangefunction]",
278 i, rte->eref->aliasname);
281 printf("%d\t%s\t[join]",
282 i, rte->eref->aliasname);
285 printf("%d\t%s\t[special]",
286 i, rte->eref->aliasname);
289 printf("%d\t%s\t[unknown rtekind]",
290 i, rte->eref->aliasname);
294 (rte->inh ? "inh" : ""),
295 (rte->inFromCl ? "inFromCl" : ""));
303 * print an expression
306 print_expr(Node *expr, List *rtable)
316 Var *var = (Var *) expr;
334 Assert(var->varno > 0 &&
335 (int) var->varno <= list_length(rtable));
336 rte = rt_fetch(var->varno, rtable);
337 relname = rte->eref->aliasname;
338 attname = get_rte_attribute_name(rte, var->varattno);
342 printf("%s.%s", relname, attname);
344 else if (IsA(expr, Const))
346 Const *c = (Const *) expr;
357 getTypeOutputInfo(c->consttype,
358 &typoutput, &typIsVarlena);
360 outputstr = DatumGetCString(OidFunctionCall1(typoutput,
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 list of PathKeyItems
409 print_pathkeys(List *pathkeys, List *rtable)
416 List *pathkey = (List *) lfirst(i);
422 PathKeyItem *item = (PathKeyItem *) lfirst(k);
424 print_expr(item->key, rtable);
437 * print targetlist in a more legible way.
440 print_tl(List *tlist, List *rtable)
447 TargetEntry *tle = (TargetEntry *) lfirst(tl);
449 printf("\t%d %s\t", tle->resno,
450 tle->resname ? tle->resname : "<null>");
451 if (tle->ressortgroupref != 0)
452 printf("(%u):\t", tle->ressortgroupref);
455 print_expr((Node *) tle->expr, rtable);
463 * print out the tuple with the given TupleTableSlot
466 print_slot(TupleTableSlot *slot)
470 printf("tuple is null.\n");
473 if (!slot->tts_tupleDescriptor)
475 printf("no tuple descriptor.\n");
479 debugtup(slot, NULL);
483 plannode_type(Plan *p)
503 case T_BitmapIndexScan:
504 return "BITMAPINDEXSCAN";
505 case T_BitmapHeapScan:
506 return "BITMAPHEAPSCAN";
510 return "SUBQUERYSCAN";
512 return "FUNCTIONSCAN";
543 * Recursively prints a simple text description of the plan tree
546 print_plan_recursive(Plan *p, Query *parsetree, int indentLevel, char *label)
549 char extraInfo[NAMEDATALEN + 100];
553 for (i = 0; i < indentLevel; i++)
555 printf("%s%s :c=%.2f..%.2f :r=%.0f :w=%d ", label, plannode_type(p),
556 p->startup_cost, p->total_cost,
557 p->plan_rows, p->plan_width);
560 IsA(p, BitmapHeapScan))
564 rte = rt_fetch(((Scan *) p)->scanrelid, parsetree->rtable);
565 StrNCpy(extraInfo, rte->eref->aliasname, NAMEDATALEN);
567 else if (IsA(p, IndexScan))
571 rte = rt_fetch(((IndexScan *) p)->scan.scanrelid, parsetree->rtable);
572 StrNCpy(extraInfo, rte->eref->aliasname, NAMEDATALEN);
574 else if (IsA(p, FunctionScan))
578 rte = rt_fetch(((FunctionScan *) p)->scan.scanrelid, parsetree->rtable);
579 StrNCpy(extraInfo, rte->eref->aliasname, NAMEDATALEN);
583 if (extraInfo[0] != '\0')
584 printf(" ( %s )\n", extraInfo);
587 print_plan_recursive(p->lefttree, parsetree, indentLevel + 3, "l: ");
588 print_plan_recursive(p->righttree, parsetree, indentLevel + 3, "r: ");
593 Append *appendplan = (Append *) p;
595 foreach(l, appendplan->appendplans)
597 Plan *subnode = (Plan *) lfirst(l);
599 print_plan_recursive(subnode, parsetree, indentLevel + 3, "a: ");
603 if (IsA(p, BitmapAnd))
606 BitmapAnd *bitmapandplan = (BitmapAnd *) p;
608 foreach(l, bitmapandplan->bitmapplans)
610 Plan *subnode = (Plan *) lfirst(l);
612 print_plan_recursive(subnode, parsetree, indentLevel + 3, "a: ");
616 if (IsA(p, BitmapOr))
619 BitmapOr *bitmaporplan = (BitmapOr *) p;
621 foreach(l, bitmaporplan->bitmapplans)
623 Plan *subnode = (Plan *) lfirst(l);
625 print_plan_recursive(subnode, parsetree, indentLevel + 3, "a: ");
633 * prints just the plan node types
636 print_plan(Plan *p, Query *parsetree)
638 print_plan_recursive(p, parsetree, 0, "");