aboutsummaryrefslogtreecommitdiff
path: root/src/bin/psql/print.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/psql/print.c')
-rw-r--r--src/bin/psql/print.c482
1 files changed, 298 insertions, 184 deletions
diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c
index 65d107acc4c..b232906426e 100644
--- a/src/bin/psql/print.c
+++ b/src/bin/psql/print.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.79 2005/10/27 13:34:47 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.80 2006/02/10 00:39:04 momjian Exp $
*/
#include "postgres_fe.h"
#include "common.h"
@@ -49,6 +49,20 @@ pg_local_malloc(size_t size)
return tmp;
}
+static void *
+pg_local_calloc(int count, size_t size)
+{
+ void *tmp;
+
+ tmp = calloc(count, size);
+ if (!tmp)
+ {
+ fprintf(stderr, _("out of memory\n"));
+ exit(EXIT_FAILURE);
+ }
+ return tmp;
+}
+
static int
integer_digits(const char *my_str)
{
@@ -87,6 +101,7 @@ strlen_with_numeric_locale(const char *my_str)
return strlen(my_str) + additional_numeric_locale_len(my_str);
}
+/* Returns the appropriately formatted string in a new allocated block, caller must free */
static char *
format_numeric_locale(const char *my_str)
{
@@ -342,13 +357,20 @@ print_aligned_text(const char *title, const char *const * headers,
{
unsigned int col_count = 0;
unsigned int cell_count = 0;
- unsigned int *head_w,
- *cell_w;
unsigned int i,
tmp;
unsigned int *widths,
total_w;
- const char *const * ptr;
+ unsigned int *heights;
+ unsigned int *format_space;
+ unsigned char **format_buf;
+
+ const char *const *ptr;
+
+ struct lineptr **col_lineptrs; /* pointers to line pointer for each column */
+ struct lineptr *lineptr_list; /* complete list of linepointers */
+
+ int *complete; /* Array remembering which columns have completed output */
/* count columns */
for (ptr = headers; *ptr; ptr++)
@@ -356,64 +378,61 @@ print_aligned_text(const char *title, const char *const * headers,
if (col_count > 0)
{
- widths = calloc(col_count, sizeof(*widths));
- if (!widths)
- {
- fprintf(stderr, _("out of memory\n"));
- exit(EXIT_FAILURE);
- }
-
- head_w = calloc(col_count, sizeof(*head_w));
- if (!head_w)
- {
- fprintf(stderr, _("out of memory\n"));
- exit(EXIT_FAILURE);
- }
+ widths = pg_local_calloc(col_count, sizeof(*widths));
+ heights = pg_local_calloc(col_count, sizeof(*heights));
+ col_lineptrs = pg_local_calloc(col_count, sizeof(*col_lineptrs));
+ format_space = pg_local_calloc(col_count, sizeof(*format_space));
+ format_buf = pg_local_calloc(col_count, sizeof(*format_buf));
+ complete = pg_local_calloc(col_count, sizeof(*complete));
+
}
else
{
widths = NULL;
- head_w = NULL;
+ heights = NULL;
+ col_lineptrs = NULL;
+ format_space = NULL;
+ format_buf = NULL;
+ complete = NULL;
}
-
+
/* count cells (rows * cols) */
for (ptr = cells; *ptr; ptr++)
cell_count++;
- if (cell_count > 0)
- {
- cell_w = calloc(cell_count, sizeof(*cell_w));
- if (!cell_w)
- {
- fprintf(stderr, _("out of memory\n"));
- exit(EXIT_FAILURE);
- }
- }
- else
- cell_w = NULL;
-
/* calc column widths */
for (i = 0; i < col_count; i++)
{
- tmp = pg_wcswidth(headers[i], strlen(headers[i]), encoding);
+ /* Get width & height */
+ int height, space;
+ pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding, &tmp, &height, &space);
if (tmp > widths[i])
widths[i] = tmp;
- head_w[i] = tmp;
+ if (height > heights[i])
+ heights[i] = height;
+ if (space > format_space[i])
+ format_space[i] = space;
}
for (i = 0, ptr = cells; *ptr; ptr++, i++)
{
- int add_numeric_locale_len;
+ int numeric_locale_len;
+ int height, space;
if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
- add_numeric_locale_len = additional_numeric_locale_len(*ptr);
- else
- add_numeric_locale_len = 0;
-
- tmp = pg_wcswidth(*ptr, strlen(*ptr), encoding) + add_numeric_locale_len;
+ numeric_locale_len = additional_numeric_locale_len(*ptr);
+ else
+ numeric_locale_len = 0;
+
+ /* Get width, ignore height */
+ pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, &tmp, &height, &space);
+ tmp += numeric_locale_len;
if (tmp > widths[i % col_count])
widths[i % col_count] = tmp;
- cell_w[i] = tmp;
+ if (height > heights[i % col_count])
+ heights[i % col_count] = height;
+ if (space > format_space[i % col_count])
+ format_space[i % col_count] = space;
}
if (opt_border == 0)
@@ -426,10 +445,38 @@ print_aligned_text(const char *title, const char *const * headers,
for (i = 0; i < col_count; i++)
total_w += widths[i];
+ /* At this point:
+ * widths contains the max width of each column
+ * heights contains the max height of a cell of each column
+ * format_space contains maximum space required to store formatted string
+ * so we prepare the formatting structures
+ */
+ {
+ int heights_total = 0;
+ struct lineptr *lineptr;
+
+ for (i = 0; i < col_count; i++)
+ heights_total += heights[i];
+
+ lineptr = lineptr_list = pg_local_calloc(heights_total, sizeof(*lineptr_list));
+
+ for (i = 0; i < col_count; i++)
+ {
+ col_lineptrs[i] = lineptr;
+ lineptr += heights[i];
+
+ format_buf[i] = pg_local_malloc(format_space[i]);
+
+ col_lineptrs[i]->ptr = format_buf[i];
+ }
+ }
+
/* print title */
if (title && !opt_tuples_only)
{
- tmp = pg_wcswidth(title, strlen(title), encoding);
+ /* Get width & height */
+ int height;
+ pg_wcssize((unsigned char *)title, strlen(title), encoding, &tmp, &height, NULL);
if (tmp >= total_w)
fprintf(fout, "%s\n", title);
else
@@ -439,90 +486,138 @@ print_aligned_text(const char *title, const char *const * headers,
/* print headers */
if (!opt_tuples_only)
{
+ int cols_todo;
+ int line_count;
+
if (opt_border == 2)
_print_horizontal_line(col_count, widths, opt_border, fout);
- if (opt_border == 2)
- fputs("| ", fout);
- else if (opt_border == 1)
- fputc(' ', fout);
-
for (i = 0; i < col_count; i++)
+ pg_wcsformat((unsigned char *)headers[i], strlen(headers[i]), encoding, col_lineptrs[i], heights[i]);
+
+ cols_todo = col_count;
+ line_count = 0;
+ memset(complete, 0, col_count*sizeof(int));
+ while (cols_todo)
{
- unsigned int nbspace;
+ if (opt_border == 2)
+ fprintf(fout, "|%c", line_count ? '+' : ' ');
+ else if (opt_border == 1)
+ fputc(line_count ? '+' : ' ', fout);
- nbspace = widths[i] - head_w[i];
+ for (i = 0; i < col_count; i++)
+ {
+ unsigned int nbspace;
- /* centered */
- fprintf(fout, "%-*s%s%-*s",
- nbspace / 2, "", headers[i], (nbspace + 1) / 2, "");
+ struct lineptr *this_line = col_lineptrs[i] + line_count;
+ if (!complete[i])
+ {
+ nbspace = widths[i] - this_line->width;
- if (i < col_count - 1)
- {
- if (opt_border == 0)
- fputc(' ', fout);
+ /* centered */
+ fprintf(fout, "%-*s%s%-*s",
+ nbspace / 2, "", this_line->ptr, (nbspace + 1) / 2, "");
+
+ if (line_count == (heights[i]-1) || !(this_line+1)->ptr)
+ {
+ cols_todo--;
+ complete[i] = 1;
+ }
+ }
else
- fputs(" | ", fout);
+ fprintf(fout, "%*s", widths[i], "");
+ if (i < col_count - 1)
+ {
+ if (opt_border == 0)
+ fputc(line_count ? '+' : ' ', fout);
+ else
+ fprintf(fout, " |%c", line_count ? '+' : ' ');
+ }
}
+ line_count++;
+
+ if (opt_border == 2)
+ fputs(" |", fout);
+ else if (opt_border == 1)
+ fputc(' ', fout);;
+ fputc('\n', fout);
}
- if (opt_border == 2)
- fputs(" |", fout);
- else if (opt_border == 1)
- fputc(' ', fout);;
- fputc('\n', fout);
_print_horizontal_line(col_count, widths, opt_border, fout);
}
/* print cells */
- for (i = 0, ptr = cells; *ptr; i++, ptr++)
+ for (i = 0, ptr = cells; *ptr; i+=col_count, ptr+=col_count)
{
- /* beginning of line */
- if (i % col_count == 0)
+ int j;
+ int cols_todo = col_count;
+ int line_count; /* Number of lines output so far in row */
+
+ for (j = 0; j < col_count; j++)
+ pg_wcsformat((unsigned char*)ptr[j], strlen(ptr[j]), encoding, col_lineptrs[j], heights[j]);
+
+ line_count = 0;
+ memset(complete, 0, col_count*sizeof(int));
+ while (cols_todo)
{
+ /* beginning of line */
if (opt_border == 2)
fputs("| ", fout);
else if (opt_border == 1)
fputc(' ', fout);
- }
- /* content */
- if (opt_align[i % col_count] == 'r')
- {
- if (opt_numeric_locale)
+ for (j = 0; j < col_count; j++)
{
- char *my_cell = format_numeric_locale(*ptr);
+ struct lineptr *this_line = col_lineptrs[j] + line_count;
+ if (complete[j]) /* Just print spaces... */
+ fprintf(fout, "%*s", widths[j], "");
+ else
+ {
- fprintf(fout, "%*s%s", widths[i % col_count] - cell_w[i], "", my_cell);
- free(my_cell);
+ /* content */
+ if (opt_align[j] == 'r')
+ {
+ if (opt_numeric_locale)
+ {
+ /* Assumption: This code used only on strings
+ * without multibyte characters, otherwise
+ * this_line->width < strlen(this_ptr) and we
+ * get an overflow */
+
+ char *my_cell = format_numeric_locale(this_line->ptr);
+ fprintf(fout, "%*s%s", widths[i % col_count] - strlen(my_cell), "", my_cell);
+ free(my_cell);
+ }
+ else
+ fprintf(fout, "%*s%s", widths[j] - this_line->width, "", this_line->ptr);
+ }
+ else
+ fprintf(fout, "%-s%*s", this_line->ptr,
+ widths[j] - this_line->width, "");
+ /* If at the right height, done this col */
+ if (line_count == heights[j]-1 || !this_line[1].ptr)
+ {
+ complete[j] = 1;
+ cols_todo--;
+ }
+ }
+
+ /* divider */
+ if ((j + 1) % col_count)
+ {
+ if (opt_border == 0)
+ fputc(' ', fout);
+ else if (line_count == 0)
+ fputs(" | ", fout);
+ else
+ fprintf(fout, " %c ", complete[j+1] ? ' ' : ':');
+ }
}
- else
- fprintf(fout, "%*s%s", widths[i % col_count] - cell_w[i], "", *ptr);
- }
- else
- {
- if ((i + 1) % col_count == 0 && opt_border != 2)
- fputs(cells[i], fout);
- else
- fprintf(fout, "%-s%*s", cells[i],
- widths[i % col_count] - cell_w[i], "");
- }
-
- /* divider */
- if ((i + 1) % col_count)
- {
- if (opt_border == 0)
- fputc(' ', fout);
- else
- fputs(" | ", fout);
- }
- /* end of line */
- else
- {
if (opt_border == 2)
fputs(" |", fout);
fputc('\n', fout);
+ line_count++;
}
}
@@ -543,9 +638,15 @@ print_aligned_text(const char *title, const char *const * headers,
#endif
/* clean up */
- free(cell_w);
- free(head_w);
free(widths);
+ free(heights);
+ free(col_lineptrs);
+ free(format_space);
+ free(complete);
+ free(lineptr_list);
+ for (i= 0; i < col_count; i++)
+ free(format_buf[i]);
+ free(format_buf);
}
@@ -563,12 +664,15 @@ print_aligned_vertical(const char *title, const char *const * headers,
unsigned int i,
tmp = 0,
hwidth = 0,
- dwidth = 0;
+ dwidth = 0,
+ hheight = 1,
+ dheight = 1,
+ hformatsize = 0,
+ dformatsize = 0;
char *divider;
unsigned int cell_count = 0;
- unsigned int *cell_w,
- *head_w;
-
+ struct lineptr *hlineptr, *dlineptr;
+
if (cells[0] == NULL)
{
fprintf(fout, _("(No rows)\n"));
@@ -578,58 +682,52 @@ print_aligned_vertical(const char *title, const char *const * headers,
/* count headers and find longest one */
for (ptr = headers; *ptr; ptr++)
col_count++;
- if (col_count > 0)
- {
- head_w = calloc(col_count, sizeof(*head_w));
- if (!head_w)
- {
- fprintf(stderr, _("out of memory\n"));
- exit(EXIT_FAILURE);
- }
- }
- else
- head_w = NULL;
+ /* Find the maximum dimensions for the headers */
for (i = 0; i < col_count; i++)
{
- tmp = pg_wcswidth(headers[i], strlen(headers[i]), encoding);
+ int height, fs;
+ pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding, &tmp, &height, &fs);
if (tmp > hwidth)
hwidth = tmp;
- head_w[i] = tmp;
+ if (height > hheight)
+ hheight = height;
+ if (fs > hformatsize)
+ hformatsize = fs;
}
/* Count cells, find their lengths */
for (ptr = cells; *ptr; ptr++)
cell_count++;
- if (cell_count > 0)
- {
- cell_w = calloc(cell_count, sizeof(*cell_w));
- if (!cell_w)
- {
- fprintf(stderr, _("out of memory\n"));
- exit(EXIT_FAILURE);
- }
- }
- else
- cell_w = NULL;
-
/* find longest data cell */
for (i = 0, ptr = cells; *ptr; ptr++, i++)
{
- int add_numeric_locale_len;
+ int numeric_locale_len;
+ int height, fs;
if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
- add_numeric_locale_len = additional_numeric_locale_len(*ptr);
- else
- add_numeric_locale_len = 0;
+ numeric_locale_len = additional_numeric_locale_len(*ptr);
+ else
+ numeric_locale_len = 0;
- tmp = pg_wcswidth(*ptr, strlen(*ptr), encoding) + add_numeric_locale_len;
+ pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, &tmp, &height, &fs);
+ tmp += numeric_locale_len;
if (tmp > dwidth)
dwidth = tmp;
- cell_w[i] = tmp;
+ if (height > dheight)
+ dheight = height;
+ if (fs > dformatsize)
+ dformatsize = fs;
}
-
+
+ /* We now have all the information we need to setup the formatting structures */
+ dlineptr = pg_local_malloc(sizeof(*dlineptr) * dheight);
+ hlineptr = pg_local_malloc(sizeof(*hlineptr) * hheight);
+
+ dlineptr->ptr = pg_local_malloc(dformatsize);
+ hlineptr->ptr = pg_local_malloc(hformatsize);
+
/* print title */
if (!opt_tuples_only && title)
fprintf(fout, "%s\n", title);
@@ -653,6 +751,8 @@ print_aligned_vertical(const char *title, const char *const * headers,
/* print records */
for (i = 0, ptr = cells; *ptr; i++, ptr++)
{
+ int line_count, dcomplete, hcomplete;
+
if (i % col_count == 0)
{
if (!opt_tuples_only)
@@ -688,33 +788,66 @@ print_aligned_vertical(const char *title, const char *const * headers,
fprintf(fout, "%s\n", divider);
}
- if (opt_border == 2)
- fputs("| ", fout);
- fprintf(fout, "%-s%*s", headers[i % col_count],
- hwidth - head_w[i % col_count], "");
-
- if (opt_border > 0)
- fputs(" | ", fout);
- else
- fputs(" ", fout);
-
- if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
+ /* Format the header */
+ pg_wcsformat((unsigned char*)headers[i % col_count],
+ strlen(headers[i % col_count]), encoding, hlineptr, hheight);
+ /* Format the data */
+ pg_wcsformat((unsigned char*)*ptr, strlen(*ptr), encoding, dlineptr, dheight);
+
+ line_count = 0;
+ dcomplete = hcomplete = 0;
+ while (!dcomplete || !hcomplete)
{
- char *my_cell = format_numeric_locale(*ptr);
-
- if (opt_border < 2)
- fprintf(fout, "%s\n", my_cell);
+ if (opt_border == 2)
+ fputs("| ", fout);
+ if (!hcomplete)
+ {
+ fprintf(fout, "%-s%*s", hlineptr[line_count].ptr,
+ hwidth - hlineptr[line_count].width, "");
+
+ if (line_count == (hheight-1) || !hlineptr[line_count+1].ptr)
+ hcomplete = 1;
+ }
else
- fprintf(fout, "%-s%*s |\n", my_cell, dwidth - cell_w[i], "");
- free(my_cell);
- }
- else
- {
- if (opt_border < 2)
- fprintf(fout, "%s\n", *ptr);
+ fprintf(fout, "%*s", hwidth, "");
+
+ if (opt_border > 0)
+ fprintf(fout, " %c ", (line_count==0)?'|':':');
else
- fprintf(fout, "%-s%*s |\n", *ptr, dwidth - cell_w[i], "");
- }
+ fputs(" ", fout);
+
+ if (!dcomplete)
+ {
+ if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
+ {
+ char *my_cell = format_numeric_locale(dlineptr[line_count].ptr);
+ if (opt_border < 2)
+ fprintf(fout, "%s\n", my_cell);
+ else
+ fprintf(fout, "%-s%*s |\n", my_cell, dwidth - strlen(my_cell), "");
+ free(my_cell);
+ }
+ else
+ {
+ if (opt_border < 2)
+ fprintf(fout, "%s\n", dlineptr[line_count].ptr);
+ else
+ fprintf(fout, "%-s%*s |\n", dlineptr[line_count].ptr,
+ dwidth - dlineptr[line_count].width, "");
+ }
+
+ if (line_count == dheight - 1 || !dlineptr[line_count+1].ptr)
+ dcomplete = 1;
+ }
+ else
+ {
+ if (opt_border < 2)
+ fputc('\n', fout);
+ else
+ fprintf(fout, "%*s |\n", dwidth, "");
+ }
+ line_count++;
+ }
}
if (opt_border == 2)
@@ -732,9 +865,10 @@ print_aligned_vertical(const char *title, const char *const * headers,
fputc('\n', fout);
free(divider);
-
- free(cell_w);
- free(head_w);
+ free(hlineptr->ptr);
+ free(dlineptr->ptr);
+ free(hlineptr);
+ free(dlineptr);
}
@@ -1613,24 +1747,14 @@ printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *f
/* extract headers */
nfields = PQnfields(result);
- headers = calloc(nfields + 1, sizeof(*headers));
- if (!headers)
- {
- fprintf(stderr, _("out of memory\n"));
- exit(EXIT_FAILURE);
- }
+ headers = pg_local_calloc(nfields + 1, sizeof(*headers));
for (i = 0; i < nfields; i++)
headers[i] = mbvalidate(PQfname(result, i), opt->topt.encoding);
/* set cells */
ncells = PQntuples(result) * nfields;
- cells = calloc(ncells + 1, sizeof(*cells));
- if (!cells)
- {
- fprintf(stderr, _("out of memory\n"));
- exit(EXIT_FAILURE);
- }
+ cells = pg_local_calloc(ncells + 1, sizeof(*cells));
for (i = 0; i < ncells; i++)
{
@@ -1646,12 +1770,7 @@ printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *f
footers = opt->footers;
else if (!opt->topt.expanded && opt->default_footer)
{
- footers = calloc(2, sizeof(*footers));
- if (!footers)
- {
- fprintf(stderr, _("out of memory\n"));
- exit(EXIT_FAILURE);
- }
+ footers = pg_local_calloc(2, sizeof(*footers));
footers[0] = pg_local_malloc(100);
if (PQntuples(result) == 1)
@@ -1663,12 +1782,7 @@ printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *f
footers = NULL;
/* set alignment */
- align = calloc(nfields + 1, sizeof(*align));
- if (!align)
- {
- fprintf(stderr, _("out of memory\n"));
- exit(EXIT_FAILURE);
- }
+ align = pg_local_calloc(nfields + 1, sizeof(*align));
for (i = 0; i < nfields; i++)
{