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