]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix handling of array of char pointers in ecpglib.
authorMichael Meskes <meskes@postgresql.org>
Tue, 6 May 2014 11:04:30 +0000 (13:04 +0200)
committerMichael Meskes <meskes@postgresql.org>
Tue, 6 May 2014 11:24:13 +0000 (13:24 +0200)
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
src/interfaces/ecpg/ecpglib/execute.c
src/interfaces/ecpg/preproc/type.c

index c219aed1e9edecc7a3f507b90c05708277ad7028..e416e31757595e52ab2b1efc7c04882b11a09270 100644 (file)
@@ -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);
index 8ad671e70a09922a1539e1e519d5abe7182cd323..51f6ebd2b9c9bbd46f08528088c470eedc136e67 100644 (file)
@@ -1851,7 +1851,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;
index 448e4f16e8dde3a2bf5f2e28b6193956f77f2b36..4e9d9d0a52338a99b62e46b690404c5c346244e1 100644 (file)
@@ -407,7 +407,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 []
@@ -417,12 +418,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:
 
                                /*