From 645cb44c5490f70da4dca57b8ecca6562fb883a7 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C3=81lvaro=20Herrera?= Date: Mon, 3 Nov 2025 17:40:39 +0100 Subject: [PATCH] Add \pset options for boolean value display MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit New \pset variables display_true and display_false allow the user to change how true and false values are displayed. Author: David G. Johnston Reviewed-by: Álvaro Herrera Discussion: https://postgr.es/m/CAKFQuwYts3vnfQ5AoKhEaKMTNMfJ443MW2kFswKwzn7fiofkrw@mail.gmail.com Discussion: https://postgr.es/m/56308F56.8060908@joh.to --- doc/src/sgml/ref/psql-ref.sgml | 20 +++++++++++++++ src/bin/psql/command.c | 41 +++++++++++++++++++++++++++++- src/bin/psql/help.c | 10 +++++--- src/bin/psql/tab-complete.in.c | 3 ++- src/fe_utils/print.c | 4 +++ src/include/fe_utils/print.h | 2 ++ src/test/regress/expected/psql.out | 32 +++++++++++++++++++++++ src/test/regress/sql/psql.sql | 16 ++++++++++++ 8 files changed, 123 insertions(+), 5 deletions(-) diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index 84683f62b1c..7e96a8e1ddb 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -3099,6 +3099,26 @@ SELECT $1 \parse stmt1 + + display_false + + + Sets the string to be printed in place of a false value. + The default is to print f. + + + + + + display_true + + + Sets the string to be printed in place of a true value. + The default is to print t. + + + + expanded (or x) diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index cc602087db2..4a2976dddf0 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,10 @@ 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/bin/psql/help.c b/src/bin/psql/help.c index ed00c36695e..6ae1a9940de 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -290,9 +290,9 @@ slashUsage(unsigned short int pager) HELPN(" \\H toggle HTML output mode (currently %s)\n", ON(pset.popt.topt.format == PRINT_HTML)); HELP0(" \\pset [NAME [VALUE]] set table output option\n" - " (border|columns|csv_fieldsep|expanded|fieldsep|\n" - " fieldsep_zero|footer|format|linestyle|null|\n" - " numericlocale|pager|pager_min_lines|recordsep|\n" + " (border|columns|csv_fieldsep|display_false|display_true|\n" + " expanded|fieldsep|fieldsep_zero|footer|format|linestyle|\n" + " null|numericlocale|pager|pager_min_lines|recordsep|\n" " recordsep_zero|tableattr|title|tuples_only|\n" " unicode_border_linestyle|unicode_column_linestyle|\n" " unicode_header_linestyle|xheader_width)\n"); @@ -480,6 +480,10 @@ helpVariables(unsigned short int pager) " border style (number)\n"); HELP0(" columns\n" " target width for the wrapped format\n"); + HELP0(" display_false\n" + " set the string to be printed in place of a boolean 'false'\n"); + HELP0(" display_true\n" + " set the string to be printed in place of a boolean 'true'\n"); HELP0(" expanded (or x)\n" " expanded output [on, off, auto]\n"); HELPN(" fieldsep\n" diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c index 36ea6a4d557..0b7b3aead7c 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -5478,7 +5478,8 @@ match_previous_words(int pattern_id, else if (TailMatchesCS("\\password")) COMPLETE_WITH_QUERY(Query_for_list_of_roles); else if (TailMatchesCS("\\pset")) - COMPLETE_WITH_CS("border", "columns", "csv_fieldsep", "expanded", + COMPLETE_WITH_CS("border", "columns", "csv_fieldsep", + "display_false", "display_true", "expanded", "fieldsep", "fieldsep_zero", "footer", "format", "linestyle", "null", "numericlocale", "pager", "pager_min_lines", diff --git a/src/fe_utils/print.c b/src/fe_utils/print.c index 73847d3d6b3..4d97ad2ddeb 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 c99c2ee1a31..6a6fc7e132c 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 fa8984ffe0d..c8f3932edf0 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 f064e4f5456..dcdbd4fc020 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 -- 2.47.3