Thread: ECPG support for struct in INTO list

ECPG support for struct in INTO list

From
Boszormenyi Zoltan
Date:
Hi,

one of our clients wants to port their application suite
from Informix to PostgreSQL, they use constructs like

SELECT * INTO :tablerec FROM table ...

where "tablerec" mirrors the table fields in a C struct.

Currently ECPG dumps core on this, more exactly aborts on it
in ecpg_type_name().

Patch is attached that solves it by introducing add_struct_to_head()
called  from rule "coutputvariable"  that also catches C unions now,
emitting an error because unions cannot be unambiguously unrolled.
It tries to handle NULL indicator, expecting a struct with at least
the same amount of members.

Best regards,
Zoltán Böszörményi

--
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zoltán Böszörményi
Cybertec Schönig & Schönig GmbH
http://www.postgresql.at/

diff -dcrpN pgsql85dev.4string/src/interfaces/ecpg/preproc/ecpg.trailer
pgsql85dev.5struct/src/interfaces/ecpg/preproc/ecpg.trailer
*** pgsql85dev.4string/src/interfaces/ecpg/preproc/ecpg.trailer    2009-07-14 21:36:58.000000000 +0200
--- pgsql85dev.5struct/src/interfaces/ecpg/preproc/ecpg.trailer    2009-07-17 12:24:30.000000000 +0200
*************** c_args: /*EMPTY*/        { $$ = EMPTY; }
*** 1835,1843 ****
          ;

  coutputvariable: cvariable indicator
!             { add_variable_to_head(&argsresult, find_variable($1), find_variable($2)); }
          | cvariable
!             { add_variable_to_head(&argsresult, find_variable($1), &no_indicator); }
          ;


--- 1835,1873 ----
          ;

  coutputvariable: cvariable indicator
!         {
!             struct variable *var = find_variable($1);
!
!             switch (var->type->type)
!             {
!                 case ECPGt_struct:
!                     add_struct_to_head(&argsresult, var, find_variable($2));
!                     break;
!                 case ECPGt_union:
!                     mmerror(PARSE_ERROR, ET_FATAL, "variable \"%s\" is a union", var->name);
!                     break;
!                 default:
!                     add_variable_to_head(&argsresult, var, find_variable($2));
!                     break;
!             }
!         }
          | cvariable
!         {
!             struct variable *var = find_variable($1);
!
!             switch (var->type->type)
!             {
!                 case ECPGt_struct:
!                     add_struct_to_head(&argsresult, var, &no_indicator);
!                     break;
!                 case ECPGt_union:
!                     mmerror(PARSE_ERROR, ET_FATAL, "variable \"%s\" is a union", var->name);
!                     break;
!                 default:
!                     add_variable_to_head(&argsresult, var, &no_indicator);
!                     break;
!             }
!         }
          ;


diff -dcrpN pgsql85dev.4string/src/interfaces/ecpg/preproc/extern.h
pgsql85dev.5struct/src/interfaces/ecpg/preproc/extern.h
*** pgsql85dev.4string/src/interfaces/ecpg/preproc/extern.h    2009-07-14 21:36:58.000000000 +0200
--- pgsql85dev.5struct/src/interfaces/ecpg/preproc/extern.h    2009-07-17 12:24:30.000000000 +0200
*************** extern struct descriptor *lookup_descrip
*** 91,96 ****
--- 91,97 ----
  extern struct variable *descriptor_variable(const char *name, int input);
  extern struct variable *sqlda_variable(const char *name);
  extern void add_variable_to_head(struct arguments **, struct variable *, struct variable *);
+ extern void add_struct_to_head(struct arguments **, struct variable *, struct variable *);
  extern void add_variable_to_tail(struct arguments **, struct variable *, struct variable *);
  extern void remove_variable_from_list(struct arguments ** list, struct variable * var);
  extern void dump_variables(struct arguments *, int);
diff -dcrpN pgsql85dev.4string/src/interfaces/ecpg/preproc/variable.c
pgsql85dev.5struct/src/interfaces/ecpg/preproc/variable.c
*** pgsql85dev.4string/src/interfaces/ecpg/preproc/variable.c    2009-07-14 21:36:58.000000000 +0200
--- pgsql85dev.5struct/src/interfaces/ecpg/preproc/variable.c    2009-07-17 12:24:30.000000000 +0200
*************** add_variable_to_head(struct arguments **
*** 382,387 ****
--- 382,461 ----
      *list = p;
  }

+ /*
+  * Insert a struct's members unrolled into our request list.
+  * This is needed for the case when the user says
+  *
+  * SELECT * INTO :mystruct FROM ...
+  * or
+  * SELECT a.*, b.* INTO :struct_a, :struct_b FROM a, b ...
+  *
+  * Just in case, implement it recursively.
+  */
+ void
+ add_struct_to_head(struct arguments ** list, struct variable * var, struct variable * ind)
+ {
+     struct ECPGstruct_member *member;
+     struct ECPGstruct_member *ind_member = NULL;
+     bool no_ind;
+
+     if (var->type->type != ECPGt_struct)
+         mmerror(PARSE_ERROR, ET_FATAL, "variable \"%s\" is not a struct", var->name);
+
+     no_ind = (ind == &no_indicator);
+
+     if (!no_ind && ind->type->type != ECPGt_struct)
+         mmerror(INDICATOR_NOT_STRUCT, ET_FATAL, "struct variable \"%s\" was associated with a non-struct indicator
variable", var->name); 
+
+     member = var->type->u.members;
+     if (!no_ind)
+         ind_member = ind->type->u.members;
+
+     while (member && (no_ind || ind_member))
+     {
+         char *newvarname;
+         char *newindname;
+         struct variable *newvar;
+         struct variable *newind = &no_indicator;
+
+         newvarname = mm_alloc(strlen(var->name) + strlen(member->name) + 2);
+         sprintf(newvarname, "%s.%s", var->name, member->name);
+         newvar = find_variable(newvarname);
+         if (newvar == NULL)
+             mmerror(PARSE_ERROR, ET_FATAL, "internal error: variable \"%s\" is not found", newvarname);
+
+         if (!no_ind)
+         {
+             newindname = mm_alloc(strlen(ind->name) + strlen(ind_member->name) + 2);
+             sprintf(newindname, "%s.%s", ind->name, ind_member->name);
+             newind = find_variable(newindname);
+             if (newind == NULL)
+                 mmerror(PARSE_ERROR, ET_FATAL, "internal error: variable \"%s\" is not found", newvarname);
+         }
+
+         switch (newvar->type->type)
+         {
+             case ECPGt_struct:
+                 add_struct_to_head(list, newvar, newind);
+                 break;
+             case ECPGt_union:
+                 mmerror(PARSE_ERROR, ET_FATAL, "variable \"%s\" is a union", newvarname);
+                 break;
+             default:
+                 add_variable_to_head(list, newvar, newind);
+                 break;
+         }
+         free(newvarname);
+
+         member = member->next;
+         if (!no_ind)
+             ind_member = ind_member->next;
+     }
+
+     if (member != NULL && !no_ind && ind_member == NULL)
+         mmerror(PARSE_ERROR, ET_FATAL, "indicator struct has less members than variable struct");
+ }
+
  /* Append a new variable to our request list. */
  void
  add_variable_to_tail(struct arguments ** list, struct variable * var, struct variable * ind)

Re: ECPG support for struct in INTO list

From
Michael Meskes
Date:
On Fri, Jul 17, 2009 at 12:27:49PM +0200, Boszormenyi Zoltan wrote:
> one of our clients wants to port their application suite
> from Informix to PostgreSQL, they use constructs like
> 
> SELECT * INTO :tablerec FROM table ...
> 
> where "tablerec" mirrors the table fields in a C struct.

Well, this was supposed to work.

> Currently ECPG dumps core on this, more exactly aborts on it
> in ecpg_type_name().

Could you please send an example where it dumps core?

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
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!


Re: ECPG support for struct in INTO list

From
Boszormenyi Zoltan
Date:
Michael Meskes írta:
> On Fri, Jul 17, 2009 at 12:27:49PM +0200, Boszormenyi Zoltan wrote:
>
>> one of our clients wants to port their application suite
>> from Informix to PostgreSQL, they use constructs like
>>
>> SELECT * INTO :tablerec FROM table ...
>>
>> where "tablerec" mirrors the table fields in a C struct.
>>
>
> Well, this was supposed to work.
>
>
>> Currently ECPG dumps core on this, more exactly aborts on it
>> in ecpg_type_name().
>>
>
> Could you please send an example where it dumps core?
>

Attached is the short example I can reproduce with.
The version I used was final PostgreSQL 8.4.0, without our
extensions posted already. I added an indication to ecpg_type_name():

[zozo@db00 ecpg-test]$ ecpg -C INFORMIX test28.pgc
ecpg_type_name: unhandled type 22
Félbeszakítva (core dumped)

Type 22 is exactly ECPGt_struct. gdb cannot get the passed value:

[zozo@db00 ecpg-test]$ gdb ~/pgc84pre/bin/ecpg core.850
...
#0  0x0000003994032215 in raise (sig=<value optimized out>) at
../nptl/sysdeps/unix/sysv/linux/raise.c:64
64      return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig);
(gdb) bt
#0  0x0000003994032215 in raise (sig=<value optimized out>) at
../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1  0x0000003994033d83 in abort () at abort.c:88
#2  0x0000000000423d65 in ecpg_type_name (typ=<value optimized out>) at
typename.c:65
#3  0x0000000000402742 in adjust_informix (list=0x1e74560) at preproc.y:272
#4  0x0000000000406ca7 in base_yyparse () at preproc.y:6581
#5  0x0000000000422b22 in main (argc=4, argv=0x7fff24b40aa8) at ecpg.c:456

test28.pgc contains this, ECPG aborts:

EXEC SQL DECLARE mycur CURSOR FOR SELECT * INTO :myvar FROM a1 WHERE id = 1;
EXEC SQL FETCH FROM mycur;

But you are right about the "supposed to work" part,
if I modify it the way below, it works:

EXEC SQL DECLARE mycur CURSOR FOR SELECT * FROM a1 WHERE id = 1;
EXEC SQL FETCH FROM mycur INTO :myvar;

Thanks,
Zoltán Böszörményi

> Michael
>


--
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zoltán Böszörményi
Cybertec Schönig & Schönig GmbH
http://www.postgresql.at/


struct mytype {
    int    id;
    char    t[64];
    dec_t    d1;
    double    d2;
    char    c[30];
};
typedef struct mytype MYTYPE;
/*
 * Test DECLARE ... SELECT ... INTO ...
 * with "string"
 */

#include <stdio.h>
#include <stdlib.h>

EXEC SQL DEFINE MYDB1 zozo;
EXEC SQL DEFINE MYUSER1 zozo;

EXEC SQL BEGIN DECLARE SECTION;
EXEC SQL include test28.h;
EXEC SQL END DECLARE SECTION;

int main(int argc, char **argv) {
    EXEC SQL BEGIN DECLARE SECTION;
    MYTYPE         myvar;
    EXEC SQL END DECLARE SECTION;

    EXEC SQL WHENEVER SQLWARNING SQLPRINT;
    EXEC SQL WHENEVER SQLERROR SQLPRINT;

    EXEC SQL connect to MYDB1 USER MYUSER1;
    if (sqlca.sqlcode)
    {
        printf ("connect error = %ld\n", sqlca.sqlcode);
        exit (sqlca.sqlcode);
    }

    EXEC SQL DECLARE mycur CURSOR FOR SELECT * INTO :myvar FROM a1 WHERE id = 1;
    EXEC SQL OPEN mycur;

    EXEC SQL WHENEVER NOT FOUND GOTO out;

    EXEC SQL FETCH FROM mycur;

    printf("c = '%s'\n", myvar.c);

out:
    EXEC SQL CLOSE mycur;

    EXEC SQL DISCONNECT;

    return 0;
}

Re: ECPG support for struct in INTO list

From
Michael Meskes
Date:
On Fri, Jul 17, 2009 at 03:58:21PM +0200, Boszormenyi Zoltan wrote:
> Attached is the short example I can reproduce with.
> The version I used was final PostgreSQL 8.4.0, without our
> extensions posted already. I added an indication to ecpg_type_name():
> 
> [zozo@db00 ecpg-test]$ ecpg -C INFORMIX test28.pgc
> ...
> But you are right about the "supposed to work" part,
> if I modify it the way below, it works:

Thanks for spotting this. It appears to be a bug in Informix compatibility
mode. Without -C INFORMIX it works nicely. Thus I guess we have to find and fix
the bug. Your patch probably/hopefully is not needed.

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
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!


Re: ECPG support for struct in INTO list

From
Boszormenyi Zoltan
Date:
Michael Meskes írta:
> On Fri, Jul 17, 2009 at 03:58:21PM +0200, Boszormenyi Zoltan wrote:
>
>> Attached is the short example I can reproduce with.
>> The version I used was final PostgreSQL 8.4.0, without our
>> extensions posted already. I added an indication to ecpg_type_name():
>>
>> [zozo@db00 ecpg-test]$ ecpg -C INFORMIX test28.pgc
>> ...
>> But you are right about the "supposed to work" part,
>> if I modify it the way below, it works:
>>
>
> Thanks for spotting this. It appears to be a bug in Informix compatibility
> mode. Without -C INFORMIX it works nicely. Thus I guess we have to find and fix
> the bug. Your patch probably/hopefully is not needed.
>
> Michael
>

My previous patch on this broke "make check" in ecpg,
so ignore that. Your comment that it's a bug in Informix-mode
made me look around more. Find the attached patch I came up with.
Now my previous test code works and produces similar C code
as without "-C INFORMIX". Can it be this simple?
Can you see anything wrong with this approach?

Best regards,
Zoltán Böszörményi

--
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zoltán Böszörményi
Cybertec Schönig & Schönig GmbH
http://www.postgresql.at/

diff -dcrpN pgsql85dev.4string/src/interfaces/ecpg/preproc/ecpg.header
pgsql85dev.5struct/src/interfaces/ecpg/preproc/ecpg.header
*** pgsql85dev.4string/src/interfaces/ecpg/preproc/ecpg.header    2009-07-15 11:19:06.000000000 +0200
--- pgsql85dev.5struct/src/interfaces/ecpg/preproc/ecpg.header    2009-07-31 11:38:50.000000000 +0200
*************** adjust_informix(struct arguments *list)
*** 266,271 ****
--- 266,273 ----
              ptr->variable = new_variable(cat_str(4, make_str("("),
mm_strdup(ecpg_type_name(ptr->variable->type->type)),make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)),
ECPGmake_simple_type(ptr->variable->type->type,ptr->variable->type->size, ptr->variable->type->lineno), 0); 
              sprintf(temp, "%d, (", ecpg_informix_var++);
          }
+         else if (ptr->variable->type->type == ECPGt_struct || ptr->variable->type->type == ECPGt_union)
+             continue;
          else
          {
              ptr->variable = new_variable(cat_str(4, make_str("*("),
mm_strdup(ecpg_type_name(ptr->variable->type->type)),make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)),
ECPGmake_simple_type(ptr->variable->type->type,ptr->variable->type->size, ptr->variable->type->lineno), 0); 

Re: ECPG support for struct in INTO list

From
Michael Meskes
Date:
On Fri, Jul 31, 2009 at 11:42:33AM +0200, Boszormenyi Zoltan wrote:
> made me look around more. Find the attached patch I came up with.
> Now my previous test code works and produces similar C code
> as without "-C INFORMIX". Can it be this simple?

Unfortunately it is not.

> Can you see anything wrong with this approach?

Yes, please look at the slightly changed test version that is attached to this email.

If you use e.g. int instead of MYTYPE, it works nicely, but not with MYTYPE.
Please see the comments in adjust_informix to see what this function is
supposed to do.

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
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!

Attachment

Re: ECPG support for struct in INTO list

From
Boszormenyi Zoltan
Date:
Michael Meskes írta:
> On Fri, Jul 31, 2009 at 11:42:33AM +0200, Boszormenyi Zoltan wrote:
>   
>> made me look around more. Find the attached patch I came up with.
>> Now my previous test code works and produces similar C code
>> as without "-C INFORMIX". Can it be this simple?
>>     
>
> Unfortunately it is not.
>
>   
>> Can you see anything wrong with this approach?
>>     
>
> Yes, please look at the slightly changed test version that is attached to this email.
>   

I have looked at it. The code seems to be invalid.

get_var(void)
{EXEC SQL BEGIN DECLARE SECTION;MYTYPE        myvar;EXEC SQL END DECLARE SECTION;
EXEC SQL DECLARE mycur CURSOR FOR SELECT * INTO :myvar FROM a1 WHERE id = 1;
}


"myvar" is lost as soon as the function returns
and is not visible to calling functions.

I tried to compile your code (with my previous "fix"
in place, so at least :myvar is processed and C code is output):

$ make test28
ecpg -C INFORMIX test28.pgc
cc -g -O2 -Wall -Wmissing-prototypes -Wpointer-arith
-Wdeclaration-after-statement -Wendif-labels -fno-strict-aliasing
-fwrapv -g -I/home/zozo/pgc84pre/include
-I/home/zozo/pgc84pre/include/postgresql/internal -c -o test28.o test28.c
test28.pgc:15: warning: return type defaults to ‘int’
test28.pgc:14: warning: no previous prototype for ‘get_var’
test28.pgc: In function ‘get_var’:
test28.pgc:17: warning: unused variable ‘myvar’
test28.pgc: In function ‘main’:
test28.pgc:45: error: ‘myvar’ undeclared (first use in this function)
test28.pgc:45: error: (Each undeclared identifier is reported only once
test28.pgc:45: error: for each function it appears in.)
make: *** [test28.o] Error 1
rm test28.c

Line 45 in the modified code sent by you is:
printf("c = '%s'\n", myvar.c);
and the compiler correctly complains.

> If you use e.g. int instead of MYTYPE, it works nicely, but not with MYTYPE.
>   

I modified getvar this way:

get_var(void)
{
EXEC SQL BEGIN DECLARE SECTION;
int myid;
EXEC SQL END DECLARE SECTION;

EXEC SQL DECLARE mycur CURSOR FOR SELECT id INTO :myid FROM a1 WHERE id
= 1;
}

And the preprocessed code via "ecpg -C INFORMIX" is:

get_var(void)
{
/* exec sql begin declare section */


#line 17 "test28.pgc"
int myid ;
/* exec sql end declare section */
#line 18 "test28.pgc"


ECPG_informix_set_var( 0, &( myid ), __LINE__);\
/* declare mycur cursor for select id from a1 where id = 1 */
#line 20 "test28.pgc"

}

Some systems (stack-protector extensions to GCC, etc)
make the code segfault immediately as soon as the first
FETCH statement tries to touch the lost memory area.
Just because ECPG does some tricks with ECPG_informix_set_var()
and ECPG_informix_get_var() converting variable reference
to runtime pointer values, the code wouldn't get magically valid.


> Please see the comments in adjust_informix to see what this function is
> supposed to do.
>   

I did and I don't understand. I think it's just a bug
in ESQL/C to accept such constructs.

> Michael
>   

Best regards,
Zoltán Böszörményi

-- 
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zoltán Böszörményi
Cybertec Schönig & Schönig GmbH
http://www.postgresql.at/



Re: ECPG support for struct in INTO list

From
Michael Meskes
Date:
On Wed, Aug 05, 2009 at 11:08:26AM +0200, Boszormenyi Zoltan wrote:
> I have looked at it. The code seems to be invalid.

Yes, it is, I was too lazy to make it valid. If you just allocate the memory
for the variable in get_var() it becomes valid.

> I tried to compile your code (with my previous "fix"
> in place, so at least :myvar is processed and C code is output):

Yes, but incorrect one.

> Some systems (stack-protector extensions to GCC, etc)
> make the code segfault immediately as soon as the first
> FETCH statement tries to touch the lost memory area.
> Just because ECPG does some tricks with ECPG_informix_set_var()
> and ECPG_informix_get_var() converting variable reference
> to runtime pointer values, the code wouldn't get magically valid.

Again, this doesn't matter in this case as we try to get the preprocessor to
work with a test case as small as possible.

> I did and I don't understand. I think it's just a bug
> in ESQL/C to accept such constructs.

I do not like this "feature" either, but it's there and therefore should work
in our compatibility mode. And it does with non-struct variables. Just look at
test/compat_informix/test_informix.pgc for a real and working example.

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
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!


Re: ECPG support for struct in INTO list

From
Boszormenyi Zoltan
Date:
Michael Meskes írta:
> On Wed, Aug 05, 2009 at 11:08:26AM +0200, Boszormenyi Zoltan wrote:
>   
>> I have looked at it. The code seems to be invalid.
>>     
>
> Yes, it is, I was too lazy to make it valid. If you just allocate the memory
> for the variable in get_var() it becomes valid.
>   

With allocated memory, yes, the code would be valid.

This means that what I did in my first patch for this
problem in "add_struct_to_head()" (unrolling members
of the struct) has to be done in adjust_informix(),
turning it into a recursive function.
I think this would be a good solution. What do you think?

>   
>> I tried to compile your code (with my previous "fix"
>> in place, so at least :myvar is processed and C code is output):
>>     
>
> Yes, but incorrect one.
>
>   
>> Some systems (stack-protector extensions to GCC, etc)
>> make the code segfault immediately as soon as the first
>> FETCH statement tries to touch the lost memory area.
>> Just because ECPG does some tricks with ECPG_informix_set_var()
>> and ECPG_informix_get_var() converting variable reference
>> to runtime pointer values, the code wouldn't get magically valid.
>>     
>
> Again, this doesn't matter in this case as we try to get the preprocessor to
> work with a test case as small as possible.
>
>   
>> I did and I don't understand. I think it's just a bug
>> in ESQL/C to accept such constructs.
>>     
>
> I do not like this "feature" either, but it's there and therefore should work
> in our compatibility mode. And it does with non-struct variables. Just look at
> test/compat_informix/test_informix.pgc for a real and working example.
>
> Michael
>   

-- 
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zoltán Böszörményi
Cybertec Schönig & Schönig GmbH
http://www.postgresql.at/



Re: ECPG support for struct in INTO list

From
Michael Meskes
Date:
On Wed, Aug 05, 2009 at 11:52:57AM +0200, Boszormenyi Zoltan wrote:
> This means that what I did in my first patch for this
> problem in "add_struct_to_head()" (unrolling members
> of the struct) has to be done in adjust_informix(),
> turning it into a recursive function.
> I think this would be a good solution. What do you think?

No, this doesn't seem right. There should be no need to unroll a struct.
Instead I would think struct support should be added to the get_var/set_var
functions. At least that's my guess without really digging into it.

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
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!


Re: ECPG support for struct in INTO list

From
Boszormenyi Zoltan
Date:
Michael Meskes írta:
> On Wed, Aug 05, 2009 at 11:52:57AM +0200, Boszormenyi Zoltan wrote:
>   
>> This means that what I did in my first patch for this
>> problem in "add_struct_to_head()" (unrolling members
>> of the struct) has to be done in adjust_informix(),
>> turning it into a recursive function.
>> I think this would be a good solution. What do you think?
>>     
>
> No, this doesn't seem right. There should be no need to unroll a struct.
> Instead I would think struct support should be added to the get_var/set_var
> functions. At least that's my guess without really digging into it.
>
> Michael
>   

My question is: why not unroll the struct in the preprocessor?
This adjust_informix() issue aside, if I do this in the same function:
       EXEC SQL BEGIN DECLARE SECTION;       MYTYPE          myvar;       MYNULLTYPE      mynullvar;       EXEC SQL END
DECLARESECTION;
 
       EXEC SQL DECLARE mycur CURSOR FOR SELECT * INTO :myvar
:mynullvar FROM a1;       EXEC SQL OPEN mycur;
       EXEC SQL WHENEVER NOT FOUND DO BREAK;       while (1) {               EXEC SQL FETCH FROM mycur;
...       }
 

then the preprocessed code for DECLARE and FETCH look like below:
       { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "declare mycur
cursor for select * from a1 where id = 1", ECPGt_EOIT,       ECPGt_int,&(myvar.id),(long)1,(long)1,sizeof(int),
ECPGt_NO_INDICATOR,NULL , 0L, 0L, 0L,       ECPGt_char,&(myvar.t),(long)64,(long)1,(64)*sizeof(char),
ECPGt_NO_INDICATOR,NULL , 0L, 0L, 0L,       ECPGt_double,&(myvar.d1),(long)1,(long)1,sizeof(double),
ECPGt_NO_INDICATOR,NULL , 0L, 0L, 0L,       ECPGt_double,&(myvar.d2),(long)1,(long)1,sizeof(double),
ECPGt_NO_INDICATOR,NULL , 0L, 0L, 0L,       ECPGt_char,&(myvar.c),(long)30,(long)1,(30)*sizeof(char),
ECPGt_NO_INDICATOR,NULL , 0L, 0L, 0L, ECPGt_EORT);
 
#line 39 "test28.pgc"

...
       { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch from
mycur", ECPGt_EOIT,       ECPGt_int,&(myvar.id),(long)1,(long)1,sizeof(int),       ECPGt_NO_INDICATOR, NULL , 0L, 0L,
0L,      ECPGt_char,&(myvar.t),(long)64,(long)1,(64)*sizeof(char),       ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
ECPGt_double,&(myvar.d1),(long)1,(long)1,sizeof(double),      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
ECPGt_double,&(myvar.d2),(long)1,(long)1,sizeof(double),      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
ECPGt_char,&(myvar.c),(long)30,(long)1,(30)*sizeof(char),      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
 
#line 43 "test28.pgc"

These are done by ECPGdump_a_struct(), when the struct's members
and their type, size, etc are known. It's unrolled by the ecpg preprocessor.
Your idea about pushing struct support into set_var/get_var seems
not appropriate. With the current set_var scheme, you pass one variable's
properties. Why not keep this simplicity and unroll the struct in the
preprocessor into multiple set_var() calls for simple types?

Best regards,
Zoltán Böszörményi

-- 
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zoltán Böszörményi
Cybertec Schönig & Schönig GmbH
http://www.postgresql.at/



Re: ECPG support for struct in INTO list

From
Michael Meskes
Date:
On Wed, Aug 05, 2009 at 03:04:00PM +0200, Boszormenyi Zoltan wrote:
> My question is: why not unroll the struct in the preprocessor?

The problem is not that the struct is unrolled in the preprocessor. I just
don't like the idea of having two places where structs are unrolled when one
could be sufficient.

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
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!


Re: ECPG support for struct in INTO list

From
Boszormenyi Zoltan
Date:
Michael Meskes írta:
> On Wed, Aug 05, 2009 at 11:08:26AM +0200, Boszormenyi Zoltan wrote:
>
>> I have looked at it. The code seems to be invalid.
>>
>
> Yes, it is, I was too lazy to make it valid. If you just allocate the memory
> for the variable in get_var() it becomes valid.
>

If you meant like this below, then ECPG segfaults on this too:

int *
get_var(void)
{
        EXEC SQL BEGIN DECLARE SECTION;
        int *myvar;
        EXEC SQL END DECLARE SECTION;

        myvar = malloc(sizeof(int));
        EXEC SQL DECLARE mycur CURSOR FOR SELECT id INTO :myvar FROM a1
WHERE id = 1;
        return myvar;
}

ecpg_type_name() aborts, ECPGt_array is unhandled
besides struct and union, it's called at the same place
in adjust_informix() as ECPGt_struct.

Attached is my modified test28.pgc. Compiling it
*without* -C INFORMIX makes it unusable, the variable
or the address where the data should be fetched into
doesn't even gets emitted in neither the DECLARE/OPEN
nor the FETCH callsites. I think this code should be valid
even in non-Informix-compatible mode.

> ... Just look at
> test/compat_informix/test_informix.pgc for a real and working example.
>

The example there is the other way around.
The variable, the DECLARE and FETCH commands
are in the outer main() function, and it calls a function called
openit() where the OPEN command is emitted, so that
example doesn't help here too much.

Best regards,
Zoltán Böszörményi

--
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zoltán Böszörményi
Cybertec Schönig & Schönig GmbH
http://www.postgresql.at/

/*
 * Test DECLARE ... SELECT ... INTO ...
 * with "string"
 * Does make ecpg segfault when run with -C INFORMIX
 */

#include <stdio.h>
#include <stdlib.h>

EXEC SQL BEGIN DECLARE SECTION;
EXEC SQL include test28.h;
EXEC SQL END DECLARE SECTION;

EXEC SQL BEGIN DECLARE SECTION;
int    *myvar1;
EXEC SQL END DECLARE SECTION;

int *
get_var(void)
{
    EXEC SQL BEGIN DECLARE SECTION;
    int *myvar;
    EXEC SQL END DECLARE SECTION;

    myvar = malloc(sizeof(int));
    EXEC SQL DECLARE mycur CURSOR FOR SELECT id INTO :myvar FROM a1 WHERE id = 1;
    return myvar;
}

int main(int argc, char **argv) {
    EXEC SQL WHENEVER SQLWARNING SQLPRINT;
    EXEC SQL WHENEVER SQLERROR SQLPRINT;

    EXEC SQL connect to test;
    if (sqlca.sqlcode)
    {
        printf ("connect error = %ld\n", sqlca.sqlcode);
        exit (sqlca.sqlcode);
    }

    EXEC SQL CREATE TABLE a1 (id int, t text, d2 numeric, c text);

    EXEC SQL INSERT INTO a1 values(1, 'text1', 14.7, 'text2');

    myvar1 = get_var();
    EXEC SQL OPEN mycur;

    EXEC SQL WHENEVER NOT FOUND GOTO out;

    EXEC SQL FETCH FROM mycur;

    printf("id = %d\n", *myvar1);

out:
    EXEC SQL CLOSE mycur2;
    EXEC SQL CLOSE mycur;

    EXEC SQL DISCONNECT;

    return 0;
}

Re: ECPG support for struct in INTO list

From
Boszormenyi Zoltan
Date:
Michael Meskes írta:
> On Wed, Aug 05, 2009 at 03:04:00PM +0200, Boszormenyi Zoltan wrote:
>   
>> My question is: why not unroll the struct in the preprocessor?
>>     
>
> The problem is not that the struct is unrolled in the preprocessor. I just
> don't like the idea of having two places where structs are unrolled when one
> could be sufficient.
>   

Yes, one place should be sufficient. Read my other mail about
the modified get_var() function. I start to get convinced that
adjust_informix() and ECPG_informix_{get|set}_var() should not
be Informix compat specific at all.

Best regards,
Zoltán Böszörményi

-- 
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zoltán Böszörményi
Cybertec Schönig & Schönig GmbH
http://www.postgresql.at/



Re: ECPG support for struct in INTO list

From
Boszormenyi Zoltan
Date:
Boszormenyi Zoltan írta:
> Michael Meskes írta:
>   
>> On Wed, Aug 05, 2009 at 11:08:26AM +0200, Boszormenyi Zoltan wrote:
>>   
>>     
>>> I have looked at it. The code seems to be invalid.
>>>     
>>>       
>> Yes, it is, I was too lazy to make it valid. If you just allocate the memory
>> for the variable in get_var() it becomes valid.
>>   
>>     
>
> If you meant like this below, then ECPG segfaults on this too:
>
> int *
> get_var(void)
> {
>         EXEC SQL BEGIN DECLARE SECTION;
>         int *myvar;
>         EXEC SQL END DECLARE SECTION;
>
>         myvar = malloc(sizeof(int));
>         EXEC SQL DECLARE mycur CURSOR FOR SELECT id INTO :myvar FROM a1
> WHERE id = 1;
>         return myvar;
> }
>   

And another problem that we have run into already.
ECPG is a one-stage preprocessor, instead of a two-stage one.
If the above function is located later in the source file than
the "OPEN mycur" or "FETCH mycur", then ECPG complains
about an unknown cursor. Not a big annoyance, but ESQL/C
supports that.

> ecpg_type_name() aborts, ECPGt_array is unhandled
> besides struct and union, it's called at the same place
> in adjust_informix() as ECPGt_struct.
>
> Attached is my modified test28.pgc. Compiling it
> *without* -C INFORMIX makes it unusable, the variable
> or the address where the data should be fetched into
> doesn't even gets emitted in neither the DECLARE/OPEN
> nor the FETCH callsites. I think this code should be valid
> even in non-Informix-compatible mode.
>
>   
>> ... Just look at
>> test/compat_informix/test_informix.pgc for a real and working example.
>>   
>>     
>
> The example there is the other way around.
> The variable, the DECLARE and FETCH commands
> are in the outer main() function, and it calls a function called
> openit() where the OPEN command is emitted, so that
> example doesn't help here too much.
>
> Best regards,
> Zoltán Böszörményi
>
>   
> ------------------------------------------------------------------------
>
>


-- 
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zoltán Böszörményi
Cybertec Schönig & Schönig GmbH
http://www.postgresql.at/



Re: ECPG support for struct in INTO list

From
Michael Meskes
Date:
On Wed, Aug 05, 2009 at 04:22:53PM +0200, Boszormenyi Zoltan wrote:
> If you meant like this below, then ECPG segfaults on this too:

Right, because arrays as as well unimplemented as are structs. I meant
something like this;

int *
get_var(void)
{
        EXEC SQL BEGIN DECLARE SECTION;
        static int myvar;
        EXEC SQL END DECLARE SECTION;

        EXEC SQL DECLARE mycur CURSOR FOR SELECT id INTO :myvar FROM a1 WHERE id = 1;
        return (&myvar);
}

> Attached is my modified test28.pgc. Compiling it
> *without* -C INFORMIX makes it unusable, the variable
> or the address where the data should be fetched into
> doesn't even gets emitted in neither the DECLARE/OPEN
> nor the FETCH callsites. I think this code should be valid
> even in non-Informix-compatible mode.

I don't think i buy into this. The variable is out of scope at the time open is
called. Why do you think this should work?

> > ... Just look at
> > test/compat_informix/test_informix.pgc for a real and working example.
> >
>
> The example there is the other way around.
> The variable, the DECLARE and FETCH commands
> are in the outer main() function, and it calls a function called
> openit() where the OPEN command is emitted, so that
> example doesn't help here too much.

Eh, why not? We're talking about a bug/missing feature in the precompiler
itself. And the precompiler doesn't see this difference. I just pointed you to
one working example. Anyway I attached a modified test28.pgc that should work
in compatibility mode.

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
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!

Attachment

Re: ECPG support for struct in INTO list

From
Boszormenyi Zoltan
Date:
Michael Meskes írta:
> On Wed, Aug 05, 2009 at 04:22:53PM +0200, Boszormenyi Zoltan wrote:
>   
>> If you meant like this below, then ECPG segfaults on this too:
>>     
>
> Right, because arrays as as well unimplemented as are structs. I meant
> something like this;
>
> int *
> get_var(void)
> {
>         EXEC SQL BEGIN DECLARE SECTION;
>         static int myvar;
>         EXEC SQL END DECLARE SECTION;
>
>         EXEC SQL DECLARE mycur CURSOR FOR SELECT id INTO :myvar FROM a1 WHERE id = 1;
>         return (&myvar);
> }
>   

Which isn't exactly a good programming habit.
It can break subtly in multi-threaded code.
And you were talking about allocated variables, which,
in my book (without explicitely mentioning "statically")
boils down to malloc().

>> Attached is my modified test28.pgc. Compiling it
>> *without* -C INFORMIX makes it unusable, the variable
>> or the address where the data should be fetched into
>> doesn't even gets emitted in neither the DECLARE/OPEN
>> nor the FETCH callsites. I think this code should be valid
>> even in non-Informix-compatible mode.
>>     
>
> I don't think i buy into this. The variable is out of scope at the time open is
> called. Why do you think this should work? 
>   

Because the allocated area, the pointer to it that's returned
from the function _is_ in scope. Possibly under a new name,
but that's why ECPG employs ECPG_informix_set_var() and
_get_var(), to make OPEN and FETCH independent of the
out of scope variables, no?

This code is not much different:

int *
get_var(void)
{       static int myvar;       return (&myvar);
}


another_func(...)
{       EXEC SQL BEGIN DECLARE SECTION;int    *myvar = get_var();       EXEC SQL END DECLARE SECTION;
       EXEC SQL DECLARE mycur CURSOR FOR SELECT id INTO :myvar FROM a1 WHERE id = 1;
EXEC SQL OPEN mycur;
...
}


But it also breaks in compatibility mode, exactly because
adjust_informix() is called on it and even in-scope variables
are replaced with ECPG_informix_set_var() and _get_var() calls
and adjust_informix() is not prepared to certain types (array, struct).

And if you just consider this which doesn't break:

another_func(...)
{       EXEC SQL BEGIN DECLARE SECTION;int    myvar;       EXEC SQL END DECLARE SECTION;
       EXEC SQL DECLARE mycur CURSOR FOR SELECT id INTO :myvar FROM a1 WHERE id = 1;
EXEC SQL OPEN mycur;
...
}


In the above code local, in-scope variables are also replaced
with ECPG_informix_set_var() and _get_var() calls.
Totally unnecessary, or totally necessary even in non-compatible
mode, depending on which leg I stand on. If you move the
struct/union unrolling into adjust_informix() and handle arrays,
ECPGdump_a_struct() won't be needed then.

>>> ... Just look at
>>> test/compat_informix/test_informix.pgc for a real and working example.
>>>   
>>>       
>> The example there is the other way around.
>> The variable, the DECLARE and FETCH commands
>> are in the outer main() function, and it calls a function called
>> openit() where the OPEN command is emitted, so that
>> example doesn't help here too much.
>>     
>
> Eh, why not?

Because that example contradicts all sensible programming habits.
(Well, what is "sensible" is different between people, so don't take it
personal.)

>  We're talking about a bug/missing feature in the precompiler
> itself. And the precompiler doesn't see this difference. I just pointed you to
> one working example. Anyway I attached a modified test28.pgc that should work
> in compatibility mode.
>
> Michael
>   


-- 
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zoltán Böszörményi
Cybertec Schönig & Schönig GmbH
http://www.postgresql.at/



Re: ECPG support for struct in INTO list

From
Michael Meskes
Date:
On Fri, Aug 07, 2009 at 11:48:33AM +0200, Boszormenyi Zoltan wrote:
> Which isn't exactly a good programming habit.

I couldn't agree more.

> In the above code local, in-scope variables are also replaced
> with ECPG_informix_set_var() and _get_var() calls.
> Totally unnecessary, or totally necessary even in non-compatible
> mode, depending on which leg I stand on. If you move the
> struct/union unrolling into adjust_informix() and handle arrays,
> ECPGdump_a_struct() won't be needed then.

Yeah, right, and you also add this hack to all applications. No.

> Because that example contradicts all sensible programming habits.
> (Well, what is "sensible" is different between people, so don't take it
> personal.)

Hey, don't blame me! Informix uses this feature to some extend, this is why it
got implemented. If you look into the source code you will see this:
 * This breaks standard and leads to some very dangerous programming.        * Since they do, we have to work around
andaccept their syntax as well.        * But we will do so ONLY in Informix mode.
 

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
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!


Re: ECPG support for struct in INTO list

From
Boszormenyi Zoltan
Date:
Michael Meskes írta:
> On Fri, Aug 07, 2009 at 11:48:33AM +0200, Boszormenyi Zoltan wrote:
>   
>> Which isn't exactly a good programming habit.
>>     
>
> I couldn't agree more.
>   

:-)

>> In the above code local, in-scope variables are also replaced
>> with ECPG_informix_set_var() and _get_var() calls.
>> Totally unnecessary, or totally necessary even in non-compatible
>> mode, depending on which leg I stand on. If you move the
>> struct/union unrolling into adjust_informix() and handle arrays,
>> ECPGdump_a_struct() won't be needed then.
>>     
>
> Yeah, right, and you also add this hack to all applications. No.
>   

What do you mean?

In the meantime, I recalled my original idea, the patch
you have already seen, where an unrolling was introduced
in "ecpg_into:" rule with a new add_struct_to_head() function.
"ecpg_into:" is a good central place where this unrolling
can be done, so:
- ECPGdump_a_struct() won't be needed, and
- adjust_informix() doesn't encounter structs or unions.
So, struct unrolling would still be done at only one place
and one problem goes away.
About the arrays, I have to think about more.

>> Because that example contradicts all sensible programming habits.
>> (Well, what is "sensible" is different between people, so don't take it
>> personal.)
>>     
>
> Hey, don't blame me! Informix uses this feature to some extend, this is why it
> got implemented. If you look into the source code you will see this:
>
>      * This breaks standard and leads to some very dangerous programming.
>          * Since they do, we have to work around and accept their syntax as well.
>          * But we will do so ONLY in Informix mode.
>   

I didn't want to blame you, I just wanted to say that
from my experience, it's more common that these are
the separation blocks:
1. memory allocation
1a. DECLARE
2. OPEN/FETCH
2a. CLOSE
3. memory freeing

Point "1a" can be grouped with either "1" or "2", similarly
point "2a" can be grouped with either "2" or "3".
"Grouped" means that they are in the same function, at
the same visibility level.

It was very alien to me seeing that only OPEN was
moved out to another function in the mentioned
regression test example.

I think that the DECLARE doing this adjust_informix()
call (which should be called adjust_out_of_scope_vars() ;-) )
shouldn't be Informix-specific at all. The above separation
is natural (again, a very subjective POV), and should be
supported in native mode, too.

Best regards,
Zoltán Böszörményi

-- 
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zoltán Böszörményi
Cybertec Schönig & Schönig GmbH
http://www.postgresql.at/



Re: ECPG support for struct in INTO list

From
Boszormenyi Zoltan
Date:
Hi,

I got around to fix the struct problem, when ECPG aborted
upon finding the following statement:

DECLARE mycur
    CURSOR FOR
    SELECT *
    INTO :mystruct [:myindicatorstruct] ...

As I found out earlier, ECPG also aborted when the variable
is a pointer, like:
    struct mytype   *myvar;

I fixed both cases, and added the quirk to the lexer to keep
the last identifier as a function name before any ( or { is
encountered and this allowed me to detect and handle
out of scope DECLARE/OPEN/FETCH.
You know the ecpg lexer/grammar better than me,
you may find a better way to do this.

Anyway, the end result is that now in compat mode
ECPGinformix_get_var() type vars are not always used,
only when OPEN and FETCH are out of scope, i.e. they
are in a function different from where the cursor was
DECLAREd.

I added two regression tests, one tests only the struct
usability in compat mode, which didn't work before and
started this little "crusade". :-) The other tests struct pointers
and out of scope DECLARE/OPEN/FETCH.

Tell me that this isn't a useful feature in non-compat mode.
I will leave the rewrite to you if you find it so, I left a comment
for you in the code. ;-)

Best regards,
Zoltán Böszörményi

--
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zoltán Böszörményi
Cybertec Schönig & Schönig GmbH
http://www.postgresql.at/

diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/preproc/descriptor.c
pgsql.ooscur/src/interfaces/ecpg/preproc/descriptor.c
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/preproc/descriptor.c    2009-08-11 10:32:34.000000000 +0200
--- pgsql.ooscur/src/interfaces/ecpg/preproc/descriptor.c    2009-08-14 09:59:15.000000000 +0200
*************** struct variable *
*** 317,323 ****
  descriptor_variable(const char *name, int input)
  {
      static char descriptor_names[2][MAX_DESCRIPTOR_NAMELEN];
!     static const struct ECPGtype descriptor_type = {ECPGt_descriptor, NULL, NULL, {NULL}, 0};
      static const struct variable varspace[2] = {
          {descriptor_names[0], (struct ECPGtype *) & descriptor_type, 0, NULL},
          {descriptor_names[1], (struct ECPGtype *) & descriptor_type, 0, NULL}
--- 317,323 ----
  descriptor_variable(const char *name, int input)
  {
      static char descriptor_names[2][MAX_DESCRIPTOR_NAMELEN];
!     static const struct ECPGtype descriptor_type = {ECPGt_descriptor, NULL, NULL, NULL, {NULL}, 0};
      static const struct variable varspace[2] = {
          {descriptor_names[0], (struct ECPGtype *) & descriptor_type, 0, NULL},
          {descriptor_names[1], (struct ECPGtype *) & descriptor_type, 0, NULL}
diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/preproc/ecpg.addons
pgsql.ooscur/src/interfaces/ecpg/preproc/ecpg.addons
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/preproc/ecpg.addons    2009-08-13 17:40:41.000000000 +0200
--- pgsql.ooscur/src/interfaces/ecpg/preproc/ecpg.addons    2009-08-14 21:18:34.000000000 +0200
*************** ECPG: DeclareCursorStmtDECLAREcursor_nam
*** 309,314 ****
--- 309,315 ----

          this->next = cur;
          this->name = $2;
+         this->function = (current_function ? mm_strdup(current_function) : NULL);
          this->connection = connection;
          this->opened = false;
          this->command =  cat_str(7, make_str("declare"), cursor_marker, $3, make_str("cursor"), $5, make_str("for"),
$7);
*************** ECPG: DeclareCursorStmtDECLAREcursor_nam
*** 328,337 ****
              {
                  char *command = (char *)mm_alloc(sizeof("ECPGreset_sqlca(__LINE__, );") + strlen(con));
                  sprintf(command, "ECPGreset_sqlca(__LINE__, %s);", con);
!                 $$ = cat_str(4, adjust_informix(this->argsinsert), adjust_informix(this->argsresult), command,
comment);
              }
              else
!                 $$ = cat_str(3, adjust_informix(this->argsinsert), adjust_informix(this->argsresult), comment);
          }
          else
              $$ = cat_str(3, make_str("/*"), mm_strdup(this->command), make_str("*/"));
--- 329,338 ----
              {
                  char *command = (char *)mm_alloc(sizeof("ECPGreset_sqlca(__LINE__, );") + strlen(con));
                  sprintf(command, "ECPGreset_sqlca(__LINE__, %s);", con);
!                 $$ = cat_str(4, adjust_informix(this, true), adjust_informix(this, false), command, comment);
              }
              else
!                 $$ = cat_str(3, adjust_informix(this, true), adjust_informix(this, false), comment);
          }
          else
              $$ = cat_str(3, make_str("/*"), mm_strdup(this->command), make_str("*/"));
diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/preproc/ecpg.header
pgsql.ooscur/src/interfaces/ecpg/preproc/ecpg.header
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/preproc/ecpg.header    2009-08-13 17:37:57.000000000 +0200
--- pgsql.ooscur/src/interfaces/ecpg/preproc/ecpg.header    2009-08-14 21:49:27.000000000 +0200
***************
*** 33,38 ****
--- 33,39 ----
   */
  int struct_level = 0;
  int braces_open; /* brace level counter */
+ char *current_function;
  int ecpg_informix_var = 0;
  char    *connection = NULL;
  char    *input_filename = NULL;
*************** static char *ECPGstruct_sizeof = NULL;
*** 53,62 ****
  /* for forward declarations we have to store some data as well */
  static char *forward_name = NULL;

! struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, NULL, NULL, {NULL}, 0};
  struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL};

! struct ECPGtype ecpg_query = {ECPGt_char_variable, NULL, NULL, {NULL}, 0};

  /*
   * Handle parsing errors and warnings
--- 54,63 ----
  /* for forward declarations we have to store some data as well */
  static char *forward_name = NULL;

! struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, NULL, NULL, NULL, {NULL}, 0};
  struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL};

! struct ECPGtype ecpg_query = {ECPGt_char_variable, NULL, NULL, NULL, {NULL}, 0};

  /*
   * Handle parsing errors and warnings
*************** create_questionmarks(char *name, bool ar
*** 230,236 ****
  }

  static char *
! adjust_informix(struct arguments *list)
  {
      /* Informix accepts DECLARE with variables that are out of scope when OPEN is called.
        * for instance you can declare variables in a function, and then subsequently use them
--- 231,237 ----
  }

  static char *
! adjust_informix(struct cursor *cur, bool insert)
  {
      /* Informix accepts DECLARE with variables that are out of scope when OPEN is called.
        * for instance you can declare variables in a function, and then subsequently use them
*************** adjust_informix(struct arguments *list)
*** 244,252 ****
--- 245,275 ----
       * We have to change the variables to our own struct and just store the pointer instead of the variable
       */

+      struct arguments *list;
       struct arguments *ptr;
+      struct arguments *newlist = NULL;
+      struct variable *newvar, *newind;
       char *result = make_str("");

+ /*
+  * This only needed if the out-of-scope DECLARE is
+  * decided to be useful for non-compat mode, too.
+  * DECLARE has just been proved to be a non-declarative
+  * statement in Informix.
+  */
+ #if 0
+     /*
+      * If we're outside of a function, then DECLARE can only reference
+      * variables in the global scope. They don't need transforming.
+      * This also prevents emitting ECPGinformix_set_var() calls
+      * outside of functions.
+      */
+      if (cur->function == NULL) /* same as checking for (braces_open == 0) */
+         return result;
+ #endif
+
+      list = (insert ? cur->argsinsert : cur->argsresult);
+
       for (ptr = list; ptr != NULL; ptr = ptr->next)
       {
           char temp[20]; /* this should be sufficient unless you have 8 byte integers */
*************** adjust_informix(struct arguments *list)
*** 258,274 ****

          if ((ptr->variable->type->type != ECPGt_varchar && ptr->variable->type->type != ECPGt_char &&
ptr->variable->type->type!= ECPGt_unsigned_char && ptr->variable->type->type != ECPGt_string) &&
atoi(ptr->variable->type->size)> 1) 
          {
!             ptr->variable = new_variable(cat_str(4, make_str("("),
mm_strdup(ecpg_type_name(ptr->variable->type->u.element->type)),make_str(" *)(ECPG_informix_get_var("),
mm_strdup(temp)),ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type, make_str("1"),
ptr->variable->type->u.element->lineno),ptr->variable->type->size), 0); 
              sprintf(temp, "%d, (", ecpg_informix_var++);
          }
          else if ((ptr->variable->type->type == ECPGt_varchar || ptr->variable->type->type == ECPGt_char ||
ptr->variable->type->type== ECPGt_unsigned_char || ptr->variable->type->type == ECPGt_string) &&
atoi(ptr->variable->type->size)> 1) 
          {
!             ptr->variable = new_variable(cat_str(4, make_str("("),
mm_strdup(ecpg_type_name(ptr->variable->type->type)),make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)),
ECPGmake_simple_type(ptr->variable->type->type,ptr->variable->type->size, ptr->variable->type->lineno), 0); 
              sprintf(temp, "%d, (", ecpg_informix_var++);
          }
          else
          {
!             ptr->variable = new_variable(cat_str(4, make_str("*("),
mm_strdup(ecpg_type_name(ptr->variable->type->type)),make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)),
ECPGmake_simple_type(ptr->variable->type->type,ptr->variable->type->size, ptr->variable->type->lineno), 0); 
              sprintf(temp, "%d, &(", ecpg_informix_var++);
          }

--- 281,317 ----

          if ((ptr->variable->type->type != ECPGt_varchar && ptr->variable->type->type != ECPGt_char &&
ptr->variable->type->type!= ECPGt_unsigned_char && ptr->variable->type->type != ECPGt_string) &&
atoi(ptr->variable->type->size)> 1) 
          {
!             newvar = new_variable(cat_str(4, make_str("("),
mm_strdup(ecpg_type_name(ptr->variable->type->u.element->type)),make_str(" *)(ECPG_informix_get_var("),
mm_strdup(temp)),ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type, make_str("1"),
ptr->variable->type->u.element->lineno),ptr->variable->type->size), 0); 
              sprintf(temp, "%d, (", ecpg_informix_var++);
          }
          else if ((ptr->variable->type->type == ECPGt_varchar || ptr->variable->type->type == ECPGt_char ||
ptr->variable->type->type== ECPGt_unsigned_char || ptr->variable->type->type == ECPGt_string) &&
atoi(ptr->variable->type->size)> 1) 
          {
!             newvar = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->type)),
make_str("*)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->variable->type->type,
ptr->variable->type->size,ptr->variable->type->lineno), 0); 
              sprintf(temp, "%d, (", ecpg_informix_var++);
          }
+         else if (ptr->variable->type->type == ECPGt_struct || ptr->variable->type->type == ECPGt_union)
+         {
+             sprintf(temp, "%d)))", ecpg_informix_var);
+             newvar = new_variable(cat_str(4, make_str("(*("), mm_strdup(ptr->variable->type->type_name), make_str("
*)(ECPG_informix_get_var("),mm_strdup(temp)), ECPGmake_struct_type(ptr->variable->type->u.members,
ptr->variable->type->type,ptr->variable->type->type_name, ptr->variable->type->struct_sizeof), 0); 
+             sprintf(temp, "%d, &(", ecpg_informix_var++);
+         }
+         else if (ptr->variable->type->type == ECPGt_array)
+         {
+             if (ptr->variable->type->u.element->type == ECPGt_struct || ptr->variable->type->u.element->type ==
ECPGt_union)
+             {
+                 sprintf(temp, "%d)))", ecpg_informix_var);
+                 newvar = new_variable(cat_str(4, make_str("(*("),
mm_strdup(ptr->variable->type->u.element->type_name),make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)),
ECPGmake_struct_type(ptr->variable->type->u.element->u.members,ptr->variable->type->u.element->type,
ptr->variable->type->u.element->type_name,ptr->variable->type->u.element->struct_sizeof), 0); 
+                 sprintf(temp, "%d, (", ecpg_informix_var++);
+             }
+             else
+             {
+                 newvar = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->type)),
make_str("*)(ECPG_informix_get_var("), mm_strdup(temp)),
ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type,ptr->variable->type->u.element->size,
ptr->variable->type->u.element->lineno),ptr->variable->type->size), 0); 
+                 sprintf(temp, "%d, &(", ecpg_informix_var++);
+             }
+         }
          else
          {
!             newvar = new_variable(cat_str(4, make_str("*("), mm_strdup(ecpg_type_name(ptr->variable->type->type)),
make_str("*)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->variable->type->type,
ptr->variable->type->size,ptr->variable->type->lineno), 0); 
              sprintf(temp, "%d, &(", ecpg_informix_var++);
          }

*************** adjust_informix(struct arguments *list)
*** 276,305 ****
          result = cat_str(5, result, make_str("ECPG_informix_set_var("), mm_strdup(temp), mm_strdup(original_var),
make_str("),__LINE__);\n")); 

          /* now the indicator if there is one */
!         if (ptr->indicator->type->type != ECPGt_NO_INDICATOR)
          {
              /* change variable name to "ECPG_informix_get_var(<counter>)" */
              original_var = ptr->indicator->name;
              sprintf(temp, "%d))", ecpg_informix_var);

              /* create call to "ECPG_informix_set_var(<counter>, <pointer>. <linen number>)" */
!             if (atoi(ptr->indicator->type->size) > 1)
              {
!                 ptr->indicator = new_variable(cat_str(4, make_str("("),
mm_strdup(ecpg_type_name(ptr->indicator->type->type)),make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)),
ECPGmake_simple_type(ptr->indicator->type->type,ptr->indicator->type->size, ptr->variable->type->lineno), 0); 
                  sprintf(temp, "%d, (", ecpg_informix_var++);
              }
              else
              {
!                 ptr->indicator = new_variable(cat_str(4, make_str("*("),
mm_strdup(ecpg_type_name(ptr->indicator->type->type)),make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)),
ECPGmake_simple_type(ptr->indicator->type->type,ptr->indicator->type->size, ptr->variable->type->lineno), 0); 
                  sprintf(temp, "%d, &(", ecpg_informix_var++);
              }
              result = cat_str(5, result, make_str("ECPG_informix_set_var("), mm_strdup(temp), mm_strdup(original_var),
make_str("),__LINE__);\n")); 
          }
       }

       return result;
  }

  static struct cursor *
  add_additional_variables(char *name, bool insert)
  {
--- 319,384 ----
          result = cat_str(5, result, make_str("ECPG_informix_set_var("), mm_strdup(temp), mm_strdup(original_var),
make_str("),__LINE__);\n")); 

          /* now the indicator if there is one */
!         if (ptr->indicator->type->type == ECPGt_NO_INDICATOR)
!         {
!             newind = ptr->indicator;
!         }
!         else
          {
              /* change variable name to "ECPG_informix_get_var(<counter>)" */
              original_var = ptr->indicator->name;
              sprintf(temp, "%d))", ecpg_informix_var);

              /* create call to "ECPG_informix_set_var(<counter>, <pointer>. <linen number>)" */
!             if (ptr->indicator->type->type == ECPGt_struct || ptr->indicator->type->type == ECPGt_union)
              {
!                 sprintf(temp, "%d)))", ecpg_informix_var);
!                 newind = new_variable(cat_str(4, make_str("(*("), mm_strdup(ptr->indicator->type->type_name),
make_str("*)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_struct_type(ptr->indicator->type->u.members,
ptr->indicator->type->type,ptr->indicator->type->type_name, ptr->indicator->type->struct_sizeof), 0); 
!                 sprintf(temp, "%d, &(", ecpg_informix_var++);
!             }
!             else if (ptr->indicator->type->type == ECPGt_array)
!             {
!                 if (ptr->indicator->type->u.element->type == ECPGt_struct || ptr->indicator->type->u.element->type ==
ECPGt_union)
!                 {
!                     sprintf(temp, "%d)))", ecpg_informix_var);
!                     newind = new_variable(cat_str(4, make_str("(*("),
mm_strdup(ptr->indicator->type->u.element->type_name),make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)),
ECPGmake_struct_type(ptr->indicator->type->u.element->u.members,ptr->indicator->type->u.element->type,
ptr->indicator->type->u.element->type_name,ptr->indicator->type->u.element->struct_sizeof), 0); 
!                     sprintf(temp, "%d, (", ecpg_informix_var++);
!                 }
!                 else
!                 {
!                     newind = new_variable(cat_str(4, make_str("("),
mm_strdup(ecpg_type_name(ptr->indicator->type->u.element->type)),make_str(" *)(ECPG_informix_get_var("),
mm_strdup(temp)),ECPGmake_array_type(ECPGmake_simple_type(ptr->indicator->type->u.element->type,
ptr->indicator->type->u.element->size,ptr->indicator->type->u.element->lineno), ptr->indicator->type->size), 0); 
!                     sprintf(temp, "%d, &(", ecpg_informix_var++);
!                 }
!             }
!             else if (atoi(ptr->indicator->type->size) > 1)
!             {
!                 newind = new_variable(cat_str(4, make_str("("),
mm_strdup(ecpg_type_name(ptr->indicator->type->type)),make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)),
ECPGmake_simple_type(ptr->indicator->type->type,ptr->indicator->type->size, ptr->variable->type->lineno), 0); 
                  sprintf(temp, "%d, (", ecpg_informix_var++);
              }
              else
              {
!                 newind = new_variable(cat_str(4, make_str("*("),
mm_strdup(ecpg_type_name(ptr->indicator->type->type)),make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)),
ECPGmake_simple_type(ptr->indicator->type->type,ptr->indicator->type->size, ptr->variable->type->lineno), 0); 
                  sprintf(temp, "%d, &(", ecpg_informix_var++);
              }
              result = cat_str(5, result, make_str("ECPG_informix_set_var("), mm_strdup(temp), mm_strdup(original_var),
make_str("),__LINE__);\n")); 
          }
+
+         add_variable_to_tail(&newlist, newvar, newind);
       }

+      if (insert)
+         cur->argsinsert_oos = newlist;
+      else
+         cur->argsresult_oos = newlist;
+
       return result;
  }

+ /* This tests whether the cursor was declared and opened in the same function. */
+ #define SAMEFUNC(cur)    \
+     ((cur->function == NULL) ||        \
+      (cur->function != NULL && !strcmp(cur->function, current_function)))
+
  static struct cursor *
  add_additional_variables(char *name, bool insert)
  {
*************** add_additional_variables(char *name, boo
*** 322,333 ****
      {
          /* add all those input variables that were given earlier
           * note that we have to append here but have to keep the existing order */
!         for (p = ptr->argsinsert; p; p = p->next)
              add_variable_to_tail(&argsinsert, p->variable, p->indicator);
      }

      /* add all those output variables that were given earlier */
!     for (p = ptr->argsresult; p; p = p->next)
          add_variable_to_tail(&argsresult, p->variable, p->indicator);

      return ptr;
--- 401,412 ----
      {
          /* add all those input variables that were given earlier
           * note that we have to append here but have to keep the existing order */
!         for (p = (SAMEFUNC(ptr) ? ptr->argsinsert : ptr->argsinsert_oos); p; p = p->next)
              add_variable_to_tail(&argsinsert, p->variable, p->indicator);
      }

      /* add all those output variables that were given earlier */
!     for (p = (SAMEFUNC(ptr) ? ptr->argsresult : ptr->argsresult_oos); p; p = p->next)
          add_variable_to_tail(&argsresult, p->variable, p->indicator);

      return ptr;
diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/preproc/ecpg.trailer
pgsql.ooscur/src/interfaces/ecpg/preproc/ecpg.trailer
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/preproc/ecpg.trailer    2009-08-13 17:48:27.000000000 +0200
--- pgsql.ooscur/src/interfaces/ecpg/preproc/ecpg.trailer    2009-08-14 21:19:35.000000000 +0200
*************** statement: ecpgstart at stmt ';'
*** 16,22 ****
                  | c_thing               { fprintf(yyout, "%s", $1); free($1); }
                  | CPP_LINE              { fprintf(yyout, "%s", $1); free($1); }
                  | '{'                   { braces_open++; fputs("{", yyout); }
!                 | '}'                   { remove_typedefs(braces_open); remove_variables(braces_open--); fputs("}",
yyout);} 
                  ;

  CreateAsStmt: CREATE OptTemp TABLE create_as_target AS {FoundInto = 0;} SelectStmt opt_with_data
--- 16,32 ----
                  | c_thing               { fprintf(yyout, "%s", $1); free($1); }
                  | CPP_LINE              { fprintf(yyout, "%s", $1); free($1); }
                  | '{'                   { braces_open++; fputs("{", yyout); }
!                 | '}'
!         {
!             remove_typedefs(braces_open);
!             remove_variables(braces_open--);
!             if (braces_open == 0)
!             {
!                 free(current_function);
!                 current_function = NULL;
!             }
!             fputs("}", yyout);
!         }
                  ;

  CreateAsStmt: CREATE OptTemp TABLE create_as_target AS {FoundInto = 0;} SelectStmt opt_with_data
*************** ECPGCursorStmt:  DECLARE cursor_name cur
*** 336,341 ****
--- 346,352 ----
              /* initial definition */
              this->next = cur;
              this->name = $2;
+             this->function = (current_function ? mm_strdup(current_function) : NULL);
              this->connection = connection;
              this->command =  cat_str(6, make_str("declare"), cursor_marker, $3, make_str("cursor"), $5, make_str("for
$1"));
              this->argsresult = NULL;
*************** var_declaration: storage_declaration
*** 452,457 ****
--- 463,469 ----
          var_type
          {
              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;
              actual_type[struct_level].type_index = $2.type_index;
              actual_type[struct_level].type_sizeof = $2.type_sizeof;
*************** var_declaration: storage_declaration
*** 465,470 ****
--- 477,483 ----
          | var_type
          {
              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;
              actual_type[struct_level].type_index = $1.type_index;
              actual_type[struct_level].type_sizeof = $1.type_sizeof;
*************** variable: opt_pointer ECPGColLabel opt_a
*** 876,884 ****
                  case ECPGt_struct:
                  case ECPGt_union:
                      if (atoi(dimension) < 0)
!                         type = ECPGmake_struct_type(struct_member_list[struct_level],
actual_type[struct_level].type_enum,actual_type[struct_level].type_sizeof); 
                      else
!                         type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level],
actual_type[struct_level].type_enum,actual_type[struct_level].type_sizeof), dimension); 

                      $$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5);
                      break;
--- 889,897 ----
                  case ECPGt_struct:
                  case ECPGt_union:
                      if (atoi(dimension) < 0)
!                         type = ECPGmake_struct_type(struct_member_list[struct_level],
actual_type[struct_level].type_enum,actual_type[struct_level].type_str, actual_type[struct_level].type_sizeof); 
                      else
!                         type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level],
actual_type[struct_level].type_enum,actual_type[struct_level].type_str, actual_type[struct_level].type_sizeof),
dimension);

                      $$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5);
                      break;
*************** ECPGVar: SQL_VAR
*** 1382,1390 ****
                      case ECPGt_struct:
                      case ECPGt_union:
                          if (atoi(dimension) < 0)
!                             type = ECPGmake_struct_type(struct_member_list[struct_level], $5.type_enum,
$5.type_sizeof);
                          else
!                             type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level],
$5.type_enum,$5.type_sizeof),dimension); 
                          break;

                      case ECPGt_varchar:
--- 1395,1403 ----
                      case ECPGt_struct:
                      case ECPGt_union:
                          if (atoi(dimension) < 0)
!                             type = ECPGmake_struct_type(struct_member_list[struct_level], $5.type_enum, $5.type_str,
$5.type_sizeof);
                          else
!                             type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level],
$5.type_enum,$5.type_str, $5.type_sizeof), dimension); 
                          break;

                      case ECPGt_varchar:
diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/preproc/extern.h
pgsql.ooscur/src/interfaces/ecpg/preproc/extern.h
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/preproc/extern.h    2009-08-13 17:14:43.000000000 +0200
--- pgsql.ooscur/src/interfaces/ecpg/preproc/extern.h    2009-08-13 16:32:38.000000000 +0200
*************** extern int    braces_open,
*** 29,34 ****
--- 29,35 ----
              ecpg_informix_var,
              regression_mode,
              auto_prepare;
+ extern char *current_function;
  extern char *descriptor_index;
  extern char *descriptor_name;
  extern char *connection;
diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/preproc/pgc.l pgsql.ooscur/src/interfaces/ecpg/preproc/pgc.l
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/preproc/pgc.l    2009-08-13 17:14:15.000000000 +0200
--- pgsql.ooscur/src/interfaces/ecpg/preproc/pgc.l    2009-08-14 21:23:48.000000000 +0200
*************** static char    *literalbuf = NULL;        /* e
*** 41,46 ****
--- 41,49 ----
  static int        literallen;                /* actual current length */
  static int        literalalloc;            /* current allocated buffer size */

+ /* Used for detecting global state together with braces_open */
+ static int        parenths_open;
+
  #define startlit()    (literalbuf[0] = '\0', literallen = 0)
  static void addlit(char *ytext, int yleng);
  static void addlitchar (unsigned char);
*************** cppline            {space}*#(.*\\{space})*.*{newl
*** 788,794 ****
                      }
  <C>{identifier}     {
                          const ScanKeyword        *keyword;
!
                          /* Informix uses SQL defines only in SQL space */
                          /* however, some defines have to be taken care of for compatibility */
                          if ((!INFORMIX_MODE || !isinformixdefine()) && !isdefine())
--- 791,807 ----
                      }
  <C>{identifier}     {
                          const ScanKeyword        *keyword;
!
!                         /*
!                          * Try to detect a function name:
!                          * look for identifiers at the global scope
!                          * keep the last identifier before the first '(' and '{' */
!                         if (braces_open == 0 && parenths_open == 0)
!                         {
!                             if (current_function)
!                                 free(current_function);
!                             current_function = mm_strdup(yytext);
!                         }
                          /* Informix uses SQL defines only in SQL space */
                          /* however, some defines have to be taken care of for compatibility */
                          if ((!INFORMIX_MODE || !isinformixdefine()) && !isdefine())
*************** cppline            {space}*#(.*\\{space})*.*{newl
*** 811,818 ****
  <C>"/"                { return('/'); }
  <C>"+"                { return('+'); }
  <C>"-"                { return('-'); }
! <C>"("                { return('('); }
! <C>")"                { return(')'); }
  <C,xskip>{space}        { ECHO; }
  <C>\{                { return('{'); }
  <C>\}                { return('}'); }
--- 824,831 ----
  <C>"/"                { return('/'); }
  <C>"+"                { return('+'); }
  <C>"-"                { return('-'); }
! <C>"("                { parenths_open++; return('('); }
! <C>")"                { parenths_open--; return(')'); }
  <C,xskip>{space}        { ECHO; }
  <C>\{                { return('{'); }
  <C>\}                { return('}'); }
*************** void
*** 1178,1183 ****
--- 1191,1198 ----
  lex_init(void)
  {
      braces_open = 0;
+     parenths_open = 0;
+     current_function = NULL;

      preproc_tos = 0;
      yylineno = 1;
diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/preproc/type.c
pgsql.ooscur/src/interfaces/ecpg/preproc/type.c
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/preproc/type.c    2009-08-11 11:46:04.000000000 +0200
--- pgsql.ooscur/src/interfaces/ecpg/preproc/type.c    2009-08-14 20:11:34.000000000 +0200
*************** ECPGstruct_member_dup(struct ECPGstruct_
*** 46,52 ****
          {
              case ECPGt_struct:
              case ECPGt_union:
!                 type = ECPGmake_struct_type(rm->type->u.members, rm->type->type, rm->type->struct_sizeof);
                  break;
              case ECPGt_array:

--- 46,52 ----
          {
              case ECPGt_struct:
              case ECPGt_union:
!                 type = ECPGmake_struct_type(rm->type->u.members, rm->type->type, rm->type->type_name,
rm->type->struct_sizeof);
                  break;
              case ECPGt_array:

*************** ECPGstruct_member_dup(struct ECPGstruct_
*** 55,61 ****
                   * create the struct too
                   */
                  if (rm->type->u.element->type == ECPGt_struct)
!                     type = ECPGmake_struct_type(rm->type->u.element->u.members, rm->type->u.element->type,
rm->type->u.element->struct_sizeof);
                  else
                      type = ECPGmake_array_type(ECPGmake_simple_type(rm->type->u.element->type,
rm->type->u.element->size,rm->type->u.element->lineno), rm->type->size); 
                  break;
--- 55,61 ----
                   * create the struct too
                   */
                  if (rm->type->u.element->type == ECPGt_struct)
!                     type = ECPGmake_struct_type(rm->type->u.element->u.members, rm->type->u.element->type,
rm->type->u.element->type_name,rm->type->u.element->struct_sizeof); 
                  else
                      type = ECPGmake_array_type(ECPGmake_simple_type(rm->type->u.element->type,
rm->type->u.element->size,rm->type->u.element->lineno), rm->type->size); 
                  break;
*************** ECPGmake_simple_type(enum ECPGttype type
*** 98,103 ****
--- 98,104 ----
      struct ECPGtype *ne = (struct ECPGtype *) mm_alloc(sizeof(struct ECPGtype));

      ne->type = type;
+     ne->type_name = NULL;
      ne->size = size;
      ne->u.element = NULL;
      ne->struct_sizeof = NULL;
*************** ECPGmake_array_type(struct ECPGtype * ty
*** 117,126 ****
  }

  struct ECPGtype *
! ECPGmake_struct_type(struct ECPGstruct_member * rm, enum ECPGttype type, char *struct_sizeof)
  {
      struct ECPGtype *ne = ECPGmake_simple_type(type, make_str("1"), 0);

      ne->u.members = ECPGstruct_member_dup(rm);
      ne->struct_sizeof = struct_sizeof;

--- 118,128 ----
  }

  struct ECPGtype *
! ECPGmake_struct_type(struct ECPGstruct_member * rm, enum ECPGttype type, char *type_name, char *struct_sizeof)
  {
      struct ECPGtype *ne = ECPGmake_simple_type(type, make_str("1"), 0);

+     ne->type_name = mm_strdup(type_name);
      ne->u.members = ECPGstruct_member_dup(rm);
      ne->struct_sizeof = struct_sizeof;

diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/preproc/type.h
pgsql.ooscur/src/interfaces/ecpg/preproc/type.h
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/preproc/type.h    2009-06-13 18:25:05.000000000 +0200
--- pgsql.ooscur/src/interfaces/ecpg/preproc/type.h    2009-08-14 20:11:34.000000000 +0200
*************** struct ECPGstruct_member
*** 17,22 ****
--- 17,23 ----
  struct ECPGtype
  {
      enum ECPGttype type;
+     char       *type_name;            /* For struct and union types it is the struct name */
      char       *size;            /* For array it is the number of elements. For
                                   * varchar it is the maxsize of the area. */
      char       *struct_sizeof;    /* For a struct this is the sizeof() type as
*************** void        ECPGmake_struct_member(char *, str
*** 36,42 ****
  struct ECPGtype *ECPGmake_simple_type(enum ECPGttype, char *, int);
  struct ECPGtype *ECPGmake_varchar_type(enum ECPGttype, long);
  struct ECPGtype *ECPGmake_array_type(struct ECPGtype *, char *);
! struct ECPGtype *ECPGmake_struct_type(struct ECPGstruct_member *, enum ECPGttype, char *);
  struct ECPGstruct_member *ECPGstruct_member_dup(struct ECPGstruct_member *);

  /* Frees a type. */
--- 37,43 ----
  struct ECPGtype *ECPGmake_simple_type(enum ECPGttype, char *, int);
  struct ECPGtype *ECPGmake_varchar_type(enum ECPGttype, long);
  struct ECPGtype *ECPGmake_array_type(struct ECPGtype *, char *);
! struct ECPGtype *ECPGmake_struct_type(struct ECPGstruct_member *, enum ECPGttype, char *, char *);
  struct ECPGstruct_member *ECPGstruct_member_dup(struct ECPGstruct_member *);

  /* Frees a type. */
*************** struct _include_path
*** 123,133 ****
--- 124,137 ----
  struct cursor
  {
      char       *name;
+     char       *function;
      char       *command;
      char       *connection;
      bool        opened;
      struct arguments *argsinsert;
+     struct arguments *argsinsert_oos;
      struct arguments *argsresult;
+     struct arguments *argsresult_oos;
      struct cursor *next;
  };

diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/preproc/variable.c
pgsql.ooscur/src/interfaces/ecpg/preproc/variable.c
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/preproc/variable.c    2009-08-09 15:42:06.000000000 +0200
--- pgsql.ooscur/src/interfaces/ecpg/preproc/variable.c    2009-08-14 10:16:01.000000000 +0200
*************** find_struct_member(char *name, char *str
*** 47,53 ****
                          return (new_variable(name,
ECPGmake_array_type(ECPGmake_simple_type(members->type->u.element->type,members->type->u.element->size,
members->type->u.element->lineno),members->type->size), brace_level)); 
                      case ECPGt_struct:
                      case ECPGt_union:
!                         return (new_variable(name, ECPGmake_struct_type(members->type->u.members,
members->type->type,members->type->struct_sizeof), brace_level)); 
                      default:
                          return (new_variable(name, ECPGmake_simple_type(members->type->type, members->type->size,
members->type->lineno),brace_level)); 
                  }
--- 47,53 ----
                          return (new_variable(name,
ECPGmake_array_type(ECPGmake_simple_type(members->type->u.element->type,members->type->u.element->size,
members->type->u.element->lineno),members->type->size), brace_level)); 
                      case ECPGt_struct:
                      case ECPGt_union:
!                         return (new_variable(name, ECPGmake_struct_type(members->type->u.members,
members->type->type,members->type->type_name, members->type->struct_sizeof), brace_level)); 
                      default:
                          return (new_variable(name, ECPGmake_simple_type(members->type->type, members->type->size,
members->type->lineno),brace_level)); 
                  }
*************** find_struct_member(char *name, char *str
*** 94,100 ****
                                  return (new_variable(name,
ECPGmake_array_type(ECPGmake_simple_type(members->type->u.element->u.element->type,
members->type->u.element->u.element->size,members->type->u.element->u.element->lineno),
members->type->u.element->size),brace_level)); 
                              case ECPGt_struct:
                              case ECPGt_union:
!                                 return (new_variable(name, ECPGmake_struct_type(members->type->u.element->u.members,
members->type->u.element->type,members->type->u.element->struct_sizeof), brace_level)); 
                              default:
                                  return (new_variable(name, ECPGmake_simple_type(members->type->u.element->type,
members->type->u.element->size,members->type->u.element->lineno), brace_level)); 
                          }
--- 94,100 ----
                                  return (new_variable(name,
ECPGmake_array_type(ECPGmake_simple_type(members->type->u.element->u.element->type,
members->type->u.element->u.element->size,members->type->u.element->u.element->lineno),
members->type->u.element->size),brace_level)); 
                              case ECPGt_struct:
                              case ECPGt_union:
!                                 return (new_variable(name, ECPGmake_struct_type(members->type->u.element->u.members,
members->type->u.element->type,members->type->u.element->type_name, members->type->u.element->struct_sizeof),
brace_level));
                              default:
                                  return (new_variable(name, ECPGmake_simple_type(members->type->u.element->type,
members->type->u.element->size,members->type->u.element->lineno), brace_level)); 
                          }
*************** find_variable(char *name)
*** 235,241 ****
                          return (new_variable(name,
ECPGmake_array_type(ECPGmake_simple_type(p->type->u.element->u.element->type,p->type->u.element->u.element->size,
p->type->u.element->u.element->lineno),p->type->u.element->size), p->brace_level)); 
                      case ECPGt_struct:
                      case ECPGt_union:
!                         return (new_variable(name, ECPGmake_struct_type(p->type->u.element->u.members,
p->type->u.element->type,p->type->u.element->struct_sizeof), p->brace_level)); 
                      default:
                          return (new_variable(name, ECPGmake_simple_type(p->type->u.element->type,
p->type->u.element->size,p->type->u.element->lineno), p->brace_level)); 
                  }
--- 235,241 ----
                          return (new_variable(name,
ECPGmake_array_type(ECPGmake_simple_type(p->type->u.element->u.element->type,p->type->u.element->u.element->size,
p->type->u.element->u.element->lineno),p->type->u.element->size), p->brace_level)); 
                      case ECPGt_struct:
                      case ECPGt_union:
!                         return (new_variable(name, ECPGmake_struct_type(p->type->u.element->u.members,
p->type->u.element->type,p->type->u.element->type_name, p->type->u.element->struct_sizeof), p->brace_level)); 
                      default:
                          return (new_variable(name, ECPGmake_simple_type(p->type->u.element->type,
p->type->u.element->size,p->type->u.element->lineno), p->brace_level)); 
                  }
diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/compat_informix/Makefile
pgsql.ooscur/src/interfaces/ecpg/test/compat_informix/Makefile
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/compat_informix/Makefile    2009-08-11 16:56:15.000000000 +0200
--- pgsql.ooscur/src/interfaces/ecpg/test/compat_informix/Makefile    2009-08-14 20:59:01.000000000 +0200
*************** TESTS = test_informix test_informix.c \
*** 14,19 ****
--- 14,21 ----
          test_informix2 test_informix2.c \
          cursor cursor.c \
          describe describe.c \
+         struct struct.c \
+         outofscope outofscope.c \
          dec_test dec_test.c \
          rfmtdate rfmtdate.c \
          rfmtlong rfmtlong.c \
*************** describe.c: describe.pgc ../regression.h
*** 38,43 ****
--- 40,51 ----
  sqlda.c: sqlda.pgc ../regression.h
      $(ECPG) -o $@ -I$(srcdir) $<

+ struct.c: struct.pgc ../regression.h
+     $(ECPG) -o $@ -I$(srcdir) $<
+
+ outofscope.c: outofscope.pgc ../regression.h
+     $(ECPG) -o $@ -I$(srcdir) $<
+
  dec_test.c: dec_test.pgc ../regression.h
      $(ECPG) -o $@ -I$(srcdir) $<

diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/compat_informix/outofscope.pgc
pgsql.ooscur/src/interfaces/ecpg/test/compat_informix/outofscope.pgc
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/compat_informix/outofscope.pgc    1970-01-01 01:00:00.000000000
+0100
--- pgsql.ooscur/src/interfaces/ecpg/test/compat_informix/outofscope.pgc    2009-08-14 21:32:41.000000000 +0200
***************
*** 0 ****
--- 1,122 ----
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+
+ exec sql include ../regression;
+
+ exec sql begin declare section;
+ exec sql include struct.h;
+ exec sql end declare section;
+
+ exec sql whenever sqlerror stop;
+
+ static void
+ get_var(MYTYPE **myvar0, MYNULLTYPE **mynullvar0)
+ {
+     exec sql begin declare section;
+     MYTYPE        *myvar = malloc(sizeof(MYTYPE));
+     MYNULLTYPE    *mynullvar = malloc(sizeof(MYNULLTYPE));
+     exec sql end declare section;
+
+     /* Test DECLARE ... SELECT ... INTO with pointers */
+
+     exec sql declare mycur cursor for select * INTO :myvar :mynullvar from a1;
+
+     if (sqlca.sqlcode != 0)
+         exit(1);
+
+     *myvar0 = myvar;
+     *mynullvar0 = mynullvar;
+ }
+
+ static void
+ open_cur(void)
+ {
+     exec sql open mycur;
+
+     if (sqlca.sqlcode != 0)
+         exit(1);
+ }
+
+ static void
+ get_record(void)
+ {
+     exec sql fetch mycur;
+
+     if (sqlca.sqlcode != 0 && sqlca.sqlcode != SQLNOTFOUND)
+         exit(1);
+ }
+
+ static void
+ close_cur(void)
+ {
+     exec sql close mycur;
+
+     if (sqlca.sqlcode != 0)
+         exit(1);
+ }
+
+ int
+ main (void)
+ {
+     MYTYPE        *myvar;
+     MYNULLTYPE    *mynullvar;
+
+     char msg[128];
+
+     ECPGdebug(1, stderr);
+
+     strcpy(msg, "connect");
+     exec sql connect to REGRESSDB1;
+
+     strcpy(msg, "set");
+     exec sql set datestyle to iso;
+
+     strcpy(msg, "create");
+     exec sql create table a1(id serial primary key, t text, d1 numeric, d2 float8, c character(10));
+
+     strcpy(msg, "insert");
+     exec sql insert into a1(id, t, d1, d2, c) values (default, 'a', 1.0, 2, 'a');
+     exec sql insert into a1(id, t, d1, d2, c) values (default, null, null, null, null);
+     exec sql insert into a1(id, t, d1, d2, c) values (default, '"a"', -1.0, 'nan'::float8, 'a');
+     exec sql insert into a1(id, t, d1, d2, c) values (default, 'b', 2.0, 3, 'b');
+
+     strcpy(msg, "commit");
+     exec sql commit;
+
+     /* Test out-of-scope DECLARE/OPEN/FETCH/CLOSE */
+
+     get_var(&myvar, &mynullvar);
+     open_cur();
+
+     exec sql whenever not found do break;
+
+     while (1)
+     {
+         memset(myvar, 0, sizeof(MYTYPE));
+         get_record();
+         if (sqlca.sqlcode == SQLNOTFOUND)
+             break;
+         printf("id=%d%s t='%s'%s d1=%lf%s d2=%lf%s c = '%s'%s\n",
+             myvar->id, mynullvar->id ? " (NULL)" : "",
+             myvar->t, mynullvar->t ? " (NULL)" : "",
+             myvar->d1, mynullvar->d1 ? " (NULL)" : "",
+             myvar->d2, mynullvar->d2 ? " (NULL)" : "",
+             myvar->c, mynullvar->c ? " (NULL)" : "");
+     }
+
+     close_cur();
+
+     /* End test */
+
+     strcpy(msg, "drop");
+     exec sql drop table a1;
+
+     strcpy(msg, "commit");
+     exec sql commit;
+
+     strcpy(msg, "disconnect");
+     exec sql disconnect;
+
+     return (0);
+ }
diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/compat_informix/struct.h
pgsql.ooscur/src/interfaces/ecpg/test/compat_informix/struct.h
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/compat_informix/struct.h    1970-01-01 01:00:00.000000000 +0100
--- pgsql.ooscur/src/interfaces/ecpg/test/compat_informix/struct.h    2009-08-14 20:34:35.000000000 +0200
***************
*** 0 ****
--- 1,18 ----
+
+ struct mytype {
+     int    id;
+     char    t[64];
+     double    d1; /* dec_t */
+     double    d2;
+     char    c[30];
+ };
+ typedef struct mytype MYTYPE;
+
+ struct mynulltype {
+     int    id;
+     int    t;
+     int    d1;
+     int    d2;
+     int    c;
+ };
+ typedef struct mynulltype MYNULLTYPE;
diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/compat_informix/struct.pgc
pgsql.ooscur/src/interfaces/ecpg/test/compat_informix/struct.pgc
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/compat_informix/struct.pgc    1970-01-01 01:00:00.000000000
+0100
--- pgsql.ooscur/src/interfaces/ecpg/test/compat_informix/struct.pgc    2009-08-14 21:26:31.000000000 +0200
***************
*** 0 ****
--- 1,76 ----
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+
+ exec sql include ../regression;
+
+ exec sql begin declare section;
+ exec sql include struct.h;
+ exec sql end declare section;
+
+ exec sql whenever sqlerror stop;
+
+ int
+ main (void)
+ {
+     exec sql begin declare section;
+     MYTYPE        myvar;
+     MYNULLTYPE    mynullvar;
+     exec sql end declare section;
+
+     char msg[128];
+
+     ECPGdebug(1, stderr);
+
+     strcpy(msg, "connect");
+     exec sql connect to REGRESSDB1;
+
+     strcpy(msg, "set");
+     exec sql set datestyle to iso;
+
+     strcpy(msg, "create");
+     exec sql create table a1(id serial primary key, t text, d1 numeric, d2 float8, c character(10));
+
+     strcpy(msg, "insert");
+     exec sql insert into a1(id, t, d1, d2, c) values (default, 'a', 1.0, 2, 'a');
+     exec sql insert into a1(id, t, d1, d2, c) values (default, null, null, null, null);
+     exec sql insert into a1(id, t, d1, d2, c) values (default, '"a"', -1.0, 'nan'::float8, 'a');
+     exec sql insert into a1(id, t, d1, d2, c) values (default, 'b', 2.0, 3, 'b');
+
+     strcpy(msg, "commit");
+     exec sql commit;
+
+     /* Test DECLARE ... SELECT ... INTO with struct type */
+
+     exec sql declare mycur cursor for select * into :myvar :mynullvar from a1;
+     exec sql open mycur;
+
+     exec sql whenever not found do break;
+
+     while (1)
+     {
+         memset(&myvar, 0, sizeof(myvar));
+         exec sql fetch mycur;
+         printf("id=%d%s t='%s'%s d1=%lf%s d2=%lf%s c = '%s'%s\n",
+             myvar.id, mynullvar.id ? " (NULL)" : "",
+             myvar.t, mynullvar.t ? " (NULL)" : "",
+             myvar.d1, mynullvar.d1 ? " (NULL)" : "",
+             myvar.d2, mynullvar.d2 ? " (NULL)" : "",
+             myvar.c, mynullvar.c ? " (NULL)" : "");
+     }
+
+     exec sql close mycur;
+
+     /* End test */
+
+     strcpy(msg, "drop");
+     exec sql drop table a1;
+
+     strcpy(msg, "commit");
+     exec sql commit;
+
+     strcpy(msg, "disconnect");
+     exec sql disconnect;
+
+     return (0);
+ }
diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/ecpg_schedule
pgsql.ooscur/src/interfaces/ecpg/test/ecpg_schedule
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/ecpg_schedule    2009-08-11 17:00:27.000000000 +0200
--- pgsql.ooscur/src/interfaces/ecpg/test/ecpg_schedule    2009-08-14 20:59:24.000000000 +0200
*************** test: compat_informix/rnull
*** 6,11 ****
--- 6,13 ----
  test: compat_informix/cursor
  test: compat_informix/sqlda
  test: compat_informix/describe
+ test: compat_informix/struct
+ test: compat_informix/outofscope
  test: compat_informix/test_informix
  test: compat_informix/test_informix2
  test: connect/test2
diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/ecpg_schedule_tcp
pgsql.ooscur/src/interfaces/ecpg/test/ecpg_schedule_tcp
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/ecpg_schedule_tcp    2009-08-11 17:00:33.000000000 +0200
--- pgsql.ooscur/src/interfaces/ecpg/test/ecpg_schedule_tcp    2009-08-14 20:59:24.000000000 +0200
*************** test: compat_informix/rnull
*** 6,11 ****
--- 6,13 ----
  test: compat_informix/cursor
  test: compat_informix/sqlda
  test: compat_informix/describe
+ test: compat_informix/struct
+ test: compat_informix/outofscope
  test: compat_informix/test_informix
  test: compat_informix/test_informix2
  test: connect/test2
diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/expected/compat_informix-cursor.c
pgsql.ooscur/src/interfaces/ecpg/test/expected/compat_informix-cursor.c
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/expected/compat_informix-cursor.c    2009-08-13
17:00:25.000000000+0200 
--- pgsql.ooscur/src/interfaces/ecpg/test/expected/compat_informix-cursor.c    2009-08-14 21:30:57.000000000 +0200
*************** if (sqlca.sqlcode < 0) exit (1);}
*** 162,168 ****

      strcpy(msg, "open");
      { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "declare $0 cursor for select id , t from t1",
!     ECPGt_char,&(*( char  *)(ECPG_informix_get_var( 0))),(long)0,(long)1,(1)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
  #line 62 "cursor.pgc"

--- 162,168 ----

      strcpy(msg, "open");
      { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "declare $0 cursor for select id , t from t1",
!     ECPGt_char,&(curname1),(long)0,(long)1,(1)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
  #line 62 "cursor.pgc"

*************** if (sqlca.sqlcode < 0) exit (1);}
*** 298,308 ****

      strcpy(msg, "open");
      { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "declare $0 cursor for select id , t from t1",
!     ECPGt_char,&(*( char  *)(ECPG_informix_get_var( 3))),(long)0,(long)1,(1)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT,
!     ECPGt_int,&(*( int  *)(ECPG_informix_get_var( 2))),(long)1,(long)1,sizeof(int),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
!     ECPGt_char,(( char  *)(ECPG_informix_get_var( 1))),(long)64,(long)1,(64)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
  #line 103 "cursor.pgc"

--- 298,308 ----

      strcpy(msg, "open");
      { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "declare $0 cursor for select id , t from t1",
!     ECPGt_char,&(curname2),(long)0,(long)1,(1)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT,
!     ECPGt_int,&(id),(long)1,(long)1,sizeof(int),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
!     ECPGt_char,(t),(long)64,(long)1,(64)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
  #line 103 "cursor.pgc"

*************** if (sqlca.sqlcode < 0) exit (1);}
*** 314,322 ****
      { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch from $0",
      ECPGt_char,&(curname2),(long)0,(long)1,(1)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT,
!     ECPGt_int,&(*( int  *)(ECPG_informix_get_var( 2))),(long)1,(long)1,sizeof(int),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
!     ECPGt_char,(( char  *)(ECPG_informix_get_var( 1))),(long)64,(long)1,(64)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
  #line 106 "cursor.pgc"

--- 314,322 ----
      { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch from $0",
      ECPGt_char,&(curname2),(long)0,(long)1,(1)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT,
!     ECPGt_int,&(id),(long)1,(long)1,sizeof(int),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
!     ECPGt_char,(t),(long)64,(long)1,(64)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
  #line 106 "cursor.pgc"

*************** if (sqlca.sqlcode < 0) exit (1);}
*** 329,337 ****
      { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch $0",
      ECPGt_char,&(curname2),(long)0,(long)1,(1)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT,
!     ECPGt_int,&(*( int  *)(ECPG_informix_get_var( 2))),(long)1,(long)1,sizeof(int),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
!     ECPGt_char,(( char  *)(ECPG_informix_get_var( 1))),(long)64,(long)1,(64)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
  #line 110 "cursor.pgc"

--- 329,337 ----
      { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch $0",
      ECPGt_char,&(curname2),(long)0,(long)1,(1)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT,
!     ECPGt_int,&(id),(long)1,(long)1,sizeof(int),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
!     ECPGt_char,(t),(long)64,(long)1,(64)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
  #line 110 "cursor.pgc"

*************** if (sqlca.sqlcode < 0) exit (1);}
*** 344,352 ****
      { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch 1 from $0",
      ECPGt_char,&(curname2),(long)0,(long)1,(1)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT,
!     ECPGt_int,&(*( int  *)(ECPG_informix_get_var( 2))),(long)1,(long)1,sizeof(int),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
!     ECPGt_char,(( char  *)(ECPG_informix_get_var( 1))),(long)64,(long)1,(64)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
  #line 114 "cursor.pgc"

--- 344,352 ----
      { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch 1 from $0",
      ECPGt_char,&(curname2),(long)0,(long)1,(1)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT,
!     ECPGt_int,&(id),(long)1,(long)1,sizeof(int),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
!     ECPGt_char,(t),(long)64,(long)1,(64)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
  #line 114 "cursor.pgc"

*************** if (sqlca.sqlcode < 0) exit (1);}
*** 362,370 ****
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
      ECPGt_char,&(curname2),(long)0,(long)1,(1)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT,
!     ECPGt_int,&(*( int  *)(ECPG_informix_get_var( 2))),(long)1,(long)1,sizeof(int),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
!     ECPGt_char,(( char  *)(ECPG_informix_get_var( 1))),(long)64,(long)1,(64)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
  #line 119 "cursor.pgc"

--- 362,370 ----
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
      ECPGt_char,&(curname2),(long)0,(long)1,(1)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT,
!     ECPGt_int,&(id),(long)1,(long)1,sizeof(int),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
!     ECPGt_char,(t),(long)64,(long)1,(64)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
  #line 119 "cursor.pgc"

*************** if (sqlca.sqlcode < 0) exit (1);}
*** 377,385 ****
      { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "move absolute 0 $0",
      ECPGt_char,&(curname2),(long)0,(long)1,(1)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT,
!     ECPGt_int,&(*( int  *)(ECPG_informix_get_var( 2))),(long)1,(long)1,sizeof(int),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
!     ECPGt_char,(( char  *)(ECPG_informix_get_var( 1))),(long)64,(long)1,(64)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
  #line 123 "cursor.pgc"

--- 377,385 ----
      { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "move absolute 0 $0",
      ECPGt_char,&(curname2),(long)0,(long)1,(1)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT,
!     ECPGt_int,&(id),(long)1,(long)1,sizeof(int),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
!     ECPGt_char,(t),(long)64,(long)1,(64)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
  #line 123 "cursor.pgc"

*************** if (sqlca.sqlcode < 0) exit (1);}
*** 391,399 ****
      { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch 1 $0",
      ECPGt_char,&(curname2),(long)0,(long)1,(1)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT,
!     ECPGt_int,&(*( int  *)(ECPG_informix_get_var( 2))),(long)1,(long)1,sizeof(int),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
!     ECPGt_char,(( char  *)(ECPG_informix_get_var( 1))),(long)64,(long)1,(64)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
  #line 126 "cursor.pgc"

--- 391,399 ----
      { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch 1 $0",
      ECPGt_char,&(curname2),(long)0,(long)1,(1)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT,
!     ECPGt_int,&(id),(long)1,(long)1,sizeof(int),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
!     ECPGt_char,(t),(long)64,(long)1,(64)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
  #line 126 "cursor.pgc"

*************** if (sqlca.sqlcode < 0) exit (1);}
*** 409,417 ****
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
      ECPGt_char,&(curname2),(long)0,(long)1,(1)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT,
!     ECPGt_int,&(*( int  *)(ECPG_informix_get_var( 2))),(long)1,(long)1,sizeof(int),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
!     ECPGt_char,(( char  *)(ECPG_informix_get_var( 1))),(long)64,(long)1,(64)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
  #line 131 "cursor.pgc"

--- 409,417 ----
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
      ECPGt_char,&(curname2),(long)0,(long)1,(1)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT,
!     ECPGt_int,&(id),(long)1,(long)1,sizeof(int),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
!     ECPGt_char,(t),(long)64,(long)1,(64)*sizeof(char),
      ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
  #line 131 "cursor.pgc"

diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/expected/compat_informix-outofscope.c
pgsql.ooscur/src/interfaces/ecpg/test/expected/compat_informix-outofscope.c
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/expected/compat_informix-outofscope.c    1970-01-01
01:00:00.000000000+0100 
--- pgsql.ooscur/src/interfaces/ecpg/test/expected/compat_informix-outofscope.c    2009-08-14 21:33:31.000000000 +0200
***************
*** 0 ****
--- 1,308 ----
+ /* Processed by ecpg (regression mode) */
+ /* These include files are added by the preprocessor */
+ #include <ecpglib.h>
+ #include <ecpgerrno.h>
+ #include <sqlca.h>
+ /* Needed for informix compatibility */
+ #include <ecpg_informix.h>
+ /* End of automatic include section */
+ #define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+ #line 1 "outofscope.pgc"
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+
+
+ #line 1 "regression.h"
+
+
+
+
+
+
+ #line 5 "outofscope.pgc"
+
+
+ /* exec sql begin declare section */
+
+ #line 1 "struct.h"
+
+
+
+
+          /* dec_t */
+
+
+
+    typedef struct mytype  MYTYPE ;
+
+ #line 9 "struct.h"
+
+
+
+
+
+
+
+
+
+    typedef struct mynulltype  MYNULLTYPE ;
+
+ #line 18 "struct.h"
+
+
+ #line 8 "outofscope.pgc"
+
+ struct mytype {
+ #line 3 "struct.h"
+  int id ;
+
+ #line 4 "struct.h"
+  char t [ 64 ] ;
+
+ #line 5 "struct.h"
+  double d1 ;
+
+ #line 6 "struct.h"
+  double d2 ;
+
+ #line 7 "struct.h"
+  char c [ 30 ] ;
+  } ; struct mynulltype {
+ #line 12 "struct.h"
+  int id ;
+
+ #line 13 "struct.h"
+  int t ;
+
+ #line 14 "struct.h"
+  int d1 ;
+
+ #line 15 "struct.h"
+  int d2 ;
+
+ #line 16 "struct.h"
+  int c ;
+  } ;/* exec sql end declare section */
+ #line 9 "outofscope.pgc"
+
+
+ /* exec sql whenever sqlerror  stop ; */
+ #line 11 "outofscope.pgc"
+
+
+ static void
+ get_var(MYTYPE **myvar0, MYNULLTYPE **mynullvar0)
+ {
+     /* exec sql begin declare section */
+
+
+
+ #line 17 "outofscope.pgc"
+  MYTYPE * myvar = malloc ( sizeof ( MYTYPE ) ) ;
+
+ #line 18 "outofscope.pgc"
+  MYNULLTYPE * mynullvar = malloc ( sizeof ( MYNULLTYPE ) ) ;
+ /* exec sql end declare section */
+ #line 19 "outofscope.pgc"
+
+
+     /* Test DECLARE ... SELECT ... INTO with pointers */
+
+     ECPG_informix_set_var( 0, ( myvar ), __LINE__);\
+  ECPG_informix_set_var( 1, ( mynullvar ), __LINE__);\
+  ECPGreset_sqlca(__LINE__, NULL); /* declare mycur cursor for select * from a1 */
+ #line 23 "outofscope.pgc"
+
+
+     if (sqlca.sqlcode != 0)
+         exit(1);
+
+     *myvar0 = myvar;
+     *mynullvar0 = mynullvar;
+ }
+
+ static void
+ open_cur(void)
+ {
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "declare mycur cursor for select * from a1", ECPGt_EOIT,
+     ECPGt_int,&((*( MYTYPE  *)(ECPG_informix_get_var( 0))).id),(long)1,(long)1,sizeof(int),
+     ECPGt_int,&((*( MYNULLTYPE  *)(ECPG_informix_get_var( 1))).id),(long)1,(long)1,sizeof(int),
+     ECPGt_char,&((*( MYTYPE  *)(ECPG_informix_get_var( 0))).t),(long)64,(long)1,(64)*sizeof(char),
+     ECPGt_int,&((*( MYNULLTYPE  *)(ECPG_informix_get_var( 1))).t),(long)1,(long)1,sizeof(int),
+     ECPGt_double,&((*( MYTYPE  *)(ECPG_informix_get_var( 0))).d1),(long)1,(long)1,sizeof(double),
+     ECPGt_int,&((*( MYNULLTYPE  *)(ECPG_informix_get_var( 1))).d1),(long)1,(long)1,sizeof(int),
+     ECPGt_double,&((*( MYTYPE  *)(ECPG_informix_get_var( 0))).d2),(long)1,(long)1,sizeof(double),
+     ECPGt_int,&((*( MYNULLTYPE  *)(ECPG_informix_get_var( 1))).d2),(long)1,(long)1,sizeof(int),
+     ECPGt_char,&((*( MYTYPE  *)(ECPG_informix_get_var( 0))).c),(long)30,(long)1,(30)*sizeof(char),
+     ECPGt_int,&((*( MYNULLTYPE  *)(ECPG_informix_get_var( 1))).c),(long)1,(long)1,sizeof(int), ECPGt_EORT);
+ #line 35 "outofscope.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 35 "outofscope.pgc"
+
+
+     if (sqlca.sqlcode != 0)
+         exit(1);
+ }
+
+ static void
+ get_record(void)
+ {
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch mycur", ECPGt_EOIT,
+     ECPGt_int,&((*( MYTYPE  *)(ECPG_informix_get_var( 0))).id),(long)1,(long)1,sizeof(int),
+     ECPGt_int,&((*( MYNULLTYPE  *)(ECPG_informix_get_var( 1))).id),(long)1,(long)1,sizeof(int),
+     ECPGt_char,&((*( MYTYPE  *)(ECPG_informix_get_var( 0))).t),(long)64,(long)1,(64)*sizeof(char),
+     ECPGt_int,&((*( MYNULLTYPE  *)(ECPG_informix_get_var( 1))).t),(long)1,(long)1,sizeof(int),
+     ECPGt_double,&((*( MYTYPE  *)(ECPG_informix_get_var( 0))).d1),(long)1,(long)1,sizeof(double),
+     ECPGt_int,&((*( MYNULLTYPE  *)(ECPG_informix_get_var( 1))).d1),(long)1,(long)1,sizeof(int),
+     ECPGt_double,&((*( MYTYPE  *)(ECPG_informix_get_var( 0))).d2),(long)1,(long)1,sizeof(double),
+     ECPGt_int,&((*( MYNULLTYPE  *)(ECPG_informix_get_var( 1))).d2),(long)1,(long)1,sizeof(int),
+     ECPGt_char,&((*( MYTYPE  *)(ECPG_informix_get_var( 0))).c),(long)30,(long)1,(30)*sizeof(char),
+     ECPGt_int,&((*( MYNULLTYPE  *)(ECPG_informix_get_var( 1))).c),(long)1,(long)1,sizeof(int), ECPGt_EORT);
+ #line 44 "outofscope.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 44 "outofscope.pgc"
+
+
+     if (sqlca.sqlcode != 0 && sqlca.sqlcode != SQLNOTFOUND)
+         exit(1);
+ }
+
+ static void
+ close_cur(void)
+ {
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "close mycur", ECPGt_EOIT, ECPGt_EORT);
+ #line 53 "outofscope.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 53 "outofscope.pgc"
+
+
+     if (sqlca.sqlcode != 0)
+         exit(1);
+ }
+
+ int
+ main (void)
+ {
+     MYTYPE        *myvar;
+     MYNULLTYPE    *mynullvar;
+
+     char msg[128];
+
+     ECPGdebug(1, stderr);
+
+     strcpy(msg, "connect");
+     { ECPGconnect(__LINE__, 1, "regress1" , NULL, NULL , NULL, 0);
+ #line 70 "outofscope.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 70 "outofscope.pgc"
+
+
+     strcpy(msg, "set");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "set datestyle to iso", ECPGt_EOIT, ECPGt_EORT);
+ #line 73 "outofscope.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 73 "outofscope.pgc"
+
+
+     strcpy(msg, "create");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "create table a1 ( id serial primary key , t text , d1 numeric ,
d2float8 , c character ( 10 ) )", ECPGt_EOIT, ECPGt_EORT); 
+ #line 76 "outofscope.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 76 "outofscope.pgc"
+
+
+     strcpy(msg, "insert");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "insert into a1 ( id , t , d1 , d2 , c ) values ( default , 'a'
,1.0 , 2 , 'a' )", ECPGt_EOIT, ECPGt_EORT); 
+ #line 79 "outofscope.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 79 "outofscope.pgc"
+
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "insert into a1 ( id , t , d1 , d2 , c ) values ( default , null
,null , null , null )", ECPGt_EOIT, ECPGt_EORT); 
+ #line 80 "outofscope.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 80 "outofscope.pgc"
+
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "insert into a1 ( id , t , d1 , d2 , c ) values ( default ,
'\"a\"', - 1.0 , 'nan' :: float8 , 'a' )", ECPGt_EOIT, ECPGt_EORT); 
+ #line 81 "outofscope.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 81 "outofscope.pgc"
+
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "insert into a1 ( id , t , d1 , d2 , c ) values ( default , 'b'
,2.0 , 3 , 'b' )", ECPGt_EOIT, ECPGt_EORT); 
+ #line 82 "outofscope.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 82 "outofscope.pgc"
+
+
+     strcpy(msg, "commit");
+     { ECPGtrans(__LINE__, NULL, "commit");
+ #line 85 "outofscope.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 85 "outofscope.pgc"
+
+
+     /* Test out-of-scope DECLARE/OPEN/FETCH/CLOSE */
+
+     get_var(&myvar, &mynullvar);
+     open_cur();
+
+     /* exec sql whenever not found  break ; */
+ #line 92 "outofscope.pgc"
+
+
+     while (1)
+     {
+         memset(myvar, 0, sizeof(MYTYPE));
+         get_record();
+         if (sqlca.sqlcode == SQLNOTFOUND)
+             break;
+         printf("id=%d%s t='%s'%s d1=%lf%s d2=%lf%s c = '%s'%s\n",
+             myvar->id, mynullvar->id ? " (NULL)" : "",
+             myvar->t, mynullvar->t ? " (NULL)" : "",
+             myvar->d1, mynullvar->d1 ? " (NULL)" : "",
+             myvar->d2, mynullvar->d2 ? " (NULL)" : "",
+             myvar->c, mynullvar->c ? " (NULL)" : "");
+     }
+
+     close_cur();
+
+     /* End test */
+
+     strcpy(msg, "drop");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "drop table a1", ECPGt_EOIT, ECPGt_EORT);
+ #line 113 "outofscope.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 113 "outofscope.pgc"
+
+
+     strcpy(msg, "commit");
+     { ECPGtrans(__LINE__, NULL, "commit");
+ #line 116 "outofscope.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 116 "outofscope.pgc"
+
+
+     strcpy(msg, "disconnect");
+     { ECPGdisconnect(__LINE__, "CURRENT");
+ #line 119 "outofscope.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 119 "outofscope.pgc"
+
+
+     return (0);
+ }
diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/expected/compat_informix-outofscope.stderr
pgsql.ooscur/src/interfaces/ecpg/test/expected/compat_informix-outofscope.stderr
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/expected/compat_informix-outofscope.stderr    1970-01-01
01:00:00.000000000+0100 
--- pgsql.ooscur/src/interfaces/ecpg/test/expected/compat_informix-outofscope.stderr    2009-08-14 21:33:31.000000000
+0200
***************
*** 0 ****
--- 1,136 ----
+ [NO_PID]: ECPGdebug: set to 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGconnect: opening database regress1 on <DEFAULT> port <DEFAULT>
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 73: query: set datestyle to iso; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 73: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 73: OK: SET
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 76: query: create table a1 ( id serial primary key , t text , d1 numeric , d2 float8 ,
ccharacter ( 10 ) ); with 0 parameter(s) on connection regress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 76: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 76: OK: CREATE TABLE
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 79: query: insert into a1 ( id , t , d1 , d2 , c ) values ( default , 'a' , 1.0 , 2 ,
'a'); with 0 parameter(s) on connection regress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 79: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 79: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 80: query: insert into a1 ( id , t , d1 , d2 , c ) values ( default , null , null ,
null, null ); with 0 parameter(s) on connection regress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 80: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 80: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 81: query: insert into a1 ( id , t , d1 , d2 , c ) values ( default , '"a"' , - 1.0 ,
'nan':: float8 , 'a' ); with 0 parameter(s) on connection regress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 81: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 81: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 82: query: insert into a1 ( id , t , d1 , d2 , c ) values ( default , 'b' , 2.0 , 3 ,
'b'); with 0 parameter(s) on connection regress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 82: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 82: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGtrans on line 85: action "commit"; connection "regress1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 35: query: declare mycur cursor for select * from a1; with 0 parameter(s) on
connectionregress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 35: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 35: OK: DECLARE CURSOR
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 44: query: fetch mycur; with 0 parameter(s) on connection regress1
+ [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_execute on line 44: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 44: RESULT: 1 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 44: RESULT: a offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 44: RESULT: 1.0 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 44: RESULT: 2 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 44: RESULT: a          offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 44: query: fetch mycur; with 0 parameter(s) on connection regress1
+ [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_execute on line 44: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 44: RESULT: 2 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 44: RESULT:  offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 44: RESULT:  offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 44: RESULT:  offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 44: RESULT:  offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 44: query: fetch mycur; with 0 parameter(s) on connection regress1
+ [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_execute on line 44: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 44: RESULT: 3 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 44: RESULT: "a" offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 44: RESULT: -1.0 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 44: RESULT: NaN offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 44: RESULT: a          offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 44: query: fetch mycur; with 0 parameter(s) on connection regress1
+ [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_execute on line 44: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 44: RESULT: 4 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 44: RESULT: b offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 44: RESULT: 2.0 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 44: RESULT: 3 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 44: RESULT: b          offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 44: query: fetch mycur; with 0 parameter(s) on connection regress1
+ [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_execute on line 44: correctly got 0 tuples with 5 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 53: query: close mycur; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 53: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 53: OK: CLOSE CURSOR
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 113: query: drop table a1; with 0 parameter(s) on connection regress1
+ [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_execute on line 113: OK: DROP TABLE
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGtrans on line 116: action "commit"; connection "regress1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_finish: connection regress1 closed
+ [NO_PID]: sqlca: code: 0, state: 00000
diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/expected/compat_informix-outofscope.stdout
pgsql.ooscur/src/interfaces/ecpg/test/expected/compat_informix-outofscope.stdout
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/expected/compat_informix-outofscope.stdout    1970-01-01
01:00:00.000000000+0100 
--- pgsql.ooscur/src/interfaces/ecpg/test/expected/compat_informix-outofscope.stdout    2009-08-14 21:33:31.000000000
+0200
***************
*** 0 ****
--- 1,4 ----
+ id=1 t='a' d1=1.000000 d2=2.000000 c = 'a         '
+ id=2 t='' (NULL) d1=0.000000 (NULL) d2=0.000000 (NULL) c = '' (NULL)
+ id=3 t='"a"' d1=-1.000000 d2=nan c = 'a         '
+ id=4 t='b' d1=2.000000 d2=3.000000 c = 'b         '
diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/expected/compat_informix-struct.c
pgsql.ooscur/src/interfaces/ecpg/test/expected/compat_informix-struct.c
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/expected/compat_informix-struct.c    1970-01-01
01:00:00.000000000+0100 
--- pgsql.ooscur/src/interfaces/ecpg/test/expected/compat_informix-struct.c    2009-08-14 21:28:18.000000000 +0200
***************
*** 0 ****
--- 1,265 ----
+ /* Processed by ecpg (regression mode) */
+ /* These include files are added by the preprocessor */
+ #include <ecpglib.h>
+ #include <ecpgerrno.h>
+ #include <sqlca.h>
+ /* Needed for informix compatibility */
+ #include <ecpg_informix.h>
+ /* End of automatic include section */
+ #define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+ #line 1 "struct.pgc"
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+
+
+ #line 1 "regression.h"
+
+
+
+
+
+
+ #line 5 "struct.pgc"
+
+
+ /* exec sql begin declare section */
+
+ #line 1 "struct.h"
+
+
+
+
+          /* dec_t */
+
+
+
+    typedef struct mytype  MYTYPE ;
+
+ #line 9 "struct.h"
+
+
+
+
+
+
+
+
+
+    typedef struct mynulltype  MYNULLTYPE ;
+
+ #line 18 "struct.h"
+
+
+ #line 8 "struct.pgc"
+
+ struct mytype {
+ #line 3 "struct.h"
+  int id ;
+
+ #line 4 "struct.h"
+  char t [ 64 ] ;
+
+ #line 5 "struct.h"
+  double d1 ;
+
+ #line 6 "struct.h"
+  double d2 ;
+
+ #line 7 "struct.h"
+  char c [ 30 ] ;
+  } ; struct mynulltype {
+ #line 12 "struct.h"
+  int id ;
+
+ #line 13 "struct.h"
+  int t ;
+
+ #line 14 "struct.h"
+  int d1 ;
+
+ #line 15 "struct.h"
+  int d2 ;
+
+ #line 16 "struct.h"
+  int c ;
+  } ;/* exec sql end declare section */
+ #line 9 "struct.pgc"
+
+
+ /* exec sql whenever sqlerror  stop ; */
+ #line 11 "struct.pgc"
+
+
+ int
+ main (void)
+ {
+     /* exec sql begin declare section */
+
+
+
+ #line 17 "struct.pgc"
+  MYTYPE myvar ;
+
+ #line 18 "struct.pgc"
+  MYNULLTYPE mynullvar ;
+ /* exec sql end declare section */
+ #line 19 "struct.pgc"
+
+
+     char msg[128];
+
+     ECPGdebug(1, stderr);
+
+     strcpy(msg, "connect");
+     { ECPGconnect(__LINE__, 1, "regress1" , NULL, NULL , NULL, 0);
+ #line 26 "struct.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 26 "struct.pgc"
+
+
+     strcpy(msg, "set");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "set datestyle to iso", ECPGt_EOIT, ECPGt_EORT);
+ #line 29 "struct.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 29 "struct.pgc"
+
+
+     strcpy(msg, "create");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "create table a1 ( id serial primary key , t text , d1 numeric ,
d2float8 , c character ( 10 ) )", ECPGt_EOIT, ECPGt_EORT); 
+ #line 32 "struct.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 32 "struct.pgc"
+
+
+     strcpy(msg, "insert");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "insert into a1 ( id , t , d1 , d2 , c ) values ( default , 'a'
,1.0 , 2 , 'a' )", ECPGt_EOIT, ECPGt_EORT); 
+ #line 35 "struct.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 35 "struct.pgc"
+
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "insert into a1 ( id , t , d1 , d2 , c ) values ( default , null
,null , null , null )", ECPGt_EOIT, ECPGt_EORT); 
+ #line 36 "struct.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 36 "struct.pgc"
+
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "insert into a1 ( id , t , d1 , d2 , c ) values ( default ,
'\"a\"', - 1.0 , 'nan' :: float8 , 'a' )", ECPGt_EOIT, ECPGt_EORT); 
+ #line 37 "struct.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 37 "struct.pgc"
+
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "insert into a1 ( id , t , d1 , d2 , c ) values ( default , 'b'
,2.0 , 3 , 'b' )", ECPGt_EOIT, ECPGt_EORT); 
+ #line 38 "struct.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 38 "struct.pgc"
+
+
+     strcpy(msg, "commit");
+     { ECPGtrans(__LINE__, NULL, "commit");
+ #line 41 "struct.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 41 "struct.pgc"
+
+
+     /* Test DECLARE ... SELECT ... INTO with struct type */
+
+     ECPG_informix_set_var( 0, &( myvar ), __LINE__);\
+  ECPG_informix_set_var( 1, &( mynullvar ), __LINE__);\
+  ECPGreset_sqlca(__LINE__, NULL); /* declare mycur cursor for select * from a1 */
+ #line 45 "struct.pgc"
+
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "declare mycur cursor for select * from a1", ECPGt_EOIT,
+     ECPGt_int,&(myvar.id),(long)1,(long)1,sizeof(int),
+     ECPGt_int,&(mynullvar.id),(long)1,(long)1,sizeof(int),
+     ECPGt_char,&(myvar.t),(long)64,(long)1,(64)*sizeof(char),
+     ECPGt_int,&(mynullvar.t),(long)1,(long)1,sizeof(int),
+     ECPGt_double,&(myvar.d1),(long)1,(long)1,sizeof(double),
+     ECPGt_int,&(mynullvar.d1),(long)1,(long)1,sizeof(int),
+     ECPGt_double,&(myvar.d2),(long)1,(long)1,sizeof(double),
+     ECPGt_int,&(mynullvar.d2),(long)1,(long)1,sizeof(int),
+     ECPGt_char,&(myvar.c),(long)30,(long)1,(30)*sizeof(char),
+     ECPGt_int,&(mynullvar.c),(long)1,(long)1,sizeof(int), ECPGt_EORT);
+ #line 46 "struct.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 46 "struct.pgc"
+
+
+     /* exec sql whenever not found  break ; */
+ #line 48 "struct.pgc"
+
+
+     while (1)
+     {
+         memset(&myvar, 0, sizeof(myvar));
+         { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch mycur", ECPGt_EOIT,
+     ECPGt_int,&(myvar.id),(long)1,(long)1,sizeof(int),
+     ECPGt_int,&(mynullvar.id),(long)1,(long)1,sizeof(int),
+     ECPGt_char,&(myvar.t),(long)64,(long)1,(64)*sizeof(char),
+     ECPGt_int,&(mynullvar.t),(long)1,(long)1,sizeof(int),
+     ECPGt_double,&(myvar.d1),(long)1,(long)1,sizeof(double),
+     ECPGt_int,&(mynullvar.d1),(long)1,(long)1,sizeof(int),
+     ECPGt_double,&(myvar.d2),(long)1,(long)1,sizeof(double),
+     ECPGt_int,&(mynullvar.d2),(long)1,(long)1,sizeof(int),
+     ECPGt_char,&(myvar.c),(long)30,(long)1,(30)*sizeof(char),
+     ECPGt_int,&(mynullvar.c),(long)1,(long)1,sizeof(int), ECPGt_EORT);
+ #line 53 "struct.pgc"
+
+ if (sqlca.sqlcode == ECPG_NOT_FOUND) break;
+ #line 53 "struct.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 53 "struct.pgc"
+
+         printf("id=%d%s t='%s'%s d1=%lf%s d2=%lf%s c = '%s'%s\n",
+             myvar.id, mynullvar.id ? " (NULL)" : "",
+             myvar.t, mynullvar.t ? " (NULL)" : "",
+             myvar.d1, mynullvar.d1 ? " (NULL)" : "",
+             myvar.d2, mynullvar.d2 ? " (NULL)" : "",
+             myvar.c, mynullvar.c ? " (NULL)" : "");
+     }
+
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "close mycur", ECPGt_EOIT, ECPGt_EORT);
+ #line 62 "struct.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 62 "struct.pgc"
+
+
+     /* End test */
+
+     strcpy(msg, "drop");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "drop table a1", ECPGt_EOIT, ECPGt_EORT);
+ #line 67 "struct.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 67 "struct.pgc"
+
+
+     strcpy(msg, "commit");
+     { ECPGtrans(__LINE__, NULL, "commit");
+ #line 70 "struct.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 70 "struct.pgc"
+
+
+     strcpy(msg, "disconnect");
+     { ECPGdisconnect(__LINE__, "CURRENT");
+ #line 73 "struct.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 73 "struct.pgc"
+
+
+     return (0);
+ }
diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/expected/compat_informix-struct.stderr
pgsql.ooscur/src/interfaces/ecpg/test/expected/compat_informix-struct.stderr
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/expected/compat_informix-struct.stderr    1970-01-01
01:00:00.000000000+0100 
--- pgsql.ooscur/src/interfaces/ecpg/test/expected/compat_informix-struct.stderr    2009-08-14 21:28:19.000000000 +0200
***************
*** 0 ****
--- 1,136 ----
+ [NO_PID]: ECPGdebug: set to 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGconnect: opening database regress1 on <DEFAULT> port <DEFAULT>
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 29: query: set datestyle to iso; with 0 parameter(s) on connection regress1
+ [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_execute on line 29: OK: SET
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 32: query: create table a1 ( id serial primary key , t text , d1 numeric , d2 float8 ,
ccharacter ( 10 ) ); with 0 parameter(s) on connection regress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 32: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 32: OK: CREATE TABLE
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 35: query: insert into a1 ( id , t , d1 , d2 , c ) values ( default , 'a' , 1.0 , 2 ,
'a'); with 0 parameter(s) on connection regress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 35: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 35: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 36: query: insert into a1 ( id , t , d1 , d2 , c ) values ( default , null , null ,
null, null ); with 0 parameter(s) on connection regress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 36: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 36: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 37: query: insert into a1 ( id , t , d1 , d2 , c ) values ( default , '"a"' , - 1.0 ,
'nan':: float8 , 'a' ); with 0 parameter(s) on connection regress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 37: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 37: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 38: query: insert into a1 ( id , t , d1 , d2 , c ) values ( default , 'b' , 2.0 , 3 ,
'b'); with 0 parameter(s) on connection regress1 
+ [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_execute on line 38: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGtrans on line 41: action "commit"; connection "regress1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 46: query: declare mycur cursor for select * from a1; with 0 parameter(s) on
connectionregress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 46: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 46: OK: DECLARE CURSOR
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 53: query: fetch mycur; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 53: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 53: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 53: RESULT: 1 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 53: RESULT: a offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 53: RESULT: 1.0 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 53: RESULT: 2 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 53: RESULT: a          offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 53: query: fetch mycur; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 53: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 53: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 53: RESULT: 2 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 53: RESULT:  offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 53: RESULT:  offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 53: RESULT:  offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 53: RESULT:  offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 53: query: fetch mycur; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 53: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 53: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 53: RESULT: 3 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 53: RESULT: "a" offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 53: RESULT: -1.0 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 53: RESULT: NaN offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 53: RESULT: a          offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 53: query: fetch mycur; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 53: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 53: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 53: RESULT: 4 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 53: RESULT: b offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 53: RESULT: 2.0 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 53: RESULT: 3 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 53: RESULT: b          offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 53: query: fetch mycur; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 53: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 53: correctly got 0 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: raising sqlcode 100 on line 53: no data found on line 53
+ [NO_PID]: sqlca: code: 100, state: 02000
+ [NO_PID]: ecpg_execute on line 62: query: close mycur; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 62: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 62: OK: CLOSE CURSOR
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 67: query: drop table a1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 67: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 67: OK: DROP TABLE
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGtrans on line 70: action "commit"; connection "regress1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_finish: connection regress1 closed
+ [NO_PID]: sqlca: code: 0, state: 00000
diff -dcrpN pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/expected/compat_informix-struct.stdout
pgsql.ooscur/src/interfaces/ecpg/test/expected/compat_informix-struct.stdout
*** pgsql.declare-reset-sqlca/src/interfaces/ecpg/test/expected/compat_informix-struct.stdout    1970-01-01
01:00:00.000000000+0100 
--- pgsql.ooscur/src/interfaces/ecpg/test/expected/compat_informix-struct.stdout    2009-08-14 21:28:20.000000000 +0200
***************
*** 0 ****
--- 1,4 ----
+ id=1 t='a' d1=1.000000 d2=2.000000 c = 'a         '
+ id=2 t='' (NULL) d1=0.000000 (NULL) d2=0.000000 (NULL) c = '' (NULL)
+ id=3 t='"a"' d1=-1.000000 d2=nan c = 'a         '
+ id=4 t='b' d1=2.000000 d2=3.000000 c = 'b         '