The following bug has been logged on the website:
Bug reference: 15176
Logged by: Uwe Höppner
Email address: uhoeppner@psi.de
PostgreSQL version: 10.3
Operating system: PostgreSQL 10.3, compiled by Visual C++ build 180
Description:
Hello,
we are very happy, that PostgreSQL exists as an alternative and we want to
migrate to postgresql and try to use ecpg to precompile our existing code to
produce c-Code to access our pg-database. But the generated code does not
compile. We tested with Microsoft Visual Studio Professional 2015, Version
14.
Our C++ applications have a lot of embedded SQL, so it is not possible to
change fast to other frameworks.
The main problem arises, when we use structs with VARCHAR elements.
an example-table:
CREATE TABLE public.test_ta
(
bb double precision,
ii integer,
nname character varying(80)
)
WITH (
OIDS = FALSE
);
ALTER TABLE public.test_ta
OWNER to postgres;
----------------------------------------------------------------------------------------------------------
pgc-Code snippet start:
int fkt1()
{
EXEC SQL BEGIN DECLARE SECTION;
struct a_t
{
double b;
int i;
VARCHAR name[180];
};
struct a_ind_t
{
short b;
short i;
short name;
};
struct a_t a_var;
struct a_ind_t a_ind_var;
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT bb,ii, nname INTO :a_var:a_ind_var FROM test_ta;
pgc-code snippet stop
--------------------------------------------------------------------------------------------------------------------------
ecpg generates the following output:
int fkt1()
{
/* exec sql begin declare section */
(yes, these empty lines are produced by ecpg :-) )
struct a_t {
#line 37 "D:/dev/ems/master/src/db/bdp/app/pgtest/CTestApp.pc"
double b ;
#line 38 "D:/dev/ems/master/src/db/bdp/app/pgtest/CTestApp.pc"
int i ;
#line 39 "D:/dev/ems/master/src/db/bdp/app/pgtest/CTestApp.pc"
struct varchar_1 { int len; char arr[ 180 ]; } name ;
} ; struct a_ind_t {
#line 44 "D:/dev/ems/master/src/db/bdp/app/pgtest/CTestApp.pc"
short b ;
#line 45 "D:/dev/ems/master/src/db/bdp/app/pgtest/CTestApp.pc"
short i ;
#line 46 "D:/dev/ems/master/src/db/bdp/app/pgtest/CTestApp.pc"
short name ;
} ;
#line 49 "D:/dev/ems/master/src/db/bdp/app/pgtest/CTestApp.pc"
struct a_t a_var ;
#line 50 "D:/dev/ems/master/src/db/bdp/app/pgtest/CTestApp.pc"
struct a_ind_t a_ind_var ;
/* exec sql end declare section */
#line 52 "D:/dev/ems/master/src/db/bdp/app/pgtest/CTestApp.pc"
{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select bb , ii , nname
from test_ta", ECPGt_EOIT,
ECPGt_double,&(a_var.b),(long)1,(long)1,sizeof( struct a_t ),
ECPGt_short,&(a_ind_var.b),(long)1,(long)1,sizeof( struct a_ind_t ),
ECPGt_int,&(a_var.i),(long)1,(long)1,sizeof( struct a_t ),
ECPGt_short,&(a_ind_var.i),(long)1,(long)1,sizeof( struct a_ind_t ),
ECPGt_varchar,&(a_var.name),(long)180,(long)1,sizeof( struct a_t ),
ECPGt_short,&(a_ind_var.name),(long)1,(long)1,sizeof( struct a_ind_t ),
ECPGt_EORT);}
#line 54 "D:/dev/ems/master/src/db/bdp/app/pgtest/CTestApp.pc"
--------------------------------------------------------------------------------------------------------------------------
For select statements the generated code compiles, but IMO, the parameters
of all sizeof() calls are wrong. I would expect code like this:
{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select bb , ii , nname
from test_ta", ECPGt_EOIT,
ECPGt_double,&(a_var.b),(long)1,(long)1,sizeof(a_var.b),
ECPGt_short,&(a_ind_var.b),(long)1,(long)1,sizeof(a_ind_var.b),
ECPGt_int,&(a_var.i),(long)1,(long)1,sizeof(a_var.i),
ECPGt_short,&(a_ind_var.i),(long)1,(long)1,sizeof(a_ind_var.i),
ECPGt_varchar,&(a_var.name),(long)180,(long)1,sizeof(a_var.name),
ECPGt_short,&(a_ind_var.name),(long)1,(long)1,sizeof(a_ind_var.name),
ECPGt_EORT);}
--------------------------------------------------------------------------------------------------------------------------
The result is even worse, if you try to insert into the database.
the pgc-code:
a_var.b = 1.0;
a_var.i = 2;
//a_var.name is empty
EXEC SQL INSERT INTO test_ta(bb,ii,nname) VALUES(:a_var.b, :a_var.i,
:a_var.name);
pgc-code stop
--------------------------------------------------------------------------------------------------------------------------
ecpg generates the following output:
a_var.b = 1.0;
a_var.i = 2;
//a_var.name is empty
{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into test_ta ( bb
, ii , nname ) values ( $1 , $2 , $3 )",
ECPGt_double,&(a_var.b),(long)1,(long)1,sizeof(double),
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
ECPGt_int,&(a_var.i),(long)1,(long)1,sizeof(int),
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
ECPGt_varchar,&(a_var.name),(long)180,(long)1,sizeof(struct varchar_1),
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);}
#line 62 "D:/dev/ems/master/src/db/bdp/app/pgtest/CTestApp.pc"
--------------------------------------------------------------------------------------------------------------------------
This code does not compile!
If you look to #line 39 you can see the definition of struct varchar_1
inside of struct a_t in function fkt1. So this results in the following
error message:
1>d:\dev\ems\master\src\db\bdp\app\pgtest\ctestapp.pc(67): error C2027:
Verwendung des undefinierten Typs "fkt1::varchar_1"
varchar_1 is unknown.
After manual correction it compiles:
{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into test_ta ( bb
, ii , nname ) values ( $1 , $2 , $3 )",
ECPGt_double,&(a_var.b),(long)1,(long)1,sizeof(double),
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
ECPGt_int,&(a_var.i),(long)1,(long)1,sizeof(int),
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
/* ECPGt_varchar,&(a_var.name),(long)180,(long)1,sizeof(struct varchar_1),
wrong generated */
/* ECPGt_varchar,&(a_var.name),(long)180,(long)1,sizeof(struct
a_t::varchar_1), also okay */
ECPGt_varchar, &(a_var.name), (long)180, (long)1, sizeof(a_var.name),
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);}
#line 62 "D:/dev/ems/master/src/db/bdp/app/pgtest/CTestApp.pc"
I would prefer the variant with use of the variable over the variant with
the type. Both seem ok.
Could you please repair ecpg, so it generates code, that compiles. :-)
Cheers,
Uwe