Informix

 View Only

 ESQL/C and 4GL issue with OPTOFC=1 when mixing OPEN USING and OPEN without USING

Jump to  Best Answer
Sebastien FLAESCH's profile image
Sebastien FLAESCH posted 04/23/26 10:49 AM

Hello,

Context: Informix IDS 14.10.FC10 + ESQL 4.50.F11W1

We face what I consider as a quite critical issue, where a sequence of OPEN USING / OPEN without USING end up fetching unexpected data rows.

I could write an ESQL/C sample to reproduce the issue (attached as .txt file since .ec are denied).

To me there is a bug here.

The sequence of SQL instructions is:

  1. PREPARE
  2. DECLARE
  3. OPEN USING (with value 101)
  4. FETCH => expected data
  5. OPEN USING (with value 102)
  6. OPEN (without USING clause)
  7. FETCH => invalid data 

When we skip steps 3 and 4, we get error -245

To reproduce with test013.ec:

$ esql -o test013.bin test013.ec && OPTOFC=0 ./test013.bin 
[DATABASE test1                ]:  sqlcode=0
[CREATE TABLE tab1             ]:  sqlcode=0
[INSERT INTO tab1 #1           ]:  sqlcode=0
[INSERT INTO tab1 #2           ]:  sqlcode=0

[PREPARE s1                    ]:  sqlcode=0
[DECLARE c1 CURSOR             ]:  sqlcode=0

[OPEN c1 USING  #1             ]:  sqlcode=0
[FETCH c1 #1.1                 ]:  sqlcode=0
>> FETCH #1.1:  v_pkey:   101   v_name: aaaa                

[OPEN c1 USING  #2.1           ]:  sqlcode=0
[OPEN c1        #2.2           ]:  sqlcode=0
[FETCH c1 #2.1                 ]:  sqlcode=0
>> FETCH #2.1:  v_pkey:   102   v_name: bbbb                <- OK, expected data from row 102

[CLOSE c1                      ]:  sqlcode=0

Now with OPTOFC=1:

$ esql -o test013.bin test013.ec && OPTOFC=1 ./test013.bin 
[DATABASE test1                ]:  sqlcode=0
[CREATE TABLE tab1             ]:  sqlcode=0
[INSERT INTO tab1 #1           ]:  sqlcode=0
[INSERT INTO tab1 #2           ]:  sqlcode=0

[PREPARE s1                    ]:  sqlcode=0
[DECLARE c1 CURSOR             ]:  sqlcode=0

[OPEN c1 USING  #1             ]:  sqlcode=0
[FETCH c1 #1.1                 ]:  sqlcode=0
>> FETCH #1.1:  v_pkey:   101   v_name: aaaa                

[OPEN c1 USING  #2.1           ]:  sqlcode=0
[OPEN c1        #2.2           ]:  sqlcode=0
[FETCH c1 #2.1                 ]:  sqlcode=0
>> FETCH #2.1:  v_pkey:   101   v_name: aaaa                <-- not ok

[CLOSE c1                      ]:  sqlcode=0

Now skip first OPEN USING / FETCH sequend, we get -254 error on second FETCH (which is much better than silently fetching invalid data!)

$ esql -DSKIP_FIRST_FETCH -o test013.bin test013.ec && OPTOFC=1 ./test013.bin 
[DATABASE test1                ]:  sqlcode=0
[CREATE TABLE tab1             ]:  sqlcode=0
[INSERT INTO tab1 #1           ]:  sqlcode=0
[INSERT INTO tab1 #2           ]:  sqlcode=0

[PREPARE s1                    ]:  sqlcode=0
[DECLARE c1 CURSOR             ]:  sqlcode=0

[OPEN c1 USING  #2.1           ]:  sqlcode=0
[OPEN c1        #2.2           ]:  sqlcode=0
[FETCH c1 #2.1                 ]:  sqlcode=-254

I would expect error -254 in all cases when OPTOFC=1.

Take care: this issue comes from legacy I4GL code where you can have following sequence of instructions:

    PREPARE s1 FROM "SELECT ... WHERE col = ?"
    DECLARE c1 CURSOR FOR s1
    LET param1 = 101 
    OPEN c1 USING param1
    FETCH c1 INTO rec.* -- OK
    LET param1 = 102
    OPEN c1 USING param1
    FOREACH c1 INTO rec.*  -- WRONG: Re-uses param value 101
       ...
    END FOREACH

Above FOREACH without USING clause is equivalent to (OPEN c1 USING param1 is already done):

    OPEN c1 ( without USING clause )
    WHILE sqlca.sqlcode == 0
       FETCH c1 INTO rec.*
       ...
    END WHILE
    CLOSE c1

It would also be nice to clarify what are the possible values of OPTOFC: Documentation mentions 1/0 but we experience the problem with values 1 to 7.

Seb

Attachment  View in library
Javier Sagrera's profile image
Javier Sagrera  Best Answer

Had a look again this morning and still can't see anything wrong here.
Pretty sure Art already explained what was going one, but just in case.

Look at this 4GL code:

    informix@t14ito:~/7.51.FC3$ cat t1.4gl
    database sysmaster
    MAIN
        DEFINE p1 INTEGER
        DEFINE p2 INTEGER
        DEFINE v1 INTEGER

        LET p1 = 1
        LET p2 = 2

        PREPARE s1 FROM "SELECT tabid FROM systables WHERE tabid = ?"
        DECLARE c1 CURSOR FOR s1

        OPEN c1 USING p1
        #FETCH c1 INTO v1 
        FOREACH c1 USING p2 INTO v1
        #FOREACH c1 INTO v1
           DISPLAY "     v1: ", v1
        END FOREACH

    END MAIN
    informix@t14ito:~/7.51.FC3$

We are doing an OPEN with "1" and FOREACH with "2".

but in reality the "c1" cursor is only opened once with the implicit OPEN created by the FOREACH.

FOREACH is basically the same as doing OPEN/FETCH/CLOSE. If you don't use "USING", you are NOT specifying any parameter to be used on the FETCH.
The code above results in:

    informix@t14ito:~/7.51.FC3$ c4gl t1.4gl ; OPTOFC=1 ./a.out
         v1:           2
    informix@t14ito:~/7.51.FC3$

The "OPEN c1 USING p1" is ignored and "overriten" by the second OPEN (implicit) from the FOREACH statement:
 
    informix@t14ito:~/7.51.FC3$ c4gl -keep t1.4gl ;  grep open t1.ec
     $  open i00160615zo0lsl2ln using $p1;
     $  open i00160615zo0lsl2ln using $p2;
     $  fetch i00160615zo0lsl2ln into $v1;
    informix@t14ito:~/7.51.FC3$

It may be easier to understand if you try without supplying any parameters in the FOREACH.
Changing:
        FOREACH c1 USING p2 INTO v1
for:
        FOREACH c1 INTO v1

FOREACH will translate to OPEN/FETCH/CLOSE (notice the plain "open" statement)
        
    informix@t14ito:~/7.51.FC3$ c4gl -keep t1.4gl ; grep -e open -e fetch t1.ec
     $  open i0016064c50bsvy5u2 using $p1;
     $  open i0016064c50bsvy5u2;
     $  fetch i0016064c50bsvy5u2 into $v1;
    informix@t14ito:~/7.51.FC3$

Without OPTOFC that plain OPEN will reuse the host variable already associated with the cursor (so 'p1'):

    informix@t14ito:~/7.51.FC3$ c4gl t1.4gl ; OPTOFC=0 ./a.out
         v1:           1
    informix@t14ito:~/7.51.FC3$

but with OPTOFC enabled, it will not. And because we didn't run a FETCH, it throws the expected -254 error

    informix@t14ito:~/7.51.FC3$ c4gl t1.4gl ; OPTOFC=1 ./a.out
    Program stopped at "t1.4gl", line number 15.
    SQL statement error number -254.
    Too many or too few host variables given.
    informix@t14ito:~/7.51.FC3$

this shows how the OPEN parameters are handled when using OPTOFC

And you can see the same behavior with plain a basic ESQL/C code

    informix@t14ito:~/7.51.FC3$ cat e1.ec
    #include <stdio.h>
    #include <time.h>
    $include "sqlca.h";
    $include "sqlhdr.h";
    $include "sqltypes.h";

    main()
    {
    int error;
    $ BEGIN DECLARE SECTION;
      int p1,p2,v1;
    $ END DECLARE SECTION;

      p1=1;
      p2=2;

    $ whenever sqlerror stop;
    $ connect to 'sysmaster';
    $ prepare sel1 from 'SELECT tabid FROM systables where tabid=?';
    $ declare ifxcursor cursor for sel1;
    $ open ifxcursor using :p1;
    $ fetch ifxcursor into :v1;

    $ open ifxcursor using :p2;
    $ open ifxcursor;
    $ fetch ifxcursor into :v1;

      printf("    v1 : %d\n",v1);
    }

We do OPEN with "p1", FETCH the result and then another two OPENs.
one with "p2" and one without a parameter:

    informix@t14ito:~/7.51.FC3$ c4gl e1.ec; OPTOFC=0 ./a.out
        v1 : 2
    informix@t14ito:~/7.51.FC3$ c4gl e1.ec; OPTOFC=1 ./a.out
        v1 : 1
    informix@t14ito:~/7.51.FC3$

With OPTOFC enabled, only the initial value of "p1" is used for the fetch.
Because there is no fetch after  "open ifxcursor using :p2", the value of "p2" is never sent to the database or "applied" to memory.
When the plain "open ifxcursor" executes without parameters, the runtime falls back to "p1", which is the only parameter currently synchronized in memory.


As I see it:

1. 4GL's FOREACH is the same as writing OPEN, FETCH and CLOSE. 
    If you have a FOREACH without USING you will get an OPEN without USING.   Nothing wrong with that.

2. The OPTOFC optimization affects when parameters are processed. We have documented several restrictions when using OPTOFC here:
    https://www.ibm.com/docs/en/informix-servers/15.0.x?topic=close-restrictions-optofc

   I do agree that maybe it will be a good idea to also add a statement describing how parameters handling is affected  when its OPTOFC is enabled.

Art Kagel's profile image
Art Kagel IBM Champions

Sebastien:

Your code never executed the FETCH between the second OPEN and the third OPEN! Fixed the code and it works regardless of whether OPTOFC is set or not and whether the first FETCH sequence is included or not.  

The only thing that's a bit confusing is why the third OPEN without the USING clause does not generate an error. It runs without setting SQLCODE though it does not overwrite the existing value in v_pkey which is expected. Code attached.

Art

Attachment  View in library
test02.txt 3 KB
Art Kagel's profile image
Art Kagel IBM Champions

Oh, forgot to mention, I also added explicit closes between the OPENs (which are commented out in the file I uploaded) and it does not matter whether they are there or not, regardless of the setting of OPTOFC or commenting out the first OPEN... FETCH sequence.

Art

Sebastien FLAESCH's profile image
Sebastien FLAESCH

Hi Art and thanks for your quick reaction, but understand that changing the ESQL/C code is not possible in this case:

As I wrote, the origin of the issue comes from 4GL and legacy code that does an OPEN USING + FOREACH without USING, where you don't want to do a FETCH in between!

Here my original 4GL code:

MAIN
    DEFINE p1 INTEGER
    DEFINE rec RECORD pkey INTEGER, name VARCHAR(20) END RECORD

    DATABASE test1

    CREATE TEMP TABLE tmp1 ( pkey INTEGER, name VARCHAR(50) )
    INSERT INTO tmp1 VALUES (101,"aaa")
    INSERT INTO tmp1 VALUES (102,"bbb")

    PREPARE s1 FROM "SELECT * FROM tmp1 WHERE pkey = ?"
    DECLARE c1 CURSOR FOR s1

    LET p1 = 101
    OPEN c1 USING p1
    FETCH c1 INTO rec.*
    DISPLAY "FETCH 101   rec: ", rec.pkey, " ", rec.name

    LET p1 = 102
    OPEN c1 USING p1
    FOREACH c1 INTO rec.*                 # Fail: Reuses p1=101 when OPTOFC=1 !
       DISPLAY "FOREACH     rec: ", rec.pkey, " ", rec.name
    END FOREACH

END MAIN

See:

$ fglcomp -M main.4gl && fglrun main.42m
FETCH 101   rec:         101 aaa
FOREACH     rec:         102 bbb               <= OK

$ fglcomp -M main.4gl && OPTOFC=1 fglrun main.42m
FETCH 101   rec:         101 aaa
FOREACH     rec:         101 aaa                <= Not OK...

Same issue occurs with Informix 4GL 7.51.FC4 (c4gl and RDS fglpc/fglgo) - give it a try!

Seb

Art Kagel's profile image
Art Kagel IBM Champions

Sebastien:

I just compiled your code using C4GL  7.50.FC5 and it seems to work just fine:

art@Gandolf:~/Downloads$ vi test01.4gl
art@Gandolf:~/Downloads$ c4gl -o test01c test01.4gl
art@Gandolf:~/Downloads$ ./test01c
FETCH 101 rec:         101 aaa
FOREACH rec:         102 bbb
art@Gandolf:~/Downloads$ c4gl -V
IBM INFORMIX-4GL Version 7.50.FC5   
Software Serial Number RDS#N000000

Looks like a compiler bug.

Art

Sebastien FLAESCH's profile image
Sebastien FLAESCH

Hello Art,

You have tested with Informix 4GL 7.50.FC5.

I can reproduce with Informix 4GL two 7.51.FC2 and FC4 on my Linux Debian 12:

$ . /opt3/dbs/ifx/DEV-7.51.FC2/informix.env 
$ c4gl -V
IBM INFORMIX-4GL Version 7.51.FC2   
Software Serial Number RDS#N000000
$ esql -V
IBM Informix CSDK Version 4.10, IBM Informix-ESQL Version 4.10.FC6  
Software Serial Number RDS#N000000
$ c4gl -o main.bin main.4gl
$ export OPTOFC=1
$ ./main.bin
FETCH 101   rec:         101 aaa
FOREACH     rec:         101 aaa                       <= WRONG

$ . /opt3/dbs/ifx/DEV-7.51.FC4/informix.env 
$ c4gl -V
IBM INFORMIX-4GL Version 7.51.FC4   
$ esql -V
IBM Informix CSDK Version 15.0, IBM Informix-ESQL Version 15.0.0.1
$ c4gl -o main.bin main.4gl
$ export OPTOFC=1
$ ./main.bin 
FETCH 101   rec:         101 aaa
FOREACH     rec:         101 aaa                       <= WRONG

$ unset OPTOFC
$ ./main.bin 
FETCH 101   rec:         101 aaa
FOREACH     rec:         102 bbb                       <= OK

Can you try a more recent version of I4GL?

Seb

Art Kagel's profile image
Art Kagel IBM Champions

Sebastien:

OK, just compiled with c4gl latest (7.51.FC5) against my HCL Informix v15.0.1.6 on Ubuntu (x86-64).

It's working fine here.

art@Gandolf:~/Downloads$ c4gl -o test01 test01.4gl
art@Gandolf:~/Downloads$ dirtail
-rw-rw-r--  1 art art      3888 Apr 23 11:56 test02.txt
-rw-rw-r--  1 art art       574 Apr 23 13:46 test01.4gl~
-rw-rw-r--  1 art art       589 Apr 23 13:56 test01.4gl
-rwxrwxr-x  1 art art     20000 Apr 23 13:56 test01c*
-rwxrwxr-x  1 art art     20000 Apr 23 14:04 test01C*
-rw-rw-r--  1 art art    285546 Apr 23 14:10 IR260424.pdf
drwxr-xr-x 58 art art      4096 Apr 23 16:00 ../
-rw-rw-r--  1 art art     12192 Apr 24 06:30 test01.o
-rwxrwxr-x  1 art art     20000 Apr 24 06:30 test01*
drwxr-xr-x  2 art art     36864 Apr 24 06:30 ./
art@Gandolf:~/Downloads$ ./test01
FETCH 101 rec:         101 aaa
FOREACH rec:         102 bbb
art@Gandolf:~/Downloads$ c4gl -V
HCL INFORMIX-4GL Version 7.51.FC5   
art@Gandolf:~/Downloads$ 

Sebastien FLAESCH's profile image
Sebastien FLAESCH

Hi Art,

Sorry to insist, but did you set the OPTOFC=1 env var ?

I cannot see this in your command lines...

export OPTOFC=1

I will try to find c4gl 7.51.FC5 and test on my side.

Seb

Art Kagel's profile image
Art Kagel IBM Champions

Apologies, I did forget to try that. Here, and you are correct, this is a bug in the v7.51 compiler:

art@Gandolf:~/Downloads$ ./test01
FETCH 101 rec:         101 aaa
FOREACH rec:         102 bbb
art@Gandolf:~/Downloads$ c4gl -V
HCL INFORMIX-4GL Version 7.51.FC5   
art@Gandolf:~/Downloads$ OPTOFC=1 ./test01
FETCH 101 rec:         101 aaa
FOREACH rec:         101 aaa
art@Gandolf:~/Downloads$ 

Sebastien FLAESCH's profile image
Sebastien FLAESCH

Hi Art,

Glad that you could reproduce with OPTOFC=1 !!!

Since the problem exist also with ESQL/C, I believe it's rather an ESQL/C bug.

We should now register a defect.

Seb

Art Kagel's profile image
Art Kagel IBM Champions

Sebastien:

I have to disagree, the generated ESQL/C is producing the same result but that is because the generated code is faulty. Just look at and test the version that I sent you. 

The generated code never fetches after the second OPEN but only after the third one. It works when you do not set OPTOFC because the FETCH after the third OPEN, the one without a USING clause, fetches the data from the second OPEN. That third OPEN just silently fails which is a bug in itself, but has nothing to do with the code not working when you set OPTOFC. 

Here is what is actually happening: Remember that OPTOFC defers the OPEN until the FETCH and automatically closes the cursor when the last row is fetched. In the generated code, since there is not FETCH immediately after the OPEN the open is queued in the local library's memory but not executed. Then the third OPEN executes with not USING so it is completely ignored (I agree that it should generate an error) and probably clears the scheduled OPEN from the second OPEN call. Then the FETCH that follows the third OPEN also silently fails and the target host variables simply have retained their values from the first successful fetch. 

When you comment out the first OPEN and FETCH, there is no data in the target host variables so you finally get an error.

In the correctly built code I send, where there is a second FETCH, the results are correct regardless of OPTOFC and regardless of whether you comment out the first fetch.

Now, not returning errors when the third OPEN is presented on top of the second one with no fetch? Maybe when OPTOFC is NOT set. It should not like either the back-to-back OPENs nor that the third OPEN does not present a value to use. On the other hand, if you OPEN a cursor again without first issuing a CLOSE, that is not an error and the OPEN executes a CLOSE internally first, so maybe not an error. In the OPTOFC case, I think not an ESQL compiler or engine bug but rather that the second OPEN was just NO-OP because of how OPTOFC works.

Nope, I maintain that the ONLY problem is the C4GL V7.51 compiler that has generated bad ESQL/C code (the 7.50 compiler gets it correct. I would like to see JC or Jonathan Leffler chime in on this one.

Art Kagel's profile image
Art Kagel IBM Champions

FORGET WHAT I SAID. I just realized what the issue is. The 4GL code it bad. You have:
LET p1 = 102
OPEN c1 USING p1
FOREACH  c1 INTO rec.* 
    # Fail: Reuses p1=101 when OPTOFC=1 ! 
    DISPLAY "FOREACH rec: ", rec.pkey, " ", rec.name 
END FOREACH 
END MAIN

But the FOREACH does its own OPEN. That is the 3rd open and and since the FOREACH does not have a USING clause that 3rd OPEN doesn't either in the generated code.

The code should be:

LET p1 = 102

FOREACH  c1 using p1 INTO rec.* 
    # Fail: Reuses p1=101 when OPTOFC=1 ! 
    DISPLAY "FOREACH rec: ", rec.pkey, " ", rec.name 
END FOREACH 
END MAIN

That works perfectly regardless of which compiler version I use. There is still the issued of whether or not the third open should have generated an error and why the FOREACH is indeed fetching the value 101 instead of 102, but bottom line? Correct 4GL code generates correct ESQL/C code.


Art

Sebastien FLAESCH's profile image
Sebastien FLAESCH

Hello Art,

I fully agree that proper FOREACH programming is to put a USING clause if there are ? parameters in the query.

However, AFAIKR, in first versions of I4GL, the FOREACH instruction did not allow a USING clause, and that's why you can find sequences like: 

  1. OPEN curs USING ...
  2. FOREACH curs INTO ...      (without USING clause)

And in such case, it's "normal" to have no FETCH between OPEN and FOREACH!

By the way, we have a migration/update page about this in our Genero documentation:

https://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_fgl_MigI4GL_031.html

I4GL or Genero users will face the issue discussed here, if they want to use OPTOFC=1 and cannot or don't want to touch their legacy code.

I can understand that it's a 4GL-only bug (not an ESQL/C bug), assuming that this tricky OPEN USING followed by OPEN or FOREACH without USING is to be handled at the 4GL compiler level. But since (I assume) the OPTOFC optimization is implemented in ESQL/C libs, maybe it would be good to raise error -254 when OPTOFC is enabled, and an OPEN without USING clause is performed right after an OPEN c USING. This would at least prevent legacy code to fetch invalid data.

Thanks for your investigation, it's a tricky one.

Seb

PS: You wrote that you sent me your sample but I did not get any email

Sebastien FLAESCH's profile image
Sebastien FLAESCH

Hello,

Anyone from IBM or HCL to comment on this?

Seb

Andreas Legner's profile image
Andreas Legner IBM Champions

Hi Seb,

we're looking into this, esp. what changed in this regard between 7.50 and 7.51... but what probably can be told already now:  at the point where the esql/c code gets produced from 4GL it can't be guessed whether OPTOFC will be used or not.

Stay tuned or, better, provide us with a support case if possible.

BR,
 Andreas

Javier Sagrera's profile image
Javier Sagrera

Hi guys,

Can I double check the 4GL versions you are testing with?  I think you mentioned it "worked" with 7.50, but I did a quick test with the oldest 4GL I have installed (7.32.UC2) and still see the same which to me it is kind of expected (as in a "caveat" of using OPTOFC and the delay of doing the "real" OPEN)

informix@irk:/opt/informix/IBM/7.32.UC2$ c4gl -V
IBM INFORMIX-4GL Version   7.32.UC2   
Software Serial Number RDS#N000000
informix@irk:/opt/informix/IBM/7.32.UC2$ cat t.4gl
database sysmaster
MAIN
    DEFINE p1 INTEGER
    DEFINE rec RECORD like systables.*

    PREPARE s1 FROM "SELECT * FROM systables WHERE tabid = ?"
    DECLARE c1 CURSOR FOR s1

    LET p1 = 1
    OPEN c1 USING p1
    FETCH c1 INTO rec.*
    DISPLAY    "FETCH 1     rec: ", rec.tabid, " ", rec.tabname

    LET p1 = 2
    OPEN c1 USING p1
    FOREACH c1 INTO rec.*                 # FAILS  OPTOFC=1 !
       DISPLAY "FOREACH     rec: ", rec.tabid, " ", rec.tabname
    END FOREACH

END MAIN

informix@irk:/opt/informix/IBM/7.32.UC2$ c4gl t.4gl
informix@irk:/opt/informix/IBM/7.32.UC2$ ./a.out
FETCH 1       rec:           1 systables
FOREACH     rec:           2 syscolumns

informix@irk:/opt/informix/IBM/7.32.UC2$ OPTOFC=1 ./a.out
FETCH 1       rec:           1 systables
FOREACH     rec:           1 systables
informix@irk:/opt/informix/IBM/7.32.UC2$ 

Regarding the values of OPTOFC, back in 3.50.xC1 we changed how we check if the variable is set or not. Before it was checking if it was just "1",  after 3.50 it will take from "1" to "7":

    if ((tmpstr = idx_ggetenv("OPTOFC", IDX_OPTOFC)) != NULL)
        if ((tmpstr[0] == '1' ||
             tmpstr[0] == '2' ||
             tmpstr[0] == '3' ||
             tmpstr[0] == '4' ||
             tmpstr[0] == '5' ||
             tmpstr[0] == '6' ||
             tmpstr[0] == '7')
           && tmpstr[1] == 0)
        cp->optofc = 1;

Javier

Sebastien FLAESCH's profile image
Sebastien FLAESCH

Hello Javier,

First, thanks for looking at this issue.

Can you please clarify what you mean by:

"... which to me it is kind of expected (as in a "caveat" of using OPTOFC and the delay of doing the "real" OPEN)"

?

Do we agree that when OPTOFC=1-7, with OPEN USING + FOREACH without USING (which is legacy 4GL), you see invalid data fetched without any further error?

Do we agree that this is not good at all and that we should strongly warn users about that?

If this cannot be easily fixed at the ESQL/C level, any 4GL runtime should raise an error, when OPTOFC=1-7, and for a given cursor, an OPEN USING is followed by a FOREACH with no USING clause.

BTW I am not sure to get why OPTOFC can be 1 to 7... quite strange code you show there.
I would just test for OPTOFC>0.

Seb

Javier Sagrera's profile image
Javier Sagrera

My take is that this behavior is a direct consequence of how OPTOFC was designed to work.
When OPTOFC is enabled an OPEN statement does not execute immediately. Instead, the OPEN request and its USING parameters are stored internally and the actual OPEN is performed only when the first FETCH occurs.

Due this deferred execution model, only the first OPEN issued after the DECLARE is ever really applied.
After the first FETCH has executed the pending OPEN, the cursor is considered "opened" for the life of that DECLARE and any subsequent OPEN statements (explicit or implicit like the generated by the FOREACH) are ignored because OPTOFC does not re‑evaluate stored OPEN parameters after the first FETCH.

I do agree with you that a note of warning on the OPTOFC page could be a good idea, but as far as I know, nobody has complained or requested that in at least 25 years. 4GL 7.32.UC2 was released in 2003. I can try to dig up older versions but I'm sure it would have been like that with earlier versions too.

Regarding the 1 to 7 OPTOFC values, the engine supports 7 internal OPTOFC modes (1 through 7), but originally the client only recognized values 0 or 1.
 In version CSDK 3.50.xC1 (back in 2008), the client was updated to also detect and pass OPTOFC values from 1 to 7 to the server. 
The logic was implemented like that for performance reasons, avoiding the use of functions like atoi().

Javier

Sebastien FLAESCH's profile image
Sebastien FLAESCH

Hello Javier,

Thanks for you last analysis.

I think we can close this thread.

Seb