Remove the encoding *numbers* from the comments. They are useless, and
[PostgreSQL.git] / src / backend / nodes / print.c
blob0adfa516ec25f2008918ae234aa605115c8959fe
1 /*-------------------------------------------------------------------------
3 * print.c
4 * various print routines (used mostly for debugging)
6 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * IDENTIFICATION
11 * $PostgreSQL$
13 * HISTORY
14 * AUTHOR DATE MAJOR EVENT
15 * Andrew Yu Oct 26, 1994 file creation
17 *-------------------------------------------------------------------------
20 #include "postgres.h"
22 #include "access/printtup.h"
23 #include "lib/stringinfo.h"
24 #include "nodes/print.h"
25 #include "optimizer/clauses.h"
26 #include "parser/parsetree.h"
27 #include "utils/lsyscache.h"
28 #include "utils/rel.h"
32 * print
33 * print contents of Node to stdout
35 void
36 print(void *obj)
38 char *s;
39 char *f;
41 s = nodeToString(obj);
42 f = format_node_dump(s);
43 pfree(s);
44 printf("%s\n", f);
45 fflush(stdout);
46 pfree(f);
50 * pprint
51 * pretty-print contents of Node to stdout
53 void
54 pprint(void *obj)
56 char *s;
57 char *f;
59 s = nodeToString(obj);
60 f = pretty_format_node_dump(s);
61 pfree(s);
62 printf("%s\n", f);
63 fflush(stdout);
64 pfree(f);
68 * elog_node_display
69 * send pretty-printed contents of Node to postmaster log
71 void
72 elog_node_display(int lev, const char *title, void *obj, bool pretty)
74 char *s;
75 char *f;
77 s = nodeToString(obj);
78 if (pretty)
79 f = pretty_format_node_dump(s);
80 else
81 f = format_node_dump(s);
82 pfree(s);
83 ereport(lev,
84 (errmsg_internal("%s:", title),
85 errdetail("%s", f)));
86 pfree(f);
90 * Format a nodeToString output for display on a terminal.
92 * The result is a palloc'd string.
94 * This version just tries to break at whitespace.
96 char *
97 format_node_dump(const char *dump)
99 #define LINELEN 78
100 char line[LINELEN + 1];
101 StringInfoData str;
102 int i;
103 int j;
104 int k;
106 initStringInfo(&str);
107 i = 0;
108 for (;;)
110 for (j = 0; j < LINELEN && dump[i] != '\0'; i++, j++)
111 line[j] = dump[i];
112 if (dump[i] == '\0')
113 break;
114 if (dump[i] == ' ')
116 /* ok to break at adjacent space */
117 i++;
119 else
121 for (k = j - 1; k > 0; k--)
122 if (line[k] == ' ')
123 break;
124 if (k > 0)
126 /* back up; will reprint all after space */
127 i -= (j - k - 1);
128 j = k;
131 line[j] = '\0';
132 appendStringInfo(&str, "%s\n", line);
134 if (j > 0)
136 line[j] = '\0';
137 appendStringInfo(&str, "%s\n", line);
139 return str.data;
140 #undef LINELEN
144 * Format a nodeToString output for display on a terminal.
146 * The result is a palloc'd string.
148 * This version tries to indent intelligently.
150 char *
151 pretty_format_node_dump(const char *dump)
153 #define INDENTSTOP 3
154 #define MAXINDENT 60
155 #define LINELEN 78
156 char line[LINELEN + 1];
157 StringInfoData str;
158 int indentLev;
159 int indentDist;
160 int i;
161 int j;
163 initStringInfo(&str);
164 indentLev = 0; /* logical indent level */
165 indentDist = 0; /* physical indent distance */
166 i = 0;
167 for (;;)
169 for (j = 0; j < indentDist; j++)
170 line[j] = ' ';
171 for (; j < LINELEN && dump[i] != '\0'; i++, j++)
173 line[j] = dump[i];
174 switch (line[j])
176 case '}':
177 if (j != indentDist)
179 /* print data before the } */
180 line[j] = '\0';
181 appendStringInfo(&str, "%s\n", line);
183 /* print the } at indentDist */
184 line[indentDist] = '}';
185 line[indentDist + 1] = '\0';
186 appendStringInfo(&str, "%s\n", line);
187 /* outdent */
188 if (indentLev > 0)
190 indentLev--;
191 indentDist = Min(indentLev * INDENTSTOP, MAXINDENT);
193 j = indentDist - 1;
194 /* j will equal indentDist on next loop iteration */
195 /* suppress whitespace just after } */
196 while (dump[i + 1] == ' ')
197 i++;
198 break;
199 case ')':
200 /* force line break after ), unless another ) follows */
201 if (dump[i + 1] != ')')
203 line[j + 1] = '\0';
204 appendStringInfo(&str, "%s\n", line);
205 j = indentDist - 1;
206 while (dump[i + 1] == ' ')
207 i++;
209 break;
210 case '{':
211 /* force line break before { */
212 if (j != indentDist)
214 line[j] = '\0';
215 appendStringInfo(&str, "%s\n", line);
217 /* indent */
218 indentLev++;
219 indentDist = Min(indentLev * INDENTSTOP, MAXINDENT);
220 for (j = 0; j < indentDist; j++)
221 line[j] = ' ';
222 line[j] = dump[i];
223 break;
224 case ':':
225 /* force line break before : */
226 if (j != indentDist)
228 line[j] = '\0';
229 appendStringInfo(&str, "%s\n", line);
231 j = indentDist;
232 line[j] = dump[i];
233 break;
236 line[j] = '\0';
237 if (dump[i] == '\0')
238 break;
239 appendStringInfo(&str, "%s\n", line);
241 if (j > 0)
242 appendStringInfo(&str, "%s\n", line);
243 return str.data;
244 #undef INDENTSTOP
245 #undef MAXINDENT
246 #undef LINELEN
250 * print_rt
251 * print contents of range table
253 void
254 print_rt(List *rtable)
256 ListCell *l;
257 int i = 1;
259 printf("resno\trefname \trelid\tinFromCl\n");
260 printf("-----\t---------\t-----\t--------\n");
261 foreach(l, rtable)
263 RangeTblEntry *rte = lfirst(l);
265 switch (rte->rtekind)
267 case RTE_RELATION:
268 printf("%d\t%s\t%u",
269 i, rte->eref->aliasname, rte->relid);
270 break;
271 case RTE_SUBQUERY:
272 printf("%d\t%s\t[subquery]",
273 i, rte->eref->aliasname);
274 break;
275 case RTE_JOIN:
276 printf("%d\t%s\t[join]",
277 i, rte->eref->aliasname);
278 break;
279 case RTE_SPECIAL:
280 printf("%d\t%s\t[special]",
281 i, rte->eref->aliasname);
282 break;
283 case RTE_FUNCTION:
284 printf("%d\t%s\t[rangefunction]",
285 i, rte->eref->aliasname);
286 break;
287 case RTE_VALUES:
288 printf("%d\t%s\t[values list]",
289 i, rte->eref->aliasname);
290 break;
291 case RTE_CTE:
292 printf("%d\t%s\t[cte]",
293 i, rte->eref->aliasname);
294 break;
295 default:
296 printf("%d\t%s\t[unknown rtekind]",
297 i, rte->eref->aliasname);
300 printf("\t%s\t%s\n",
301 (rte->inh ? "inh" : ""),
302 (rte->inFromCl ? "inFromCl" : ""));
303 i++;
309 * print_expr
310 * print an expression
312 void
313 print_expr(Node *expr, List *rtable)
315 if (expr == NULL)
317 printf("<>");
318 return;
321 if (IsA(expr, Var))
323 Var *var = (Var *) expr;
324 char *relname,
325 *attname;
327 switch (var->varno)
329 case INNER:
330 relname = "INNER";
331 attname = "?";
332 break;
333 case OUTER:
334 relname = "OUTER";
335 attname = "?";
336 break;
337 default:
339 RangeTblEntry *rte;
341 Assert(var->varno > 0 &&
342 (int) var->varno <= list_length(rtable));
343 rte = rt_fetch(var->varno, rtable);
344 relname = rte->eref->aliasname;
345 attname = get_rte_attribute_name(rte, var->varattno);
347 break;
349 printf("%s.%s", relname, attname);
351 else if (IsA(expr, Const))
353 Const *c = (Const *) expr;
354 Oid typoutput;
355 bool typIsVarlena;
356 char *outputstr;
358 if (c->constisnull)
360 printf("NULL");
361 return;
364 getTypeOutputInfo(c->consttype,
365 &typoutput, &typIsVarlena);
367 outputstr = OidOutputFunctionCall(typoutput, c->constvalue);
368 printf("%s", outputstr);
369 pfree(outputstr);
371 else if (IsA(expr, OpExpr))
373 OpExpr *e = (OpExpr *) expr;
374 char *opname;
376 opname = get_opname(e->opno);
377 if (list_length(e->args) > 1)
379 print_expr(get_leftop((Expr *) e), rtable);
380 printf(" %s ", ((opname != NULL) ? opname : "(invalid operator)"));
381 print_expr(get_rightop((Expr *) e), rtable);
383 else
385 /* we print prefix and postfix ops the same... */
386 printf("%s ", ((opname != NULL) ? opname : "(invalid operator)"));
387 print_expr(get_leftop((Expr *) e), rtable);
390 else if (IsA(expr, FuncExpr))
392 FuncExpr *e = (FuncExpr *) expr;
393 char *funcname;
394 ListCell *l;
396 funcname = get_func_name(e->funcid);
397 printf("%s(", ((funcname != NULL) ? funcname : "(invalid function)"));
398 foreach(l, e->args)
400 print_expr(lfirst(l), rtable);
401 if (lnext(l))
402 printf(",");
404 printf(")");
406 else
407 printf("unknown expr");
411 * print_pathkeys -
412 * pathkeys list of PathKeys
414 void
415 print_pathkeys(List *pathkeys, List *rtable)
417 ListCell *i;
419 printf("(");
420 foreach(i, pathkeys)
422 PathKey *pathkey = (PathKey *) lfirst(i);
423 EquivalenceClass *eclass;
424 ListCell *k;
425 bool first = true;
427 eclass = pathkey->pk_eclass;
428 /* chase up, in case pathkey is non-canonical */
429 while (eclass->ec_merged)
430 eclass = eclass->ec_merged;
432 printf("(");
433 foreach(k, eclass->ec_members)
435 EquivalenceMember *mem = (EquivalenceMember *) lfirst(k);
437 if (first)
438 first = false;
439 else
440 printf(", ");
441 print_expr((Node *) mem->em_expr, rtable);
443 printf(")");
444 if (lnext(i))
445 printf(", ");
447 printf(")\n");
451 * print_tl
452 * print targetlist in a more legible way.
454 void
455 print_tl(List *tlist, List *rtable)
457 ListCell *tl;
459 printf("(\n");
460 foreach(tl, tlist)
462 TargetEntry *tle = (TargetEntry *) lfirst(tl);
464 printf("\t%d %s\t", tle->resno,
465 tle->resname ? tle->resname : "<null>");
466 if (tle->ressortgroupref != 0)
467 printf("(%u):\t", tle->ressortgroupref);
468 else
469 printf(" :\t");
470 print_expr((Node *) tle->expr, rtable);
471 printf("\n");
473 printf(")\n");
477 * print_slot
478 * print out the tuple with the given TupleTableSlot
480 void
481 print_slot(TupleTableSlot *slot)
483 if (TupIsNull(slot))
485 printf("tuple is null.\n");
486 return;
488 if (!slot->tts_tupleDescriptor)
490 printf("no tuple descriptor.\n");
491 return;
494 debugtup(slot, NULL);