2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2005, PostgreSQL Global Development Group
6 * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.54 2005/01/01 05:43:08 momjian Exp $
8 #include "postgres_fe.h"
15 #ifndef WIN32_CLIENT_ONLY
20 #include <sys/ioctl.h> /* for ioctl() */
32 /*************************/
34 /*************************/
38 print_unaligned_text(const char *title, const char *const * headers,
39 const char *const * cells, const char *const * footers,
40 const char *opt_fieldsep, const char *opt_recordsep, bool opt_barebones,
43 unsigned int col_count = 0;
45 const char *const * ptr;
46 bool need_recordsep = false;
54 if (!opt_barebones && title)
55 fprintf(fout, "%s%s", title, opt_recordsep);
57 /* print headers and count columns */
58 for (ptr = headers; *ptr; ptr++)
64 fputs(opt_fieldsep, fout);
69 need_recordsep = true;
73 for (ptr = cells; *ptr; ptr++)
77 fputs(opt_recordsep, fout);
78 need_recordsep = false;
81 if ((i + 1) % col_count)
82 fputs(opt_fieldsep, fout);
84 need_recordsep = true;
90 if (!opt_barebones && footers)
91 for (ptr = footers; *ptr; ptr++)
95 fputs(opt_recordsep, fout);
96 need_recordsep = false;
99 need_recordsep = true;
102 /* the last record needs to be concluded with a newline */
110 print_unaligned_vertical(const char *title, const char *const * headers,
111 const char *const * cells, const char *const * footers,
112 const char *opt_fieldsep, const char *opt_recordsep, bool opt_barebones,
115 unsigned int col_count = 0;
117 const char *const * ptr;
125 if (!opt_barebones && title)
129 for (ptr = headers; *ptr; ptr++)
133 for (i = 0, ptr = cells; *ptr; i++, ptr++)
135 if (i != 0 || (!opt_barebones && title))
137 fputs(opt_recordsep, fout);
138 if (i % col_count == 0)
139 fputs(opt_recordsep, fout); /* another one */
142 fputs(headers[i % col_count], fout);
143 fputs(opt_fieldsep, fout);
148 if (!opt_barebones && footers && *footers)
150 fputs(opt_recordsep, fout);
151 for (ptr = footers; *ptr; ptr++)
153 fputs(opt_recordsep, fout);
163 /********************/
165 /********************/
170 _print_horizontal_line(const unsigned int col_count, const unsigned int *widths, unsigned short border, FILE *fout)
177 else if (border == 2)
180 for (i = 0; i < col_count; i++)
182 for (j = 0; j < widths[i]; j++)
185 if (i < col_count - 1)
196 else if (border == 1)
205 print_aligned_text(const char *title, const char *const * headers,
206 const char *const * cells, const char *const * footers,
207 const char *opt_align, bool opt_barebones,
208 unsigned short int opt_border, int encoding,
211 unsigned int col_count = 0;
212 unsigned int cell_count = 0;
213 unsigned int *head_w,
217 unsigned int *widths,
219 const char *const * ptr;
222 for (ptr = headers; *ptr; ptr++)
227 widths = calloc(col_count, sizeof(*widths));
230 fprintf(stderr, gettext("out of memory\n"));
234 head_w = calloc(col_count, sizeof(*head_w));
237 fprintf(stderr, gettext("out of memory\n"));
247 /* count cells (rows * cols) */
248 for (ptr = cells; *ptr; ptr++)
253 cell_w = calloc(cell_count, sizeof(*cell_w));
256 fprintf(stderr, gettext("out of memory\n"));
263 /* calc column widths */
264 for (i = 0; i < col_count; i++)
266 tmp = pg_wcswidth((unsigned char *) headers[i], strlen(headers[i]), encoding);
272 for (i = 0, ptr = cells; *ptr; ptr++, i++)
274 tmp = pg_wcswidth((unsigned char *) *ptr, strlen(*ptr), encoding);
275 if (tmp > widths[i % col_count])
276 widths[i % col_count] = tmp;
281 total_w = col_count - 1;
282 else if (opt_border == 1)
283 total_w = col_count * 3 - 1;
285 total_w = col_count * 3 + 1;
287 for (i = 0; i < col_count; i++)
288 total_w += widths[i];
291 if (title && !opt_barebones)
293 tmp = pg_wcswidth((unsigned char *) title, strlen(title), encoding);
295 fprintf(fout, "%s\n", title);
297 fprintf(fout, "%-*s%s\n", (total_w - tmp) / 2, "", title);
304 _print_horizontal_line(col_count, widths, opt_border, fout);
308 else if (opt_border == 1)
311 for (i = 0; i < col_count; i++)
313 unsigned int nbspace;
315 nbspace = widths[i] - head_w[i];
318 fprintf(fout, "%-*s%s%-*s",
319 nbspace / 2, "", headers[i], (nbspace + 1) / 2, "");
321 if (i < col_count - 1)
332 else if (opt_border == 1)
336 _print_horizontal_line(col_count, widths, opt_border, fout);
340 for (i = 0, ptr = cells; *ptr; i++, ptr++)
342 /* beginning of line */
343 if (i % col_count == 0)
347 else if (opt_border == 1)
352 if (opt_align[i % col_count] == 'r')
354 fprintf(fout, "%*s%s",
355 widths[i % col_count] - cell_w[i], "", cells[i]);
359 if ((i + 1) % col_count == 0 && opt_border != 2)
360 fputs(cells[i], fout);
362 fprintf(fout, "%-s%*s", cells[i],
363 widths[i % col_count] - cell_w[i], "");
367 if ((i + 1) % col_count)
384 _print_horizontal_line(col_count, widths, opt_border, fout);
387 if (footers && !opt_barebones)
388 for (ptr = footers; *ptr; ptr++)
389 fprintf(fout, "%s\n", *ptr);
394 * for some reason MinGW outputs an extra newline, so this supresses
409 print_aligned_vertical(const char *title, const char *const * headers,
410 const char *const * cells, const char *const * footers,
411 bool opt_barebones, unsigned short int opt_border,
412 int encoding, FILE *fout)
414 unsigned int col_count = 0;
415 unsigned int record = 1;
416 const char *const * ptr;
422 unsigned int cell_count = 0;
423 unsigned int *cell_w,
426 if (cells[0] == NULL)
428 puts(gettext("(No rows)\n"));
432 /* count headers and find longest one */
433 for (ptr = headers; *ptr; ptr++)
437 head_w = calloc(col_count, sizeof(*head_w));
440 fprintf(stderr, gettext("out of memory\n"));
447 for (i = 0; i < col_count; i++)
449 tmp = pg_wcswidth((unsigned char *) headers[i], strlen(headers[i]), encoding);
455 /* Count cells, find their lengths */
456 for (ptr = cells; *ptr; ptr++)
461 cell_w = calloc(cell_count, sizeof(*cell_w));
464 fprintf(stderr, gettext("out of memory\n"));
471 /* find longest data cell */
472 for (i = 0, ptr = cells; *ptr; ptr++, i++)
474 tmp = pg_wcswidth((unsigned char *) *ptr, strlen(*ptr), encoding);
481 if (!opt_barebones && title)
482 fprintf(fout, "%s\n", title);
484 /* make horizontal border */
485 divider = malloc(hwidth + dwidth + 10);
488 fprintf(stderr, gettext("out of memory\n"));
493 strcat(divider, "+-");
494 for (i = 0; i < hwidth; i++)
495 strcat(divider, opt_border > 0 ? "-" : " ");
497 strcat(divider, "-+-");
499 strcat(divider, " ");
500 for (i = 0; i < dwidth; i++)
501 strcat(divider, opt_border > 0 ? "-" : " ");
503 strcat(divider, "-+");
506 for (i = 0, ptr = cells; *ptr; i++, ptr++)
508 if (i % col_count == 0)
512 char *record_str = malloc(32);
513 size_t record_str_len;
517 fprintf(stderr, gettext("out of memory\n"));
522 snprintf(record_str, 32, "* Record %d", record++);
524 snprintf(record_str, 32, "[ RECORD %d ]", record++);
525 record_str_len = strlen(record_str);
527 if (record_str_len + opt_border > strlen(divider))
528 fprintf(fout, "%.*s%s\n", opt_border, divider, record_str);
531 char *div_copy = strdup(divider);
535 fprintf(stderr, gettext("out of memory\n"));
539 strncpy(div_copy + opt_border, record_str, record_str_len);
540 fprintf(fout, "%s\n", div_copy);
545 else if (i != 0 || opt_border == 2)
546 fprintf(fout, "%s\n", divider);
551 fprintf(fout, "%-s%*s", headers[i % col_count],
552 hwidth - head_w[i % col_count], "");
560 fprintf(fout, "%s\n", *ptr);
562 fprintf(fout, "%-s%*s |\n", *ptr, dwidth - cell_w[i], "");
566 fprintf(fout, "%s\n", divider);
570 if (!opt_barebones && footers && *footers)
574 for (ptr = footers; *ptr; ptr++)
575 fprintf(fout, "%s\n", *ptr);
589 /**********************/
590 /* HTML printing ******/
591 /**********************/
595 html_escaped_print(const char *in, FILE *fout)
599 for (p = in; *p; p++)
603 fputs("&", fout);
612 fputs("<br />\n", fout);
615 fputs(""", fout);
618 fputs("'", fout);
628 print_html_text(const char *title, const char *const * headers,
629 const char *const * cells, const char *const * footers,
630 const char *opt_align, bool opt_barebones, unsigned short int opt_border,
631 const char *opt_table_attr,
634 unsigned int col_count = 0;
636 const char *const * ptr;
638 fprintf(fout, "<table border=\"%d\"", opt_border);
640 fprintf(fout, " %s", opt_table_attr);
644 if (!opt_barebones && title)
646 fputs(" <caption>", fout);
647 html_escaped_print(title, fout);
648 fputs("</caption>\n", fout);
651 /* print headers and count columns */
653 fputs(" <tr>\n", fout);
654 for (i = 0, ptr = headers; *ptr; i++, ptr++)
659 fputs(" <th align=\"center\">", fout);
660 html_escaped_print(*ptr, fout);
661 fputs("</th>\n", fout);
665 fputs(" </tr>\n", fout);
668 for (i = 0, ptr = cells; *ptr; i++, ptr++)
670 if (i % col_count == 0)
671 fputs(" <tr valign=\"top\">\n", fout);
673 fprintf(fout, " <td align=\"%s\">", opt_align[(i) % col_count] == 'r' ? "right" : "left");
674 if ((*ptr)[strspn(*ptr, " \t")] == '\0') /* is string only
676 fputs(" ", fout);
678 html_escaped_print(*ptr, fout);
679 fputs("</td>\n", fout);
681 if ((i + 1) % col_count == 0)
682 fputs(" </tr>\n", fout);
685 fputs("</table>\n", fout);
689 if (!opt_barebones && footers && *footers)
692 for (ptr = footers; *ptr; ptr++)
694 html_escaped_print(*ptr, fout);
695 fputs("<br />\n", fout);
705 print_html_vertical(const char *title, const char *const * headers,
706 const char *const * cells, const char *const * footers,
707 const char *opt_align, bool opt_barebones, unsigned short int opt_border,
708 const char *opt_table_attr,
711 unsigned int col_count = 0;
713 unsigned int record = 1;
714 const char *const * ptr;
716 fprintf(fout, "<table border=\"%d\"", opt_border);
718 fprintf(fout, " %s", opt_table_attr);
722 if (!opt_barebones && title)
724 fputs(" <caption>", fout);
725 html_escaped_print(title, fout);
726 fputs("</caption>\n", fout);
730 for (ptr = headers; *ptr; ptr++)
734 for (i = 0, ptr = cells; *ptr; i++, ptr++)
736 if (i % col_count == 0)
739 fprintf(fout, "\n <tr><td colspan=\"2\" align=\"center\">Record %d</td></tr>\n", record++);
741 fputs("\n <tr><td colspan=\"2\"> </td></tr>\n", fout);
743 fputs(" <tr valign=\"top\">\n"
745 html_escaped_print(headers[i % col_count], fout);
746 fputs("</th>\n", fout);
748 fprintf(fout, " <td align=\"%s\">", opt_align[i % col_count] == 'r' ? "right" : "left");
749 if ((*ptr)[strspn(*ptr, " \t")] == '\0') /* is string only
751 fputs(" ", fout);
753 html_escaped_print(*ptr, fout);
754 fputs("</td>\n </tr>\n", fout);
757 fputs("</table>\n", fout);
760 if (!opt_barebones && footers && *footers)
763 for (ptr = footers; *ptr; ptr++)
765 html_escaped_print(*ptr, fout);
766 fputs("<br />\n", fout);
775 /*************************/
777 /*************************/
781 latex_escaped_print(const char *in, FILE *fout)
785 for (p = in; *p; p++)
807 fputs("\\backslash", fout);
820 print_latex_text(const char *title, const char *const * headers,
821 const char *const * cells, const char *const * footers,
822 const char *opt_align, bool opt_barebones, unsigned short int opt_border,
825 unsigned int col_count = 0;
827 const char *const * ptr;
831 if (!opt_barebones && title)
833 fputs("\\begin{center}\n", fout);
834 latex_escaped_print(title, fout);
835 fputs("\n\\end{center}\n\n", fout);
839 for (ptr = headers; *ptr; ptr++)
842 /* begin environment and set alignments and borders */
843 fputs("\\begin{tabular}{", fout);
847 for (i = 0; i < col_count; i++)
849 fputc(*(opt_align + i), fout);
850 if (opt_border != 0 && i < col_count - 1)
858 if (!opt_barebones && opt_border == 2)
859 fputs("\\hline\n", fout);
861 /* print headers and count columns */
862 for (i = 0, ptr = headers; i < col_count; i++, ptr++)
868 fputs("\\textit{", fout);
869 latex_escaped_print(*ptr, fout);
876 fputs(" \\\\\n", fout);
877 fputs("\\hline\n", fout);
881 for (i = 0, ptr = cells; *ptr; i++, ptr++)
883 latex_escaped_print(*ptr, fout);
885 if ((i + 1) % col_count == 0)
886 fputs(" \\\\\n", fout);
892 fputs("\\hline\n", fout);
894 fputs("\\end{tabular}\n\n\\noindent ", fout);
899 if (footers && !opt_barebones)
900 for (ptr = footers; *ptr; ptr++)
902 latex_escaped_print(*ptr, fout);
903 fputs(" \\\\\n", fout);
912 print_latex_vertical(const char *title, const char *const * headers,
913 const char *const * cells, const char *const * footers,
914 const char *opt_align, bool opt_barebones, unsigned short int opt_border,
917 unsigned int col_count = 0;
919 const char *const * ptr;
920 unsigned int record = 1;
922 (void) opt_align; /* currently unused parameter */
925 if (!opt_barebones && title)
927 fputs("\\begin{center}\n", fout);
928 latex_escaped_print(title, fout);
929 fputs("\n\\end{center}\n\n", fout);
932 /* begin environment and set alignments and borders */
933 fputs("\\begin{tabular}{", fout);
936 else if (opt_border == 1)
938 else if (opt_border == 2)
939 fputs("|c|l|", fout);
944 for (ptr = headers; *ptr; ptr++)
949 for (i = 0, ptr = cells; *ptr; i++, ptr++)
952 if (i % col_count == 0)
958 fputs("\\hline\n", fout);
959 fprintf(fout, "\\multicolumn{2}{|c|}{\\textit{Record %d}} \\\\\n", record++);
962 fprintf(fout, "\\multicolumn{2}{c}{\\textit{Record %d}} \\\\\n", record++);
965 fputs("\\hline\n", fout);
968 latex_escaped_print(headers[i % col_count], fout);
970 latex_escaped_print(*ptr, fout);
971 fputs(" \\\\\n", fout);
975 fputs("\\hline\n", fout);
977 fputs("\\end{tabular}\n\n\\noindent ", fout);
982 if (footers && !opt_barebones)
983 for (ptr = footers; *ptr; ptr++)
985 latex_escaped_print(*ptr, fout);
986 fputs(" \\\\\n", fout);
994 /********************************/
995 /* Public functions */
996 /********************************/
1002 * Tests if pager is needed and returns appropriate FILE pointer.
1005 PageOutput(int lines, unsigned short int pager)
1007 /* check whether we need / can / are supposed to use pager */
1011 isatty(fileno(stdin)) &&
1012 isatty(fileno(stdout))
1016 const char *pagerprog;
1020 struct winsize screen_size;
1022 result = ioctl(fileno(stdout), TIOCGWINSZ, &screen_size);
1024 /* >= accounts for a one-line prompt */
1025 if (result == -1 || lines >= screen_size.ws_row || pager > 1)
1028 pagerprog = getenv("PAGER");
1030 pagerprog = DEFAULT_PAGER;
1032 pqsignal(SIGPIPE, SIG_IGN);
1034 return popen(pagerprog, "w");
1046 printTable(const char *title,
1047 const char *const * headers,
1048 const char *const * cells,
1049 const char *const * footers,
1051 const printTableOpt *opt, FILE *fout)
1053 const char *default_footer[] = {NULL};
1054 unsigned short int border = opt->border;
1057 if (opt->format == PRINT_NOTHING)
1061 footers = default_footer;
1063 if (opt->format != PRINT_HTML && border > 2)
1071 const char *const * ptr;
1073 /* rough estimate of columns and rows */
1075 for (ptr = headers; *ptr; ptr++)
1078 for (ptr = cells; *ptr; ptr++)
1081 row_count /= col_count;
1084 lines = (col_count + 1) * row_count;
1086 lines = row_count + 1;
1087 if (footers && !opt->tuples_only)
1088 for (ptr = footers; *ptr; ptr++)
1090 output = PageOutput(lines, opt->pager);
1095 /* print the stuff */
1097 switch (opt->format)
1099 case PRINT_UNALIGNED:
1101 print_unaligned_vertical(title, headers, cells, footers, opt->fieldSep, opt->recordSep, opt->tuples_only, output);
1103 print_unaligned_text(title, headers, cells, footers, opt->fieldSep, opt->recordSep, opt->tuples_only, output);
1107 print_aligned_vertical(title, headers, cells, footers, opt->tuples_only, border, opt->encoding, output);
1109 print_aligned_text(title, headers, cells, footers, align, opt->tuples_only, border, opt->encoding, output);
1113 print_html_vertical(title, headers, cells, footers, align, opt->tuples_only, border, opt->tableAttr, output);
1115 print_html_text(title, headers, cells, footers, align, opt->tuples_only, border, opt->tableAttr, output);
1119 print_latex_vertical(title, headers, cells, footers, align, opt->tuples_only, border, output);
1121 print_latex_text(title, headers, cells, footers, align, opt->tuples_only, border, output);
1124 fprintf(stderr, "+ Oops, you shouldn't see this!\n");
1127 /* Only close if we used the pager */
1128 if (fout == stdout && output != stdout)
1132 pqsignal(SIGPIPE, SIG_DFL);
1140 printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout)
1144 const char **headers;
1150 /* extract headers */
1151 nfields = PQnfields(result);
1153 headers = calloc(nfields + 1, sizeof(*headers));
1156 fprintf(stderr, gettext("out of memory\n"));
1160 for (i = 0; i < nfields; i++)
1161 headers[i] = mbvalidate(PQfname(result, i), opt->topt.encoding);
1164 ncells = PQntuples(result) * nfields;
1165 cells = calloc(ncells + 1, sizeof(*cells));
1168 fprintf(stderr, gettext("out of memory\n"));
1172 for (i = 0; i < ncells; i++)
1174 if (PQgetisnull(result, i / nfields, i % nfields))
1175 cells[i] = opt->nullPrint ? opt->nullPrint : "";
1177 cells[i] = mbvalidate(PQgetvalue(result, i / nfields, i % nfields), opt->topt.encoding);
1183 footers = opt->footers;
1184 else if (!opt->topt.expanded && opt->default_footer)
1186 footers = calloc(2, sizeof(*footers));
1189 fprintf(stderr, gettext("out of memory\n"));
1193 footers[0] = malloc(100);
1196 fprintf(stderr, gettext("out of memory\n"));
1199 if (PQntuples(result) == 1)
1200 snprintf(footers[0], 100, gettext("(1 row)"));
1202 snprintf(footers[0], 100, gettext("(%d rows)"), PQntuples(result));
1208 align = calloc(nfields + 1, sizeof(*align));
1211 fprintf(stderr, gettext("out of memory\n"));
1215 for (i = 0; i < nfields; i++)
1217 Oid ftype = PQftype(result, i);
1219 if (ftype == 20 || /* int8 */
1220 ftype == 21 || /* int2 */
1221 ftype == 23 || /* int4 */
1222 (ftype >= 26 && ftype <= 30) || /* ?id */
1223 ftype == 700 || /* float4 */
1224 ftype == 701 || /* float8 */
1225 ftype == 790 || /* money */
1226 ftype == 1700 /* numeric */
1233 /* call table printer */
1234 printTable(opt->title, headers, cells,
1235 (const char *const *) footers,
1236 align, &opt->topt, fout);