Header And Logo

PostgreSQL
| The world's most advanced open source database.

print.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * print.c
00004  *    various print routines (used mostly for debugging)
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/nodes/print.c
00012  *
00013  * HISTORY
00014  *    AUTHOR            DATE            MAJOR EVENT
00015  *    Andrew Yu         Oct 26, 1994    file creation
00016  *
00017  *-------------------------------------------------------------------------
00018  */
00019 
00020 #include "postgres.h"
00021 
00022 #include "access/printtup.h"
00023 #include "lib/stringinfo.h"
00024 #include "nodes/print.h"
00025 #include "optimizer/clauses.h"
00026 #include "parser/parsetree.h"
00027 #include "utils/lsyscache.h"
00028 
00029 
00030 /*
00031  * print
00032  *    print contents of Node to stdout
00033  */
00034 void
00035 print(const void *obj)
00036 {
00037     char       *s;
00038     char       *f;
00039 
00040     s = nodeToString(obj);
00041     f = format_node_dump(s);
00042     pfree(s);
00043     printf("%s\n", f);
00044     fflush(stdout);
00045     pfree(f);
00046 }
00047 
00048 /*
00049  * pprint
00050  *    pretty-print contents of Node to stdout
00051  */
00052 void
00053 pprint(const void *obj)
00054 {
00055     char       *s;
00056     char       *f;
00057 
00058     s = nodeToString(obj);
00059     f = pretty_format_node_dump(s);
00060     pfree(s);
00061     printf("%s\n", f);
00062     fflush(stdout);
00063     pfree(f);
00064 }
00065 
00066 /*
00067  * elog_node_display
00068  *    send pretty-printed contents of Node to postmaster log
00069  */
00070 void
00071 elog_node_display(int lev, const char *title, const void *obj, bool pretty)
00072 {
00073     char       *s;
00074     char       *f;
00075 
00076     s = nodeToString(obj);
00077     if (pretty)
00078         f = pretty_format_node_dump(s);
00079     else
00080         f = format_node_dump(s);
00081     pfree(s);
00082     ereport(lev,
00083             (errmsg_internal("%s:", title),
00084              errdetail_internal("%s", f)));
00085     pfree(f);
00086 }
00087 
00088 /*
00089  * Format a nodeToString output for display on a terminal.
00090  *
00091  * The result is a palloc'd string.
00092  *
00093  * This version just tries to break at whitespace.
00094  */
00095 char *
00096 format_node_dump(const char *dump)
00097 {
00098 #define LINELEN     78
00099     char        line[LINELEN + 1];
00100     StringInfoData str;
00101     int         i;
00102     int         j;
00103     int         k;
00104 
00105     initStringInfo(&str);
00106     i = 0;
00107     for (;;)
00108     {
00109         for (j = 0; j < LINELEN && dump[i] != '\0'; i++, j++)
00110             line[j] = dump[i];
00111         if (dump[i] == '\0')
00112             break;
00113         if (dump[i] == ' ')
00114         {
00115             /* ok to break at adjacent space */
00116             i++;
00117         }
00118         else
00119         {
00120             for (k = j - 1; k > 0; k--)
00121                 if (line[k] == ' ')
00122                     break;
00123             if (k > 0)
00124             {
00125                 /* back up; will reprint all after space */
00126                 i -= (j - k - 1);
00127                 j = k;
00128             }
00129         }
00130         line[j] = '\0';
00131         appendStringInfo(&str, "%s\n", line);
00132     }
00133     if (j > 0)
00134     {
00135         line[j] = '\0';
00136         appendStringInfo(&str, "%s\n", line);
00137     }
00138     return str.data;
00139 #undef LINELEN
00140 }
00141 
00142 /*
00143  * Format a nodeToString output for display on a terminal.
00144  *
00145  * The result is a palloc'd string.
00146  *
00147  * This version tries to indent intelligently.
00148  */
00149 char *
00150 pretty_format_node_dump(const char *dump)
00151 {
00152 #define INDENTSTOP  3
00153 #define MAXINDENT   60
00154 #define LINELEN     78
00155     char        line[LINELEN + 1];
00156     StringInfoData str;
00157     int         indentLev;
00158     int         indentDist;
00159     int         i;
00160     int         j;
00161 
00162     initStringInfo(&str);
00163     indentLev = 0;              /* logical indent level */
00164     indentDist = 0;             /* physical indent distance */
00165     i = 0;
00166     for (;;)
00167     {
00168         for (j = 0; j < indentDist; j++)
00169             line[j] = ' ';
00170         for (; j < LINELEN && dump[i] != '\0'; i++, j++)
00171         {
00172             line[j] = dump[i];
00173             switch (line[j])
00174             {
00175                 case '}':
00176                     if (j != indentDist)
00177                     {
00178                         /* print data before the } */
00179                         line[j] = '\0';
00180                         appendStringInfo(&str, "%s\n", line);
00181                     }
00182                     /* print the } at indentDist */
00183                     line[indentDist] = '}';
00184                     line[indentDist + 1] = '\0';
00185                     appendStringInfo(&str, "%s\n", line);
00186                     /* outdent */
00187                     if (indentLev > 0)
00188                     {
00189                         indentLev--;
00190                         indentDist = Min(indentLev * INDENTSTOP, MAXINDENT);
00191                     }
00192                     j = indentDist - 1;
00193                     /* j will equal indentDist on next loop iteration */
00194                     /* suppress whitespace just after } */
00195                     while (dump[i + 1] == ' ')
00196                         i++;
00197                     break;
00198                 case ')':
00199                     /* force line break after ), unless another ) follows */
00200                     if (dump[i + 1] != ')')
00201                     {
00202                         line[j + 1] = '\0';
00203                         appendStringInfo(&str, "%s\n", line);
00204                         j = indentDist - 1;
00205                         while (dump[i + 1] == ' ')
00206                             i++;
00207                     }
00208                     break;
00209                 case '{':
00210                     /* force line break before { */
00211                     if (j != indentDist)
00212                     {
00213                         line[j] = '\0';
00214                         appendStringInfo(&str, "%s\n", line);
00215                     }
00216                     /* indent */
00217                     indentLev++;
00218                     indentDist = Min(indentLev * INDENTSTOP, MAXINDENT);
00219                     for (j = 0; j < indentDist; j++)
00220                         line[j] = ' ';
00221                     line[j] = dump[i];
00222                     break;
00223                 case ':':
00224                     /* force line break before : */
00225                     if (j != indentDist)
00226                     {
00227                         line[j] = '\0';
00228                         appendStringInfo(&str, "%s\n", line);
00229                     }
00230                     j = indentDist;
00231                     line[j] = dump[i];
00232                     break;
00233             }
00234         }
00235         line[j] = '\0';
00236         if (dump[i] == '\0')
00237             break;
00238         appendStringInfo(&str, "%s\n", line);
00239     }
00240     if (j > 0)
00241         appendStringInfo(&str, "%s\n", line);
00242     return str.data;
00243 #undef INDENTSTOP
00244 #undef MAXINDENT
00245 #undef LINELEN
00246 }
00247 
00248 /*
00249  * print_rt
00250  *    print contents of range table
00251  */
00252 void
00253 print_rt(const List *rtable)
00254 {
00255     const ListCell *l;
00256     int         i = 1;
00257 
00258     printf("resno\trefname  \trelid\tinFromCl\n");
00259     printf("-----\t---------\t-----\t--------\n");
00260     foreach(l, rtable)
00261     {
00262         RangeTblEntry *rte = lfirst(l);
00263 
00264         switch (rte->rtekind)
00265         {
00266             case RTE_RELATION:
00267                 printf("%d\t%s\t%u\t%c",
00268                        i, rte->eref->aliasname, rte->relid, rte->relkind);
00269                 break;
00270             case RTE_SUBQUERY:
00271                 printf("%d\t%s\t[subquery]",
00272                        i, rte->eref->aliasname);
00273                 break;
00274             case RTE_JOIN:
00275                 printf("%d\t%s\t[join]",
00276                        i, rte->eref->aliasname);
00277                 break;
00278             case RTE_FUNCTION:
00279                 printf("%d\t%s\t[rangefunction]",
00280                        i, rte->eref->aliasname);
00281                 break;
00282             case RTE_VALUES:
00283                 printf("%d\t%s\t[values list]",
00284                        i, rte->eref->aliasname);
00285                 break;
00286             case RTE_CTE:
00287                 printf("%d\t%s\t[cte]",
00288                        i, rte->eref->aliasname);
00289                 break;
00290             default:
00291                 printf("%d\t%s\t[unknown rtekind]",
00292                        i, rte->eref->aliasname);
00293         }
00294 
00295         printf("\t%s\t%s\n",
00296                (rte->inh ? "inh" : ""),
00297                (rte->inFromCl ? "inFromCl" : ""));
00298         i++;
00299     }
00300 }
00301 
00302 
00303 /*
00304  * print_expr
00305  *    print an expression
00306  */
00307 void
00308 print_expr(const Node *expr, const List *rtable)
00309 {
00310     if (expr == NULL)
00311     {
00312         printf("<>");
00313         return;
00314     }
00315 
00316     if (IsA(expr, Var))
00317     {
00318         const Var  *var = (const Var *) expr;
00319         char       *relname,
00320                    *attname;
00321 
00322         switch (var->varno)
00323         {
00324             case INNER_VAR:
00325                 relname = "INNER";
00326                 attname = "?";
00327                 break;
00328             case OUTER_VAR:
00329                 relname = "OUTER";
00330                 attname = "?";
00331                 break;
00332             case INDEX_VAR:
00333                 relname = "INDEX";
00334                 attname = "?";
00335                 break;
00336             default:
00337                 {
00338                     RangeTblEntry *rte;
00339 
00340                     Assert(var->varno > 0 &&
00341                            (int) var->varno <= list_length(rtable));
00342                     rte = rt_fetch(var->varno, rtable);
00343                     relname = rte->eref->aliasname;
00344                     attname = get_rte_attribute_name(rte, var->varattno);
00345                 }
00346                 break;
00347         }
00348         printf("%s.%s", relname, attname);
00349     }
00350     else if (IsA(expr, Const))
00351     {
00352         const Const *c = (const Const *) expr;
00353         Oid         typoutput;
00354         bool        typIsVarlena;
00355         char       *outputstr;
00356 
00357         if (c->constisnull)
00358         {
00359             printf("NULL");
00360             return;
00361         }
00362 
00363         getTypeOutputInfo(c->consttype,
00364                           &typoutput, &typIsVarlena);
00365 
00366         outputstr = OidOutputFunctionCall(typoutput, c->constvalue);
00367         printf("%s", outputstr);
00368         pfree(outputstr);
00369     }
00370     else if (IsA(expr, OpExpr))
00371     {
00372         const OpExpr *e = (const OpExpr *) expr;
00373         char       *opname;
00374 
00375         opname = get_opname(e->opno);
00376         if (list_length(e->args) > 1)
00377         {
00378             print_expr(get_leftop((const Expr *) e), rtable);
00379             printf(" %s ", ((opname != NULL) ? opname : "(invalid operator)"));
00380             print_expr(get_rightop((const Expr *) e), rtable);
00381         }
00382         else
00383         {
00384             /* we print prefix and postfix ops the same... */
00385             printf("%s ", ((opname != NULL) ? opname : "(invalid operator)"));
00386             print_expr(get_leftop((const Expr *) e), rtable);
00387         }
00388     }
00389     else if (IsA(expr, FuncExpr))
00390     {
00391         const FuncExpr *e = (const FuncExpr *) expr;
00392         char       *funcname;
00393         ListCell   *l;
00394 
00395         funcname = get_func_name(e->funcid);
00396         printf("%s(", ((funcname != NULL) ? funcname : "(invalid function)"));
00397         foreach(l, e->args)
00398         {
00399             print_expr(lfirst(l), rtable);
00400             if (lnext(l))
00401                 printf(",");
00402         }
00403         printf(")");
00404     }
00405     else
00406         printf("unknown expr");
00407 }
00408 
00409 /*
00410  * print_pathkeys -
00411  *    pathkeys list of PathKeys
00412  */
00413 void
00414 print_pathkeys(const List *pathkeys, const List *rtable)
00415 {
00416     const ListCell *i;
00417 
00418     printf("(");
00419     foreach(i, pathkeys)
00420     {
00421         PathKey    *pathkey = (PathKey *) lfirst(i);
00422         EquivalenceClass *eclass;
00423         ListCell   *k;
00424         bool        first = true;
00425 
00426         eclass = pathkey->pk_eclass;
00427         /* chase up, in case pathkey is non-canonical */
00428         while (eclass->ec_merged)
00429             eclass = eclass->ec_merged;
00430 
00431         printf("(");
00432         foreach(k, eclass->ec_members)
00433         {
00434             EquivalenceMember *mem = (EquivalenceMember *) lfirst(k);
00435 
00436             if (first)
00437                 first = false;
00438             else
00439                 printf(", ");
00440             print_expr((Node *) mem->em_expr, rtable);
00441         }
00442         printf(")");
00443         if (lnext(i))
00444             printf(", ");
00445     }
00446     printf(")\n");
00447 }
00448 
00449 /*
00450  * print_tl
00451  *    print targetlist in a more legible way.
00452  */
00453 void
00454 print_tl(const List *tlist, const List *rtable)
00455 {
00456     const ListCell *tl;
00457 
00458     printf("(\n");
00459     foreach(tl, tlist)
00460     {
00461         TargetEntry *tle = (TargetEntry *) lfirst(tl);
00462 
00463         printf("\t%d %s\t", tle->resno,
00464                tle->resname ? tle->resname : "<null>");
00465         if (tle->ressortgroupref != 0)
00466             printf("(%u):\t", tle->ressortgroupref);
00467         else
00468             printf("    :\t");
00469         print_expr((Node *) tle->expr, rtable);
00470         printf("\n");
00471     }
00472     printf(")\n");
00473 }
00474 
00475 /*
00476  * print_slot
00477  *    print out the tuple with the given TupleTableSlot
00478  */
00479 void
00480 print_slot(TupleTableSlot *slot)
00481 {
00482     if (TupIsNull(slot))
00483     {
00484         printf("tuple is null.\n");
00485         return;
00486     }
00487     if (!slot->tts_tupleDescriptor)
00488     {
00489         printf("no tuple descriptor.\n");
00490         return;
00491     }
00492 
00493     debugtup(slot, NULL);
00494 }