diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index 84683f62b1c8..80e6ee21b108 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -3099,6 +3099,30 @@ SELECT $1 \parse stmt1 + + display_false + + + Sets the string to be printed in place of a false value. + The default is to print f, as that is the value + transmitted by the server. For readability, + \pset display_false 'false' is recommended. + + + + + + display_true + + + Sets the string to be printed in place of a true value. + The default is to print t, as that is the value + transmitted by the server. For readability, + \pset display_true 'true' is recommended. + + + + expanded (or x) diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index cc602087db24..f7454daf6ed7 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -2709,7 +2709,8 @@ exec_command_pset(PsqlScanState scan_state, bool active_branch) int i; static const char *const my_list[] = { - "border", "columns", "csv_fieldsep", "expanded", "fieldsep", + "border", "columns", "csv_fieldsep", + "display_false", "display_true", "expanded", "fieldsep", "fieldsep_zero", "footer", "format", "linestyle", "null", "numericlocale", "pager", "pager_min_lines", "recordsep", "recordsep_zero", @@ -5300,6 +5301,26 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet) } } + /* 'false' display */ + else if (strcmp(param, "display_false") == 0) + { + if (value) + { + free(popt->falsePrint); + popt->falsePrint = pg_strdup(value); + } + } + + /* 'true' display */ + else if (strcmp(param, "display_true") == 0) + { + if (value) + { + free(popt->truePrint); + popt->truePrint = pg_strdup(value); + } + } + /* field separator for unaligned text */ else if (strcmp(param, "fieldsep") == 0) { @@ -5474,6 +5495,20 @@ printPsetInfo(const char *param, printQueryOpt *popt) popt->topt.csvFieldSep); } + /* show boolean 'false' display */ + else if (strcmp(param, "display_false") == 0) + { + printf(_("Boolean false display is \"%s\".\n"), + popt->falsePrint ? popt->falsePrint : "f"); + } + + /* show boolean 'true' display */ + else if (strcmp(param, "display_true") == 0) + { + printf(_("Boolean true display is \"%s\".\n"), + popt->truePrint ? popt->truePrint : "t"); + } + /* show field separator for unaligned text */ else if (strcmp(param, "fieldsep") == 0) { @@ -5743,6 +5778,12 @@ pset_value_string(const char *param, printQueryOpt *popt) return psprintf("%d", popt->topt.columns); else if (strcmp(param, "csv_fieldsep") == 0) return pset_quoted_string(popt->topt.csvFieldSep); + else if (strcmp(param, "display_false") == 0) + return pset_quoted_string(popt->falsePrint ? + popt->falsePrint : "f"); + else if (strcmp(param, "display_true") == 0) + return pset_quoted_string(popt->truePrint ? + popt->truePrint : "t"); else if (strcmp(param, "expanded") == 0) return pstrdup(popt->topt.expanded == 2 ? "auto" diff --git a/src/fe_utils/print.c b/src/fe_utils/print.c index 73847d3d6b3e..4d97ad2ddeb7 100644 --- a/src/fe_utils/print.c +++ b/src/fe_utils/print.c @@ -3775,6 +3775,10 @@ printQuery(const PGresult *result, const printQueryOpt *opt, if (PQgetisnull(result, r, c)) cell = opt->nullPrint ? opt->nullPrint : ""; + else if (PQftype(result, c) == BOOLOID) + cell = (PQgetvalue(result, r, c)[0] == 't' ? + (opt->truePrint ? opt->truePrint : "t") : + (opt->falsePrint ? opt->falsePrint : "f")); else { cell = PQgetvalue(result, r, c); diff --git a/src/include/fe_utils/print.h b/src/include/fe_utils/print.h index c99c2ee1a31a..6a6fc7e132c2 100644 --- a/src/include/fe_utils/print.h +++ b/src/include/fe_utils/print.h @@ -184,6 +184,8 @@ typedef struct printQueryOpt { printTableOpt topt; /* the options above */ char *nullPrint; /* how to print null entities */ + char *truePrint; /* how to print boolean true values */ + char *falsePrint; /* how to print boolean false values */ char *title; /* override title */ char **footers; /* override footer (default is "(xx rows)") */ bool translate_header; /* do gettext on column headers */ diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out index fa8984ffe0da..c8f3932edf09 100644 --- a/src/test/regress/expected/psql.out +++ b/src/test/regress/expected/psql.out @@ -445,6 +445,8 @@ environment value border 1 columns 0 csv_fieldsep ',' +display_false 'f' +display_true 't' expanded off fieldsep '|' fieldsep_zero off @@ -464,6 +466,36 @@ unicode_border_linestyle single unicode_column_linestyle single unicode_header_linestyle single xheader_width full +-- test the simple display substitution settings +prepare q as select null as n, true as t, false as f; +\pset null '(null)' +\pset display_true 'true' +\pset display_false 'false' +execute q; + n | t | f +--------+------+------- + (null) | true | false +(1 row) + +\pset null +\pset display_true +\pset display_false +execute q; + n | t | f +--------+------+------- + (null) | true | false +(1 row) + +\pset null '' +\pset display_true 't' +\pset display_false 'f' +execute q; + n | t | f +---+---+--- + | t | f +(1 row) + +deallocate q; -- test multi-line headers, wrapping, and newline indicators -- in aligned, unaligned, and wrapped formats prepare q as select array_to_string(array_agg(repeat('x',2*n)),E'\n') as "ab diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql index f064e4f54560..dcdbd4fc0209 100644 --- a/src/test/regress/sql/psql.sql +++ b/src/test/regress/sql/psql.sql @@ -219,6 +219,22 @@ select 'drop table gexec_test', 'select ''2000-01-01''::date as party_over' -- show all pset options \pset +-- test the simple display substitution settings +prepare q as select null as n, true as t, false as f; +\pset null '(null)' +\pset display_true 'true' +\pset display_false 'false' +execute q; +\pset null +\pset display_true +\pset display_false +execute q; +\pset null '' +\pset display_true 't' +\pset display_false 'f' +execute q; +deallocate q; + -- test multi-line headers, wrapping, and newline indicators -- in aligned, unaligned, and wrapped formats prepare q as select array_to_string(array_agg(repeat('x',2*n)),E'\n') as "ab