Programmeren in COBOL/Embedded SQL

Uit Wikibooks

Programmeren in COBOL

Inhoudsopgave

  1. Groepsvelden en conditie met voorwaardenaam Zeer goed ontwikkeld. Revisiedatum: 21 oktober 2007 (Oef Nog vrijwel niets. Revisiedatum: 20 november 2007 )
  2. Tabellen Goed ontwikkeld. Revisiedatum: 21 oktober 2007 (Oef Nog vrijwel niets. Revisiedatum: 20 november 2007 )
  3. Editing Zeer goed ontwikkeld. Revisiedatum: 16 november 2007 (Oef Nog vrijwel niets. Revisiedatum: 20 november 2007 )
  4. Embedded SQL Redelijk ontwikkeld. Revisiedatum: 21 oktober 2007



In COBOL kan SQL-code opgenomen worden om gegevens uit databanken te gebruiken en te bewerken. Een voorbeeld is DB2 op mainframe (z/OS). De precompiler haalt alle blokken die beginnen met EXEC SQL en eindigen met END-EXEC eruit, en laat ze door DB2 binden.

Singleton SELECT

Indien we slechts één rij zullen lezen:

COBOL + embedded SQL-code: Singleton SELECT

       IDENTIFICATION DIVISION.
       PROGRAM-ID. Student.

       DATA DIVISION.
       WORKING-Storage section.
       01 studid     PIC X(7).
       01 achternaam PIC X(10).

       PROCEDURE DIVISION.
       HOOFD.
           DISPLAY "Geef het studentennummer"
           ACCEPT studid
           EXEC SQL
              SELECT achtern INTO :achternaam 
              FROM leerlingen
              WHERE sid = :studid
           END-EXEC
           DISPLAY "De gezochte persoon heeft als achternaam " achternaam
           STOP RUN.

De COBOL-variabelen worden in de SQL-statements voorafgegaan door een dubbelpunt. Op dezelfde manier kan een UPDATE of INSERT uitgevoerd worden:

COBOL + embedded SQL-code: Singleton UPDATE

           EXEC SQL
              UPDATE leerlingen
              SET achtern = :achternaam
              WHERE sid = :studid
           END-EXEC

COBOL + embedded SQL-code: Singleton INSERT

           EXEC SQL
              INSERT
              INTO leerlingen (sid, achtern)
              VALUES (:studid, :achternaam)
           END-EXEC

Indien je er niet zeker van bent of je slechts één resultaat zal hebben (omdat je niet selecteert op basis van een unieke index (zoals een primaire sleutel), dan kan je gebruik maken van FETCH FIRST ROW ONLY.

COBOL + embedded SQL-code: FETCH FIRST ROW ONLY

           EXEC SQL
              SELECT achtern INTO :achternaam 
              FROM leerlingen
              WHERE sid = :studid
              FETCH FIRST ROW ONLY
           END-EXEC

SELECT met CURSOR

Bij meerdere rijen, laat een CURSOR ons toe om de opgevraagde tabel die door het DBMS bijgehouden wordt, rij per rij op te vragen. Zoals bij het werken met bestanden, moet de query geopend (OPEN), gelezen (FETCH) en weer gesloten (CLOSE) worden. Bij OPEN wordt hij in het geheugen geladen en beschikbaar gehouden tot het CLOSE-commando dit geheugen weer vrijmaakt.

COBOL + embedded SQL-code: Meervoudige SELECT

       IDENTIFICATION DIVISION.
       PROGRAM-ID. Student.

       DATA DIVISION.
       WORKING-Storage section.
       01 voornaam PIC X(10).
           EXEC SQL
              INCLUDE SQLCA
           END-EXEC. 
           EXEC SQL
              INCLUDE leraar-tabel-declaratie
           END-EXEC. 
           EXEC SQL
              DECLARE crs CURSOR FOR
              SELECT voorn 
              FROM leraars
              WHERE vak = 'WISKUNDE'
           END-EXEC. 

       PROCEDURE DIVISION.
       HOOFD.
           DISPLAY "Hierna volgen alle voornamen van leraars die wiskunde geven:
           EXEC SQL
              OPEN crs
           END-EXEC
           PERFORM UNTIL SQLCODE NOT = 0.
            EXEC SQL
               FETCH crs INTO :voornaam
            END-EXEC
            DISPLAY voornaam
           END-PERFORM
           EXEC SQL
              CLOSE crs
           END-EXEC
           STOP RUN.

In bovenstaand programma wordt met INCLUDE extra COBOL-code van elders opgehaald door de precompiler. SQLCA (SQL communication area) wordt automatisch door het DBMS gegenereerd en bevat de foutcode SQLCODE en . Een tabeldefinitie kan met een commando (DCLGEN) aangemaakt worden, samen met de declaratie van de gelijknamige overeenkomstige COBOL-variabelen. Dit gegenereerde bestand kan ook met INCLUDE opgehaald worden. Op die manier hoeft de programmeur niet uit te vissen van welk overeenkomstig COBOL-datatype de DB2-variabelen zijn.

COBOL + embedded SQL + embedded SQL-code: leraar-tabel-declaratie (voor INCLUDE)

       01 leraar.
         02 lid   PIC 9(3).
         02 voorn PIC X(10).
         02 vak   PIC X(10).

       EXEC SQL
         DECLARE leraars
          ( lid   SMALLINT NOT NULL,
            voorn CHAR(10),
            vak   CHAR(10)
          )
       END-EXEC.

Hieronder een overzicht van hoe DB2-variabelen kunnen omgezet worden naar COBOL-variabelen:

SQL-DB2 COBOL
var CHAR(4),
var PIC X(4).
SMALLINT,
PIC S9(4) COMP.
DECIMAL (9,2),
PIC S9(7)V9(2) COMP-3.
var VARCHAR (60),
01 var.
  49 lengte PIC S9(4) COMP.
  49 tekst  PIC X(60).

Merk op dat bij een VARCHAR, de overeenkomstige COBOL-variabele opgesplitst wordt in twee level-49 variabelen waarvan de eerst de 2 extra bytes voorstelt die de eigenlijke lengte van het veld bijhouden.

UPDATE met CURSOR

Het volstaat om FOR UPDATE OF variabele toe te voegen, zodat er een update-lock (U; zie locking) op de tabel geplaatst wordt door DB2. Hierdoor kunnen andere gebruikers niet tegelijkertijd deze rij wijzigen, waardoor inconsistente data zouden ontstaan. Met WHERE CURRENT OF crs kan je dan aanduiden waar er iets moet veranderen.

COBOL + embedded SQL-code: Meervoudige UPDATE

           EXEC SQL
              DECLARE crs CURSOR FOR
              SELECT voorn 
              FROM leraars
              WHERE vak = 'WISKUNDE'
              FOR UPDATE OF vak
           END-EXEC. 
...
          EXEC SQL
             OPEN crs
          END-EXEC
          EXEC SQL
             FETCH crs INTO :voornaam
          END-EXEC
          PERFORM update UNTIL SQLCODE NOT = 0
          EXEC SQL
             CLOSE crs
          END-EXEC
          
      update.
          EXEC SQL
             UPDATE leraars
             SET vak = 'MEETKUNDE'
             WHERE CURRENT OF crs
          END-EXEC
          EXEC SQL
             FETCH crs INTO :voornaam
          END-EXEC
          .

NULLs

Databanksystemen kennen naast (alfa)numerieke waarden, ook het concept "NULL", met alle problemen van dien (zie driewaardige logica). Bij embedded SQL kan een extra NULL-indicator gedefinieerd worden, die -1 wordt indien er een NULL overgedragen wordt tussen het databanksysteem en COBOL: "01 indicator PIC S9(4) COMP." In een SQL-statement wordt dan de indicator onmiddellijk na de variabele geplaatst (met of zonder spatie ertussen): "... INTO :voornaam:indicator ... "

COBOL + embedded SQL-code: NULL-indicator

       01 naam   PIC X(10).
       01 naam-i PIC S9(4) COMP.
       01 postnr PIC 9(4).
       01 post-i PIC S9(4) COMP.
...
          EXEC SQL
            SELECT dorpnaam, postnummer
            INTO :naam:naam-i, :postnr:post-i
            FROM dorpen
            WHERE postnummer = :postnr
          END-EXEC

COBOL + embedded SQL-code: NULL-indicator-rij

       01 dorp.
         02 naam    PIC X(10).
         02 postnr  PIC 9(4).
       01 indicator PIC S9(4) COMP OCCURS 2.
...
          EXEC SQL
            SELECT dorpnaam, postnummer
            INTO :naam:indicator(1), :postnr:indicator(2)
            FROM dorpen
            WHERE postnummer = :postnr
          END-EXEC

Omdat SQLCODE uit SQLCA van het datatype COMP is, en dus niet toonbaar is, moet je ze eerst overbrengen naar een zelf te definiëren variabele van het type PIC S9(3):

COBOL + embedded SQL-code: NULL-indicator-test

           01 leesbare-code PIC S9(3).
...
          MOVE SQLCODE TO leesbare-code
          IF SQLCODE < 0
            DISPLAY 'Even Apeldoorn bellen: error ' leesbare-code
          ELSE
            DISPLAY 'Alles OK'
          END-IF

Dynamische SQL

Sommige programma's moeten telkens een andere SQL-code uitvoeren. Denk maar aan het programma waarmee je SQL leert en verschillende SQL-statements uittest. Met PREPARE kan je een SQL-statement stap voor stap opbouwen; Met IMMEDIATE kan je een SQL-statement onmiddellijk uitvoeren:

COBOL + embedded SQL-code: PREPARE

       01 sqltekst.
         02 lengte PIC S9(4) COMP VALUE 250.
         02 inhoud PIC X(250).
       01 pid PIC X(4)

           EXEC SQL
             DECLARE crs CURSOR FOR STMT
           END-EXEC.
...
          MOVE 'SELECT pid FROM personen' TO inhoud
          MOVE 'WHERE pid > ?' TO inhoud(25:)
          EXEC SQL
            PREPARE STMT FROM :sqltekst
          END-EXEC
          ACCEPT pid
          EXEC SQL
            OPEN crs USING :pid 
          END-EXEC
          EXEC SQL
            FETCH crs INTO :pid 
          END-EXEC
          PERFORM UNTIL SQLCODE NOT = 0
           DISPLAY 'pid = ' pid
           EXEC SQL
             FETCH crs INTO :pid 
           END-EXEC
          END-PERFORM
          MOVE 'CLOSE crs' TO inhoud
          EXEC SQL
            EXECUTE IMMEDIATE :sqltekst 
          END-EXEC
Informatie afkomstig van https://nl.wikibooks.org Wikibooks NL.
Wikibooks NL is onderdeel van de wikimediafoundation.