Add \pset options for boolean value display
authorÁlvaro Herrera <[email protected]>
Mon, 3 Nov 2025 16:40:39 +0000 (17:40 +0100)
committerÁlvaro Herrera <[email protected]>
Mon, 3 Nov 2025 16:40:39 +0000 (17:40 +0100)
New \pset variables display_true and display_false allow the user to
change how true and false values are displayed.

Author: David G. Johnston <[email protected]>
Reviewed-by: Álvaro Herrera <[email protected]>
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
src/bin/psql/command.c
src/bin/psql/help.c
src/bin/psql/tab-complete.in.c
src/fe_utils/print.c
src/include/fe_utils/print.h
src/test/regress/expected/psql.out
src/test/regress/sql/psql.sql

index 84683f62b1c86ba816fc166605b9bc44b8dcbb32..7e96a8e1ddb7cf0124ab241845527270741e0727 100644 (file)
@@ -3099,6 +3099,26 @@ SELECT $1 \parse stmt1
           </listitem>
           </varlistentry>
 
+          <varlistentry id="app-psql-meta-command-pset-display-false">
+          <term><literal>display_false</literal></term>
+          <listitem>
+          <para>
+          Sets the string to be printed in place of a false value.
+          The default is to print <literal>f</literal>.
+          </para>
+          </listitem>
+          </varlistentry>
+
+          <varlistentry id="app-psql-meta-command-pset-display-true">
+          <term><literal>display_true</literal></term>
+          <listitem>
+          <para>
+          Sets the string to be printed in place of a true value.
+          The default is to print <literal>t</literal>.
+          </para>
+          </listitem>
+          </varlistentry>
+
           <varlistentry id="app-psql-meta-command-pset-expanded">
           <term><literal>expanded</literal> (or <literal>x</literal>)</term>
           <listitem>
index cc602087db24662eead468fc6897b3eec2339f3a..4a2976dddf066941934104ff1247bf8e3031deaa 100644 (file)
@@ -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"
index ed00c36695e859cc066cc9d6c14eff3f98e17a1d..6ae1a9940dec7362f1f2a5a76351cb93edb0c6e1 100644 (file)
@@ -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"
index 36ea6a4d5570982e29c5462f713ae8efbb82a57d..0b7b3aead7c78d87ff44856f2a58d06238cf681c 100644 (file)
@@ -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",
index 73847d3d6b3e96068d90d8b9ad006f7ebae6f260..4d97ad2ddeb779f53feae6b6b11334caff76d08f 100644 (file)
@@ -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);
index c99c2ee1a31a2a3d09b27ee338d01ee13aafafc2..6a6fc7e132c226f9f50e709fcfe87d6a3b11defa 100644 (file)
@@ -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 */
index fa8984ffe0da2c9ec115dfda547f003aabb02d82..c8f3932edf094fd4e9ebed41a44774278acd6a4d 100644 (file)
@@ -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
index f064e4f54560794bbdd0171ea21d506d5ee1c7a6..dcdbd4fc020917f8e1a3d5f61a40fec073d4f567 100644 (file)
@@ -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