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