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