Deutsch English
Blog
Home
Über tdbengine
Newsletter
Download
Helpware
Chat
Dokumentation
Einführungskurs
Grundlagen
Programmierumgebung
CGI Aufbereitung
EASY Programmierung
Standard-Bibliothek
Die Datenbank
HTML-Formulare
Befehlsreferenz
HOWTO - Wie kann ich...?
Projekte
Links
Benchmarks
Bug Reporting
Supportanfrage
 
Home    Überblick    Suche    Impressum    Kontakt    Mitglieder
Lektion 2: Die Programmierumgebung der tdbengine

Nachdem in der letzten Lektion die Grundlagen des CGI-Interface vorgestellt wurden, geht es in dieser Lektion um die spezielle Programmierumgebung der tdbengine.

Installation der tdbengine
Um an den Übungen dieser und der folgenden Lektionen teilnehmen zu können, müssen Sie die tdbengine installiert haben. Sie können sich das Programm inklusive der (vorläufigen) Entwicklungsumgebung unter Download herunterladen. Derzeit stehen Versionen für Win32 (also Windows NT, Windows 95/98) und Linux x86 zur Verfügung. Das Paket umfasst auch ein kleines Installationsskript, das im Normalfall folgende Verzeichnisstruktur anlegt:

/home/tdbengine CGI-Programme wie pdk, ddk, dmk und auch test
/home/tdbengine/bin tdbengine(.exe), Log-Dateien
/home/tdbengin/database Datenbank-Grundverzeichnis

Hinweis: Wir verwenden in diesem Kurs grundsätzlich die Unix-Schreibweise für Verzeichnisse. Unter Windows heissen die Verzeichnisse entsprechend dem Installationslaufwerk c:\home\tdbengine etc.

Die Programmierumgebung der tdbengine
Bei der tdbengine handelt es sich um eine 32-Bit Konsolen-Applikation. Sie kann sowohl von der Konsole aus benutzt, als auch als EASY-Interpreter für das CGI-Interface eingesetzt werden. Auf EASY, die Programmiesprache der tdbengine, gehen wir erst in der vierten Lektion genauer ein.

Die tdbengine kann je nach Anforderung folgende Aufgaben übernehmen:

  • EASY-Compiler
  • EASY-Interpreter
  • Datenbank-Server
EASY-Programme werden immer in einen kompakten P-Code compiliert (übersetzt), bevor sie ausgeführt werden (P-Code ist ein maschinenunabhängiger Zwischencode, ein Verfahren, das auch beispielsweise bei Java eingesetzt wird). Diese Vorgehensweise hat folgende Vorteile:
  • Der P-Code kann wesentlich schneller ausgeführt werden als ein Text-Script.
  • Die Syntax-Überprüfung wird vor der Ausführung durchgeführt.
  • Programme können ohne Quelltext weitergegeben werden.
Besonders der zweite Punkt ist wichtig: Stellen Sie sich vor, mitten in einer Datenbank-Transaktion wird das Programm wegen eines Syntax-Fehlers abgebrochen...

Der dritte Punkt ist in Zeiten des Open Source eigentlich nicht mehr besonders relevant, kann aber bei kommerziell erstellten Programmen durchaus eine entscheidende Rolle spielen.

Am wichtigsten freilich ist die Performance, gerade wenn es um CGI-Programme geht. Auf einer gut besuchten Webseite fallen stündlich tausende von CGI-Aufrufen an, und schwerfällig ausgeführte CGI-Programme können den Datendurchsatz drastisch reduzieren. Aus diesem Grund wurden in die tdbengine zusätzlich eine Reihe von Features eingebaut, die allein einer Steigerung der Performance dienen. Doch dazu später mehr.

Die reine Konsolenanwendung
Tdbengine kann auch gänzlich ohne CGI benützt werden. Die folgende kleine Übung zeigt den Einsatz als reine Konsolen-Anwendung:

Übung

Wechseln Sie auf eine Konsole (Windows-Anwender machen ein Fenster für die Eingabe-Aufforderung auf) in das Verzeichnis /home/tdbengine, falls Sie die Standard-Installation vorgenommen haben, andernfalls in das Verzeichnis der EASY-Programme (nicht in das bin-Verzeichnis, in dem tdbengine(.exe) liegt). Löschen Sie hier die Datei test.prg und geben Sie hier folgendes ein:

bin/tdbengine test.mod <RETURN> (bin\tdbengine test.mod bei Windows)

Sie erhalten folgende Ausgabe:

test.mod successfully compiled.

Sie werden sehen, dass im Verzeichnis die Datei test.prg angelegt wurde. Die folgende Eingabe von

bin/tdbengine test.prg <RETURN>

liefert

content-type: text/html
Hello world...

Wir haben hier die tdbengine einmal als Compiler und einmal als Interpreter kennengelernt. Für die nächste Übung öffnen wir eine weitere Konsole und starten dort einen beliebigen Texteditor. Geben Sie hier folgenden Text ein:

PROCEDURE Main
VAR x,y: INTEGER
VAR summe, produkt, quotient, maximum : REAL
  CGICloseBuffer
  Write(0,'Geben Sie eine Zahl ein: ')
  x:=Val(ReadLn(0))
  Write(0,'Geben Sie eine andere Zahl ein: ')
  y:=Val(ReadLn(0))
  summe:=x+y
  produkt:=x*y
  quotient:=x/y
  maximum:=Choice(Sel(x>=y),x,y)
  WriteLn(0,'Summe = '+str(summe))
  WriteLn(0,'Produkt = '+str(produkt))
  WriteLn(0,'Quotient = '+str(quotient,1,4))
  WriteLn(0,'Maximum = '+str(maximum))
ENDPROC

Speichern Sie diesen Text in /home/tdbengine unter mtest.mod ab. Die Übersetzung erfolgt mit

bin/tdbengine mtest.mod <RETURN>

Wir starten das Programm mit

bin/tdbengine mtest.prg <RETURN>

Das Programm verlangt nun die Eingabe zweier Zahlen, und anschließend werden Summe, Produkt, Quotient und Maximum der beiden Zahlen ausgegeben. Das ist eigentlich trivial, und darauf komt es auch gar nicht an. Starten Sie das Programm nochmals, und geben Sie für die zweite Zahl das Wort "hans" ein. Sie erhalten nun keine Antwort des Programms - es ist (wie man so schön sagt) abgestürzt, also vorzeitig beendet worden. In solchen Fällen schreibt die tdbengine einen Eintrag in die Datei error.log in dem Verzeichnis, in dem sich auch tdbengine befindet. Mit

more bin/error.log <RETURN>

können Sie sich diese Datei anzeigen lassen:

21.01.2000 09:35:14.41: 50 (Unbekannter Bezeichner: y:=VAL (READLN (0))) in (61)
21.01.2000 09:35:14.41: 50 (Unbekannter Bezeichner: Main) in (61)
21.01.2000 09:35:14.41: 50 (Unbekannter Bezeichner: Main) in (61)

Meist werden die Fehler mehrfach ausgegeben, da jede Prozedur eine eigene Fehlermeldung schreibt. Jede Zeile beginnt immer mit einer genauen Datums- und Zeitangabe. Dann folgen Fehlercode (hier 50), die dazu gehörende Fehlermeldung (unbekannter Bezeichner), der Programmname (nur beim Einsatz als CGI-Programm) und schließlich die Fehlerposition im P-Code (61).

In den meisten Fällen, vor allem in kleineren Programmen, kann man schon allein aus diesen Angaben die Fehlerpostion im Quelltext bestimmen. Hier würde die Angabe y:=Val(ReadLn(0)) ausreichen, da dieser Ausdruck ja nur ein einziges Mal im Programm vorkommt.

In größeren Progammen freilich, vor allem, wenn mit Bibliotheken gearbeitet wird (USES xyz...), verliert man doch recht schnell den Überblick. Hier kommt nun der zweite Parameter des Compilers tdbengine zum Einsatz. Übergibt man an dieser Stelle die Fehlerposition im P-Code, so compiliert die tdbengine den Quelltext, zeigt aber zusätzlich den gerade übersetzten Queltext an, und zwar solange, bis die übergebene Fehlerpostion erreicht ist. Damit läßt sich nun der Laufzeit-Fehler (= Fehler, der erst zur Laufzeit eines Programms auftritt, und der deshalb nicht vom Compiler erkannt werden kann) sehr genau lokalisieren.

Programme, die abstürzen und vorzeitig beendet werden, erfüllen zwar selten ihren Zweck, sind aber (vor allem in Hinblick auf einen Einsatz als CGI-Programm) nicht so schlimm, wie solche, die überhaupt nicht mehr beendet werden. Wir schreiben ein weiteres Programm, das nur aus den wenigen Zeilen besteht:

PROCEDURE Main
  WHILE 1=1
  END
ENDPROC

Wir speichern das Programm unter ltest.mod, übersetzen und starten es. Wie erwartet, läuft das Programm in einer Endlosschleife - der Rechner zeigt an dieser Konsole keine Reaktion mehr. Nun kann man freilich auf der Konsole Strg-C drücken, was zu einem gewaltsamen Abbruch des Programms führt. Man kann unter Linux auch den Prozess "killen", oder unter Windows den Task-Manager bemühen, um das Programm zu beenden. Läuft jedoch das Programm als CGI-Anwendung auf einem (unter Umständen recht weit) entfernten Rechner, so stehen all diese Mittel nicht zur Verfügung. Hier wird das Programm erst beendet, wenn es der http-Server wegen Zeitüberschreitung "abschießt". Da aber bis dahin vom Pogramm unter Umständen wichtige Ressourcen gebunden werden (Speicher, Prozessorleistung), kann es wichtig werden, das Programm ferngesteuert zu beenden. Dazu machen wir eine weitere Konsole auf und geben dort folgenden Befehl ein:

Linux:

cat > /home/tdbengine/bin/abort <RETURN>
x<Strg-D>

Windows:

copy con \home\tdbengine\bin\abort <RETURN>
x<Strg-Z>

Wir legen also im Verzeichnis der tdbengine eine (nur aus einem Zeichen bestehende) Datei namens "abort" an. Wenige Augenblicke später wird das Programm mit der Endlosschleife klaglos beendet. Und wenn Sie das Verzeichnis überprüfen, so werden Sie feststellen, dass die Datei "abort" auch verschwunden ist.

Damit ist Ihnen eine Möglichkeit gegeben, jedes Programm vorzeitig zu beenden. Sie müssen nur (beispielsweise via ftp) in das Verzeichnis der tdbengine eine Datei mit dem Namen "abort" kopieren. Die tdbengine prüft nach jeder Sekunde Laufzeit, ob eine solche Datei vorhanden ist, und beendet sich, falls die Bedingung zutrifft, aber nicht, ohne zuvor die Datei zu löschen.

Programmsteuerung über tdbengine.ini
Hinweis: Für die folgende Übung sollten Sie unbedingt die neueste Version der tdbengine (ab 20.01.2000) haben, da andernfalls die Pfade für die tdbengine als Konsolenanwendung nicht richtig sind.

Für das nächste Experiment wechseln Sie bitte wieder in den Texteditor und geben dort folgende Zeilen ein

[globals]
logcgi=1

Legen Sie Datei unter dem Namen "tdbengine.ini" im Verzeichnis /home/tdbengine/bin ab. Starten Sie nun das Programm test.prg mit

bin/tdbengine test.prg <RETURN>

Im bin-Verzeichnis finden Sie nun die Datei cgi.log mit folgendem Eintrag:

11:19:55.30 [ ] - 00:00:00.00 - 00:00:00.00 - 00:00:00.00: test.prg ()

In dieser Datei wird, falls in tdbengine.ini unter [globals] der Eintrag loccgi=1 steht, jeder Aufruf der tdbengine protokolliert. Ganz links sehen Sie die Startzeit der tdbengine. Dann folgt (in eckigen Klammern) der Inhalt der Enironment-Variablen REMOTE_ADDR, also die IP-Nummer des Klienten (nur verfügbar, wenn als CGI-Programm gestartet). Dann folgen drei Zeitangaben:

1. Übertragung der Daten vom Klienten
2. Laufzeit des Programms
3. Übertragung der Daten zum Klienten

Dass hier überall der Wert 0 steht liegt daran, dass die Ausführung des Programms test.prg viel zu schnell erfolgt (irgendwo im Mikrosekunden-Bereich).

Dann folgt der Name des Programms, und schließlich in runden Klammern die erweiterte Log-Information, die man vom Programm aus mit der Funktion SetCGILog setzen kann.

Über die Log-Datei kann man sehr genau das Laufzeitverhalten der Programme feststellen. Das kann auf stark frequentierten http-Servern mit vielen CGI-Progammaufrufen eine wesentliche Rolle spielen.

Semaphoren
Bei unserer letzten Übung auf der Konsole geht es um die gleichzeitige Abarbeitung mehrerer CGI-Programme. Starten Sie auf einer Konsole das Programm ltest.prg (unsere Endlosschleife). Wechseln Sie dann auf eine andere Konsole und starten Sie dort das Programm test.prg. Sie erhalten hier nach etwa 10 Sekunden folgende Ausgabe:

content-type: text/html

<h2>tdbengine message</h2>
<h3>CGI-overrun</h3>

Diese Meldung (eigentlich ein HTML-Text) besagt, dass das Programm nicht ausgeführt werden konnte, weil der CGI-timeout überschritten wurde. Das bedeutet also offensichtlich, dass nur ein Proramm zur gleichen Zeit bearbeitet werden kann. Hier kommt nun die Sicherheitsstrategie der tdbengine zum Vorschein. Die tdbengine geht dabei vom ungünstigsten Fall aus, dass eine Programm wesentliche Transaktionen an einem Datenbestand vornimmt. Während einer solchen Transaktion darf kein weiteres Programm ebenfalls eine Transaktion ausführen, denn das würde zu einem inkosistenten Datenbestand führen. Also wartet die tdbengine mit der Bearbeitung des Programms erst einmal eine gewisse Zeit, ob das zuerst gestartete Programm seine Arbeit beendet. Falls dem nicht so ist, wird das zweite Programm überhaupt nicht gestartet, sondern statt dessen die obige Fehlermeldung ausgegeben.

Um das Verhalten genauer untersuchen zu können, ergänzen wird unsere tdbengine.ini folgendermaßen:

[globals]
logcgi=1
timeout=100000

Damit setzen wir die timeout-Zeit (also die Zeit des Wartens für den zweiten Prozess) auf 100 Sekunden = 100000 Millisekunden (Vorgabe ist 10 Sekunden). Nach dem Speichern starten wir wieder test.prg, wechseln dann aber auf die Konsole, auf der ja immer noch unsere Endlosschleife (ltest.prg) läuft, und beenden dieses Programm durch einen beherzten Druck auf Strg-C. Sie werden sehen, dass nahezu im gleichen Augenblick auf der anderen Konsole das Programm test.prg ganz normal abgearbeitet wird.

Mit dieser Strategie ist die tdbengine auf der sicheren Seite. Es kann jedoch sein, dass zwei Programme nichts miteinander zu tun haben, also nicht auf einen gemeinsamen Datenbestand zugreifen. In diesem Fall könnten doch die beiden Programme problemlos nebeneinander laufen, oder? Wir können diesen Zustand recht einfach herstellen, indem wir wiederum in der Datei tdbengine.ini folgende Einträge machen:

[globals]
logcgi=1
timeout=100000
[test]
sema=test.sema

Wieder wollen wir auf der einen Konsolen das Programm ltest.prg starten, und dann auf der anderen Konsole test.prg. Sie werden sehen, dass test.prg sofort (ohne auf irgendwetwas zu warten) abgearbeitet wird.

Ohne hier zu tief ins Detail zu gehen (Semaphoren sind Thema des Fortsetzungskurses), sei hier soviel festgestellt:

Jedes Programm (.prg) kann einen eigenen Eintrag in der tdbengine.ini haben. Wird dabei unter dem Punkt "sema" ein eigener Dateiname angegeben, so kann das Programm parallel zu anderen Programmen gestartet werden.

Als Semaphor können wir uns einen Wächter mit einem Namen vorstellen. Dieser Wächter sorgt dafür, dass nur ein Prozess zu einem Zeitpunkt abgearbeitet wird. Für jedes zu startende Programm schaut die tdbengine zunächst in tdbengine.ini nach, welcher Wächter für das Programm zuständig ist. Falls kein spezieller Wächter angegeben wurde, verwendet die tdbengine den Wächter mit dem Namen "cgi".

Hinweis: Semaphoren werden von der tdbengine in Form von (physikalischen) Dateien realisiert. Wenn kein anderes Verzeichnis angegeben ist, legt tdbengine diese Dateien im aktuellen Verzeichnis an. Sollte hier kein Schreibrecht (und das Recht zum Erzeugen von Dateien) vorliegen, erhalten Sie immer die Meldung "cgi overrun".

Die HTML-Umgebung
Zum Lieferumfang der tdbengine gehören u.a.

  • pdk.prg program developement kit (Programmeditor und Compiler)
  • ddk.prg database developement kit (Datenbank-Erstellung)
  • dmk.prg database modification kit (Datenbank-Bearbeitung)
Mit diesen Kits kann man sehr einfach Programme schreiben und Datenbanken verwalten. Es handelt sich um reine CGI-Anwendungen. Also muss der http-Server aktiviert sein, und Sie benötigen einen Browser.

program develeopent kit

Geben Sie in Ihren Browser die URL http://localhost/cgi-tdb/pdk.prg ein. Sie erhalten ein Formular mit folgenden Eingabefeldern und Schaltern:
source: Eingabefeld Dateiname des EASY-Moduls
load Schalter zur interaktiven Dateiauswahl
new Schalter löscht Text im Eingabefeld und Dateinamen
compile Schalter startet den Compiler
(ohne Namen) Eingabefeld Editor für das EASY-Modul
window 2 Eingabefelder Zeilen / Spalten des Editors
refresh Schalter zeigt das gesamte Formular neu an

Wenn Sie nun den Schalter "load" drücken, wird ein weiteres CGI-Programm (scanfile.prg) gestartet, das eine intraktive Auswahl einer Datei mit der Extension ".mod" gestattet. Hier wählen wir nun "test.mod" aus, und sofort wird der Quelltext in das Editorfenster des pdk-Formulars geladen. Ebenfalls wird der Dateiname im "source"-Feld eingetragen.

Hier können wir nun den Quelltext beliebig verändern. Eine Betätigung des "compile"-Schalters führt zu folgenden Aktionen:

Der Text im Editor-Eingabefeld wird unter dem Namen, der im "source"-Eingabefeld steht, abgespeichert. Dann wird dieser Text compiliert. Schließlich wird "pdk.prg" automatisch wieder gestartet zunächst in das Formular das Ergebnis der Compilierung eingetragen:

test.mod successfully compiled to /cgi-tdb/test.prg

codesize: 68 bytes
variables: 0
procedures: 1

Das Ergebnis der Compilierung, in diesem Fall also /cgi-bin/test.prg, wird als Link ausgeführt, so dass man das frisch erzeugte Programm sofort testen kann (in einem neuen Browser-Fenster). Zusätzlich werden die Eingabefelder mit den bisherigen Informationen gefüllt, damit man gleich weiterarbeiten kann.

Tritt jedoch bei der Compilierung ein Fehler auf, werden zunächst Fehlerart und -position angezeigt. Zusätzlich werden in den Quelltext des Programms Zeilennummern eingeblendet, damit die Fehlerposition leichter auffindbar ist.

Um das Verhalten von pdk zu testen, verändern wir den Text von test.mod fogendermaßen:

PROCEDURE Main
  CGIWriteLn("content-type: text/html")
  CGIWriteLn("")
  CGIWriteLn("<html><body bgcolor=yellow>"
  CGIWriteLn("Hello world...")
  CGIWriteLn("</body></html>")
ENDPROC

Hier fehlt die schließende runde Klammer in der vierten Programmzeile. Der Druck auf den "compile"-Schalter bringt folgende Ausgabe:

error 56: ) erwartet (line 4/42)

CGIWriteLn("<html><body bgcolor=yellow>"
                                        ^

1:
PROCEDURE Main
2:   CGIWriteLn("content-type: text/html")
3:   CGIWriteLn("")
4:   CGIWriteLn("<html><body bgcolor=yellow>"
5:   CGIWriteLn("Hello world...")
6:   CGIWriteLn("</body></html>")
7: ENDPROC

Sie können nun sofort in die entsprechende Zeile gehen (mit dem Cursor selbstverständlich) und dort die fehlende Klammer ergänzen. Die Zeilennummern werden vom Compiler ignoriert. Aus diesem Grund dürfen Sie auch dann, wenn Zeilenummern ausgegeben werden, weitere Zeilen einfügen, weglöschen usw (die Zeilennummern werden übrigens vor dem Abspeichern wieder automatisch entfernt).

Hinweis: Sie können sich mit pdk auch den Quelltext von pdk (pdk.mod) selbst ansehen. Allerdings sollten Sie hier keine Änderungen vonehmen, da ansonsten das wesentliche Programmierwerkzeug u.U. nicht mehr funktioniert.

Bevor wir uns nun dem nächsten Program zuwenden, wollen wir ein neues Verzeichnis anlegen. Drücken Sie dazu nochmals den Schalter "load". Hier wechseln sie zunächst in das Verzeichnis "database" und wählen dort den Punkt "new directory". Geben Sie "address" ein und drücken Sie die RETURN-Taste. Damit haben Sie das Verzeichnis /home/tdbengine/database/address angelegt.

database developement kit

Das nächste Programm, das wir uns näher ansehen, ist ddk.prg. Es dient zum Erzeugen und Umstrukturieren von Datenbanken. Geben Sie die URLhttp://localhost/cgi-tdb/ddk.prg ein, und Sie erhalten wiederum ein Formular, diesmal mit folgenden Eingabefeldern und Schaltern:

database Eingabefeld Datename der Tabelle (*.dat)
load Schalter zur interaktiven Dateiauswahl
new Schalter zum Löschen der Eingabefelder
restructure Schalter zum Umstruktieren einer bestehenden Tabelle
generate Schalter zum Anlegen einer neuen Tabelle
(ohne Namen) Eingabefeld Editor für die Tabellenstruktur
window 2 Eingabefelder Zeilen / Spalten des Editors
refresh Schalter zeigt das gesamte Formular neu an

Geben Sie nun im Feld database folgends ein:

database/adress/adress.dat

In das (große) Textfeld machen Sie folgende Angaben:

[STRUCTURE]
field_1=Vorname,STRING,40
field_2=Name,STRING,40
field_3=Strasse,STRING,40
field_4=Land,STRING,5
field_5=PLZ,STRING,10
field_6=Ort,STRING,40
field_7=Tel,STRING,20
field_8=Fax,STRING,20
field_9=Email,STRING,30

Jetzt drücken Sie den Schalter "generate" und erhalten (falls kein Tippfehler vorliegt) diese Antwort des Programms:

database/address/address.dat successfully generated

database: /home/tdbengine/database/address/adress.dat
records: 0
fields: 9

Damit haben wir eine neue Tabelle erzeugt. Ausgangspunkt ist eine Strukturbeschreibung, also eine Text-Datei, die wie eine Ini-Datei aufgebaut ist. Unter der Abteilung [STRUCTURE] werden die einzelnen Datenfelder festgelegt. Jede Felddefinition beginnt immer mit "field_" und wird fortlaufend durchnumeriert. Die zugrunde liegende Datenbank kann Tabellen mit jeweils bis zu 1000 Feldern verarbeiten. Nach dem Gleichheitszeichen folgt der Feldname und dann, durch ein Komma abgtrennt, der Feldtyp. Allgemein also:

field_x=Feldname,Feldtyp

Das hat zunächst zur Folge, dass im Feldnamen (auch mit Feld-Label bezeichnet) kein Komma enthalten sein kann. Allerdings gibt es für den Feldnamen noch weitere Einschränkungen:

Ein Feldname darf nur aus Buchstaben, Ziffern und dem Unterstrich bestehen. Er darf nicht mit einer Ziffer beginnen.

Der Feldtyp wird immer durch den Typnamen angegeben, eventuell ergänzt um weitere Typangaben. In unserer Tabelle tritt nur der Typ "STRING" auf, der beliebige alphanmerische Daten speichern kann. Der Typ "STRING" bedarf immer einer weiteren Angabe, mit der die maximal zu speichernde Zeichenzahl festgelegt wird.

Folgende Datentypen stehen zur Verfügung:

  • AUTO,Startnummer
  • BLOB
  • BOOLEAN
  • DATE
  • LINK,Zieltabelle
  • MEMO
  • NUMBER,Speichergröße,Nachkommastellen,Null-Leer-Unterscheidung
  • REL,Zieltabelle
  • SELECT,Auswahlliste
  • STRING,max_Zeichenzahl
  • TIME
  • UTIME
Beim Typ "NUMBER" ergeben sich je nach angegebener Speichergöße unterschiedliche Zahlenformate:

Speichergröße Wertbereich
1             0 bis 255
2             -32.768 bis +32.767
4             -2.147.483.648 bis 2.147.483.647
6             Fließkomma mit 11-stelliger Genauigkeit (altes TDB-Format)
8             Fließkomma mit doppelter Genauigkeit (neues TDB-Format)

Die Anzahl der Nachkommastellen (bei Fließkommazahlen) spielt nur eine untergeordnete Bedeutung, intern werden die Daten immer mit voller Genauigkeit gespeichert und verarbeitet.

Hinweis: Sie sollten bei Fließkommazahlen immer den neuen Typ (8) verwenden, da hier nicht nur der wesentlich genauer, sondern zudem auch wesentlich schneller gerechnet werden kann.

Hier noch einige Bemerkungen zu den Datentypen:

AUTO führt zu einem Feld des Typs NUMBER,4 mit automatischer Hochzählung bei jedem neuen Datensatz. Wird kein Startwert angegeben, so beginnt die Zählung mit 1. Enthält eine Tabelle ein AUTO-Feld, so wird über dieses Feld zudem automatisch ein Index angelegt (Tabellenname.INR), un es muss zusätzlich unter der Abteilung [INDEX] ein sogenannter ID-Index festgelegt werden:

[INDEX]
id=Name,Vorname

BLOB steht für Binary Large OBjects. Felder dieses Types können (im Prinzip) beliebig große Binärdaten speichern, wie zum Beispiel Bilder, Sounds etc. Diese Felder werden in diesem Kurs nicht verwendet.

BOOLEAN führen zu einem NUMBER,1-Feld, das jedoch nur die Werte 0 (für falsch, trifft nicht zu) oder 1 (für wahr, trifft zu) annehmen kann.

DATE speichert ein Datum in NUMBER,4-Form. Es kennt zwar keine vorchristlichen Termine (negative Werte), dafür aber auch keine Jahrtausend-Probleme.

LINK benötigt als zusätzliche Angabe den Namen einer Zieltabelle. Das Feld speichert dann die Autonummer der Zieltabelle, und ermöglicht somit recht einfach die Bildung von 1:n-Relationen. LINK-Felder bilden den Kern des ADL-Systems (Automatic Data Link = Automatische Datenverknüpfung). LINK-Felder werden in diesem Kurs nicht verwendet.

MEMO speichert beliebig langen (unformatierten) Text. Sie werden in einer eigenen Datei abgelegt (Tabellenname.MMO). In der Tabellendatei selbst steht nur ein Verweis auf den Beginn des Textes (als NUMBER,4).

NUMBER speichert Zahlen mit dem bereits angegebenen Wertbereich. Zusätzlich kann mit "U" angegeben werden, ob eine Unterscheidung Null/undefiniert gewünscht wird. Diese Unterscheidung erhöht den Speicherbedarf um ein Byte.

REL erlaubt n:m-Relationen mit Hilfe des ADL-Systems. Sie werden zwar in diesem Kurs nicht implizit behandelt, wir begegnen ihnen aber in Verbindung mit der Volltext-Indizierung#

SELECT definiert ein Auswahlfeld. Die Konstanten des Auswahlfeldes werden einfach - durch Komma getrennt - angegeben.

Beispiel:

Field_19=Familienstand,SELECT,ledig,vereiratet,geschieden,verwitwet

Es wird ein NUMBER,1-Feld erzeugt, das entweder 0 enthält, wenn noch kein Wert zugewiesen wurde, oder die Nummer der entsprechenden Konstante (1 für ledig, 2 für verheiratet...)

STRING speichert Zeichenketten, die alle Zeichen (inclusive chr(0)) enthalten dürfen.

TIME speichert eine Zeitangabe im NUMBER,2-Format (Anzahl der Minuten seit Mitternacht). Für genauere Zeitangaben muß ein Fließkomma-Typ gewählt werden, wobei Sekunden als Minutenbruchteile angegeben werden Die Funktionen "now" und "timestr" können mit Zeitangaben bis 1/1.000-tel Sekunden arbeiten.

Wir werden in diesem Kurs vorwiegend mit STRING und MEMO arbeiten.

Sie können mit ddk.prg eine einmal angelegte Tabelle jederzeit umstrukturieren, d.h. Felder hinzufügen, wegnehmen, in der Reihenfolge oder im Typ verändern. Beachten Sie jedoch, dass der Inhalt eines Feldes unwiderruflich verloren ist, wenn das Feld bei einer Umstrukturierung entfernt wurde.

Wenn Sie ein Feld im Zuge eine Umstruktuierung umbenennen wollen, so müssen Sie die Ursprungsnamen in runden Klammern an das Ende der Felddefinition stellen. Beispiel:

field_2=Familienname,STRING,40(Name)

Bei der Umstrukturierung wird dann der Inhalt des (bisherigen) Feldes "Name" in das (neue) Feld "Familienname" übertragen.

database modification kit

Als letztes unserer Werkzeuge wollen wir das database modification kit dmk.prg betrachten. Es erlaubt alle Basisoperationen mit einer Tabelle:

  • Eingabe von neuen Datensätzen
  • Verändern von bestehenden Datensätzen
  • Löschen von Datensätzen
  • Sequentielle Suche nach Datensätzen
Darüber hinaus kann dmk noch ein paar weitergehende Operationen mit Tabellen:
  • Volltext-Indizierung und -Suche über die ersten 8 Felder der Tabelle
  • Suchen und Ersetzen von Datenfeldern
  • Export von beliebigen Spaltenkombinationen im ASCII- und ANSI-Format
Eingabe von Datensätzen

Wenn Sie den Schalter "open", können Sie unsere Datenbank "address.dat" auswählen. Nachdem die Tabelle bislang leer ist, müssen wir erst ein paar Datensätze eingeben. Dazu wählen wir nun den Punkt "append new record". Wir erhalten ein Eingabeformular mit genau den Feldern, die wir in unserer Tabelle angelegt haben. Wenn Sie das Formular ausgefüllt haben, drücken Sie den Schalter "append", und schon wird der Datensatz in der Tabelle angezeigt. Geben Sie auf diese Art und Weise eine handvoll Datensätze ein, damit die weiteren Möglichkeiten des Programms sinnvoll getestet werden können.

Editieren eines Datensatzes

In der Tabelle werden immer zwei Links eingefügt: "edit" und "delete". Wenn Sie "edit" auswählen, können Sie den entsprechenden Datensatz editieren. Dazu wird der Datensatz im Eingabeformular angezeigt. Sie können nun beliebige Änderungen vornehmen. Mit "save" wird der Datensatz zurückgeschrieben. "append new record" fügt den geänderten Datensatz an die Tabelle an. Das ist praktisch, wenn sich zwei Datensätze nur wenig unterscheiden. Man gibt einen ein, wählt "edit", trägt die Unterschiede des zweiten ein und speichert den Satz dann neu.

Löschen eines Satzes

Betätigt man den Link "delete", wird der entsprechende Datensatz gelöscht. Es erfolgt hier aber eine Sicherheitsabfrage, denn ein gelöschter Datensatz ist wirklich aus der Tabelle entfernt. Deshalb wird zunächst der ausgewähle Datensatz komplett angezeigt, und man kann nun wählen, ob der Satz wirklich gelöscht ("delete") werden soll, oder ob man es lieber unterlässt ("cancel").

Auswahl der angezeigten Felder

Wenn Sie nichts weiter auswählen, werden die ersten acht Felder einer Datenbank in der Tabelle angezeigt. Über dem Schalter "view" können Sie aber eine beliebige Auswahl aus den Feldern treffen (unter Windows erfolgt die Mehrfachauswahl mit der Strg-Taste, unter Linux durch einfaches Anklicken). Beachten Sie, dass der Inhalt von Memofeldern nicht in der Tabelle ausgegeben wird. Hier wird nur "leer" ausgegeben, wenn kein Inhalt vorhanden ist, andernfalls "Memo".

Suchen in der Tabelle

Solange eine Tabelle aus nur ein paar Datensätzen besteht, reicht der Überblick, den die Tabellenform bietet. Immerhin hat man dabei eine bestimmte Zahl (kann unter "recs/page" eingegeben werden) von Datensätzen im Direktzugriff, und man kann mit den Schaltern am Ende der Tabelle "navigieren":

<< zum Anfang der Tabelle
< eine Seite zurück
> eine Seite weiter
>> an das Tabellenende

Die tdbengine ist aber in der Lage, sehr große Tabellen mit Millionen von Datensätzen zu verwalten. Um hier einen Datensatz bzw. eine Datensatzmenge zu selektieren, müssen bestimmte Mechanismen bereitgestellt werden. Dmk.prg arbeitet dabei mit einer Kombination aus "sequentieller Suche" und "Volltext-Suche". Die Ergebnisse werden mit logischem "und" verknüpft, so dass nur diejenigen Datensätze zur Anzeige kommen, die beide Kriterien erfüllen.

Die genaue Syntax einer Selektion in EASY werden wir erst später im Kurs kennenlernen. Hier reicht erst einmal eine einfache Form:

Feldname Vergleichsoperator Konstante

Die Feldnamen haben Sie in der Strukturdefinition festgelegt. Nachdem wir in unserer Tabelle nur STRING-Felder haben, wollen wir an dieser Stelle auch nur die wichtigsten Vergleichsoperatoren für STRINGs besprechen

= genaue Gleichheit
> lexikalisch nach
>= lexikalisch gleich oder nach
< lexikalisch vor
<= lexikalisch gleich oder vor
<> ungleich
like Mustervergleich mit den Wildcards "?" und "*"
in Mengenvergleich

Die Konstanten müssen immer in einfachen oder doppelten Anführungszeichen angegeben werden. Beim Mengenvergleich wird eine Aufzählung von Konstanten in eckigen Klammern angegeben.

Beispiele für Selektionen:

Name = "Huber"
Vorname >= "M"
PLZ like "80*"
Ort <> "München"
Strasse like "h*platz*"
Ort in ["München","Hamburg","Berlin"]

Derartige logische Grundausdrücke können mit logischen Operatoren (AND OR NOT) zu komplexen logischen Aussagen verknüpft werden:

Beispiele für zusammengesetzte Selektionen:

Ort like "M*" AND Name in ["Müller","Huber","M??er"]
PLZ = "80335" OR PLZ = "80336"

Eine Selektion können Sie im Eingabefeld "select" eintragen und dann den zugehörigen Schalter drücken. Sie sehen in der Statusanzeige, wie viele Datensätze gefunden wurden ("selected"), und es werden nur noch solche Datensätze angezeigt, die die Selektion erfüllen.

Hinweis: Bei Feldnamen wird Groß/Kleinschreibung unterschieden (ebenso wie bei allen selbstdefinierten Bezeichnern).

Die Eingabe einer Selektion führt zu einer sequentiellen Suche in der Tabelle. Diese heisst so, weil im Prinzip die gesamte Tabelle Datensatz für Datensatz (=sequentiell) geprüft wird, ob die Selektion zutrifft oder nicht. "Im Prinzip" deshalb, weil die tdbengine selbstverständlich alle verfügbaren Zusatzinformationen (wie beispielsweise Indizes) heranzieht, um die Anfrage möglichst schnell beantworten zu können.

Volltextsuche

Das database modification kit legt für jede einmal geöffnete Tabelle einen feldselektiven Volltextindex über die ersten acht Felder an. Dieser Index wird bei jeder Änderung der Tabelle (Neueinabe, Editieren, Löschen) mitgepflegt, also laufend aktualisert. Feldselektiv nennen wir den Volltextindex, weil darin nicht nur Datensatz, sondern auch Datenfeld des Vorkommens von Wörtern gespeichert wird.

Zur Bildung eines Volltextindex werden die Feldinhalte eines Datensatzes nach Wörtern untersucht. Als Wort gilt hierbei eine zusammenhängende Folge von Buchstaben. Jedes neu gefundene Wort wird in eine eigene Tabelle eingetragen. Zusätzlich wird eine "Referenzliste" erstellt, in der festgehalten wird, welches Wort in welchem Datensatz (und in welchem Feld) gefunden wurde.

Bei der Suche im Volltextindex wird die Vorgehensweise umgekehrt. Hier wird das gesuchte Wort zunächst in Tabelle mit den extrahierten Wörtern (über einen Index, also sehr schnell) gesucht. Daraufhin stehen über die Referenzliste alle Datensätze der Ausgangstabelle zur Verfügung, in denen das Wort vorkommt. Diese Suche erfolgt extrem schnell und ist immer dann mit Vorteil einsetzbar, wenn ganze Wörter (oder Wortfragmente) in Datenfeldern gesucht werden.

Geben Sie in das Eingabefeld "search" ein Wort ein und drücken Sie dann den zugehörigen Schalter. Sofort wird Ihnen das Ergebnis der Volltextsuche angezeigt. Dabei wird das Wort (wie bereits gesagt) in den ersten acht Datenfeldern der Tabelle gesucht. Sie können auch die Wildcards "?" und "*" mit der gewohnten Bedeutung benutzen ("*" für eine beliebige Zeichenfolge, "?" für genau ein Zeichen). Sie können auch die Operatoren '+' (für logisches oder) und ',' (für logisches und) verwenden:

Hamburg + München wenigstens eines der Wörter kommt vor
Hamburg , München beide Wörter kommen gemeinsam vor

Wenn Sie das Vorkommen eines Wortes in einem bestimmten Feld prüfen wollen, kommen Sie einfach den Felddnamen und einen Doppelpunkt dem gesuchten Wort voranstellen:

Ort:München
PLZ:90*

Wiederum kann hier nur ein Teil der Möglichkeiten der Volltextsuche beschreiben werden. Eine genauere Analyse und der Einsatz der Volltextindizierung in eigenen CGI-Programmen ist Gegenstand eines Folgekurses.

Sortierreihenfolge ändern

Im Eingabefeld "sort" kann eine Sortierreihenfolge angegeben werden, die allerdings nur zum Tragen kommt, wenn über sequientielle Suche und/oder Volltextsuche eine Teiltabelle festgelegt wurde. Geben Sie hier die Sortierreihenfolge durch die entsprechenden Feldnamen (durch Komma getrennt) ein.

Beispiel:

Name,Vorname

In diesem Fall wird die Teil-Tabelle zunächst nach Namen sortiert, bei gleichen Namen wird auch noch der Vorname herangezogen. Die Sortierung erfolgt lexikalisch aufsteigend, also "A" vor B". Sie können die Reihenfolge aber auch umdrehen, indem Sie ein Minuszeichen dem jeweligen Feldnamen voranstellen:

-Name,-Vorname

Datensätze exportieren

Sie können sich auch die gesamte Tabelle oder den (via Selektion oder Volltextsuche) definierten Ausschnitt daraus "downloaden". Es werden alle Felder (mit Ausnahme von Memos und Blobs) exportiert, die auch für die Tabellenanzeige unter "view" angegeben wurden. Sie haben die Wahl zwischen "ASCII Tab delimited" und "ANSI Tab delimited". "ASCII" und "ANSI" geben die Sonderzeichen (Umlaute etc.) gemäß DOS (ASCII) oder Windows/Linux (ANSI) aus. Die einzelnen Felder werden durch das Tab-Zeichen getrennt.

Die exportierten Datei können Sie irgendwo auf Ihrer Platte speichern und dann direkt in anderen Programmen weiterverarbeiten, wie beispielsweise MS-Word oder MS-Excel.

Zusammenfassung
Damit ist der Standard-Werkzeugkasten der tdbengine komplett vorgestellt:

Als reine Konsolen-Applikation kann die tdbengine als EASY-Interpreter, Compiler und zur Suche von Laufzeitfehlern dienen.

Mit dem program developement kit können Sie Programme schreiben, übersetzen und ausführen. Das database developement kit eignet sich hervorragend zur Anlage von Tabellen. Und das database modification kit erlaubt schließlich alle grundelgenden Operationen an einer Tabelle. Freilich sind das alles keine End-User-Anwendungen. Wenn Sie eine Adressen-Datenbank zur allgemeinen Verfügung stellen wollen, werden Sie selbstverständlich eigene (individuelle) Eingabemasken verwenden und ebenso spezielle Auswertungen realisieren wollen. Dies sind die Themen der nächsten Folgen unseres Kurses.

Aufgaben:
1. EASY-Programme werden vor der Ausführung in einen speziellen P-Code übersetzt. Warum werden die Programmtexte nicht direkt interpretiert, wie etwa bei PERL?

2. Was versteht man unter einem "Laufzeitfehler"

3. Wie kann man ein von der tdbengine gerade ausgeführtes CGI-Programm vorzeitig beenden?

4. In der Datei tdbengine.ini steht u.a. folgender Eintrag:

    [address]
    sema=address
    timeout=5000

    Was folgt daraus, wenn das CGI-Programm address.prg gestartet wird?

5. Was bedeutet BLOB?

6. Geben Sie die Selektionen an, mit der in unserer Adress-Tabelle gefunden werden:

  a) Alle "Münchner"
  b) Alle "Huber" und "Müller" aus dem PLZ-Gebiet "7"



tdbengine Anwendungen im Web:

Open-Source Web CMS


Open-Source Bug-Tracking


Free wiki hosting

Open-Source Wiki-System

Kostenloses Foren-Hosting

Diät mit tdbengine 8-)

tdbengine chat
irc.tdbengine.org
#tdbengine

   Copyright © 2003-2004 tdb Software Service GmbH
   Alle rechte vorbehalten. / All rights reserved
   Letzte Änderung: 04.05.2004


ranking-charts.de

Programmers Heaven - Where programmers go!