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.
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
--
Andrey Sokolov
Arenadata https://arenadata.tech/
From c8f8fc7a211938569e7d46c91a428d8cb25b6f9c Mon Sep 17 00:00:00 2001 From: Andrey Sokolov <a.soko...@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