diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index dd59aa116c..7f91ff9fce 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -2407,12 +2407,12 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet) else if (strcmp(param, "footer") == 0) { if (value) - popt->default_footer = ParseVariableBool(value); + popt->topt.default_footer = ParseVariableBool(value); else - popt->default_footer = !popt->default_footer; + popt->topt.default_footer = !popt->topt.default_footer; if (!quiet) { - if (popt->default_footer) + if (popt->topt.default_footer) puts(_("Default footer is on.")); else puts(_("Default footer is off.")); diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index ffaaf4049f..8dfb5705ce 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -1130,6 +1130,7 @@ describeOneTableDetails(const char *schemaname, retval = false; + myopt.default_footer = false; /* This output looks confusing in expanded mode. */ myopt.expanded = false; @@ -2363,6 +2364,8 @@ describeRoles(const char *pattern, bool verbose) const char align = 'l'; char **attr; + myopt.default_footer = false; + initPQExpBuffer(&buf); if (pset.sversion >= 80100) @@ -3362,7 +3365,7 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname) sprintf(title, _("Text search parser \"%s\""), prsname); myopt.title = title; myopt.footers = NULL; - myopt.default_footer = false; + myopt.topt.default_footer = false; myopt.translate_header = true; myopt.translate_columns = translate_columns; @@ -3393,7 +3396,7 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname) sprintf(title, _("Token types for parser \"%s\""), prsname); myopt.title = title; myopt.footers = NULL; - myopt.default_footer = true; + myopt.topt.default_footer = true; myopt.translate_header = true; myopt.translate_columns = NULL; @@ -3725,7 +3728,7 @@ describeOneTSConfig(const char *oid, const char *nspname, const char *cfgname, myopt.nullPrint = NULL; myopt.title = title.data; myopt.footers = NULL; - myopt.default_footer = false; + myopt.topt.default_footer = false; myopt.translate_header = true; printQuery(res, &myopt, pset.queryFout, pset.logfile); diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c index d2474716db..c431f6a437 100644 --- a/src/bin/psql/print.c +++ b/src/bin/psql/print.c @@ -44,6 +44,9 @@ static char *decimal_point; static char *grouping; static char *thousands_sep; +static char default_footer[100]; +static printTableFooter default_footer_cell = { default_footer, NULL }; + /* Line style control structures */ const printTextFormat pg_asciiformat = { @@ -278,6 +281,34 @@ print_separator(struct separator sep, FILE *fout) } +/* + * Return the list of explicitly-requested footers or, when applicable, the + * default "(xx rows)" footer. Always omit the default footer when given + * non-default footers, "\pset footer off", or a specific instruction to that + * effect from a calling backslash command. Vertical formats number each row, + * making the default footer redundant; they do not call this function. + * + * The return value may point to static storage; do not keep it across calls. + */ +static printTableFooter * +footers_with_default(const printTableContent *cont) +{ + if (cont->footers == NULL && cont->opt->default_footer) + { + unsigned long total_records; + + total_records = cont->opt->prior_records + cont->nrows; + snprintf(default_footer, sizeof(default_footer), + ngettext("(%lu row)", "(%lu rows)", total_records), + total_records); + + return &default_footer_cell; + } + else + return cont->footers; +} + + /*************************/ /* Unaligned text */ /*************************/ @@ -340,11 +371,13 @@ print_unaligned_text(const printTableContent *cont, FILE *fout) /* print footers */ if (cont->opt->stop_table) { - if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed) + printTableFooter *footers = footers_with_default(cont); + + if (!opt_tuples_only && footers != NULL && !cancel_pressed) { printTableFooter *f; - for (f = cont->footers; f; f = f->next) + for (f = footers; f; f = f->next) { if (need_recordsep) { @@ -1034,16 +1067,18 @@ print_aligned_text(const printTableContent *cont, FILE *fout) if (cont->opt->stop_table) { + printTableFooter *footers = footers_with_default(cont); + if (opt_border == 2 && !cancel_pressed) _print_horizontal_line(col_count, width_wrap, opt_border, PRINT_RULE_BOTTOM, format, fout); /* print footers */ - if (cont->footers && !opt_tuples_only && !cancel_pressed) + if (footers && !opt_tuples_only && !cancel_pressed) { printTableFooter *f; - for (f = cont->footers; f; f = f->next) + for (f = footers; f; f = f->next) fprintf(fout, "%s\n", f->data); } @@ -1447,15 +1482,17 @@ print_html_text(const printTableContent *cont, FILE *fout) if (cont->opt->stop_table) { + printTableFooter *footers = footers_with_default(cont); + fputs("\n", fout); /* print footers */ - if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed) + if (!opt_tuples_only && footers != NULL && !cancel_pressed) { printTableFooter *f; fputs("
", fout);
- for (f = cont->footers; f; f = f->next)
+ for (f = footers; f; f = f->next)
{
html_escaped_print(f->data, fout);
fputs("
\n", fout);
@@ -1668,17 +1705,19 @@ print_latex_text(const printTableContent *cont, FILE *fout)
if (cont->opt->stop_table)
{
+ printTableFooter *footers = footers_with_default(cont);
+
if (opt_border == 2)
fputs("\\hline\n", fout);
fputs("\\end{tabular}\n\n\\noindent ", fout);
/* print footers */
- if (cont->footers && !opt_tuples_only && !cancel_pressed)
+ if (footers && !opt_tuples_only && !cancel_pressed)
{
printTableFooter *f;
- for (f = cont->footers; f; f = f->next)
+ for (f = footers; f; f = f->next)
{
latex_escaped_print(f->data, fout);
fputs(" \\\\\n", fout);
@@ -1871,14 +1910,16 @@ print_troff_ms_text(const printTableContent *cont, FILE *fout)
if (cont->opt->stop_table)
{
+ printTableFooter *footers = footers_with_default(cont);
+
fputs(".TE\n.DS L\n", fout);
/* print footers */
- if (cont->footers && !opt_tuples_only && !cancel_pressed)
+ if (footers && !opt_tuples_only && !cancel_pressed)
{
printTableFooter *f;
- for (f = cont->footers; f; f = f->next)
+ for (f = footers; f; f = f->next)
{
troff_ms_escaped_print(f->data, fout);
fputc('\n', fout);
@@ -2481,18 +2522,6 @@ printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *f
for (footer = opt->footers; *footer; footer++)
printTableAddFooter(&cont, *footer);
}
- else if (!opt->topt.expanded && opt->default_footer)
- {
- unsigned long total_records;
- char default_footer[100];
-
- total_records = opt->topt.prior_records + cont.nrows;
- snprintf(default_footer, sizeof(default_footer),
- ngettext("(%lu row)", "(%lu rows)", total_records),
- total_records);
-
- printTableAddFooter(&cont, default_footer);
- }
printTable(&cont, fout, flog);
printTableCleanup(&cont);
diff --git a/src/bin/psql/print.h b/src/bin/psql/print.h
index c7377562c5..25adfc5813 100644
--- a/src/bin/psql/print.h
+++ b/src/bin/psql/print.h
@@ -85,6 +85,7 @@ typedef struct printTableOpt
bool tuples_only; /* don't output headers, row counts, etc. */
bool start_table; /* print start decoration, eg