LCOV - code coverage report
Current view: top level - src/interfaces/libpq - fe-print.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 42.0 % 348 146
Test Date: 2026-03-10 11:15:00 Functions: 57.1 % 7 4
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         3915 : PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po)
      70              : {
      71              :     int         nFields;
      72              : 
      73         3915 :     nFields = PQnfields(res);
      74              : 
      75         3915 :     if (nFields > 0)
      76              :     {                           /* only print rows with at least 1 field.  */
      77              :         int         i,
      78              :                     j;
      79              :         int         nTups;
      80         3854 :         int        *fieldMax = NULL;    /* in case we don't use them */
      81         3854 :         unsigned char *fieldNotNum = NULL;
      82         3854 :         char       *border = NULL;
      83         3854 :         char      **fields = NULL;
      84         3854 :         const char **fieldNames = NULL;
      85         3854 :         int         fieldMaxLen = 0;
      86              :         int         numFieldName;
      87         3854 :         int         fs_len = strlen(po->fieldSep);
      88         3854 :         int         total_line_length = 0;
      89         3854 :         bool        usePipe = false;
      90              :         char       *pagerenv;
      91              : 
      92              : #if !defined(WIN32)
      93              :         sigset_t    osigset;
      94         3854 :         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         3854 :         if (fs_len < strlen(po->fieldSep))
     113              :         {
     114            0 :             fprintf(stderr, libpq_gettext("overlong field separator\n"));
     115            0 :             goto exit;
     116              :         }
     117              : 
     118         3854 :         nTups = PQntuples(res);
     119         3854 :         fieldNames = (const char **) calloc(nFields, sizeof(char *));
     120         3854 :         fieldNotNum = (unsigned char *) calloc(nFields, 1);
     121         3854 :         fieldMax = (int *) calloc(nFields, sizeof(int));
     122         3854 :         if (!fieldNames || !fieldNotNum || !fieldMax)
     123              :         {
     124            0 :             fprintf(stderr, libpq_gettext("out of memory\n"));
     125            0 :             goto exit;
     126              :         }
     127         3854 :         for (numFieldName = 0;
     128         3854 :              po->fieldName && po->fieldName[numFieldName];
     129            0 :              numFieldName++)
     130              :             ;
     131         9972 :         for (j = 0; j < nFields; j++)
     132              :         {
     133              :             int         len;
     134         6118 :             const char *s = (j < numFieldName && po->fieldName[j][0]) ?
     135         6118 :                 po->fieldName[j] : PQfname(res, j);
     136              : 
     137         6118 :             fieldNames[j] = s;
     138         6118 :             len = s ? strlen(s) : 0;
     139         6118 :             fieldMax[j] = len;
     140         6118 :             len += fs_len;
     141         6118 :             if (len > fieldMaxLen)
     142         5086 :                 fieldMaxLen = len;
     143         6118 :             total_line_length += len;
     144              :         }
     145              : 
     146         3854 :         total_line_length += nFields * strlen(po->fieldSep) + 1;
     147              : 
     148         3854 :         if (fout == NULL)
     149            0 :             fout = stdout;
     150         3854 :         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         3854 :         if (!po->expanded && (po->align || po->html3))
     207              :         {
     208         3854 :             fields = (char **) calloc((size_t) nTups + 1,
     209              :                                       nFields * sizeof(char *));
     210         3854 :             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         3854 :         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         9449 :         for (i = 0; i < nTups; i++)
     256              :         {
     257         5595 :             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        15531 :             for (j = 0; j < nFields; j++)
     267              :             {
     268         9936 :                 if (!do_field(po, res, i, j, fs_len, fields, nFields,
     269              :                               fieldNames, fieldNotNum,
     270              :                               fieldMax, fieldMaxLen, fout))
     271            0 :                     goto exit;
     272              :             }
     273         5595 :             if (po->html3 && po->expanded)
     274            0 :                 fputs("</table>\n", fout);
     275              :         }
     276         3854 :         if (!po->expanded && (po->align || po->html3))
     277              :         {
     278         3854 :             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         3854 :             if (po->header)
     298         3854 :                 border = do_header(fout, po, nFields, fieldMax, fieldNames,
     299              :                                    fieldNotNum, fs_len, res);
     300         9449 :             for (i = 0; i < nTups; i++)
     301         5595 :                 output_row(fout, po, nFields, fields,
     302              :                            fieldNotNum, fieldMax, border, i);
     303              :         }
     304         3854 :         if (po->header && !po->html3)
     305         3854 :             fprintf(fout, "(%d row%s)\n\n", PQntuples(res),
     306         3854 :                     (PQntuples(res) == 1) ? "" : "s");
     307         3854 :         if (po->html3 && !po->expanded)
     308            0 :             fputs("</table>\n", fout);
     309              : 
     310         3854 : exit:
     311         3854 :         free(fieldMax);
     312         3854 :         free(fieldNotNum);
     313         3854 :         free(border);
     314         3854 :         if (fields)
     315              :         {
     316              :             /* if calloc succeeded, this shouldn't overflow size_t */
     317         3854 :             size_t      numfields = ((size_t) nTups + 1) * (size_t) nFields;
     318              : 
     319        19908 :             while (numfields-- > 0)
     320        16054 :                 free(fields[numfields]);
     321         3854 :             free(fields);
     322              :         }
     323         3854 :         free(fieldNames);
     324         3854 :         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         3915 : }
     338              : 
     339              : 
     340              : static bool
     341         9936 : 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         9936 :     plen = PQgetlength(res, i, j);
     354         9936 :     pval = PQgetvalue(res, i, j);
     355              : 
     356         9936 :     if (plen < 1 || !pval || !*pval)
     357              :     {
     358          671 :         if (po->align || po->expanded)
     359          671 :             skipit = true;
     360              :         else
     361              :         {
     362            0 :             skipit = false;
     363            0 :             goto efield;
     364              :         }
     365              :     }
     366              :     else
     367         9265 :         skipit = false;
     368              : 
     369         9936 :     if (!skipit)
     370              :     {
     371         9265 :         if (po->align && !fieldNotNum[j])
     372              :         {
     373              :             /* Detect whether field contains non-numeric data */
     374         7930 :             char        ch = '0';
     375              : 
     376        23625 :             for (p = pval; *p; p += PQmblenBounded(p, res->client_encoding))
     377              :             {
     378        17565 :                 ch = *p;
     379        20751 :                 if (!((ch >= '0' && ch <= '9') ||
     380         3189 :                       ch == '.' ||
     381         3186 :                       ch == 'E' ||
     382         3186 :                       ch == 'e' ||
     383              :                       ch == ' ' ||
     384              :                       ch == '-'))
     385              :                 {
     386         1870 :                     fieldNotNum[j] = 1;
     387         1870 :                     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         7930 :             if (*pval == 'E' || *pval == 'e' ||
     397         7891 :                 !(ch >= '0' && ch <= '9'))
     398         1870 :                 fieldNotNum[j] = 1;
     399              :         }
     400              : 
     401         9265 :         if (!po->expanded && (po->align || po->html3))
     402              :         {
     403         9265 :             if (plen > fieldMax[j])
     404         1383 :                 fieldMax[j] = plen;
     405         9265 :             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         9265 :             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         9936 :     return true;
     452              : }
     453              : 
     454              : 
     455              : static char *
     456         3854 : 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         3854 :     char       *border = NULL;
     462              : 
     463         3854 :     if (po->html3)
     464            0 :         fputs("<tr>", fout);
     465              :     else
     466              :     {
     467         3854 :         size_t      tot = 0;
     468         3854 :         int         n = 0;
     469         3854 :         char       *p = NULL;
     470              : 
     471              :         /* Calculate the border size, checking for overflow. */
     472         9972 :         for (; n < nFields; n++)
     473              :         {
     474              :             /* Field plus separator, plus 2 extra '-' in standard format. */
     475        12236 :             if (pg_add_size_overflow(tot, fieldMax[n], &tot) ||
     476         6118 :                 pg_add_size_overflow(tot, fs_len, &tot) ||
     477         6118 :                 (po->standard && pg_add_size_overflow(tot, 2, &tot)))
     478            0 :                 goto overflow;
     479              :         }
     480         3854 :         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         3854 :         if (pg_add_size_overflow(tot, 1, &tot)) /* terminator */
     489            0 :             goto overflow;
     490              : 
     491         3854 :         border = malloc(tot);
     492         3854 :         if (!border)
     493              :         {
     494            0 :             fprintf(stderr, libpq_gettext("out of memory\n"));
     495            0 :             return NULL;
     496              :         }
     497         3854 :         p = border;
     498         3854 :         if (po->standard)
     499              :         {
     500            0 :             char       *fs = po->fieldSep;
     501              : 
     502            0 :             while (*fs++)
     503            0 :                 *p++ = '+';
     504              :         }
     505         9972 :         for (j = 0; j < nFields; j++)
     506              :         {
     507              :             int         len;
     508              : 
     509        63067 :             for (len = fieldMax[j] + (po->standard ? 2 : 0); len--; *p++ = '-');
     510         6118 :             if (po->standard || (j + 1) < nFields)
     511              :             {
     512         2264 :                 char       *fs = po->fieldSep;
     513              : 
     514         4528 :                 while (*fs++)
     515         2264 :                     *p++ = '+';
     516              :             }
     517              :         }
     518         3854 :         *p = '\0';
     519         3854 :         if (po->standard)
     520            0 :             fprintf(fout, "%s\n", border);
     521              :     }
     522         3854 :     if (po->standard)
     523            0 :         fputs(po->fieldSep, fout);
     524         9972 :     for (j = 0; j < nFields; j++)
     525              :     {
     526         6118 :         const char *s = PQfname(res, j);
     527              : 
     528         6118 :         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         6118 :             int         n = strlen(s);
     536              : 
     537         6118 :             if (n > fieldMax[j])
     538            0 :                 fieldMax[j] = n;
     539         6118 :             if (po->standard)
     540            0 :                 fprintf(fout,
     541            0 :                         fieldNotNum[j] ? " %-*s " : " %*s ",
     542            0 :                         fieldMax[j], s);
     543              :             else
     544         6118 :                 fprintf(fout, fieldNotNum[j] ? "%-*s" : "%*s", fieldMax[j], s);
     545         6118 :             if (po->standard || (j + 1) < nFields)
     546         2264 :                 fputs(po->fieldSep, fout);
     547              :         }
     548              :     }
     549         3854 :     if (po->html3)
     550            0 :         fputs("</tr>\n", fout);
     551              :     else
     552         3854 :         fprintf(fout, "\n%s\n", border);
     553         3854 :     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         5595 : 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         5595 :     if (po->html3)
     569            0 :         fputs("<tr>", fout);
     570         5595 :     else if (po->standard)
     571            0 :         fputs(po->fieldSep, fout);
     572        15531 :     for (field_index = 0; field_index < nFields; field_index++)
     573              :     {
     574         9936 :         char       *p = fields[row_index * nFields + field_index];
     575              : 
     576         9936 :         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        19872 :             fprintf(fout,
     582         9936 :                     fieldNotNum[field_index] ?
     583         9936 :                     (po->standard ? " %-*s " : "%-*s") :
     584         6720 :                     (po->standard ? " %*s " : "%*s"),
     585         9936 :                     fieldMax[field_index],
     586              :                     p ? p : "");
     587         9936 :             if (po->standard || field_index + 1 < nFields)
     588         4341 :                 fputs(po->fieldSep, fout);
     589              :         }
     590              :     }
     591         5595 :     if (po->html3)
     592            0 :         fputs("</tr>", fout);
     593         5595 :     else if (po->standard)
     594            0 :         fprintf(fout, "\n%s", border);
     595         5595 :     fputc('\n', fout);
     596         5595 : }
     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 2.0-1