]> granicus.if.org Git - postgresql/blob - src/backend/nodes/print.c
MIN() -> Min, fixes compile problem.
[postgresql] / src / backend / nodes / print.c
1 /*-------------------------------------------------------------------------
2  *
3  * print.c
4  *        various print routines (used mostly for debugging)
5  *
6  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.51 2001/12/20 02:39:26 momjian Exp $
12  *
13  * HISTORY
14  *        AUTHOR                        DATE                    MAJOR EVENT
15  *        Andrew Yu                     Oct 26, 1994    file creation
16  *
17  *-------------------------------------------------------------------------
18  */
19
20 #include "postgres.h"
21
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"
29
30 static char *plannode_type(Plan *p);
31
32 /*
33  * print
34  *        print contents of Node to stdout
35  */
36 void
37 print(void *obj)
38 {
39         char       *s;
40
41         s = nodeToString(obj);
42         printf("%s\n", s);
43         fflush(stdout);
44         pfree(s);
45 }
46
47 /*
48  * pretty print hack extraordinaire.  -ay 10/94
49  */
50 void
51 pprint(void *obj)
52 {
53 #define INDENTSTOP      3
54 #define MAXINDENT       60
55 #define LINELEN         80
56         char       *s;
57         int                     i;
58         char            line[LINELEN];
59         int                     indentLev;
60         int                     indentDist;
61         int                     j;
62
63         s = nodeToString(obj);
64
65         indentLev = 0;                          /* logical indent level */
66         indentDist = 0;                         /* physical indent distance */
67         i = 0;
68         for (;;)
69         {
70                 for (j = 0; j < indentDist; j++)
71                         line[j] = ' ';
72                 for (; j < LINELEN-1 && s[i] != '\0'; i++, j++)
73                 {
74                         line[j] = s[i];
75                         switch (line[j])
76                         {
77                                 case '}':
78                                         if (j != indentDist)
79                                         {
80                                                 /* print data before the } */
81                                                 line[j] = '\0';
82                                                 printf("%s\n", line);
83                                         }
84                                         /* print the } at indentDist */
85                                         line[indentDist] = '\0';
86                                         printf("%s}\n", line);
87                                         /* outdent */
88                                         if (indentLev > 0)
89                                         {
90                                                 indentLev--;
91                                                 indentDist = Min(indentLev * INDENTSTOP, MAXINDENT);
92                                         }
93                                         j = indentDist - 1;
94                                         /* j will equal indentDist on next loop iteration */
95                                         break;
96                                 case ')':
97                                         /* force line break after ')' */
98                                         line[j + 1] = '\0';
99                                         printf("%s\n", line);
100                                         j = indentDist - 1;
101                                         break;
102                                 case '{':
103                                         /* force line break before { */
104                                         if (j != indentDist)
105                                         {
106                                                 line[j] = '\0';
107                                                 printf("%s\n", line);
108                                         }
109                                         /* indent */
110                                         indentLev++;
111                                         indentDist = Min(indentLev * INDENTSTOP, MAXINDENT);
112                                         for (j = 0; j < indentDist; j++)
113                                                 line[j] = ' ';
114                                         line[j] = s[i];
115                                         break;
116                                 case ':':
117                                         /* force line break before : */
118                                         if (j != indentDist)
119                                         {
120                                                 line[j] = '\0';
121                                                 printf("%s\n", line);
122                                         }
123                                         j = indentDist;
124                                         line[j] = s[i];
125                                         break;
126                         }
127                 }
128                 line[j] = '\0';
129                 if (s[i] == '\0')
130                         break;
131                 printf("%s\n", line);
132         }
133         if (j != 0)
134                 printf("%s\n", line);
135         fflush(stdout);
136         pfree(s);
137 }
138
139 /*
140  * print_rt
141  *        print contents of range table
142  */
143 void
144 print_rt(List *rtable)
145 {
146         List       *l;
147         int                     i = 1;
148
149         printf("resno\trelname(refname)\trelid\tinFromCl\n");
150         printf("-----\t----------------\t-----\t--------\n");
151         foreach(l, rtable)
152         {
153                 RangeTblEntry *rte = lfirst(l);
154
155                 if (rte->relname)
156                         printf("%d\t%s (%s)\t%u",
157                                    i, rte->relname, rte->eref->relname, rte->relid);
158                 else
159                         printf("%d\t[subquery] (%s)\t",
160                                    i, rte->eref->relname);
161                 printf("\t%s\t%s\n",
162                            (rte->inh ? "inh" : ""),
163                            (rte->inFromCl ? "inFromCl" : ""));
164                 i++;
165         }
166 }
167
168
169 /*
170  * print_expr
171  *        print an expression
172  */
173 void
174 print_expr(Node *expr, List *rtable)
175 {
176         if (expr == NULL)
177         {
178                 printf("<>");
179                 return;
180         }
181
182         if (IsA(expr, Var))
183         {
184                 Var                *var = (Var *) expr;
185                 char       *relname,
186                                    *attname;
187
188                 switch (var->varno)
189                 {
190                         case INNER:
191                                 relname = "INNER";
192                                 attname = "?";
193                                 break;
194                         case OUTER:
195                                 relname = "OUTER";
196                                 attname = "?";
197                                 break;
198                         default:
199                                 {
200                                         RangeTblEntry *rte;
201
202                                         Assert(var->varno > 0 &&
203                                                    (int) var->varno <= length(rtable));
204                                         rte = rt_fetch(var->varno, rtable);
205                                         relname = rte->eref->relname;
206                                         attname = get_rte_attribute_name(rte, var->varattno);
207                                 }
208                                 break;
209                 }
210                 printf("%s.%s", relname, attname);
211         }
212         else if (IsA(expr, Const))
213         {
214                 Const      *c = (Const *) expr;
215                 HeapTuple       typeTup;
216                 Oid                     typoutput;
217                 Oid                     typelem;
218                 char       *outputstr;
219
220                 if (c->constisnull)
221                 {
222                         printf("NULL");
223                         return;
224                 }
225
226                 typeTup = SearchSysCache(TYPEOID,
227                                                                  ObjectIdGetDatum(c->consttype),
228                                                                  0, 0, 0);
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);
234
235                 outputstr = DatumGetCString(OidFunctionCall3(typoutput,
236                                                                                                          c->constvalue,
237                                                                                            ObjectIdGetDatum(typelem),
238                                                                                                          Int32GetDatum(-1)));
239                 printf("%s", outputstr);
240                 pfree(outputstr);
241         }
242         else if (IsA(expr, Expr))
243         {
244                 Expr       *e = (Expr *) expr;
245
246                 if (is_opclause(expr))
247                 {
248                         char       *opname;
249
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);
254                 }
255                 else
256                         printf("an expr");
257         }
258         else
259                 printf("not an expr");
260 }
261
262 /*
263  * print_pathkeys -
264  *        pathkeys list of list of PathKeyItems
265  */
266 void
267 print_pathkeys(List *pathkeys, List *rtable)
268 {
269         List       *i,
270                            *k;
271
272         printf("(");
273         foreach(i, pathkeys)
274         {
275                 List       *pathkey = lfirst(i);
276
277                 printf("(");
278                 foreach(k, pathkey)
279                 {
280                         PathKeyItem *item = lfirst(k);
281
282                         print_expr(item->key, rtable);
283                         if (lnext(k))
284                                 printf(", ");
285                 }
286                 printf(")");
287                 if (lnext(i))
288                         printf(", ");
289         }
290         printf(")\n");
291 }
292
293 /*
294  * print_tl
295  *        print targetlist in a more legible way.
296  */
297 void
298 print_tl(List *tlist, List *rtable)
299 {
300         List       *tl;
301
302         printf("(\n");
303         foreach(tl, tlist)
304         {
305                 TargetEntry *tle = lfirst(tl);
306
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);
310                 else
311                         printf("    :\t");
312                 print_expr(tle->expr, rtable);
313                 printf("\n");
314         }
315         printf(")\n");
316 }
317
318 /*
319  * print_slot
320  *        print out the tuple with the given TupleTableSlot
321  */
322 void
323 print_slot(TupleTableSlot *slot)
324 {
325         if (!slot->val)
326         {
327                 printf("tuple is null.\n");
328                 return;
329         }
330         if (!slot->ttc_tupleDescriptor)
331         {
332                 printf("no tuple descriptor.\n");
333                 return;
334         }
335
336         debugtup(slot->val, slot->ttc_tupleDescriptor, NULL);
337 }
338
339 static char *
340 plannode_type(Plan *p)
341 {
342         switch (nodeTag(p))
343         {
344                 case T_Plan:
345                         return "PLAN";
346                 case T_Result:
347                         return "RESULT";
348                 case T_Append:
349                         return "APPEND";
350                 case T_Scan:
351                         return "SCAN";
352                 case T_SeqScan:
353                         return "SEQSCAN";
354                 case T_IndexScan:
355                         return "INDEXSCAN";
356                 case T_TidScan:
357                         return "TIDSCAN";
358                 case T_SubqueryScan:
359                         return "SUBQUERYSCAN";
360                 case T_Join:
361                         return "JOIN";
362                 case T_NestLoop:
363                         return "NESTLOOP";
364                 case T_MergeJoin:
365                         return "MERGEJOIN";
366                 case T_HashJoin:
367                         return "HASHJOIN";
368                 case T_Material:
369                         return "MATERIAL";
370                 case T_Sort:
371                         return "SORT";
372                 case T_Agg:
373                         return "AGG";
374                 case T_Unique:
375                         return "UNIQUE";
376                 case T_SetOp:
377                         return "SETOP";
378                 case T_Limit:
379                         return "LIMIT";
380                 case T_Hash:
381                         return "HASH";
382                 case T_Group:
383                         return "GROUP";
384                 default:
385                         return "UNKNOWN";
386         }
387 }
388
389 /*
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
393    printed out
394
395 */
396 void
397 print_plan_recursive(Plan *p, Query *parsetree, int indentLevel, char *label)
398 {
399         int                     i;
400         char            extraInfo[NAMEDATALEN + 100];
401
402         if (!p)
403                 return;
404         for (i = 0; i < indentLevel; i++)
405                 printf(" ");
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))
410         {
411                 RangeTblEntry *rte;
412
413                 rte = rt_fetch(((Scan *) p)->scanrelid, parsetree->rtable);
414                 StrNCpy(extraInfo, rte->relname, NAMEDATALEN);
415         }
416         else if (IsA(p, IndexScan))
417         {
418                 RangeTblEntry *rte;
419
420                 rte = rt_fetch(((IndexScan *) p)->scan.scanrelid, parsetree->rtable);
421                 StrNCpy(extraInfo, rte->relname, NAMEDATALEN);
422         }
423         else
424                 extraInfo[0] = '\0';
425         if (extraInfo[0] != '\0')
426                 printf(" ( %s )\n", extraInfo);
427         else
428                 printf("\n");
429         print_plan_recursive(p->lefttree, parsetree, indentLevel + 3, "l: ");
430         print_plan_recursive(p->righttree, parsetree, indentLevel + 3, "r: ");
431
432         if (IsA(p, Append))
433         {
434                 List       *lst;
435                 int                     whichplan = 0;
436                 Append     *appendplan = (Append *) p;
437
438                 foreach(lst, appendplan->appendplans)
439                 {
440                         Plan       *subnode = (Plan *) lfirst(lst);
441
442                         /*
443                          * I don't think we need to fiddle with the range table here,
444                          * bjm
445                          */
446                         print_plan_recursive(subnode, parsetree, indentLevel + 3, "a: ");
447
448                         whichplan++;
449                 }
450         }
451 }
452
453 /* print_plan
454   prints just the plan node types */
455
456 void
457 print_plan(Plan *p, Query *parsetree)
458 {
459         print_plan_recursive(p, parsetree, 0, "");
460 }