1 /*-------------------------------------------------------------------------
4 * functions for pretty-printing query results
6 * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
9 * These functions were formerly part of fe-exec.c, but they
10 * didn't really belong there.
13 * src/interfaces/libpq/fe-print.c
15 *-------------------------------------------------------------------------
17 #include "postgres_fe.h"
25 #include <sys/ioctl.h>
32 #include <sys/termios.h>
37 #include "libpq-int.h"
40 static void do_field(const PQprintOpt *po, const PGresult *res,
41 const int i, const int j, const int fs_len,
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,
52 static void fill(int length, int max, char filler, FILE *fp);
57 * Format results of a query for printing.
59 * PQprintOpt is a typedef (structure) that contains
60 * various flags and options. consult libpq-fe.h for
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.
68 PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po)
72 nFields = PQnfields(res);
75 { /* only print rows with at least 1 field. */
79 int *fieldMax = NULL; /* in case we don't use them */
80 unsigned char *fieldNotNum = NULL;
83 const char **fieldNames;
86 int fs_len = strlen(po->fieldSep);
87 int total_line_length = 0;
91 #if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32)
93 bool sigpipe_masked = false;
96 #if !defined(ENABLE_THREAD_SAFETY) && !defined(WIN32)
97 pqsigfunc oldsigpipehandler = NULL;
101 struct winsize screen_size;
110 nTups = PQntuples(res);
111 if (!(fieldNames = (const char **) calloc(nFields, sizeof(char *))))
113 fprintf(stderr, libpq_gettext("out of memory\n"));
116 if (!(fieldNotNum = (unsigned char *) calloc(nFields, 1)))
118 fprintf(stderr, libpq_gettext("out of memory\n"));
121 if (!(fieldMax = (int *) calloc(nFields, sizeof(int))))
123 fprintf(stderr, libpq_gettext("out of memory\n"));
126 for (numFieldName = 0;
127 po->fieldName && po->fieldName[numFieldName];
130 for (j = 0; j < nFields; j++)
133 const char *s = (j < numFieldName && po->fieldName[j][0]) ?
134 po->fieldName[j] : PQfname(res, j);
137 len = s ? strlen(s) : 0;
140 if (len > fieldMaxLen)
142 total_line_length += len;
145 total_line_length += nFields * strlen(po->fieldSep) + 1;
149 if (po->pager && fout == stdout && isatty(fileno(stdin)) &&
150 isatty(fileno(stdout)))
153 * If we think there'll be more than one screen of output, try to
154 * pipe to the pager program.
157 if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) == -1 ||
158 screen_size.ws_col == 0 ||
159 screen_size.ws_row == 0)
161 screen_size.ws_row = 24;
162 screen_size.ws_col = 80;
165 screen_size.ws_row = 24;
166 screen_size.ws_col = 80;
168 pagerenv = getenv("PAGER");
169 if (pagerenv != NULL &&
170 pagerenv[0] != '\0' &&
173 nTups * (nFields + 1) >= screen_size.ws_row) ||
175 nTups * (total_line_length / screen_size.ws_col + 1) *
176 (1 + (po->standard != 0)) >= screen_size.ws_row -
178 (total_line_length / screen_size.ws_col + 1) * 2
179 - (po->header != 0) * 2 /* row count and newline */
182 fout = popen(pagerenv, "w");
187 #ifdef ENABLE_THREAD_SAFETY
188 if (pq_block_sigpipe(&osigset, &sigpipe_pending) == 0)
189 sigpipe_masked = true;
191 oldsigpipehandler = pqsignal(SIGPIPE, SIG_IGN);
192 #endif /* ENABLE_THREAD_SAFETY */
200 if (!po->expanded && (po->align || po->html3))
202 if (!(fields = (char **) calloc(nFields * (nTups + 1), sizeof(char *))))
204 fprintf(stderr, libpq_gettext("out of memory\n"));
208 else if (po->header && !po->html3)
213 fprintf(fout, libpq_gettext("%-*s%s Value\n"),
214 fieldMaxLen - fs_len, libpq_gettext("Field"), po->fieldSep);
216 fprintf(fout, libpq_gettext("%s%sValue\n"), libpq_gettext("Field"), po->fieldSep);
222 for (j = 0; j < nFields; j++)
224 const char *s = fieldNames[j];
227 len += strlen(s) + fs_len;
228 if ((j + 1) < nFields)
229 fputs(po->fieldSep, fout);
232 for (len -= fs_len; len--; fputc('-', fout));
236 if (po->expanded && po->html3)
239 fprintf(fout, "<center><h2>%s</h2></center>\n", po->caption);
243 "Query retrieved %d rows * %d fields"
247 for (i = 0; i < nTups; i++)
253 "<table %s><caption align=\"top\">%d</caption>\n",
254 po->tableOpt ? po->tableOpt : "", i);
256 fprintf(fout, libpq_gettext("-- RECORD %d --\n"), i);
258 for (j = 0; j < nFields; j++)
259 do_field(po, res, i, j, fs_len, fields, nFields,
260 fieldNames, fieldNotNum,
261 fieldMax, fieldMaxLen, fout);
262 if (po->html3 && po->expanded)
263 fputs("</table>\n", fout);
265 if (!po->expanded && (po->align || po->html3))
273 "<table %s><caption align=\"top\">%s</caption>\n",
274 po->tableOpt ? po->tableOpt : "",
278 "<table %s><caption align=\"top\">"
279 "Retrieved %d rows * %d fields"
281 po->tableOpt ? po->tableOpt : "", nTups, nFields);
284 fprintf(fout, "<table %s>", po->tableOpt ? po->tableOpt : "");
287 border = do_header(fout, po, nFields, fieldMax, fieldNames,
288 fieldNotNum, fs_len, res);
289 for (i = 0; i < nTups; i++)
290 output_row(fout, po, nFields, fields,
291 fieldNotNum, fieldMax, border, i);
296 if (po->header && !po->html3)
297 fprintf(fout, "(%d row%s)\n\n", PQntuples(res),
298 (PQntuples(res) == 1) ? "" : "s");
301 free((void *) fieldNames);
309 #ifdef ENABLE_THREAD_SAFETY
310 /* we can't easily verify if EPIPE occurred, so say it did */
312 pq_reset_sigpipe(&osigset, sigpipe_pending, true);
314 pqsignal(SIGPIPE, oldsigpipehandler);
315 #endif /* ENABLE_THREAD_SAFETY */
318 if (po->html3 && !po->expanded)
319 fputs("</table>\n", fout);
325 do_field(const PQprintOpt *po, const PGresult *res,
326 const int i, const int j, const int fs_len,
328 const int nFields, char const ** fieldNames,
329 unsigned char *fieldNotNum, int *fieldMax,
330 const int fieldMaxLen, FILE *fout)
337 plen = PQgetlength(res, i, j);
338 pval = PQgetvalue(res, i, j);
340 if (plen < 1 || !pval || !*pval)
342 if (po->align || po->expanded)
355 if (po->align && !fieldNotNum[j])
357 /* Detect whether field contains non-numeric data */
360 for (p = pval; *p; p += PQmblen(p, res->client_encoding))
363 if (!((ch >= '0' && ch <= '9') ||
376 * Above loop will believe E in first column is numeric; also, we
377 * insist on a digit in the last column for a numeric. This test
378 * is still not bulletproof but it handles most cases.
380 if (*pval == 'E' || *pval == 'e' ||
381 !(ch >= '0' && ch <= '9'))
385 if (!po->expanded && (po->align || po->html3))
387 if (plen > fieldMax[j])
389 if (!(fields[i * nFields + j] = (char *) malloc(plen + 1)))
391 fprintf(stderr, libpq_gettext("out of memory\n"));
394 strcpy(fields[i * nFields + j], pval);
402 "<tr><td align=\"left\"><b>%s</b></td>"
403 "<td align=\"%s\">%s</td></tr>\n",
405 fieldNotNum[j] ? "left" : "right",
412 fieldMaxLen - fs_len, fieldNames[j],
418 fieldNames[j], po->fieldSep, pval);
427 if ((j + 1) < nFields)
428 fputs(po->fieldSep, fout);
439 do_header(FILE *fout, const PQprintOpt *po, const int nFields, int *fieldMax,
440 const char **fieldNames, unsigned char *fieldNotNum,
441 const int fs_len, const PGresult *res)
443 int j; /* for loop index */
454 for (; n < nFields; n++)
455 tot += fieldMax[n] + fs_len + (po->standard ? 2 : 0);
457 tot += fs_len * 2 + 2;
458 border = malloc(tot + 1);
461 fprintf(stderr, libpq_gettext("out of memory\n"));
467 char *fs = po->fieldSep;
472 for (j = 0; j < nFields; j++)
476 for (len = fieldMax[j] + (po->standard ? 2 : 0); len--; *p++ = '-');
477 if (po->standard || (j + 1) < nFields)
479 char *fs = po->fieldSep;
487 fprintf(fout, "%s\n", border);
490 fputs(po->fieldSep, fout);
491 for (j = 0; j < nFields; j++)
493 const char *s = PQfname(res, j);
497 fprintf(fout, "<th align=\"%s\">%s</th>",
498 fieldNotNum[j] ? "left" : "right", fieldNames[j]);
508 fieldNotNum[j] ? " %-*s " : " %*s ",
511 fprintf(fout, fieldNotNum[j] ? "%-*s" : "%*s", fieldMax[j], s);
512 if (po->standard || (j + 1) < nFields)
513 fputs(po->fieldSep, fout);
517 fputs("</tr>\n", fout);
519 fprintf(fout, "\n%s\n", border);
525 output_row(FILE *fout, const PQprintOpt *po, const int nFields, char **fields,
526 unsigned char *fieldNotNum, int *fieldMax, char *border,
529 int field_index; /* for loop index */
533 else if (po->standard)
534 fputs(po->fieldSep, fout);
535 for (field_index = 0; field_index < nFields; field_index++)
537 char *p = fields[row_index * nFields + field_index];
540 fprintf(fout, "<td align=\"%s\">%s</td>",
541 fieldNotNum[field_index] ? "left" : "right", p ? p : "");
545 fieldNotNum[field_index] ?
546 (po->standard ? " %-*s " : "%-*s") :
547 (po->standard ? " %*s " : "%*s"),
548 fieldMax[field_index],
550 if (po->standard || field_index + 1 < nFields)
551 fputs(po->fieldSep, fout);
557 fputs("</tr>", fout);
558 else if (po->standard)
559 fprintf(fout, "\n%s", border);
566 * really old printing routines
570 PQdisplayTuples(const PGresult *res,
571 FILE *fp, /* where to send the output */
572 int fillAlign, /* pad the fields with spaces */
573 const char *fieldSep, /* field separator */
574 int printHeader, /* display headers? */
578 #define DEFAULT_FIELD_SEP " "
586 if (fieldSep == NULL)
587 fieldSep = DEFAULT_FIELD_SEP;
589 /* Get some useful info about the results */
590 nFields = PQnfields(res);
591 nTuples = PQntuples(res);
596 /* Figure the field lengths to align to */
597 /* will be somewhat time consuming for very large results */
600 fLength = (int *) malloc(nFields * sizeof(int));
603 fprintf(stderr, libpq_gettext("out of memory\n"));
607 for (j = 0; j < nFields; j++)
609 fLength[j] = strlen(PQfname(res, j));
610 for (i = 0; i < nTuples; i++)
612 int flen = PQgetlength(res, i, j);
614 if (flen > fLength[j])
622 /* first, print out the attribute names */
623 for (i = 0; i < nFields; i++)
625 fputs(PQfname(res, i), fp);
627 fill(strlen(PQfname(res, i)), fLength[i], ' ', fp);
632 /* Underline the attribute names */
633 for (i = 0; i < nFields; i++)
636 fill(0, fLength[i], '-', fp);
642 /* next, print out the instances */
643 for (i = 0; i < nTuples; i++)
645 for (j = 0; j < nFields; j++)
647 fprintf(fp, "%s", PQgetvalue(res, i, j));
649 fill(strlen(PQgetvalue(res, i, j)), fLength[j], ' ', fp);
656 fprintf(fp, "\nQuery returned %d row%s.\n", PQntuples(res),
657 (PQntuples(res) == 1) ? "" : "s");
668 PQprintTuples(const PGresult *res,
669 FILE *fout, /* output stream */
670 int PrintAttNames, /* print attribute names or not */
671 int TerseOutput, /* delimiter bars or not? */
672 int colWidth /* width of column, if 0, use variable width */
679 char formatString[80];
680 char *tborder = NULL;
682 nFields = PQnfields(res);
683 nTups = PQntuples(res);
686 sprintf(formatString, "%%s %%-%ds", colWidth);
688 sprintf(formatString, "%%s %%s");
691 { /* only print rows with at least 1 field. */
697 width = nFields * 14;
698 tborder = (char *) malloc(width + 1);
701 fprintf(stderr, libpq_gettext("out of memory\n"));
704 for (i = 0; i < width; i++)
706 tborder[width] = '\0';
707 fprintf(fout, "%s\n", tborder);
710 for (i = 0; i < nFields; i++)
714 fprintf(fout, formatString,
715 TerseOutput ? "" : "|",
725 fprintf(fout, "|\n%s\n", tborder);
728 for (i = 0; i < nTups; i++)
730 for (j = 0; j < nFields; j++)
732 const char *pval = PQgetvalue(res, i, j);
734 fprintf(fout, formatString,
735 TerseOutput ? "" : "|",
741 fprintf(fout, "|\n%s\n", tborder);
750 /* simply send out max-length number of filler characters to fp */
753 fill(int length, int max, char filler, FILE *fp)
757 count = max - length;