[BUG] Storage declaration in ECPG

Started by Andrey Sokolovover 3 years ago4 messages
#1Andrey Sokolov
a.sokolov@arenadata.io
1 attachment(s)

Attachments:

0001-Fix-storage-declaration-in-ECPG.patchtext/x-diff; name=0001-Fix-storage-declaration-in-ECPG.patchDownload
From c8f8fc7a211938569e7d46c91a428d8cb25b6f9c Mon Sep 17 00:00:00 2001
From: Andrey Sokolov <a.sokolov@arenadata.io>
Date: Sun, 4 Sep 2022 12:48:22 +0300
Subject: [PATCH] Fix storage declaration in ECPG

The ECPG preprocessor converted the code
"static VARCHAR str1[10], str2[20], str3[30];"
into
"static  struct varchar_1  { int len; char arr[ 10 ]; }  str1 ;
         struct varchar_2  { int len; char arr[ 20 ]; }  str2 ;
         struct varchar_3  { int len; char arr[ 30 ]; }  str3 ;".
Storage declaration applied only to the first structure.
Now storage declaration is repeated before each structure.
---
 src/interfaces/ecpg/preproc/ecpg.trailer      |   4 +-
 src/interfaces/ecpg/preproc/type.h            |   1 +
 src/interfaces/ecpg/test/ecpg_schedule        |   1 +
 .../test/expected/preproc-static_variables.c  | 145 ++++++++++++++++++
 .../expected/preproc-static_variables.stderr  |  96 ++++++++++++
 .../expected/preproc-static_variables.stdout  |   3 +
 src/interfaces/ecpg/test/preproc/.gitignore   |   2 +
 src/interfaces/ecpg/test/preproc/Makefile     |   1 +
 .../ecpg/test/preproc/static_variables.pgc    |  55 +++++++
 9 files changed, 307 insertions(+), 1 deletion(-)
 create mode 100644 src/interfaces/ecpg/test/expected/preproc-static_variables.c
 create mode 100644 src/interfaces/ecpg/test/expected/preproc-static_variables.stderr
 create mode 100644 src/interfaces/ecpg/test/expected/preproc-static_variables.stdout
 create mode 100644 src/interfaces/ecpg/test/preproc/static_variables.pgc

diff --git a/src/interfaces/ecpg/preproc/ecpg.trailer b/src/interfaces/ecpg/preproc/ecpg.trailer
index 0b100b9b04..54254e2f97 100644
--- a/src/interfaces/ecpg/preproc/ecpg.trailer
+++ b/src/interfaces/ecpg/preproc/ecpg.trailer
@@ -479,6 +479,7 @@ type_declaration: S_TYPEDEF
 var_declaration: storage_declaration
 		var_type
 		{
+			actual_type[struct_level].type_storage = $1;
 			actual_type[struct_level].type_enum = $2.type_enum;
 			actual_type[struct_level].type_str = $2.type_str;
 			actual_type[struct_level].type_dimension = $2.type_dimension;
@@ -493,6 +494,7 @@ var_declaration: storage_declaration
 		}
 		| var_type
 		{
+			actual_type[struct_level].type_storage = EMPTY;
 			actual_type[struct_level].type_enum = $1.type_enum;
 			actual_type[struct_level].type_str = $1.type_str;
 			actual_type[struct_level].type_dimension = $1.type_dimension;
@@ -949,7 +951,7 @@ variable_list: variable
 		| variable_list ',' variable
 		{
 			if (actual_type[struct_level].type_enum == ECPGt_varchar || actual_type[struct_level].type_enum == ECPGt_bytea)
-				$$ = cat_str(3, $1, mm_strdup(";"), $3);
+				$$ = cat_str(4, $1, mm_strdup(";"), mm_strdup(actual_type[struct_level].type_storage), $3);
 			else
 				$$ = cat_str(3, $1, mm_strdup(","), $3);
 		}
diff --git a/src/interfaces/ecpg/preproc/type.h b/src/interfaces/ecpg/preproc/type.h
index fb20be53e0..08b739e5f3 100644
--- a/src/interfaces/ecpg/preproc/type.h
+++ b/src/interfaces/ecpg/preproc/type.h
@@ -114,6 +114,7 @@ struct exec
 
 struct this_type
 {
+	char	   *type_storage;
 	enum ECPGttype type_enum;
 	char	   *type_str;
 	char	   *type_dimension;
diff --git a/src/interfaces/ecpg/test/ecpg_schedule b/src/interfaces/ecpg/test/ecpg_schedule
index e034c5a420..d594c4d9b0 100644
--- a/src/interfaces/ecpg/test/ecpg_schedule
+++ b/src/interfaces/ecpg/test/ecpg_schedule
@@ -24,6 +24,7 @@ test: preproc/comment
 test: preproc/cursor
 test: preproc/define
 test: preproc/init
+test: preproc/static_variables
 test: preproc/strings
 test: preproc/type
 test: preproc/variable
diff --git a/src/interfaces/ecpg/test/expected/preproc-static_variables.c b/src/interfaces/ecpg/test/expected/preproc-static_variables.c
new file mode 100644
index 0000000000..b0f62a8b14
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/preproc-static_variables.c
@@ -0,0 +1,145 @@
+/* Processed by ecpg (regression mode) */
+/* These include files are added by the preprocessor */
+#include <ecpglib.h>
+#include <ecpgerrno.h>
+#include <sqlca.h>
+/* End of automatic include section */
+#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+#line 1 "static_variables.pgc"
+#include <stdlib.h>
+
+
+#line 1 "regression.h"
+
+
+
+
+
+
+#line 3 "static_variables.pgc"
+
+
+/* exec sql whenever sqlerror  stop ; */
+#line 5 "static_variables.pgc"
+
+
+/* declare cur cursor for select firstname , lastname , address from persons */
+#line 8 "static_variables.pgc"
+
+
+/* exec sql begin declare section */
+	    
+
+#line 11 "static_variables.pgc"
+ static  struct varchar_1  { int len; char arr[ 50 ]; }  firstname ; static  struct varchar_2  { int len; char arr[ 50 ]; }  lastname ; static  struct varchar_3  { int len; char arr[ 255 ]; }  address ;
+/* exec sql end declare section */
+#line 12 "static_variables.pgc"
+
+
+int
+main (void)
+{
+	int loopcount;
+
+	ECPGdebug(1, stderr);
+
+	{ ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); 
+#line 21 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 21 "static_variables.pgc"
+
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table persons ( firstname varchar ( 50 ) not null , lastname varchar ( 50 ) not null , address varchar ( 255 ) not null )", ECPGt_EOIT, ECPGt_EORT);
+#line 27 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 27 "static_variables.pgc"
+
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into persons ( firstname , lastname , address ) values ( 'firstname1' , 'lastname1' , 'address1' )", ECPGt_EOIT, ECPGt_EORT);
+#line 30 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 30 "static_variables.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into persons ( firstname , lastname , address ) values ( 'firstname2' , 'lastname2' , 'address2' )", ECPGt_EOIT, ECPGt_EORT);
+#line 32 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 32 "static_variables.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into persons ( firstname , lastname , address ) values ( 'firstname3' , 'lastname3' , 'address3' )", ECPGt_EOIT, ECPGt_EORT);
+#line 34 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 34 "static_variables.pgc"
+
+
+	{ ECPGtrans(__LINE__, NULL, "commit");
+#line 36 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 36 "static_variables.pgc"
+
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "declare cur cursor for select firstname , lastname , address from persons", ECPGt_EOIT, ECPGt_EORT);
+#line 38 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 38 "static_variables.pgc"
+
+
+	/* exec sql whenever not found  break ; */
+#line 40 "static_variables.pgc"
+
+
+	for (loopcount = 0; loopcount < 100; loopcount++)
+	{
+		{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "fetch cur", ECPGt_EOIT, 
+	ECPGt_varchar,&(firstname),(long)50,(long)1,sizeof(struct varchar_1), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_varchar,&(lastname),(long)50,(long)1,sizeof(struct varchar_2), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_varchar,&(address),(long)255,(long)1,sizeof(struct varchar_3), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 44 "static_variables.pgc"
+
+if (sqlca.sqlcode == ECPG_NOT_FOUND) break;
+#line 44 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 44 "static_variables.pgc"
+
+		printf("%.*s\t%.*s\t%.*s\n", firstname.len, firstname.arr,
+									 lastname.len, lastname.arr,
+									 address.len, address.arr);
+	}
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "close cur", ECPGt_EOIT, ECPGt_EORT);
+#line 50 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 50 "static_variables.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table persons", ECPGt_EOIT, ECPGt_EORT);
+#line 51 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 51 "static_variables.pgc"
+
+	{ ECPGtrans(__LINE__, NULL, "commit");
+#line 52 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 52 "static_variables.pgc"
+
+	{ ECPGdisconnect(__LINE__, "CURRENT");
+#line 53 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 53 "static_variables.pgc"
+
+	return 0;
+}
diff --git a/src/interfaces/ecpg/test/expected/preproc-static_variables.stderr b/src/interfaces/ecpg/test/expected/preproc-static_variables.stderr
new file mode 100644
index 0000000000..0ccf740238
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/preproc-static_variables.stderr
@@ -0,0 +1,96 @@
+[NO_PID]: ECPGdebug: set to 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGconnect: opening database ecpg1_regression on <DEFAULT> port <DEFAULT>  
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 23: query: create table persons ( firstname varchar ( 50 ) not null , lastname varchar ( 50 ) not null , address varchar ( 255 ) not null ); with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 23: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 23: OK: CREATE TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 29: query: insert into persons ( firstname , lastname , address ) values ( 'firstname1' , 'lastname1' , 'address1' ); with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 29: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 29: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 31: query: insert into persons ( firstname , lastname , address ) values ( 'firstname2' , 'lastname2' , 'address2' ); with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 31: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 31: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 33: query: insert into persons ( firstname , lastname , address ) values ( 'firstname3' , 'lastname3' , 'address3' ); with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 33: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 33: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGtrans on line 36: action "commit"; connection "ecpg1_regression"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 38: query: declare cur cursor for select firstname , lastname , address from persons; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 38: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 38: OK: DECLARE CURSOR
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 44: query: fetch cur; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 44: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 44: correctly got 1 tuples with 3 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 44: RESULT: firstname1 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 44: RESULT: lastname1 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 44: RESULT: address1 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 44: query: fetch cur; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 44: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 44: correctly got 1 tuples with 3 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 44: RESULT: firstname2 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 44: RESULT: lastname2 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 44: RESULT: address2 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 44: query: fetch cur; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 44: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 44: correctly got 1 tuples with 3 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 44: RESULT: firstname3 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 44: RESULT: lastname3 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 44: RESULT: address3 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 44: query: fetch cur; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 44: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 44: correctly got 0 tuples with 3 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: raising sqlcode 100 on line 44: no data found on line 44
+[NO_PID]: sqlca: code: 100, state: 02000
+[NO_PID]: ecpg_execute on line 50: query: close cur; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 50: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 50: OK: CLOSE CURSOR
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 51: query: drop table persons; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 51: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 51: OK: DROP TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGtrans on line 52: action "commit"; connection "ecpg1_regression"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_finish: connection ecpg1_regression closed
+[NO_PID]: sqlca: code: 0, state: 00000
diff --git a/src/interfaces/ecpg/test/expected/preproc-static_variables.stdout b/src/interfaces/ecpg/test/expected/preproc-static_variables.stdout
new file mode 100644
index 0000000000..1c17696d46
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/preproc-static_variables.stdout
@@ -0,0 +1,3 @@
+firstname1	lastname1	address1
+firstname2	lastname2	address2
+firstname3	lastname3	address3
diff --git a/src/interfaces/ecpg/test/preproc/.gitignore b/src/interfaces/ecpg/test/preproc/.gitignore
index fd63e645a3..831accc526 100644
--- a/src/interfaces/ecpg/test/preproc/.gitignore
+++ b/src/interfaces/ecpg/test/preproc/.gitignore
@@ -14,6 +14,8 @@
 /outofscope.c
 /pointer_to_struct
 /pointer_to_struct.c
+/static_variables
+/static_variables.c
 /strings
 /strings.c
 /type
diff --git a/src/interfaces/ecpg/test/preproc/Makefile b/src/interfaces/ecpg/test/preproc/Makefile
index 39b1974f5f..a3cfe6533f 100644
--- a/src/interfaces/ecpg/test/preproc/Makefile
+++ b/src/interfaces/ecpg/test/preproc/Makefile
@@ -10,6 +10,7 @@ TESTS = array_of_struct array_of_struct.c \
 	cursor cursor.c \
 	define define.c \
 	init init.c \
+	static_variables static_variables.c \
 	strings strings.c \
 	outofscope outofscope.c \
 	type type.c \
diff --git a/src/interfaces/ecpg/test/preproc/static_variables.pgc b/src/interfaces/ecpg/test/preproc/static_variables.pgc
new file mode 100644
index 0000000000..5c1f738f45
--- /dev/null
+++ b/src/interfaces/ecpg/test/preproc/static_variables.pgc
@@ -0,0 +1,55 @@
+#include <stdlib.h>
+
+exec sql include ../regression;
+
+exec sql whenever sqlerror stop;
+
+exec sql declare cur cursor for
+	select firstname, lastname, address from persons;
+
+exec sql begin declare section;
+	static varchar firstname[50], lastname[50], address[255];
+exec sql end declare section;
+
+int
+main (void)
+{
+	int loopcount;
+
+	ECPGdebug(1, stderr);
+
+	exec sql connect to REGRESSDB1;
+
+	exec sql create table persons (
+		firstname varchar(50) not null,
+		lastname varchar(50) not null,
+		address varchar(255) not null
+	);
+
+	exec sql insert into persons (firstname, lastname, address)
+			 values ('firstname1', 'lastname1', 'address1');
+	exec sql insert into persons (firstname, lastname, address)
+			 values ('firstname2', 'lastname2', 'address2');
+	exec sql insert into persons (firstname, lastname, address)
+			 values ('firstname3', 'lastname3', 'address3');
+
+	exec sql commit;
+
+	exec sql open cur;
+
+	exec sql whenever not found do break;
+
+	for (loopcount = 0; loopcount < 100; loopcount++)
+	{
+		exec sql fetch cur into :firstname, :lastname, :address;
+		printf("%.*s\t%.*s\t%.*s\n", firstname.len, firstname.arr,
+									 lastname.len, lastname.arr,
+									 address.len, address.arr);
+	}
+
+	exec sql close cur;
+	exec sql drop table persons;
+	exec sql commit;
+	exec sql disconnect;
+	return 0;
+}
-- 
2.33.3

#2Kyotaro Horiguchi
horikyota.ntt@gmail.com
In reply to: Andrey Sokolov (#1)
Re: [BUG] Storage declaration in ECPG

At Sun, 04 Sep 2022 13:49:53 +0300, Andrey Sokolov <a.sokolov@arenadata.io> wrote in

Hi,

The ECPG preprocessor converts the code
"static VARCHAR str1[10], str2[20], str3[30];"
into
"static struct varchar_1 { int len; char arr[ 10 ]; } str1 ;
struct varchar_2 { int len; char arr[ 20 ]; } str2 ;
struct varchar_3 { int len; char arr[ 30 ]; } str3 ;".
Storage declaration applies only to the first structure.

Good catch!

The patch in the attachment fixes the bug. Storage declaration will be
repeated before each structure.
The patch is on github too:
https://github.com/andr-sokolov/postgresql/commit/c8f8fc7a211938569e7d46c91a428d8cb25b6f9c

And the code looks good to me.

About the test, don't we need the test for non-varchar/bytea static
variables like "static int inta, intb, intc;"?

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center

#3Andrey Sokolov
a.sokolov@arenadata.io
In reply to: Kyotaro Horiguchi (#2)
1 attachment(s)
Re: [BUG] Storage declaration in ECPG

Attachments:

v2-0001-Fix-storage-declaration-in-ECPG.patchtext/x-diff; name=v2-0001-Fix-storage-declaration-in-ECPG.patchDownload
From 5a4adc1b5a2a0adfc152debcaf825e7a95a47450 Mon Sep 17 00:00:00 2001
From: Andrey Sokolov <a.sokolov@arenadata.io>
Date: Sun, 4 Sep 2022 12:48:22 +0300
Subject: [PATCH v2] Fix storage declaration in ECPG

The ECPG preprocessor converted the code
"static VARCHAR str1[10], str2[20], str3[30];"
into
"static  struct varchar_1  { int len; char arr[ 10 ]; }  str1 ;
         struct varchar_2  { int len; char arr[ 20 ]; }  str2 ;
         struct varchar_3  { int len; char arr[ 30 ]; }  str3 ;".
Storage declaration applied only to the first structure.
Now storage declaration is repeated before each structure.
---
 src/interfaces/ecpg/preproc/ecpg.trailer      |   4 +-
 src/interfaces/ecpg/preproc/type.h            |   1 +
 src/interfaces/ecpg/test/ecpg_schedule        |   1 +
 .../test/expected/preproc-static_variables.c  | 215 ++++++++++++++++++
 .../expected/preproc-static_variables.stderr  | 150 ++++++++++++
 .../expected/preproc-static_variables.stdout  |  12 +
 src/interfaces/ecpg/test/preproc/.gitignore   |   2 +
 src/interfaces/ecpg/test/preproc/Makefile     |   1 +
 .../ecpg/test/preproc/static_variables.pgc    | 118 ++++++++++
 9 files changed, 503 insertions(+), 1 deletion(-)
 create mode 100644 src/interfaces/ecpg/test/expected/preproc-static_variables.c
 create mode 100644 src/interfaces/ecpg/test/expected/preproc-static_variables.stderr
 create mode 100644 src/interfaces/ecpg/test/expected/preproc-static_variables.stdout
 create mode 100644 src/interfaces/ecpg/test/preproc/static_variables.pgc

diff --git a/src/interfaces/ecpg/preproc/ecpg.trailer b/src/interfaces/ecpg/preproc/ecpg.trailer
index 0b100b9b04..54254e2f97 100644
--- a/src/interfaces/ecpg/preproc/ecpg.trailer
+++ b/src/interfaces/ecpg/preproc/ecpg.trailer
@@ -479,6 +479,7 @@ type_declaration: S_TYPEDEF
 var_declaration: storage_declaration
 		var_type
 		{
+			actual_type[struct_level].type_storage = $1;
 			actual_type[struct_level].type_enum = $2.type_enum;
 			actual_type[struct_level].type_str = $2.type_str;
 			actual_type[struct_level].type_dimension = $2.type_dimension;
@@ -493,6 +494,7 @@ var_declaration: storage_declaration
 		}
 		| var_type
 		{
+			actual_type[struct_level].type_storage = EMPTY;
 			actual_type[struct_level].type_enum = $1.type_enum;
 			actual_type[struct_level].type_str = $1.type_str;
 			actual_type[struct_level].type_dimension = $1.type_dimension;
@@ -949,7 +951,7 @@ variable_list: variable
 		| variable_list ',' variable
 		{
 			if (actual_type[struct_level].type_enum == ECPGt_varchar || actual_type[struct_level].type_enum == ECPGt_bytea)
-				$$ = cat_str(3, $1, mm_strdup(";"), $3);
+				$$ = cat_str(4, $1, mm_strdup(";"), mm_strdup(actual_type[struct_level].type_storage), $3);
 			else
 				$$ = cat_str(3, $1, mm_strdup(","), $3);
 		}
diff --git a/src/interfaces/ecpg/preproc/type.h b/src/interfaces/ecpg/preproc/type.h
index fb20be53e0..08b739e5f3 100644
--- a/src/interfaces/ecpg/preproc/type.h
+++ b/src/interfaces/ecpg/preproc/type.h
@@ -114,6 +114,7 @@ struct exec
 
 struct this_type
 {
+	char	   *type_storage;
 	enum ECPGttype type_enum;
 	char	   *type_str;
 	char	   *type_dimension;
diff --git a/src/interfaces/ecpg/test/ecpg_schedule b/src/interfaces/ecpg/test/ecpg_schedule
index e034c5a420..d594c4d9b0 100644
--- a/src/interfaces/ecpg/test/ecpg_schedule
+++ b/src/interfaces/ecpg/test/ecpg_schedule
@@ -24,6 +24,7 @@ test: preproc/comment
 test: preproc/cursor
 test: preproc/define
 test: preproc/init
+test: preproc/static_variables
 test: preproc/strings
 test: preproc/type
 test: preproc/variable
diff --git a/src/interfaces/ecpg/test/expected/preproc-static_variables.c b/src/interfaces/ecpg/test/expected/preproc-static_variables.c
new file mode 100644
index 0000000000..5a6bcee666
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/preproc-static_variables.c
@@ -0,0 +1,215 @@
+/* Processed by ecpg (regression mode) */
+/* These include files are added by the preprocessor */
+#include <ecpglib.h>
+#include <ecpgerrno.h>
+#include <sqlca.h>
+/* End of automatic include section */
+#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+#line 1 "static_variables.pgc"
+#include <stdlib.h>
+
+
+#line 1 "regression.h"
+
+
+
+
+
+
+#line 3 "static_variables.pgc"
+
+
+/* exec sql whenever sqlerror  stop ; */
+#line 5 "static_variables.pgc"
+
+
+/* declare cur cursor for select firstname , lastname , address , year_of_birth , height_in_sm , weight_in_kg , data1 , data2 , data3 from persons */
+#line 11 "static_variables.pgc"
+
+
+/* exec sql begin declare section */
+	    
+	    
+	        
+				    
+
+#line 14 "static_variables.pgc"
+ static  struct varchar_1  { int len; char arr[ 50 ]; }  firstname ; static  struct varchar_2  { int len; char arr[ 50 ]; }  lastname ; static  struct varchar_3  { int len; char arr[ 255 ]; }  address ;
+ 
+#line 15 "static_variables.pgc"
+ static int year_of_birth , height_in_sm , weight_in_kg ;
+ 
+#line 16 "static_variables.pgc"
+ static  struct bytea_1  { int len; char arr[ 5 ]; }  data1 ; static  struct bytea_2  { int len; char arr[ 8 ]; }  data2 ; static  struct bytea_3  { int len; char arr[ 12 ]; }  data3 ; static  struct bytea_4  { int len; char arr[ 5 ]; }  data1_2 ; static  struct bytea_5  { int len; char arr[ 8 ]; }  data2_2 ; static  struct bytea_6  { int len; char arr[ 12 ]; }  data3_2 ;
+/* exec sql end declare section */
+#line 18 "static_variables.pgc"
+
+
+static void
+dump_binary(char *buf, int len)
+{
+	int i;
+
+	printf("len=%d, data=0x", len);
+	for (i = 0; i < len; ++i)
+		printf("%02x", buf[i]);
+	printf("\n");
+}
+
+int
+main (void)
+{
+	int loopcount;
+
+	ECPGdebug(1, stderr);
+
+	{ ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); 
+#line 38 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 38 "static_variables.pgc"
+
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table persons ( firstname varchar ( 50 ) not null , lastname varchar ( 50 ) not null , address varchar ( 255 ) not null , year_of_birth int not null , height_in_sm int not null , weight_in_kg int not null , data1 bytea not null , data2 bytea not null , data3 bytea not null )", ECPGt_EOIT, ECPGt_EORT);
+#line 50 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 50 "static_variables.pgc"
+
+
+	data1.len = 5;
+	for (loopcount = 0; loopcount < data1.len; loopcount++)
+		data1.arr[loopcount] = 1;
+
+	data2.len = 8;
+	for (loopcount = 0; loopcount < data2.len; loopcount++)
+		data2.arr[loopcount] = 2;
+
+	data3.len = 12;
+	for (loopcount = 0; loopcount < data3.len; loopcount++)
+		data3.arr[loopcount] = 3;
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into persons ( firstname , lastname , address , year_of_birth , height_in_sm , weight_in_kg , data1 , data2 , data3 ) values ( 'firstname1' , 'lastname1' , 'address1' , 1985 , 180 , 70 , $1  , $2  , $3  )", 
+	ECPGt_bytea,&(data1),(long)5,(long)1,sizeof(struct bytea_1), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_bytea,&(data2),(long)8,(long)1,sizeof(struct bytea_2), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_bytea,&(data3),(long)12,(long)1,sizeof(struct bytea_3), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+#line 71 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 71 "static_variables.pgc"
+
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into persons ( firstname , lastname , address , year_of_birth , height_in_sm , weight_in_kg , data1 , data2 , data3 ) values ( 'firstname2' , 'lastname2' , 'address2' , 1995 , 170 , 65 , $1  , $2  , $3  )", 
+	ECPGt_bytea,&(data1),(long)5,(long)1,sizeof(struct bytea_1), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_bytea,&(data2),(long)8,(long)1,sizeof(struct bytea_2), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_bytea,&(data3),(long)12,(long)1,sizeof(struct bytea_3), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+#line 80 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 80 "static_variables.pgc"
+
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into persons ( firstname , lastname , address , year_of_birth , height_in_sm , weight_in_kg , data1 , data2 , data3 ) values ( 'firstname3' , 'lastname3' , 'address3' , 2000 , 172 , 80 , $1  , $2  , $3  )", 
+	ECPGt_bytea,&(data1),(long)5,(long)1,sizeof(struct bytea_1), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_bytea,&(data2),(long)8,(long)1,sizeof(struct bytea_2), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_bytea,&(data3),(long)12,(long)1,sizeof(struct bytea_3), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+#line 89 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 89 "static_variables.pgc"
+
+
+	{ ECPGtrans(__LINE__, NULL, "commit");
+#line 91 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 91 "static_variables.pgc"
+
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "declare cur cursor for select firstname , lastname , address , year_of_birth , height_in_sm , weight_in_kg , data1 , data2 , data3 from persons", ECPGt_EOIT, ECPGt_EORT);
+#line 93 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 93 "static_variables.pgc"
+
+
+	/* exec sql whenever not found  break ; */
+#line 95 "static_variables.pgc"
+
+
+	for (loopcount = 0; loopcount < 100; loopcount++)
+	{
+		{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "fetch cur", ECPGt_EOIT, 
+	ECPGt_varchar,&(firstname),(long)50,(long)1,sizeof(struct varchar_1), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_varchar,&(lastname),(long)50,(long)1,sizeof(struct varchar_2), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_varchar,&(address),(long)255,(long)1,sizeof(struct varchar_3), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_int,&(year_of_birth),(long)1,(long)1,sizeof(int), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_int,&(height_in_sm),(long)1,(long)1,sizeof(int), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_int,&(weight_in_kg),(long)1,(long)1,sizeof(int), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_bytea,&(data1_2),(long)5,(long)1,sizeof(struct bytea_4), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_bytea,&(data2_2),(long)8,(long)1,sizeof(struct bytea_5), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_bytea,&(data3_2),(long)12,(long)1,sizeof(struct bytea_6), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 101 "static_variables.pgc"
+
+if (sqlca.sqlcode == ECPG_NOT_FOUND) break;
+#line 101 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 101 "static_variables.pgc"
+
+
+		printf("%.*s\t%.*s\t%.*s\t%i\t%i\t%i\n",
+			firstname.len, firstname.arr,
+			lastname.len, lastname.arr,
+			address.len, address.arr,
+			year_of_birth, height_in_sm, weight_in_kg);
+		dump_binary(data1_2.arr, data1_2.len);
+		dump_binary(data2_2.arr, data2_2.len);
+		dump_binary(data3_2.arr, data3_2.len);
+	}
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "close cur", ECPGt_EOIT, ECPGt_EORT);
+#line 113 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 113 "static_variables.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table persons", ECPGt_EOIT, ECPGt_EORT);
+#line 114 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 114 "static_variables.pgc"
+
+	{ ECPGtrans(__LINE__, NULL, "commit");
+#line 115 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 115 "static_variables.pgc"
+
+	{ ECPGdisconnect(__LINE__, "CURRENT");
+#line 116 "static_variables.pgc"
+
+if (sqlca.sqlcode < 0) exit (1);}
+#line 116 "static_variables.pgc"
+
+	return 0;
+}
diff --git a/src/interfaces/ecpg/test/expected/preproc-static_variables.stderr b/src/interfaces/ecpg/test/expected/preproc-static_variables.stderr
new file mode 100644
index 0000000000..b3e94f1c52
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/preproc-static_variables.stderr
@@ -0,0 +1,150 @@
+[NO_PID]: ECPGdebug: set to 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGconnect: opening database ecpg1_regression on <DEFAULT> port <DEFAULT>  
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 40: query: create table persons ( firstname varchar ( 50 ) not null , lastname varchar ( 50 ) not null , address varchar ( 255 ) not null , year_of_birth int not null , height_in_sm int not null , weight_in_kg int not null , data1 bytea not null , data2 bytea not null , data3 bytea not null ); with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 40: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 40: OK: CREATE TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 64: query: insert into persons ( firstname , lastname , address , year_of_birth , height_in_sm , weight_in_kg , data1 , data2 , data3 ) values ( 'firstname1' , 'lastname1' , 'address1' , 1985 , 180 , 70 , $1  , $2  , $3  ); with 3 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 64: using PQexecParams
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_free_params on line 64: parameter 1 = 0101010101
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_free_params on line 64: parameter 2 = 0202020202020202
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_free_params on line 64: parameter 3 = 030303030303030303030303
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 64: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 73: query: insert into persons ( firstname , lastname , address , year_of_birth , height_in_sm , weight_in_kg , data1 , data2 , data3 ) values ( 'firstname2' , 'lastname2' , 'address2' , 1995 , 170 , 65 , $1  , $2  , $3  ); with 3 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 73: using PQexecParams
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_free_params on line 73: parameter 1 = 0101010101
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_free_params on line 73: parameter 2 = 0202020202020202
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_free_params on line 73: parameter 3 = 030303030303030303030303
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 73: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 82: query: insert into persons ( firstname , lastname , address , year_of_birth , height_in_sm , weight_in_kg , data1 , data2 , data3 ) values ( 'firstname3' , 'lastname3' , 'address3' , 2000 , 172 , 80 , $1  , $2  , $3  ); with 3 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 82: using PQexecParams
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_free_params on line 82: parameter 1 = 0101010101
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_free_params on line 82: parameter 2 = 0202020202020202
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_free_params on line 82: parameter 3 = 030303030303030303030303
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 82: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGtrans on line 91: action "commit"; connection "ecpg1_regression"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 93: query: declare cur cursor for select firstname , lastname , address , year_of_birth , height_in_sm , weight_in_kg , data1 , data2 , data3 from persons; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 93: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 93: OK: DECLARE CURSOR
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 99: query: fetch cur; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 99: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 99: correctly got 1 tuples with 9 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: firstname1 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: lastname1 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: address1 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: 1985 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: 180 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: 70 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: \x0101010101 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: \x0202020202020202 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: \x030303030303030303030303 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 99: query: fetch cur; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 99: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 99: correctly got 1 tuples with 9 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: firstname2 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: lastname2 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: address2 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: 1995 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: 170 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: 65 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: \x0101010101 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: \x0202020202020202 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: \x030303030303030303030303 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 99: query: fetch cur; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 99: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 99: correctly got 1 tuples with 9 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: firstname3 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: lastname3 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: address3 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: 2000 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: 172 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: 80 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: \x0101010101 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: \x0202020202020202 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 99: RESULT: \x030303030303030303030303 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 99: query: fetch cur; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 99: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 99: correctly got 0 tuples with 9 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: raising sqlcode 100 on line 99: no data found on line 99
+[NO_PID]: sqlca: code: 100, state: 02000
+[NO_PID]: ecpg_execute on line 113: query: close cur; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 113: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 113: OK: CLOSE CURSOR
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 114: query: drop table persons; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 114: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 114: OK: DROP TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGtrans on line 115: action "commit"; connection "ecpg1_regression"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_finish: connection ecpg1_regression closed
+[NO_PID]: sqlca: code: 0, state: 00000
diff --git a/src/interfaces/ecpg/test/expected/preproc-static_variables.stdout b/src/interfaces/ecpg/test/expected/preproc-static_variables.stdout
new file mode 100644
index 0000000000..d5148f78fa
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/preproc-static_variables.stdout
@@ -0,0 +1,12 @@
+firstname1	lastname1	address1	1985	180	70
+len=5, data=0x0101010101
+len=8, data=0x0202020202020202
+len=12, data=0x030303030303030303030303
+firstname2	lastname2	address2	1995	170	65
+len=5, data=0x0101010101
+len=8, data=0x0202020202020202
+len=12, data=0x030303030303030303030303
+firstname3	lastname3	address3	2000	172	80
+len=5, data=0x0101010101
+len=8, data=0x0202020202020202
+len=12, data=0x030303030303030303030303
diff --git a/src/interfaces/ecpg/test/preproc/.gitignore b/src/interfaces/ecpg/test/preproc/.gitignore
index fd63e645a3..831accc526 100644
--- a/src/interfaces/ecpg/test/preproc/.gitignore
+++ b/src/interfaces/ecpg/test/preproc/.gitignore
@@ -14,6 +14,8 @@
 /outofscope.c
 /pointer_to_struct
 /pointer_to_struct.c
+/static_variables
+/static_variables.c
 /strings
 /strings.c
 /type
diff --git a/src/interfaces/ecpg/test/preproc/Makefile b/src/interfaces/ecpg/test/preproc/Makefile
index 39b1974f5f..a3cfe6533f 100644
--- a/src/interfaces/ecpg/test/preproc/Makefile
+++ b/src/interfaces/ecpg/test/preproc/Makefile
@@ -10,6 +10,7 @@ TESTS = array_of_struct array_of_struct.c \
 	cursor cursor.c \
 	define define.c \
 	init init.c \
+	static_variables static_variables.c \
 	strings strings.c \
 	outofscope outofscope.c \
 	type type.c \
diff --git a/src/interfaces/ecpg/test/preproc/static_variables.pgc b/src/interfaces/ecpg/test/preproc/static_variables.pgc
new file mode 100644
index 0000000000..05be898e01
--- /dev/null
+++ b/src/interfaces/ecpg/test/preproc/static_variables.pgc
@@ -0,0 +1,118 @@
+#include <stdlib.h>
+
+exec sql include ../regression;
+
+exec sql whenever sqlerror stop;
+
+exec sql declare cur cursor for
+	select firstname, lastname, address,
+		   year_of_birth, height_in_sm, weight_in_kg,
+		   data1, data2, data3
+	from persons;
+
+exec sql begin declare section;
+	static varchar firstname[50], lastname[50], address[255];
+	static int year_of_birth, height_in_sm, weight_in_kg;
+	static bytea data1[5],   data2[8],   data3[12],
+				 data1_2[5], data2_2[8], data3_2[12]; 
+exec sql end declare section;
+
+static void
+dump_binary(char *buf, int len)
+{
+	int i;
+
+	printf("len=%d, data=0x", len);
+	for (i = 0; i < len; ++i)
+		printf("%02x", buf[i]);
+	printf("\n");
+}
+
+int
+main (void)
+{
+	int loopcount;
+
+	ECPGdebug(1, stderr);
+
+	exec sql connect to REGRESSDB1;
+
+	exec sql create table persons (
+		firstname varchar(50) not null,
+		lastname varchar(50) not null,
+		address varchar(255) not null,
+		year_of_birth int not null,
+		height_in_sm int not null,
+		weight_in_kg int not null,
+		data1 bytea not null,
+		data2 bytea not null,
+		data3 bytea not null
+	);
+
+	data1.len = 5;
+	for (loopcount = 0; loopcount < data1.len; loopcount++)
+		data1.arr[loopcount] = 1;
+
+	data2.len = 8;
+	for (loopcount = 0; loopcount < data2.len; loopcount++)
+		data2.arr[loopcount] = 2;
+
+	data3.len = 12;
+	for (loopcount = 0; loopcount < data3.len; loopcount++)
+		data3.arr[loopcount] = 3;
+
+	exec sql insert into persons (
+				firstname, lastname, address, 
+				year_of_birth, height_in_sm, weight_in_kg,
+				data1, data2, data3)
+			 values (
+				'firstname1', 'lastname1', 'address1',
+				1985, 180, 70,
+				:data1, :data2, :data3);
+
+	exec sql insert into persons (
+				firstname, lastname, address, 
+				year_of_birth, height_in_sm, weight_in_kg,
+				data1, data2, data3)
+			 values (
+				'firstname2', 'lastname2', 'address2',
+				1995, 170, 65,
+				:data1, :data2, :data3);
+
+	exec sql insert into persons (
+				firstname, lastname, address, 
+				year_of_birth, height_in_sm, weight_in_kg,
+				data1, data2, data3)
+			 values (
+				'firstname3', 'lastname3', 'address3',
+				2000, 172, 80,
+				:data1, :data2, :data3);
+
+	exec sql commit;
+
+	exec sql open cur;
+
+	exec sql whenever not found do break;
+
+	for (loopcount = 0; loopcount < 100; loopcount++)
+	{
+		exec sql fetch cur into :firstname, :lastname, :address,
+								:year_of_birth, :height_in_sm, :weight_in_kg,
+								:data1_2, :data2_2, :data3_2;
+
+		printf("%.*s\t%.*s\t%.*s\t%i\t%i\t%i\n",
+			firstname.len, firstname.arr,
+			lastname.len, lastname.arr,
+			address.len, address.arr,
+			year_of_birth, height_in_sm, weight_in_kg);
+		dump_binary(data1_2.arr, data1_2.len);
+		dump_binary(data2_2.arr, data2_2.len);
+		dump_binary(data3_2.arr, data3_2.len);
+	}
+
+	exec sql close cur;
+	exec sql drop table persons;
+	exec sql commit;
+	exec sql disconnect;
+	return 0;
+}
-- 
2.33.3

#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: Andrey Sokolov (#3)
Re: [BUG] Storage declaration in ECPG

Andrey Sokolov <a.sokolov@arenadata.io> writes:

[ v2-0001-Fix-storage-declaration-in-ECPG.patch ]

Pushed. I didn't think a whole new test case was appropriate,
either from the patch-footprint or test-runtime standpoint,
so I just added a couple of declarations to preproc/variable.pgc.

regards, tom lane