Skip to content

Commit 7a5f8b5

Browse files
committed
Improve coding of column-name parsing in psql's new crosstabview.c.
Coverity complained about this code, not without reason because it was rather messy. Adjust it to not scribble on the passed string; that adds one malloc/free cycle per column name, which is going to be insignificant in context. We can actually const-ify both the string argument and the PGresult. Daniel Verité, with some further cleanup by me
1 parent 2201d80 commit 7a5f8b5

File tree

2 files changed

+40
-27
lines changed

2 files changed

+40
-27
lines changed

src/bin/psql/crosstabview.c

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,16 @@ static bool printCrosstab(const PGresult *results,
8282
int num_columns, pivot_field *piv_columns, int field_for_columns,
8383
int num_rows, pivot_field *piv_rows, int field_for_rows,
8484
int field_for_data);
85-
static int parseColumnRefs(char *arg, PGresult *res, int **col_numbers,
85+
static int parseColumnRefs(const char *arg, const PGresult *res,
86+
int **col_numbers,
8687
int max_columns, char separator);
8788
static void avlInit(avl_tree *tree);
8889
static void avlMergeValue(avl_tree *tree, char *name, char *sort_value);
8990
static int avlCollectFields(avl_tree *tree, avl_node *node,
9091
pivot_field *fields, int idx);
9192
static void avlFree(avl_tree *tree, avl_node *node);
9293
static void rankSort(int num_columns, pivot_field *piv_columns);
93-
static int indexOfColumn(const char *arg, PGresult *res);
94+
static int indexOfColumn(const char *arg, const PGresult *res);
9495
static int pivotFieldCompare(const void *a, const void *b);
9596
static int rankCompare(const void *a, const void *b);
9697

@@ -103,7 +104,7 @@ static int rankCompare(const void *a, const void *b);
103104
* then call printCrosstab() for the actual output.
104105
*/
105106
bool
106-
PrintResultsInCrosstab(PGresult *res)
107+
PrintResultsInCrosstab(const PGresult *res)
107108
{
108109
char *opt_field_for_rows = pset.ctv_col_V;
109110
char *opt_field_for_columns = pset.ctv_col_H;
@@ -475,33 +476,37 @@ printCrosstab(const PGresult *results,
475476
}
476477

477478
/*
478-
* Parse col1[<sep>col2][<sep>col3]...
479-
* where colN can be:
479+
* Parse "arg", which is a string of column IDs separated by "separator".
480+
*
481+
* Each column ID can be:
480482
* - a number from 1 to PQnfields(res)
481483
* - an unquoted column name matching (case insensitively) one of PQfname(res,...)
482484
* - a quoted column name matching (case sensitively) one of PQfname(res,...)
483-
* max_columns: 0 if no maximum
485+
*
486+
* If max_columns > 0, it is the max number of column IDs allowed.
487+
*
488+
* On success, return number of column IDs found (possibly 0), and return a
489+
* malloc'd array of the matching column numbers of "res" into *col_numbers.
490+
*
491+
* On failure, return -1 and set *col_numbers to NULL.
484492
*/
485493
static int
486-
parseColumnRefs(char *arg,
487-
PGresult *res,
494+
parseColumnRefs(const char *arg,
495+
const PGresult *res,
488496
int **col_numbers,
489497
int max_columns,
490498
char separator)
491499
{
492-
char *p = arg;
500+
const char *p = arg;
493501
char c;
494-
int col_num = -1;
495-
int nb_cols = 0;
496-
char *field_start = NULL;
502+
int num_cols = 0;
497503

498504
*col_numbers = NULL;
499505
while ((c = *p) != '\0')
500506
{
507+
const char *field_start = p;
501508
bool quoted_field = false;
502509

503-
field_start = p;
504-
505510
/* first char */
506511
if (c == '"')
507512
{
@@ -533,20 +538,27 @@ parseColumnRefs(char *arg,
533538

534539
if (p != field_start)
535540
{
536-
/* look up the column and add its index into *col_numbers */
537-
if (max_columns != 0 && nb_cols == max_columns)
541+
char *col_name;
542+
int col_num;
543+
544+
/* enforce max_columns limit */
545+
if (max_columns > 0 && num_cols == max_columns)
538546
{
539-
psql_error(_("No more than %d column references expected\n"), max_columns);
547+
psql_error(_("No more than %d column references expected\n"),
548+
max_columns);
540549
goto errfail;
541550
}
542-
c = *p;
543-
*p = '\0';
544-
col_num = indexOfColumn(field_start, res);
551+
/* look up the column and add its index into *col_numbers */
552+
col_name = pg_malloc(p - field_start + 1);
553+
memcpy(col_name, field_start, p - field_start);
554+
col_name[p - field_start] = '\0';
555+
col_num = indexOfColumn(col_name, res);
556+
pg_free(col_name);
545557
if (col_num < 0)
546558
goto errfail;
547-
*p = c;
548-
*col_numbers = (int *) pg_realloc(*col_numbers, (1 + nb_cols) * sizeof(int));
549-
(*col_numbers)[nb_cols++] = col_num;
559+
*col_numbers = (int *) pg_realloc(*col_numbers,
560+
(num_cols + 1) * sizeof(int));
561+
(*col_numbers)[num_cols++] = col_num;
550562
}
551563
else
552564
{
@@ -557,7 +569,7 @@ parseColumnRefs(char *arg,
557569
if (*p)
558570
p += PQmblen(p, pset.encoding);
559571
}
560-
return nb_cols;
572+
return num_cols;
561573

562574
errfail:
563575
pg_free(*col_numbers);
@@ -776,7 +788,7 @@ fieldNameEquals(const char *arg, const char *fieldname)
776788
char c;
777789

778790
if (*p++ != '"')
779-
return !pg_strcasecmp(arg, fieldname);
791+
return (pg_strcasecmp(arg, fieldname) == 0);
780792

781793
while ((c = *p++))
782794
{
@@ -805,7 +817,7 @@ fieldNameEquals(const char *arg, const char *fieldname)
805817
* or if it's ambiguous (arg corresponding to several columns)
806818
*/
807819
static int
808-
indexOfColumn(const char *arg, PGresult *res)
820+
indexOfColumn(const char *arg, const PGresult *res)
809821
{
810822
int idx;
811823

src/bin/psql/crosstabview.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@
2222
#define CROSSTABVIEW_MAX_COLUMNS 1600
2323

2424
/* prototypes */
25-
extern bool PrintResultsInCrosstab(PGresult *res);
25+
extern bool PrintResultsInCrosstab(const PGresult *res);
26+
2627
#endif /* CROSSTABVIEW_H */

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy