]> granicus.if.org Git - postgresql/blob - src/backend/nodes/print.c
Add const qualifiers to node inspection functions
[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-2011, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        src/backend/nodes/print.c
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(const 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(const 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, const 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_internal("%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(const List *rtable)
253 {
254         const 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\t%c",
267                                            i, rte->eref->aliasname, rte->relid, rte->relkind);
268                                 break;
269                         case RTE_SUBQUERY:
270                                 printf("%d\t%s\t[subquery]",
271                                            i, rte->eref->aliasname);
272                                 break;
273                         case RTE_JOIN:
274                                 printf("%d\t%s\t[join]",
275                                            i, rte->eref->aliasname);
276                                 break;
277                         case RTE_FUNCTION:
278                                 printf("%d\t%s\t[rangefunction]",
279                                            i, rte->eref->aliasname);
280                                 break;
281                         case RTE_VALUES:
282                                 printf("%d\t%s\t[values list]",
283                                            i, rte->eref->aliasname);
284                                 break;
285                         case RTE_CTE:
286                                 printf("%d\t%s\t[cte]",
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(const Node *expr, const List *rtable)
308 {
309         if (expr == NULL)
310         {
311                 printf("<>");
312                 return;
313         }
314
315         if (IsA(expr, Var))
316         {
317                 const Var                  *var = (const Var *) expr;
318                 char       *relname,
319                                    *attname;
320
321                 switch (var->varno)
322                 {
323                         case INNER_VAR:
324                                 relname = "INNER";
325                                 attname = "?";
326                                 break;
327                         case OUTER_VAR:
328                                 relname = "OUTER";
329                                 attname = "?";
330                                 break;
331                         case INDEX_VAR:
332                                 relname = "INDEX";
333                                 attname = "?";
334                                 break;
335                         default:
336                                 {
337                                         RangeTblEntry *rte;
338
339                                         Assert(var->varno > 0 &&
340                                                    (int) var->varno <= list_length(rtable));
341                                         rte = rt_fetch(var->varno, rtable);
342                                         relname = rte->eref->aliasname;
343                                         attname = get_rte_attribute_name(rte, var->varattno);
344                                 }
345                                 break;
346                 }
347                 printf("%s.%s", relname, attname);
348         }
349         else if (IsA(expr, Const))
350         {
351                 const Const        *c = (const Const *) expr;
352                 Oid                     typoutput;
353                 bool            typIsVarlena;
354                 char       *outputstr;
355
356                 if (c->constisnull)
357                 {
358                         printf("NULL");
359                         return;
360                 }
361
362                 getTypeOutputInfo(c->consttype,
363                                                   &typoutput, &typIsVarlena);
364
365                 outputstr = OidOutputFunctionCall(typoutput, c->constvalue);
366                 printf("%s", outputstr);
367                 pfree(outputstr);
368         }
369         else if (IsA(expr, OpExpr))
370         {
371                 const OpExpr       *e = (const OpExpr *) expr;
372                 char       *opname;
373
374                 opname = get_opname(e->opno);
375                 if (list_length(e->args) > 1)
376                 {
377                         print_expr(get_leftop((const Expr *) e), rtable);
378                         printf(" %s ", ((opname != NULL) ? opname : "(invalid operator)"));
379                         print_expr(get_rightop((const Expr *) e), rtable);
380                 }
381                 else
382                 {
383                         /* we print prefix and postfix ops the same... */
384                         printf("%s ", ((opname != NULL) ? opname : "(invalid operator)"));
385                         print_expr(get_leftop((const Expr *) e), rtable);
386                 }
387         }
388         else if (IsA(expr, FuncExpr))
389         {
390                 const FuncExpr   *e = (const FuncExpr *) expr;
391                 char       *funcname;
392                 ListCell   *l;
393
394                 funcname = get_func_name(e->funcid);
395                 printf("%s(", ((funcname != NULL) ? funcname : "(invalid function)"));
396                 foreach(l, e->args)
397                 {
398                         print_expr(lfirst(l), rtable);
399                         if (lnext(l))
400                                 printf(",");
401                 }
402                 printf(")");
403         }
404         else
405                 printf("unknown expr");
406 }
407
408 /*
409  * print_pathkeys -
410  *        pathkeys list of PathKeys
411  */
412 void
413 print_pathkeys(const List *pathkeys, const List *rtable)
414 {
415         const ListCell   *i;
416
417         printf("(");
418         foreach(i, pathkeys)
419         {
420                 PathKey    *pathkey = (PathKey *) lfirst(i);
421                 EquivalenceClass *eclass;
422                 ListCell   *k;
423                 bool            first = true;
424
425                 eclass = pathkey->pk_eclass;
426                 /* chase up, in case pathkey is non-canonical */
427                 while (eclass->ec_merged)
428                         eclass = eclass->ec_merged;
429
430                 printf("(");
431                 foreach(k, eclass->ec_members)
432                 {
433                         EquivalenceMember *mem = (EquivalenceMember *) lfirst(k);
434
435                         if (first)
436                                 first = false;
437                         else
438                                 printf(", ");
439                         print_expr((Node *) mem->em_expr, rtable);
440                 }
441                 printf(")");
442                 if (lnext(i))
443                         printf(", ");
444         }
445         printf(")\n");
446 }
447
448 /*
449  * print_tl
450  *        print targetlist in a more legible way.
451  */
452 void
453 print_tl(const List *tlist, const List *rtable)
454 {
455         const ListCell   *tl;
456
457         printf("(\n");
458         foreach(tl, tlist)
459         {
460                 TargetEntry *tle = (TargetEntry *) lfirst(tl);
461
462                 printf("\t%d %s\t", tle->resno,
463                            tle->resname ? tle->resname : "<null>");
464                 if (tle->ressortgroupref != 0)
465                         printf("(%u):\t", tle->ressortgroupref);
466                 else
467                         printf("    :\t");
468                 print_expr((Node *) tle->expr, rtable);
469                 printf("\n");
470         }
471         printf(")\n");
472 }
473
474 /*
475  * print_slot
476  *        print out the tuple with the given TupleTableSlot
477  */
478 void
479 print_slot(TupleTableSlot *slot)
480 {
481         if (TupIsNull(slot))
482         {
483                 printf("tuple is null.\n");
484                 return;
485         }
486         if (!slot->tts_tupleDescriptor)
487         {
488                 printf("no tuple descriptor.\n");
489                 return;
490         }
491
492         debugtup(slot, NULL);
493 }