Virtual OS/2 International Consumer Education
VOICE-Homepage: http://de.os2voice.org
Juli 2004

Inhaltsverzeichnis
< Vorherige Seite | Nächste Seite >
Artikelverzeichnis

editor@os2voice.org


Auf gute Zusammenarbeit: MySQL und OS/2 - Teil 6: Zugriff auf MySQL mit REXX

Von Wolfgang Draxler © Juli 2004

Heute werden wir den Versuch unternehmen, von REXX aus auf die Datenbank zuzugreifen. Dazu ist es notwendig, den Treiber für REXX herunterzuladen. Diesen Treiber findet man im Internet auf der Seite http://rexxsql.sourceforge.net/, im Bereich Download. Dort finden Sie die Datei rxsql24RC1_my_os2.zip. Laden Sie diese Datei herunter und speichern Sie sie in einem eigenen Verzeichnis. Als nächstes entpacken Sie diese Datei. Es sollten folgende Dateien entstehen:

   Copying
   History
   Install
   Readme
   rexxmy.dll
   rexxmy.exe
   rexxsql.dll
   rexxsql.exe

und das Verzeichnis samples.

Die Dateien rexxmy.dll und rexxsql.dll kopieren wir in ein Verzeichnis, daß in der CONFIG.SYS-Anweisung LIBPATH angegeben worden ist, z.B. in das Verzeichnis \os2\dll.

Als nächstes erstellen wir ein eigenes Verzeichnis für die REXX-Programme. Ich verwende dazu das Verzeichnis P:\Rexx\mysql. Nun erstellen Sie in diesem Verzeichnis eine leere Datei namens ListLand.cmd und öffnen diese mit dem OS/2-Systemeditor.

Wie Sie im Artikel »DrDialog, oder wie ich lernte, REXX zu lieben« von Thomas Klein sicherlich schon gelesen haben, muß jedes REXX-Programm mit einer Kommentar-Zeile anfangen.

/* Programm: ListLand.cmd */
/* Autor: Wolfgang Draxler */
/* Datum: 05.05.2004 */

Als nächster Schritt müssen wir den Treiber rexxsql.dll in REXX einbinden. Dies geschieht mittels der Befehle RxFuncAdd und SQLLoadFuncs.

Call RxFuncAdd "SQLLoadFuncs", "rexxsql", "SQLLoadFuncs"
Call SQLLoadFuncs

Genauere Informationen zu den Befehlen finden Sie in der April-Ausgabe von Voice im Artikel »DrDialog, oder wie ich lernte, REXX zu lieben - Teil 12.

Im nächsten Schritt müssen wir eine Verbindung zur MySQL-Datenbank aufbauen. Diese geschieht mit dem Befehl SQLConnect.

Der Aufbau des Befehls ist folgender:

SQLCONNECT([Verbindungsname], [username], [passwort], [datenbank], [host])

Wenn SQLConnect ein negatives Ergebnis liefert, hat der Verbindungsaufbau nicht funktioniert. Dies kann beispielsweise passieren, wenn die Datenbank nicht läuft oder der User oder das Passwort falsch sind.

Es werden fünf Werte übergeben:

Verbindungsname
Damit wird der Verbindung zwischen dem REXX-Programm und der Datenbank ein Name zugewiesen. Andere REXX-SQL-Befehle benötigen diese Information, um den Befehl korrekt abzuarbeiten. Natürlich ist es auch möglich, mehrere Verbindungen in einem REXX-Programm zu verwenden. Dies wird z.B. bei Programmen genutzt, die aus mehreren Datenbanken (auch auf verschieden Computern) diverse Daten verarbeiten sollen.
Username
Hier wird der Username definiert, mit dem sich das Programm bei der MySQL-Datenbank anmelden soll.
Passwort
Das Anwender-Passwort, mit dem sich das Programm bei der MySQL-Datenbank anmelden soll.
Datenbank
Die Datenbank, mit der gearbeitet werden soll.
Host
Hier der Rechner angegeben, auf dem die Datenbank läuft, bei der sich das Programm anmelden soll. Es kann die IP-Adresse oder der Hostname des Rechners angegeben werden. "Localhost" bezeichnet den Rechner, auf dem auch das REXX-Programm läuft.

Für unser Beispiel sollte dann der Aufruf folgender sein, wobei Sie für das Passwort »<PW>« Ihr eigenes Root-Passwort eingeben müssen:

if SQLConnect("Conn", "root", "<PW>", "adressen", "localhost") < 0 then
  do
    say "Verbindungsaufbau hat nicht funktioniert"
    exit
  end

Für den Fall, daß ein Fehler auftritt, schreiben wir das REXX-Programm so, dass es sich korrekt von der Datenbank abmeldet und beendet. Zum korrekten Abmelden von der Datenbank gibt es den Befehl:

SQLDisconnect([Verbindungsname])

Wie Sie sehen, brauchen wir hier den Namen der Verbindung, den wir unter SQLConnect definiert haben.

Nun schicken wir eine Abfrage an die Datenbank. Dies erfolgt durch den Befehl:

SQLPrepare([Statementname, SQL-Statement)

Bei einem negativen Ergebnis konnte das SQL-Statement von MySQL nicht verarbeitet werden. Dies passiert beispielsweise, wenn das SQL-Statement nicht korrekt ist oder die angegebene Tabelle nicht existiert.

SQLPrepare nimmt folgende Parameter entgegen:

Statementname
Hier geben Sie der Abfrage einen Namen. Dieser ist notwendig, damit der Treiber bei anderen REXX-SQL-Befehlen weiß, um welche Abfrage es sich handelt. (Es ist so ähnlich wie bei dem Verbinungsnamen des Befehls SQLConnect.)
SQL-Statement
Hier geben Sie die gewünschte Abfrage ein. Als SQL-Statement können alle (SQL-)Befehle an die MySQL-Datenbank geschickt werden, die wir in den vorherigen Artikeln gelernt haben, z.B. Select, Insert, Delete, Update, Show, Create, Drop usw.

Für den ersten Versuch habe ich nun ein einfaches SQL-Statement ausgesucht. Dieses werden wir vorher in der MySQL-Console ausprobieren. Damit ist sichergestellt, daß uns beim Eingeben des REXX-SQL-Befehls kein SQL-syntaktischer Fehler passiert.

mysql> Select * from land;
+---------+-------------------------+---------+
| kurzbez | bezeichnung             | vorwahl |
+---------+-------------------------+---------+
| A       | Oesterreich             | +43     |
| D       | Deutschland             | +49     |
| CH      | Schweiz                 | +41     |
| GB      | Grossbritannien         | +44     |
| USA     | United State of America | +1      |
| I       | Italien                 | +39     |
| H       | Ungarn                  | +36     |
| NL      | Niederlande             | +31     |
| L       | Luxemburg               | +352    |
| B       | Belgien                 | +32     |
| E       | Spanien                 | +43     |
+---------+-------------------------+---------+
11 rows in set (0.08 sec)

Wie Sie sehen, hat das SQL-Statement funktioniert und wir können es in unser REXX-Programm kopieren. Damit sieht das ganze dann so aus:

if SQLPrepare("prep","Select * from land") < 0 then
  do
    say "SQL-Statement hat nicht funktioniert"
    call SQLDisconnect("conn")
  end

Um auf das Ergebnis zugreifen zu können, muß es mit Hilfe des Befehls

SQLOPEN(Statementname)

geöffnet werden. Wie schon bei den anderen Funktionen gilt: Ein negatives Ergebnis weist auf einen aufgetretenen Fehler hin. Tritt dies ein, soll sich das Programm auch hier korrekt von der Datenbank abmelden und beenden. Das heißt, als erstes muß das Statement, das wir mit SQLOpen geöffnet haben, geschlossen werden und dann muß die Verbindung mit SQLDisconnect beendet werden.

Zum Schließen eines Statements steht folgender Befehl zur Verfügung:

SQLClose(Statement)

Insgesamt sieht das ganze dann so aus:

if sqlopen("prep") < 0 then
  do
    say "SQL-Statement hat nicht funktioniert"
    call SQLClose("prep")
    call SQLDisconnect("conn")
  end

Nun lassen wir uns die Eigenschaften des ersten Feldes (»Kurzbez«) anzeigen. Dazu muß folgender Befehl verwendet werden:

SQLDescribe(Statementname [,Info])

Das Array Info hat dabei folgende Struktur:

NAME

Name der Spalte

TYPE

Datentyp

SIZE, SCALE , PRECISION

Größe des Feldes

NULLABLE ... =1

Die Spalte erlaubt den Wert NULL.

Im Programm sieht dies folgendermaßen aus:

rv=SQLDescribe("prep","desc")
say "Name-Anzahl: " desc.column.name.0
say "Name-Bezeichnung:" desc.column.name.1
say "Name-Type: " desc.column.type.1
say "Name-Groesse: " desc.column.size.1 ", " desc.column.precision.1
say "Name-Scale: " desc.column.scale.1
say "Name-Nullable: " desc.column.nullable.1

Mit dem Befehl SQLFetch(Statementname [, zeilenanzahl]) wird das SQL-Ergebnis zeilenweise gelesen, d.h. jeder Zeile entspricht ein Datensatz. Da wir mehrere Sätze/Zeilen erwarten, müssen wir eine Schleife verwenden, die bei jedem Durchlauf SQLFetch aufruft. Da zu einem gewissen Zeitpunkt alle Sätze gelesen worden sein werden, muß es auch eine Möglichkeit geben, diese Schleife wieder zu verlassen. Diesen Zeitpunkt zeigt uns SQLFetch auch an, und zwar durch das Ergebnis 0. Bei einem negativen Ergebnis ist ein Fehler aufgetreten.

Wie kommt man nun an die einzelnen Felder? Dies ist relativ einfach, wenn man weiß wie es geht. Die Lösung ist folgende: Bei SQLPrepare haben wir einen Statementnamen vergeben. SQLPrepare schickt nicht nur das SQL-Statement an die Datenbank, sondern generiert auch eine sogenannte Stammvariable mit dem Statementnamen, in unserem Beispiel prep. Diese Stammvariable hat als Struktur die Feldnamen des SQL-Statements, in unserem Beispiel also prep.kurzbez, prep.bezeichnung, prep.vorwahl. Diese (Stamm-)Variablen lassen wir uns dann mit dem REXX-Befehl SAY ausgeben.

Dazu müssen wir unserem REXX-Programm folgende Zeilen hinzufügen:

do forever
  rc = SQLFetch('prep')
  if rc < 0 then exit 1
  if rc = 0 then leave
  say prep.kurzbez ', ' prep.bezeichnung "," prep.vorwahl
end

Zum Schluß müssen noch das Statement und die Verbindung geschlossen werden. Dies geschieht, wie schon oben beschrieben, mit SQLClose und SQLDisconnect.

call SQLClose("prep")
call SQLDisconnect("conn")
say "Fertig"

Der gesamte Quellcode sieht damit folgendermaßen aus:


/* Programm: ListLand.cmd  */
/* Autor: Wolfgang Draxler */
/* Datum: 05.05.2004       */

Call RxFuncAdd "SQLLoadFuncs", "rexxsql", "SQLLoadFuncs"
Call SQLLoadFuncs

if SQLConnect( "Conn", "root", "<PW>", "adressen", "localhost") < 0 then
  do
    say "Verbindungsaufbau hat nicht funktioniert"
    exit
  end

if SQLPrepare("prep","Select * from land") < 0 then
  do
    say "SQL-Statement hat nicht funktioniert"
    call SQLDisconnect("conn")
  end

if SQLOpen("prep") < 0 then
  do
    say "SQL-Statement hat nicht funktioniert"
    call SQLClose("prep")
    call SQLDisconnect("conn")
  end

rv=SQLDescribe("prep","desc")
say "Name-Anzahl: " desc.column.name.0
say "Name-Bezeichnung:" desc.column.name.1
say "Name-Type: " desc.column.type.1
say "Name-Groesse: " desc.column.size.1 ", " desc.column.precision.1
say "Name-Scale: " desc.column.scale.1
say "Name-Nullable: " desc.column.nullable.1

do forever
  rc = SQLFetch('prep')
  if rc < 0 then exit 1
  if rc = 0 then leave
  say prep.kurzbez ', ' prep.bezeichnung "," prep.vorwahl
end

call SQLClose("prep")
call SQLDisconnect("conn")
say "Fertig"

Wie Sie sehen, ist es relativ einfach, eine Verbindung zwischen REXX und MySQL aufzubauen.

Nun programmieren wir eine kleine Eingabe für die Tabelle Land. Dazu werden wir eine neue CMD-Datei namens SaveLand.cmd erzeugen.

Als erstes wieder der Kopf und das Einbinden der REXX-MySQL-Funktionen:

/* Programm: SaveLand.cmd */
/* Autor: Wolfgang Draxler */
/* Datum: 05.05.2004 */
Call RxFuncAdd 'SQLLoadFuncs', 'rexxsql', 'SQLLoadFuncs'
Call SQLLoadFuncs

Als nächstes fragen wir den User nach Werten für Kurzbez, Bezeichnung und Vorwahl. Dies geschieht durch den REXX-Befehl Parse Pull:

Say "Kurzbez:"
Parse Pull Kurzbez
Say "Bezeichnung:"
Parse Pull Bezeichnung
Say "Vorwahl:"
Parse Pull Vorwahl

Nun werden wir wieder die Verbindung zu der Datenbank aufbauen, wobei Sie »PW« durch Ihr Root-Passwort ersetzen.

if SQLConnect("Conn", "root", "<PW>", "adressen", "localhost") < 0 then
  do
    say "Verbindungsaufbau hat nicht funktioniert"
    exit
  end

Im nächsten Schritt erstellen wir die Variable »SQL«, die den Insert-Befehl beinhaltet.

SQL = "Insert into land values ('"Kurzbez"','"Bezeichnung"','"Vorwahl"')"
say "SQL=" SQL

Diese Variable wird nun an SQLPrepare übergeben:

if SQLPrepare("prep", SQL) < 0 then
  do
    say "SQL-Statement hat nicht funktioniert"
    call SQLDisconnect("conn")
  end

Im nächsten Schritt wird die Verbindung geschlossen:

call SQLClose("prep")
call SQLDisconnect("conn")
say "Fertig"

Zum testen, öffnen wir ein OS/2-Fenster und wechseln in das Verzeichnis, in dem sich die zwei REXX-Programme befinden (beim mir also P:\Rexx\mySQL):

[P:\rexx\mysql]saveland
Kurzbez:
E
Bezeichnung:
Spanien
Vorwahl:
+43
SQL= Insert into land values ('E','Spanien','+43')
Fertig

Zur Überprüfung starten wir das erste Programm Listland.cmd:

[P:\rexx\mysql]listland
Name-Anzahl: 3
Name-Bezeichnung: bezeichnung
Name-Type: CHAR
Name-Groesse: 3 , 3
Name-Scale: 0
Name-Nullable: 0
A , Oesterreich , +43
D , Deutschland , +49
CH , Schweiz , +41
GB , Grossbritannien , +44
USA , United State of America , +1
I , Italien , +39
H , Ungarn , +36
NL , Niederlande , +31
L , Luxemburg , +352
B , Belgien , +32
E , Spanien , +43
Fertig

Wie Sie sehen, ist »Spanien« nun auch in der Tabelle. Natürlich können Sie dieses auch mit der MySQL-Console überprüfen.

Jetzt wissen Sie, wie Sie REXX und MySQL verbinden können und ich beende hiermit diese Artikel-Serie.

Weitere Informationen zu den Befehlen finden Sie in der Dokumentation des REXX-Treibers.

Daten und Quellen:

MySQL: http://www.mysql.de
MySQL für OS/2 (Yuri Dario): http://www.os2power.com/yuri/
MySQL für OS/2 (Netlabs): http://mysql.netlabs.org
MySQL-Dokumentation: http://www.mysql.com/doc/de/index.html
Weitere MySQL-Dokumentation: http://www.rent-a-database.de/mysql/
REXX-Treiber: http://rexxsql.sourceforge.net


Wolfgang Draxler lebt mit seiner Ehefrau Yvonne in Wien. Er ist für eine Softwareentwicklungs- und Beratungsfirma im Bereich der Organisations- und Datenbankprogrammierung tätig. Privat arbeitet er unter anderem an der Weiterentwicklung von Sibyl für OS/2, einer Delphi-ähnlichen Programmiersprache.

Artikelverzeichnis
editor@os2voice.org
< Vorherige Seite | Inhaltsverzeichnis | Nächste Seite >
VOICE-Homepage: http://de.os2voice.org