Einsatz der Kombination von Perl und mSQL

geschrieben von Uwe Debacher 1999

Im folgenden Text soll es darum gehen, wie man mit der Programmiersprache Perl und dem Datenbanksystem mSQL Datenbankanwendungen innerhalb eines Intranetsystems erstellen kann. Es müssen folgende Bedingungen erfüllt sein:

Ein Problem besteht darin, daß hier mit drei verschiedenen Programmen gearbeitet wird, die jeweils ihre eigene Programmiersprache besitzen. Die Befehle müssen aber alle in den gleichen Programmtext eingebunden sein. Grundlage ist immer ein Perl-Text. Es ist deshalb wichtig zu beachten, an wen sich der jeweilige Programmierbefehl jeweils richtet.

1. Perl

Perl ist die Abkürzung von Practical Extraction and Report Language (Praktische Sprache für Daten-Extraktion und -Ausgabe) und wird von Larry Wall entwickelt. Es handelt sich hierbei um eine Script-Sprache, eine Sprache die nicht compiliert, sondern interpretiert wird. Die Leistungsfähigkeit dieser Sprache ist enorm und wird durch viele Programmbibliotheken noch erweitert. Die Sprache kann sogar objektorientiert genutzt werden.

Verzweiflung und Begeisterung liegen beim Umgang mit Perl dicht beieinander. Manche Programme, die in Pascal mehrere Seiten umfassen, kann man hier in wenigen Zeilen schreiben. Dafür sind die Fehlermeldungen oft wenig hilfreich, vor allem wenn man über die CGI-Schnittstelle geht, dann bekommt man nur eine nichtssagende Information im Browser, dass ein Fehler aufgetreten ist.

Nähere Hinweise über die Art des Fehlers kann man dann nur in der Fehlerdatei /var/log/httpd.error_log finden

Bevor nun ein Mißverständnis auftaucht möchte ich betonen, dass Perl nicht zwangsläufig etwas mit dem WWW zu tun hat. Es ist einfach nur eine der Sprachen, mit denen man Programme für WWW-Anwendungen schreiben kann. Im folgenden Text wollen wir WWW-Seiten mit Datenbankanbindung erstellen, insofern brauchen wir die CGI-Schnittstelle, die es erlaubt Programme im Web zu nutzen..

1.1. Ein erstes Beispiel über CGI

An dem folgenden einfachen Beispiel kann man ein paar Grundlagen erkennen:

#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "<HTML><HEAD><TITLE>Beispiel1</TITLE></HEAD>";
print "<BODY>Beispiel1</BODY></HTML>";

Alle Perl-Programme beginnen mit einem Pseudo-Kommentar, mit dem das Programm festgelegt wird, das diese Datei auswerten soll, hier also Perl.

Das Beispielprogramm soll eine kleine HTML-Seite erzeugen und würde dazu normalerweise im Ordner cgi-bin abgelegt werden, dem einzigen Platz wo normalerweise ausführbare Programme erlaubt sind.

Da die Seite also nicht normal über den Webserver läuft muß hier auch die zusätzliche Information über den Dokumententyp übermittelt werden, gefolgt von zwei Leerzeilen. Das Zeichen \n" steht für eine neu Zeile.

Die Bedeutung von print dürfte klar sein, hiermit wird eine Ausgabe erzeugt. Der eigentliche HTML-Text steht innerhalb der Anführungszeichen. Sollte man innerhalb der HTML-Tags Anführungszeichen benötigen, so muß man diese als \" schreiben, damit sie nicht das Ende von print markieren.

1.2 Zur Arbeitsweise

Für das Arbeiten an unseren Programmen können wir nicht mit Dos-Editoren arbeiten, da sich die Zeilenendmarkierungen von Dos und Unix unterscheiden. Unix beendet eine Zeile mit dem Zeichen #10, Dos mit #13#10. Das überschüssige #13 irritiert Perl, man erkennt es an einem hellen M am Zeilenende im Linux-Editor.

Zusätzlich möchte ich nicht, dass wir mit dem Kurs im cgi-bin Verzeichnis arbeiten. Ich habe daher einen Ordner /usr/local/httpd/kurs eingerichtet und ihn dem Leistungskurs übereignet. Es können also nur Leistungskurs-Mitglieder in diesem Ordner schreiben. Zusätzlich habe ich erlaubt, dass Programme in diesem Ordner ausgeführt werden können, indem ich in der Datei /etc/httpd/srm.conf die Zeile:

ScriptAlias /kurs/ /usr/local/httpd/kurs/

hinzugefügt habe. Damit wird ein Aufruf von http://gyloh.hh.schule.de/kurs/beispiel.pl auf diesen Ordner umgelenkt.

Das Ausführen von Programmen in diesem Ordner wird durch folgenden Eintrag in der Datei /etc/httpd/access.conf erlaubt:

<Directory /usr/local/httpd/kurs>
AllowOverride None
Options ExecCGI
</Directory>

Wer das auf seinem Rechner entsprechend einrichtet, der muß nach der Änderung den Webserver mittel /sbin/init.d/apache restart neu starten.

1.3. In Perl gibt es immer mehrere Wege

Für umfangreichere Web-Seiten ist das Verfahren mit den vielen Print-Anweisungen unpraktisch. Einfacher ist dann der folgende Weg:

#!/usr/bin/perl
print <<EOF;
Content-type: text/html\n\n
<HTML><HEAD><TITLE>Beispiel1</TITLE></HEAD>
<BODY>Beispiel1</BODY></HTML>
EOF

Im Prinzip ist dies eine Eingabe innerhalb der Datei. Alles bis zur Zeichenkombination EOF wird von Print einfach ausgegeben. Der Bereich kann beliebig lang sein.

2. Formulare in HTML

Im Text will ich nicht auf die Grundlagen von HTML eingehen. Lediglich auf die Arbeit mit Formularen. Alle Eingaben, die wir in den folgenden Abschnitten programmieren wollen erfolgen in ein HTML-Formular. Ein Formular besteht mindestens aus den folgenden Tags: (Kursiv gesetzte Wörter sind Platzhalter für eigene Bezeichner)

<FORM ACTION="/cgi-bin/auswert.pl" METHOD="get">
<INPUT TYPE="text" NAME="name" SIZE="Size"
MAXLENGTH="Länge">
<INPUT TYPE="submit" VALUE="Absenden">
<INPUT TYPE="reset" VALUE="Verwerfen">
</FORM>

Mit dem Einleitungstag muß ein Programm angegeben werden, das die Eingabedaten auswertet, in diesem Fall ein Programm namens auswert.pl. Zusätzlich muß angegeben werden, wie dieses Programm die Daten erhält. Dazu gibt es die Möglichkeiten get und post. Bei der Methode get werden die Daten einfach an die URL des Auswertprogrammes angehängt:

auswert.pl?name=Meier&vorname=Klaus

Bei der Methode post sieht man diese Daten nicht, da eine Art Dialog erfolgt. Bei der Programmentwicklung ist die Methode get praktischer, im endgültigen Programm ist post vorteilhafter.

Die zweite Zeile definiert ein Eingabefeld mit dem Namen name und der Größe Size. Diese Angabe betrifft nur die Darstellung auf dem Bildschirm. Die Maximalzahl der Zeichen die eingegeben werden kann wird auf Länge festgelegt.

Normalerweise hat ein Formular natürlich mehr als ein Eingabefeld. Die einzelnen Felder werden dabei durch ihre Namen unterschieden.

Wichtig für jedes Formular ist auch ein Knopf zum Abschicken. Dazu dient der Typ submit. Die Daten im Formular werden ausgelesen und an das Auswertprogramm übergeben. Üblich in Formularen ist auch ein Resetknopf. Klickt man auf diesen Knopf, so werden alle Eingabefelder gelöscht.

2.1 Ergänzungen zu Formularen

Als action kann anstelle eines eigentlichen Auswertprogrammes auch eine Mail verschickt werden:

<FORM ACTION="mailto:gast@gyloh.hh.schule.de" METHOD="post" enctype="text/plain">

Damit die Mail besser interpretierbar ist, sollte man den Verschlüsselungstyp auf text/plain setzen. Das Eingabefeld vom Typ text erlaubt auch die Angabe eines Wertes, der vorab in das Feld eingetragen wird.

<INPUT TYPE="text" NAME="name" VALUE="Klausi">

Diese Möglichkeit ist besonders dann wichtig, wenn man mittels Formular vorhandene Datensätze ändern möchte. Es stehen innerhalb eines Formulars nicht nur Eingabezeilen zu Verfügung.

2.2 Hidden

Eine Angabe der folgenden Art:

<INPUT TYPE="hidden" NAME="name" VALUE="Klausi">

bewirkt keinerlei Darstellung auf dem Bildschirm. Dieses Feld wird mit seinem Wert einfach nur an das Auswertprogramm übergeben, ohne daß der Benutzer Eingabe machen kann oder überhaupt etwas von diesem Feld bemerkt. Dieser Tag macht nur Sinn, wenn ein VALUE mit angegeben wird.

2.3 Password

Auch dies ist nur eine Variation des Types Text.

<INPUT TYPE="password" NAME="name">

Hierbei wird der Eingabetext nicht auf dem Bildschirm dargestellt, sondern Sternchen.

2.4 Textarea

Mit diesem Tag wird ein Eingabefeld definiert, dessen Höhe und Breite festgelegt werden müssen

<TEXTAREA NAME="name" ROWS=Höhe COLS=Breite>Vorgabe </TEXTAREA>

Dem Eingabefeld kann man leider keine Maximalzahl von Zeichen übergeben. Höhe und Breite beziehen sich auf die Bildschirmdarstellung. Innerhalb des Bereiches kann gescrollt werden.

Vorgaben werden hier nicht mit dem value Tag eingetragen, sondern zwischen Anfangs- und Endtag gesetzt.

2.5 Auswahlfelder

Will man keine freie Eingabe zulassen, sondern dem Benutzer nur die Auswahl zwischen vorgegebenen Werten ermöglichen, dann bietet sich die folgende Kombination an:

<SELECT NAME="name" SIZE=Zeilen>
<OPTION VALUE="wert">Beschreibungstext
<OPTION SELECTED VALUE="wert">Beschreibungstext
...
</SELECT>

Hiermit stelle ich dem Benutzer ein Feld zur Verfügung, das mit einem Mausklick geöffnet wird und die angegebenen Einträge zur Auswahl stellt. Nachdem ein Eintrag angeklickt wurde schließt sich das Auswahlfenster wieder.

Ein Wert darf durch Zusatz von SELECTED als voreingestellt gekennzeichnet werden. Dieser Wert erscheint dann auch im geschlossenen Eingabefeld.

2.6 Checkboxen

Die Verwendung von Auswahlfeldern ist sehr platzsparend. Manchmal möchte man aber alle Optionen immer auf dem Bildschirm sehen, dann arbeitet man besser mit Checkboxen

<INPUT TYPE="checkbox" NAME="name1" VALUE="wert1">Text1<br>
<INPUT TYPE="checkbox" NAME="name2" VALUE="wert2">Text2<br>

Für jeden der Einträge taucht auf dem Bildschirm ein ankreuzbares Kästchen auf. Diese Kästchen sind voneinander unabhängig. Es können also z.B. alle Kästchen oder kein Kästchen angekreuzt sein. Läßt man den VALUE-Eintrag weg, so wert im Zweifelsfall der Wert on genommen.

2.7 Radiobuttons

Will man erreichen, daß immer nur eine Möglichkeit aus einer Auswahl markiert werden kann, dann arbeitet man besser mit Radiobuttons:

<INPUT TYPE="radio" NAME="name" VALUE="eintrag1">Text1<br>
<INPUT TYPE="radio" NAME="name" VALUE="eintrag2">Text2<br>

Hier haben alle Felder den gleichen Namen aber unterschiedliche Werte.

2.8 Ein kleines Beispiel

Im folgenden Seitenquelltext sind fast alle Möglichkeiten berücksichtig:

<!-- Bespielformular von Uwe Debacher,
erstellt am 18.09.98 letzte Aenderung am 12.02.99 -->
<HTML><HEAD><TITLE>Beispielformular</TITLE></HEAD>
<BODY><CENTER><H1>Beispielformular</H1></CENTER>
<FORM ACTION="mailto:gast@server" METHOD="post" enctype="text/plain">
<!-- Ein verstecktes Feld -->
<INPUT TYPE="hidden" NAME="geheim" VALUE="Webformular">
<!-- Ein normales Eingabefeld -->
Wie hei&szlig;t du?<br>
<INPUT TYPE="text" NAME="name" SIZE=20 MAXLENGTH=50>
<!-- Ein Textfeld -->
<p>Sage mir deine Meinung:<br>
<TEXTAREA NAME="meinung" ROWS=3 COLS=60>
Ich habe keine eigene Meinung
</TEXTAREA>
<!-- Ein Auswahlfeld -->
<p>Welches Verkehrsmittel benutzt du zur Schule?
<SELECT NAME="verkehrsm" SIZE=1>
<OPTION VALUE="b">BUS
<OPTION VALUE="a">Auto
<OPTION SELECTED VALUE="f">Fahrrad
</SELECT>
<!-- Checkboxen -->
<p>Besuchst du einen oder mehrere der folgenden
Leistungskurse?:<br>
<INPUT TYPE="checkbox" NAME="mathe">Mathematik
<INPUT TYPE="checkbox" CHECKED NAME="info">Informatik
<!-- Radiobuttons -->
<p>Wie gef&auml;llt dir diese Schule?:<br>
<INPUT TYPE="radio" NAME="urteil" VALUE="s">Sehr gut
<INPUT TYPE="radio" NAME="urteil" CHECKED VALUE="g">Gut
<INPUT TYPE="radio" NAME="urteil" VALUE="m">Mittel

<P><CENTER>
<INPUT TYPE="submit" VALUE="Absenden">
<INPUT TYPE="reset" VALUE="Verwerfen">
</CENTER></FORM></BODY></HTML>

Netscape macht daraus die folgende Darstellung:

Klickt man einfach nur auf Absenden" ohne weitere Eingaben zu machen, so
erscheint folgende URL in der Eingabezeile:
http://server/lk/auswert.pl?name=&meinung=Ich+habe+keine+eigene+Meinung&verkehrsm=f&info=on&urteil=g

Damit sieht man genau welche Daten an das Auswertprogramm übergeben werden.

3. CGI-Grundlagen

Die CGI-Schnittstelle (Common Gateway Interface) ist der Teil des Web-Servers, der mit anderem Programmen auf dem Rechner kommunizieren kann. Da jedes ausführbare Programm für einen Webserver ein Risiko darstellt, gibt es ein paar Einschränkungen und Übergabetechniken, die zu beachten sind.

Wenn der Webserver erkennt, das es sich bei einer angeforderten Seite um ein ausführbares Programm handelt, so liefert er nicht dessen Inhalt zurück, sondern er startet dieses Programm und übergibt dessen Ausgabe.

Das Programm kann in einer (fast) beliebigen Programmiersprache geschrieben sein, die meisten CGI-Programme werden aber in Perl geschrieben.

3.1. Umgebungsvariablen

Über die CGI-Schnittstelle werden die Informationen zwischen Client und Server ausgetauscht. Dieser Informationsfluß ist umfangreicher, als die meisten Benutzer ahnen. Das folgende Programm zeigt, wie man diese Informationen abfragen kann:

#!/usr/local/bin/perl
print "Content-type: text/html\n\n";
print "<HTML><HEAD><TITLE>Environment Variable</TITLE></HEAD>";
print "<BODY><H1>CGI Environment Variable</H1><HR>";
print "Der Server-Name ist: <b>$ENV{'SERVER_NAME'}</b><br>";
print "<HR></BODY></HTML>";
exit (0);

In der Umgebung (dem Environment) sind mehrere Variablen gesetzt. Im vorliegenden Beispiel wird die Variable SERVER_NAME abgefragt und auf der Ergebnisseite angezeigt. Bei $ENV handelt es sich um ein Hash-Array, im Prinzip um ein Feld, dessen Indizes beliebige Texte sind. Der Eintrag, der zu dem Index SERVER_NAME gehört, beinhaltet den Namen des Server, in unserem Fall müßte das server.gyloh.hh.schule.de sein.

Die CGI-Schnittstelle kennt (u.a.) die folgenden Variablen:

Variable

Aktueller Wert

Beschreibung

SERVER_SOFTWARE Apache/1.2.6 Version der Server-Software
SERVER_NAME server.gyloh.hh.schule.de Server-Name oder IP
SERVER_PROTOCOL HTTP/1.0 Revision des Server-Protokolls
SERVER_PORT 80 Portnummer des Servers
REQUEST_METHOD GET oder POST Abfragemethode
REMOTE_HOST hh53-42.gyloh.hh.schule.de Client Name
HTTP_USER_AGENT Mozilla/4.07 [de] (Win95; I) Browser
HTTP_ACCEPT image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */* Was kann der Browser
REMOTE_ADDR 192.168.53.42 Client-IP

Nun darf aber niemand auf die Idee kommen, sich mühsam ein Abfrageprogramm für die einzelnen Umgebungsvariablen zu schreiben (Wir arbeiten doch mit Perl!).

Die komplette Liste aller belegten Variablen kann man mit dem folgenden Programm recht einfach abfragen:

#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "<HTML><BODY>";
foreach $index (keys %ENV){
 print "$index = $ENV{$index}<br>\n";
}
print "</BODY></HTML>";

Wir hatten doch gesagt, dass SERVER_NAME ein Index in das Hash-Array ENV ist. Wir gehen nun einfach alle derartigen Indices durch foreach ... keys und geben den jeweiligen Index und seinen zugehörigen Wert aus.

Wenn man ein Hash-Array als Ganzes bezeichnen will, so setzt man das Prozentzeichen vor den Bezeichner, hier als %ENV.

Diese Umgebungsvariablen stehen auch Programmen zur Verfügung, die Formulare auswerten.

3.2. Auswertung von Formulardaten

Die Auswertung von Formulardaten gilt (nicht zu Unrecht) als etwas kompliziert. Aber man kann sich das Leben vereinfachen, wenn man dafür Routinen aus einer Bibliothek benutzt, wie in dem folgenden Listing. Das Beispiel setzt ein beliebiges Formular voraus, das mit dem Eintrag action im Form-Tag auf dieses Programm verweist und keine Einstellungen für das Encoding vornimmt:

#!/usr/bin/perl
require "common.pl";
&parse_form_data (*formdaten);

print "Content-type: text/html\n\n";
print "<HTML><BODY>";
foreach $index (keys %formdaten){
 print "$index = $formdaten{$index}<br>\n";
}
print "</BODY></HTML>";

Der Hauptteil des Programmes entspricht dem vorherigen Listing. Neu sind hier eigentlich nur die ersten beiden Zeilen. Die erste Zeile bindet das Listing common.pl (Achtung: Download-Hinweise beachten) mit ein. In diesem Listing gibt es eine Funktion &parse_form_data, die mit einem Parameter aufgerufen wird. Dieser Parameter bezeichnet wieder ein Hash-Array, in das die Formulardaten hineingeschrieben werden. Schlüssel sind jeweils die Feldbezeichner im Formular, Werte die entsprechenden Einträge im Formular.

Das Programm gibt dann einfach alle Einträge aus.

4. Daten in Perl

In den folgenden abschnitten wollen wir uns mit einigen Grundlagen von Perl etwas systematischer befassen, zuerst mit Daten, also Variablen und Konstanten. Perl unterscheidet zwischen skalaren Daten und Arrays bzw. Listen. Zu den skalaren Daten gehören Zahlen und Texte. Bezeichner für skalare Daten (Skalarvariablen) beginnen immer mit dem $-Zeichen und dahinter einem Buchstaben. Danach können weitere Buchstaben, Ziffern und Unterstriche folgen. Zwischen Groß- und Kleinschreibung wird unterschieden.

Variable müssen aber nicht deklariert werden, der Typ wird bei der Zuweisung festgelegt.

4.1. Zahlen

Perl kennt nur Fließkommazahlen mit doppelter Genauigkeit. Man kann zwar auch Ganzzahlen deklarieren, intern wird aber immer mit Fließkommazahlen gerechnet.

$zahl1 = 4.44444;
$zahl2 = 5;
$zahl3 = -1.2e-23;

Folgende Operationen für Zahlen kennt Perl:
Beispiel Ergebnis
+ 2 + 3.5 5.5 Addition
- 7 - 5.6 1.4 Subtraktion
/ 3 / 2 1.5 Division (Gleitkomma)
** 2**8 256 Potenzieren
% 10 % 3 1 Modulo (Rest beim Teilen)

4.2 Zeichenketten (Strings)

Natürlich kennt Perl auch Zeichenketten oder Strings, sogar gleich zwei unterschiedliche Darstellungen, nämlich Zeichenketten in einfachen Anführungsstrichen und Zeichenketten in doppelten Anführungsstrichen.

Eine Zeichenkette mit einfachen Anführungsstrichen kann alle Zeichen beinhalten, auch einen Zeilenumbruch. Will man einen einfachen Anführungsstrich innerhalb eines solchen Textes haben, so muß man ihn als \' schreiben. Beispiel:

$text= 'eine Zeile
und in der nächsten Zeile weiter';

wäre eine Zulässige Definition.

Bei Texten mit doppelten Anführungszeichen hat der Backslash eine viel größere Bedeutung, man kann damit besondere Zeichen angeben (hier eine Auswahl):
\n Neue Zeile \\ Backslash
\r Wagenrücklauf \" doppeltes Anführungszeichen
\t Tabulator \x40f Hexcode, hier @
\f Formfeed (neue Seite) \cC Controlzeichen, hier Control-C
\a Tonsignal \b Backspace

In doppelten Anführungszeichen (nicht bei den einfachen) werden auch Variable ausgewertet, wie wir es in den Beispielen bereits gesehen haben.

$a = "Hallo";
$b = "$a du!";

Ergibt "Hallo du!" für $b.

Den gleichen Effekt hätte man mit der Addition für Strings erreichen können, für die der einfache Punkt als Operator dient:

$a = "Hallo";
$b = $a . " du!";

4.3. Konvertierung zwischen Zahlen und Zeichenketten

Perl versucht alle Operationen durchzuführen, sofern dies möglich ist:

$a = 3 +"4Meerschweinchen";

ergibt 7, da es sich um eine Addition von Zahlen handelt. Perl versucht den String als Zahl zu interpretieren, nimmt die 4 und ignoriert das Meerschweinchen.

$a = "A" . (4*5);

ergibt A20, da es sich um eine Textaddition handelt. Wegen der Klammer wird hier 4*5 zuerst berechnet.

4.4. Arrays und Datenlisten

Ein Array ist eine geordnete Liste skalarer Daten. Die Daten stehen in einer festen Reihenfolge, die Größe eines Arrays unterliegt (theoretisch) keinen Beschränkungen, es dürfen auch Zahlen und Strings gemischt werden:

(1 ,2 ,3) Array mit drei Zahlen
("Uwe", 4711, 1.8) Array mit einem String, einer Ganzzahl und einer Fließkommazahl

Innerhalt eines Arrays können auch Ausdrücke sein.

Zur Unterscheidung von skalaren Variablen beginnen Array-Variablen mit dem Klammeraffen:

@namen = ("Uwe", "Hannelore", "Anke");
@mehr_namen = ("Karin", @namen, "Inga");

Der Zugriff auf ein bestimmtes Element erfolg dann folgendermaßen:

$wer = $mehr_namen[2]

würde also "Hannelore" der Variablen $wer zuweisen (man zählt ab 0).

Das $-Zeichen bei $mehr_namen[2] ist kein Tippfehler, sondern erklärt sich daraus, dass wir nun ja eine skalare Variable abfragen wollen.

4.5. Assoziative Arrays

assoziative Arrays haben wir ja bereits benutzt. Es handelt sich dabei um Felder, die über skalare Schlüssel angesprochen werden. Aufgrund der internen Darstellung werden diese Felder auch als Hash-Arrays bezeichnet.

$feld{"aaa"}="bbb";
$feld{3.5} = 4711;

Will ich das gesamte Feld bezeichnen, so muß der Bezeichner mit dem %-Zeichen beginnen.

5. Bedingte Anweisungen

Für bedingte Anweisungen besitzt Perl folgendes Konstrukt:

if (Bedingung) {
  Befehl
}

Auch eine zweiseitige Auswahl ist möglich:

if (Bedingung) {
  Befehle
}
else {
  Befehle
}

Will man noch mehr Fälle unterscheiden, so ist auch folgende Erweiterung vorhanden:

elsif (Bedingung) {
  Befehle
}

Wichtig ist, daß die Bedingung immer in Klammern gesetzt werden muß, auch die geschweiften Klammern sind notwendig. In der Bedingung können folgende Vergleichsoperatoren auftauchen:
Vergleich Zahlen Zeichenketten
gleich == eq
ungleich != ne
kleiner als < lt
größer als > gt
kleiner oder gleich <= le
größer oder gleich >= ge

Innerhalb der Bedingung können mehrere Teilbedingungen verknüpft werden. Dafür gibt es die folgenden Operatoren:

&& and logisches Und
|| or logisches Oder
! not Verneinung

Ein kleines Beispiel für die Konsole:

#!/usr/bin/perl
$a=5;
$b=-3;
if ($a>0 && $b>0) {
 print "Beide Zahlen sind positiv"
}
elsif ($a<0 && $b<0) {
 print "Beide Zahlen sind negativ"
}
else {
 print "Ein dritter Fall"
}

6. Wiederholungen

Perl bietet hier viele verschieden Möglichkeiten. Die folgende Darstellung kann keinen Anspruch auf Vollständigkeit erheben.

6.1. foreach

Bei dieser Art der Wiederholung wird auf alle Elemente eines Arrays bzw. einer Liste zugegriffen:

foreach $zeile (@ergebnis) {
  print "$zeile \n";
}

Stellt man im laufenden Programm fest, dass man die Schleife abbrechen könnte, z.B. weil man ein gesuchtes Element gefunden hat, so kann man mittels next an das Ende des laufenden Iterationsschrittes springen bzw. mittels last die Wiederholung beenden.

6.2. for

Bei dieser Wiederholstruktur kann man Anfang und Ende der Wiederholung angegeben:

for ($i=0; $i<100; $i=$i+1) {
 print "$i \n";
}

Die erste Angabe bezeichnet den Anfangswert, die zweite Angabe bestimmt das Ende der Wiederholung und die dritte angabe legt die Schrittweite fest. Im vorliegenden Fall würde ein Perl-Programmierer natürlich $i++; schreiben.

6.3. while

While könnte man mit solange übersetzen.

while ($i < 10) {
 print "noch kleiner\n";
$i++;
}

6.4. until

Until ist ein Gegenstück zu while

until ($i > 10) {
 print "noch kleiner\n";
$i++;
}

Für jede Wiederholstruktur ist es wichtig, daß die ausgeführten Befehle die Bedingung verändert, sonst läuft die Schleife endlos.

7. mSQL

SQL steht für Structured Query Language, was soviel wie strukturierte Abfragesprache bedeutet. Diese Sprache ist recht weit verbreitet und wird z.B. auch von Ms-Access unterstützt. Das m" steht für Mini, was andeuten soll, daß nicht alle Befehle unterstützt werden.

Bevor wir uns mit der Einbindung von mSQL in das Perl-System kümmern erst einmal eine Zusammenstellung der möglichen mSQL Befehle oder wie es in der Dokumentation heißt Clauses".

Alle Befehle lassen sich auch direkt an mSQL absenden. Dazu muß man in einer Telnet-Sitzung folgendes Programm aufrufen

/usr/local/Hughes/bin/msql datenbankname

In unserem Fall heißt die Datenbank kurs. Datenbanken dürfen nur von einem Systemadministrator eingerichtet werden.

7.1 Create

Hiermit wird eine neue Datentabelle in einer vorhandenen Datenbank eingerichtet. Der Name der Datenbank wurde schon vorher festgelegt.

CREATE TABLE tabellen_name (
feld_name feld_typ [not null]
[,feld_name feld_typ [not null]]
[,feld_name feld_typ [not null]] )

Wird die optionale Angabe not null gemacht, so darf dieses Feld nicht leer bleiben.

Als Feld Typen stehen u.a. zur Verfügung:

CHAR(Länge) letztendlich Strings
INT ganze Zahlen
REAL Real Zahlen
DATE Datum in der Art 1-Jan-1997"

Die Tabelle darf auch über mehrere Indexfelder verfügen, die folgendermaßen definiert werden:

CREATE [UNIQUE] INDEX index_name ON
tabellen_name ( feld_name [,feld_name] )

Die optionale Angabe "unique" bewirkt, daß das entsprechende Feld nicht doppelt vorkommen darf.

Beispiel:

CREATE TABLE telfonliste ( name CHAR(20), vorname CHAR(20), telefon CHAR(15) )

7.2 Drop

Drop löscht Informationen. Eine Tabelle wird einfach gelöscht mit:

DROP TABLE tabellen_name

Ein Index wird entsprechend gelöscht mittels:

DROP INDEX index_name FROM tabellen_name

7.3 Insert

Insert dient zum Einfügen von Datensätzen in die Datenbank:

INSERT INTO tabellen_name
[(feld_name, feld_name, ..)]
VALUES (wert1, wert2,..)

Werden die optionalen Spaltennamen weggelassen, so müssen alle Werte in der richtigen Reihenfolge angegeben werden. Will man nur einige Werte eingeben, so müssen die zugehörigen Spaltennamen angegeben sein.

7.4 Select

Dies ist sicherlich die meistbenutzte clause. Hiermit wird eine vorhandene Datenbank abgefragt. Die (vereinfachte) Syntax lautet:

SELECT feld_name [,feld_name] FROM tabellen_name
[WHERE feld_name vergleichs_operator wert]
[ORDER BY feld_name [DESC]]

Als feld_name nach SELECT ist auch * als Jokerzeichen für alle Felder zulässig. Vergleichsoperatoren können sein:

< kleiner als
> größer als
= gleich
<= kleiner oder gleich
>= größer oder gleich
<> ungleich
LIKE Operator für reguläre Ausdrücke im SQL-Stil
CLIKE wie LIKE aber nicht case-sensitiv
RLIKE Operator für reguläre Ausdrücke im Unix-Stil
SLIKE Soundex-Operator für phonetische Vergleiche

Beispiele:

SELECT * FROM telefonliste

liefert als Ergebnis die vollständige Tabelle

SELECT * FROM telefonliste ORDER BY telefon

liefert die vollständige Telefonliste sortiert nach Telefonnummern

SELECT name FROM telefonliste

liefert alle Namen aus der Tabelle

SELECT name FROM telefonliste WHERE name SLIKE 'Meier'

liefert die Namen alle Einträge, die wir Meier klingen.

7.5 Delete

Hiermit werden Datensätze einer Tabelle gelöscht:

DELETE FROM tabellen_name WHERE
spalten_name vergleichs_operator wert

Beispiel:

DELETE FROM telefonliste WHERE telefon=4711

7.6 Update

Aktualisiert einen vorhandenen Datensatz:

UPDATE tabellen_name
SET spalten_name=wert
WHERE spalten_name vergleichs_operator wert

Beispiel

UPDATE telefonliste SET telefon='4711' WHERE telefon='0815'

8. Einbindung von mSQL in Perl

Will man eine Datenbank ansprechen, so muß zuerst eine Verbindung zum mSQL-Server aufgebaut werden. Dazu gibt es viele Möglichkeiten. In der folgenden Beschreibung habe ich mich dafür entschieden das Msql-Mysql Modul aus dem CPAN-Archiv zu benutzen, das mit use Msql; in Perl-Programme eingebunden werden kann. Dies ist zwar ein proprietäres Treiber-Paket, wenn man allgemeiner arbeiten wollte, dann müßte man das universellere Paket DBI einbinden.

Bei der weiten Verbreitung von mSQL überwiegen aber die Vorteil der proprietären Treiber.

Die Perl-Module arbeiten objektorientiert und benutzen zur Kommunikation mit der Datenbank sogenannte Handle.

Das Beispiellisting (Achtung: Download-Hinweise beachten) ist für eigene Experimente ganz hilfreich, da es die Abfrage aller Datenbanken auf einem lokalen System erlaubt. Damit kann man dann eigene Programme kontrollieren, die Tabellen einrichten oder Daten einfügen (sollen).

8.1. Datenbankhandle

Bevor man mit einer Datenbank arbeiten kann, muß man erst einmal eine Verbindung mit ihr aufbauen und einen Datenbankhandle erhalten:

$dbh=Msql->connect; oder
$dbh=Msql->connect("Rechnername", "Datenbank");

Der Datenbankhandel steht danach in der Variablen $dbh zur Verfügung. Der Bezeichner ist natürlich frei wählbar, obwohl $dbh für Datenbankhandle natürlich leicht zu merken ist.

Die Syntax Msql->connect; macht deutlich, dass es sich bei Msql um ein Objekt (aus dem gleichnamigen Modul) handelt, dessen Methode connect wir hier aufrufen. Das Zeichen ->" entspricht hier also dem Punkt in Java bzw. Pascal.

Gibt man der Methode keine Parameter an, so hat man nur einen allgemeinen Zugriff auf das Msql-System und nicht auf eine konkrete Datenbank. Will man auf eine konkrete Datenbank zugreifen, so gibt man ihren Namen als Parameter an. Der Rechnername kann leer bleiben, dann wird der lokale Rechner benutzt, was meistens sinnvoll ist.

Methoden:

-$dbh->selectdb("Datenbank");
 Erlaubt das nachträgliche Angeben einer Datenbank.
-@arr=$dbh->listdbs;
 Liefert ein Array mit den Namen aller Datenbanken auf dem System.
-@arr=$dbh->listtables;
 Liefert ein Array mit den Namen aller Tabellen der gewählten Datenbank.
-$sth=$dbh->query("Abfrage");
 Liefert einen Statementhandle, der die Ergebnisse der Abfrage verfügbar macht.
-$sth=$dbh->listfields("Tabelle");
 Liefert einen Statementhandle, der die Felddefinitionen (Namen, Typen, Längen u.a.) verfügbar macht.
-$scalar=$dbh->errmsg;
 Liefert einen Fehlertext. Dieser kann Notfall auch über $scalar=Msql->errmsg(); abgefragt werden.
-@arr=$dbh->listindex("Tabelle", "Index");
 Liefert ein Array mit den Indizes.
-$scalar=$dbh->host;
 Liefert den Hostnamen.
-$scalar=$dbh->database;
 Liefert den Datenbanknamen

8.2. Statementhandle

Die Ergebnisse von Anfragen und Aufträgen an die Datenbank werden über Statementdandles zurückgeliefert und können über diesen Handle dann abgefragt werden.

Das folgende Beispiel beschreibt eine derartige Datenbankabfrage:

$sth=$dbh->query("SELECT * FROM kurs");

Hier würde also der komplette Inhalt der Tabelle kurs zurückgeliefert werden und kann dann mit den Methoden des Statementhandles abgefragt werden. Im skalaren Kontext wird bei der Abfrage die Zahl der veränderten Zeilen zurückgeliefert. Dies ist vor allem dann wichtig, wenn schreibend auf die Datenbank zugegriffen wurde.

Methoden:

-$scalar=$sth->numrows;
 Liefert die Anzahl der Ergebniszeilen.
-$scalar=$sth->numfields;
 Liefert die Anzahl der Spalten (Felder) im Ergebnis.
-@arr=$sth->fetchrow;
 Liefert eine Ergebniszeile als Array aus den Feldern zurück.
-@arr=$sth->table;
 Liefert ein Array mit den Datenbanken, zu denen das jeweilige Feld gehört.
-@arr=$sth->name;
 Liefert ein Array mit den Namen der Tabellenfelder. Man kann aber auch gezielt
 einzelne Namen abfragen $scalar=$sth->name->[2]; liefert den Namen des dritten
 Feldes zurück.
-@arr=$sth->type;
 Liefert ein Array mit den Typnummern der Tabellenfelder (1=INT, 2=CHAR, 253=key)
-@arr=$sth->length;
 Liefert ein Array mit der erlaubten Länge der Felder.
-@arr=$sth->maxlength;
 Liefert ein Array mit der momentanen Maximallänge der Felder. Kann recht
 lange dauern, da alle Zeilen getestet werden.
-@arr=$sth->isnotnull;
 Liefert ein Array mit Wahrheitswerten aus denen hervorgeht, ob das jeweilige
 Feld leer ist..
-@arr=$sth->isprikey;
 Liefert ein Array mit Wahrheitswerten aus denen hervorgeht, ob das jeweilige
 Feld Primärschlüssel ist..
-@arr=$sth->isnum;
 Liefert ein Array mit Wahrheitswerten aus denen hervorgeht, ob das jeweilige
 Feld numerisch ist.
-$sth->dataseek(Zeilennummer);
 Setzt den Lesezeiger auf die angegebene Zeile. Wird keine Zeilennummer angegeben,
 so wird die erste Zeile (Nummer 0) gewählt. Der Nächste Zugriff
 mit $sth->fetchrow; würde dann die angegebene Zeile liefern.


geschrieben von Uwe Debacher, letzte Änderung am 16.6.99