diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c index 0e266a3e18..3254a140b3 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -9,6 +9,7 @@ #include "common.h" #include +#include #include #ifndef WIN32 #include /* for write() */ @@ -537,7 +538,7 @@ PSQLexecWatch(const char *query, const printQueryOpt *opt) switch (PQresultStatus(res)) { case PGRES_TUPLES_OK: - printQuery(res, opt, pset.queryFout, pset.logfile); + printQuery(res, opt, pset.queryFout, false, pset.logfile); break; case PGRES_COMMAND_OK: @@ -624,7 +625,7 @@ PrintQueryTuples(const PGresult *results) return false; } - printQuery(results, &my_popt, pset.queryFout, pset.logfile); + printQuery(results, &my_popt, pset.queryFout, false, pset.logfile); /* close file/pipe, restore old setting */ setQFout(NULL); @@ -633,7 +634,7 @@ PrintQueryTuples(const PGresult *results) pset.queryFoutPipe = queryFoutPipe_copy; } else - printQuery(results, &my_popt, pset.queryFout, pset.logfile); + printQuery(results, &my_popt, pset.queryFout, false, pset.logfile); return true; } @@ -1336,11 +1337,11 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec) * If query requires multiple result sets, hack to ensure that * only one pager instance is used for the whole mess */ - pset.queryFout = PageOutput(100000, &(my_popt.topt)); + pset.queryFout = PageOutput(INT_MAX, &(my_popt.topt)); did_pager = true; } - printQuery(results, &my_popt, pset.queryFout, pset.logfile); + printQuery(results, &my_popt, pset.queryFout, did_pager, pset.logfile); PQclear(results); diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 92ed6e2970..a8acdc25ef 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -123,7 +123,7 @@ describeAggregates(const char *pattern, bool verbose, bool showSystem) myopt.title = _("List of aggregate functions"); myopt.translate_header = true; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -204,7 +204,7 @@ describeTablespaces(const char *pattern, bool verbose) myopt.title = _("List of tablespaces"); myopt.translate_header = true; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -469,7 +469,7 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool myopt.translate_columns = translate_columns; myopt.n_translate_columns = lengthof(translate_columns); - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -585,7 +585,7 @@ describeTypes(const char *pattern, bool verbose, bool showSystem) myopt.title = _("List of data types"); myopt.translate_header = true; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -660,7 +660,7 @@ describeOperators(const char *pattern, bool verbose, bool showSystem) myopt.title = _("List of operators"); myopt.translate_header = true; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -731,7 +731,7 @@ listAllDbs(const char *pattern, bool verbose) myopt.title = _("List of databases"); myopt.translate_header = true; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -847,7 +847,7 @@ permissionsList(const char *pattern) myopt.translate_columns = translate_columns; myopt.n_translate_columns = lengthof(translate_columns); - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); termPQExpBuffer(&buf); PQclear(res); @@ -921,7 +921,7 @@ listDefaultACLs(const char *pattern) myopt.translate_columns = translate_columns; myopt.n_translate_columns = lengthof(translate_columns); - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); termPQExpBuffer(&buf); PQclear(res); @@ -1117,7 +1117,7 @@ objectDescription(const char *pattern, bool showSystem) myopt.translate_columns = translate_columns; myopt.n_translate_columns = lengthof(translate_columns); - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -1260,7 +1260,7 @@ describeOneTableDetails(const char *schemaname, { printfPQExpBuffer(&buf, "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, " - "c.relhastriggers, c.relrowsecurity, c.relforcerowsecurity, " + "c.relhastriggers, c.relrowsecurity, c.relforcerowsecurity, " "c.relhasoids, %s, c.reltablespace, " "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, " "c.relpersistence, c.relreplident\n" @@ -2546,8 +2546,7 @@ describeOneTableDetails(const char *schemaname, printTableAddFooter(&cont, buf.data); } - printTable(&cont, pset.queryFout, pset.logfile); - printTableCleanup(&cont); + printTable(&cont, pset.queryFout, false, pset.logfile); retval = true; @@ -2791,7 +2790,7 @@ describeRoles(const char *pattern, bool verbose) } termPQExpBuffer(&buf); - printTable(&cont, pset.queryFout, pset.logfile); + printTable(&cont, pset.queryFout, false, pset.logfile); printTableCleanup(&cont); for (i = 0; i < nrows; i++) @@ -2865,7 +2864,7 @@ listDbRoleSettings(const char *pattern, const char *pattern2) myopt.title = _("List of settings"); myopt.translate_header = true; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); } PQclear(res); @@ -3029,7 +3028,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys myopt.translate_columns = translate_columns; myopt.n_translate_columns = lengthof(translate_columns); - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); } PQclear(res); @@ -3105,7 +3104,7 @@ listLanguages(const char *pattern, bool verbose, bool showSystem) myopt.title = _("List of languages"); myopt.translate_header = true; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -3192,7 +3191,7 @@ listDomains(const char *pattern, bool verbose, bool showSystem) myopt.title = _("List of domains"); myopt.translate_header = true; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -3268,7 +3267,7 @@ listConversions(const char *pattern, bool verbose, bool showSystem) myopt.translate_columns = translate_columns; myopt.n_translate_columns = lengthof(translate_columns); - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -3334,7 +3333,7 @@ listEventTriggers(const char *pattern, bool verbose) myopt.translate_columns = translate_columns; myopt.n_translate_columns = lengthof(translate_columns); - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -3433,7 +3432,7 @@ listCasts(const char *pattern, bool verbose) myopt.translate_columns = translate_columns; myopt.n_translate_columns = lengthof(translate_columns); - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -3509,7 +3508,7 @@ listCollations(const char *pattern, bool verbose, bool showSystem) myopt.translate_columns = translate_columns; myopt.n_translate_columns = lengthof(translate_columns); - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -3566,7 +3565,7 @@ listSchemas(const char *pattern, bool verbose, bool showSystem) myopt.title = _("List of schemas"); myopt.translate_header = true; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -3623,7 +3622,7 @@ listTSParsers(const char *pattern, bool verbose) myopt.title = _("List of text search parsers"); myopt.translate_header = true; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -3769,7 +3768,7 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname) myopt.translate_columns = translate_columns; myopt.n_translate_columns = lengthof(translate_columns); - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); @@ -3801,7 +3800,7 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname) myopt.translate_columns = NULL; myopt.n_translate_columns = 0; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -3869,7 +3868,7 @@ listTSDictionaries(const char *pattern, bool verbose) myopt.title = _("List of text search dictionaries"); myopt.translate_header = true; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -3937,7 +3936,7 @@ listTSTemplates(const char *pattern, bool verbose) myopt.title = _("List of text search templates"); myopt.translate_header = true; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -3994,7 +3993,7 @@ listTSConfigs(const char *pattern, bool verbose) myopt.title = _("List of text search configurations"); myopt.translate_header = true; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -4132,7 +4131,7 @@ describeOneTSConfig(const char *oid, const char *nspname, const char *cfgname, myopt.topt.default_footer = false; myopt.translate_header = true; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); termPQExpBuffer(&title); @@ -4215,7 +4214,7 @@ listForeignDataWrappers(const char *pattern, bool verbose) myopt.title = _("List of foreign-data wrappers"); myopt.translate_header = true; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -4294,7 +4293,7 @@ listForeignServers(const char *pattern, bool verbose) myopt.title = _("List of foreign servers"); myopt.translate_header = true; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -4352,7 +4351,7 @@ listUserMappings(const char *pattern, bool verbose) myopt.title = _("List of user mappings"); myopt.translate_header = true; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -4426,7 +4425,7 @@ listForeignTables(const char *pattern, bool verbose) myopt.title = _("List of foreign tables"); myopt.translate_header = true; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -4480,7 +4479,7 @@ listExtensions(const char *pattern) myopt.title = _("List of installed extensions"); myopt.translate_header = true; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; @@ -4587,7 +4586,7 @@ listOneExtensionContents(const char *extname, const char *oid) myopt.title = title; myopt.translate_header = true; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; diff --git a/src/bin/psql/large_obj.c b/src/bin/psql/large_obj.c index 621d632059..35cfdb90ec 100644 --- a/src/bin/psql/large_obj.c +++ b/src/bin/psql/large_obj.c @@ -308,7 +308,7 @@ do_lo_list(void) myopt.title = _("Large objects"); myopt.translate_header = true; - printQuery(res, &myopt, pset.queryFout, pset.logfile); + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); PQclear(res); return true; diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c index 97f9c2f169..190f2bc5d8 100644 --- a/src/bin/psql/print.c +++ b/src/bin/psql/print.c @@ -191,10 +191,11 @@ const unicodeStyleFormat unicode_style = { /* Local functions */ static int strlen_max_width(unsigned char *str, int *target_width, int encoding); -static void IsPagerNeeded(const printTableContent *cont, const int extra_lines, bool expanded, +static void IsPagerNeeded(const printTableContent *cont, int extra_lines, bool expanded, FILE **fout, bool *is_pager); -static void print_aligned_vertical(const printTableContent *cont, FILE *fout); +static void print_aligned_vertical(const printTableContent *cont, + FILE *fout, bool is_pager); /* Count number of digits in integral part of number */ @@ -570,7 +571,7 @@ _print_horizontal_line(const unsigned int ncolumns, const unsigned int *widths, * Print pretty boxes around cells. */ static void -print_aligned_text(const printTableContent *cont, FILE *fout) +print_aligned_text(const printTableContent *cont, FILE *fout, bool is_pager) { bool opt_tuples_only = cont->opt->tuples_only; int encoding = cont->opt->encoding; @@ -605,7 +606,7 @@ print_aligned_text(const printTableContent *cont, FILE *fout) int *bytes_output; /* Bytes output for column value */ printTextLineWrap *wrap; /* Wrap status for each column */ int output_columns = 0; /* Width of interactive console */ - bool is_pager = false; + bool is_local_pager = false; if (cancel_pressed) return; @@ -813,7 +814,7 @@ print_aligned_text(const printTableContent *cont, FILE *fout) if (cont->opt->expanded == 2 && output_columns > 0 && (output_columns < total_header_width || output_columns < width_total)) { - print_aligned_vertical(cont, fout); + print_aligned_vertical(cont, fout, is_pager); goto cleanup; } @@ -822,11 +823,11 @@ print_aligned_text(const printTableContent *cont, FILE *fout) (output_columns < total_header_width || output_columns < width_total)) { fout = PageOutput(INT_MAX, cont->opt); /* force pager */ - is_pager = true; + is_pager = is_local_pager = true; } /* Check if newlines or our wrapping now need the pager */ - if (!is_pager) + if (!is_pager && fout == stdout) { /* scan all cells, find maximum width, compute cell_count */ for (i = 0, ptr = cont->cells; *ptr; ptr++, cell_count++) @@ -862,6 +863,7 @@ print_aligned_text(const printTableContent *cont, FILE *fout) } } IsPagerNeeded(cont, extra_output_lines, false, &fout, &is_pager); + is_local_pager = is_pager; } /* time to output */ @@ -1153,7 +1155,7 @@ cleanup: free(bytes_output); free(wrap); - if (is_pager) + if (is_local_pager) ClosePager(fout); } @@ -1215,7 +1217,8 @@ print_aligned_vertical_line(const printTextFormat *format, } static void -print_aligned_vertical(const printTableContent *cont, FILE *fout) +print_aligned_vertical(const printTableContent *cont, + FILE *fout, bool is_pager) { bool opt_tuples_only = cont->opt->tuples_only; unsigned short opt_border = cont->opt->border; @@ -1233,7 +1236,7 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout) dformatsize = 0; struct lineptr *hlineptr, *dlineptr; - bool is_pager = false, + bool is_local_pager = false, hmultiline = false, dmultiline = false; int output_columns = 0; /* Width of interactive console */ @@ -1267,7 +1270,11 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout) * get here via print_aligned_text() in expanded auto mode, and so we have * to recalculate the pager requirement based on vertical output. */ - IsPagerNeeded(cont, 0, true, &fout, &is_pager); + if (!is_pager) + { + IsPagerNeeded(cont, 0, true, &fout, &is_pager); + is_local_pager = is_pager; + } /* Find the maximum dimensions for the headers */ for (i = 0; i < cont->ncolumns; i++) @@ -1714,7 +1721,7 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout) free(hlineptr); free(dlineptr); - if (is_pager) + if (is_local_pager) ClosePager(fout); } @@ -3075,8 +3082,8 @@ printTableCleanup(printTableContent *const content) * Setup pager if required */ static void -IsPagerNeeded(const printTableContent *cont, const int extra_lines, bool expanded, FILE **fout, - bool *is_pager) +IsPagerNeeded(const printTableContent *cont, int extra_lines, bool expanded, + FILE **fout, bool *is_pager) { if (*fout == stdout) { @@ -3107,12 +3114,18 @@ IsPagerNeeded(const printTableContent *cont, const int extra_lines, bool expande } /* - * Use this to print just any table in the supported formats. + * Use this to print any table in the supported formats. + * + * cont: table data and formatting options + * fout: where to print to + * is_pager: true if caller has already redirected fout to be a pager pipe + * flog: if not null, also print the table there (for --log-file option) */ void -printTable(const printTableContent *cont, FILE *fout, FILE *flog) +printTable(const printTableContent *cont, + FILE *fout, bool is_pager, FILE *flog) { - bool is_pager = false; + bool is_local_pager = false; if (cancel_pressed) return; @@ -3120,15 +3133,19 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog) if (cont->opt->format == PRINT_NOTHING) return; - /* print_aligned_*() handles the pager themselves */ - if (cont->opt->format != PRINT_ALIGNED && + /* print_aligned_*() handle the pager themselves */ + if (!is_pager && + cont->opt->format != PRINT_ALIGNED && cont->opt->format != PRINT_WRAPPED) + { IsPagerNeeded(cont, 0, (cont->opt->expanded == 1), &fout, &is_pager); + is_local_pager = is_pager; + } /* print the stuff */ if (flog) - print_aligned_text(cont, flog); + print_aligned_text(cont, flog, false); switch (cont->opt->format) { @@ -3140,10 +3157,17 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog) break; case PRINT_ALIGNED: case PRINT_WRAPPED: - if (cont->opt->expanded == 1) - print_aligned_vertical(cont, fout); + + /* + * In expanded-auto mode, force vertical if a pager is passed in; + * else we may make different decisions for different hunks of the + * query result. + */ + if (cont->opt->expanded == 1 || + (cont->opt->expanded == 2 && is_pager)) + print_aligned_vertical(cont, fout, is_pager); else - print_aligned_text(cont, fout); + print_aligned_text(cont, fout, is_pager); break; case PRINT_HTML: if (cont->opt->expanded == 1) @@ -3181,17 +3205,22 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog) exit(EXIT_FAILURE); } - if (is_pager) + if (is_local_pager) ClosePager(fout); } /* * Use this to print query results * - * It calls printTable with all the things set straight. + * result: result of a successful query + * opt: formatting options + * fout: where to print to + * is_pager: true if caller has already redirected fout to be a pager pipe + * flog: if not null, also print the data there (for --log-file option) */ void -printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *flog) +printQuery(const PGresult *result, const printQueryOpt *opt, + FILE *fout, bool is_pager, FILE *flog) { printTableContent cont; int i, @@ -3271,7 +3300,7 @@ printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *f printTableAddFooter(&cont, *footer); } - printTable(&cont, fout, flog); + printTable(&cont, fout, is_pager, flog); printTableCleanup(&cont); } diff --git a/src/bin/psql/print.h b/src/bin/psql/print.h index b0b6bf5251..df514cffb0 100644 --- a/src/bin/psql/print.h +++ b/src/bin/psql/print.h @@ -184,9 +184,10 @@ extern void printTableAddFooter(printTableContent *const content, extern void printTableSetFooter(printTableContent *const content, const char *footer); extern void printTableCleanup(printTableContent *const content); -extern void printTable(const printTableContent *cont, FILE *fout, FILE *flog); +extern void printTable(const printTableContent *cont, + FILE *fout, bool is_pager, FILE *flog); extern void printQuery(const PGresult *result, const printQueryOpt *opt, - FILE *fout, FILE *flog); + FILE *fout, bool is_pager, FILE *flog); extern void setDecimalLocale(void); extern const printTextFormat *get_line_style(const printTableOpt *opt); diff --git a/src/bin/scripts/createlang.c b/src/bin/scripts/createlang.c index 38cc20d9d4..87cd623d25 100644 --- a/src/bin/scripts/createlang.c +++ b/src/bin/scripts/createlang.c @@ -162,7 +162,7 @@ main(int argc, char *argv[]) popt.translate_columns = translate_columns; popt.n_translate_columns = lengthof(translate_columns); - printQuery(result, &popt, stdout, NULL); + printQuery(result, &popt, stdout, false, NULL); PQfinish(conn); exit(0); diff --git a/src/bin/scripts/droplang.c b/src/bin/scripts/droplang.c index 502ec6475e..fb4025ddf7 100644 --- a/src/bin/scripts/droplang.c +++ b/src/bin/scripts/droplang.c @@ -161,7 +161,7 @@ main(int argc, char *argv[]) popt.translate_columns = translate_columns; popt.n_translate_columns = lengthof(translate_columns); - printQuery(result, &popt, stdout, NULL); + printQuery(result, &popt, stdout, false, NULL); PQfinish(conn); exit(0);