]> granicus.if.org Git - postgresql/blob - src/backend/nodes/print.c
pgindent run for 8.3.
[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-2007, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/nodes/print.c,v 1.86 2007/11/15 21:14:35 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 "nodes/print.h"
24 #include "optimizer/clauses.h"
25 #include "parser/parsetree.h"
26 #include "utils/lsyscache.h"
27
28
29 /*
30  * print
31  *        print contents of Node to stdout
32  */
33 void
34 print(void *obj)
35 {
36         char       *s;
37         char       *f;
38
39         s = nodeToString(obj);
40         f = format_node_dump(s);
41         pfree(s);
42         printf("%s\n", f);
43         fflush(stdout);
44         pfree(f);
45 }
46
47 /*
48  * pprint
49  *        pretty-print contents of Node to stdout
50  */
51 void
52 pprint(void *obj)
53 {
54         char       *s;
55         char       *f;
56
57         s = nodeToString(obj);
58         f = pretty_format_node_dump(s);
59         pfree(s);
60         printf("%s\n", f);
61         fflush(stdout);
62         pfree(f);
63 }
64
65 /*
66  * elog_node_display
67  *        send pretty-printed contents of Node to postmaster log
68  */
69 void
70 elog_node_display(int lev, const char *title, void *obj, bool pretty)
71 {
72         char       *s;
73         char       *f;
74
75         s = nodeToString(obj);
76         if (pretty)
77                 f = pretty_format_node_dump(s);
78         else
79                 f = format_node_dump(s);
80         pfree(s);
81         ereport(lev,
82                         (errmsg_internal("%s:", title),
83                          errdetail("%s", f)));
84         pfree(f);
85 }
86
87 /*
88  * Format a nodeToString output for display on a terminal.
89  *
90  * The result is a palloc'd string.
91  *
92  * This version just tries to break at whitespace.
93  */
94 char *
95 format_node_dump(const char *dump)
96 {
97 #define LINELEN         78
98         char            line[LINELEN + 1];
99         StringInfoData str;
100         int                     i;
101         int                     j;
102         int                     k;
103
104         initStringInfo(&str);
105         i = 0;
106         for (;;)
107         {
108                 for (j = 0; j < LINELEN && dump[i] != '\0'; i++, j++)
109                         line[j] = dump[i];
110                 if (dump[i] == '\0')
111                         break;
112                 if (dump[i] == ' ')
113                 {
114                         /* ok to break at adjacent space */
115                         i++;
116                 }
117                 else
118                 {
119                         for (k = j - 1; k > 0; k--)
120                                 if (line[k] == ' ')
121                                         break;
122                         if (k > 0)
123                         {
124                                 /* back up; will reprint all after space */
125                                 i -= (j - k - 1);
126                                 j = k;
127                         }
128                 }
129                 line[j] = '\0';
130                 appendStringInfo(&str, "%s\n", line);
131         }
132         if (j > 0)
133         {
134                 line[j] = '\0';
135                 appendStringInfo(&str, "%s\n", line);
136         }
137         return str.data;
138 #undef LINELEN
139 }
140
141 /*
142  * Format a nodeToString output for display on a terminal.
143  *
144  * The result is a palloc'd string.
145  *
146  * This version tries to indent intelligently.
147  */
148 char *
149 pretty_format_node_dump(const char *dump)
150 {
151 #define INDENTSTOP      3
152 #define MAXINDENT       60
153 #define LINELEN         78
154         char            line[LINELEN + 1];
155         StringInfoData str;
156         int                     indentLev;
157         int                     indentDist;
158         int                     i;
159         int                     j;
160
161         initStringInfo(&str);
162         indentLev = 0;                          /* logical indent level */
163         indentDist = 0;                         /* physical indent distance */
164         i = 0;
165         for (;;)
166         {
167                 for (j = 0; j < indentDist; j++)
168                         line[j] = ' ';
169                 for (; j < LINELEN && dump[i] != '\0'; i++, j++)
170                 {
171                         line[j] = dump[i];
172                         switch (line[j])
173                         {
174                                 case '}':
175                                         if (j != indentDist)
176                                         {
177                                                 /* print data before the } */
178                                                 line[j] = '\0';
179                                                 appendStringInfo(&str, "%s\n", line);
180                                         }
181                                         /* print the } at indentDist */
182                                         line[indentDist] = '}';
183                                         line[indentDist + 1] = '\0';
184                                         appendStringInfo(&str, "%s\n", line);
185                                         /* outdent */
186                                         if (indentLev > 0)
187                                         {
188                                                 indentLev--;
189                                                 indentDist = Min(indentLev * INDENTSTOP, MAXINDENT);
190                                         }
191                                         j = indentDist - 1;
192                                         /* j will equal indentDist on next loop iteration */
193                                         /* suppress whitespace just after } */
194                                         while (dump[i + 1] == ' ')
195                                                 i++;
196                                         break;
197                                 case ')':
198                                         /* force line break after ), unless another ) follows */
199                                         if (dump[i + 1] != ')')
200                                         {
201                                                 line[j + 1] = '\0';
202                                                 appendStringInfo(&str, "%s\n", line);
203                                                 j = indentDist - 1;
204                                                 while (dump[i + 1] == ' ')
205                                                         i++;
206                                         }
207                                         break;
208                                 case '{':
209                                         /* force line break before { */
210                                         if (j != indentDist)
211                                         {
212                                                 line[j] = '\0';
213                                                 appendStringInfo(&str, "%s\n", line);
214                                         }
215                                         /* indent */
216                                         indentLev++;
217                                         indentDist = Min(indentLev * INDENTSTOP, MAXINDENT);
218                                         for (j = 0; j < indentDist; j++)
219                                                 line[j] = ' ';
220                                         line[j] = dump[i];
221                                         break;
222                                 case ':':
223                                         /* force line break before : */
224                                         if (j != indentDist)
225                                         {
226                                                 line[j] = '\0';
227                                                 appendStringInfo(&str, "%s\n", line);
228                                         }
229                                         j = indentDist;
230                                         line[j] = dump[i];
231                                         break;
232                         }
233                 }
234                 line[j] = '\0';
235                 if (dump[i] == '\0')
236                         break;
237                 appendStringInfo(&str, "%s\n", line);
238         }
239         if (j > 0)
240                 appendStringInfo(&str, "%s\n", line);
241         return str.data;
242 #undef INDENTSTOP
243 #undef MAXINDENT
244 #undef LINELEN
245 }
246
247 /*
248  * print_rt
249  *        print contents of range table
250  */
251 void
252 print_rt(List *rtable)
253 {
254         ListCell   *l;
255         int                     i = 1;
256
257         printf("resno\trefname  \trelid\tinFromCl\n");
258         printf("-----\t---------\t-----\t--------\n");
259         foreach(l, rtable)
260         {
261                 RangeTblEntry *rte = lfirst(l);
262
263                 switch (rte->rtekind)
264                 {
265                         case RTE_RELATION:
266                                 printf("%d\t%s\t%u",
267                                            i, rte->eref->aliasname, rte->relid);
268                                 break;
269                         case RTE_SUBQUERY:
270                                 printf("%d\t%s\t[subquery]",
271                                            i, rte->eref->aliasname);
272                                 break;
273                         case RTE_FUNCTION:
274                                 printf("%d\t%s\t[rangefunction]",
275                                            i, rte->eref->aliasname);
276                                 break;
277                         case RTE_VALUES:
278                                 printf("%d\t%s\t[values list]",
279                                            i, rte->eref->aliasname);
280                                 break;
281                         case RTE_JOIN:
282                                 printf("%d\t%s\t[join]",
283                                            i, rte->eref->aliasname);
284                                 break;
285                         case RTE_SPECIAL:
286                                 printf("%d\t%s\t[special]",
287                                            i, rte->eref->aliasname);
288                                 break;
289                         default:
290                                 printf("%d\t%s\t[unknown rtekind]",
291                                            i, rte->eref->aliasname);
292                 }
293
294                 printf("\t%s\t%s\n",
295                            (rte->inh ? "inh" : ""),
296                            (rte->inFromCl ? "inFromCl" : ""));
297                 i++;
298         }
299 }
300
301
302 /*
303  * print_expr
304  *        print an expression
305  */
306 void
307 print_expr(Node *expr, List *rtable)
308 {
309         if (expr == NULL)
310         {
311                 printf("<>");
312                 return;
313         }
314
315         if (IsA(expr, Var))
316         {
317                 Var                *var = (Var *) expr;
318                 char       *relname,
319                                    *attname;
320
321                 switch (var->varno)
322                 {
323                         case INNER:
324                                 relname = "INNER";
325                                 attname = "?";
326                                 break;
327                         case OUTER:
328                                 relname = "OUTER";
329                                 attname = "?";
330                                 break;
331                         default:
332                                 {
333                                         RangeTblEntry *rte;
334
335                                         Assert(var->varno > 0 &&
336                                                    (int) var->varno <= list_length(rtable));
337                                         rte = rt_fetch(var->varno, rtable);
338                                         relname = rte->eref->aliasname;
339                                         attname = get_rte_attribute_name(rte, var->varattno);
340                                 }
341                                 break;
342                 }
343                 printf("%s.%s", relname, attname);
344         }
345         else if (IsA(expr, Const))
346         {
347                 Const      *c = (Const *) expr;
348                 Oid                     typoutput;
349                 bool            typIsVarlena;
350                 char       *outputstr;
351
352                 if (c->constisnull)
353                 {
354                         printf("NULL");
355                         return;
356                 }
357
358                 getTypeOutputInfo(c->consttype,
359                                                   &typoutput, &typIsVarlena);
360
361                 outputstr = OidOutputFunctionCall(typoutput, c->constvalue);
362                 printf("%s", outputstr);
363                 pfree(outputstr);
364         }
365         else if (IsA(expr, OpExpr))
366         {
367                 OpExpr     *e = (OpExpr *) expr;
368                 char       *opname;
369
370                 opname = get_opname(e->opno);
371                 if (list_length(e->args) > 1)
372                 {
373                         print_expr(get_leftop((Expr *) e), rtable);
374                         printf(" %s ", ((opname != NULL) ? opname : "(invalid operator)"));
375                         print_expr(get_rightop((Expr *) e), rtable);
376                 }
377                 else
378                 {
379                         /* we print prefix and postfix ops the same... */
380                         printf("%s ", ((opname != NULL) ? opname : "(invalid operator)"));
381                         print_expr(get_leftop((Expr *) e), rtable);
382                 }
383         }
384         else if (IsA(expr, FuncExpr))
385         {
386                 FuncExpr   *e = (FuncExpr *) expr;
387                 char       *funcname;
388                 ListCell   *l;
389
390                 funcname = get_func_name(e->funcid);
391                 printf("%s(", ((funcname != NULL) ? funcname : "(invalid function)"));
392                 foreach(l, e->args)
393                 {
394                         print_expr(lfirst(l), rtable);
395                         if (lnext(l))
396                                 printf(",");
397                 }
398                 printf(")");
399         }
400         else
401                 printf("unknown expr");
402 }
403
404 /*
405  * print_pathkeys -
406  *        pathkeys list of PathKeys
407  */
408 void
409 print_pathkeys(List *pathkeys, List *rtable)
410 {
411         ListCell   *i;
412
413         printf("(");
414         foreach(i, pathkeys)
415         {
416                 PathKey    *pathkey = (PathKey *) lfirst(i);
417                 EquivalenceClass *eclass;
418                 ListCell   *k;
419                 bool            first = true;
420
421                 eclass = pathkey->pk_eclass;
422                 /* chase up, in case pathkey is non-canonical */
423                 while (eclass->ec_merged)
424                         eclass = eclass->ec_merged;
425
426                 printf("(");
427                 foreach(k, eclass->ec_members)
428                 {
429                         EquivalenceMember *mem = (EquivalenceMember *) lfirst(k);
430
431                         if (first)
432                                 first = false;
433                         else
434                                 printf(", ");
435                         print_expr((Node *) mem->em_expr, rtable);
436                 }
437                 printf(")");
438                 if (lnext(i))
439                         printf(", ");
440         }
441         printf(")\n");
442 }
443
444 /*
445  * print_tl
446  *        print targetlist in a more legible way.
447  */
448 void
449 print_tl(List *tlist, List *rtable)
450 {
451         ListCell   *tl;
452
453         printf("(\n");
454         foreach(tl, tlist)
455         {
456                 TargetEntry *tle = (TargetEntry *) lfirst(tl);
457
458                 printf("\t%d %s\t", tle->resno,
459                            tle->resname ? tle->resname : "<null>");
460                 if (tle->ressortgroupref != 0)
461                         printf("(%u):\t", tle->ressortgroupref);
462                 else
463                         printf("    :\t");
464                 print_expr((Node *) tle->expr, rtable);
465                 printf("\n");
466         }
467         printf(")\n");
468 }
469
470 /*
471  * print_slot
472  *        print out the tuple with the given TupleTableSlot
473  */
474 void
475 print_slot(TupleTableSlot *slot)
476 {
477         if (TupIsNull(slot))
478         {
479                 printf("tuple is null.\n");
480                 return;
481         }
482         if (!slot->tts_tupleDescriptor)
483         {
484                 printf("no tuple descriptor.\n");
485                 return;
486         }
487
488         debugtup(slot, NULL);
489 }