Informix

Informix

Connect with Db2, Informix, Netezza, open source, and other data experts to gain value from your data, share insights, and solve problems.

 View Only
Expand all | Collapse all

ESQL/C DESCRIBE OUTPUT after OPEN (with DECLARE CURSOR name) fails with -410

  • 1.  ESQL/C DESCRIBE OUTPUT after OPEN (with DECLARE CURSOR name) fails with -410

    Posted 29 days ago

    Hello,

    With ESQL/C 4.50.FC10 (Linux Debian 12):

    I am trying to use the DESCRIBE OUTPUT instruction to get column information of a SELECT, after the PREPARE / DECLARE CURSOR / OPEN sequence.

    The idea here is to postpone the DESCRIBE OUTPUT after the OPEN, to potentially use the IFX_DEFERRED_PREPARE=1 env var to optimize SQL execution.

    I want to use the cursor name used in the DECLARE/OPEN instruction, in the DESCRIBE OUTPUT instruction (since we want to use deferred prepare, I can't use the PREPARE statement name, assuming this would generate a ping/pong with the server - right? Note we have generic code that implies to know only the OPEN cursor name in this context)

    With this PREPARE / DECLARE CURSOR cuname / OPEN cuname, the DESCRIBE OUTPUT cuname fails with error

     -410 "Prepare statement failed or was not executed."

    I am missing something here?

    The cursor is declared and opened (=executed), without error, so the SELECT is executed on the server side.

    To me it must be possible to use a DESCRIBE OUTPUT only after the OPEN, before starting to FETCH, to benefit from the deferred prepare option.

    Warning: We want to use dynamic sqlda, not system descriptors as this would required too much code change.

    Here the code:

    #include <stdlib.h>
    #include <stdio.h>
    #include <signal.h>
    #include <string.h>
    
    void check_sqlcode(const char *msg)
    {
        printf(">> [%-40s]:  sqlcode=%d sqlerrd[2]=%d\n", msg, sqlca.sqlcode, sqlca.sqlerrd[2]);
        if (sqlca.sqlcode < 0) {
            exit(1);
        }
    }
    
    int main(int argc, char ** argv)
    {
    
        struct sqlda *tmp = NULL;
        EXEC SQL BEGIN DECLARE SECTION;
        char *stmt_name = "s1";
        char *curs_name = "c1";
        char *sqlcmd = "SELECT * FROM systables ORDER BY tabid";
        EXEC SQL END DECLARE SECTION;
    
        EXEC SQL DATABASE test1;
        check_sqlcode("DATABASE test1");
    
        EXEC SQL PREPARE :stmt_name FROM :sqlcmd;
        check_sqlcode("PREPARE");
    
    #if 1
        EXEC SQL DESCRIBE OUTPUT :stmt_name INTO tmp;
        check_sqlcode("DESCRIBE OUTPUT using statement name");
        fprintf(stdout, ">> Statement type / sqlca.sqlcode: %d\n", sqlca.sqlcode);
    #endif
    
        EXEC SQL DECLARE :curs_name CURSOR FOR :stmt_name;
        check_sqlcode("DECLARE CURSOR");
    
        EXEC SQL OPEN :curs_name;
        check_sqlcode("OPEN CURSOR");
    
    #if 1
        EXEC SQL DESCRIBE OUTPUT :curs_name INTO tmp;
        check_sqlcode("DESCRIBE OUTPUT using cursor name");
        fprintf(stdout, ">> Statement type / sqlca.sqlcode: %d\n", sqlca.sqlcode);
    #endif
    
    }
    

    Seb



    ------------------------------
    Sebastien FLAESCH
    ------------------------------


  • 2.  RE: ESQL/C DESCRIBE OUTPUT after OPEN (with DECLARE CURSOR name) fails with -410

    Posted 29 days ago

    Sebastian:

    Even though you will be issuing the DESCRIBE statement after the OPEN, you still need to pass the statement name not the cursor name, so make that one change as below:

    #include <stdlib.h>
    #include <stdio.h>
    #include <signal.h>
    #include <string.h>
     
    void check_sqlcode(const char *msg)
    {
        printf(">> [%-40s]: sqlcode=%d sqlerrd[2]=%d\n",
       msg,
       sqlca.sqlcode,
       sqlca.sqlerrd[2]);
        if (sqlca.sqlcode < 0) {
    exit(1);
        }
    }
    int main(int argc, char ** argv) {
        struct sqlda *tmp = NULL;
        EXEC SQL BEGIN DECLARE SECTION;
        char *stmt_name = "s1";
        char *curs_name = "c1";
        char *sqlcmd = "SELECT * FROM systables ORDER BY tabid";
        EXEC SQL END DECLARE SECTION;
     
        EXEC SQL DATABASE test1;
        check_sqlcode("DATABASE test1");
        EXEC SQL PREPARE :stmt_name FROM :sqlcmd;
        check_sqlcode("PREPARE");
    #if 1
        EXEC SQL DESCRIBE OUTPUT :stmt_name INTO tmp;
        check_sqlcode("DESCRIBE OUTPUT using statement name");
        fprintf(stdout, ">> Statement type / sqlca.sqlcode: %d\n", sqlca.sqlcode);
    #endif
        EXEC SQL DECLARE :curs_name CURSOR FOR :stmt_name;
        check_sqlcode("DECLARE CURSOR");
        EXEC SQL OPEN :curs_name;
        check_sqlcode("OPEN CURSOR");
    #if 1
        EXEC SQL DESCRIBE OUTPUT :curs_name INTO tmp;
        check_sqlcode("DESCRIBE OUTPUT using stmt_name");
        fprintf(stdout, ">> Statement type / sqlca.sqlcode: %d\n", sqlca.sqlcode);
    #endif
    }


    ------------------------------
    Art S. Kagel, President and Principal Consultant
    ASK Database Management Corp.
    www.askdbmgt.com
    ------------------------------



  • 3.  RE: ESQL/C DESCRIBE OUTPUT after OPEN (with DECLARE CURSOR name) fails with -410

    Posted 29 days ago

    Thank you Art!

    I tried that too, after sending my question.

    So this seems to be the way to do it.

    Will do more tests tomorrow to see if IFX_DEFERRED_PREPARE=1 can take place.

    Any clue to detect/debug client/server communication to make sure that the PREPARE/DECLARE is postponed to the OPEN?

    Seb

    PS: in your modified code, last DESCRIBE is still using :curs_name, seems you changed the message only.
    You might want to send a diff next time.



    ------------------------------
    Sebastien FLAESCH
    ------------------------------



  • 4.  RE: ESQL/C DESCRIBE OUTPUT after OPEN (with DECLARE CURSOR name) fails with -410

    Posted 29 days ago
    Oops. Sorry about that. Not enough coffee this morning.

    Art

    Art S. Kagel, President and Principal Consultant
    ASK Database Management


    Disclaimer: Please keep in mind that my own opinions are my own opinions and do not reflect on the IIUG, nor any other organization with which I am associated either explicitly, implicitly, or by inference.  Neither do those opinions reflect those of other individuals affiliated with any entity with which I am affiliated nor those of the entities themselves.











  • 5.  RE: ESQL/C DESCRIBE OUTPUT after OPEN (with DECLARE CURSOR name) fails with -410

    Posted 28 days ago

    Trying to identify if IFX_DEFFERED_PREPARE=1 is taken into account with my test002.ec sample:

    With SQLIDEBUG=1 set, I can see differences in the client debug log files (assuming C->S means Client to Server, and S->C the Server to Client response):

    On the left, without IFX_DEFFERED_PREPARE, and on the right, with IFX_DEFFERED_PREPARE=1 set.

    Can I conclude that IFX_DEFERRED_PREPARE=1 works?

    Seb



    ------------------------------
    Sebastien FLAESCH
    ------------------------------



  • 6.  RE: ESQL/C DESCRIBE OUTPUT after OPEN (with DECLARE CURSOR name) fails with -410

    Posted 28 days ago

    Hello,

    I have another question related to the DESCRIBE instruction:

    With an instruction sequence of type:

    1. PREPARE s1 FROM ...
    2. DECLARE c1 CURSOR FOR s1
    3. OPEN c1 USING ...
    4. DESCRIBE s1 INTO dynsqlda
    5. FETCH c1 INTO dynsqlda

    I assume that it can be optimized with IFX_DEFERRED_PREPARE, since the DESCRIBE is done after the OPEN and the client should already have column list information returned by the server.

    But what about executing a single-row SELECT, with PREPARE + EXECUTE? (remember we need to implement generic code as we don't know what SQL will be executed at runtime)

    1. PREPARE s1 FROM ...
    2. EXECUTE s1 USING ... INTO dynsqlda

    How can I get column info at runtime with DESCRIBE, and have only one single ping-pong with the server?

    The DESCRIBE will create the dynsqlda elements, that will then be used by EXECUTE INTO.

    Currently we are doing:

    1. PREPARE s1 FROM ...
    2. DESCRIBE s1 INTO dynsqlda
    3. EXECUTE s1 USING ... INTO dynsqlda

    Ideally I would expect to have an extension of EXECUTE:

    1. PREPARE s1 FROM ...
    2. EXECUTE s1 USING ... INTO DYNAMIC dynsqlda

    where dynsqlca elements are automatically created, and filled with the fetched row. 

    Or did I miss something?

    Seb 



    ------------------------------
    Sebastien FLAESCH
    ------------------------------



  • 7.  RE: ESQL/C DESCRIBE OUTPUT after OPEN (with DECLARE CURSOR name) fails with -410

    Posted 28 days ago

    Sebastian:

    So, if you have IFX_DEFERRED_PREPARE set or have executed SET DEFERRED_PREPARE, you realistically cannot use the PREPARE ... EXECUTE ... INTO paradigm and must use PREPARE...DECLARE CURSOR...OPEN ... FETCH ... CLOSE paradigm in order to be able to DESCRIBE the prepared statement before executing it and fetching the data. All of that is happening under the hood anyway when you just EXECUTE ... INTO, so that is only really saving you a few lines of code no real execution time or saved message trips.

    Alternatively, when you want to use PREPARE...EXECUTE in your code, you could use SET DEFERRED_PREPARE to turn the feature off and back on again afterwards.

    On your follow-up post, yes, the deferred prepare is working.

    If you really want to save execution time in dynamic SQL code, check out array fetching! Your code gets back possibly hundreds of rows in a single FETCH. You just place an array of <whatever> into the  sqlda.sqlvar.sqldata field instead of a scalar locations for each returned value and set the FetArrSize global variable to the number of values each array can hold, and poof! That's the biggest performance improver for dynamic SQL code. Look at the code for my dbcopy, dbdelete, or dbmove utility for examples.

    Art



    ------------------------------
    Art S. Kagel, President and Principal Consultant
    ASK Database Management Corp.
    www.askdbmgt.com
    ------------------------------



  • 8.  RE: ESQL/C DESCRIBE OUTPUT after OPEN (with DECLARE CURSOR name) fails with -410

    Posted 27 days ago

    Thank you Art for your advice!

    Understand that we implement the Informix ODI driver for Genero BDL, and the code needs to be generic.
    We do not know what SQL statement will be executed by the .4gl code.
    We cannot use SET DEFERRED_PREPARE, as we want to leave the option to the end users.
    All we know at this driver code context is the actual .4gl instruction (EXECUTE IMMEDIATE / PREPARE / EXECUTE / DECLARE / OPEN / FOREACH / FETCH / CLOSE / FREE / ...) that is to be performed.

    In order to implement the .4gl instruction EXECUTE stmt [USING...] [INTO ...], we known if the INTO clause is used.
    When an INTO clause is provided, it is because the SQL is producing a result set (SELECT or something else).
    So we could switch to a PREPARE / DECLARE / OPEN / DESCRIBE / FETCH, since anyway this is what happens behind the scene when doing PREPARE / EXECUTE INTO ... 

    Using array fetching is another story, and would require much more code change in our generic code, in order to fetch many rows into a .4gl DYNAMIC ARRAY in one single .4gl FETCH ...

    Seb



    ------------------------------
    Sebastien FLAESCH
    ------------------------------



  • 9.  RE: ESQL/C DESCRIBE OUTPUT after OPEN (with DECLARE CURSOR name) fails with -410

    Posted 27 days ago

    Sebastian:

    Yes, I forgot your context. Obviously array fetching is not a valid strategy for your context.

    At least the recommendation is out there for others reading the thread who may be able to take advantage.

    Art



    ------------------------------
    Art S. Kagel, President and Principal Consultant
    ASK Database Management Corp.
    www.askdbmgt.com
    ------------------------------



  • 10.  RE: ESQL/C DESCRIBE OUTPUT after OPEN (with DECLARE CURSOR name) fails with -410

    Posted 26 days ago

    Art,

    Just re-read you last comment where you write:

    and must use PREPARE...DECLARE CURSOR...OPEN ... FETCH ... CLOSE paradigm in order to be able to DESCRIBE the prepared statement before executing it and fetching the data.

    In fact the idea is to perform the DESCRIBE after the execution (OPEN) and before FETCH

    The sequence is:

    1. PREPARE s1 FROM ...
    2. DECLARE c1 CURSOR FOR s1
    3. OPEN c1 USING ...
    4. DESCRIBE s1 INTO dynsqlda
    5. FETCH c1 INTO dynsqlda

    Otherwise it brings no added value.

    Seb



    ------------------------------
    Sebastien FLAESCH
    ------------------------------



  • 11.  RE: ESQL/C DESCRIBE OUTPUT after OPEN (with DECLARE CURSOR name) fails with -410

    Posted 26 days ago

    Sebatian:

    Yes, you are correct, I should have said to do the DESCRIBE "before the FETCH" meaning after the open.

    Art



    ------------------------------
    Art S. Kagel, President and Principal Consultant
    ASK Database Management Corp.
    www.askdbmgt.com
    ------------------------------



  • 12.  RE: ESQL/C DESCRIBE OUTPUT after OPEN (with DECLARE CURSOR name) fails with -410

    Posted 26 days ago

    Hello

    Searching the Informix doc about IFX_DEFERRED_PREPARE, found in this page:

    https://www.ibm.com/docs/en/informix-servers/15.0.0?topic=statement-enable-deferred-prepare-feature

    BUT not listed here:

    https://www.ibm.com/docs/en/informix-servers/15.0.0?topic=variables-environment-in-informix-products

    Doc bug?

    There is another env var called OPTOFC that I would like to test and understand the effect when used in conjunction with IFX_DEFERRED_PREPARE:

    https://www.ibm.com/docs/en/informix-servers/15.0.0?topic=products-optofc-environment-variable

    Any advice/experience is welcome.

    Seb



    ------------------------------
    Sebastien FLAESCH
    ------------------------------



  • 13.  RE: ESQL/C DESCRIBE OUTPUT after OPEN (with DECLARE CURSOR name) fails with -410

    Posted 26 days ago

    Hello,

    I did some tests with Informix 4GL 7.51.FC4 (c4gl and RDS fglpc/fglgo), with IFX_DEFERRED_PREPARE=1 and OPTOFC=1, using various combinations of PREPARE / EXECUTE / DECLARE / OPEN / FETCH / FOREACH instructions.

    IFX_DEFERRED_PREPARE=1 seems to work with c4gl, but is not well supported by RDS fglpc/fglgo:

    $ fglgo dc_test1.4go test1
    time:         0 00:00:04.896
    
    $ fglgo dc_test1.4go test2
    time:         0 00:00:11.660
    
    $ export IFX_DEFERRED_PREPARE=1
    
    $ fglgo dc_test1.4go test1
    free(): invalid pointer
    Aborted
    
    $ fglgo dc_test1.4go test2
    free(): invalid pointer
    Aborted

    OPTOFC=1 is not well supported, neither by c4gl nor by RDS.


    1) I get error -254 in the FOREACH, when doing old-style OPEN USING + FOREACH:

        LET p1 = 102
        OPEN c1 USING p1
        FOREACH c1 INTO rec.*
           DISPLAY "  rec: ", rec.pkey, " ", rec.name
        END FOREACH

    2) Wrong values are fetched in the execution of a FOREACH loop after a first FETCH INTO, when changing the USING variable values, and the USING clause is specified in an OPEN preceding the FOREACH with no USING clause. Happens only when using PREPARE/DECLARE, not with DECLARE + static SQL referencing the USING variable.

    Instruction sequence:

    1. PREPARE s1 FROM "SELECT ..."

    2. DECLARE c1 CURSOR FROM s1

    3. LET p1 = 101

    4. OPEN c1 USING p1

    5. FETCH c1 INTO ... (OK, values of row 101 fetched)

    6. LET p1 = 102

    7. OPEN c1 USING p1

    8. FOREACH c1 INTO ... (fails: we get values of row 101, expecting 102)

    So I strongly suggest to avoid using these env vars with Informix 4GL 7.51

    Seb



    ------------------------------
    Sebastien FLAESCH
    ------------------------------