aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Meskes <meskes@postgresql.org>2014-05-06 13:04:30 +0200
committerMichael Meskes <meskes@postgresql.org>2014-05-06 13:20:22 +0200
commitfb66e88cf8f7ce7abf27cff1570a703e1cb8f562 (patch)
tree72c07f0b3fa040325394863e0b30c3787128d65a
parent2f4ee3a2f02f612046ecc134ccf50af10240bbb1 (diff)
downloadpostgresql-fb66e88cf8f7ce7abf27cff1570a703e1cb8f562.tar.gz
postgresql-fb66e88cf8f7ce7abf27cff1570a703e1cb8f562.zip
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>
-rw-r--r--src/interfaces/ecpg/ecpglib/data.c8
-rw-r--r--src/interfaces/ecpg/ecpglib/execute.c9
-rw-r--r--src/interfaces/ecpg/preproc/type.c17
3 files changed, 31 insertions, 3 deletions
diff --git a/src/interfaces/ecpg/ecpglib/data.c b/src/interfaces/ecpg/ecpglib/data.c
index 192d1a3db31..04f4c2212c7 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 3f1478694de..eee1b16c27e 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 43f91fe1ab6..d268d774157 100644
--- a/src/interfaces/ecpg/preproc/type.c
+++ b/src/interfaces/ecpg/preproc/type.c
@@ -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:
/*