Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 6a8c67f

Browse files
committed
Fix incorrect error reporting for duplicate data in \crosstabview.
\crosstabview's complaint about multiple entries for the same crosstab cell quoted the wrong row and/or column values. It would accidentally appear to work if the data had been in strcmp() order to start with, which probably explains how we missed noticing this during development. This could be fixed in more than one way, but the way I chose was to hang onto both result pointers from bsearch() and use those to get at the value names. In passing, avoid casting away const in the bsearch comparison functions. No bug there, just poor style. Per bug #14476 from Tomonari Katsumata. Back-patch to 9.6 where \crosstabview was introduced. Report: https://postgr.es/m/20161225021519.10139.45460@wrigleys.postgresql.org
1 parent d51af65 commit 6a8c67f

File tree

3 files changed

+48
-24
lines changed

3 files changed

+48
-24
lines changed

src/bin/psql/crosstabview.c

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -352,35 +352,36 @@ printCrosstab(const PGresult *results,
352352
{
353353
int row_number;
354354
int col_number;
355-
pivot_field *p;
355+
pivot_field *rp,
356+
*cp;
356357
pivot_field elt;
357358

358359
/* Find target row */
359360
if (!PQgetisnull(results, rn, field_for_rows))
360361
elt.name = PQgetvalue(results, rn, field_for_rows);
361362
else
362363
elt.name = NULL;
363-
p = (pivot_field *) bsearch(&elt,
364-
piv_rows,
365-
num_rows,
366-
sizeof(pivot_field),
367-
pivotFieldCompare);
368-
Assert(p != NULL);
369-
row_number = p->rank;
364+
rp = (pivot_field *) bsearch(&elt,
365+
piv_rows,
366+
num_rows,
367+
sizeof(pivot_field),
368+
pivotFieldCompare);
369+
Assert(rp != NULL);
370+
row_number = rp->rank;
370371

371372
/* Find target column */
372373
if (!PQgetisnull(results, rn, field_for_columns))
373374
elt.name = PQgetvalue(results, rn, field_for_columns);
374375
else
375376
elt.name = NULL;
376377

377-
p = (pivot_field *) bsearch(&elt,
378-
piv_columns,
379-
num_columns,
380-
sizeof(pivot_field),
381-
pivotFieldCompare);
382-
Assert(p != NULL);
383-
col_number = p->rank;
378+
cp = (pivot_field *) bsearch(&elt,
379+
piv_columns,
380+
num_columns,
381+
sizeof(pivot_field),
382+
pivotFieldCompare);
383+
Assert(cp != NULL);
384+
col_number = cp->rank;
384385

385386
/* Place value into cell */
386387
if (col_number >= 0 && row_number >= 0)
@@ -396,10 +397,10 @@ printCrosstab(const PGresult *results,
396397
if (cont.cells[idx] != NULL)
397398
{
398399
psql_error("\\crosstabview: query result contains multiple data values for row \"%s\", column \"%s\"\n",
399-
piv_rows[row_number].name ? piv_rows[row_number].name :
400-
popt.nullPrint ? popt.nullPrint : "(null)",
401-
piv_columns[col_number].name ? piv_columns[col_number].name :
402-
popt.nullPrint ? popt.nullPrint : "(null)");
400+
rp->name ? rp->name :
401+
(popt.nullPrint ? popt.nullPrint : "(null)"),
402+
cp->name ? cp->name :
403+
(popt.nullPrint ? popt.nullPrint : "(null)"));
403404
goto error;
404405
}
405406

@@ -694,8 +695,8 @@ indexOfColumn(char *arg, const PGresult *res)
694695
static int
695696
pivotFieldCompare(const void *a, const void *b)
696697
{
697-
pivot_field *pa = (pivot_field *) a;
698-
pivot_field *pb = (pivot_field *) b;
698+
const pivot_field *pa = (const pivot_field *) a;
699+
const pivot_field *pb = (const pivot_field *) b;
699700

700701
/* test null values */
701702
if (!pb->name)
@@ -704,12 +705,11 @@ pivotFieldCompare(const void *a, const void *b)
704705
return 1;
705706

706707
/* non-null values */
707-
return strcmp(((pivot_field *) a)->name,
708-
((pivot_field *) b)->name);
708+
return strcmp(pa->name, pb->name);
709709
}
710710

711711
static int
712712
rankCompare(const void *a, const void *b)
713713
{
714-
return *((int *) a) - *((int *) b);
714+
return *((const int *) a) - *((const int *) b);
715715
}

src/test/regress/expected/psql_crosstab.out

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,3 +201,16 @@ SELECT a,a,1 FROM generate_series(1,3000) AS a
201201
SELECT 1 \crosstabview
202202
\crosstabview: query must return at least three columns
203203
DROP TABLE ctv_data;
204+
-- check error reporting (bug #14476)
205+
CREATE TABLE ctv_data (x int, y int, v text);
206+
INSERT INTO ctv_data SELECT 1, x, '*' || x FROM generate_series(1,10) x;
207+
SELECT * FROM ctv_data \crosstabview
208+
x | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
209+
---+----+----+----+----+----+----+----+----+----+-----
210+
1 | *1 | *2 | *3 | *4 | *5 | *6 | *7 | *8 | *9 | *10
211+
(1 row)
212+
213+
INSERT INTO ctv_data VALUES (1, 10, '*'); -- duplicate data to cause error
214+
SELECT * FROM ctv_data \crosstabview
215+
\crosstabview: query result contains multiple data values for row "1", column "10"
216+
DROP TABLE ctv_data;

src/test/regress/sql/psql_crosstab.sql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,14 @@ SELECT a,a,1 FROM generate_series(1,3000) AS a
111111
SELECT 1 \crosstabview
112112

113113
DROP TABLE ctv_data;
114+
115+
-- check error reporting (bug #14476)
116+
CREATE TABLE ctv_data (x int, y int, v text);
117+
118+
INSERT INTO ctv_data SELECT 1, x, '*' || x FROM generate_series(1,10) x;
119+
SELECT * FROM ctv_data \crosstabview
120+
121+
INSERT INTO ctv_data VALUES (1, 10, '*'); -- duplicate data to cause error
122+
SELECT * FROM ctv_data \crosstabview
123+
124+
DROP TABLE ctv_data;

0 commit comments

Comments
 (0)