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

Generated by: LCOV version 1.16