5

I am trying to move from Oracle to PostgreSQL on GnuCOBOL. I have a piece of code which uses cursors and need opening a cursor multiple times. However when trying to open the cursor again I get the error ERROR: cursor "fetchtbl_c1" already exists

        IDENTIFICATION              DIVISION.
        PROGRAM-ID.                 FETCHTBL.

        DATA                        DIVISION.
        WORKING-STORAGE             SECTION.
        01  D-SOC-REC.
            05  D-SOC-NO-1          PIC  X(3).
            05  FILLER              PIC  X.
            05  D-SOC-NO-2          PIC  X(3).

        EXEC SQL BEGIN DECLARE SECTION END-EXEC.
        01  USERNAME                PIC  X(30) VALUE SPACE.
        01  SOC-REC-VARS.
            05  SOC-NO-1            PIC X(3).
            05  SOC-NO-2            PIC X(3).
        EXEC SQL END DECLARE SECTION END-EXEC.

        EXEC SQL INCLUDE SQLCA END-EXEC.
        PROCEDURE                   DIVISION.
        MAIN-RTN.
            MOVE  SPACE             TO   USERNAME.
            EXEC SQL
                CONNECT :USERNAME
            END-EXEC.
            IF  SQLCODE NOT = ZERO DISPLAY "ERROR CONNECTING".

       *    DECLARE CURSOR
            EXEC SQL
                DECLARE C1 CURSOR FOR
                SELECT SOC_NO_1, SOC_NO_2
                       FROM INSP
                       ORDER BY SOC_NO_1
            END-EXEC.
            EXEC SQL
                OPEN C1
            END-EXEC.
            IF SQLCODE = ZERO DISPLAY "OPEN SUCCESSFUL"
            ELSE DISPLAY "OPEN FAILED".

       *    FETCH
            EXEC SQL
                FETCH C1 INTO :SOC-NO-1,:SOC-NO-2
            END-EXEC.
            IF SQLCODE = ZERO DISPLAY "FETCH SUCCESSFUL"
            ELSE DISPLAY "FETCH FAILED".
            PERFORM UNTIL SQLCODE NOT = ZERO
               MOVE  SOC-NO-1      TO    D-SOC-NO-1
               MOVE  SOC-NO-2      TO    D-SOC-NO-2
               DISPLAY D-SOC-REC
               EXEC SQL
                   FETCH C1 INTO :SOC-NO-1,:SOC-NO-2
               END-EXEC
            END-PERFORM.

       *    CLOSE CURSOR
            EXEC SQL
                CLOSE C1
            END-EXEC.
            IF SQLCODE = ZERO DISPLAY "CLOSE SUCCESSFUL"
            ELSE DISPLAY "CLOSE FAILED".

       *    OPEN AGAIN
            EXEC SQL
                OPEN C1
            END-EXEC.
            IF SQLCODE = ZERO DISPLAY "REOPEN SUCCESSFUL"
            ELSE DISPLAY "REOPEN FAILED " SQLERRMC.
       *    COMMIT
            EXEC SQL
                COMMIT WORK
            END-EXEC.

       *    DISCONNECT
            EXEC SQL
                DISCONNECT ALL
            END-EXEC.

       *    END
            STOP RUN.

Pre-compiled the code using ocesql and compiled using cobc -x

Postgres Output

OPEN SUCCESSFUL
FETCH SUCCESSFUL
003 001
005 001
CLOSE SUCCESSFUL
REOPEN FAILED ERROR:  cursor "fetchtbl_c1" already exists

The above code works perfectly fine (except for connection part) in Oracle.

Oracle output

OPEN SUCCESSFUL
FETCH SUCCESSFUL
003 001
CLOSE SUCCESSFUL
REOPEN SUCCESSFUL

I have tried searching on the internet but without any luck. Anybody can help me with this? I am using PostgreSQL version 10.3 and GnuCOBOL version 2.2.0.

Ankit Jain
  • 314
  • 3
  • 10
  • A shot in the dark: can you try `deallocate`ing the prepared statement (behind the cursor)? https://www.postgresql.org/docs/current/static/sql-deallocate.html –  Apr 19 '18 at 13:58
  • I am not using prepare statement. As you can see the code above, its a direct cursor. The problem is I have 1000s of components which need to be changed if I am going to make use of prepared statement. – Ankit Jain Apr 19 '18 at 14:03
  • My thought was that the cursor implicitly creates (or uses) a prepared statement (from Postgres' point of view). A `deallocate all` after closing the cursor could verify that theory. –  Apr 19 '18 at 14:07
  • Just tried this, sadly this doesn't work. I have checked `SQLCODE` after `DEALLOCATE ALL` which is successful but still getting the same error `ERROR: cursor "fetchtbl_c1" already exists` – Ankit Jain Apr 19 '18 at 14:16
  • I’m thinking if this could be a pre-compiler issue? The last update for ocesql precompiler was in Jan 2015. Tomorrow I’ll search for a new pre-compiler or if anybody knows any good pre-compiler that works with PostgreSQL then it would be helpful. – Ankit Jain Apr 19 '18 at 14:43
  • 1
    What version of ocesql and what OS did you use? Did you tried [esqlOC](https://sourceforge.net/p/open-cobol/contrib/HEAD/tree/trunk/esql/, too? This would mean to use COBOL<->ODBC(via ocsql library)<->PostgreSQL. Note: I've checked your sample code and esqlOC currently does not support `DISCONNECT` yet, at least adding `DISCONNECT ALL` should be possible to do quick. But this only makes sense if the other parts work for you... – Simon Sobisch Apr 19 '18 at 18:56
  • I am using ocesql version 1.1.0 (February 27, 2015) on Linux (RHEL 7.4), so I guess its a bit old. I will try with esqlOC today. Thanks for the link. Will update once I am able to test esqlOC. – Ankit Jain Apr 20 '18 at 04:39
  • @SimonSobisch Could you provide the set-up for unixODBC driver (odbc.ini) to use PostgreSQL in GnuCOBOL (connection string in the program)? Note: I am using peer authentication method. – Ankit Jain Apr 20 '18 at 06:01
  • @SimonSobisch `esqlOC` didn't work for me as it doesn't support `PREPARE` statements. However, I think I found an issue in `ocesql` code and fixed a statement in `ocdb.c` and things are working fine as of now :) – Ankit Jain Apr 20 '18 at 10:25

1 Answers1

0

There seemed to be an issue with ocesql pre-compiler. I have put a fix in ocdb.c in function OCDBSetResultStatus to return a successful code in case there is not result resource (which happens for open cursor case).

This might not be entirely correct but after spending a few hours testing I see this working fine.

Code changes:

int
OCDBSetResultStatus(int id, struct sqlca_t *st){
    struct s_conn *p_conn;
    int retval;

    p_conn = look_up_conn_lists(id);
    if(p_conn == NULL){
      //return OCDB_RES_FATAL_ERROR;
        return RESULT_ERROR;
    }
    if(p_conn->resaddr == OCDB_RES_DEFAULT_ADDRESS){
        // 結果リソースが無いため成功で返す
        // Ankit: uncommented since there is no result resource,
        //        (true in case of open cursor)
        return OCDB_RES_COMMAND_OK;
        //return RESULT_ERROR;
    }

#ifdef PGSQL_MODE_ON
    retval = OCDB_PGSetResultStatus(p_conn->resaddr,st);
#endif
    return retval;
}

Let me know if anybody faces any issues because of this change.

Ankit Jain
  • 314
  • 3
  • 10
  • 1
    Seems like a reasonable PR to be posted at https://github.com/opensourcecobol/Open-COBOL-ESQL/blob/develop/dblib/ocdb.c with also creating an issue that includes your sample code posted in the question, your explanation and referencing the PR. – Simon Sobisch Apr 20 '18 at 19:52