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

Generated by: LCOV version 1.16