diff options
Diffstat (limited to 'src/bin/psql/print.c')
-rw-r--r-- | src/bin/psql/print.c | 482 |
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++) { |