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);