GDG Generic Database Gateway

GDG GDG (Generic Database Gateway) is a solution that allows to keep as is your MVS DB2 COBOL applications replacing DB2 for z/OS with a DBMS on Open system: DB2 LUW or Oracle, Postgres, MySQL, cutting DB2 for z/OS licensing costs and CPU costs.

Introduction

  1. General Concept
  2. GDG Preprocessor
  3. GDG batch utility
  4. GDG C langage API

Annexes

  1. GDG Area COBOL structure
  2. GDG Area header for C program
  3. Sample use of GDG COBOL preprocesseur
  4. Sample use of GDGUTIL utility on MVS

1 - General Concept

GDG runs in Client/Server mode.

Server side:

Server side runs on a UNIX/Linux system that has access to target DMBS engine using standard SQL API("exec sql ..."), normaly featuring within the DMBS Client.

It runs as a TCP/IP standard service, listening on a choosen port.

Fig.1 Client/Server organisation

Client side:

Client side runs on z/OS: it is the COBOL applications.

It consists of a COBOL pre-compiler, a batch utility, and a proprietary API (LOADLIB).

The COBOL precompiler processes a COBOL program containing 'EXEC GDG ...' statements, and builds a COBOL program with GDG API specific calls.

The GDGUTIL batch program uses tha GDG API : it reads SQL requests from system logical output (SYSPIN on z/OS, stdin on USS). sends to GDG Server that executes, then sends results on system logical output (SYSPRINT on z/OS, stdout on USS).

The API allows call to Stored Procedures on server, raw SQL requests, and to retreive results either on a row per row mode, either on one field-separated record, either stored into user variables.

Available Platforms:

GDG Client
Item z/OS USS OMVS
GDG API Ready Ready
COBOL Precompiler Ready Ready
GDGUTIL batch tool Ready Ready

GDG Server
SGBD z/Linux Linux-x86 AIX Solaris
PostGreSQL Ready Ready Ready Ready
MySQL Ready Ready Ready Ready
DB2 UDB Ready Ready Ready Ready
Oracle Ready Ready Ready Ready
Top of Document

2 - GDG Preprocesseur

GDG preprocessor is for COBOL Developers.

It processes 'EXEC GDG' clauses in COBOL programs and turns corresponding GDG API calls.

It includes necessary work areas in the WORKING-STORAGE SECTION, in particular 'GDG-AREA' communication area, and its 2 return-codes: GDGRC and SQLRC.

Sous MVS, il lit le programme à transformer par le DDNAME 'FGDG', et produit le résultat par le DDNAME 'FCOB'.

Sous USS, ces deux fichiers sont passés en paramètres dans la ligne de commande, et valent par défaut stdin et stdout :

 gdg2cob fichier-gdg fichier-cobol
ou
 gdg2cob < fichier-gdg  > fichier-cobol 
Le préprocesseur reconnaît et traite les primitives suivantes (c.f. Fig.2): Début / fin de session :

  • EXEC GDG 'INIT'.
  • EXEC GDG 'CONNECT' USING dbalias connectstring.
  • EXEC GDG 'CLOSE'.
Exécution de Procédure ou commande SQL :

  • EXEC GDG 'CALLPROC' USING procname [ param1 [ param2 ...] ].
  • EXEC GDG 'SENDSQL' USING requete.
Lecture des résultats :

  • EXEC GDG 'SETREPLY' USING { 'GDG-PARSE' | 'GDG-NO-PARSE' } .
  • EXEC GDG 'GETREPLY' [ USING champ1 [champ2 ...] ].

API GDG COBOL
Fig. 2 - Structure générale d'un programme COBOL en API GDG.

Une clause EXEC GDG suit les règles de présentation des programmes COBOL : elle peut occuper plusieurs lignes et elle doit se terminer par un '.'

Les divers paramètres (dbalias, connectstring, procname, param1,...) s'expriment :

  • soit directement sous forme d'une constante alphanumérique,
  • soit sous forme d'une variable COBOL (qui doit être définie avec le type USAGE IS DISPLAY), et précédée de ":"


La primitive 'INIT' permet à l'API d'initialiser sa zone de communication ('GDG-AREA'), automatiquement générée avec toutes les autres zone de travail de l'API par le préprocesseur 'GDG2COB'.

Codes Retour
néant


La primitive 'CONNECT' établi la liaison avec le serveur GDG, et authentifie le programme vis à vis de la base de données concernée:
  • le paramètre dbalias (variable ou constante alphanumérique) indique la base, l'instance ou l'alias à utiliser;
  • le paramètre connectstring (variable ou constante alphanumérique) est de la forme 'userid[:passwd]@hostname[:port]' ;
    noter que certaines valeurs de ce paramètre sont facultatives et que les valeurs par défaut sont des constantes d'installation.
Codes Retour
GDGRC : 0 si OK,
            <> 0 si liaison TCPIP ou accès à la database impossible.
SQLRC : néant


La primitive 'CALLPROC' admet au moins un paramètre : le nom de la procédure cataloguée à éxecuter (variable ou constante alphanumérique).
Les arguments, facultatifs, sont passés sous forme de constantes alphanumériques ou de variables.

Codes Retour
GDGRC : 0 si OK,
            1001, 1002, ... (1000 + n) : le nème paramètre est invalide,
            autres : liaison TCPIP interrompue.
SQLRC : néant


La primitive 'SENDSQL' n'admet qu'un seul paramètre : la requête SQL, soit sous forme d'une contante alphanumérique, soit sous forme d'une variable.

Codes Retour
GDGRC : 0 si OK,
            <> 0 si liaison TCPIP ou accès à la database interrompue.
SQLRC : néant


La primitive 'SETREPLY' permet d'indiquer à l'API la manière de traiter les résultats d'une commande SQL de type 'SELECT' :

  • Le paramètre 'GDG-PARSE' indique que ces résultats seront découpés champ par champ dans les variables COBOL de la prochaîne commande 'GETREPLY'.
  • Le paramètre 'GDG-NO-PARSE' indique que chaque ligne de résultat est à ranger telle quelle dans la variable COBOL de la prochaîne commande 'GETREPLY', ou bien que ces résultats sont sans intérêt (pas de variable.).
Codes Retour
GDGRC : néant
SQLRC : néant


La primitive 'GETREPLY' n'admet aucune constante, mais seulement une liste facultative de variables où l'API doit déposer les résultats de la requête précédente.

Elle est obligatoire après chaque primitive 'SENDSQL' ou 'CALLPROC'.

Codes Retour
GDGRC : 0 si OK,
            1001, 1002, ... (1000 + n) : le n-ième paramètre est invalide.
            autres : liaison TCPIP interompue.
SQLRC : 0 : Ok
            100 : plus de résultats en magasin.
            autres ( en général < 0) : codes propres au moteur SQL impliqué.


Exemples d'EXEC GDG dans un programme COBOL :

EXEC GDG 'INIT'.

EXEC GDG 'CONNECT' USING 'MYBASE' :MYUSERID
IF GDGRC NOT = 0 GO TO NO-CONNECT.

EXEC GDG 'CALLPROC' USING 'PROCSEL1' :PARAM1 'VALEUR-PARAM2'.
IF GDGRC NOT = 0 GO TO BROKEN-CONN.

MOVE 'procsel2' TO PROCNAME
EXEC GDG 'CALLPROC" USING :PROCNAME.

EXEC GDG 'SENDSQL' USING :MYREQUEST.
EXEC GDG 'SENDSQL' USING 'UPDATE mytab set F1=v1 where F2=v2'.

EXEC GDG 'SETREPLY' USING 'GDG-PARSE'.
EXEC GDG 'GETREPLY' USING :FLD1 :FLD2 :FLD3.
IF SQLRC = 100 GO TO NO-MORE.

EXEC GDG 'SETREPLY' USING 'GDG-NO-PARSE'.
EXEC GDG 'GETREPLY'.
Top of Document

3 - GDG batch utility

Le programme GDGUTIL permet d'envoyer des requêtes à un serveur GDG.

Il traite des sous-commandes GDG ou SQL en entrée, les envoie au serveur, et affiche les résultats.

Les sous-commandes sont lues sur le DDNAME 'SYSIN' pour MVS, ou le standard input pour USS.

Les résultats sont affichés sur le DDNAME 'SYSPRINT' pour MVS, ou le standard output pour USS.

GDGUTIL reconnaît et traite explicitement les 2 sous-commandes suivantes :

echo texte quelconque

connect dbalias [userid[:password]@hostname[:port]]

Toutes les autres clauses sont considérées comme commandes SQL valides, et sont envoyées 'ex-abrupto' au serveur GDG, qui se charge de les reconnaître et de les traiter.

Voir exemples d'utilisation en Annexe D .

Top of Document

4 - GDG C langage API

L'API se compose :
  • d'un 'header' pour les programmes C (gdgbase.h, cf en annexe)
  • d'une librairie, livrée sous forme de DLL (Windows), de 'shared object' (UNIX/Linux), et d'une librairie statique d'objets traditionnels (Librairie objet MVS, librairie statique UNIX/Linux ou Windows)

La librairie implémente 5 points d'entrée ou routines :

Début / fin de session : 2 routines
GDGOPEN
GDGCLOSE
Exécution de Procédure ou commande SQL : 2 routines
GDGSPROC
GDGSRQST
Lecture des résultats : 1 routine
GDGGRPLY

Elles prennent en commun la GDG_AREA en premier paramètre, et au retour, présentent 1 ou 2 codes retour :

  1. le code GDGRC, qui matérialise l'état de la connexion,
  2. le code SQLRC, donné par le moteur SQL lors de la lecture des résultats.

La routine GDGOPEN

But : établissement de la connexion avec le serveur GDG
Arguments : GDG_AREA, nom de la base ou de l'instance, chaîne d'identification
nom de la base : 20 caractères.
identification : 50 caractères, de la forme userid[:password]@machine_IP[:port_GDG]
code retour GDGRC : = 0 si ok et liaison établie, sinon problème de connexion ou paramètres incorrects.

La routine GDGCLOSE

But : coupure de la connexion avec le serveur GDG
Arguments : GDG_AREA
pas de code retour significatif

La routine GDGSPROC

But : lancement d'un procédure cataloguée SQL au serveur GDG
Arguments : GDG_AREA, liste de paramètres et leur longueur, paramètre NULL
code retour : GDGRC = 0 si ok et liaison établie, sinon problème de connexion ou paramètres incorrects.
Le ou les résultat de la procédure sont à disposition via la routine GDGGRPLY,obligatoire.

La routine GDGSRQST

But : envoi d'une commande SQL arbitraire au serveur GDG
Arguments : GDG_AREA, commande SQL, longueur
code retour GDGRC : = 0 si ok et liaison établie, sinon problème de connexion ou paramètres incorrects.
Le ou les résultat de la commande sont à disposition via la routine GDGGRPLY, obligatoire.

La routine GDGGRPLY

But : lecture d'une ligne de résultat en provenance du serveur GDG, après GDGSPROC ou GDGSRQST.
Arguments : GDG_AREA, liste de champs et leur longueur, champ NULL
code retour GDGRC : = 0 si ok et liaison établie, sinon problème de connexion ou paramètres incorrects.
code retour SQLRC : = 0 si ok, = 100 si pas de résultat significatif, ou code renvoyé par le moteur SQL

Le code retour GDGRC matérialise l'état de la connexion, et la validité des paramètres :

0 : la connexion est ou reste établie, et les paramètres sont bons.
1 : la connexion n'est pas établie, ou a été coupée.
1001, 1002, .... : le couple de paramètres [zone, longueur] n.1, 2, ... est incorrect.

Le code retour SQLRC n'est établi que pour la routine GDGGRPLY.
Il est renvoyé par le moteur SQL concerné, et restitué par le serveur GDG tel quel pour les commandes de type 'SELECT' ou procédure assimilées.

Pour les autres commandes SQL, qui ne renvoient pas de résultat à proprement parlé, la valeur 0 est remplacé par 100 (plus de résultat disponibles), de manière à unifier la programmation; les autres valeur sont transmises inchangées.

Top of Document

Annexe A : GDG AREA COBOL structure

   * Zone automatiquement generee par le preprocesseur GDG :
    01  GDG-AREA.
        05 SQLRC   PIC S9(9) COMP.
        05 GDGRC   PIC S9(9) COMP.
        05 CNXFD   PIC S9(9) COMP.
        05 REQNO   PIC S9(9) COMP.
        05 GDGDBG   PIC X.
        05 GDGRQTYP  PIC X.
        05 GDGPRG   PIC X(8).
        05 FILLER   PIC X.
Top of Document

Annexe B : GDG Area header for C program (gdgbase.h)


typedef struct t_gdg {
      int  sqlrc;         /* retcode sql */
      int  gdgrc;         /* retcode GDG */
      int  cnxfd;         /* handle  (0, 1, ... */
      int  reqno;         /* n. requete, future extension */
      char gdgdbg;        /* 'D' = debug GDG */
      char reqtyp;        /* 'S' = résultat global, autre = par champ */
      char prgname[8];    /* pour les traces                          */
      char filler;        /* internal                                 */

} T_GDG, * PGDG;

#define LGDG sizeof(T_GDG)

void GDGOPEN(PGDG pgdg, char * dbn, char * cnxstr);
void GDGCLOSE(PGDG pgdg);
void GDGSPROC(PGDG pgdg, char * procname, ... );
void GDGSRQST(PGDG pgdg, char * rqst, int * plg);
void GDGGRPLY(PGDG pgdg, ... );

#define GDG_ERR_OK         0
#define GDG_ERR_NOPIPE     1
#define GDG_ERR_BROKEN     2
#define GDG_ERR_BADARG  1000
Top of Document

Annexe C : Sample use of GDG COBOL preprocesseur

//PRECOMP  JOB XYZ,'ACCOUNT',MSGLEVEL=(1,1),MSGCLASS=X,CLASS=A
//PREGDG   EXEC PGM=GDG2COB
//STEPLIB  DD  DISP=SHR,DSN=XYZ.GDG.LOADLIB
//FCOB     DD  DISP=SHR,DSN=XYZ.DEVEL.COB(ESGDGCB)
//FGDG     DD  *
       IDENTIFICATION DIVISION.
       PROGRAM-ID.    ESGDGCB.
      *----------------------------------------------------------------
      *
      * Ce programme demontre l'utilisation du preprocesseur GDG COBOL :
      *
      * 1) connexion a la database
      * 2) envoyer une procédure cataloguee avec ses arguments,
      *    lire les résultats ligne a ligne dans des champs determines.
      * 3) envoyer une commande select en format libre,
      *    lire les résultats ligne a ligne, par ligne complete.
      * 4) envoyer une commande update en format libre,
      *    lire le résultat pour le retcode SQL unisquement
      * 5) couper la connexion.
      *
      *----------------------------------------------------------------
       ENVIRONMENT DIVISION.
      *
       CONFIGURATION SECTION.
       SPECIAL-NAMES.
           DECIMAL-POINT IS COMMA.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
      *
       DATA DIVISION.
       FILE SECTION.
      *
      *
       WORKING-STORAGE SECTION.
      *
      *------  LES ZONES DE MANOEUVRE ------------------
      *
      * Zones  pour connexion
       77  ESGDGV  PIC X(8)  VALUE 'V 3.12A'.
       77  CNXSTR  PIC X(50).
       77  DBNAME  PIC X(10) VALUE 'archives'.
      * Champs pour résultats select
       77  JD           PIC X(15).
       77  PATH         PIC X(40).
       77  NUM          PIC 9999.
       77  SIZ          PIC 9999.
       77  DAT          PIC X(12).
      * Divers
       77  CATEG        PIC X(12).
       77  STMT         PIC X(1000).
       77  résultat     PIC X(1000).
      *
       PROCEDURE DIVISION.
       MAIN SECTION.
      *
      *--------------------------------------------------------------*
      *
           DISPLAY "Debut programme " ESGDGV
           ACCEPT CNXSTR
           DISPLAY "Database archives on " CNXSTR.
      *--------------------------------------------------------------*
      *       PRIMITIVE INIT                                         *
           EXEC GDG 'INIT'.
      *--------------------------------------------------------------*
      *
      *--------------------------------------------------------------*
      *--------------------------------------------------------------*
      *--------------------------------------------------------------*
      *       PRIMITIVE CONNECT                                      *
      *       BUT : ETABLIR LA CONNEXION                             *
      *       ARGS: NOM de la base, chaîne d'identification          *
      *       RETCODE  : GDGRC = 0 : Ok,  <> 0 : KO                  *
      *--------------------------------------------------------------*
      *--------------------------------------------------------------*
      *--------------------------------------------------------------*
      *
           DISPLAY "GDG CONNECT " DBNAME " + " CNXSTR " ..."
           EXEC GDG 'CONNECT'  USING :DBNAME :CNXSTR.
           DISPLAY "gdgopen  -> GDGRC=" GDGRC.
           IF GDGRC NOT = 0  GO TO FIN.
      *
      *
      *
      *--------------------------------------------------------------*
      *--------------------------------------------------------------*
      *--------------------------------------------------------------*
      *       PRIMITIVE CALLPROC :                                   *
      *       BUT :   DEMANDE D'EXEC D'UNE PROCEDURE                 *
      *       ARGS: NOM de la proc, params_proc ...                  *
      *       NOM DE LA PROC : procsel1                              *
      *       Param de la PROC: CATEG, 12 octets                     *
      *       RETCODE  : GDGRC = 0 : Ok,  <> 0 : KO                  *
      *--------------------------------------------------------------*
      *--------------------------------------------------------------*
      *--------------------------------------------------------------*
      *
           DISPLAY "GDG CallProc for procsel1 ..."
           MOVE 'DBMS' TO CATEG
           EXEC GDG 'CALLPROC' USING 'procsel1' :CATEG.
           DISPLAY "gdg Callproc : retcode GDGRC=" GDGRC.
           IF GDGRC NOT = 0  GO TO CLOSE-IT.
      *
      *--------------------------------------------------------------*
      *--------------------------------------------------------------*
      *--------------------------------------------------------------*
      *       PRIMITIVE GETREPLY :                                   *
      *       BUT : LIRE UNE LIGNE DE résultatS                      *
      *       ARGS: Liste de champs                                  *
      *             ex       : JD, NUM, PATH, SIZ                    *
      *       NOTE: mettre GDGRQTYP a blanc pour la lecture par champ*
      *       RETCODES : GDGRC = 0 : Ok,  <> 0 : KO                  *
      *                  SQLRC = 0 : Ok,  <> 0 (100) : plus rien     *
      *--------------------------------------------------------------*
      *--------------------------------------------------------------*
      *--------------------------------------------------------------*
      *
           DISPLAY "gdg getreply for procsel1 ...".
      * Pour dire qu'on veut les résultats champ/champ :
           EXEC GDG 'SETREPLY' USING 'GDG-PARSE'.
       LEC.
      * Lecture une ligne de résultats dans les champs designes :
           EXEC GDG 'GETREPLY' USING :JD :NUM :PATH :SIZ :DAT.
           IF GDGRC NOT = 0 GO TO CLOSE-IT.
           IF SQLRC = 0
                 DISPLAY JD "+" NUM "+" PATH "+" SIZ "+" DAT
                 GO TO LEC.
      * On s'arrete quand SQLRC est different de 0
      *
      *--------------------------------------------------------------*
      *--------------------------------------------------------------*
      *--------------------------------------------------------------*
      *       PRIMITIVE SENDSQL  :                                   *
      *       BUT : ENVOYER UN PHRASE SQL ARBITRAIRE                 *
      *       ARGS: La commande sql                                       *
      *       RETCODES : GDGRC = 0 : Ok,  <> 0 : KO                  *
      *--------------------------------------------------------------*
      *--------------------------------------------------------------*
      *--------------------------------------------------------------*
      *
      * Une select en format libre :
           DISPLAY "gdg sendsql select EIFFEL 1 ..."
           EXEC GDG 'SENDSQL'  USING
            "select id, num, dat, siz from arch where ID='EIFFEL'".
           IF GDGRC NOT = 0  GO TO CLOSE-IT.
           DISPLAY "Gdg Select : retcode SQL=" SQLRC.
      *--------------------------------------------------------------
      *  GETREPLY : lecture d'une ligne complete de résultat
      *--------------------------------------------------------------
           DISPLAY "gdg getreply for select ...".
      * Pour dire qu'on veut les résultats bruts de fonderie :
           EXEC GDG 'SETREPLY' USING 'GDG-NO-PARSE'.
       LEC2.
      * Lecture une ligne de résultats, telle quelle :
           EXEC GDG 'GETREPLY' USING :résultat.
           IF GDGRC NOT = 0 GO TO CLOSE-IT.
           IF SQLRC = 0
                 DISPLAY résultat
                 GO TO LEC2.
      * On s'arrete quand SQLRC est different de 0
      *
      *--------------------------------------------------------------
      *------- idem pour une commande update :
      *--------------------------------------------------------------
           DISPLAY "gdg sendsql update EIFFEL ..."
      * Mettre en place la commande SQL :
           MOVE
            "update arch set dat='200-05-14' where ID='EIFFEL'"
           TO STMT
      * Envoyer la commande par la routine GDGSRQST :
           EXEC GDG 'SENDSQL'  USING :STMT.
           IF GDGRC NOT = 0  GO TO CLOSE-IT.
      * Lecture du résultat, seul les retcodes sont interessants :
           EXEC GDG 'SETREPLY' USING 'GDG-NO-PARSE'.
      * Appel de la routine GDGGRPLY, sans arguments,
      * juste pour les return codes :
           DISPLAY "gdg getreply for update EIFFEL ..."
           EXEC GDG 'GETREPLY'.
           IF GDGRC NOT = 0 GO TO CLOSE-IT.
           DISPLAY "Gdg Update : retcode SQL=" SQLRC.
      *
           DISPLAY "gdg sendsql select EIFFEL 2 ..."
      *--------------------------------------------------------------
      * Une autre select en format libre :
      *--------------------------------------------------------------
           EXEC GDG 'SENDSQL'  USING
            "select dat from arch where ID='EIFFEL'".
           IF GDGRC NOT = 0  GO TO CLOSE-IT.
           DISPLAY "Gdg Select : retcode SQL=" SQLRC.
      *--------------------------------------------------------------
      *  GETREPLY : lecture d'une ligne complete de résultat
      *--------------------------------------------------------------
           DISPLAY "gdg getreply for select EIFFEL ...".
      * Pour dire qu'on veut les résultats par champ :
           EXEC GDG 'SETREPLY' USING 'GDG-PARSE'.
       LEC3.
      * Lecture une ligne de résultats, telle quelle :
           EXEC GDG 'GETREPLY' USING :DAT.
           IF GDGRC NOT = 0 GO TO CLOSE-IT.
           IF SQLRC = 0
                 DISPLAY "DAT For EIFEEL : " dat
                 GO TO LEC3.
      * On s'arrete quand SQLRC est different de 0
      *--------------------------------------------------------------*
      *--------------------------------------------------------------*
      *--------------------------------------------------------------*
      *       PRIMITIVE CLOSE    :                                   *
      *       BUT : COUPER LA CONNEXION                              *
      *       ARGS: NEANT.                                           *
      *--------------------------------------------------------------*
      *--------------------------------------------------------------*
      *--------------------------------------------------------------*
      *
       CLOSE-IT.
           EXEC GDG 'CLOSE'.
       FIN.
           STOP RUN.
/*
Top of Document

Annexe D : Sample use of GDGUTIL utility on MVS

//JHHEUTL  JOB 1,'PP5645-001',MSGLEVEL=(1,1),MSGCLASS=X,CLASS=A     
//*------ EXEC GDGUTIL         
//GDGUTIL  EXEC PGM=GDGUTIL     
//STEPLIB  DD DISP=SHR,DSN=XYZ.GDG.LOADLIB      
//SYSUDUMP DD SYSOUT=*
//SYSTERM  DD SYSOUT=*   
//SYSPRINT DD SYSOUT=*   
//SYSIN    DD  *
echo ------------ connexion ... ------------------
connect archives myuserid:mypasswd!mygdgsrv:5432
echo ------------ procedure procsel1 ... ---------
select procsel1('MMEDIA')
echo ------------ select DBMS ... ----------------
select id, num, path, dat from arch where cat='DBMS'
echo ------------ update EIFFEL ... --------------
update arch set dat='2003-08-10'  where id='EIFFEL'
echo ------------ display EIFFEL ... -------------
select id, num, path, dat from arch where id='EIFFEL'
echo ============ End of Job =====================
/*

Pour plus d'information, contactez-nous.