1 /*-------------------------------------------------------------------------
4 * various print routines (used mostly for debugging)
6 * Portions Copyright (c) 1996-2003, 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.69 2004/06/06 00:41:26 tgl 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;
358 getTypeOutputInfo(c->consttype,
359 &typoutput, &typioparam, &typIsVarlena);
361 outputstr = DatumGetCString(OidFunctionCall3(typoutput,
363 ObjectIdGetDatum(typioparam),
365 printf("%s", outputstr);
368 else if (IsA(expr, OpExpr))
370 OpExpr *e = (OpExpr *) expr;
373 opname = get_opname(e->opno);
374 if (list_length(e->args) > 1)
376 print_expr(get_leftop((Expr *) e), rtable);
377 printf(" %s ", ((opname != NULL) ? opname : "(invalid operator)"));
378 print_expr(get_rightop((Expr *) e), rtable);
382 /* we print prefix and postfix ops the same... */
383 printf("%s ", ((opname != NULL) ? opname : "(invalid operator)"));
384 print_expr(get_leftop((Expr *) e), rtable);
387 else if (IsA(expr, FuncExpr))
389 FuncExpr *e = (FuncExpr *) expr;
393 funcname = get_func_name(e->funcid);
394 printf("%s(", ((funcname != NULL) ? funcname : "(invalid function)"));
397 print_expr(lfirst(l), rtable);
404 printf("unknown expr");
409 * pathkeys list of list of PathKeyItems
412 print_pathkeys(List *pathkeys, List *rtable)
419 List *pathkey = (List *) lfirst(i);
425 PathKeyItem *item = (PathKeyItem *) lfirst(k);
427 print_expr(item->key, rtable);
440 * print targetlist in a more legible way.
443 print_tl(List *tlist, List *rtable)
450 TargetEntry *tle = (TargetEntry *) lfirst(tl);
452 printf("\t%d %s\t", tle->resdom->resno,
453 tle->resdom->resname ? tle->resdom->resname : "<null>");
454 if (tle->resdom->ressortgroupref != 0)
455 printf("(%u):\t", tle->resdom->ressortgroupref);
458 print_expr((Node *) tle->expr, rtable);
466 * print out the tuple with the given TupleTableSlot
469 print_slot(TupleTableSlot *slot)
473 printf("tuple is null.\n");
476 if (!slot->ttc_tupleDescriptor)
478 printf("no tuple descriptor.\n");
482 debugtup(slot->val, slot->ttc_tupleDescriptor, NULL);
486 plannode_type(Plan *p)
505 return "SUBQUERYSCAN";
507 return "FUNCTIONSCAN";
538 * Recursively prints a simple text description of the plan tree
541 print_plan_recursive(Plan *p, Query *parsetree, int indentLevel, char *label)
544 char extraInfo[NAMEDATALEN + 100];
548 for (i = 0; i < indentLevel; i++)
550 printf("%s%s :c=%.2f..%.2f :r=%.0f :w=%d ", label, plannode_type(p),
551 p->startup_cost, p->total_cost,
552 p->plan_rows, p->plan_width);
558 rte = rt_fetch(((Scan *) p)->scanrelid, parsetree->rtable);
559 StrNCpy(extraInfo, rte->eref->aliasname, NAMEDATALEN);
561 else if (IsA(p, IndexScan))
565 rte = rt_fetch(((IndexScan *) p)->scan.scanrelid, parsetree->rtable);
566 StrNCpy(extraInfo, rte->eref->aliasname, NAMEDATALEN);
568 else if (IsA(p, FunctionScan))
572 rte = rt_fetch(((FunctionScan *) p)->scan.scanrelid, parsetree->rtable);
573 StrNCpy(extraInfo, rte->eref->aliasname, NAMEDATALEN);
577 if (extraInfo[0] != '\0')
578 printf(" ( %s )\n", extraInfo);
581 print_plan_recursive(p->lefttree, parsetree, indentLevel + 3, "l: ");
582 print_plan_recursive(p->righttree, parsetree, indentLevel + 3, "r: ");
588 Append *appendplan = (Append *) p;
590 foreach(l, appendplan->appendplans)
592 Plan *subnode = (Plan *) lfirst(l);
595 * I don't think we need to fiddle with the range table here,
598 print_plan_recursive(subnode, parsetree, indentLevel + 3, "a: ");
606 prints just the plan node types */
609 print_plan(Plan *p, Query *parsetree)
611 print_plan_recursive(p, parsetree, 0, "");