Thread: BUG #15176: ecpg generation error

BUG #15176: ecpg generation error

From
PG Bug reporting form
Date:
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


Re: BUG #15176: ecpg generation error

From
Michael Meskes
Date:
Dear Uwe,

> (yes, these empty lines are produced    by ecpg :-) )

Your point being?

> For select statements the generated code compiles, but IMO, the
> parameters
> of all sizeof() calls are wrong. I would expect code like this:

You obviously have no idea what this code is doing nor did you check
with the source code. So what makes you think you can educate us about
what the code should look like? May I remind you that ecpg has been
used for 20 years and on millions and millions of source code. You're
hardly the first one to use it.

>
> The result is even worse, if you try to insert into the database.
> the pgc-code:
> ...
> This code does not compile!

Compiles cleanly on my system.

> 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.

To everyone out there that does not read German, the error message says
that type "fkt1::varchar1" is undefined. Uwe, it surely helps sending
English error messages to an English language mailing list.

Not sure what you or your compiler are doing, but the last time I
checked defining a struct within a struct works nicely in *C*. It
probably does not in C++, but ecpg is not a C++ precompiler!

> After manual correction it compiles:

I hardly call commenting out these lines a correction.

> Could you please repair ecpg, so it generates code, that compiles. :-
> )

Could you please show a different attitude? Otherwise it's highly
unlikely anyone volunteers to use their spare time to help you. And
after all it seems to be you using ecpg wrongly and not ecpg being
buggy.

Michael

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


RE: BUG #15176: ecpg generation error

From
Höppner, Uwe
Date:
Hello Michael,

sorry how I wrote my message. English is not my first language. 
I didn't try to offend or blame anybody. I am happy, that there are volunteers like you
and I respect all who work at postgresql.

You wrote:
> To everyone out there that does not read German, the error message says
> that type "fkt1::varchar1" is undefined. Uwe, it surely helps sending
> English error messages to an English language mailing list.
> 
> Not sure what you or your compiler are doing, but the last time I
> checked defining a struct within a struct works nicely in *C*. It
> probably does not in C++, but ecpg is not a C++ precompiler!
>

I compiled again the generated file in C mode and it worked. So thank you for this hint. 
It was not clear for me, that scope works differently in C and C++ and 
scope does not really exist under C.

I would appreciate a small change. If ecpg would use sizeof("variable") instead of sizeof("type") the
generated code compile also with a C++-compiler. Is it possible to extend ecpg that way?
The name of the variable is already used in the same line to describe the input or output value 
in ECPGdo command.

Cheers,
Uwe


An example:

int main()
{
  EXEC SQL BEGIN DECLARE SECTION;
  struct HostVar_t
  {
    int i;
    VARCHAR name[128];
  };

  struct HostVar_t hostvar;

  EXEC SQL END DECLARE SECTION;


  unsigned long long sz;

  /* sizeof used by ecpg in ECPGdo */
  sz =  sizeof(struct varchar_1);

  /* change, compiles as C and C++ */
  sz =  sizeof(hostvar.name);


  EXEC SQL INSERT INTO names_ta(col_i,col_name)
    VALUES(
      :hostvar.i,
      :hostvar.name
    );

  return 0;
}

/* generated code by ecpg

  { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into names_ta ( col_i , col_name ) values ( $1  , $2  )", 
    ECPGt_int,&(hostvar.i),(long)1,(long)1,sizeof(int), 
    ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
    ECPGt_varchar,&(hostvar.name),(long)128,(long)1,sizeof(struct varchar_1), 
    ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);}
*/



Re: BUG #15176: ecpg generation error

From
Michael Meskes
Date:
Hi Uwe,

> sorry how I wrote my message. English is not my first language.

Guess what, neither is mine. :)

> I didn't try to offend or blame anybody. I am happy, that there are
> volunteers like you
> and I respect all who work at postgresql.

Thanks.

> I would appreciate a small change. If ecpg would use
> sizeof("variable") instead of sizeof("type") the
> generated code compile also with a C++-compiler. Is it possible to
> extend ecpg that way?

Certainly it is but frankly I don't know how much effort that would be.
 I would have to check the code to see how much work it'll be. No idea,
though, when I find the time to do it. Of course patches are always
welcome.

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