Search code examples
sqldb2cobol

How to use parameter markers in sql / cobol


I have to write a COBOL program that reads some records from a file and does some computation with them. If the routine is called with a non-blank filter, results, should be filtered.

I tried to use parameter markers in SQL. Here's my attempt:

    100        IDENTIFICATION DIVISION.                                                                                 19/11/07
    200        PROGRAM-ID.    MINIMALEX.                                                                                01/07/20
    300        AUTHOR.        ME.                                                                                       01/07/20
    400        DATE-WRITTEN.  JULY 2020.                                                                                01/07/20
    500       *----------------------------------------------------------------*                                        01/07/20
    600       *--- Minimal example.                                         ---*                                        01/07/20
    700       *----------------------------------------------------------------*                                        01/07/20
    800        ENVIRONMENT DIVISION.                                                                                    19/11/07
    900        CONFIGURATION SECTION.                                                                                   19/11/07
   1000        SOURCE-COMPUTER. IBM-AS400.                                                                              19/11/07
   1100        OBJECT-COMPUTER. IBM-AS400.                                                                              19/11/07
   1200        SPECIAL-NAMES. DECIMAL-POINT IS COMMA.                                                                   28/12/10
   1300       *----------------------------------------------------------------*                                        01/07/20
   1400        INPUT-OUTPUT SECTION.                                                                                    19/11/07
   1500        FILE-CONTROL.                                                                                            19/11/07
   1600       *----------------------------------------------------------------*                                        19/11/07
   1700        DATA DIVISION.                                                                                           19/11/07
   1800        FILE SECTION.                                                                                            19/11/07
   1900       *----------------------------------------------------------------*                                        19/11/07
   2000        WORKING-STORAGE SECTION.                                                                                 19/11/07
   2100       *--- Variables for SQL.                                                                                   01/07/20
   2200            EXEC SQL                                                                                             01/07/20
   2300              INCLUDE SQLCA                                                                                      01/07/20
   2400            END-EXEC.                                                                                            01/07/20
   2500            EXEC SQL                                                                                             01/07/20
   2600              INCLUDE SQLDA                                                                                      01/07/20
   2700            END-EXEC.                                                                                            01/07/20
   2800                                                                                                                 01/07/20
   2900        01  WK-NAME                        PIC X(80).                                                            01/07/20
   3000        01  WK-LASTNAME                    PIC X(80).                                                            01/07/20
   3100        01  WK-SELECT                      PIC X(34).                                                            01/07/20
   3200        01  WK-WHERE                       PIC X(65).                                                            01/07/20
   3300        01  WK-STATEMENT                   PIC X(100).                                                           01/07/20
   3400       *----------------------------------------------------------------*                                        01/07/20
   3500        LINKAGE SECTION.                                                                                         19/11/07
   3600        01  LK-NAME                        PIC X(80).                                                            01/07/20
   3700       *----------------------------------------------------------------*                                        01/07/20
   3800        PROCEDURE DIVISION USING LK-NAME.                                                                        01/07/20
   3900       *----------------------------------------------------------------*                                        01/07/20
   4000        A01-START.                                                                                               01/07/20
   4100       *--- Create and insert data into file.                                                                    01/07/20
   4200            EXEC SQL                                                                                             01/07/20
   4300                 DROP TABLE QTEMP/T                                                                              01/07/20
   4400            END-EXEC.                                                                                            01/07/20
   4600            EXEC SQL                                                                                             01/07/20
   4700                 CREATE TABLE QTEMP/T                                                                            01/07/20
   4800                        (NAME CHAR (80), LASTNAME CHAR (80))                                                     01/07/20
   4900            END-EXEC.                                                                                            01/07/20
   5100            EXEC SQL                                                                                             01/07/20
   5200                 INSERT INTO QTEMP/T VALUES ("ALFRED", "HITCHCOCK")                                              01/07/20
   5300            END-EXEC.                                                                                            01/07/20
   5500                                                                                                                 01/07/20
   5600            MOVE 'SELECT NAME, LASTNAME FROM QTEMP/T' TO WK-SELECT.                                              01/07/20
   5700                                                                                                                 21/03/08
   5800            MOVE SPACES TO WK-WHERE.                                                                             01/07/20
   5900            MOVE 0 TO SQLN.                                                                                      01/07/20
   6000                                                                                                                 01/07/20
   6100            IF LK-NAME NOT = SPACES                                                                              01/07/20
   6200               STRING 'WHERE NAME LIKE ("%" CONCAT '                                                             01/07/20
   6300                      'TRIM(CAST(? AS CHAR(80))) CONCAT "%")'                                                    01/07/20
   6400                      DELIMITED BY SIZE INTO WK-WHERE                                                            01/07/20
   6500               ADD 1 TO SQLN                                                                                     01/07/20
   6600            END-IF.                                                                                              01/07/20
   6700                                                                                                                 28/04/08
   6800            STRING WK-SELECT DELIMITED BY SIZE                                                                   01/07/20
   6900                   ' '       DELIMITED BY SIZE                                                                   01/07/20
   7000                   WK-WHERE  DELIMITED BY '   ' INTO WK-STATEMENT                                                01/07/20
   7100            END-STRING.                                                                                          21/04/08
   7200                                                                                                                 30/06/20
   7300            EXEC SQL                                                                                             30/06/20
   7400                 PREPARE STMT FROM :WK-STATEMENT                                                                 01/07/20
   7500            END-EXEC.                                                                                            30/06/20
   7700            EXEC SQL                                                                                             30/06/20
   7800                 DESCRIBE INPUT STMT INTO :SQLDA                                                                 01/07/20
   7900            END-EXEC.                                                                                            30/06/20
   8100                                                                                                                 21/04/08
   8200       *--- Setting values for SQLDA.                                                                            01/07/20
   8300            IF LK-NAME NOT = SPACES                                                                              01/07/20
   8400               SET SQLDATA(1) TO ADDRESS OF LK-NAME                                                              01/07/20
   8500            END-IF.                                                                                              01/07/20
   8600                                                                                                                 30/06/20
   8700            EXEC SQL                                                                                             21/04/08
   8800                 DECLARE SQL_LIST CURSOR FOR STMT                                                                01/07/20
   8900            END-EXEC.                                                                                            21/04/08
   9000                                                                                                                 21/04/08
   9100            EXEC SQL                                                                                             21/04/08
   9200                 OPEN SQL_LIST                                                                                   01/07/20
   9300            END-EXEC.                                                                                            21/04/08
   9500                                                                                                                 21/04/08
   9600        A01-FETCH.                                                                                               01/07/20
   9700            EXEC SQL                                                                                             01/07/20
   9800                 FETCH NEXT FROM SQL_LIST INTO :WK-NAME, :WK-LASTNAME                                            01/07/20
   9900            END-EXEC.                                                                                            01/07/20
  10100            IF SQLCODE NOT = 0                                                                                   01/07/20
  10200               GO TO A01-CLOSE                                                                                   01/07/20
  10300            END-IF.                                                                                              01/07/20
  10400                                                                                                                 01/07/20
  10500       *--- Do some stuff with the fetched data, then fetch next row.                                            01/07/20
  10600            GO TO A01-FETCH.                                                                                     01/07/20
  10700                                                                                                                 21/04/08
  10800        A01-CLOSE.                                                                                               01/07/20
  10900            EXEC SQL                                                                                             13/02/20
  11000                 CLOSE SQL_LIST                                                                                  01/07/20
  11100            END-EXEC.                                                                                            13/02/20
  11300                                                                                                                 13/02/20
  11400        A01-END.                                                                                                 01/07/20
  11500            GOBACK.                                                                                              01/07/20

Unfortunately, when I run the program (giving a vAlue other than blank to LK-NAME), the OPEN statement returns a SQLCODE -313 (The number of host variables specified in the EXECUTE or OPEN statement is not the same as the number of parameter markers (question marks) appearing in the prepared SQL statement.) It seems to me that the number of both host variables and parameter markers is 1, so where's the problem?

EDIT

Following Charles' suggestion, line 9200 was changed to

OPEN SQL_LIST USING DESCRIPTOR :SQLDA

This now gives SQLCODE -822.

EDIT 2

Upon further research, I understood that each host variable must be associated to an indicator variable in the linkage section and that occurrences of SQLIND must be to addresses of those indicator variables. Thanks @Charles


Solution

  • Knowing the platform would be helpful..

    However, I'd expect see the variable you intend to use in the parameter makers in your open statement.

    EXEC SQL
      OPEN SQL_LIST USING :LK-NAME
    END-EXEC.
    

    The open statement is where the value used to replace the parameter marker is replaced.

    Having said that, you may want to consider static SQL instead of dyanmic.

    Static SQL doesn't have to be prepared...it'd just look like

    EXEC SQL
      DECLARE SQL_LIST CURSOR FOR
       SELECT NAME, LASTNAME FROM QTEMP/T
       WHERE :LK-NAME = ' '
             OR NAME LIKE ( '%' CONCAT TRIM(:LK-NAME) CONCAT '%')
    END-EXEC.
    
    EXEC SQL
      OPEN SQL_LIST
    END-EXEC.
    

    note that even here, the value of LK-NAME is passed in at the time the cursor is opened, the DECLARE CURSOR is really a compile time statement.

    EDIT
    You can use the descriptor area, if that case the open would specify OPEN…USING DESCRIPTOR descriptor-name according to the docs. I've honestly never done it that way.

    You have read through the embedded SQL programming manual correct?

    Yes, generally a static statement is faster. As long as it's not too complex compared to the dynamic version.