LCOV - code coverage report
Current view: top level - src/interfaces/libpq - fe-print.c (source / functions) Hit Total Coverage
Test: PostgreSQL 15devel Lines: 147 337 43.6 %
Date: 2021-12-09 04:09:06 Functions: 4 7 57.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * fe-print.c
       4             :  *    functions for pretty-printing query results
       5             :  *
       6             :  * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  * These functions were formerly part of fe-exec.c, but they
      10             :  * didn't really belong there.
      11             :  *
      12             :  * IDENTIFICATION
      13             :  *    src/interfaces/libpq/fe-print.c
      14             :  *
      15             :  *-------------------------------------------------------------------------
      16             :  */
      17             : #include "postgres_fe.h"
      18             : 
      19             : #include <signal.h>
      20             : 
      21             : #ifdef WIN32
      22             : #include "win32.h"
      23             : #else
      24             : #include <unistd.h>
      25             : #include <sys/ioctl.h>
      26             : #endif
      27             : 
      28             : #ifdef HAVE_TERMIOS_H
      29             : #include <termios.h>
      30             : #else
      31             : #ifndef WIN32
      32             : #include <sys/termios.h>
      33             : #endif
      34             : #endif
      35             : 
      36             : #include "libpq-fe.h"
      37             : #include "libpq-int.h"
      38             : 
      39             : 
      40             : static bool do_field(const PQprintOpt *po, const PGresult *res,
      41             :                      const int i, const int j, const int fs_len,
      42             :                      char **fields,
      43             :                      const int nFields, const char **fieldNames,
      44             :                      unsigned char *fieldNotNum, int *fieldMax,
      45             :                      const int fieldMaxLen, FILE *fout);
      46             : static char *do_header(FILE *fout, const PQprintOpt *po, const int nFields,
      47             :                        int *fieldMax, const char **fieldNames, unsigned char *fieldNotNum,
      48             :                        const int fs_len, const PGresult *res);
      49             : static void output_row(FILE *fout, const PQprintOpt *po, const int nFields, char **fields,
      50             :                        unsigned char *fieldNotNum, int *fieldMax, char *border,
      51             :                        const int row_index);
      52             : static void fill(int length, int max, char filler, FILE *fp);
      53             : 
      54             : /*
      55             :  * PQprint()
      56             :  *
      57             :  * Format results of a query for printing.
      58             :  *
      59             :  * PQprintOpt is a typedef (structure) that contains
      60             :  * various flags and options. consult libpq-fe.h for
      61             :  * details
      62             :  *
      63             :  * This function should probably be removed sometime since psql
      64             :  * doesn't use it anymore. It is unclear to what extent this is used
      65             :  * by external clients, however.
      66             :  */
      67             : void
      68        6114 : PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po)
      69             : {
      70             :     int         nFields;
      71             : 
      72        6114 :     nFields = PQnfields(res);
      73             : 
      74        6114 :     if (nFields > 0)
      75             :     {                           /* only print rows with at least 1 field.  */
      76             :         int         i,
      77             :                     j;
      78             :         int         nTups;
      79        6114 :         int        *fieldMax = NULL;    /* in case we don't use them */
      80        6114 :         unsigned char *fieldNotNum = NULL;
      81        6114 :         char       *border = NULL;
      82        6114 :         char      **fields = NULL;
      83        6114 :         const char **fieldNames = NULL;
      84        6114 :         int         fieldMaxLen = 0;
      85             :         int         numFieldName;
      86        6114 :         int         fs_len = strlen(po->fieldSep);
      87        6114 :         int         total_line_length = 0;
      88        6114 :         bool        usePipe = false;
      89             :         char       *pagerenv;
      90             : 
      91             : #if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32)
      92             :         sigset_t    osigset;
      93        6114 :         bool        sigpipe_masked = false;
      94             :         bool        sigpipe_pending;
      95             : #endif
      96             : #if !defined(ENABLE_THREAD_SAFETY) && !defined(WIN32)
      97             :         pqsigfunc   oldsigpipehandler = NULL;
      98             : #endif
      99             : 
     100             : #ifdef TIOCGWINSZ
     101             :         struct winsize screen_size;
     102             : #else
     103             :         struct winsize
     104             :         {
     105             :             int         ws_row;
     106             :             int         ws_col;
     107             :         }           screen_size;
     108             : #endif
     109             : 
     110        6114 :         nTups = PQntuples(res);
     111        6114 :         fieldNames = (const char **) calloc(nFields, sizeof(char *));
     112        6114 :         fieldNotNum = (unsigned char *) calloc(nFields, 1);
     113        6114 :         fieldMax = (int *) calloc(nFields, sizeof(int));
     114        6114 :         if (!fieldNames || !fieldNotNum || !fieldMax)
     115             :         {
     116           0 :             fprintf(stderr, libpq_gettext("out of memory\n"));
     117           0 :             goto exit;
     118             :         }
     119        6114 :         for (numFieldName = 0;
     120        6114 :              po->fieldName && po->fieldName[numFieldName];
     121           0 :              numFieldName++)
     122             :             ;
     123       15272 :         for (j = 0; j < nFields; j++)
     124             :         {
     125             :             int         len;
     126        9158 :             const char *s = (j < numFieldName && po->fieldName[j][0]) ?
     127        9158 :             po->fieldName[j] : PQfname(res, j);
     128             : 
     129        9158 :             fieldNames[j] = s;
     130        9158 :             len = s ? strlen(s) : 0;
     131        9158 :             fieldMax[j] = len;
     132        9158 :             len += fs_len;
     133        9158 :             if (len > fieldMaxLen)
     134        8284 :                 fieldMaxLen = len;
     135        9158 :             total_line_length += len;
     136             :         }
     137             : 
     138        6114 :         total_line_length += nFields * strlen(po->fieldSep) + 1;
     139             : 
     140        6114 :         if (fout == NULL)
     141           0 :             fout = stdout;
     142        6114 :         if (po->pager && fout == stdout && isatty(fileno(stdin)) &&
     143           0 :             isatty(fileno(stdout)))
     144             :         {
     145             :             /*
     146             :              * If we think there'll be more than one screen of output, try to
     147             :              * pipe to the pager program.
     148             :              */
     149             : #ifdef TIOCGWINSZ
     150           0 :             if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) == -1 ||
     151           0 :                 screen_size.ws_col == 0 ||
     152           0 :                 screen_size.ws_row == 0)
     153             :             {
     154           0 :                 screen_size.ws_row = 24;
     155           0 :                 screen_size.ws_col = 80;
     156             :             }
     157             : #else
     158             :             screen_size.ws_row = 24;
     159             :             screen_size.ws_col = 80;
     160             : #endif
     161             : 
     162             :             /*
     163             :              * Since this function is no longer used by psql, we don't examine
     164             :              * PSQL_PAGER.  It's possible that the hypothetical external users
     165             :              * of the function would like that to happen, but in the name of
     166             :              * backwards compatibility, we'll stick to just examining PAGER.
     167             :              */
     168           0 :             pagerenv = getenv("PAGER");
     169             :             /* if PAGER is unset, empty or all-white-space, don't use pager */
     170           0 :             if (pagerenv != NULL &&
     171           0 :                 strspn(pagerenv, " \t\r\n") != strlen(pagerenv) &&
     172           0 :                 !po->html3 &&
     173           0 :                 ((po->expanded &&
     174           0 :                   nTups * (nFields + 1) >= screen_size.ws_row) ||
     175           0 :                  (!po->expanded &&
     176           0 :                   nTups * (total_line_length / screen_size.ws_col + 1) *
     177           0 :                   (1 + (po->standard != 0)) >= screen_size.ws_row -
     178           0 :                   (po->header != 0) *
     179           0 :                   (total_line_length / screen_size.ws_col + 1) * 2
     180           0 :                   - (po->header != 0) * 2    /* row count and newline */
     181             :                   )))
     182             :             {
     183           0 :                 fout = popen(pagerenv, "w");
     184           0 :                 if (fout)
     185             :                 {
     186           0 :                     usePipe = true;
     187             : #ifndef WIN32
     188             : #ifdef ENABLE_THREAD_SAFETY
     189           0 :                     if (pq_block_sigpipe(&osigset, &sigpipe_pending) == 0)
     190           0 :                         sigpipe_masked = true;
     191             : #else
     192             :                     oldsigpipehandler = pqsignal(SIGPIPE, SIG_IGN);
     193             : #endif                          /* ENABLE_THREAD_SAFETY */
     194             : #endif                          /* WIN32 */
     195             :                 }
     196             :                 else
     197           0 :                     fout = stdout;
     198             :             }
     199             :         }
     200             : 
     201        6114 :         if (!po->expanded && (po->align || po->html3))
     202             :         {
     203        6114 :             fields = (char **) calloc((size_t) nTups + 1,
     204             :                                       nFields * sizeof(char *));
     205        6114 :             if (!fields)
     206             :             {
     207           0 :                 fprintf(stderr, libpq_gettext("out of memory\n"));
     208           0 :                 goto exit;
     209             :             }
     210             :         }
     211           0 :         else if (po->header && !po->html3)
     212             :         {
     213           0 :             if (po->expanded)
     214             :             {
     215           0 :                 if (po->align)
     216           0 :                     fprintf(fout, libpq_gettext("%-*s%s Value\n"),
     217             :                             fieldMaxLen - fs_len, libpq_gettext("Field"), po->fieldSep);
     218             :                 else
     219           0 :                     fprintf(fout, libpq_gettext("%s%sValue\n"), libpq_gettext("Field"), po->fieldSep);
     220             :             }
     221             :             else
     222             :             {
     223           0 :                 int         len = 0;
     224             : 
     225           0 :                 for (j = 0; j < nFields; j++)
     226             :                 {
     227           0 :                     const char *s = fieldNames[j];
     228             : 
     229           0 :                     fputs(s, fout);
     230           0 :                     len += strlen(s) + fs_len;
     231           0 :                     if ((j + 1) < nFields)
     232           0 :                         fputs(po->fieldSep, fout);
     233             :                 }
     234           0 :                 fputc('\n', fout);
     235           0 :                 for (len -= fs_len; len--; fputc('-', fout));
     236           0 :                 fputc('\n', fout);
     237             :             }
     238             :         }
     239        6114 :         if (po->expanded && po->html3)
     240             :         {
     241           0 :             if (po->caption)
     242           0 :                 fprintf(fout, "<center><h2>%s</h2></center>\n", po->caption);
     243             :             else
     244           0 :                 fprintf(fout,
     245             :                         "<center><h2>"
     246             :                         "Query retrieved %d rows * %d fields"
     247             :                         "</h2></center>\n",
     248             :                         nTups, nFields);
     249             :         }
     250       14800 :         for (i = 0; i < nTups; i++)
     251             :         {
     252        8686 :             if (po->expanded)
     253             :             {
     254           0 :                 if (po->html3)
     255           0 :                     fprintf(fout,
     256             :                             "<table %s><caption align=\"top\">%d</caption>\n",
     257           0 :                             po->tableOpt ? po->tableOpt : "", i);
     258             :                 else
     259           0 :                     fprintf(fout, libpq_gettext("-- RECORD %d --\n"), i);
     260             :             }
     261       23362 :             for (j = 0; j < nFields; j++)
     262             :             {
     263       14676 :                 if (!do_field(po, res, i, j, fs_len, fields, nFields,
     264             :                               fieldNames, fieldNotNum,
     265             :                               fieldMax, fieldMaxLen, fout))
     266           0 :                     goto exit;
     267             :             }
     268        8686 :             if (po->html3 && po->expanded)
     269           0 :                 fputs("</table>\n", fout);
     270             :         }
     271        6114 :         if (!po->expanded && (po->align || po->html3))
     272             :         {
     273        6114 :             if (po->html3)
     274             :             {
     275           0 :                 if (po->header)
     276             :                 {
     277           0 :                     if (po->caption)
     278           0 :                         fprintf(fout,
     279             :                                 "<table %s><caption align=\"top\">%s</caption>\n",
     280           0 :                                 po->tableOpt ? po->tableOpt : "",
     281             :                                 po->caption);
     282             :                     else
     283           0 :                         fprintf(fout,
     284             :                                 "<table %s><caption align=\"top\">"
     285             :                                 "Retrieved %d rows * %d fields"
     286             :                                 "</caption>\n",
     287           0 :                                 po->tableOpt ? po->tableOpt : "", nTups, nFields);
     288             :                 }
     289             :                 else
     290           0 :                     fprintf(fout, "<table %s>", po->tableOpt ? po->tableOpt : "");
     291             :             }
     292        6114 :             if (po->header)
     293        6114 :                 border = do_header(fout, po, nFields, fieldMax, fieldNames,
     294             :                                    fieldNotNum, fs_len, res);
     295       14800 :             for (i = 0; i < nTups; i++)
     296        8686 :                 output_row(fout, po, nFields, fields,
     297             :                            fieldNotNum, fieldMax, border, i);
     298             :         }
     299        6114 :         if (po->header && !po->html3)
     300        6114 :             fprintf(fout, "(%d row%s)\n\n", PQntuples(res),
     301        6114 :                     (PQntuples(res) == 1) ? "" : "s");
     302        6114 :         if (po->html3 && !po->expanded)
     303           0 :             fputs("</table>\n", fout);
     304             : 
     305        6114 : exit:
     306        6114 :         if (fieldMax)
     307        6114 :             free(fieldMax);
     308        6114 :         if (fieldNotNum)
     309        6114 :             free(fieldNotNum);
     310        6114 :         if (border)
     311        6114 :             free(border);
     312        6114 :         if (fields)
     313             :         {
     314             :             /* if calloc succeeded, this shouldn't overflow size_t */
     315        6114 :             size_t      numfields = ((size_t) nTups + 1) * (size_t) nFields;
     316             : 
     317       29948 :             while (numfields-- > 0)
     318             :             {
     319       23834 :                 if (fields[numfields])
     320       14208 :                     free(fields[numfields]);
     321             :             }
     322        6114 :             free(fields);
     323             :         }
     324        6114 :         if (fieldNames)
     325        6114 :             free((void *) fieldNames);
     326        6114 :         if (usePipe)
     327             :         {
     328             : #ifdef WIN32
     329             :             _pclose(fout);
     330             : #else
     331           0 :             pclose(fout);
     332             : 
     333             : #ifdef ENABLE_THREAD_SAFETY
     334             :             /* we can't easily verify if EPIPE occurred, so say it did */
     335           0 :             if (sigpipe_masked)
     336           0 :                 pq_reset_sigpipe(&osigset, sigpipe_pending, true);
     337             : #else
     338             :             pqsignal(SIGPIPE, oldsigpipehandler);
     339             : #endif                          /* ENABLE_THREAD_SAFETY */
     340             : #endif                          /* WIN32 */
     341             :         }
     342             :     }
     343        6114 : }
     344             : 
     345             : 
     346             : static bool
     347       14676 : do_field(const PQprintOpt *po, const PGresult *res,
     348             :          const int i, const int j, const int fs_len,
     349             :          char **fields,
     350             :          const int nFields, char const **fieldNames,
     351             :          unsigned char *fieldNotNum, int *fieldMax,
     352             :          const int fieldMaxLen, FILE *fout)
     353             : {
     354             :     const char *pval,
     355             :                *p;
     356             :     int         plen;
     357             :     bool        skipit;
     358             : 
     359       14676 :     plen = PQgetlength(res, i, j);
     360       14676 :     pval = PQgetvalue(res, i, j);
     361             : 
     362       14676 :     if (plen < 1 || !pval || !*pval)
     363             :     {
     364         468 :         if (po->align || po->expanded)
     365         468 :             skipit = true;
     366             :         else
     367             :         {
     368           0 :             skipit = false;
     369           0 :             goto efield;
     370             :         }
     371             :     }
     372             :     else
     373       14208 :         skipit = false;
     374             : 
     375       14676 :     if (!skipit)
     376             :     {
     377       14208 :         if (po->align && !fieldNotNum[j])
     378             :         {
     379             :             /* Detect whether field contains non-numeric data */
     380       12816 :             char        ch = '0';
     381             : 
     382       41210 :             for (p = pval; *p; p += PQmblenBounded(p, res->client_encoding))
     383             :             {
     384       31032 :                 ch = *p;
     385       36266 :                 if (!((ch >= '0' && ch <= '9') ||
     386        5240 :                       ch == '.' ||
     387        5234 :                       ch == 'E' ||
     388        5234 :                       ch == 'e' ||
     389             :                       ch == ' ' ||
     390             :                       ch == '-'))
     391             :                 {
     392        2638 :                     fieldNotNum[j] = 1;
     393        2638 :                     break;
     394             :                 }
     395             :             }
     396             : 
     397             :             /*
     398             :              * Above loop will believe E in first column is numeric; also, we
     399             :              * insist on a digit in the last column for a numeric. This test
     400             :              * is still not bulletproof but it handles most cases.
     401             :              */
     402       12816 :             if (*pval == 'E' || *pval == 'e' ||
     403       12804 :                 !(ch >= '0' && ch <= '9'))
     404        2638 :                 fieldNotNum[j] = 1;
     405             :         }
     406             : 
     407       14208 :         if (!po->expanded && (po->align || po->html3))
     408             :         {
     409       14208 :             if (plen > fieldMax[j])
     410        1920 :                 fieldMax[j] = plen;
     411       14208 :             if (!(fields[i * nFields + j] = (char *) malloc(plen + 1)))
     412             :             {
     413           0 :                 fprintf(stderr, libpq_gettext("out of memory\n"));
     414           0 :                 return false;
     415             :             }
     416       14208 :             strcpy(fields[i * nFields + j], pval);
     417             :         }
     418             :         else
     419             :         {
     420           0 :             if (po->expanded)
     421             :             {
     422           0 :                 if (po->html3)
     423           0 :                     fprintf(fout,
     424             :                             "<tr><td align=\"left\"><b>%s</b></td>"
     425             :                             "<td align=\"%s\">%s</td></tr>\n",
     426           0 :                             fieldNames[j],
     427           0 :                             fieldNotNum[j] ? "left" : "right",
     428             :                             pval);
     429             :                 else
     430             :                 {
     431           0 :                     if (po->align)
     432           0 :                         fprintf(fout,
     433             :                                 "%-*s%s %s\n",
     434           0 :                                 fieldMaxLen - fs_len, fieldNames[j],
     435             :                                 po->fieldSep,
     436             :                                 pval);
     437             :                     else
     438           0 :                         fprintf(fout,
     439             :                                 "%s%s%s\n",
     440           0 :                                 fieldNames[j], po->fieldSep, pval);
     441             :                 }
     442             :             }
     443             :             else
     444             :             {
     445           0 :                 if (!po->html3)
     446             :                 {
     447           0 :                     fputs(pval, fout);
     448           0 :             efield:
     449           0 :                     if ((j + 1) < nFields)
     450           0 :                         fputs(po->fieldSep, fout);
     451             :                     else
     452           0 :                         fputc('\n', fout);
     453             :                 }
     454             :             }
     455             :         }
     456             :     }
     457       14676 :     return true;
     458             : }
     459             : 
     460             : 
     461             : static char *
     462        6114 : do_header(FILE *fout, const PQprintOpt *po, const int nFields, int *fieldMax,
     463             :           const char **fieldNames, unsigned char *fieldNotNum,
     464             :           const int fs_len, const PGresult *res)
     465             : {
     466             :     int         j;              /* for loop index */
     467        6114 :     char       *border = NULL;
     468             : 
     469        6114 :     if (po->html3)
     470           0 :         fputs("<tr>", fout);
     471             :     else
     472             :     {
     473        6114 :         int         tot = 0;
     474        6114 :         int         n = 0;
     475        6114 :         char       *p = NULL;
     476             : 
     477       15272 :         for (; n < nFields; n++)
     478        9158 :             tot += fieldMax[n] + fs_len + (po->standard ? 2 : 0);
     479        6114 :         if (po->standard)
     480           0 :             tot += fs_len * 2 + 2;
     481        6114 :         border = malloc(tot + 1);
     482        6114 :         if (!border)
     483             :         {
     484           0 :             fprintf(stderr, libpq_gettext("out of memory\n"));
     485           0 :             return NULL;
     486             :         }
     487        6114 :         p = border;
     488        6114 :         if (po->standard)
     489             :         {
     490           0 :             char       *fs = po->fieldSep;
     491             : 
     492           0 :             while (*fs++)
     493           0 :                 *p++ = '+';
     494             :         }
     495       15272 :         for (j = 0; j < nFields; j++)
     496             :         {
     497             :             int         len;
     498             : 
     499       77054 :             for (len = fieldMax[j] + (po->standard ? 2 : 0); len--; *p++ = '-');
     500        9158 :             if (po->standard || (j + 1) < nFields)
     501             :             {
     502        3044 :                 char       *fs = po->fieldSep;
     503             : 
     504        6088 :                 while (*fs++)
     505        3044 :                     *p++ = '+';
     506             :             }
     507             :         }
     508        6114 :         *p = '\0';
     509        6114 :         if (po->standard)
     510           0 :             fprintf(fout, "%s\n", border);
     511             :     }
     512        6114 :     if (po->standard)
     513           0 :         fputs(po->fieldSep, fout);
     514       15272 :     for (j = 0; j < nFields; j++)
     515             :     {
     516        9158 :         const char *s = PQfname(res, j);
     517             : 
     518        9158 :         if (po->html3)
     519             :         {
     520           0 :             fprintf(fout, "<th align=\"%s\">%s</th>",
     521           0 :                     fieldNotNum[j] ? "left" : "right", fieldNames[j]);
     522             :         }
     523             :         else
     524             :         {
     525        9158 :             int         n = strlen(s);
     526             : 
     527        9158 :             if (n > fieldMax[j])
     528           0 :                 fieldMax[j] = n;
     529        9158 :             if (po->standard)
     530           0 :                 fprintf(fout,
     531           0 :                         fieldNotNum[j] ? " %-*s " : " %*s ",
     532           0 :                         fieldMax[j], s);
     533             :             else
     534        9158 :                 fprintf(fout, fieldNotNum[j] ? "%-*s" : "%*s", fieldMax[j], s);
     535        9158 :             if (po->standard || (j + 1) < nFields)
     536        3044 :                 fputs(po->fieldSep, fout);
     537             :         }
     538             :     }
     539        6114 :     if (po->html3)
     540           0 :         fputs("</tr>\n", fout);
     541             :     else
     542        6114 :         fprintf(fout, "\n%s\n", border);
     543        6114 :     return border;
     544             : }
     545             : 
     546             : 
     547             : static void
     548        8686 : output_row(FILE *fout, const PQprintOpt *po, const int nFields, char **fields,
     549             :            unsigned char *fieldNotNum, int *fieldMax, char *border,
     550             :            const int row_index)
     551             : {
     552             :     int         field_index;    /* for loop index */
     553             : 
     554        8686 :     if (po->html3)
     555           0 :         fputs("<tr>", fout);
     556        8686 :     else if (po->standard)
     557           0 :         fputs(po->fieldSep, fout);
     558       23362 :     for (field_index = 0; field_index < nFields; field_index++)
     559             :     {
     560       14676 :         char       *p = fields[row_index * nFields + field_index];
     561             : 
     562       14676 :         if (po->html3)
     563           0 :             fprintf(fout, "<td align=\"%s\">%s</td>",
     564           0 :                     fieldNotNum[field_index] ? "left" : "right", p ? p : "");
     565             :         else
     566             :         {
     567       29352 :             fprintf(fout,
     568       14676 :                     fieldNotNum[field_index] ?
     569       14676 :                     (po->standard ? " %-*s " : "%-*s") :
     570       10636 :                     (po->standard ? " %*s " : "%*s"),
     571       14676 :                     fieldMax[field_index],
     572             :                     p ? p : "");
     573       14676 :             if (po->standard || field_index + 1 < nFields)
     574        5990 :                 fputs(po->fieldSep, fout);
     575             :         }
     576             :     }
     577        8686 :     if (po->html3)
     578           0 :         fputs("</tr>", fout);
     579        8686 :     else if (po->standard)
     580           0 :         fprintf(fout, "\n%s", border);
     581        8686 :     fputc('\n', fout);
     582        8686 : }
     583             : 
     584             : 
     585             : 
     586             : /*
     587             :  * really old printing routines
     588             :  */
     589             : 
     590             : void
     591           0 : PQdisplayTuples(const PGresult *res,
     592             :                 FILE *fp,       /* where to send the output */
     593             :                 int fillAlign,  /* pad the fields with spaces */
     594             :                 const char *fieldSep,   /* field separator */
     595             :                 int printHeader,    /* display headers? */
     596             :                 int quiet
     597             : )
     598             : {
     599             : #define DEFAULT_FIELD_SEP " "
     600             : 
     601             :     int         i,
     602             :                 j;
     603             :     int         nFields;
     604             :     int         nTuples;
     605           0 :     int        *fLength = NULL;
     606             : 
     607           0 :     if (fieldSep == NULL)
     608           0 :         fieldSep = DEFAULT_FIELD_SEP;
     609             : 
     610             :     /* Get some useful info about the results */
     611           0 :     nFields = PQnfields(res);
     612           0 :     nTuples = PQntuples(res);
     613             : 
     614           0 :     if (fp == NULL)
     615           0 :         fp = stdout;
     616             : 
     617             :     /* Figure the field lengths to align to */
     618             :     /* will be somewhat time consuming for very large results */
     619           0 :     if (fillAlign)
     620             :     {
     621           0 :         fLength = (int *) malloc(nFields * sizeof(int));
     622           0 :         if (!fLength)
     623             :         {
     624           0 :             fprintf(stderr, libpq_gettext("out of memory\n"));
     625           0 :             return;
     626             :         }
     627             : 
     628           0 :         for (j = 0; j < nFields; j++)
     629             :         {
     630           0 :             fLength[j] = strlen(PQfname(res, j));
     631           0 :             for (i = 0; i < nTuples; i++)
     632             :             {
     633           0 :                 int         flen = PQgetlength(res, i, j);
     634             : 
     635           0 :                 if (flen > fLength[j])
     636           0 :                     fLength[j] = flen;
     637             :             }
     638             :         }
     639             :     }
     640             : 
     641           0 :     if (printHeader)
     642             :     {
     643             :         /* first, print out the attribute names */
     644           0 :         for (i = 0; i < nFields; i++)
     645             :         {
     646           0 :             fputs(PQfname(res, i), fp);
     647           0 :             if (fillAlign)
     648           0 :                 fill(strlen(PQfname(res, i)), fLength[i], ' ', fp);
     649           0 :             fputs(fieldSep, fp);
     650             :         }
     651           0 :         fprintf(fp, "\n");
     652             : 
     653             :         /* Underline the attribute names */
     654           0 :         for (i = 0; i < nFields; i++)
     655             :         {
     656           0 :             if (fillAlign)
     657           0 :                 fill(0, fLength[i], '-', fp);
     658           0 :             fputs(fieldSep, fp);
     659             :         }
     660           0 :         fprintf(fp, "\n");
     661             :     }
     662             : 
     663             :     /* next, print out the instances */
     664           0 :     for (i = 0; i < nTuples; i++)
     665             :     {
     666           0 :         for (j = 0; j < nFields; j++)
     667             :         {
     668           0 :             fprintf(fp, "%s", PQgetvalue(res, i, j));
     669           0 :             if (fillAlign)
     670           0 :                 fill(strlen(PQgetvalue(res, i, j)), fLength[j], ' ', fp);
     671           0 :             fputs(fieldSep, fp);
     672             :         }
     673           0 :         fprintf(fp, "\n");
     674             :     }
     675             : 
     676           0 :     if (!quiet)
     677           0 :         fprintf(fp, "\nQuery returned %d row%s.\n", PQntuples(res),
     678           0 :                 (PQntuples(res) == 1) ? "" : "s");
     679             : 
     680           0 :     fflush(fp);
     681             : 
     682           0 :     if (fLength)
     683           0 :         free(fLength);
     684             : }
     685             : 
     686             : 
     687             : 
     688             : void
     689           0 : PQprintTuples(const PGresult *res,
     690             :               FILE *fout,       /* output stream */
     691             :               int PrintAttNames,    /* print attribute names or not */
     692             :               int TerseOutput,  /* delimiter bars or not? */
     693             :               int colWidth      /* width of column, if 0, use variable width */
     694             : )
     695             : {
     696             :     int         nFields;
     697             :     int         nTups;
     698             :     int         i,
     699             :                 j;
     700             :     char        formatString[80];
     701           0 :     char       *tborder = NULL;
     702             : 
     703           0 :     nFields = PQnfields(res);
     704           0 :     nTups = PQntuples(res);
     705             : 
     706           0 :     if (colWidth > 0)
     707           0 :         sprintf(formatString, "%%s %%-%ds", colWidth);
     708             :     else
     709           0 :         sprintf(formatString, "%%s %%s");
     710             : 
     711           0 :     if (nFields > 0)
     712             :     {                           /* only print rows with at least 1 field.  */
     713             : 
     714           0 :         if (!TerseOutput)
     715             :         {
     716             :             int         width;
     717             : 
     718           0 :             width = nFields * 14;
     719           0 :             tborder = (char *) malloc(width + 1);
     720           0 :             if (!tborder)
     721             :             {
     722           0 :                 fprintf(stderr, libpq_gettext("out of memory\n"));
     723           0 :                 return;
     724             :             }
     725           0 :             for (i = 0; i < width; i++)
     726           0 :                 tborder[i] = '-';
     727           0 :             tborder[width] = '\0';
     728           0 :             fprintf(fout, "%s\n", tborder);
     729             :         }
     730             : 
     731           0 :         for (i = 0; i < nFields; i++)
     732             :         {
     733           0 :             if (PrintAttNames)
     734             :             {
     735           0 :                 fprintf(fout, formatString,
     736             :                         TerseOutput ? "" : "|",
     737             :                         PQfname(res, i));
     738             :             }
     739             :         }
     740             : 
     741           0 :         if (PrintAttNames)
     742             :         {
     743           0 :             if (TerseOutput)
     744           0 :                 fprintf(fout, "\n");
     745             :             else
     746           0 :                 fprintf(fout, "|\n%s\n", tborder);
     747             :         }
     748             : 
     749           0 :         for (i = 0; i < nTups; i++)
     750             :         {
     751           0 :             for (j = 0; j < nFields; j++)
     752             :             {
     753           0 :                 const char *pval = PQgetvalue(res, i, j);
     754             : 
     755           0 :                 fprintf(fout, formatString,
     756             :                         TerseOutput ? "" : "|",
     757             :                         pval ? pval : "");
     758             :             }
     759           0 :             if (TerseOutput)
     760           0 :                 fprintf(fout, "\n");
     761             :             else
     762           0 :                 fprintf(fout, "|\n%s\n", tborder);
     763             :         }
     764             :     }
     765             : 
     766           0 :     if (tborder)
     767           0 :         free(tborder);
     768             : }
     769             : 
     770             : 
     771             : /* simply send out max-length number of filler characters to fp */
     772             : 
     773             : static void
     774           0 : fill(int length, int max, char filler, FILE *fp)
     775             : {
     776             :     int         count;
     777             : 
     778           0 :     count = max - length;
     779           0 :     while (count-- >= 0)
     780           0 :         putc(filler, fp);
     781           0 : }

Generated by: LCOV version 1.14