1 /*-------------------------------------------------------------------------
4 * various print routines (used mostly for debugging)
6 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.52 2002/03/21 16:00:41 tgl Exp $
14 * AUTHOR DATE MAJOR EVENT
15 * Andrew Yu Oct 26, 1994 file creation
17 *-------------------------------------------------------------------------
22 #include "access/printtup.h"
23 #include "catalog/pg_type.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
41 s = nodeToString(obj);
48 * pretty print hack extraordinaire. -ay 10/94
63 s = nodeToString(obj);
65 indentLev = 0; /* logical indent level */
66 indentDist = 0; /* physical indent distance */
70 for (j = 0; j < indentDist; j++)
72 for (; j < LINELEN-1 && s[i] != '\0'; i++, j++)
80 /* print data before the } */
84 /* print the } at indentDist */
85 line[indentDist] = '\0';
86 printf("%s}\n", line);
91 indentDist = Min(indentLev * INDENTSTOP, MAXINDENT);
94 /* j will equal indentDist on next loop iteration */
97 /* force line break after ')' */
103 /* force line break before { */
107 printf("%s\n", line);
111 indentDist = Min(indentLev * INDENTSTOP, MAXINDENT);
112 for (j = 0; j < indentDist; j++)
117 /* force line break before : */
121 printf("%s\n", line);
131 printf("%s\n", line);
134 printf("%s\n", line);
141 * print contents of range table
144 print_rt(List *rtable)
149 printf("resno\trelname(refname)\trelid\tinFromCl\n");
150 printf("-----\t----------------\t-----\t--------\n");
153 RangeTblEntry *rte = lfirst(l);
156 printf("%d\t%s (%s)\t%u",
157 i, rte->relname, rte->eref->aliasname, rte->relid);
159 printf("%d\t[subquery] (%s)\t",
160 i, rte->eref->aliasname);
162 (rte->inh ? "inh" : ""),
163 (rte->inFromCl ? "inFromCl" : ""));
171 * print an expression
174 print_expr(Node *expr, List *rtable)
184 Var *var = (Var *) expr;
202 Assert(var->varno > 0 &&
203 (int) var->varno <= length(rtable));
204 rte = rt_fetch(var->varno, rtable);
205 relname = rte->eref->aliasname;
206 attname = get_rte_attribute_name(rte, var->varattno);
210 printf("%s.%s", relname, attname);
212 else if (IsA(expr, Const))
214 Const *c = (Const *) expr;
226 typeTup = SearchSysCache(TYPEOID,
227 ObjectIdGetDatum(c->consttype),
229 if (!HeapTupleIsValid(typeTup))
230 elog(ERROR, "Cache lookup for type %u failed", c->consttype);
231 typoutput = ((Form_pg_type) GETSTRUCT(typeTup))->typoutput;
232 typelem = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;
233 ReleaseSysCache(typeTup);
235 outputstr = DatumGetCString(OidFunctionCall3(typoutput,
237 ObjectIdGetDatum(typelem),
239 printf("%s", outputstr);
242 else if (IsA(expr, Expr))
244 Expr *e = (Expr *) expr;
246 if (is_opclause(expr))
250 print_expr((Node *) get_leftop(e), rtable);
251 opname = get_opname(((Oper *) e->oper)->opno);
252 printf(" %s ", ((opname != NULL) ? opname : "(invalid operator)"));
253 print_expr((Node *) get_rightop(e), rtable);
259 printf("not an expr");
264 * pathkeys list of list of PathKeyItems
267 print_pathkeys(List *pathkeys, List *rtable)
275 List *pathkey = lfirst(i);
280 PathKeyItem *item = lfirst(k);
282 print_expr(item->key, rtable);
295 * print targetlist in a more legible way.
298 print_tl(List *tlist, List *rtable)
305 TargetEntry *tle = lfirst(tl);
307 printf("\t%d %s\t", tle->resdom->resno, tle->resdom->resname);
308 if (tle->resdom->reskey != 0)
309 printf("(%d):\t", tle->resdom->reskey);
312 print_expr(tle->expr, rtable);
320 * print out the tuple with the given TupleTableSlot
323 print_slot(TupleTableSlot *slot)
327 printf("tuple is null.\n");
330 if (!slot->ttc_tupleDescriptor)
332 printf("no tuple descriptor.\n");
336 debugtup(slot->val, slot->ttc_tupleDescriptor, NULL);
340 plannode_type(Plan *p)
359 return "SUBQUERYSCAN";
390 prints the ascii description of the plan nodes
391 does this recursively by doing a depth-first traversal of the
392 plan tree. for SeqScan and IndexScan, the name of the table is also
397 print_plan_recursive(Plan *p, Query *parsetree, int indentLevel, char *label)
400 char extraInfo[NAMEDATALEN + 100];
404 for (i = 0; i < indentLevel; i++)
406 printf("%s%s :c=%.2f..%.2f :r=%.0f :w=%d ", label, plannode_type(p),
407 p->startup_cost, p->total_cost,
408 p->plan_rows, p->plan_width);
409 if (IsA(p, Scan) ||IsA(p, SeqScan))
413 rte = rt_fetch(((Scan *) p)->scanrelid, parsetree->rtable);
414 StrNCpy(extraInfo, rte->relname, NAMEDATALEN);
416 else if (IsA(p, IndexScan))
420 rte = rt_fetch(((IndexScan *) p)->scan.scanrelid, parsetree->rtable);
421 StrNCpy(extraInfo, rte->relname, NAMEDATALEN);
425 if (extraInfo[0] != '\0')
426 printf(" ( %s )\n", extraInfo);
429 print_plan_recursive(p->lefttree, parsetree, indentLevel + 3, "l: ");
430 print_plan_recursive(p->righttree, parsetree, indentLevel + 3, "r: ");
436 Append *appendplan = (Append *) p;
438 foreach(lst, appendplan->appendplans)
440 Plan *subnode = (Plan *) lfirst(lst);
443 * I don't think we need to fiddle with the range table here,
446 print_plan_recursive(subnode, parsetree, indentLevel + 3, "a: ");
454 prints just the plan node types */
457 print_plan(Plan *p, Query *parsetree)
459 print_plan_recursive(p, parsetree, 0, "");