Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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:14:01 +0000 (13:14 +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 5f9a3d4604fbf40f9fbf48bfe6cb9b17b9decb30..3ec774ca6d0c5d9d2c04e5636a3ab278e7497c01 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 1a7876ecf2d7db90abda37e289f2b38d9e15f1b5..4acb345972cc247b4f8543ac137056bfe459e13a 100644 (file)
@@ -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;
index 64e8361f1f453b9e1c5738513576f71aa7f8e30c..9fb979febb0c931b6d67aeb1f2fb8478228b3dd8 100644 (file)
@@ -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:
 
                /*