From 95489222b9bf42b7b063ccecf5da58dd8caafa60 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=81lvaro=20Herrera?= <alvherre@kurilemu.de>
Date: Fri, 19 Jun 2026 16:37:14 +0200
Subject: [PATCH] fix crosstabview for true/false print

---
 src/bin/psql/crosstabview.c                 | 28 +++++++++++++++------
 src/test/regress/expected/psql_crosstab.out | 15 +++++++++++
 src/test/regress/sql/psql_crosstab.sql      | 10 ++++++++
 3 files changed, 46 insertions(+), 7 deletions(-)

diff --git a/src/bin/psql/crosstabview.c b/src/bin/psql/crosstabview.c
index 111e8823bdb..dddef624a06 100644
--- a/src/bin/psql/crosstabview.c
+++ b/src/bin/psql/crosstabview.c
@@ -7,6 +7,8 @@
  */
 #include "postgres_fe.h"
 
+#include "catalog/pg_type_d.h"
+
 #include "common.h"
 #include "common/int.h"
 #include "common/logging.h"
@@ -288,6 +290,7 @@ printCrosstab(const PGresult *result,
 {
 	printQueryOpt popt = pset.popt;
 	printTableContent cont;
+	Oid			data_ftype = PQftype(result, field_for_data);
 	int			i,
 				rn;
 	char		col_align;
@@ -317,7 +320,7 @@ printCrosstab(const PGresult *result,
 	/*
 	 * The display alignment depends on its PQftype().
 	 */
-	col_align = column_type_alignment(PQftype(result, field_for_data));
+	col_align = column_type_alignment(data_ftype);
 
 	for (i = 0; i < num_columns; i++)
 	{
@@ -335,10 +338,10 @@ printCrosstab(const PGresult *result,
 	for (i = 0; i < num_rows; i++)
 	{
 		int			k = piv_rows[i].rank;
+		int			idx = k * (num_columns + 1);
 
-		cont.cells[k * (num_columns + 1)] = piv_rows[i].name ?
-			piv_rows[i].name :
-			(popt.nullPrint ? popt.nullPrint : "");
+		cont.cells[idx] = piv_rows[i].name ?
+			piv_rows[i].name : (popt.nullPrint ? popt.nullPrint : "");
 	}
 	cont.cellsadded = num_rows * (num_columns + 1);
 
@@ -401,9 +404,20 @@ printCrosstab(const PGresult *result,
 				goto error;
 			}
 
-			cont.cells[idx] = !PQgetisnull(result, rn, field_for_data) ?
-				PQgetvalue(result, rn, field_for_data) :
-				(popt.nullPrint ? popt.nullPrint : "");
+			if (PQgetisnull(result, rn, field_for_data))
+				cont.cells[idx] = (popt.nullPrint ? popt.nullPrint : "");
+			else if (data_ftype == BOOLOID)
+			{
+				char	*value;
+
+				value = PQgetvalue(result, rn, field_for_data);
+				if (value[0] == 't')
+					cont.cells[idx] = popt.truePrint ? popt.truePrint : "t";
+				else
+					cont.cells[idx] = popt.falsePrint ? popt.falsePrint : "f";
+			}
+			else
+				cont.cells[idx] = PQgetvalue(result, rn, field_for_data);
 		}
 	}
 
diff --git a/src/test/regress/expected/psql_crosstab.out b/src/test/regress/expected/psql_crosstab.out
index e09e3310165..f2307dbf910 100644
--- a/src/test/regress/expected/psql_crosstab.out
+++ b/src/test/regress/expected/psql_crosstab.out
@@ -137,6 +137,21 @@ GROUP BY v, h ORDER BY h,v
 (3 rows)
 
 \pset null ''
+-- boolean display
+\pset display_true 'true'
+\pset display_false 'false'
+SELECT false as row_key, true as col_key, true as val
+UNION ALL
+SELECT true, false, false
+ \crosstabview row_key col_key val
+ row_key |  t   |   f   
+---------+------+-------
+ f       | true | 
+ t       |      | false
+(2 rows)
+
+\pset display_true 't'
+\pset display_false 'f'
 -- refer to columns by position
 SELECT v,h,string_agg(i::text, E'\n'), string_agg(c, E'\n')
 FROM ctv_data GROUP BY v, h ORDER BY h,v
diff --git a/src/test/regress/sql/psql_crosstab.sql b/src/test/regress/sql/psql_crosstab.sql
index 5a4511389de..00b395d7168 100644
--- a/src/test/regress/sql/psql_crosstab.sql
+++ b/src/test/regress/sql/psql_crosstab.sql
@@ -69,6 +69,16 @@ GROUP BY v, h ORDER BY h,v
  \crosstabview v h i
 \pset null ''
 
+-- boolean display
+\pset display_true 'true'
+\pset display_false 'false'
+SELECT false as row_key, true as col_key, true as val
+UNION ALL
+SELECT true, false, false
+ \crosstabview row_key col_key val
+\pset display_true 't'
+\pset display_false 'f'
+
 -- refer to columns by position
 SELECT v,h,string_agg(i::text, E'\n'), string_agg(c, E'\n')
 FROM ctv_data GROUP BY v, h ORDER BY h,v
-- 
2.47.3

