LCOV - code coverage report
Current view: top level - src/backend/nodes - print.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 0.0 % 237 0
Test Date: 2026-03-10 06:14:44 Functions: 0.0 % 10 0
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.0-1