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.83 2007/01/20 20:45:38 tgl 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"
28 static char *plannode_type(Plan *p);
32 * print contents of Node to stdout
40 s = nodeToString(obj);
41 f = format_node_dump(s);
50 * pretty-print contents of Node to stdout
58 s = nodeToString(obj);
59 f = pretty_format_node_dump(s);
68 * send pretty-printed contents of Node to postmaster log
71 elog_node_display(int lev, const char *title, void *obj, bool pretty)
76 s = nodeToString(obj);
78 f = pretty_format_node_dump(s);
80 f = format_node_dump(s);
83 (errmsg_internal("%s:", title),
89 * Format a nodeToString output for display on a terminal.
91 * The result is a palloc'd string.
93 * This version just tries to break at whitespace.
96 format_node_dump(const char *dump)
99 char line[LINELEN + 1];
105 initStringInfo(&str);
109 for (j = 0; j < LINELEN && dump[i] != '\0'; i++, j++)
115 /* ok to break at adjacent space */
120 for (k = j - 1; k > 0; k--)
125 /* back up; will reprint all after space */
131 appendStringInfo(&str, "%s\n", line);
136 appendStringInfo(&str, "%s\n", line);
143 * Format a nodeToString output for display on a terminal.
145 * The result is a palloc'd string.
147 * This version tries to indent intelligently.
150 pretty_format_node_dump(const char *dump)
155 char line[LINELEN + 1];
162 initStringInfo(&str);
163 indentLev = 0; /* logical indent level */
164 indentDist = 0; /* physical indent distance */
168 for (j = 0; j < indentDist; j++)
170 for (; j < LINELEN && dump[i] != '\0'; i++, j++)
178 /* print data before the } */
180 appendStringInfo(&str, "%s\n", line);
182 /* print the } at indentDist */
183 line[indentDist] = '}';
184 line[indentDist + 1] = '\0';
185 appendStringInfo(&str, "%s\n", line);
190 indentDist = Min(indentLev * INDENTSTOP, MAXINDENT);
193 /* j will equal indentDist on next loop iteration */
194 /* suppress whitespace just after } */
195 while (dump[i + 1] == ' ')
199 /* force line break after ), unless another ) follows */
200 if (dump[i + 1] != ')')
203 appendStringInfo(&str, "%s\n", line);
205 while (dump[i + 1] == ' ')
210 /* force line break before { */
214 appendStringInfo(&str, "%s\n", line);
218 indentDist = Min(indentLev * INDENTSTOP, MAXINDENT);
219 for (j = 0; j < indentDist; j++)
224 /* force line break before : */
228 appendStringInfo(&str, "%s\n", line);
238 appendStringInfo(&str, "%s\n", line);
241 appendStringInfo(&str, "%s\n", line);
250 * print contents of range table
253 print_rt(List *rtable)
258 printf("resno\trefname \trelid\tinFromCl\n");
259 printf("-----\t---------\t-----\t--------\n");
262 RangeTblEntry *rte = lfirst(l);
264 switch (rte->rtekind)
268 i, rte->eref->aliasname, rte->relid);
271 printf("%d\t%s\t[subquery]",
272 i, rte->eref->aliasname);
275 printf("%d\t%s\t[rangefunction]",
276 i, rte->eref->aliasname);
279 printf("%d\t%s\t[values list]",
280 i, rte->eref->aliasname);
283 printf("%d\t%s\t[join]",
284 i, rte->eref->aliasname);
287 printf("%d\t%s\t[special]",
288 i, rte->eref->aliasname);
291 printf("%d\t%s\t[unknown rtekind]",
292 i, rte->eref->aliasname);
296 (rte->inh ? "inh" : ""),
297 (rte->inFromCl ? "inFromCl" : ""));
305 * print an expression
308 print_expr(Node *expr, List *rtable)
318 Var *var = (Var *) expr;
336 Assert(var->varno > 0 &&
337 (int) var->varno <= list_length(rtable));
338 rte = rt_fetch(var->varno, rtable);
339 relname = rte->eref->aliasname;
340 attname = get_rte_attribute_name(rte, var->varattno);
344 printf("%s.%s", relname, attname);
346 else if (IsA(expr, Const))
348 Const *c = (Const *) expr;
359 getTypeOutputInfo(c->consttype,
360 &typoutput, &typIsVarlena);
362 outputstr = OidOutputFunctionCall(typoutput, c->constvalue);
363 printf("%s", outputstr);
366 else if (IsA(expr, OpExpr))
368 OpExpr *e = (OpExpr *) expr;
371 opname = get_opname(e->opno);
372 if (list_length(e->args) > 1)
374 print_expr(get_leftop((Expr *) e), rtable);
375 printf(" %s ", ((opname != NULL) ? opname : "(invalid operator)"));
376 print_expr(get_rightop((Expr *) e), rtable);
380 /* we print prefix and postfix ops the same... */
381 printf("%s ", ((opname != NULL) ? opname : "(invalid operator)"));
382 print_expr(get_leftop((Expr *) e), rtable);
385 else if (IsA(expr, FuncExpr))
387 FuncExpr *e = (FuncExpr *) expr;
391 funcname = get_func_name(e->funcid);
392 printf("%s(", ((funcname != NULL) ? funcname : "(invalid function)"));
395 print_expr(lfirst(l), rtable);
402 printf("unknown expr");
407 * pathkeys list of PathKeys
410 print_pathkeys(List *pathkeys, List *rtable)
417 PathKey *pathkey = (PathKey *) lfirst(i);
418 EquivalenceClass *eclass;
422 eclass = pathkey->pk_eclass;
423 /* chase up, in case pathkey is non-canonical */
424 while (eclass->ec_merged)
425 eclass = eclass->ec_merged;
428 foreach(k, eclass->ec_members)
430 EquivalenceMember *mem = (EquivalenceMember *) lfirst(k);
436 print_expr((Node *) mem->em_expr, rtable);
447 * print targetlist in a more legible way.
450 print_tl(List *tlist, List *rtable)
457 TargetEntry *tle = (TargetEntry *) lfirst(tl);
459 printf("\t%d %s\t", tle->resno,
460 tle->resname ? tle->resname : "<null>");
461 if (tle->ressortgroupref != 0)
462 printf("(%u):\t", tle->ressortgroupref);
465 print_expr((Node *) tle->expr, rtable);
473 * print out the tuple with the given TupleTableSlot
476 print_slot(TupleTableSlot *slot)
480 printf("tuple is null.\n");
483 if (!slot->tts_tupleDescriptor)
485 printf("no tuple descriptor.\n");
489 debugtup(slot, NULL);
493 plannode_type(Plan *p)
513 case T_BitmapIndexScan:
514 return "BITMAPINDEXSCAN";
515 case T_BitmapHeapScan:
516 return "BITMAPHEAPSCAN";
520 return "SUBQUERYSCAN";
522 return "FUNCTIONSCAN";
555 * Recursively prints a simple text description of the plan tree
558 print_plan_recursive(Plan *p, Query *parsetree, int indentLevel, char *label)
561 char extraInfo[NAMEDATALEN + 100];
565 for (i = 0; i < indentLevel; i++)
567 printf("%s%s :c=%.2f..%.2f :r=%.0f :w=%d ", label, plannode_type(p),
568 p->startup_cost, p->total_cost,
569 p->plan_rows, p->plan_width);
572 IsA(p, BitmapHeapScan))
576 rte = rt_fetch(((Scan *) p)->scanrelid, parsetree->rtable);
577 StrNCpy(extraInfo, rte->eref->aliasname, NAMEDATALEN);
579 else if (IsA(p, IndexScan))
583 rte = rt_fetch(((IndexScan *) p)->scan.scanrelid, parsetree->rtable);
584 StrNCpy(extraInfo, rte->eref->aliasname, NAMEDATALEN);
586 else if (IsA(p, FunctionScan))
590 rte = rt_fetch(((FunctionScan *) p)->scan.scanrelid, parsetree->rtable);
591 StrNCpy(extraInfo, rte->eref->aliasname, NAMEDATALEN);
593 else if (IsA(p, ValuesScan))
597 rte = rt_fetch(((ValuesScan *) p)->scan.scanrelid, parsetree->rtable);
598 StrNCpy(extraInfo, rte->eref->aliasname, NAMEDATALEN);
602 if (extraInfo[0] != '\0')
603 printf(" ( %s )\n", extraInfo);
606 print_plan_recursive(p->lefttree, parsetree, indentLevel + 3, "l: ");
607 print_plan_recursive(p->righttree, parsetree, indentLevel + 3, "r: ");
612 Append *appendplan = (Append *) p;
614 foreach(l, appendplan->appendplans)
616 Plan *subnode = (Plan *) lfirst(l);
618 print_plan_recursive(subnode, parsetree, indentLevel + 3, "a: ");
622 if (IsA(p, BitmapAnd))
625 BitmapAnd *bitmapandplan = (BitmapAnd *) p;
627 foreach(l, bitmapandplan->bitmapplans)
629 Plan *subnode = (Plan *) lfirst(l);
631 print_plan_recursive(subnode, parsetree, indentLevel + 3, "a: ");
635 if (IsA(p, BitmapOr))
638 BitmapOr *bitmaporplan = (BitmapOr *) p;
640 foreach(l, bitmaporplan->bitmapplans)
642 Plan *subnode = (Plan *) lfirst(l);
644 print_plan_recursive(subnode, parsetree, indentLevel + 3, "a: ");
652 * prints just the plan node types
655 print_plan(Plan *p, Query *parsetree)
657 print_plan_recursive(p, parsetree, 0, "");