Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

+38-26
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

+2-1
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)