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

Generated by: LCOV version 1.14