Re: [HACKERS] using array of char pointers gives wrong results

2014-05-06 Thread Ashutosh Bapat
Thanks Michael.



On Tue, May 6, 2014 at 5:01 PM, Michael Meskes wrote:

> > PFA patch ecpg_char_ptr_arr.patch to fix this issue. It has changes as
> > follows
> > ...
>
> Thanks for finding and fixing the problem. Patch applied to complete 9
> series with only a minor change.
>
> Michael
> --
> Michael Meskes
> Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org)
> Michael at BorussiaFan dot De, Meskes at (Debian|Postgresql) dot Org
> Jabber: michael.meskes at gmail dot com
> VfL Borussia! Força Barça! Go SF 49ers! Use Debian GNU/Linux, PostgreSQL
>



-- 
Best Wishes,
Ashutosh Bapat
EnterpriseDB Corporation
The Postgres Database Company


Re: [HACKERS] using array of char pointers gives wrong results

2014-05-06 Thread Michael Meskes
> PFA patch ecpg_char_ptr_arr.patch to fix this issue. It has changes as
> follows
> ...

Thanks for finding and fixing the problem. Patch applied to complete 9 series 
with only a minor change.

Michael
-- 
Michael Meskes
Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org)
Michael at BorussiaFan dot De, Meskes at (Debian|Postgresql) dot Org
Jabber: michael.meskes at gmail dot com
VfL Borussia! Força Barça! Go SF 49ers! Use Debian GNU/Linux, PostgreSQL


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] using array of char pointers gives wrong results

2014-05-05 Thread Ashutosh Bapat
Let me bring the bug fix again to the surface. Is anybody looking at this
fix?


On Tue, Apr 29, 2014 at 2:25 PM, Ashutosh Bapat <
ashutosh.ba...@enterprisedb.com> wrote:

> Hi,
> When array of char * is used as target for the FETCH statement returning
> more than one row, it tries to store all the result in the first element.
> PFA test_char_select.pgc, which fetches first 3 relnames from pg_class
> ordered by relname. The program prints following result
>
> steps to compile and build the program
> ecpg -c -I test_char_select.pgc
> cc -I -g   -c -o test_char_select.o
> test_char_select.c
> cc -g  test_char_select.o  -L -lecpg -lpq
> -lpgtypes -o test_char_select
>
> output
> ./test_char_select
> relname=___pg_foreign_table_columns
> relname=
> relname=
>
> The first three relnames should have been
> postgres=# select relname from pg_class order by relname limit 3;
>   relname
> ---
>  _pg_foreign_data_wrappers
>  _pg_foreign_servers
>  _pg_foreign_table_columns
>
> It's obvious that the first element of the array is being overwritten with
> an offset of 1.
>
> This happens because, the array of char pointer is dumped as
>  /* Fetch multiple columns into one structure. */
> { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "fetch 3 from cur1",
> ECPGt_EOIT,
> ECPGt_char,(strings),(long)0,(long)3,*(1)*sizeof(char)*,
> ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
>
> Since the offset is 1, the next result overwrites the previous result
> except for the first byte.
>
> PFA patch ecpg_char_ptr_arr.patch to fix this issue. It has changes as
> follows
> 1. Dump array of char pointer with right offset i.e. sizeof(char *)
> 2. While reading array of char pointer in ecpg_do_prologue(), use the
> address instead of the value at that address
> 3. The pointer arithmetic should treat such variable as char **, instead
> of char *
>
> ECPG regression tests do not show any failures with this patch.
> --
> Best Wishes,
> Ashutosh Bapat
> EnterpriseDB Corporation
> The Postgres Database Company
>



-- 
Best Wishes,
Ashutosh Bapat
EnterpriseDB Corporation
The Postgres Database Company


[HACKERS] using array of char pointers gives wrong results

2014-04-29 Thread Ashutosh Bapat
Hi,
When array of char * is used as target for the FETCH statement returning
more than one row, it tries to store all the result in the first element.
PFA test_char_select.pgc, which fetches first 3 relnames from pg_class
ordered by relname. The program prints following result

steps to compile and build the program
ecpg -c -I test_char_select.pgc
cc -I -g   -c -o test_char_select.o
test_char_select.c
cc -g  test_char_select.o  -L -lecpg -lpq
-lpgtypes -o test_char_select

output
./test_char_select
relname=___pg_foreign_table_columns
relname=
relname=

The first three relnames should have been
postgres=# select relname from pg_class order by relname limit 3;
  relname
---
 _pg_foreign_data_wrappers
 _pg_foreign_servers
 _pg_foreign_table_columns

It's obvious that the first element of the array is being overwritten with
an offset of 1.

This happens because, the array of char pointer is dumped as
 /* Fetch multiple columns into one structure. */
{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "fetch 3 from cur1",
ECPGt_EOIT,
ECPGt_char,(strings),(long)0,(long)3,*(1)*sizeof(char)*,
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);

Since the offset is 1, the next result overwrites the previous result
except for the first byte.

PFA patch ecpg_char_ptr_arr.patch to fix this issue. It has changes as
follows
1. Dump array of char pointer with right offset i.e. sizeof(char *)
2. While reading array of char pointer in ecpg_do_prologue(), use the
address instead of the value at that address
3. The pointer arithmetic should treat such variable as char **, instead of
char *

ECPG regression tests do not show any failures with this patch.
-- 
Best Wishes,
Ashutosh Bapat
EnterpriseDB Corporation
The Postgres Database Company
diff --git a/src/interfaces/ecpg/ecpglib/data.c b/src/interfaces/ecpg/ecpglib/data.c
index 5f9a3d4..3ec774c 100644
--- a/src/interfaces/ecpg/ecpglib/data.c
+++ b/src/interfaces/ecpg/ecpglib/data.c
@@ -448,20 +448,28 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
 			   ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
 	return (false);
 	break;
 
 case ECPGt_char:
 case ECPGt_unsigned_char:
 case ECPGt_string:
 	{
 		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);
 			/* do the rtrim() */
 			if (type == ECPGt_string)
 			{
 char	   *last = str + size;
 
 while (last > str && (*last == ' ' || *last == '\0'))
 {
diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c
index a90fb41..aa917b9 100644
--- a/src/interfaces/ecpg/ecpglib/execute.c
+++ b/src/interfaces/ecpg/ecpglib/execute.c
@@ -1923,25 +1923,33 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
 return false;
 			}
 
 			var->type = type;
 			var->pointer = va_arg(args, char *);
 
 			var->varcharsize = va_arg(args, long);
 			var->arrsize = va_arg(args, long);
 			var->offset = va_arg(args, long);
 
-			if (var->arrsize == 0 || var->varcharsize == 0)
+			if ((var->arrsize == 0 || var->varcharsize == 0))
 var->value = *((char **) (var->pointer));
 			else
 var->value = var->pointer;
 
+			/* 
+			 * If the type is character without known varcharsize but with known array
+			 * size, it is an array of pointers to char, so use the pointer as
+			 * it is.
+			 */
+			if ((var->type == ECPGt_char || type == ECPGt_unsigned_char) &&
+	var->arrsize > 1 && var->varcharsize == 0)
+var->value = var->pointer;
 			/*
 			 * negative values are used to indicate an array without given
 			 * bounds
 			 */
 			/* reset to zero for us */
 			if (var->arrsize < 0)
 var->arrsize = 0;
 			if (var->varcharsize < 0)
 var->varcharsize = 0;
 
diff --git a/src/interfaces/ecpg/preproc/type.c b/src/interfaces/ecpg/preproc/type.c
index 308660e..e54f05d5 100644
--- a/src/interfaces/ecpg/preproc/type.c
+++ b/src/interfaces/ecpg/preproc/type.c
@@ -441,36 +441,49 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype type,
  */
 if (counter)
 	sprintf(offset, "sizeof(struct varchar_%d)", counter);
 else
 	sprintf(offset, "sizeof(struct varchar)");
 break;
 			case ECPGt_char:
 			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 []
  */
 if ((atoi(varcharsize) > 1 ||
 	 (atoi(arrsize) > 0) ||
  (atoi(varcharsize) == 0 && strcm