*/
#include "postgres_fe.h"
+#include "catalog/pg_type_d.h"
#include "common.h"
#include "common/int.h"
#include "common/logging.h"
int num_columns, pivot_field *piv_columns, int field_for_columns,
int num_rows, pivot_field *piv_rows, int field_for_rows,
int field_for_data);
+static char *displayValue(char *value, Oid ftype, char *default_null);
+
static void avlInit(avl_tree *tree);
static void avlMergeValue(avl_tree *tree, char *name, char *sort_value);
static int avlCollectFields(avl_tree *tree, avl_node *node,
rn;
char col_align;
int *horiz_map;
+ Oid col_ftype = PQftype(result, field_for_columns);
+ Oid row_ftype = PQftype(result, field_for_rows);
+ Oid data_ftype = PQftype(result, field_for_data);
bool retval = false;
printTableInit(&cont, &popt.topt, popt.title, num_columns + 1, num_rows);
printTableAddHeader(&cont,
PQfname(result, field_for_rows),
false,
- column_type_alignment(PQftype(result,
- field_for_rows)));
+ column_type_alignment(row_ftype));
/*
* To iterate over piv_columns[] by piv_columns[].rank, create a reverse
/*
* 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++)
{
char *colname;
- colname = piv_columns[horiz_map[i]].name ?
- piv_columns[horiz_map[i]].name :
- (popt.nullPrint ? popt.nullPrint : "");
+ colname = displayValue(piv_columns[horiz_map[i]].name, col_ftype, "");
printTableAddHeader(&cont, colname, false, col_align);
}
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] = displayValue(piv_rows[i].name, row_ftype, "");
}
cont.cellsadded = num_rows * (num_columns + 1);
if (col_number >= 0 && row_number >= 0)
{
int idx;
+ char *value;
/* index into the cont.cells array */
idx = 1 + col_number + row_number * (num_columns + 1);
if (cont.cells[idx] != NULL)
{
pg_log_error("\\crosstabview: query result contains multiple data values for row \"%s\", column \"%s\"",
- rp->name ? rp->name :
- (popt.nullPrint ? popt.nullPrint : "(null)"),
- cp->name ? cp->name :
- (popt.nullPrint ? popt.nullPrint : "(null)"));
+ displayValue(rp->name, row_ftype, "(null)"),
+ displayValue(cp->name, col_ftype, "(null)"));
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))
+ value = NULL;
+ else
+ value = PQgetvalue(result, rn, field_for_data);
+ cont.cells[idx] = displayValue(value, data_ftype, "");
}
}
return retval;
}
+/*
+ * Return the display representation of one cell value in \crosstabview,
+ * following pset substitutions.
+ *
+ * The returned pointer is not to be freed.
+ */
+static char *
+displayValue(char *value, Oid ftype, char *default_null)
+{
+ printQueryOpt popt = pset.popt;
+
+ if (value == NULL)
+ value = popt.nullPrint ? popt.nullPrint : default_null;
+ else if (ftype == BOOLOID)
+ {
+ if (value[0] == 't' && popt.truePrint)
+ value = popt.truePrint;
+ else if (value[0] == 'f' && popt.falsePrint)
+ value = popt.falsePrint;
+ }
+
+ return value;
+}
+
/*
* The avl* functions below provide a minimalistic implementation of AVL binary
* trees, to efficiently collect the distinct values that will form the horizontal
| | | | -3 |
(3 rows)
+\pset null ''
+-- boolean display
+\pset display_true 'Aye'
+\pset display_false 'Nay'
+\pset null 'Wut'
+with rows (display_bools, col_key, val) as (values
+ (false, false, false),
+ (true, true, true),
+ (null, null, null),
+ (null, true, false),
+ (null, false, true),
+ (true, null, false),
+ (false, null, true)
+) select * from rows
+ \crosstabview display_bools col_key val
+ display_bools | Nay | Aye | Wut
+---------------+-----+-----+-----
+ Nay | Nay | | Aye
+ Aye | | Aye | Nay
+ Wut | Aye | Nay | Wut
+(3 rows)
+
+with rows (tst, col, val) as (values
+ (true, null, 42), (true, null, 142857)
+) select * from rows
+ \crosstabview tst col
+\crosstabview: query result contains multiple data values for row "Aye", column "Wut"
+\pset display_true 't'
+\pset display_false 'f'
\pset null ''
-- refer to columns by position
SELECT v,h,string_agg(i::text, E'\n'), string_agg(c, E'\n')