YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

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