MainframeSupports
tip uge 29/2015:

Som lovet i mit forrige tip vil jeg i dette tip skrive om, hvordan du bruger IBM's eget REXX-interface mod DB2 til at udføre SELECT SQL statements. Det er nemlig en kende mere kompliceret, især i sammenligning med mange af de andre DB2/REXX-interfaces, der er lavet gennem tiden.

Lad mig springe direkte ud i det:

/* REXX */
SUBCOM DSNREXX
IF RC THEN X=RXSUBCOM('ADD','DSNREXX','DSNREXX')
CALL SQLEXEC 0, "CONNECT MYDB"
CALL SQLEXEC 0, "EXECSQL SET CURRENT PACKAGESET='DSNREXCS'"

SQLSTMT="SELECT SUBSTR(CREATOR, 1, 8), SUBSTR(NAME, 1, 18)",
        "FROM SYSIBM.SYSTABLES",
        "WHERE CREATOR = 'SYSIBM'",
        "  AND TYPE = 'T'"
CALL SQLSELECT

CALL SQLEXEC 0, "EXECSQL COMMIT"
CALL SQLEXEC 0, "DISCONNECT"
RC=RXSUBCOM('DELETE','DSNREXX','DSNREXX')
EXIT

SQLSELECT:
  ROWS = 0
  CALL SQLEXEC 0, "EXECSQL DECLARE C1 CURSOR FOR S1"
  CALL SQLEXEC 0, "EXECSQL PREPARE S1 INTO :OUTSQLDA FROM :SQLSTMT"
  CALL SQLEXEC 0, "EXECSQL OPEN C1"
  CALL SQLEXEC 100, "EXECSQL FETCH C1 USING DESCRIPTOR :OUTSQLDA"
  DO WHILE(SQLCODE = 0)
    ROW = ''
    SEP = ''
    DO COLNO = 1 TO OUTSQLDA.SQLD
      ROW = ROW''SEP''OUTSQLDA.COLNO.SQLDATA
      SEP = ' '
    END
    SAY ROW
    CALL SQLEXEC 100, "EXECSQL FETCH C1 USING DESCRIPTOR :OUTSQLDA"
  END
  CALL SQLEXEC 0, "EXECSQL CLOSE C1"
RETURN

SQLEXEC:
  ARG ACCEPT, STMT
  ADDRESS DSNREXX STMT
  IF SQLCODE <> 0 & SQLCODE <> ACCEPT
  THEN
    IF WORD(STMT,1) = 'EXECSQL'
    THEN
      SAY WORD(STMT,2)': SQLCODE='SQLCODE
    ELSE
      SAY WORD(STMT,1)': SQLCODE='SQLCODE
RETURN

Den kvikke læser vil straks bemærke, at programmet i forhold til forrige tip ligner sig selv bortset fra, at der er kommet en hel procedure til, der håndterer eksekveringen af et SELECT statement. Og så er det ene statement, der udførte ikke-SELECT SQL'et blevet erstattet med et kald til den nye procedure. Den ekstra kvikke læser vil også bemærke, at de to sidste linier før RETURN i SQLEXEC proceduren er forsvundet. De er fjernet, fordi det virker ret dumt at skrive en masse FETCH statements ud, så længe de gør, hvad de skal.

Først udføres en DECLARE, som faktisk er overflødig, men alle eksempler i diverse IBM manualer har den med. Det vigtige er, at bruge navnet C1 for cursoren og S1 for statementet. Hvis du får brug for at have to cursore åbne samtidig, så benyt C2 og S2 og så fremdeles. Efter den overflødige DECLARE udføres en såkaldt PREPARE af SQL statementet. Det er her, at DB2 finder accessvejen for dit SELECT statement. Det svarer faktisk til en BIND af SELECT'en. Retur får REXX'en en variabel, som jeg har valgt at kalde OUTSQLDA. Denne variabel er faktisk en STEM-variabel med alle de informationer, der skal til for at kommunikere resultatet af dit SELECT statement fra DB2 over i REXX.

Resten af programmet ligner et hvilket som helst PLI eller COBOL program, der behandler en SQL cursor. Den store forskel ligger i at få data ud af STEM-variablen, som assignes indholdet af en række for hver FETCH. I STEM-variablen er der en variabel for hver kolonne i rækken. Indholdet af den første kolonne findes i OUTSQLDA.1.SQLDATA, den næste kolonnes værdi i OUTSQLDA.2.SQLDATA og så fremdeles. Læg mærke til, at jeg har brugt SUBSTR for hver af de to kolonner, jeg henter. Det gør jeg for at få de to kolonner til at stå pænt under hinanden, når jeg udskriver de opbyggede rækker en for en. Du skal altså selv stå for at formatere data, hvis du som i dette eksempel skal have rækkerne til at stå i de samme positioner fra række til række. Du skal dog ikke sørge for at konvertere de forskellige datatyper. Det klarer interfacet for dig.

Der er flere informationer i OUTSQLDA ud over selve indholdet af kolonnen for den pågældende række, bare så du ved, at der er mere information at hente. Hvis du har prøvet at kode dynamisk SQL fra PLI eller COBOL, så vil du selvfølgelig bemærke, at der næsten ikke er nogen forskel i forhold til DSNREXX interfacet. IBM har ikke forsøgt at skjule ret meget af den bagvedliggende teknik, som der ellers er tradition for, når der laves REXX interfaces. Det synes jeg er ærgerligt, for det er med til at gøre IBM's REXX interface meget lidt brugervenligt og ikke særligt REXX-agtigt.

Forrige danske tip        Last tip in english        Tip oversigten