]> granicus.if.org Git - postgresql/blob - src/backend/nodes/print.c
Extend code that deduces implied equality clauses to detect whether a
[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.48 2001/10/18 16:11:41 tgl 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 }
45
46 /*
47  * pretty print hack extraordinaire.  -ay 10/94
48  */
49 void
50 pprint(void *obj)
51 {
52         char       *s;
53         int                     i;
54         char            line[80];
55         int                     indentLev;
56         int                     j;
57
58         s = nodeToString(obj);
59
60         indentLev = 0;
61         i = 0;
62         for (;;)
63         {
64                 for (j = 0; j < indentLev * 3; j++)
65                         line[j] = ' ';
66                 for (; j < 75 && s[i] != '\0'; i++, j++)
67                 {
68                         line[j] = s[i];
69                         switch (line[j])
70                         {
71                                 case '}':
72                                         if (j != indentLev * 3)
73                                         {
74                                                 line[j] = '\0';
75                                                 printf("%s\n", line);
76                                                 line[indentLev * 3] = '\0';
77                                                 printf("%s}\n", line);
78                                         }
79                                         else
80                                         {
81                                                 line[j] = '\0';
82                                                 printf("%s}\n", line);
83                                         }
84                                         indentLev--;
85                                         j = indentLev * 3 - 1;          /* print the line before :
86                                                                                                  * and resets */
87                                         break;
88                                 case ')':
89                                         line[j + 1] = '\0';
90                                         printf("%s\n", line);
91                                         j = indentLev * 3 - 1;
92                                         break;
93                                 case '{':
94                                         indentLev++;
95                                         /* !!! FALLS THROUGH */
96                                 case ':':
97                                         if (j != 0)
98                                         {
99                                                 line[j] = '\0';
100                                                 printf("%s\n", line);
101                                                 /* print the line before : and resets */
102                                                 for (j = 0; j < indentLev * 3; j++)
103                                                         line[j] = ' ';
104                                         }
105                                         line[j] = s[i];
106                                         break;
107                         }
108                 }
109                 line[j] = '\0';
110                 if (s[i] == '\0')
111                         break;
112                 printf("%s\n", line);
113         }
114         if (j != 0)
115                 printf("%s\n", line);
116         fflush(stdout);
117         return;
118 }
119
120 /*
121  * print_rt
122  *        print contents of range table
123  */
124 void
125 print_rt(List *rtable)
126 {
127         List       *l;
128         int                     i = 1;
129
130         printf("resno\trelname(refname)\trelid\tinFromCl\n");
131         printf("-----\t----------------\t-----\t--------\n");
132         foreach(l, rtable)
133         {
134                 RangeTblEntry *rte = lfirst(l);
135
136                 if (rte->relname)
137                         printf("%d\t%s (%s)\t%u",
138                                    i, rte->relname, rte->eref->relname, rte->relid);
139                 else
140                         printf("%d\t[subquery] (%s)\t",
141                                    i, rte->eref->relname);
142                 printf("\t%s\t%s\n",
143                            (rte->inh ? "inh" : ""),
144                            (rte->inFromCl ? "inFromCl" : ""));
145                 i++;
146         }
147 }
148
149
150 /*
151  * print_expr
152  *        print an expression
153  */
154 void
155 print_expr(Node *expr, List *rtable)
156 {
157         if (expr == NULL)
158         {
159                 printf("<>");
160                 return;
161         }
162
163         if (IsA(expr, Var))
164         {
165                 Var                *var = (Var *) expr;
166                 char       *relname,
167                                    *attname;
168
169                 switch (var->varno)
170                 {
171                         case INNER:
172                                 relname = "INNER";
173                                 attname = "?";
174                                 break;
175                         case OUTER:
176                                 relname = "OUTER";
177                                 attname = "?";
178                                 break;
179                         default:
180                                 {
181                                         RangeTblEntry *rte;
182
183                                         Assert(var->varno > 0 &&
184                                                    (int) var->varno <= length(rtable));
185                                         rte = rt_fetch(var->varno, rtable);
186                                         relname = rte->eref->relname;
187                                         attname = get_rte_attribute_name(rte, var->varattno);
188                                 }
189                                 break;
190                 }
191                 printf("%s.%s", relname, attname);
192         }
193         else if (IsA(expr, Const))
194         {
195                 Const      *c = (Const *) expr;
196                 HeapTuple       typeTup;
197                 Oid                     typoutput;
198                 Oid                     typelem;
199                 char       *outputstr;
200
201                 if (c->constisnull)
202                 {
203                         printf("NULL");
204                         return;
205                 }
206
207                 typeTup = SearchSysCache(TYPEOID,
208                                                                  ObjectIdGetDatum(c->consttype),
209                                                                  0, 0, 0);
210                 if (!HeapTupleIsValid(typeTup))
211                         elog(ERROR, "Cache lookup for type %u failed", c->consttype);
212                 typoutput = ((Form_pg_type) GETSTRUCT(typeTup))->typoutput;
213                 typelem = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;
214                 ReleaseSysCache(typeTup);
215
216                 outputstr = DatumGetCString(OidFunctionCall3(typoutput,
217                                                                                                          c->constvalue,
218                                                                                                          ObjectIdGetDatum(typelem),
219                                                                                                          Int32GetDatum(-1)));
220                 printf("%s", outputstr);
221                 pfree(outputstr);
222         }
223         else if (IsA(expr, Expr))
224         {
225                 Expr       *e = (Expr *) expr;
226
227                 if (is_opclause(expr))
228                 {
229                         char       *opname;
230
231                         print_expr((Node *) get_leftop(e), rtable);
232                         opname = get_opname(((Oper *) e->oper)->opno);
233                         printf(" %s ", ((opname != NULL) ? opname : "(invalid operator)"));
234                         print_expr((Node *) get_rightop(e), rtable);
235                 }
236                 else
237                         printf("an expr");
238         }
239         else
240                 printf("not an expr");
241 }
242
243 /*
244  * print_pathkeys -
245  *        pathkeys list of list of PathKeyItems
246  */
247 void
248 print_pathkeys(List *pathkeys, List *rtable)
249 {
250         List       *i,
251                            *k;
252
253         printf("(");
254         foreach(i, pathkeys)
255         {
256                 List       *pathkey = lfirst(i);
257
258                 printf("(");
259                 foreach(k, pathkey)
260                 {
261                         PathKeyItem *item = lfirst(k);
262
263                         print_expr(item->key, rtable);
264                         if (lnext(k))
265                                 printf(", ");
266                 }
267                 printf(")");
268                 if (lnext(i))
269                         printf(", ");
270         }
271         printf(")\n");
272 }
273
274 /*
275  * print_tl
276  *        print targetlist in a more legible way.
277  */
278 void
279 print_tl(List *tlist, List *rtable)
280 {
281         List       *tl;
282
283         printf("(\n");
284         foreach(tl, tlist)
285         {
286                 TargetEntry *tle = lfirst(tl);
287
288                 printf("\t%d %s\t", tle->resdom->resno, tle->resdom->resname);
289                 if (tle->resdom->reskey != 0)
290                         printf("(%d):\t", tle->resdom->reskey);
291                 else
292                         printf("    :\t");
293                 print_expr(tle->expr, rtable);
294                 printf("\n");
295         }
296         printf(")\n");
297 }
298
299 /*
300  * print_slot
301  *        print out the tuple with the given TupleTableSlot
302  */
303 void
304 print_slot(TupleTableSlot *slot)
305 {
306         if (!slot->val)
307         {
308                 printf("tuple is null.\n");
309                 return;
310         }
311         if (!slot->ttc_tupleDescriptor)
312         {
313                 printf("no tuple descriptor.\n");
314                 return;
315         }
316
317         debugtup(slot->val, slot->ttc_tupleDescriptor, NULL);
318 }
319
320 static char *
321 plannode_type(Plan *p)
322 {
323         switch (nodeTag(p))
324         {
325                         case T_Plan:
326                         return "PLAN";
327                 case T_Result:
328                         return "RESULT";
329                 case T_Append:
330                         return "APPEND";
331                 case T_Scan:
332                         return "SCAN";
333                 case T_SeqScan:
334                         return "SEQSCAN";
335                 case T_IndexScan:
336                         return "INDEXSCAN";
337                 case T_TidScan:
338                         return "TIDSCAN";
339                 case T_SubqueryScan:
340                         return "SUBQUERYSCAN";
341                 case T_Join:
342                         return "JOIN";
343                 case T_NestLoop:
344                         return "NESTLOOP";
345                 case T_MergeJoin:
346                         return "MERGEJOIN";
347                 case T_HashJoin:
348                         return "HASHJOIN";
349                 case T_Material:
350                         return "MATERIAL";
351                 case T_Sort:
352                         return "SORT";
353                 case T_Agg:
354                         return "AGG";
355                 case T_Unique:
356                         return "UNIQUE";
357                 case T_SetOp:
358                         return "SETOP";
359                 case T_Limit:
360                         return "LIMIT";
361                 case T_Hash:
362                         return "HASH";
363                 case T_Group:
364                         return "GROUP";
365                 default:
366                         return "UNKNOWN";
367         }
368 }
369
370 /*
371    prints the ascii description of the plan nodes
372    does this recursively by doing a depth-first traversal of the
373    plan tree.  for SeqScan and IndexScan, the name of the table is also
374    printed out
375
376 */
377 void
378 print_plan_recursive(Plan *p, Query *parsetree, int indentLevel, char *label)
379 {
380         int                     i;
381         char            extraInfo[100];
382
383         if (!p)
384                 return;
385         for (i = 0; i < indentLevel; i++)
386                 printf(" ");
387         printf("%s%s :c=%.2f..%.2f :r=%.0f :w=%d ", label, plannode_type(p),
388                    p->startup_cost, p->total_cost,
389                    p->plan_rows, p->plan_width);
390         if (IsA(p, Scan) ||IsA(p, SeqScan))
391         {
392                 RangeTblEntry *rte;
393
394                 rte = rt_fetch(((Scan *) p)->scanrelid, parsetree->rtable);
395                 StrNCpy(extraInfo, rte->relname, NAMEDATALEN);
396         }
397         else if (IsA(p, IndexScan))
398         {
399                 RangeTblEntry *rte;
400
401                 rte = rt_fetch(((IndexScan *) p)->scan.scanrelid, parsetree->rtable);
402                 StrNCpy(extraInfo, rte->relname, NAMEDATALEN);
403         }
404         else
405                 extraInfo[0] = '\0';
406         if (extraInfo[0] != '\0')
407                 printf(" ( %s )\n", extraInfo);
408         else
409                 printf("\n");
410         print_plan_recursive(p->lefttree, parsetree, indentLevel + 3, "l: ");
411         print_plan_recursive(p->righttree, parsetree, indentLevel + 3, "r: ");
412
413         if (IsA(p, Append))
414         {
415                 List       *lst;
416                 int                     whichplan = 0;
417                 Append     *appendplan = (Append *) p;
418
419                 foreach(lst, appendplan->appendplans)
420                 {
421                         Plan       *subnode = (Plan *) lfirst(lst);
422
423                         /*
424                          * I don't think we need to fiddle with the range table here,
425                          * bjm
426                          */
427                         print_plan_recursive(subnode, parsetree, indentLevel + 3, "a: ");
428
429                         whichplan++;
430                 }
431         }
432 }
433
434 /* print_plan
435   prints just the plan node types */
436
437 void
438 print_plan(Plan *p, Query *parsetree)
439 {
440         print_plan_recursive(p, parsetree, 0, "");
441 }