postgres.git / summary / log / commit / refs

commit    b4eeb9d58ec9237a3f2a9d6c5b1d4374beb2e675
Author:   Michael Meskes <meskes@postgresql.org>
Date:     Tue May 06 11:04:30 2014 +0000

    Fix handling of array of char pointers in ecpglib.
    
    When array of char * was used as target for a FETCH statement returning more
    than one row, it tried to store all the result in the first element. Instead it
    should dump array of char pointers with right offset, use the address instead
    of the value of the C variable while reading the array and treat such variable
    as char **, instead of char * for pointer arithmetic.
    
    Patch by Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>


src/interfaces/ecpg/ecpglib/data.c | 8 ++++++++ src/interfaces/ecpg/ecpglib/execute.c | 9 ++++++++- src/interfaces/ecpg/preproc/type.c | 17 +++++++++++++++-- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/interfaces/ecpg/ecpglib/data.c b/src/interfaces/ecpg/ecpglib/data.c index 5f9a3d4604f..3ec774ca6d0 100644 --- a/src/interfaces/ecpg/ecpglib/data.c +++ b/src/interfaces/ecpg/ecpglib/data.c @@ -455,6 +455,14 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno, { char *str = (char *) (var + offset * act_tuple); + /* + * If varcharsize is unknown and the offset is that of + * char *, then this variable represents the array of + * character pointers. So, use extra indirection. + */ + if (varcharsize == 0 && offset == sizeof(char *)) + str = *(char **)str; + if (varcharsize == 0 || varcharsize > size) { strncpy(str, pval, size + 1); diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c index 1a7876ecf2d..4acb345972c 100644 --- a/src/interfaces/ecpg/ecpglib/execute.c +++ b/src/interfaces/ecpg/ecpglib/execute.c @@ -1850,7 +1850,14 @@ ECPGdo(const int lineno, const int compat, const int force_indicator, const char var->arrsize = va_arg(args, long); var->offset = va_arg(args, long); - if (var->arrsize == 0 || var->varcharsize == 0) + /* + * Unknown array size means pointer to an array. + * Unknown varcharsize usually also means pointer. But if the + * type is character and the array size is known, it is an + * array of pointers to char, so use var->pointer as it is. + */ + if (var->arrsize == 0 || + (var->varcharsize == 0 && ((var->type != ECPGt_char && var->type != ECPGt_unsigned_char) || (var->arrsize <= 1)))) var->value = *((char **) (var->pointer)); else var->value = var->pointer; diff --git a/src/interfaces/ecpg/preproc/type.c b/src/interfaces/ecpg/preproc/type.c index 780b6aab71b..3e37fb9d3c1 100644 --- a/src/interfaces/ecpg/preproc/type.c +++ b/src/interfaces/ecpg/preproc/type.c @@ -410,7 +410,8 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype type, case ECPGt_unsigned_char: case ECPGt_char_variable: case ECPGt_string: - + { + char *sizeof_name = "char"; /* * we have to use the pointer except for arrays with given * bounds, ecpglib will distinguish between * and [] @@ -420,12 +421,24 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype type, (atoi(varcharsize) == 0 && strcmp(varcharsize, "0") != 0) || (atoi(arrsize) == 0 && strcmp(arrsize, "0") != 0)) && siz == NULL) + { sprintf(variable, "(%s%s)", prefix ? prefix : "", name); + if ((type == ECPGt_char || type == ECPGt_unsigned_char) && + strcmp(varcharsize, "0") == 0) + { + /* + * If this is an array of char *, the offset would be + * sizeof(char *) and not sizeof(char). + */ + sizeof_name = "char *"; + } + } else sprintf(variable, "&(%s%s)", prefix ? prefix : "", name); - sprintf(offset, "(%s)*sizeof(char)", strcmp(varcharsize, "0") == 0 ? "1" : varcharsize); + sprintf(offset, "(%s)*sizeof(%s)", strcmp(varcharsize, "0") == 0 ? "1" : varcharsize, sizeof_name); break; + } case ECPGt_numeric: /* [parent: 4f4ef042fddb]