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:20:22 +0000 (13:20 +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 192d1a3db317ff2e9bccf637243837a570a4fa6f..04f4c2212c738079bfa7ea99559eed236bbf4dcc 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 3f1478694de91ba0f91519948bf5c87fc2d7349e..eee1b16c27e9b268cebbe4df09cca97911653e0b 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 43f91fe1ab68cf6ba9c455ba76c85172b3f91415..d268d774157f6fc53b0e9d10f270dca3a2ba08c8 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:
 
                /*