LCOV - differential code coverage report
Current view: top level - src/interfaces/libpq - fe-print.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 42.5 % 334 142 3 10 103 76 13 55 5 69 100 56 3 7
Current Date: 2023-04-08 15:15:32 Functions: 57.1 % 7 4 3 3 1 1 3 2
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a